first
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
package com.aida.buyer.common.constants;
|
||||
|
||||
public class BuyerConstants {
|
||||
|
||||
public static final Integer FAVORITE_STATUS_ACTIVE = 1;
|
||||
public static final Integer FAVORITE_STATUS_REMOVED = 0;
|
||||
|
||||
public static final Integer CART_STATUS_ACTIVE = 1;
|
||||
public static final Integer CART_STATUS_REMOVED = 0;
|
||||
|
||||
public static final Integer ADDRESS_STATUS_DEFAULT = 1;
|
||||
public static final Integer ADDRESS_STATUS_NORMAL = 0;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.aida.buyer.common.constants;
|
||||
|
||||
public class CommonConstants {
|
||||
|
||||
public static final int MINIO_PATH_TIMEOUT = 7 * 24 * 60 * 60; // minio图片临时访问地址 7 天过期(second)
|
||||
|
||||
public static final int TOKEN_EXPIRE_TIME = 7 * 24; // token 7 天过期(Hour)
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.aida.buyer.common.constants;
|
||||
|
||||
public class MinioFileConstants {
|
||||
|
||||
public static final String PATH_SEPARATOR = "/";
|
||||
|
||||
public static final String FILE_TYPE_PNG = "png";
|
||||
public static final String FILE_TYPE_JPG = "jpg";
|
||||
public static final String FILE_TYPE_JPEG = "jpeg";
|
||||
public static final String FILE_TYPE_GIF = "gif";
|
||||
public static final String FILE_TYPE_WEBP = "webp";
|
||||
public static final String FILE_TYPE_PDF = "pdf";
|
||||
|
||||
public static final String CONTENT_TYPE_PNG = "image/png";
|
||||
public static final String CONTENT_TYPE_JPG = "image/jpeg";
|
||||
public static final String CONTENT_TYPE_GIF = "image/gif";
|
||||
public static final String CONTENT_TYPE_WEBP = "image/webp";
|
||||
public static final String CONTENT_TYPE_PDF = "application/pdf";
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.aida.buyer.common.constants;
|
||||
|
||||
public class StatusConstants {
|
||||
|
||||
public static final Integer ENABLE = 1;
|
||||
public static final Integer DISABLE = 0;
|
||||
public static final Integer DELETE = 1;
|
||||
public static final Integer NOT_DELETE = 0;
|
||||
public static final Integer AUDIT_PENDING = 0;
|
||||
public static final Integer AUDIT_APPROVED = 1;
|
||||
public static final Integer AUDIT_REJECTED = 2;
|
||||
}
|
||||
54
src/main/java/com/aida/buyer/common/context/UserContext.java
Normal file
54
src/main/java/com/aida/buyer/common/context/UserContext.java
Normal file
@@ -0,0 +1,54 @@
|
||||
package com.aida.buyer.common.context;
|
||||
|
||||
import com.aida.buyer.common.exception.UnauthorizedException;
|
||||
import com.aida.buyer.model.vo.AuthPrincipalVo;
|
||||
|
||||
public class UserContext {
|
||||
private static final ThreadLocal<AuthPrincipalVo> userHolder = new ThreadLocal<>();
|
||||
private static final ThreadLocal<Boolean> optionalAuth = ThreadLocal.withInitial(() -> false);
|
||||
|
||||
public static void setUserHolder(AuthPrincipalVo authPrincipalVo) {
|
||||
userHolder.set(authPrincipalVo);
|
||||
}
|
||||
|
||||
public static void setOptionalAuth(boolean value) {
|
||||
optionalAuth.set(value);
|
||||
}
|
||||
|
||||
public static AuthPrincipalVo getUserHolder() {
|
||||
AuthPrincipalVo holder = userHolder.get();
|
||||
if (holder == null) {
|
||||
if (optionalAuth.get()) {
|
||||
return null;
|
||||
}
|
||||
throw new UnauthorizedException("Gateway token verification failed");
|
||||
}
|
||||
if (!"AIDA".equals(holder.getSource())) {
|
||||
throw new UnauthorizedException("Gateway token verification failed");
|
||||
}
|
||||
return holder;
|
||||
}
|
||||
|
||||
public static void delete() {
|
||||
userHolder.remove();
|
||||
optionalAuth.remove();
|
||||
}
|
||||
|
||||
public static Long getUserId() {
|
||||
return getUserHolder() == null ? null : getUserHolder().getId();
|
||||
}
|
||||
|
||||
public static Long getBuyerId() {
|
||||
AuthPrincipalVo holder = userHolder.get();
|
||||
if (holder == null) {
|
||||
if (optionalAuth.get()) {
|
||||
return null;
|
||||
}
|
||||
throw new UnauthorizedException("Gateway token verification failed");
|
||||
}
|
||||
if (!"BUYER".equals(holder.getSource())) {
|
||||
throw new UnauthorizedException("Gateway token verification failed");
|
||||
}
|
||||
return holder.getId();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.aida.buyer.common.exception;
|
||||
|
||||
import com.aida.buyer.common.result.ResultEnum;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public class BusinessException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final Integer code;
|
||||
private final String msg;
|
||||
|
||||
public BusinessException(ResultEnum resultEnum) {
|
||||
super(resultEnum.getMessage());
|
||||
this.code = resultEnum.getCode();
|
||||
this.msg = resultEnum.getMessage();
|
||||
}
|
||||
|
||||
public BusinessException(Integer code, String msg) {
|
||||
super(msg);
|
||||
this.code = code;
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
public BusinessException(String message) {
|
||||
super(message);
|
||||
this.code = -1;
|
||||
this.msg = message;
|
||||
}
|
||||
|
||||
public BusinessException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
this.code = -1;
|
||||
this.msg = message;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.aida.buyer.common.exception;
|
||||
|
||||
import com.aida.buyer.common.result.Response;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.validation.BindException;
|
||||
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
|
||||
@Slf4j
|
||||
@RestControllerAdvice
|
||||
public class GlobalExceptionHandler {
|
||||
|
||||
@ExceptionHandler(UnauthorizedException.class)
|
||||
public ResponseEntity<Response<Void>> handleUnauthorizedException(UnauthorizedException e) {
|
||||
log.error("Unauthorized: {}", e.getMessage());
|
||||
return new ResponseEntity<>(
|
||||
Response.fail(401, e.getMessage()),
|
||||
HttpStatus.UNAUTHORIZED
|
||||
);
|
||||
}
|
||||
|
||||
@ExceptionHandler(BusinessException.class)
|
||||
public Response<Void> handleBusinessException(BusinessException e) {
|
||||
return Response.fail(e.getCode(), e.getMsg());
|
||||
}
|
||||
|
||||
@ExceptionHandler(MethodArgumentNotValidException.class)
|
||||
public Response<Void> handleValidationException(MethodArgumentNotValidException e) {
|
||||
String message = e.getBindingResult().getFieldErrors().stream()
|
||||
.map(error -> error.getField() + ": " + error.getDefaultMessage())
|
||||
.findFirst()
|
||||
.orElse("validation error");
|
||||
return Response.fail(-2, message);
|
||||
}
|
||||
|
||||
@ExceptionHandler(BindException.class)
|
||||
public Response<Void> handleBindException(BindException e) {
|
||||
String message = e.getBindingResult().getFieldErrors().stream()
|
||||
.map(error -> error.getField() + ": " + error.getDefaultMessage())
|
||||
.findFirst()
|
||||
.orElse("bind error");
|
||||
return Response.fail(-2, message);
|
||||
}
|
||||
|
||||
@ExceptionHandler(Exception.class)
|
||||
public Response<Void> handleException(Exception e) {
|
||||
log.error("system error: ", e);
|
||||
return Response.error("系统繁忙");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.aida.buyer.common.exception;
|
||||
|
||||
public class UnauthorizedException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public UnauthorizedException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public UnauthorizedException() {
|
||||
super("Gateway token verification failed");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package com.aida.buyer.common.interceptor;
|
||||
|
||||
import com.aida.buyer.common.context.UserContext;
|
||||
import com.aida.buyer.config.GatewayAuthProperties;
|
||||
import com.aida.buyer.model.vo.AuthPrincipalVo;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class UserContextInterceptor implements HandlerInterceptor {
|
||||
|
||||
private static final String USER_ID_HEADER = "X-User-Id";
|
||||
private static final String USER_INFO_HEADER = "X-User-Info";
|
||||
|
||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||
private final AntPathMatcher pathMatcher = new AntPathMatcher();
|
||||
private final List<String> localOptionalAuthPaths;
|
||||
|
||||
public UserContextInterceptor(GatewayAuthProperties gatewayAuthProperties) {
|
||||
this.localOptionalAuthPaths = gatewayAuthProperties.getOptionalAuthPaths().stream()
|
||||
.map(this::toLocalPath)
|
||||
.collect(Collectors.toList());
|
||||
log.info("Local optional auth paths: {}", localOptionalAuthPaths);
|
||||
}
|
||||
|
||||
private String toLocalPath(String gatewayPath) {
|
||||
if (gatewayPath == null) {
|
||||
return gatewayPath;
|
||||
}
|
||||
if (gatewayPath.startsWith("/buyer")) {
|
||||
String local = gatewayPath.substring("/buyer".length());
|
||||
return local.isEmpty() ? "/" : local;
|
||||
}
|
||||
return gatewayPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
|
||||
String userInfoJson = request.getHeader(USER_INFO_HEADER);
|
||||
if (userInfoJson != null && !userInfoJson.isBlank()) {
|
||||
try {
|
||||
AuthPrincipalVo principal = objectMapper.readValue(userInfoJson, AuthPrincipalVo.class);
|
||||
UserContext.setUserHolder(principal);
|
||||
} catch (Exception e) {
|
||||
log.warn("Failed to parse X-User-Info header: {}", e.getMessage());
|
||||
}
|
||||
} else if (isOptionalAuthPath(request.getRequestURI())) {
|
||||
UserContext.setOptionalAuth(true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean isOptionalAuthPath(String requestUri) {
|
||||
if (localOptionalAuthPaths == null || localOptionalAuthPaths.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
for (String pattern : localOptionalAuthPaths) {
|
||||
if (pathMatcher.match(pattern, requestUri)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
|
||||
Object handler, Exception ex) {
|
||||
UserContext.delete();
|
||||
}
|
||||
}
|
||||
29
src/main/java/com/aida/buyer/common/result/PageResponse.java
Normal file
29
src/main/java/com/aida/buyer/common/result/PageResponse.java
Normal file
@@ -0,0 +1,29 @@
|
||||
package com.aida.buyer.common.result;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class PageResponse<T> implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Long page;
|
||||
private Long size;
|
||||
private Long pages;
|
||||
private Long total;
|
||||
private List<T> content;
|
||||
|
||||
public static <T> PageResponse<T> success(IPage<T> page) {
|
||||
PageResponse<T> response = new PageResponse<>();
|
||||
response.setPage(page.getCurrent());
|
||||
response.setSize(page.getSize());
|
||||
response.setPages(page.getPages());
|
||||
response.setTotal(page.getTotal());
|
||||
response.setContent(page.getRecords());
|
||||
return response;
|
||||
}
|
||||
}
|
||||
48
src/main/java/com/aida/buyer/common/result/Response.java
Normal file
48
src/main/java/com/aida/buyer/common/result/Response.java
Normal file
@@ -0,0 +1,48 @@
|
||||
package com.aida.buyer.common.result;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
public class Response<T> implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Integer errCode;
|
||||
private String errMsg;
|
||||
private T data;
|
||||
|
||||
public static <T> Response<T> success() {
|
||||
return success(null);
|
||||
}
|
||||
|
||||
public static <T> Response<T> success(T data) {
|
||||
Response<T> response = new Response<>();
|
||||
response.setErrCode(ResultEnum.SUCCESS.getCode());
|
||||
response.setErrMsg(ResultEnum.SUCCESS.getMessage());
|
||||
response.setData(data);
|
||||
return response;
|
||||
}
|
||||
|
||||
public static <T> Response<T> fail(String errMsg) {
|
||||
Response<T> response = new Response<>();
|
||||
response.setErrCode(ResultEnum.FAIL.getCode());
|
||||
response.setErrMsg(errMsg);
|
||||
return response;
|
||||
}
|
||||
|
||||
public static <T> Response<T> fail(Integer errCode, String errMsg) {
|
||||
Response<T> response = new Response<>();
|
||||
response.setErrCode(errCode);
|
||||
response.setErrMsg(errMsg);
|
||||
return response;
|
||||
}
|
||||
|
||||
public static <T> Response<T> error(String errMsg) {
|
||||
Response<T> response = new Response<>();
|
||||
response.setErrCode(ResultEnum.FAIL.getCode());
|
||||
response.setErrMsg(errMsg);
|
||||
return response;
|
||||
}
|
||||
}
|
||||
19
src/main/java/com/aida/buyer/common/result/ResultEnum.java
Normal file
19
src/main/java/com/aida/buyer/common/result/ResultEnum.java
Normal file
@@ -0,0 +1,19 @@
|
||||
package com.aida.buyer.common.result;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum ResultEnum {
|
||||
|
||||
SUCCESS(0, "success"),
|
||||
FAIL(-1, "fail"),
|
||||
PARAMETER_ERROR(-2, "parameter error"),
|
||||
NO_LOGIN(-100, "no login"),
|
||||
NO_PERMISSION(-200, "no permission"),
|
||||
ACCOUNT_LOCK(-300, "account locked");
|
||||
|
||||
private final Integer code;
|
||||
private final String message;
|
||||
}
|
||||
Reference in New Issue
Block a user