Spring Boot + MyBatis-Plus 实战中的那些“坑”与思考 —— 以身份认证服务为例

最近自己在折腾全栈 DDD 架构时,踩了一些"坑",也有不少思考,特此记录。这篇文章适合有一点 Java 基础、正在搞全栈、追求代码结构和工程规范的你。

1. 背景与业务场景

做后台服务,身份认证登录注册总是绕不过去,特别是要支持"邮箱、手机号、第三方登录(微信、QQ、Github)"这种后续可扩展需求时,表设计就很重要了。

我的目标很简单:

  • 数据库要能灵活扩展多种登录方式
  • 业务分层要体现DDD思想
  • 后端要多数据源适配(PostgreSQL为主,MySQL也能兼容)
  • 前后端联调不被安全框架挡住路
  • 关键配置要清楚,后续不踩重复的坑

2. 表结构这样设计,未来少掉头发

大致SQL如下,推荐每一列都写上中文注释(强烈建议!):

sql 复制代码
CREATE TABLE identity.users (
    id BIGSERIAL PRIMARY KEY,           -- 用户ID
    email VARCHAR(64) UNIQUE,           -- 邮箱
    phone VARCHAR(32) UNIQUE,           -- 手机号
    password VARCHAR(255) NOT NULL,     -- 密码
    nickname VARCHAR(64),               -- 昵称
    avatar VARCHAR(255),                -- 头像
    is_email_verified BOOLEAN DEFAULT FALSE, -- 邮箱是否已验证
    is_phone_verified BOOLEAN DEFAULT FALSE, -- 手机号是否已验证
    status SMALLINT DEFAULT 1,          -- 状态
    last_login_at TIMESTAMP,            -- 上次登录时间
    created_at TIMESTAMP DEFAULT now(), -- 创建时间
    updated_at TIMESTAMP DEFAULT now(), -- 更新时间
    created_by VARCHAR(64),             -- 创建人
    updated_by VARCHAR(64),             -- 修改人
    wechat_unionid VARCHAR(64),         -- 微信unionId(扩展)
    qq_openid VARCHAR(64),              -- QQ openId(扩展)
    github_id VARCHAR(64),              -- github账号(扩展)
    version INT DEFAULT 0,              -- 乐观锁
    is_deleted BOOLEAN DEFAULT FALSE    -- 软删除
);

小建议:

表名、字段名都尽量"意图明确",小写蛇形,严格区分限界上下文(如 identity.users)。写注释不仅是对自己负责,也是对团队和未来的你负责。

3. 多数据源这样配,PostgreSQL / MySQL 随便切

用 dynamic-datasource-spring-boot-starter,YAML配置极其简单(节选):

yaml 复制代码
spring:
  datasource:
    dynamic:
      primary: pg
      datasource:
        pg:
          driver-class-name: org.postgresql.Driver
          url: jdbc:postgresql://localhost:5432/your_db?currentSchema=identity
          username: postgres
          password: your_password
        mysql:
          driver-class-name: com.mysql.cj.jdbc.Driver
          url: jdbc:mysql://localhost:3306/your_db?serverTimezone=Asia/Shanghai
          username: root
          password: your_password

想切库,代码里加@DS("mysql")@DS("pg")即可。是不是有种"撸起袖子就能干"的感觉?

4. 你的后端代码,分层要自觉

领域层、应用层、基础设施层、接口层......大家都懂,但真能做到清晰分层,其实是对自我约束的磨炼。

一个标准认证流程,推荐结构如下:

  • Controller(接口层,处理请求响应)
  • Service(应用层,编排业务逻辑)
  • Mapper(基础设施层,数据库操作,MyBatis-Plus自动管理)
  • Domain(领域层,定义实体/聚合)

代码示例:

java 复制代码
// Mapper接口
@Mapper
public interface UserMapper extends BaseMapper<User> {}

// Service接口
public interface UserService {
    User register(User user);
    User login(String email, String password);
}

// Service实现
@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserMapper userMapper;
    // ...具体逻辑
}

人话解释:

Controller 不要注入 Mapper,也不要写 if else 业务细节。分层,是为了"今天自己看、明天同事看、后天重构都不难受"。

5. 说一说 MyBatis-Plus 的"坑"

最大的大坑:@MapperScan配置太宽导致BindingException!

真实血泪:

java 复制代码
@MapperScan("pers.seekersferry.*") // ❌ 致命!把service等接口全当Mapper扫描了!

结果所有的service接口也被MyBatis-Plus"当成Mapper"去找SQL语句,必然报错:

bash 复制代码
Invalid bound statement (not found): pers.seekersferry.identity.application.service.UserService.register

修正方案:

java 复制代码
@MapperScan("pers.seekersferry.identity.infrastructure.mapper")

只扫描Mapper包,永远不要一把梭所有包。

另一个常见误区:@Mapper写错地方

@Mapper 只写在Mapper接口(如UserMapper),绝不能写在Service接口。

6. Spring Security 默认401/403的那些"小惊喜"

很多人一开始加上spring-boot-starter-security就疯了------接口全部 401,swagger也打不开,开发体验直接爆炸。

人话解决方案:

本地开发阶段,把所有接口都放开(安全的事以后再说),加一个安全配置类:

java 复制代码
@Configuration
public class SecurityConfig {
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .csrf(csrf -> csrf.disable())
            .authorizeHttpRequests(authorize -> authorize
                .anyRequest().permitAll()
            );
        return http.build();
    }
}

友情提醒:

生产环境一定要收紧权限,但开发联调阶段别给自己添堵。

7. @MapperScan能写在yaml里吗?

答案很干脆:不能!

  • yaml 只能配 mapper-locations、type-aliases-package 这类属性,扫描 Mapper 包必须在 Java 里用注解或者配置类。
  • 以后看到"为什么我的service也被当Mapper了?"第一反应就该查MapperScan!

8. 结语:规范不是负担,是"防脱发"的最佳姿势

每一次规范的小坚持,都是在为自己的效率和团队的可维护性加分。

遇到bug和踩坑,别慌,debug和Google是最靠谱的好朋友。别让配置文件和注解把你绕晕,读源码、翻官方文档、反思自己的调用链,一步步就能爬出来

希望这篇文章对同为全栈的你,有点共鸣、有点实用,也祝你的后端工程越来越稳,"长久在线,头发依旧"。


如果你有类似经历或者更骚气的踩坑,欢迎留言交流!

相关推荐
HuiSoul2003 小时前
Spring MVC
java·后端·spring mvc
摇滚侠5 小时前
面试实战 问题二十四 Spring 框架中循环依赖问题的解决方法
java·后端·spring
三木水6 小时前
Spring-rabbit使用实战七
java·分布式·后端·spring·消息队列·java-rabbitmq·java-activemq
别来无恙1497 小时前
Spring Boot文件下载功能实现详解
java·spring boot·后端·数据导出
optimistic_chen7 小时前
【Java EE初阶 --- 网络原理】JVM
java·jvm·笔记·网络协议·java-ee
weixin_456904277 小时前
Java泛型与委托
java·spring boot·spring
悟能不能悟8 小时前
能刷java题的网站
java·开发语言
程序员陆通8 小时前
Java高并发场景下的缓存穿透问题定位与解决方案
java·开发语言·缓存
北执南念9 小时前
Java多线程基础总结
java
David爱编程10 小时前
JDK vs JRE:到底有什么本质区别?99% 的人都答不上来
java·后端