About springboot-init
A development-guidelines skill for Spring Boot projects, intended for developers setting up projects and writing application code. It covers layered structure, response and exception handling, access control, and ORM conventions.
Key features
- 01Configure Spring Boot and JDK versions
- 02Define project layers and naming
- 03Standardize responses and exception handling
- 04Document access-control approaches
- 05Cover ORM and utility-library conventions
- 06Provide reusable code templates
Use cases
- 01Set up a Spring Boot backend project
- 02Align team conventions for Controllers and Services
- 03Establish access-control and ORM choices
- 04Implement response and exception handling from templates
Install
Copy the command and run it in a terminal.
$
npx skills add https:/ / github.com/ wardbit/ springboot-init-skills --skill springboot-initAfter installing, type/springboot-initin Claude Code to confirm it loaded.
Bundled files
References and scripts installed along with SKILL.md.
.gitignoreREADME.md.claude/settings.local.jsonreferences/code-templates.mdDetails
From the project READMEspringboot-init
0. 技术栈配置
使用本规范前,请确认项目的技术选型:
0.1 核心框架版本
| 配置项 | 可选值 | 说明 |
|---|---|---|
| Spring Boot | 2.x / 3.x / 4.x | 2.x 支持 Java 8+,3.x/4.x 需要 Java 17+ |
| JDK | 8 / 11 / 17 / 21 / 25 | 根据 Spring Boot 版本选择 |
版本兼容矩阵:
| Spring Boot | 最低 JDK | 推荐 JDK | Jakarta EE |
|---|---|---|---|
| 2.x | 8 | 11 | javax.* |
| 3.x | 17 | 17 | jakarta.* |
| 4.x | 17 | 21 | jakarta.* |
0.2 ORM 框架
| 框架 | 特点 | 适用场景 |
|---|---|---|
| MyBatis-Plus | 增强 MyBatis,简化 CRUD | 传统项目、快速开发 |
| MyBatis-Flex | 轻量级、高性能、链式查询 | 追求性能、灵活查询 |
| Jimmer | 不可变对象、强类型 DSL | 复杂领域模型、DDD 项目 |
0.3 工具库
| 库 | 说明 | 建议 |
|---|---|---|
| Hutool | 全能工具库(日期、加密、HTTP、JSON 等) | 推荐,减少重复代码 |
| Apache Commons | 经典工具库集合 | 轻量需求可选 |
| Guava | Google 工具库 | 集合处理、缓存需求 |
0.4 访问控制框架
| 框架 | 特点 | 适用场景 |
|---|---|---|
| Sa-Token | 轻量级、开箱即用、功能全面 | 快速开发、中小项目 |
| Spring Security | Spring 官方、功能强大、高度可定制 | 企业级项目、复杂权限 |
| Shiro | Apache 项目、简单易用 | 传统项目、简单权限、脱离Spring Boot |
| Casbin | 强大、灵活、可扩展 | 复杂动态权限控制,对性能不敏感 |
| Keycloak | 独立的身份认证服务 | 实现 SSO (单点登录) 和 IAM (身份识别与访问管理) |
| 自定义 AOP | 注解 + 拦截器 | 轻量需求、完全可控 |
1. 项目结构
1.1 包命名
com.{company}.{project}
├── controller # REST API 端点
├── service # 业务逻辑接口
│ └── impl # 业务逻辑实现
├── mapper # 数据访问层 (MyBatis-Plus/Flex)
├── repository # 数据访问层 (Jimmer)
├── model
│ ├── entity # 数据库实体
│ ├── dto # 请求数据传输对象
│ ├── vo # 响应值对象
│ └── enums # 枚举类
├── api # 外部 API 集成门面
├── manager # 业务协调层
├── config # Spring 配置类
├── annotation # 自定义注解
├── aop # AOP 拦截器
├── exception # 异常类
├── utils # 工具类
├── constant # 常量定义
└── common # 通用基类
1.2 分层职责
| 层级 | 职责 | 禁止事项 |
|---|---|---|
| Controller | 接收请求、参数校验、权限控制、调用 Service、返回统一响应 | 禁止包含业务逻辑 |
| Service | 业务逻辑处理、事务管理 | 禁止直接操作 HttpServletRequest |
| Mapper/Repository | 数据库操作 | 禁止包含业务逻辑 |
| Manager | 复杂业务协调、外部 API 调用封装 | 仅用于跨服务协调 |
2. 编码规范
2.1 Controller 层
@Tag(name = "XxxController", description = "模块描述")
@RestController
@RequestMapping("/xxx")
public class XxxController {
@Resource // 或 @Autowired(根据团队规范)
private XxxService xxxService;
@PostMapping("/action")
@Operation(summary = "操作摘要", description = "操作描述")
@ApiResponses(value = {
@ApiResponse(responseCode = "0", description = "ok"),
@ApiResponse(responseCode = "40000", description = "参数错误"),
})
public BaseResponse<XxxVO> doAction(
@RequestBody XxxRequest request,
HttpServletRequest httpServletRequest) {
ThrowUtils.throwIf(request == null, ErrorCode.PARAMS_ERROR);
// 调用 Service
return ResultUtils.success(result);
}
}
强制规范:
- 所有 Controller 必须使用
@Tag注解(OpenAPI 3.0) - 所有方法必须使用
@Operation+@ApiResponses注解 - 返回类型必须为
BaseResponse<T> - 多参数必须封装为 Request 对象(禁止多个
@RequestParam)
2.2 Service 层
MyBatis-Plus 风格
public interface XxxService extends IService<Xxx> {
XxxVO doSomething(XxxRequest request);
}
@Slf4j
@Service
public class XxxServiceImpl extends ServiceImpl<XxxMapper, Xxx>
implements XxxService {
@Override
@Transactional(rollbackFor = Exception.class)
public XxxVO doSomething(XxxRequest request) {
// 业务逻辑
}
}
MyBatis-Flex 风格
public interface XxxService extends IService<Xxx> {
XxxVO doSomething(XxxRequest request);
}
@Slf4j
@Service
public class XxxServiceImpl extends ServiceImpl<XxxMapper, Xxx>
implements XxxService {
@Override
public XxxVO doSomething(XxxRequest request) {
// 使用 QueryWrapper 链式查询
QueryWrapper query = QueryWrapper.create()
.where(XXX.ID.eq(request.getId()));
return mapper.selectOneByQuery(query);
}
}
Jimmer 风格
public interface XxxService {
XxxVO doSomething(XxxRequest request);
}
@Slf4j
@Service
@RequiredArgsConstructor
public class XxxServiceImpl implements XxxService {
private final JSqlClient sqlClient;
@Override
public XxxVO doSomething(XxxRequest request) {
// 使用 Jimmer DSL
return sqlClient.createQuery(XxxTable.$)
.where(XxxTable.$.id().eq(request.getId()))
.select(XxxTable.$)
.fetchOne();
}
}
强制规范:
- 使用
@Slf4j注解 - 涉及多表操作必须使用
@Transactional
2.3 Mapper/Repository 层
MyBatis-Plus
@Mapper
public interface XxxMapper extends BaseMapper<Xxx> {
// 复杂查询使用 @Select 或 XML
}
MyBatis-Flex
@Mapper
public interface XxxMapper extends BaseMapper<Xxx> {
// 支持链式查询,无需 XML
}
Jimmer
public interface XxxRepository extends JRepository<Xxx, Long> {
// Jimmer 自动生成实现
}
2.4 Model 层
Entity:
// MyBatis-Plus / MyBatis-Flex
@Data
@TableName("table_name")
public class Xxx implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(type = IdType.ASSIGN_ID)
private Long id;
@TableLogic
private Integer isDelete;
}
// Jimmer(不可变对象)
@Entity
public interface Xxx {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
long id();
String name();
@LogicalDeleted("1")
int isDelete();
}
Request DTO:
@Data
public class XxxRequest implements Serializable {
private static final long serialVersionUID = 1L;
// 请求字段
}
VO:
@Data
public class XxxVO implements Serializable {
private static final long serialVersionUID = 1L;
// 响应字段
}
强制规范:
- 所有 Request/VO 必须实现
Serializable - 必须声明
serialVersionUID - 使用
@Data注解(Jimmer Entity 除外)
3. 统一响应规范
3.1 BaseResponse 结构
public class BaseResponse<T> implements Serializable {
private int code; // 状态码
private T data; // 响应数据
private String message; // 响应消息
}
3.2 ResultUtils 使用
// 成功响应
return ResultUtils.success(data);
// 失败响应
return ResultUtils.error(ErrorCode.PARAMS_ERROR);
return ResultUtils.error(ErrorCode.PARAMS_ERROR, "自定义消息");
3.3 ErrorCode 枚举
| 错误码 | 常量 | 说明 |
|---|---|---|
| 0 | SUCCESS | 成功 |
| 40000 | PARAMS_ERROR | 请求参数错误 |
| 40100 | NOT_LOGIN_ERROR | 未登录 |
| 40101 | NO_AUTH_ERROR | 无权限 |
| 40300 | FORBIDDEN_ERROR | 禁止访问 |
| 40400 | NOT_FOUND_ERROR | 数据不存在 |
| 50000 | SYSTEM_ERROR | 系统内部异常 |
| 50001 | OPERATION_ERROR | 操作失败 |
4. 异常处理规范
4.1 ThrowUtils 使用
// 条件抛出
ThrowUtils.throwIf(condition, ErrorCode.PARAMS_ERROR);
ThrowUtils.throwIf(condition, ErrorCode.PARAMS_ERROR, "自定义消息");
// 示例
ThrowUtils.throwIf(request == null, ErrorCode.PARAMS_ERROR);
ThrowUtils.throwIf(user == null, ErrorCode.NOT_FOUND_ERROR, "用户不存在");
4.2 BusinessException 使用
// 直接抛出
throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
throw new BusinessException(ErrorCode.OPERATION_ERROR, "操作失败原因");
5. 访问控制规范
5.1 Sa-Token 方案
// 配置类
@Configuration
public class SaTokenConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new SaInterceptor(handle -> {
SaRouter.match("/**").check(r -> StpUtil.checkLogin());
SaRouter.match("/admin/**").check(r -> StpUtil.checkRole("admin"));
})).addPathPatterns("/**").excludePathPatterns("/user/login");
}
}
// Controller 使用
@SaCheckLogin
@SaCheckRole("admin")
@PostMapping("/admin/action")
public BaseResponse<Boolean> adminAction(...) { }
5.2 Spring Security 方案
// 配置类
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(auth -> auth
.requestMatchers("/user/login").permitAll()
.requestMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
);
return http.build();
}
}
// Controller 使用
@PreAuthorize("hasRole('ADMIN')")
@PostMapping("/admin/action")
public BaseResponse<Boolean> adminAction(...) { }
5.3 Shiro 方案
// 配置类
@Configuration
public class ShiroConfig {
@Bean
public ShiroFilterFactoryBean shiroFilter(SecurityManager manager) {
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
bean.setSecurityManager(manager);
Map<String, String> map = new LinkedHashMap<>();
map.put("/user/login", "anon");
map.put("/admin/**", "roles[admin]");
map.put("/**", "authc");
bean.setFilterChainDefinitionMap(map);
return bean;
}
}
// Controller 使用
@RequiresRoles("admin")
@PostMapping("/admin/action")
public BaseResponse<Boolean> adminAction(...) { }
5.4 自定义 AOP 方案
// 注解定义
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface AuthCheck {
String mustRole() default "";
}
// AOP 拦截器
@Aspect
@Component
public class AuthInterceptor {
@Around("@annotation(authCheck)")
public Object doAuth(ProceedingJoinPoint joinPoint, AuthCheck authCheck) throws Throwable {
String mustRole = authCheck.mustRole();
// 权限校验逻辑
return joinPoint.proceed();
}
}
// Controller 使用
@AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
@PostMapping("/admin/action")
public BaseResponse<Boolean> adminAction(...) { }
5.5 角色常量
public interface UserConstant {
String DEFAULT_ROLE = "user"; // 普通用户
String ADMIN_ROLE = "admin"; // 管理员
String VIP_ROLE = "vip"; // VIP 用户
}
6. 工具库使用规范
6.1 Hutool 使用
// 字符串处理
StrUtil.isBlank(str);
StrUtil.format("Hello, {}", name);
// 日期处理
DateUtil.format(date, "yyyy-MM-dd");
DateUtil.parse("2024-01-01");
// 对象拷贝
BeanUtil.copyProperties(source, target);
// JSON 处理
JSONUtil.toJsonStr(object);
JSONUtil.toBean(jsonStr, Xxx.class);
// 加密
SecureUtil.md5(password);
SecureUtil.sha256(password);
// 随机数
RandomUtil.randomNumbers(6); // 6位数字验证码
RandomUtil.randomString(32); // 32位随机字符串
6.2 原生 Java 替代(不使用 Hutool)
// 字符串处理
str == null || str.isBlank();
String.format("Hello, %s", name);
// 日期处理
LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
// 对象拷贝
BeanUtils.copyProperties(source, target); // Spring
// JSON 处理
objectMapper.writeValueAsString(object); // Jackson
objectMapper.readValue(jsonStr, Xxx.class);
// 加密
MessageDigest.getInstance("MD5").digest(password.getBytes());
// 随机数
new Random().nextInt(1000000);
UUID.randomUUID().toString().replace("-", "");
7. 命名规范
7.1 类命名
| 类型 | 命名模式 | 示例 |
|---|---|---|
| Controller | XxxController | UserController, PictureController |
| Service 接口 | XxxService | UserService, PictureService |
| Service 实现 | XxxServiceImpl | UserServiceImpl, PictureServiceImpl |
| Mapper | XxxMapper | UserMapper, PictureMapper |
| Repository | XxxRepository | UserRepository (Jimmer) |
| Entity | Xxx | User, Picture |
| VO | XxxVO | UserVO, PictureVO |
7.2 DTO 命名
| 操作类型 | 命名模式 | 示例 |
|---|---|---|
| 通用请求 | XxxRequest | UserRequest |
| 创建/添加 | XxxAddRequest / XxxCreateRequest | PictureAddRequest |
| 更新 | XxxUpdateRequest | UserUpdateRequest |
| 编辑 | XxxEditRequest | PictureEditRequest |
| 查询 | XxxQueryRequest | PictureQueryRequest |
| 登录 | XxxLoginRequest | UserLoginRequest |
| 注册 | XxxRegisterRequest | UserRegisterRequest |
7.3 方法命名
| 操作 | 命名模式 | 示例 |
|---|---|---|
| 查询单个 | getXxx / getXxxById | getUser, getPictureById |
| 查询列表 | listXxx | listPictures |
| 分页查询 | listXxxByPage | listPictureByPage |
| 添加 | addXxx / createXxx | addPicture |
| 更新 | updateXxx | updateUser |
| 删除 | deleteXxx | deletePicture |
8. 依赖注入规范
8.1 推荐方式
| 方式 | 说明 | 适用场景 |
|---|---|---|
@Resource | JSR-250 标准,按名称注入 | 推荐,明确性强 |
@Autowired | Spring 原生,按类型注入 | Spring 项目通用 |
| 构造器注入 | 不可变、利于测试 | Lombok @RequiredArgsConstructor |
// @Resource(推荐)
@Resource
private UserService userService;
// @Autowired
@Autowired
private UserService userService;
// 构造器注入(Lombok)
@RequiredArgsConstructor
@Service
public class XxxServiceImpl {
private final UserService userService;
}
9. 日志规范
9.1 使用方式
@Slf4j
@Service
public class XxxServiceImpl {
public void doSomething() {
log.info("操作描述, param={}", param);
log.error("错误描述", exception);
}
}
9.2 日志级别
| 级别 | 场景 |
|---|---|
| ERROR | 系统异常、业务关键错误 |
| WARN | 潜在问题、降级处理 |
| INFO | 重要业务操作、状态变更 |
| DEBUG | 开发调试信息 |
10. 分页规范
10.1 分页请求
@Data
@EqualsAndHashCode(callSuper = true)
public class XxxQueryRequest extends PageRequest {
// 查询字段
}
// PageRequest 基类
@Data
public class PageRequest implements Serializable {
private int current = 1;
private int pageSize = 10;
private String sortField;
private String sortOrder = "descend"; // ascend / descend
}
10.2 分页返回
Page<XxxVO> page = xxxService.listByPage(request);
return ResultUtils.success(page);
11. Spring Boot 版本差异
11.1 包导入差异
| 功能 | Spring Boot 2.x | Spring Boot 3.x+ |
|---|---|---|
| Servlet | javax.servlet.* | jakarta.servlet.* |
| Validation | javax.validation.* | jakarta.validation.* |
| Persistence | javax.persistence.* | jakarta.persistence.* |
11.2 配置差异
# Spring Boot 2.x
spring:
redis:
host: localhost
port: 6379
# Spring Boot 3.x+
spring:
data:
redis:
host: localhost
port: 6379
12. 禁止事项
- 禁止 在 Controller 中编写业务逻辑
- 禁止 使用多个
@RequestParam接收参数(封装为 Request 对象) - 禁止 返回非
BaseResponse<T>类型 - 禁止 Request/VO 不实现
Serializable - 禁止 在 Service 中直接操作
HttpServletRequest - 禁止 硬编码角色字符串(使用常量)
- 禁止 混用不同 ORM 框架的写法
- 禁止 在生产环境使用 DEBUG 级别日志
附录:当前项目配置
本项目(yun-picture-backend)使用的技术栈:
| 配置项 | 选择 |
|---|---|
| Spring Boot | 3.5.7 |
| JDK | 17 |
| ORM | MyBatis-Plus 3.5.14 |
| 工具库 | Hutool 5.8.40 |
| 访问控制 | 自定义 AOP(@AuthCheck) |
| 依赖注入 | @Resource |
| API 文档 | SpringDoc OpenAPI 3.0 |
13. 代码模板
完整可复制的代码模板见 references/code-templates.md,包含:
| 包 | 类 |
|---|---|
| common | BaseResponse, PageRequest, DeleteRequest |
| controller | MainController |
| exception | ErrorCode, BusinessException, GlobalExceptionHandler |
| utils | ResultUtils, ThrowUtils |
| config | MybatisPlusConfig, JsonConfig, OpenApiConfig |
Comments
Markdown supported