2026/5/21 11:36:05
网站建设
项目流程
网站的开发包括什么东西,个人网站建设作用,微信小程序专业开发公司,外贸网站建设定制开发大家好#xff0c;我是小悟。
一、参数校验#xff1a;程序员的“防杠精神器”
假如你的API像个热情的饭店服务员#xff0c;用户说“随便来点吃的”#xff0c;你就真给他上了盘空气——这可不妙#xff01;参数校验就像是那个会耐心问“要辣的还是不辣的#xff1f;要牛…大家好我是小悟。一、参数校验程序员的“防杠精神器”假如你的API像个热情的饭店服务员用户说“随便来点吃的”你就真给他上了盘空气——这可不妙参数校验就像是那个会耐心问“要辣的还是不辣的要牛肉还是鸡肉”的细心服务员确保不闹出“我要咖啡你却给我上了杯洗脚水”的尴尬。SpringBoot的注解校验就像给你的方法参数请了个私人保镖专门拦截那些不靠谱的输入。没有它用户传个null过来你的程序可能就会表演“当场崩溃”的绝活。二、详细步骤给代码戴上“紧箍咒”第1步先来点“开胃菜”——添加依赖!-- pom.xml里加入这个就像泡面加卤蛋标配 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-validation/artifactId /dependency第2步创建个“相亲简历”DTO类import javax.validation.constraints.*; import java.util.Date; import java.util.List; /** * 用户注册DTO - 比相亲网站的个人资料要求还严格 */ public class UserRegisterDTO { NotBlank(message 用户名不能为空难道您是无名氏) Size(min 2, max 20, message 用户名长度在2-20之间太短没存在感太长记不住) private String username; Email(message 邮箱格式不对这可不是在写情书随便写写就行) private String email; Pattern(regexp ^(?.*[A-Za-z])(?.*\\d)[A-Za-z\\d]{8,}$, message 密码至少8位包含字母和数字别再用123456了) private String password; Min(value 18, message 未满18岁小朋友先去写作业) Max(value 120, message 超过120岁您是老神仙吧) private Integer age; NotNull(message 手机号必须填不然外卖到了找谁) private String phone; AssertTrue(message 必须接受协议虽然可能没人看) private Boolean acceptedAgreement; Future(message 预约时间必须是未来时光机还没发明呢) private Date appointmentTime; Size(min 1, max 3, message 最多选3个爱好您是想成为全能超人吗) private ListString hobbies; // 此处省略getter和setter但它们确实存在我发誓 // 用Lombok的Data也行但今天咱们保持纯洁的Java关系 // 自定义校验注解示例 ValidGender private String gender; }第3步自定义校验注解——打造专属“安检仪”import javax.validation.Constraint; import javax.validation.Payload; import java.lang.annotation.*; /** * 性别校验注解 - 咱们思想很开放但数据要规范 */ Target({ElementType.FIELD}) Retention(RetentionPolicy.RUNTIME) Constraint(validatedBy GenderValidator.class) public interface ValidGender { String message() default 性别必须是男、女或保密您这是来自火星吗; Class?[] groups() default {}; Class? extends Payload[] payload() default {}; } /** * 性别校验器 - 严肃的判官 */ public class GenderValidator implements ConstraintValidatorValidGender, String { private static final SetString VALID_GENDERS new HashSet(Arrays.asList(男, 女, 保密)); Override public boolean isValid(String value, ConstraintValidatorContext context) { if (value null) { return true; // 用NotNull管非空咱们只管格式 } return VALID_GENDERS.contains(value); } }第4步控制器里使用——给API装上“安检门”import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import javax.validation.Valid; import javax.validation.constraints.NotBlank; RestController RequestMapping(/api/users) Validated // 这个注解让方法参数校验生效就像给方法吃了“严格丸” public class UserController { /** * 注册用户 - 参数校验比丈母娘挑女婿还严格 */ PostMapping(/register) public Result register(RequestBody Valid UserRegisterDTO userDTO) { // 如果参数校验失败根本走不到这里 // 就像考试不及格进不了下一轮面试 return Result.success(注册成功恭喜通过严格审查); } /** * 方法参数校验 - 连路径变量都不放过 */ GetMapping(/{id}) public Result getUser( PathVariable Min(value 1, message ID必须大于0您这是要找空气用户吗) Long id, RequestParam NotBlank(message 令牌不能为空您这是想蒙混过关) String token) { return Result.success(找到了用户ID: id); } /** * 分组校验 - 根据不同场景使用不同规则 * 就像上班穿正装在家穿睡衣场合要分清 */ PostMapping(/update) public Result updateUser(RequestBody Validated(UserUpdateGroup.class) UserUpdateDTO dto) { return Result.success(更新成功); } } // 分组接口定义 interface UserUpdateGroup {} interface UserCreateGroup {}第5步全局异常处理——优雅的“救火队员”import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.validation.FieldError; /** * 全局异常处理器 - 专业收拾校验失败的烂摊子 */ RestControllerAdvice public class GlobalExceptionHandler { /** * 处理参数校验异常 - 把技术语言翻译成人话 */ ExceptionHandler(MethodArgumentNotValidException.class) public Result handleValidationException(MethodArgumentNotValidException ex) { // 收集所有错误信息就像收集考试错题 MapString, String errors new HashMap(); ex.getBindingResult().getAllErrors().forEach(error - { String fieldName ((FieldError) error).getField(); String errorMessage error.getDefaultMessage(); errors.put(fieldName, errorMessage); }); return Result.error(400, 参数校验失败, errors) .setMessage(您提交的数据有点小问题请检查后再试哦~); } /** * 处理ConstraintViolationException - 方法参数校验失败 */ ExceptionHandler(ConstraintViolationException.class) public Result handleConstraintViolationException(ConstraintViolationException ex) { ListString errors ex.getConstraintViolations().stream() .map(violation - violation.getMessage()) .collect(Collectors.toList()); return Result.error(400, 参数不合法, errors); } } /** * 统一返回结果 - 给前端一个标准的“成绩单” */ Data AllArgsConstructor NoArgsConstructor public class ResultT { private Integer code; private String message; private T data; private Long timestamp System.currentTimeMillis(); public static T ResultT success(T data) { return new Result(200, 成功, data); } public static T ResultT error(Integer code, String message, T data) { return new Result(code, message, data); } public ResultT setMessage(String message) { this.message message; return this; } }第6步进阶玩法——嵌套校验和集合校验/** * 订单DTO - 俄罗斯套娃式的校验 */ public class OrderDTO { NotNull(message 订单信息不能为空) Valid // 这个注解让嵌套校验生效就像班主任检查每个学生的作业 private UserDTO user; Valid // 集合也要逐个校验一个都别想逃 private ListValid OrderItemDTO items; Valid private AddressDTO address; } /** * 地址DTO - 精确到门牌号 */ public class AddressDTO { NotBlank(message 省份不能空您这是要寄到外太空) private String province; NotBlank(message 城市不能空) private String city; Size(min 5, max 100, message 详细地址5-100字说清楚点快递员会感谢您) private String detail; }三、测试一下看看“保镖”工作认不认真// 测试Controller - 专门捣乱看系统反应 SpringBootTest AutoConfigureMockMvc class UserControllerTest { Autowired private MockMvc mockMvc; Test void testRegisterWithInvalidData() throws Exception { String invalidUserJson { username: A, // 太短了 email: not-an-email, // 这不是邮箱 password: 123, // 太弱了 age: 10, // 未成年 phone: null, // 空值 acceptedAgreement: false, // 不同意协议 appointmentTime: 2020-01-01, // 过去的时间 hobbies: [吃饭, 睡觉, 打豆豆, 刷手机, 发呆] // 爱好太多 } ; mockMvc.perform(MockMvcRequestBuilders.post(/api/users/register) .contentType(MediaType.APPLICATION_JSON) .content(invalidUserJson)) .andExpect(status().isBadRequest()) // 应该返回400 .andExpect(jsonPath($.code).value(400)) .andExpect(jsonPath($.data).exists()) // 错误详情 .andDo(print()); // 打印响应看看“保镖”怎么怼你 } }四、性能优化小贴士/** * 校验配置 - 让校验既严格又高效 */ Configuration public class ValidationConfig { Bean public Validator validator() { ValidatorFactory factory Validation.buildDefaultValidatorFactory(); Validator validator factory.getValidator(); // 可以在这里配置一些自定义设置 // 比如缓存校验器避免重复创建 return validator; } /** * 快速失败模式 - 发现一个错误就立即返回 * 就像考试发现第一题错了就交卷不建议真人尝试 */ Bean public Validator fastFailValidator() { return Validation.byDefaultProvider() .configure() .addProperty(hibernate.validator.fail_fast, true) .buildValidatorFactory() .getValidator(); } }总结参数校验的“人生哲理”为什么需要参数校验防止GIGO垃圾进垃圾出——输入决定输出质量安全第一很多安全漏洞都源于不可信的输入用户体验早发现错误早提示用户别让用户猜谜注解校验的优点声明式像贴标签一样简单告别一堆if-else集中管理规则在实体类上一目了然易于维护改注解就能改规则不用翻业务代码丰富内置Spring提供了几十种注解总有一款适合你最佳实践建议在DTO层做校验保持业务层纯洁错误消息要友好说人话别甩技术术语区分必填和非必填字段别要求用户填宇宙复杂逻辑用自定义校验器别硬塞到一个注解里记得处理异常给前端统一的错误格式总结参数校验就像给你的代码请了个门卫大爷不合格的一律不让进语文老师检查格式对不对内容全不全健身教练严格要求不容马虎相声演员出错时还能用幽默的方式告诉你严谨的程序员对待输入就像猫奴对待猫主子既要有爱也要有规矩你的API会因为良好的参数校验而变得更加健壮、安全、用户友好。谢谢你看我的文章既然看到这里了如果觉得不错随手点个赞、转发、在看三连吧感谢感谢。那我们下次再见。您的一键三连是我更新的最大动力谢谢山水有相逢来日皆可期谢谢阅读我们再会我手中的金箍棒上能通天下能探海