Struts2 原理浅析

JavaEE把MVC设计模式引入了web领域,并在此基础上机构出了称为Model2的体系。

Struts2 原理浅析
从struts2.1.3版本开始,官方团队极力推荐用StrutsPrepareFilter取代原ActionContextCleanUp,用StrutsExecuteFilter取代原FilterDispatcher,并在全新的核心控制器StrutsPrepareAndExecuteFilter中集成了StrutsPrepareFilter和StrutsExecuteFilter的功能。
Java代码
  1. .......
  2. <filter>
  3. <filter-name>struts2Filter</filter-name>
  4. <filter-class>
  5. org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
  6. </filter-class>
  7. </filter>
  8. <filter-mapping>
  9. <filter-name>struts2Filter</filter-name>
  10. <url-pattern>/*</url-pattern>
  11. </filter-mapping>
  12. .......

这个时候在struts2的StrutsPrepareAndExecuteFilter与一系列拦截器Interceptor实现了Model2架构,如下图:
Struts2 原理浅析

其实图中的ActionContextCleanUp改成StrutsPrepareFilter,第三步的FilterDispatcher改为StrutsExecuteFilter更准确,不得不说官方团队也有偷懒的时候,在最新的2.3.4版本中的文档估计是以前2.1版本的图。上图是我修改后的流程图,技术粗糙请见谅。

这是官方文档中的介绍:
1.The web browser requests a resource (/mypage.action, /reports/myreport.pdf, et cetera)
2.The Filter Dispatcher looks at the request and determines the appropriate Action
3.The Interceptors automatically apply common functionality to the request, like workflow, validation, and file upload handling
4.The Action method executes, usually storing and/or retrieving information from a database
5.The Result renders the output to the browser, be it HTML, images, PDF, or something else

要想灵活运用struts2个人认为必须对常用的类非常熟悉,那么不得不提到Action的基类ActionSupport了。
Java代码
  1. publicclassActionSupportimplementsAction,Validateable,ValidationAware,TextProvider,LocaleProvider,Serializable{
  2. ...

这里的ActionSupport实现了很多接口,我们一一来了解:
Action:
Java代码
  1. /**
  2. *定义了Action5个常用的字符串常量,并且规定至少要有一个默认的execute方法
  3. *在ActionSupport实现execute方法返回值是SUCCESS
  4. */
  5. publicinterfaceAction{
  6. publicstaticfinalStringSUCCESS="success";
  7. publicstaticfinalStringNONE="none";
  8. publicstaticfinalStringERROR="error";
  9. publicstaticfinalStringINPUT="input";
  10. publicstaticfinalStringLOGIN="login";
  11. publicStringexecute()throwsException;
  12. }

Validateable:
Java代码
  1. /**
  2. *验证框架,在ActionSupport中此方法的实现为空,如果Action中需要验证只需重写
  3. *validate()方法就会在执行execute之前调用,然后通过ValidationAware接口中的
  4. *addFieldError这些方法就可以达到服务端验证的效果。
  5. */
  6. publicinterfaceValidateable{
  7. voidvalidate();
  8. }

ValidationAware:
Java代码
  1. publicinterfaceValidationAware{
  2. //为当前Action添加Action级别的错误信息集
  3. voidsetActionErrors(Collection<String>errorMessages);
  4. Collection<String>getActionErrors();
  5. //为当前Action添加Action级别的错误信息集
  6. voidsetActionMessages(Collection<String>messages);
  7. Collection<String>getActionMessages();
  8. //为制定字段添加错误信息集
  9. voidsetFieldErrors(Map<String,List<String>>errorMap);
  10. Map<String,List<String>>getFieldErrors();
  11. //为当前Action添加Action级别的错误信息
  12. voidaddActionError(StringanErrorMessage);
  13. //为当前Action添加Action级别的普通信息
  14. voidaddActionMessage(StringaMessage);
  15. //为制定字段添加错误信息
  16. voidaddFieldError(StringfieldName,StringerrorMessage);
  17. booleanhasActionErrors();//判断当前Action环境中是否存在Action级别错误
  18. booleanhasActionMessages();//判断当前Action环境中是否存在Action级别消息
  19. booleanhasErrors();//判断当前Action环境中是否存在Action级别错误
  20. booleanhasFieldErrors();//判断当前Action环境中是否存在字段错误消息
  21. }

TextProvider:
Java代码
  1. /**
  2. *通过key得到资源文件中的value,如果是全局类型有变量的value可以带上变量值
  3. *通常此方法配合validation框架使用
  4. */
  5. publicinterfaceTextProvider{
  6. booleanhasKey(Stringkey);
  7. StringgetText(Stringkey);
  8. StringgetText(Stringkey,StringdefaultValue);
  9. StringgetText(Stringkey,StringdefaultValue,Stringobj);
  10. StringgetText(Stringkey,List<?>args);
  11. StringgetText(Stringkey,String[]args);
  12. StringgetText(Stringkey,StringdefaultValue,List<?>args);
  13. StringgetText(Stringkey,StringdefaultValue,String[]args);
  14. StringgetText(Stringkey,StringdefaultValue,List<?>args,ValueStackstack);
  15. StringgetText(Stringkey,StringdefaultValue,String[]args,ValueStackstack);
  16. ResourceBundlegetTexts(StringbundleName);
  17. ResourceBundlegetTexts();
  18. }

LocaleProvider:
Java代码
  1. publicinterfaceLocaleProvider{
  2. LocalegetLocale();
  3. }

除了ActionSupport这个关键的基类外,还有个常用的类就是ServletActionContext,这个类继承了ActionContext并实现StrutsStatics接口,所以他可以称为Struts2直接访问Servlet API(如HttpServletRequest,HttpSession,HttpServletResponse,ServletContext)的工具类
Java代码
  1. publicclassServletActionContextextendsActionContextimplementsStrutsStatics{
  2. privatestaticfinallongserialVersionUID=-666854718275106687L;
  3. publicstaticfinalStringSTRUTS_VALUESTACK_KEY="struts.valueStack";
  4. publicstaticfinalStringACTION_MAPPING="struts.actionMapping";
  5. @SuppressWarnings("unused")
  6. privateServletActionContext(Mapcontext){
  7. super(context);
  8. }
  9. publicstaticActionContextgetActionContext(HttpServletRequestreq){
  10. ValueStackvs=getValueStack(req);
  11. if(vs!=null){
  12. returnnewActionContext(vs.getContext());
  13. }else{
  14. returnnull;
  15. }
  16. }
  17. publicstaticValueStackgetValueStack(HttpServletRequestreq){
  18. return(ValueStack)req.getAttribute(STRUTS_VALUESTACK_KEY);
  19. }
  20. publicstaticActionMappinggetActionMapping(){
  21. return(ActionMapping)ActionContext.getContext().get(ACTION_MAPPING);
  22. }
  23. //得到当前web应用中的PageContext对象
  24. publicstaticPageContextgetPageContext(){
  25. return(PageContext)ActionContext.getContext().get(PAGE_CONTEXT);
  26. }
  27. publicstaticvoidsetRequest(HttpServletRequestrequest){
  28. ActionContext.getContext().put(HTTP_REQUEST,request);
  29. }
  30. //得到当前web应用中的HttpServletRequest对象
  31. publicstaticHttpServletRequestgetRequest(){
  32. return(HttpServletRequest)ActionContext.getContext().get(HTTP_REQUEST);
  33. }
  34. publicstaticvoidsetResponse(HttpServletResponseresponse){
  35. ActionContext.getContext().put(HTTP_RESPONSE,response);
  36. }
  37. //得到当前web应用中的HttpServletResponse对象
  38. publicstaticHttpServletResponsegetResponse(){
  39. return(HttpServletResponse)ActionContext.getContext().get(HTTP_RESPONSE);
  40. }
  41. //得到当前web应用中的ServletContext对象
  42. publicstaticServletContextgetServletContext(){
  43. return(ServletContext)ActionContext.getContext().get(SERVLET_CONTEXT);
  44. }
  45. publicstaticvoidsetServletContext(ServletContextservletContext){
  46. ActionContext.getContext().put(SERVLET_CONTEXT,servletContext);
  47. }
  48. }