1.pom.xml
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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>xxx</groupId>
<artifactId>xxx</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>xxx</name>
<description>xxx</description>
<properties>
<java.version>17</java.version>
<spring-cloud.version>2023.0.2</spring-cloud.version>
</properties>
<dependencies>
<!-- springboot-web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- open feign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- knife4j 接口文档 -->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
<version>4.5.0</version>
</dependency>
<!-- springboot 参数校验 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<!-- JPA 转JSON与数据库映射 -->
<dependency>
<groupId>io.hypersistence</groupId>
<artifactId>hypersistence-utils-hibernate-63</artifactId>
<version>3.7.5</version>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- springboot test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--hutool 工具类 -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.27</version>
</dependency>
<!-- springboot3 druid兼容的启动器 -->
<!-- <dependency>-->
<!-- <groupId>com.alibaba</groupId>-->
<!-- <artifactId>druid-spring-boot-3-starter</artifactId>-->
<!-- <version>1.2.20</version>-->
<!-- </dependency>-->
</dependencies>
<!-- 依赖版本管理 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>主启动类全限定名</mainClass>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
2.全局异常处理器
java
复制代码
/**
* 全局异常处理器
*/
@Slf4j
@RestControllerAdvice
public class ControllerExceptionHandleAdvice {
@ExceptionHandler(RetryableException.class)
public ResponseEntity<ErrorResultVo> handleRetryableException(RetryableException e) {
String message = e.getMessage();
log.error(message,e);
return ResponseEntity.internalServerError()
.body(new ErrorResultVo(ErrorCode.NETWORK_ERROR.getCode(), "网路请求出错:"+message));
}
@ExceptionHandler(FeignException.class)
public ResponseEntity<ErrorResultVo> handleFeignException(FeignException e) {
try {
String body = e.contentUTF8();
ErrorResultVo errorResultVo = JsonUtils.jsonToObj(body, ErrorResultVo.class);
log.error(e.getMessage(), e);
if (errorResultVo!=null){
return ResponseEntity.status(e.status())
.body(errorResultVo);
}else {
R r = JsonUtils.jsonToObj(body, R.class);
if (r==null){
throw new RuntimeException("json解析失败");
}
return ResponseEntity.status(e.status()).body(new ErrorResultVo(String.valueOf(r.getErrorcode()), r.getMessage()));
}
} catch (Exception ex) {
ex.printStackTrace();
return ResponseEntity.internalServerError()
.body(new ErrorResultVo(HttpStatus.INTERNAL_SERVER_ERROR.name(), "内部错误!"));
}
}
@ExceptionHandler(CodeException.class)
public ResponseEntity<ErrorResultVo> handleCodeException(CodeException e) {
log.error(e.getMessage(), e);
return ResponseEntity.status(HttpStatus.FORBIDDEN).body(new ErrorResultVo(ErrorCode.TOKEN_ERROR.getCode(), e.getMessage()));
}
@ExceptionHandler(TokenException.class)
public ResponseEntity<ErrorResultVo> handleTokenException(TokenException e) {
log.error(e.getMessage(), e);
return ResponseEntity.status(HttpStatus.FORBIDDEN).body(new ErrorResultVo(ErrorCode.TOKEN_EXCEPTION.getCode(), e.getMessage()));
}
@ExceptionHandler(HttpStatusException.class)
public ResponseEntity<ErrorResultVo> handleHttpStatusException(HttpStatusException e) {
log.error(e.getMessage());
if (e.getCause() != null) {
log.error(e.getMessage(), e);
}
HttpStatus httpStatus = e.getHttpStatus();
if (httpStatus == null) {
httpStatus = HttpStatus.INTERNAL_SERVER_ERROR;
}
ErrorResultVo errorResultVo = new ErrorResultVo(e.getCode(), e.getMessage());
return ResponseEntity.status(httpStatus).body(errorResultVo);
}
/**
* jakarta.validation 校验器异常处理
* @param e ConstraintViolationException
* @return
*/
@ExceptionHandler(ConstraintViolationException.class)
public ResponseEntity<ErrorResultVo> handleHandlerConstraintViolationException(ConstraintViolationException e) {
log.error(e.getMessage(),e);
return ResponseEntity.badRequest()
.body(new ErrorResultVo(HttpStatus.BAD_REQUEST.name(), e.getMessage()));
}
@ExceptionHandler(HandlerMethodValidationException.class)
public ResponseEntity<ErrorResultVo> handleHandlerMethodValidationException(HandlerMethodValidationException e) {
log.error(e.getMessage(),e);
return ResponseEntity.badRequest()
.body(new ErrorResultVo(HttpStatus.BAD_REQUEST.name(), "方法参数错误!"));
}
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ErrorResultVo> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
FieldError fieldError = e.getBindingResult().getFieldError();
return ResponseEntity.badRequest()
.body(
new ErrorResultVo(HttpStatus.BAD_REQUEST.name(),
fieldError == null ? "参数错误!" : fieldError.getDefaultMessage()));
}
@ExceptionHandler(MissingServletRequestParameterException.class)
public ResponseEntity<ErrorResultVo> handleMissingServletRequestParameterException(MissingServletRequestParameterException e) {
return ResponseEntity.badRequest()
.body(
new ErrorResultVo(HttpStatus.BAD_REQUEST.name(),
"缺少参数"" + e.getParameterName() + ""!"));
}
@ExceptionHandler(HttpMessageNotReadableException.class)
public ResponseEntity<ErrorResultVo> handleHttpMessageNotReadableException(HttpMessageNotReadableException e) {
String message = "数据格式错误!";
Throwable cause = e.getCause();
if (cause instanceof InvalidFormatException) {
InvalidFormatException causeException = (InvalidFormatException) cause;
message += "错误值:"" + causeException.getValue() + """;
}
return ResponseEntity.badRequest()
.body(
new ErrorResultVo(HttpStatus.BAD_REQUEST.name(),
message));
}
@ExceptionHandler(MissingRequestHeaderException.class)
public ResponseEntity<ErrorResultVo> handleHttpMessageNotReadableException(MissingRequestHeaderException e) {
return ResponseEntity.badRequest()
.body(
new ErrorResultVo(HttpStatus.BAD_REQUEST.name(),
"Header缺少:" + e.getHeaderName()));
}
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResultVo> handleException(Exception e) {
log.error(e.getMessage(), e);
return ResponseEntity.internalServerError()
.body(new ErrorResultVo(HttpStatus.INTERNAL_SERVER_ERROR.name(), "内部错误!"));
}
@ExceptionHandler(Throwable.class)
public ResponseEntity<ErrorResultVo> handleThrowable(Throwable e) {
log.error(e.getMessage(), e);
return ResponseEntity.internalServerError()
.body(new ErrorResultVo(HttpStatus.INTERNAL_SERVER_ERROR.name(), "内部错误!"));
}
}
3.Knife4jConfig
java
复制代码
@Configuration
public class Knife4jConfig {
@Value("${spring.application.version}")
private String applicationVersion;
@Bean
public OpenAPI openAPI() {
return new OpenAPI().info(new Info()
.title("项目标题")
.description("项目描述")
.contact(new Contact().name("作者"))
.version(applicationVersion));
}
}
4.application.yml
java
复制代码
server:
port: ${SERVER_PORT:10001}
spring:
application:
name: xxx
version: @project.version@
# datasource:
# druid:
# driver-class-name: com.mysql.cj.jdbc.Driver
# username: root
# password: root
# url: jdbc:mysql://localhost:3306/student?useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
# type: com.alibaba.druid.pool.DruidDataSource
# data:
# redis:
# host: ${REDIS_HOST:localhost}
# port: ${REDIS_PORT:6379}
# password: ${REDIS_PASSWORD:xxx}
# database: ${REDIS_DATABASE:1}
# jpa:
# show-sql: true #是否显示SQL
# hibernate:
# ddl-auto: update
# properties:
# hibernate:
# format_sql: true #格式化SQL
# generate-ddl: true #打印建表修改表信息
# cloud:
# openfeign:
# httpclient:
# connection-timeout: 5000
# ok-http:
# read-timeout: 10000
# springdoc-openapi项目配置
springdoc:
swagger-ui:
path: /swagger-ui.html
tags-sorter: alpha
operations-sorter: order
api-docs:
path: /v3/api-docs
group-configs:
- group: '分组名称'
paths-to-match: 'url路径'
packages-to-scan: 扫描包全限定名
# knife4j的增强配置,不需要增强可以不配
knife4j:
enable: true
setting:
language: zh_cn
5.错误返回类
java
复制代码
public record ErrorResultVo(String code, String message) {
}
6.自定义异常
java
复制代码
public class HttpStatusException extends RuntimeException {
private HttpStatus httpStatus;
private String code;
public HttpStatusException(String code, String message) {
super(message);
this.code = code;
this.httpStatus = HttpStatus.INTERNAL_SERVER_ERROR;
}
public HttpStatusException(String code, String message, Throwable cause) {
super(message, cause);
this.code = code;
this.httpStatus = HttpStatus.INTERNAL_SERVER_ERROR;
}
public HttpStatusException(HttpStatus httpStatus, String code, String message) {
super(message);
this.code = code;
this.httpStatus = httpStatus;
}
public HttpStatusException(HttpStatus httpStatus, String code, String message, Throwable cause) {
super(message, cause);
this.code = code;
this.httpStatus = httpStatus;
}
public HttpStatus getHttpStatus() {
return httpStatus;
}
public String getCode() {
return code;
}
}
java
复制代码
public class TokenException extends RuntimeException {
public TokenException(String message) {
super(message);
}
}
java
复制代码
public class CodeException extends RuntimeException {
/**
*
*/
private static final long serialVersionUID = 6804604143303073491L;
private final int errorcode;
public CodeException(int errorcode, String message, Throwable cause) {
super(message, cause);
this.errorcode = errorcode;
}
public CodeException(int errorcode, String message) {
super(message);
this.errorcode = errorcode;
}
public int getErrorcode() {
return errorcode;
}
}
7.错误码
java
复制代码
import lombok.Getter;
import org.springframework.http.HttpStatus;
@Getter
public enum ErrorCode {
INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR.value(),"internal_server_error","服务内部错误"),
NETWORK_ERROR(HttpStatus.INTERNAL_SERVER_ERROR.value(),"network_error","网络连接异常"),
RESOURCE_NOT_FOUND(HttpStatus.NOT_FOUND.value(), "resource_not_found","资源没有找到"),
TOKEN_ERROR(HttpStatus.FORBIDDEN.value(), "token_error","TOKEN校验失败"),
TOKEN_EXCEPTION(HttpStatus.FORBIDDEN.value(), "token_exception","TOKEN解析异常"),
USER_AUTH_ERROR(HttpStatus.FORBIDDEN.value(), "user_auth_error","用户权限错误"),
PARAM_ERROR(HttpStatus.BAD_REQUEST.value(), "param_error","参数错误"),
ENUM_ERROR(HttpStatus.BAD_REQUEST.value(), "enum_error","传入枚举类型错误"),
FEIGN_INTERNET_ERROR(HttpStatus.INTERNAL_SERVER_ERROR.value(), "feign_internet_error","远程调用接口异常")
;
private Integer ref;
private String code;
private String name;
ErrorCode(Integer ref, String code, String name) {
this.ref = ref;
this.code = code;
this.name = name;
}
}