前言
前面一段时间做一个管理后端需要登录验证以及不同角色的权限限制,我在每个方法中都会从HttpServletRequest中取出token来判断,费时费力。现在准备使用spring mvc的拦截器切面来重新实现这个逻辑。
正文
以前的做法
/**@author lx
* 个人会员列表
*/
@ResponseBody
@RequestMapping("/allUserLoanList")
public String allUserLoanList(HttpServletRequest request,@RequestParam(value="supervisorId") long supervisorId,@RequestParam(value="name",required=false) String name,@RequestParam(value="realityName",required=false) String realityName,@RequestParam(value="mobile",required=false) String mobile,@RequestParam(value="beginTimeStr",required=false) String beginTimeStr,
@RequestParam(value="endTimeStr",required=false) String endTimeStr, @RequestParam(value="isAllowLogin",required=false,defaultValue="0") int isAllowLogin,@RequestParam(value="orderTypeStr",required=false,defaultValue="0") String orderTypeStr,@RequestParam(value="currPageStr",required=true) String currPageStr,@RequestParam(value="pageSizeStr",required=false,defaultValue="10") String pageSizeStr,@RequestParam int type){
String token=request.getHeader("token");
ResponseBuilder responseBuilder=new ResponseBuilder();
ErrorInfo error = new ErrorInfo();
boolean islogin=TokenUtil.islogin(supervisorId, token);
if(!islogin) {
error.code=-2;
error.msg="未登陆";
return responseBuilder.Response(error.code, error.msg);
}
Date beginTime = null;
Date endTime = null;
int orderType = 0;
int currPage = Constants.ONE;
int pageSize = Constants.PAGE_SIZE;
if (RegexUtils.isDate(beginTimeStr)) {
beginTime = DateUtil.strDateToStartDate(beginTimeStr);
}
if (RegexUtils.isDate(endTimeStr)) {
endTime = DateUtil.strDateToEndDate(endTimeStr);
}
if (NumberUtil.isNumericInt(orderTypeStr)) {
orderType = Integer.parseInt(orderTypeStr);
}
if (NumberUtil.isNumericInt(currPageStr)) {
currPage = Integer.parseInt(currPageStr);
}
if (NumberUtil.isNumericInt(pageSizeStr)) {
pageSize = Integer.parseInt(pageSizeStr);
}
if (orderType < 0 || orderType > 14) {
orderType = 0;
}
StringBuffer ggsql = new StringBuffer();
if (StringUtils.isNotBlank(name)) {
/* sql.append("and t_users.name like ?"+(params.size()+1)+""+(params
* .size()+1)+" "); params.add("%" + name + "%");*/
ggsql.append(" and name like '%" + name + "%' ");
}
if (StringUtils.isNotBlank(realityName)) {
ggsql.append(" and reality_name like '%" + realityName + "%' ");
}
if (StringUtils.isNotBlank(mobile)) {
ggsql.append(" and mobile like '%" + mobile + "%' ");
}
if (isAllowLogin == 1) {//未锁定
ggsql.append(" and is_allow_login = false ");
} else if (isAllowLogin == 2) {//已锁定
ggsql.append(" and is_allow_login = true ");
}else {
ggsql.append(" and is_allow_login = false or is_allow_login = true");
}
List<Long> lists=null;
if (StringUtils.isNotBlank(ggsql.toString())) {
lists = userService.queryUserId(ggsql.toString());
}
int count=0;
List<User> users=null;
if(lists!=null) {
count=allUserService.queryallUserLoanCount(beginTime, endTime, orderType, lists, error);
users=allUserService.allUserLoanList(beginTime, endTime, orderType, currPage, pageSize, lists, error);
}
if (users.size() > 0) {
com.hzjr.user.facade.model.User user = null;
for (User user_info : users) {
if (user_info.getId() < 1) {
users.remove(user_info);
continue;
}
user = userService.getUserById(user_info.getId());
user_info.setName(user.getName());
user_info.setEmail(user.getEmail()==null? "":user.getEmail());
user_info.setRealityName(user.getRealityName()==null? "":user.getRealityName());
user_info.setIdNumber(user.getIdNumber()==null? "":user.getIdNumber());
user_info.setMobile(user.getMobile()==null? "":user.getMobile());
user_info.setAddBaseInfo( user.isAddBaseInfo());
user_info.setTime(user.getTime());
user_info.setLastLoginTime(StringUtils.isBlank(user.getLastLoginTime() + "") ? null:user.getLastLoginTime());
user_info.setAllowLogin(user.isAllowLogin());
}
}
PageBean<User> page = new PageBean<User>();
page.pageSize = pageSize;
page.currPage = currPage;
page.totalCount = count;
page.page = users;
return responseBuilder.Response(error.code, error.msg,page);
}
可以看到根据用户是否登录,要不要继续执行下去,真正实现该方法功能的就一行。
这里就引入了Spring MVC的拦截器来减少重复代码。
拦截器工作方式
springMVC拦截器的实现一般有两种方式:
第一种方式是自定义Interceptor类来实现Spring的 HandlerInterceptor 接口;
第二种方式是继承实现了HandlerInterceptor接口的类,比如Spring已经提供的实现了HandlerInterceptor接口的抽象类 HandlerInterceptorAdapter
HandlerInterceptor 接口中定义了三个方法,我们就是通过这三个方法来对用户的请求进行拦截处理的。
preHandle(): 这个方法在业务处理器处理请求之前被调用,SpringMVC 中的Interceptor 是链式的调用的,在一个应用中或者说是在一个请求中可以同时存在多个Interceptor 。每个Interceptor 的调用会依据它的声明顺序依次执行,而且最先执行的都是Interceptor 中的preHandle 方法,所以可以在这个方法中进行一些前置初始化操作或者是对当前请求的一个预处理,也可以在这个方法中进行一些判断来决定请求是否要继续进行下去。该方法的返回值是 Boolean 类型的,当它返回为 false 时,表示请求结束,后续的Interceptor 和 Controller 都不会再执行;当返回值为true 时就会继续调用下一个Interceptor 的preHandle 方法,如果已经是最后一个Interceptor 的时候就会是调用当前请求的Controller 方法。
postHandle():这个方法在当前请求进行处理之后,也就是Controller 方法调用之后执行,但是它会在 DispatcherServlet 进行视图返回渲染之前被调用,所以我们可以在这个方法中对Controller 处理之后的 ModelAndView 对象进行操作。postHandle 方法被调用的方向跟preHandle 是相反的,也就是说先声明的Interceptor 的postHandle 方法反而会后执行。
afterCompletion():该方法也是需要当前对应的Interceptor 的preHandle 方法的返回值为true 时才会执行。顾名思义,该方法将在整个请求结束之后,也就是在DispatcherServlet 渲染了对应的视图之后执行。这个方法的主要作用是用于进行资源清理工作的。
拦截器的使用
拦截器类:
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import com.zpc.entity.User;
public class MyInterceptor implements HandlerInterceptor {
private static final String[] IGNORE_URI = {"/login"};
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception exception)
throws Exception {
System.out.println("afterCompletion方法执行了...");
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView mv)
throws Exception {
System.out.println("postHandle方法执行了...");
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle方法执行了...");
boolean flag = false;
String servletPath = request.getServletPath();
for(String s : IGNORE_URI) {
if(servletPath.contains(s)) {
flag = true;
break;
}
}
if(flag == false) {
String token=request.getHeader("token");
if(token==null) {
jsonMap.put("error", -2);
jsonMap.put("msg", "请先登录");
return JSON.toJSONString(jsonMap);
}
User user =JwtUtils.decode(token,User .class);
if(user == null) {
request.setAttribute("error", "您还没有登录,请登录!");
request.getRequestDispatcher("login").forward(request, response);
}else {
flag = true;
}
}
return flag;
}
}
SpringMVC配置文件(主要看 定义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-4.3.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<context:annotation-config/>
<mvc:annotation-driven/>
<!-- 定义SpringMVC拦截器 -->
<mvc:interceptors>
<mvc:interceptor>
<!-- 拦截所有请求 -->
<mvc:mapping path="/*"/>
<bean class="com.user.interceptor.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
<!-- 使用默认的Servlet响应静态文件。如js,css,image等 -->
<mvc:default-servlet-handler/>
<!-- 只管理Controller类型的bean,忽略其它类型的bean,如@Service -->
<context:component-scan base-package="com.user.controller" >
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!-- 对模型视图名称的解析,即在模型视图名称添加前后缀 -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"/>
</beans>