拦截器 订阅
拦截器(Interceptor),主要完成请求参数的解析、将页面表单参数赋给值栈中相应属性、执行功能检验、程序异常调试等工作。 [1] 展开全文
拦截器(Interceptor),主要完成请求参数的解析、将页面表单参数赋给值栈中相应属性、执行功能检验、程序异常调试等工作。 [1]
信息
外文名
Interceptor
领    域
计算机与信息科学 [2]
中文名
拦截器
应    用
java [2]
拦截器简介
拦截器(Interceptor)是Struts2框架的核心功能之一,Struts 2是一个基于MVC设计模式的开源框架, [3]  主要完成请求参数的解析、将页面表单参数赋给值栈中相应属性、执行功能检验、程序异常调试等工作。Struts2拦截器是一种可插拔策略,实现了面向切面的组件开发,当需要扩展功能时,只需要提供对应拦截器,并将它配置在Struts2容器中即可,如果不需要该功能时,也只需要在配置文件取消该拦截器的设置,整个过程不需要用户添加额外的代码。拦截器中更为重要的概念即拦截器栈(Interceptor Stack),拦截器栈就是Struts2中的拦截器按一定的顺序组成的一个线性链,页面发出请求,访问Action对象或方法时,栈中被设置好的拦截器就会根据堆栈的原理顺序的被调用。 [1] 
收起全文
精华内容
下载资源
问答
  • 拦截器
    千次阅读
    2019-03-08 07:54:25

    什么是拦截器:
    拦截器是AOP中的概念,它本身是一段代码,可以通过定义“织入点”,来指定拦截器的代码在“织入点”的前后执行,从而起到拦截的作用
    正如上面 Struts2的Reference中讲述的,Struts2的Interceptor,其拦截的对象是Action代码,可以定义在Action代码之前或者之后执行拦截器的代码。

    在项目中,我们经常用来拦截通过非正常程序而进行的访问
    Struts2的拦截器和Servlet过滤器类似。在执行Action的execute方法之前,Struts2会首先执行在struts.xml中引用的拦截器,在执行完所有引用的拦截器的intercept方法后,会执行Action的execute方法。
    其中intercept方法是拦截器的核心方法,所有安装的拦截器都会调用之个方法。在Struts2中已经在struts-default.xml中预定义了一些自带的拦截器,如timer、params等。如果在标签中继承struts-default,则当前package就会自动拥有struts-default.xml中的所有配置。代码如下:

    拦截器是Struts2框架的核心,它主要完成解析请求参数、将请求参数赋值给Action属性、执行数据校验、文件上传等工作在struts-default.xml中有一个默认的引用,在默认情况下(也就是中未引用拦截器时)会自动引用一些拦截器。struts2中默认的拦截器是defaultStack.自定义拦截器需要特别注意的是不要忘记引入struts2默认的拦截器。为了实现某些操作,我们可以自定义拦截器,

    自定义拦截器有三种方式定义
    分别为实现Interceptor接口,
    继承抽象类AbstractInterceptor,
    继承MethodFilterInteceptor类。

    拦截器在项目中的运用:
    同时可以减轻代码冗余,提高重用率。
    如果要求用户密码、权限等的验证,就可以用自定义的拦截器进行密码验证和权限限制。对符合的登入者才跳转到正确页面。

    更多相关内容
  • 本篇文章主要介绍了详解springmvc拦截器拦截静态资源,具有一定的参考价值,感兴趣的小伙伴们可以参考一下。
  • 主要介绍了解决拦截器对ajax请求的拦截实例详解的相关资料,需要的朋友可以参考下
  • SpringBoot的拦截器

    2020-11-26 14:40:10
    idea软件。SpringBoot的拦截器的博客所写的例子。preHandle()方法的返回值true和false的详细区别还未描述
  • 通过mybatis拦截器将查询语句、更新语句、删除语句、插入语句中指定表明替换为另一个表名
  • spring-boot添加 拦截器

    2017-08-21 16:41:31
    spring-boot 拦截器 登录拦截spring-boot 拦截器 登录拦截spring-boot 拦截器 登录拦截spring-boot 拦截器 登录拦截
  • 使用mybatis的拦截器功能实现分页操作,使分页代码在整个项目中通用,减少代码冗余。
  • 数据修改与删除日志记录demo @Intercepts({ @Signature(type = Executor.class, method = "update", args = { MappedStatement.class, Object.class }) })
  • SpringBoot整合Mybatis完整详细版含注册、登录、拦截器配置功能
  • MyBatis拦截器分页与动态修改SQL及其参数值 提取SQL Like 字段
  • 拦截器统一处理用户的请求信息,包含网站的用户登录验证以及app的接口规范。
  • spring拦截器,高级参数绑定,controller返回值
  • 配置图文,超详细!!SpringMVC拦截器Interceptor详解,多个拦截器的执行顺序,拦截器进行权限判断和日志记录,拦截器和过滤器的区别

    SpringMVC拦截器

      Interceptor拦截器,是SpringMVC提供用来拦截发送给Controller层方法请求的拦截器。类似于filter 主要进行记录日志,判断用户是否登录,过滤权限(没有登录就跳转登录之类的)
      拦截器和我们所学的过滤器是很相似的,只是范围不一样。

    • 过滤器filter:是JavaEE提供的用来拦截所有的请求,进行过滤,它主要用于实现编码过滤,进行统一编码,防止乱码。
    • 拦截器interceptor:主要用来拦截Controller控制器的方法,一般用于拦截Controller层,满足条件才放行,主要用于实现权限分配,不满足条件不能访问一些界面(比如登录才能进入)。

    【注意】一般请求都是先通过过滤器filter过滤,才会被拦截器interceptor处理,决定是否放行,两个过程有任何一个不放行,都不能访问到Controller层方法。

    1. 过滤器和拦截器的大概执行流程【***】

    在这里插入图片描述

    2. 拦截器的三个方法

    1. boolean preHandle():在访问controller方法之前执行,返回为true才会去执行Controller方法,返回false,就被拦截了,原路打回(主要做权限控制,有权限才放行)。
    2. void postHandle():在执行controller方法之后执行jsp页面之前执行该方法,可以向作用域中放入数据,影响jsp展示效果,(可以在执行jsp之前做渲染)
    3. void afterCompletion在jsp页面渲染完成之后执行,(主要用于记录日志,资源释放
      ,
      【注意小知识点来啦】如果preHadle返回true,但是没有找到对应的Controller,是不会执行postHandle方法哦。

    差不多就是这样的模板

    public class MyInterceptor implements HandlerInterceptor {
    
    //    在访问controller方法之前执行
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            //prehandle:访问controller之前执行,返回true 继续访问controller。
            System.out.println("\n----------AuthInterceptor 【preHandle】--------------");
            return true;//返回false就不再继续执行controller方法
        }
    
    //    如果没有controller就不执行postHandle方法
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    		//posthandle:在执行controller方法之后, 执行jsp之前执行该方法,可以向作用域中放入数据,影响jsp展示效果,(可以执行jsp之前做渲染)
            System.out.println("----------AuthInterceptor 【postHandle】-------------- ");
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            //afterCompletion:在jsp渲染之后执行,用于记录日志,资源释放
            System.out.println("----------AuthInterceptor 【afterCompletion】--------------");
    
    		//记录日志  向文件里面写日志
            String logdir = request.getServletContext().getRealPath("log");//获取服务器记录日志log文件所存放的目录位置 -- tomcat下的真实路径+log目录
            //路径不存在就创建
            Path logdirPath = Paths.get(logdir);
            if(Files.notExists(logdirPath)){
                Files.createDirectories(logdirPath);
            }
            //目录存在就将数据[字符]写入
            Path logfile = Paths.get(logdir,"userlog.log");//存放日志的路径+文件名
            BufferedWriter writer = new BufferedWriter(new FileWriter(logfile.toFile(),true));//logfile.toFile() paths转换为File类型 true以追加的方式写入
    		
    		//获取登录用户信息
            Users user = (Users)request.getSession().getAttribute("user");
            String username = user.getUsername();
            //记录user登录时间,存入日志
            String message = username+" 登录时间:"+new Date();
            writer.write(message+"\r\n");
            writer.flush();
            writer.close();
        }
    }
    

    3. 多个拦截器的执行顺序

    如果所有拦截器都通过(都不拦截)执行顺序是这样的:
    (都执行的话,preHandle顺序执行,postHandler逆序执行,最后再afterCompletion逆序执行)
    在这里插入图片描述
    如果拦截器1拦截(也就是preHandle1返回false),那么后面的拦截器也不执行,直接原路打回。
    在这里插入图片描述
    如果拦截器3拦截,那么也不执行controller方法,大概是这样的。
    在这里插入图片描述


    4. SpringMVC拦截器的配置

    4.1 自定义拦截器,实现HandlerInterceptor接口

    //实现一个接口HandlerInterceptor
    public class Demo01Interceptor  implements HandlerInterceptor {
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            System.out.println("preHandle");
            return true;//放行执行controller
        }
    
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        
        }
    
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    
        }
    }
    

    4.2 springmvc.xml配置拦截器

    配置多个拦截器

    <!-- /** 是拦截所有的请求   path="/interceptor"只拦截interceptor路径-->
         <mvc:interceptors>
             <mvc:interceptor>
             	<!-- /**拦截所有请求,配置全局拦截器 -->
                 <mvc:mapping path="/**"/>
                 <bean class="com.xgf.springmvc.ajax.interceptor.AuthInterceptor"/>
             </mvc:interceptor>
             <mvc:interceptor>
             	<!-- /interceptor 之拦截interceptor该路径 -->
                 <mvc:mapping path="/interceptor"/>
                 <bean class="com.xgf.springmvc.ajax.interceptor.AuthInterceptor1"/>
             </mvc:interceptor>
         </mvc:interceptors>
    

    5. 案例:用户权限拦截器和日志记录

    有些页面只有用户登录才能访问,未登录不能访问。

    5.1 案例图解【***】

    在这里插入图片描述
    浏览器进行访问,想去购物车模块/订单模块需要先进行用户登录,用户权限拦截器进行判断用户登录没有,登录成功,放行,可以访问。未登录,拦截,跳转登录界面。

    5.2 用户权限拦截器UserAuthInterceptor

    作用:判断访问路径,如果访问的是order订单模块或者cart购物车模块.就需要判断用户是否登录,读取session中的用户信息,未登录强制跳转到登入页面,登录就放行,进入相应页面

    public class UserAuthInterceptor implements HandlerInterceptor {
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            System.out.println("UserAuthInterceptor preHandle------------------------");
            User user = (User) request.getSession().getAttribute("user");
            if(user == null){//未登录才判断,登录了直接放行
                String address = request.getRequestURI();//获取路径
                System.out.println("address = "+address);
                //是购物车或者订单页面,就直接跳转登录界面
                if(address.contains("order")||address.contains("cart")){
    	            //强制到登录页面
                    response.sendRedirect(request.getContextPath() + "/login.jsp");
                    //设置为false,不访问controller
                    return false;
                }
            }
            //其它模块或者已经登录,就直接放行
            return true;
        }
    
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
            System.out.println("UserAuthInterceptor postHandle------------------------");
        }
    
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            System.out.println("UserAuthInterceptor afterCompletion------------------------");
            
    		//记录日志  向文件里面写日志
            String logdir = request.getServletContext().getRealPath("log");//获取服务器记录日志log文件所存放的目录位置 -- tomcat下的真实路径+log目录
            //路径不存在就创建
            Path logdirPath = Paths.get(logdir);
            if(Files.notExists(logdirPath)){
                Files.createDirectories(logdirPath);
            }
            //目录存在就将数据[字符]写入
            Path logfile = Paths.get(logdir,"userlog.log");//存放日志的路径+文件名
            BufferedWriter writer = new BufferedWriter(new FileWriter(logfile.toFile(),true));//logfile.toFile() paths转换为File类型 true以追加的方式写入
    		
    		//获取登录用户信息
            Users user = (Users)request.getSession().getAttribute("user");
            String username = user.getUsername();
            //记录user登录时间,存入日志
            String message = username+" 登录时间:"+new Date();
            writer.write(message+"\r\n");
            writer.flush();
            writer.close();
        }
    }
    
    

    5.3 OrderController订单controller

    订单模块

    @Controller
    @RequestMapping("/toOrder")
    public class OrderController {
        @RequestMapping(path = "/orderInfo.action",method = {RequestMethod.GET,RequestMethod.POST})
        public String query(Integer id){
            System.out.println("订单信息");
            return "order";
        }
    }
    

    5.4 CartController购物车controller

    购物车模块

    @Controller
    @RequestMapping("/toCart")
    public class OrderController {
        @RequestMapping(path = "/cartInfo.action",method = {RequestMethod.GET,RequestMethod.POST})
        public String query(Integer id){
            System.out.println("购物车信息");
            return "cart";
        }
    }
    

    5.5 springmvc中配置拦截器

       <!--配置用户权限拦截器-->
        <mvc:interceptors>
            <!--用于测试的拦截器-->
            <mvc:interceptor>
                <!--拦截路径的配置 /**拦截所有请求 -->
                <mvc:mapping path="/**"/>
                <bean id="interceptor1" class="com.xgf.interceptor.UserAuthInterceptor"/>
            </mvc:interceptor>
    	<!-- 可以配置多个拦截器,继续用mvc:interceptor-->
        </mvc:interceptors>
    

    大佬们,画图不容易啊,给个关注给个赞呗,感谢感谢=

    展开全文
  • 自定义拦截器的实现以及拦截器的详细配置,配置文件里面有特别详细的注释,希望对刚接触拦截器的同学有帮助
  • 自定义MyBatis拦截器

    千次阅读 2022-02-07 15:04:29
    文章目录自定义MyBatis拦截器作用MyBatis中的四大核心对象在mybatis中可被拦截的类型有四种(按照拦截顺序)拦截器需要实现Mybatis提供的Interceptor接口利用反射获取运行中的实体字段的名字利用反射动态的为sql语句...

    自定义MyBatis拦截器

    作用

    通过拦截器可以拦截四大核心对象中的其中一个,我下文中拦截的是Executor核心对象,然后对这个核心对象的update方法进行了拦截,再结合反射,在每次更新的时候都动态的给sql加上一个更新人操作,在每次插入的时候都动态的给sql加上一个创建人操作。下文中的拦截器主要是在更新或者插入的时候,给sql语句多传递一个参数。
    我们还可以通过拦截StatementHandler核心对象修改sql语句,还可以通过拦截其它两个核心对象达到某些目的。但是目前只掌握拦截Executor核心对象给sql语句动态的增加参数就行了。

    MyBatis中的四大核心对象

    MyBatis中的四大核心对象:Executor,StatementHandler,ParamterHandler,ResultSetHandler

    拦截器可以拦截四大核心对象中的其中一个对象,然后对这个对象进行增强,如下图:

    在这里插入图片描述

    2.各个参数的含义:
    @Intercepts:标识该类是一个拦截器;
    @Signature:指明自定义拦截器需要拦截哪一个类型,哪一个方法;
    	2.1 type:对应四种类型中的一种;
    	2.2 method:对应接口中的哪个方法;
    	2.3 args:对应哪一个方法参数类型(因为可能存在重载方法);
    

    上图中的MyInterceptor拦截器,拦截的就是StatementHandler对象。至于上图中的method的值是什么,那就具体要看你是什么需求了,如下图:

    在这里插入图片描述

    通过args来指定上图中的方法中的参数,如下图:

    在这里插入图片描述

    什么叫做增强呢,就比如现在有一个sql语句,那么它在经过拦截器的时候,拦截器会给这个sql语句在原有的基础上增加一些新的东西,这就叫做增强。

    在mybatis中可被拦截的类型有四种(按照拦截顺序)

    Executor:拦截执行器的方法。
    ParameterHandler:拦截参数的处理。
    StatementHandler:拦截Sql语法构建的处理。
    ResultHandler:拦截结果集的处理。
    
    拦截器顺序
    Executor -> ParameterHandler -> StatementHandler -> ResultSetHandler
    

    拦截器需要实现Mybatis提供的Interceptor接口

    拦截器通过实现Mybatis提供的Interceptor拦截接口,重写了三个方法:setProperties/plugin/ intercept,三者执行顺序是setProperties—》plugin—》Interceptor。

     setProperties方法:该方法通过设置属性,将核心配置文件configuration.xml文件中对拦截器的配置项下的属性获取过来,便于在拦截器中使用。
    
     plugin方法:该方法用来协商,达成协议,把代理权给普通的业务员this,传进wrap方法实现的源码去做代理,没有获取代理权的代理人在这个地方就会停下,不会向下走了,获取代理权的代理人可以去做拦截代理。
    
    intercept方法:则是获取拦截对象下的要拦截的东西,然后对其加以改编,添加自己的行为,按照条件进行改编拦截对象,然后通过源码下的反射invocation来调用被拦截的方法,让原本被拦截的方法继续执行(invocation.proceed())。
    

    invocation.proceed()是拦截器是否放行,如果拦截器执行了此句代码,那么表示拦截器要放行,那么我们的动态代理接口可以成功执行,但是如果拦截器中的intercept方法中,没有执行此句代码,那么就表示拦截器没有放行,那么动态代理接口就不可以成功执行;

    如果我们在intercept方法中想要放行,直接return invocation.proceed();就可以了。

    利用反射获取运行中的实体字段的名字

    利用反射获取实体类中的字段的时候,必须要把setAccessible方法的值设置成true,这样在进行访问安全检查的时候才不会抛出异常,要不然利用反射获取实体类中的字段的时候会抛IllegalAccessException异常。

    在这里插入图片描述

    利用反射动态的为sql语句传递新参数

    我们如果没有用反射,那么传递给sql语句的参数就是动态代理接口中传递的哪些参数,是不能够更改的,但是如果用上了反射,也就是使用BeanUtils.setProperty(bean,name,value)方法,那么我们会在运行期间,增加新的参数传递给sql语句。我们这里的bean对象是一个Map集合,如下图:

    在这里插入图片描述
    注意上图中的叙述有错误,不是改变一个实体类中的属性,而是往map集合中加一个键值对,bean是一个map集合。

    在这里插入图片描述

    使用mybatis自定义的拦截器为插入,更新语句自动赋值的时候的小bug

    mapper映射文件中,从拦截器中取值的参数,一定要和拦截器中自动设置的参数保持一致,要不然的话是取不到拦截器中的值的,如下图:

    在这里插入图片描述

    update修改的时候,我们传递的goodsDO并没有modifyMan字段的值,但是因为有拦截器自动添加了modifyMan字段,所以数据库中的值会被自动插入,如下图:

    在这里插入图片描述

    使用自定义MyBatis拦截器在对数据库进行更新插入的时候动态添加修改人,创建人参数

    定义拦截器类

    如下图:

    在这里插入图片描述

    /**
     * @Date 2022/1/29 17:42
     * @Author 望轩
     */
    @Intercepts({
            @Signature(
                    type = Executor.class ,
                    method = "update",
                    args={MappedStatement.class,Object.class})
    })
    public class MyInterceptor implements Interceptor {
        @Override
        public Object intercept(Invocation invocation) throws Throwable {
            //invocation.getArgs()得到的结果就是args中的参数,第一个元素肯定是MappedStatement,第二个元素是我们传递给sql语句的参数
            //如果没有传递则只能得到一个元素,也就是invocation.getArgs().length的长度是1
            //如果相关的动态代理接口没有传递参数,则我们不需要对传递给sql语句的参数进行处理,直接放行动态代理接口方法
            if(invocation.getArgs().length == 1){
                //只要执行了invocation.proceed()方法才会对动态代理接口进行放行,否则动态代理接口不会执行
                return invocation.proceed();
            }
    
            //获取动态代理接口传递给sql语句的参数实体
            Object parameter = invocation.getArgs()[1];
            System.out.println(parameter);
    
            //获取Sql语句的类型,也即是Sql语句是增删改查中的哪一个
            MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
            SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();
    
            //修改人或者是创建人
            String man = "";
            if(sqlCommandType.equals(SqlCommandType.INSERT)){
                man = "createMan";
            }
            if(sqlCommandType.equals(SqlCommandType.UPDATE)){
                man = "modifyMan";
            }
    
            //通过反射获取我们传递给sql语句也即是动态代理接口中的实体属性
            Field[] fields = GoodsDO.class.getDeclaredFields();
            for(Field field : fields){
                //安全性访问检查:设置为true
                field.setAccessible(true);
    
                String fieldName = field.getName();
    
                if(fieldName.equals(man)){
                    BeanUtils.setProperty(parameter,man,"wangxuan");
                    System.out.println(parameter);
                }
            }
    
            return invocation.proceed();
        }
    
    
        @Override
        public Object plugin(Object target) {
            //plugin方法主要是将拦截器中定义的增强功能(也就是拦截器)和原来的核心对象合并起来,成为最终的核心对象wrap,然后把这个对象返回
            Object wrap = Plugin.wrap(target, this);
            return wrap;
        }
    
        @Override
        public void setProperties(Properties properties) {
            //这个方法里面可以取出来我们mybatis的配置文件中插件中配置的属性
        }
    
    }
    

    在mybatis的配置文件中声明拦截器

    在这里插入图片描述

    在mapper映射文件中获取拦截器中设置的参数

    在这里插入图片描述

    验证结果

    在这里插入图片描述

    MyBatis会把动态代理中所有的接口生成一个map集合以及BeanUtils.setProperty()可以往这个map集合里面动态添加键值对

    当MyBatis底层在处理动态代理接口中的参数的时候,会把动态代理接口中的参数处理成一个map集合。

    如果动态代理接口中没有使用@Param注解。假设某个动态代理接口inter1(Object A,Object B,Object C),那么Mybatis最终会处理成Map{A:A(),B:B(),C:C(),param1:A(),param2:B(),param3:C()};我们在mapper的xml映射文件中,可以通过#{A}获取参数,也可以通过#{param1}获取参数。

    **如果动态代理接口中使用了@Param注解。**假设某个动态代理接口inter2(@Param(“variable1”) Object A,@Param(“variable2”) Object B,@Param(“variable3”) Object C),那么MyBatis最终会处理成Map{“variable1”:A(),“variable2”:B(),“variable3”:C()}的形式。

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    interceptor方法中的invocation对象

    Invocation对象可以通过反射调度获取到拦截的某个核心对象的具体内容,比如说拦截的核心对象的名字,拦截的核心对象的方法,传递给核心对象的这个方法的参数,这些参数包括动态代理接口中传递给sql语句的参数。总之我们可以通过invocation这个对象通过反射调度,获取到sql语句的全部信息。

    拦截器其实拦截的是四大核心对象中的某个方法,如果它拦截这个方法不放行,对应的动态代理接口,它就过不去,所以就不能执行sql语句;只要当拦截器放行了,动态代理接口才会执行。
    invocation.proceed()是拦截器是否放行,如果拦截器执行了此句代码,那么表示拦截器要放行,那么我们的动态代理接口可以成功执行,但是如果拦截器中的intercept方法中,没有执行此句代码,那么就表示拦截器没有放行,那么动态代理接口就不可以成功执行;

    如果我们在intercept方法中想要放行,直接return invocation.proceed();就可以了。

    展开全文
  • Servlet、过滤器、监听器、拦截器

    千次阅读 2021-06-04 09:24:05
    详细介绍Servlet、过滤器、监听器、拦截器,以及他们的关系以及区别。

    前言:Servlet是javaEE规范中的一种,javaEE中的规范很多除了Servlet还有很多我们熟悉的JSP、JDBC、RMI、XML、EJB、JTS等等。他们每个都有自己不同的角色,每一种规范在企业级java应用中都承担了不可或缺的角色。Servlet是Service + Applet的缩写,表示小服务程序。从命名就可以看出他是被用来书写服务端程序的。但是在这个很讲究开发效率的年代已久见不到原生的Servlet程序写的服务端程序了。几乎主流的框架都对他进行了封装,比如SpringMVC便是如此,比如SpringMVC的核心DispatcherServlet,SpringMVC正是基于他来将请求进行解析、适配、映射的最后到达我们想要调用的接口中。

    一、Servlet

    1.Servlet是什么

    Servlet = Service + Applet,表示小服务程序,他是javaEE中的一种规范,狭义的Servlet是指Java语言实现的一个接口,广义的Servlet是指任何实现了这个Servlet接口的类,一般情况下,人们将Servlet理解为后者。Servlet运行于支持Java的应用服务器中比如Tomcat。从原理上讲,Servlet可以响应任何类型的请求,但绝大多数情况下Servlet只用来扩展基于HTTP协议的Web服务器。

    2.Servlet的作用

    从上面的介绍我们可以看出,Servlet的作用就是写服务端程序的,这是没有任何问题的,在开发者的角度这就是Servlet的作用,此外Servlet其他的作用都是相对于服务器来说的,他指定了Http服务器管理动态资源文件的规则等。java中所有的前端发送的请求都必须经过Servlet接口的实现类。我们使用的主流框架中比如SpringBoot、SpringCloud都看不到Servlet的身影,那是因为他们内置的SpringMVC中对Servlet都进行了封装。

    3.ServletDemo

    下面展示一个Servlet程序的写法,首先需要使用IDEA创建一个javaEE的工程,
    第一步:选择Module来进行创建。
    在这里插入图片描述
    第二步:选择java企业版,然后勾选web应用即可,剩余的部分都是自己随便填好了,这样我们就可以创建出一个Servlet的应用了。
    在这里插入图片描述
    第三步:创建一个java类继承Servlet接口,并重写doGet、doPost方法。

    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.io.PrintWriter;
    
    public class Servlet extends HttpServlet {
    
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            System.out.println("执行了post请求。。。");
        }
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            System.out.println("执行了get请求。。。");
        }
    
    
    }
    

    第四步:在web.xml中配置Servlet

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
             version="4.0">
        <servlet>
            <servlet-name>Servlet</servlet-name><!--Servlet起个别名 -->
            <servlet-class>com.cn.controller.Servlet</servlet-class><!-- Servlet的全限定名 -->
        </servlet>
        <servlet-mapping>
            <servlet-name>Servlet</servlet-name><!-- 上方起的别名在下面为他配映射地址 -->
            <url-pattern>/test</url-pattern><!-- 为该别名配置地址,相当于我们在注解RequestMapping中配地址 -->
        </servlet-mapping>
    </web-app>
    

    到这里为止,一个简单的Servlet就开发完了,剩下的就是部署测试了,我们需要将这个程序打成war包发布到Tomcat上,IDEA已经帮我们打好了包,我们只需要将该包加载进Tomcat即可,值得注意的是我们最好服务名从新配置一个,不然会有些长,就是图中所示位置
    在这里插入图片描述
    这一切都准备完了,我们就可以来开始启动Tomcat访问了,启动后自动弹出地址,我们加上自己配的test即可访问到刚刚的Servlet了。展示如下,可以看到IDEA中正常输出了“执行了get请求。。。”,地址栏请求都是get请求,因此我们程序是没有问题的,这样就完成了简单的前后端交互,说明这个Servlet没有问题。
    在这里插入图片描述

    4.Servlet的生命周期

    说Servlet就必须提的是Servlet的声明周期,Servlet默认是在有请求到达时才会创建,可以通过配置实现在Http服务器启动时就启动,且默认也都是单利模式。然后会调用Servelt的init方法,然后就是service方法,然后service会根据是get还是post请求去调用不同的子类方法,最后在Http服务器关闭时会调用distroy方法销毁Servlet的实例。这里还涉及到了一个设计模式的使用即模板模式,我们继承HttpServlet时只要重写doGet、doPost等方法,是因为在HttpServlet中会根据请求的不同去分别调用不同的方法,我们只需要提供方法的实现就可以,逻辑都是确定的了,这便是模板模式。
    生命周期:创建-init----->service----->doGet(doPost)----->distroy

    二、过滤器Filter、监听器Listener

    1.过滤器

    Servlet是javaEE的一种规范,而过滤器Filter可以看成是Servlet的一种规范,过滤器的作用主要是过滤请求地址,过滤请求参数的信息,过滤器在实际开发中最常用的就是Xss过滤(Xss过滤就是将报文中可能产生危害的信息进行替换)。

    2.监听器

    与过滤器类似,监听器也是Servlet的一种规范,我们可以将它们都看出是Servlet,因为他们的实现机制都是一样的,但是监听器的用途就比较单一了。监听器主要用于监控作用域以及作用域中属性的变化。监听器总共有8种,与过滤器类似,他们都是接口都需要我们自己实现。下面列出8种监听器接口:

    监听作用域的声明周期的监听器:
    	ServletContextListener
    	ServletRequestListener
    	HttpSessionListener
    监听作用域属性变化的监听器:
    	ServletContextAttributeListener
    	ServletRequestAttributeListener
    	HttpSessionAttributeListener
    监听Session的活化与钝化
    	HttpSessionActivationListener
    监听Session与对象的绑定
    	HttpSessionBindingListener
    

    3.过滤器的示例Demo

    3.1实现Filter接口

    写一个类继承Filter,然后重写doFilter方法即可,init和destroy重不重写没有关系

    public class LoginFilter implements Filter {
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            System.out.println("初始化");
        }
    
        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
            System.out.println("进入到过滤器1");
            filterChain.doFilter(servletRequest,servletResponse);
            System.out.println("退出了过滤器1");
        }
    
        @Override
        public void destroy() {
            System.out.println("销毁");
        }
    }
    

    3.2配置web.xml

    在web.xml中配置该Filter,如下,这样就完成了Filter的开发。

    	<filter>
            <filter-name>LoginFilter</filter-name>
            <filter-class>com.cn.filter.LoginFilter</filter-class>
        </filter>
        <filter-mapping>
            <filter-name>LoginFilter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
    

    3.3 展示测试结果

    因为过滤器中只是打印了进入和退出,就直接放行了,所以正常就会输出进入过滤器->进入请求->退出过滤器,下面来看下结果也正如预测那样。
    在这里插入图片描述

    3.4多个Filter时,过滤器是如何执行的

    这里就不展示了,我们可以看到一个过滤器时请求到达服务端是先进入过滤器,再到达接口,接口处理完再经过过滤器退出服务器的。多个过滤器时其实就是对接口进行套娃,或者说对多虑的内容进行套娃。画个丑图理解下:
    在这里插入图片描述
    如上图所示一个请求想要到达接口需要穿过所有的过滤器,进入过滤时的顺序和退出时恰恰是相反的,整个流程应该是Filter1—>Filter2—>Filter3—>进入接口执行完毕—>Filter3—>Filter2—>Filter1。这样一看这个流程是不是就像个俄罗斯套娃呢,最里面的就相当于接口,他被层层过滤器所包裹。上面所说的是多个过滤器的执行顺序固定后就是这么处理的,多个处理器到底应该先执行哪一个则是根据他们在web.xml中的配置顺序决定的。

    4.比较监听器与过滤器

    监听器与过滤器的实现没啥区别,就不一一赘述了,说下监听器与过滤器的区别,监听器主要作用就是监听作用域的,所有监听器都是为了监听作用域,再无他用,不能说应用场景很少,只能说开发中很少用到,写框架应该会经常用到,开发中用的确实不多,而过滤器的作用就很明显了,基本上每个项目都是必不可少的,我们可以通过过滤器对请求和响应都设置一些通用的东西,或者过滤掉有安全隐患的内容,以上是他们作用的不同,他们的相同点就是都是Servlet的规范的实现。

    三、拦截器interceptor

    说到过滤器和监听器不提拦截器是不合适的,因为他们是java里面的三大器,这三大器各司其职共同保证了程序的稳定运行。每当提起其中一个都会自然而然想到另外两个,那下面我们就来总结下拦截器。

    1.拦截器是什么

    拦截器我们使用时基本都是使用框架已经实现好的拦截器,基本不会自己写,现在常用的框架中SpringBoot、SpringCloud中我们可以去继承HandlerInterceptorAdapter类来去重写里面的preHandle、postHandle、afterHandle三个方法,如下所示:

    public class LoginInterceptor extends HandlerInterceptorAdapter {
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            System.out.println("拦截器预处理");
            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("拦截器返回之后执行");
        }
    }
    

    此外我们还需要将这个拦截器交给Spring容器去管理,还需要为该拦截器配置拦截路径和排除路径,如下:

    @Configuration
    public class InterceptorConfiguration extends WebMvcConfigurerAdapter {
    
        @Bean
        public LoginInterceptor getLoginInterceptor(){
            return new LoginInterceptor();
        }
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(getLoginInterceptor())
                    .addPathPatterns("/**")
                    .excludePathPatterns("/find");
        }
    }
    

    这样我们就完成了拦截器的开发了,如果你使用的是最新版本的SpringBoot和SpringCloud你会发现,WebMvcConfigurerAdapter 和HandlerInterceptorAdapter 都已经被弃用了。他们的实现类上都被加了Deprecated这个注解,最新的实现方式已经不使用者两个类了,而是变成了两个接口,但是对于使用者来说实现的方式还是完全一样,对使用影响很小,最新版我们分别使用这两个接口就可以,操作什么的都还是一样:
    WebMvcConfigurer、HandlerInterceptor,此外这里值得提一句的是配置过滤路径是我们一定要写成/**而不能写成/*,前者代表拦截所有请求,后者则只拦截根路径下的请求,在真实项目中使用后者基本没有意义。

    2.拦截器的原理

    与过滤器和监听器不同的是,拦截器的实现不是Servlet,而是通过java的动态代理来实现的。java的动态代理相信基本都会知道,如果不清楚可以翻下资料,拦截器正是使用的java的动态代理机制,来对接口执行前后来进行处理的,从而达到了对接口进出拦截的目的。

    3.多个拦截器是如何执行的

    前面说过多个过滤器的执行顺序就像是套娃,那拦截器呢,拦截器也是一样多个拦截器的执行也和俄罗斯套娃一样,图就不重复画了。值得注意的一点是postHandle是在方法返回之前执行的。

    4.多个拦截器的执行顺序

    我们在addInterceptors中可以配置多个拦截器,在该方法中配置拦截器的顺序就是拦截器执行的顺序,假如有如下的代码,那就是先执行CSRFInterceptor再执行LoginInterceptor。

        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(getCSRFInterceptor())
                    .addPathPatterns("/**");
            registry.addInterceptor(getLoginInterceptor())
                    .addPathPatterns("/**")
                    .excludePathPatterns("/find");
            
        }
    

    5.拦截器的应用场景

    拦截器常被用于拦截CSRF(跨站点请求伪造)的请求,还经常被应用于登录拦截,验证用户是否已经登录。这些都是比较常用的。

    四、过滤器和拦截器

    上面已经总结完了,过滤器、监听器、拦截器。其中监听器作用比较单一仅是被用作监听作用域(这里只讨论Servlet提供的原生监听接口),但是过滤器和拦截器好像都可以拦截用户发出的请求,那他们有什么区别呢。

    • 区别:
    • 1.实现原理不同,拦截器是动态代理,过滤器是Servlet
    • 2.作用点不一样,过滤器因为是Servlet所以请求肯定先到达过滤器才能到达拦截器。
    • 3.拦截器除了可以处理响应前后的数据,还可以对返回之前的数据进行处理,这得益于java的动态代理。
    • 相同点
    • 1.都可以对请求响应前后进行处理。

    有人说过滤器可以过滤所有请求,而拦截器不可以拦截所有请求,这里笔者不敢苟同,他们虽然实现机制不一样,但是都是可以拦截到所有请求的,只是拦截的位置不一样,过滤器相当于第一层、然后才会走到Servelt(可以看成DispatherServlet)再然后才到拦截器最后才能进入到接口,其实他们都可以对所有请求进行拦截,只不过过滤器的拦截点更靠前,所以对于安全性要求较高的拦截还是应该使用过滤器来处理。下面画个丑图来展现下过滤器和拦截器。

    在这里插入图片描述

    展开全文
  • Spring中的拦截器

    千次阅读 2021-12-30 10:36:12
    1.Spring中的拦截器 在web开发中,拦截器是经常用到的功能。它可以帮我们验证是否登陆、预先设置数据以及统计方法的执行效率等等。 今天就来详细的谈一下spring中的拦截器。spring中拦截器主要分两种,一个是...
  • 1.拦截器的作用 Spring MVC 的拦截器类似于 Servlet 开发中的过滤器 Filter,用于对处理器进行预处理和后处理。 将拦截器按一定的顺序联结成一条链,这条链称为拦截器链(Interceptor Chain)。在访问被拦截的方法或...
  • kafka自定义拦截器|案例实战

    千次阅读 多人点赞 2020-04-29 14:33:01
    本文详细解释kafka的拦截器拦截器链,并根据案例实现两个常见的自定义拦截器并组成拦截链,Talk is cheap,Show me the code
  • Jfinal通过拦截器实现登录验证

    热门讨论 2015-10-02 17:24:59
    Jfinal通过拦截器实现登录验证,要访问控制层的方法必须先登录通过验证
  • cas-client扩展拦截器支持excludes

    热门讨论 2014-04-09 13:01:06
    cas-client扩展拦截器支持excludes,用于支持排除拦截指定路径。只是简单的在filter中进行过滤,希望大家继续完善。
  • Mybatis拦截器

    万次阅读 多人点赞 2019-04-16 22:31:18
    一 Mybatis拦截器介绍        Mybatis拦截器设计的初衷就是为了供用户在某些时候可以实现自己的逻辑而不必去动Mybatis固有的逻辑。通过Mybatis拦截器我们可以拦截某些方法的调用,我们可以选择...
  • mvc的拦截器控制权限的例子

    热门讨论 2014-03-25 22:50:06
    1、里面使用mvc的拦截器来作为权限控制,源码希望对你有用。
  • Mybatis之拦截器

    千次阅读 2021-04-20 12:33:08
    拦截器生成及调用流程 Mybatis拦截器生效过程 Mybatis拦截器需要实现的接口如下 public interface Interceptor { //主要做拦截后的逻辑处理 Object intercept(Invocation invocation) throws Throwable; //代理类...
  • spring+springMVC+mybatis拦截器分页
  • OkHttp + Retrofit 拦截器 拼装参数拦截器 日志输出拦截器 欢迎入群交流 ​ //手动创建一个OkHttpClient并设置超时时间缓存等设置 OkHttpClient.Builder builder = new OkHttpClient.Builder(); builder....
  • 拦截器Interceptor

    千次阅读 2022-03-02 15:30:21
    拦截器 是 SpringMVC 框架自己的,只有使用了 SpringMVC 框架的工程才能用。 作用:可以构成拦截器栈,完成特定功能。比如日志记录、登录判断、权限检查等作用。 好处:拦截器也可以让你将通用的代码模块化并...
  • MyBatis的拦截器及分页插件

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 427,374
精华内容 170,949
关键字:

拦截器