一、请求数据绑定
1.1、逐一接收参数信息
- index.jsp首页
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head>
<title>首页</title>
</head>
<body>
<form action="/student/register" method="post">
姓名:<input type="text" name="username"/><br>
年龄:<input type="text" name="age"/><br>
<button type="submit">登录</button>
</form>
</body>
</html>
- PeopleController处理类
@Controller
@RequestMapping("/student")
public class PeopleController {
@RequestMapping("/register")
public ModelAndView doRegister(@RequestParam("username") String name, int age){
return new ModelAndView("user")
.addObject("username",name)
.addObject("age",age);
}
}
@RequestParam作用:将首页中的请求参数名进行校正,即将username的值映射给name
- user.jsp页面
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head>
<title>用户页面</title>
</head>
<body>
<h1>username : ${username}</h1>
<h1>age : ${age}</h1>
</body>
</html>
注意:isELIgnored=“false” 时,${username}占位符才能获取后台model提交的数据
- 测试结果
- 点击登录按钮,跳转到 user.jsp页面
1.2、通过实例对象接受请求参数
- 创建Student类
public class Student {
private String name;
private int age;
private School school;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", school=" + school +
'}';
}
}
- PeopleController处理器类
@Controller
@RequestMapping("/student")
public class PeopleController {
@RequestMapping("/register")
public ModelAndView doRegister(Student student){
return new ModelAndView("user")
.addObject("username",student.getName())
.addObject("age",student.getAge());
}
- 因为通过实体类接受请求参数必须保持请求参数名与实体属性名一致,故改变index.jsp 后如下
<body>
<form action="/student/register" method="post">
姓名:<input type="text" name="name"/><br>
年龄:<input type="text" name="age"/><br>
<button type="submit">登录</button>
</form>
</body>
- 测试得到user.jsp页面:
1.3、域属性参数接受
- 需求:在user实体中添加一个school域属性,一起接受前段传递的参数
- School类
private String name;
private String address;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "School{" +
"name='" + name + '\'' +
", address='" + address + '\'' +
'}';
}
- index.jsp修改后页面
<body>
<form action="/student/register" method="post">
姓名:<input type="text" name="name"/><br>
年龄:<input type="text" name="age"/><br>
所在学校:<input type="text" name="school.name"/><br>
学校地址:<input type="text" name="school.address"/><br>
<button type="submit">登录</button>
</form>
</body>
school.name对应的就是school类中的name属性,school.address对应的就是school类中的address属性;提交请求是springmvc会自动将这两个属性映射到user实例中的school对象中去。
- PeopleController类
@RequestMapping("/register")
public ModelAndView doRegister(Student student){
return new ModelAndView("user")
.addObject("username",student.getName())
.addObject("age",student.getAge())
.addObject("school",student.getSchool());
}
- user.jsp页面
<body>
<h1>username : ${username}</h1>
<h1>age : ${age}</h1>
<h1>schoolName : ${school.name}</h1>
<h1>schoolAddress : ${school.address}</h1>
</body>
- 测试结果
注意:因为这里我们还没有解决中文乱码问题,所以测试仍然使用英文
1.4、通过请求路径变量接受参数@PathVariable
- 注意:因为通过请求路径传参都是get请求,所以此例我们不使用表单。
- PeopleController类中加入一个新的处理方法
@RequestMapping("/login/{username}/{age}")
public ModelAndView doRegister(@PathVariable("username") String name,@PathVariable int age){
return new ModelAndView("user")
.addObject("username",name)
.addObject("age",age);
}
@PathVariable获取请求路径中的参数值,也可以矫正参数类型,即将username的值映射给name。
- 测试
- 此方法不推荐,通过路径获取参数值非常不安全,应尽量避免这样的参数接受方式
1.5、List对象
<tr>
<td>学生信息:</td>
<td>
学校名:<input type="text"name="schools[0].name"/>地址:<input type="text"name="schools[0].address"/><br/>
学校名:<input type="text"name="schools[1].name"/>地址:<input type="text"name="schools[1].address"/><br/>
</td>
</tr>
- 每一个数组元素代表一个school对象,然后获取每一个对象响应的属性名即可,注意属性名与实体中的属性名要一样
1.6、map对象
<td>学生信息:</td>
<td>
学校名:<input type="text"name="schoolinfo['name']"/>
地址:<input type="text"name="schoolinfo['age']"/>
二、请求/响应乱码的解决
2.1、解决方案
- 在web.xml中加入filter并设置全局的相应编码
<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>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
2.2、CharacterEncodingFilter源码分析
- doFilterInternal方法分析:设置请求、响应的编码
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String encoding = this.getEncoding();
if (encoding != null) {
if (this.isForceRequestEncoding() || request.getCharacterEncoding() == null) {
request.setCharacterEncoding(encoding);
}
if (this.isForceResponseEncoding()) {
response.setCharacterEncoding(encoding);
}
}
filterChain.doFilter(request, response);
}
-
逻辑分析:
1)如果encoding 的值不为空,向下执行,encoding 对应的就是filter标签中的init-param中的encoding ;
2)第二个判断是说只要isForceRequestEncoding()的返回值为true或者request请求的编码为空,则向下执行设置请求的UTF-8编码;也就是说只要设置了encoding 的值,则一定会设置request的编码;
3)isForceResponseEncoding()的返回值为true,才会设置response响应的中文编码。- isForceResponseEncoding()源码
public boolean isForceResponseEncoding() {
return this.forceResponseEncoding;
}
故我们要使response响应的编码也符合我们的要求,我们就将forceResponseEncoding的值设置为true,所以我们在filter标签中也要设置forceResponseEncoding的值为true最好。
<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>
<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>
三、controller处理器方法返回值
- Controller处理器方法返回值可以是ModelAndView、String、List、Map、自定义对象、字符串、布尔常量
3.1、返回String字符串
- PeopleController类中的doFirst方法
@RequestMapping("/first")
public String doFirst(){
return "home";
}
- springmvc.xml配置
<context:component-scan base-package="com.chuan.annotation.controller"/>
<!--注册处理器映射器和处理器适配器-->
<mvc:annotation-driven/>
<!--注册视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="suffix" value=".jsp"/>
<property name="prefix" value="/WEB-INF/jsp/"/>
</bean>
- home.jsp内容
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head>
<title>Title</title>
</head>
<body>
${msg}
<h2>hello 杠精儿</h2>
</body>
</html>
- 测试结果
返回字符串时,如果配置了InternalResourceViewResolver视图解析器,则springmvc会自动进行url拼接,然后跳转到该字符串匹配的页面。
3.2、返回string字符串并使用BeanNameViewResolver视图解析器
- springmvc.xml配置文件
<context:component-scan base-package="com.chuan.annotation.controller"/>
<!--注册处理器映射器和处理器适配器-->
<mvc:annotation-driven/>
<!--外部资源视图-->
<bean id="jd" class="org.springframework.web.servlet.view.RedirectView">
<property name="url" value="http://www.jd.com"/>
</bean>
<!--注册视图解析器-->
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver"/>
- PeopleController类
@RequestMapping("/first")
public String doFirst(){
return "jd";
}
- 测试结果:成功跳转至京东主页
3.3、返回Object ------ 环境搭建
- 引入@ResponseBody需要使用的jackson包,因为Spring默认的json协议解析由Jackson完成
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.7.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.7.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.7.3</version>
</dependency>
<!--注册处理器映射器和处理器适配器-->
<mvc:annotation-driven/>
3.4、返回Object ------ 数值型
- 自定义处理器MyController类
@Controller
@RequestMapping("/my")
@ResponseBody
public class MyController {
@RequestMapping("/number")
public Object doNumber(){
return 1;
}
注意:如上所示,我将@ResponseBody标签申明到类名上面了,那么该类下面的所有url映射方法的返回值都会以json的方式返回给前台。
- 测试结果
3.5、返回Object ------ 字符串
- MyController处理器类新增返回字符串的方法
@RequestMapping("/string")
public Object doString(){
return "index";
}
- 注意 :这里index并没有跳转待index.jsp页面
-
- 测试结果
- 测试结果
3.6、返回Object ------ 自定义类型对象
- MyController处理器类新增返回自定义对象的方法
@RequestMapping("/student")
public Object doStudent(){
Student student = new Student();
student.setName("张益达");
student.setAge(45);
School school = new School();
school.setName("哈弗大学");
school.setAddress("美国");
student.setSchool(school);
return student;
}
- 测试
3.7、返回Object ------ Map
- MyController处理器类新增返回Map对象的方法
@RequestMapping("/map")
public Object doMap(){
Map<String, String> map = new HashMap<>();
map.put("123","常德");
map.put("234","长沙");
map.put("345","深圳");
return map;
}
- 测试结果
3.8、返回Object ------ List
- MyController处理器类新增返回数组对象的方法
@RequestMapping("/list")
public Object doList(){
ArrayList<String> arrayList = new ArrayList<>();
arrayList.add("mark");
arrayList.add("李四");
arrayList.add("小微");
return arrayList;
}
+测试结果
3.9、无返回值 ------- void
- PeopleController类
@RequestMapping("/void") //无返回值,通过ServletAPI完成参数传递和跳转
public void doVoid(String name, int age, HttpServletRequest request, HttpServletResponse response) throws Exception{
request.setAttribute("username", name);
request.setAttribute("age", age);
request.getRequestDispatcher("/WEB-INF/jsp/user.jsp").forward(request, response);
}
无返回值就使用servlet的重定向实现。
- index.jsp首页:指明要跳转的url路径
<form action="/student/void" method="post">
姓名:<input type="text" name="name"/><br>
年龄:<input type="text" name="age"/><br>
<button type="submit">登录</button>
</form>
</body>
- 测试得到user.jsp的页面效果
3.10、@RequestBody读取json格式的请求参数
- MyController处理器类新增接受student对象实例的方法
@RequestMapping("/receive")
public void getStudent(@RequestBody Student student){
System.out.println(student.getName());
System.out.println(student.getAge());
System.out.println(student.getSchool());
}
- 打开Postman测试软件,输入一组自定义的json数据
- 控制台打印结果
从上可知:后台成功获取了前端提交的json数据并自动进行了映射。
@RequestBody 、 @ResponseBody 实现json数据交互
1·、 @RequestBody
作用:@RequestBody注解用于读取http请求的内容(字符串),通过springmvc提供的HttpMessageConverter接口将读到的内容转换为json、xml等格式的数据并绑定到controller方法的参数上。
使用场景:@RequestBody注解实现接收http请求的json数据,将json数据转换为java对象。
2、 @ResponseBody
作用:该注解用于将Controller的方法返回的对象,通过 HttpMessageConverter接口转换为指定格式的数据如:json,xml等,通过Response响应给客户端;
使用场景:@ResponseBody注解实现将controller方法返回对象转换为json响应给客户端
3、springmvc.xml一定要有下列配置