第二部
第三部
目次:
1. ThymeleafとSpringの統合
2. SpringStandardダイアレクト
3.ビューとビューリゾルバー
3.1 Spring MVCのビューとビューリゾルバー
3.2 Thymeleafのビューとビューリゾルバー
4. Spring Thyme Seedスターターマネージャー
4.1コンセプト
4.2ビジネス層
4.3 Spring MVC設定
4.4コントローラー
4.5変換サービスの構成
5シードスターターデータの表示
6フォームの作成
6.1コマンドオブジェクトの処理
6.2入力
6.3チェックボックスのフィールド
6.4ラジオボタンフィールド
6.5ドロップダウン/リストセレクター
6.6動的フィールド
7検証とエラーメッセージ
7.1フィールドエラー
7.2すべてのエラー
7.3グローバルエラー
7.4フォーム外のエラーの表示
7.5リッチエラーオブジェクト
8これはまだプロトタイプです!
9変換サービス
9.1設定
9.2二重ブラケット構文
9.3フォームでの使用
9.4 #conversions変換オブジェクト
10テンプレートテンプレートフラグメントのレンダリングフラグメント(AJAXなど)
10.1ビューBeanでのフラグメントの定義
10.2コントローラーの戻り値でフラグメントを定義する
11高度な統合機能
11.1 RequestDataValueProcessorとの統合
11.1コントローラへのURIの構築
12 Spring WebFlow統合
12.2 Spring WebFlowのAJAXスニペット
このガイドでは、 ThymeleafをSpring Framework、特に(ただしこれに限定されない)Spring MVCと統合する方法について説明します。
Thymeleafには、thymeleaf-spring3およびthymeleaf-spring4と呼ばれる2つの別個のライブラリーによって提供される、Spring Frameworkのバージョン3.xおよび4.x以降の統合があります。 これらのライブラリは個別の.jarファイル(thymeleaf-spring3- {version} .jarおよびthymeleaf-spring4- {version} .jar)にパッケージ化されており、アプリケーションでThymeleaf Spring統合を使用するには、クラスパスに追加する必要があります。
このガイドのコード例とサンプルアプリケーションでは、Spring 4.xとそれに対応するThymeleaf統合を使用していますが、このテキストの内容はSpring 3.xにも適用されます。 アプリケーションでSpring 3.xを使用している場合は、コード例でorg.thymeleaf.spring4パッケージをorg.thymeleaf.spring3に置き換えるだけです。
1. ThymeleafとSpringの統合
Thymeleafは、Spring MVCアプリケーションでフル機能のJSP置換として使用できるようにするSpring Integrationのセットを提供します。
これらの統合により、次のことが可能になります。
- JSPの場合と同じように、Thymeleaf駆動型テンプレートのSpring MVC Controllerオブジェクトのメソッドにマッピングを作成します。
- テンプレートでOGNLの代わりにSpring Expression Language(Spring EL)を使用します。
- プロパティエディター、変換サービス、検証エラー処理の使用を含む、フォームサポートコンポーネントおよびBeanと完全に統合されたテンプレートでフォームを作成します。
- Springによって管理されるメッセージファイルから国際化メッセージを表示します(通常のMessageSourceオブジェクトを介して)。
- ネイティブのSpringリソース解決メカニズムを使用してパターンを見つけます。
このチュートリアルを完全に理解するには、最初に「 Thymeleafの使用 」 チュートリアルを実行する必要があります。このチュートリアルでは、標準的な方言について詳しく説明します。
2. SpringStandardダイアレクト
より簡単で優れた統合を実現するために、Thymeleafは、Springを正しく動作させるために必要なすべての機能を具体的に実装する方言を提供しています。
この特定の方言は、標準のThymeleaf方言に基づいており、実際にorg.thymeleaf.standard.StandardDialectから派生したクラスorg.thymeleaf.spring4.dialect.SpringStandardDialectに実装されています。
標準の方言にすでに存在し、したがって継承されているすべての機能に加えて、SpringStandard方言は次の特定の機能を提供します。
- OGNLではなく、Spring Expression Language(Spring ELまたはSpEL)を変数式言語として使用します。 したがって、すべての$ {...}および* {...}式は、Spring式言語エンジンによって評価されます。 また、Spring ELコンパイラサポート(Spring 4.2.4+)が利用可能であることに注意してください。
- SpringEL構文を使用したアプリケーションのコンテキスト内のコンポーネントへのアクセス: $ {@ myBean.doSomething()}
- フォームを処理するための新しい属性: th:field 、 th:errors、およびth:errorclass 。ただし、フォームコマンドを選択するために使用できる新しいth:オブジェクトの実装は除きます。
- #themes.code(...)オブジェクトと式メソッド。JSPspring :テーマカスタムタグに相当します。
- オブジェクトと式のメソッド#mvc.uri(...)は、JSP スプリングカスタム関数mvcUrl(...) (Spring 4.1以降のみ)と同等です。
ほとんどの場合、この方言を構成の一部として通常のTemplateEngineオブジェクトで直接使用しないでください。 Springとの特別な統合ニーズがない場合は、代わりに、必要なすべての構成手順を自動的に実行する新しいテンプレートクラスのインスタンスorg.thymeleaf.spring4.SpringTemplateEngineを作成する必要があります。
Beanの構成例:
@Bean public SpringResourceTemplateResolver templateResolver(){ // SpringResourceTemplateResolver automatically integrates with Spring's own // resource resolution infrastructure, which is highly recommended. SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver(); templateResolver.setApplicationContext(this.applicationContext); templateResolver.setPrefix("/WEB-INF/templates/"); templateResolver.setSuffix(".html"); // HTML is the default value, added here for the sake of clarity. templateResolver.setTemplateMode(TemplateMode.HTML); // Template cache is true by default. Set to false if you want // templates to be automatically updated when modified. templateResolver.setCacheable(true); return templateResolver; } @Bean public SpringTemplateEngine templateEngine(){ // SpringTemplateEngine automatically applies SpringStandardDialect and // enables Spring's own MessageSource message resolution mechanisms. SpringTemplateEngine templateEngine = new SpringTemplateEngine(); templateEngine.setTemplateResolver(templateResolver()); // Enabling the SpringEL compiler with Spring 4.2.4 or newer can // speed up execution in most scenarios, but might be incompatible // with specific cases when expressions in one template are reused // across different data types, so this flag is "false" by default // for safer backwards compatibility. templateEngine.setEnableSpringELCompiler(true); return templateEngine; }
または、XMLベースのSpring構成を使用します。
<!-- SpringResourceTemplateResolver automatically integrates with Spring's own --> <!-- resource resolution infrastructure, which is highly recommended. --> <bean id="templateResolver" class="org.thymeleaf.spring4.templateresolver.SpringResourceTemplateResolver"> <property name="prefix" value="/WEB-INF/templates/" /> <property name="suffix" value=".html" /> <!-- HTML is the default value, added here for the sake of clarity. --> <property name="templateMode" value="HTML" /> <!-- Template cache is true by default. Set to false if you want --> <!-- templates to be automatically updated when modified. --> <property name="cacheable" value="true" /> </bean> <!-- SpringTemplateEngine automatically applies SpringStandardDialect and --> <!-- enables Spring's own MessageSource message resolution mechanisms. --> <bean id="templateEngine" class="org.thymeleaf.spring4.SpringTemplateEngine"> <property name="templateResolver" ref="templateResolver" /> <!-- Enabling the SpringEL compiler with Spring 4.2.4 or newer can speed up --> <!-- execution in most scenarios, but might be incompatible with specific --> <!-- cases when expressions in one template are reused across different data --> <!-- ypes, so this flag is "false" by default for safer backwards --> <!-- compatibility. --> <property name="enableSpringELCompiler" value="true" /> </bean>
3.ビューとビューリゾルバー
3.1 Spring MVCのビューとビューリゾルバー
Spring MVCには、テンプレートシステムのコアに対応する2つのインターフェイスがあります。
- org.springframework.web.servlet.View
- org.springframework.web.servlet.ViewResolver
ビューはアプリケーションのページをモデル化し、それらをBeanコンポーネントとして定義することで、動作を変更および事前に決定できます。 ビューは、実際のHTMLインターフェイスのレンダリングを担当します。通常、Thymeleafなどの何らかのテンプレートエンジンを実行します。
ViewResolverは、特定の操作およびロケールのViewオブジェクトを取得するオブジェクトです。 通常、コントローラーはViewResolversに特定の名前(コントローラーメソッドによって返される文字列)でビューを転送するように要求し、アプリケーションのビューを解決するすべての手段は、それらの1つがこのビューを解決できるまで順序付けられたチェーンで実行されます。その場合、Viewオブジェクトが返され、コントロールが転送されますHTMLのレンダリング用。
アプリケーションのすべてのページを表現として定義する必要はありませんが、動作を特別な方法でカスタマイズまたはカスタマイズしたい(たとえば、特別なコンポーネントをそれに接続する)ページのみを定義する必要があります。 ViewResolverが 、対応するBeanを持たないビューに対して要求された場合(これは一般的なケースです)、新しいビューがアドホックに作成され、返されます 。
過去のSpring MVCアプリケーションでの典型的なJSP + JSTL ViewResolver構成は次のようになりました。
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" /> <property name="prefix" value="/WEB-INF/jsps/" /> <property name="suffix" value=".jsp" /> <property name="order" value="2" /> <property name="viewNames" value="*jsp" /> </bean>
プロパティの概要を見るだけで、どのように設定されているかがわかります。
- viewClassは、Viewインスタンスのクラスを設定します。 これはJSPレコグナイザーに必要ですが、Thymeleafで作業しているときにはまったく必要ありません。
- プレフィックスとサフィックスは、Thymeleaf TemplateResolverオブジェクトの同じ名前の属性と同様に機能します。
- orderは、チェーン内でViewResolverが要求される順序を設定します。
- viewNamesを使用すると、このViewResolverが解決するビューの名前を(ワイルドカードで)定義できます 。
3.2 Thymeleafのビューとビューリゾルバー
Thymeleafは、上記の2つのインターフェイスの実装を提供します。
- org.thymeleaf.spring4.view.ThymeleafView
- org.thymeleaf.spring4.view.ThymeleafViewResolver
これらの2つのクラスは、コントローラーの実行の結果としてThymeleafテンプレートを処理する役割を果たします。
Resolver Thymeleafビューの構成は、JSPに非常に似ています。
@Bean public ThymeleafViewResolver viewResolver(){ ThymeleafViewResolver viewResolver = new ThymeleafViewResolver(); viewResolver.setTemplateEngine(templateEngine()); // NOTE 'order' and 'viewNames' are optional viewResolver.setOrder(1); viewResolver.setViewNames(new String[] {".html", ".xhtml"}); return viewResolver; }
...またはXML:
<bean class="org.thymeleaf.spring4.view.ThymeleafViewResolver"> <property name="templateEngine" ref="templateEngine" /> <!-- NOTE 'order' and 'viewNames' are optional --> <property name="order" value="1" /> <property name="viewNames" value="*.html,*.xhtml" /> </bean>
templateEngineパラメーターは、もちろん、前の章で定義したSpringTemplateEngineオブジェクトです。 他の2つ( orderとviewNames )はオプションであり、前に見たJSP ViewResolverと同じ意味を持ちます。
接頭辞または接尾辞のパラメータはテンプレートリゾルバで既に指定されているため(これはテンプレートエンジンに渡されるため)必要ないことに注意してください。
しかし、 View Beanを定義していくつかの静的変数を追加したい場合はどうでしょうか? 簡単で、プロトタイプを定義するだけです。
@Bean @Scope("prototype") public ThymeleafView mainView() { ThymeleafView view = new ThymeleafView("main"); // templateName = 'main' view.setStaticVariables( Collections.singletonMap("footer", "The ACME Fruit Company")); return view; }
これが完了したら、名前(この場合はmainView)で選択して、このコンポーネントを要求できます。
4. Spring Thyme Seedスターターマネージャー
このガイドのこの章および以降の章に示す例のソースコードは、 GitHub Spring Seyme Seed Starter Managerリポジトリにあります。
4.1コンセプト
タイムリーフに関して、私たちはタイムの大ファンであり、毎年春に良い土壌と好きな種でスターターキットを準備し、スペインの太陽の下で植えて、新しい植物が成長するのを辛抱強く待ちます。
しかし、今年は、コンテナの各セルにあるシードを確認するために開始シードコンテナにラベルを貼るのにうんざりしていたため、Spring MVCとThymeleafを使用してアプリケーションを準備し、スターターのカタログ化を支援することにしました: Spring Thyme SeedStarter Manager 。
Thymeleafの使用チュートリアルで開発したGood Thymes Virtual Groceryアプリケーションと同様に、STSMを使用すると、ThymeleafをSpring MVCのテンプレートエンジンとして統合する最も重要な側面を示すことができます。
4.2ビジネス層
アプリケーションには非常にシンプルなビジネスレイヤーが必要です。 まず、モデルオブジェクトを見てみましょう。
いくつかの非常に単純なサービスクラスが、必要なビジネスメソッドを提供します。 のような:
@Service public class SeedStarterService { @Autowired private SeedStarterRepository seedstarterRepository; public List<SeedStarter> findAll() { return this.seedstarterRepository.findAll(); } public void add(final SeedStarter seedStarter) { this.seedstarterRepository.add(seedStarter); } }
そして:
@Service public class VarietyService { @Autowired private VarietyRepository varietyRepository; public List<Variety> findAll() { return this.varietyRepository.findAll(); } public Variety findById(final Integer id) { return this.varietyRepository.findById(id); } }
4.3 Spring MVC設定
次に、アプリケーションのSpring MVC構成を構成する必要があります。これには、処理リソースやスキャンアノテーションなどの標準のSpring MVCアーティファクトだけでなく、 Template EngineとView Resolverのインスタンスも作成されます。
@Configuration @EnableWebMvc @ComponentScan public class SpringWebConfig extends WebMvcConfigurerAdapter implements ApplicationContextAware { private ApplicationContext applicationContext; public SpringWebConfig() { super(); } public void setApplicationContext(final ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } /* ******************************************************************* */ /* GENERAL CONFIGURATION ARTIFACTS */ /* Static Resources, i18n Messages, Formatters (Conversion Service) */ /* ******************************************************************* */ @Override public void addResourceHandlers(final ResourceHandlerRegistry registry) { super.addResourceHandlers(registry); registry.addResourceHandler("/images/**").addResourceLocations("/images/"); registry.addResourceHandler("/css/**").addResourceLocations("/css/"); registry.addResourceHandler("/js/**").addResourceLocations("/js/"); } @Bean public ResourceBundleMessageSource messageSource() { ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource(); messageSource.setBasename("Messages"); return messageSource; } @Override public void addFormatters(final FormatterRegistry registry) { super.addFormatters(registry); registry.addFormatter(varietyFormatter()); registry.addFormatter(dateFormatter()); } @Bean public VarietyFormatter varietyFormatter() { return new VarietyFormatter(); } @Bean public DateFormatter dateFormatter() { return new DateFormatter(); } /* **************************************************************** */ /* THYMELEAF-SPECIFIC ARTIFACTS */ /* TemplateResolver <- TemplateEngine <- ViewResolver */ /* **************************************************************** */ @Bean public SpringResourceTemplateResolver templateResolver(){ // SpringResourceTemplateResolver automatically integrates with Spring's own // resource resolution infrastructure, which is highly recommended. SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver(); templateResolver.setApplicationContext(this.applicationContext); templateResolver.setPrefix("/WEB-INF/templates/"); templateResolver.setSuffix(".html"); // HTML is the default value, added here for the sake of clarity. templateResolver.setTemplateMode(TemplateMode.HTML); // Template cache is true by default. Set to false if you want // templates to be automatically updated when modified. templateResolver.setCacheable(true); return templateResolver; } @Bean public SpringTemplateEngine templateEngine(){ // SpringTemplateEngine automatically applies SpringStandardDialect and // enables Spring's own MessageSource message resolution mechanisms. SpringTemplateEngine templateEngine = new SpringTemplateEngine(); templateEngine.setTemplateResolver(templateResolver()); // Enabling the SpringEL compiler with Spring 4.2.4 or newer can // speed up execution in most scenarios, but might be incompatible // with specific cases when expressions in one template are reused // across different data types, so this flag is "false" by default // for safer backwards compatibility. templateEngine.setEnableSpringELCompiler(true); return templateEngine; } @Bean public ThymeleafViewResolver viewResolver(){ ThymeleafViewResolver viewResolver = new ThymeleafViewResolver(); viewResolver.setTemplateEngine(templateEngine()); return viewResolver; } }
4.4コントローラー
もちろん、アプリケーション用のコントローラーも必要です。 STSMには、初期値のリストと新しい値を追加するためのフォームを含む1つのWebページのみが含まれるため、すべてのサーバーインタラクションに対して1つのコントローラークラスのみを記述します。
@Controller public class SeedStarterMngController { @Autowired private VarietyService varietyService; @Autowired private SeedStarterService seedStarterService; ... }
次に、このコントローラークラスに追加できるものを見てみましょう。
モデル属性
最初に、ページに必要ないくつかのモデル属性を追加します。
@ModelAttribute("allTypes") public List<Type> populateTypes() { return Arrays.asList(Type.ALL); } @ModelAttribute("allFeatures") public List<Feature> populateFeatures() { return Arrays.asList(Feature.ALL); } @ModelAttribute("allVarieties") public List<Variety> populateVarieties() { return this.varietyService.findAll(); } @ModelAttribute("allSeedStarters") public List<SeedStarter> populateSeedStarters() { return this.seedStarterService.findAll(); }
マッピングされたメソッド
そして今、コントローラーの最も重要な部分であるマッピングされたメソッド:フォームページを表示するメソッドと、新しいSeedStarterオブジェクトの追加を処理するメソッドです。
@RequestMapping({"/","/seedstartermng"}) public String showSeedstarters(final SeedStarter seedStarter) { seedStarter.setDatePlanted(Calendar.getInstance().getTime()); return "seedstartermng"; } @RequestMapping(value="/seedstartermng", params={"save"}) public String saveSeedstarter( final SeedStarter seedStarter, final BindingResult bindingResult, final ModelMap model) { if (bindingResult.hasErrors()) { return "seedstartermng"; } this.seedStarterService.add(seedStarter); model.clear(); return "redirect:/seedstartermng"; }
4.5変換サービスの構成
ビューレイヤーのDateオブジェクトとVarietyオブジェクトの簡単なフォーマットを提供するために、必要ないくつかのフォーマットオブジェクトを使用してSpring ConversionServiceオブジェクトが作成および初期化されるようにアプリケーションを構成しました(拡張可能なWebMvcConfigurerAdapter )。
もう一度見てください:
@Override public void addFormatters(final FormatterRegistry registry) { super.addFormatters(registry); registry.addFormatter(varietyFormatter()); registry.addFormatter(dateFormatter()); } @Bean public VarietyFormatter varietyFormatter() { return new VarietyFormatter(); } @Bean public DateFormatter dateFormatter() { return new DateFormatter(); }
Spring フォーマッタはorg.springframework.format.Formatterインターフェイスの実装です。 Spring変換インフラストラクチャの機能の詳細については、 spring.ioのドキュメントを参照してください。
Messages.propertiesの date.formatキーにあるフォーマット文字列に従って日付をフォーマットするDateFormatterを見てみましょう:
public class DateFormatter implements Formatter<Date> { @Autowired private MessageSource messageSource; public DateFormatter() { super(); } public Date parse(final String text, final Locale locale) throws ParseException { final SimpleDateFormat dateFormat = createDateFormat(locale); return dateFormat.parse(text); } public String print(final Date object, final Locale locale) { final SimpleDateFormat dateFormat = createDateFormat(locale); return dateFormat.format(object); } private SimpleDateFormat createDateFormat(final Locale locale) { final String format = this.messageSource.getMessage("date.format", null, locale); final SimpleDateFormat dateFormat = new SimpleDateFormat(format); dateFormat.setLenient(false); return dateFormat; } }
VarietyFormatterは、 Varietyオブジェクトと、フォームでの使用方法(主にidフィールドの値によって)を自動的に変換します。
public class VarietyFormatter implements Formatter<Variety> { @Autowired private VarietyService varietyService; public VarietyFormatter() { super(); } public Variety parse(final String text, final Locale locale) throws ParseException { final Integer varietyId = Integer.valueOf(text); return this.varietyService.findById(varietyId); } public String print(final Variety object, final Locale locale) { return (object != null ? object.getId().toString() : ""); } }
これらの書式設定ツールが今後のデータの表示方法にどのように影響するかについて詳しく学習します。