Spring Boot + MyBatis Plus 实战:企业级应用开发的最佳实践指南

Will241
Will241 2026-02-07T05:11:04+08:00
0 0 0

引言

在现代Java企业级应用开发中,Spring Boot与MyBatis Plus的组合已成为主流技术栈之一。Spring Boot凭借其"约定优于配置"的理念,极大地简化了Spring应用的初始搭建和开发过程;而MyBatis Plus作为MyBatis的增强工具,在保留MyBatis原有特性的同时,提供了更加便捷的CRUD操作和强大的代码生成能力。

本文将结合实际项目经验,深入探讨如何在企业级应用中高效地集成和使用Spring Boot与MyBatis Plus,涵盖从环境搭建到核心功能实现的完整开发流程,帮助开发者构建高性能、易维护的企业级应用系统。

一、技术栈概述与环境准备

1.1 Spring Boot简介

Spring Boot是Spring框架的扩展,旨在简化新Spring应用的初始搭建以及开发过程。它通过自动配置和起步依赖机制,让开发者能够快速创建独立的、生产级别的Spring应用程序。

1.2 MyBatis Plus特性

MyBatis Plus是MyBatis的增强工具,主要特性包括:

  • 代码生成器:自动生成Mapper、Service、Controller等基础代码
  • 通用CRUD操作:无需编写SQL即可实现基本的增删改查
  • 分页插件:内置分页功能,支持多种数据库
  • 条件构造器:链式调用构建复杂查询条件
  • 乐观锁支持:内置乐观锁机制
  • 自动填充:支持字段自动填充功能

1.3 环境准备

<!-- pom.xml -->
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.5.3.1</version>
    </dependency>
    
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>
    
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

二、项目结构设计与配置

2.1 项目目录结构

src/
├── main/
│   ├── java/
│   │   └── com/example/demo/
│   │       ├── DemoApplication.java
│   │       ├── config/
│   │       ├── controller/
│   │       ├── entity/
│   │       ├── mapper/
│   │       ├── service/
│   │       └── util/
│   └── resources/
│       ├── application.yml
│       └── mapper/
└── test/

2.2 核心配置文件

# application.yml
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
    username: root
    password: password
    driver-class-name: com.mysql.cj.jdbc.Driver
  
  # MyBatis Plus配置
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    map-underscore-to-camel-case: true
  global-config:
    db-config:
      id-type: auto
      table-prefix: t_
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: com.example.demo.entity

# 分页插件配置
pagehelper:
  helper-dialect: mysql
  reasonable: true
  support-methods-arguments: true
  params: count=countSql

三、实体类设计与基础配置

3.1 实体类定义

// User.java
package com.example.demo.entity;

import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import java.time.LocalDateTime;

@Data
@TableName("t_user")
public class User {
    
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;
    
    private String username;
    
    private String password;
    
    private String email;
    
    private Integer status;
    
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;
    
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;
    
    @Version
    private Integer version;
}

3.2 全局配置类

// MybatisPlusConfig.java
package com.example.demo.config;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MybatisPlusConfig {
    
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // 分页插件
        PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor();
        paginationInnerInterceptor.setDbType(DbType.MYSQL);
        paginationInnerInterceptor.setOverflow(true);
        paginationInnerInterceptor.setMaxLimit(1000L);
        interceptor.addInnerInterceptor(ppaginationInnerInterceptor);
        return interceptor;
    }
}

四、代码生成器实战

4.1 代码生成器配置

// CodeGenerator.java
package com.example.demo.generator;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;

public class CodeGenerator {
    
    public static void main(String[] args) {
        AutoGenerator mpg = new AutoGenerator();
        
        // 全局配置
        GlobalConfig gc = new GlobalConfig();
        String projectPath = System.getProperty("user.dir");
        gc.setOutputDir(projectPath + "/src/main/java");
        gc.setAuthor("developer");
        gc.setOpen(false);
        gc.setSwagger2(true);
        gc.setIdType(IdType.AUTO);
        mpg.setGlobalConfig(gc);
        
        // 数据源配置
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl("jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai");
        dsc.setDriverName("com.mysql.cj.jdbc.Driver");
        dsc.setUsername("root");
        dsc.setPassword("password");
        mpg.setDataSource(dsc);
        
        // 包配置
        PackageConfig pc = new PackageConfig();
        pc.setModuleName("demo");
        pc.setParent("com.example");
        mpg.setPackageInfo(pc);
        
        // 策略配置
        StrategyConfig strategy = new StrategyConfig();
        strategy.setNaming(NamingStrategy.underline_to_camel);
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
        strategy.setEntityLombokModel(true);
        strategy.setRestControllerStyle(true);
        strategy.setInclude("t_user");
        strategy.setControllerMappingHyphenStyle(true);
        strategy.setTablePrefix(pc.getModuleName() + "_");
        mpg.setStrategy(strategy);
        
        mpg.execute();
    }
}

4.2 自动生成的代码示例

// UserMapper.java
package com.example.demo.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.demo.entity.User;

public interface UserMapper extends BaseMapper<User> {
    
}
// UserService.java
package com.example.demo.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.example.demo.entity.User;

public interface UserService extends IService<User> {
    
}

五、核心功能实现

5.1 基础CRUD操作

// UserServiceImpl.java
package com.example.demo.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.demo.entity.User;
import com.example.demo.mapper.UserMapper;
import com.example.demo.service.UserService;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    
    // 可以在此添加自定义业务逻辑
}
// UserController.java
package com.example.demo.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.demo.entity.User;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/users")
public class UserController {
    
    @Autowired
    private UserService userService;
    
    // 新增用户
    @PostMapping
    public User createUser(@RequestBody User user) {
        userService.save(user);
        return user;
    }
    
    // 查询单个用户
    @GetMapping("/{id}")
    public User getUserById(@PathVariable Long id) {
        return userService.getById(id);
    }
    
    // 查询所有用户
    @GetMapping
    public List<User> getAllUsers() {
        return userService.list();
    }
    
    // 更新用户
    @PutMapping("/{id}")
    public User updateUser(@PathVariable Long id, @RequestBody User user) {
        user.setId(id);
        userService.updateById(user);
        return user;
    }
    
    // 删除用户
    @DeleteMapping("/{id}")
    public void deleteUser(@PathVariable Long id) {
        userService.removeById(id);
    }
}

5.2 条件查询与链式调用

// 高级查询示例
@GetMapping("/search")
public List<User> searchUsers(
    @RequestParam(required = false) String username,
    @RequestParam(required = false) String email,
    @RequestParam(defaultValue = "0") Integer status) {
    
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    
    // 使用链式调用构建复杂查询条件
    if (username != null && !username.isEmpty()) {
        wrapper.like("username", username);
    }
    
    if (email != null && !email.isEmpty()) {
        wrapper.like("email", email);
    }
    
    if (status != null) {
        wrapper.eq("status", status);
    }
    
    // 排序
    wrapper.orderByDesc("create_time");
    
    return userService.list(wrapper);
}

// 复杂条件查询示例
@GetMapping("/advanced-search")
public List<User> advancedSearch(
    @RequestParam(required = false) String keyword,
    @RequestParam(required = false) Integer minAge,
    @RequestParam(required = false) Integer maxAge,
    @RequestParam(defaultValue = "create_time") String sortBy,
    @RequestParam(defaultValue = "desc") String sortOrder) {
    
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    
    // 模糊搜索
    if (keyword != null && !keyword.isEmpty()) {
        wrapper.and(w -> w.like("username", keyword)
                          .or()
                          .like("email", keyword));
    }
    
    // 年龄范围查询
    if (minAge != null) {
        wrapper.ge("age", minAge);
    }
    
    if (maxAge != null) {
        wrapper.le("age", maxAge);
    }
    
    // 排序
    if ("asc".equalsIgnoreCase(sortOrder)) {
        wrapper.orderByAsc(sortBy);
    } else {
        wrapper.orderByDesc(sortBy);
    }
    
    return userService.list(wrapper);
}

5.3 分页查询实现

// 分页查询控制器
@GetMapping("/page")
public Page<User> getUsersByPage(
    @RequestParam(defaultValue = "1") Integer current,
    @RequestParam(defaultValue = "10") Integer size,
    @RequestParam(required = false) String username) {
    
    // 创建分页对象
    Page<User> page = new Page<>(current, size);
    
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    if (username != null && !username.isEmpty()) {
        wrapper.like("username", username);
    }
    
    // 执行分页查询
    return userService.page(page, wrapper);
}

// 带排序的分页查询
@GetMapping("/page-with-sort")
public Page<User> getUsersWithSort(
    @RequestParam(defaultValue = "1") Integer current,
    @RequestParam(defaultValue = "10") Integer size,
    @RequestParam(defaultValue = "create_time") String sortBy,
    @RequestParam(defaultValue = "desc") String sortOrder) {
    
    Page<User> page = new Page<>(current, size);
    
    // 设置排序规则
    if ("asc".equalsIgnoreCase(sortOrder)) {
        page.setAsc(sortBy);
    } else {
        page.setDesc(sortBy);
    }
    
    return userService.page(page);
}

六、事务管理与异常处理

6.1 事务管理配置

// Service层事务控制示例
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    
    @Autowired
    private UserMapper userMapper;
    
    // 事务管理示例
    @Transactional(rollbackFor = Exception.class)
    public void batchUpdateUserStatus(List<Long> userIds, Integer status) {
        try {
            for (Long userId : userIds) {
                User user = new User();
                user.setId(userId);
                user.setStatus(status);
                userMapper.updateById(user);
            }
        } catch (Exception e) {
            // 事务会自动回滚
            throw new RuntimeException("批量更新用户状态失败", e);
        }
    }
    
    // 复杂业务逻辑事务
    @Transactional(rollbackFor = Exception.class)
    public void complexBusinessOperation(Long userId, String newEmail) {
        // 1. 更新用户邮箱
        User user = new User();
        user.setId(userId);
        user.setEmail(newEmail);
        updateById(user);
        
        // 2. 记录操作日志
        // logService.saveOperationLog(userId, "update_email", newEmail);
        
        // 3. 发送邮件通知
        // emailService.sendEmailNotification(user, newEmail);
    }
}

6.2 全局异常处理

// GlobalExceptionHandler.java
package com.example.demo.exception;

import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice
public class GlobalExceptionHandler {
    
    @ExceptionHandler(MybatisPlusException.class)
    public ResponseEntity<ErrorResponse> handleMybatisPlusException(MybatisPlusException e) {
        ErrorResponse error = new ErrorResponse(
            HttpStatus.INTERNAL_SERVER_ERROR.value(),
            "数据库操作异常",
            e.getMessage()
        );
        return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR);
    }
    
    @ExceptionHandler(Exception.class)
    public ResponseEntity<ErrorResponse> handleGeneralException(Exception e) {
        ErrorResponse error = new ErrorResponse(
            HttpStatus.INTERNAL_SERVER_ERROR.value(),
            "系统内部错误",
            e.getMessage()
        );
        return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR);
    }
    
    @ExceptionHandler(IllegalArgumentException.class)
    public ResponseEntity<ErrorResponse> handleIllegalArgumentException(IllegalArgumentException e) {
        ErrorResponse error = new ErrorResponse(
            HttpStatus.BAD_REQUEST.value(),
            "参数错误",
            e.getMessage()
        );
        return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
    }
}

// 错误响应实体类
class ErrorResponse {
    private int code;
    private String message;
    private String details;
    
    public ErrorResponse(int code, String message, String details) {
        this.code = code;
        this.message = message;
        this.details = details;
    }
    
    // getter和setter方法
    public int getCode() { return code; }
    public void setCode(int code) { this.code = code; }
    
    public String getMessage() { return message; }
    public void setMessage(String message) { this.message = message; }
    
    public String getDetails() { return details; }
    public void setDetails(String details) { this.details = details; }
}

七、性能优化与最佳实践

7.1 缓存策略实现

// Redis缓存配置
@Configuration
@EnableCaching
public class RedisConfig {
    
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(connectionFactory);
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        return template;
    }
}

// 带缓存的Service实现
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    @Cacheable(value = "users", key = "#id")
    @Override
    public User getById(Long id) {
        return super.getById(id);
    }
    
    @CacheEvict(value = "users", key = "#user.id")
    @Override
    public boolean updateById(User user) {
        return super.updateById(user);
    }
    
    @CacheEvict(value = "users", key = "#id")
    @Override
    public boolean removeById(Long id) {
        return super.removeById(id);
    }
}

7.2 SQL优化技巧

// 使用SelectList优化查询性能
@GetMapping("/optimized-search")
public List<User> optimizedSearch(@RequestParam String keyword) {
    // 避免SELECT *,只选择需要的字段
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.select("id", "username", "email", "create_time")
           .like("username", keyword)
           .or()
           .like("email", keyword);
    
    return userService.list(wrapper);
}

// 使用LambdaQueryWrapper简化代码
@GetMapping("/lambda-search")
public List<User> lambdaSearch(@RequestParam String username) {
    LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
    wrapper.select(User::getId, User::getUsername, User::getEmail)
           .eq(User::getStatus, 1)
           .like(User::getUsername, username);
    
    return userService.list(wrapper);
}

7.3 批量操作优化

// 批量插入优化
@PostMapping("/batch-insert")
public void batchInsertUsers(@RequestBody List<User> users) {
    // 使用批量插入提高性能
    userService.saveBatch(users, 1000);
}

// 批量更新优化
@PutMapping("/batch-update")
public void batchUpdateUsers(@RequestBody List<User> users) {
    // 使用批量更新
    userService.updateBatchById(users, 1000);
}

// 使用自定义SQL进行批量操作
@DeleteMapping("/batch-delete")
public void batchDeleteUsers(@RequestBody List<Long> ids) {
    String sql = "DELETE FROM t_user WHERE id IN (" + 
                 ids.stream().map(String::valueOf).collect(Collectors.joining(",")) + ")";
    // 执行自定义SQL
    userMapper.deleteBatchIds(ids);
}

八、安全与权限控制

8.1 数据权限控制

// 自定义分页插件增强
public class DataPermissionInterceptor implements InnerInterceptor {
    
    @Override
    public void beforeQuery(MetaObject metaObject, MappedStatement mappedStatement, 
                           Object parameter, RowBounds rowBounds, ResultHandler resultHandler) {
        // 在查询前添加数据权限过滤条件
        String currentUserId = getCurrentUserId();
        if (currentUserId != null) {
            // 添加用户权限过滤条件
            // 这里可以根据业务需求实现具体的权限控制逻辑
        }
    }
    
    private String getCurrentUserId() {
        // 从SecurityContext或ThreadLocal中获取当前用户ID
        return "1"; // 示例返回值
    }
}

8.2 参数校验与安全

// 用户实体类参数校验
@Data
public class UserDTO {
    
    @NotNull(message = "用户ID不能为空")
    private Long id;
    
    @NotBlank(message = "用户名不能为空")
    @Size(min = 3, max = 20, message = "用户名长度必须在3-20个字符之间")
    private String username;
    
    @NotBlank(message = "密码不能为空")
    @Size(min = 6, max = 20, message = "密码长度必须在6-20个字符之间")
    private String password;
    
    @Email(message = "邮箱格式不正确")
    private String email;
    
    @Min(value = 0, message = "状态值不能小于0")
    @Max(value = 1, message = "状态值不能大于1")
    private Integer status;
}

// 控制器参数校验
@PostMapping
public ResponseEntity<User> createUser(@Valid @RequestBody UserDTO userDTO) {
    User user = new User();
    // 转换DTO到Entity
    BeanUtils.copyProperties(userDTO, user);
    userService.save(user);
    return ResponseEntity.ok(user);
}

九、测试与监控

9.1 单元测试

// UserServiceTest.java
@SpringBootTest
class UserServiceTest {
    
    @Autowired
    private UserService userService;
    
    @Test
    void testSaveUser() {
        User user = new User();
        user.setUsername("testuser");
        user.setPassword("password");
        user.setEmail("test@example.com");
        user.setStatus(1);
        
        boolean result = userService.save(user);
        assertTrue(result);
        assertNotNull(user.getId());
    }
    
    @Test
    void testGetUserById() {
        User user = userService.getById(1L);
        assertNotNull(user);
        assertEquals("testuser", user.getUsername());
    }
    
    @Test
    void testPageQuery() {
        Page<User> page = new Page<>(1, 10);
        Page<User> result = userService.page(page);
        assertNotNull(result.getRecords());
        assertTrue(result.getRecords().size() > 0);
    }
}

9.2 性能监控

// 监控配置类
@Component
public class PerformanceMonitor {
    
    private static final Logger logger = LoggerFactory.getLogger(PerformanceMonitor.class);
    
    @EventListener
    public void handleQueryEvent(QueryEvent event) {
        long executionTime = event.getExecutionTime();
        if (executionTime > 1000) { // 超过1秒的查询记录日志
            logger.warn("Slow query detected: {}ms", executionTime);
        }
    }
}

十、总结与展望

通过本文的详细介绍,我们全面了解了Spring Boot与MyBatis Plus在企业级应用开发中的集成实践。从基础配置到高级功能实现,从性能优化到安全控制,涵盖了现代Java Web应用开发的核心要点。

MyBatis Plus作为Spring Boot生态中的优秀ORM工具,不仅简化了数据库操作的复杂度,还提供了丰富的扩展机制和强大的功能特性。通过合理使用代码生成器、分页插件、条件构造器等核心功能,我们可以大幅提高开发效率,同时保证代码质量和系统性能。

在实际项目中,建议开发者:

  1. 合理规划项目结构和代码组织方式
  2. 充分利用MyBatis Plus提供的各种便利特性
  3. 建立完善的异常处理和日志监控机制
  4. 注重性能优化和安全控制
  5. 做好单元测试和集成测试

随着技术的不断发展,Spring Boot与MyBatis Plus的生态系统也在持续完善。未来我们可以期待更多创新特性的出现,如更好的云原生支持、更智能的代码生成能力等。开发者应保持学习的热情,及时跟进技术发展趋势,不断提升自己的技术能力。

通过本文的实践指南,相信读者能够在实际项目中更好地应用Spring Boot与MyBatis Plus,构建出更加高效、稳定、易维护的企业级应用系统。

相关推荐
广告位招租

相似文章

    评论 (0)

    0/2000