springmvc学习笔记(28)——自定义拦截器

1. 自定义拦截器

所谓的拦截器,就是用来拦截请求,因此我们可以对用户发来的请求做处理。 

  • 写一个类,实现拦截器的接口
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

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

public class FirstInterceptor implements HandlerInterceptor{

    /**
     * 该方法在 目标方法之前被调用
     * 可以用来做 权限,日志,事务
     * 若 return false,后续的拦截器和目标方法将不被调用
     * 若 return true,后续的拦截器和目标方法正常调用
     */
    @Override
    public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1,
            Object arg2) throws Exception {
        System.out.println("preHandle");
        return true;
    }

    /**
     * 该方法在 目标方法之后,渲染视图之前 被调用
     * 可以用来 修改请求域,修改目标视图等
     */
    @Override
    public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1,
            Object arg2, ModelAndView arg3) throws Exception {
        System.out.println("postHandle");

    }
    /**
     * 该方法在 目标方法被调用,渲染视图之后被调用
     * 可以用来 释放资源
     */
    @Override
    public void afterCompletion(HttpServletRequest arg0,
            HttpServletResponse arg1, Object arg2, Exception arg3)
            throws Exception {
        System.out.println("afterCompletion");

    }


}

代码中已经有了详细的注释,包括三个方法的调用顺序方法 
在三个方法中打印出一句话,以便我们能看到效果

  让拦截器起作用,就要在springmvc配置文件中配置

     <!-- 拦截器 -->
    <mvc:interceptors>
        <!-- 配置自定义的拦截器 -->
        <bean class="com.zj.interceptor.FirstInterceptor"></bean>
    </mvc:interceptors>

 到这里,配置就完成了,访问任意目标方法,控制台打印出如下结果 

 2. 配置拦截器的作用范围

 <mvc:interceptors>

     <!-- 配置自定义的拦截器 -->
     <bean class="com.zj.interceptor.FirstInterceptor"></bean>

      <mvc:interceptor>
         <!-- 只有访问/hello这个路径,拦截器才起作用 -->
         <mvc:mapping path="/hello"/>
         <!-- 
            除了/index这个路径,其他都起作用
            <mvc:exclude-mapping path="/index"/>
         -->
         <bean class="com.zj.interceptor.SecondInterceptor"></bean>
      </mvc:interceptor>
  </mvc:interceptors>

在最外层是一个mvc:interceptors,在里面,我们又配置了一个mvc:interceptor。请注意,前者有s,后者没有。
在mvc:interceptor中,我们可以配置拦截器SecondInterceptor的作用范围,只作用于某个路径或者只有某个路径不被作用

3. 多个拦截器的调用顺序

上面我们配了两个拦截器,现在我们来测试以下他们的调用顺序

访问某个路径,控制台打印出如下结果 

  • 在配置文件中,FirstInterceptor拦截器的配置在SecondInterceptor前面
  • 根据结果分析可以得到,preHandle()方法的调用顺序和拦截器的配置顺序一致
  • postHandle()和afterCompletion()方法的调用顺序则是反序

4. 特殊情况


刚刚的例子中,FirstInterceptor和SecondInterceptor两个拦截器的preHandler方法都是return true,因此后面的方面都可以正常执行。

现在假设SecondInterceptor的preHandle返回false,会怎样?我们来看结果截图 

1. 从结果中看到,FirstInterceptor 的preHandle先被执行,这没问题

2.然后执行SecondInterceptor的preHandle,它返回false,因此后续的目标方法都不被执行,但是,FirstInterceptor的afterCompletion方法居然被执行了。
3.如果从源码分析,可以明白这是为什么,但是对于大多数人来说这太难。
4.我们从这个结果中总结出一个结论:一个拦截器一旦preHandle被执行return true,那么它就一定要释放资源(之前说过afterCompletion方法用来释放资源)
 

======================================================

根据上面的分析下面我写了一个不使用xml进行拦截路径的案例。

import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;

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

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import com.xxxx.dkyw.moudles.doctorinfo.service.DoctorInfoService;
import com.xxxx.dkyw.moudles.hosinfo.service.HosInfoService;
import com.xxxx.dkyw.moudles.examorg.service.ExamOrgInfoService;
import com.xxxx.dkyw.moudles.organizationinfo.service.OrganizationInfoService;
import com.xxxx.dkyw.core.extensions.process.service.ProcessService;
import com.xxxx.dkyw.persistence.entity.HosInfo;
import com.xxxx.dkyw.persistence.entity.OrganizationInfo;
import com.xxxx.dkyw.persistence.entity.Process;

@Component
public class AdminPermOrgInterceptor implements HandlerInterceptor {
	@Autowired
	private DoctorInfoService doctorInfoService;
	@Autowired
	private ProcessService processService;
	@Autowired
	private HosInfoService hosInfoService;
	@Autowired
	private OrganizationInfoService organizationInfoService;
	@Autowired
	private ExamOrgInfoService examOrgInfoService;

	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		return true;
	}

	@SuppressWarnings("static-access")
	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {
		String absolutePath = request.getScheme()+"://" + request.getServerName() + ":" + request.getServerPort() + request.getContextPath();
		String url = request.getRequestURL().toString();
		if(request.getMethod().toUpperCase().equals("GET")) {
			if(StringUtils.containsAny(url, "/doctor/", "/exam/", "/examorg/", "/hos/", "/org/") && 
					StringUtils.containsAny(url, "edit", "view")) {
				Map<String, Object> model = modelAndView.getModel();
				
				HandlerMethod methodHandler = (HandlerMethod) handler;
				Class<?>[] parameterTypes = methodHandler.getMethod().getParameterTypes();
				Class<?> beanClass = parameterTypes[0];
				
				String beanName = beanClass.getName();
				char[] simpleName = beanClass.getSimpleName().toCharArray();
				simpleName[0] += 32;
				
				Object value = model.get(String.valueOf(simpleName));
				Class<?> valueClass = value.getClass().forName(beanName);
				Field[] fields = valueClass.getDeclaredFields();
				String uuid = null;
				String orgUuid = null;
				List<String> orgUuids = null;
				for(Field f: fields) {
					f.setAccessible(true);
					if(f.getName().equals("uuid")) {
						uuid = f.get(value).toString();
						break;
					}
				}
				
				if(StringUtils.contains(url, "/doctor/")) {	//	医师信息
//					DoctorBaseInfo doctorBaseInfo = doctorInfoService.getDoctorBaseInfoByUuid(uuid);
//					orgUuid = doctorBaseInfo.getOrgUuid();
					orgUuid = doctorInfoService.getDoctorOrgUuid(uuid);
				}else if(StringUtils.contains(url, "/exam/")) {	//	考核进度信息
					Process process = processService.getProcessByUuid(uuid);
					orgUuid = process.getOrgUuid();
				}else if(StringUtils.contains(url, "/hos/")) {	//	卫生机构信息
					HosInfo hosInfo = hosInfoService.getHosInfoByUuid(uuid);
					orgUuid = hosInfo.getOrgUuid();
				}else if(StringUtils.contains(url, "/org/")) {	//	行政机构信息
					OrganizationInfo orgInfo = organizationInfoService.getOrgInfoByUuid(uuid);
					orgUuid = orgInfo.getFirstUuid();
				}else {	//	考核机构信息
					orgUuids = examOrgInfoService.getBelongOrgIdByUuid(uuid);
				}
				
				List<String> permOrgList = (List<String>) request.getSession().getAttribute("SESSION_ORG_LIST");
				
				if(CollectionUtils.isNotEmpty(permOrgList)) {
					if(StringUtils.isNotEmpty(orgUuid)) {
						OrganizationInfo org = organizationInfoService.findOrgFirstUuid(orgUuid);
						orgUuid = org.getUuid();
						
						if(!permOrgList.contains(orgUuid)) {	//	当前用户的机构权限无法查看用户的情况
//							response.sendError(HttpServletResponse.SC_FORBIDDEN, "没有权限的操作。");
							
							response.sendRedirect(absolutePath + "/a/forbidden");
						}
					}else if(CollectionUtils.isNotEmpty(orgUuids)) {
						List<OrganizationInfo> orgs = organizationInfoService.queryOrgsByUuidList(orgUuids);
						for(OrganizationInfo o: orgs) {
							
							if(!permOrgList.contains(o.getFirstUuid())) {
								response.sendRedirect(absolutePath + "/a/forbidden");
							}
						}
					}else {
						response.sendRedirect(absolutePath + "/a/forbidden");
					}
				
					
				}
			}
		}
	}

	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
			throws Exception {
	}

}

request.getSchema() 可以返回当前页面使用的协议,http 或是 https;

request.getServerName() 可以返回当前页面所在的服务器的名字;

request.getServerPort() 可以返回当前页面所在的服务器使用的端口

request.getContextPath() 可以返回当前页面所在的应用的名字

request.getRequestURL().toString(); 可以返回整个请求路径的名称

猜你喜欢

转载自blog.csdn.net/qq_36826506/article/details/84997921