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' }