首先,需要再次声明的是:struts是web层的框架。在介绍struts的第一篇文章就已经有了论述,如果不使用struts框架同样可以进行开发,但是需要在Servlet里面写大量的“if……else……”语句,在每个条件下分别去new相应的Action,以及做相应的转向。

在学习设计模式中设计原则的时候学到开闭原则:对扩展开放,多修改封闭。这里如果要变动(增加、删除、修改)转向页面,我们就需要在Servlet里面的“if……else”功能块儿里面进行变动。而且,这个Servlet里面拥有了太多的职责,不符合单一职责。此外,MartinFowler在《重构》中写过一个很重要的代码坏味道,叫做‘Long Method’:方法如果过长其实极有可能是有坏味道了

在这里,我想到了设计模式中学过的“状态模式”。大家都知道,在机房收费系统中,上下机的逻辑是比较复杂的,我们需要写大量的“if……else……”语句进行判断,这里如果日后需要维护的话,将是一件非常糟糕的事情。这里,就可以用到状态模式将职责进行分解,将判断的每一种条件都看作是一种状态,进而达到类职责的分离。

反过来看我们前面说的设计,经过上面的分析,我们知道这样存在大量“if……else……”语句,而且经常会进行增删的设计是非常糟糕的。所以,那些聪明的“懒人”们就设计了web层的开源框架Struts,是他们的不将就,给现在现在的开发人员带来了大大的便利。

Struts框架中,将Servlet进行了封装。用户在编码的时候,无须像之前一样编写大量的Servlet,以及Servlet中冗长的“if……else……”语句,只需要在配置文件里面进行配置,就能够轻松完成转向,为开发人员带来了极大的方便。

为了深入学习Struts框架,我们不仅要对它的作用了然于胸,更需要深入剖析它的实现原理(因为Struts框架相对简单,所以我们可以直接看它的代码,较复杂的框架千万不要一猛子扎进去)。

配置文件action_config.xml:

<?xml version="1.0" encoding="UTF-8"?>
<action-config>
<action path="/servlet/delUser" type="com.lzq.servlet.DelUserAction">
<forward name="success">/del_success.jsp</forward>
<forward name="error">/del_error.jsp</forward>
</action> <action path="/servlet/addUser" type="com.lzq.servlet.AddUserAction">
<forward name="success">/add_success.jsp</forward>
<forward name="error">/add_error.jsp</forward>
</action>
</action-config>

ActionMapping,主要用于存放Action信息。

package com.lzq.servlet;

import java.util.Map;
public class ActionMapping {
private String path;
private Object type;
private Map forwardMap; public String getPath() {
return path;
} public void setPath(String path) {
this.path = path;
} public Object getType() {
return type;
} public void setType(Object type) {
this.type = type;
} public Map getForwardMap() {
return forwardMap;
} public void setForwardMap(Map forwardMap) {
this.forwardMap = forwardMap;
}
}

读取action_config.xml配置文件,并动态实例化配置文件中的Action,并将Action、转向信息都放在ActionMapping里返回。

package com.lzq.servlet;

import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader; public class XmlConfigReader {
private static XmlConfigReader instance=new XmlConfigReader(); ActionMapping actionMapping=new ActionMapping();
private Document doc;
private Map actionMap=new HashMap();
private XmlConfigReader(){
try {
SAXReader reader=new SAXReader();
InputStream in=Thread.currentThread().getContextClassLoader().getResourceAsStream("action_config.xml");
doc=reader.read(in);
} catch (DocumentException e) {
e.printStackTrace();
}
} public ActionMapping getActionMapping(String path){
synchronized(this){
Object type=null;
/*if(action.containsKey(path)){
type=action.get(path);
}*/
Element eltAction = (Element)doc.selectObject("//action[@path=\"" + path + "\"]");
try{
type=Class.forName(eltAction.attributeValue("type")).newInstance();
}catch(Exception e){
e.printStackTrace();
}
Element eltForwards = eltAction.element("forward");
for (Iterator iter = eltForwards.elementIterator(); iter.hasNext();) {
Element eltForward = (Element) iter.next();
actionMap.put(eltForward.attributeValue("name"),eltForward.getTextTrim());
}
actionMapping.setPath(path);
actionMapping.setType(type);
actionMapping.setForwardMap(actionMap);
return actionMapping;
}
}
public static synchronized XmlConfigReader getInstance(){
return instance;
}
/**
* 测试读取
* @param args
*/
public static void main(String[] args) {
ActionMapping actionMapping=XmlConfigReader.getInstance().getActionMapping("/servlet/delUser");
System.out.println(actionMapping.getPath());
System.out.println(actionMapping.getType());
System.out.println(actionMapping.getForwardMap().toString());
}
}

这时的Servlet就没有了冗长的“if……else……”:

package com.lzq.servlet;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; public class TestServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String requestURI=request.getRequestURI();
System.out.println("request="+requestURI);
String path=requestURI.substring(requestURI.indexOf("/",1),requestURI.indexOf("."));
System.out.println("path="+path); String forward="";
ActionMapping actionMapping=XmlConfigReader.getInstance().getActionMapping(path);
Action action=(Action)actionMapping.getType();
try {
forward=action.execute(request, response);
} catch (Exception e) {
e.printStackTrace();
}
request.getRequestDispatcher(forward).forward(request, response);
}
}

Struts框架尽管相对简单些,但是它的真正实现却比这里复杂的多。而我们这里的实现尽管很简单,但是却涵盖了框架的核心思想。对于一个初学者,经过一边笼统的学习,能够总结出它原型也是很重要的。正所谓:大道至简。


下面提供源码下载Struts原型解析实例

Strurts(四)——从Struts原型模拟看大道至简(含实例下载)的更多相关文章

  1. [转载]大道至简!!!从SAP HANA作为SAP加速器的方式,看ERP on HANA的春天

    I AM A ABAPER! 科技的进步,一定会使一些东西变得越来越精简! 大道至简!!! 文章很好!!!!!!!!!!! -------------------------------------- ...

  2. JavaScript夯实基础系列(四):原型

      在JavaScript中有六种数据类型:number.string.boolean.null.undefined以及对象,ES6加入了一种新的数据类型symbol.其中对象称为引用类型,其他数据类 ...

  3. JavaScript学习总结(四)——this、原型链、javascript面向对象

    一.this 在JavaScript中this表示:谁调用当前函数this就指向谁,不知道调用者时this指向window. JavaScript是由对象组成的,一切皆为对象,万物皆为对象.this是 ...

  4. 从原型链看DOM--Comment,CDATASection,DocumentType,DocumentFragment,Attr类型

    这次总结的是剩下的这些DOM类型节点,可能你见过却不经常使用但是了解一下总是好的,可以加深对DOM体系的整体理解~.本篇要介绍的是Comment,CDATASection,DocumentType,D ...

  5. 轻量级Java EE企业应用实战(第4版):Struts 2+Spring 4+Hibernate整合开发(含CD光盘1张)

    轻量级Java EE企业应用实战(第4版):Struts 2+Spring 4+Hibernate整合开发(含CD光盘1张)(国家级奖项获奖作品升级版,四版累计印刷27次发行量超10万册的轻量级Jav ...

  6. 《大道至简》第一章读后感Java伪代码

    在<大道至简>第一章中,周爱民先生引用一则<愚公移山>的寓言,引出了编程的根本:顺序.选择.循环.“愚公移山”的工程虽然庞大,但是可以通过极其简单的变成来完成.我身边的有一些人 ...

  7. 《大道至简》第三章读后感+ppt课后作业

                   大道至简读后感 ——第三章团队 古人云“三人为众”,众则是指团体或团队.对于一个团队而言,重要的是凝聚力,大家能在一起把拳头握紧那么产生的力量就不紧紧是能以1+1=2 来 ...

  8. 大道至简第一章读后感Java伪代码

    //一.愚公移山 /*原始需求 惩山北直塞,出入之迁也. 项目沟通的方式 聚室而谋 项目目标 毕力平险,指通豫南,达于汉阴 人员组成 愚公,子孙荷担者三夫,邻人遗男 技术方案 叩石垦壤 簸萁运与渤海之 ...

  9. 大道至简第一章Java伪代码读后感

    import.java.大道至简.*; //周爱民 import.java.读后感*; public class shawanyia { //1. 编程的精义 while(山没有消失) {if(愚公没 ...

随机推荐

  1. 修改Fedora 20 启动项

    在Fedora 20里面,Fedora 使用了systemd作为系统与服务的管理工具,这个守护进程是系统开机后第一个开启的进程,pid 为1.systemd扮演着初始化系统的角色,主要用于开启与维护系 ...

  2. OpenStackCLI调试及术语识记

    1,Project are organizational units in the cloud,and are also known as tenants or accounts.Each user ...

  3. STS(Spring Tool Suite)使用前准备

    sts 的基础框架拿的eclipse的,你可以理解为eclipse + spring插件的高级升华版.在使用上可以很大限度的参考eclipse的操作. 首先,调整字体. 中文很麻烦的,因为编码问题.习 ...

  4. PC--CSS常识

    1.不要使用过小的图片做背景平铺.这就是为何很多人都不用 1px 的原因,这才知晓.宽高 1px 的图片平铺出一个宽高 200px 的区域,需要 200*200=40, 000 次,占用资源.2.无 ...

  5. Android UI布局之FrameLayout

    一个FrameLayout对象就好比一块屏幕上提前预定好的空白区域.然后能够填充一些元素到里边.例如说一张图片等.须要注意的是,全部的元素都被放置在FrameLayout区域最左边上的区域.并且无法为 ...

  6. (HYSBZ)BZOJ 1588 营业额统计

    营业额统计 Time Limit: 5000MS   Memory Limit: 165888KB   64bit IO Format: %lld & %llu Description 营业额 ...

  7. SQL记录-字符串的截取与拼接

    SELECT concat( substr(t1.CODE, , ), '****', substr(t1.CODE, ) ), t1.CODE, t2.TITLE FROM table1 t1 LE ...

  8. flashback database操作步骤

    默认情况数据库的flashback database是关闭的. 启用Flashback Database 步骤:1.配置Flash Recovery Area 检查是否启动了flash recover ...

  9. TCP/IP系列——长连接与短连接的区别

    1 什么是长连接和短连接       三次握手和四次挥手   TCP区别于UDP最重要的特点是TCP必须建立在可靠的连接之上,连接的建立和释放就是握手和挥手的过程. 三次握手为连接的建立过程,握手失败 ...

  10. 关于position和float的用法!

    我要说的是这部分的切图, 先说一下为什么要用到position 看我的截图, 应该知道这块的组成是有两部分, 但中间那个绿圈中, 组成的两个部分有重叠的, 这时候, 可能会想用float, 但floa ...