回顾:
在前面的学习中,我了解到spring核心servlet的执行顺序,以及对基本的spring web mvc的注解的配置,@Controller和@RequestMapping一些基本的用法,再就是在xml中配置了我们所需要用的interceptor,这一节,我将根据实例对mvc中的请求参数进行测试、学习,进而加深了解spring的工作,go ! 我将还会在maven里创建的工程里进行测试学习,最终的资源我也将会上传,也算是自己这段学习的一个成果, GOGOGO!
还是始于@RequestMapping的处理方法
这算是对上节学习中的一个补充学习,还是从定义@RequestMapping的处理方法谈起吧。在spring 3.1中引入了两个类来支持@RequestMapping使用,它们分别是:RequestMapingHandlerMapping和RequestMappingHandlerAdapter,在spring的官方说明中,它们都被建议使用,代表了spring的在不断革新、改进,一般我们在用xml配置或者在使用基于纯java配置的时候,它们都被默认开启使用。
@ReqeustMapping所映射的方法支持的参数类型多达到20来种,这里我不细细根据文档把它们写出来了,我要做的就是对它们给出的例子进行测试、学习。
返回类型也是有多达10几种,一般我们会用到的有:ModelAndView,model,view,String,void等。
用@RequestParam注解绑定request的参数
我们用到的项目是在maven学习第二节中的搭建的spsh,这里先一步一步让它支持mvc,首先加入spring-mvc依赖包:我们首去这个地址查询spring mvc最新的jar依赖:点击打开链接,找到maven-metadata文件后,将依赖加入到spsh工程的pom.xm中去:
<!-- 加入spring4.0的webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.0.0.RELEASE</version>
</dependency>
这个时候,系统工程自动将依赖的jar包从远程仓库下载下来(如果本地仓库没有的话),并引入到eclipse工程中去。spsh在建好以后是一个空工程,这里我们将它填满,首先我们这里是基于xml来配置的,就需要将DispatchServlet在窗口里配置上,在spsh的项目的web.xml配置好如下:
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<servlet>
<servlet-name>spsh</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spsh</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
</web-app>
我们这里用的servlet版本稍低,这里只是测试学习,所以先不管这些。在WEB-INF需要加入一个以spsh开头,以"-servlet.xml"结尾的默认的spring要在启动时读取的配置文件,这里的文件名字应该是:spsh-servlet..xml,将其加入到项目中去,配置是这样子的:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
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.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.spsh" />
</beans>
其中context:component-scan是说我们要对这个基本的包及其子文件夹下的文件进行扫描,扫描的目的就是发现其中使用@Controller,@Autowired等注解的类和属性,好将它们注册到spring的容器中去。
先给出我测试的Controller,代码如下:
package com.spsh.controller;
import hello.Pet;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.SessionAttributes;
@Controller
@RequestMapping("/hello")
public class HelloColtroller {
@RequestMapping(method=RequestMethod.GET)
// @RequestMapping("/test")
public String hello(@RequestParam(value="petId",required=false) int petId,ModelMap model) {
Pet pet = new Pet();
pet.setPetId(petId);
model.addAttribute("pet", pet);
return "/hello.jsp";
}
}
参数类型转换
@RequestParam,从代码里就可以看出,这是指传过来的参数的接收,用petId进行接收,默认情况之下required=true,指的是,必须传这样的一个参数,如果不传,就会报错,我们可以修改为:required=false,这样,请求这个方法的时候,就可以不用填写这个参数了。
默认情况之下,如果方法的参数不是String类型的话,spring会自动检测,并将从请求传过来的参数进行必要的转换,以让其和方法中的参数类型一致,以下,我们将传到后台的参数叫请求参数,将接收参数叫目标参数,一些简单的类型如:int 、long、Date都已经很好的支持自动转换了,我们当然可以能通过WebDataBinder来进行进一步的自定义这个参数转换的过程。
Spring 3 Type Conversion
package org.springframework.core.convert.converter;
public interface Converter<S, T> {
T convert(S source);
}
如果我们想要写出自己的转换设置,注必须要实现这个接口。其中S代表你所有转换来源,要保证不能为空,T就是转换成的目标源。在spring的core.convert.support里有最基本的stringToInterger的实现:
package org.springframework.core.convert.support;
final class StringToInteger implements Converter<String, Integer> {
public Integer convert(String source) {
return Integer.valueOf(source);
}
}
如果你在写自己的转换规则的时候,请保证你所写的代码是线程安全的。
ConversionService API
<bean id="conversionService"
class="org.springframework.context.support.ConversionServiceFactoryBean"/>
<bean id="conversionService"
class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<list>
<bean class="example.MyCustomConverter"/>
</list>
</property>
</bean>
<mvc:annotation-driven/>
这样的配置,一些默认的格式化工作,比如对整数的处理、对日期格式的处理,都会被加载进来来,我们也可以用自己定义的转换器,下面是官方文档给出的算定义配置 :
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
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.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<mvc:annotation-driven conversion-service="conversionService"/>
<bean id="conversionService"
class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="org.example.MyConverter"/>
</set>
</property>
<property name="formatters">
<set>
<bean class="org.example.MyFormatter"/>
<bean class="org.example.MyAnnotationFormatterFactory"/>
</set>
</property>
<property name="formatterRegistrars">
<set>
<bean class="org.example.MyFormatterRegistrar"/>
</set>
</property>
</bean>
</beans>
可以看出,mvc:annotation-driven里有一个属性,可以指向算定义的转换器,再将算定义的转换器注册到spring容器中即可。