Struts 1.3 + Spring 3.2 + Hibernate 3.6 錯誤筆記
買了一本「王者歸來 Java Web 整合開發 (第二版)」,書中包含了 JSP + Servlet + Struts + Hibernate + Spring 等的教學及範例,K了一個星期後,發現最困難的部份竟然在環境架設上,光是環境架設就花了好長的時間,再來是設定檔,小蛙的 Eclipse 有些設定檔的 auto-complete 跑不出東西,加上每個版本的套件下載下來後的 Jar 檔、設定檔都不相同,不同版本的整合方式也不同 … 花了很久的時間在環境架設及設定檔上,這篇文章不記錄完整經過(忘的差不多了),只挑著把過程中要注意的事情及錯誤記錄下來。
-
隱藏 .jsp 頁面,對外以 .do 為主
將 jsp 頁面通通放在 WEB-INF 底下,可自行建立其他分類資料夾,ex. pages, pages/admin, pages/member … 等。並且在 struts-conf.xml 中設定
<action-mappings> <action path="/index" type="org.apache.struts.actions.ForwardAction" parameter="/WEB-INF/pages/index.jsp"></action> </action-mappings>
-
java.lang ClassNotFoundException 各式各樣怪怪的情況
這情況太容易出現了,小蛙原本使用 Eclipse IDE 裡面自訂 User Library 的功能,卻一直報錯,最後把所有會用到的 Spring, Struts Jar 通通放在 Web/WEB-INF/lib 下,這些怪裡怪氣的錯誤就自己消失了 …
-
亂碼處理
這應該是最容易遇到的問題,有幾項前提要先遵守:
R1. 必須先將每一頁 JSP 或每一個 Servelt 設定成 UTF-8 編碼(小蛙直接用 UTF-8 編碼,可以省掉 BIG5 的一些麻煩),如果是 Eclipse 專案請確定專案編碼為 UTF-8,有些文字編輯器可以看到目前檔案編碼。
R2. 設定 JSP 表頭:
<%@ page language=”java” contentType=”text/html; charset=UTF-8″ pageEncoding=”UTF-8″%>R3. html meta:
<meta http-equiv=”Content-Type” content=”text/html; charset=UTF-8″>以上三個一定要指定同一編碼,確定之後接下來四種方法只要選一種來做就可以了:
-
勤勞工人法:
在每個 JSP 頁面及每個 Servelt 中設定
request.setCharacterEncoding("UTF-8"); response.setCharacterEncoding("UTF-8");
-
源頭搞定法:
使用 tomcat 預設過濾器 (在 Tomcat安裝目錄/conf/ web.xml 中解開註解)
<filter> <filter-name>setCharacterEncodingFilter</filter-name> <filter-class>org.apache.catalina.filters.SetCharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <async-supported>true</async-supported> </filter> <filter-mapping> <filter-name>setCharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
-
自我肯定法:
自定義過濾器
CharacterEncodingFilter.javapackage com.hans.filter; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; public class CharacterEncodingFilter implements Filter { private String characterEncoding; @Override public void init(FilterConfig config) throws ServletException { characterEncoding = config.getInitParameter("encoding"); } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { request.setCharacterEncoding(characterEncoding); response.setCharacterEncoding(characterEncoding); chain.doFilter(request, response); } @Override public void destroy() { characterEncoding = null; } }
web 下的 web.xml 加入對應
<filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>com.hans.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>utf-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
-
套件嵌用法:
使用 Spring 過濾器
<filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>utf-8</param-value> </init-param> <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
以上幾種方法可以挑選適用於自己的方法來用,勤勞工人法是比較累一點,每一頁都要記得檢查,不然就可能在表單傳遞的時候發生亂碼。
-
-
JNDI 錯誤
javax.servlet.ServletException: javax.servlet.jsp.JspException: Unable to get connection, DataSource invalid: "org.apache.tomcat.dbcp.dbcp.SQLNestedException: Cannot create JDBC driver of class '' for connect URL 'null'" javax.servlet.ServletException: org.apache.jasper.JasperException: javax.servlet.ServletException: javax.servlet.jsp.JspException: Unable to get connection, DataSource invalid: "org.apache.tomcat.dbcp.dbcp.SQLNestedException: Cannot create JDBC driver of class '' for connect URL 'null'"
明明設定上沒有什麼問題,卻發生以上 exception,設定檔如下(MySQL):
<Resource name="jdbc/TestDB" auth="Container" type="javax.sql.DataSource" maxActive="5" maxIdle="2" maxWait="60" username="your_account" password="your_password" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://your_domain:3306/your_database?characterEncoding=UTF-8"/>
不管設定在 server.xml 的 <GlobalNamingResources> 標籤中、設定在 <Host> 標籤下或是設定在 localhost/context.xml 下都會出現上面的錯誤,如果有遇到這樣問題的網友,試試看設定在 Tomcat安裝目錄/conf/context.xml 裡面就不會發生這個錯誤囉!如果用這個方法要把 mysql-connector-java-5.1.22-bin.jar 複製到 Tomcat安裝目錄/conf/ 資料夾下。
在 Spring 中加入上述 DataSource,可以供其他部份使用(透過 id 指定)
<!-- 吃 tomcat 內部設定的 jndi 不然就要自己設定 --> <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean"> <property name="jndiName" value="java:comp/env/jdbc/TestDB"></property> </bean>
-
Struts 標籤設定
前面提到書上的範例是寫
<%@ taglib uri="http://jakarta.apache.org/struts/tags-bean" prefix="bean" %> <%@ taglib uri="http://jakarta.apache.org/struts/tags-html" prefix="html" %>
Eclipse 頻頻出現錯誤訊息,後來才查到 1.3 版要改成以下才可以使用
<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %> <%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
-
struts-conf.xml 錯誤
如果使用 1.3 的表頭檔是沒辦法設定標籤的
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.3//EN" "http://struts.apache.org/dtds/struts-config_1_3.dtd">
要把它改成 1.2 版本的,並且要注意每個 tag 之間的順序,這邊出錯的時候 Eclipse 會列出順序,照著排就可以了。
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.2//EN" "http://struts.apache.org/dtds/struts-config_1_2.dtd">
-
Action 中使用 getDataSource 錯誤
書上的範例以及網路上查到的資料都說在 Struts Action 中,可以透過 getDataSource(request).getConnection(); 的方式來取得連接池的 Connection,實際上試了之後才會發現 1.3 根本就沒有 getDataSource 這個方法,繞了好久才找到必須透過以下方式取得剛剛設定在 context.xml 中的 datasource。
DataSource ds = (DataSource)new InitialContext().lookup("java:comp/env/jdbc/TestDB"); Connection conn = ds.getConnection();
-
Spring, Struts 接合
接著設定 struts-config.xml 加入 <controller> 及 <plug-in> 標籤,這邊家玩如果有 ClassNotFoundException 一樣參考這篇文章第 2 點說明,Eclipse 有報錯要注意 tag 間的順序。
<controller processorClass="org.springframework.web.struts.DelegatingRequestProcessor"></controller> <plug-in className="org.springframework.web.struts.ContextLoaderPlugIn"> <set-property value="/WEB-INF/beans-conf.xml" property="contextConfigLocation"/> </plug-in>
原本 struts-config.xml 中的 action 設定如下
<action-mappings> <!-- 這種是預設到特定頁面的,為了隱藏 jsp --> <action path="/index" type="org.apache.struts.actions.ForwardAction" parameter="/WEB-INF/pages/index.jsp"></action> <!-- 接合 Spring 後的寫法,注意 action path (struts) 要跟 bean name (spring) 一致--> <action path="/hello2"> <forward name="helloUser" path="/WEB-INF/pages/footer.jsp"></forward> </action> </action-mappings>
Spring 設定 beans-conf.xml 如下 (範例參考自良葛格學習筆記,userChecker 及 HelloAction 請參考 良葛格學習筆記)
<bean id="userChecker" class="com.hans.pojo.UserChecker"></bean> <!-- bean name 要跟 struts 裡面設定的 action path 一致 --> <bean name="/hello2" class="com.hans.struts.action.HelloAction2"> <property name="userChecker" ref="userChecker" /> </bean>
- Hibernate – getHibernateTemplate().find() 錯誤
小蛙讓 MemberDao 繼承 HibernateDaoSupport 操作資料庫上比較方便,但透過 HibernateTemplate().find() 查找資料的時候(程式碼如下)List<Member> list = this.getHibernateTemplate().find("from Member member"); if(list.size() > 0) return list.get(0);
出現以下錯誤
javax.servlet.ServletException: org.springframework.orm.hibernate3.HibernateQueryException: unexpected token: member near line 1, column 29 [from com.hans.entity.Member member]; nested exception is org.hibernate.hql.ast.QuerySyntaxException: unexpected token: member near line 1, column 29 [from com.hans.entity.Member member]
把 from Member member 改成 from member,出現下面錯誤
javax.servlet.ServletException: org.springframework.orm.hibernate3.HibernateQueryException: unexpected token: member near line 1, column 6 [from member]; nested exception is org.hibernate.hql.ast.QuerySyntaxException: unexpected token: member near line 1, column 6 [from member]
改成 from Member 之後才可正常執行,後來在這篇文章看到原來 … member 是保留字 … 難怪怎麼試都會錯,還以為自己哪裡有問題。
參考資料:
- Struts+Spring+Hibernate项目框架构建中的问题及解决方法集锦(1) @ Morecans的专栏
http://blog.csdn.net/morecans/article/details/1686416 - Spring Gossip: 在 Struts 中整合 Spring @ 良葛格學習筆記
http://caterpillar.onlyfun.net/Gossip/SpringGossip/StrutsSpring.html - Hibernate 查詢數據時報錯,請問這是什麽原因呢?急死了! @ JWorld@TW
http://www.javaworld.com.tw/jute/post/view?bid=41&id=171839