从零开发校园墙微信小程序(5)——Spring Boot+MyBatis Plus后端架构搭建指南
一、技术栈选型
1.1 核心组件
技术 | 版本 | 作用 |
---|---|---|
Spring Boot | 3.1.5 | 快速构建基础框架 |
MyBatis Plus | 3.5.3.1 | 增强ORM操作 |
MySQL | 8.0+ | 数据存储 |
Lombok | 1.18.28 | 简化POJO编写 |
Swagger | 3.0.0 | API文档生成 |
二、项目初始化
2.1 使用Spring Initializr创建项目
<!-- pom.xml核心依赖 -->
<dependencies>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.1</version>
</dependency>
<dependency>
<groupId>com.github.jsqlparser</groupId>
<artifactId>jsqlparser</artifactId>
<version>4.6</version>
</dependency>
</dependencies>
三、MyBatis Plus集成
3.1 配置数据源
# application.yml
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/campus_wall?useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: 123456
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
db-config:
logic-delete-field: deleted # 逻辑删除字段
logic-delete-value: 1
logic-not-delete-value: 0
3.2 代码生成器配置
public class CodeGenerator {
public static void main(String[] args) {
AutoGenerator generator = new AutoGenerator();
// 数据源配置
DataSourceConfig dsc = new DataSourceConfig.Builder(
"jdbc:mysql://localhost:3306/campus_wall",
"root",
"123456")
.build();
// 全局配置
GlobalConfig gc = new GlobalConfig.Builder()
.outputDir(System.getProperty("user.dir") + "/src/main/java")
.author("开发者")
.enableSwagger()
.build();
// 包配置
PackageConfig pc = new PackageConfig.Builder()
.parent("com.campus.wall")
.entity("model.entity")
.mapper("mapper")
.build();
// 策略配置
StrategyConfig strategy = new StrategyConfig.Builder()
.addInclude("status", "comments") // 生成指定表
.entityBuilder()
.enableLombok()
.enableTableFieldAnnotation()
.build();
generator.dataSource(dsc)
.global(gc)
.packageInfo(pc)
.strategy(strategy)
.execute();
}
}
四、核心功能实现
4.1 实体类定义(使用MP注解)
@Data
@TableName("status")
public class Status {
@TableId(type = IdType.AUTO)
private Long id;
private String content;
private String images;
private String openid;
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@Version
private Integer version;
}
4.2 Mapper接口开发
public interface StatusMapper extends BaseMapper<Status> {
@Select("SELECT * FROM status WHERE content LIKE CONCAT('%',#{keyword},'%')")
List<Status> searchByKeyword(@Param("keyword") String keyword);
}
4.3 Service层实现
@Service
public class StatusService {
private final StatusMapper statusMapper;
// 分页查询(使用MP分页插件)
public Page<Status> getStatusPage(String keyword, int pageNum, int pageSize) {
Page<Status> page = new Page<>(pageNum, pageSize);
QueryWrapper<Status> wrapper = new QueryWrapper<>();
wrapper.like(StringUtils.isNotBlank(keyword), "content", keyword);
return statusMapper.selectPage(page, wrapper);
}
// 使用Lambda表达式构建查询
public List<Status> getLatestStatus(int limit) {
LambdaQueryWrapper<Status> wrapper = Wrappers.lambdaQuery();
wrapper.orderByDesc(Status::getCreateTime).last("LIMIT " + limit);
return statusMapper.selectList(wrapper);
}
}
五、Controller优化实现
5.1 投稿接口优化
@PostMapping("/sendStatus")
public Result sendStatus(@RequestParam MultipartFile file,
@RequestParam String text,
@RequestParam String openid) {
try {
// 1. 文件上传处理
String imageUrl = fileStorageService.upload(file);
// 2. 构建实体
Status status = new Status();
status.setContent(text);
status.setOpenid(openid);
status.setImages(imageUrl);
// 3. 数据库保存(使用MP的save方法)
statusMapper.insert(status);
return Result.success("投稿成功");
} catch (Exception e) {
log.error("投稿失败", e);
return Result.fail(500, "系统繁忙");
}
}
5.2 分页查询接口
@GetMapping("/statusList")
public Result getStatusList(
@RequestParam(required = false) String keyword,
@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer size) {
Page<Status> pageResult = statusService.getStatusPage(keyword, page, size);
Map<String, Object> result = new HashMap<>();
result.put("list", pageResult.getRecords());
result.put("total", pageResult.getTotal());
return Result.success(result);
}
六、最佳实践建议
6.1 分页插件配置
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 分页插件
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
// 乐观锁插件
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
}
6.2 自动填充配置
@Component
public class MetaHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
this.strictInsertFill(metaObject, "createTime", LocalDateTime::now, LocalDateTime.class);
}
@Override
public void updateFill(MetaObject metaObject) {
this.strictUpdateFill(metaObject, "updateTime", LocalDateTime::now, LocalDateTime.class);
}
}
七、常见问题解决方案
7.1 分页失效排查
- 检查是否配置分页插件
- 确保Page参数是第一个参数
- 验证SQL是否包含LIMIT语句
7.2 逻辑删除实现
// 实体类添加注解
@TableLogic
private Integer deleted;
// 查询自动过滤已删除数据
wrapper.eq(Status::getDeleted, 0);
7.3 多数据源配置
@Configuration
@MapperScan(basePackages = "com.campus.wall.mapper.db1", sqlSessionFactoryRef = "db1SqlSessionFactory")
public class Db1DataSourceConfig {
// 配置主数据源...
}
@Configuration
@MapperScan(basePackages = "com.campus.wall.mapper.db2", sqlSessionFactoryRef = "db2SqlSessionFactory")
public class Db2DataSourceConfig {
// 配置从数据源...
}
八、性能优化建议
二级缓存配置:
mybatis-plus: configuration: cache-enabled: true
批量插入优化:
List<Status> batchList = new ArrayList<>(); // ...填充数据 statusMapper.insertBatchSomeColumn(batchList);
SQL打印格式化:
@Bean public PerformanceInterceptor performanceInterceptor() { PerformanceInterceptor interceptor = new PerformanceInterceptor(); interceptor.setFormat(true); return interceptor; }
开发心法:
使用MyBatis Plus就像获得了一个智能工具箱——它能自动完成80%的常规数据库操作,但关键是要掌握其设计哲学。记住:
- 优先使用Lambda表达式构建查询
- 合理利用代码生成器
- 定期检查官方更新日志
- 复杂SQL仍建议使用XML方式管理
下一章预告:《高并发场景下的缓存策略设计》
你将学到:
- Redis集成与缓存穿透解决方案
- 二级缓存与本地缓存结合实践
- 消息队列在异步处理中的应用