1、创建拦截器LoginInterceptor并实现HandlerInterceptor

@Component的作用

1、@component (把普通pojo实例化到spring容器中,相当于配置文件中的<bean id="" class=""/>) 2、@Component泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。

package com.sgcc.epri.basis.config;

import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component
public class LoginInterceptor implements HandlerInterceptor {

    /**
     * 预处理回调方法,实现处理器的预处理
     * 返回值:true表示继续流程;false表示流程中断,不会继续调用其他的拦截器或处理器
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        System.out.println("开始拦截.........");
        //业务代码
        return false;
    }

    /**
     * 后处理回调方法,实现处理器(controller)的后处理,但在渲染视图之前
     * 此时我们可以通过modelAndView对模型数据进行处理或对视图进行处理
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                           ModelAndView modelAndView) throws Exception {
        // TODO Auto-generated method stub

    }
    /**
     * 整个请求处理完毕回调方法,即在视图渲染完毕时回调,
     * 如性能监控中我们可以在此记录结束时间并输出消耗时间,
     * 还可以进行一些资源清理,类似于try-catch-finally中的finally,
     * 但仅调用处理器执行链中
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        // TODO Auto-generated method stub

    }

}

2、创建配置类,引入拦截器

@Configuration的作用

从Spring3.0,@Configuration用于定义配置类,可替换xml配置文件,被注解的类内部包含有一个或多个被@Bean注解的方法,这些方法将会被AnnotationConfigApplicationContext或AnnotationConfigWebApplicationContext类进行扫描,并用于构建bean定义,初始化Spring容器。

package com.sgcc.epri.basis.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

@Configuration
public class MvcInterceptorConfig extends WebMvcConfigurationSupport {

    @Autowired
    private LoginInterceptor loginInterceptor;

    @Override
    protected void addInterceptors(InterceptorRegistry registry) {
        // 多个拦截器组成一个拦截器链
        // addPathPatterns 用于添加拦截规则,/**表示拦截所有请求
        // excludePathPatterns 用户排除拦截
        registry.addInterceptor(loginInterceptor).addPathPatterns("/**")
                .excludePathPatterns("/demo","/test");
        super.addInterceptors(registry);
    }
}

registry.addInterceptor(loginInterceptor).addPathPatterns("/**").excludePathPatterns("/demo","/test");

它的意思是拦截所有请求,但是放过/demo,/test两个请求

但是我们不会直接把放行的方法写到这里,每次修改代码的操作很冗余也不规范。

3、将不拦截方法写入到配置文件里

application.yml配置放行地址

# 权限校验url白名单,不用登录和授权也能访问的后端接口路径
# (多个使用逗号分隔)  换行请以“\”结尾
permitted-url: "/demo,\
                /test"

在配置类里获取这个配置的内容

@Value("${permitted-url}")
private String permittedUrl;

注释之前代码改为一下内容

List<String> permittedUrls =new ArrayList<String>() ;
        for(String permitted :permittedUrl.split(",") ) {
            permittedUrls.add(permitted) ;
        }   

registry.addInterceptor(loginInterceptor).addPathPatterns("/**").excludePathPatterns(permittedUrls);

全代码如下

package com.sgcc.epri.basis.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

import java.util.ArrayList;
import java.util.List;

@Configuration
public class MvcInterceptorConfig extends WebMvcConfigurationSupport {

    @Autowired
    private LoginInterceptor loginInterceptor;

    @Value("${permitted-url}")
    private String permittedUrl;

    @Override
    protected void addInterceptors(InterceptorRegistry registry) {
        // 多个拦截器组成一个拦截器链
        // addPathPatterns 用于添加拦截规则,/**表示拦截所有请求
        // excludePathPatterns 用户排除拦截
        /*registry.addInterceptor(loginInterceptor).addPathPatterns("/**")
                .excludePathPatterns("/demo","/test");
                 super.addInterceptors(registry);*/

        // 读取配置文件的放行方法
        List<String> permittedUrls =new ArrayList<String>() ;
        for(String permitted :permittedUrl.split(",") ) {
            permittedUrls.add(permitted) ;
        }
        registry.addInterceptor(loginInterceptor).addPathPatterns("/**").excludePathPatterns(permittedUrls);
    }
}

4、测试

测试一下,先随便访问一个需要拦截的方法

java 拦截器判断处理类是否有注解 spring 拦截器注解_拦截器

拦截住了,并且没有执行下面的方法,控制台输出了拦截日志

java 拦截器判断处理类是否有注解 spring 拦截器注解_ide_02

我们再访问一下放行的方法

java 拦截器判断处理类是否有注解 spring 拦截器注解_spring_03

访问成功,测试结束,但是直接放行的方法注定只是极小数,主要的还是拦截以后的验证

5、拦截器的自定义业务验证功能

在上面我们的LoginInterceptor类里只是写了个输出并且全部返回了false,这里面的代码就需要我们根据不同的需求自己定义,我的需求就是在拦截的方法中会带着手机号,我们拿手机号匹配用户信息,匹配到了就展示此用户的业务数据,如果没有或者没带手机号就展示示例数据,所以在我的需求里只会有放行,但是也可以设想为有匹配数据就是验证成功,如果没有就验证失败,返回错误信息,这个就看各自的业务需求。

/**
     * 预处理回调方法,实现处理器的预处理
     * 返回值:true表示继续流程;false表示流程中断,不会继续调用其他的拦截器或处理器
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        // 获取登陆手机号
        String loginPhone = request.getParameter("loginPhone");
        // 判断是否传递了手机号
        if (loginPhone != null && !"".equals(loginPhone)){
            String consId = demoService.getConsId();
            request.getSession().setAttribute("consId",consId);
            return true;
        }else{
            request.getSession().setAttribute("consId","0");
            return true;
        }
    }

现在我们都设置了true再试试之前被拦截的方法是否能通过,到这里拦截器就配好了。

java 拦截器判断处理类是否有注解 spring 拦截器注解_java 拦截器判断处理类是否有注解_04

可能还有许多验证用户是否过期,没有过期就无需拦截,或者访问的时候自动更新活跃状态,这些可能还需要多验证一下session和缓存,看业务需求了,下面是我们之前的拦截请求,包含了pc和小程序的拦截,由于pc登陆时已经存储了session所以主要是给小程序做复核token使用,不完整的地方是未验证企业id是否存在,但是我们的需求企业id是平台给的,所以是获取的企业id是已经存在的所以直接返回true,如果是单独系统的话需要再验证一下的

response.setContentType("text/plain;charset=UTF-8");
        response.setCharacterEncoding("utf-8");
        JSONObject json =  JSONObject.parseObject(String.valueOf(request.getSession().getAttribute("consInfo")));// 获取用户信息
        if (json != null) {// 验证企业id是否存在
        	return true;
		}else {
			String token = request.getParameter("token");// 获取传递的token
        	System.err.println(token);
        	if (token!=null&&!"".equals(token)) {// 验证是否传递token
        		request.getSession().setAttribute("token", token);
        		System.err.println(request.getSession().getAttribute("token"));
        		ResponseParam responseParam = userInterface.login(request,response);
        		if ("200".equals(String.valueOf(responseParam.getStatus()))) {
        			return true;
				}else {
			        JSONObject data = new JSONObject();
			        data.put("status", 500);
			        data.put("message", "用户失效");
			        data.put("sessionExpired", true);
			        response.getWriter().write(data.toString());
					return false;
				}
    		}
        	JSONObject data = new JSONObject();
	        data.put("status", 500);
	        data.put("message", "用户失效");
	        data.put("sessionExpired", true);
	        response.getWriter().write(data.toString());
        	return false;
		}