当前位置: 代码迷 >> Web前端 >> Java反照模拟Webwork的URL解析(转)
  详细解决方案

Java反照模拟Webwork的URL解析(转)

热度:255   发布时间:2012-11-11 10:07:57.0
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中配置上一个核心控制器和字符过滤器,很简单,如下进行即可。

Xml代码 ?收藏代码
  1. < filter > ??
  2. ????< filter-name > characterEncoding </ filter-name > ??
  3. < filter-class > mvc.filters.CharacterEncodingFilter </ filter-class > ??
  4. ????< init-param > ??
  5. ????????< param-name > encoding </ param-name > ??
  6. ????????< param-value > UTF-8 </ param-value > ??
  7. ????</ init-param > ??
  8. </ filter > ??
  9. < filter-mapping > ??
  10. ????< filter-name > characterEncoding </ filter-name > ??
  11. ????< servlet-name > FrontController </ servlet-name > ??
  12. </ filter-mapping > ??
  13. < servlet > ??
  14. ????< servlet-name > FrontController </ servlet-name > ??
  15. ????< servlet-class > mvc.ctl.FrontController </ servlet-class > ??
  16. </ servlet > ??
  17. < servlet-mapping > ??
  18. ????< servlet-name > FrontController </ servlet-name > ??
  19. ????< url-pattern > *.action </ url-pattern > ??
  20. </ servlet-mapping > ??
	<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>


??? 这样所有已action为服务请求名的请求都被核心控制器FrontController处理了,那么只要设计好这个核心控制器就行了,那么我们就用这个 核心控制器来实现MVC模式。

Java代码 ?收藏代码
  1. package ?mvc.ctl;??
  2. import ?java.io.*;??
  3. import ?java.util.*;??
  4. import ?java.lang.reflect.*;??
  5. import ?javax.servlet.*;??
  6. import ?javax.servlet.http.*;??
  7. public ? class ?FrontController? extends ?HttpServlet?{??
  8. ????private ?Map?actions?=? new ?HashMap(); //?装 资源文件中配置的action ??
  9. ????public ?Map?urls?=? new ?HashMap(); //?装 资源文件配置的url ??
  10. ????@Override ??
  11. ????public ? void ?init()? throws ?ServletException?{??
  12. ????????//?读取action配置文件 ??
  13. ????????ResourceBundle?rb?=?ResourceBundle.getBundle("actions" );??
  14. ????????Enumeration?keys?=?rb.getKeys();??
  15. ????????while ?(keys.hasMoreElements())?{??
  16. ????????????String?key?=?(String)?keys.nextElement();??
  17. ????????????String?value?=?rb.getString(key);??
  18. ????????????try ?{??
  19. ????????????????//?根据资源文件的value反射获取action对象并装入HashMap ??
  20. ????????????????Object?o?=?Class.forName(value).newInstance();??
  21. ????????????????actions.put(key,?o);??
  22. ????????????}?catch ?(Exception?e)?{??
  23. ????????????????e.printStackTrace();??
  24. ????????????}??
  25. ????????}??
  26. ????????//?读取目的地址配置文件 ??
  27. ????????ResourceBundle?url?=?ResourceBundle.getBundle("urls" );??
  28. ????????keys?=?url.getKeys();??
  29. ????????while ?(keys.hasMoreElements())?{??
  30. ????????????String?key?=?(String)?keys.nextElement();??
  31. ????????????String?value?=?url.getString(key);??
  32. ????????????urls.put(key,?value);??
  33. ????????}??
  34. ????}??
  35. ????public ? void ?doGet(HttpServletRequest?request,?HttpServletResponse?response)??
  36. ????????????throws ?ServletException,?IOException?{??
  37. ????????processRequest(request,?response);??
  38. ????}??
  39. ????public ? void ?doPost(HttpServletRequest?request,?HttpServletResponse?response)??
  40. ????????????throws ?ServletException,?IOException?{??
  41. ????????processRequest(request,?response);??
  42. ????}??
  43. ????public ? void ?processRequest(HttpServletRequest?request,??
  44. ????????????HttpServletResponse?response)?throws ?ServletException,?IOException?{??
  45. ????????//?从请求中获取URI ??
  46. ????????String?requestUri?=?request.getRequestURI();??
  47. ????????//?根据最后一个/截取请求地址(包含.action) ??
  48. ????????String?actionurl?=?requestUri.substring(??
  49. ????????????????requestUri.lastIndexOf('/' )?+? 1 ,?requestUri.length());??
  50. ????????//?截取.action前的有效数据 ??
  51. ????????actionurl?=?actionurl.substring(0 ,?actionurl.indexOf( ".action" ));??
  52. ????????//?创建保存处理类和方法的变量 ??
  53. ????????String?action?=?"" ;??
  54. ????????String?method?=?"" ;??
  55. ????????if ?(actionurl.indexOf( "!" )?>=? 0 )?{ //?有!号的请求这样处理 ??
  56. ????????????action?=?actionurl.substring(0 ,?actionurl.indexOf( "!" ));??
  57. ????????????method?=?actionurl.substring(actionurl.indexOf("!" )?+? 1 );??
  58. ????????}?else ?{ //?没有!号 时则默认执行execute()方法 ??
  59. ????????????action?=?actionurl;??
  60. ????????????method?=?"execute" ;??
  61. ????????}??
  62. ????????//?根据截取的action名获得存放在HashMap中的action对象 ??
  63. ????????Object?handler?=?null ;??
  64. ????????handler?=?actions.get(action);??
  65. ????????if ?(handler?==? null )?{ //?没有找到 时默认执行default配置的action ??
  66. ????????????handler?=?actions.get("default" );??
  67. ????????????method?=?"execute" ;??
  68. ????????}??
  69. ????????//?存在时,获取Class实例 ??
  70. ????????Class?handlerClass?=?handler.getClass();??
  71. ????????Method?executor?=?null ;??
  72. ????????//?设置请求处理结束的派发地址 ??
  73. ????????String?toJump?=?"index" ;??
  74. ????????try ?{??
  75. ????????????//?反射获取执行方法,由于是Servlet,所以参数是HttpServletRequest和 HttpServletResponse ??
  76. ????????????executor?=?handlerClass.getMethod(method,?new ?Class[]?{??
  77. ????????????????????HttpServletRequest.class ,?HttpServletResponse. class ?});??
  78. ????????}?catch ?(Exception?e)?{??
  79. ????????????e.printStackTrace();??
  80. ????????????toJump?=?"frameerror" ;??
  81. ????????}??
  82. ????????try ?{??
  83. ????????????//?利用反射机制执行方法,方法调用结束,返回值都是String类型的 ??
  84. ????????????toJump?=?(String)?executor.invoke(handler,?new ?Object[]?{?request,??
  85. ????????????????????response?});??
  86. ????????}?catch ?(Exception?e)?{??
  87. ????????????e.printStackTrace();??
  88. ????????????toJump?=?"frameerror" ;??
  89. ????????}??
  90. ????????//?转发处理结束以后的地址 ??
  91. ????????request.getRequestDispatcher(getURL(toJump)).forward(request,?response);??
  92. ????}??
  93. ????/** ?
  94. ?????*?从 HashMap中获取URL的方法 ?
  95. ?????*/ ??
  96. ????public ? final ?String?getURL(String?url)?{??
  97. ????????return ?(String)?urls.get(url);??
  98. ????}??
  99. }??
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();// 装资源文件中配置的action
	public Map urls = new HashMap();// 装资源文件配置的url
	@Override
	public 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对象并装入HashMap
				Object 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 {
		// 从请求中获取URI
		String 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配置的action
			handler = actions.get("default");
			method = "execute";
		}
		// 存在时,获取Class实例
		Class handlerClass = handler.getClass();
		Method executor = null;
		// 设置请求处理结束的派发地址
		String toJump = "index";
		try {
			// 反射获取执行方法,由于是Servlet,所以参数是HttpServletRequest和HttpServletResponse
			executor = 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);
	}
}


??? 代码中有详细的注释,我们说一下简单的思路。这是一个Servlet,那是肯定的,因为我们已经在web.xml中声明了。那么就要覆盖父类中的 doGet()和doPost()两个基本方法实现对Http请求的处理。但是这里我们也覆盖了init()方法用来初始化一些东西。可以看出是从 action.properties中加载配置信息,那么这个文件中有什么呢?很简单,就是action的名和类全名,如下:

Java代码 ?收藏代码
  1. base=mvc.action.BaseAction??
  2. default =mvc.action.DefaultAction??
base=mvc.action.BaseAction
default=mvc.action.DefaultAction


??? 读取出这两个信息后,使用反射生成Action的实例并保存到一个HashMap中。这样就是以名/值对方式存在的了。下面就是获取 urls.properties中信息了,这里面记录了跳转的地址信息,是V层的实现。如下:

Java代码 ?收藏代码
  1. index=index.jsp??
  2. frameerror=frameerror.jsp??
index=index.jsp
frameerror=frameerror.jsp


??? init()方法解释完后,我们看看具体的servlet处理方法processRequest()。首先获取到请求的URI,然后解析这个URI看看其 具体格式。分为有!号的请求和没有!号的请求,这里就是模拟webwork的实现。创建两个String遍历存放handler和method,然后匹配 URI解析到的内容。进而使用反射机制获取具体的Action实例和方法。最后判断跳转到路径,然后使用 request.getRequestDispatcher().forward()方法进行跳转,那么流程处理就完成了。至此控制器C的原理就说完了。
??? 模型M就是配置的Action类,我们看一看默认Action的写法:

Java代码 ?收藏代码
  1. package ?mvc.action;??
  2. import ?javax.servlet.http.HttpServletRequest;??
  3. import ?javax.servlet.http.HttpServletResponse;??
  4. public ? class ?DefaultAction?{??
  5. ??
  6. ????public ?String?execute(HttpServletRequest?request,??
  7. ????????????HttpServletResponse?response)?{??
  8. ????????request.setAttribute("msg" ,? "未定义操作" );??
  9. ????????return ? "error" ;??
  10. ????}??
  11. }??
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";
	}
}


??? 是不是和WebWork的Action类很相似,这里还可以操作原始的request,response对象,执行效率也很高。
??? 其实,这也是一个小框架的简单实现,功能简单但是原理清晰,对于理解MVC模式非常有帮助。
??? 一家之言,仅供参考,欢迎交流。

  相关解决方案