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

Spring Boot中捕获多异常并对应不同HTTP状态码实现方案

实现方案

1. 自定义校验注解(绑定状态码)

给每个校验规则创建带状态码属性的自定义注解,让校验失败时能直接关联对应HTTP状态码,示例如下:

密码长度校验注解

@Target({FIELD})
@Retention(RUNTIME)
@Constraint(validatedBy = PasswordLengthValidator.class)
public @interface ValidPassword {
    String message() default "Password should have 16 characters.";
    int status() default 403; // 绑定403状态码
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

对应校验器:

public class PasswordLengthValidator implements ConstraintValidator<ValidPassword, String> {
    @Override
    public boolean isValid(String password, ConstraintValidatorContext context) {
        return password != null && password.length() == 16;
    }
}

邮箱格式校验注解

@Target({FIELD})
@Retention(RUNTIME)
@Constraint(validatedBy = EmailFormatValidator.class)
public @interface ValidEmail {
    String message() default "Invalid Email Format.";
    int status() default 422; // 绑定422状态码
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

对应校验器:

public class EmailFormatValidator implements ConstraintValidator<ValidEmail, String> {
    private static final String EMAIL_PATTERN = "^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+$";
    private Pattern pattern = Pattern.compile(EMAIL_PATTERN);

    @Override
    public boolean isValid(String email, ConstraintValidatorContext context) {
        if (email == null) return false;
        Matcher matcher = pattern.matcher(email);
        return matcher.matches();
    }
}

姓名非空校验注解

@Target({FIELD})
@Retention(RUNTIME)
@Constraint(validatedBy = NotEmptyNameValidator.class)
public @interface ValidName {
    String message() default "Name cannot be empty.";
    int status() default 500; // 绑定500状态码
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

对应校验器:

public class NotEmptyNameValidator implements ConstraintValidator<ValidName, String> {
    @Override
    public boolean isValid(String name, ConstraintValidatorContext context) {
        return name != null && !name.trim().isEmpty();
    }
}

2. 在用户DTO中使用自定义注解

public class UserCreateDTO {
    @ValidPassword
    private String password;

    @ValidEmail
    private String email;

    @ValidName
    private String name;

    // 生成getter、setter方法
}

3. 解析BindingResult生成指定格式响应

在Controller的创建用户方法中,遍历BindingResult的错误信息,通过反射获取字段上的自定义注解,提取对应状态码:

@PostMapping("/users")
public ResponseEntity<?> createUser(@Valid @RequestBody UserCreateDTO userDTO, BindingResult bindingResult) {
    if (bindingResult.hasErrors()) {
        List<Mistake> mistakes = new ArrayList<>();
        for (ObjectError error : bindingResult.getAllErrors()) {
            if (error instanceof FieldError fieldError) {
                try {
                    Field field = UserCreateDTO.class.getDeclaredField(fieldError.getField());
                    // 匹配对应注解并提取状态码
                    ValidPassword validPassword = field.getAnnotation(ValidPassword.class);
                    if (validPassword != null && validPassword.message().equals(error.getDefaultMessage())) {
                        mistakes.add(new Mistake(String.valueOf(validPassword.status()), error.getDefaultMessage()));
                        continue;
                    }
                    ValidEmail validEmail = field.getAnnotation(ValidEmail.class);
                    if (validEmail != null && validEmail.message().equals(error.getDefaultMessage())) {
                        mistakes.add(new Mistake(String.valueOf(validEmail.status()), error.getDefaultMessage()));
                        continue;
                    }
                    ValidName validName = field.getAnnotation(ValidName.class);
                    if (validName != null && validName.message().equals(error.getDefaultMessage())) {
                        mistakes.add(new Mistake(String.valueOf(validName.status()), error.getDefaultMessage()));
                    }
                } catch (NoSuchFieldException e) {
                    e.printStackTrace();
                }
            }
        }
        return ResponseEntity.badRequest().body(Map.of("mistakes", mistakes));
    }
    // 执行用户创建逻辑
    return ResponseEntity.ok("User created successfully");
}

4. 定义错误实体类

public class Mistake {
    private String status;
    private String detail;

    public Mistake(String status, String detail) {
        this.status = status;
        this.detail = detail;
    }

    // 生成getter、setter方法
}

简化方案(适合简单场景)

如果不想自定义过多注解,可直接通过错误消息映射状态码:

// 定义消息与状态码的映射关系
private static final Map<String, String> MESSAGE_STATUS_MAP = new HashMap<>();
static {
    MESSAGE_STATUS_MAP.put("Password should have 16 characters.", "403");
    MESSAGE_STATUS_MAP.put("Invalid Email Format.", "422");
    MESSAGE_STATUS_MAP.put("Name cannot be empty.", "500");
}

// 在Controller中使用
for (ObjectError error : bindingResult.getAllErrors()) {
    String status = MESSAGE_STATUS_MAP.getOrDefault(error.getDefaultMessage(), "400");
    mistakes.add(new Mistake(status, error.getDefaultMessage()));
}

内容的提问来源于stack exchange,提问作者R3bck

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 11:18:43