整合Struts 2 + Convention + Tiles 3
雖然之前 Struts 2 出了個大漏洞, 但它仍是Java界的主流Web開發框架之一。Convention Plugin 能把 Struts 2 轉換成零配置的模式,也就是如果只需照著預定的規則走,便不用再去設定struts.xml裡頭action mapping的部份。用wildcards的方式也能做出類似的效果,但總覺得不是很乾淨,到最後還是會需要設定一堆例外的mapping。
Convention Plugin細節的部份就不多說了,之前不用的原因是因為它預設尋找result的方式是去找固定路徑底下的檔案,遇到Tiles這種要去找設定檔內容的,就得用 annontation 定義的方式處理,這就失去了原本零配置的意義。最近研究出來可以不用 annontation 的方法,趕緊來做一下筆記。
pom.xml (部份)
1: <dependency>
2: <groupId>org.apache.struts</groupId>
3: <artifactId>struts2-core</artifactId>
4: <version>2.3.15.1</version>
5: <scope>compile</scope>
6: </dependency>
7: <dependency>
8: <groupId>org.apache.struts</groupId>
9: <artifactId>struts2-convention-plugin</artifactId>
10: <version>2.3.15.1</version>
11: <type>jar</type>
12: <scope>compile</scope>
13: </dependency>
14: <dependency>
15: <groupId>org.apache.struts</groupId>
16: <artifactId>struts2-tiles3-plugin</artifactId>
17: <version>2.3.15.1</version>
18: <type>jar</type>
19: <scope>compile</scope>
20: </dependency>
web.xml
1: <?xml version="1.0" encoding="UTF-8"?>
2: <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3: xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
4: xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
5: id="iTax" version="2.5">
6: <welcome-file-list>
7: <welcome-file>index.jsp</welcome-file>
8: </welcome-file-list>
9:
10: <listener>
11: <listener-class>org.apache.tiles.extras.complete.CompleteAutoloadTilesListener</listener-class>
12: </listener>
13:
14: <filter>
15: <filter-name>struts2</filter-name>
16: <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
17: </filter>
18: <filter-mapping>
19: <filter-name>struts2</filter-name>
20: <url-pattern>/*</url-pattern>
21: </filter-mapping>
22: </web-app>
struts.xml (部份)
1: <constant name="struts.convention.default.parent.package" value="app-package" />
2: <bean type="com.opensymphony.xwork2.UnknownHandler" name="tilesUnknownHandler" class="com.xxx.tiles.TilesUnknownHandler"/>
3:
4: <package name="app-package" extends="convention-default">
5: ....
6: </package >
重點在第2行的部分,定義當Struts找不到對應的mapping時,該如何處理。
TilesUnknownHandler.java
1: public class TilesUnknownHandler extends ConventionUnknownHandler {
2:
3: @Inject
4: public TilesUnknownHandler(Configuration configuration, ObjectFactory objectFactory,
5: ServletContext servletContext, Container container,
6: @Inject("struts.convention.default.parent.package") String defaultParentPackageName,
7: @Inject("struts.convention.redirect.to.slash") String redirectToSlash,
8: @Inject("struts.convention.action.name.separator") String nameSeparator) {
9: super(configuration, objectFactory, servletContext, container, defaultParentPackageName,
10: redirectToSlash, nameSeparator);
11: }
12:
13: @Override
14: public Result handleUnknownResult(ActionContext actionContext, String actionName,
15: ActionConfig actionConfig, String resultCode) throws XWorkException {
16:
17: StringBuilder location = new StringBuilder();
18:
19: location.append(getPackageName(actionConfig.getClassName()));
20:
21: if(location.length() == 0)
22: location.append(actionConfig.getClassName());
23:
24: location.append(".");
25:
26: if(resultCode.equals("success"))
27: {
28: location.append(actionConfig.getName());
29: }
30: else
31: {
32: location.append(resultCode);
33: }
34:
35: TilesResult result = new TilesResult(location.toString());
36: return result;
37: }
38:
39: private String getPackageName(String className)
40: {
41: int basePackageIndex = className.indexOf("actions.");
42: if(basePackageIndex == -1)
43: basePackageIndex = className.indexOf("action.");
44:
45: if(basePackageIndex != -1)
46: {
47: return className.substring(findPackageEndIndex(className, basePackageIndex)+1);
48: }
49: return null;
50: }
51:
52: private int findPackageEndIndex(String className, int packageIndex)
53: {
54: return className.indexOf(".", packageIndex);
55: }
56: }
當Struts找不到對應的result type時,將呼叫handleUnknownResult來處理,因此便可以在此時直接生出一個TilesResult好讓Tiles接手處理,並且把result code直接當成是Tiles的名稱參數帶進去,接下來Tiles的部份也用Wildcard的方式設定。
tiles.xml(部份)
1: <definition name="WILDCARD:*.*.*" template="/WEB-INF/content/common/layout.jsp">
2: <put-attribute name="body" value="/WEB-INF/content/{1}/{2}/{3}.jsp" />
3: </definition>
我想這樣應該可以處理90%以上的狀況了。