SpringMVC初步学习(终)----添加过滤器实现URL重写

URL重写:客户访问一个URL的时候,通过后台过滤器让它变成另外一个URL并跳转到新的URL对应的controller方法中,这样可以提高我们项目的安全性,并方便维护
具体实现方式:
创建一个类来继承HttpServletRequestWrapper,重写getRequestURI,getRequestURL,getServletPath方法

这里我把需要重写的URL统一放在一个容器里(map)
代码如下:

package com.jym.filter;

import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

/**
* @author 作者 :Jym
* @version 创建时间:2019年10月8日 上午9:39:39
* HttpServletRequest的装饰类
* 用来改变HttpServletRequest的状态, 对请求内容的过滤
* 
*/
public class JymUrlRewriteServletRequestWrapper extends HttpServletRequestWrapper{
	
	private Map<String,String> resourceMap;  // 资源映射表

	public JymUrlRewriteServletRequestWrapper(HttpServletRequest request) {
		super(request);
	}
	

	@Override
	public String getRequestURI(){
		String s1 = super.getRequestURI();
		int i = super.getContextPath().length();
		String oldUri = s1.substring(i);
		return transcode(oldUri);
	}

	@Override
	public StringBuffer getRequestURL(){
		String oldUri = super.getRequestURI().substring(super.getContextPath().length());
		StringBuffer sb = new StringBuffer();
		String url = super.getRequestURL().toString().replaceAll(oldUri,transcode(oldUri));
		return sb.append(url);
	}

	@Override
	public String getServletPath(){
		String s1 = super.getRequestURI();
		int i = super.getContextPath().length();
		String oldUri = s1.substring(i);
		return super.getServletPath().replaceAll(oldUri,transcode(oldUri));
	}
	
	//初始化url资源
	public void initMapping(Map<String, String> resourceMap) {
		this.resourceMap = resourceMap;
	}
	
	/**
	 * 
	* @Title: transcode  
	* @Description: 获取css等静态资源重写的url
	* @param @param key 原来的请求路径
	* @param @return      
	* @return String      
	* @throws
	 */
	private String transcode(String key){
		//如果map中有对应的value,则采用value的请求路径 否则采用原来的
		String value = resourceMap.get(key);
		if(null != value){
			return value;
		} else {
			return key;
		}
	}

}

处理URL的类写完了,然后编写过滤器继承于OncePerRequestFilter类

这里我简单的把资源容器添加了几条数据,正常可以维护进数据库

这里的实现方式是将原来的url作为key,去容器里那对应的value作为新的url,如果没有,就还用原来的url,这样可以实现选择性重写
package com.jym.filter;

import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;



/**
* @author 作者 :Jym
* @version 创建时间:2019年10月8日 上午9:39:03
* 
*/
public class JymUrlRewriteFilter extends OncePerRequestFilter{
	
	//不参加重写的请求后缀 如果web.xml没配置则默认用该变量
	private static final String DEFAULT_EXECUDE_EXTENTIONS = "jsp,jspx,do";
	//默认统一静态资源路径到static文件夹下(如果SpringMVC配置文件已经对静态资源处理 则不需要此变量) 如果web.xml没配置则默认用该变量
	private static final String DEFAULT_PREFIX = "/static";
	private final Logger logger = LoggerFactory.getLogger(JymUrlRewriteFilter.class);
	//统一静态资源路径 web.xml配置
	private String prefix;
	//不参加重写的请求后缀  web.xml配置
	private Set<String> excludeExtentions = new HashSet<String>();
	//资源映射map 可维护到数据库
	private Map<String, String> resourcemap = new HashMap<String, String>();
	
	

	/**
	 * 初始化时装置静态资源
	 */
	@Override
	protected void initFilterBean() throws ServletException {
		//这里简单写死,正常应该从数据库读取,初始化map 
		resourcemap.put("/test","/model/test");
		super.initFilterBean();
		try {
			//初始化参数prefix excludeExtentions
			initParameter(getFilterConfig());
		} catch (IOException e) {
			throw new ServletException("init paramerter error",e);
		}
	}
	
	
	@Override
	protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
			throws ServletException, IOException {
		// 防止缓存
		response.setHeader("Cache-Control", "no-cache");
		response.setHeader("Pragma", "no-cache");
		// 在请求消息中发送将使得请求和响应消息都不使用缓存
		response.setHeader("Cache-Control", "no-store");
		// 设置过期的时间期限  0s 不进行缓存
		response.setDateHeader("Expires", 0);
		
		String from = request.getRequestURI().substring(request.getContextPath().length());
		if(rewriteURL(from)) {
			//css,js等静态资源 统一放入static文件夹下 否则404
			final String to = prefix + transcode(from);
			logger.debug("UrlRewriteFilter: forward request from "+from+" to "+to);
			//重定向到该路径
			request.getRequestDispatcher(to).forward(request, response);
		}else {
			//重写url
			JymUrlRewriteServletRequestWrapper newRequest = new JymUrlRewriteServletRequestWrapper((HttpServletRequest) request);
			//初始化url重写容器
			newRequest.initMapping(resourcemap);
			logger.debug("UrlRewriteFilter: rewrite newuri:"+newRequest.getRequestURI());
			filterChain.doFilter(newRequest, response);
		}
		
	}
	
	/**
	 * 
	* @Title: transcode  
	* @Description: 获取css等静态资源重写的url
	* @param @param key 原来的请求路径
	* @param @return      
	* @return String      
	* @throws
	 */
	private String transcode(String key){
		//如果map中有对应的value,则采用value的请求路径 否则采用原来的
		String value = resourcemap.get(key);
		if(null != value){
			return value;
		} else {
			return key;
		}
	}

	/**
	 * 
	* @Title: initParameter  
	* @Description: 从web.xml中读取 初始化参数 
	* @param @param filterConfig
	* @param @throws IOException      
	* @return void      
	* @throws
	 */
	private void initParameter(FilterConfig filterConfig) throws IOException {
		//如果xml中该拦截器参数没有配置prefix,则启用默认DEFAULT_PREFIX,如果配置了 采用xml中配置的参数
		prefix = getStringParameter(filterConfig,"prefix",DEFAULT_PREFIX);
		String excludeExtentionsString = getStringParameter(filterConfig,"excludeExtentions",DEFAULT_EXECUDE_EXTENTIONS);
		excludeExtentions = new HashSet<String>((Arrays.asList(excludeExtentionsString.split(","))));


		logger.debug("RestUrlRewriteFilter.prefix="+prefix+" will rewrite url from /demo.html => ${prefix}/demo.html by forward");
		logger.debug("RestUrlRewriteFilter.excludeExtentions=["+excludeExtentionsString+"] will not rewrite url");
	}

	/**
	 * 
	* @Title: rewriteURL  
	* @Description: 判断是否需要重写url 
	* @param 请求url
	* @param @return      
	* @return boolean      
	* @throws
	 */
	private boolean rewriteURL(String from) {
		//获取url请求的后缀
		String extension = StringUtils.getFilenameExtension(from);
		//正常后台请求
		if(extension == null || "".equals(extension)) {
			return false;
		}
		//json,xml等
		if(excludeExtentions.contains(extension)) {
			return false;
		}
		//css,js,jpg等静态文件返回true
		return true;
	}

	/**
	 * 
	* @Title: getStringParameter  
	* @Description: 如果web.xml中该拦截器参数没有配置name参数,则启用默认defaultValue,如果配置了 采用xml中配置的参数 
	* @param @param filterConfig
	* @param @param name
	* @param @param defaultValue
	* @param @return      
	* @return String      
	* @throws
	 */
	private String getStringParameter(FilterConfig filterConfig,String name,String defaultValue) {
		String value = filterConfig.getInitParameter(name);
		if(value == null || "".equals(value.trim())) {
			return defaultValue;
		}
		return value;
	}


}

将编写好的过滤器配置到web.xml中
	
		JymUrlRewriteFilter
		com.jym.filter.JymUrlRewriteFilter
		
			prefix
			/static
		
		
			excludeExtentions
			jsp,jspx,do,json,xml,swf,zip
		
	
	
		JymUrlRewriteFilter
		/*
	
测试:
@Controller
@RequestMapping("/model")
public class ModelDataController {
	
	@RequestMapping("/test")
	public String test(Student student){
		return "index";
	}
}

正常应该访问:/model/test
但是我们之前在重写过滤器中的map中添加了resourcemap.put("/test","/model/test")这段代码
所以我们直接访问/test

SpringMVC初步学习(终)----添加过滤器实现URL重写_第1张图片

访问成功!!

世界上有10种人,一种是懂二进制的,一种是不懂二进制的。

感谢您的收看,如有哪里写的不对 请留言,谢谢。

你可能感兴趣的:(spring)