生活随笔
收集整理的這篇文章主要介紹了
自己动手写一个Struts2
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
使用Struts2或webwork2有一段時間了,想把Struts2框架的思路簡單的與大家分享一下,之前我是看過Struts2源代碼的,所以本文算是它的一個功能非常有限的壓縮版本。我也不打算重復發明輪子,只想讓Struts2或Webwork2的新手更多的了解框架本身,而不僅僅是應用。廢話少說,開始吧。
?
?
本文采用基本Xml來配置Action,如果有時間會繼續寫Annotation的實現。Xml文件結構與Struts2的配置文件struts.xml幾乎一樣,這樣大家都比較熟悉,不過我簡寫了某些地方:
?
Struts.xml
Xml代碼??
<?xml?version="1.0"?encoding="UTF-8"??>?? ?? <struts>?? ????<package>?? ????????<action?name="hello"?method="hello"?? ????????????class="com.leo.action.HelloAction">?? ????????????<result?name="success">/index.jsp</result>?? ????????</action>?? ????</package>?? </struts>??
?
?
是不是很熟悉啊,不過為了簡單我都給簡化了,否則這是一個沒有盡頭的工作。核心部分仍然是Filter,Struts2所有工作都是通過一個Filter來完成的(struts1.*是通過一個Action實現的)。我們先來看代碼:
?
Java代碼??
public?class?StrutsFilter?implements?Filter?{?? ????public?void?doFilter(ServletRequest?req,?ServletResponse?res,?? ????????????FilterChain?chain)?throws?IOException,?ServletException?{?? ?????????? ????????HttpServletRequest?request?=?(HttpServletRequest)?req;?? ????????HttpServletResponse?response?=?(HttpServletResponse)?res;?? ????????ServletContext?servletContext?=?filterConfig.getServletContext();?? ?????????? ????????String?actionName?=?StringUtil.parseServletPath(request?? ????????????????.getServletPath());?? ?? ?????????? ????????if?(StringUtil.isEmpty(actionName))?{?? ????????????chain.doFilter(request,?response);?? ????????}?else?{?? ?????????????? ????????????ActionClass?clas?=?this.getActionClass(actionName);?? ?????????????? ????????????Map<String,?String[]>?params?=?request.getParameterMap();?? ?????????????? ????????????setBeforeActionValue(clas,?params);?? ?????????????? ????????????setResultValue(clas,?request);?? ?????????????? ????????????servletContext.getRequestDispatcher(clas.getResult()).forward(?? ????????????????????request,?response);?? ????????}?? ????}?? }??
?
?沒錯一些因果都因doFilter方法而起。我的作法是:
?
- 解析URL路徑,從而得到相應action在struts.xml配置文件中所配置的方法。如果不為合法的action后綴,直接chain.doFilter(request, response)放行。
- 將URL上的參數通過request.getParameterMap()取出,在調用action執行方法之前,將具有set**屬性的字段賦值。這里利用了反射。
- 繼續利用反射,執行Action的方法。結束前將具有get**屬性的字段存于request域中,供頁面使用。大家記得在每次執行Action的方法時都會返回一個String字符串,比如SUCCESS,INPUT,ERROR等,我們可以將這個值與struts.xml的<result name="success" ....>/index.jsp</result> 結點進行匹配,取出返回頁面/index.jsp
- 一切準備就緒后,調用servletContext.getRequestDispatcher().forward()方法到相應的頁面上去。
這就是大概的流程。因為是一個入門的框架所以很不完善,攔截器,result type的各種類型都沒有去實現,因為我壓根沒想過要重復發明輪子。好,我們開始一步一步的看。
?
?
?
我們先來看這一句:ActionClass clas = this.getActionClass(actionName);
其中ActionClass的結構如下:
?
Java代碼??
public?class?ActionClass?{?? ????? ? ?? ????private?String?className;?? ????? ? ?? ????private?String?method;?? ????? ? ?? ????private?String?result;?? ????? ? ?? ????private?List<Element>?elements?=?new?ArrayList<Element>();?? ?? ????? ? ?? ????private?Object?action;?? ?? ?????? }???
?
ActionClass主要是用來存放解析struts.xml文件一些有用的值,以及反射時所調用的Action本身對象,其實就是一個簡單的JavaBean,存儲臨信息。
?
?
getActionClass(actionName)方法就是將URL上的actionName取出與struts.xml中的<action>結點匹配,可以得到Action的類全名,Action所調用的具體哪個方法名,Action的所有result結點(因為方法還沒有執行,還不知道是具體哪一個result結點,所以先存起來,后面來解析)分別存在ActionClass對象中相應的屬性中去。具體的解析代碼我就不打出來了,否則文章太長。
?
?
再來看看setBeforeActionValue(clas, params)這一句。其實就是將得到的ActionClass對象與提交的參數全部傳進去,給Action的那些set屬性賦值:
?
Java代碼??
? ? ? ? ? ? ?? ????public?Object?setActionValues(ActionClass?actionClass,?? ????????????Map<String,?String[]>?params)?{?? ????????try?{?? ?????????????? ????????????Class?clas?=?Class.forName(actionClass.getClassName());?? ????????????Object?obj?=?clas.newInstance();?? ?? ????????????if?(params?!=?null?&&?params.size()?>?0)?{?? ????????????????Iterator<String>?it?=?params.keySet().iterator();?? ????????????????while?(it.hasNext())?{?? ????????????????????String?key?=?it.next();?? ????????????????????String[]?value?=?params.get(key);?? ????????????????????String?upperFirstLetter?=?key.substring(0,?1).toUpperCase();?? ?????????????????????? ????????????????????String?setMethodName?=?"set"?+?upperFirstLetter?? ????????????????????????????+?key.substring(1);?? ????????????????????Method?method?=?null;?? ?????????????????????? ????????????????????try?{?? ????????????????????????method?=?clas.getMethod(setMethodName,?? ????????????????????????????????new?Class[]?{?String.class?});?? ????????????????????}?catch?(NoSuchMethodException?e)?{?? ????????????????????????System.out.println("警告?"?+?actionClass.getClassName()?? ????????????????????????????????+?"."?+?setMethodName?+?"("?? ????????????????????????????????+?String.class.getName()?+?")?不存在");?? ????????????????????}?? ????????????????????if?(method?!=?null)?{?? ?????????????????????????? ????????????????????????String?result?=?StringUtil.StringArrayToString(value);?? ????????????????????????method.invoke(obj,?new?String[]?{?result?});?? ????????????????????}?? ?? ????????????????}?? ?? ????????????}?? ????????????return?obj;?? ????????......?? ????}??
?
?
這樣就順利的將頁面的值賦給了Action的相應屬性,接下來就是Action調用工作了。通過setActionValues方法,我們已經可以得到Action對象本身了,可以存在ActionClass對象clas中去,我們直接調用setResultValue(clas, request)在Action執行后,同時也把有get方法的屬性一并存于request域中:
?
?
Java代碼??
? ? ? ? ? ? ? ?? ????public?Object?invokeAction(ActionClass?actionClass)?{?? ????????try?{?? ????????????Object?obj?=?actionClass.getAction();?? ????????????Class?clas?=?obj.getClass();?? ????????????Method?method?=?clas.getMethod(actionClass.getMethod(),?null);?? ????????????String?result?=?(String)?method.invoke(obj,?null);?? ????????????this.setInvokeResult(result,?actionClass);?? ????????????actionClass.setAction(obj);?? ????????????return?obj;?? ????????????????????????????????????????????????......?? ????????}?? ????}??
?
很簡單的代碼——調用Action那個無參執行方法,得到返回String類型的返回結果,然后我們可以再次利用ActionClass將最終的返回結果也給解析出來,看this.setInvokeResult(result, actionClass)方法
?
?
Java代碼??
? ? ? ? ? ? ?? ????private?void?setInvokeResult(String?result,?ActionClass?actionClass)?{?? ????????List<Element>?elements?=?actionClass.getElements();?? ????????for?(Element?elem?:?elements)?{?? ????????????Attribute?name?=?XmlUtil.getAttributeByName(elem,?"name");?? ????????????if?(StringUtil.equals(result,?name.getText()))?{?? ????????????????actionClass.setResult(elem.getText());?? ????????????????return;?? ????????????}?? ?? ????????}?? ????????throw?new?RuntimeException("請確定在xml配置文件中是否有名叫?["?+?result?? ????????????????+?"] 的返回類型結點?");?? ????}??
?
?
?
一切大功告成,將剛剛得到的返回結果用servletContext.getRequestDispatcher(clas.getResult()).forward(
request, response)轉發出去,編碼部分完畢。
?
?
別忘記了在web.xml中配置這個Filter:
?
?
Xml代碼??
<filter>?? ????<filter-name>struts</filter-name>?? ????<filter-class>com.framework.core.StrutsFilter</filter-class>?? </filter>?? <filter-mapping>?? ????<filter-name>struts</filter-name>?? ????<url-pattern>/*</url-pattern>?? </filter-mapping>??
?
?
?
?
最后寫個測試Action吧,就按照本文最開始的那個struts.xml配置編寫HelloAction.java
?
?
Java代碼??
public?class?HelloAction?{?? ?? ????private?String?message;?? ?? ????public?String?hello()?{?? ????????message?=?"superleo?"?+?this.message;?? ????????return?"success";?? ????}?? ?? ????public?String?getMessage()?{?? ????????return?message;?? ????}?? ?? ????public?void?setMessage(String?message)?{?? ????????this.message?=?message;?? ????}?? ?? } ?
總結
以上是生活随笔為你收集整理的自己动手写一个Struts2的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。