自己写的J2EE通用URL重定向工具

来源:互联网 发布:思念去世的父亲 知乎 编辑:程序博客网 时间:2024/04/30 04:19

[2011-5-8]

这次项目需要对一个URL进行重写,一个简单的方法就是针对本次的应用对请求的URL做一个特殊的处理。但是为了以后扩展方便,我把他写成了一个通用的URLRewrite工具类,理论上是支持各种框架的。项目的地址是:http://code.google.com/p/eagle-beak/, GPLv2协议,有兴趣的可以研究一下。

这里我给大家举个例子如何使用我的URLRewrite工具,以最基础的JavaEE做为例子。大家都知道,在JavaEE中要对请求进行处理自然要选择Filter,所以我们就把URLRewrite的工作放在Fitler 之中,如本实例的URLRewriteFilter,当然这里我们需要用“/*”来拦截所有的请求,以进行URL分析。URLRewriteFilter的代码如下:

package org.sefler.test;import java.io.IOException;/** * Servlet Filter implementation class URLRewriteFilter */public class URLRewriteFilter implements Filter {    private static final Logger LOG = Logger.getRootLogger();        private static URLRewriteConfiger CONFIG;    /**     * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)     */    @Override    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,            ServletException {        HttpServletRequest httpServletRequest = (HttpServletRequest) request;        LOG.debug("Requesting: " + httpServletRequest.getServletPath());                URLRewriter rewriter = CONFIG.getURLRewriter("test");        try {            URLRequest urlRequest = rewriter.rewrite(httpServletRequest.getServletPath());                        RequestDispatcher dispatcher = request.getRequestDispatcher(urlRequest.getTarget());             dispatcher .forward(new ModifiableHttpServletRequest(httpServletRequest, urlRequest.getQueries()), response);                        LOG.debug("Redirecting to " + urlRequest.getTarget());        } catch (NoURLMappingFoundException e) {            // do not rewrite            LOG.debug("No matching patterns were found, will do nothing");            chain.doFilter(request, response);        } catch (URLRewriteException e) {            LOG.error("Error when rewriting URL in URLRewriteFilter, Reuqest URL: "                    + httpServletRequest.getServletPath(), e);        }    }    /**     * @see Filter#init(FilterConfig)     */    public void init(FilterConfig fConfig) throws ServletException {        try {            String configPath = fConfig.getInitParameter("configFile");                        URLXMLConfiger.getInstance().init(fConfig.getServletContext().getResourceAsStream(configPath));            CONFIG = URLXMLConfiger.getInstance();        } catch (MalformedConfigException e) {            LOG.error("Error when initializing filter: " + getClass().toString(), e);        }                CONFIG = URLXMLConfiger.getInstance();    }    @Override    public void destroy() {}}
请注意里面的init方法,在这个方法中我们发现以下两行,这里需要初始化URLRewrite的配置,我们的URLRewrite支持各种各样的配置,这里我们使用的是XML的方式进行配置的。

String configPath = fConfig.getInitParameter("configFile");URLXMLConfiger.getInstance().init(fConfig.getServletContext().getResourceAsStream(configPath));

XML文件的内容如下:

<?xml version="1.0" encoding="utf-8"?><config xmlns="http://www.taobao.com/wing/urlrewrite" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.taobao.com/wing/urlrewrite urlrewrite.xsd "> <rewriter name="test" type="regex" >  <mapping>   <target>/index.jsp</target>   <pattern>/123.htm</pattern>   <handler>org.sefler.test.SimpleTestHandler</handler>  </mapping>  <mapping>   <target>/WEB-INF/viewArticle.jsp</target>   <pattern>/a[0-9]+.htm</pattern>   <handler>org.sefler.test.ArticleHandler</handler>  </mapping> </rewriter></config>
好了,配置好了以后,我们就可以在Filter里面实现我们的大计了。从刚才的XML配置文件我们也看到了,对个mapping对应一个pattern(即客户端请求的URL模式)、target(即最终需映射到的服务器的页面)与一个handler,handler是需要用户自己来实现的。我们现在先来一个简单的,它要做的只是把index.jsp重写成123.htm,那么配置就是我们的第一个Mapping写的那样了,我们使用一个名为SimpleTestHandler的Handler来处理这个重写,它的代码如下:

package org.sefler.test;import java.util.Collections;import java.util.Map;import com.taobao.matrix.eagle.beak.URLMapping;import com.taobao.matrix.eagle.beak.URLRequest;import com.taobao.matrix.eagle.beak.URLRewriteHandler;public class SimpleTestHandler implements URLRewriteHandler {    @SuppressWarnings("unchecked")    @Override    public URLRequest parse(String requestPath, URLMapping mapping) {        URLRequest urlRequest = new URLRequest(mapping.getTarget(), Collections.EMPTY_MAP);        return urlRequest;    }    @Override    public String render(Map<String, Object> queries, URLMapping mapping) {        return "No render rule defined! Will do nothing!";    }}
可以看出这个Handler什么都没有做,只是把pattern映射成了target。那么最终的结果就如下:



OK, 现在我们来弄个更复杂的,现在我们的URL Patter的为a1234.htm,后面的数字是隐藏的参数,取名arNo。我们使用ArticleHandler来处理这个请求

package org.sefler.test;import java.util.HashMap;import java.util.Map;import org.apache.commons.lang.math.NumberUtils;import org.apache.log4j.Logger;import com.taobao.matrix.eagle.beak.URLMapping;import com.taobao.matrix.eagle.beak.URLRequest;import com.taobao.matrix.eagle.beak.URLRewriteHandler;import com.taobao.matrix.eagle.beak.URLUtil;public class ArticleHandler implements URLRewriteHandler {    public static final Logger LOG = Logger.getLogger("test");         @Override    public URLRequest parse(String requestPath, URLMapping mapping) {        int arNo =  NumberUtils.toInt(URLUtil.getFileName(requestPath).substring(1), 0);        LOG.debug("Parsed arNo parameter: " + arNo);                Map<String, Object> queries = new HashMap<String, Object>();        queries.put("arNo", arNo);                URLRequest urlRequest = new URLRequest(mapping.getTarget(), queries);        return urlRequest;    }    @Override    public String render(Map<String, Object> queries, URLMapping mapping) {        if (queries.size() == 0 || queries.get("arNo") == null) {            return "index.jsp";        }               String renderedURL = "a" + queries.get("arNo") + ".htm";                LOG.debug("Rended URL: " + renderedURL);        return renderedURL;    }}

需要注意的是,JavaEE的HttpServletRequst并不充许你更改请求的参数,所以我们需要用HttpServletRequestWrapper进行wrap一下,具体怎么wrap 大家可以看最后附带的源码,这里也不多说了。至于重写URL的生成,比如在JSP里使用“viewArticle.jsp?arNO=123”这类的href自然希望渲染成“a123.htm”。由于JavaEE并没有专门负责URL的模块,这里们可以自己建一个应用级的URLBroker来负责生成想要的URL。例如在viewArticle.jsp下:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%><jsp:useBean id="urlBroker" class="org.sefler.test.URLBroker" scope="request" /><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>View Article</title></head><body style="font-family: Arial"> <div>  You're viewing: <span style="color: green">viewArticle.jsp</span> </div> <div>  Requesting article No.: <span style="color: green"><%= request.getParameter("arNo") %></span> </div> <div style="background-color: lightblue;">  <% int arNo = org.apache.commons.lang.math.NumberUtils.toInt(request.getParameter("arNo"), 0) + 1; %>  Click <a href="<%= urlBroker.setTarget("/WEB-INF/viewArticle.jsp").addParameter("arNo", arNo).render() %>"> here</a>  to view next article </div></body></html>
只要把URLBroker作为JavaBean注入就可以。当然,我这里只是提供一种简单的方法,肯定有更优雅的方法,大家可以照着这种思想去想一想(偶们公司的框架解决这个问题轻而易举,^_^)。话说,某个开源项目与我的思想很像(好吧,我与它的很像吧),不过我想说的是,有些问题由于限制问题,可选用的解决方案也不多,大家的解决方案自然也就很像了~

?

地址:http://code.google.com/p/eagle-beak/