Spring WebMVCをやってみる (16) - Converter -

2013-12-26T00:00:00+00:00 Java Spring Framework

以前にも引数にDateを使う場合だとかはConversionServiceな設定が必要だって件を書いたけど、そういう所を自分で作って利用したい場合どうすれば良いのかって所を検証してみた

SampleController.java

package sample;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping("/sample")
public class SampleController {
    @RequestMapping("/test")
    @ResponseBody
    public String test(@RequestParam("id") SampleForm form) {
        return String.valueOf(form.getId());
    }
}

っていうようにidパラメーターを取ってそこからSampleFormなインスタンスを引数で利用したい場合とかを普通にやるとorg.springframework.beans.ConversionNotSupportedExceptionになる訳だけど、上記でも書いたように以前だとDateを利用する引数な場合には@DateTimeFormatなアノテーションを付与する事で利用できるがConversionServiceの設定をしておかないといけない。でこの場合においてidパラメーターからSampleFormに変換するConversionServiceのconverterを用意する事で対処できる

StringToSampleFormConverter.java

package sample;

import org.springframework.core.convert.converter.Converter;

public class StringToSampleFormConverter implements Converter<String, SampleForm> {
    @Override
    public SampleForm convert(String source) {
        SampleForm form = new SampleForm();

        try {
            form.setId(Integer.parseInt(source));
        } catch (NumberFormatException e) {
            e.printStackTrace();
        }

        return form;
    }
}

Converterインターフェースを実装すれば良い。

まぁ定義しただけじゃなくて設定したいと作用しないので

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

    <context:component-scan base-package="sample" />
    <mvc:annotation-driven conversion-service="conversionService" />

    <bean
        id="conversionService"
        class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
        <property name="converters">
            <list>
                <bean class="sample.StringToSampleFormConverter" />
            </list>
        </property>
    </bean>

    <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
        <property name="webBindingInitializer">
            <bean class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
                <property name="conversionService" ref="conversionService" />
            </bean>
        </property>
    </bean>

</beans>

っていう感じで作ったConverterな実装をConversionSerivceのconvertersに入れてやれば良い模様で

余談1: ConversionServiceを@Autowiredしてやる場合

package sample;

import java.util.Date;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.convert.ConversionService;
import org.springframework.format.support.DefaultFormattingConversionService;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping("/sample")
public class SampleController {

    @Autowired
    public SampleController(ConversionService conversion) {
        ((DefaultFormattingConversionService)conversion)
            .addConverter(new StringToSampleFormConverter());
    }

    @RequestMapping("/test")
    @ResponseBody
    public String test(@RequestParam("id") SampleForm form)
        return String.valueOf(form.getId());
    }
}

っていう感じにやっても出来る模様ではあるけれどもまぁ普通ならXMLに定義するなりでしておいた方がいいのかも

ちなみに@InitBinderの引数で使用されるWebDataBinderでもConversionServiceなインスタンスは取れる

余談2: オブジェクト等からString等へconvertする場合

Stringからオブジェクトへ変換する方式は上記でやってるけど、その逆の場合どういう動作によって行われるのか

package sample;

import org.springframework.core.convert.converter.Converter;

public class SampleFormToStringConverter implements Converter<SampleForm, String> {
    @Override
    public String convert(SampleForm source) {
        return String.valueOf(source.getId());
    }
}

っていう所だと思うのですが、この場合JSP等で

<%@ page contentType="text/html; charset=utf-8" %>
<%@ taglib uri="http://www.springframework.org/tags" prefix="spring" %>
<spring:eval expression="sample" />

というように使う事で上記のConverterが作用するようになるらしい。普通のEL式で書いても作用しない模様

thymeleaf Spring WebMVCをやってみる (15) - TypeMismatch -