ThymeleafでNumber.javaを継承したクラスをメッセージ式のパラメータとして渡すと千の位で区切ってくれる話

先日、仕事でThymeleafで千の位で区切って表示することをやりました。いわゆる金額表示です。
結論から述べると、以下のようにすると、実現できます。

ちなみにこれはたまたま発見できちゃいました。。。笑
最初は、次のように書いてました。

<p th:text="${#numbers.formatInteger(1234567890, 3, 'COMMA')} + '円'">1,234,567,890円</p>

ある記事を読んでいてメッセージ式にパラメータを渡せることを知りました。
そこでカンマ区切りのことは気にせず、上のように書いてみたら、金額表示になってました。
しかし、なぜ数値をパラメータとして渡すと千の位で区切ってくれる(区切って欲しくないときもあるけど)のか気になったのでソースコード追ってみました。
MessageSourceインターフェースのgetMessageメソッドにブレークポイントを張りました。
MessageFormat.java#subformatが気になりました。

案の定、16行目に止まり、ここでsubformatにDecimalFormat.javaを返していました。
そして、DecimalFormat.javaのsubformatメソッドに処理がうつり、ここで実際に1000の位に区切っていました。それが以下の箇所です。

実際にソースを読んでもらえればわかるのですが、groupingという変数に「,」が格納されています。
DecimalFormatSymbols (Java Platform SE 8 )
ループで回し、パラメタを1個ずつ渡して、1000の位で「,」を入れています。

ちなみに、NumberFormatProvider.javaにこのようなメソッドがあったのでこれをうまく呼ぶ方法を見つけたいなと思いました。

public abstract NumberFormat getCurrencyInstance(Locale locale);

以上です。

Intelli Jのショートカット一覧が日本語訳されました

以前、Intelli Jのショートカットを以下の記事でまとめたのですが、公式で発表されてるのもを日本語訳された会社さんがいらっしゃいました。
uchi-fashion.hatenablog.com

こっちの方が私の拙い日本語訳より参考になると思うのでぜひ!
IntelliJ や PhpStorm などの日本語化

Intelli J ショートカットまとめ

4回にわたってIntelli Jのショートカットをまとめたのですが、みてる自分がめんどくさくなったので1つにまとめました。
Keymapは、Mac OS Xです。異なる方はちょいとキーが変わってくると思います!

Editing
ショートカットキー 説明
^ Space ベーシックなコード補完(いくつかクラスやメソッドや変数の候補をあげる)
^ Shift Space スマートなコード補完(そのメソッドで期待されるタイプの変数の候補をあげる)
Command P パラメータ情報表示
^ J クイックドキュメント表示
Command コードをマウスオーバー 簡単なドキュメント表示
^ N GetterやSetterやConstructorなどのコードを生成
Command O オーバーライドメソッドの表示
Command Option T if...elseやtry...catchなどの雛形コード生成
Command / カーソルがある行のコメントアウト
^ Shift Q コンテキスト情報の表示。puclic class Test extends Hoge { を表示
Command Option L コードフォーマット
^ Shift O import文の整理。使ってないものの削除やソートを行う
Command D カーソルがある行を下に向かってコピペを行う
Command Enter カーソルがある箇所から改行する
Shift Enter カーソルがある行の次の行に空行を追加
Command Shift [ カーソルがある箇所のブロックの始まりからカーソルの箇所まで選択
Command Shift ] カーソルがある箇所からブロックの終わりまで選択
Option → カーソルが単語の終わりに遷移
Option ← カーソルが単語の始まりに遷移
Command W カーソルがある単語を選択
Command Shift U 選択してる単語の大文字小文字切り替え
Command G 開いたモーダルで指定した行数に遷移する
Usage Search
ショートカットキー 説明
Option F7 プロジェクト内でカーソルが当たっているクラス(メソッド)が使われている箇所を表示
Command F7 ファイル内でカーソルが当たっているクラス(メソッド)が使われている箇所を表示
Command Shift F7 ファイル内でカーソルが当たっているクラス(メソッド)が使われている箇所を強調して表示
Command Option F7 プロジェクト内でカーソルが当たっているクラス(メソッド)が使われている箇所を一覧表示
Navigation
ショートカットキー 説明
F12 アクティブウインドウをツールウインドウにする
ESC アクティブウインドウをエディタにする
Shift ESC (直近の)アクティブウインドウを隠す
Command F4 アクティブなタブを閉じる
Command E 最近開いたファイルをポップアップ表示
Command B または Command Click 変数の宣言箇所にカーソルを移動(Command Clickは変数にカーソルが当たってる時)
Command Option B または Command Click 実装箇所にカーソルを移動(Command Clickはメソッドにカーソルが当たってる時))
Command [ コードブロックのはじまりに移動
Command ] コードブロックの終わりに移動
Command F12 ファイル構成(フィールドやメソッド)をポップアップ表示
^ H タイプハイアラーキーを表示
Command Shift H メソッドハイアラーキーを表示
Option ^ H コールハイアラーキーを表示
Search / Replace
ショートカットキー 説明
Shift * 2 どこでも検索
Command F ファイル内検索
Command R 置換
^ Shift F 全ファイルから文字列検索
VCS/Local History
ショートカットキー 説明
^ V バージョン管理システムメニューをポップアップ表示
Refactoring(左ペインで)
ショートカットキー 説明
F5 ファイルのコピー
F6 ファイルの移動
Command Delete セーフデリート
Shift F6 リネーム
Debugging
ショートカットキー 説明
F8 ブレークポイントから一行進める
F7 呼び先のメソッドに入る
F9 次のブレークポイントにとぶ
Shift F8 F7で入ったメソッドから出る
Option F8 ブレークポイントで止まっているときにポップアップウインドウで好きなことを試せる
Command F8 ブレークポイントを解除する
Command Shift F8 ブレークポイントの一覧を表示
ブレークポイントで止まってる時に変数を)Option click 変数の中身が見られる。watchで見られるのと同じ
General
ショートカットキー 説明
Command 1 ~ Command 9 割り当てているツールウインドウを表示
Command ^F フルスクリーンモードにする
Command Shift F12 開いているツールウインドウを全て閉じる
Command , 設定画面開く
Command ; プロジェクトストラクチャーを開く
Others
table>tr>td*2と入力してTabを押す tr * 1、td * 2のテーブルを生成

この中でも1番オススメの機能がこれです!
Option F8:ブレークポイントで止まっているときにポップアップウインドウで好きなことを試せる
f:id:b1a9id:20170707101940p:plain
実際にプロダクトコードで宣言されているものは、vだけです。
変数宣言もできるのでデバッグ能力が格段にあがると思います!
ちなみにAndroid Studioでも使えるらしいのでぜひ試してみてください。

ThymeleafとJSPを共存させた話

転職して、JSPを使っている会社に入りました。今どきJSPはないだろ!っていうことでThymeleafと共存させることにしました。
プロジェクト構成は、こんな感じです。

JavaCofigでBean定義を行うプロジェクト構成

f:id:b1a9id:20170627220712p:plain

xmlでBean定義を行うプロジェクト構成

f:id:b1a9id:20170627234120p:plain

では、さっそくコードを見ていただこうと思います。

pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.example</groupId>
	<artifactId>spring-framework-sandbox</artifactId>
	<version>1.0-SNAPSHOT</version>
	<packaging>war</packaging>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<spring.mvc.version>4.3.8.RELEASE</spring.mvc.version>
		<jvl.over.slf4j.version>1.7.25</jvl.over.slf4j.version>
		<logback.classic.version>1.2.3</logback.classic.version>
		<lombok.version>1.16.16</lombok.version>
		<thymeleaf.version>3.0.5.RELEASE</thymeleaf.version>
	</properties>

	<dependencies>
		<!-- Spring MVC -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${spring.mvc.version}</version>
		</dependency>

		<!-- Jvl over slf4j -->
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>jcl-over-slf4j</artifactId>
			<version>${jvl.over.slf4j.version}</version>
		</dependency>

		<!-- logback classic -->
		<dependency>
			<groupId>ch.qos.logback</groupId>
			<artifactId>logback-classic</artifactId>
			<version>${logback.classic.version}</version>
		</dependency>

		<!-- Lombok -->
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<version>${lombok.version}</version>
		</dependency>

		<!-- Thymeleaf -->
		<dependency>
			<groupId>org.thymeleaf</groupId>
			<artifactId>thymeleaf-spring4</artifactId>
			<version>${thymeleaf.version}</version>
		</dependency>

		<!-- JSP -->
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jsp-api</artifactId>
			<version>2.0</version>
		</dependency>

		<!-- JSTL -->
		<dependency>
			<groupId>jstl</groupId>
			<artifactId>jstl</artifactId>
			<version>1.2</version>
		</dependency>
	</dependencies>
</project>

JavaConfig

ThymeleafConfig.java
@Configuration
public class ThymeleafConfig {

	@Bean
	public SpringResourceTemplateResolver templateResolver(){
		SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
                // テンプレートファイルがどのディレクトリの配下にあるかを指定。ここでは、/WEB-INF/views/配下
		templateResolver.setPrefix("/WEB-INF/views/");
                // 接尾字が何かを指定。ここでは.html
		templateResolver.setSuffix(".html");
                // テンプレートの種類は何かを指定。ここでhtml
		templateResolver.setTemplateMode(TemplateMode.HTML);
		return templateResolver;
	}

	@Bean
	public SpringTemplateEngine templateEngine(){
		SpringTemplateEngine templateEngine = new SpringTemplateEngine();
		templateEngine.setTemplateResolver(templateResolver());
		templateEngine.setEnableSpringELCompiler(true);
		return templateEngine;
	}

	@Bean
	public ThymeleafViewResolver viewResolver(){
		ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
		viewResolver.setTemplateEngine(templateEngine());
		viewResolver.setCharacterEncoding("UTF-8");
                // ViewResolverを使う順序を指定。JSPより先にする。
		viewResolver.setOrder(1);
                // Controllerから返すView名がこの文字列であれば、ThymeleafViewResolverを使う
		viewResolver.setViewNames(new String[] {"thymeleaf/*"});
		return viewResolver;
	}
}
WevMvcConfig.java

JSP用のViewResolverを登録する。Thymeleafとほぼ同じなので説明は割愛します。

@Configuration
@EnableWebMvc
@ComponentScan("com.example")
// ThymeleafConfigをインポートします。
@Import(ThymeleafConfig.class)
public class WebMvcConfig extends WebMvcConfigurerAdapter {

	@Override
	public void configureViewResolvers(ViewResolverRegistry registry) {
		registry.jsp()
				.prefix("/WEB-INF/views/")
				.suffix(".jsp")
				.viewNames("jsp/*");
		registry.order(2);
	}
}

xml

beans-biz.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"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

	<context:component-scan base-package="com.example"/>

	<bean id="messageSource"
	      class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
		<property name="basename" value="META-INF.messages" />
	</bean>

	<bean id="globalValidator"
	      class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
		<property name="validationMessageSource" ref="messageSource" />
	</bean>
</beans>
beans-webmvc.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"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd">

	<context:component-scan base-package="com.example.web.controller" />

	<!-- Spring MVCアノテーション利用設定 -->
	<mvc:annotation-driven validator="globalValidator" />

	<!-- Static Resourceの設定 -->
	<mvc:resources mapping="/resources/**" location="/WEB-INF/views/" />

	<!-- ViewResolverの設定 -->
	<!-- Thymeleaf -->
	<beans>
		<bean id="templateResolver" class="org.thymeleaf.spring4.templateresolver.SpringResourceTemplateResolver" >
			<property name="prefix" value="/WEB-INF/views/" />
			<property name="suffix" value=".html" />
			<property name="characterEncoding" value="UTF-8" />
		</bean>
		<bean id="templateEngine" class="org.thymeleaf.spring4.SpringTemplateEngine">
			<property name="templateResolver" ref="templateResolver" />
		</bean>
		<bean class="org.thymeleaf.spring4.view.ThymeleafViewResolver">
			<property name="templateEngine" ref="templateEngine" />
			<property name="characterEncoding" value="UTF-8" />
			<property name="viewNames" value="thymeleaf/*" />
			<property name="order" value="1" />
		</bean>
	</beans>
	<!-- JSP -->
	<beans>
		<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
			<property name="prefix" value="/WEB-INF/views/" />
			<property name="suffix" value=".jsp" />
			<property name="viewNames" value="jsp/*" />
			<property name="order" value="2" />
		</bean>
	</beans>

</beans>


JavaConfigとxmlの共通のControllerクラスです。
View返すだけのControllerなので、特に説明はいらないかと思います。

WelcomeController.java
@Controller
@RequestMapping("/hello")
public class WelcomeController {

	@GetMapping("/jsp")
	public String helloJsp() {
		return "jsp/hello/index";
	}

	@GetMapping("/thymeleaf")
	public String helloThymeleaf() {
		return "thymeleaf/hello/index";
	}
}

あとは、アプリケーションを起動して次にアクセスするだけです。
http://localhost:8080/hello/jsp
http://localhost:8080/hello/thymeleaf

※ViewResolverの順序は、JSPよりThymeleafを先に指定してください。JSPを先に指定してしまうと、JSP以降に登録されてあるViewResolverを使わなくなってしまいます。

IntelliJ KEYMAP #4(Mac)

4回目は、デバッグと一般的なショートカットです。ちなみにKeymapは、Mac OS Xです。
今回が最終回です!気が向いたらWindowsも書こうかな?(たぶん気が向かない)

Debugging
ショートカットキー 説明
F8 ブレークポイントから一行進める
F7 呼び先のメソッドに入る
F9 次のブレークポイントにとぶ
Shift F8 F7で入ったメソッドから出る
Option F8 Watchと同じ機能をポップアップウインドウで
Command F8 ブレークポイントを解除する
Command Shift F8 ブレークポイントの一覧を表示
General
ショートカットキー 説明
Command 1 ~ Command 9 割り当てているツールウインドウを表示
Command ^F フルスクリーンモードにする
Command Shift F12 開いているツールウインドウを全て閉じる
Command , 設定画面開く
Command ; プロジェクトストラクチャーを開く

以上です。最後の3つは感動しましたw

IntelliJ KEYMAP #3(Mac)

3回目は、検索と置換とVCS/Local Historyリファクタリングです。ちなみにKeymapは、Mac OS Xです。

Search / Replace
ショートカットキー 説明
Shift * 2 どこでも検索
Command F ファイル内検索
Command R 置換
^ Shift F 全ファイルから文字列検索
VCS/Local History
ショートカットキー 説明
^ V バージョン管理システムメニューをポップアップ表示
Refactoring(左ペインで)
ショートカットキー 説明
F5 ファイルのコピー
F6 ファイルの移動
Command Delete セーフデリート
Shift F6 リネーム

IntelliJ KEYMAP #2(Mac)

2回目は、Usage SearchとNavigationです。ちなみにKeymapは、Mac OS Xです。

Usage Search
ショートカットキー 説明
Option F7 プロジェクト内でカーソルが当たっているクラス(メソッド)が使われている箇所を表示
Command F7 ファイル内でカーソルが当たっているクラス(メソッド)が使われている箇所を表示
Command Shift F7 ファイル内でカーソルが当たっているクラス(メソッド)が使われている箇所を強調して表示
Command Option F7 プロジェクト内でカーソルが当たっているクラス(メソッド)が使われている箇所を一覧表示
Navigation
ショートカットキー 説明
F12 アクティブウインドウをツールウインドウにする
ESC アクティブウインドウをエディタにする
Shift ESC (直近の)アクティブウインドウを隠す
Command F4 アクティブなタブを閉じる
Command E 最近開いたファイルをポップアップ表示
Command B または Command Click 変数の宣言箇所にカーソルを移動(Command Clickは変数にカーソルが当たってる時)
Command Option B または Command Click 実装箇所にカーソルを移動(Command Clickはメソッドにカーソルが当たってる時))
Command [ コードブロックのはじまりに移動
Command ] コードブロックの終わりに移動
Command F12 ファイル構成(フィールドやメソッド)をポップアップ表示
^ H タイプハイアラーキーを表示
Command Shift H メソッドハイアラーキーを表示
Option ^ H コールハイアラーキーを表示