过滤器&拦截器

过滤器Filter
过滤器的实现基于回调函数
实现方式一:
1)创建类实现Filter接口;2)注入springboot容器(代码注入 / 通过注解@WebFilter注入)
package com.duing.filter;import javax.servlet.*;import javax.servlet.annotation.WebFilter;import java.io.IOException;/*** 原先实现过滤器,需要在web.xml中进行配置,*/public class CustomFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {System.out.println("CustomFilter init");}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {System.out.println("CustomFilter doFilter");filterChain.doFilter(servletRequest, servletResponse);}@Overridepublic void destroy() {System.out.println("CustomFilter destroy");}}
package com.duing.config;import com.duing.filter.CustomFilter;import org.springframework.boot.web.servlet.FilterRegistrationBean;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;//代替了web.xml文件@Configurationpublic class FilterConfig {@Beanpublic FilterRegistrationBean<CustomFilter> filterRegistrationBean(){FilterRegistrationBean<CustomFilter> filterRegistrationBean=new FilterRegistrationBean<>();filterRegistrationBean.setFilter(new CustomFilter());filterRegistrationBean.addUrlPatterns("/*");//过滤规则//filterRegistrationBean.setOrder(0);//决定注册的优先级return filterRegistrationBean;}}
实现方式二:
1)创建类实现Filter接口;@WebFilter(filterName=”customFilter”,urlPatterns={“/*”})
2)入口类增加注解@ServletComponentScan
package com.duing.filter;import javax.servlet.*;import javax.servlet.annotation.WebFilter;import java.io.IOException;@WebFilter(filterName = "customFilter2",urlPatterns = {"/*"})public class CustomFilter2 implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {System.out.println("CustomFilter2 init");}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {System.out.println("CustomFilter2 doFilter");filterChain.doFilter(servletRequest, servletResponse);}@Overridepublic void destroy() {System.out.println("CustomFilter2 destroy");}}
package com.duing;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.boot.web.servlet.ServletComponentScan;@SpringBootApplication@ServletComponentScanpublic class ServletApplication {public static void main(String[] args) {SpringApplication.run(ServletApplication.class, args);}}


拦截器Interceptor
拦截器(代理模式)的实现基于反射
实现方式:
1)创建拦截器类实现HandlerInterceptor接口 2)创建配置类实现WebMvcConfigurer接口
package com.duing.config;import com.duing.interceptor.CustomInterceptor;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Configuration;import org.springframework.web.servlet.config.annotation.InterceptorRegistry;import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configurationpublic class InterceptorConfig implements WebMvcConfigurer {@Autowiredprivate CustomInterceptor customInterceptor;/*** 注册自定义的拦截器,并且定义拦截规则* @param registry*/@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(customInterceptor).addPathPatterns("/**");}}
package com.duing.interceptor;import org.springframework.stereotype.Service;import org.springframework.web.servlet.HandlerInterceptor;import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;@Service//交给spring管理,看做是一个服务public class CustomInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("CustomInterceptor------preHandle");return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("CustomInterceptor------postHandle");}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("CustomInterceptor------afterCompletion");}}
package com.duing.controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;@RestControllerpublic class ServletController {@RequestMapping("/servlet")public String servlet(){System.out.println("ServletController---");return "hello";}}

错误&异常处理机制
一、错误和异常
Error ExceptionError经常是程序无法处理的 (用户引入的错误 系统的错误)Exception 程序员引发的,能够在程序中处理, try catch / throws
优秀的处理机制
问题:怎么处理? 如何做到优秀?
二、处理方式
统共分为三种:数据验证错误、错误页指派、全局异常处理
1)数据验证错误

注解 @NotNull @NotEmpty @NotBlank 三者的区别
@NotNull不为空 广泛用于基础类的判断(int、double)
@NotEmpty 内容不为空 广泛用于集合等的判断(map、set)
@NotBlank不为空串 广泛用于String类型的判断
package com.duing.bean;import lombok.AllArgsConstructor;import lombok.Data;import javax.validation.constraints.NotBlank;@Data@AllArgsConstructorpublic class Guest {@NotBlank(message = "快乐小慧自定义的名字不能为空")private String name;@NotBlankprivate String role;}
package com.duing;import com.duing.bean.Guest;import javax.validation.ConstraintViolation;import javax.validation.Validation;import javax.validation.Validator;import java.util.Set;public class GuestValidTest {public static void main(String[] args) {//通过validation创建一个validator实例//普通模式Validator validator= Validation.buildDefaultValidatorFactory().getValidator();//创建一个不符合要求的bean(不得为空串)Guest guest=new Guest("","");//开始验证 接受验证结果Set<ConstraintViolation<Guest>> violationSet= validator.validate(guest);for (ConstraintViolation<Guest> violation:violationSet){System.out.println(violation.getPropertyPath()+","+violation.getMessage());}}}
这是校验框架的模式之一,“普通模式”(遍历所有属性,不符合校验规则的都返回)
执行结果:
“快速失败模式”(遍历所有属性,有一个不符合校验规则即返回)
Guest.java不变
package com.duing;import com.duing.bean.Guest;import javax.validation.ConstraintViolation;import javax.validation.Validation;import javax.validation.Validator;import java.util.Set;public class GuestValidTest {public static void main(String[] args) {//通过validation创建一个validator实例//快速失败模式Validator validatorFastFail=Validation.byDefaultProvider().configure().addProperty("hibernate.validator.fail_fast","true")//打开快速失败模式.buildValidatorFactory().getValidator();//创建一个不符合要求的bean(不得为空串)Guest guest=new Guest("","");//开始验证 接受验证结果Set<ConstraintViolation<Guest>> violationFastFailSet = validatorFastFail.validate(guest);for(ConstraintViolation violation : violationFastFailSet){System.out.println(violation.getPropertyPath() + "," + violation.getMessage());}}}

SpringBoot 中可以集成Validation对数据进行校验
这里我们使用postman测试
默认的处理方式
package com.duing.controller;import com.duing.bean.Guest;import org.springframework.web.bind.annotation.PostMapping;import org.springframework.web.bind.annotation.RestController;import javax.validation.Valid;@RestControllerpublic class GuestController {/**** @Valid 直接放在bean前方* 用来校验它是否符合注解规则* 校验失败时直接返回400和失败原因* 处理方式是普通模式** @param guest* @return*/@PostMapping("/guest")public String add(@Valid Guest guest){return "Success";}}


自定义的处理方式通过BindingResult实现(BindingResult要紧跟在@Valid注解后面)
@PostMapping("/guest")public String add(@Valid Guest guest, BindingResult result){//校验结果有错误if(result.getErrorCount()>0){List<FieldError> fieldErrors= result.getFieldErrors();StringBuilder builder=new StringBuilder();for (FieldError error:fieldErrors){builder.append(error.getField());builder.append("\t");builder.append(error.getDefaultMessage());builder.append("\n");}return builder.toString();}return "Success";}

SpringBoot支持通过配置文件设置校验信息,文件名为ValidationMessages.properties
通过{key}来获取对应的value
package com.duing.bean;import lombok.AllArgsConstructor;import lombok.Data;import javax.validation.constraints.NotBlank;@Data@AllArgsConstructorpublic class Guest {//通过{key}来获取对应的value@NotBlank(message = "{guest.name.notblank}")private String name;@NotBlankprivate String role;}
