一 开文背景 -- 废话讲一段~
本文借助动力节点-王勇老师的视频教程中的引例来了解struts1的实现原理,虽然现在已经很少使用struts1了,但是了解了其原理之后,对了解其他mvc框架还是有较大的帮助的.
二 简介 -- 切入主题
struts1主要实现从请求到servlet的映射.
e.g. 现有的一个业务为实现用户的添加删除修改,按照原有的model2的原理可以实现上述功能.
2.1没有struts1之前的基于model2 mvc的实现.
直接在servlet中实现如下代码:
String username = request.getParameter("username"); UserManager userManager = new UserManager(); String forward = ""; if ("/servlet/delUser".equals(path)) { userManager.del(username); forward = "/del_success.jsp"; }else if ("/servlet/addUser".equals(path)) { userManager.add(username); forward = "/add_success.jsp"; }else if ("/servlet/modifyUser".equals(path)) { userManager.modify(username); forward = "/modify_success.jsp"; }else if ("/servlet/queryUser".equals(path)) { List userList = userManager.query(username); request.setAttribute("userList", userList); forward = "/query_success.jsp"; }else { throw new RuntimeException("请求失败"); } request.getRequestDispatcher(forward).forward(request, response);
到现在,基本的功能是已经实现了,但是看着上面的代码就像吐啊~一坨的if-else,复杂的每一个if-else节点处理~毫无半点的扩展性可言.
解决办法:
将每一个小的业务处理单独来处理.抽象出一个借口Action,抽象方法:execute(HttpServletRequest,HttpServletResponse). struts1中返回一个ActionForword对象.
public interface Action {
public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception; }
每一个小的功能(添加\删除\修改),都抽象成一个action,实现上面的接口.
1 Action action = null; 2 if ("/servlet/delUser".equals(path)) { 3 action = new DelUserAction(); 4 }else if ("/servlet/addUser".equals(path)) { 5 action = new AddUserAction(); 6 }else if ("/servlet/modifyUser".equals(path)) { 7 action = new ModifyUserAction(); 8 }else if ("/servlet/queryUser".equals(path)) { 9 action = new QueryUserAction(); 10 }else { 11 throw new RuntimeException("请求失败"); 12 } 13 String forward = null; 14 try { 15 forward = action.execute(request, response); 16 } catch (Exception e) { 17 e.printStackTrace(); 18 } 19 request.getRequestDispatcher(forward).forward(request, response);
虽然相对上面的"代码",这次有了一定程度的提高(仅仅是思想上),代码的扩展性,还是没有达到要求的.
如今,对一些较多可选择性的代码,将其从代码中抽离出来,转化为配置文件是提高扩展性的一种方式.
1 / 2 <action-config> 3 <action path="/servlet/delUser" type="com.bjpowernode.servlet.DelUserAction"> 4 <forward name="success">/del_success.jsp</forward> 5 <forward name="error">/del_error.jsp</forward> 6 </action 7 8 <action path="/servlet/addUser" type="com.bjpowernode.servlet.AddUserAction"> 9 <forward name="success">/add_success.jsp</forward> 10 <forward name="error">/add_error.jsp</forward> 11 </action 12 13 <action path="/servlet/modifyUser" type="com.bjpowernode.servlet.ModifyUserAction"> 14 <forward name="success">/modify_success.jsp</forward> 15 <forward name="error">/modify_error.jsp</forward> 16 </action 17 18 <action path="/servlet/queryUser" type="com.bjpowernode.servlet.QueryUserAction"> 19 <forward name="success">/query_success.jsp</forward> 20 <forward name="error">/query_error.jsp</forward> 21 </action 22 23 24 </action-config>
每一个<action></action>结点指定该action对应的请求路径,对应处理该请求的具体Action类型,以及处理之后的转向.在装载这些配置文件需要一个对象来装填,这就是ActionMapping类型.
1 / 2 ActionMapping { 3 private String path;//请求路径 4 private String type;//对应的处理该请求的action类型. 5 Map forwardMap; //处理完成之后的跳转信息. 6 /
同样,需要将跳转信息保存起来,实现对象为ForwordMap<key,value>
1 / 2 } 3 forwardMap { 4 key="success"; 5 value="/del_success.jsp" 6 key="error" 7 value="/del_error.jsp" 8 } 9 /
在struts1中使用Map将这些action保存起来Map<request_url,ActionMapping>.在actionmapping中同样保存着request_url.
1 Map map = new HashMap(); 2 map.put("/servlet/delUser", actionMapping1); 3 map.put("/servlet/addUser", actionMapping2); 4 map.put("/servlet/modifyUser", actionMapping3); 5 map.put("/servlet/queryUser", actionMapping4); 6
如果是删除ActionMapping存储如下:
1 actionMapping { 2 path= "/servlet/delUser"; 3 type = "com.bjpowernode.servlet.DelUserAction"; 4 forwardMap { 5 key="success",value="/del_success.jsp" 6 key="error", value="/del_error.jsp" 7 } 8 }
三 综合总结
下面就使用一个例子来总结一下整个struts1的处理流程
String path = "/servlet/delUser";
1.根据截取的URL请求,到Map(从配置文件中获取)中取得本次请求对应的Action
ActionMappint actionMappint = (ActionMappint)map.get(path);
2.取得本请求对应的Action类的完整路径
String type = actionMappint.getType(); //com.bjpowernode.servlet.DelUserAction
3.采用反射动态实例化Action
Action action = (Action)class.forName(type).newInstance();
4.动态待用Action中的execute方法
String forward = action.execute(request, response);
5.根据路径完成转向
request.getRequestDispatcher(forward).forward(request, response);
真正来驱动这一切行为的操作者为Servlet,也就是MVC中的控制器,实现了请求url的截取,然后从配置文件中按照截取的url,来实现分发.读取配置文件,创建actionmapping,forwardmap对象,由此创建action对象,实现业务的处理,然后转向.