SSH 專案過程中遇到的問題和解決方法彙總 struts2 spring hibernate

weixin_34402090發表於2011-07-28

問題:struts如何傳遞資料到jsp?
答案:
Struts的action傳參給jsp:可以用傳統的在request/session中加入引數的方法
也可以:
    <s:set name="userList" value="persons"></s:set> (persons是action的變數,需要有getPersons())
    <s:property value="persons"/>
也相當於用傳統的jsp嵌入java的寫法:
    <%=request.getAttribute("persons") %>
如果比較邏輯比較複雜的時候,如果不熟悉struts,建議後最後這種傳統方法

Struts2獲取response和request
HttpServletRequest request = ServletActionContext.getRequest();

HttpServletResponse response = ServletActionContext.getResponse();

HttpSession session = request.getSession();

  如果你只是想訪問session的屬性(Attribute),你也可以通過ActionContext.getContext().getSession()獲取或新增session範圍(Scoped)的物件



在action中返回下載流或者json:
如果單獨返回,不用配置的返回的話,就需要手工配置返回的字元編碼
action函式執行完不要返回任何東西,但需要先操作response
response.reset();
response.setContentType("application/x-msdownload;charset=utf-8");    response.setHeader("Content-disposition", "attachment; filename="+ "table.xls");        try {
            excelWriter.export();            
System.out.println(" 匯出Excel檔案[成功] ");
        } catch (IOException ex) {
            System.out.println(" 匯出Excel檔案[失敗] ");
            ex.printStackTrace();
        }
        response.getOutputStream().flush();


Hibernate:
1.由於沒有配置openSessionInView(一個request過程中用一個Hibernate的session),現在需要每次查詢都開啟一次session。這樣的好處是減低資料庫連線池的消耗,另外不會出一些難以理解的問題。
所 以,例如選擇了class(班級) a,然後a裡邊有一個studentList。student是class的1對多,多的那端。這個studentList.get(0).id是有的, 但其他資訊都為null。也就是說,如果需要student資訊,需要利用id再查詢student。

問題:下拉選單怎麼多個聯動?

回答:
1.可以全部一次獲取到前臺
2.可以下拉一個之後,就submit到同一個jsp,重新整理頁面(但如果jsp有原來struts的action傳來的收據的話,這種做法就行不通了)
3.ajax~~

建議使用第一種:
參考:http://zhidao.baidu.com/question/161625934.html

問題:struts2如何返回錯誤資訊到提交請求的頁面?
答案:在result中配置一個name為input的跳轉,然後處理請求的函式返回“input”,返回前需要把錯誤資訊放到session中,然後jsp獲取出來顯示

這樣會有問題,也就是原來那個jsp的頁面狀態儲存不了(例如下拉框選擇了什麼,分頁顯示到第幾頁)。
這沒辦法的~~需要我們自己另外把頁面的狀態儲存起來。

問題:怎麼上傳excel的時候做到不重新整理本頁面,就等待返回成功或者錯誤的彈出框?

答案:在form中設定target屬性,指向一個 隱藏的iframe,表示返回的內容在哪裡顯示。可以參考filemanager的fileManager.html。然後action處理完不要轉到 jsp,只需要返回“alert('xxxxxx')"或者自定義函式,使得在iframe中控制父頁面執行某些動作。
我做檔案管理器就是這樣做的。

<form id="uploadFileForm" target="hiddenFrame" method="post" enctype="multipart/form-data">
                            <input id="fileInput" type="file" name="upload" >
                            <input id="hiddenDirectory" type="hidden" value="" name="directory">
                            <input type="button" id ="uploadButton" value="開始上傳"/>
                        </form>

問題:jsp頁面怎麼在提交之後,繼續保持狀態?例如當前是第幾頁,下拉框選擇了什麼?

答案:沒有像asp.net這麼簡單的做法,只能 根據原理去做。提交的時候,把頁碼,下拉框之類的都post過去。第一個action處理完之後,帶著request引數轉到另外一個action。在第 二個action中獲取相應的引數(這時還是繼續有struts自動封裝的效果)。
(見陽江專案)

問題:struts2如何批量刪除?

答案:這個跟普通的jsp+Servlet做法類似。定義checkbox,name都統一為例如select。普通Servlet做法就是,request.getParameterValues("select"),獲取String[]。
action中定義String[] select陣列(或者其他型別)。struts2自動裝配進去。

例如:
<form action="testPerson.action" method="post">
            <input type="checkbox" name="select" value="1">
            <input type="checkbox" name="select" value="2">
            <input type="checkbox" name="select" value="3">
            <input type="checkbox" name="select" value="4">
            <input type='submit' value="Submit" />
        </form>
在前臺,例如我只選中了1,4兩個框。
那麼在後臺獲取的String[],則只有“1”和“4”

問題:怎麼直接new新建一個DAO或者Service進行測試?

答案:通過Spring,獲取配置檔案中的Bean。這些bean將會在ApplicationContext.xml載入的時候初始化。

        ApplicationContext ac = new FileSystemXmlApplicationContext("classpath:applicationContext.xml");
        PersonDAO personDAO = (PersonDAO) ac.getBean("personDAO");
      System.out.println(personDAO.getEntityName());

問題:在XXXXList頁面,點選修改,跳轉到修改頁面,修改之後,如何返回XXXList頁面,同時保持原來的狀態(頁碼)?

回答:使用彈出視窗。XXXXList頁面使用以下程式碼:
<script>
function refresh(){
    XXXXform.submit();   //使用post的方式重新整理
}
function newWin(){
window.open('newWin.htm');
}
</script>

新開的頁面,儲存/關閉的時候,呼叫:
function closeme(){
window.opener.refresh();

//以下程式碼是為了避免瀏覽器提問是否關閉
var browserName=navigator.appName;
if (browserName=="Netscape") {
window.open('','_parent','');
window.close();
} else if (browserName=="Microsoft Internet Explorer") {
window.opener = "whocares";
window.close();
} }

如果沒必要保持狀態的修改,例如使用者列表,聯絡人列表,就直接同一個視窗內跳轉就可以了。

問題:java.io.CharConversionException: Not an ISO 8859-1 character: XXX

回答:這個問題可能是因為outputstream輸出中文字造成的影響。

response.setContentType("text/html;charset=UTF-8");
//response.getOutputStream().print("中文字"); //這行會出錯
response.getWriter().print("中文字"); //換成這個就好了
response.getWriter().close();

原因我個人覺得是因為outputstream是以位元組為單位輸出字串的,需要符合那個ISO 8859-1編碼;但要輸出的字串是UTF8編碼的,所以就有問題。但根源問題,我真沒想通。

換成Writer就好了。可能是因為那個inputstream和reader,outputstream和Writer的區別吧。


問題:使用struts2,如何處理action的路徑?還有,在action轉到的jsp中,如何寫js,css,圖片的路徑?(例如訪問http://localhost/project/listUser.action後轉到http://localhost/project/user/listUser.jsp,這時候瀏覽器還是停留在http://localhost/project/addUser.action

答:action的話,就不需要關心路徑問題。我們不使用action的名稱空間。因為使用了這樣的匹配:
    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>*.action</url-pattern>
    </filter-mapping>
無論前邊是什麼路徑,struts2只看後邊的匹配。

而解決jsp的路徑問題,以下方式就基本完美了:
第一步:在jsp的head中新增base標籤和一段java
<%
    String path = request.getContextPath();
    String basePath = request.getScheme() + "://"
            + request.getServerName() + ":" + request.getServerPort()
            + path + "/";
%>
<base href="<%=basePath%>">

第二步:所有的路徑使用“半絕對路徑”。所謂半絕對路徑,是我亂說的。例如:<link rel="stylesheet" type="text/css" href="style/table.css" />
這種本來是相對路徑,就是當前jsp目錄下的style目錄的table.css。
在我們struts2和配置了base的前提下,這裡就會被瀏覽器解釋為http://localhost/project/style/table.css
也就是說,需要寫從專案根目錄算起的絕對路徑,但去掉開頭的"/"

第三步:所有action跳轉,form提交寫的action路徑,都不要帶目錄位置。只寫action名,例如addUser.action。

這樣,瀏覽器就一直停留在http://localhost/project/XXXXX.action  這一層。

第一步:在jsp的head中同樣新增base,但把getContextPath改為getRequestURI
d
<%
    String path = request.getRequestURI();
    String basePath = request.getScheme() + "://"
            + request.getServerName() + ":" + request.getServerPort()
            + path;
%>
<base href="<%=basePath%>">
注意是request.getRequestURI,這樣獲取出來的正好就是jsp的絕對路徑。
例如瀏覽器位址列是:http://localhost:8084/project/listUser.action
base是<base href="http://localhost:8084/project/admin/listUser.jsp">

第二步:jsp頁面內,全部使用相對路徑訪問。

第三步,就不必管action的路徑如何了。

這個方法,可以相容使用action和不使用action兩種情況
問題:如何使用多個Struts和Spring配置檔案?

回答:有不少方法,但我喜歡在主配置檔案中import其他子檔案。
Spring:在檔案最後</beans>前,加入include。例如
    <import resource="wenhui-springConfig.xml"></import>
    <import resource="xiangpeng-springConfig.xml"></import>
    <import resource="mingyi-springConfig.xml"></import>
    <import resource="haichuan-springConfig.xml"></import>
</beans>
然後子檔案寫法跟主配置檔案一致,從beans節點開始,裡邊全部是bean

Struts:在檔案最後</struts>前,include其他檔案。例如
<include file="struts_wenhui.xml"></include>
    <include file="struts_xiangpeng.xml"></include>
    <include file="struts_mingyi.xml"></include>
    <include file="struts_haichuan.xml"></include>
</struts>
然後子檔案寫法跟主配置檔案一致,從<struts>開始,然後是<package>。需要注意的是每個檔案的package的name屬性要不相同

問題:資料庫沒有設定級聯刪除,Hibernate刪除“一那方”的時候,會不會刪除“多的那方”?

答案:如果按預設配置是不會的。需要在hbm檔案中配置cascade規則。
參考:http://www.blogjava.net/zhyiwww/archive/2006/04/06/39576.html
但這樣其實也不方便,還不如直接到資料庫裡邊設定級聯刪除。
所以我們做法是:Hibernate裡就不設定級聯的配置,基本一旦有外來鍵就無法刪除,需要手工去刪除多的一方(這樣一般來說也符合業務要求)。如果真需要(例如刪除使用者,就刪除UserToRole和LoginLog),所以就到資料庫設定級聯刪除。

問題:spring啟動的執行緒,或者普通的java類中怎麼獲取web目錄?例如刪除臨時檔案的執行緒類中。

答案:

在web.xml中的<web-app>節點內加入:

<context-param>
<param-name>webAppRootKey</param-name>
<param-value>tansungWeb.root</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.util.WebAppRootListener</listener-class>
</listener>

然後在普通類中,使用
System.getProperty("tansungWeb.root")獲取了web根目錄。
然後再拼湊路徑的時候,最好不要直接使用/或者\,最好使用File.separatorChar

相關文章