You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 06:39:14