一:struts2运行机制:

  Tomcat一启动,一些信息就已经加载完成,例如StrutsPrepareAndExecuteFilter加载的那些strut.xml以及Action的class类文件

1)客户端在浏览器中输入一个url地址,例如。

2)这个url请求通过http协议发送给tomcat。
3)tomcat根据url找到对应项目里面的web.xml文件。
4)在web.xml里面会发现有struts2的配置。
5)然后会找到struts2对应的struts.xml配置文件。
6)根据url解析struts.xml配置文件就会找到对应的class。
7)调用完class返回一个字String,根据struts.xml返回到对应的jsp。

 

二:struts2运行原理(网络摘抄)

上图来源于Struts2官方站点,是Struts 2 的整体结构。

一个请求在Struts2框架中的处理大概分为以下几个步骤:
1)  客户端初始化一个指向Servlet容器(例如Tomcat)的请求。
2)  这个请求经过一系列的过滤器(Filter)。
3)  接着FilterDispatcher被调用,FilterDispatcher询问ActionMapper来决定这个请是否需要调用某个Action。
4)  如果ActionMapper决定需要调用某个Action,FilterDispatcher把请求的处理交给ActionProxy。
5)  ActionProxy通过Configuration Manager询问框架的配置文件,找到需要调用的Action类。
6)  ActionProxy创建一个ActionInvocation的实例。
7)  ActionInvocation实例使用命名模式来调用,在调用Action的过程前后,涉及到相关拦截器(Intercepter)的调用。
8)  一旦Action执行完毕,ActionInvocation负责根据struts.xml中的配置找到对应的返回结果。
Struts2的核心就是拦截器。Struts.xml中所有的package都要extends="struts-default"。同理与所有的Java类都要extends自Object一样。struts-default.xml里面就是要做以上事情。

三:下面带大家自定义简单的实现一下struts2

1、创建存放解析struts后的文件,保存里面的name和class以及result结果的Map集合

package com.s.bean;    import java.util.HashMap;  import java.util.Map;    public class ActionXml {  	//对应存放的name  	private String name;        //对应存放的class  	private String clazz;  	//对应存放的那些result,保存ResultXml bean结果  	private Map results = new HashMap();  	public String getName() {  		return name;  	}  	public void setName(String name) {  		this.name = name;  	}  	public String getClazz() {  		return clazz;  	}  	public void setClazz(String clazz) {  		this.clazz = clazz;  	}  	public Map getResults() {  		return results;  	}  	public void setResults(Map results) {  		this.results = results;  	}  }

2、创建存放解析struts后的文件,保存里面的result文件信息

package com.s.bean;    public class ResultXml {  	//名称  	private String name;  	//值  	private String value;  	public String getName() {  		return name;  	}  	public void setName(String name) {  		this.name = name;  	}  	public String getValue() {  		return value;  	}  	public void setValue(String value) {  		this.value = value;  	}  }

3、创建解析XML的类文件

package com.s.parse;    import java.io.File;  import java.util.HashMap;  import java.util.List;  import java.util.Map;    import org.dom4j.Document;  import org.dom4j.DocumentException;  import org.dom4j.Element;  import org.dom4j.io.SAXReader;    import com.s.bean.ActionXml;  import com.s.bean.ResultXml;    public class ParseXml {	  	private static Map
map = new HashMap
(); public ParseXml(){ } public static Map
getXML(){ SAXReader sax = new SAXReader(); Document doc = null; try { doc = sax.read(Thread.currentThread().getContextClassLoader().getResourceAsStream("struts.xml")); } catch (DocumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } //得到根目录 Element root = doc.getRootElement(); //得到所有action配置 List list = root.elements(); for(Object obj : list){ ActionXml ax = new ActionXml(); Element a = (Element)obj; ax.setName(a.attributeValue("name")); ax.setClazz(a.attributeValue("class")); //得到所有result List results = a.elements(); for(Object obj1 : results){ ResultXml rx = new ResultXml(); Element r = (Element)obj1; rx.setName(r.attributeValue("name")); rx.setValue(r.getText()); ax.getResults().put(rx.getName(), rx.getValue()); } //将所有的action的配置读取出来,放入到一个MAP中 map.put(ax.getName(), ax); } return map; } /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub ParseXml.getXML(); } }

4、创建过滤器,tomcat启动后,struts.xml中的文件被解析,并且对应的class文件实体被创建,使用了反射,相当于struts2中的FilterDispatcher

package com.s.filter;    import java.io.IOException;  import java.io.PrintWriter;  import java.lang.reflect.InvocationTargetException;  import java.util.Map;    import javax.servlet.Filter;  import javax.servlet.FilterChain;  import javax.servlet.FilterConfig;  import javax.servlet.ServletException;  import javax.servlet.ServletRequest;  import javax.servlet.ServletResponse;  import javax.servlet.http.HttpServlet;  import javax.servlet.http.HttpServletRequest;  import javax.servlet.http.HttpServletResponse;    import com.s.bean.Action;  import com.s.bean.ActionXml;  import com.s.parse.ParseXml;  import com.sun.org.apache.commons.beanutils.BeanUtils;    public class DispatherFilter  implements Filter {	      //专门放配置的map  	private static Map
map; public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2) throws IOException, ServletException { // TODO Auto-generated method stub HttpServletRequest request = (HttpServletRequest)arg0; //得到表单请求的名字,比如a String actionName = request.getRequestURI().split("/")[2].split("\\.")[0]; //根椐表单请求的名字找到对应的处理类 ActionXml ax = map.get(actionName); String clazz = ax.getClazz(); String result = ""; try { Class cla = Class.forName(clazz); Object obj = cla.newInstance();//根椐clazz产生接收和处理数据的对象 //将表单中的数据交给该obj BeanUtils.populate(obj, request.getParameterMap()); Action action = (Action)obj; result = action.execute();//执行方法后得到result //根椐result找到对应的要跳转的界面 String resultPage = (String)ax.getResults().get(result); //根椐结果页面跳转 request.getRequestDispatcher(resultPage).forward(arg0, arg1); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InstantiationException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public void destroy() { // TODO Auto-generated method stub } public void init(FilterConfig arg0) throws ServletException { // TODO Auto-generated method stub map = ParseXml.getXML();//读取配置 } }

4、定义一个Action的接口类,里面只有一个execute方法

package com.s.bean;    public interface Action {  	  	public String execute();    }

这样,一个小型的框架就完成了,它里面包含Tomcat启动后对struts.xml文件的解析,以及Action类的实体化,这样我们只要定义我们的action实现类和加入我们的struts.xml就可以灵活驾驭这个框架了。

5、定义struts.xml

/success.jsp
/fail.jsp
/ok.jsp

6、定义我们的Action的实现类

package com.s.bean;    import java.io.Serializable;    public class Users implements Serializable,Action{    	/**  	 *   	 */  	private static final long serialVersionUID = -4293478837686410970L;  	private int uid;  	private String uname;  	private String upwd;  	public int getUid() {  		return uid;  	}  	public void setUid(int uid) {  		this.uid = uid;  	}  	public String getUname() {  		return uname;  	}  	public void setUname(String uname) {  		this.uname = uname;  	}  	public String getUpwd() {  		return upwd;  	}  	public void setUpwd(String upwd) {  		this.upwd = upwd;  	}  	//处理数据的方法  	public String execute(){  		//在这里操作数据库  		if(uname.equals("admin")){  		  return "fail";  		}else{  			return "success";  		}  		  	}  }

7、测试页面,或者使用超链接进行测试::

username:
password:

解析:

Tomcat已启动,DispatherFilter中的init方法得到执行,解析struts.xml文件,并把相应的信息保存在全局变量的map中

当用户通过超链接的方式访问,转入到DispatherFilter,通过DispatherFilter解析超链接request.getRequestURI().split("/")[2].split("\\.")[0];,得到action中的name名称,然后通过parseXML类得到相对应的class类,然后利用反射机制创建它的实体,系统默认执行里面的execute方法,得到相应的字符串信息,根据返回的字符串信息,通过解析xml找到相应的结果页面,然后通过request.getRequestDispatcher(resultPage).forward(arg0, arg1);跳转到相应的页面,得到相应的结果

结合struts2原理,我们不然发现struts2中的FilterDispatcher相当与我们自定义的DispatherFilter,里面的ActionMapper就是我们自己定义的全局变量map,至于struts2中的ActionProxy,以及Configuration Manager,ActionInvocation and (Intercepter)我们这里就没有涉及了,用户可以自己依次去实现,这里只是简单的实现了一下struts2的原理,仅供学习参考!

源代码下载: