1.1自定义拦截器类css
public class RoleInterceptor implements HandlerInterceptor { /** * 拦截器处理器处理以前会先通过该方法:前置方法 * @return 若是返回true,会进入(放行)下一个拦截器(链) */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("前置方法,返回true,进入后面的处理流程,返回false,完成处理,请求结束"); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("后置方法,处理器完成处理,视图渲染以前调用"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("完成方法:视图渲染完成"); } }
1.2 配置拦截器html
java配置:在springMVCConfig类上配置前端
package com.wise.tiger.config; //*************************import******************************// iguration @ComponentScan(basePackages = "com.wise.tiger.web") @EnableWebMvc public class WebConfig implements WebMvcConfigurer { // 视图解析器 @Bean public InternalResourceViewResolver viewResolver() { var viewResolver = new InternalResourceViewResolver(); viewResolver.setPrefix("/WEB-INF/pages/"); viewResolver.setSuffix(".jsp"); return viewResolver; } @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new RoleInterceptor()).addPathPatterns("/control/**"); } @Override // 静态资源不被前端过滤器 public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/static/**")// 添加静态资源的url-pattern .addResourceLocations("/static/"); } }
xml配置:在spring-mvc.xml上配置java
<mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/controll/**"/> <bean class="com.wise.bbs.interceptor.RoleInterceptor"/> </mvc:interceptor> </mvc:interceptors>
在xml配置中,用元素mvc:interceptors配置拦截器,在里面能够配置多个拦截器,path属性告诉拦截器拦截什么请求,它使用一个正则式的匹配。下面介绍下用java代码 配置:mysql
1.3 多个拦截器执行顺序git
多个拦截器执行顺序犹如嵌套的if语句。首先讨论preHandler方法返回为true的状况,先建三个角色拦截器,对其进行测试,能够看到结果是这样的 (责任链模式)web
preHandle1
preHandle2
preHandle3
postHadle3
postHadle2
postHadle1
afterCompletion3
afterCompletion2
afterCompletion1正则表达式
有些时候前置方法可能返回false,咱们将RoleInterceptor2中的前置方法给为false进行测试后获得的结果:spring
preHandle1
preHandle2
afterCompletion1sql
注意:当其中一个preHandle方法返回false后,按配置顺序,后面的preHandle方法都不会执行了,而控制器和后面的postHandle也不会再运行。
Spring 提供了对Bean的功能校验,经过注解@Valid标明哪一个Bean须要启用注解式的验证。在javax.validation.constrains.*中定义了一系列的JSR 303规范给出的注解:
限制 |
说明 |
限制只能为null |
|
限制必须不为null |
|
限制必须为false |
|
@AssertTrue |
限制必须为true |
@DecimalMax(value) |
限制必须为一个不大于指定值的数字 |
@DecimalMin(value) |
限制必须为一个不小于指定值的数字 |
@Digits(integer,fraction) |
限制必须为一个小数,且整数部分的位数不能超过integer,小数部分的位数不能超过fraction |
@Future |
限制必须是一个未来的日期 |
@Max(value) |
限制必须为一个不大于指定值的数字 |
@Min(value) |
限制必须为一个不小于指定值的数字 |
@Past |
限制必须是一个过去的日期 |
@Pattern(value) |
限制必须符合指定的正则表达式 |
@Size(max,min) |
限制字符长度必须在min到max之间 |
|
邮箱类型 |
@NotEmpty |
集合,不为空 |
@NotBlank |
不为空字符串 |
@Positive |
数字,正数 |
@PositiveOrZero |
数字,正数或0 |
@NegativeOrZero |
数字,负数 |
@NegativeOrZero |
数字,负数或0 |
@PastOrPresent |
过去或者如今日期 |
@FutrueOrPresent |
未来或者如今日期 |
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <title>添加员工</title> </head> <body> <form action="${pageContext.request.contextPath }/control/emp/save" method="post" > 用户名:<input type="text" name="username" placeholder="请输入用户名,最小4位,最大12位" required/> <span></span> <br/> 密码:<input type="password" name="password" placeholder="请输入登陆密码"/><br/> 电子邮箱:<input type="email" name="email" placeholder="请输入电子邮箱"/><br/> 员工生日:<input type="date" name="bornDate" /><br/> 薪水:<input type="number" name="salary" placeholder="请输入员工薪水" /><br/> 联系电话:<input type="text" name="phone" placeholder="请输入员工联系电话" pattern="^1[358]\d{9}$"/><br/> 员工简介: <textarea placeholder="请输入员工简介" name="intro"></textarea> <br/> <input type="submit" value="提交" /> <input type="reset"> </form:form> </body> </html>
创建pojo,肯定校验规则:
public class Employee { private Integer id; /** * 用户名,不容许为空,最小4位,最大12位 */ @NotBlank(message = "用户名不能为空") @Size(min = 4,max = 12,message = "{employee.username.valid.size.message}") private String username; /** * 密码:不能为空,最小6位 */ @NotBlank(message = "密码不能为空") @Size(min = 6,max = 12,message = "密码最低6位") private String password; /** * 电子邮箱,不能为空,要知足邮箱基本格式 */ @NotNull(message = "邮箱不能为空") @Email(message="邮箱必须知足基本格式") private String email; /** * 员工生日,格式为:yyyy-MM-dd * 必须是一个过去的日期 */ @DateTimeFormat(iso = ISO.DATE) @Past(message = "你不能录用还未出生的员工") private LocalDate bornDate; /** * 入职日期,格式为:yyyy-MM-dd * 必须是一个如今或者未来的日期 */ @DateTimeFormat(iso = ISO.DATE) @FutureOrPresent private LocalDate entryDate = LocalDate.now(); /** * 员工联系(手机)电话 * 必须符合手机号码格式(正则表达式) */ @Pattern(regexp = "^1[358]\\d{9}$",message = "请输入正确的手机号码") private String phone; /** * 员工薪水,最低2000,最高5万 */ @Min(value = 2000,message="工资不能低于2000,不然麻烦了") @Max(value=50000,message="工资不能大于50000,不然交奢侈税") private float salary; /** * 员工简介,最大不超过200 */ @Size(min = 6,max = 12,message = "员工简介不能超过200字") private String intro; //***************setter and getter*************/ }
这样就定义了一个pojo,用于接收表单的信息。字段上面的注解反映了对每个字段的验证要求,这样就能够加入对应校验,若是没有指定message属性,会生成默认的错误信息。message配置项用来定义当校验失败后的错误信息,这样就能启动Spring的检验规则来校验表单了。
在post请求接收数据时,用控制器验证表单:
@Controller @RequestMapping("/control/emp") public class EmployeeController { @RequestMapping("/save") public String save(@Valid Employee emp,BindingResult errors) { if(errors.hasErrors()) { return "emp/emp_save"; } return "redirect:./list"; } }
使用了注解@Valid标明这个Bean将会被校验,另一个类型为BindingResult的参数(或者为Errors)是用于保存校验是否存在错误信息的,也就是当采用JSR 303规范进行校验后,它会将这个错误信息保存到这个参数中,在方法中判断是否有错误信息,若是有错误信息,跳转到填写表单页面告诉用户错误信息。
如何在jsp页面中显示错误信息呢?这时可使用jsp提供给咱们的标签库
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <span style="background-color: #fafafa; font-family: monospace;"><%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%></span> <!DOCTYPE html> <html> <head> <title>添加员工</title> </head> <body> <form:form action="${pageContext.request.contextPath }/control/emp/save" method="post" modelAttribute="employee"> 用户名:<input type="text" name="username" placeholder="请输入用户名,最小4位,最大12位" required/> <span><span style="background-color: #fafafa; font-family: monospace;"><form:errors path="username" cssStyle="color: red"/></span></span> <br/> 密码:<input type="password" name="password" placeholder="请输入登陆密码"/><br/> 电子邮箱:<input type="email" name="email" placeholder="请输入电子邮箱"/><br/> 员工生日:<input type="date" name="bornDate" /><br/> 薪水:<input type="number" name="salary" placeholder="请输入员工薪水" /><br/> 联系电话:<input type="text" name="phone" placeholder="请输入员工联系电话" pattern="^1[358]\d{9}$"/><br/> 员工简介: <textarea placeholder="请输入员工简介" name="intro"></textarea> <br/> <input type="submit" value="提交" /> <input type="reset"> </form:form> </body> </html>
看起来彷佛很是不错,可是咱们的message错误提示信息是硬编码在pojo身上,为了不其硬编码而实现可配置,咱们在src/main/resource下新建messageSource.properties文件:
employee.username.valid.notnull.message=用户名不能为空 employee.username.valid.size.message=用户名不能少于4位且不能超过12位
上面简单罗列了两个错误信息配置,其它道理同样,哪怎么应用(读取)指定的错误信息呢?在pojo验证规则之上:
/** * 用户名,不容许为空,最小4位,最大12位 */ @NotBlank(message = "{employee.username.valid.notnull.message}") @Size(min = 4,max = 12,message = "{employee.username.valid.size.message}") private String username;
能够采用{}表达式对配置文件的key加以读取其对应的value。其它字段同理,到这里还不能读取指定配置文件,须要告诉spring的检验器加载什么样的配置文件,在springMVCConfig配置类配置:
@Configuration @ComponentScan(basePackages = "com.wise.tiger.web") @EnableWebMvc public class WebConfig implements WebMvcConfigurer{ @Bean public InternalResourceViewResolver viewResolver() { var viewResolver = new InternalResourceViewResolver(); viewResolver.setPrefix("/WEB-INF/pages/"); viewResolver.setSuffix(".jsp"); return viewResolver; } @Override //静态资源不被前端过滤器过滤 public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/static/**")//添加静态资源的url-pattern .addResourceLocations("/static/"); } @Bean public ReloadableResourceBundleMessageSource messageResource() { var messageResource = new ReloadableResourceBundleMessageSource(); //若是不指定,默认会去classpath下的messages.properties配置文件 messageResource.setBasename("classpath:resourceMessage"); return messageResource; } /** * 添加表单校验器 */ @Override public Validator getValidator() { var validator = new LocalValidatorFactoryBean(); validator.setProviderClass(HibernateValidator.class); validator.setValidationMessageSource(messageResource()); return validator; } }
1.定义分组:能够采用标识接口来进行分组区分
//分组校验1 public interface ValidationGroup1 { } //分组校验2 public interface ValidationGroup2 {
/** * 用户名,不容许为空,最小4位,最大12位 */ @NotBlank(message = "{employee.username.valid.notnull.message}",groups = ValidationGroup1.class) @Size(min = 4,max = 12,message = "{employee.username.valid.size.message}",groups = ValidationGroup2.class) private String username;
@Controller @RequestMapping("/control/emp") public class EmployeeController { @RequestMapping("/save") public String save( @Validated(ValidationGroup2.class) @ModelAttribute Employee emp,BindingResult errors,Model model) { if(errors.hasErrors()) { for (var i = 0; i < errors.getErrorCount();i++) { System.out.println(errors.getObjectName() + ":" + errors.getFieldError().getDefaultMessage()); } return "emp/emp_save"; } return "redirect:./list"; } }
public interface Validator { /** * 判断当前校验器是否用于检验clazz类型的pojo * @param clazz -- pojo类型 * @return true 启动校验,false 不校验 */ @Override public boolean supports(Class<?> clazz) { return false; } /** * 检验pojo的合法性 * @param target 请求对象 * @param errors 错误信息 */ @Override public void validate(Object target, Errors errors) { } }
、Validator接口是SpringMvc校验表单的核心接口,它只是一个验证器,在Spring中最终被注册到验证器的列表中,这样就能够提供给各个控制器去定义,而后经过supports方法断定是否会启用验证器去验证数据。对于校验的过程,则是经过validate方法去实现的。
package com.wise.tiger.pojo; import org.springframework.validation.Errors; import org.springframework.validation.Validator; /** * @Description: 员工校验器 * @author: <a href="mailto:1020zhaodan@163.com">Adan</a> * @date: 2019年5月28日 下午7:23:40 * @version:1.0-snapshot */ public class EmployeeValidator implements Validator { /** * 判断当前校验器是否用于检验clazz类型的pojo * @param clazz -- pojo类型 * @return true 启动校验,false 不校验 */ @Override public boolean supports(Class<?> clazz) { //判断验证是否为Employee,若是是则进行校验 return Employee.class.equals(clazz); } /** * 检验pojo的合法性 * @param target 请求对象 * @param errors 错误信息 */ @Override public void validate(Object target, Errors errors) { var employee = (Employee)target; //对employee pojo类中年薪计算规则为薪水 * 16 var yearlySalary = employee.getSalary() * 16; //若是年薪小于1,则认为业务错误 if(yearlySalary < 1) //加入错误信息 errors.rejectValue("yearlySalary", null, "年薪和月薪不匹配,月薪输入错误"); } }
须要将该验证器捆绑到对应的控制器中,Spring MVC提供了注解@InitBinder,经过该注解就能够将验证器和控制器捆绑在一块儿,这样就能对请求表单进行验证了。
@Controller @RequestMapping("/control/emp") public class EmployeeController { @InitBinder public void initBinder(DataBinder binder){ //数据绑定器加入验证器 binder.setValidator(new EmployeeValidator()); } @RequestMapping("/save") public String save( @Validated(ValidationGroup2.class) @ModelAttribute Employee emp,BindingResult errors,Model model) { if(errors.hasErrors()) { for (var i = 0; i < errors.getErrorCount();i++) { System.out.println(errors.getObjectName() + ":" + errors.getFieldError().getDefaultMessage()); } return "emp/emp_save"; } return "redirect:./list"; } }
这样就能对比较复杂的逻辑关系进行校验了。
springMVC自带HandlerExceptionResolver异常处理器,定义一个异常处理器,实现HandlerExceptionResolver接口,重写方法中的handler是指放生错误时的处理对象,ex指发生的错误,加上@Component并打开注解开关后会自动生效。
@Component public class ExceptionResolver implements HandlerExceptionResolver{ @Override public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { var mv = new ModelAndView(); mv.addObject("message","哎呀,一不当心出错了呀!"); mv.setViewName("message"); return mv; } }
springMVC自带Converter转换类,定义一个转换器实现Converter类,并在Converter后面写上源类型和目标类型,重写convert方法加上@Component并打开注解开关后会自动生效。
@Component public class PrivilegeConverter implements Converter<String[], Set<Privilege>> { @Override public Set<Privilege> convert(String[] source) { if(source == null) return null; var ret = new HashSet<Privilege>(); for(String dest : source) ret.add(new Privilege(dest.split("\\_")[0],dest.split("\\_")[1])); return ret; } }
附依赖:
dependencies { compile group: 'org.springframework', name: 'spring-context', version: '5.1.7.RELEASE' compile group: 'org.springframework', name: 'spring-webmvc', version: '5.1.7.RELEASE' compile group: 'org.springframework', name: 'spring-test', version: '5.1.7.RELEASE' providedCompile group: 'javax.servlet.jsp', name: 'javax.servlet.jsp-api', version: '2.3.3' providedCompile group: 'javax.servlet', name: 'javax.servlet-api', version: '4.0.1' compile group: 'taglibs', name: 'standard', version: '1.1.2' compile group: 'javax.servlet', name: 'jstl', version: '1.2' compile group: 'io.springfox', name: 'springfox-swagger2', version: '2.9.2' compile group: 'io.springfox', name: 'springfox-swagger-ui', version: '2.9.2' compile group: 'org.mybatis', name: 'mybatis-spring', version: '2.0.1' compile group: 'org.mybatis', name: 'mybatis', version: '3.5.1' compile group: 'com.alibaba', name: 'druid', version: '1.1.16' compile group: 'mysql', name: 'mysql-connector-java', version: '8.0.16' compile group: 'org.springframework', name: 'spring-jdbc', version: '5.1.7.RELEASE' compile group: 'javax.validation', name: 'validation-api', version: '2.0.1.Final' compile group: 'org.hibernate', name: 'hibernate-validator', version: '6.0.16.Final' compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.9.9' }