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

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

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

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

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

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中配置我们自定义的拦截器:

<?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"/>

然后我们测试:

在门户首页搜索 商品

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

 因为这回的请求是 以 /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=" 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。

原文地址:https://www.cnblogs.com/libin6505/p/9871853.html