# 后端通用模板 **Repository Path**: hanser_wei_admin/backend-universal-template ## Basic Information - **Project Name**: 后端通用模板 - **Description**: 后端通用模板,提供高效、可复用的后端开发框架,支持快速搭建RESTful API服务,适用于多种业务场景。 - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2025-09-24 - **Last Updated**: 2025-09-25 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 后端通用模板(Spring Boot) 这是一个基于 Spring Boot 的后端通用模板项目,适用于快速搭建社区类或其他通用业务的后端服务。项目集成了 MyBatis Plus、Redis、OSS、Druid、SpringDoc/Knife4j 等常用组件,并提供了统一的异常处理与响应封装。 ## 功能特性 - **统一响应封装**:`ApiResponse` 统一返回结构。 - **统一异常处理**:`ApiException` + `GlobalExceptionHandler` 捕获并格式化错误。 - **异常工具类**:`ThrowUtils` 简化条件校验并抛错。 - **分页参数模型**:`PageRequest` 提供标准分页与排序入参。 - **MyBatis Plus**:自动扫描 Mapper,内置分页拦截器。 - **Redis 管理**:`RedisManager` 封装验证码等常用缓存操作。 - **阿里云 OSS**:`OssManager` 封装对象存储上传能力。 - **跨域 CORS**:全局跨域配置。 - **Druid 监控去广告**:优化内置监控页体验。 ## 快速开始 ### 环境要求 - Java 17+ - Maven 3.8+ - MySQL 8.0+ - Redis 6.0+ - 阿里云 OSS 账号(可选) ### 安装与启动 1. 克隆项目 ```bash git clone https://gitee.com/hanser_wei_admin/backend-universal-template.git cd backend-universal-template ``` 2. 配置数据库与中间件 - 修改 `src/main/resources/application.yml` 中的 MySQL、Redis 配置。 - 导入 `sql/newCommunity.sql` 初始化数据库。 - 如需 OSS,分别在 `application.yml` 与 `application-local.yml` 中补齐 `aliyun.oss.*`。 3. 启动服务 ```bash mvn spring-boot:run ``` 默认端口与上下文:`http://localhost:8088/api` ### 接口文档(Swagger/Knife4j) - Swagger UI: `http://localhost:8088/api/swagger-ui.html` - OpenAPI JSON: `http://localhost:8088/api/v3/api-docs` - Knife4j UI(若启用): `http://localhost:8088/api/doc.html` > 以上路径来源于 `application.yml` 中的 springdoc 与 knife4j 配置,并结合 `server.servlet.context-path: /api`。 ## 统一响应与异常 ### 统一响应类 `ApiResponse` 位置:`com.hanserwei.community.common.ApiResponse` 核心结构与工厂方法: ```1:45:src/main/java/com/hanserwei/community/common/ApiResponse.java package com.hanserwei.community.common; import com.hanserwei.community.enums.ErrorCodeEnum; /** * 统一API响应类 (Unified API Response) * * @param code 响应状态码, 对应 ErrorCodeEnum 中的 code * @param message 响应提示信息 * @param data 响应数据 * @param 响应数据的泛型 */ public record ApiResponse(int code, String message, T data) { // ========== 成功响应的静态工厂方法 ========== /** * 成功响应(无数据) */ public static ApiResponse success() { return new ApiResponse<>(ErrorCodeEnum.SUCCESS.getCode(), ErrorCodeEnum.SUCCESS.getMessage(), null); } /** 成功响应(有数据) */ public static ApiResponse success(T data) { return new ApiResponse<>(ErrorCodeEnum.SUCCESS.getCode(), ErrorCodeEnum.SUCCESS.getMessage(), data); } } ``` 使用示例(在 `@RestController` 中): ```java @GetMapping("/ping") public ApiResponse ping() { return ApiResponse.success("pong"); } ``` 标准响应 JSON 示例: ```json { "code": 200, "message": "操作成功", "data": "pong" } ``` ### 错误码枚举 `ErrorCodeEnum` 位置:`com.hanserwei.community.enums.ErrorCodeEnum` ```1:33:src/main/java/com/hanserwei/community/enums/ErrorCodeEnum.java package com.hanserwei.community.enums; import lombok.Getter; /** * 响应状态码枚举 */ @Getter public enum ErrorCodeEnum { SUCCESS(200, "操作成功"), SYSTEM_ERROR(1000, "系统繁忙,请稍后重试"), INVALID_PARAMETER(1001, "参数无效或缺失"), UNAUTHORIZED(1002, "未授权或凭证已过期"), FORBIDDEN_ACCESS(1003, "无权访问该资源"), RESOURCE_NOT_FOUND(1004, "请求的资源不存在"), USER_NOT_FOUND(2000, "用户不存在"), USER_NOT_LOGIN(2001, "用户未登录"), USER_ACCOUNT_LOCKED(2002, "用户账户已被锁定"), USERNAME_ALREADY_EXISTS(2003, "该用户名已被注册"), USER_PASSWORD_ERROR(2004, "用户密码错误"), USER_ACCOUNT_ERROR(2005, "用户账户错误"), USER_CAPTCHA_ERROR(2006, "验证码错误"); } ``` ### 自定义异常 `ApiException` 与全局处理 `GlobalExceptionHandler` 位置: - `com.hanserwei.community.exception.ApiException` - `com.hanserwei.community.exception.GlobalExceptionHandler` ```1:26:src/main/java/com/hanserwei/community/exception/ApiException.java package com.hanserwei.community.exception; import com.hanserwei.community.enums.ErrorCodeEnum; import lombok.Getter; public class ApiException extends RuntimeException { @Getter private final ErrorCodeEnum responseCode; private final String message; public ApiException(ErrorCodeEnum responseCode) { super(responseCode.getMessage()); this.responseCode = responseCode; this.message = responseCode.getMessage(); } public ApiException(ErrorCodeEnum responseCode, String message) { super(message); this.responseCode = responseCode; this.message = message; } } ``` ```1:31:src/main/java/com/hanserwei/community/exception/GlobalExceptionHandler.java package com.hanserwei.community.exception; import com.hanserwei.community.common.ApiResponse; import com.hanserwei.community.enums.ErrorCodeEnum; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestControllerAdvice; @RestControllerAdvice @Slf4j public class GlobalExceptionHandler { @ExceptionHandler(ApiException.class) @ResponseStatus(HttpStatus.OK) public ApiResponse handleApiException(ApiException e) { return ApiResponse.error(e.getResponseCode(), e.getMessage()); } } ``` 在业务中抛出异常示例: ```java if (user == null) { throw new ApiException(ErrorCodeEnum.USER_NOT_FOUND); } ``` 统一错误响应 JSON 示例: ```json { "code": 2000, "message": "用户不存在", "data": null } ``` ### 异常工具类 `ThrowUtils` 位置:`com.hanserwei.community.uitils.ThrowUtils`(注意包名为 `uitils`) ```1:23:src/main/java/com/hanserwei/community/uitils/ThrowUtils.java package com.hanserwei.community.uitils; import com.hanserwei.community.enums.ErrorCodeEnum; import com.hanserwei.community.exception.ApiException; public class ThrowUtils { public static void throwIf(boolean condition, ErrorCodeEnum errorCode) { if (condition) throw new ApiException(errorCode); } } ``` 典型用法: ```java ThrowUtils.throwIf(param == null, ErrorCodeEnum.INVALID_PARAMETER); ThrowUtils.throwIf(!Objects.equals(captcha, input), ErrorCodeEnum.USER_CAPTCHA_ERROR, "验证码不匹配"); ``` ## 分页与排序 ### 通用分页请求模型 `PageRequest` 位置:`com.hanserwei.community.common.PageRequest` ```1:29:src/main/java/com/hanserwei/community/common/PageRequest.java package com.hanserwei.community.common; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; @Data public class PageRequest { @Schema(description = "当前页码") private int current = 1; @Schema(description = "每页数量") private int pageSize = 10; @Schema(description = "要排序的字段") private String sortField; @Schema(description = "排序顺序(默认降序)") private String sortOrder = "descend"; } ``` 结合 MyBatis Plus 的分页插件(已在 `MybatisPlusConfig` 中启用),示例: ```java @GetMapping("/list") public ApiResponse> list(PageRequest req) { Page page = new Page<>(req.getCurrent(), req.getPageSize()); IPage result = userService.page(page); return ApiResponse.success(result); } ``` 当然你也通过查询请求类继承 `PageRequest` 来实现分页排序。 ## 常用注解与说明 - `@RestController` / `@Controller`:控制器声明。 - `@RequestMapping` / `@GetMapping` / `@PostMapping`:路由映射。 - `@Validated` / `@Valid`:参数校验触发,异常由 `GlobalExceptionHandler` 处理。 - `@Schema` / `@Operation` / `@Parameter`:OpenAPI 文档注解。 - `@Slf4j`:日志。 - `@Service` / `@Component` / `@Configuration`:业务与配置声明。 - `@Mapper`:MyBatis Mapper 接口。 - `@Transactional`:事务管理。 - `@Autowired` / `@Resource`:依赖注入。 ## 管理类简述 - `OssManager`:封装文件上传,需先在 `application.yml` 与 `application-local.yml` 配置 `aliyun.oss.*`。 - `RedisManager`:封装验证码等 Key-Value 操作(见 `RedisConfig` 连接与池化配置)。 ## 运行配置关键项 - 服务器端口与上下文:`server.port: 8088`,`server.servlet.context-path: /api` - 日志:`logging.config: classpath:logback.xml` - OpenAPI:`springdoc.swagger-ui.path: /swagger-ui.html`, `springdoc.api-docs.path: /v3/api-docs` - Knife4j:`knife4j.enable: true` ## 项目结构(关键包) - `com.hanserwei.community`:应用入口 `NewCommunityApplication` - `com.hanserwei.community.common`:`ApiResponse`、`PageRequest` - `com.hanserwei.community.enums`:`ErrorCodeEnum` - `com.hanserwei.community.exception`:`ApiException`、`GlobalExceptionHandler` - `com.hanserwei.community.uitils`:`ThrowUtils` - `com.hanserwei.community.manager`:`OssManager`、`RedisManager` - `com.hanserwei.community.config`:`MybatisPlusConfig`、`RedisConfig`、`OssConfig`、`GlobalCorsConfiguration`、`FuckDruidAdConfiguration` ## 贡献指南 欢迎提交 Issue 或 Pull Request: 1. Fork 项目 2. 创建新分支 3. 提交 Pull Request ## 许可证 本项目采用 MIT 协议