✏️作者:银河罐头
📋系列专栏:JavaEE
🌲“种一棵树最好的时间是十年前,其次是现在”
目录
- 什么是 Spring MVC
- MVC 定义
- 怎么学 Spring MVC
- Spring MVC 创建和连接
- 创建 Spring MVC 项目
- @RequestMapping 注解介绍
- @PostMapping
- 获取参数
- 获取单个参数
- 获取多个参数
- 传递对象
- 后端参数重命名
- @RequestBody 接收JSON对象
- 获取URL中参数@PathVariable
- 上传文件@RequestPart
- 获取Cookie/Session/header
- 返回数据
什么是 Spring MVC
SSM = Spring Boot + Spring Web(Spring MVC) + MyBatis
Spring Web MVC 是基于 Servlet API 构建的原始 Web 框架,从⼀开始就包含在 Spring 框架中。它的正式名称"Spring Web MVC"来自其源模块的名称(Spring-webmvc), 但它通常被称为"Spring MVC".
- Spring MVC 是⼀个 Web 框架。
- Spring MVC 是基于 Servlet API 构建的。
MVC 定义
MVC 是 Model View Controller 的缩写,它是软件⼯程中的⼀种软件架构模式,它把软件系统分为模型、视图和控制器三个基本部分。
怎么学 Spring MVC
学习 Spring MVC 我们只需要掌握以下 3 个功能:
1.连接的功能:将⽤户(浏览器)和 Java 程序连接起来,也就是访问⼀个地址能够调⽤到我们的 Spring 程序
2.获取参数的功能:⽤户访问的时候会带⼀些参数,在程序中要想办法获取到参数。
3.输出数据的功能:执⾏了业务逻辑之后,要把程序执⾏的结果返回给⽤户。
对于 Spring MVC 来说,掌握了以上 3 个功能就相当于掌握了 Spring MVC。
Spring MVC 创建和连接
创建 Spring MVC 项目
2018年之前,使用 maven 项目添加 Spring MVC 框架的方式来创建,太复杂。
2018年之后 ,使用 Spring Boot 来创建 Spring MVC 项目。
@RestController
public class UserController {
@RequestMapping("/say")//可以是 1 级路由,也可以是 n 级路由
public String sayHi(){
return "hi spring mvc";
}
}
实现用户到 spring 程序的连接。
@RequestMapping 注解介绍
它支持 GET 请求
那它是否支持 post 请求?
用 postman 测试:
得出结论:它也支持 POST 请求.
GET, HEAD, POST,PUT, PATCH, DELETE, OPTIONS, TRACE 都支持。
在浏览器地址栏输入地址,默认是 GET 请求。
- 如果我想设置成只支持其中某一种请求类型,如何实现?
@RestController
public class UserController {
@RequestMapping(value = "/sayhi",method = RequestMethod.POST)
public String sayHi(){
return "hi spring mvc";
}
}
设置成只支持 POST 请求,再发 GET 请求就失败了。
@PostMapping
除了通过 @RequestMapping 来设置 POST,还可以通过@PostMapping 来设置。
@PostMapping("/sayhello")
public String sayHello(){
return "hello spring mvc";
}
小结:
2种实现路由连接的方式 :@RequestMapping 和 @PostMapping
@GetMapping("/hi")
public String hi(){
return "spring mvc hi";
}
获取参数
获取单个参数
@RequestMapping("/sayhi")
public String sayHi(String name){
return "hi " + name;
}
这里地址栏里 key 必须写"name", 才能成功拿到 value
如果传了错误的 key 或者不传参数 ,结果就是String 的默认值 null
@RequestMapping("/sayhi2")
public String sayHi2(Integer id){
return "hi " + id;
}
@RequestMapping("/sayhi3")
public String sayHi3(int id){
return "hi " + id;
}
参数传递不要使用基本数据类型(如 int)。
@RequestMapping("/sayhi4")
public String sayHi4(HttpServletRequest request, HttpServletResponse response){
return "hi " + request.getParameter("name");
}
@RequestMapping("/sayhi4")
public String sayHi4(HttpServletRequest request, HttpServletResponse response) throws IOException {
response.sendRedirect("https://www.sogou.com");
}
还可以实现重定向跳转页面。
获取多个参数
@RequestMapping("/sayhi")
public String sayHi(String name, String password){
return "name = " + name + " | password = " + password;
}
参数顺序不重要,保证 key 正确就行。
传递对象
@Data
public class Userinfo {
private int id;
private String name;
private String password;
private int age;
}
//获取对象
@RequestMapping("/reg")
public Object reg(Userinfo userinfo){
return userinfo;
}
@RequestMapping("/h1")
public Object getH1(){
return "<h1>我是 h1</h1>";
}
后端参数重命名
某些特殊的情况下,前端传递的参数 key 和我们后端接收的 key 可以不⼀致, 比如前端传递一个 username 给后端,后端用 name 接收,这样就会出现参数接收不到的情况,如果出现这种情况,我们就可以使用@RequestParam 来重命名前后端的参数值。
@RequestMapping("/reg2")
public Object reg(@RequestParam("username") String name, String password){
return "name = " + name + " | password = " + password;
}
如果前端传的是 name, 会怎样?
规定 前端必须传 “username”.
@RequestMapping("/reg2")
public Object reg(@RequestParam(value = "username",required = false) String name,
String password){
return "name = " + name + " | password = " + password;
}
required = false 设置之后
前端:对象/JSON 对象字符串
后端:对象/JSON 对象字符串
@RequestBody 接收JSON对象
用之前接收对象的方式,不能成功接收到 JSON 对象。
@RequestMapping("/reg")
public Object reg(Userinfo userinfo){
System.out.println(userinfo);
return userinfo;
}
用 postman 发送一个 post 请求。
用 @RequestBody 这个注解就可以成功接收到 JSON 对象了。
@RequestMapping("/reg3")
public Object reg3(@RequestBody Userinfo userinfo){
return userinfo;
}
获取URL中参数@PathVariable
/user?uid=12345
/user/12345 优点:搜索引擎抓取关键字权重更高,更简洁
@RequestMapping("/reg4/{name}/{password}")
public Object reg4(@PathVariable String name, @PathVariable String password){
return "name = " + name + " | password = " + password;
}
如果把路径里的 password 改成 pwd,会怎样?
这个参数是必须的。所以会报错。
@RequestMapping("/reg4/{name}/{pwd}")
public Object reg4(@PathVariable String name, @PathVariable(required = false) String password){
return "name = " + name + " | password = " + password;
}
加 required = false 之后就不会报错,但是 还是得不到 password 的值。
小结:
@PathVariable: 基础 url 里面的参数(? 之前的参数)
@RequestParam: url 参数部分的参数(? 之后的参数)
@RequestMapping("/reg4/{name}/{pwd}")
public Object reg4(@PathVariable String name, @PathVariable(required = false,name = "pwd") String password){
return "name = " + name + " | password = " + password;
}
上传文件@RequestPart
@RequestMapping("/myupload")
public Object upload(@RequestPart("myimg")MultipartFile file){
File saveFile = new File("D:\\Data\\myimg.png");
try {
file.transferTo(saveFile);
return true;
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
用 postman 发送 post 请求:
文件上传成功。
默认要求上传单个文件大小不超过 1MB.
Common Application Properties (spring.io)
如果我要上传的文件很大怎么办?
可以设置上传文件大小。
有一个问题,后面上传的文件会把之前的文件覆盖。
MySQL -> InnoDB(5.5) -> B+存储 -> 聚簇索引树
叶子(数据页) 主键(如果有) + 数据
- 如何保证每次上传的文件不会覆盖?也就是最终保存的是不同的文件名。
UUID。
//上传文件
@RequestMapping("/myupload")
public Object upload(@RequestPart("myimg")MultipartFile file){
String fileName = UUID.randomUUID() + //文件名
file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));//后缀名
File saveFile = new File("D:\\Data\\" + fileName);
try {
file.transferTo(saveFile);
return true;
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
成功上传,没有覆盖原有的。
获取Cookie/Session/header
//获取 cookie
@RequestMapping("/getCookie")
public Object getCookie(@CookieValue(value = "java",required = false) String java){
return "java = " + java;
}
我们可以手动构造一个 cookie。
- 获取 Header
//获取 header
@RequestMapping("/header")
public Object getHeader(@RequestHeader("user-agent") String userAgent){
return "userAgent = " + userAgent;
}
- 获取 Session
private static final String SESSION_KEY = "USERINFO_SESSION_KEY";
//存储 session
@RequestMapping("/setSession")
public void setSession(HttpServletRequest request){
HttpSession session = request.getSession();//没有就创建,默认是 true
session.setAttribute(SESSION_KEY,"zhangsan");
}
//获取 session
@RequestMapping("/session")
public Object getSession(@SessionAttribute(SESSION_KEY) String name){
return "session = " + name;
}
返回数据
1)返回静态页面
@Controller
@RequestMapping("/test")
public class TestController {
@RequestMapping("/getIndex")
public Object getIndex(){
return "index.html";
}
}
确认 target 下有 index.html.
那是什么原因?
加了"/"之后就能访问成功了。
加了"/“表示是 从根目录去找"index.html”, 不加"/"是在 test 目录下去找 "index.html"就找不到.
2)请求转发或请求重定向
1.请求转发
//请求转发
@RequestMapping("/forward")
public String forward(){
return "forward:/index.html";
//return "/index.html"; 默认就是请求转发
}
2.请求重定向
//请求重定向
@RequestMapping("/redirect")
public String redirect(){
return "redirect:/index.html";
}
@RequestMapping("/redirect2")
public void redirect2(HttpServletResponse response) throws IOException {
response.sendRedirect("https://www.baidu.com");
}
forward 和 redirect 具体区别如下:
- 请求重定向(redirect)将请求重新定位到资源;请求转发(forward)服务器端转发。
- 请求重定向地址发生变化,请求转发地址不发⽣变化。
- 请求重定向,不存在原来的外部资源不能访问;请求转发服务器端转发 有可能造成原外部资源不能访问。
举例:
请求转发:张三找李四借钱,李四自己也没钱,李四又去找王五借,最终张三只借了一次钱,剩下的事都是 李四干的。
请求重定向:张三找李四借钱,李四自己也没钱,李四告诉张三说自己没钱让张三去找王五借钱。然后张三又去找王五借到了钱。
请求转发和请求重定向有什么区别? | Javaᶜⁿ 面试突击 (javacn.site)