精华内容
下载资源
问答
  • Spring Boot 拦截

    万次阅读 多人点赞 2016-01-12 09:21:48
    Web开发中,我们除了使用 Filter 来过滤请web求外,还可以使用Spring提供的HandlerInterceptor(拦截器)。HandlerInterceptor 的功能跟过滤器类似,但是提供更精细的的控制能力:在request被响应之前、request被...

    上一篇对过滤器的定义做了说明,也比较简单。过滤器属于Servlet范畴的API,与Spring 没什么关系。
    Web开发中,我们除了使用 Filter 来过滤请web求外,还可以使用Spring提供的HandlerInterceptor(拦截器)。

    HandlerInterceptor 的功能跟过滤器类似,但是提供更精细的的控制能力:在request被响应之前、request被响应之后、视图渲染之前以及request全部结束之后。我们不能通过拦截器修改request内容,但是可以通过抛出异常(或者返回false)来暂停request的执行。

    实现 UserRoleAuthorizationInterceptor 的拦截器有:
    ConversionServiceExposingInterceptor
    CorsInterceptor
    LocaleChangeInterceptor
    PathExposingHandlerInterceptor
    ResourceUrlProviderExposingInterceptor
    ThemeChangeInterceptor
    UriTemplateVariablesHandlerInterceptor
    UserRoleAuthorizationInterceptor

    其中 LocaleChangeInterceptor 和 ThemeChangeInterceptor 比较常用。

    配置拦截器也很简单,Spring 为什么提供了基础类WebMvcConfigurerAdapter ,我们只需要重写 addInterceptors 方法添加注册拦截器。

    实现自定义拦截器只需要3步:
    1、创建我们自己的拦截器类并实现 HandlerInterceptor 接口。
    2、创建一个Java类继承WebMvcConfigurerAdapter,并重写 addInterceptors 方法。
    2、实例化我们自定义的拦截器,然后将对像手动添加到拦截器链中(在addInterceptors方法中添加)。
    PS:本文重点在如何在Spring-Boot中使用拦截器,关于拦截器的原理请大家查阅资料了解。

    代码示例:

    MyInterceptor1.java

    package org.springboot.sample.interceptor;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;
    
    /**
     * 自定义拦截器1
     *
     * @author   单红宇(365384722)
     * @myblog  http://blog.csdn.net/catoop/
     * @create    2016年1月7日
     */
    public class MyInterceptor1 implements HandlerInterceptor {
    
    	@Override
    	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
    			throws Exception {
    		System.out.println(">>>MyInterceptor1>>>>>>>在请求处理之前进行调用(Controller方法调用之前)");
    		
    		return true;// 只有返回true才会继续向下执行,返回false取消当前请求
    	}
    
    	@Override
    	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
    			ModelAndView modelAndView) throws Exception {
    		System.out.println(">>>MyInterceptor1>>>>>>>请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后)");
    	}
    
    	@Override
    	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
    			throws Exception {
    		System.out.println(">>>MyInterceptor1>>>>>>>在整个请求结束之后被调用,也就是在DispatcherServlet 渲染了对应的视图之后执行(主要是用于进行资源清理工作)");
    	}
    
    }
    
    

    MyInterceptor2.java

    package org.springboot.sample.interceptor;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;
    
    /**
     * 自定义拦截器2
     *
     * @author   单红宇(365384722)
     * @myblog  http://blog.csdn.net/catoop/
     * @create    2016年1月7日
     */
    public class MyInterceptor2 implements HandlerInterceptor {
    
    	@Override
    	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
    			throws Exception {
    		System.out.println(">>>MyInterceptor2>>>>>>>在请求处理之前进行调用(Controller方法调用之前)");
    		
    		return true;// 只有返回true才会继续向下执行,返回false取消当前请求
    	}
    
    	@Override
    	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
    			ModelAndView modelAndView) throws Exception {
    		System.out.println(">>>MyInterceptor2>>>>>>>请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后)");
    	}
    
    	@Override
    	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
    			throws Exception {
    		System.out.println(">>>MyInterceptor2>>>>>>>在整个请求结束之后被调用,也就是在DispatcherServlet 渲染了对应的视图之后执行(主要是用于进行资源清理工作)");
    	}
    
    }
    
    

    MyWebAppConfigurer.java

    package org.springboot.sample.config;
    
    import org.springboot.sample.interceptor.MyInterceptor1;
    import org.springboot.sample.interceptor.MyInterceptor2;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
    
    @Configuration
    public class MyWebAppConfigurer 
    		extends WebMvcConfigurerAdapter { // 这里注意,在spring 5.0之后 WebMvcConfigurerAdapter 过时了,可以直接实现接口 implements WebMvcConfigurer(下面实现的方法是一样的)
    
    	@Override
    	public void addInterceptors(InterceptorRegistry registry) {
    		// 多个拦截器组成一个拦截器链
    		// addPathPatterns 用于添加拦截规则
    		// excludePathPatterns 用户排除拦截
    		registry.addInterceptor(new MyInterceptor1()).addPathPatterns("/**");
    		registry.addInterceptor(new MyInterceptor2()).addPathPatterns("/**");
    		super.addInterceptors(registry);
    	}
    
    }
    
    

    然后在浏览器输入地址: http://localhost:8080/index 后,控制台的输出为:

    >>>MyInterceptor1>>>>>>>在请求处理之前进行调用(Controller方法调用之前)
    >>>MyInterceptor2>>>>>>>在请求处理之前进行调用(Controller方法调用之前)
    >>>MyInterceptor2>>>>>>>请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后)
    >>>MyInterceptor1>>>>>>>请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后)
    >>>MyInterceptor2>>>>>>>在整个请求结束之后被调用,也就是在DispatcherServlet 渲染了对应的视图之后执行(主要是用于进行资源清理工作)
    >>>MyInterceptor1>>>>>>>在整个请求结束之后被调用,也就是在DispatcherServlet 渲染了对应的视图之后执行(主要是用于进行资源清理工作)
    

    根据输出可以了解拦截器链的执行顺序(具体原理介绍,大家找度娘一问便知)

    最后强调一点:只有经过DispatcherServlet 的请求,才会走拦截器链,我们自定义的Servlet 请求是不会被拦截的,比如我们自定义的Servlet地址 http://localhost:8080/xs/myservlet 是不会被拦截器拦截的。并且不管是属于哪个Servlet 只要复合过滤器的过滤规则,过滤器都会拦截。

    最后说明下,我们上面用到的 WebMvcConfigurerAdapter 并非只是注册添加拦截器使用,其顾名思义是做Web配置用的,它还可以有很多其他作用,通过下面截图便可以大概了解,具体每个方法都是干什么用的,留给大家自己研究(其实都大同小异也很简单)。
    这里写图片描述

    展开全文
  • 前端路由的基本原理、使用 history 路由模式时后端登录拦截器的配置、Vuex 的引入以及前端拦截器的实现。

    前言

    这一篇主要讲前端路由与登录拦截器的实现。放在一起讲是因为我在开发登录拦截器时因为这个路由的问题遇到了很多坑,花费了很长时间,网上的解决方案都不怎么靠谱,综合了好几种办法才最终成功,其实关于这个部分能写两三篇文章,名字起好了还能多很多访问量,不过为了保证文章的质量我没有这么做,毕竟我不是大神,如果再不用点心,写出来的文章自己都不想再看第二遍,更别提能对大家有所帮助了。

    一、前端路由

    大家如果留心观察就会发现,之前我们做的页面的 URL 里有一个 # 号,这个 # 号有什么含义呢?

    假设在 html 中有这么一段代码:<div id="test">This is a test</div>,如果我们想让页面定位到这个 div 所在的位置,可以加一个超链接 <a herf="#test">Jump to test</a>,这里的 # 被称为“锚点”,点击超链接,可以发现网页的 URL 发生了变化,但页面并不会跳转。

    在互联网流量如此庞大的今天,我们需要想办法后端服务器的压力,利用 AJAX,我们可以不重载页面就刷新数据,如果再加上 # 号的特性(即改变 URL 却不请求后端),我们就可以在前端实现页面的整体变化,而不用每次都去请求后端。

    为了实现前端路由,我们可以监听 # 号后面内容的变化(hashChange),从而动态改变页面内容。URL 的 # 号后面的地址被称为 hash ,估计是哪个大神拍脑袋想的,不用深究。这种实现方式我们称之为 Hash 模式,是非常典型的前端路由方式。

    另一种常用的方式被称为 History 模式,这种方式使用了 History APIHistory API 顾名思义就是针对历史记录的 API ,这种模式的原理是先把页面的状态保存到一个对象(state)里,当页面的 URL 变化时找到对应的对象,从而还原这个页面。其实原本人家这个功能是为了方便浏览器前进后退的,不得不说程序员们的脑洞真大。使用了这种模式,就可以摆脱 # 号实现前端路由。

    Vue 已经为我们提供了两种模式的前端路由,无需我们自己去实现。

    二、使用 History 模式

    首先我们把 Vue 中配置的路由从默认的 hash 模式切换为 histroy 模式。打开我们的前端项目 wj-vue,修改 router\index.js,加入 mode: 'history 这句话。整体代码如下:

    import Vue from 'vue'
    import Router from 'vue-router'
    import AppIndex from '@/components/home/AppIndex'
    import Login from '@/components/Login'
    
    Vue.use(Router)
    
    export default new Router({
      mode: 'history',
      routes: [
        {
          path: '/login',
          name: 'Login',
          component: Login
        },
        {
          path: '/index',
          name: 'AppIndex',
          component: AppIndex
        }
      ]
    })
    

    运行项目,访问不加 # 号的 http://localhost:8080/login ,成功加载页面。

    接下来,我们把前端打包后部署在后端。这不是前后端分离项目推荐的做法,之前我们讲过其实应该把前后端分别部署在不同的服务器中,但实际上仍有不少项目会选择把前后端整合在一起,只使用一个服务器,所以这里我们也提及一下这种方式,但在之后的开发中不会这样部署。

    先在项目目录执行 npm run build,控制台输出如下内容表明执行完毕:
    在这里插入图片描述
    这时在项目的 dist 文件夹下生成了 static 文件夹和 index.html 文件,把这两个文件,拷贝到我们后端项目的 wj\src\main\resources\static 文件夹下,一定要注意这个位置,这时后端配置的静态文件的 path,虽然看起来很诡异,但一般都不作修改。
    在这里插入图片描述
    接下来,打开后端项目并运行,访问 http://localhost:8443/index.html ,(注意输入后缀 .html)发现页面是空白的,但确实取到了这个页面,再访问 http://localhost:8443/login ,发现跳转到了错误页面(White Error Page)。
    在这里插入图片描述
    这里我们回顾一下单页面应用的概念,在我们这个项目中,其实只有 index.html 这一个页面,所有的其它内容都是在这个页面里动态渲染的。当我们直接在后端访问 /login 路径时,服务器会后端并没有这个路径对应的内容,所以返回了 Error Page。

    为了获取到我们需要的内容,我们要想办法触发前端路由,即在后端添加处理内容,把 通过这个 URL 渲染出的 index.html 返回到浏览器。

    在后端项目中新建一个 package 名为 error,新建实现 ErrorPageRegistrar 接口的类 ErrorConfig,把默认的错误页面设置为 /index.html,代码如下

    package com.evan.wj.error;
    
    import org.springframework.boot.web.server.ErrorPageRegistrar;
    import org.springframework.boot.web.server.ErrorPage;
    import org.springframework.boot.web.server.ErrorPageRegistry;
    import org.springframework.http.HttpStatus;
    import org.springframework.stereotype.Component;
    
    @Component
    public class ErrorConfig implements ErrorPageRegistrar {
    
        @Override
        public void registerErrorPages(ErrorPageRegistry registry) {
            ErrorPage error404Page = new ErrorPage(HttpStatus.NOT_FOUND, "/index.html");
            registry.addErrorPages(error404Page);
        }
    
    }
    

    重新启动项目,访问 http://localhost:8443/login ,成功进入登录页面。

    三、后端登录拦截器

    为了完善登录功能,我们需要限制未登录状态下对核心功能页面的访问。登录拦截可以由多种方式来实现,我们首先讲解后端拦截器的开发。(注意如果没有把前后端项目整合起来,就没有办法使用这种方式)

    一个简单拦截器的逻辑如下:

    1.用户访问 URL,检测是否为登录页面,如果是登录页面则不拦截
    2.如果用户访问的不是登录页面,检测用户是否已登录,如果未登录则跳转到登录页面

    1.LoginController

    首先我们修改 LoginController 的内容。之前我们实现了通过查询数据库验证用户名是否正确,但仅此而已。

    为了保存登录状态,我们可以把用户信息存在 Session 对象中(当用户在应用程序的 Web 页之间跳转时,存储在 Session 对象中的变量不会丢失),这样在访问别的页面时,可以通过判断是否存在用户变量来判断用户是否登录。这是一种比较简单的方式,感兴趣的同学可以尝试别的方法。

    修改后的代码内容如下:

    package com.evan.wj.controller;
    
    import com.evan.wj.pojo.User;
    import com.evan.wj.result.Result;
    import com.evan.wj.service.UserService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.*;
    import org.springframework.web.util.HtmlUtils;
    
    import javax.servlet.http.HttpSession;
    
    @Controller
    public class LoginController {
    
        @Autowired
        UserService userService;
    
        @CrossOrigin
        @PostMapping(value = "/api/login")
        @ResponseBody
        public Result login(@RequestBody User requestUser, HttpSession session) {
            String username = requestUser.getUsername();
            username = HtmlUtils.htmlEscape(username);
    
            User user = userService.get(username, requestUser.getPassword());
            if (null == user) {
                return new Result(400);
            } else {
                session.setAttribute("user", user);
                return new Result(200);
            }
        }
    }
    
    

    其实只是添加了一条语句 session.setAttribute("user", user);

    2.LoginInterceptor

    新建 package 名为 interceptor,新建类 LoginInterceptor

    Interceptor 即拦截器,在 Springboot 我们可以直接继承拦截器的接口,然后实现 preHandle 方法。preHandle 方法里的代码会在访问需要拦截的页面时执行。

    代码如下:

    package com.evan.wj.interceptor;
    
    import com.evan.wj.pojo.User;
    import org.apache.commons.lang.StringUtils;
    import org.springframework.web.servlet.HandlerInterceptor;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.HttpSession;
    
    public class LoginInterceptor  implements HandlerInterceptor{
    
        @Override
        public boolean preHandle (HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
            HttpSession session = httpServletRequest.getSession();
            String contextPath=session.getServletContext().getContextPath();
            String[] requireAuthPages = new String[]{
                    "index",
            };
    
            String uri = httpServletRequest.getRequestURI();
    
            uri = StringUtils.remove(uri, contextPath+"/");
            String page = uri;
    
            if(begingWith(page, requireAuthPages)){
                User user = (User) session.getAttribute("user");
                if(user==null) {
                    httpServletResponse.sendRedirect("login");
                    return false;
                }
            }
            return true;
        }
    
        private boolean begingWith(String page, String[] requiredAuthPages) {
            boolean result = false;
            for (String requiredAuthPage : requiredAuthPages) {
                if(StringUtils.startsWith(page, requiredAuthPage)) {
                    result = true;
                    break;
                }
            }
            return result;
        }
    }
    
    

    看起来似乎比较长,其实就是判断 session 中是否存在 user 属性,如果存在就放行,如果不存在就跳转到 login 页面。这里使用了一个路径列表(requireAuthPages),可以在里面写下需要拦截的路径。当然我们也可以拦截所有路径,那样就不用写这么多了,但会有逻辑上的问题,就是你访问了 \login 页面,仍然会需要跳转,这样就会引发多次重定向问题。

    3.WebConfigurer

    我们写完了拦截器,但是它却并不会生效,因为我们还没有把它配置到项目中。

    新建 package 名为 config,新建类 MyWebConfigurer,代码如下:

    package com.evan.wj.config;
    
    import com.evan.wj.interceptor.LoginInterceptor;
    import org.springframework.boot.SpringBootConfiguration;
    import org.springframework.context.annotation.Bean;
    import org.springframework.web.servlet.config.annotation.*;
    
    @SpringBootConfiguration
    public class MyWebConfigurer implements WebMvcConfigurer {
    
        @Bean
        public LoginInterceptor getLoginIntercepter() {
            return new LoginInterceptor();
        }
    
        @Override
        public void addInterceptors(InterceptorRegistry registry){
            registry.addInterceptor(getLoginIntercepter()).addPathPatterns("/**").excludePathPatterns("/index.html");
        }
    }
    
    

    通过这个配置类,我们添加了之前写好的拦截器。这里有一句非常重要的语句,即

    registry.addInterceptor(getLoginIntercepter()).addPathPatterns("/**").excludePathPatterns("/index.html");
    

    这条语句的作用是对所有路径应用拦截器,除了 /index.html

    之前我们在拦截器 LoginInterceptor 中配置的路径,即 index,触发的时机是在拦截器生效之后。也就是说,我们访问一个 URL,会首先通过 Configurer 判断是否需要拦截,如果需要,才会触发拦截器 LoginInterceptor,根据我们自定义的规则进行再次判断。

    /index/index.html 是不同的,也就是说 /index 会触发拦截器而 /index.html 不会,但根据拦截器 LoginInterceptor 中我们定义的判断条件,以 /index 开头的路径都会被转发,包括 index.html

    因为我们做的是单页面应用,之前通过配置 ErrorPage,实际上访问所有路径都会重定向到 /index.html 。我们直接在浏览器地址栏输入 /index 会触发拦截器,经过拦截器重定向到 /login,然后 /login 再经过 Configurer 的判断,再次触发拦截器,由于不在需要拦截的路径中,所以被放行,页面则重新定向到了 /index.html,如果没有再 Configurer 中取消对 /index.html 的拦截,则会再次触发拦截器,再次重定向到 /login,引发如下错误。
    在这里插入图片描述
    上述过程比较绕,这是我开发时的失误,但我觉得恰好可以帮助大家理解拦截器与单页面应用,所以保留了下来。

    4.效果检验

    运行后端项目,访问 http://localhost:8443/index ,发现页面自动跳转到了 http://localhost:8443/login ,输入用户名和密码登录,跳转到 http://localhost:8443/index , 这时可以把浏览器标签关掉,再在一个新标签页输入 http://localhost:8443/index ,发现不会被拦截。

    四、Vuex 与前端登录拦截器

    前面我们使用了后端拦截器,但这种拦截器只有在将前后端项目整合在一起时才能生效,而前后端分离的项目实际上不推荐这么做,接下来我们尝试用前端实现相似的功能。

    实现前端登录器,需要在前端判断用户的登录状态。我们可以像之前那样在组件的 data 中设置一个状态标志,但登录状态应该被视为一个全局属性,而不应该只写在某一组件中。所以我们需要引入一个新的工具——Vuex,它是专门为 Vue 开发的状态管理方案,我们可以把需要在各个组件中传递使用的变量、方法定义在这里。之前我一直没有使用它,所以在不同组件传值的问题上十分头疼,要写很多多余的代码来调用不同组件的值,所以推荐大家从一开始就去熟悉这种管理方式。

    1.引入 Vuex

    在我们的项目文件夹中,运行 npm install vuex --save,之后,在 src 目录下新建一个文件夹 store,并在该目录下新建 index.js 文件,在该文件中引入 vue 和 vuex,代码如下:

    import Vue from 'vue'
    import Vuex from 'vuex'
    
    Vue.use(Vuex)
    

    之后,我们在 index.js 里设置我们需要的状态变量和方法。为了实现登录拦截器,我们需要一个记录用户信息的变量。为了方便日后的扩展(权限认证等),我们使用一个用户对象而不是仅仅使用一个布尔变量。同时,设置一个方法,触发这个方法时可以为我们的用户对象赋值。完整的代码如下:

    import Vue from 'vue'
    import Vuex from 'vuex'
    
    Vue.use(Vuex)
    
    export default new Vuex.Store({
      state: {
        user: {
          username: window.localStorage.getItem('user' || '[]') == null ? '' : JSON.parse(window.localStorage.getItem('user' || '[]')).username
        }
      },
      mutations: {
        login (state, user) {
          state.user = user
          window.localStorage.setItem('user', JSON.stringify(user))
        }
      }
    })
    

    这里我们还用到了 localStorage,即本地存储,在项目打开的时候会判断本地存储中是否有 user 这个对象存在,如果存在就取出来并获得 username 的值,否则则把 username 设置为空。这样我们只要不清除缓存,登录的状态就会一直保存。

    2.修改路由配置

    为了区分页面是否需要拦截,我们需要修改一下 src\router\index.js,在需要拦截的路由中加一条元数据,设置一个 requireAuth 字段如下:

        {
          path: '/index',
          name: 'AppIndex',
          component: AppIndex,
          meta: {
            requireAuth: true
          }
        }
    

    完整的 index.js 代码如下:

    import Vue from 'vue'
    import Router from 'vue-router'
    import AppIndex from '@/components/home/AppIndex'
    import Login from '@/components/Login'
    
    Vue.use(Router)
    
    export default new Router({
      mode: 'history',
      routes: [
        {
          path: '/login',
          name: 'Login',
          component: Login
        },
        {
          path: '/index',
          name: 'AppIndex',
          component: AppIndex,
          meta: {
            requireAuth: true
          }
        }
      ]
    })
    
    

    3.使用钩子函数判断是否拦截

    钩子函数及在某些时机会被调用的函数。这里我们使用 router.beforeEach(),意思是在访问每一个路由前调用。

    打开 src\main.js ,首先添加对 store 的引用

    import store from './store'
    

    并修改 Vue 对象里的内容

    new Vue({
      el: '#app',
      render: h => h(App),
      router,
      // 注意这里
      store,
      components: { App },
      template: '<App/>'
    })
    

    接着写 beforeEach() 函数

    router.beforeEach((to, from, next) => {
        if (to.meta.requireAuth) {
          if (store.state.user.username) {
            next()
          } else {
            next({
              path: 'login',
              query: {redirect: to.fullPath}
            })
          }
        } else {
          next()
        }
      }
    )
    

    这个的逻辑很简单,首先判断访问的路径是否需要登录,如果需要,判断 store 里有没有存储 user 的信息,如果存在,则放行,否则跳转到登录页面,并存储访问的页面路径(以便在登录后跳转到访问页)。

    完整的 main.js 代码如下:

    import Vue from 'vue'
    import App from './App'
    import router from './router'
    import store from './store'
    import ElementUI from 'element-ui'
    import 'element-ui/lib/theme-chalk/index.css'
    
    var axios = require('axios')
    axios.defaults.baseURL = 'http://localhost:8443/api'
    Vue.prototype.$axios = axios
    Vue.config.productionTip = false
    
    Vue.use(ElementUI)
    
    router.beforeEach((to, from, next) => {
        if (to.meta.requireAuth) {
          if (store.state.user.username) {
            next()
          } else {
            next({
              path: 'login',
              query: {redirect: to.fullPath}
            })
          }
        } else {
          next()
        }
      }
    )
    
    /* eslint-disable no-new */
    new Vue({
      el: '#app',
      render: h => h(App),
      router,
      store,
      components: { App },
      template: '<App/>'
    })
    
    

    4.修改 Login.vue

    之前的登录组件中,我们只是判断后端返回的状态码,如果是 200,就重定向到首页。在经过前面的配置后,我们需要修改一下登录逻辑,以最终实现登录拦截。

    修改后的逻辑如下:

    1.点击登录按钮,向后端发送数据
    2.受到后端返回的成功代码时,触发 store 中的 login() 方法,把 loginForm 对象传递给 store 中的 user 对象
    (*这里只是简单的实现,在后端我们可以通过用户名和密码查询数据库,获得 user 表的完整信息,比如用户昵称、用户级别等,返回前端,并传递给 user 对象,以实现更复杂的功能)
    3.获取登录前页面的路径并跳转,如果该路径不存在,则跳转到首页

    修改后的 login() 方法如下:

    login () {
      var _this = this
      console.log(this.$store.state)
      this.$axios
        .post('/login', {
          username: this.loginForm.username,
          password: this.loginForm.password
        })
        .then(successResponse => {
          if (successResponse.data.code === 200) {
            // var data = this.loginForm
            _this.$store.commit('login', _this.loginForm)
            var path = this.$route.query.redirect
            this.$router.replace({path: path === '/' || path === undefined ? '/index' : path})
          }
        })
        .catch(failResponse => {
        })
    }
    

    完整的 Login.vue 代码如下:

    <template>
      <body id="poster">
        <el-form class="login-container" label-position="left"
                 label-width="0px">
          <h3 class="login_title">系统登录</h3>
          <el-form-item>
            <el-input type="text" v-model="loginForm.username"
                      auto-complete="off" placeholder="账号"></el-input>
          </el-form-item>
          <el-form-item>
            <el-input type="password" v-model="loginForm.password"
                      auto-complete="off" placeholder="密码"></el-input>
          </el-form-item>
          <el-form-item style="width: 100%">
            <el-button type="primary" style="width: 100%;background: #505458;border: none" v-on:click="login">登录</el-button>
          </el-form-item>
        </el-form>
      </body>
    </template>
    
    <script>
    
      export default {
        name: 'Login',
        data () {
          return {
            loginForm: {
              username: 'admin',
              password: '123'
            },
            responseResult: []
          }
        },
        methods: {
          login () {
            var _this = this
            console.log(this.$store.state)
            this.$axios
              .post('/login', {
                username: this.loginForm.username,
                password: this.loginForm.password
              })
              .then(successResponse => {
                if (successResponse.data.code === 200) {
                  // var data = this.loginForm
                  _this.$store.commit('login', _this.loginForm)
                  var path = this.$route.query.redirect
                  this.$router.replace({path: path === '/' || path === undefined ? '/index' : path})
                }
              })
              .catch(failResponse => {
              })
          }
        }
      }
    </script>
    
    <style>
      #poster {
        background:url("../assets/eva.jpg") no-repeat;
        background-position: center;
        height: 100%;
        width: 100%;
        background-size: cover;
        position: fixed;
      }
      body{
        margin: 0px;
      }
      .login-container {
        border-radius: 15px;
        background-clip: padding-box;
        margin: 90px auto;
        width: 350px;
        padding: 35px 35px 15px 35px;
        background: #fff;
        border: 1px solid #eaeaea;
        box-shadow: 0 0 25px #cac6c6;
      }
      .login_title {
        margin: 0px auto 40px auto;
        text-align: center;
        color: #505458;
      }
    
    </style>
    
    

    5.效果检验

    同时运行前后端项目,访问 http://localhost:8080/index ,发现页面直接跳转到了 http://localhost:8080/login?redirect=%2Findex

    在这里插入图片描述
    输入账号密码后登录,成功跳转到 http://localhost:8080/index ,之后再次访问则无需登录(除非清除缓存)。


    最后吐槽两句,人呐,真是不能乱立 flag,写第一篇文章的时候,我说感谢老板不让我 996,然后就 895 了,上一篇文章我说这两天闲,多写几篇文章,然后就又接了个大项目,周末还在出差开会,昨天晚上忙到 12 点困得不行,想着先睡觉早上早点起来再把工作收个尾,结果酒店隔壁房间一群小孩儿在玩狼人杀,回想起我们过去同样的行径,这口气我忍了。。。

    所以读者大人们请原谅我没有及时更新,作为一个不知名博主,十分感谢大家的支持。我会坚持下去的,希望大家都能坚持做自己想做的事,一起变得更加牛批!

    查看系列文章目录:
    https://learner.blog.csdn.net/article/details/88925013

    上一篇:Vue + Spring Boot 项目实战(五):使用 Element 辅助前端开发

    下一篇: Vue + Spring Boot 项目实战(七):导航栏与图书页面设计

    展开全文
  • 配置图文,超详细!!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>
    

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

    展开全文
  • SpringBoot之HandlerInterceptor拦截器的使用 ——(一)

    万次阅读 多人点赞 2018-08-15 14:06:37
    拦截器我想大家都并不陌生,最常用的登录拦截、或是权限校验、或是防重复提交、或是根据业务像12306去校验购票时间,总之可以去做很多的事情。 1、定义实现类 定义一个Interceptor 非常简单方式也有几种,...

    HandlerInterceptor简介

    拦截器我想大家都并不陌生,最常用的登录拦截、或是权限校验、或是防重复提交、或是根据业务像12306去校验购票时间,总之可以去做很多的事情。
    我仔细想了想
    这里我分三篇博客来介绍HandlerInterceptor的使用,从基本的使用、到自定义注解、最后到读取body中的流解决无法多次读取的问题。

    1、定义实现类

    定义一个Interceptor 非常简单方式也有几种,我这里简单列举两种
    1、类要实现Spring 的HandlerInterceptor 接口
    2、类继承实现了HandlerInterceptor 接口的类,例如 已经提供的实现了HandlerInterceptor 接口的抽象类HandlerInterceptorAdapter

    这里博主用的是第二种方法继承HandlerInterceptorAdapter

    2、HandlerInterceptor方法介绍

    
    	boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
    			throws Exception;
    
    	void postHandle(
    			HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
    			throws Exception;
    
    	void afterCompletion(
    			HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
    			throws Exception;
    
    • preHandle:在业务处理器处理请求之前被调用。预处理,可以进行编码、安全控制、权限校验等处理;
    • postHandle:在业务处理器处理请求执行完成后,生成视图之前执行。后处理(调用了Service并返回ModelAndView,但未进行页面渲染),有机会修改ModelAndView (这个博主就基本不怎么用了);
    • afterCompletion:在DispatcherServlet完全处理完请求后被调用,可用于清理资源等。返回处理(已经渲染了页面);

    接下来让我们来实现一个登陆 and 访问权限校验的拦截器吧

    拦截器实现

    • 新建TestFilter
    package com.xxx.core.filter;
    
    import com.xxx.common.exception.FastRuntimeException;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.web.servlet.ModelAndView;
    import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    
    public class TestFilter extends HandlerInterceptorAdapter {
    	private final Logger logger = LoggerFactory.getLogger(TestFilter.class);
    	@Override
    	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
    			throws Exception {
    		logger.info("request请求地址path[{}] uri[{}]", request.getServletPath(),request.getRequestURI());
    		//request.getHeader(String) 从请求头中获取数据
    		//从请求头中获取用户token(登陆凭证根据业务而定)
    		Long userId= getUserId(request.getHeader("H-User-Token"));
    		if (userId != null && checkAuth(userId,request.getRequestURI())){
    			return true;
    		}
    		//这里的异常是我自定义的异常,系统抛出异常后框架捕获异常然后转为统一的格式返回给前端, 其实这里也可以返回false
    		throw new FastRuntimeException(20001,"No access");
    	}
    
    	/**
    	 * 根据token获取用户ID
    	 * @param userToken
    	 * @return
    	 */
    	private Long getUserId(String userToken){
    		Long userId = null;
    		return userId;
    	}
    
    	/**
    	 * 校验用户访问权限
    	 * @param userId
    	 * @param requestURI
    	 * @return
    	 */
    	private boolean checkAuth(Long userId,String requestURI){
    		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 {}
    }
    
    • 新建WebAppConfigurer 实现WebMvcConfigurer接口

    其实以前都是继承WebMvcConfigurerAdapter类 不过springBoot2.0以上 WebMvcConfigurerAdapter 方法过时,有两种替代方案:
    1、继承WebMvcConfigurationSupport
    2、实现WebMvcConfigurer
    但是继承WebMvcConfigurationSupport会让Spring-boot对mvc的自动配置失效。根据项目情况选择。现在大多数项目是前后端分离,并没有对静态资源有自动配置的需求所以继承WebMvcConfigurationSupport也未尝不可。

    @Configuration
    public class WebAppConfigurer implements WebMvcConfigurer {
    
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            // 可添加多个
            registry.addInterceptor(new TestFilter()).addPathPatterns("/**");
        }
    
        ....
    }
    

    其实下面还有很多方法我这里就省略了,过滤器可以添加多个,可以指定Path,这里的/**是对所有的请求都做拦截。

    是否感觉配置这个地址是不特别方便?下一篇博客介绍2.0版本引入注解来协助完成一系列的拦截任务。
    SpringBoot之HandlerInterceptor拦截器的使用 ——(二)自定义注解
    SpringBoot之HandlerInterceptor拦截器的使用 ——(三)获取请求参数解决java.io.IOException: Stream closed
    SpringBoot之HandlerInterceptor拦截器的使用 ——(四)防重复提交

    展开全文
  • CHROME扩展笔记之webRequest·图片拦截

    万次阅读 2021-02-24 15:28:00
    //插件监听拦截-图片 chrome.webRequest.onBeforeRequest.addListener ( function(details) { // console.log(details); // 回调返回一个对象,如果对象里得cancel为true则会拦截不继续请求 return {can
  • axios拦截器(请求拦截和响应拦截

    千次阅读 2019-10-11 18:36:09
    axios拦截器分为request请求拦截器和response响应拦截器。 request请求拦截器:发送请求前统一处理,如:设置请求头headers等。 response响应拦截器:有时候我们要根据响应的状态码来进行下一步操作。 axios....
  • Java 里的拦截器是动态拦截 action 调用的对象。它提供了一种机制可以使开发者可以定义在一个 action 执行的前后执行的代码,也可以在一个 action 执行前阻止其执行,同时也提供了一种可以提取 action 中可重用部分...
  • 拦截导弹

    千次阅读 2021-02-28 20:03:54
    某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭。由于...
  • SpringBoot拦截器实现登录拦截

    万次阅读 多人点赞 2019-07-12 22:27:29
    SpringBoot拦截器可以做什么 可以对URL路径进行拦截,可以用于权限验证、解决乱码、操作日志记录、性能监控、异常处理等 SpringBoot拦截器实现登录拦截 pom.xml: <?xml version="1.0" encoding="UTF-8"?> ...
  • 详述 Spring MVC 框架中拦截器 Interceptor 的使用方法

    万次阅读 多人点赞 2017-03-30 17:02:05
    1 前言 昨天新接了一个需要,“拦截 XXX,然后 OOO”,好吧,说白了就是要用拦截器干点事(实现一个具体的功能)。之前,也在网络上搜了很多关于Interceptor的文章,但感觉内容都大同小异,而且知识点零零散散,不...
  • springmvc下写一个登录的拦截器,怎么在XML配置文件中配置拦截多个路径?还是一个拦截器只能有一个拦截路径?
  • Mybatis拦截

    万次阅读 多人点赞 2019-04-16 22:31:18
    通过Mybatis拦截器我们可以拦截某些方法的调用,我们可以选择在这些被拦截的方法执行前后加上某些逻辑,也可以在执行这些被拦截的方法时执行自己的逻辑而不再执行被拦截的方法。所以Mybatis拦截器的使用范围是...
  • SpringBoot使用拦截

    万次阅读 多人点赞 2020-12-22 15:52:56
    拦截器对使用SpringMvc、的开发人员来说特别熟悉,因为你只要想去做好一个项目必然会用到它。拦截器在我们平时的项目中用处有很多,如:日志记录、用户登录状态拦截、安全拦截等等。而SpringBoot内部集成的是...
  • android事件拦截处理机制详解

    万次阅读 多人点赞 2014-11-13 19:43:33
    android 事件拦截处理机制详解
  • springboot下的拦截

    万次阅读 2020-03-22 11:34:05
    1.拦截所有需要登录才能访问的页面 实现HandlerInterceptor的类, response.sendRedirect("/user-exit");是将没有登录的用户拦截到user-exit的页面 package com.example.intecepter; import java.io.IOException; ...
  • Springboot 拦截器链 - 加载拦截

    千次阅读 2018-04-01 17:30:39
    Springboot 拦截器链 - 加载拦截器 1.创建拦截器 // 创建拦截器需要实现 HandlerInterceptor 接口 @Slf4j public class HandleInterceptorImpl implements HandlerInterceptor{ @Override public boolean...
  • springboot拦截器的拦截与不拦截

    千次阅读 2018-12-24 20:07:19
    //登陆拦截器 public class LoginInterceptor implements HandlerInterceptor { //访问controller之前被调用 @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response,...
  • 1.定义拦截器(设置要拦截的方法或者不拦截的)2.拦截器写法(这里用了两个,一个拦截html标签,一个拦截html事件属性)IllegalCharInterceptor拦截器写法如下:其中HTMLSprit.delHTMLTag()方法如下:...
  • swagger被拦截拦截

    万次阅读 2018-09-28 14:01:02
    配置swagger文档,被拦截拦截不能使用 拦截器中添加以下配置,适当修改即可使用 重写addInterceptors registry.addInterceptor(new UserInterceptor()).addPathPatterns(&quot;/**&quot;) ....
  • springmvc下写一个登录的拦截器,怎么在配置文件中配置拦截多个路径?还是一个拦截器只能有一个拦截
  • Struts2_拦截器(Action拦截和全局拦截)

    千次阅读 2017-07-11 13:53:40
    先说说什么是拦截器: 拦截器,顾名思义,拦截请求(Action),可以达到增强Action的功能,框架本身默认提供很多拦截器,大概有35种,但往往实际开发中,还需要自定义一些拦截器,比如:权限(访问)拦截。再说说怎么
  • 拦截器只会拦截一次还是每次访问都会拦截? ``` public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 获取请求的URL String ...
  • struts2登录拦截拦截Action,拦截url)
  • Spring Boot 拦截器无效,不起作用

    万次阅读 多人点赞 2018-08-10 10:37:49
    导致这个问题可能有两个原因:一个是拦截器写错了,另一个是拦截器配置错了。 1、需求是这样的 拦截所有的api请求,判断其请求头中的secret参数是否正确,正确的请求才能访问api。 2、拦截器配置 需要先写...
  • ![图片说明](https://img-ask.csdn.net/upload/201803/12/1520825226_409876.png) !...这里excludePathPatterns("/")可以排除index,但是excludePathPatterns("index")还是会拦截index,这是什么原理
  • springboot拦截拦截IP

    千次阅读 2019-01-22 15:25:09
    springboot拦截拦截IP 新建MyWebMvcConfigurerAdapter 代码 去博客设置页面,选择一款你喜欢的代码片高亮样式,下面展示同样高亮的 代码片. import org.springframework.context.annotation.Bean; import org....
  • Spring Boot拦截器配置拦截登陆

    万次阅读 多人点赞 2018-07-09 18:34:57
     2,每一个拦截器有需要实现的 HandlerInterceptor 接口,这个接口有三个方法,每个方法会在请求调用的不同时期完成,因为我们需要在接口调用之前拦截请求判断是否登陆,所以这里需要使用 preHandle 方法,在里面写...
  • 请问谁有Struts2拦截器学习的详细资料,请问谁有Struts2拦截器学习的详细资料,感谢哈
  • kafka自定义拦截器|案例实战

    千次阅读 多人点赞 2020-04-29 14:33:01
    本文详细解释kafka的拦截器及拦截器链,并根据案例实现两个常见的自定义拦截器并组成拦截链,Talk is cheap,Show me the code
  • Mybatis拦截拦截所有更新操作

    千次阅读 2019-08-05 22:46:49
    MyBatis 允许你在已映射语句执行过程中的某一点进行拦截调用。默认情况下,MyBatis 允许使用插件来拦截的方法调用包括: Executor (update, query, flushStatements, commit, rollback, getTransaction, close, is...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 561,020
精华内容 224,408
关键字:

拦截