Java全局校验案例怎么封装

wen java案例 25

本文目录导读:

Java全局校验案例怎么封装

  1. 基于Spring框架的全局校验封装
  2. 全局异常处理封装
  3. 参数校验工具类
  4. DTO对象校验示例
  5. Service层校验封装
  6. 高级校验器封装
  7. 使用示例

我来为你提供一个完整的Java全局校验封装方案,包括多种实现方式:

基于Spring框架的全局校验封装

1 自定义注解

import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = PhoneValidator.class)
@Documented
public @interface ValidPhone {
    String message() default "手机号格式不正确";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

2 自定义校验器

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.regex.Pattern;
public class PhoneValidator implements ConstraintValidator<ValidPhone, String> {
    private static final String PHONE_REGEX = "^1[3-9]\\d{9}$";
    @Override
    public boolean isValid(String phone, ConstraintValidatorContext context) {
        if (phone == null || phone.isEmpty()) {
            return true; // 交给@NotNull处理
        }
        return Pattern.matches(PHONE_REGEX, phone);
    }
}

全局异常处理封装

1 通用响应类

import lombok.Data;
import java.io.Serializable;
@Data
public class ApiResponse<T> implements Serializable {
    private Integer code;
    private String message;
    private T data;
    private Long timestamp;
    public ApiResponse() {
        this.timestamp = System.currentTimeMillis();
    }
    public static <T> ApiResponse<T> success(T data) {
        ApiResponse<T> response = new ApiResponse<>();
        response.setCode(200);
        response.setMessage("success");
        response.setData(data);
        return response;
    }
    public static <T> ApiResponse<T> error(Integer code, String message) {
        ApiResponse<T> response = new ApiResponse<>();
        response.setCode(code);
        response.setMessage(message);
        return response;
    }
}

2 自定义异常类

import lombok.Getter;
@Getter
public class BusinessException extends RuntimeException {
    private Integer code;
    public BusinessException(Integer code, String message) {
        super(message);
        this.code = code;
    }
    public BusinessException(String message) {
        super(message);
        this.code = 500;
    }
}

3 全局异常处理器

import org.springframework.http.HttpStatus;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.stream.Collectors;
@RestControllerAdvice
public class GlobalExceptionHandler {
    // 处理参数校验异常
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ApiResponse<Void> handleValidationExceptions(MethodArgumentNotValidException ex) {
        String errorMessage = ex.getBindingResult().getFieldErrors()
                .stream()
                .map(FieldError::getDefaultMessage)
                .collect(Collectors.joining(", "));
        return ApiResponse.error(400, errorMessage);
    }
    // 处理单个参数校验异常
    @ExceptionHandler(ConstraintViolationException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ApiResponse<Void> handleConstraintViolation(ConstraintViolationException ex) {
        String errorMessage = ex.getConstraintViolations()
                .stream()
                .map(ConstraintViolation::getMessage)
                .collect(Collectors.joining(", "));
        return ApiResponse.error(400, errorMessage);
    }
    // 处理业务异常
    @ExceptionHandler(BusinessException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ApiResponse<Void> handleBusinessException(BusinessException ex) {
        return ApiResponse.error(ex.getCode(), ex.getMessage());
    }
    // 处理通用异常
    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public ApiResponse<Void> handleException(Exception ex) {
        return ApiResponse.error(500, "服务器内部错误: " + ex.getMessage());
    }
}

参数校验工具类

import org.apache.commons.lang3.StringUtils;
import java.util.regex.Pattern;
public class ValidateUtils {
    // 手机号正则
    private static final String PHONE_REGEX = "^1[3-9]\\d{9}$";
    // 邮箱正则
    private static final String EMAIL_REGEX = "^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$";
    // 身份证正则
    private static final String ID_CARD_REGEX = "^[1-9]\\d{5}(18|19|20)\\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\\d|3[01])\\d{3}[0-9Xx]$";
    public static boolean isPhone(String phone) {
        if (StringUtils.isBlank(phone)) {
            return false;
        }
        return Pattern.matches(PHONE_REGEX, phone);
    }
    public static boolean isEmail(String email) {
        if (StringUtils.isBlank(email)) {
            return false;
        }
        return Pattern.matches(EMAIL_REGEX, email);
    }
    public static boolean isIdCard(String idCard) {
        if (StringUtils.isBlank(idCard)) {
            return false;
        }
        return Pattern.matches(ID_CARD_REGEX, idCard);
    }
    public static void validatePhone(String phone) {
        if (!isPhone(phone)) {
            throw new BusinessException(400, "手机号格式不正确");
        }
    }
    public static void validateEmail(String email) {
        if (!isEmail(email)) {
            throw new BusinessException(400, "邮箱格式不正确");
        }
    }
}

DTO对象校验示例

1 基础校验

import lombok.Data;
import javax.validation.constraints.*;
import java.time.LocalDate;
@Data
public class UserCreateRequest {
    @NotBlank(message = "用户名不能为空")
    @Size(min = 2, max = 20, message = "用户名长度在2-20个字符之间")
    private String username;
    @NotBlank(message = "密码不能为空")
    @Size(min = 6, max = 20, message = "密码长度在6-20个字符之间")
    private String password;
    @NotBlank(message = "手机号不能为空")
    @ValidPhone(message = "手机号格式不正确")
    private String phone;
    @Email(message = "邮箱格式不正确")
    private String email;
    @NotNull(message = "年龄不能为空")
    @Min(value = 1, message = "年龄最小为1")
    @Max(value = 150, message = "年龄最大为150")
    private Integer age;
    @NotNull(message = "生日不能为空")
    @Past(message = "生日必须是过去的时间")
    private LocalDate birthday;
}

2 分组校验

import javax.validation.groups.Default;
public class ValidationGroups {
    public interface Create extends Default {}
    public interface Update extends Default {}
    public interface Query extends Default {}
}
@Data
public class UserDTO {
    @NotNull(groups = {Update.class}, message = "ID不能为空")
    private Long id;
    @NotBlank(groups = {Create.class}, message = "用户名不能为空")
    private String username;
    @NotBlank(groups = {Create.class}, message = "密码不能为空")
    private String password;
    @NotBlank(groups = {Create.class, Update.class}, message = "手机号不能为空")
    @ValidPhone(groups = {Create.class, Update.class}, message = "手机号格式不正确")
    private String phone;
}

Service层校验封装

import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
@Service
@Validated
public class UserService {
    public User createUser(@Valid @NotNull UserCreateRequest request) {
        // 业务逻辑
        return new User();
    }
    @Validated(ValidationGroups.Update.class)
    public User updateUser(@Valid UserUpdateRequest request) {
        // 业务逻辑
        return new User();
    }
}

高级校验器封装

import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import javax.validation.ConstraintViolation;
import javax.validation.Validator;
import java.util.Set;
import java.util.stream.Collectors;
@Component
public class ValidationHelper {
    private final Validator validator;
    public ValidationHelper(Validator validator) {
        this.validator = validator;
    }
    public <T> void validate(T object) {
        Set<ConstraintViolation<T>> violations = validator.validate(object);
        if (!CollectionUtils.isEmpty(violations)) {
            String errorMessage = violations.stream()
                    .map(ConstraintViolation::getMessage)
                    .collect(Collectors.joining(", "));
            throw new BusinessException(400, errorMessage);
        }
    }
    public <T> void validate(T object, Class<?>... groups) {
        Set<ConstraintViolation<T>> violations = validator.validate(object, groups);
        if (!CollectionUtils.isEmpty(violations)) {
            String errorMessage = violations.stream()
                    .map(ConstraintViolation::getMessage)
                    .collect(Collectors.joining(", "));
            throw new BusinessException(400, errorMessage);
        }
    }
}

使用示例

import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/users")
public class UserController {
    @PostMapping
    public ApiResponse<User> createUser(@Valid @RequestBody UserCreateRequest request) {
        // 参数已自动校验
        User user = userService.createUser(request);
        return ApiResponse.success(user);
    }
    @GetMapping("/{id}")
    public ApiResponse<User> getUser(@PathVariable @Min(value = 1, message = "ID必须大于0") Long id) {
        User user = userService.getUser(id);
        return ApiResponse.success(user);
    }
    @PostMapping("/validate")
    public ApiResponse<String> manualValidate(@RequestBody UserCreateRequest request) {
        // 手动调用校验
        validationHelper.validate(request);
        // 或者使用工具类
        ValidateUtils.validatePhone(request.getPhone());
        ValidateUtils.validateEmail(request.getEmail());
        return ApiResponse.success("校验通过");
    }
}

这个封装方案提供了:

  • 声明式校验(@Valid注解)
  • 自定义校验器
  • 全局异常处理
  • 分组校验
  • 工具类支持
  • 手动校验支持

可以根据项目需求选择合适的校验方式组合使用。

抱歉,评论功能暂时关闭!