大家好,关于struts2很多朋友都还不太明白,不过没关系,因为今天小编就来为大家分享关于struts2原理及配置详解的知识点,相信应该可以解决大家的一些困惑和问题,如果碰巧可以解决您的问题,还望关注下本站哦,希望对各位有所帮助!
Struts2是一个基于MVC设计模式的Web应用框架,它本质上相当于一个servlet,在MVC设计模式中,Struts2作为控制器(Controller)来建立模型与视图的数据交互。Struts2是Struts的下一代产品,是在struts1和WebWork的技术基础上进行了合并的全新的Struts2框架。其全新的Struts2的体系结构与Struts1的体系结构差别巨大。Struts2以WebWork为核心,采用拦截器的机制来处理用户的请求,这样的设计也使得业务逻辑控制器能够与ServletAPI完全脱离开,所以Struts2可以理解为WebWork的更新产品。虽然从Struts1到Struts2有着太大的变化,但是相对于WebWork,Struts2的变化很小。
当Web容器收到请求(HttpServletRequest)它将请求传递给一个标准的的过滤链包括(ActionContextCleanUp)过滤器。
经过Otherfilters(SiteMesh,etc),需要调用FilterDispatcher核心控制器,然后它调用ActionMapper确定请求哪个Action,ActionMapper返回一个收集Action详细信息的ActionMaping对象。
FilterDispatcher将控制权委派给ActionProxy,ActionProxy调用配置管理器(ConfigurationManager)从配置文件中读取配置信息(struts.xml),然后创建ActionInvocation对象。
ActionInvocation在调用Action之前会依次的调用所用配置拦截器(InterceptorN)一旦执行结果返回结果字符串ActionInvocation负责查找结果字符串对应的(Result)然后执行这个ResultResult会调用一些模版(JSP)来呈现页面。
拦截器(InterceptorN)会再被执行(顺序和Action执行之前相反)最后响应(HttpServletResponse)被返回在web.xml中配置的那些过滤器和核心控制器(FilterDispatcher)
Struts2框架的内部执行过程
上面讲了MVC中个文件的执行过程,那只是一小部分,现在来看一下整个struts2框架的执行机制,下面的图来源于官网,然后加了自己的改动。
由上图看出,整个框架的运行又紧紧围绕着核心过滤器StrutsPrepareAndExecuteFilter展开工作。深入到filter的源码中会对理解有所帮助。下面几篇博客对filter的介绍很好。
3,默认拦截器
struts-default.xml配置文件中定义了一个默认拦截器栈,这些拦截器就是动作方法执行之前的要执行的。常用的有封装用户表单数据到javabean的modelDriven拦截器,用于输入验证的validation拦截器,等等。
4,View和Controller之间的交互
从视图页面每次发来的用户请求都会产生一些数据,这些数据都存放在哪儿呢?实际上,每次动作类执行前,核心过滤器StrutsPrepareAndExecuteFilter都会创建2个对象:ActionContext和ValueStack,这2个对象存储了动作访问期间用到的所有数据。这些数据又可以在jsp页面上通过strut标签和OGNL表达式来取得。
(1),ActionContext是一个map数据结构,其中的key是一些常见的域对象(application,session,request等),而value又是一个map。也就是说ActionContext是一个大map包裹着一些小map。
(2),ValueStack是一个ArrayList数据结构,并且是一个栈结构,每次都在栈顶存取数据。
5,Controller与Model之间的交互
C和M之间的交互比较简单,利用Struts框架提供的拦截器:ModelDriven,即可实现将用户表单提交的数据封装到对应的javabean中。要点:(1)javabean类自己编写。(2)动作类要实现ModelDriven接口。(3)实现抽象方法getModel()。
首先我们使用struts2框架都会在web.xml中注册和映射struts2,配置内容如下:
1<filter>\n2<filter-name>struts2</filter-name>\n3<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>\n4</filter>\n5<filter-mapping>\n6<filter-name>struts2</filter-name>\n7<url-pattern>/*</url-pattern>\n8</filter-mapping>
注:在早期的struts2中,都是使用FilterDispathcer,从Struts2.1.3开始,它已不推荐使用。如果你使用的Struts的版本>=2.1.3,推荐升级到新的Filter,StrutsPrepareAndExecuteFilter。在此研究的是StrutsPrepareAndExecuteFilter。
StrutsPrepareAndExecuteFilter中的方法:
web容器一启动,就会初始化核心过滤器StrutsPrepareAndExecuteFilter,并执行初始化方法,初始化方法如下:
1publicvoidinit(FilterConfigfilterConfig)throwsServletException{\n2InitOperationsinit=newInitOperations();\n3Dispatcherdispatcher=null;\n4try{\n5//封装filterConfig,其中有个主要方法getInitParameterNames将参数名字以String格式存储在List中\n6FilterHostConfigconfig=newFilterHostConfig(filterConfig);\n7//初始化struts内部日志\n8init.initLogging(config);\n9//创建dispatcher,并初始化\n10dispatcher=init.initDispatcher(config);\n11init.initStaticContentLoader(config,dispatcher);\n12//初始化类属性:prepare、execute\n13prepare=newPrepareOperations(filterConfig.getServletContext(),dispatcher);\n14execute=newExecuteOperations(filterConfig.getServletContext(),dispatcher);\n15this.excludedPatterns=init.buildExcludedPatternsList(dispatcher);\n16//回调空的postInit方法17postInit(dispatcher,filterConfig);\n18}finally{\n19if(dispatcher!=null){\n20dispatcher.cleanUpAfterInit();21}\n22init.cleanup();\n23}\n24}
关于封装filterConfig,首先看下FilterHostConfig,源码如下:
1publicclassFilterHostConfigimplementsHostConfig{\n2\n3privateFilterConfigconfig;\n4//构造方法5publicFilterHostConfig(FilterConfigconfig){\n6this.config=config;\n7}\n8//根据init-param配置的param-name获取param-value的值\n9publicStringgetInitParameter(Stringkey){\n10returnconfig.getInitParameter(key);\n11}\n12//返回初始化参数名的迭代器\n13publicIterator<String>getInitParameterNames(){\n14returnMakeIterator.convert(config.getInitParameterNames());\n15}\n16//返回Servlet上下文\n17publicServletContextgetServletContext(){\n18returnconfig.getServletContext();\n19}\n20}只有短短的几行代码,getInitParameterNames是这个类的核心,将Filter初始化参数名称有枚举类型转为Iterator。此类的主要作为是对filterConfig封装。
一个Action内包含多个请求处理方法的处理
Struts1提供了DispatchAction,从而允许一个Action内包含多个请求处理方法。Struts2也提供了类似的功能。
处理方式主要有以下三种方式:
1.1动态方法调用:
DMI:DynamicMethodInvocation动态方法调用。
动态方法调用是指:表单元素的action不直接等于某个Action的名字,而是以感叹号后加方法名来指定对应的动作名:
<!--动态方法调用HTML标签与Struts2标签-->\n<formaction="computeAction!add.action"name="from">\n<s:formaction="computeAction!add.action"name="form"theme="simple">
则用户的请求将提交到名为”computeAction”的Action实例,Action实例将调用名为”add”方法来处理请求。
当指定调用某一方法来处理请求时,就不会走默认执行处理请求的execute()方法。
注意:要使用动态方法调用,必须设置Struts2允许动态方法调用,通过设置struts.enable.DynamicMethodInvocation常量来完成,该常量属性的默认值是true。
<struts>\n<!--\n//禁用动态方法调用,默认为true启用,false禁用\nconstant:name="struts.enable.DynamicMethodInvocation"-->\n<constantname="struts.enable.DynamicMethodInvocation"value="true"/></struts>
示列:简单的一个加法和减法例子。
1.index.jsp用户在页面输入两个数字,选择相加,或者相减
当用户点击加或减需要走同一个Action但处理请求方法不同,这里使用了js动态选择。
<body>\n<!--动态方法调用使用:Struts2标签也可以使用HTML标签-->\n<s:name="form"theme="simple">\nnum1:<s:textfieldname="num1"/>\nnum2:<s:textfieldname="num2"/>\n<s:submittype="button"value="加"onclick="computeMethod('add')"/>\n<s:submittype="button"value="减"onclick="computeMethod('subtract')"/>\n</s:form>\n<!--js-->\n<scripttype="text/javascript">\nfunctioncomputeMethod(op){\ndocument.form.action="computeAction!"+op;//动态选择处理请求的方法document.form.submit();//提交}</script>\n</body>
2.struts.xml配置信息,启用动态方法调用(可选)
<?xmlversion="1.0"encoding="UTF-8"?><!DOCTYPEstrutsPUBLIC"-//ApacheSoftwareFoundation//DTDStrutsConfiguration2.1//EN""struts-2.1.dtd"><struts>\n<!--\n//禁用动态方法调用,默认为true启用,false禁用\nconstant:name="struts.enable.DynamicMethodInvocation"-->\n<constantname="struts.enable.DynamicMethodInvocation"value="true"/>\n<packagename="struts2"extends="struts-default">\n<actionname="computeAction"class="com.struts.ComputeAction">\n<resultname="fruitPage">/fruit.jsp</result>\n</action>\n</package></struts>
3.ComputeAction控制器的类处理请求
\n*Struts2控制器的类\n*@authorasus\n**/publicclassComputeAction{/**属性*/\nprivateintnum1;privateintnum2;privateintfruit;//结果\n/**若请求为指定操作方法默认执行execute()方法*/\npublicStringexecute(){\nSystem.out.println("当调用其它方法就不会走这个方法!");return"";\n}\n/**执行处理加法*/\npublicStringadd(){this.fruit=num1+num2;//加\nreturn"fruitPage";\n}\n/**执行处理减法*/\npublicStringsubtract(){this.fruit=num1-num2;//减\nreturn"fruitPage";\n}\n/**JavaBean*/\npublicintgetNum1(){returnnum1;\n}publicvoidsetNum1(intnum1){this.num1=num1;\n}publicintgetNum2(){returnnum2;\n}publicvoidsetNum2(intnum2){this.num2=num2;\n}publicintgetFruit(){returnfruit;\n}publicvoidsetFruit(intfruit){this.fruit=fruit;\n}\n}
4.fruit.jsp响应结果的页面
<body>\n<!--结果页面-->\n计算结果:<s:propertyvalue="fruit"/></body>
1.2Action配置method属性(示列与以上代码大多一致,只修改有变更的):
将Action类中的每一个处理方法都定义成一个逻辑Action方法。
<body>\n<!--Action配置method属性使用:Struts2标签也可以使用HTML标签-->\n<s:formname="form"theme="simple">\nnum1:<s:textfieldname="num1"/>\nnum2:<s:textfieldname="num2"/>\n<s:submittype="button"value="加"onclick="computeMethod('addAction')"/>\n<s:submittype="button"value="减"onclick="computeMethod('subtractAction')"/>\n</s:form>\n<!--js-->\n<scripttype="text/javascript">\nfunctioncomputeMethod(op){\ndocument.form.action=op;//动态选择处理请求的方法document.form.submit();//提交}\n</script>\n</body>
2.struts.xml配置信息
<?xmlversion="1.0"encoding="UTF-8"?><!DOCTYPEstrutsPUBLIC"-//ApacheSoftwareFoundation//DTDStrutsConfiguration2.1//EN""struts-2.1.dtd"><struts>\n<packagename="struts2"extends="struts-default">\n<actionname="addAction"class="com.struts.ComputeAction"method="add">\n<resultname="fruitPage">/fruit.jsp</result>\n</action>\n<actionname="subtractAction"class="com.struts.ComputeAction"method="subtract">\n<resultname="fruitPage">/fruit.jsp</result>\n</action>\n</package></struts>
通过action元素的method属性来指定Action执行时调用的方法。
优点:使得以更加安全的方式来实现动态方法的调用,不让别人看到你的实现方法。
缺点:繁琐,一个处理请求的方法要跟一个action。
Struts2根据method属性查找方法有两种途径:
1.查找与method属性值完全一致的方法
使用动态方法调用和method属性的区别:
1.通过以上三个struts.xml中的配置信息例子来说,他们的共同点是都在操作同一个Action。
2.<formaction="">中请求地址不同。
3.动态方法的返回值相同,则会通过result进入一个页面。而method属性就算两个方法的返回值相同但进去不同的result,可能会进入两个不同的页面。
(1)如果使用同一个Action,不同的处理请求的方法,响应使用相同的配置(result等)则使用动态方法调用。
(2)如果使用同一个Action,不同的处理请求的方法,响应分别使用不同的配置,则使用action元素的method属性,为同一个Action配置多个名称。
关于struts2到此分享完毕,希望能帮助到您。