在springMVC中写拦截器,只需要两步:

一、写 java 拦截器类,实现 interceptor 拦截器接口。

二、在 springMVC 的xml配置文件中,配置我们创建的拦截器对象及其拦截目标 url

首先,在前台门户项目中创建一个拦截器java类:

taotao用户登录springMVC拦截器的实现-LMLPHP

package com.taotao.portal.interceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView; import com.taotao.common.utils.CookieUtils;
import com.taotao.pojo.TbUser;
import com.taotao.portal.service.impl.UserServiceImpl; public class LoginInterceptor implements HandlerInterceptor { /**
* 注意,因为拦截器属于Controller,而在Controller中是不能使用Value注解来获取配置文件中设置的值的,
* 因为 Value是spring父容器加载的属性,而Controller是springMVC子容器加载的,子容器可以访问父容器中的对象,
* 但是不能访问父容器中的属性
*
* 而我们在这里还需要用到 配置文件 中的 url值,只要用变通的方法
* 1.首先在service的实现类 UserServiceImpl 中用@Value获取到属性,并将其设置成 public类型
* 2.在Controller这里,不注入接口,而是直接注入 UserServiceImpl 实现类
* 这样就可以在Controller中直接使用注入的service实现类的属性了
*/
@Autowired
private UserServiceImpl userService; //在handler执行之前处理
//返回值决定handler是否执行。true:执行, false:不执行
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
//判断用户是否登录
//从cookie中取token
String token = CookieUtils.getCookieValue(request, "TT_TOKEN");
//根据token换取用户信息,调用sso系统的接口
///这里需要写一些业务 逻辑,不要在拦截器中写,单写一个service,只在这里注入并调用
TbUser user = userService.getUserByToken(token);
//如果取不到用户信息
if (user==null) {
//跳转到登录页面,把用户请求的url作为参数传递给登录页面
response.sendRedirect(userService.SSO_BASE_URL+userService.SSO_PAGE_LOGIN
+"?redirect="+request.getRequestURL());
//返回false
return false;
}
//如果取到用户信息,放行
        //把用户信息放到request中,以便后面在Controller中使用用户信息
        request.setAttribute("user", user); //request中可以直接存对象,只要到了后台都可以直接存对象
return true;
} //在 handler执行之后,返回ModelAndView之前处理
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
// TODO Auto-generated method stub } //返回ModelAndView之后处理(响应用户之后,可以用来处理异常)
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
// TODO Auto-generated method stub } }

只要实现拦截器接口,覆盖其中的方法即可。

在方法中,我们需要写一些业务逻辑,这里其实就是用 从 cookie 中取出的 token,到redis中查询,看是否能查到用户,若能查到,说明已经登录,拦截器不拦截,继续往下访问;若查询不到,说明当前用户登录已经过期,需要携带目标 url 跳转到登录页面(以便登录完可以继续访问之前的目标 url)。

其中用到的 service:

package com.taotao.portal.service.impl;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service; import com.taotao.common.pojo.TaotaoResult;
import com.taotao.common.utils.HttpClientUtil;
import com.taotao.pojo.TbUser;
import com.taotao.portal.service.UserService; @Service
public class UserServiceImpl implements UserService { @Value("${SSO_BASE_URL}")
public String SSO_BASE_URL;//#单点登录系统的url SSO_BASE_URL=http://localhost:8084 @Value("${SSO_USER_TOKEN}")
private String SSO_USER_TOKEN; //#根据token获取用户信息的url user/token/ @Value("${SSO_PAGE_LOGIN}")
public String SSO_PAGE_LOGIN; //#单点登录系统登录url /page/login/ @Value("${SSO_USER_LOGOUT}")
public String SSO_USER_LOGOUT; //#退出登录 SSO_USER_LOGOUT=/user/logout/ @Override
public TbUser getUserByToken(String token) {
try {
//调用sso接口,根据token获取用户信息
String json = HttpClientUtil.doGet(SSO_BASE_URL+SSO_USER_TOKEN+token);
TaotaoResult taotaoResult = TaotaoResult.formatToPojo(json, TbUser.class);
if (taotaoResult.getStatus()==200) {
TbUser user = (TbUser) taotaoResult.getData();
return user;
}
} catch (Exception e) {
e.printStackTrace();
}
//如果没有获取到user或者出现异常,都返回null
return null;
} }

写好拦截器java类后,需要在SpringMVC中配置我们自定义的拦截器:

taotao用户登录springMVC拦截器的实现-LMLPHP

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="com.taotao.portal.controller" />
<mvc:annotation-driven />
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean> <!-- 资源映射 因为此工程访问的是 *.html 所以不用配置静态资源映射 静态资源映射只有当web.xml中的servlet—mapping 中的url-pattern为 / 时才需要用 -->
<!-- <mvc:resources location="/WEB-INF/css/" mapping="/css/**"/>
<mvc:resources location="/WEB-INF/js/" mapping="/js/**"/> --> <!-- 定义文件上传解析器 -->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 设定默认编码 -->
<property name="defaultEncoding" value="UTF-8"></property>
<!-- 设定文件上传的最大值5MB,5*1024*1024 -->
<property name="maxUploadSize" value="5242880"></property>
</bean> <!-- 拦截器配置 -->
<mvc:interceptors>
<mvc:interceptor>
<!-- 拦截订单类请求 -->
<mvc:mapping path="/item/**"/>
<bean class="com.taotao.portal.interceptor.LoginInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
</beans>

其中 path属性配置我们要拦截的请求路径:

<mvc:mapping path="/item/**"/>

这里我们拦截所有以  /item  开头的请求。

然后bean就是配置我们自定义的java类的全限定名:

<bean class="com.taotao.portal.interceptor.LoginInterceptor"/>

然后我们测试:

在门户首页搜索 商品
taotao用户登录springMVC拦截器的实现-LMLPHP

因为请求不是 item 开头的,所以拦截器不拦截,然后我们点击我们搜索到的商品,发送查看商品信息请求:

taotao用户登录springMVC拦截器的实现-LMLPHP

因为这回的请求是 以 /item 开头的,所以被拦截器拦截,拦截器检查到当前 的 token 没有在redis中查到对应用户,所以判断为未登录,跳转到登录页

http://localhost:8084/page/login/

并且携带了原 url 作为参数 redirect=http://localhost:8082/item/153984258656220.html

然后,在跳转到登录页请求的Controller中,又将 参数 redirect 取出,放到 model域中,存到 jsp 页面上

sso中的 PageController 中的登录页面跳转方法:

    /**
* 跳转到登录页面
* @param redirect 登录成功后跳转的回调页面url
* @param model
* @return
*/
@RequestMapping("/login")
public String showLogin(String redirect,Model model) {
model.addAttribute("redirect", redirect);
return "login";
}

前台 login.jsp:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page trimDirectiveWhitespaces="true" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312"/>
<title>登录淘淘</title>
<link type="text/css" rel="stylesheet" href="/css/login.css"/>
<script type="text/javascript" src="/js/jquery-1.6.4.js"></script>
</head>
<body>
<div class="w">
<div id="logo">
<a href="http://localhost:8082" clstag="passport|keycount|login|01">
<img src="/images/taotao-logo.gif" alt="淘淘" width="170" height="60"/>
</a><b></b>
</div>
</div>
<form id="formlogin" method="post" onsubmit="return false;">
<div class=" w1" id="entry">
<div class="mc " id="bgDiv">
<div id="entry-bg" clstag="passport|keycount|login|02" style="width: 511px; height: 455px; position: absolute; left: -44px; top: -44px; background: url(/images/544a11d3Na5a3d566.png) 0px 0px no-repeat;">
</div>
<div class="form ">
<div class="item fore1">
<span>用户名</span>
<div class="item-ifo">
<input type="text" id="loginname" name="username" class="text" tabindex="1" autocomplete="off"/>
<div class="i-name ico"></div>
<label id="loginname_succeed" class="blank invisible"></label>
<label id="loginname_error" class="hide"><b></b></label>
</div>
</div>
<script type="text/javascript">
setTimeout(function () {
if (!$("#loginname").val()) {
$("#loginname").get(0).focus();
}
}, 0);
</script>
<div id="capslock"><i></i><s></s>键盘大写锁定已打开,请注意大小写</div>
<div class="item fore2">
<span>密码</span>
<div class="item-ifo">
<input type="password" id="nloginpwd" name="password" class="text" tabindex="2" autocomplete="off"/>
<div class="i-pass ico"></div>
<label id="loginpwd_succeed" class="blank invisible"></label>
<label id="loginpwd_error" class="hide"></label>
</div>
</div>
<div class="item login-btn2013">
<input type="button" class="btn-img btn-entry" id="loginsubmit" value="登录" tabindex="8" clstag="passport|keycount|login|06"/>
</div>
</div>
</div>
<div class="free-regist">
<span><a href="/page/register" clstag="passport|keycount|login|08">免费注册&gt;&gt;</a></span>
</div>
</div>
</form>
<script type="text/javascript">
var redirectUrl = "${redirect}";
var LOGIN = {
checkInput:function() {
if ($("#loginname").val() == "") {
alert("用户名不能为空");
$("#loginname").focus();
return false;
}
if ($("#nloginpwd").val() == "") {
alert("密码不能为空");
$("#nloginpwd").focus();
return false;
}
return true;
},
doLogin:function() {
$.post("/user/login", $("#formlogin").serialize(),function(data){
if (data.status == 200) {
alert("登录成功!");
if (redirectUrl == "") {//如果没有回调跳转到首页
location.href = "http://localhost:8082";
} else { //有回调,跳转到回调页面
location.href = redirectUrl;
}
} else {
alert("登录失败,原因是:" + data.msg);
$("#loginname").select();
}
});
},
login:function() {
if (this.checkInput()) {
this.doLogin();
}
} };
$(function(){
$("#loginsubmit").click(function(){
LOGIN.login();
});
});
</script>
</body>
</html>

前台填写好用户名、密码后,登录表单提交,如果登录成功,前台则会继续 跳转之前要访问的 目标 url。

05-26 06:55