java后端初始化模版
目录
新建项目
整合依赖
通用基础代码
1.自定义异常
2.响应包装类
3.全局异常处理器
4.请求包装类
5.全局跨域配置
新建项目
在idea中新建项目,选择spring boot模版,maven,jdk21
选择 Spring Boot 3.5.x版本,必须添加的依赖包括 Spring Web、MySQL、Lombok
点击创建,就得到了一个Spring Boot项目,需要等待 Maven 为我们安装依赖。
修改资源目录下的配置文件为application.yml,指定项目启动的端口号和访问地址前缀、项目名称,代码如下:
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.36</version><optional>true</optional>
</dependency>
整合依赖
Hutool工具库
Hutool是主流的Java 工具类库,集合了丰富的工具类,涵盖字符串处理、日期操作、文件处理、加解密、反射、正则匹配等常见功能。它的轻量化和无侵入性让开发者能够专注于业务逻辑而不必编写重复的工具代码。例如,DateUtil.formatDate(newDate())可以快速将当前日期格式化为字符串。
在Maven的pom.xml中添加依赖:
<dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.38</version>
</dependency>
Knife4j接口文档
Knife4j是基于Swagger接口文档的增强工具,提供了更加友好的API文档界面和功能扩展,例如动态参数调试、分组文档等。它适合用于Spring Boot项目中,能够通过简单的配置自动生成接口文档,让开发者和前端快速了解和调试接口,提高协作效率。
1.在maven的pom.xml中添加依赖
<dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId><version>4.4.0</version>
</dependency>
2.在application.yml 中追加接口文档配置,重点是指定扫描 Controller 包的路径:
# springdoc-openapi
springdoc:group-configs:- group: 'default'packages-to-scan: com.yupi.yuaicodemother.controller
# knife4j
knife4j:enable: truesetting:language: zh_cn
3.在controller包下新建一个测试接口
@RestController
@RequestMapping("/health")
public class HealthController {@GetMapping("/")public String healthCheck() {return "ok";}
}
通用基础代码
无论在任何后端项目中,都可以复用的代码。这种代码一般"一辈子只用写一次,了解作用之后复制粘贴即可,无需记忆。
目录结构

1.自定义异常
自定义错误码,对错误进行收敛,便于前端统一处理。
好处:有些异常是框架抛出的,但是有些异常是自己的业务中异常,很好的区分内部异常和业务异常。
自定义错误码时,建议跟主流的错误码(比如HTTP错误码)的含义保持一致,比如"未登录”定义为40100,和HTTP401错误(用户需要进行身份认证)保持一致,500后端服务器异常,会更容易理解。
错误码不要完全连续,预留一些间隔,便于后续扩展。
在exception包下新建错误码枚举类:
@Getter
public enum ErrorCode {SUCCESS(0, "ok"),PARAMS_ERROR(40000, "请求参数错误"),NOT_LOGIN_ERROR(40100, "未登录"),NO_AUTH_ERROR(40101, "无权限"),NOT_FOUND_ERROR(40400, "请求数据不存在"),FORBIDDEN_ERROR(40300, "禁止访问"),SYSTEM_ERROR(50000, "系统内部异常"),OPERATION_ERROR(50001, "操作失败");/*** 状态码*/private final int code;/*** 信息*/private final String message;ErrorCode(int code, String message) {this.code = code;this.message = message;}}
一般不建议直接抛出Java内置的RuntimeException,而是自定义一个业务异常,和内置的异常类区分开,便于定制化输出错误信息:
@Getter
public class BusinessException extends RuntimeException {/*** 错误码*/private final int code;public BusinessException(int code, String message) {super(message);this.code = code;}public BusinessException(ErrorCode errorCode) {super(errorCode.getMessage());this.code = errorCode.getCode();}public BusinessException(ErrorCode errorCode, String message) {super(message);this.code = errorCode.getCode();}
}
为了更方便地根据情况抛出异常,可以封装一个ThrowUtils,类似断言类,简化抛异常的代码:
public class ThrowUtils {/*** 条件成立则抛异常** @param condition 条件* @param runtimeException 异常*/public static void throwIf(boolean condition, RuntimeException runtimeException) {if (condition) {throw runtimeException;}}/*** 条件成立则抛异常** @param condition 条件* @param errorCode 错误码*/public static void throwIf(boolean condition, ErrorCode errorCode) {throwIf(condition, new BusinessException(errorCode));}/*** 条件成立则抛异常** @param condition 条件* @param errorCode 错误码* @param message 错误信息*/public static void throwIf(boolean condition, ErrorCode errorCode, String message) {throwIf(condition, new BusinessException(errorCode, message));}
}
每个接口都返回给前端,返回给前端的数据未包装,前端不能判断正常与否。一般需要对后端传给前端的接口进行封装。
2.响应包装类
一般情况下,每个后端接口都要返回调用码、数据、调用信息等,前端可以根据这些信息进行相应的处理。我们可以封装统一的响应结果类,便于前端统一获取这些信息。
我们可以封装统一的响应结果类,便于前端统一获取这些信息。
通用响应类
@Data
public class BaseResponse<T> implements Serializable {private int code;private T data;private String message;public BaseResponse(int code, T data, String message) {this.code = code;this.data = data;this.message = message;}public BaseResponse(int code, T data) {this(code, data, "");}public BaseResponse(ErrorCode errorCode) {this(errorCode.getCode(), null, errorCode.getMessage());}
}
但之后每次接口返回值时,都要手动new一个BaseResponse对象并传入参数,比较麻烦,我们可以新建一个工具类,提供成功调用和失败调用的方法,支持灵活地传参,简化调用。
public class ResultUtils {/*** 成功** @param data 数据* @param <T> 数据类型* @return 响应*/public static <T> BaseResponse<T> success(T data) {return new BaseResponse<>(0, data, "ok");}/*** 失败** @param errorCode 错误码* @return 响应*/public static BaseResponse<?> error(ErrorCode errorCode) {return new BaseResponse<>(errorCode);}/*** 失败** @param code 错误码* @param message 错误信息* @return 响应*/public static BaseResponse<?> error(int code, String message) {return new BaseResponse<>(code, null, message);}/*** 失败** @param errorCode 错误码* @return 响应*/public static BaseResponse<?> error(ErrorCode errorCode, String message) {return new BaseResponse<>(errorCode.getCode(), null, message);}
}
3.全局异常处理器
为了防止意料之外的异常,利用AOP切面全局对业务异常和RuntimeException进行捕获:
@Hidden
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {@ExceptionHandler(BusinessException.class)public BaseResponse<?> businessExceptionHandler(BusinessException e) {log.error("BusinessException", e);return ResultUtils.error(e.getCode(), e.getMessage());}@ExceptionHandler(RuntimeException.class)public BaseResponse<?> runtimeExceptionHandler(RuntimeException e) {log.error("RuntimeException", e);return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "系统错误");}
}
注意!由于本项目使用的 Spring Boot版本>=3.4、并且是OpenAPl 3版本的Knife4j,这会导致@RestControllerAdvice注解不兼容,所以必须给这个类加上@Hidden 注解,不被Swagger加载。虽然网上也有其他的解决方案,但这种方法是最直接有效的。
@RestControllerAdvice:捕获所有的controller异常
4.请求包装类
对于“分页"、“删除某条数据”这类通用的请求,可以封装统一的请求包装类,用于接受前端传来的参数,之后相同参数的请求就不用专门再新建一个类了。分页请求包装类,包括当前页号、页面大小、排序字段、排序顺序参数:
@Data
public class PageRequest {/*** 当前页号*/private int pageNum = 1;/*** 页面大小*/private int pageSize = 10;/*** 排序字段*/private String sortField;/*** 排序顺序(默认降序)*/private String sortOrder = "descend";
}
删除请求包装类,接受要删除数据的id作为参数:
@Data
public class DeleteRequest implements Serializable {/*** id*/private Long id;private static final long serialVersionUID = 1L;
}
5.全局跨域配置
跨域是指浏览器访问的URL(前端地址)和后端接口地址的域名(或端口号)不一致导致的,浏览器为了安全,默认禁止跨域请求访问。

这就是跨域!
为了开发调试方便,我们可以通过全局跨域配置,让整个项目所有的接口支持跨域,解决跨域报错。
新建config包,用于存放所有的配置相关代码。全局跨域配置代码如下:
@Configuration
public class CorsConfig implements WebMvcConfigurer {@Overridepublic void addCorsMappings(CorsRegistry registry) {// 覆盖所有请求registry.addMapping("/**")// 允许发送 Cookie.allowCredentials(true)// 放行哪些域名(必须用 patterns,否则 * 会和 allowCredentials 冲突).allowedOriginPatterns("*").allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS").allowedHeaders("*").exposedHeaders("*");}
}
