Spring MVC中每个控制器中可以定义多个请求处理方法,我们把这种请求处理方法简称为Action,每个请求处理方法可以有多个不同的参数,以及一个多种类型的返回结果。
一、Action参数类型
如果在请求处理方法中需要访问HttpSession对象,则可以添加HttpSession作为参数,Spring会将对象正确的传递给方法,如:public String action(HttpSession session);若需要访问客户端语言环境和HttpServletRequest对象,则可以在方法签名上包含这样的参数,如:public String action(HttpServletRequest request,Locale locale)。可以在请求中出现的参数类型有:
org.springframework.web.context.request.WebRequest
org.springframework.web.context.request.NativeWebRequest
java.util.Locale 当前请求的语言环境
java.util.TimeZone 时区
java.io.InputStream或java.io.Reader
java.io.OutputStream或java.io.Writer
org.springframework.http.HttpMethod
java.security.Principal
HttpEntity >参数用于访问Servlet的HTTP请求的标题和内容
java.util.Map / org.springframework.ui.Model / org.springframework.ui.ModelMap 视图隐含模型
org.springframework.web.servlet.mvc.support.RedirectAttributes 重定向
命令或表单对象
基本数据类型,如int,String,double...
复杂数据类型,如自定义的POJO对象
HandlerAdapter
org.springframework.validation.Errors / org.springframework.validation.BindingResult 验证结果
org.springframework.web.bind.support.SessionStatus 会话状态
org.springframework.web.util.UriComponentsBuilder
@PathVariable 注解参数访问URI模板变量。
@MatrixVariable 注释参数用于访问位于URI路径段键值对对,矩阵变量。
@RequestParam 注解参数访问特定的Servlet请求参数,请求参数绑定。
@RequestHeader 注解参数访问特定的servlet请求HTTP标头,映射请求头。
@RequestBody 注解参数访问HTTP请求主体,注解映射请求体
@RequestPart 注解参数访问“的multipart / form-data的”请求部分的内容。处理客户端上传文件,多部分文件上传的支持
@SessionAttribute 注解参数会话属性
@RequestAttribute 注解参数访问请求属性
1.1、自动参数映射
1.1.1、基本数据类型
方法的参数可以是任意基本数据类型,如果方法参数名与http中请求的参数名称相同时会进行自动映射,视图foo目录下的index.jsp与示例代码如下:
// 自动参数映射
@RequestMapping("/action0")
public String action0(Model model, int id, String name) {
model.addAttribute("message", "name=" + name + ",id=" + id);
return "foo/index";
}
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
运行结果如下:
image
包装类型也一样,但如果参数中没有对应名称与类型的数据则会异常。
1.1.2、自定义数据类型
除了基本数据类型,也可以自定义的数据类型,如一个自定义的POJO对象,Spring MVC会通过反射把请中的参数设置到对象中,转换类型,示例代码如下:
package com.zhangguo.springmvc03.entities;
import java.io.Serializable;
/** * 产品 */
public class Product implements Serializable {
private static final long serialVersionUID = 1L;
private int id;
private String name;
private double price;
public Product() {
}
public Product(String name, double price) {
super();
this.name = name;
this.price = price;
}
public Product(int id, String name, double price) {
super();
this.id = id;
this.name = name;
this.price = price;
}
@Override
public String toString() {
return "编号(id):" + this.getId() + ",名称(name):" + this.getName() + ",价格(price):" + this.getPrice();
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
}
// 自动参数映射自定义数据类型
@RequestMapping("/action01")
public String action01(Model model, Product product) {
model.addAttribute("message", product);
return "foo/index";
}
运行结果如下:
image
示例中使用的是的URL中的参数,其实也可以是客户端提交的任意参数,特别是表单中的数据。
1.1.3、复杂数据类型
这里指的复杂数据类型指的是一个自定义类型中还包含另外一个对象类型,如用户类型中包含产品对象:
package com.zhangguo.springmvc03.entities;
public class User {
private String username;
private Product product;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public Product getProduct() {
return product;
}
public void setProduct(Product product) {
this.product = product;
}
}
示例代码如下:
// 自动参数映射复杂数据类型
@RequestMapping("/action02")
public String action02(Model model, User user) {
model.addAttribute("message", user.getUsername() + "," + user.getProduct().getName());
return "foo/index";
}
测试运行结果:
image
为了方便这里我使用的是url,这里当然可以是一个表单,如下代码所示:
1.1.4、数组
方法一:
提交时使用param1=aaa¶m1=bbb¶m1=3
接收时使用String param1[] 这种参数即可以获取数组的值
示例:
//3.自动参数映射数组数据类型
@RequestMapping("/act03")
public String act03(Model model,Integer[] id){
model.addAttribute("msg",Arrays.toString(id));
return "hi";
}
结果:
image
方法二:
提交时使用param1=aaa¶m1=bbb¶m1=3
接收时使用List
示例:
POJO Car.java
package com.zhangguo.springmvc01.entities;
import java.util.ArrayList;
import java.util.List;
/**车*/
public class Car {
/**编号*/
private int id;
/**名称*/
private String name;
/**价格*/
private double price;
/**尺寸*/
private Size size;
private List
public List
return ids;
}
public void setIds(List
this.ids = ids;
}
public Car(int id, String name, double price) {
this.id = id;
this.name = name;
this.price = price;
}
public Car() {
}
public Size getSize() {
return size;
}
public void setSize(Size size) {
this.size = size;
}
public static List
return cars;
}
public static void setCars(List
Car.cars = cars;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
@Override
public String toString() {
return "Car{" +
"id=" + id +
", name='" + name + '\'' +
", price=" + price +
", size=" + size +
", ids=" + ids +
'}';
}
public static List
static {
cars.add(new Car(101,"朗逸",16.59));
cars.add(new Car(102,"菲斯塔",15.50));
cars.add(new Car(103,"雅阁",25.98));
cars.add(new Car(104,"卡罗拉",17.58));
cars.add(new Car(105,"轩逸",16.15));
}
}
Action
@RequestMapping("/act02")
public String act02(Model model,Car car){
model.addAttribute("msg",car);
return "hi";
}
结果:
image
1.1.5、List集合类型
不能直接在action的参数中指定List
package com.zhangguo.springmvc03.entities;
import java.util.List;
//产品集合
public class ProductList {
private List
public List
return items;
}
public void setItems(List
this.items = items;
}
}
定义的action代码如下所示:
// 集合类型
@RequestMapping("/action03")
public String action03(Model model, ProductList products) {
model.addAttribute("message", products.getItems().get(0) + "
" + products.getItems().get(1));
return "foo/index";
}
在url中模拟表单数据,提交后的结果如下所示:
image
这里同样可以使用一个表单向服务器提交数据。
TomCat高版本可能会产生如下错误:
java.lang.IllegalArgumentException: Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC 3986
at org.apache.coyote.http11.Http11InputBuffer.parseRequestLine(Http11InputBuffer.java:479)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:684)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:806)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1498)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
Get请求新的安全规范要求URL中不能直接带[],如下所示:
25-Oct-2018 14:12:09.277 警告 [http-nio-8080-exec-2] org.apache.tomcat.util.http.parser.HttpParser.
解决办法(四种):
1、替换url请求。不用{}[]特殊字符! * ’( ) ; : @ & = + $ , / ? # [ ])
2、对请求编码解码。 UrlDecode、UrlEncode
3、配置Tomcat对字符的支持:
3.1、更换Tomcat版本 (注,Tomcat从 7.0.73, 8.0.39, 8.5.7 版本后添加了对Url的限制。)
3.2、配置tomcat支持|{}等字符的方法是:
在 conf/catalina.properties 中最后添加一行:
org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH=true
tomcat.util.http.parser.HttpParser.requestTargetAllow=|{}[]
注3.2这种方法从8.5以后就被放弃的了,新的方法如下:
tomcat.util.http.parser.HttpParser.requestTargetAllow is deprecated since Tomcat 8.5: tomcat official doc.
You can use relaxedQueryChars / relaxedPathChars in the connectors definition to allow these chars: tomcat official doc.
修改conf/server.xml文件,如下所示:
connectionTimeout="20000" redirectPort="8443" URIEncoding="utf-8" relaxedQueryChars="],["/> 1.1.6、Map集合类型 Map与List的实现方式基本一样,这里先定义了一个包装Map的类型ProductMap,代码如下所示: package com.zhangguo.springmvc03.entities; import java.util.Map; /** * * 产品字典 */ public class ProductMap { private Map public Map return items; } public void setItems(Map this.items = items; } } Action的定义如下: // Map类型 @RequestMapping("/action04") public String action04(Model model, ProductMap map) { model.addAttribute("message", map.getItems().get("p1") + " return "foo/index"; } 测试运行结果如下: image 集合类型基本都一样,set也差不多,问题是如果为了获得一个集合需要刻意去包装会很麻烦,可以通过@RequestParam结合@RequestBody等注解完成。 1.2、@RequestParam参数绑定 简单的参数可以使用上一节中讲过的自动参数映射,复杂一些的需使用@RequestParam完成,虽然自动参数映射很方便,但有些细节是不能处理的,如参数是否为必须参数,名称没有办法指定,参数的默认值就没有有办法做到了。如果使用@RequestParam可以实现请求参数绑定,Spring MVC会自动查找请求中的参数转类型并将与参数进行绑定,示例代码如下: 1.2.1、基本数据类型绑定与注解属性 package com.zhangguo.springmvc03.controllers; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; @Controller @RequestMapping("/foo") public class FooController { @RequestMapping("/action1") public String action1(Model model, @RequestParam(required = false, defaultValue = "99") int id) { model.addAttribute("message", id); return "foo/index"; } } @RequestParam共有4个注解属性,required属性表示是否为必须,默认值为true,如果请求中没有指定的参数会报异常;defaultValue用于设置参数的默认值,如果不指定值则使用默认值,只能是String类型的。name与value互为别名关系用于指定参数名称。 运行结果: image image 1.2.2、List与数组绑定基本数据类型 在上一节中我们使用自动参数映射是不能直接完成List与数组绑定的,结合@RequestParam可以轻松实现,示例代码如下所示: // List集合与数组类型 @RequestMapping("/action05") public String action05(Model model, @RequestParam("u") List model.addAttribute("message", users.get(0) + "," + users.get(1)); return "foo/index"; } 运行结果: image 直接在URL中输入测试数据可以绑定成功,使用表单同样可行,页面脚本如下:
" + map.getItems().get("p2"));
阅读
上网
电游
请求处理方法action代码如下:
// List与数组绑定基本数据类型
@RequestMapping("/action11")
public String action11(Model model, @RequestParam("id") List
model.addAttribute("message", Arrays.deepToString(ids.toArray()));
return "bar/index";
}
运行结果:
image
image
@RequestParam("id")是必须的,因为页面中的表单name的名称为id,所有服务器在收集数据时应该使用id页非ids,如果同名则可以省去。
1.2.3、@RequestBody
@RequestBody 注解将HTTP请求正文插入方法中,使用适合的 HttpMessageConverter将请求体写入某个对象。
作用:
该注解用于读取Request请求的body部分数据,使用系统默认配置的HttpMessageConverter进行解析,然后把相应的数据绑定到要返回的对象上;
再把HttpMessageConverter返回的对象数据绑定到 controller中方法的参数上。
使用时机:
A) GET、POST方式提时, 根据request header Content-Type的值来判断:
application/x-www-form-urlencoded, 可选(即非必须,因为这种情况的数据@RequestParam, @ModelAttribute也可以处理,当然@RequestBody也能处理);
multipart/form-data, 不能处理(即使用@RequestBody不能处理这种格式的数据);
其他格式, 必须(其他格式包括application/json, application/xml等。这些格式的数据,必须使用@RequestBody来处理);
B) PUT方式提交时, 根据request header Content-Type的值来判断:
application/x-www-form-urlencoded, 必须;multipart/form-data, 不能处理;其他格式, 必须;
说明:request的body部分的数据编码格式由header部分的Content-Type指定;
例如:
@RequestMapping(value = "user/login")
@ResponseBody
// 将ajax(datas)发出的请求写入 User 对象中
public User login(@RequestBody User user) {
// 这样就不会再被解析为跳转路径,而是直接将user对象写入 HTTP 响应正文中
return user;
}
@requestBody注解常用来处理content-type不是默认的application/x-www-form-urlcoded编码的内容,比如说:application/json或者是application/xml等。一般情况下来说常用其来处理application/json类型。
通过@requestBody可以将请求体中的JSON字符串绑定到相应的bean上,当然,也可以将其分别绑定到对应的字符串上。
例如:
$.ajax({
url:"/login",
type:"POST",
data:'{"userName":"admin","pwd","admin123"}',
content-type:"application/json charset=utf-8",
success:function(data){
alert("request success ! ");
}
});
action:
@requestMapping("/login")
public void login(@requestBody String userName,@requestBody String pwd){
System.out.println(userName+" :"+pwd);
}
这种情况是将JSON字符串中的两个变量的值分别赋予了两个字符串,但是假如我有一个User类,拥有如下字段:
String userName;
String pwd;
那么上述参数可以改为以下形式:@requestBody User user 这种形式会将JSON字符串中的值赋予user中对应的属性上
需要注意的是,JSON字符串中的key必须对应user中的属性名,否则是请求不过去的。
1.2.4、List与数组直接绑定自定义数据类型与AJAX
上一小节中我们绑定的集合中存放的只是基本数据类型,如果需要直接绑定更加复杂的数据类型则需要使用@RequestBody与@ResponseBody注解了,先解释一下他们的作用:
@RequestBody 将HTTP请求正文转换为适合的HttpMessageConverter对象。
@ResponseBody 将内容或对象作为 HTTP 响应正文返回,并调用适合HttpMessageConverter的Adapter转换对象,写入输出流。
AnnotationMethodHandlerAdapter将会初始化7个转换器,可以通过调用AnnotationMethodHandlerAdapter的getMessageConverts()方法来获取转换器的一个集合 List
ByteArrayHttpMessageConverter
StringHttpMessageConverter
ResourceHttpMessageConverter
SourceHttpMessageConverter
XmlAwareFormHttpMessageConverter
Jaxb2RootElementHttpMessageConverter
MappingJacksonHttpMessageConverter
@RequestBody默认接收的Content-Type是application/json,因此发送POST请求时需要设置请求报文头信息,否则Spring MVC在解析集合请求参数时不会自动的转换成JSON数据再解析成相应的集合,Spring默认的json协议解析由Jackson完成。要完成这个功能还需要修改配置环境,具体要求如下:
a)、修改Spring MVC配置文件,启用mvc注解驱动功能,
b)、pom.xml,添加jackson依赖,添加依赖的配置内容如下:
c)、ajax请求时需要设置属性dataType 为 json,contentType 为 'application/json;charse=UTF-8',data 转换成JSON字符串,如果条件不满足有可能会出现415异常。
Action定义的示例代码如下:
// List与数组直接绑定自定义数据类型与AJAX
@RequestMapping("/action21")
public void action21(@RequestBody List
response.setCharacterEncoding("UTF-8");
System.out.println(Arrays.deepToString(products.toArray()));
response.getWriter().write("添加成功");
}
action21的参数@RequestBody List
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
var products = new Array();
products.push({
id : 1,
name : "iPhone 6 Plus",
price : 4987.5
});
products.push({
id : 2,
name : "iPhone 7 Plus",
price : 5987.5
});
products.push({
id : 3,
name : "iPhone 8 Plus",
price : 6987.5
});
function addPdts_click1() {
$.ajax({
type : "POST",
//请求谓词类型
url : "bar/action21",
data : JSON.stringify(products), //将products对象转换成json字符串
contentType : "application/json;charset=UTF-8",
//发送信息至服务器时内容编码类型,(默认: "application/x-www-form-urlencoded")
dataType : "text", //预期服务器返回的数据类型
success : function(result) {
$("#msg").html(result);
}
});
}
function addPdts_click2() {
$.ajax({
type : "POST",
//请求谓词类型
url : "bar/action22",
data : JSON.stringify(products), //将products对象转换成json字符串
contentType : "application/json;charset=UTF-8",
//发送信息至服务器时内容编码类型,(默认: "application/x-www-form-urlencoded")
dataType : "json", //预期服务器返回的数据类型
success : function(result) {
var str = "";
$.each(result, function(i, obj) {
str += "编号:" + obj.id + ",名称:" + obj.name + ",价格:"+ obj.price + "
";
});
$("#msg").html(str);
}
});
}
页面中有两个方法,第一个方法是实现将一个json集合发送到服务器并映射成一个List集合;第二个方法是实现接收服务器返回的json对象。
点击按钮1时的运行结果如下:
image
控制台输出:
[编号(id):1,名称(name):iPhone 6 Plus,价格(price):4987.5, 编号(id):2,名称(name):iPhone 7 Plus,价格(price):5987.5, 编号(id):3,名称(name):iPhone 8 Plus,价格(price):6987.5]
点击按钮2时的运行结果如下:
image
1.3、重定向与Flash属性
在一个请求处理方法Action中如果返回结果为“index”字符则表示转发到视图index,有时候我们需要重定向,则可以在返回的结果前加上一个前缀“redirect:”,可以重定向到一个指定的页面也可以是另一个action,示例代码如下:
// 重定向
@RequestMapping("/action2")
public String action2(Model model) {
return "foo/index";
}
@RequestMapping("/action3")
public String action3(Model model) {
model.addAttribute("message", "action3Message");
return "redirect:action2";
}
当请求http://localhost:8087/SpringMVC02/foo/action3时运行结果如下:
image
在action3中返回的结果为redirect:action2,则表示重定向到action2这个请求处理方法,所有重定向都是以当前路径为起点的,请注意路径。在action3向model中添加了名称message的数据,因为重定向到action2中会发起2次请求,为了保持action3中的数据Spring MVC自动将数据重写到了url中。为了实现重定向时传递复杂数据,可以使用Flash属性,示例代码如下:
// 接收重定向参数
@RequestMapping("/action2")
public String action2(Model model, Product product) {
model.addAttribute("message", product);
System.out.println(model.containsAttribute("product")); // true
return "foo/index";
}
//重定向属性
@RequestMapping("/action3")
public String action3(Model model, RedirectAttributes redirectAttributes) {
Product product = new Product(2, "iPhone7 Plus", 6989.5);
redirectAttributes.addFlashAttribute("product", product);
return "redirect:action2";
}
当访问action3时,首先创建了一个product产口对象,将该对象添加到了Flash属性中,在重定向后取出,个人猜测应该暂时将对象存入了Session中。当请求foo/action3时运行结果如下:
image
url地址已经发生了变化,product对象其实也已经被存入了model中,在action的视图中可以直接拿到。
1.4、转发
str=”forward : 路径” 请求转发到一个页面中
str=”forward : controller的映射” 请求转发到一个controller方法中
示例:
//11.转发
@RequestMapping("/act11")
public String act11(Model model){
return "hi";
}
//12.转发
@RequestMapping("/act12")
public String act12(Model model){
model.addAttribute("msg","act12");
return "forward:act11";
}
结果:
image
URL没有变化,数据存在可以直接使用。
1.5、@ModelAttribute模型特性
@ModelAttribute可以应用在方法参数上或方法上,他的作用主要是当注解在方法中时会将注解的参数对象添加到Model中;当注解在请求处理方法Action上时会将该方法变成一个非请求处理的方法,但其它Action被调用时会首先调用该方法。
1.5.1、注解在参数上
当注解在参数上时会将被注解的参数添加到Model中,并默认完成自动数据绑定,示例代码如下:
@RequestMapping("/action6")
public String action6(Model model, @ModelAttribute(name = "product", binding = true) Product entity) {
model.addAttribute("message", model.containsAttribute("product") + "
" + entity);
return "foo/index";
}
运行结果:
image
其实不使用@ModelAttribute我也样可以完成参数与对象间的自动映射,但使用注解可以设置更多详细内容,如名称,是否绑定等。
1.5.2、注解在方法上
用于标注一个非请求处理方法,通俗说就是一个非Action,普通方法。如果一个控制器类有多个请求处理方法,以及一个有@ModelAttribute注解的方法,则在调用其它Action时会先调用非请求处理的Action,示例代码如下:
@RequestMapping("/action7")
public String action7(Model model) {
Map
for (String key : map.keySet()) {
System.out.println(key + ":" + map.get(key));
}
return "foo/index";
}
@ModelAttribute
public String noaction() {
System.out.println("noaction 方法被调用!");
String message = "来自noaction方法的信息";
return message;
}
当访问http://localhost:8087/SpringMVC03/foo/action7时,控制台显示结果如下:
image
非请求处理方法可以返回void,也可以返回一个任意对象,该对象会被自动添加到每一个要被访问的Action的Model中,key从示例中可以看出为类型名称。
二、Action返回值类型
ModelAndView
Model
Map 包含模型的属性
View
String 视图名称
void
HttpServletResponse
HttpEntity>或ResponseEntity>
HttpHeaders
Callable>
DeferredResult>
ListenableFuture>
ResponseBodyEmitter
SseEmitter
StreamingResponseBody
其它任意类型,Spring将其视作输出给View的对象模型
2.1、视图中url问题
新增一个action5,代码如下:
@RequestMapping("/action5")
public String action5(Model model) {
return "foo/action5";
}
在foo目录下添加视图action5.jsp,内容如下:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

目标结构如下:
image
访问结果:
image
这里图片访问不到的原因是因为:action5.jsp视图此时并非以它所在的目录为实际路径,他是以当前action所在的控制器为起始目录的,当前控制器的url为:http://localhost:8087/SpringMVC02/foo/,而图片的src为:../../images/3.jpg,向上2级后变成:http://localhost:8087/images/3.jpg,但我们的项目实际路径中并没有存放3.jpg这张图片,解决的办法是在视图中使用“绝对”路径;另外一个问题是我们将静态资源存放到WEB-INF下不太合理,因为该目录禁止客户端访问,修改后的视图如下:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
">
目录结构变化后如下所示:
image
运行结果:
image
小结:主要是借助了标签
2.2、返回值为String
2.2.1、String作为视图名称
默认如果action返回String,此时的String为视图名称,会去视图解析器的设定的目录下查找,查找的规则是:URL= prefix前缀+视图名称 +suffix后缀组成,示例代码如下:
//返回值为String
@RequestMapping("/action31")
public String action31(Model model)
{
model.addAttribute("message","action31");
return "bar/action31";
}
Spring MVC的配置文件内容如下:
class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
实际url=/WEB-INF/views/bar/action31.jsp
2.2.2、String作为内容输出
如果方法声明了注解@ResponseBody ,将内容或对象作为 HTTP 响应正文返回,并调用适合HttpMessageConverter的Adapter转换对象,写入输出流。些时的String不再是路径而是内容,示例脚本如下:
@RequestMapping("/action32")
@ResponseBody
public String action32()
{
return "not path,but content";
}
测试运行结果:
image
2.3、返回值为void
void在普通方法中是没有返回值的意思,但作为请求处理方法并非这样,存在如下两种情况:
2.3.1、方法名默认作为视图名
当方法没有返回值时,方法中并未指定视图的名称,则默认视图的名称为方法名,如下代码所示:
@RequestMapping("/action33")
public void action33()
{
}
直接会去访问的路径是:url=/WEB-INF/views/bar/action33.jsp,bar是当前控制器映射的路径,action33是方法名,上面的代码等同于:
@RequestMapping("/action33")
public String action33()
{
return "bar/action33"; //bar是控制器的路径
}
可见URL= prefix前缀+控制器路径+方法名称 +suffix后缀组成。
2.3.2、直接响应输出结果
当方法的返回值为void,但输出流中存在输出内容时,则不会去查找视图,而是将输入流中的内容直接响应到客户端,响应的内容类型是纯文本,如下代码所示:
@RequestMapping("/action34")
public void action34(HttpServletResponse response) throws IOException
{
response.getWriter().write("
void method
");}
运行结果如下:
image
可以看到h2标签并未渲染成标题。
2.4、返回值为ModelAndView
在旧的Spring MVC中ModelAndView使用频率非常高,它可以同时指定须返回的模型与视图对象或名称,示例代码如下:
@RequestMapping("/action35")
public ModelAndView action35()
{
//1只指定视图
//return new ModelAndView("/bar/index");
//2分别指定视图与模型
//Map
//model.put("message", "ModelAndView action35");
//return new ModelAndView("/bar/index",model);
//3同时指定视图与模型
//return new ModelAndView("/bar/index","message","action35 ModelAndView ");
//4分开指定视图与模型
ModelAndView modelAndView=new ModelAndView();
//指定视图名称
modelAndView.setViewName("/bar/index");
//添加模型中的对象
modelAndView.addObject("message", "
Hello ModelAndView
");return modelAndView;
}
ModelAndView有个多构造方法重载,单独设置属性也很方便,运行结果如下:
image
2.5、返回值为Map
当返回结果为Map时,相当于只是返回了Model,并未指定具体的视图,返回视图的办法与void是一样的,即URL= prefix前缀+控制器路径+方法名称 +suffix后缀组成,示例代码如下:
@RequestMapping("/action36")
public Map
{
Map
model.put("message", "Hello Map");
model.put("other", "more item");
return model;
}
实际访问的路径是:/SpringMVC03/WEB-INF/views/bar/action36.jsp,返回给客户端的map相当于模型,在视图中可以取出。
2.6、返回值为任意类型
2.6.1、返回值为基本数据类型
当返回结果直接为int,double,boolean等基本数据类型时的状态,测试代码如下:
@RequestMapping("/action37")
public Integer action37()
{
return 9527;
}
测试运行的结果是:exception is java.lang.IllegalArgumentException: Unknown return value type异常。
如果确实需要直接将基本数据类型返回,则可以使用注解@ReponseBody。
@RequestMapping("/action38")
@ResponseBody
public int action38()
{
return 9527;
}
运行结果:
image
2.6.2、当返值为自定义类型
当返回值为自定义类型时Spring会把方法认为是视图名称,与返回值为void的类似办法处理URL,但页面中获得数据比较麻烦,示例代码如下:
@RequestMapping("/action39")
public Product action39()
{
return new Product(1,"iPhone",1980.5);
}
如果存在action39对应的视图,页面还是可以正常显示。
image
如果在action上添加@ResponseBody注解则返回的是Product本身,而非视图,Spring会选择一个合适的方式解析对象,默认是json。示例代码如下:
@RequestMapping("/action39")
@ResponseBody
public Product action39()
{
return new Product(1,"iPhone",1980.5);
}
运行结果:
image
如果是接收json值,则需要使用注解@RequestBody指定在相应参数上。
2.7、返回值为Model类型
该接口Model定义在包org.springframework.ui下,model对象会用于页面渲染,视图路径使用方法名,与void类似。示例代码如下:
@RequestMapping("/action40")
public Model action40(Model model)
{
model.addAttribute("message", "返回类型为org.springframework.ui.Model");
return model;
}
运行结果:
image
2.8、自定义输出内容
2.8.1、输出Excel
返回的类型还有许多如view等,通过view可指定一个具体的视图,如下载Excel、Pdf文档,其实它们也修改http的头部信息,手动同样可以实现,如下代码所示:
@RequestMapping("/action41")
@ResponseBody
public String action41(HttpServletResponse response)
{
response.setHeader("Content-type","application/octet-stream");
response.setHeader("Content-Disposition","attachment; filename=table.xls");
return "
| Hello | Excel |
}
运行结果:
image
Content-disposition解释:
Content-disposition 是 MIME 协议的扩展,MIME 协议指示 MIME 用户代理如何显示附加的文件。当 Internet Explorer 接收到头时,它会激活文件下载对话框,它的文件名框自动填充了头中指定的文件名。(请注意,这是设计导致的;无法使用此功能将文档保存到用户的计算机上,而不向用户询问保存位置。)
服务端向客户端游览器发送文件时,如果是浏览器支持的文件类型,一般会默认使用浏览器打开,比如txt、jpg等,会直接在浏览器中显示,如果需要提示用户保存,就要利用Content-Disposition进行一下处理,关键在于一定要加上attachment:
Response.AppendHeader("Content-Disposition","attachment;filename=FileName.txt");
Content-Type解释:
MediaType,即是Internet Media Type,互联网媒体类型;也叫做MIME类型,在Http协议消息头中,使用Content-Type来表示具体请求中的媒体类型信息。
例如: Content-Type: text/html;charset:utf-8;
常见的MIME:
常见的媒体格式类型如下:
text/html : HTML格式
text/plain :纯文本格式
text/xml : XML格式
image/gif :gif图片格式
image/jpeg :jpg图片格式
image/png:png图片格式
以application开头的媒体格式类型:
application/xhtml+xml :XHTML格式
application/xml : XML数据格式
application/atom+xml :Atom XML聚合格式
application/json : JSON数据格式
application/pdf :pdf格式
application/msword : Word文档格式
application/octet-stream : 二进制流数据(如常见的文件下载)
application/x-www-form-urlencoded :