`
宋双旺
  • 浏览: 153251 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

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

    博客分类:
  • web
阅读更多

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 >   


    这样所有已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. }  


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

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


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

Java代码  收藏代码
  1. index=index.jsp  
  2. 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. }  


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

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics