Struts2 是一個基於 MVC 設計模式的 Web 應用框架,它本質上至關於一個 servlet,在 MVC 設計模式中,Struts2 做爲控制器 (Controller) 來創建模型與視圖的數據交互。html
Struts2 是 Struts1 的下一代產品,是在 struts1和 WebWork 的技術基礎上進行了合併的全新的 Struts2 框架。其全新的 Struts2 的體系結構與 Struts1 的體系結構差異巨大。java
Struts2 以 WebWork 爲核心,採用攔截器的機制來處理用戶的請求,這樣的設計也使得業務邏輯控制器可以與ServletAPI徹底脫離開,因此 Struts2 能夠理解爲 WebWork 的更新產品。web
雖然從 Struts1到 Struts2 有着太大的變化,可是相對於 WebWork,Struts2 的變化很小。spring
開發環境官網下載,下面示例使用版本爲 struts-2.3.37,點擊可直接下載 。express
這裏能夠直接導入解壓目錄下 apps/struts2-blank.war 中全部 jar 。apache
一、編寫 Action 類:設計模式
package com.zze.action; public class HelloAction { public String execute() { System.out.println("hello Struts 2"); return "hello"; } }
二、新建要跳轉到的 jsp 頁:瀏覽器
<%-- Created by zze. Date: 2019/1/22 Time: 10:48 --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Hello</title> </head> <body> <h3>hello Struts2</h3> </body> </html>
三、在 src 下新建以下配置文件:tomcat
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd"> <struts> <!--配置 Strut 2 的包--> <package name="test1" extends="struts-default" namespace="/"> <!--配置 Action--> <action name="hello" class="com.zze.action.HelloAction"> <result name="hello">/WEB-INF/hello.jsp</result> </action> </package> </struts>
四、在 web.xml 中配置核心過濾器:app
<filter> <filter-name>struts2</filter-name> <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class> </filter> <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
五、部署到 tomcat,運行:
一、首先瀏覽器請求 localhost:8080/hello 。
二、在 web.xml 中配置的核心過濾器會攔截到請求。
三、攔截器會解析 url,在 struts.xml 中根據 package 標籤上的 namespace 屬性和 action 標籤上的 name 找到對應請求路徑的 action。
四、執行對應 action 標籤對應 Action 類對象的 execute 方法。
五、execute 方法返回字符串,這個字符串與 action 標籤下的 result 標籤的 name 匹配。
六、返回匹配到的 result 標籤中定義的路徑對應的 jsp。
七、瀏覽器接收、渲染。
已經知道 Struts2 的入口就是核心過濾器 org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter ,在程序啓動時會執行過濾器的 init 方法,及會執行核心過濾器的 init 方法:
1 public void init(FilterConfig filterConfig) throws ServletException { 2 InitOperations init = new InitOperations(); 3 Dispatcher dispatcher = null; 4 try { 5 FilterHostConfig config = new FilterHostConfig(filterConfig); 6 init.initLogging(config); 7 dispatcher = init.initDispatcher(config); 8 init.initStaticContentLoader(config, dispatcher); 9 10 prepare = new PrepareOperations(dispatcher); 11 execute = new ExecuteOperations(dispatcher); 12 this.excludedPatterns = init.buildExcludedPatternsList(dispatcher); 13 14 postInit(dispatcher, filterConfig); 15 } finally { 16 if (dispatcher != null) { 17 dispatcher.cleanUpAfterInit(); 18 } 19 init.cleanup(); 20 } 21 }
而 Struts2 相關的配置文件就是在第 7 行的 init.initDispatcher(config) 中加載的:
1 public Dispatcher initDispatcher( HostConfig filterConfig ) { 2 Dispatcher dispatcher = createDispatcher(filterConfig); 3 dispatcher.init(); 4 return dispatcher; 5 }
再看到 dispatcher.init() :
1 public void init() { 2 3 if (configurationManager == null) { 4 configurationManager = createConfigurationManager(DefaultBeanSelectionProvider.DEFAULT_BEAN_NAME); 5 } 6 7 try { 8 init_FileManager(); 9 init_DefaultProperties(); // [1] 10 init_TraditionalXmlConfigurations(); // [2] 11 init_LegacyStrutsProperties(); // [3] 12 init_CustomConfigurationProviders(); // [5] 13 init_FilterInitParameters() ; // [6] 14 init_AliasStandardObjects() ; // [7] 15 16 Container container = init_PreloadConfiguration(); 17 container.inject(this); 18 init_CheckWebLogicWorkaround(container); 19 20 if (!dispatcherListeners.isEmpty()) { 21 for (DispatcherListener l : dispatcherListeners) { 22 l.dispatcherInitialized(this); 23 } 24 } 25 errorHandler.init(servletContext); 26 27 } catch (Exception ex) { 28 if (LOG.isErrorEnabled()) 29 LOG.error("Dispatcher initialization failed", ex); 30 throw new StrutsException(ex); 31 } 32 }
在上述 9-14 行就會加載 Struts2 相關配置文件,以下:
init_DefaultProperties(); // [1] 加載 struts2-core-2.3.37.jar!/org/apache/struts2/default.properties init_TraditionalXmlConfigurations(); // [2] 加載 struts2-core-2.3.37.jar!/struts-default.xml、src:struts-plugin.xml、src:struts.xml init_LegacyStrutsProperties(); // [3] 加載 src:struts.properties init_CustomConfigurationProviders(); // [5] 加載配置提供類 init_FilterInitParameters() ; // [6] 加載 web.xml中 過濾器初始化參數 init_AliasStandardObjects() ; // [7] 加載 Bean 對象
-> default.properties
-> struts-default.xml
-> struts-plugin.xml
-> struts.xml
-> struts.properties
-> web.xml
標綠的是咱們可配置的。
注意:後配置的常量會覆蓋以前配置的常量。
package 標籤稱爲包,這個包與 Java 中的包概念不一致,它是爲了更好地管理 action 的配置。
屬性:
一、帶名稱的名稱空間:namespace="/aaa"。
二、根名稱空間:namespace="/"。
三、默認名稱空間:namespace=""。
配置 action 類。
屬性:
配置常量。
屬性:
分模塊開發時使用,用來引入其它配置文件。
屬性:
在 Struts2 中提供了很是多默認的常量,在 "struts2-core-2.3.37.jar!/org/apache/struts2/default.properties" 中,以下:
# # $Id$ # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # ### START SNIPPET: complete_file ### Struts default properties ###(can be overridden by a struts.properties file in the root of the classpath) ### ### This can be used to set your default locale and encoding scheme # struts.locale=en_US struts.i18n.encoding=UTF-8 ### if specified, the default object factory can be overridden here ### Note: short-hand notation is supported in some cases, such as "spring" ### Alternatively, you can provide a com.opensymphony.xwork2.ObjectFactory subclass name here # struts.objectFactory = spring ### specifies the autoWiring logic when using the SpringObjectFactory. ### valid values are: name, type, auto, and constructor (name is the default) struts.objectFactory.spring.autoWire = name ### indicates to the struts-spring integration if Class instances should be cached ### this should, until a future Spring release makes it possible, be left as true ### unless you know exactly what you are doing! ### valid values are: true, false (true is the default) struts.objectFactory.spring.useClassCache = true ### ensures the autowire strategy is always respected. ### valid values are: true, false (false is the default) struts.objectFactory.spring.autoWire.alwaysRespect = false ### By default SpringObjectFactory doesn't support AOP ### This flag was added just temporally to check if nothing is broken ### See https://issues.apache.org/jira/browse/WW-4110 struts.objectFactory.spring.enableAopSupport = false ### if specified, the default object type determiner can be overridden here ### Note: short-hand notation is supported in some cases, such as "tiger" or "notiger" ### Alternatively, you can provide a com.opensymphony.xwork2.util.ObjectTypeDeterminer implementation name here ### Note: By default, com.opensymphony.xwork2.util.DefaultObjectTypeDeterminer is used which handles type detection ### using generics. com.opensymphony.xwork2.util.GenericsObjectTypeDeterminer was deprecated since XWork 2, it's ### functions are integrated in DefaultObjectTypeDeterminer now. ### To disable tiger support use the "notiger" property value here. #struts.objectTypeDeterminer = tiger #struts.objectTypeDeterminer = notiger ### Parser to handle HTTP POST requests, encoded using the MIME-type multipart/form-data # struts.multipart.parser=cos # struts.multipart.parser=pell # struts.multipart.parser=jakarta-stream struts.multipart.parser=jakarta # uses javax.servlet.context.tempdir by default struts.multipart.saveDir= struts.multipart.maxSize=2097152 ### Load custom property files (does not override struts.properties!) # struts.custom.properties=application,org/apache/struts2/extension/custom ### How request URLs are mapped to and from actions #struts.mapper.class=org.apache.struts2.dispatcher.mapper.DefaultActionMapper ### Used by the DefaultActionMapper ### You may provide a comma separated list, e.g. struts.action.extension=action,jnlp,do ### The blank extension allows you to match directory listings as well as pure action names ### without interfering with static resources, which can be specified as an empty string ### prior to a comma e.g. struts.action.extension=, or struts.action.extension=x,y,z,, struts.action.extension=action,, ### Used by FilterDispatcher ### If true then Struts serves static content from inside its jar. ### If false then the static content must be available at <context_path>/struts struts.serve.static=true ### Used by FilterDispatcher ### This is good for development where one wants changes to the static content be ### fetch on each request. ### NOTE: This will only have effect if struts.serve.static=true ### If true -> Struts will write out header for static contents such that they will ### be cached by web browsers (using Date, Cache-Content, Pragma, Expires) ### headers). ### If false -> Struts will write out header for static contents such that they are ### NOT to be cached by web browser (using Cache-Content, Pragma, Expires ### headers) struts.serve.static.browserCache=true ### Set this to false if you wish to disable implicit dynamic method invocation ### via the URL request. This includes URLs like foo!bar.action, as well as params ### like method:bar (but not action:foo). ### An alternative to implicit dynamic method invocation is to use wildcard ### mappings, such as <action name="*/*" method="{2}" class="actions.{1}"> struts.enable.DynamicMethodInvocation = false ### Set this to true if you wish to allow slashes in your action names. If false, ### Actions names cannot have slashes, and will be accessible via any directory ### prefix. This is the traditional behavior expected of WebWork applications. ### Setting to true is useful when you want to use wildcards and store values ### in the URL, to be extracted by wildcard patterns, such as ### <action name="*/*" method="{2}" class="actions.{1}"> to match "/foo/edit" or ### "/foo/save". struts.enable.SlashesInActionNames = false ### Disables support for action: prefix struts.mapper.action.prefix.enabled = false ### Blocks access to actions in other namespace than current with action: prefix struts.mapper.action.prefix.crossNamespaces = false ### use alternative syntax that requires %{} in most places ### to evaluate expressions for String attributes for tags struts.tag.altSyntax=true ### when set to true, Struts will act much more friendly for developers. This ### includes: ### - struts.i18n.reload = true ### - struts.configuration.xml.reload = true ### - raising various debug or ignorable problems to errors ### For example: normally a request to foo.action?someUnknownField=true should ### be ignored (given that any value can come from the web and it ### should not be trusted). However, during development, it may be ### useful to know when these errors are happening and be told of ### them right away. struts.devMode = false ### when set to true, resource bundles will be reloaded on _every_ request. ### this is good during development, but should never be used in production ### struts.i18n.reload=false ### Standard UI theme ### Change this to reflect which path should be used for JSP control tag templates by default struts.ui.theme=xhtml struts.ui.templateDir=template ### Change this to use a different token to indicate template theme expansion struts.ui.theme.expansion.token=~~~ #sets the default template type. Either ftl, vm, or jsp struts.ui.templateSuffix=ftl ### Configuration reloading ### This will cause the configuration to reload struts.xml when it is changed ### struts.configuration.xml.reload=false ### Location of velocity.properties file. defaults to velocity.properties struts.velocity.configfile = velocity.properties ### Comma separated list of VelocityContext classnames to chain to the StrutsVelocityContext struts.velocity.contexts = ### Location of the velocity toolbox struts.velocity.toolboxlocation= ### used to build URLs, such as the UrlTag struts.url.http.port = 80 struts.url.https.port = 443 ### possible values are: none, get or all struts.url.includeParams = none ### Load custom default resource bundles # struts.custom.i18n.resources=testmessages,testmessages2 ### workaround for some app servers that don't handle HttpServletRequest.getParameterMap() ### often used for WebLogic, Orion, and OC4J struts.dispatcher.parametersWorkaround = false ### configure the Freemarker Manager class to be used ### Allows user to plug-in customised Freemarker Manager if necessary ### MUST extends off org.apache.struts2.views.freemarker.FreemarkerManager #struts.freemarker.manager.classname=org.apache.struts2.views.freemarker.FreemarkerManager ### Enables caching of FreeMarker templates ### Has the same effect as copying the templates under WEB_APP/templates ### struts.freemarker.templatesCache=false ### Enables caching of models on the BeanWrapper struts.freemarker.beanwrapperCache=false ### See the StrutsBeanWrapper javadocs for more information struts.freemarker.wrapper.altMap=true ### maxStrongSize for MruCacheStorage for freemarker, when set to 0 SoftCacheStorage which performs better in heavy loaded application ### check WW-3766 for more details struts.freemarker.mru.max.strong.size=0 ### configure the XSLTResult class to use stylesheet caching. ### Set to true for developers and false for production. struts.xslt.nocache=false ### Whether to always select the namespace to be everything before the last slash or not struts.mapper.alwaysSelectFullNamespace=false ### Whether to allow static method access in OGNL expressions or not struts.ognl.allowStaticMethodAccess=false ### Whether to throw a RuntimeException when a property is not found ### in an expression, or when the expression evaluation fails struts.el.throwExceptionOnFailure=false ### Logs as Warnings properties that are not found (very verbose) struts.ognl.logMissingProperties=false ### Caches parsed OGNL expressions, but can lead to memory leaks ### if the application generates a lot of different expressions struts.ognl.enableExpressionCache=true ### Indicates if Dispatcher should handle unexpected exceptions by calling sendError() ### or simply rethrow it as a ServletException to allow future processing by other frameworks like Spring Security struts.handle.exception=true ### END SNIPPET: complete_file
下面描述部分配置的含義:
struts.i18n.encoding=UTF-8 # 處理了 POST 請求中文亂碼 struts.multipart.saveDir= # 上傳文件默認保存位置 struts.multipart.maxSize=2097152 # 上傳文件最大大小 struts.action.extension=action,, # 請求路徑默認後綴爲 action 或空白
能夠在三個位置修改常量的值:
直接經過 constant 標籤修改常量。
<constant name="struts.action.extension" value="do"/>
需在 src 下新建一個 struts.properties 文件,在其中以 key=value 的形式修改常量,例:
struts.action.extension=do
需在過濾器中經過配置過濾器的初始化參數修改常量,例:
<filter> <filter-name>struts2</filter-name> <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class> <init-param> <param-name>struts.action.extension</param-name> <param-value>do</param-value> </init-param> </filter>
Action 類的編寫可有三種方式以下:
Action 類能夠是一個 POJO(簡單的 Java 類),例:
package com.zze.action; public class HelloAction1 { public String execute() { System.out.println("hello Struts2"); return "hello"; } }
Action 類也能夠實現 Action 接口,例:
package com.zze.action; import com.opensymphony.xwork2.Action; /** * 實現接口 Action * Action 接口中提供了五個邏輯視圖名稱常量: * public static final String SUCCESS = "success"; * public static final String NONE = "none"; * public static final String ERROR = "error"; * public static final String INPUT = "input"; * public static final String LOGIN = "login"; */ public class HelloAction2 implements Action { @Override public String execute() throws Exception { System.out.println("hello Struts2"); return SUCCESS; } }
Action 類還能夠繼承 ActionSupport 類,例:
package com.zze.action; import com.opensymphony.xwork2.ActionSupport; public class HelloAction3 extends ActionSupport { @Override public String execute() throws Exception { System.out.println("hello Struts2"); return super.execute(); } }
Action 訪問配置也有三種方式,下面經過三種配置來訪問下面 Action。
package com.zze.action; import com.opensymphony.xwork2.ActionSupport; public class TestAction extends ActionSupport { public String save() { System.out.println("from save"); return NONE; } public String delete(){ System.out.println("from delete"); return NONE; } public String select(){ System.out.println("from select"); return NONE; } public String update(){ System.out.println("from update"); return NONE; } }
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd"> <struts> <package name="test" extends="struts-default" namespace="/"> <!--localhost:8080/save--> <action name="save" class="com.zze.action.TestAction" method="save"></action> <!--localhost:8080/delete--> <action name="delete" class="com.zze.action.TestAction" method="delete"></action> <!--localhost:8080/select--> <action name="select" class="com.zze.action.TestAction" method="select"></action> <!--localhost:8080/update--> <action name="update" class="com.zze.action.TestAction" method="update"></action> </package> </struts>
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd"> <struts> <package name="test" extends="struts-default" namespace="/"> <!--localhost:8080/save--> <!--localhost:8080/delete--> <!--localhost:8080/update--> <!--localhost:8080/select--> <!--method:{1} 表明 name 中第一個通配符的取值--> <action name="*" class="com.zze.action.TestAction" method="{1}"></action> <!--localhost:8080/Test_save--> <!--localhost:8080/Test_delete--> <!--localhost:8080/Test_update--> <!--localhost:8080/Test_select--> <!--通配符更抽象寫法--> <!--<action name="*_*" class="com.zze.action.{1}Action" method="{2}"></action>--> </package> </struts>
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd"> <struts> <!-- 設置常量,開啓動態方法訪問 開啓以後可經過 <host>:<port>/<actionName>!<methodName> 訪問: host : ip port : 端口 actionName : action 名稱 methodName : 要訪問的方法名稱 --> <constant name="struts.enable.DynamicMethodInvocation" value="true"/> <package name="test" extends="struts-default" namespace="/"> <!--localhost:8080/test!save--> <!--localhost:8080/test!delete--> <!--localhost:8080/test!select--> <!--localhost:8080/test!delete--> <action name="test" class="com.zze.action.TestAction" method="{1}"></action> </package> </struts>