refactor: replace BizException with ResponseStatusException

This commit is contained in:
siujamo committed 2026-08-06 17:20:36 +08:00
1 parent 4aafbaeadc
commit b131738dda
16 files changed
+97 -93

No files matched your search

@@ -3,6 +3,8 @@ package com.onixbyte.deltaforceguide.config;
import com.auth0.jwt.JWT; import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier; import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.algorithms.Algorithm;
import com.onixbyte.deltaforceguide.exeption.ForbiddenException;
import com.onixbyte.deltaforceguide.exeption.UnauthorisedException;
import com.onixbyte.deltaforceguide.filter.TokenAuthenticationFilter; import com.onixbyte.deltaforceguide.filter.TokenAuthenticationFilter;
import com.onixbyte.deltaforceguide.properties.CookieProperties; import com.onixbyte.deltaforceguide.properties.CookieProperties;
import com.onixbyte.deltaforceguide.properties.TokenProperties; import com.onixbyte.deltaforceguide.properties.TokenProperties;
@@ -12,7 +14,6 @@ import org.slf4j.LoggerFactory;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.ProviderManager; import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
@@ -22,7 +23,6 @@ import org.springframework.security.config.annotation.web.configurers.AbstractHt
import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;
import com.onixbyte.deltaforceguide.exeption.BizException;
import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.ExceptionTranslationFilter; import org.springframework.security.web.access.ExceptionTranslationFilter;
import org.springframework.web.cors.CorsConfigurationSource; import org.springframework.web.cors.CorsConfigurationSource;
@@ -43,7 +43,7 @@ public class SecurityConfig {
/** /**
* Configures the HTTP security filter chain including endpoint authorisation and JWT filter. * Configures the HTTP security filter chain including endpoint authorisation and JWT filter.
* *
* @param http the HTTP security builder * @param httpSecurity the HTTP security builder
* @return the configured security filter chain * @return the configured security filter chain
*/ */
@Bean @Bean
@@ -64,11 +64,11 @@ public class SecurityConfig {
.exceptionHandling(customiser -> customiser .exceptionHandling(customiser -> customiser
.authenticationEntryPoint((request, response, authException) -> { .authenticationEntryPoint((request, response, authException) -> {
log.error("Unauthenticated request: {}", request, authException); log.error("Unauthenticated request: {}", request, authException);
throw new BizException(HttpStatus.UNAUTHORIZED, "请先登录"); throw new UnauthorisedException("请先登录");
}) })
.accessDeniedHandler((request, response, accessDeniedException) -> { .accessDeniedHandler((request, response, accessDeniedException) -> {
log.error("Denied request: {}", request, accessDeniedException); log.error("Denied request: {}", request, accessDeniedException);
throw new BizException(HttpStatus.FORBIDDEN, "权限不足"); throw new ForbiddenException("权限不足");
}) })
) )
.addFilterAfter(tokenAuthenticationFilter, ExceptionTranslationFilter.class) .addFilterAfter(tokenAuthenticationFilter, ExceptionTranslationFilter.class)
@@ -77,6 +77,7 @@ public class SecurityConfig {
/** /**
* Provides the BCrypt password encoder for credential hashing. * Provides the BCrypt password encoder for credential hashing.
*
* @return the BCrypt password encoder * @return the BCrypt password encoder
*/ */
@Bean @Bean
@@ -1,7 +1,6 @@
package com.onixbyte.deltaforceguide.controller; package com.onixbyte.deltaforceguide.controller;
import com.onixbyte.deltaforceguide.domain.dto.ErrorResponse; import com.onixbyte.deltaforceguide.domain.dto.ErrorResponse;
import com.onixbyte.deltaforceguide.exeption.BizException;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.security.access.AccessDeniedException; import org.springframework.security.access.AccessDeniedException;
@@ -9,6 +8,7 @@ import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.server.ResponseStatusException;
/** /**
* Global exception handler that translates exceptions into standard error responses. * Global exception handler that translates exceptions into standard error responses.
@@ -17,12 +17,11 @@ import org.springframework.web.bind.annotation.RestControllerAdvice;
*/ */
@RestControllerAdvice @RestControllerAdvice
public class GlobalExceptionHandler { public class GlobalExceptionHandler {
@ExceptionHandler(ResponseStatusException.class)
@ExceptionHandler(BizException.class) public ResponseEntity<ErrorResponse> handleResponseStatusException(ResponseStatusException exception) {
public ResponseEntity<ErrorResponse> handleBizException(BizException exception) { var status = exception.getStatusCode();
var status = exception.getStatus();
return ResponseEntity.status(status) return ResponseEntity.status(status)
.body(new ErrorResponse(exception.getMessage())); .body(new ErrorResponse(exception.getReason()));
} }
@ExceptionHandler(AuthenticationException.class) @ExceptionHandler(AuthenticationException.class)
@@ -0,0 +1,11 @@
package com.onixbyte.deltaforceguide.exeption;
import org.springframework.http.HttpStatus;
import org.springframework.web.server.ResponseStatusException;
public class BadRequestException extends ResponseStatusException {
public BadRequestException(String reason) {
super(HttpStatus.BAD_REQUEST, reason);
}
}
@@ -1,40 +0,0 @@
package com.onixbyte.deltaforceguide.exeption;
import org.springframework.http.HttpStatus;
/**
* Custom runtime exception that carries an HTTP status code for API error responses.
*
* @author zihluwang
*/
public class BizException extends RuntimeException {
/**
* The HTTP status code associated with this business exception.
* <p>
* This status code indicates the appropriate HTTP response status that should be returned to
* clients when this exception occurs. It enables consistent error handling across
* REST API endpoints.
*/
private final HttpStatus status;
public BizException(String message) {
super(message);
this.status = HttpStatus.INTERNAL_SERVER_ERROR;
}
public BizException(HttpStatus status, String message) {
super(message);
this.status = status;
}
/**
* Returns the HTTP status code associated with this business exception.
*
* @return the HTTP status code that should be used in the error response
*/
public HttpStatus getStatus() {
return status;
}
}
@@ -0,0 +1,11 @@
package com.onixbyte.deltaforceguide.exeption;
import org.springframework.http.HttpStatus;
import org.springframework.web.server.ResponseStatusException;
public class ForbiddenException extends ResponseStatusException {
public ForbiddenException(String reason) {
super(HttpStatus.FORBIDDEN, reason);
}
}
@@ -0,0 +1,11 @@
package com.onixbyte.deltaforceguide.exeption;
import org.springframework.http.HttpStatus;
import org.springframework.web.server.ResponseStatusException;
public class InternalServerErrorException extends ResponseStatusException {
public InternalServerErrorException(String reason) {
super(HttpStatus.INTERNAL_SERVER_ERROR, reason);
}
}
@@ -0,0 +1,11 @@
package com.onixbyte.deltaforceguide.exeption;
import org.springframework.http.HttpStatus;
import org.springframework.web.server.ResponseStatusException;
public class NotFoundException extends ResponseStatusException {
public NotFoundException(String reason) {
super(HttpStatus.NOT_FOUND, reason);
}
}
@@ -0,0 +1,11 @@
package com.onixbyte.deltaforceguide.exeption;
import org.springframework.http.HttpStatus;
import org.springframework.web.server.ResponseStatusException;
public class UnauthorisedException extends ResponseStatusException {
public UnauthorisedException(String reason) {
super(HttpStatus.UNAUTHORIZED, reason);
}
}
@@ -2,7 +2,7 @@ package com.onixbyte.deltaforceguide.filter;
import com.auth0.jwt.exceptions.JWTVerificationException; import com.auth0.jwt.exceptions.JWTVerificationException;
import com.onixbyte.deltaforceguide.client.TokenClient; import com.onixbyte.deltaforceguide.client.TokenClient;
import com.onixbyte.deltaforceguide.exeption.BizException; import com.onixbyte.deltaforceguide.exeption.UnauthorisedException;
import com.onixbyte.deltaforceguide.manager.UserManager; import com.onixbyte.deltaforceguide.manager.UserManager;
import com.onixbyte.deltaforceguide.manager.UserRoleManager; import com.onixbyte.deltaforceguide.manager.UserRoleManager;
import com.onixbyte.deltaforceguide.security.authentication.UsernamePasswordAuthentication; import com.onixbyte.deltaforceguide.security.authentication.UsernamePasswordAuthentication;
@@ -16,11 +16,11 @@ import org.jspecify.annotations.NonNull;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter; import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.servlet.HandlerExceptionResolver; import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.util.WebUtils; import org.springframework.web.util.WebUtils;
@@ -89,7 +89,7 @@ public class TokenAuthenticationFilter extends OncePerRequestFilter {
var userWrapper = userManager.findByUsername(username); var userWrapper = userManager.findByUsername(username);
if (userWrapper.isEmpty()) { if (userWrapper.isEmpty()) {
throw new BizException(HttpStatus.UNAUTHORIZED, "登录已过期,请重新登录"); throw new UnauthorisedException("登录已过期,请重新登录");
} }
var user = userWrapper.get(); var user = userWrapper.get();
@@ -110,8 +110,8 @@ public class TokenAuthenticationFilter extends OncePerRequestFilter {
} catch (JWTVerificationException e) { } catch (JWTVerificationException e) {
log.error("JWT verification failed.", e); log.error("JWT verification failed.", e);
handlerExceptionResolver.resolveException(request, response, null, handlerExceptionResolver.resolveException(request, response, null,
new BizException(HttpStatus.UNAUTHORIZED, "登录已过期,请重新登录")); new UnauthorisedException("登录已过期,请重新登录"));
} catch (BizException e) { } catch (ResponseStatusException e) {
handlerExceptionResolver.resolveException(request, response, null, e); handlerExceptionResolver.resolveException(request, response, null, e);
} }
} }
@@ -1,7 +1,8 @@
package com.onixbyte.deltaforceguide.interceptor; package com.onixbyte.deltaforceguide.interceptor;
import com.onixbyte.crypto.util.CryptoUtil; import com.onixbyte.crypto.util.CryptoUtil;
import com.onixbyte.deltaforceguide.exeption.BizException; import com.onixbyte.deltaforceguide.exeption.InternalServerErrorException;
import com.onixbyte.deltaforceguide.exeption.UnauthorisedException;
import com.onixbyte.deltaforceguide.manager.WebhookManager; import com.onixbyte.deltaforceguide.manager.WebhookManager;
import com.onixbyte.deltaforceguide.shared.GitHubWebhookHeader; import com.onixbyte.deltaforceguide.shared.GitHubWebhookHeader;
import com.onixbyte.deltaforceguide.wrapper.RepeatedlyReadRequestWrapper; import com.onixbyte.deltaforceguide.wrapper.RepeatedlyReadRequestWrapper;
@@ -10,7 +11,6 @@ import jakarta.servlet.http.HttpServletResponse;
import org.jspecify.annotations.NonNull; import org.jspecify.annotations.NonNull;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.HandlerInterceptor;
@@ -44,7 +44,7 @@ public class GitHubWebhookInterceptor implements HandlerInterceptor {
@NonNull Object handler @NonNull Object handler
) { ) {
if (!(request instanceof RepeatedlyReadRequestWrapper req)) { if (!(request instanceof RepeatedlyReadRequestWrapper req)) {
throw new BizException(HttpStatus.INTERNAL_SERVER_ERROR, throw new InternalServerErrorException(
"Request body is not readable"); "Request body is not readable");
} }
@@ -58,7 +58,7 @@ public class GitHubWebhookInterceptor implements HandlerInterceptor {
if (signatureHeader == null || signatureHeader.isBlank()) { if (signatureHeader == null || signatureHeader.isBlank()) {
log.warn("Missing {} header from ip={}", log.warn("Missing {} header from ip={}",
GitHubWebhookHeader.SIGNATURE_256, request.getRemoteAddr()); GitHubWebhookHeader.SIGNATURE_256, request.getRemoteAddr());
throw new BizException(HttpStatus.UNAUTHORIZED, throw new UnauthorisedException(
"Missing webhook signature header"); "Missing webhook signature header");
} }
@@ -70,13 +70,13 @@ public class GitHubWebhookInterceptor implements HandlerInterceptor {
computed.getBytes(StandardCharsets.UTF_8), computed.getBytes(StandardCharsets.UTF_8),
signatureHeader.getBytes(StandardCharsets.UTF_8))) { signatureHeader.getBytes(StandardCharsets.UTF_8))) {
log.warn("Invalid webhook signature from ip={}", request.getRemoteAddr()); log.warn("Invalid webhook signature from ip={}", request.getRemoteAddr());
throw new BizException(HttpStatus.UNAUTHORIZED, "Invalid webhook signature"); throw new UnauthorisedException("Invalid webhook signature");
} }
return true; return true;
} catch (NoSuchAlgorithmException | InvalidKeyException e) { } catch (NoSuchAlgorithmException | InvalidKeyException e) {
log.error("Failed to compute HMAC-SHA256", e); log.error("Failed to compute HMAC-SHA256", e);
throw new BizException(HttpStatus.INTERNAL_SERVER_ERROR, throw new InternalServerErrorException(
"Failed to verify webhook signature"); "Failed to verify webhook signature");
} }
} }
@@ -4,11 +4,10 @@ import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategies; import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.onixbyte.deltaforceguide.domain.dto.DailyPasswordResponse; import com.onixbyte.deltaforceguide.domain.dto.DailyPasswordResponse;
import com.onixbyte.deltaforceguide.exeption.BizException; import com.onixbyte.deltaforceguide.exeption.InternalServerErrorException;
import com.onixbyte.deltaforceguide.shared.JacksonModules; import com.onixbyte.deltaforceguide.shared.JacksonModules;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.web.client.RestClient; import org.springframework.web.client.RestClient;
@@ -76,7 +75,7 @@ public class DailyPasswordManager {
.body(DailyPasswordResponse.class); .body(DailyPasswordResponse.class);
if (Objects.isNull(response)) { if (Objects.isNull(response)) {
throw new BizException(HttpStatus.INTERNAL_SERVER_ERROR, "暂无每日密码数据。"); throw new InternalServerErrorException("暂无每日密码数据。");
} }
redisTemplate.opsForValue().set(key, response, Duration.ofDays(1L)); redisTemplate.opsForValue().set(key, response, Duration.ofDays(1L));
@@ -1,7 +1,8 @@
package com.onixbyte.deltaforceguide.security.provider; package com.onixbyte.deltaforceguide.security.provider;
import com.onixbyte.deltaforceguide.domain.entity.UserCredential; import com.onixbyte.deltaforceguide.domain.entity.UserCredential;
import com.onixbyte.deltaforceguide.exeption.BizException; import com.onixbyte.deltaforceguide.exeption.InternalServerErrorException;
import com.onixbyte.deltaforceguide.exeption.UnauthorisedException;
import com.onixbyte.deltaforceguide.manager.UserManager; import com.onixbyte.deltaforceguide.manager.UserManager;
import com.onixbyte.deltaforceguide.repository.UserCredentialRepository; import com.onixbyte.deltaforceguide.repository.UserCredentialRepository;
import com.onixbyte.deltaforceguide.security.authentication.UsernamePasswordAuthentication; import com.onixbyte.deltaforceguide.security.authentication.UsernamePasswordAuthentication;
@@ -10,7 +11,6 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example; import org.springframework.data.domain.Example;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.AuthenticationException;
@@ -50,14 +50,14 @@ public class UsernamePasswordAuthenticationProvider implements AuthenticationPro
@Override @Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException { public Authentication authenticate(Authentication authentication) throws AuthenticationException {
if (!(authentication instanceof UsernamePasswordAuthentication usernamePasswordAuthentication)) { if (!(authentication instanceof UsernamePasswordAuthentication usernamePasswordAuthentication)) {
throw new BizException(HttpStatus.INTERNAL_SERVER_ERROR, "用户认证失败,请稍后再试。"); throw new InternalServerErrorException("用户认证失败,请稍后再试。");
} }
// get userContainer from database // get userContainer from database
var userContainer = userManager.findByUsernameOrEmail(usernamePasswordAuthentication.getPrincipal()); var userContainer = userManager.findByUsernameOrEmail(usernamePasswordAuthentication.getPrincipal());
if (userContainer.isEmpty()) { if (userContainer.isEmpty()) {
log.error("User {} is trying to authenticate but no userContainer found.", usernamePasswordAuthentication.getPrincipal()); log.error("User {} is trying to authenticate but no userContainer found.", usernamePasswordAuthentication.getPrincipal());
throw new BizException(HttpStatus.UNAUTHORIZED, "用户名或密码错误。"); throw new UnauthorisedException("用户名或密码错误。");
} }
var user = userContainer.get(); var user = userContainer.get();
@@ -68,12 +68,12 @@ public class UsernamePasswordAuthenticationProvider implements AuthenticationPro
// get userContainer credentials from database // get userContainer credentials from database
var userCredentials = userCredentialRepository.findOne(Example.of(userCredentialExample)) var userCredentials = userCredentialRepository.findOne(Example.of(userCredentialExample))
.orElseThrow(() -> new BizException(HttpStatus.UNAUTHORIZED, "您还没有配置密码,请联系管理员处理。")); .orElseThrow(() -> new UnauthorisedException("您还没有配置密码,请联系管理员处理。"));
// validate password // validate password
if (!passwordEncoder.matches(usernamePasswordAuthentication.getCredentials(), userCredentials.getCredential())) { if (!passwordEncoder.matches(usernamePasswordAuthentication.getCredentials(), userCredentials.getCredential())) {
log.error("User {} is trying to authenticate but password is incorrect.", usernamePasswordAuthentication.getPrincipal()); log.error("User {} is trying to authenticate but password is incorrect.", usernamePasswordAuthentication.getPrincipal());
throw new BizException(HttpStatus.UNAUTHORIZED, "用户名或密码错误。"); throw new UnauthorisedException("用户名或密码错误。");
} }
// erase credentials // erase credentials
@@ -2,11 +2,10 @@ package com.onixbyte.deltaforceguide.service;
import com.onixbyte.deltaforceguide.domain.dto.LoginRequest; import com.onixbyte.deltaforceguide.domain.dto.LoginRequest;
import com.onixbyte.deltaforceguide.domain.entity.User; import com.onixbyte.deltaforceguide.domain.entity.User;
import com.onixbyte.deltaforceguide.exeption.BizException; import com.onixbyte.deltaforceguide.exeption.InternalServerErrorException;
import com.onixbyte.deltaforceguide.security.authentication.UsernamePasswordAuthentication; import com.onixbyte.deltaforceguide.security.authentication.UsernamePasswordAuthentication;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@@ -33,7 +32,6 @@ public class AuthService {
* *
* @param request the login credentials containing principle and password * @param request the login credentials containing principle and password
* @return the authenticated {@link User} * @return the authenticated {@link User}
* @throws BizException if authentication fails or the result type is unexpected
*/ */
public User login(LoginRequest request) { public User login(LoginRequest request) {
var _authentication = authenticationManager.authenticate(UsernamePasswordAuthentication var _authentication = authenticationManager.authenticate(UsernamePasswordAuthentication
@@ -43,7 +41,7 @@ public class AuthService {
"Type mismatched, required type is UsernamePasswordAuthentication but got {}.", "Type mismatched, required type is UsernamePasswordAuthentication but got {}.",
_authentication.getClass() _authentication.getClass()
); );
throw new BizException(HttpStatus.INTERNAL_SERVER_ERROR, "登录服务异常,请稍后再试。"); throw new InternalServerErrorException("登录服务异常,请稍后再试。");
} }
return authentication.getDetails(); return authentication.getDetails();
@@ -5,7 +5,7 @@ import com.onixbyte.deltaforceguide.domain.dto.FirearmResponse;
import com.onixbyte.deltaforceguide.domain.dto.PageResponse; import com.onixbyte.deltaforceguide.domain.dto.PageResponse;
import com.onixbyte.deltaforceguide.domain.entity.Firearm; import com.onixbyte.deltaforceguide.domain.entity.Firearm;
import com.onixbyte.deltaforceguide.enumeration.FirearmType; import com.onixbyte.deltaforceguide.enumeration.FirearmType;
import com.onixbyte.deltaforceguide.exeption.BizException; import com.onixbyte.deltaforceguide.exeption.NotFoundException;
import com.onixbyte.deltaforceguide.repository.FirearmRepository; import com.onixbyte.deltaforceguide.repository.FirearmRepository;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
@@ -84,7 +84,7 @@ public class FirearmService {
*/ */
public FirearmResponse updateFirearm(Long id, FirearmRequest request) { public FirearmResponse updateFirearm(Long id, FirearmRequest request) {
var firearm = firearmRepository.findById(id) var firearm = firearmRepository.findById(id)
.orElseThrow(() -> new BizException(HttpStatus.NOT_FOUND, "Firearm not found: " + id)); .orElseThrow(() -> new NotFoundException("Firearm not found: " + id));
firearm.setName(request.name()); firearm.setName(request.name());
firearm.setType(request.type()); firearm.setType(request.type());
@@ -105,7 +105,7 @@ public class FirearmService {
*/ */
public void deleteFirearm(Long id) { public void deleteFirearm(Long id) {
Firearm firearm = firearmRepository.findById(id) Firearm firearm = firearmRepository.findById(id)
.orElseThrow(() -> new BizException(HttpStatus.NOT_FOUND, "Firearm not found: " + id)); .orElseThrow(() -> new NotFoundException("Firearm not found: " + id));
firearmRepository.delete(firearm); firearmRepository.delete(firearm);
} }
} }
@@ -1,14 +1,10 @@
package com.onixbyte.deltaforceguide.service; package com.onixbyte.deltaforceguide.service;
import com.onixbyte.deltaforceguide.domain.dto.BuildSummaryResponse; import com.onixbyte.deltaforceguide.domain.dto.*;
import com.onixbyte.deltaforceguide.domain.dto.ChangePasswordRequest;
import com.onixbyte.deltaforceguide.domain.dto.PageResponse;
import com.onixbyte.deltaforceguide.domain.dto.UpdateProfileRequest;
import com.onixbyte.deltaforceguide.domain.dto.UserProfileResponse;
import com.onixbyte.deltaforceguide.domain.entity.User; import com.onixbyte.deltaforceguide.domain.entity.User;
import com.onixbyte.deltaforceguide.domain.entity.UserCredential; import com.onixbyte.deltaforceguide.domain.entity.UserCredential;
import com.onixbyte.deltaforceguide.domain.entity.UserRole; import com.onixbyte.deltaforceguide.domain.entity.UserRole;
import com.onixbyte.deltaforceguide.exeption.BizException; import com.onixbyte.deltaforceguide.exeption.BadRequestException;
import com.onixbyte.deltaforceguide.manager.UserCredentialManager; import com.onixbyte.deltaforceguide.manager.UserCredentialManager;
import com.onixbyte.deltaforceguide.manager.UserManager; import com.onixbyte.deltaforceguide.manager.UserManager;
import com.onixbyte.deltaforceguide.manager.UserRoleManager; import com.onixbyte.deltaforceguide.manager.UserRoleManager;
@@ -213,12 +209,11 @@ public class UserService {
* *
* @param user the authenticated user * @param user the authenticated user
* @param request the change password request containing old and new passwords * @param request the change password request containing old and new passwords
* @throws BizException if the old password is incorrect
*/ */
public void changePassword(User user, ChangePasswordRequest request) { public void changePassword(User user, ChangePasswordRequest request) {
var credential = userCredentialManager.findByUserIdAndProvider(user.getId(), CredentialProvider.LOCAL); var credential = userCredentialManager.findByUserIdAndProvider(user.getId(), CredentialProvider.LOCAL);
if (credential.isEmpty() || !passwordEncoder.matches(request.oldPassword(), credential.get().getCredential())) { if (credential.isEmpty() || !passwordEncoder.matches(request.oldPassword(), credential.get().getCredential())) {
throw new BizException(HttpStatus.BAD_REQUEST, "旧密码不正确。"); throw new BadRequestException("旧密码不正确。");
} }
var encoded = passwordEncoder.encode(request.newPassword()); var encoded = passwordEncoder.encode(request.newPassword());
upsertCredential(user.getId(), CredentialProvider.LOCAL, encoded); upsertCredential(user.getId(), CredentialProvider.LOCAL, encoded);
@@ -243,11 +238,10 @@ public class UserService {
* *
* @param userId the target user ID * @param userId the target user ID
* @param role the role to assign * @param role the role to assign
* @throws BizException if attempting to assign a protected role
*/ */
public void assignRole(Long userId, String role) { public void assignRole(Long userId, String role) {
if (!Role.ROLE_ADMIN.equals(role)) { if (!Role.ROLE_ADMIN.equals(role)) {
throw new BizException(HttpStatus.BAD_REQUEST, "只能通过API分配ROLE_ADMIN角色。"); throw new BadRequestException("只能通过API分配ROLE_ADMIN角色。");
} }
var user = ensureUserExists(userId); var user = ensureUserExists(userId);
if (userRoleManager.existsByUserIdAndRole(userId, role)) { if (userRoleManager.existsByUserIdAndRole(userId, role)) {
@@ -265,11 +259,10 @@ public class UserService {
* *
* @param userId the target user ID * @param userId the target user ID
* @param role the role to remove * @param role the role to remove
* @throws BizException if attempting to remove a protected role
*/ */
public void removeRole(Long userId, String role) { public void removeRole(Long userId, String role) {
if (!Role.ROLE_ADMIN.equals(role)) { if (!Role.ROLE_ADMIN.equals(role)) {
throw new BizException(HttpStatus.BAD_REQUEST, "只能通过API移除ROLE_ADMIN角色。"); throw new BadRequestException("只能通过API移除ROLE_ADMIN角色。");
} }
ensureUserExists(userId); ensureUserExists(userId);
userRoleManager.deleteByUserIdAndRole(userId, role); userRoleManager.deleteByUserIdAndRole(userId, role);
@@ -1,14 +1,13 @@
package com.onixbyte.deltaforceguide.service; package com.onixbyte.deltaforceguide.service;
import com.onixbyte.deltaforceguide.domain.dto.*; import com.onixbyte.deltaforceguide.domain.dto.*;
import com.onixbyte.deltaforceguide.exeption.BadRequestException;
import com.onixbyte.deltaforceguide.manager.ModificationManager; import com.onixbyte.deltaforceguide.manager.ModificationManager;
import com.onixbyte.deltaforceguide.manager.WebhookManager; import com.onixbyte.deltaforceguide.manager.WebhookManager;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import com.onixbyte.deltaforceguide.exeption.BizException;
import org.yaml.snakeyaml.Yaml; import org.yaml.snakeyaml.Yaml;
import java.time.Duration; import java.time.Duration;
@@ -111,7 +110,7 @@ public class WebhookService {
toLong(data.get("firearmId")), toLong(data.get("firearmId")),
(String) data.get("firearmName")); (String) data.get("firearmName"));
if (firearmId == null) { if (firearmId == null) {
throw new BizException(HttpStatus.BAD_REQUEST, throw new BadRequestException(
"YAML must contain firearmId or firearmName"); "YAML must contain firearmId or firearmName");
} }
String name = (String) data.get("name"); String name = (String) data.get("name");