文章目录
- 一、概念
- 1、MVC 定义
- 2、MVC 和 Spring MVC 的关系
- 3、Spring MVC 和 Spring 的关系
- 二、Spring MVC 创建和连接
- 1、创建 Spring MVC 项目
- ① 对比
- ② 注意
- 2、@RequestMapping 注解介绍
- 3、@RequestMapping 是 post 还是 get 请求?
- ① GET
- ② POST
- 4、@GetMapping 和 @PostMapping
- 三、获取参数
- 1、传递单个参数
- ① Request 对象
- ② 直接传参
- 2、传递多个参数(非对象)
- 3、传递对象
- 4、表单参数传递
- ① 传递多个参数
- ② 封装为对象
- 5、后端参数重命名
- 6、设置参数必传 @RequestParam
- 7、@RequestBody 接收JSON对象
- ① postman 传递 JSON 对象
- ② 错误的传递
- ③ @RequestBody
- 8、获取URL中参数 @PathVariable
- 9、上传文件@RequestPart
- ① postman 传递文件
- ② @RequestPart
- ③ 获取当前项目的绝对路径
- 10、获取Cookie/Session/header
- ① Cookie
- Ⅰ. 增加 Cookie
- Ⅱ. 传统获取
- Ⅲ. @CookieValue
- ② header
- Ⅰ. 传统获取
- Ⅱ. @RequestHeader
- ③ Session
- Ⅰ. 创建 Session
- Ⅱ. 传统获取
- Ⅲ. @SessionAttribute
- 四、返回数据
- 1、返回静态页面
- 2、返回 text/html
- 3、返回 JSON 对象
- 4、请求转发或请求重定向
- ① 转发和重定向的区别
- ② 举例说明
- 5、@ResponseBody 说明
- 6、查看更多注解
一、概念
官方给出的定义:
Spring Web MVC 是基于 Servlet API 构建的原始 Web 框架,从⼀开始就包含在 Spring 框架中。它的正式名称“Spring Web MVC”来⾃其源模块的名称(Spring-webmvc),但它通常被称为“Spring MVC”。
总结:
- Spring MVC 是⼀个 Web 框架。
- Spring MVC 是基于 Servlet API 构建的
1、MVC 定义
MVC 是 Model View Controller 的缩写,它是软件⼯程中的⼀种软件架构模式,它把软件系统分
为模型、视图和控制器三个基本部分。
- **Model(模型)**是应⽤程序中⽤于处理应⽤程序数据逻辑的部分。通常模型对象负责在数据库中存取数据。
- **View(视图)**是应⽤程序中处理数据显示的部分。通常视图是依据模型数据创建的。
- **Controller(控制器)**是应⽤程序中处理⽤户交互的部分。通常控制器负责从视图读取数据, 控制⽤户输⼊,并向模型发送数据。
2、MVC 和 Spring MVC 的关系
MVC 是⼀种思想,⽽ Spring MVC 是对 MVC 思想的具体实现。
3、Spring MVC 和 Spring 的关系
绝⼤部分的 Java 项⽬都是基于 Spring(或 Spring Boot)的,⽽ Spring 的核⼼就是 Spring MVC。
简单来说,咱们之所以要学习 Spring MVC 是因为它是⼀切项⽬的基础,我们以后创建的所有 Spring、Spring Boot 项⽬基本都是基于 Spring MVC 的。
二、Spring MVC 创建和连接
1、创建 Spring MVC 项目
Spring MVC 项目的创建其实我们之前已经学习过了,和 Spring Boot 项目创建是一模一样的:
接下来,创建⼀个 UserController 类,实现⽤户到 Spring 程序的互联互通,代码如下:
@Controller // 在 Spring 启动的时候,加载并注册
@ResponseBody // 当前类返回非静态页面
@RequestMapping("/web") // 路由器规则注册
public class WebController {
@RequestMapping("/hi") // 路由器规则注册
public Object sayHi() {
return "Hi,Spring MVC.";
}
}
访问 http://localhost:8080/web/hi,运行结果为:
① 对比
- @Controller:在 Spring 启动的时候,加载并注册,这个注解也是必须的,否则访问不到 Bean 对象。
- @ResponseBody:当前类返回非静态页面,这个注解一般情况下是必须的,但如果返回静态页面,也可以不加这个注解。
@Controller // 在 Spring 启动的时候,加载并注册
public class WebController {
@RequestMapping("/hi") // 路由器规则注册
public Object sayHi() {
return "/index.html";
}
}
- @RequestMapping(“/web”):路由器规则注册,这个注解一定要有,根据这个注解提供的路径,我们才能访问对应的东西。
- @RestController:@Controller + @ResponseBody
② 注意
我们之前学过五大类注解,那么这里使用其他类注解是否可以呢?
不行!!!只能用 @Controller 注解
2、@RequestMapping 注解介绍
@RequestMapping 是 Spring Web 应⽤程序中最常被⽤到的注解之⼀,它是⽤来注册接⼝的路
由映射的。
@RequestMapping 即可以修饰类,也可以修饰方法。
@RestController
@RequestMapping("/web") // 路由器规则注册
public class WebController {
@RequestMapping("/hi") // 路由器规则注册
public Object sayHi() {
return "Hi,Spring MVC.";
}
}
- 当修饰类和⽅法时,访问的地址是类 + ⽅法,例如:http://localhost:8080/web/hi
- 当修饰⽅法时,访问的地址是⽅法,例如:http://localhost:8080/hi(假设没有修饰类)
3、@RequestMapping 是 post 还是 get 请求?
① GET
@RequestMapping 默认是 get ⽅式的请求,可以使⽤ postman 进⾏测试。
测试一下上面的代码,结果如下:
② POST
我们还可以通过 @RequestMapping 注解来修改为 POST 请求,代码如下:
@RestController
@RequestMapping("/web") // 路由器规则注册
public class WebController {
@RequestMapping(value = "/hi",method = RequestMethod.POST) // 路由器规则注册
public Object sayHi() {
return "Hi,Spring MVC.";
}
}
postman 测试结果如下:
但如果我们测试 GET 方法,就会报错:
4、@GetMapping 和 @PostMapping
在学习 @RequestMapping 注解的时候,我们了解到,可以用 method 这个参数来设置请求方式,但是这种方式比较繁琐,有没有更简单的方法呢?
@GetMapping 和 @PostMapping 注解就应运而生了,@GetMapping 注解表示 GET 请求,@PostMapping 注解表示 POST 请求。
// 两者选其一,否则按最先注册的请求方式执行
@PostMapping("/hi")
@GetMapping("/hi")
public Object sayHi() {
return "Hi,Spring MVC.";
}
下面,我们总结一下 GET 和 POST 请求的写法:
GET:
// @RequestMapping 注解默认为 GET 请求
@RequestMapping("/hi")
// 通过 @RequestMapping 注解的 method 属性声明为 GET 请求
@RequestMapping(value = "/hi",method = RequestMethod.GET)
// 使用 @GetMapping 注解
@GetMapping("/hi")
POST:
// 通过 @RequestMapping 注解的 method 属性声明为 POST 请求
@RequestMapping(value = "/hi",method = RequestMethod.POST)
// 使用 @PostMapping 注解
@PostMapping("/hi")
三、获取参数
1、传递单个参数
① Request 对象
我们之前学习过 servlet 的传递参数,用 request 方式获取;在 Spring MVC 中,我们同样可以,用 request 方式获取。
在 Spring MVC 中,默认内置隐藏了两个参数,Request 和 Response 对象;如果想要使用这两个参数,只需要在方法中声明即可。代码如下:
@RestController
@RequestMapping("/web") // 路由器规则注册
public class WebController {
@GetMapping("/hi")
public Object sayHi(HttpServletRequest request, HttpServletResponse response) {
return "Hi,"+request.getParameter("name");
}
}
postman 测试结果如下:
② 直接传参
但是用 request 方式获取,只能传递 String 类型的参数,如果需要强制转化,就需要考虑空指向异常的问题,而且还很麻烦。实际上,在 Spring MVC 中,我们可以直接用方法中的参数进行传参,代码如下:
@RestController
@RequestMapping("/web") // 路由器规则注册
public class WebController {
/**
* 获取单个参数
* @param name
* @return
*/
@GetMapping("/get1")
public String getParm1(String name) {
return "Hi," + name;
}
}
postman 测试结果如下:
2、传递多个参数(非对象)
和传递单个参数相同,直接传参可以了,代码如下:
@RestController
@RequestMapping("/web") // 路由器规则注册
public class WebController {
/**
* 获取多个参数
*
* @param name
* @param age
* @return
*/
@GetMapping("/get1")
public String getParm1(String name, Integer age) {
return "Hi,name:" + name + " | age:" + age;
}
}
postman 测试结果如下:
注意:这里是以 参数名 进行参数匹配的,与参数的顺序无关!
3、传递对象
我们刚刚学习了传递多个参数,但是这样维护起来就很麻烦,所以可以采用传递对象的方式,这样我们只需要维护一个对象即可。
示例:
先新建一个 Student 类:
@Data
public class Student {
private Integer id;
private String name;
private Integer age;
}
接口如下:
@RestController
@RequestMapping("/web") // 路由器规则注册
public class WebController {
/**
* 传递对象
* @param student
* @return
*/
@GetMapping("/get3")
public String getParm3(Student student) {
return student.toString();
}
}
postman 测试结果如下:
4、表单参数传递
① 传递多个参数
写一个简单的登录页面 login.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form method="get" action="/web/login">
<div>
<h1> 登录 </h1>
用户:<input name="name"><br>
密码:<input name="password"><br>
<input type="submit" value=" 提 交 ">
</div>
</form>
</body>
</html>
接口代码:
@RestController
@RequestMapping("/web") // 路由器规则注册
public class WebController {
/**
* 表单参数传递
* @param name
* @param password
* @return
*/
@RequestMapping("/login")
public String login(String name, String password) {
// 这里参数较少,就直接传参了,一般情况下是传递对象
return "<h1>用户名:" + name + " | 密码:" + password + "</h1>";
}
}
访问网页 http://localhost:8080/login.html:
随便输入数据点击提交,结果如下:
② 封装为对象
要传递的 User 类:
@Data
public class User {
private String name;
private String password;
}
简单的前端页面 reg.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>注册</title>
</head>
<body>
<form method="get" action="/web/reg">
<div>
<h1> 注册 </h1>
用户:<input name="name"><br>
密码:<input name="password"><br>
<input type="submit" value=" 提 交 ">
</div>
</form>
</body>
</html>
接口代码:
@RestController
@RequestMapping("/web") // 路由器规则注册
public class WebController {
/**
* 表单参数传递(对象参数)
* @param user
* @return
*/
@RequestMapping("/reg")
public String req(User user) {
return user.toString();
}
}
访问网页 http://localhost:8080/reg.html:
随便输入数据点击提交,结果如下:
5、后端参数重命名
某些特殊的情况下,前端传递的参数 key 和我们后端接收的 key 可以不⼀致,可以使⽤ @RequestParam 来重命名前后端的参数值。
@RestController
@RequestMapping("/web") // 路由器规则注册
public class WebController {
/**
* 使用 @RequestParam 注解重命名
* @param username
* @return
*/
@GetMapping("/get4")
public String getParm1(@RequestParam("name")String username) {
return "Hi," + username;
}
}
使用 postman 测试:
6、设置参数必传 @RequestParam
在使用 @RequestParam 注解的时候,默认参数的必传的,如果前端没有传递相应的参数,就会出错,所以我们还需要设置一下参数为非必传,这个使用 @RequestParam 注解的 required 属性即可。
@RestController
@RequestMapping("/web") // 路由器规则注册
public class WebController {
/**
* 使用 @RequestParam 注解设置参数非必传
* @param username
* @return
*/
@GetMapping("/get5")
public String getParm5(@RequestParam(value = "name",required = false) String username) {
return "Hi," + username;
}
}
使用 postman 测试:
7、@RequestBody 接收JSON对象
① postman 传递 JSON 对象
在传参之前,我们先来了解一下如何使用 postman 传递 JSON 对象:
然后在下面按照 JSON 的格式写即可:
② 错误的传递
@RestController
@RequestMapping("/web") // 路由器规则注册
public class WebController {
@RequestMapping("/login2")
public HashMap<String,Object> login2(String name, String password) {
HashMap<String,Object> result = new HashMap<>();
result.put("name",name);
result.put("password",password);
return result;
}
@RequestMapping("/login3")
public HashMap<String,Object> login3(User user) {
HashMap<String,Object> result = new HashMap<>();
result.put("name",user.getName());
result.put("password",user.getPassword());
return result;
}
}
分别用 postman 测试:
login2接口:
login3接口:
我们可以看到,明明我们传递的是 JSON 对象,但是却无法接收,这是为什么呢?这是因为在 Spring MVC 中,需要用到 @RequestBody 注解来传递 JSON 对象参数。
③ @RequestBody
接口代码:
@RestController
@RequestMapping("/web") // 路由器规则注册
public class WebController {
/**
* 传递 JSON 对象
* @param user
* @return
*/
@RequestMapping("/login3")
public HashMap<String,Object> login3(@RequestBody User user) {
HashMap<String,Object> result = new HashMap<>();
result.put("name",user.getName());
result.put("password",user.getPassword());
return result;
}
}
使用 postman 测试:
这里我们就获取到了 JSON 对象。
注意:@RequestBody 注解拿到的一定是一个对象,不能是属性!!!
8、获取URL中参数 @PathVariable
@RestController
@RequestMapping("/web") // 路由器规则注册
public class WebController {
/**
* 使用 @PathVariable 注解 获取 URL 中参数
* @param name
* @param password
* @return
*/
@GetMapping("/get6/{name}/{password}")
public String getParm6(@PathVariable String name, @PathVariable String password) {
return "Hi," + name + ": " + password;
}
}
使用 postman 测试:
9、上传文件@RequestPart
① postman 传递文件
在传参之前,我们先来了解一下如何使用 postman 传递文件:
postman
② @RequestPart
测试接口:
@RestController
@RequestMapping("/web") // 路由器规则注册
public class WebController {
/**
* 上传文件
* @param name
* @param file
* @return
* @throws IOException
*/
@RequestMapping("/upload")
public String upload(String name, @RequestPart("picture") MultipartFile file) throws IOException {
// 保存文件
file.transferTo(new File("E:\\work\\img.pmg"));
return "success";
}
}
使用 postman 测试:
前往 E:\work 查看 img.pmg 是否存在:
③ 获取当前项目的绝对路径
ResourceUtils.getFile(ResourceUtils.CLASSPATH_URL_PREFIX).getPath();
new ClassPathResource("").getFile().getAbsolutePath();
ClassUtils.getDefaultClassLoader().getResource("").getPath();
ResourceUtils.getFile("classpath:static/").getPath();
10、获取Cookie/Session/header
① Cookie
Ⅰ. 增加 Cookie
在网页中,F12 打开开发者工具:
Ⅱ. 传统获取
@RestController
@RequestMapping("/web") // 路由器规则注册
public class WebController {
/**
* 传统方法获取 Cookie
* @param request
* @param response
* @return
*/
@RequestMapping("/cookie")
@ResponseBody
public String cookie(HttpServletRequest request, HttpServletResponse response) {
String name = request.getParameter("name");
Cookie[] cookies = request.getCookies();
return "Hi," + name;
}
}
Ⅲ. @CookieValue
@RestController
@RequestMapping("/web") // 路由器规则注册
public class WebController {
/**
* 使用 @CookieValue 注解
* @param name
* @return
*/
@RequestMapping("/cookie2")
@ResponseBody
public String cookie2(@CookieValue("name") String name) {
return "name: " + name;
}
}
使用 网页 测试:
② header
Ⅰ. 传统获取
@RestController
@RequestMapping("/web") // 路由器规则注册
public class WebController {
/**
* 传统方法获取 Header
* @param request
* @param response
* @return
*/
@RequestMapping("/header")
@ResponseBody
public String header(HttpServletRequest request, HttpServletResponse response) {
String name = request.getParameter("name");
String userAgent = request.getHeader("User-Agent");
return "Hi," + name + ": " + userAgent;
}
}
使用 postman 测试:
Ⅱ. @RequestHeader
@RestController
@RequestMapping("/web") // 路由器规则注册
public class WebController {
/**
* 使用 @RequestHeader 注解
* @param userAgent
* @return
*/
@RequestMapping("/header2")
@ResponseBody
public String header2(@RequestHeader("User-Agent") String userAgent) {
return "Hi," + userAgent;
}
}
使用 postman 测试:
③ Session
Ⅰ. 创建 Session
@RestController
@RequestMapping("/web") // 路由器规则注册
public class WebController {
/**
* 创建 Session
* @param request
* @param response
* @return
*/
@RequestMapping("/setsession")
@ResponseBody
public String session(HttpServletRequest request, HttpServletResponse response) {
// 是否必须,是,如果没有就创建一个 session
HttpSession session = request.getSession(true);
if(session!=null){
session.setAttribute("username","wangwu");
}
return "success";
}
}
Ⅱ. 传统获取
@RestController
@RequestMapping("/web") // 路由器规则注册
public class WebController {
/**
* 传统方法获取 Session
*
* @param request
* @param response
* @return
*/
@RequestMapping("/session")
@ResponseBody
public String session(HttpServletRequest request, HttpServletResponse response) {
// 如果 session 不存在,不会⾃动创建
HttpSession session = request.getSession(false);
String username = "暂⽆";
if (session != null && session.getAttribute("username") != null) {
username = (String) session.getAttribute("username");
}
return "username:" + username;
}
}
使用 postman 测试:
Ⅲ. @SessionAttribute
@RestController
@RequestMapping("/web") // 路由器规则注册
public class WebController {
/**
* 使用 @SessionAttribute 注解
*
* @param username
* @return
*/
@RequestMapping("/session2")
@ResponseBody
public String session2(@SessionAttribute(value = "username", required = false) String username) {
return "username:" + username;
}
}
使用 postman 测试:
四、返回数据
1、返回静态页面
先创建一个 html 页面:
@Controller // 在 Spring 启动的时候,加载并注册
@RequestMapping("/web") // 路由器规则注册
public class WebController {
/**
* 返回 静态⻚⾯
* @return
*/
@RequestMapping("/retindex")
public Object retindex(){
return "/index.html";
}
}
访问网址:http://localhost:8080/web/retindex
2、返回 text/html
@Controller // 在 Spring 启动的时候,加载并注册
@RequestMapping("/web") // 路由器规则注册
public class WebController {
/**
* 返回 html
* @return
*/
@RequestMapping("/rethtml")
@ResponseBody
public Object rethtml(){
return "<h1>Hello~</h1>";
}
}
访问网址:http://localhost:8080/web/rethtml
3、返回 JSON 对象
@Controller // 在 Spring 启动的时候,加载并注册
@RequestMapping("/web") // 路由器规则注册
public class WebController {
/**
* 返回 JSON
* @return
*/
@RequestMapping("/retjson")
@ResponseBody
public HashMap<String, String> retjson() {
HashMap<String, String> map = new HashMap<>();
map.put("zhangsan", "123");
map.put("lisi", "666");
map.put("wangwu", "777");
return map;
}
}
访问网址:http://localhost:8080/web/retjson
4、请求转发或请求重定向
forward VS redirect
return 不但可以返回⼀个视图,还可以实现跳转,跳转的⽅式有两种:
- forward:请求转发;
- redirect:请求重定向。
① 转发和重定向的区别
@Controller
public class TestController {
/**
* 请求转发
* @return
*/
@RequestMapping("/hello")
public Object hello(){
return "forward:/index.html";
}
/**
* 请求重定向
* @return
*/
@RequestMapping("/hello2")
public Object hello2(){
return "redirect:/login.html";
}
}
打开网址:http://localhost:8080/hello
打开网址:http://localhost:8080/hello2
我们可以看到,转发的地址还是原地址,但重定向的地址发生了改变!
forward 和 redirect 具体区别如下:
- 请求重定向(redirect)将请求重新定位到资源;请求转发(forward)服务器端转发。
- 请求重定向地址发⽣变化,请求转发地址不发⽣变化。
- 请求重定向与直接访问新地址效果⼀直,不存在原来的外部资源不能访问;请求转发服务器端转发
有可能造成原外部资源不能访问
② 举例说明
forward(请求转发)和 redirect(请求重定向)的区别,举例来说,例如,你告诉你妈妈,你想吃辣条,如果你妈妈,说好,我帮你去买,这就是 forward 请求转发;如果你妈妈让你⾃⼰去买,那么就是请求 redirect 重定向。
5、@ResponseBody 说明
- @ResponseBody 返回的值如果是字符会转换成 text/html,如果返回的是对象会转换成 application/json 返回给前端。
- @ResponseBody 可以⽤来修饰⽅法或者是修饰类,修饰类表示类中的所有⽅法都会返回 html 或者 json,⽽不是视图。
6、查看更多注解
https://docs.spring.io/springframework/docs/current/reference/html/web.html#mvc-ann-requestmapping