其实这篇文章算不上是 springboot 的东西, 我们在 spring 普通项目中也是可以直接使用的
设置过滤器:
以前在普通项目中我们要在 web.xml 中进行 filter 的配置, 但是只从 servlet 3.0 后, 我们就可以在直接在项目中进行 filter 的设置, 因为她提供了一个注解 @WebFilter(在 javax.servlet.annotation 包下), 使用这个注解我们就可以进行 filter 的设置了, 同时也解决了我们使用 springboot 项目没有 Web.xml 的尴尬, 使用方法如下所示
- @WebFilter(urlPatterns="/*",filterName="corsFilter", asyncSupported = true)
- public class CorsFilter implements Filter{
- @Override
- public void init(FilterConfig filterConfig) throws ServletException {
- }
- @Override
- public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
- FilterChain chain) throws IOException, ServletException {
- HttpServletResponse response = (HttpServletResponse)servletResponse;
- HttpServletRequest request = (HttpServletRequest)servletRequest;
- chain.doFilter(servletRequest, servletResponse);
- }
- @Override
- public void destroy() {
- }
- }
其实在 WebFilter 注解中有一些属性我们需要进行设置, 比如 value,urlPatterns, 这两个属性其实都是一样的作用, 都是为了设置拦截路径, asyncSupported 这个属性是设置配置的 filter 是否支持异步响应, 默认是不支持的, 如果我们的项目需要进行请求的异步响应, 请求经过了 filter, 那么这个 filter 的 asyncSupported 属性必须设置为 true 不然请求的时候会报异常.
设置拦截器:
编写一个配置类, 继承 org.springframework.Web.servlet.config.annotation.WebMvcConfigurerAdapter 或者 org.springframework.Web.servlet.config.annotation.WebMvcConfigurationSupport 并重写 addInterceptors(InterceptorRegistry registry) 方法, 其实父类的 addInterceptors(InterceptorRegistry registry) 方法就是个空方法. 使用方法如下:
- @Configuration
- public class MvcConfig extends WebMvcConfigurationSupport {
- @Override
- public void addInterceptors(InterceptorRegistry registry) {
- InterceptorRegistration registration = registry.addInterceptor(new HandlerInterceptor() {
- @Override
- public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
- return true;
- }
- @Override
- public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
- }
- @Override
- public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
- }
- });
- // 配置拦截路径
- registration.addPathPatterns("/**");
- // 配置不进行拦截的路径
- registration.excludePathPatterns("/static/**");
- }
- }
配置监听器:
一般我们常用的就是 request 级别的 javax.servlet.ServletRequestListener 和 session 级别的 javax.servlet.http.HttpSessionListener, 下面以 ServletRequestListener 为例, 编写一个类实现 ServletRequestListener 接口并实现 requestInitialized(ServletRequestEvent event) 方法和 requestDestroyed(ServletRequestEvent event) 方法, 在实现类上加上 @WebListener(javax.servlet.annotation 包下), 如下所示
- @WebListener
- public class RequestListener implements ServletRequestListener {
- @Override
- public void requestDestroyed(ServletRequestEvent sre) {
- System.out.println("请求结束");
- }
- @Override
- public void requestInitialized(ServletRequestEvent sre) {
- System.out.println("请求开始");
- }
- }
这样每一个请求都会被监听到, 在请求处理前 equestInitialized(ServletRequestEvent event) 方法, 在请求结束后调用 requestDestroyed(ServletRequestEvent event) 方法, 其实在 spring 中有一个非常好的例子, 就是 org.springframework.Web.context.request.RequestContextListener 类
- public class RequestContextListener implements ServletRequestListener {
- private static final String REQUEST_ATTRIBUTES_ATTRIBUTE =
- RequestContextListener.class.getName() + ".REQUEST_ATTRIBUTES";
- @Override
- public void requestInitialized(ServletRequestEvent requestEvent) {
- if (!(requestEvent.getServletRequest() instanceof HttpServletRequest)) {
- throw new IllegalArgumentException(
- "Request is not an HttpServletRequest:" + requestEvent.getServletRequest());
- }
- HttpServletRequest request = (HttpServletRequest) requestEvent.getServletRequest();
- ServletRequestAttributes attributes = new ServletRequestAttributes(request);
- request.setAttribute(REQUEST_ATTRIBUTES_ATTRIBUTE, attributes);
- LocaleContextHolder.setLocale(request.getLocale());
- RequestContextHolder.setRequestAttributes(attributes);
- }
- @Override
- public void requestDestroyed(ServletRequestEvent requestEvent) {
- ServletRequestAttributes attributes = null;
- Object reqAttr = requestEvent.getServletRequest().getAttribute(REQUEST_ATTRIBUTES_ATTRIBUTE);
- if (reqAttr instanceof ServletRequestAttributes) {
- attributes = (ServletRequestAttributes) reqAttr;
- }
- RequestAttributes threadAttributes = RequestContextHolder.getRequestAttributes();
- if (threadAttributes != null) {
- // We're assumably within the original request thread...
- LocaleContextHolder.resetLocaleContext();
- RequestContextHolder.resetRequestAttributes();
- if (attributes == null && threadAttributes instanceof ServletRequestAttributes) {
- attributes = (ServletRequestAttributes) threadAttributes;
- }
- }
- if (attributes != null) {
- attributes.requestCompleted();
- }
- }
- }
在这个类中, spring 将每一个请求开始前都将请求进行了一次封装并设置了一个 threadLocal, 这样我们在请求处理的任何地方都可以通过这个 threadLocal 获取到请求对象, 好处当然是有的啦, 比如我们在 service 层需要用到 request 的时候, 可以不需要调用者传 request 对象给我们, 我们可以通过一个工具类就可以获取, 岂不美哉.
扩充: 在 springboot 的启动类中我们可以添加一些 ApplicationListener 监听器, 例如:
- @SpringBootApplication
- public class DemoApplication {
- public static void main(String[] args) {
- SpringApplication application = new SpringApplication(DemoApplication.class);
- application.addListeners(new ApplicationListener<ApplicationEvent>() {
- @Override
- public void onApplicationEvent(ApplicationEvent event) {
- System.err.println(event.toString());
- }
- });
- application.run(args);
- }
- }
ApplicationEvent 是一个抽象类, 她的子类有很多比如 ServletRequestHandledEvent(发生请求事件的时候触发),ApplicationStartedEvent(应用开始前触发, 做一些启动准备工作),ContextRefreshedEvent(容器初始化结束后触发), 其他还有很多, 这里不再多说, 但是这些 ApplicationListener 只能在 springboot 项目以 main 方法启动的时候才会生效, 也就是说项目要打 jar 包时才适用, 如果打 war 包, 放在 Tomcat 等 Web 容器中是没有效果的.
来源: https://www.cnblogs.com/zzw-blog/p/10656181.html