Java参数接收流程如何规整

wen java案例 27

本文目录导读:

Java参数接收流程如何规整

  1. 基础参数接收规整
  2. 参数校验增强
  3. 参数转换与处理
  4. 最佳实践总结

我来系统介绍Java参数接收的规整方法,涵盖请求参数、方法参数、校验和转换等各个方面。

基础参数接收规整

Controller层参数接收规范

@RestController
@RequestMapping("/api/users")
public class UserController {
    // 1. 路径参数
    @GetMapping("/{id}")
    public Result<User> getUserById(@PathVariable Long id) {
        // 使用@PathVariable
    }
    // 2. 查询参数
    @GetMapping("/list")
    public Result<List<User>> listUsers(
        @RequestParam(defaultValue = "1") Integer page,
        @RequestParam(defaultValue = "10") Integer size,
        @RequestParam(required = false) String keyword) {
        // 使用@RequestParam
    }
    // 3. 表单参数/JSON体
    @PostMapping
    public Result<User> createUser(@Valid @RequestBody UserCreateDTO dto) {
        // 使用@RequestBody
    }
    // 4. 混合参数
    @PutMapping("/{id}")
    public Result<User> updateUser(
        @PathVariable Long id,
        @Valid @RequestBody UserUpdateDTO dto) {
        // 组合使用
    }
}

DTO(数据传输对象)设计

@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserCreateDTO {
    @NotBlank(message = "用户名不能为空")
    @Size(min = 2, max = 50, message = "用户名长度2-50个字符")
    private String username;
    @NotBlank(message = "密码不能为空")
    @Size(min = 6, max = 20, message = "密码长度6-20个字符")
    private String password;
    @Email(message = "邮箱格式不正确")
    private String email;
    @Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确")
    private String phone;
    @Min(value = 0, message = "年龄不能小于0")
    @Max(value = 150, message = "年龄不能大于150")
    private Integer age;
    @Future(message = "过期时间必须是将来的时间")
    private LocalDateTime expireTime;
}

参数校验增强

分组校验

// 定义分组接口
public interface CreateGroup {}
public interface UpdateGroup {}
// DTO使用分组
@Data
public class UserDTO {
    @Null(groups = CreateGroup.class)
    @NotNull(groups = UpdateGroup.class)
    private Long id;
    @NotBlank(groups = CreateGroup.class)
    @Size(min = 2, max = 50)
    private String username;
    @NotBlank(groups = CreateGroup.class)
    private String password;
    @NotNull(groups = UpdateGroup.class)
    private Integer status;
}
// Controller使用分组
@RestController
@RequestMapping("/api/users")
public class UserController {
    @PostMapping
    public Result<User> create(@Validated(CreateGroup.class) @RequestBody UserDTO dto) {
        // 创建时的校验
    }
    @PutMapping("/{id}")
    public Result<User> update(
        @PathVariable Long id,
        @Validated(UpdateGroup.class) @RequestBody UserDTO dto) {
        // 更新时的校验
    }
}

自定义校验注解

// 自定义注解
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = MobileValidator.class)
public @interface Mobile {
    String message() default "手机号格式不正确";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}
// 校验器实现
public class MobileValidator implements ConstraintValidator<Mobile, String> {
    private static final Pattern MOBILE_PATTERN = 
        Pattern.compile("^1[3-9]\\d{9}$");
    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        if (value == null) {
            return true; // 是否为空由@NotNull控制
        }
        return MOBILE_PATTERN.matcher(value).matches();
    }
}
// 使用自定义注解
@Data
public class UserDTO {
    @Mobile
    private String phone;
}

全局异常处理统一返回

@RestControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Result<Map<String, String>> handleValidationExceptions(
        MethodArgumentNotValidException ex) {
        Map<String, String> errors = new HashMap<>();
        ex.getBindingResult().getFieldErrors().forEach(error -> 
            errors.put(error.getField(), error.getDefaultMessage()));
        return Result.error(400, "参数校验失败", errors);
    }
    @ExceptionHandler(ConstraintViolationException.class)
    public Result<Map<String, String>> handleConstraintViolation(
        ConstraintViolationException ex) {
        Map<String, String> errors = new HashMap<>();
        ex.getConstraintViolations().forEach(violation ->
            errors.put(
                violation.getPropertyPath().toString(),
                violation.getMessage()
            ));
        return Result.error(400, "参数校验失败", errors);
    }
}

参数转换与处理

通用转换器

@Component
public class StringToLocalDateConverter 
    implements Converter<String, LocalDate> {
    private static final DateTimeFormatter FORMATTER = 
        DateTimeFormatter.ofPattern("yyyy-MM-dd");
    @Override
    public LocalDate convert(String source) {
        if (source == null || source.trim().isEmpty()) {
            return null;
        }
        return LocalDate.parse(source, FORMATTER);
    }
}
// 配置转换器
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addConverter(new StringToLocalDateConverter());
    }
}

参数脱敏处理

// 自定义序列化注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside
@JsonSerialize(using = SensitiveSerializer.class)
public @interface Sensitive {
    SensitiveType type() default SensitiveType.PHONE;
}
enum SensitiveType {
    PHONE, EMAIL, ID_CARD, NAME
}
// 脱敏处理器
public class SensitiveSerializer extends JsonSerializer<String> {
    @Override
    public void serialize(String value, 
        JsonGenerator gen, 
        SerializerProvider serializers) throws IOException {
        if (value == null) {
            gen.writeNull();
            return;
        }
        String masked = mask(value);
        gen.writeString(masked);
    }
    private String mask(String value, SensitiveType type) {
        switch (type) {
            case PHONE:
                return value.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2");
            case EMAIL:
                return value.replaceAll("(.{2}).+(@.+)", "$1****$2");
            case ID_CARD:
                return value.replaceAll("(.{4}).+(.{4})", "$1********$2");
            case NAME:
                return value.replaceAll("(.{1}).+", "$1**");
            default:
                return value;
        }
    }
}
// 使用
@Data
public class UserVO {
    @Sensitive(type = SensitiveType.PHONE)
    private String phone;
    @Sensitive(type = SensitiveType.EMAIL)
    private String email;
}

最佳实践总结

参数接收规范

// 推荐:使用DTO统一接收
@PostMapping("/batch")
public Result<List<User>> batchCreate(
    @Valid @RequestBody List<@Valid UserCreateDTO> dtos) {
    // 集合参数校验
}
// 推荐:查询参数使用对象封装
@GetMapping("/search")
public Result<PageResult<User>> searchUsers(
    @Validated UserSearchDTO searchDTO,
    @RequestParam(defaultValue = "1") Integer page,
    @RequestParam(defaultValue = "10") Integer size) {
    // 复杂查询参数
}

参数校验顺序

// 1. 基础类型校验(框架自动)
// 2. @Valid/@Validated 注解校验(JSR-303)
// 3. 业务逻辑校验(自定义校验器)
// 4. 幂等性校验(防止重复提交)

完整示例

@RestController
@RequestMapping("/api/orders")
@Validated // 类级别校验
public class OrderController {
    @PostMapping
    public Result<OrderVO> createOrder(
        @Valid @RequestBody OrderCreateDTO dto,
        @RequestHeader("X-Request-Id") String requestId) {
        // 1. 幂等性校验
        if (idempotentService.isDuplicate(requestId)) {
            return Result.error("重复提交");
        }
        // 2. 业务参数校验
        validateBusinessParams(dto);
        // 3. 执行业务
        Order order = orderService.createOrder(dto);
        // 4. 返回结果
        return Result.success(convertToVO(order));
    }
    private void validateBusinessParams(OrderCreateDTO dto) {
        // 复杂业务逻辑校验
        if (dto.getTotalAmount().compareTo(dto.getPayAmount()) < 0) {
            throw new BusinessException("支付金额不能大于总金额");
        }
        // 其他业务校验...
    }
}

通过以上规整方式,可以实现:

  • 统一性:所有参数接收格式统一
  • 可维护性:校验逻辑集中管理,便于修改
  • 安全性:防XSS、SQL注入等
  • 可读性:代码结构清晰,易于理解
  • 复用性:DTO和校验规则可复用

这样即使团队多人协作,也能保持代码风格一致,减少沟通成本。

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