Integrating MyBatis-Plus with Spring Boot
1. Dependency Setup
To begin integrating MyBatis-Plus into your Spring Boot project, add the following dependencies to your pom.xml:
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>3.5.11</version>
</dependency>
<!-- Pagination plugin with matching version -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-jsqlparser</artifactId>
<version>3.5.11</version>
</dependency>
2. Database Configuration
Configure your database connection in the application.yml file:
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/project_db?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
username: admin
password: secure_password
3. Entity Class Creation
Create your entity class with proper annotations:
@NoArgsConstructor
@AllArgsConstructor
@Data
@TableName("`customer`")
public class Customer {
@TableId(type = IdType.AUTO)
private Long customerId;
private String fullName;
private String credentials;
private String nickname;
private String emailAddress;
@TableField(fill = FieldFill.INSERT)
private LocalDateTime registrationTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime lastModified;
@Version
private Integer recordVersion;
}
4. Mapper Interface
Create a mapper interface that extends the BaseMapper:
@Mapper
public interface CustomerMapper extends BaseMapper<Customer> {
}
5. Basic Usage Example
Here's how to use the mapper in your service:
@Autowired
private CustomerMapper customerRepository;
public void addNewCustomer() {
Customer newCustomer = new Customer();
newCustomer.setFullName("John Doe");
customerRepository.insert(newCustomer);
}
6. Advanced Features: Optimistic Locking and Pagination
6.1 Configuration Class
Create a configuration class for interceptors:
@Configuration
public class MybatisPlusConfiguration {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
6.2 Optimistic Locking
Ensure your entity has the @Version annotation:
@Version
private Integer recordVersion;
6.3 Pagination Implementation
Implement pagination in your service:
public List<Customer> getPaginatedCustomers() {
Page<Customer> customerPage = new Page<>(2, 3);
QueryWrapper<Customer> queryWrapper = new QueryWrapper<>();
queryWrapper.orderByDesc("customerId");
return customerRepository.selectPage(customerPage, queryWrapper).getRecords();
}
7. Automatic Timestmap Management
7.1 Database Setup
Create timestamp columns in your database table:
- registration_time (datetime)
- last_modified (datetime)
7.2 Entity Annotations
Add field annotations for automatic timestamp filling:
@TableField(fill = FieldFill.INSERT)
private LocalDateTime registrationTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime lastModified;
7.3 Custom Handler Implementation
Create a meta object handler:
@Component
public class TimestampHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
this.strictInsertFill(metaObject, "registrationTime", LocalDateTime.class, LocalDateTime.now());
this.strictUpdateFill(metaObject, "lastModified", LocalDateTime.class, LocalDateTime.now());
}
@Override
public void updateFill(MetaObject metaObject) {
this.strictUpdateFill(metaObject, "lastModified", LocalDateTime.class, LocalDateTime.now());
}
}
Data Validation with Spring Boot
1. Validation Dependencies
Add validation starter to your project:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<version>3.2.2</version>
</dependency>
2. Validation Implementation
Apply validation to your controller methods:
@Validated
@PostMapping("/authenticate")
public Response authenticate(
@Pattern(regexp = "^\\S{5,16}$") String username,
@Pattern(regexp = "^\\S{5,16}$") String password) {
Customer customer = customerRepository.findByUsername(username);
if (customer == null) {
return Response.error("User not found");
}
if (customer.getCredentials().equals(PasswordUtil.encrypt(password))) {
Map<String, Object> payload = new HashMap<>();
payload.put("id", customer.getCustomerId());
payload.put("name", customer.getFullName());
String token = TokenUtil.generate(payload);
return Response.success(token);
}
return Response.error("Invalid credentials");
}
JWT Token Implementation
1. JWT Dependencies
Add the JWT library to your project:
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>4.4.0</version>
</dependency>
2. Token Utility Class
Create a utility class for token operations:
public class TokenUtil {
private static final String SECRET_KEY = "SecureSecretKey123";
public static String generate(Map<String, Object> claims) {
return JWT.create()
.withClaim("payload", claims)
.withExpiresAt(new Date(System.currentTimeMillis() + 12 * 60 * 60 * 1000))
.sign(Algorithm.HMAC256(SECRET_KEY));
}
public static Map<String, Object> verify(String token) {
return JWT.require(Algorithm.HMAC256(SECRET_KEY))
.build()
.verify(token)
.getClaim("payload")
.asMap();
}
}
3. Authentication Interceptor
Create an interceptor for token validation:
@Component
public class AuthInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
String token = request.getHeader("Authorization");
try {
TokenUtil.verify(token);
return true;
} catch (Exception e) {
response.setStatus(401);
return false;
}
}
}
4. Interceptor Configuration
Register the interceptor in your Web configuration:
@Configuration
public class WebSecurityConfig implements WebMvcConfigurer {
@Autowired
private AuthInterceptor authInterceptor;
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authInterceptor)
.excludePathPatterns("/api/auth/login", "/api/auth/register");
}
}
5. Global Exception Handler
Create a centralized exception handler:
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public Response handleException(Exception e) {
return Response.error(e.getMessage() != null ? e.getMessage() : "Operation failed");
}
}
MD5 Encryption Utility
public class PasswordUtil {
private static final char[] hexChars = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
public static String encrypt(String input) {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(input.getBytes());
byte[] digest = md.digest();
char[] result = new char[digest.length * 2];
int position = 0;
for (byte b : digest) {
result[position++] = hexChars[(b & 0xF0) >>> 4];
result[position++] = hexChars[b & 0x0F];
}
return new String(result);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return null;
}
}
}
Unified Response Structure
@Builder
@Data
public class Response<T> {
private int statusCode;
private String message;
private T data;
private static final int SUCCESS = 0;
private static final String SUCCESS_MESSAGE = "Operation successful";
private static final int ERROR = 1;
private static final String ERROR_MESSAGE = "Operation failed";
public static <T> Response<T> success(T data) {
return new Response<>(SUCCESS, SUCCESS_MESSAGE, data);
}
public static <T> Response<T> success(String message, T data) {
return new Response<>(SUCCESS, message, data);
}
public static <T> Response<T> error() {
return new Response<>(ERROR, ERROR_MESSAGE, null);
}
public static <T> Response<T> error(String message) {
return new Response<>(ERROR, message, null);
}
public static <T> Response<T> error(int code, String message) {
return new Response<>(code, message, null);
}
}
Customer Controller with Authentication
@CrossOrigin
@RestController
@RequestMapping("/api/customers")
public class CustomerController {
@Autowired
private CustomerMapper customerRepository;
@PostMapping("/register")
public Response register(
@Pattern(regexp = "^\\S{5,16}$") String username,
@Pattern(regexp = "^\\S{5,16}$") String password) {
if (customerRepository.existsByUsername(username)) {
return Response.error("Username already exists");
}
Customer newCustomer = new Customer();
newCustomer.setFullName(username);
newCustomer.setCredentials(PasswordUtil.encrypt(password));
customerRepository.insert(newCustomer);
return Response.success("Registration successful");
}
@PostMapping("/login")
public Response login(
@Pattern(regexp = "^\\S{5,16}$") String username,
@Pattern(regexp = "^\\S{5,16}$") String password) {
Customer customer = customerRepository.findByUsername(username);
if (customer == null) {
return Response.error("User not found");
}
if (customer.getCredentials().equals(PasswordUtil.encrypt(password))) {
Map<String, Object> payload = new HashMap<>();
payload.put("id", customer.getCustomerId());
payload.put("name", customer.getFullName());
String token = TokenUtil.generate(payload);
return Response.success(token);
}
return Response.error("Invalid credentials");
}
}