diff --git a/common/pom.xml b/common/pom.xml index 58601bd..7e4f0b8 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -17,4 +17,32 @@ UTF-8 + + + net.rzdata + demo-core + 5.1.0-SNAPSHOT + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-validation + + + com.baomidou + mybatis-plus-boot-starter + + + cn.dev33 + sa-token-core + + + org.projectlombok + lombok + provided + + diff --git a/common/src/main/java/net/rzdata/demo/exception/GlobalExceptionHandler.java b/common/src/main/java/net/rzdata/demo/exception/GlobalExceptionHandler.java new file mode 100644 index 0000000..40a1ca3 --- /dev/null +++ b/common/src/main/java/net/rzdata/demo/exception/GlobalExceptionHandler.java @@ -0,0 +1,164 @@ +package net.rzdata.demo.exception; + +import cn.dev33.satoken.exception.NotLoginException; +import cn.dev33.satoken.exception.NotPermissionException; +import cn.dev33.satoken.exception.NotRoleException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.validation.ConstraintViolation; +import jakarta.validation.ConstraintViolationException; +import lombok.extern.slf4j.Slf4j; +import net.rzdata.domain.Result; +import net.rzdata.exception.ClientException; +import net.rzdata.exception.ServerException; +import net.rzdata.exception.ThirdPartyException; +import org.springframework.context.support.DefaultMessageSourceResolvable; +import org.springframework.http.HttpStatus; +import org.springframework.validation.BindException; +import org.springframework.web.HttpRequestMethodNotSupportedException; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseStatus; + +import java.util.stream.Collectors; + +/** + * 全局异常处理 + */ +@Slf4j +public class GlobalExceptionHandler { + + protected final transient String errorMessage = "系统错误,请联系系统管理员"; + + /** + * 权限码异常 + */ + @ExceptionHandler(NotPermissionException.class) + @ResponseStatus(HttpStatus.FORBIDDEN) + public Result handleNotPermissionException(NotPermissionException e, HttpServletRequest request) { + String requestURI = request.getRequestURI(); + log.error("请求地址'{}',权限码校验失败'{}'", requestURI, e.getMessage()); + ClientException ce = new ClientException("没有访问权限,请联系管理员授权", e); + return Result.fail(ce); + } + + /** + * 角色权限异常 + */ + @ExceptionHandler(NotRoleException.class) + @ResponseStatus(HttpStatus.FORBIDDEN) + public Result handleNotRoleException(NotRoleException e, HttpServletRequest request) { + String requestURI = request.getRequestURI(); + log.error("请求地址'{}',角色权限校验失败'{}'", requestURI, e.getMessage()); + ClientException ce = new ClientException("没有访问权限,请联系管理员授权", e); + return Result.fail(ce); + } + + /** + * 认证失败 + */ + @ExceptionHandler(NotLoginException.class) + @ResponseStatus(HttpStatus.UNAUTHORIZED) + public Result handleNotLoginException(NotLoginException e, HttpServletRequest request) { + String requestURI = request.getRequestURI(); + log.error("请求地址'{}',认证失败'{}',无法访问系统资源", requestURI, e.getMessage()); + ClientException ce = new ClientException("没有访问权限,请联系管理员授权", e); + return Result.fail(ce); + } + + /** + * 请求方式不支持 + */ + @ExceptionHandler(HttpRequestMethodNotSupportedException.class) + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) + public Result handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException e, HttpServletRequest request) { + String requestURI = request.getRequestURI(); + log.error("请求地址'{}',不支持'{}'请求", requestURI, e.getMethod()); + ServerException se = new ServerException("请求方式不支持", e); + return Result.fail(se, errorMessage); + } + + @ExceptionHandler(ClientException.class) + @ResponseStatus(HttpStatus.BAD_REQUEST) + public Result handleClientException(ClientException e) { + log.error("客户端异常: {}", e.getMessage(), e); + return Result.fail(e); + } + + @ExceptionHandler(ServerException.class) + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) + public Result handleServerException(ServerException e) { + log.error("服务端异常: {}", e.getMessage(), e); + return Result.fail(e, errorMessage); + } + + @ExceptionHandler(ThirdPartyException.class) + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) + public Result handleThirdPartyException(ThirdPartyException e) { + log.error("第三方服务异常: {}", e.getMessage(), e); + return Result.fail(e, errorMessage); + } + + /** + * 拦截未知的运行时异常 + */ + @ExceptionHandler(RuntimeException.class) + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) + public Result handleRuntimeException(RuntimeException e, HttpServletRequest request) { + String requestURI = request.getRequestURI(); + log.error("请求地址'{}',发生未知异常.", requestURI, e); + ServerException se = new ServerException(errorMessage, e); + return Result.fail(se); + } + + /** + * 系统异常 + */ + @ExceptionHandler(Exception.class) + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) + public Result handleException(Exception e, HttpServletRequest request) { + String requestURI = request.getRequestURI(); + log.error("请求地址'{}',发生系统异常.", requestURI, e); + ServerException se = new ServerException(errorMessage, e); + return Result.fail(se); + } + + /** + * 自定义验证异常 + */ + @ExceptionHandler(BindException.class) + @ResponseStatus(HttpStatus.BAD_REQUEST) + public Result handleBindException(BindException e) { + log.error(e.getMessage(), e); + String message = e.getAllErrors().parallelStream() + .map(DefaultMessageSourceResolvable::getDefaultMessage) + .collect(Collectors.joining(", ")); + ClientException ce = new ClientException(message, e); + return Result.fail(ce); + } + + /** + * 自定义验证异常 + */ + @ExceptionHandler(ConstraintViolationException.class) + @ResponseStatus(HttpStatus.BAD_REQUEST) + public Result constraintViolationException(ConstraintViolationException e) { + log.error(e.getMessage(), e); + String message = e.getConstraintViolations().parallelStream() + .map(ConstraintViolation::getMessage) + .collect(Collectors.joining(", ")); + ClientException ce = new ClientException(message, e); + return Result.fail(ce); + } + + /** + * 自定义验证异常 + */ + @ExceptionHandler(MethodArgumentNotValidException.class) + @ResponseStatus(HttpStatus.BAD_REQUEST) + public Result handleMethodArgumentNotValidException(MethodArgumentNotValidException e) { + log.error(e.getMessage(), e); + String message = e.getBindingResult().getFieldError().getDefaultMessage(); + ClientException ce = new ClientException(message, e); + return Result.fail(ce); + } +} diff --git a/common/src/main/java/net/rzdata/demo/trait/BaseRepository.java b/common/src/main/java/net/rzdata/demo/trait/BaseRepository.java new file mode 100644 index 0000000..6ef7c4b --- /dev/null +++ b/common/src/main/java/net/rzdata/demo/trait/BaseRepository.java @@ -0,0 +1,16 @@ +package net.rzdata.demo.trait; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +public abstract class BaseRepository> { + + private final transient M mapper; + + public BaseRepository(M mapper) { + this.mapper = mapper; + } + + public M get() { + return this.mapper; + } +} diff --git a/common/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/common/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..da71b2a --- /dev/null +++ b/common/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +net.rzdata.demo.exception.GlobalExceptionHandler diff --git a/core/pom.xml b/core/pom.xml new file mode 100644 index 0000000..474f2ff --- /dev/null +++ b/core/pom.xml @@ -0,0 +1,27 @@ + + + 4.0.0 + + net.rzdata + demo + 5.1.0-SNAPSHOT + + demo-core + jar + + + 17 + 17 + UTF-8 + + + + + org.projectlombok + lombok + provided + + + diff --git a/core/src/main/java/net/rzdata/domain/Id.java b/core/src/main/java/net/rzdata/domain/Id.java new file mode 100644 index 0000000..2c4aa5b --- /dev/null +++ b/core/src/main/java/net/rzdata/domain/Id.java @@ -0,0 +1,8 @@ +package net.rzdata.domain; + +public record Id(String id) { + + public static Id of(String id) { + return new Id(id); + } +} diff --git a/core/src/main/java/net/rzdata/domain/Result.java b/core/src/main/java/net/rzdata/domain/Result.java new file mode 100644 index 0000000..65e4a47 --- /dev/null +++ b/core/src/main/java/net/rzdata/domain/Result.java @@ -0,0 +1,42 @@ +package net.rzdata.domain; + +import lombok.*; +import net.rzdata.exception.BaseException; + +@Getter +@ToString +@NoArgsConstructor +@AllArgsConstructor(access = AccessLevel.PROTECTED) +public class Result { + + public static final String SUCCESS_CODE = "00000"; + public static final String SUCCESS_MESSAGE = "操作成功"; + + private String code; + private String message; + private T data; + + public static Result ok() { + return new Result<>(SUCCESS_CODE, SUCCESS_MESSAGE, null); + } + + public static Result ok(T data) { + return new Result<>(SUCCESS_CODE, SUCCESS_MESSAGE, data); + } + + public static Result fail(BaseException e) { + return new Result<>(e.getCode(), e.getMessage(), null); + } + + public static Result fail(BaseException e, T data) { + return new Result<>(e.getCode(), e.getMessage(), data); + } + + public static Result fail(BaseException e, String message) { + return new Result<>(e.getCode(), message, null); + } + + public static Result fail(BaseException e, String message, T data) { + return new Result<>(e.getCode(), message, data); + } +} diff --git a/core/src/main/java/net/rzdata/exception/BaseException.java b/core/src/main/java/net/rzdata/exception/BaseException.java new file mode 100644 index 0000000..48c21cf --- /dev/null +++ b/core/src/main/java/net/rzdata/exception/BaseException.java @@ -0,0 +1,21 @@ +package net.rzdata.exception; + +public abstract sealed class BaseException extends RuntimeException + permits ClientException, ServerException, ThirdPartyException { + + private final String code; + + protected BaseException(String code, String message) { + super(message); + this.code = code; + } + + protected BaseException(String code, String message, Throwable cause) { + super(message, cause); + this.code = code; + } + + public String getCode() { + return this.code; + } +} diff --git a/core/src/main/java/net/rzdata/exception/ClientException.java b/core/src/main/java/net/rzdata/exception/ClientException.java new file mode 100644 index 0000000..0a63d41 --- /dev/null +++ b/core/src/main/java/net/rzdata/exception/ClientException.java @@ -0,0 +1,25 @@ +package net.rzdata.exception; + +/** + * 客户端异常 + */ +public non-sealed class ClientException extends BaseException { + + public static final String CLIENT_ERROR_CODE = "A0001"; + + public ClientException(String message) { + super(CLIENT_ERROR_CODE, message); + } + + public ClientException(String message, Throwable cause) { + super(CLIENT_ERROR_CODE, message, cause); + } + + protected ClientException(String code, String message) { + super(code, message); + } + + protected ClientException(String code, String message, Throwable cause) { + super(code, message, cause); + } +} diff --git a/core/src/main/java/net/rzdata/exception/ServerException.java b/core/src/main/java/net/rzdata/exception/ServerException.java new file mode 100644 index 0000000..f436288 --- /dev/null +++ b/core/src/main/java/net/rzdata/exception/ServerException.java @@ -0,0 +1,25 @@ +package net.rzdata.exception; + +/** + * 服务端异常 + */ +public non-sealed class ServerException extends BaseException { + + public static final String SERVER_ERROR_CODE = "B0001"; + + public ServerException(String message) { + super(SERVER_ERROR_CODE, message); + } + + public ServerException(String message, Throwable cause) { + super(SERVER_ERROR_CODE, message, cause); + } + + protected ServerException(String code, String message) { + super(code, message); + } + + protected ServerException(String code, String message, Throwable cause) { + super(code, message, cause); + } +} diff --git a/core/src/main/java/net/rzdata/exception/ThirdPartyException.java b/core/src/main/java/net/rzdata/exception/ThirdPartyException.java new file mode 100644 index 0000000..dc287e3 --- /dev/null +++ b/core/src/main/java/net/rzdata/exception/ThirdPartyException.java @@ -0,0 +1,25 @@ +package net.rzdata.exception; + +/** + * 第三方服务异常 + */ +public non-sealed class ThirdPartyException extends BaseException { + + public static final String THIRD_PARTY_ERROR_CODE = "C0001"; + + public ThirdPartyException(String message) { + super(THIRD_PARTY_ERROR_CODE, message); + } + + public ThirdPartyException(String message, Throwable cause) { + super(THIRD_PARTY_ERROR_CODE, message, cause); + } + + protected ThirdPartyException(String code, String message) { + super(code, message); + } + + protected ThirdPartyException(String code, String message, Throwable cause) { + super(code, message, cause); + } +} diff --git a/core/src/main/java/net/rzdata/trait/IConverter.java b/core/src/main/java/net/rzdata/trait/IConverter.java new file mode 100644 index 0000000..94679f4 --- /dev/null +++ b/core/src/main/java/net/rzdata/trait/IConverter.java @@ -0,0 +1,11 @@ +package net.rzdata.trait; + +/** + * 实体转换类 + * @param 源类型 + * @param 目标类型 + */ +public interface IConverter { + + T convert(S source); +} diff --git a/core/src/main/java/net/rzdata/trait/IQuery.java b/core/src/main/java/net/rzdata/trait/IQuery.java new file mode 100644 index 0000000..b2f891e --- /dev/null +++ b/core/src/main/java/net/rzdata/trait/IQuery.java @@ -0,0 +1,10 @@ +package net.rzdata.trait; + +/** + * 请求实体类 + * @param 核心模型类型 + */ +public interface IQuery { + + T into(); +} diff --git a/pom.xml b/pom.xml index d0730f6..2d8acb4 100644 --- a/pom.xml +++ b/pom.xml @@ -16,6 +16,7 @@ service common + core diff --git a/service/pom.xml b/service/pom.xml index 5c6f4eb..a85c73b 100644 --- a/service/pom.xml +++ b/service/pom.xml @@ -67,10 +67,6 @@ org.mapstruct mapstruct - - org.liquibase - liquibase-core - org.springframework.boot spring-boot-starter-test