网站首页 > 基础教程 正文
“早成者未必有成,晚达者未必不达。不可以年少而自恃,不可以年老而自弃。”
验证框架
Spring Boot支持JSR-303、Bean验证框架,默认实现用的是Hibernate validator。在Spring MVC中,只需要使用@Valid注解标注中方法参数上,Spring Boot即可对参数对象进行校验,校验结果放在BindingResult对象中。
JSR-303定义了一系列注解用来验证Bean的属性,常用的有如下几种:
通常,不同的业务逻辑会有不同的验证逻辑,比如对于WorkInfoForm来说,当更新的时候,id必须不为null,但增加的时候,id必须是null。
JSR-303定义了group概念,每个校验注解都必须支持。校验注解作用在字段上的时候,可以指定一个或多个group,当Spring Boot校验对象的时候,也可以指定校验的上下文属于哪个group。这样,只有group匹配的时候,校验注解才能生效。上面的WorkInfoForm定义id字段校验可以更改为如下内容:
public class WorkInfoForm{ //定义一个类,更新时校验组 public interface Update{} //定义一个类,添加时校验组 public interface Add{} @NotNull(groups={Update.class}) @Null(groups={Add.class}) Long id; }
这段代码表示,当校验上下文为Add.class的时候,@Null生效,id需要为空才能校验通过;当校验上下文为Update.class的时候,@NotNull生效,id不能为空。
MVC中使用@Validated
在Controller中,只需要给方法参数加上@Validated即可触发一次校验。
@RequestMapping("/addworkinfo.html") public void addWorkInfo(@Validated({WorkInfoForm.Add.class}) WorkInfoForm woekInfo,BindingResult result) { if(result.hasErrors()){ List<ObjectError> list = result.getAllErrors(); FieldError error = (FieldError) list.get(0); System.out.println(error.getObjectName()+","+error.getField()+","+error.getDefaultMessage()); return; } return; }
此方法可以接受HTTP参数并映射到WorkInfoForm对象,此参数使用了@Validated注解,将触发Spring到校验,并将验证结果存放到BindingResult对象中。这里,Validated注解使用了校验的上下文WorkInfoForm.Add.class,因此,整个校验将按照Add.class来校验。
BindingResult包含了验证结果,提供了如下方法:
hasErrors,判断验证是否通过。
getAllErrors,得到所有的错误信息,通常返回的是FieldError列表。
如果Controller参数未提供BindingResult对象,则Spring MVC将抛出异常。
自定义校验
JSR-303提供的大部分校验注解已经够用, 也允许定制校验注解,比如在WorkInfoForm类中,我们新增一个加班时间:
@WorkOverTime int workTime;
属性workTime使用了注解@WorkOverTime,当属性值超过max值的时候,将会验证 失败。WorkOverTime跟其他注解差不多,但提供了@Constraint来说明用什么类作为验证注解实现类,代码如下:
import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import javax.validation.Constraint; import javax.validation.Payload; @Constraint(validatedBy = {WorkOverTimeValidator.class}) @Documented @Target({ElementType.ANNOTATION_TYPE,ElementType.METHOD,ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) public @interface WorkOverTime { String message() default "加班时间过长,不能超过{max}小时"; int max() default 5; Class<?> [] groups() default {}; Class<? extends Payload>[] payload() default {}; }
@Constraint注解说明用什么类来实现验证,我们将创建一个WorkOverTimeValidator来进行验证。注解必须提供如下信息:
message,用于创建错误信息,支持表达式,如“错误,不能超过(max)小时”。
groups,验证规则分组,比如新增和修改的验证规则不一样,分为两个组,验证注解必须提供。
payload,定义了验证的有效负荷。
WorkOverTimeValidator必须实现ConstraintValidator接口initialize方法及验证方法isValid:
package com.scg.springboot; import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; public class WorkOverTimeValidator implements ConstraintValidator<WorkOverTime, Integer>{ WorkOverTime work; int max; public void initialize(WorkOverTime work){ //获取注解的定义 this.work = work; max = work.max(); } @Override public boolean isValid(Integer value, ConstraintValidatorContext context) { if(value==null){ return true; } return value<max; } }
WebMvcConfigurer
WebMvcConfigurer 是用来全局定制化Spring Boot的MVC特性。开发者可以通过实现WebMvcConfigurer接口来配置应用的MVC全局特性。
package com.scg.springboot; import org.springframework.context.annotation.Configuration; import org.springframework.format.FormatterRegistry; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class MvcConfigurer implements WebMvcConfigurer{ //拦截器 @Override public void addInterceptors(InterceptorRegistry registry) { WebMvcConfigurer.super.addInterceptors(registry); } //跨域访问配置 @Override public void addCorsMappings(CorsRegistry registry) { //允许所有跨域访问 registry.addMapping("/**"); //允许来自domain2.com的跨域访问,并且限定访问路径为/api、方法是POST或者GET。 registry.addMapping("/api/**") .allowedOrigins("http://domain2.com") .allowedMethods("POST","GET"); } //格式化 @Override public void addFormatters(FormatterRegistry registry) { /** * 将HTTP请求映射到Controller方法的参数上后,Spring会自动进行类型转化。对于日期类型的参数, * Spring默认并没有配置如何将字符串转为日期类型。为了支持可按照指定格式转为日期类型,需要添加 * 一个DateFormatter类: */ registry.addFormatter(new DateFormatter("yyyy-MM-dd HH:mm:ss")); } //URI到视图到映射 @Override public void addViewControllers(ViewControllerRegistry registry) { WebMvcConfigurer.super.addViewControllers(registry); } }
使用JackSon
在MVC框架中,Spring Boot内置了Jackson来完成JSON的序列化和反序列化。在Controller中,方法注解为@ResponseBody,自动将方法返回的对象序列化成JSON。如果想自己全局自定义一个ObjectMapper来代替默认的,则可以使用Java Config,联合使用@Bean,代码如下:
package com.scg.springboot.controller; import java.text.SimpleDateFormat; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import com.fasterxml.jackson.databind.ObjectMapper; @Configuration public class JackSonConf { @Bean public ObjectMapper getObjectMapper(){ ObjectMapper objectMapper = new ObjectMapper(); objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")); return objectMapper; } }
上述Java Config会使Spring Boot使用自定义的Jackson来序列化而非默认配置的。以下是一个用来获取当前时间的请求:
package com.scg.springboot.controller; import java.util.Date; import java.util.HashMap; import java.util.Map; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; @Controller @RequestMapping("/json") public class JackSonController { @GetMapping("/user/{id}.json") public @ResponseBody Map<String,Date> now(){ Map<String,Date> mp = new HashMap<String,Date>(); mp.put("time", new Date()); return mp; } }
当用户访问now.json的时候,会得到如下输出:
{“time”:“2018-10-23 20:50:05”}
Redirect和Forward
有些情况下,Controller会返回客户端一个HTTP Redirect重定向请求,希望客户端按照指定地址重新发起一次请求,比如客户端登录成功后,重定向到后台系统首页。再比如客户端通过POST提交了一个名单,可以返回一个重定向请求到此订单明显的请求地址。这样做的好处是,如果用户再次刷新页面,则访问的是订单详情地址,而不会再次提交订单。
Controller中重定向可以返回以“redirect:”为前缀的URI:
@RequestMapping("/order/saveorder.html") public String saveOrder(Order order){ Long orderId = service.addOrder(order); return "redirect:/order/detail.html?orderId="+orderId; }
还可以在ModelAndView中设置带有“redirect:”前缀的URI:
ModelAndView view = new ModelAndView("redirect:/order/detail.html?orderId="+orderId);
或者直接使用RedirectView类:
RedirectView view = new RedirectView("/order/detail.html?orderId="+orderId);
Spring MVC也支持forward前缀,用来在Controller执行完毕后,再执行另外一个Controller的方法。
@RequestMapping("/bbs") public String index(){ //forward 到 module方法 return "forward:/bbs/module/1-1.html"; } @RequestMapping("/bbs/moudle/{type}-{page}") public ModelAndView module(@PathVariable int type,@PathVariable int page){ …… }
对所有访问/bbs的请求,都会forward到module方法,因为forward的URL是/bbs/module/1-1.html,正好匹配module方法的@RequestMapping的定义。
历史文章推荐:
猜你喜欢
- 2024-10-16 web前端移动端最流行的网页布局技术:flexbox弹性布局学习详解
- 2024-10-16 美团团购订单系统优化记 美团团购订单系统优化记录怎么删
- 2024-10-16 6.8 Apache访问控制 控制用户访问apache目录的配置文件
- 2024-10-16 快速学会html表单提交(php) html提交表单到php
- 2024-10-16 Django开发教程(七) django开发工具
- 2024-10-16 前端配置prettier,eslint ,stylelint
- 2024-10-16 电脑绝技教你22天学精Csharp之第十八天HTML和CSS补充3
- 2024-10-16 HTML部分第四章——HTML常用标签 html标签大全及用法图解
- 2024-10-16 基于Django+mysql的点餐系统设计-第八篇(H5主页调试-静态页面)
- 2024-10-16 什么是 Promise.all 什么是suv汽车
- 最近发表
- 标签列表
-
- gitpush (61)
- pythonif (68)
- location.href (57)
- tail-f (57)
- pythonifelse (59)
- deletesql (62)
- c++模板 (62)
- css3动画 (57)
- c#event (59)
- linuxgzip (68)
- 字符串连接 (73)
- nginx配置文件详解 (61)
- html标签 (69)
- c++初始化列表 (64)
- exec命令 (59)
- canvasfilltext (58)
- mysqlinnodbmyisam区别 (63)
- arraylistadd (66)
- node教程 (59)
- console.table (62)
- c++time_t (58)
- phpcookie (58)
- mysqldatesub函数 (63)
- window10java环境变量设置 (66)
- c++虚函数和纯虚函数的区别 (66)