Spring Boot多异常同时抛出:如何返回用户名和Pin重复提示
如何在保存员工时同时返回用户名和Pin重复的异常提示?
问题描述
我编写了EmployeeController类,通过自定义异常校验用户名和Pin的唯一性,但在Postman测试时,当用户名和Pin同时重复,仅返回其中一个异常提示。我希望能同时返回两个提示(如“该Pin已被使用!该用户名已被使用!”),请问如何实现?
原代码
@RestController @RequestMapping("/api") public class EmployeeController { //private EmployeeService employeeService; private final EmployeeRepository employeeRepository; // ControllerException controllerException; @Autowired public EmployeeController(EmployeeRepository employeeRepository) { this.employeeRepository = employeeRepository; } @PostMapping("/employee") public ResponseEntity<Employee> saveEmployee(@RequestBody Employee employee, BindingResult bindingResult) throws EmployeeAlreadyExistsException { if (employeeRepository.existsById(employee.getId())) { throw new EmployeeAlreadyExistsException(); } String temUsername = employee.getUsername(); if(temUsername !=null && !"".equals(temUsername)) { Employee userObject = employeeRepository.findByUsername(temUsername); if(userObject!=null) { throw new EmployeeUsernameAlreadyExistsException(); } } String pin = employee.getPin(); if(pin !=null && !"".equals(pin)) { Employee userObject = employeeRepository.findByPin(pin); if(userObject!=null) { throw new EmployeePinAlreadyExistsException(); } } Employee employee1 = employeeRepository.save(employee); return new ResponseEntity<>(employee1, HttpStatus.CREATED); } @GetMapping("/employees") public ResponseEntity<List<Employee>> getAllEmployee() throws EmployeeNotFoundException { return new ResponseEntity<>((List<Employee>) employeeRepository.findAll(), HttpStatus.OK); } @PostMapping("/update") public ResponseEntity<?> updateEmployee(@RequestBody Employee employee) throws EmployeeNotFoundException, EmployeePinAlreadyExistsException { if (!employeeRepository.existsById(employee.getId())) { throw new EmployeeNotFoundException(); } else { Employee employee1 = employeeRepository.save(employee); return new ResponseEntity<>(employee1, HttpStatus.CREATED); } } @GetMapping("employee/{id}") public ResponseEntity<?> getEmployeeById(@PathVariable("id") int id, Employee employee) throws EmployeeNotFoundException { if (!employeeRepository.existsById(employee.getId())) { throw new EmployeeNotFoundException(); } return new ResponseEntity<>(employeeRepository.findById(id), HttpStatus.OK); } @ExceptionHandler(value = EmployeeAlreadyExistsException.class) public ResponseEntity<?> EmployeeAlreadyExistsException(EmployeeAlreadyExistsException employeeAlreadyExistsException) { ErrorResponse erResp = ErrorResponse.builder() .message("This Employee already exist!") .code("101") .traceId(UUID.randomUUID().toString()) .build(); return new ResponseEntity<>(erResp, HttpStatus.CONFLICT); } @ExceptionHandler(value = EmployeeNotFoundException.class) public ResponseEntity<?> EmployeeNotFoundException(EmployeeNotFoundException employeeNotFoundException) { ErrorResponse erResp = ErrorResponse.builder() .message("This id is not valid!") .code("404") .traceId(UUID.randomUUID().toString()) .build(); return new ResponseEntity<>(erResp, HttpStatus.CONFLICT); } @ExceptionHandler(value = EmployeePinAlreadyExistsException.class) public ResponseEntity<?> EmployeePinAlreadyExistsException(EmployeePinAlreadyExistsException employeePinAlreadyExistsException) { ErrorResponse erResp = ErrorResponse.builder() .message("This pin Already in use!") .code("101") .traceId(UUID.randomUUID().toString()) .build(); return new ResponseEntity<>(erResp, HttpStatus.CONFLICT); } @ExceptionHandler(value = EmployeeUsernameAlreadyExistsException.class) public ResponseEntity<?> EmployeeUsernameAlreadyExistsException(EmployeeUsernameAlreadyExistsException employeeUsernameAlreadyExistsException) { ErrorResponse erResp = ErrorResponse.builder() .message("This Username Already in use!") .code("109") .traceId(UUID.randomUUID().toString()) .build(); return new ResponseEntity<>(erResp, HttpStatus.CONFLICT); } }
解决方案
当前代码的问题是发现一个异常就立即抛出,后续校验逻辑不会执行,因此只能返回单个错误。要实现多错误同时返回,需要先收集所有校验错误,再统一抛出并处理。
1. 创建多校验异常类
定义一个能存储多个错误信息的异常类:
public class MultiValidationException extends RuntimeException { private final List<String> errorMessages; public MultiValidationException(List<String> errorMessages) { this.errorMessages = errorMessages; } public List<String> getErrorMessages() { return errorMessages; } }
2. 修改saveEmployee方法的校验逻辑
不再逐个抛出异常,而是先收集所有错误,最后统一抛出:
@PostMapping("/employee") public ResponseEntity<Employee> saveEmployee(@RequestBody Employee employee) throws MultiValidationException { List<String> errors = new ArrayList<>(); // 校验员工ID是否存在 if (employeeRepository.existsById(employee.getId())) { errors.add("该员工已存在!"); } // 校验用户名是否重复 String temUsername = employee.getUsername(); if (temUsername != null && !"".equals(temUsername)) { Employee userObject = employeeRepository.findByUsername(temUsername); if (userObject != null) { errors.add("该用户名已被使用!"); } } // 校验Pin是否重复 String pin = employee.getPin(); if (pin != null && !"".equals(pin)) { Employee userObject = employeeRepository.findByPin(pin); if (userObject != null) { errors.add("该Pin已被使用!"); } } // 存在错误则抛出多校验异常 if (!errors.isEmpty()) { throw new MultiValidationException(errors); } Employee employee1 = employeeRepository.save(employee); return new ResponseEntity<>(employee1, HttpStatus.CREATED); }
3. 添加多校验异常的处理器
在EmployeeController中新增@ExceptionHandler来处理MultiValidationException,把所有错误信息返回给前端:
@ExceptionHandler(value = MultiValidationException.class) public ResponseEntity<?> handleMultiValidationException(MultiValidationException ex) { // 方式1:将错误消息拼接成单个字符串返回 String combinedMessage = String.join(" ", ex.getErrorMessages()); ErrorResponse erResp = ErrorResponse.builder() .message(combinedMessage) .code("102") // 自定义多错误状态码 .traceId(UUID.randomUUID().toString()) .build(); return new ResponseEntity<>(erResp, HttpStatus.CONFLICT); }
如果希望返回更规范的多错误结构,可以修改ErrorResponse类,添加messages列表字段:
// 修改后的ErrorResponse示例 public class ErrorResponse { private String message; // 兼容原有单消息逻辑 private List<String> messages; // 新增多消息字段 private String code; private String traceId; // 构建器模式 public static Builder builder() { return new Builder(); } public static class Builder { private String message; private List<String> messages; private String code; private String traceId; public Builder message(String message) { this.message = message; return this; } public Builder messages(List<String> messages) { this.messages = messages; return this; } public Builder code(String code) { this.code = code; return this; } public Builder traceId(String traceId) { this.traceId = traceId; return this; } public ErrorResponse build() { ErrorResponse response = new ErrorResponse(); response.message = this.message; response.messages = this.messages; response.code = this.code; response.traceId = this.traceId; return response; } } // getter和setter方法省略 }
对应的异常处理器修改为:
@ExceptionHandler(value = MultiValidationException.class) public ResponseEntity<?> handleMultiValidationException(MultiValidationException ex) { ErrorResponse erResp = ErrorResponse.builder() .messages(ex.getErrorMessages()) .code("102") .traceId(UUID.randomUUID().toString()) .build(); return new ResponseEntity<>(erResp, HttpStatus.CONFLICT); }
4. (可选)调整原有异常的消息为中文
如果需要统一中文提示,可以修改原有异常处理器的message内容,比如:
@ExceptionHandler(value = EmployeeAlreadyExistsException.class) public ResponseEntity<?> EmployeeAlreadyExistsException(EmployeeAlreadyExistsException employeeAlreadyExistsException) { ErrorResponse erResp = ErrorResponse.builder() .message("该员工已存在!") .code("101") .traceId(UUID.randomUUID().toString()) .build(); return new ResponseEntity<>(erResp, HttpStatus.CONFLICT); }
这样修改后,当用户名和Pin同时重复时,前端会收到包含所有错误提示的响应。
内容的提问来源于stack exchange,提问作者DeadSilent
相关产品推荐
相关产品推荐

