澳门网络娱乐游戏平台-澳门电子游戏娱乐网址-官方直营

Spring Boot Servlet、Filter、Listener、Interceptor

SpringBoot自定义拦截器完成IP白名单功能

  springboot作为微服务的便捷框架,在错误页面管理上也许有了部分新的管理,不一致于从前的pringmvc500的页面管理是比较轻松的,用java config可能xml的花样,定义如下的Bean就能够

Web开拓应用 Controller 基本上能够做到超越1/3需求,但是大家还有可能会用到 Servlet、Filter、Listener、Interceptor 等等。

转发请申明源地址:

 1 <bean
 2 class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> 
 3   <property name="exceptionMappings"> 
 4     <props> 
 5      <prop key="org.apache.shiro.authz.UnauthenticatedException">pages/403</prop> 
 6      <prop key="org.apache.shiro.authz.UnauthorizedException">pages/403</prop> 
 7      <prop key="org.apache.shiro.authc.LockedAccountException">pages/locked</prop> 
 8      <prop key="java.lang.Throwable">pages/500</prop> 
 9     </props> 
10   </property> 
11 </bean>

当使用Spring-Boot时,嵌入式Servlet容器通过扫描声明的章程注册Servlet、Filter和Servlet规范的享有监听器(如HttpSessionListener监听器)。

  首先,相关成效已经上线了,且先让本身先祷祝生龙活虎番:  

  404相比独特,有二种方法能够参见

Spring boot 的主 Servlet 为 DispatcherServlet,其默许的url-pattern为“/”。或许大家在应用中还亟需定义越多的Servlet,该怎么采纳SpringBoot来达成吗?

澳门官网网址 1

1.先设置 dispatcherServlet 

在spring boot中增加自个儿的Servlet有三种艺术,代码注册Servlet和注释自动注册(Filter和Listener也是那样)。

  阿门~ (-__-)

1 @Bean
2 public ServletRegistrationBean dispatcherRegistration(DispatcherServlet dispatcherServlet) { 
3    ServletRegistrationBean registration = new ServletRegistrationBean(dispatcherServlet); 
4    dispatcherServlet.setThrowExceptionIfNoHandlerFound(true); 
5    return registration; 
6 }

大器晚成、代码注册通过ServletRegistrationBean、 FilterRegistrationBean 和ServletListenerRegistrationBean 得到调控。也得以通过兑现 ServletContextInitializer 接口直接登记。

  额,正文开首前笔者先说两句吧,能成功那个效果特别感激csdn网络亲密的朋友的后生可畏篇帖子的救助,在那深表以致谢澳门官网网址 2

  再追加管理错误页面包车型大巴handler,加上 @ControllerAdvice  表明

二、在 SpringBootApplication 上行使@ServletComponentScan 评释后,Servlet、Filter、Listener 能够向来通过 @WebServlet、@WebFilter、@WebListener 注明自动注册,不供给任何代码。

  那位相爱的人的源贴也很正确,如感觉自家写的不得了,可以运动这里:

 1 @ControllerAdvice
 2 public class GlobalControllerExceptionHandler { 
 3    public static final String DEFAULT_ERROR_VIEW = "pages/404"; 
 4 
 5 @ExceptionHandler(value = NoHandlerFoundException.class) 
 6 public ModelAndView defaultErrorHandler(HttpServletRequest req, Exception e) throws Exception { 
 7     ModelAndView mav = new ModelAndView(); 
 8      mav.addObject("exception", e); 
 9      mav.addObject("url", req.getRequestURL()); 
10      mav.setViewName(DEFAULT_ERROR_VIEW); 
11      return mav; 
12    } 
13  }

通过代码注册Servlet示例代码:
SpringBootSampleApplication.java

  先,小编简单来讲下这么做的来头,公司明日的主体结构是thinkphp的,由于php的开荒职员走的早就大半了再增加php岗位一时半会也很难补上,别的工头也是写java的...,算是元婴各样吧,以后具有的着入眼职能代码都慢慢的往java方向迁移,同有时间,请在意,java的开荒人士近来来看唯有本身一个,遂结构迁移只好以springboot模块功效的秘籍渐渐走,前端的构造刚早先走,又不能够上线,只好将付出出来的模块给php后端调用,三种语言的后端数据人机联作又无法太复杂(正是无法加Auth卡塔尔(英语:State of Qatar),不然会加剧php与java数据交互作用的工本,遂,就有了在springboot端做ip过滤。

  不过上面这种拍卖方法,会导致对js,css等能源的过滤,最棒使用第三种艺术

package org.springboot.sample;

import org.springboot.sample.servlet.MyServlet;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.embedded.ServletRegistrationBean;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.context.annotation.Bean;
import org.springframework.web.servlet.DispatcherServlet;

@SpringBootApplication
public class SpringBootSampleApplication {

    /**
     * 使用代码注册Servlet(不需要@ServletComponentScan注解)
     *
     * @return
     * @author SHANHY
     * @create  2016年1月6日
     */
    @Bean
    public ServletRegistrationBean servletRegistrationBean() {
        return new ServletRegistrationBean(new MyServlet(), "/xs/*");// ServletName默认值为首字母小写,即myServlet
    }

    public static void main(String[] args) {
        SpringApplication.run(SpringBootSampleApplication.class, args);
    }
}

  额,笔者留心深入分析了下,达成此功效如今差十分少可有三种艺术:

2.集成 ErrorController 

MyServlet.java

    A>因为spring框架中各类controller就是二个拦截器,遂,能够在每种拦截器里面加ip过滤,总体上看的难点是=>代码会超负荷冗余,不实惠维护

 1 @Controller
 2 public class MainsiteErrorController implements ErrorController { 
 3 
 4   private static final String ERROR_PATH = "/error"; 
 5 
 6 @RequestMapping(value=ERROR_PATH) 
 7 public String handleError(){ 
 8     return "pages/404"; 
 9 } 
10 
11 @Override
12 public String getErrorPath() { 
13       // TODO Auto-generated method stub 
14       return ERROR_PATH; 
15     } 
16   }
package org.springboot.sample.servlet;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet
 *
 * @author   单红宇(365384722)
 * @myblog  http://blog.csdn.net/catoop/
 * @create    2016年1月6日
 */
//@WebServlet(urlPatterns="/xs/*", description="Servlet的说明")
public class MyServlet extends HttpServlet{

    private static final long serialVersionUID = -8685285401859800066L;

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println(">>>>>>>>>>doGet()<<<<<<<<<<<");
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println(">>>>>>>>>>doPost()<<<<<<<<<<<");
        resp.setContentType("text/html");  
        PrintWriter out = resp.getWriter();  
        out.println("<html>");  
        out.println("<head>");  
        out.println("<title>Hello World</title>");  
        out.println("</head>");  
        out.println("<body>");  
        out.println("<h1>大家好,我的名字叫Servlet</h1>");  
        out.println("</body>");  
        out.println("</html>"); 
    }

}

    B>能够在springboot提供的拦截器里面做,那样。。。,恐怕是相比适宜的,但就像也会设有代码冗余的主题材料

3.拦截器的秘籍

选用申明注册Servlet示例代码
SpringBootSampleApplication.java

    C>可以在挨门逐户模块的顶上部分使用拦截器组件,例如Zuul,。。。难点是大家将来的框架还未到家到这一步

  几眼前给我们介绍一下SpringBoot中拦截器的用法,比较Struts第22中学的拦截器,SpringBoot的拦截器就展现特别有利轻便了。
澳门官网网址,只须要写多少个贯彻类就足以轻便达成拦截器的机能了,并且无需配置任何多余的音讯,对技术员来讲差相当的少是生机勃勃种便利啊。
废话非常少说,上面初步介绍拦截器的兑现进度:

package org.springboot.sample;

import org.springboot.sample.servlet.MyServlet;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.embedded.ServletRegistrationBean;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.context.annotation.Bean;
import org.springframework.web.servlet.DispatcherServlet;

@SpringBootApplication
@ServletComponentScan
public class SpringBootSampleApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringBootSampleApplication.class, args);
    }
}

  其实,如框架相比较康健的境况下,以上办法都不太好,最棒的是将前端分离,间接调用java,登录校验等利用OAuth2来做具名认证。

先是步:创制大家和谐的阻拦器类并促成  HandlerInterceptor  接口。

MyServlet2.java

  欸~,大概是因为个体力量简单,小编就说说利用springboot自带的拦截器做的职能吗。

 1 package example.Interceptor;
 2 import javax.servlet.http.HttpServletRequest;
 3 import javax.servlet.http.HttpServletResponse;
 4 import org.springframework.stereotype.Controller;
 5 import org.springframework.web.bind.annotation.RequestMapping;
 6 import org.springframework.web.servlet.HandlerInterceptor;
 7 import org.springframework.web.servlet.ModelAndView;
 8 
 9 /**
10  * 自定义拦截器1 
11  *
12  * @author 林志强(208017534)
13  * @myblog www.wolzq.com
14  * @create 2016年9月20日
15  */
16 @Controller
17 public class ErrorInterceptor implements HandlerInterceptor {
18 
19     /**
20      * preHandle方法是进行处理器拦截用的,顾名思义,该方法将在Controller处理之前进行调用,SpringMVC中的Interceptor拦截器是链式的,可以同时存在 
21      * 多个Interceptor,然后SpringMVC会根据声明的前后顺序一个接一个的执行,而且所有的Interceptor中的preHandle方法都会在 
22      * Controller方法调用之前调用。SpringMVC的这种Interceptor链式结构也是可以进行中断的,这种中断方式是令preHandle的返 
23      * 回值为false,当preHandle的返回值为false的时候整个请求就结束了。 
24      */
25     @Override
26     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
27         throws Exception {
28         System.out.println(">>>MyInterceptor1>>>>>>>在请求处理之前进行调用(Controller方法调用之前)");
29         return true;// 只有返回true才会继续向下执行,返回false取消当前请求 
30     }
31     /**
32      * 这个方法只会在当前这个Interceptor的preHandle方法返回值为true的时候才会执行。postHandle是进行处理器拦截用的,它的执行时间是在处理器进行处理之 
33      * 后,也就是在Controller的方法调用之后执行,但是它会在DispatcherServlet进行视图的渲染之前执行,也就是说在这个方法中你可以对ModelAndView进行操 
34      * 作。这个方法的链式结构跟正常访问的方向是相反的,也就是说先声明的Interceptor拦截器该方法反而会后调用,这跟Struts2里面的拦截器的执行过程有点像, 
35      * 只是Struts2里面的intercept方法中要手动的调用ActionInvocation的invoke方法,Struts2中调用ActionInvocation的invoke方法就是调用下一个Interceptor 
36      * 或者是调用action,然后要在Interceptor之前调用的内容都写在调用invoke之前,要在Interceptor之后调用的内容都写在调用invoke方法之后。 
37      */
38     @Override
39     public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
40                            ModelAndView modelAndView) throws Exception {
41         System.out.println(">>>MyInterceptor1>>>>>>>请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后)");
42         if(response.getStatus()==500){
43             modelAndView.setViewName("/errorpage/500");
44         }else if(response.getStatus()==404){
45             modelAndView.setViewName("/errorpage/404");
46         }
47     }
48 
49     /**
50      * 该方法也是需要当前对应的Interceptor的preHandle方法的返回值为true时才会执行。该方法将在整个请求完成之后,也就是DispatcherServlet渲染了视图执行, 
51      * 这个方法的主要作用是用于清理资源的,当然这个方法也只能在当前这个Interceptor的preHandle方法的返回值为true时才会执行。 
52      */
53     @Override
54     public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
55         throws Exception {
56         System.out.println(">>>MyInterceptor1>>>>>>>在整个请求结束之后被调用,也就是在DispatcherServlet 渲染了对应的视图之后执行(主要是用于进行资源清理工作)");
57     }
58 }
package org.springboot.sample.servlet;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet
 *
 * @author   单红宇(365384722)
 * @myblog  http://blog.csdn.net/catoop/
 * @create    2016年1月6日
 */
@WebServlet(urlPatterns="/xs/myservlet", description="Servlet的说明") // 不指定name的情况下,name默认值为类全路径,即org.springboot.sample.servlet.MyServlet2
public class MyServlet2 extends HttpServlet{

    private static final long serialVersionUID = -8685285401859800066L;

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println(">>>>>>>>>>doGet2()<<<<<<<<<<<");
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println(">>>>>>>>>>doPost2()<<<<<<<<<<<");
        resp.setContentType("text/html");  
        PrintWriter out = resp.getWriter();  
        out.println("<html>");  
        out.println("<head>");  
        out.println("<title>Hello World</title>");  
        out.println("</head>");  
        out.println("<body>");  
        out.println("<h1>大家好,我的名字叫Servlet2</h1>");  
        out.println("</body>");  
        out.println("</html>"); 
    }

}

  放代码:

  拦截器实现类中几个函数的效劳,以致调用的前后相继顺序都很显明,小编这边就十分的少介绍了。

运用 @WebServlet 评释,在那之中能够设置有些性情。

 1 package com.github.carvechris.security.common.util;
 2 
 3 import javax.servlet.http.HttpServletRequest;
 4 
 5 /**
 6  * CREATE BY funnyZpC ON 2018/5/3
 7  **/
 8 public class IPUtils {
 9     /**
10      * 获取用户真实IP地址,不使用request.getRemoteAddr()的原因是有可能用户使用了代理软件方式避免真实IP地址,
11      * 可是,如果通过了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP值
12      *
13      * @return ip
14      */
15     public static String getRealIP(HttpServletRequest request) {
16         String ip = request.getHeader("x-forwarded-for");
17         if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {
18             // 多次反向代理后会有多个ip值,第一个ip才是真实ip
19             if( ip.indexOf(",")!=-1 ){
20                 ip = ip.split(",")[0];
21             }
22         }
23         if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
24             ip = request.getHeader("Proxy-Client-IP");
25             System.out.println("Proxy-Client-IP ip: " + ip);
26         }
27         if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
28             ip = request.getHeader("WL-Proxy-Client-IP");
29             System.out.println("WL-Proxy-Client-IP ip: " + ip);
30         }
31         if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
32             ip = request.getHeader("HTTP_CLIENT_IP");
33             System.out.println("HTTP_CLIENT_IP ip: " + ip);
34         }
35         if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
36             ip = request.getHeader("HTTP_X_FORWARDED_FOR");
37             System.out.println("HTTP_X_FORWARDED_FOR ip: " + ip);
38         }
39         if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
40             ip = request.getHeader("X-Real-IP");
41             System.out.println("X-Real-IP ip: " + ip);
42         }
43         if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
44             ip = request.getRemoteAddr();
45             System.out.println("getRemoteAddr ip: " + ip);
46         }
47         return ip;
48     }
49 }

第二步:成立贰个Java类继承WebMvcConfigurerAdapter,并重写 addInterceptors 方法。

有个难题:DispatcherServlet 暗许拦截“/”,MyServlet 拦截“/xs/*”,MyServlet2 拦截“/xs/myservlet”,那么在大家访谈http://localhost:8080/xs/myservlet 的时候系统会怎么处理吧?
假若访谈 http://localhost:8080/xs/abc 的时候又是怎么样结果吗?这里就不给大家卖关子了,其结果是合作的开始时期级是从精确到模糊,相符条件的Servlet并不会都实施

是因为每一遍校验ip的时候是从央求头里面获取的(HttpSevletRequest卡塔尔国,央求头里面的ip两种多种,譬如在应用了nginx反向代理的时候ip就很丰裕了,遂小编就写了个IPUtils单独做这么些事情。

  实例化大家自定义的拦截器,然后将对像手动加多到拦截器链中(在addInterceptors方法中增进)。

既是系统DispatcherServlet 暗许拦截“/”,那么大家是或不是能做更正呢,答案是料定的,我们在SpringBootSampleApplication中增添代码:

  ,接下去就将以此Utils用起来,起底计划拦截器:

 1 import example.Interceptor.ErrorInterceptor;
 2 import example.Interceptor.MyInterceptor2;
 3 import org.springframework.context.annotation.Configuration;
 4 import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
 5 import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
 6 @Configuration
 7 public class MyWebAppConfigurer extends WebMvcConfigurerAdapter {
 8     @Override
 9     public void addInterceptors(InterceptorRegistry registry) {
10 // 多个拦截器组成一个拦截器链 
11 // addPathPatterns 用于添加拦截规则 
12 // excludePathPatterns 用户排除拦截 
13         registry.addInterceptor(new ErrorInterceptor()).addPathPatterns("/**");
14         super.addInterceptors(registry);
15     }
16 
17 }
 /**
     * 修改DispatcherServlet默认配置
     *
     * @param dispatcherServlet
     * @return
     * @author SHANHY
     * @create  2016年1月6日
     */
    @Bean
    public ServletRegistrationBean dispatcherRegistration(DispatcherServlet dispatcherServlet) {
        ServletRegistrationBean registration = new ServletRegistrationBean(dispatcherServlet);
        registration.getUrlMappings().clear();
        registration.addUrlMappings("*.do");
        registration.addUrlMappings("*.json");
        return registration;
    }
 1 package com.github.carvechris.security.bankFlow.config;
 2 
 3 import com.github.carvechris.security.bankFlow.entity.ZwIpFilter;
 4 import com.github.carvechris.security.bankFlow.mapper.ZwIpFilterMapper;
 5 import com.github.carvechris.security.common.util.IPUtils;
 6 import org.apache.commons.lang3.StringUtils;
 7 import org.apache.log4j.Logger;
 8 import org.springframework.beans.factory.annotation.Autowired;
 9 import org.springframework.web.servlet.HandlerInterceptor;
10 import org.springframework.web.servlet.ModelAndView;
11 
12 import javax.servlet.http.HttpServletRequest;
13 import javax.servlet.http.HttpServletResponse;
14 import java.util.List;
15 
16 /**
17  * CREATE BY funnyZpC ON 2018/5/3
18  **/
19 
20 public class IPInterceptor implements HandlerInterceptor {
21     private static final Logger LOG= Logger.getLogger(IPInterceptor.class.getName());
22 
23 
24     @Autowired
25     private ZwIpFilterMapper ipFilterMapper;
26 
27     private ZwIpFilter ipFilter;
28 
29     @Override
30     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
31         //过滤ip,若用户在白名单内,则放行
32         String ipAddress=IPUtils.getRealIP(request);
33         LOG.info("USER IP ADDRESS IS =>"+ipAddress);
34         if(!StringUtils.isNotBlank(ipAddress))
35             return false;
36         ipFilter=new ZwIpFilter();
37         ipFilter.setModule("sino-bankflow");//模块
38         ipFilter.setIp(ipAddress);//ip地址
39         ipFilter.setMark(0);//白名单
40         List<ZwIpFilter> ips=ipFilterMapper.select(ipFilter);
41         if(ips.isEmpty()){
42             response.getWriter().append("<h1 style="text-align:center;">Not allowed!</h1>");
43             return false;
44         }
45         return true;
46     }
47 
48 
49     @Override
50     public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
51 
52     }
53 
54 
55     @Override
56     public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
57 
58     }
59 }

  到那边拦截器就着力落到实处了,作者上边给出的事例中是能够完结对404大概500的阻挠。
而是必要注意的是,这种阻碍不经常候也会现身特地大标题。举例一个网页中意气风发旦必要加载相当多的图片可能js文件财富,可是无独有偶未有那么些财富,相当于找不到这样三个能源报一群的404漏洞非常多。这时候假使仍然唯有的利用这种阻碍就能够师世null指针非凡的图景。
  针对这种景色,作者研商了意气风发种方法能够解决那样好像的标题。
  解决方案就是:创设八个类并落实 ErrorController 接口,这样就足以行使这几个类来拍卖方面发生的主题素材了。
上面给出代码:

理之当然,这里能够对DispatcherServlet做过多改正,实际不是只是UrlMappings。

拦截器不是随随意便写的,供给选用SpringBoot提供的拦截器(HandlerInterceptor卡塔尔(英语:State of Qatar)模板来做,拦截器是何等=>"切面编制程序",此外部要求要表达的是那七个主意:

 1 package example.controller; 
 2 import org.springframework.boot.autoconfigure.web.ErrorController; 
 3 import org.springframework.stereotype.Controller; 
 4 import org.springframework.web.bind.annotation.RequestMapping; 
 5 @Controller 
 6 public class MainsiteErrorController implements ErrorController { 
 7      
 8     private static final String ERROR_PATH = "/error"; 
 9 
10 @RequestMapping(value=ERROR_PATH) 
11 public String handleError(){ 
12      return "errorpage/error"; 
13 } 
14 @Override 
15 public String getErrorPath() { 
16      return ERROR_PATH; 
17    } 
18 } 

一贯行使@WebFilter和@WebListener的方法,达成二个Filter 和一个 Listener。

本文由澳门网络娱乐游戏平台发布于编程,转载请注明出处:Spring Boot Servlet、Filter、Listener、Interceptor

相关阅读