Spring中利用拦截器控制登录及页面跳转

一、问题简要描述:

在做web开发的时候往往会遇到这种情况,用户在没登录的情况下访问一些需要身份验证的页面,系统会自动帮用户跳转到登录页面,用户登录成功后,不会返回一个固定的页面,系统会跳转到用户之前访问的页面,用户可以继续进行刚才的操作。或者是session里面保存的用户信息过期了,用户需要重新进行身份验证(重新登录),用户登录成功后,页面还是会回到之前访问的页面。

二、问题所涉及的知识和技术:

Shiro,Spring,SpringMVC,拦截器,java,Servlet

三、问题解决

这个问题我现在知道的有两种解决办法(本人能力有限),一种是利用SpringMVC里面的拦截器(实现HandlerInterceptor接口),一种是使用Shiro插件(不久我会整理一份《Apache Shiro简介》和《Spring整合Shiro详解》,具体可查看我的这两个博文)

1、实现HandlerInterceptor接口从而实现控制登录及页面跳转

HandlerInterceptor接口中定义了三个方法,我们就是通过这三个方法来对用户的请求进行拦截处理的。

(1 )preHandle(HttpServletRequest request, HttpServletResponse response, Object handle) 方法,顾名思义,该方法将在请求处理之前进行调用。SpringMVC 中的Interceptor是链式的调用的,在一个应用中或者说是在一个请求中可以同时存在多个Interceptor 。每个Interceptor的调用会依据它的声明顺序依次执行,而且最先执行的都是Interceptor 中的preHandle方法,所以可以在这个方法中进行一些前置初始化操作或者是对当前请求的一个预处理,也可以在这个方法中进行一些判断来决定请求是否要继续进行下去。该方法的返回值是布尔值Boolean 类型的,当它返回为false时,表示请求结束,后续的Interceptor 和Controller都不会再执行;当返回值为true 时就会继续调用下一个Interceptor 的preHandle 方法,如果已经是最后一个Interceptor 的时候就会是调用当前请求的Controller方法。

   (2 )postHandle (HttpServletRequest request,HttpServletResponse response, Object handle, ModelAndView modelAndView) 方法,由preHandle 方法的解释我们知道这个方法包括后面要说到的afterCompletion 方法都只能是在当前所属的Interceptor的preHandle 方法的返回值为true时才能被调用。postHandle 方法,顾名思义就是在当前请求进行处理之后,也就是Controller 方法调用之后执行,但是它会在DispatcherServlet进行视图返回渲染之前被调用,所以我们可以在这个方法中对Controller 处理之后的ModelAndView对象进行操作。postHandle 方法被调用的方向跟preHandle是相反的,也就是说先声明的Interceptor 的postHandle方法反而会后执行,这和Struts2 里面的Interceptor的执行过程有点类型。Struts2 里面的Interceptor的执行过程也是链式的,只是在Struts2 里面需要手动调用ActionInvocation的invoke 方法来触发对下一个Interceptor或者是Action 的调用,然后每一个Interceptor中在invoke 方法调用之前的内容都是按照声明顺序执行的,而invoke 方法之后的内容就是反向的。

   (3 )afterCompletion(HttpServletRequest request,HttpServletResponse response, Object handle, Exception ex) 方法,该方法也是需要当前对应的Interceptor 的preHandle 方法的返回值为true 时才会执行。顾名思义,该方法将在整个请求结束之后,也就是在DispatcherServlet 渲染了对应的视图之后执行。这个方法的主要作用是用于进行资源清理工作的。

下面给出具体的代码:(具体思路是这样的,在preHandle这个方法中,获得请求的地址(具体读者可以了解项目地址,真实地址,带参地址)然后把它保存在session中,最后在你认证登录的时候作一个判断,取出这个session里面的地址,进行登录跳转)

        @Override
	public void afterCompletion(HttpServletRequest arg0,
			HttpServletResponse arg1, Object arg2, Exception arg3)
			throws Exception {
		
		
	}
	@Override
	public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1,
			Object arg2, ModelAndView arg3) throws Exception {
		
		
	}
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
			Object arg2) throws Exception {
		
		User user = (User) request.getSession().getAttribute("loginUser");
		if(user == null){
			request.getRequestDispatcher("/login.jsp").forward(request, response);  
			HttpSession session = request.getSession(true); 
	    	String uri = request.getRequestURI();//拿到上一个页面地址
	    	String path = uri.substring(request.getContextPath().length());//去掉项目地址长度的字符(因为我的默认项目地址是给出的)
	    	String query = request.getQueryString();//得到参数
	    	if(query == null) {
	    		query = "";
	    	}
	    	String realPath = path+"?"+query;
	    	System.out.println(uri+"?"+query);//测试用
	    	System.out.println(realPath);//测试用
	    	session.setAttribute("realPath", realPath);
			return false;
		}
		return true;
	}
}

2、使用Shiro插件实现

如果你的项目里面集成了Shiro安全框架,那么恭喜你,你可以很方便的实现控制登录及页面跳转,我也推荐使用这个方法,因为Shiro实在是太强大了,读者可以阅读我的另外两个博文(即将发出):《Apache Shiro简介》和《Spring整合Shiro详解》。先来介绍这个,Shiro里面有一个方法,可以得到跳转到登录页面之前的页面的地址SavedRequest savedRequest =WebUtils.getSavedRequest(request);是不是很方便。

具体代码如下(因为牵扯的太多,所以只讲述这一块,如果想深入了解,可以阅读我的其他博文,谢谢):

这段是你的项目里面的认证控制器

        @SysLog(operation="登录")
	@RequestMapping(value = "/login", method = RequestMethod.POST)
	public String login(String username, String password, String remember, String captcha, Model model, HttpSession httpSession,HttpServletRequest request) throws IOException {
		httpSession.setAttribute("username", username);
		User user = userService.getByUsername(username);
		httpSession.setAttribute("loginUser", userService.getByUsername(username));
		
		SavedRequest savedRequest = WebUtils.getSavedRequest(request);
		if(savedRequest == null){
			if(user.getUserType() == UserType.admin) {
				return "redirect:/admin/dashboard";
			}
			return "redirect:/user";
		}else {
			String url = savedRequest.getRequestUrl().substring(request.getContextPath().length());
			return "redirect:"+url;
		}
	}

作者声明:写这篇文章的初衷旨在不忘记一些工作中需要的知识点和技能,方便以后查阅,也方便有需要的同行拿去参考。以上文字和图片都不是本人敲打上去的(除了本段),因为没那时间和精力,也没必要。东凑西拼的东西好用就行,也能发挥互联网共享的理念,我也做一个不辞辛苦的搬运工。以上内容的原文如有,“转载注明原文出处”,还望见谅没能实现,早已忘记是从哪里摘录。此致!奋斗在猿类世界的小晨。

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值