整合Struts 2 + Convention + Tiles 3

整合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%以上的狀況了。