Java反射模拟Webwork的URL解析
Webwork是一款优秀的WEB应用框架,在其基础之上发展而来的Struts2已经开始替代Struts作为MVC模式下的WEB框架。熟悉Webwork的程序员很容易过渡到Struts2。本文来模拟一下Webwork的URL解析,应用反射机制实现,只作为说明,当然没有webwork本身实现的完美。
Webwork默认解析的服务请求名是.action,这个过程是Servlet容器完成的,而不是框架本身,在web.xml配置<servlet-mapping>和<filer-mapping>时设置<url-pattern>即可实现,这里我们不做过多说明,仅用Servlet来模拟,配置文件使用属性配置文件properties。
首先还是回顾一下Webwork解析服务请求的方式吧。我们提交的请求以xx.action发出时,在<xwork>中配置的<action>元素中若没有method属性时,则执行的是class类中的execute()方法,若有method属性时,则执行method中规定的方法。当请求以xx!yy.action形式发出时,在<action>元素中找到class属性的指向类,在该类中执行yy()方法来响应请求。因为Webwork的Action可以是一个POJO,而且方法返回值都默认为String,则在<action>中的<result>元素中的name值和方法返回值匹配后,就转向到<result>标识的目的地址中了,这个地址当然可以是目标页面也可以是另外一个请求地址。
创建一个WEB项目,起名就叫MVC,配置如下内容:
在web.xml中配置上一个核心控制器和字符过滤器,很简单,如下进行即可。
<filter><filter-name>characterEncoding</filter-name><filter-class>mvc.filters.CharacterEncodingFilter</filter-class><init-param><param-name>encoding</param-name><param-value>UTF-8</param-value></init-param></filter><filter-mapping><filter-name>characterEncoding</filter-name><servlet-name>FrontController</servlet-name></filter-mapping><servlet><servlet-name>FrontController</servlet-name><servlet-class>mvc.ctl.FrontController</servlet-class></servlet><servlet-mapping><servlet-name>FrontController</servlet-name><url-pattern>*.action</url-pattern></servlet-mapping>
package mvc.ctl;import java.io.*;import java.util.*;import java.lang.reflect.*;import javax.servlet.*;import javax.servlet.http.*;public class FrontController extends HttpServlet {private Map actions = new HashMap();// 装资源文件中配置的actionpublic Map urls = new HashMap();// 装资源文件配置的url@Overridepublic void init() throws ServletException {// 读取action配置文件ResourceBundle rb = ResourceBundle.getBundle("actions");Enumeration keys = rb.getKeys();while (keys.hasMoreElements()) {String key = (String) keys.nextElement();String value = rb.getString(key);try {// 根据资源文件的value反射获取action对象并装入HashMapObject o = Class.forName(value).newInstance();actions.put(key, o);} catch (Exception e) {e.printStackTrace();}}// 读取目的地址配置文件ResourceBundle url = ResourceBundle.getBundle("urls");keys = url.getKeys();while (keys.hasMoreElements()) {String key = (String) keys.nextElement();String value = url.getString(key);urls.put(key, value);}}public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {processRequest(request, response);}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {processRequest(request, response);}public void processRequest(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {// 从请求中获取URIString requestUri = request.getRequestURI();// 根据最后一个/截取请求地址(包含.action)String actionurl = requestUri.substring(requestUri.lastIndexOf('/') + 1, requestUri.length());// 截取.action前的有效数据actionurl = actionurl.substring(0, actionurl.indexOf(".action"));// 创建保存处理类和方法的变量String action = "";String method = "";if (actionurl.indexOf("!") >= 0) {// 有!号的请求这样处理action = actionurl.substring(0, actionurl.indexOf("!"));method = actionurl.substring(actionurl.indexOf("!") + 1);} else {// 没有!号时则默认执行execute()方法action = actionurl;method = "execute";}// 根据截取的action名获得存放在HashMap中的action对象Object handler = null;handler = actions.get(action);if (handler == null) {// 没有找到时默认执行default配置的actionhandler = actions.get("default");method = "execute";}// 存在时,获取Class实例Class handlerClass = handler.getClass();Method executor = null;// 设置请求处理结束的派发地址String toJump = "index";try {// 反射获取执行方法,由于是Servlet,所以参数是HttpServletRequest和HttpServletResponseexecutor = handlerClass.getMethod(method, new Class[] {HttpServletRequest.class, HttpServletResponse.class });} catch (Exception e) {e.printStackTrace();toJump = "frameerror";}try {// 利用反射机制执行方法,方法调用结束,返回值都是String类型的toJump = (String) executor.invoke(handler, new Object[] { request,response });} catch (Exception e) {e.printStackTrace();toJump = "frameerror";}// 转发处理结束以后的地址request.getRequestDispatcher(getURL(toJump)).forward(request, response);}/** * 从HashMap中获取URL的方法 */public final String getURL(String url) {return (String) urls.get(url);}}
base=mvc.action.BaseActiondefault=mvc.action.DefaultAction
index=index.jspframeerror=frameerror.jsp
package mvc.action;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;public class DefaultAction {public String execute(HttpServletRequest request,HttpServletResponse response) {request.setAttribute("msg", "未定义操作");return "error";}}