2026-04-27 23:41:58 +08:00
|
|
|
package com.xuqm.im.controller;
|
|
|
|
|
|
|
|
|
|
import com.xuqm.common.exception.BusinessException;
|
|
|
|
|
import com.xuqm.common.model.ApiResponse;
|
2026-04-30 11:47:01 +08:00
|
|
|
import org.slf4j.Logger;
|
|
|
|
|
import org.slf4j.LoggerFactory;
|
2026-04-27 23:41:58 +08:00
|
|
|
import org.springframework.http.HttpStatus;
|
|
|
|
|
import org.springframework.http.ResponseEntity;
|
2026-04-29 12:33:25 +08:00
|
|
|
import org.springframework.http.converter.HttpMessageNotReadableException;
|
2026-05-09 14:53:42 +08:00
|
|
|
import org.springframework.security.authorization.AuthorizationDeniedException;
|
|
|
|
|
import org.springframework.security.core.Authentication;
|
|
|
|
|
import org.springframework.security.core.context.SecurityContextHolder;
|
2026-04-27 23:41:58 +08:00
|
|
|
import org.springframework.web.bind.MethodArgumentNotValidException;
|
|
|
|
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
|
|
|
|
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
|
|
|
|
|
|
|
|
|
@RestControllerAdvice
|
|
|
|
|
public class GlobalExceptionHandler {
|
|
|
|
|
|
2026-04-30 11:47:01 +08:00
|
|
|
private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
|
|
|
|
|
|
2026-04-27 23:41:58 +08:00
|
|
|
@ExceptionHandler(BusinessException.class)
|
|
|
|
|
public ResponseEntity<ApiResponse<Void>> handleBusiness(BusinessException e) {
|
|
|
|
|
return ResponseEntity.status(resolveStatus(e.getCode()))
|
|
|
|
|
.body(ApiResponse.error(e.getCode(), e.getMessage()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ExceptionHandler(MethodArgumentNotValidException.class)
|
|
|
|
|
public ResponseEntity<ApiResponse<Void>> handleValidation(MethodArgumentNotValidException e) {
|
|
|
|
|
return ResponseEntity.badRequest().body(ApiResponse.badRequest(e.getBindingResult()
|
|
|
|
|
.getFieldErrors()
|
|
|
|
|
.stream()
|
|
|
|
|
.findFirst()
|
|
|
|
|
.map(error -> error.getDefaultMessage())
|
|
|
|
|
.orElse("参数错误")));
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-29 12:33:25 +08:00
|
|
|
@ExceptionHandler(IllegalArgumentException.class)
|
|
|
|
|
public ResponseEntity<ApiResponse<Void>> handleIllegalArgument(IllegalArgumentException e) {
|
|
|
|
|
return ResponseEntity.badRequest().body(ApiResponse.badRequest(e.getMessage() == null ? "参数错误" : e.getMessage()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ExceptionHandler(HttpMessageNotReadableException.class)
|
|
|
|
|
public ResponseEntity<ApiResponse<Void>> handleUnreadable(HttpMessageNotReadableException e) {
|
|
|
|
|
return ResponseEntity.badRequest().body(ApiResponse.badRequest("请求体格式错误"));
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-09 14:53:42 +08:00
|
|
|
@ExceptionHandler(AuthorizationDeniedException.class)
|
|
|
|
|
public ResponseEntity<ApiResponse<Void>> handleAuthorizationDenied(AuthorizationDeniedException e) {
|
|
|
|
|
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
|
|
|
|
String principal = authentication == null ? null : String.valueOf(authentication.getPrincipal());
|
|
|
|
|
String authorities = authentication == null ? "[]" : authentication.getAuthorities().toString();
|
|
|
|
|
log.warn("Access denied path={} principal={} authorities={} reason={}",
|
|
|
|
|
"im-service", principal, authorities, e.getMessage());
|
|
|
|
|
return ResponseEntity.status(HttpStatus.FORBIDDEN)
|
|
|
|
|
.body(ApiResponse.error(403, "Forbidden: current token lacks required role"));
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-27 23:41:58 +08:00
|
|
|
@ExceptionHandler(Exception.class)
|
|
|
|
|
public ResponseEntity<ApiResponse<Void>> handleException(Exception e) {
|
2026-04-30 11:47:01 +08:00
|
|
|
log.error("Unhandled exception", e);
|
2026-04-27 23:41:58 +08:00
|
|
|
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
|
2026-04-30 11:47:01 +08:00
|
|
|
.body(ApiResponse.error(500, "服务异常"));
|
2026-04-27 23:41:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private HttpStatus resolveStatus(int code) {
|
|
|
|
|
return switch (code) {
|
|
|
|
|
case 400 -> HttpStatus.BAD_REQUEST;
|
|
|
|
|
case 401 -> HttpStatus.UNAUTHORIZED;
|
|
|
|
|
case 403 -> HttpStatus.FORBIDDEN;
|
|
|
|
|
case 404 -> HttpStatus.NOT_FOUND;
|
|
|
|
|
default -> HttpStatus.INTERNAL_SERVER_ERROR;
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
}
|