SpringMVC的请求接收与结果响应
SpringMVC2
- 接收参数的常用注解
- 响应数据和结果视图
接收参数的常用注解
- RequestParam注解
作用:把请求中的指定名称的参数传递给控制器中的形参赋值
属性:
value:请求参数中的名称,指定请求参数名与方法参数名的映射关系(解决名称不一致的问题);
required:请求参数中是否必须提供此参数,默认值是true,表示必须提供请求参数,若未传会抛异常,设为false则允许为空;
defaultValue:如果没有传请求参数,使用该默认值。
package com.qcby.controller;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;@Controller
@RequestMapping("/dept")
public class DeptController {/*** RequestParam注解*/@RequestMapping("/save1.do")public String save(@RequestParam(value = "username", required = false, defaultValue = "abc") String name) {System.out.println("姓名:" + name);return "suc";}
}
- RequestBody注解
作用:将整个请求体的内容作为字符串接收(注意:get方法不可以)
required属性:表示是否必须有请求体,默认值是true
@requestBody注解常用的使用方式有两种:
- 将json格式的数据绑定到对应的实体类中
后端@RequestBody注解对应的类在将HTTP的输入流(含请求体)装配到目标类(即:@RequestBody后面 的类)时,会根据json字符串中的key来匹配对应实体类的属性,如果匹配一致且json中的该key对应的值符合(或可转换为)实体类的对应属性的类型要求时,会调用实体类的setter方法将值赋给该属性; - 将json格式的数据按照key值分别赋值在对应的字符串中
使用method="post"提交时,参数不会拼在 URL 后面,而是被封装到请求体(Request Body)中,格式为 key=value&key=value。
<h3>请求参数绑定(@RequestBody注解方式一)</h3><form action="/dept/save2.do" method="post">姓名:<input type="text" name="sname" /><br/>年龄:<input type="text" name="age" /><br/><input type="submit" value="提交" name="aaa"/><br/></form><h3>请求参数绑定(@RequestBody注解方式二)</h3><form action="/dept/save3.do" method="post">姓名:<input type="text" name="sname" /><br/>年龄:<input type="text" name="age" /><br/><input type="submit" value="提交" name="aaa"/><br/></form>
package com.qcby.controller;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;@Controller
@RequestMapping("/dept")
public class DeptController {/*** RequestBody注解,绑定到对应的实体类中*/@RequestMapping("/save2.do")public String save2(@RequestBody String body){System.out.println("请求体内容:"+body);return "suc";}/*** RequestBody注解,别赋值在对应的字符串中*/@RequestMapping("/save3.do")public String getUser(@RequestBody String sname,@RequestBody String age){System.out.println(sname);System.out.println(age);return "suc";}
}
打印结果:
- RequestHeader注解
作用:获取指定请求头的信息
value属性:请求头的名称
servlet 中获取指定请求头信息的方式:
@Controller
@RequestMapping("/user")
public class UserController {/*** servlet提供的获取请求头信息*/@RequestMapping("/save7.do")public String save7(HttpServletRequest request, HttpServletResponse response) {System.out.println(request.getParameter("username"));Enumeration<String> headerNames = request.getHeaderNames();while (headerNames.hasMoreElements()) {String headerName = (String) headerNames.nextElement();String headerValue = request.getHeader(headerName);System.out.println(headerName + ": " + headerValue);}return "suc";}
}
request 是 HttpServletRequest 类型的对象,代表客户端发送的 HTTP 请求,Enumeration<String> headerNames = request.getHeaderNames();
即通过 getHeaderNames() 获取所有 HTTP 请求头名称的枚举对象,while (headerNames.hasMoreElements()) { … } 循环遍历枚举对象,其中 hasMoreElements() 表示判断是否还有未处理的请求头名称,headerNames.nextElement(); 获取下一个请求头的名称,request.getHeader(headerName); 根据名称获取对应的请求头值。
<h3>获取请求头信息(servlet提供)</h3><form action="/user/save7.do" method="post">姓名:<input type="text" name="username" /><br/>年龄:<input type="text" name="age" /><br/><input type="submit" value="提交" /><br/></form>
打印结果:
Spring 框架提供的 @RequestHeader 注解用于获取请求头中指定字段的值
@Controller
@RequestMapping("/user")
public class UserController {/*** @RequestHeader 注解*/@RequestMapping("/save8.do")public String save8(@RequestHeader("cookie") String headerValue) {System.out.println(headerValue);return "suc";}
}
其中参数"cookie"表示获取请求头中名为Cookie的字段,注意是获取整个Cookie请求头的原始字符串
<h3>获取请求头信息(@RequestHeader 注解)</h3><form action="/user/save8.do" method="post">姓名:<input type="text" name="username" /><br/>年龄:<input type="text" name="age" /><br/><input type="submit" value="提交" /><br/></form>
打印结果:
- CookieValue注解
作用:用于从请求携带的Cookie中直接获取指定名称Cookie的值
value属性:cookie的名称
@Controller
@RequestMapping("/user")
public class UserController {/*** CookieValue注解*/@RequestMapping("/save9.do")public String save9(@CookieValue(value = "JSESSIONID") String cookie){System.out.println("值:"+cookie);return "suc";}
}
@CookieValue 注解会自动从所有Cookie中提取指定名称(value = “JSESSIONID”)的单个Cookie的具体值
<h3>获取请求头cookie信息(@CookieValue 注解)</h3><form action="/user/save9.do" method="post">姓名:<input type="text" name="username" /><br/>年龄:<input type="text" name="age" /><br/><input type="submit" value="提交" /><br/></form>
打印结果:
- PathVaribale注解
作用:获取 URL 路径中的占位符参数(适用于 RESTful 风格的 URL)
例如:url中有/delete/{id},{id}就是占位符
value属性:指定url中的占位符名称,若方法参数名与占位符名一致可省略
Restful 风格的 URL:请求路径一样,可以根据不同的请求方式去执行后台的不同方法
@GetMapping:映射 GET 请求,用于查询资源
@PostMapping:映射 POST 请求,用于创建新资源
@PutMapping:映射 PUT 请求,用于全量更新资源
@DeleteMapping:映射 DELETE 请求,用于删除资源
restful风格的URL优点:结构清晰、符合标准、易于理解、扩展方便
package com.qcby.controller;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;@Controller
//@RequestMapping("/emp")
public class EmpController{/*** 保存*/@RequestMapping(path ="/emp",method = RequestMethod.POST)public String save(){System.out.println("保存员工...");return "suc";}/*** 查询所有*/@RequestMapping(path ="/emp", method = RequestMethod.GET)public String findAll(){System.out.println("查询员工...");return "suc";}/*** 查询所有*/@RequestMapping(path = "/emp/{id}",method = RequestMethod.GET)public String findById(@PathVariable(value = "id") Integer id){System.out.println("通过id查询员工..."+id);return "suc";}
}
<h3>Restful风格的URL</h3><form action="/emp" method="post"><input type="submit" value="保存员工"><br/></form><form action="/emp" method="get"><input type="submit" value="查询员工"><br/></form><form action="/emp/1" method="get"><input type="submit" value="通过id查询员工"><br/></form>
打印结果:
响应数据和结果视图
- 返回String
@Controller
@RequestMapping("/redict")
public class ReController {/*** 返回字符串(常用)*/@RequestMapping("/save1.do")public String save1(){System.out.println("执行了save1...");return "suc";}
}
- 返回值是void
如果控制器的方法返回值编写成void,SpringMVC 不会自动进行视图解析或数据处理,默认查找JSP页面没有找到,执行程序报404的异常
解决方式:可以使用请求转发或者重定向跳转到指定的页面,而非依赖 Spring MVC 的视图解析器自动跳转
需要使用 Servlet 规范中的原生 API 获取请求信息和处理响应,三种常见的响应方式:
- 通过 HttpServletRequest 的 getRequestDispatcher() 方法实现请求转发,可以访问/WEB-INF目录下的资源,以及可以携带request域中的数据到目标资源;
- 通过 HttpServletResponse 的 sendRedirect() 方法实现重定向,需要注意的是不能直接访问/WEB-INF目录下的资源,且request域中的数据会丢失;
- 通过 HttpServletResponse 的输出流直接向客户端输出数据,不经过其他资源跳转。
@Controller
@RequestMapping("/redict")
public class ReController {/*** 返回值是void*/@RequestMapping("/save2.do")public void save2(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {System.out.println("执行了save2...");//请求转发request.getRequestDispatcher("/WEB-INF/pages/suc.jsp").forward(request,response);//重定向, request.getContextPath() 用于获取上下文路径//response.sendRedirect(request.getContextPath() + "/index.jsp");// 使用response对象直接向客户端输出响应数据//response.getWriter().print("hello");return;}
}
- 返回值是ModelAndView对象
ModelAndView 是 SpringMVC 提供的一个对象,可同时封装模型数据和视图信息,适合需要在一个对象中同时处理数据和视图的场景
@Controller
@RequestMapping("/redict")
public class ReController {/*** 返回ModelAndView对象*/@RequestMapping("/save3.do")public ModelAndView save3(){System.out.println("执行了save3...");// 创建mv对象ModelAndView mv = new ModelAndView();// 把一些数据,存储到mv对象中mv.addObject("msg","用户名或者密码已经存在");// 设置逻辑视图的名称mv.setViewName("suc");// 也支持redirect/forward// mv.setViewName("redirect:/index.jsp");return mv;}
}
补充另一种拆开的方式,返回值是String,视图解析器跳转至对应视图,参数列表中携带model来返回数据内容,代码示例:
@Controller
@RequestMapping("/mtype")
public class MtypeController {@RequestMapping("/list")public String selectpage(MtypeQuery mq, Model model){Page<Mtype> page = mtypeService.selectObjectByCondition(mq);model.addAttribute("page", page);return "mtype";}
}
- SpringMVC 框架提供的forward请求转发
@Controller
@RequestMapping("/redict")
public class ReController {/*** 返回String* SpringMVC框架提供的请求转发*/@RequestMapping("/save4.do")public String save4(){System.out.println("执行了save4...");return "forward:/WEB-INF/pages/suc.jsp";}
}
- SpringMVC 框架提供的redirect请求转发
@Controller
@RequestMapping("/redict")
public class ReController {/*** 返回String* SpringMVC框架提供的重定向*/@RequestMapping("/save5.do")public String save5(){System.out.println("执行了save5...");return "redirect:save1.do";// 也可重定向到外部URL但无法访问WEB-INF下的资源//return "redirect:https://www.baidu.com";}
}
前端编写
<h3>请求转发与重定向</h3><form action="/redict/save1.do" method="get"><input type="submit" value="执行"><br/></form><form action="/redict/save2.do" method="get"><input type="submit" value="执行"><br/></form><form action="/redict/save3.do" method="get"><input type="submit" value="执行"><br/></form><form action="/redict/save4.do" method="get"><input type="submit" value="执行"><br/></form><form action="/redict/save5.do" method="get"><input type="submit" value="执行"><br/></form>
打印结果:
- ResponseBody响应json数据(重要)
首先需要导入坐标依赖,引入JSON 序列化依赖
<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.9.0</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-core</artifactId><version>2.9.0</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-annotations</artifactId><version>2.9.0</version></dependency>
@ResponseBody的使用本质是 “标记返回值需转为响应体”,ResponseBody响应json数据后台代码编写有三种方式,使得返回值会被序列化为 JSON
第一种方式 @ResponseBody 注解加到返回值前
@Controller
@RequestMapping("/redict")
public class ReController {/*** ResponseBody响应json数据(重要)* 异步的数据交互*/@RequestMapping("/save6.do")public @ResponseBody User save6(@RequestBody User user){System.out.println(user);// 模拟,调用业务层代码user.setUsername("hello");user.setAge(100);// 把user对象转换成json字符串,再响应,response.getWriter().print()return user;}
}
第二种方式 @ResponseBody 注解加到方法上
@Controller
@RequestMapping("/redict")
public class ReController {// 方法上单独使用@ResponseBody@RequestMapping("/save7.do")@ResponseBody // 仅当前方法返回数据(不跳转视图)public User save7(@RequestBody User user) {System.out.println(user);user.setUsername("hello");user.setAge(100);return user; // 返回的User对象会被转换为JSON响应}
}
第三种方式 @ResponseBody 注解加到类上,即类上使用@RestController,等价于@Controller + @ResponseBody
package com.qcby.controller;import com.qcby.model.User;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/test")
public class TestController {// 方法上无需再添加@ResponseBody@RequestMapping("/save1.do")public User save6(@RequestBody User user) {System.out.println(user);user.setUsername("hello");user.setAge(100);return user; // 返回的User对象会被转换为JSON响应}
}
前端jsp代码编写
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>请求参数绑定</title><%--引入jq,使用阿里云的jQuery CDN(无integrity校验,稳定可靠) --%><script src="https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js" type="text/javascript"></script><script>// 页面加载$(function(){// 单击事件$("#btn1").click(function(){// 发送ajax的请求$.ajax({type: "post",url: "/redict/save6.do",contentType:"application/json;charset=UTF-8",data:'{"username":"haha","age":"20"}',dataType: "json",success:function(d){// 编写很多代码alert(d.username+" - "+d.age);}});});$("#btn2").click(function(){// 发送ajax的请求$.ajax({type: "post",url: "/redict/save7.do",contentType:"application/json;charset=UTF-8",data:'{"username":"haha","age":"20"}',dataType: "json",success:function(d){// 编写很多代码alert(d.username+" - "+d.age);}});});$("#btn3").click(function(){// 发送ajax的请求$.ajax({type: "post",url: "/test/save1.do",contentType:"application/json;charset=UTF-8",data:'{"username":"haha","age":"20"}',dataType: "json",success:function(d){// 编写很多代码alert(d.username+" - "+d.age);}});});});</script></head>
<body><h2>响应数据和结果视图</h2><h3>返回值是String</h3><a href="/redict/save1.do" >返回String</a><br/><h3>返回值是void</h3><a href="/redict/save2.do" >返回void</a><br/><h3>返回值是ModelAndView</h3><a href="/redict/save3.do" >返回ModelAndView</a><br/><h3>请求转发返回值是String</h3><a href="/redict/save4.do" >返回值是String</a><br/><h3>重定向返回值是String</h3><a href="/redict/save5.do" >返回值是String</a><br/><h3>异步的数据交互方式1</h3><input type="button" value="ajax交互" id="btn1"><br/><h3>异步的数据交互方式2</h3><input type="button" value="ajax交互" id="btn2"><br/><h3>异步的数据交互方式3</h3><input type="button" value="ajax交互" id="btn3"><br/></body>
</html>
需要注意的是 DispatcherServlet 会拦截到所有的资源,导致静态资源也会被拦截到,从而不能被使用,需要配置静态资源不进行拦截,在 springmvc.xml 配置文件添加如下配置:
<!-- 设置静态资源不过滤 --><mvc:resources location="/css/" mapping="/css/**"/> <!-- 样式 --><mvc:resources location="/images/" mapping="/images/**"/> <!-- 图片 --><mvc:resources location="/js/" mapping="/js/**"/> <!-- javascript -->
location元素表示webapp目录下的包下的所有文件,mapping元素表示以/static开头的所有请求路径
响应结果:
后端打印结果: