2-处理器方法
已经学了创建控制器类,控制器类里的一个方法对应一个请求或者多个请求。使用@RequestMapping来进行配置。
下面具体来讲一下处理器方法。
@RequestMapping
@RequestMapping注解可以放在类上面,也可以放在方法上。但是含义是完全不一样的。
放在类上面
放在类上面,其实很简单。只有一种情况,就是当这个类中的所有方法对应的请求都有公共部分时,就可以把该公共部分提取出来放到类上。
表示类中的响应请求的方法都是以该地址作为父路径。
例如MyController类中有doSome()方法和doOther()方法,他们对应的请求分别是/test/some.do
和/test/other.do
,那么就可以把/test
抽取出来,放在类定义上面,也就是@RquestMapper(value="/test")
,然后在方法上只使用@RequestMapping(value="/some.do")
和@RequestMapping(value="/other.do")
即可。代码更简便,同时也便于修改。
放在方法上面
之前的例子已经用过了。@RequestMapping注解放在方法上。但只用到了value属性。@RequestMapping注解还有其他的属性。
下面来讲@RequestMapping的属性
value
用来指定请求的实际地址,指定的地址是URI格式。前端代码的请求地址要和这个值保持一致。
注意:只能一个方法对应多个请求,而不能一个请求对应多个方法,那样的话会报错。
前端代码中不能加/
。
method
指定请求的方式,例如GET、POST、PUT等
它的值是RequestMethod类的枚举值。
例如:@RequestMapping(method=RequestMethod.GET)
如果不指定请求方式,那么没有限制,任意一种请求方式都可以。
consumes
这个参数指定处理请求的提交内容类型Content-Type,例如application/json,application/html
也是是说,如果这个请求没有包含这个参数指定的提交内容类型,那么就不会处理。
produces
指定返回的内容类型,只有当请求头中的Accpet的值包含这个参数指定的值,才会处理。
同时其实也暗含了这个方法会返回指定类型的值。
params
指定request中必须包含某些指定参数值,才会让该方法处理。
格式为params="key=value,.."
。
headers
指定request中必须包含某些指定的header值,才让该方法处理请求。
格式为:headers="key=value,.."
。
处理器方法参数
处理器方法可以包含以下四类参数,这些参数会在调用时由框架自动赋值,只要在方法形参中定义好,我们可以直接在方法内使用
- HttpServletRequest
- HttpServletResponse
- HttpSession
- 请求中所携带的请求参数
例如想要使用前两个参数,直接在方法签名的形参列表定义即可:public ModelAndView doSome(HttpServletRequest request, HttpServletResponse response)
。
逐个参数接受
接受请求中所携带的请求参数,可以逐个参数接受。框架会自动进行类型转换。
只需要保证,前端代码的请求参数名和处理方法的参数名相同即可。
例如:
前端代码:
1 |
|
那么处理方法中的参数名和前端提交的参数名保持一致
1 |
|
运行结果:
可以看到参数正常接收到了。
POST方式解决乱码问题
当使用POST方式提交值为中文的参数时,会出现乱码。
我们可以使用以往的解决方法,就是调用请求对象request.setCharacterEncoding(),设为UTF-8。但是这样太麻烦,需要重复编写。
可以使用过滤器,来统一设置POST请求的编码方式。
可以自定义过滤器类,也可以使用SpringMVC提供的过滤器类CharacterEncodingFilter类。
在web.xml配置过滤器
需要在配置文件web.xml中注册过滤器。
该过滤器类有三个成员变量:
- encoding:字符串类型,指定项目使用的字符编码,一般用utf-8
- forceRequestEncoding:布尔类型,指定请求对象request是否使用字符集encoding,默认是false,需要改为true
- forceResponseEncoding布尔类型,指定响应对象response是否使用字符集encoding,默认是false,需要改为true
同时设置/*
,表示强制所有的请求都必须通过该过滤器。
即:
1 |
|
@RequestParam
当请求URL的请求参数名和处理方法的形参名不相同时,使用@RequestParam注解放在形参名前,用来指定请求提交的参数名。
该注解有三个属性:
- value:请求参数名
- required:指定该参数是否是必需,默认为true,即请求中必须包含该参数,如果没有,会抛出异常
- defaultValue:默认值,如果设置了该值,那么required自动设为false。无论你是否手动配置了required。
一般将required设为false。
例子:
修改前端代码:
1 |
|
那么方法签名改为:
1 |
|
对象参数接受
若把处理器方法的参数定义为一个Java对象,那么只要保证请求的参数名和这个对象的属性名相同即可。
与逐个参数接受差不多。
只不过变成了和Java对象的属性名相同。
适合用于请求参数比较多的情况。
这种方法在实际中应用的比较多。
例如:
前端代码:
1 |
|
创建一个类Student
1 |
|
那么在处理器方法中:
1 |
|
hello.jsp代码:
1 |
|
处理器方法返回值
常见的返回值有四种类型:
- ModelAndView
- String
- void,无返回值
- 自定义类型的对象
ModelAndView
如果处理器方法处理完以后,需要跳转到其他资源,并且要在跳转的资源间传递数据,那么处理器方法返回ModelAndView比较好的。
但如果,处理器方法只是进行跳转不传递数据,或者只传递数据并不向任何资源跳转(例如异步请求ajax),则此时不应该返回ModelAndView。
String
如果处理器方法执行完后,只进行资源跳转。那么可以返回String类型。返回的字符串可以指定逻辑视图名,视图解析器会将其解析,转换为物理视图地址(就是html、jsp等资源文件)。
如果跳转的资源是内部资源,那么因为已经在springmvc.xml文件中注册了视图解析器。所以直接返回方法名即可,视图解析器会将路径前缀和后缀拓展名进行拼接。
例如:
1 |
|
发起请求就可以跳转到hello.jsp文件。
void
如果处理器方法不需要跳转到其他资源,可以让处理器方法返回void。
例如对于ajax异步请求的响应。
Object
处理器方法可以返回Object对象,这个对象可以是String、Integer对象,也可以是自定义对象。但是返回的对象不是作为逻辑视图出现的。而是作为直接在页面显示的数据出现的。
返回对象,需要使用@ResponseBody注解,将转换后的JSON数据放入响应体中。通常是用来响应AJAX请求的。
使用步骤
导入pom依赖
因为返回Object数据,一般是将数据转换为JSON对象后传递给浏览器页面的。由Object转换为JSON,是由Jackson工具库完成的。需要导入Jackson的相关jar包。
声明注解驱动
将Object数据转换为JSON数据,需要由消息转换器HttpMessageConverter完成。转换器的开启,需要声明注解驱动。
需要在springmvc配置文件中声明注解驱动,加上:<mvc:annotation-driven />。
消息转换器的功能:完成Java对象到json、xml、text和二进制等数据格式的转换。或反过来的转换。
HttpMessageConverter
HttpMessageConverter是一个接口,负责将请求信息转换为一个对象(类型为T),将对象(类型为T)输出为响应信息。
定义了Java对象转换为json、xml等数据格式的方法。
该接口中有四个方法:
boolean canRead(Class<?> clazz, MediaType mediaType)
:指定转换器可以读取的对象类型,即转换器是否可以将请求信息转换为clazz类型的对象。同时指定支持MIME类型(text/html, application/json)。简单来说,这个 方法是用来检查输入流的数据格式是否可以转换为对应的Java对象
boolean canWrite(Class<?> clazz, MediaType mediaType)
:指定转换器是否可以将clazz类型的对象写入到响应流中,响应流支持的媒体类型在MediaType中定义简单来说,这个 方法是用来检查处理器方法的返回值是否可以转换为mediaType中的数据格式
T read(Class<?> clazz, HttpInputMessage inputMessage)
:将请求信息流转换为T类型的对象T write(Class<?> clazz, HttpOutputMessage outputMessage)
:将T类型的对象写入到响应流中,同时指定响应媒体类型为contentType。就是将处理器方法返回的对象转换成指定数据格式。如果是json,就会使用Jackson的工具库来进行转换。其中MdeiaType用来表示数据格式,例如json、xml等
这个接口有很多实现类,这些实现类分别完成了Java对象到json、xml等数据格式的转换。
当Spring容器进行初始化时,在读取<mvc:annotation-driven />时,默认会创建七个HttpMessageConverter接口的实现类对象。
这七个实现类对象分别是:
- ByteArrayHttpMessageConverter:负责读取二进制格式数据和写出二进制格式数据
- StringHttpMessageConverter:负责读取字符串格式数据和写出字符串格式数据
- ResourceHttpMessageConverter:读取资源文件和写出资源文件数据
- SourceHttpMessageConverter:能够读、写来自HTTP请求与相应的javax.xml.transform.Source,支持DOMSource,SAXSource和StreamSource的XML格式
- AllEncodingpassingFormHttpMessageConverter:负责处理表单数据
- Jaxb2RootElementHttpMessageConverter:使用JAXB负责读取和写入xml格式的数据
- MapperJackson2HttpMessageConverter:负责读取和写入json格式的数据。使用Jackson的ObjectMapper读写json数据。操作Object类型数据。可读取application/json,相应媒体类型为application/json
其中加粗的两个比较常用。
添加@ResponseBody注解
将该注解放在对应处理器方法上面。通过HttpServletResponse相应请求,返回数据的。
和其他注解没有顺序先后。
例子
输出自定义对象
向浏览器返回一个自定义的对象Student,转换为json格式。
处理器方法:
1 |
|
异步请求代码:
1 |
|
运行结果:
返回对象Json数据的处理流程:
- 框架会将Student类型,调用框架中的ArrayList
中每个实现类对象的canWrite方法,检查哪个HttpMessageConverter接口的实现类可以处理Student类型的数据,找到MapperJackson2HttpMessageConverter实现类 - 框架调用实现类的write方法,把student对象转换为json数据,调用Jackson的ObjectMapper
- 框架调用@ResponseBody把结果输出到浏览器,ajax请求处理完毕。
输出List集合
将List集合转换为JSON对象数组输出。
和上个例子差不多
处理器方法:
1 |
|
JS代码:
1 |
|
运行结果:
返回文本数据
处理器方法返回的是String类型,这里String表示数据,而不是视图。
区分返回值String是数据还是视图的方法:
如果有注解@ResponseBody,那么就是数据;没有,就是视图
返回String时,默认使用"text/plain;charset=ISO-8859-1"作为contentType,中文会出现乱码。(虽然在web.xml设置了拦截器,强制设置编码方式,但好像对这个没有效果)
解决方案:在@RequestMapping注解中加上属性produces = “text/plain;charset=utf-8”,来指定新的contentType
处理器方法:
1 |
|
JS代码:
1 |
|
运行结果: