Home > Springframework

Springframework Archive

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。
  • Comments (Close): -
  • TrackBack (Close): -

SpringFramework 3.0 で FreeMarkerを使う

バーボンです。SpringFramework2.5から3.0.0 RC1に乗り換えてFreeMarkerを使おうとするとExceptionが出ました。

pom.xml (参考)


	4.0.0
	spring-freemarker
	spring-freemarker
	0.0.1-SNAPSHOT

	
		
			com.springsource.repository.bundles.milestone
			SpringSource Enterprise Bundle Repository - SpringSource Bundle Milestones
			http://repository.springsource.com/maven/bundles/milestone   
		
		
			com.springsource.repository.bundles.external
			SpringSource Enterprise Bundle Repository - SpringSource Bundle Externals
			http://repository.springsource.com/maven/bundles/external
		
	

	
		
			org.springframework
			org.springframework.web.servlet
			3.0.0.RC1
		
		
			freemarker
			freemarker
			2.3.9
		
	

[CannotLoadBeanClassException]
nested exception is java.lang.NoClassDefFoundError: org/springframework/ui/freemarker/FreeMarkerConfigurationFactory

FreeMarkerConfirurationFactoryクラスがないのでロードできないということで、再度検索してみるとorg.springframework.context.support
こちらのパッケージに入っていました。Spring3はパッケージに入っているクラスが2.5のときから変更されていますので、注意が必要です。

pom.xml 追加

		
			org.springframework
			org.springframework.context.support
			3.0.0.RC1
		

また、Spring3.0.0ではFreeMarkerViewクラス内でfreemarker.ext.servlet.AllHttpScopesHashModelクラスをインポートしようとします。が、FreeMarker 2.3.9には入っていなかったので、バージョンを上げました。

表示されたエラー内容
[java.lang.IllegalAccessError]
tried to access method freemarker.ext.servlet.AllHttpScopesHashModel.(Lfreemarker/template/ObjectWrapper;Ljavax/servlet/ServletContext;Ljavax/servlet/http/HttpServletRequest;)V from class org.springframework.web.servlet.view.freemarker.FreeMarkerView

pom.xml FreeMarker部分修正

		
			org.freemarker
			freemarker
			2.3.15
		

これで設定完了できました。

スモールスタートなプロジェクトの設定(Spring Framework MVC 2.5)

バーボンです。 SpringMVCベースでシンプルなプロジェクトを立ち上げるというささやかな試みの備忘録です。 ほとんど設定ファイルの書き方に終始しています。

Spring MVCの流れ

参考:http://www.vaannila.com/spring/spring-mvc-tutorial-1.html

  1. DispatcherServletがリクエストを受け取る
  2. DispatcherServletがHandlerMappingを調べに行き、転送先のコントローラを決定し、呼び出す。
  3. コントローラがビジネスロジックを呼び出す
  4. ビジネスロジックを呼び出して「モデル」に結果をセットする
  5. モデルと、それを表示するビュー名をセットし、DispatcherServletに返す
  6. DispatcherServletがビュー名をViewResolverに送り、ビューを解決する
  7. モデルの結果を表示する

作業手順

  • pom.xmlの設定
  • web.xmlの設定
  • [servlet-name]-servlet.xmlの設定
  • applicationContext.xmlの設定
  • Controller作って画面に表示する

①pom.xmlの設定

Maven2のこちらの記事を参考にどうぞ
今回依存するjarを登録します。

  • spring-2.5.6.jar
  • spring-webmvc-2.5.6.jar
  • freemarker-2.3.9.jar(View用)

②web.xmlの設定

まずDispatcherServlet(コントローラサーブレット。コントローラのコントローラ)の設定をweb.xmlに記述します。

【web.xml】
<?xml version="1.0" encoding="UTF-8"?>
<web-app>
  <display-name>sample</display-name>
  <servlet>
    <servlet-name>dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>dispatcher</servlet-name>
    <url-pattern>/*</url-pattern>
  </servlet-mapping>  
</web-app>

定義されたDispatcherServletはリクエストを受け取った後、WEB-INF配下の"[servlet-name]-servlet.xml"という名前の付いたBean定義ファイルを探しに行きます。ここで、サーブレット名は「dispatcher」となっているので、次はWEB-INF配下に"dispatcher-servlet.xml"という設定ファイルを作成します。

③dispatcher-servlet.xmlの設定

【dispatcher-servlet.xml】
<?xml version="1.0" encoding="UTF-8"?>
<!-- configure bean file by using XML scheme -->
<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"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-2.0.xsd 
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-2.5.xsd">
    
</beans>

ここではBeanファイルで利用するスキーマを記述しています。 スキーマを追加するときは以下の形で追加します。 「xlmns:スキーマ名=スキーマ名の名前空間を表すURI
xsi:schemaLocation=スキーマを定義するxsdファイルのURI」

④applicationContext.xmlの設定

webアプリケーションの場合、メモリに難がない限り[servlet-name]-servlet.xml以外にapplicationContext(これもbean定義ファイル)の設定を書くことが推奨されています。ApplicationContextはDispatcherServletがデフォルトで実装している BeanFactoryを拡張したもので、BeanFactoryよりも多くの機能を持っています。
今回はContextLoaderを使ってApplicationContextを宣言的に生成します。

【web.xmlに追加】
  <listener>
    <listenerclass>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
   <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/applicationContext.xml</param-value>
  </context-param>

ContextLoaderListnerはBean定義ファイルを読み込みApplicationContextの具象クラスを生成してくれるリスナです。デフォルトでWEB-INF配下のapplicationContext.xmlを読み込みに行きますが、ファイルパスを変更したいときなどはcontext-param要素にContextConfigLocationを指定するとそのパスのファイルを読み込みます。

さて、せっかくバージョンが2.5なのでクラスを自動的にコンテナに登録してくれるアノテーションを使います。次にアノテーションを付記する設定を書きます。

【applicationContext.xml】
<?xml version="1.0" encoding="UTF-8"?>
<!-- configure bean file by using XML scheme -->
<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"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-2.0.xsd 
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-2.5.xsd">
    <context:component-scan base-package="sample" />
    <context:annotation-config />
</beans>

component-scan:component-scanの設定で、base-packageで指定したパッケージ以下にあるステレオタイプアノテーションを走査して自動的にコンテナに登録してもらえます。
使えるアノテーション:@Component,@Service,@Controller,エトセトラ
annotation-config:こちらもアノテーションを解釈します。
使えるアノテーション:@Autowired,@Required,@Qualifierなど

最後にお好みのViewResolverを設定します。以下はFreeMarkerを設定した時の例です。

【applicationContext.xmlに追加】
  <bean id="viewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
    <property name="viewClass" value="org.springframework.web.servlet.view.freemarker.FreeMarkerView" />
    <property name="exposeSpringMacroHelpers" value="true"/>
    <property name="contentType" value="text/html; charset=UTF-8"/>
    <property name="cache" value="true"/>
  </bean>  
  <bean id="freemarkerConfig" 
class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
    <property name="templateLoaderPaths" value="/WEB-INF/"/>
    <property name="defaultEncoding" value="SJIS"/>
    <property name="freemarkerSettings">
      <props>
        <prop key="auto_import">/spring.ftl as spring</prop>
        <prop key="locale">ja_JP</prop>
      </props>
    </property>
  </bean>

以上で設定ファイル記述は終わりです。

⑤Controller作ってViewに表示させてみる

【SampleController】
package sample;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/sample.html")
public class SampleController
{
  @RequestMapping
  public String edit(ModelMap model)
  {
    model.addAttribute("greeting", "Hello World");
    return "/sample.html";
  }
}
【sample.html】
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>test</title>
</head>
<body>
${greeting}
</body>
</html>

サーバURL/sample/sample.htmlにアクセスするとHello Worldが表示されます。以上です。

Spring Framework 3.0の新機能 Part3

take©です。 今回はSpring3.0の新機能の1つである、AbstractRssFeedViewを試してみました。 AbstractRssFeedViewを使用すると、簡単にRSSを配信することができます。
ニュースを配信するRSSを例に手順をメモします。

<手順>
  • pom.xmlの設定
  • web.xmlの設定
  • applicationContext.xmlの設定
  • RSSを配信するコントローラを用意
  • AbstractRssFeedViewを継承したNewsRssFeedViewを用意
  • 実行してみる

pom.xmlの設定

AbstractRssFeedViewはRSSの構築にROMEを使います。 ROMEはRSSとAtomフィードの解析や生成を行うためのライブラリです。 pom.xmlにROMEへの依存関係を記述します。 (ROMEについてはこちら
また、マイルストーン版であるSpring3.0はセントラルリポジトリに登録されていないので、Springのリポジトリ登録も行います。

<project>
	<modelVersion>4.0.0</modelVersion>
	<groupId>rss</groupId>
	<artifactId>rss</artifactId>
	<version>0.0.1-SNAPSHOT</version>

	<repositories>
		<repository>
			<id>com.springsource.repository.bundles.milestone</id>
			<name>SpringSource Enterprise Bundle Repository - SpringSource Bundle Milestones</name>
			<url>http://repository.springsource.com/maven/bundles/milestone</url>
		</repository>
		<repository>
			<id>com.springsource.repository.bundles.external</id>
			<name>SpringSource Enterprise Bundle Repository - SpringSource Bundle Externals</name>
			<url>http://repository.springsource.com/maven/bundles/external</url>
		</repository>
	</repositories>

	<dependencies>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>org.springframework.web.servlet</artifactId>
			<version>3.0.0.M4</version>
		</dependency>
		<dependency>
			<groupId>rome</groupId>
			<artifactId>rome</artifactId>
			<version>0.9</version>
		</dependency>
	</dependencies>
</project>

web.xmlの設定

web.xmlを記述します。 今回はクラスパスの直下にapplicationContext.xmlを配置してみました。

<?xml version="1.0" encoding="UTF-8"?>
<web-app>
	<display-name>rss</display-name>
	
	<servlet>
		<servlet-name>dispatcher</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>classpath:/applicationContext.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
	
	<servlet-mapping>
		<servlet-name>dispatcher</servlet-name>
		<url-pattern>/*</url-pattern>
	</servlet-mapping>
</web-app>

applicationContext.xmlの設定

今回はViewの解決にBeanNameViewResolverを使用します。

<?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:p="http://www.springframework.org/schema/p" 
	xmlns:context="http://www.springframework.org/schema/context"
	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">

    <context:component-scan base-package="sample"/>
	<bean class="org.springframework.web.servlet.view.BeanNameViewResolver"/>
</beans>

RSSを配信するコントローラを用意

ModelにNewsをセットします。戻り値はBeanNameViewResolverで解決できるBean名です。 (News.javaとNewsService.javaの記述は省略)

package sample;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class NewsFeedController {
	@Autowired
	private NewsService newsService;
	
	@RequestMapping("/news.rss")
	public String rss(Model model) {
		model.addAttribute("allNews", newsService.getAllNews());
		return "newsRssFeedView";
	}
}

AbstractRssFeedViewを継承したNewsRssFeedViewを用意

AbstractRssFeedViewを継承して以下の2つのメソッドを実装します。
#buildFeedItemsでは、Modelオブジェクトを介して、Newsリストを取得します。

  • #buildFeedMetadata
  • #buildFeedItems
package sample;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Component;
import org.springframework.web.servlet.view.feed.AbstractRssFeedView;

import com.sun.syndication.feed.rss.Channel;
import com.sun.syndication.feed.rss.Description;
import com.sun.syndication.feed.rss.Item;

@Component
public class NewsRssFeedView extends AbstractRssFeedView {
	@Override
	protected void buildFeedMetadata(
		Map<String, Object> model,
		Channel feed,
		HttpServletRequest request) {
		feed.setTitle("サンプルニュース");
		feed.setDescription("これはサンプルのニュースです。");
		feed.setLink("http://sample/");
	}
	
	@Override
	protected List<Item> buildFeedItems(
		Map<String, Object> model,
		HttpServletRequest request,
		HttpServletResponse response)
	throws Exception {
		List<News> allNews = (List<News>) model.get("allNews");
		List<Item> items = new ArrayList<Item>(allNews.size());
		for (News news : allNews) {
			Item item = new Item();
			item.setTitle(news.getTitle());
			item.setPubDate(news.getPublished());
			Description description = new Description();
			description.setType("text/html");
			description.setValue(news.getArticle());
			item.setDescription(description);
			items.add(item);
		}
		return items;
	}
}

実行してみる

http://localhost:8080/コンテキスト名/news.rss
右の画像はFirefoxで表示してみた結果です。ちゃんとRSS配信できてます。 Springはこういった他のプロジェクト(今回はROME)との連携が柔軟でいいですね。


以上です。
次回はContentNegotiatingViewResolverについてレポートしたいと思います。

Springでタイマー処理

take©です。定期的に処理を実行したい場合、Linuxであればcronが定番ですが、Javaで構築する場合、やっぱりプラットフォームに依存しない方法をとりたいものです。

Javaではタイマー処理を行うために以下のクラスが用意されています。

  • java.util.Timer
  • java.util.concurrent.ScheduledExecutorService

今回はSpringからjava.util.concurrent.ScheduledExecutorServiceを使って5秒ごとに「Hello!」を出力してみます。

HelloTask.java
package sample;

import java.util.concurrent.TimeUnit;
import org.springframework.scheduling.concurrent.ScheduledExecutorTask;

public class HelloTask extends ScheduledExecutorTask implements Runnable {
	public HelloTask() {
		setTimeUnit(TimeUnit.SECONDS);
		setPeriod(5);
		setRunnable(this);
	}
	
	public void run() {
		System.out.println("Hello!");
	}
}
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="
		http://www.springframework.org/schema/beans 
		http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

	<bean id="helloTaskExecutor" class="org.springframework.scheduling.concurrent.ScheduledExecutorFactoryBean">
		<property name="scheduledExecutorTasks">
			<list>
				<ref bean="helloTask" />
			</list>
		</property>
	</bean>
	
	<bean id="helloTask" class="sample.HelloTask"/>
	
</beans>
Main.java
package sample;

import java.util.concurrent.ScheduledExecutorService;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {
	public static void main(String[] args) throws InterruptedException {
		ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
		
		Thread.sleep(30000);
		
		ScheduledExecutorService helloTaskExecutor = (ScheduledExecutorService) context.getBean("helloTaskExecutor");
		helloTaskExecutor.shutdown();
	}
}

Main.javaを実行すると、5秒おきに「Hello!」が出力され、30秒後にプログラムが終了するようになっています。 もっと高度なタイマー処理を行う場合は、Quartzを使う方法が良いでしょう。

Spring Framework 3.0の新機能 Part2

take©です。Spring Framework 3.0 M3がリリースされましたね。今回はその新機能を紹介したいと思います。 まずSpring 3.0の新機能の概要です。

  • EL式のサポート
  • IoCの強化/JavaによるBeanメタデータ定義
  • オブジェクトとXMLのマッピングサポート (OXM)
  • RESTのサポート
  • Spring MVCへの機能追加
  • アノテーションによるバリデーション
  • Java EE 6の先取りサポート

前回の記事 (Spring Framework 3.0の新機能 Part1) でEL式とSpring MVCの機能追加についてまとめてますのであわせてご覧ください。本家のリファレンスも作成が進んでますので、詳しく知りたい方は Reference Documentation が良いと思います。


Mavenを使う

まずはMavenでSpring 3.0.0.M3を使えるようにします。 まだMilestone版なのでMavenのCentral Repository (http://repo1.maven.org/maven2/) には登録されていません。 以下はSpringのMavenリポジトリを使うpom.xmlの設定です。

<repositories>
	<repository>
		<id>com.springsource.repository.bundles.milestone</id>
		<name>SpringSource Enterprise Bundle Repository - SpringSource Bundle Milestones</name>
		<url>http://repository.springsource.com/maven/bundles/milestone</url>
	</repository>
	<repository>
		<id>com.springsource.repository.bundles.external</id>
		<name>SpringSource Enterprise Bundle Repository - SpringSource Bundle Externals</name>
		<url>http://repository.springsource.com/maven/bundles/external</url>
	</repository>
</repositories>

<dependencies>
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>org.springframework.web.servlet</artifactId>
		<version>3.0.0.M3</version>
	</dependency>
</dependencies>
</project>

SpringのCoreがJava5ベースで再構築された

SpringのコアがJava5に最適化されました。例えばジェネリクスを使ってBeanFactoryからキャストなしでBeanが取得できるようになります。

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
SampleBean sampleBean = context.getBean("sampleBean", SampleBean.class);

Pure JavaでBeanの設定が書ける

Spring 2.5からアノテーションベースでBeanが定義できるようになりましたが、Spring 3.0ではJavaConfigプロジェクトの一部が取り込まれ、ついにタイプセーフでPure Javaな設定が書けるようになりました。 つまり、BeanのFactory Methodをアノテーションベースで実装できるということです。

以下の例をご覧ください。SampleBeanをシングルトンスコープでBean登録しています。 デフォルトではメソッド名がBean名として登録されます。

@Configuration
public class SampleConfig {
	@Bean
	public SampleBean sampleBean() {
		return new SampleBean();
	}
}

上記の例はXMLファイルでこのように記述するのと同じことです。

<beans>
	<bean name="sampleBean" class="sample.SampleBean"/>
</beans>

XMLファイルにはcomponent-scanの設定を記述するのみです。

<context:component-scan base-package="sample.config"/>

BeanのFactory Methodを実装できるということは、もちろんBeanの生成について初期値を設定したり、DIすることが可能です。 以下の例をご覧ください。SampleConfigにDIしたFooのインスタンスをBarにDIしています。

@Configuration
public class SampleConfig {
	@Autowired
	private Foo foo;
	
	@Bean
	public Bar bar() {
		Bar bar = new Bar();
		bar.setFoo(foo);
		return bar;
	}
}

コントローラで例外を補足できる

@ExceptionHandlerアノテーションを使用して、コントローラで発生した例外を、そのコントローラでハンドリングできるようになります。個人的にかなり嬉しい機能です。 例えば@SessionAttributesで設定したモデルを参照するとき、セッションタイムアウトなどで、期待するモデルがセッションにない場合は、HttpSessionRequiredExceptionが発生します。 以下の例をご覧ください。HttpSessionRequiredExceptionを補足して特定のViewを表示することができます。

@Controller
@RequestMapping("/sample.html")
@SessionAttributes(types=SampleCommand.class)
public class SampleController {
	@ExceptionHandler
	public String handleException(HttpSessionRequiredException e, HttpServletRequest request)
	{
		// do something...
		return "exception.html";
	}
	
	@RequestMapping
	public String doSample(@ModelAttribute("sampleCommand") SampleCommand command)
	{
		// do something...
		return "sample.html";
	}
	...

Spring 3.0 M3に含まれないもの

以下はM3にはまだ含まれない、開発中のものです。次回のリリースが楽しみですね。

アノテーションによるバリデーション
@Lengthや@NotEmptyを使ってフォームの値などをバリデーションできるようになるかもしれません。
Java EE 6の先取りサポート
@Asyncアノテーションによる非同期メソッドコールなどが予定されているようです。

今回はここまで。できれば次回は、以下の機能をレポートしたいと思います。

  • @RequestBodyアノテーション
  • Feed Views (RSS)
  • オブジェクトとXMLのマッピングサポート

今回記載した内容は、あくまでマイルストーン版の実装内容です。正式リリースまでに色々と変更はあると思います。 SpringSource TeamBlogによると次のリリースはSpring 3.0 RC1となり、アノテーションによるバリデーションが実装されるようです。

[SpringSource TeamBlog]
http://blog.springsource.com/2009/05/06/spring-framework-30-m3-released/

Home > Springframework

Recent Comments
Recent Trackback
Search
Meta
Links
Feeds

Page Top

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。