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

2013年10月3日 星期四

Spring 參考書籍

Spring framework 用博大精深來形容應不為過。

我在學習 Spring 時,參考了滿多相關文件、書籍,以下列出我的學習心得,希望能有助 Spring framework 的同好。


*官方文件
這不是廢話,真的。
Spring 的官方文件寫得很不錯,看完後可以馬上上手,尤其是Spring 更新滿快的,某些新功能的資料可能只有官方文件才有。

有 Spring rference 2.5 中文版,雖然舊了一點,但對看中文比英文快的人來說,不失為快速上手的一條捷徑。


*Spring in Action
初見此書的時候,被其廣度嚇到了,寫這樣的一本書,到底要花多少時間呢?

這本書的好處是,前幾章基本介紹看完後,後面的章節可以挑有需要看的,不需要要全部節章都看過一遍。

文筆略閒枯燥,但技術參考書籍嘛,這不算什麼大缺點。

此書做為官方文件的補充資料很適合,我在學習的時候,好幾次遇到官方文件沒寫的,在此書上可找到;有時候官方文件有的,在此書上卻沒看到。
真不知道是有意還是巧合。


此書有簡中版本,雖然通常慢英文版一個版次,但還是那句老話,對看中文比英文快的人,是一大福音。
我只看過簡中第2版,翻得還行,第3版等入手後再補充。


*SPRING揭秘
中國人寫的,看內容可以想見作者在 spring 上花了很多功夫且是通過實戰考驗的。

可惜的是此書以spring 2為主,內容稍舊。
最大的缺點是,它絕版了。
若有機會入手的話,是一本滿不錯的參考書。


以下是不推的,原因就不多說。

*Spring Live
*Spring Recipes




2011年9月28日 星期三

Spring MVC 的怪事一椿

今天遇到怪事一椿, 其實已經困擾我一陣子了, 只是今天才發現原因所在.

Spring MVC 的 @RequestMapping 註解可用來標示 Url, 例如:


@RequestMapping(value={"index"}, method=RequestMethod.POST)
public ModelAndView index(HttpSession session) {
    ...
}


如果同時有二個相同的註解, spring 會報錯, 訊息如下:

2318 [main] ERROR org.springframework.web.context.ContextLoader - Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping#0': Initialization of bean failed; nested exception is java.lang.IllegalStateException: Cannot map handler 'xxxxController' to URL path [/index]: There is already handler of type [class yyyyController$$EnhancerByCGLIB$$349da4f8] mapped.
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:527)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:295)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:580)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:900)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:455)
at org.springframework.web.context.ContextLoader.createWebApplicationContext(ContextLoader.java:294)
at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:215)
at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:47)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4206)
at org.apache.catalina.core.StandardContext.start(StandardContext.java:4705)
at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1057)
at org.apache.catalina.core.StandardHost.start(StandardHost.java:840)
at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1057)
at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:463)
at org.apache.catalina.core.StandardService.start(StandardService.java:525)
at org.apache.catalina.core.StandardServer.start(StandardServer.java:754)
at org.apache.catalina.startup.Catalina.start(Catalina.java:595)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:289)
at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:414)


但有一個例外, 就是 / , 一般看到網站的 / 會參考 tomcat 的 web.xml中 welcome-file 的設定.

若是下面的寫法, spring 不會報錯, welcome-file也不會生效, 但會連到那個 URL 就不知道了...


@RequestMapping(value={"/", "index"})
public ModelAndView index(HttpSession session) {
...
}


@RequestMapping(value={"/", "login"})
public ModelAndView login(HttpSession session) {
...
}

2011年9月5日 星期一

tomcat jsessionid url problem

Spring MVC 可以 cache static content, 例如圖檔, js, css...

參考文件

但我之前遇到一個問題, 就是原本應顯示為 /appbased/static-1.0.0/images/xxx 的 URL

在第一次執行時, URL 卻會變成 /appbased/static-1.0.0?jsessionid=481AFDE46F818357ED2096824F250AFF/images/xxx

需重新 reload 一次才回復正常.

當時我的作法是, 在首次登入頁面的 jsp 前面加一行
<% request.getSession(true).invalidate(); %>
即可.


但最近又遇到另一個問題, 就是首頁有可能是登入狀態, 也有可能是未登入狀態, 總不能老是把 session 抓出來幹掉裝作沒事, 故查了一下解法.

2011年8月8日 星期一

Spring internationalization (i18n) 學習筆記

Spring 提供了下列幾種 MessageSource 給 i18n 用.
StaticMessageSource
ResourceBundleMessageSource
ReloadableResourceBundleMessageSource

使用及設定上3者都差不多, ReloadableResourceBundleMessageSource 的設定檔不需要放在 classpath 內, 且可以指定 cache, 故我選擇它實作.


實作環境Spring 3.1.0M1

2011年7月22日 星期五

Spring Transcation 學習筆記

參考來源: Transaction Management


* 使用預設的Proxy mode時, @Transactional 只能用在 public method 上. 除非改用 AspectJ mode.

* Spring 不建議 @Transactional 用於 interface 上. (除非你使用 interface-based proxy )


* 預設只有在發生 Unchecked Exception 時才會自動 rollback, 可以指定Exception來Rollback.
ex @Transactional(rollbackFor=Exception.class)


* TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); 可以手動rollback


* eclipse 似乎無法 auto import Annotation 中的變數, 當使用 Propagation 時會出現 Propagation cannot be resolved to a variable 的錯誤, 手動 import org.springframework.transaction.annotation.Propagation; 即可.

2011年6月20日 星期一

Spring + Proxool 注意

今天把 tomcat 6 的 jdk 從 1.5 換成 1.6 後, 怪事發生了.
一直出現 java.sql.SQLException: org.logicalcobwebs.proxool.ProxoolException: Attempt to refer to a unregistered pool by its alias 'proxool_pool'

這問題之前遇過, 是因為 web.xml 中 servlet load-on-startup 順序沒設定好造成的.
<servlet>
<servlet-name>proxoolServletConfigurator</servlet-name>
<servlet-class>org.logicalcobwebs.proxool.configuration.ServletConfigurator</servlet-class>
<init-param>
    <param-name>xmlFile</param-name>
    <param-value>WEB-INF/config/proxool.xml</param-value>
</init-param>
<load-on-startup>0</load-on-startup>
</servlet>

怎麼只換了個 jdk 又沒改 xml 卻又發生了?

2011年6月15日 星期三

如何在新增資料後取得自動遞增的主鍵值? How to retrieve the auto-generated database key

自動遞增(ex: mysql 的 auto increment)的主鍵(Primary key)值, 如何在新增(insert)一筆資料後, 取得剛新增的資料鍵值呢?

Spring 的 NamedParameterJdbcTemplate 的 int update(String sql, SqlParameterSource paramSource, KeyHolder generatedKeyHolder) , 可於新增後取得鍵值.

這裡有範例.


2011年6月10日 星期五

Spring 3 + 檔案下載 (file download / export file)

網路上看到的文件都是在講怎麼處理 pdf or excel 的檔案,
但如果是要給使用者下載 jpg or txt 檔該怎麼做呢?

今天試了一下, 其實還滿簡單的. 繼承 AbstractView 即可.
下面是示範的程式碼:

2011年6月9日 星期四

Spring + Json

為了使用Json, 今天在spring xml 加入下面的設定,

<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
    <property name="mediaTypes">
        <map>
            <entry key="json" value="application/json" />
            <entry key="xml" value="text/xml" />
            <entry key="htm" value="text/html" />
            <entry key="html" value="text/html" />
        </map>
    </property>
    <property name="defaultContentType" value="text/html" />
    <property name="viewResolvers">
        <list>
            <bean class="org.springframework.web.servlet.view.BeanNameViewResolver"/>
            <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
                <property name="requestContextAttribute"><value>rc</value></property>
                <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
                <property name="prefix" value="/WEB-INF/jsp/"/>
                <property name="suffix" value=".jsp"/>
            </bean>
        </list>
    </property>
    <property name="defaultViews">
        <list>
            <bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />
        </list>
    </property>
    <property name="ignoreAcceptHeader" value="true" />
</bean>


卻出現 exception 如下
Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.web.servlet.view.ContentNegotiatingViewResolver#0' defined in ServletContext resource [/WEB-INF/config/webmvc-config.xml]: Cannot create inner bean 'org.springframework.web.servlet.view.json.MappingJacksonJsonView#17b0998' of type [org.springframework.web.servlet.view.json.MappingJacksonJsonView] while setting bean property 'defaultViews' with key [0]; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.web.servlet.view.json.MappingJacksonJsonView#17b0998' defined in ServletContext resource [/WEB-INF/config/webmvc-config.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [org.springframework.web.servlet.view.json.MappingJacksonJsonView]: Constructor threw exception; nested exception is java.lang.NoClassDefFoundError: org/codehaus/jackson/map/ObjectMapper
...
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.web.servlet.view.json.MappingJacksonJsonView#17b0998' defined in ServletContext resource [/WEB-INF/config/webmvc-config.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [org.springframework.web.servlet.view.json.MappingJacksonJsonView]: Constructor threw exception; nested exception is java.lang.NoClassDefFoundError: org/codehaus/jackson/map/ObjectMapper


是因為少了Jackson Library的關係, 可按此下載


Json 簡單的範例如下:
Java Code
@RequestMapping(value={"JsonTester"})
@ResponseBody
public ObjectNode jsonTester() {
    ObjectNode rootNode = new ObjectMapper().createObjectNode();
    rootNode.put("result", true);


    return rootNode ;
}

html code(via jQuery)
$(document).ready(function() {
    $.post("JsonTester.json",function(data) {
        if (data.result) {
           alert("成功");
        } else {
            alert("失敗");
       }
    });
});


@ResponseBody會依據收到的的 Accept Header 自動將回傳物件轉為客戶端可接受的型態.
此例會將 Java 物件轉為 Json 物件.

Spring 內建了數種轉換物件, 詳情可參考 Spring 說明文件


以下為回傳HashMap的範例:

Java Code:
@RequestMapping(value={"GetMap"})
@ResponseBody
public ObjectNode getMap(String inputValue) {
ObjectNode rootNode = new ObjectMapper().createObjectNode();


HashMap<String, String> result = myService.getMap(inputValue);
rootNode.put("result", true);
rootNode.putPOJO("myMap", result);


return rootNode ;
}



html code (via jQuery):
$.getJSON("GetMap.json", {inputValue: variable }, function(data) {
        if (data.result) {
            $.each(data.myMap, function(key, value){
                alert(key + "-" + value) ;
            });
        } else {
            alert("Get Map failed");
        }
})



ContentNegotiatingViewResolver 會依據
1. URL 的結尾(extension)

2. Accept header

3. 以上都沒有辦法判斷的話, 使用 defaultContentType

來判斷 request 的要求是那一種型態.



2011年5月25日 星期三

Spring 3 SimpleJdbcDaoSupport

網路上似乎沒看到用Annotation 又 extends SimpleJdbcDaoSupport的, 花了我一個下午的時間測試.

Spring 3 中如果要用DaoSupport的類別, 二種作法如下:
(奇怪的是, Spring Framework Reference Documentation完全沒提DaoSupport)

Annotation的作法如下:

2011年5月21日 星期六

Spring 3 Form 的處理

在 Spring 3 中, html Form 的傳接值可以使用下面幾種方式處理.


2011年5月19日 星期四

Spring + GWT 學習筆記

第一次嘗試 Spring MVC程式, 在動手前已先看完 Spring in Action 2nd 以及 Spring in Action 3rd (Early access edition).

但啟動過程中卻不順利, 在此紀錄一下遇到的問題及解決方法.

Environment:
Windows 7 32bit
JDK 1.5.0.22
Tomcat 6.0.32
Spring 3.1.0.M1 (w/ webflow 2.3.0)
GWT 2.3.0