一.导学
-
用户信息修改和删除服务
- 常用的验证注解
- 自定义消息
- 自定义校验注解
-
常用的验证注解
- 扩展
http://hibernate.org/validator/documentation/
https://docs.jboss.org/hibernate/stable/validator/reference/en-US/html_single/
二.编写用户信息修改
- 编写用户修改测试用例
@Test
public void whenUpdateSuccess() throws Exception{
Date date = new Date(LocalDateTime.now().plusYears(1).atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());//传一个未来时间 加一年 时区
String content = "{\"id\":\"1\",\"username\":\"playmaker\",\"password\":null,\"birthday\":"+date.getTime()+"}";
String result = mockMvc.perform(MockMvcRequestBuilders.put("/user/1")
.contentType(MediaType.APPLICATION_JSON_UTF8)
.content(content))
.andExpect(MockMvcResultMatchers.status().isOk())
.andExpect(MockMvcResultMatchers.jsonPath("$.id").value("1"))
.andReturn().getResponse().getContentAsString();
System.out.println(result);
}
- 编写用户修改接口
@PutMapping("/{id:\\d+}")
public User update(@Valid @RequestBody User user ,BindingResult errors){
if(errors.hasErrors()){
errors.getAllErrors().stream().forEach(error-> {
FieldError fieldError = (FieldError)error;
String message = fieldError.getField()+" "+fieldError.getDefaultMessage();
System.out.println(message);
});
}
System.out.println(user.getId());
System.out.println(user.getUsername());
System.out.println(user.getPassword());
System.out.println(user.getBirthday());
user.setId("1");
return user;
}
@NotBlank //不能为空
private String password;
@Past //必须是过去的时间
private Date birthday;
- 运行结果
- 说得不太具体,怎么控制错误消息?
- 这些注解 都有一个共同属性 message来控制错误信息
@NotBlank(message = "密码不能为空")
private String password;
@Past(message = "生日只能是过去的时间")
private Date birthday;
- 再次运行结果(这样就显而易见了)
- 很多时候提供的这些注解无法满足需求
- 非常简单逻辑 最复杂就一个正则表达式
- 有时候校验基于数据的 数据库存在嘛之类的
- 自己写校验能够通过注解方式注入进来
三.自定义校验注解
- 编写注解
@Target({ElementType.METHOD,ElementType.FIELD}) //标注可以在方法上 也可以在字段上
@Retention(RetentionPolicy.RUNTIME) //注解信息保留在运行时
@Constraint(validatedBy = MyConstraintValidator.class) //用于什么类注解这个注解,也就是有该注解的时候要执行的逻辑
public @interface MyConstraint {
//下面三个方法是自定义校验注解必须的 如下图所示 message就是自定义验证信息
String message() default "{javax.validation.constraints.NotBlank.message}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
- 编写校验逻辑
// 绑定一个注解类型,用于验证的值是什么
// 如果Object换成String,那么则只能把注解放在String类型上
//@Component
public class MyConstraintValidator implements ConstraintValidator<MyConstraint,Object> {
//实现ConstraintValidator接口后,会被spring扫描管理,所以可以直接使用注入服务 所以不用再类上面加注解了
@Autowired
private HelloService helloService;//可以注入任何spring容器来完成你的校验逻辑 比如这个测试
@Override
public void initialize(MyConstraint constraintAnnotation) {//初始化方法
System.out.println("init.....");
}
@Override
public boolean isValid(Object value, ConstraintValidatorContext context) {//注解要执行的校验逻辑
helloService.greeting("tom");
System.out.println(value);
return false;//校验成功返回true 失败返回false
}
}
- 编写服务接口来测试
public interface HelloService {
public String greeting(String name);
}
- 实现类
@Service
public class HelloServiceImpl implements HelloService {
@Override
public String greeting(String name) {
System.out.println("greeting...");
return "hello "+name;
}
}
- 在User类username上添加这个注解
@MyConstraint(message = "这是一个测试")
private String username;
- username上有这个,调用这个方法,把username值当value传进来
- 运行结果
总结:方便,自己定义一个注解,重用,免得去控制器里面反复写校验逻辑方便的多
四.删除服务
- 编写测试类
@Test
public void whenDeleteSuccess() throws Exception{
mockMvc.perform(MockMvcRequestBuilders.delete("/user/1")
.contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(MockMvcResultMatchers.status().isOk());
}
- 编写接口
@DeleteMapping("/{id:\\d+}")
public void delete(@PathVariable String id){
System.out.println(id);
}