一: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集合
[java]
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;
}
}
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文件信息
[java]
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;
}
}
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的類文件
[java]
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<String,ActionXml> map = new HashMap<String,ActionXml>();
public ParseXml(){
}
public static Map<String,ActionXml> 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();
}
}
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<String,ActionXml> map = new HashMap<String,ActionXml>();
public ParseXml(){
}
public static Map<String,ActionXml> 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
[java]
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<String ,ActionXml> 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();//讀取配置
}
}
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<String ,ActionXml> 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方法
[java]
package com.s.bean;
public interface Action {
public String execute();
}
package com.s.bean;
public interface Action {
public String execute();
}
這樣,一個小型的框架就完成了,它裡面包含Tomcat啟動後對struts.xml文件的解析,以及Action類的實體化,這樣我們只要定義我們的action實現類和加入我們的struts.xml就可以靈活駕馭這個框架了。
5、定義struts.xml
[html]
<?xml version="1.0" encoding="UTF-8" ?>
<struts>
<action name="a" class="com.s.bean.Users">
<result name='success'>/success.jsp</result>
<result name='fail'>/fail.jsp</result>
<result name='ok'>/ok.jsp</result>
</action>
</struts>
<?xml version="1.0" encoding="UTF-8" ?>
<struts>
<action name="a" class="com.s.bean.Users">
<result name='success'>/success.jsp</result>
<result name='fail'>/fail.jsp</result>
<result name='ok'>/ok.jsp</result>
</action>
</struts>
6、定義我們的Action的實現類
[java]
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";
}
}
}
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、測試頁面,或者使用超鏈接進行測試
[plain]
<form action="a.do" method="post">
username:<input type="text" name="uname"/><br>
password:<input type="text" name="upwd"/><br>
<input type="submit" value="提交"/>
</form>
<form action="a.do" method="post">
username:<input type="text" name="uname"/><br>
password:<input type="text" name="upwd"/><br>
<input type="submit" value="提交"/>
</form>解析:
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的原理,僅供學習參考!