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是最靠谱的好朋友。别让配置文件和注解把你绕晕,读源码、翻官方文档、反思自己的调用链,一步步就能爬出来

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


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

相关推荐
布朗克1682 分钟前
26 多线程基础——Thread、Runnable与线程安全
java·安全·多线程
轮子飞了6 分钟前
Spring Ai 集成 DashScope 多模态模型实现身份证信息识别
java·人工智能·spring
lulu121654407813 分钟前
大模型API聚合平台技术架构深度对比:六大平台协议转换、路由调度与安全治理全解析 - 微元算力(weytoken)
java·人工智能·安全·架构·ai编程
霸道流氓气质13 分钟前
阿里云 OSS 从零到实战:概念、配置与 Spring Boot 集成指南
数据库·spring boot·阿里云
可乐ea15 分钟前
【Spring Boot + MyBatis|第4篇】MyBatis 动态 SQL:if、where、foreach 使用详解
java·spring boot·后端·sql·mybatis
記億揺晃着的那天22 分钟前
Windows 通过 Java 获取可用端口的一个坑:Hyper-V 保留端口导致 UDP 绑定失败
java·windows·udp
组合缺一23 分钟前
SolonCode(编码智能体)支持鸿蒙 PC
java·华为·ai·ai编程·harmonyos·solon·soloncode
小bo波25 分钟前
用匿名内部类优雅地计算方法执行时间
java·设计模式·性能测试·模板方法模式·lambda·代码优化·匿名内部类
折哥的程序人生 · 物流技术专研29 分钟前
Tomcat 严重警告:JDBC 驱动未注销 + 工作线程泄漏 —— 原因、影响与彻底修复(生产级终极指南)
java·运维·数据库·mysql·oracle·tomcat
一个儒雅随和的男子32 分钟前
sentinel底层原理剖析以及实战优化
java·网络·sentinel