springboot starter实现(用户增删改查)
项目结构
auth-starter/
├── src/main/java
│ └── com/example/auth
│ ├── config/
│ ├── controller/
│ ├── entity/
│ ├── mapper/ # MyBatis-Plus Mapper接口
│ ├── service/
│ ├── service/impl/
│ ├── dto/
│ └── AuthAutoConfiguration.java
├── src/main/resources
│ └── META-INF
│ ├── spring.factories
│ └── mybatis-mapper/ # SQL映射文件(可选)
└── pom.xml
1. POM.xml 配置
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>auth-mybatisplus-starter</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<properties>
<java.version>1.8</java.version>
<spring-boot.version>2.7.0</spring-boot.version>
<mybatis-plus.version>3.5.3.1</mybatis-plus.version>
</properties>
<dependencies>
<!-- Spring Boot Starter依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<scope>provided</scope>
</dependency>
<!-- MyBatis-Plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis-plus.version}</version>
<scope>provided</scope>
</dependency>
<!-- Redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<scope>provided</scope>
</dependency>
<!-- 数据库驱动由使用方提供 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<!-- Lombok可选 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
</project>
2. 实体类定义
@Data
@TableName("${auth.table-prefix}user")
public class User {
@TableId(type = IdType.AUTO)
private Long id;
private String username;
private String password;
private String email;
private Integer status;
private Date createTime;
private Date updateTime;
}
@Data
@TableName("${auth.table-prefix}role")
public class Role {
@TableId(type = IdType.AUTO)
private Long id;
private String roleName;
private String roleCode;
private String description;
private Date createTime;
}
@Data
@TableName("${auth.table-prefix}permission")
public class Permission {
@TableId(type = IdType.AUTO)
private Long id;
private String permName;
private String permCode;
private String description;
}
// 用户-角色关联表
@Data
@TableName("${auth.table-prefix}user_role")
public class UserRole {
@TableId(type = IdType.AUTO)
private Long id;
private Long userId;
private Long roleId;
}
// 角色-权限关联表
@Data
@TableName("${auth.table-prefix}role_permission")
public class RolePermission {
@TableId(type = IdType.AUTO)
private Long id;
private Long roleId;
private Long permissionId;
}
3. Mapper接口
public interface UserMapper extends BaseMapper<User> {
// 自定义查询方法
@Select("SELECT r.* FROM ${auth.table-prefix}role r " +
"INNER JOIN ${auth.table-prefix}user_role ur ON r.id = ur.role_id " +
"WHERE ur.user_id = #{userId}")
List<Role> selectRolesByUserId(@Param("userId") Long userId);
}
public interface RoleMapper extends BaseMapper<Role> {
// 根据用户ID查询角色
List<Role> selectRolesByUserId(Long userId);
}
public interface PermissionMapper extends BaseMapper<Permission> {
// 根据角色ID查询权限
List<Permission> selectPermissionsByRoleId(Long roleId);
}
public interface UserRoleMapper extends BaseMapper<UserRole> {
}
public interface RolePermissionMapper extends BaseMapper<RolePermission> {
}
4. Service层实现
public interface UserService extends IService<User> {
User getUserWithRoles(Long userId);
boolean assignRoleToUser(Long userId, Long roleId);
boolean removeRoleFromUser(Long userId, Long roleId);
}
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
@Autowired
private RoleMapper roleMapper;
@Autowired
private UserRoleMapper userRoleMapper;
@Override
public User getUserWithRoles(Long userId) {
User user = baseMapper.selectById(userId);
if (user != null) {
List<Role> roles = roleMapper.selectRolesByUserId(userId);
// 设置角色信息(需要DTO或扩展实体)
}
return user;
}
@Override
public boolean assignRoleToUser(Long userId, Long roleId) {
UserRole userRole = new UserRole();
userRole.setUserId(userId);
userRole.setRoleId(roleId);
return userRoleMapper.insert(userRole) > 0;
}
@Override
public boolean removeRoleFromUser(Long userId, Long roleId) {
QueryWrapper<UserRole> wrapper = new QueryWrapper<>();
wrapper.eq("user_id", userId).eq("role_id", roleId);
return userRoleMapper.delete(wrapper) > 0;
}
}
5. Controller层
@RestController
@RequestMapping("/api/auth")
public class AuthController {
@Autowired
private UserService userService;
@Autowired
private RoleService roleService;
@GetMapping("/users")
public Result<List<User>> listUsers() {
return Result.success(userService.list());
}
@PostMapping("/users")
public Result<User> createUser(@RequestBody User user) {
userService.save(user);
return Result.success(user);
}
@PutMapping("/users/{id}")
public Result<User> updateUser(@PathVariable Long id, @RequestBody User user) {
user.setId(id);
userService.updateById(user);
return Result.success(user);
}
@DeleteMapping("/users/{id}")
public Result<Boolean> deleteUser(@PathVariable Long id) {
return Result.success(userService.removeById(id));
}
@PostMapping("/users/{userId}/roles/{roleId}")
public Result<Boolean> assignRole(@PathVariable Long userId, @PathVariable Long roleId) {
return Result.success(userService.assignRoleToUser(userId, roleId));
}
}
// 统一返回结果
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Result<T> {
private Integer code;
private String message;
private T data;
public static <T> Result<T> success(T data) {
return new Result<>(200, "成功", data);
}
public static <T> Result<T> error(String message) {
return new Result<>(500, message, null);
}
}
6. 自动配置类
@Configuration
@EnableConfigurationProperties(AuthProperties.class)
@ConditionalOnClass({SqlSessionFactory.class, MybatisPlusAutoConfiguration.class})
@ConditionalOnProperty(prefix = "auth", name = "enabled", havingValue = "true", matchIfMissing = true)
@AutoConfigureAfter(MybatisPlusAutoConfiguration.class)
public class AuthAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public UserMapper userMapper() {
// MyBatis-Plus会自动配置Mapper
return null; // 实际不需要显式创建,这里为了条件检测
}
@Bean
@ConditionalOnMissingBean
public UserService userService(UserMapper userMapper, RoleMapper roleMapper, UserRoleMapper userRoleMapper) {
return new UserServiceImpl(userMapper, roleMapper, userRoleMapper);
}
@Bean
@ConditionalOnMissingBean
public AuthController authController(UserService userService, RoleService roleService) {
return new AuthController(userService, roleService);
}
// 配置MyBatis-Plus分页插件(如果使用方没有配置)
@Bean
@ConditionalOnMissingBean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
7. 配置属性类
@Data
@ConfigurationProperties(prefix = "auth")
public class AuthProperties {
private boolean enabled = true;
private String tablePrefix = "sys_";
private boolean initData = false;
}
8. 使用方配置
spring:
datasource:
url: jdbc:mysql://localhost:3306/your_db
username: your_username
password: your_password
driver-class-name: com.mysql.cj.jdbc.Driver
# MyBatis-Plus配置
mybatis-plus:
mapper-locations: classpath*:mapper/**/*.xml
configuration:
map-underscore-to-camel-case: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
# Auth Starter配置
auth:
enabled: true
table-prefix: auth_ # 自定义表前缀
init-data: true # 是否初始化示例数据
9. 使用方POM依赖
<dependency>
<groupId>com.example</groupId>
<artifactId>auth-mybatisplus-starter</artifactId>
<version>1.0.0</version>
</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>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
10. SQL初始化脚本(可选)
-- 建表语句
CREATE TABLE IF NOT EXISTS auth_user (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) NOT NULL UNIQUE,
password VARCHAR(100) NOT NULL,
email VARCHAR(100),
status INT DEFAULT 1,
create_time DATETIME,
update_time DATETIME
);
-- 其他表结构...
Spring Boot Starter配置详解
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>provided</scope>
<optional>true</optional> <!-- 可选依赖 -->
</dependency>
配置意义:
-
optional=true:表示这个依赖是可选的 -
使用方可以根据实际使用的数据库添加相应的驱动依赖
-
避免强制绑定特定数据库,提高starter的灵活性
2. 自动配置类注解解析
@Configuration
@EnableConfigurationProperties(AuthProperties.class)
@ConditionalOnClass({SqlSessionFactory.class, MybatisPlusAutoConfiguration.class})
@ConditionalOnProperty(prefix = "auth", name = "enabled", havingValue = "true", matchIfMissing = true)
@AutoConfigureAfter(MybatisPlusAutoConfiguration.class)
public class AuthAutoConfiguration {
// 配置内容
}
各注解作用:
@Configuration
声明这是一个配置类
Spring会扫描这个类中的@Bean方法
@EnableConfigurationProperties(AuthProperties.class)
启用配置属性绑定
将application.yml中的配置映射到AuthProperties类
@ConditionalOnClass({SqlSessionFactory.class, MybatisPlusAutoConfiguration.class})
条件化配置:只有当类路径中存在这些类时才生效
确保只有在使用方引入了MyBatis-Plus时才启用配置
避免缺少依赖时出现ClassNotFoundException
@ConditionalOnProperty(prefix = "auth", name = "enabled", havingValue = "true", matchIfMissing = true)
prefix = "auth":配置前缀
name = "enabled":配置属性名
havingValue = "true":期望的值
matchIfMissing = true:如果配置缺失,默认启用
意义:允许使用方通过auth.enabled=false来禁用starter
@AutoConfigureAfter(MybatisPlusAutoConfiguration.class)
指定配置顺序:在MyBatis-Plus配置之后执行
确保数据库连接等基础配置先完成
避免因配置顺序问题导致的bean创建失败
3. Bean定义配置
@Bean
@ConditionalOnMissingBean
public UserService userService(UserMapper userMapper, RoleMapper roleMapper, UserRoleMapper userRoleMapper) {
return new UserServiceImpl(userMapper, roleMapper, userRoleMapper);
}
@Bean
-
声明这是一个Spring Bean
-
Spring会管理这个bean的生命周期
@ConditionalOnMissingBean
-
条件化bean创建:只有当容器中不存在UserService类型的bean时才创建
-
允许使用方自定义实现来覆盖默认实现
-
提供扩展性和灵活性
4. 配置属性类解析
@Data
@ConfigurationProperties(prefix = "auth")
public class AuthProperties {
private boolean enabled = true;
private String tablePrefix = "sys_";
private boolean initData = false;
}
@ConfigurationProperties(prefix = "auth")
-
将配置文件中的属性绑定到Java对象
-
prefix = "auth":对应配置文件中的auth.*属性
属性默认值:
-
enabled = true:默认启用starter -
tablePrefix = "sys_":默认表前缀,避免表名冲突 -
initData = false:默认不初始化数据,需要时手动开启
5. spring.factories配置
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.auth.config.AuthAutoConfiguration
配置意义:
-
Spring Boot自动配置的注册机制
-
告诉Spring Boot在启动时自动加载AuthAutoConfiguration
-
不需要使用方手动@Import配置类
6. 条件注解详解
常用条件注解:
@ConditionalOnClass
-
当指定类存在于classpath时生效
-
用于检测必要的依赖是否存在
@ConditionalOnMissingBean
-
当容器中不存在指定类型的bean时生效
-
用于提供默认实现,同时允许覆盖
@ConditionalOnProperty
-
当配置属性满足条件时生效
-
用于功能开关控制
@ConditionalOnWebApplication
-
当应用是Web应用时生效
7. 表名配置解析
@TableName("${auth.table-prefix}user")
public class User {
// 实体类
}
配置意义:
-
${auth.table-prefix}:使用配置属性动态设置表名 -
允许使用方自定义表前缀,避免与现有表名冲突
-
支持多租户或不同环境下的表名区分
8. 使用方配置示例
# 使用方的application.yml
auth:
enabled: true # 启用auth starter
table-prefix: "app_" # 自定义表前缀
init-data: true # 初始化示例数据
spring:
datasource:
url: jdbc:mysql://localhost:3306/mydb
username: user
password: pass
redis:
host: localhost
port: 6379
9. 配置的最佳实践
1. 提供合理的默认值
java
private String tablePrefix = "sys_"; // 有意义的默认值
2. 支持功能开关
@ConditionalOnProperty(prefix = "auth", name = "enabled", matchIfMissing = true)
3. 避免强制的依赖
xml
<scope>provided</scope> <optional>true</optional>
4. 支持自定义覆盖
@ConditionalOnMissingBean // 允许使用方提供自己的实现
5. 明确的配置顺序
@AutoConfigureAfter(MybatisPlusAutoConfiguration.class) // 确保依赖配置先完成
更多推荐


所有评论(0)