顯示具有 Struts2 標籤的文章。 顯示所有文章
顯示具有 Struts2 標籤的文章。 顯示所有文章

26 7月 2011

Struts2 處理404錯誤的方法

一個Member問起這個問題,我覺得很不錯。

Error Code 404 這個問題說大不大,不過是使用者敲錯了URL,又不是Error Code 500代表我們的系統出現錯誤,何況使用者要敲什麼,我們哪管得著?我想這也沒錯啦,如果我在Google Map敲個'我家',然後還希望它給我什麼好看的是不是有點超過?(也許會出現全家便利商店?)

在Struts2中,一般要解決的404URL大約是兩類,一類是struts2 的.action,另一類就是一般的resource,像jpg、js等

第一類Action的方式很容易,在struts.xml中設定一個default的package,然後用個default-action-ref就可以解決

	<package name="default" extends="struts-default">
		<default-action-ref name="index"/>
		<action name="index">
			<result>/index.jsp</result>
		</action>
	</package>

第二類非Action的話就要在xml中加上error-page的設定

	<error-page>
		<error-code>404</error-code>
		<location>/rootAction.action</location>
	</error-page>
這類的處理要注意的是,如果是直接導到jsp或html就不用在意,但若是想導到一個action的話,請注意你的struts action filter,是不是有加上error 的dispatcher。
	<filter>
		<filter-name>struts2</filter-name>
		<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
		<!-- <init-param> <param-name>actionPackages</param-name> <param-value>com.mycompany.myapp.actions</param-value> 
			</init-param> -->
	</filter>
	<filter-mapping>
		<filter-name>struts2</filter-name>
		<url-pattern>*.action</url-pattern>
		<dispatcher>REQUEST</dispatcher>
		<dispatcher>FORWARD</dispatcher>
		<dispatcher>INCLUDE</dispatcher>
		<dispatcher>ERROR</dispatcher>
	</filter-mapping>

12 4月 2010

StrutsSpringTestCase

Struts2的Unit Test說容易也是真的不麻煩,但如果希望測試得仔細些又要頗費力氣,還好在2.1.8時將一直沒有Commit到release repository的StrutsSpringTestCase放了出來,使Unit Test又更加方便。 下列寫個簡單例子:

public class FirstActionTest extends StrutsSpringTestCase{
	 public void testAction() throws Exception {  
		  ActionProxy actionProxy  = this.getActionProxy ( "first!index.action");  
		  Assert.assertNotNull(actionProxy);  
		  FirstAction action = (FirstAction) actionProxy.getAction();  
		  Assert.assertNotNull(action);  

		 String result = actionProxy.execute();  
		  Assert.assertEquals(FirstAction.SUCCESS , result);  
	 }  
} 
ActionProxy actionProxy  =  this.getActionProxy("first!index.action");
FirstAction action = (FirstAction) actionProxy.getAction();
String result = actionProxy.execute();
this.getActionProxy()內帶入你實際在跑的uri,取得Action後再設定你要測的property,最後再run actionProxy.execute();就可以做成一個簡單的測試,如果需要改變Spring configuration xml的位置,請override protected String getContextLocations(); 另外有兩點要注意,如果你使用wildcard如first_*來控制action的execution methed,請在測試時用!來分隔wildcard,trace了一段時間,還沒找出問題在哪...另一個是actionProxy.execute()會有找不到jsp的實際檔案的情形,但不影響測試,這部份應該是放到integration test就能解決。


10 6月 2009

專案心得

這個案子相對以前其他的案子,規模小上一截,所以很大膽地使用了Struts2到案子裡來,隨著開發逐漸看到當初在寫Demo沒想到的問題,而且將舊時常用的JavaScript Library從Prototype改成jQuery,大量使用Ajax來處理Data與Form Submition,而這些也改變了不少舊有Demo的Operation Pattern,中間也就累積了不少新筆記,等再空一些整理一下,有不少是蠻有趣的值得一看的東西,就數量來說的確是不少,應該可以當本小書了。

先舉個例來說,以往的分頁查詢(pagination search)模式在Action除了宣告一個domain object做為 search example來記錄使用者在Search Form輸入的條件,還會直接宣告一個int pageNo = 1;這樣每次在Search顯示Result時,可以直接將使用者輸出的舊有條件顯示出來,並將pageNo直接改為1,這樣再按下查詢钮時就直接以使用者輸入條件查詢並顯示結果中的第一頁,但改用Ajax來處理Form Submition,查詢用的Form跟pageNo根本不會也不需要被更新(我是在按下pagination 的頁碼再按form的search button才發現pageNo沒更新帶來的問題...算笨到),所以處理模式會有些小小的差異,諸如此類的東西不少,看起來重要性不高,但這些帶出來我對於Action Layer有新的想法,能少幾行Code就少幾行,嗯...整理整理。

這個案子真的一行"SQL"都沒寫,算是Hibernate完全利用吧(人懶就承認好了...),希望還有這樣的小案子,可以慢慢地實驗我的新想法。Spring 3應該不遠了,Maven 2.1跟之前2.0.x也有著不少差異...哪裡找案子來當實驗品呢?

05 3月 2007

Struts2 Note -- (3)Action Method Invocation

Action method invocation 在Struts中使用DispatchAction及設定parameter來操做同一個Action的不同Method,可以減去不少的Action數量. 在Struts2中,可以使用wildcard來達成.如下列這個Action. MyAction.java
public class MyAction extends ActionSupport {
 public String input() {
  return "patha";
 }
 
 public String output() {
  return "pathb";
 }
}
然後在struts.xml中以"*"來代表特定組合的文字,再以"{num}"取用. struts.xml
<package name="myaction" namespace="/struts2" extends="struts-default">
 <action name="myaction_*" method="{1}" class="MyAction">
  <result name="patha">
   /jsp/inputResult.jsp
  </result>
  <result name="pathb">
   /jsp/outputResult.jsp
  </result>
 </action>
</package>
這樣的話執行 http://localhost:8080/mystruts/struts2/myaction_input.action 會呼叫MyAction.input()->patha 而下列的URL http://localhost:8080/mystruts/struts2/myaction_output.action 會呼叫MyAction.output()->pathb 看起來便利性上兩者相差不遠,不過wildcard的用途還不止如此....

02 3月 2007

Struts2 Note -- (2)整合Spring2

2.0.6與之前版本整合的設定 2.0.6與之前版本的整合方式有很大不同,而整合的Spring版本也從1.2.8到了2.0.1 2.0.6將org.apache.struts2.spring.StrutsSpringObjectFactory自struts2-core移至struts2-spring-plugin, 所以必需要加入struts2-spring-plugin的Library.使用Maven2的可以這樣設定 pom.xml
<dependency>
 <groupId>org.apache.struts</groupId>
 <artifactId>struts2-spring-plugin</artifactId>
 <version>2.0.6</version>
</dependency>
2.0.6與之前的版本皆需在struts.propertis中設定
struts.objectFactory = spring
struts2-spring-plugin中除了org.apache.struts2.spring.StrutsSpringObjectFactory這個主要java外, 另外有的就是一個struts-plugin.xml,設定了struts.objectFactory真正使用的Class struts-plugin.xml
<struts>
    <bean type="com.opensymphony.xwork2.ObjectFactory" name="spring" class="org.apache.struts2.spring.StrutsSpringObjectFactory" />
    
    <!--  Make the Spring object factory the automatic default -->
    <constant name="struts.objectFactory" value="spring" />

    <package name="spring-default">
        <interceptors>
            <interceptor name="autowiring" class="com.opensymphony.xwork2.spring.interceptor.ActionAutowiringInterceptor"/>
            <interceptor name="sessionAutowiring" class="org.apache.struts2.spring.interceptor.SessionContextAutowiringInterceptor"/>
        </interceptors>
    </package>    
</struts>
2.0.6與之前版本整合的差異 之前的版本是這樣整合的
org.apache.struts2.dispatcher.Dispatcher
 private void init(ServletContext servletContext) {
  .......................
  if (Settings.isSet(StrutsConstants.STRUTS_OBJECTFACTORY)) {
   String className = (String) Settings.get(StrutsConstants.STRUTS_OBJECTFACTORY);
   if (className.equals("spring")) {
    className = "org.apache.struts2.spring.StrutsSpringObjectFactory";
   }
  }
  .......................
 }
很明顯的有硬來的嫌疑 2.0.6則是分為了幾個部份
org.apache.struts2.dispatcher.Dispatcher
 public void init() {
  init_DefaultProperties(); // [1]
  init_TraditionalXmlConfigurations(); // [2]
  init_LegacyStrutsProperties(); // [3]
  .......................
  init_AliasStandardObjects() ; // [4]
  .......................
 }
[1]載入了org/apache/struts2/default.properties [2]利用了StrutsXmlConfigurationProvider來載入struts-default.xml,struts-plugin.xml,struts.xml三個xml, 其中就包含了struts2-spring-plugin的struts-plugin.xml,這樣就能取得 <constant name="struts.objectFactory" value="spring" /> <bean ... name="spring" class="org.apache.struts2.spring.StrutsSpringObjectFactory" /> 這兩項設定 [3]載入struts.properties,透過手動設定的struts.objectFactory = spring, 就可以明白要載入的ObjectFactory Class是哪一個了 [4]此時才真正載入所有指定的Class 這樣做得確是較之前的方式好上不少,但是xml的設定檔就只能有這三個struts-default.xml,struts-plugin.xml,struts.xml 特別是struts-plugin.xml,如果自己還要寫Plugin或是希望同時能使用兩種不同的Plugin,都會遇到設定的問題.

28 2月 2007

Struts2 Note -- (1)struts-tags.tld

Struts2發佈了2.0.6,下載後沒有注意到一件事,自2.0.6後的版本,struts-tags.tld要自 source code中經maven2 build後才會產生,所以找了老半天還有點火…,還好看了一下core/src/main/resources/META-INF/README.txt,才發現這個版本是要透過maven2才能產生struts-tags.tld,只好自行run mvn來做了,需要的話可以參考Building with Maven,遇上了OutOfMemoryError別忘了為Maven2加上個MAVEN_OPTS=-Xmx512m參數來執行。 我個人是有裝Maven2,所以問題不大,不過如果是希望下載後就能使用而且沒有需求使用Maven2的朋友,還是可能會感到些許不便吧。

27 2月 2007

First Struts2 Project with Eclipse and Maven2

一個基本的Eclipse Struts Project至少需要以下的設定 pom.xml
<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <groupId>org.elliot</groupId>
 <artifactId>firststruts</artifactId>
 <packaging>war</packaging>
 <name>firststruts</name>
 <version>1.0-SNAPSHOT</version>
 <url>http://maven.apache.org</url>
 <build>
  <sourceDirectory>${basedir}/src/main/java</sourceDirectory>
  <testSourceDirectory>
   ${basedir}/src/test/java
  </testSourceDirectory>
  <resources>
   <resource>
    <directory>${basedir}/src/main/resources</directory>
   </resource>
  </resources>
  <testResources>
   <testResource>
    <directory>${basedir}/src/test/resources</directory>
   </testResource>
  </testResources>
  <plugins>
   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <configuration>
     <source>1.5</source>
     <target>1.5</target>
    </configuration>
   </plugin>

   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-war-plugin</artifactId>
    <version>2.0.2</version>
    <configuration>
     <warName>firststruts</warName>
    </configuration>
   </plugin>
  </plugins>
 </build>
 <dependencies>
  <dependency>
   <groupId>org.apache.struts</groupId>
   <artifactId>struts2-core</artifactId>
   <version>2.0.6</version>
  </dependency>
 </dependencies>
 <repositories>
  <repository>
   <id>Struts2</id>
   <name>Struts2</name>
   <snapshots>
    <enabled>true</enabled>
   </snapshots>
   <url>
    http://people.apache.org/repo/m2-snapshot-repository
   </url>
  </repository>
 </repositories>
</project>
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" 
 xmlns="http://java.sun.com/xml/ns/j2ee" 
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
 xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
 http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
 <display-name>firststruts</display-name>
 <filter>
  <filter-name>struts2</filter-name>
  <filter-class>
   org.apache.struts2.dispatcher.FilterDispatcher
  </filter-class>
 </filter>
 <filter-mapping>
  <filter-name>struts2</filter-name>
  <url-pattern>/*</url-pattern>
 </filter-mapping>
 <jsp-config>
  <taglib>
   <taglib-uri>/struts-tags</taglib-uri>
   <taglib-location>/WEB-INF/struts-tags.tld</taglib-location>
  </taglib>
 </jsp-config>
</web-app>
resources還需要有struts.properties struts.devMode = true struts.enable.DynamicMethodInvocation = false 然後實做自己的Action extends from com.opensymphony.xwork2.ActionSupport 加入到struts.xml中即可 struts.xml
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
    "http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
    <package name="first" namespace="/" extends="struts-default">
        <action name="first" class="org.elliot.action.FirstAction">
            <result name="Success">/jsp/first/firstActionResult.jsp</result>
        </action>
    </package>
</struts>