SpringMVC - 方法/参数篇
1 @RequestMapping 注解
1.1 @RequestMapping 出现的位置
@RequestMapping
注解定义了处理器对于请求的映射规则。该注解可以定义在类上,也可以定义在方法上,但是含义不同。- 一个
@Controller
所注解的类中,可以定义多个处理器方法。当然,不同的处理器方法所匹配的URI
是不同的。这些不同的URI
被指定在注解于方法之上的@RequestMapping
的value
属性中。但若这些请求具有相同的URI部分,则这些相同的URI
,可以被抽取到注解在类之上的RequestMapping
的value
属性中。此时的这个URI表示模块的名称。URI的请求是相对于Web的根目录。在类的级别上的注解会将一个特定请求或者请求模式映射到一个控制器之上。之后你还可以另外添加方法级别的注解来进一步指定到处理方法的映射关系。
示例:UserController.java
package com.murphy.controller;
import com.murphy.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
/**
* Controller
* @RequstMapping("user") - 使方法映射为 user/first.do | user/add.do | user/update.do
*
* @author murphy
*/
@Controller
@RequestMapping("user")
public class UserController {
@Autowired
private UserService userService;
@RequestMapping("/first.do")
public ModelAndView first() {
System.out.println("UserController - first---");
userService.add();
ModelAndView mv = new ModelAndView();
// 相当于 request.setAttribute("","")
mv.addObject("userName","murphy");
// 未来经过SpringMVC的视图解析器处理,然后转换成物理资源路径,相当于 request.getDispatcher("index.jsp").forward(req,resp)
mv.setViewName("index");
// 经过InternalResourceViewResolver对象的处理之后加上前后缀就变为了 /jsp/index.jsp
return mv;
}
@RequestMapping(value = "/add.do", method = RequestMethod.GET)
public ModelAndView addUser() {
System.out.println("UserController - addUser---");
ModelAndView mv = new ModelAndView();
// 视图解析器 映射成为物理资源路径:/jsp/user/add.jsp
mv.setViewName("user/add");
return mv;
}
@RequestMapping(value = "/update.do", method = RequestMethod.POST)
public ModelAndView updateUser() {
System.out.println("UserController - updateUser---");
ModelAndView mv = new ModelAndView();
// 视图解析器 映射成为物理资源路径:/jsp/user/update.jsp
mv.setViewName("user/update");
return mv;
}
}
浏览器中访问:
1.2 指定请求提交方式
@RequestMapping
的method
属性,用来对被注解方法所处理请求的提交方式进行限制,即只有满足method
属性指定的提交方式的请求,才会执行该被注解方法。Method
属性的取值为RequestMethod
枚举常量。常用的为RequestMethod.GET
与RequestMethod.POST
,分别表示提交方式的匹配规则为GET
与POST
提交。
以下表格列出了常用的提交方式:
请求方式 | 提交方式 |
---|---|
地址栏请求 | get请求 |
超链接请求 | get请求 |
表单请求 | 默认get,可以指定post |
AJAX请求 | 默认get,可以指定post |
1.3 补充url-pattern解析
1.3.1 url-pattern解析
在web.xml
配置SpringMVC的前端控制器时有这个节点。这个节点中的值一般有两种写法:
1. *.do
在没有特殊要求的情况下,SpringMVC 的前端控制器 DispatcherServlet 的常使用后辍匹配方式,可以写为*.do 或者 *.action, *.mvc 等。
2. /
可以写为/,但是 DispatcherServlet 会将向静态内容--例如.css、.js、图片等资源的获取请求时,也会当作是一个普通的 Controller 请求。前端控制器会调用处理器映射器为其查找相应的处理器。肯定找不到啊,所以所有的静态资源获取请求也均会报 404 错误。
案例:在index.jsp
页面添加一张图片,如果节点中的值为*.do
,图片可以正常访问,但是如果为/
就不能访问。
- 项目中添加图片,同时修改index.jsp页面
- 修改
web.xml
- 此时访问图片无法显示
1.3.2 静态资源访问
如果的值配置为/
后,静态资源可以通过以下两种方法解决。
1.3.2.1 使用 < mvc:default-servlet-handler/>
在springmvc.xml
的配置文件中添加如下内容:
<!-- 方案1:默认静态资源处理器 -->
<mvc:default-servlet-handler/>
<!--
声明了<mvc:default-servlet-handler/> 后,springmvc框架会在容器中创建DefaultServletHttpRequestHandler处理器对象。该对象会对所有进入DispatcherServlet的URL进行检查。如果发现是静态资源的请求,就将该请求转由Web应用服务器默认的Servlet处理。
一般的服务器都有默认的Servlet。例如咱们使用的Tomcat服务器中,有一个专门用于处理静态资源访问的Servlet名叫DefaultServlet。其<servlet-name/>为default。可以处理各种静态资源访问请求。该Servlet注册在Tomcat服务器的web.xml中。在 Tomcat安装目录/conf/web.xml。
-->
1.3.2.2 使用 < mvc:resources/>
在springmvc.xml
的配置文件中添加如下内容:
<mvc:resources mapping="../img/**" location="img/"/>
<mvc:resources mapping="../js/**" location="js/"/>
<mvc:resources mapping="../css/**" location="css/"/>
<!--
location: 表示静态资源所在目录。当然,目录不要使用/WEB-INF/及其子目录。
mapping: 表示对该资源的请求。注意,后面是两个星号 **。
-->
在Spring3.0版本后,Spring定义了专门用于处理静态资源访问请求的处理器ResourceHttpRequestHandler
。并且添加了<mvc:resources/ >
标签,专门用于解决静态资源无法访问问题。
2 处理器方法的参数
处理器方法可以包含以下四类参数,这些参数会在系统调用时由系统自动赋值,所以我们可以在方法内直接使用。以下是这四类参数:
HttpServletRequest
HttpServletResponse
HttpSession
- 请求中所携带的请求参数
准备工作:创建新的控制器ParamController.java
和前端页面hello.jsp
页面
ParamController.java
/**
* 参数控制器
*
* @author murphy
*/
@Controller
@RequestMapping("param")
public class ParamController {
@RequestMapping("hello")
public ModelAndView hello() {
return new ModelAndView("hello");
}
}
hello.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Hello</title>
</head>
<body>
<h3>1. 直接使用方法的参数逐个接收</h3>
<form action="/param/test" method="post">
用户ID:<input type="text" name="userId"/><br>
用户名称:<input type="text" name="userName"/><br>
用户位置:<input type="text" name="userLoc"/><br>
<button type="submit">提交</button>
</form>
</body>
</html>
2.1 直接使用方法的参数逐个接收
/**
* 参数控制器
*
* @author murphy
*/
@Controller
@RequestMapping("param")
public class ParamController {
/**
* 1. 直接使用方法的参数逐个接收:方法的参数名称必须与用户请求中携带的参数名称保持一致
* 好处:不需要进行类型转换
* @param userId
* @param userName
* @param userLoc
* @return
*/
@RequestMapping("test01")
public ModelAndView test01(Integer userId, String userName, String userLoc) {
System.out.println("test01 - ");
System.out.println(userId);
System.out.println(userName);
System.out.println(userLoc);
return new ModelAndView("ok");
}
@RequestMapping("hello")
public ModelAndView hello() {
return new ModelAndView("hello");
}
}
2.2 使用对象接收多个参数
hello.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Hello</title>
</head>
<body>
<h3>2. 使用对象接收多个参数</h3>
<form action="/param/test02" method="post">
用户ID:<input type="text" name="userId"/><br>
用户名称:<input type="text" name="userName"/><br>
用户位置:<input type="text" name="userLoc"/><br>
<button type="submit">提交</button>
</form>
</body>
</html>
ParamController.java
**
* 参数控制器
*
* @author murphy
*/
@Controller
@RequestMapping("param")
public class ParamController {
/**
* 使用对象接收多个参数:要求用户请求中携带的参数名称必须与实体类中的属性保持一致,否则就获取不到
* @param user
* @return
*/
@RequestMapping("test02")
public ModelAndView test02(User user) {
System.out.println("test02 - ");
System.out.println(user);
return new ModelAndView("ok");
}
@RequestMapping("hello")
public ModelAndView hello() {
return new ModelAndView("hello");
}
}
2.3 请求参数和方法名称的参数不一致
hello.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Hello</title>
</head>
<body>
<h3>3. 请求参数和方法名称的参数不一致</h3>
<form action="/param/test03" method="post">
用户ID:<input type="text" name="userId"/><br>
用户名称:<input type="text" name="userName"/><br>
用户位置:<input type="text" name="userLoc"/><br>
<button type="submit">提交</button>
</form>
</body>
</html>
ParamController.java
/**
* 参数控制器
*
* @author murphy
*/
@Controller
@RequestMapping("param")
public class ParamController {
/**
* 请求参数和方法名称的参数不一致:使用@RequestParam进行矫正
* value属性表示请求中的参数名称
* required属性表示参数是否是必须的:true - 必须赋值,否则报出400错误 / false:可以不赋值,结果为空
* @RequestParam - value = "name" / required = false - 若无法取得,则赋空值,默认为true
* @param id
* @param name
* @param loc
* @return
*/
@RequestMapping("test03")
public ModelAndView test03(@RequestParam("userId") Integer id,
@RequestParam("userName") String name,
@RequestParam("userLoc") String loc) {
System.out.println("test03 - ");
System.out.println(id);
System.out.println(name);
System.out.println(loc);
return new ModelAndView("ok");
}
@RequestMapping("hello")
public ModelAndView hello() {
return new ModelAndView("hello");
}
}
2.4 使用 HttpServletRequest 对象获取参数
hello.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Hello</title>
</head>
<body>
<h3>4. 使用HttpServletRequest对象获取参数</h3>
<form action="/param/test04" method="post">
用户ID:<input type="text" name="userId"/><br>
用户名称:<input type="text" name="userName"/><br>
用户位置:<input type="text" name="userLoc"/><br>
<button type="submit">提交</button>
</form>
</body>
</html>
ParamController.java
/**
* 参数控制器
*
* @author murphy
*/
@Controller
@RequestMapping("param")
public class ParamController {
/**
* 使用HttpServletRequest对象获取参数:同原来的JavaWeb中使用的方式一致
* @param request
* @return
*/
@RequestMapping("test04")
public ModelAndView test04(HttpServletRequest request) {
System.out.println("test04 - ");
String userId = request.getParameter("userId");
String userName = request.getParameter("userName");
String userLoc = request.getParameter("userLoc");
if (userId != null) {
System.out.println(Integer.valueOf(userId));
}
System.out.println(userName);
System.out.println(userLoc);
return new ModelAndView("ok");
}
@RequestMapping("hello")
public ModelAndView hello() {
return new ModelAndView("hello");
}
}
2.5 直接使用URL地址传参
hello.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Hello</title>
</head>
<body>
<h3>5. 直接使用URL地址传参</h3>
<form action="/param/test05" method="post">
用户ID:<input type="text" name="userId"/><br>
用户名称:<input type="text" name="userName"/><br>
用户位置:<input type="text" name="userLoc"/><br>
<button type="submit">提交</button>
</form>
</body>
</html>
ParamController.java
/**
* 参数控制器
*
* @author murphy
*/
@Controller
@RequestMapping("param")
public class ParamController {
/**
* 直接使用URL地址传参:借助 @PathVariable()
* Ex:localhost:8080/param/test05/1001/murphy/Wuxi
* @param userId
* @param userName
* @param userLoc
* @return
*/
@RequestMapping("test05/{id}/{name}/{loc}")
public ModelAndView test05(@PathVariable("id") Integer userId,
@PathVariable("name") String userName,
@PathVariable("loc") String userLoc) {
System.out.println("test05 - ");
System.out.println(userId);
System.out.println(userName);
System.out.println(userLoc);
return new ModelAndView("ok");
}
@RequestMapping("hello")
public ModelAndView hello() {
return new ModelAndView("hello");
}
}
2.6 获取日期类型的参数
hello.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Hello</title>
</head>
<body>
<h3>6. 获取日期类型的参数</h3>
<form action="/param/test06" method="post">
用户ID:<input type="text" name="userId"/><br>
用户名称:<input type="text" name="userName"/><br>
用户位置:<input type="text" name="userLoc"/><br>
创建日期:<input type="text" name="createTime"><br>
<button type="submit">提交</button>
</form>
</body>
</html>
User.java
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date createTime;
@Override
public String toString() {
return "User{" +
"userId=" + userId +
", userName='" + userName + '\'' +
", userLoc='" + userLoc + '\'' +
", createTime=" + createTime +
'}';
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
ParamController.java
/**
* 参数控制器
*
* @author murphy
*/
@Controller
@RequestMapping("param")
public class ParamController {
/**
* 获取日期的参数
* @param user
* @return
*/
@RequestMapping("test06")
public ModelAndView test06(User user) {
System.out.println("test06 - ");
System.out.println(user);
return new ModelAndView("ok");
}
@RequestMapping("hello")
public ModelAndView hello() {
return new ModelAndView("hello");
}
}
2.7 获取数组类型的参数
hello.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Hello</title>
</head>
<body>
<h3>7. 获取数组类型的参数</h3>
<form action="/param/test07" method="post">
用户名称1:<input type="text" name="userName"><br>
用户名称2:<input type="text" name="userName"><br>
用户名称3:<input type="text" name="userName"><br>
<button type="submit">提交</button>
</form>
</body>
</html>
ParamController.java
/**
* 参数控制器
*
* @author murphy
*/
@Controller
@RequestMapping("param")
public class ParamController {
/**
* 获取数组类型的参数
* @param userName
* @return
*/
@RequestMapping("test07")
public ModelAndView test07(String[] userName, HttpServletRequest request) {
System.out.println("test07 - ");
// 方式1:
for (String s : userName) {
System.out.println(s);
}
// 方式2:
String[] userNames = request.getParameterValues("userName");
for (String name : userNames) {
System.out.println(name);
}
return new ModelAndView("ok");
}
@RequestMapping("hello")
public ModelAndView hello() {
return new ModelAndView("hello");
}
}
2.8 获取集合类型的参数
hello.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Hello</title>
</head>
<body>
<h3>8. 获取集合类型的参数</h3>
<form action="/param/test07" method="post">
用户名称1:<input type="text" name="userName"><br>
用户名称2:<input type="text" name="userName"><br>
用户名称3:<input type="text" name="userName"><br>
<button type="submit">提交</button>
</form>
</body>
</html>
ParamController.java
/**
* 参数控制器
*
* @author murphy
*/
@Controller
@RequestMapping("param")
public class ParamController {
/**
* 获取集合类型的数据:
简单类型的数据可以通过@RequestParam注解实现;对象集合不支持直接获取,必须封装在类中,作为一个属性操作
* @param userList
* @return
*/
@RequestMapping("test08")
public ModelAndView test08(@RequestParam("userName") List<String> userList) {
System.out.println("test08 - ");
for (String s : userList) {
System.out.println(s);
}
return new ModelAndView("ok");
}
@RequestMapping("hello")
public ModelAndView hello() {
return new ModelAndView("hello");
}
}
SpringMVC不支持直接从参数中获取对象集合类型,需要将对象集合封装到实体类中。
案例源码:
创建实体类QueryVO.java
/**
* Query
*
* @author murphy
*/
public class QueryVO {
private List<User> userList;
public List<User> getUserList() {
return userList;
}
public void setUserList(List<User> userList) {
this.userList = userList;
}
}
前端页面hello.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Hello</title>
</head>
<body>
<h3>9. 获取集合类型的对象</h3>
<form action="/param/test09" method="post">
用户ID1:<input type="text" name="userList[0].userId"><br>
用户ID2:<input type="text" name="userList[1].userId"><br>
用户ID3:<input type="text" name="userList[2].userId"><br>
用户名称1:<input type="text" name="userList[0].userName"><br>
用户名称2:<input type="text" name="userList[1].userName"><br>
用户名称3:<input type="text" name="userList[2].userName"><br>
用户地址1:<input type="text" name="userList[0].userLoc"><br>
用户地址2:<input type="text" name="userList[1].userLoc"><br>
用户地址3:<input type="text" name="userList[2].userLoc"><br>
<button type="submit">提交</button>
</form>
</body>
</html>
控制器ParamController.java
/**
* 参数控制器
*
* @author murphy
*/
@Controller
@RequestMapping("param")
public class ParamController {
/**
* 获取集合类型对象 - 对象
* @param vo
* @return
*/
@RequestMapping("test09")
public ModelAndView test09(QueryVO vo) {
System.out.println("test09 - ");
for (User user : vo.getUserList()) {
System.out.println(user);
}
return new ModelAndView("ok");
}
@RequestMapping("hello")
public ModelAndView hello() {
return new ModelAndView("hello");
}
}
3 请求参数中文乱码
对于前面所接收的请求参数,若含有中文,则会出现中文乱码问题。Spring对于请求参数中的中文乱码问题,给出了专门的字符集过滤器CharacterEncodingFilter
类。如图所示。
3.1 乱码解决方案
- 在
web.xml
中注册字符集过滤器,推荐将该过滤器注册在其它过滤器之前。因为过滤器的执行是按照其注册顺序进行的。
在web.xml
配置文件直接注册字符集
<!-- 配置中文乱码的过滤器:post请求中文乱码问题的解决方案 -->
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<!-- 指定字符集 -->
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<!-- 强制编码转换 -->
<!-- 强制request使用字符集encoding -->
<init-param>
<param-name>forceRequestEncoding</param-name>
<param-value>true</param-value>
</init-param>
<!-- 强制response使用字符集encoding -->
<init-param>
<param-name>forceResponseEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<!-- 过滤所有请求 -->
<url-pattern>/*</url-pattern>
</filter-mapping>
3.2 解决方案原理
4 处理器方法的返回值
- 使用
@Controller
注解的处理器的处理器方法,咱们根据实际的业务选择不同的返回值,其返回值常用的有四种类型:- ModelAndView
- String
- 返回自定义类型对象
- 无返回值 void
案例准备工作:
创建控制器ResultController.java
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
/**
* 返回值问题
*
* @author murphy
*/
@Controller
@RequestMapping("result")
public class ResultController {
}
在jsp
文件夹中添加页面result.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Result</title>
</head>
<body>
<h3>Result -</h3>
</body>
</html>
4.1 返回ModelAndView
- 如果是前后端不分的开发,大部分情况下,我们返回
ModelAndView
,即数据模型 + 视图:
控制器ResultController.java
中添加方法:
/**
* 返回值问题
*
* @author murphy
*/
@Controller
@RequestMapping("result")
public class ResultController {
/**
* 返回值:ModelAndView - 既有数据的携带,也有资源的跳转
* @return
*/
@RequestMapping("test01")
public ModelAndView test01() {
// 模型与视图
ModelAndView mv = new ModelAndView();
// 携带数据 - 相当于 request.setAttribute("userName", "murphy")
mv.addObject("userName","murphy");
// 设置视图名称 - 经过视图解析器InternalResourceViewResolver的处理,将逻辑视图名称加上前后缀变为物理资源路径 /jsp/result.jsp
mv.setViewName("result");
return mv;
}
}
Model
中,放我们的数据,然后在ModelAndView
中指定视图名称。- 当处理器方法处理完后,需要跳转到其它资源的同时传递数据,选择返回
ModelAndView
比较好,但是如果只是需要传递数据或者跳转之一,这个时候ModelAndView
就不是最优选择。
result.jsp
页面中添加如下内容:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Result</title>
</head>
<body>
<h3>Result -</h3>
<h5>test01 - ${userName}</h5>
</body>
</html>
4.2 返回String
- 上一种方式中的
ModelAndView
可以拆分为两部分——Model
和View
,在SpringMVC中,Model
我们可以直接在参数中指定,然后返回值是逻辑视图名 ,视图解析器解析可以将逻辑视图名称转换为物理视图地址。 - 视图解析器通过内部资源视图解析器
InternalResourceViewResolver
将字符串与解析器中的prefix
和suffix
结合形成要跳转的额URI
。
控制器ResultController.java
中添加方法:
/**
* 返回值问题
*
* @author murphy
*/
@Controller
@RequestMapping("result")
public class ResultController {
/**
* 返回值:String
* @param request
* @return
*/
@RequestMapping("test02")
public String test02(HttpServletRequest request) {
User user = new User();
user.setUserId(1001);
user.setUserName("murphy");
user.setUserLoc("Wuxi");
// 携带数据
request.setAttribute("user",user);
request.getSession().setAttribute("user",user);
// 资源跳转 - 经过视图解析器InternalResourceViewResolver的处理,将逻辑视图名称加上前后缀变为物理资源路径 /jsp/result.jsp
return "result";
}
}
result.jsp
页面中添加如下内容:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Result</title>
</head>
<body>
<h3>Result -</h3>
<h5>test01 - ${userName}</h5>
<h5>test02 - request作用域获取: - ${requestScope.user.userName} - ${requestScope.user.userLoc}</h5>
<h5>test02 - session作用域获取: - ${sessionScope.user.userName} - ${sessionScope.user.userLoc}</h5>
</body>
</html>
4.3 返回对象类型
- 当处理器方法返回
Object
对象类型的时候,可以是Integer、String、Map、List
,也可以是自定义的对象类型。但是无论是什么类型,都不是作为逻辑视图出现,而是直接作为数据返回然后展示的。一般前端发起Ajax
请求的时候都会使用直接返回对象的形式。 - 返回对象的时候,需要使用
@ResponseBody
注解,将转换后的JSON
数据放入到响应体中。
pom.xml
文件中添加两个依赖
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.12.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.3</version>
</dependency>
4.3.1 返回基础类型
/**
* 返回值问题
*
* @author murphy
*/
@Controller
@RequestMapping("result")
public class ResultController {
/**
* 返回对象类型:Integer/Double/String/自定义类型/List/Map
* 返回的不是逻辑视图的名称,而直接就是数据返回,一般与Ajax请求搭配使用
* 相当于JSON格式的数据直接返回给响应体,一定要与@ResponseBody搭配使用
* @return
*/
@ResponseBody
@RequestMapping("test03-1")
public Integer test03_1() {
return 666;
}
@ResponseBody
@RequestMapping("test03-2")
public String test03_2() {
return "Test";
}
}
4.3.2 返回自定义对象类型
/**
* 返回值问题
*
* @author murphy
*/
@Controller
@RequestMapping("result")
public class ResultController {
@ResponseBody
@RequestMapping("test03-3")
public User test03_3() {
User user = new User();
user.setUserId(1001);
user.setUserName("murphy");
user.setUserLoc("Wuxi");
return user;
}
}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Result</title>
<script src="/js/jquery-1.12.4.min.js"></script>
</head>
<body>
<h3>Result -</h3>
<button type="button" id="btn1">Ajax请求</button>
<div>
<h5>Ajax请求自定义对象的结果展示:</h5>
<p id="res"></p>
</div>
<script>
$(function (){
$("#btn1").click(function (){
$.ajax({
type: "POST",
url: "/result/test03-3",
data: "",
success: function (msg) {
alert("Data Saved: " + msg);
var id = msg.userId;
var name = msg.userName;
var loc = msg.userLoc;
$("#res").html("id:" + id + ", name:" + name + ", loc:" + loc);
}
});
});
});
</script>
</body>
</html>
4.3.3 返回集合List
/**
* 返回值问题
*
* @author murphy
*/
@Controller
@RequestMapping("result")
public class ResultController {
/**
* 返回List集合对象
* @return
*/
@ResponseBody
@RequestMapping("test03-4")
public List<User> test03_4() {
List<User> users = new ArrayList<>(5);
for (int i=0; i<5; i++) {
User user = new User();
user.setUserId(i+1);
user.setUserName("murphy" + i);
user.setUserLoc("Wuxi");
users.add(user);
}
return users;
}
}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Result</title>
<script src="/js/jquery-1.12.4.min.js"></script>
</head>
<body>
<div>
<button type="button" id="btn2">Ajax请求List对象</button>
<h5>Ajax请求List的结果展示:</h5>
<p id="res2"></p>
</div>
<script>
$(function (){
$("#btn2").click(function (){
$.ajax({
type: "POST",
url: "/result/test03-4",
data: "",
success: function (list) {
alert("Data Saved: " + list);
var str = "";
for (var i=0; i<list.length; i++) {
var obj = list[i];
str += "id:" + obj.userId + ", name:" + obj.userName + ", loc:" + obj.userLoc + "<br/>";
}
$("#res2").html(str);
}
});
});
});
</script>
</body>
</html>
4.3.4 返回集合Map
// 修改实体类
@DateTimeFormat(pattern = "yyyy-MM-dd")
@JsonFormat(pattern = "yyyy-MM-dd")
private Date createTime;
/**
* 返回值问题
*
* @author murphy
*/
@Controller
@RequestMapping("result")
public class ResultController {
/**
* 返回Map集合对象
* @return
*/
@ResponseBody
@RequestMapping("test03-5")
public Map<String, User> test03_5() {
Map<String, User> map = new HashMap<>();
for (int i=0; i<5; i++) {
User user = new User();
user.setUserId(i+1);
user.setUserName("murphy" + i);
user.setUserLoc("Wuxi");
user.setCreateTime(new Date());
map.put(user.getUserId()+"", user);
}
return map;
}
}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Result</title>
<script src="/js/jquery-1.12.4.min.js"></script>
</head>
<body>
<div>
<button type="button" id="btn2">Ajax请求List对象</button>
<h5>Ajax请求List的结果展示:</h5>
<p id="res2"></p>
</div>
<script>
$(function (){
$("#btn3").click(function (){
$.ajax({
type: "POST",
url: "/result/test03-5",
data: "",
success: function (map) {
alert("Data Saved: " + map);
var str = "";
$.each(map,function (i,obj) {
str += "name: " + obj.userName + ", id: " + obj.userId + ", loc: " + obj.userLoc + "<br/>";
})
$("#res3").html(str);
}
});
});
});
</script>
</body>
</html>
4.4 无返回值 void
- 方法的返回值为
void
,并不一定真的没有返回值,我们可以通过其他方式给前端返回。实际上,这种方式也可以理解为Servlet
中的处理方案。
/**
* 返回值问题
*
* @author murphy
*/
@Controller
@RequestMapping("result")
public class ResultController {
/**
* 无返回值 void:原生的Servlet中的使用方式
* 通过 HttpServletRequest 做服务端跳转
* 转发 - 地址栏不变 - 一次请求
*/
@RequestMapping("test04-1")
public void test04_1(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("直接使用HttpServletRequest进行服务器端的转发");
request.getRequestDispatcher("/jsp/ok.jsp").forward(request,response);
}
/**
* 无返回值 void:原生的Servlet中的使用方式
* 通过 HttpServletResponse 做重定向
* 重定向 - 地址栏变化 - 两次请求
*/
@RequestMapping("test04-2")
public void test04_2(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("直接使用HttpServletResponse进行重定向跳转");
response.sendRedirect("/jsp/ok.jsp");
}
/**
* 无返回值 void:原生的Servlet中的使用方式
* 通过 HttpServletResponse 给出响应
* PrintWriter
*/
@RequestMapping("test04-3")
public void test04_3(HttpServletResponse response) throws ServletException, IOException {
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
PrintWriter writer = response.getWriter();
writer.write("返回void类型测试 - 直接返回字符串");
writer.flush();
writer.close();
}
/**
* 自己手动指定响应头去实现重定向
* @throws IOException
*/
@RequestMapping("test04-4")
public void test04_4(HttpServletResponse response) throws ServletException, IOException {
// 设置响应码,302表示重定向
response.setStatus(302);
response.setHeader("Location","/jsp/ok.jsp");
}
}
5 页面导航的方式
页面导航分为两种: 1. 转发 | 2. 重定向
SpringMVC有以下两种方式实现页面的转发或重定向:
-
返回字符串
-
使用ModelAndView
在SpringMVC中两种导航进行页面导航的时候使用不同的前缀指定转发还是重定向
转发:forward:url
默认
重定向:redirect:url
准备工作:创建一个新的控制器NavigationController.java
:
/**
* 页面导航
* SpringMVC导航的方式
*
* @author murphy
*/
@Controller
@RequestMapping("navigation")
public class NavigationController {
}
5.1 转发到一个jsp页面
5.1.1 字符串方式转发
/**
* 页面导航
* SpringMVC导航的方式
*
* @author murphy
*/
@Controller
@RequestMapping("navigation")
public class NavigationController {
/**
* 转发到一个JSP页面
* 1. 使用字符串转发
* @return
*/
@RequestMapping("test01-1")
public String test01_1(HttpServletRequest request) {
request.setAttribute("userName","murphy");
// 默认方式:由视图解析器处理之后将逻辑视图转为物理资源路径
// 当添加了forward之后,视图解析器中的前后缀就失效了,必须编写绝对路径
return "forward:/jsp/ok.jsp";
}
}
页面取值:<h5>${requestScope.userName}</h5>
5.1.2 ModelAndView转发
/**
* 页面导航
* SpringMVC导航的方式
*
* @author murphy
*/
@Controller
@RequestMapping("navigation")
public class NavigationController {
/**
* 2. 使用ModelAndView转发
* @return
*/
@RequestMapping("test01-2")
public ModelAndView test01_2() {
// 默认方式:由视图解析器处理之后将逻辑视图转为物理资源路径
ModelAndView mv = new ModelAndView();
mv.addObject("userName","cici");
mv.setViewName("forward:/jsp/ok.jsp");
return mv;
}
}
页面取值:<h5>${requestScope.userName}</h5>
5.2 重定向到一个jsp页面
5.2.1 字符串方式重定向
/**
* 页面导航
* SpringMVC导航的方式
*
* @author murphy
*/
@Controller
@RequestMapping("navigation")
public class NavigationController {
/**
* 重定向到一个JSP页面
* 1. 使用字符串转发 - 页面上无法获取到存储在request作用域中的值,请求中断
* @param request
* @return
*/
@RequestMapping("test02-1")
public String test02_1(HttpServletRequest request) {
request.setAttribute("userName","Josh");
// 默认方式:由视图解析器处理之后将逻辑视图转为物理资源路径
// 当添加了forward之后,视图解析器中的前后缀就失效了,必须编写绝对路径
return "redirect:/jsp/ok.jsp";
}
}
从地址栏中获取的参数值:userName - ${param.userName} | userId - ${param.userId}
5.2.2 ModelAndView重定向方式
/**
* 页面导航
* SpringMVC导航的方式
*
* @author murphy
*/
@Controller
@RequestMapping("navigation")
public class NavigationController {
/**
* 2. 使用ModelAndView转发 - 存储在request中的值以参数的形式追加在URL后面
* http://localhost:8080/jsp/ok.jsp?userName=Hanna&userId=1001
* @return
*/
@RequestMapping("test02-2")
public ModelAndView test02_2() {
// 默认方式:由视图解析器处理之后将逻辑视图转为物理资源路径
ModelAndView mv = new ModelAndView();
mv.addObject("userName","Hanna");
mv.addObject("userId",1001);
mv.setViewName("redirect:/jsp/ok.jsp");
return mv;
}
}
从地址栏中获取的参数值:userName - ${param.userName} | userId - ${param.userId}
5.3 重定向或者转发到控制器
/**
* 页面导航
* SpringMVC导航的方式
*
* @author murphy
*/
@Controller
@RequestMapping("navigation")
public class NavigationController {
/**
* 转发到控制器
* @param request
* @return
*/
@RequestMapping("test03-1")
public ModelAndView test03_1(HttpServletRequest request) {
System.out.println("转发到控制器:");
ModelAndView mv = new ModelAndView();
mv.addObject("userName","murphymurphy");
mv.setViewName("forward:/navigation/test01-1");
return mv;
}
/**
* 重定向到控制器
* http://localhost:8080/navigation/test01-1?userName=murphymurphy&userId=1002
* @param request
* @return
*/
@RequestMapping("test03-2")
public ModelAndView test03_2(HttpServletRequest request) {
System.out.println("重定向到控制器:");
ModelAndView mv = new ModelAndView();
mv.addObject("userName","murphymurphy");
mv.addObject("userId",1002);
mv.setViewName("redirect:/navigation/test01-1");
return mv;
}
}
转发:
重定向: