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

2015-06-09

為什麼 LocalSessionFactoryBean 回傳的是 SessionFactoryImpl?

我習慣使用 org.hibernate.tool.hbm2ddl.SchemaExport 來產出 SQL。
Configuration cfg = new Configuration();
cfg.configure(); // 預設讀取 hibernate.cfg.xml
SchemaExport export = new SchemaExport(cfg);
export.setOutputFile("src/main/database/all.sql");
export.setDelimiter(";");
export.setFormat(true);
export.create(true, false);
但這種作法有一個前提,就是要有 hibernate.cfg.xml,可是隨著 Spring 的不斷滲透,hibernate.cfg.xml 慢慢的已經不見了,其設定值都進到 Spring XML 設定檔裡了。

之前為了產出 SQL,還特地為此建立 hibernate.cfg.xml,但這又會造成與 Spring XML 不同步的困擾。

2014-02-10

@SessionAttributes 遇到多頁籤使用時,有很大的問題(Multiple Forms in One session)

Spring MVC 引入 Annotaion 時,將原本的 Controller 與 FormController 二合一,變成一隻 Controller 處理一個 Domain 的所有 Web request。

初期不習慣,久了也慢慢覺的好用,直到有一天,資料庫裡的資料暴走了,久思不得其解,最後 PM  點出,問題在使用者同時開啟多個頁籤編輯。

以前的 FormController 的作法是:
  • GET request進來,用 uid 到資料庫取 model 資料,然後再準備一些表單需要用到的資料,再將這些資料全部放到request裡。
  • 回到 JSP 後,從request裡取出資料顯示。
  • 使用者 submit 後,POST request進來,再用 uid 到資料庫取 model 資料,然後進行 data binding 與 validation,最後存到資料庫。
當初 FormController 也可以將 model 存在session中,但直覺怪怪的,所以並未使用過。

Annotation 以後的作法是:
  • GET request進來,用 uid 到資料庫取 model 資料,然後再準備一些表單需要用到的資料,再將這些資料全部放到request裡,另外將 model 資料放到session裡。
  • 回到 JSP 後,從request裡取出資料顯示。
  • 使用者 submit 後,POST request進來,直接到session裡取出 model 資料,然後進行 data binding 與 validation,最後存到資料庫。
問題就發生在POST reqeust進來後是到session取 model 資料,這在同時開啟多個頁籤時,必定爆炸。

2013-11-30

從 Spring + Hibernate 到 Spring Data JPA

抱著 Spring + Hibernate 的架構好長一段時間了,最近發現一個有趣的東西,Spring Data JPA,目前穩定版本是 1.4.2。

Duplicated code!!!

我的 Spring + Hibernate 的標準作法。

UserDao.java
public interface UserDao {

  User get(int uid);

  User getByAccount(String account);

  void add(User cmd);

  void update(User cmd);

  void delete(User cmd);

  List<User> list(UserQueryVO queryVO, int start, int pageSize);

  int count(UserQueryVO queryVO);
}

2013-03-22

Schedule in Spring 3.2.0 - 參數化

從前兩文 Schedule in Spring 3.1.2 與 Schedule in Spring 3.2.0 - Continued 一直逃避一個問題,就是 fixedRate 與 fixedDelay 只接受 long 型別的資料,不像 cron 接受字串。

以前是這麼用的。
@Scheduled(fixedRate = 10000)
@Scheduled(fixedDelay = 5000)
@Scheduled(cron = "*/3 50-55 9,10 26 * ?")
這有什麼問題呢?問題發生在「參數化」。

Schedule in Spring 3.2.0 - Continued

從前文 Schedule in Spring 3.1.2 來到 Spring 3.2.0.RELEASE,也許我之前沒搞清楚,也許是方法改了,我相信前者可能性較大。

Spring 設定檔修改如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:context="http://www.springframework.org/schema/context" xmlns:task="http://www.springframework.org/schema/task"
  xsi:schemaLocation="
    http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/context 
    http://www.springframework.org/schema/context/spring-context-3.0.xsd
    http://www.springframework.org/schema/task
    http://www.springframework.org/schema/task/spring-task-3.0.xsd">

  <context:component-scan base-package="ja.neil.model,ja.neil.service,ja.neil.dao" />

  <context:property-placeholder location="classpath:/neil.properties" />

  <task:annotation-driven executor="webExecutor" />
  <task:executor id="webExecutor" pool-size="5" /><!-- @Async -->
  <task:scheduler id="myScheduler" pool-size="10" /><!-- @Scheduled -->
</beans>
@Scheduled 與 @Async 的用法同 Schedule in Spring 3.1.2。
差別在於,不用在 XML 定義 scheduledTask,另外可以自訂 executor 與 scheduler,而且知道 executor 負責 @Async,scheduler 負責 @Scheduled。

2013-01-25

遇到錯誤 Configuration problem: Unable to locate Spring NamespaceHandler for XML schema namespace...

之前的 Maven 筆記 怎麼將 Source Code 與 Dependency Library 包成一個 Jar 檔?在今天遇到錯誤。

起因於我用了 Spring,然後包 jar 沒問題,都有包進去,但是執行時出錯。
Exception in thread "main" org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Unable to locate Spring NamespaceHandler for XML schema namespace [http://www.springframework.org/schema/context] Offending resource: class path resource [spring-app.xml]

說是找不到 NamespaceHandler,這是什麼鬼東西啊。

我在 Eclipse 裡執行都沒問題啊,包成 jar 來執行就丟出這個錯誤來。

抓破頭皮後終於找到解答。

2012-11-09

在 Spring MVC 3.1.2.RELEASE 與 Hibernate 4.1.7.Final 實作變動數量的值物件(Variable Component)

值物件?以前在 Hibernate 叫做 Component,現在 JPA 叫做 Embeddable,或者從 Annotation 的角度叫做 Element。

簡單講就是沒有 Primary Key(PK) 的資料,必須依附在有 PK 的資料下。

舉例來說,每個人(Person)有好幾種地址(Address),住家地址、公司地址、戶籍地與出生地等等,這些地址資料只對一個人有意義,脫離這個人就沒有存在的必要,或者說不能與其他人共用,既然不能共用,那就沒必要有 PK,與這個人共存亡。

2012-10-30

在 Spring 3.1.2.RELEASE 使用多個資料庫的宣告式交易管理(Multiple Databases with Annotation-based Declarative Transaction Management)

一般的系統只會用到一個資料庫,Spring 引進宣告式交易管理後,設定變得很簡單。

Spring 設定檔。
<context:component-scan base-package="idv.neil.model,idv.neil.service,idv.neil.dao" />

<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
  <property name="configLocation" value="classpath:hibernate.cfg.xml" />
</bean>

<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
  <property name="sessionFactory" ref="sessionFactory" />
</bean>

<tx:annotation-driven />
先用 context:component-scan 告訴 Spring 所有的 Annotation 在哪些 package 裡。

然後建立 Hibernate SessionFactory,這是給 Dao 用的。

再建立 TransactionManager,這是給 Service 用的。

最後用 tx:annotation-driven 將全部串起來。

2012-08-21

建立 Google App Engine + Spring MVC + Tiles + Maven + Eclipse 專案

  • 建立專案
    • 使用 Eclipse -> New Web Application Project
      • 輸入 Project name 與 Package
      • 取消勾選 Use Google Web Toolkit
      • 確認勾選 Google App Engine

2012-08-01

mvc:resources in Spring MVC 3.1.2

Request 從 client side 進到 Server Web App 之後,會先到 web.xml 報到,由 <servlet-mapping /> 決定下一步,以前都是用 *.do 之類的 <url-pattern />,所以為檔名不為 do 的 request 都不會進到 Spring 的地盤,直接在 web.xml 就轉到 jpg、js 或 css 了。

但是如果想讓 Spring 控管這類靜態資源,或者讓下載動態產生的 pdf 或者 csv 時可以使用正確的副檔名(pdf 或 csv),就得將這些 request 也轉到 Spring 控管。

2012-07-26

Schedule in Spring 3.1.2

排程執行就是在背景執行,Spring 提供兩種背景執行的功能,第一種是排程(@Scheduled),第二種是丟了就跑(@Async),差別在於前者是系統啟動,後者是人工啟動。

先看主程式:

2012-02-21

為什麼透過 @InitBinder 設定的 Spring Validator 會驗證 Model 裡所有的物件?

事情的起點當然是一個 Exception:
java.lang.IllegalStateException: Invalid target for Validator [idv.neil.model.ProductValidator@5ddffa]: idv.neil.web.Pager@11ba4a2
    at org.springframework.validation.DataBinder.setValidator(DataBinder.java:498)
    at idv.neil.web.ctrl.ProductController.formBackingObject(ProductController.java:100)
    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 com.google.appengine.tools.development.agent.runtime.Runtime.invoke(Runtime.java:104)
Spring MVC 3 以後可以使用 Annotation 將 MultiActionController 與 SimpleFormController 做在同一隻 controller:

Spring MVC 3.1.0 的兩種 Validation 方式

JSR-303 Validator 與 Spring Validator。

先來看我覺得不好用的 JSR-303 Validator。

在 Spring MVC 裡設定 JSR-303 Validator

第一、要有 JSR-303 實做(Provider),目前知道是 Hibernate Validator,Maven 定義如下:

2011-03-07

Spring Validation 3.0.5

  • Spring 3 支援三種驗證方式:
    • DataBinder
      • 每一個需要驗證的 model class 都應該要有一個相對應的 valitator。
      • 對於 reference class 也應該要用獨立的 validator。
      • ValidationUtils 提供一些基本的驗證 method。

Spring MVC 3.0.5 之三

  • 兩種使用 JSP & JSTL 的方式:
    • ResourceBundleViewResolver - 可以混合多種 view。
      <!-- the ResourceBundleViewResolver -->
      <bean id="viewResolver" class="org.springframework.web.servlet.view.ResourceBundleViewResolver">
        <property name="basename" value="views"/>
      </bean>
      
      # And a sample properties file is uses (views.properties in WEB-INF/classes):
      welcome.(class)=org.springframework.web.servlet.view.JstlView
      welcome.url=/WEB-INF/jsp/welcome.jsp
      
      productList.(class)=org.springframework.web.servlet.view.JstlView
      productList.url=/WEB-INF/jsp/productlist.jsp
    • InternalResourceViewResolver
      <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <property name="suffix" value=".jsp"/>
      </bean>

2011-03-03

Spring MVC 3.0.5 之二

  • Handler mappings
    • Spring 2.5 以後 DispatcherServlet 預設使用 DefaultAnnotaionHandlerMapping 去找 @Controller 裡的 @RequestMapping,所以不用在 xml 裡定義 handler mapping 了。
    • DefaultAnnotaionHandlerMapping 有些屬性可以設定:
      • interceptors
      • defaultHandler - 找不到符合的 handler 時,設定預設的 handler。
      • order - 設定多筆 handler mapping 時使用。
      • alwaysUseFullPath - 假設 servlet 過濾的 url pattern 為 /abc/*,一個 request 的 url 為 /abc/def.do,若設為 true,則用 /abc/def.do 去找 handler,若設為 false,則用 /def.do 去找,預設為 false。
      • urlDecode - 預設為 true。
      • lazyInitHandlers - 用來將 singleton handler lazy init,預設為 false。
        <bean id="handlerMapping" class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
            <property name="interceptors">
                <bean class="example.MyInterceptor"/>
            </property>
        </bean>

2011-03-02

Spring MVC 3.0.5 之一

  • Spring MVC 主要流程為 DispatcherServlet 讀取可設定的 hander mapping,將 request 傳給 handler(controller),然後再透過 view resolution 產生 response,並支援 locale 與 theme resolution 以及檔案上傳。
  • @Controller 與 @RequestMapping 組成預設的 handler。
  • Spring 3.0 以後,新增 @PathVariable等功能用來建立 RESTful 與一般 web app。
  • Spring MVC 特色:
    • 使用 POJO 作為 form backing object,不用與 Spring 有任何關聯。
    • 在 data binding 時,將型別錯誤視為驗證錯誤,而非較嚴重且難處理的系統錯誤。
    • 在 business object 的自動型別與 form field 的字串型別之間是無痛轉換的。
    • Controller 可以直接寫到 response,也可以透過 ModelAndView 來利用 view resolutaion,並使用 map 來存放 form object 或 reference data。
    • 透過 @RequestParam、@RequestHeader、 @PathVariable 等 annotation,讓 controller method 的 signature 不受任何限制。
  • Spring 的一個特色就是 Open for extension, close for modification,意思就是「擴充很容易,但不能修改」。

2011-02-24

整合 Google App Engine 與 Spring

  • 變更 Maven 預設的 webapp 位置
    • 因為要在 Google App Engine(GAE)中加入 Maven,而 GAE 與 Maven 的預設目錄架構不同,所以要變更 Maven 預設的 webapp 位置到 GAE 預設的位置。
    • 修改 pom.xml 如下:
      <build>
       ...
       <plugins>
        <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-war-plugin</artifactId>
         <version>2.1.1</version>
         <configuration>
          <warSourceDirectory>war</warSourceDirectory>
         </configuration>
        </plugin>
       </plugins>
       ...
      </build>

2011-02-23

Spring IoC Container 3.0.5 之四 - JavaConfig

  • 兩大要角:@Configuration 和 @Bean,主要用來產生、設定、初始化 Spring bean。
  • 簡單範例:
    • JavaConfig 設定:
      @Configuration
      public class AppConfig {
        @Bean
        public MyService myService() {
            return new MyServiceImpl();
        }
      }
    • 等同於下面的 XML 設定:
      <beans>
        <bean id="myService" class="com.acme.services.MyServiceImpl"/>
      </beans>
  • 為了使用 JavaConfig,必須使用 Spring 3.0 新生的 AnnotationConfigApplicationContext,除了支援 JavaConfig,也支援 JSR-330 的 annotation。

2011-02-18

Spring IoC Container 3.0.5 之三 - Annotation

  • Annotation 與 XML 可以並存,而且 Annotation 先於 XML 執行,所以 XML 可以覆蓋 Annotation 的設定。
  • XML 的優點:
    • 設定集中在幾個檔案,方便管理。
    • Java class 是單純的 POJO,沒有和 Spring 綁在一起。
    • 可快速修改,不用重新編譯。
  • Annotaion 的優點:
    • 設定值貼近 Java class,一致性高。