过滤器&拦截器
过滤器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 {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("CustomFilter init");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("CustomFilter doFilter");
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public 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文件
@Configuration
public class FilterConfig {
@Bean
public 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 {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("CustomFilter2 init");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("CustomFilter2 doFilter");
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public 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
@ServletComponentScan
public 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;
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Autowired
private CustomInterceptor customInterceptor;
/**
* 注册自定义的拦截器,并且定义拦截规则
* @param registry
*/
@Override
public 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 {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("CustomInterceptor------preHandle");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("CustomInterceptor------postHandle");
}
@Override
public 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;
@RestController
public 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
@AllArgsConstructor
public class Guest {
@NotBlank(message = "快乐小慧自定义的名字不能为空")
private String name;
@NotBlank
private 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;
@RestController
public 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
@AllArgsConstructor
public class Guest {
//通过{key}来获取对应的value
@NotBlank(message = "{guest.name.notblank}")
private String name;
@NotBlank
private String role;
}