feat: 统一响应格式与消息国际化
This commit is contained in:
@ -12,14 +12,17 @@
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
<!-- Spring Boot -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<!-- Utilities -->
|
||||
<dependency>
|
||||
<groupId>cn.hutool.v7</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
</dependency>
|
||||
<!-- Lombok -->
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
|
||||
@ -1,8 +1,4 @@
|
||||
package day.gitlab.dolphin.common.core.constants;
|
||||
|
||||
public class Constants {
|
||||
|
||||
public static final String SUCCESS = "success";
|
||||
|
||||
public static final String FAILURE = "failure";
|
||||
}
|
||||
|
||||
@ -2,54 +2,62 @@ package day.gitlab.dolphin.common.core.entity;
|
||||
|
||||
import day.gitlab.dolphin.common.core.exception.BusinessException;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import static day.gitlab.dolphin.common.core.constants.Constants.FAILURE;
|
||||
import static day.gitlab.dolphin.common.core.constants.Constants.SUCCESS;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class Result {
|
||||
public class Result<T> {
|
||||
|
||||
private int code;
|
||||
public static final String SUCCESS = "00000000";
|
||||
public static final String FAILURE = "99999999";
|
||||
|
||||
public static final String SUCCESS_MESSAGE = "success";
|
||||
public static final String FAILURE_MESSAGE = "failure";
|
||||
|
||||
private String code;
|
||||
private String message;
|
||||
private T data;
|
||||
private long timestamp;
|
||||
|
||||
private Object data;
|
||||
// ========== 通用响应方法 ==========
|
||||
|
||||
public static Result success() {
|
||||
return Result.builder().code(200).message(SUCCESS).build();
|
||||
public static <T> Result<T> result(String code, String message, T data) {
|
||||
return new Result<>(code, message, data, System.currentTimeMillis());
|
||||
}
|
||||
|
||||
public static Result success(Object data) {
|
||||
Result result = Result.builder().code(200).message(SUCCESS).build();
|
||||
if (data instanceof Supplier) {
|
||||
result.setData(((Supplier<?>) data).get());
|
||||
} else {
|
||||
result.setData(data);
|
||||
}
|
||||
return result;
|
||||
// ========== 成功响应方法 ==========
|
||||
|
||||
public static <T> Result<T> success() {
|
||||
return result(SUCCESS, SUCCESS_MESSAGE, null);
|
||||
}
|
||||
|
||||
public static Result failure() {
|
||||
return Result.builder().code(500).message(FAILURE).build();
|
||||
public static <T> Result<T> success(T data) {
|
||||
return result(SUCCESS, SUCCESS_MESSAGE, data);
|
||||
}
|
||||
|
||||
public static Result failure(String message) {
|
||||
return Result.builder().code(500).message(message).build();
|
||||
public static <T> Result<T> success(String message, T data) {
|
||||
return result(SUCCESS, message, data);
|
||||
}
|
||||
|
||||
public static Result failure(int code, String message) {
|
||||
return Result.builder().code(code).message(message).build();
|
||||
// ========== 失败响应方法 ==========
|
||||
|
||||
public static <T> Result<T> failure() {
|
||||
return result(FAILURE, FAILURE_MESSAGE, null);
|
||||
}
|
||||
|
||||
public static Result failure(BusinessException businessException) {
|
||||
return Result.builder().code(businessException.getCode()).message(businessException.getMessage()).build();
|
||||
public static <T> Result<T> failure(String message) {
|
||||
return result(FAILURE, message, null);
|
||||
}
|
||||
|
||||
public static <T> Result<T> failure(String code, String message) {
|
||||
return result(code, message, null);
|
||||
}
|
||||
|
||||
// ========== 异常响应方法 ==========
|
||||
|
||||
public static <T> Result<T> failure(BusinessException e) {
|
||||
return result(e.getCode(), e.getMessage(), null);
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,14 +5,9 @@ import lombok.Getter;
|
||||
@Getter
|
||||
public class BusinessException extends RuntimeException {
|
||||
|
||||
private final int code;
|
||||
private final String code;
|
||||
|
||||
public BusinessException(String message) {
|
||||
super(message);
|
||||
this.code = 500;
|
||||
}
|
||||
|
||||
public BusinessException(int code, String message) {
|
||||
public BusinessException(String code, String message) {
|
||||
super(message);
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
@ -8,12 +8,12 @@ import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
public class GlobalExceptionHandler {
|
||||
|
||||
@ExceptionHandler(value = BusinessException.class)
|
||||
public Result handleBusinessException(BusinessException e) {
|
||||
public <T> Result<T> handleBusinessException(BusinessException e) {
|
||||
return Result.failure(e);
|
||||
}
|
||||
|
||||
@ExceptionHandler(value = Exception.class)
|
||||
public Result handleException(Exception e) {
|
||||
public <T> Result<T> handleException(Exception e) {
|
||||
return Result.failure(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,29 @@
|
||||
package day.gitlab.dolphin.common.core.i18n;
|
||||
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.support.ResourceBundleMessageSource;
|
||||
import org.springframework.web.servlet.LocaleResolver;
|
||||
import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
@Configuration
|
||||
public class MessagesConfiguration {
|
||||
|
||||
@Bean
|
||||
public MessageSource messageSource() {
|
||||
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
|
||||
messageSource.setBasename("i18n.messages");
|
||||
messageSource.setDefaultEncoding("UTF-8");
|
||||
return messageSource;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public LocaleResolver localeResolver() {
|
||||
AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
|
||||
localeResolver.setDefaultLocale(Locale.ENGLISH);
|
||||
return localeResolver;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,51 @@
|
||||
package day.gitlab.dolphin.common.core.i18n;
|
||||
|
||||
import day.gitlab.dolphin.common.core.entity.Result;
|
||||
import day.gitlab.dolphin.common.core.exception.BusinessException;
|
||||
import lombok.Getter;
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.context.i18n.LocaleContextHolder;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
@Getter
|
||||
@Component
|
||||
public class MessagesHelper {
|
||||
|
||||
private final MessageSource messageSource;
|
||||
|
||||
public MessagesHelper(MessageSource messageSource) {
|
||||
this.messageSource = messageSource;
|
||||
}
|
||||
|
||||
// ========== 国际化消息 ==========
|
||||
|
||||
public Locale getCurrentLocale() {
|
||||
return LocaleContextHolder.getLocale();
|
||||
}
|
||||
|
||||
public String getMessage(String code, Object... args) {
|
||||
return messageSource.getMessage(code, args, getCurrentLocale());
|
||||
}
|
||||
|
||||
public String getMessage(String code, String defaultMessage, Object... args) {
|
||||
return messageSource.getMessage(code, args, defaultMessage, getCurrentLocale());
|
||||
}
|
||||
|
||||
// ========== 成功响应方法 ==========
|
||||
|
||||
public <T> Result<T> success() {
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
public <T> Result<T> success(T data) {
|
||||
return Result.success(data);
|
||||
}
|
||||
|
||||
// ========== 业务异常快捷方法 ==========
|
||||
|
||||
public BusinessException newBusinessException(String code, Object... args) {
|
||||
return new BusinessException(code, getMessage(code, args));
|
||||
}
|
||||
}
|
||||
@ -48,7 +48,7 @@ public class AuthenticationFilter extends OncePerRequestFilter {
|
||||
SecurityContextHolder.setAuthentication(initialize);
|
||||
filterChain.doFilter(request, response);
|
||||
} catch (BusinessException e) {
|
||||
response.setStatus(e.getCode());
|
||||
response.setStatus(200);
|
||||
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
|
||||
response.setCharacterEncoding("UTF-8");
|
||||
response.getWriter().write(new ObjectMapper().writeValueAsString(Result.failure(e)));
|
||||
|
||||
@ -1,31 +1,38 @@
|
||||
package day.gitlab.dolphin.common.security.annotation;
|
||||
|
||||
import day.gitlab.dolphin.common.core.i18n.MessagesHelper;
|
||||
import day.gitlab.dolphin.common.security.Authentication;
|
||||
import day.gitlab.dolphin.common.security.SecurityContextHolder;
|
||||
import day.gitlab.dolphin.common.security.exception.NotAuthorityException;
|
||||
import day.gitlab.dolphin.common.security.exception.NotLoginException;
|
||||
import day.gitlab.dolphin.common.security.constants.Exceptions;
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.annotation.Before;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Aspect
|
||||
@Component
|
||||
public class AuthorityCheckAspect {
|
||||
|
||||
private final MessagesHelper messagesHelper;
|
||||
|
||||
public AuthorityCheckAspect(MessagesHelper messagesHelper) {
|
||||
this.messagesHelper = messagesHelper;
|
||||
}
|
||||
|
||||
@Before("@annotation(authorityCheck)")
|
||||
public void check(JoinPoint joinPoint, AuthorityCheck authorityCheck) {
|
||||
Authentication authentication = SecurityContextHolder.getAuthentication();
|
||||
if (authentication == null) {
|
||||
throw new NotLoginException();
|
||||
throw messagesHelper.newBusinessException(Exceptions.NOT_LOGIN);
|
||||
}
|
||||
|
||||
// AuthorityCheck的type如果是AND,输出1
|
||||
if (authorityCheck.type() == AuthorityType.AND) {
|
||||
if (!authentication.hasAllAuthorities(authorityCheck.value())) {
|
||||
throw new NotAuthorityException(authorityCheck.value());
|
||||
throw messagesHelper.newBusinessException(Exceptions.NOT_AUTHORITY);
|
||||
}
|
||||
} else if (authorityCheck.type() == AuthorityType.OR) {
|
||||
if (!authentication.hasAnyAuthorities(authorityCheck.value())) {
|
||||
throw new NotAuthorityException(authorityCheck.value());
|
||||
throw messagesHelper.newBusinessException(Exceptions.NOT_AUTHORITY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,12 @@
|
||||
package day.gitlab.dolphin.common.security.constants;
|
||||
|
||||
public class Exceptions {
|
||||
|
||||
public static final String NOT_LOGIN = "00010001";
|
||||
|
||||
public static final String TOKEN_INVALID = "00010002";
|
||||
|
||||
public static final String TOKEN_EXPIRED = "00010003";
|
||||
|
||||
public static final String NOT_AUTHORITY = "00010004";
|
||||
}
|
||||
@ -1,12 +0,0 @@
|
||||
package day.gitlab.dolphin.common.security.exception;
|
||||
|
||||
import day.gitlab.dolphin.common.core.exception.BusinessException;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public class AuthenticationException extends BusinessException {
|
||||
|
||||
public AuthenticationException(int code, String message) {
|
||||
super(code, message);
|
||||
}
|
||||
}
|
||||
@ -1,14 +0,0 @@
|
||||
package day.gitlab.dolphin.common.security.exception;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public class InvalidTokenException extends AuthenticationException {
|
||||
|
||||
private final String token;
|
||||
|
||||
public InvalidTokenException(String token) {
|
||||
super(401, "Unauthorized: Invalid token");
|
||||
this.token = token;
|
||||
}
|
||||
}
|
||||
@ -1,14 +0,0 @@
|
||||
package day.gitlab.dolphin.common.security.exception;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public class NotAuthorityException extends AuthenticationException {
|
||||
|
||||
private final String[] userAuthorities;
|
||||
|
||||
public NotAuthorityException(String[] userAuthorities) {
|
||||
super(403, "Forbidden: Insufficient permissions");
|
||||
this.userAuthorities = userAuthorities;
|
||||
}
|
||||
}
|
||||
@ -1,8 +0,0 @@
|
||||
package day.gitlab.dolphin.common.security.exception;
|
||||
|
||||
public class NotLoginException extends AuthenticationException{
|
||||
|
||||
public NotLoginException() {
|
||||
super(401, "Unauthorized");
|
||||
}
|
||||
}
|
||||
@ -1,20 +0,0 @@
|
||||
package day.gitlab.dolphin.common.security.exception;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@Getter
|
||||
public class TokenExpiredException extends AuthenticationException {
|
||||
|
||||
private final String token;
|
||||
|
||||
private final Date expiration;
|
||||
|
||||
public TokenExpiredException(String token, Date expiration) {
|
||||
super(401, "Unauthorized: Token expired");
|
||||
this.token = token;
|
||||
this.expiration = expiration;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,14 +1,13 @@
|
||||
package day.gitlab.dolphin.common.security.jwt;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import day.gitlab.dolphin.common.core.i18n.MessagesHelper;
|
||||
import day.gitlab.dolphin.common.security.Authentication;
|
||||
import day.gitlab.dolphin.common.security.AuthenticationInitialize;
|
||||
import day.gitlab.dolphin.common.security.AuthenticationProvider;
|
||||
import day.gitlab.dolphin.common.security.UserPrincipal;
|
||||
import day.gitlab.dolphin.common.security.config.SecurityConfig;
|
||||
import day.gitlab.dolphin.common.security.exception.InvalidTokenException;
|
||||
import day.gitlab.dolphin.common.security.exception.NotLoginException;
|
||||
import day.gitlab.dolphin.common.security.exception.TokenExpiredException;
|
||||
import day.gitlab.dolphin.common.security.constants.Exceptions;
|
||||
import io.jsonwebtoken.Claims;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
@ -29,12 +28,16 @@ public class JwtAuthenticationInitialize implements AuthenticationInitialize {
|
||||
|
||||
private final AuthenticationProvider authenticationProvider;
|
||||
|
||||
private final MessagesHelper messagesHelper;
|
||||
|
||||
public JwtAuthenticationInitialize(SecurityConfig securityConfig,
|
||||
StringRedisTemplate stringRedisTemplate,
|
||||
AuthenticationProvider authenticationProvider) {
|
||||
AuthenticationProvider authenticationProvider,
|
||||
MessagesHelper messagesHelper) {
|
||||
this.securityConfig = securityConfig;
|
||||
this.stringRedisTemplate = stringRedisTemplate;
|
||||
this.authenticationProvider = authenticationProvider;
|
||||
this.messagesHelper = messagesHelper;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -44,7 +47,7 @@ public class JwtAuthenticationInitialize implements AuthenticationInitialize {
|
||||
// 1、获取Token
|
||||
String token = jwt.getTokenFromRequest(request);
|
||||
if (token == null) {
|
||||
throw new NotLoginException();
|
||||
throw messagesHelper.newBusinessException(Exceptions.NOT_LOGIN);
|
||||
}
|
||||
// 2、解析Token,获取用户ID
|
||||
String userId;
|
||||
@ -56,11 +59,11 @@ public class JwtAuthenticationInitialize implements AuthenticationInitialize {
|
||||
Objects.requireNonNull(userId);
|
||||
Objects.requireNonNull(expiration);
|
||||
} catch (Exception e) {
|
||||
throw new InvalidTokenException(token);
|
||||
throw messagesHelper.newBusinessException(Exceptions.TOKEN_INVALID);
|
||||
}
|
||||
// 3、判断是否过期
|
||||
if (expiration.before(new Date())) {
|
||||
throw new TokenExpiredException(token, expiration);
|
||||
throw messagesHelper.newBusinessException(Exceptions.TOKEN_EXPIRED);
|
||||
}
|
||||
// 4、从Redis或数据库中加载用户信息
|
||||
UserPrincipal userPrincipal;
|
||||
@ -83,7 +86,7 @@ public class JwtAuthenticationInitialize implements AuthenticationInitialize {
|
||||
userAuthorities = list.stream().map(Object::toString).collect(Collectors.toList());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new InvalidTokenException(token);
|
||||
throw messagesHelper.newBusinessException(Exceptions.TOKEN_INVALID);
|
||||
}
|
||||
|
||||
return new Authentication(userPrincipal, userAuthorities);
|
||||
|
||||
Reference in New Issue
Block a user