Spring WebMVCをやってみる (5) - PathVariable -
例えばRequestMappingで指定するパスの一部を変数で引数にマッピングしたい時とかに使うのが@PathVariableアノテーションな模様。
SampleController.java
package sample;
import java.util.Date;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
@RequestMapping("/sample")
public class SampleController {
@RequestMapping("/test/{date}")
@ResponseBody
public String test(@PathVariable Date date) throws Exception {
return "date: " + date;
}
}
っていうように引数なアノテーションに@PathVariableを指定する。但し、Date型は無設定な状態だと型変換されないので
Failed to convert value of type 'java.lang.String' to required type 'java.util.Date'; nested exception is java.lang.IllegalStateException: Cannot convert value of type [java.lang.String] to required type [java.util.Date]: no matching editors or conversion strategy found」
っていうようなエラーが起きる。なので@InitBinderを使ってDate型を処理するPropertyEditorを設定すれば良い模様
package sample;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
@RequestMapping("/sample")
public class SampleController {
@InitBinder
public void initBinder(WebDataBinder binder) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
dateFormat.setLenient(false);
binder.registerCustomEditor(
Date.class,
new CustomDateEditor(dateFormat, false)
);
}
@RequestMapping("/test/{date}")
@ResponseBody
public String test(@PathVariable Date date) throws Exception {
return "date: " + date;
}
}
ちなみにこの@InitBinderはWebBindingInitializerインターフェースを実装する事でコントローラーで@InitBinderを利用しなくても出来る
package sample;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.support.WebBindingInitializer;
import org.springframework.web.context.request.WebRequest;
public class DateTimeBindingInitializer implements WebBindingInitializer {
@Override
public void initBinder(WebDataBinder binder, WebRequest request) {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
format.setLenient(false);
binder.registerCustomEditor(
Date.class,
new CustomDateEditor(
format,
false // isEmptyAllowed
)
);
}
}
っていうクラスを作っておいて、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:p="http://www.springframework.org/schema/p"
xmlns:mvc="http://www.springframework.org/schema/mvc"
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.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="webBindingInitializer">
<bean class="sample.DateTimeBindingInitializer" />
</property>
</bean>
</beans>
っていうような感じで作ったWebBingingInitializerな実装を注入させる事が出来ると
あとは普通にテストケースなりで
package swmvc;
import org.junit.Test;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
public class SampleControllerTest extends AbstractTestCase {
@Test
public void test() throws Exception {
mock.perform(get("/sample/test/2013-01-01"))
.andExpect(status().isOk());
}
}
余談: @DateTimeFormatを使う
@PathVariableに@DateTimeFormatを設定してもDate型をサポートさせる事が出来る模様
package sample;
import java.util.Date;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import static org.springframework.format.annotation.DateTimeFormat.ISO.DATE;
@Controller
@RequestMapping("/sample")
public class SampleController {
@RequestMapping("/test/{date}")
@ResponseBody
public String test(@PathVariable @DateTimeFormat(iso = DATE) Date date) throws Exception {
return "date: " + date;
}
}
但しこれを使うにはconversationServiceの設定が必要な模様
<?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:mvc="http://www.springframework.org/schema/mvc"
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.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="webBindingInitializer">
<bean class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
<property name="conversionService">
<bean class="org.springframework.format.support.FormattingConversionServiceFactoryBean" />
</property>
</bean>
</property>
</bean>
</beans>