struts2被很多新手詬病的一個地方在於“配置過於復雜”,相信不少初學者因為這個直接改投Spring-MVC了。convention-plugin、 config-browser-plugin這二個插件的出現,很大程度改善了這個囧境。
簡言之:convention-plugin采用"約定大於配置”的思想,只要我們遵守約定,完全可以少寫配置甚至不寫配置;而config-browser-plugin則用於方便的瀏覽項目中的所有action及其與jsp view的映射。這二個插件結合起來學習,能很方便的搞定struts2中各種復雜的action-view映射需求。
一、config-browser-plugin使用

1 <dependency> 2 <groupId>org.apache.struts</groupId> 3 <artifactId>struts2-config-browser-plugin</artifactId> 4 <version>2.3.16</version> 5 </dependency>
maven項目的pom.xml中加上這個即可,運行后,瀏覽 http://localhost:8080/{你的項目名稱}/config-browser/ 即可看到當前項目中的所有action
注:以下內容中,凡有url的地方,項目名稱假設為struts2-helloworld
如果跑不起來,檢查服務器應用WEB-INF/lib/下是否有struts2-config-browser-plugin-2.3.16.jar 這個文件
二、convention-plugin 使用

1 <dependency> 2 <groupId>org.apache.struts</groupId> 3 <artifactId>struts2-convention-plugin</artifactId> 4 <version>2.3.16</version> 5 </dependency>
pom.xml中加上這個后,可以把struts.xml配置文件給干掉了(或者改個名),部署App,如果啟動正常,則表示環境ok。如果提示缺少asm 啥類,檢查下面這幾個依賴項,是否也加進來了

1 <dependency> 2 <groupId>asm</groupId> 3 <artifactId>asm</artifactId> 4 <version>3.3.1</version> 5 </dependency> 6 7 <dependency> 8 <groupId>asm</groupId> 9 <artifactId>asm</artifactId> 10 <version>3.3.1</version> 11 </dependency> 12 13 <dependency> 14 <groupId>asm</groupId> 15 <artifactId>asm-commons</artifactId> 16 <version>3.3.1</version> 17 </dependency> 18 19 <dependency> 20 <groupId>asm</groupId> 21 <artifactId>asm-tree</artifactId> 22 <version>3.3.1</version> 23 </dependency>
2.1 零action的view
convention-plugin約定所有的jsp view都放在WEB-INF/content目錄下,在這個目錄下先隨便放一個名為"no-action.jsp"的jsp文件,里面隨便寫點啥
瀏覽 http://localhost:8080/struts2-helloworld/no-action
即:即使沒有對應的Action類,struts2也能按約定正常展現頁面。(當然,這只是開胃小菜,真正應用中,除了做一些純靜態的頁面原型之外,大部分場景,背后還是要有Action類來支撐的)
2.2 常規映射
建一個HelloWorld.action類

1 package com.cnblogs.yjmyzz.action; 2 3 import org.apache.struts2.convention.annotation.Action; 4 import org.apache.struts2.convention.annotation.Namespace; 5 import org.apache.struts2.convention.annotation.Result; 6 7 @Namespace("/home") 8 public class HelloWorldAction extends BaseAction { 9 10 private static final long serialVersionUID = -8827776224243873974L; 11 12 private String message; 13 14 @Action("hello-world") 15 public String execute() throws Exception { 16 return SUCCESS; 17 } 18 19 @Action(value = "say-hi", results = { @Result(name = "success", location = "hello-world.jsp") }) 20 public String sayHi() throws Exception { 21 message = "welcome to SSH!"; 22 return SUCCESS; 23 } 24 25 public String getMessage() { 26 return message; 27 } 28 29 public void setMessage(String message) { 30 this.message = message; 31 } 32 33 }
解釋一下:
第7行,在整個Action類上使用了@Namespace("/home"),表示整個Action最終瀏覽的url,是以 http://localhost:8080/{你的項目名稱}/home/ 打頭
第14行,通過注解@Action("hello-world"),把默認的/home/index.action路徑,改成了 /home/hello-world
至於execute方法,返回success后,對應的是哪個jsp文件,這個不用死記,通過config-browser-plugin看下便知
即:execute方法返回input/error/success中的任何一個,都會映射到/WEB-INF/content/home/hello-world.jsp 這個文件上
20行sayHI()方法上的注解有點意思,@Action(value = "say-hi", results = { @Result(name = "success", location = "hello-world.jsp") }),默認情況下,如果不指定location,返回success時,它應該對應 /WEB-INF/content/home/say-hi.jsp這個文件,但是通過location值,變成了hello-world.jsp,即與/home/hello-world共用同一個view.
3、攔截器問題
上一篇學習了通過攔截器來處理異常,采用convention插件后,會發現攔截器不起作用(struts.xml中配置了也一樣)

1 <?xml version="1.0" encoding="UTF-8" ?> 2 <!DOCTYPE struts PUBLIC 3 "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" 4 "http://struts.apache.org/dtds/struts-2.3.dtd"> 5 6 <struts> 7 8 <constant name="struts.enable.DynamicMethodInvocation" value="false" /> 9 <constant name="struts.devMode" value="false" /> 10 11 <package name="default" namespace="/" extends="struts-default"> 12 13 <interceptors> 14 <interceptor name="myinterceptor" 15 class="com.cnblogs.yjmyzz.Interceptor.ExceptionInterceptor"> 16 </interceptor> 17 18 <interceptor-stack name="myStack"> 19 <interceptor-ref name="myinterceptor" /> 20 </interceptor-stack> 21 </interceptors> 22 23 <default-interceptor-ref name="myStack" /> 24 <default-action-ref name="index" /> 25 26 <global-results> 27 <result name="error">/WEB-INF/common/error.jsp</result> 28 </global-results> 29 30 <global-exception-mappings> 31 <exception-mapping exception="java.lang.Exception" 32 result="error" /> 33 </global-exception-mappings> 34 35 <action name="index"> 36 <result type="redirectAction"> 37 <param name="actionName">hello-world</param> 38 <param name="namespace">/home</param> 39 </result> 40 </action> 41 42 </package> 43 44 <!-- 因為有Convention-plugin,就不再需要手動寫action-view的映射規則了 --> 45 <!-- <include file="struts-home.xml" /> 46 <include file="struts-mytatis.xml" /> --> 47 48 </struts>
原因在於convention-plugin使用后,所有Action不再繼承自默認defaultStack對應的package,為了解決這個問題,建議所有Action都繼承自一個自定義的BaseAction類,然后在BaseAction上加上@ParentPackage("default"),讓所有Action強制繼承自struts.xml中定義的default package

1 package com.cnblogs.yjmyzz.action; 2 3 import org.apache.struts2.convention.annotation.ParentPackage; 4 import org.slf4j.Logger; 5 import org.slf4j.LoggerFactory; 6 7 import com.opensymphony.xwork2.ActionSupport; 8 9 @ParentPackage("default") 10 public class BaseAction extends ActionSupport { 11 12 private static final long serialVersionUID = -4320398837758540242L; 13 protected Logger logger = LoggerFactory.getLogger(this.getClass()); 14 15 }
基本用法就是這些,如果不清楚Action最終出來的url是啥,或者不清楚某個url最終會對應到哪個jsp文件,無需死記規則,只要善用config-browser-plugin,大多數下不用查閱文檔即可快速解決問題。