一. 什么是 Spring MVC
1) Spring MVC 是一个 Web 框架
2) Spring MVC 是基于 Servlet API 构建的
1.1 MVC 定义
MVC 是
Model View Controller 的缩写,它是软件⼯程中的⼀种软件架构模式,它把软件系统分
为模型、视图和控制器三个基本部分
Model (模型)
是应⽤程序中⽤于处理应⽤程序数据逻辑的部分。通常模型对象负责在数据库中存 取数据。
View(视图)
是应⽤程序中处理数据显示的部分。通常视图是依据模型数据创建的。
Controller(控制器)
是应⽤程序中处理⽤户交互的部分。通常控制器负责从视图读取数据,控制⽤户输⼊,并向模型发送数据。
1.2 MVC 和 Spring MVC 的关系
MVC 是⼀种思想,而Spring MVC 是对 MVC 思想的具体实现
Spring MVC 是⼀个实现了 MVC 模式,并继承了 Servlet API 的 Web 框架。既然是 Web 框架,那么当⽤户在浏览器中输⼊了 url 之后,我们的 Spring MVC 项⽬就可以感知到⽤户的请求
二. Spring MVC
1)
连接功能
:将⽤户(浏览器)和 Java 程序连接起来,也就是访问⼀个地址能够调⽤到我们的v Spring 程序。
2)
获取参数的功能
:⽤户访问的时候会带⼀些参数,在程序中要想办法获取到参数。
3)
输出数据的功能
:执⾏了业务逻辑之后,要把程序执行的结果返回给⽤户
2.1 Spring MVC 创建和连接
2.1.1 创建 Spring MVC 项目
1)Spring MVC 可以基于 Spring Boot 创建,也就是创建⼀个 Spring Boot 项⽬,勾选上 Spring Web模块即可
2)
创建⼀个 UserController 类,实现⽤户到 Spring 程序的互联互通:
@RequestMapping("/test") // 路由注册
//@Controller // 把类注册到框架中
//@ResponseBody // 告诉程序返回的是数据而非页面
@RestController //和上面两个效果相同
public class TestController {
@PostMapping("/hi")
public String sayHi(){
return "Hi,Spring boot~";
}
}
3)运行程序,
访问地址:
http://localhost:8080/test/hi
,就能打印“Hi,Spring boot”了
2.1.2 @RequestMapping 注解介绍
@RequestMapping 是用
来注册接口的路由映射的
路由映射:所谓的路由映射指的是,当⽤户访问⼀个 url 时,将⽤户的请求对应到程序中某个类的某个⽅法的过程就叫路由映射
@RequestMapping 基础使⽤:
1)
@RequestMapping 即可修饰类,也可以修饰⽅法,当修饰类和⽅法时,访问的地址是类 + ⽅
法。
@RequestMapping 也可以直接修饰⽅法
2.1.3 指定 @RequestMapping 接收 post 或 get 请求
get :
// 写法1
@RequestMapping("/index")
// 写法2
@RequestMapping(value = "/index",method = RequestMethod.GET)
// 写法3
@GetMapping("/index")
post:
// 写法1
@RequestMapping(value = "/index",method = RequestMethod.POST)
// 写法2
@PostMapping("/index")
2.2 获取参数
2.2.1 传递单个参数
在 Spring MVC 中可以直接⽤⽅法中的参数来实现传参:
@RequestMapping("/m1")
public Object method_1(String name){
System.out.println("参数 name:"+name);
return "/index.html";
}
2.2.2 传递对象
Spring MVC 可以⾃动实现参数对象的赋值
1)Person 对象
import lombok.Data;
@Data
public class Person {
private int id;
private String name;
private String password;
}
2)传递对象
@RequestMapping("/m2")
public Object method_2(Person p){
System.out.println("对象中的 name:"+p.getName());
System.out.println("对象中的 password:"+p.getPassword());
return "/index.html";
}
2.2.3
表单参数传递/传递多个参数(非对象)
@RequestMapping("/m3")
public Object method_3(String name, String pwd) {
System.out.println("name 参数:" + name);
System.out.println("pwd 参数:" + pwd);
return "/index.html";
}
2.2.4 后端参数重命名
当前端传递的参数 key 和我们后端接收的 key 可以不⼀致,⽐如前端传递了⼀个time 给后端,⽽后端⼜是有 createtime 字段来接收的,这样就会出现参数接收不到的情况,如果出现这种情况,我们就可以使⽤ @RequestParam 来重命名前后端的参数值
@RequestMapping("/m4")
public Object method_4(@RequestParam("time") String createtime) {
System.out.println("时间:" + createtime);
return "/index.html";
}
2.2.5 设置参数必传@RequestParam
上⾯的列⼦,如果我们是前端传递⼀个⾮ time 的参数,就会出现程序报错的情况
这是因为后端已经声明了前端必须传递⼀个 time 的参数,但是前端没有给后端传递
非必传参数设置
如果我们的实际业务前端的参数是⼀个⾮必传的参数,我们可以通过设置 @RequestParam 中的 required=false 来避免不传递时报错:
@RequestMapping("/m4")
public Object method_4(@RequestParam(value = "time", required = false) String createtime) {
System.out.println("时间:" + createtime);
return "/index.html";
}
2.2.6 @RequestParam 接受JOSN对象
在 postman 中访问方法
后端接收代码
@RequestMapping(value = "/m5", method = RequestMethod.POST)
public Object method_5(@RequestBody Person person) {
System.out.println("Person:" + person);
return "redirect:/index.html";
}
2.2.7 获取URL中参数@PathVariable
后端实现:
@PostMapping("/m6/{name}/{password}")
public Object method_6(@PathVariable String name, @PathVariable String password) {
System.out.println("name:" + name);
System.out.println("password:" + password);
return "redirect:/index.html";
}
前端方法地址:
2.2.8 上传文件@RequestPart
@RequestMapping("/param10")
public String param10(@RequestPart("myfile") MultipartFile file) throws IOException {
// 根目录
String path = "D:\\text3\\";
// 根目录 + 唯一文件名
path += UUID.randomUUID().toString().replace("-","");
// 根目录 + 唯一文件名 + 文件后缀
path += file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
// 保存文件
file.transferTo(new File(path));
return path;
}
获取项目目录的几种方式:
ResourceUtils.getFile(ResourceUtils.CLASSPATH_URL_PREFIX).getPath();
new ClassPathResource("").getFile().getAbsolutePath();
ClassUtils.getDefaultClassLoader().getResource("").getPath();
ResourceUtils.getFile("classpath:static/").getPath();
2.2.9 获取Cookie/Session/header
获取 Request 和 Response 对象
@RequestMapping("/param11")
public String param11(HttpServletResponse response, HttpServletRequest requ
est) {
String name = request.getParameter("name");
// 获取所有 cookie 信息
Cookie[] cookies = request.getCookies();
return name + " 你好.";
}
获取 Cookie——@CookieValue
@RequestMapping("/cookie")
@ResponseBody
public String cookie(@CookieValue("bite") String bite) {
return "cookie:" + bite;
}
获取 Header——@RequestHeader
@RequestMapping("/header")
@ResponseBody
public String header(@RequestHeader("User-Agent") String userAgent) {
return "userAgent:"+userAgent;
}
Session 存储和获取
存储:
@RequestMapping("/setsess")
@ResponseBody
public String setsess(HttpServletRequest request) {
// 获取 HttpSession 对象,参数设置为 true 表示如果没有 session 对象就创建⼀个session
HttpSession session = request.getSession(true);
if(session!=null){
session.setAttribute("username","java");
}
return "session 存储成功";
}
获取:
@RequestMapping("/sess")
@ResponseBody
public String sess(HttpServletRequest request) {
// 如果 session 不存在,不会⾃动创建
HttpSession session = request.getSession(false);
String username = "暂⽆";
if(session!=null && session.getAttribute("username")!=null){
username = (String) session.getAttribute("username");
}
return "username:"+username;
}
更简单的获取:
@RequestMapping("/sess2")
@ResponseBody
public String sess2(@SessionAttribute(value = "username",required = false)
String username) {
return "username:"+username;
}
2.3 返回数据
默认请求下⽆论是 Spring MVC 或者是 Spring Boot 返回的是视图 (xxx.html),⽽现在都是前后端分离的,后端只需要返给给前端数据即可,这个时候我们就需要使⽤
@ResponseBody
注解了
2.3.1 返回静态页面
创建前端页面 index.html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>hello,spring mvc</title>
<script src="index.js"></script>
</head>
<body>
<h1>Hello,Spring MVC.</h1>
</body>
</html>
创建控制器 controller:
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/p")
public class PersonController {
@RequestMapping("/index")
public Object index(){
// 执⾏业务...
// 返回view -> index.html
return "/index.html";
}
}
2.3.2 返回 text/html
@RequestMapping("/m7")
@ResponseBody
public String method_7() {
return "<h1>Hello,HTML~</h1>";
}
2.3.3 返回 JSON 对象
@RequestMapping("/m8")
@ResponseBody
public HashMap<String, String> method_8() {
HashMap<String, String> map = new HashMap<>();
map.put("Java", "Java Value");
map.put("MySQL", "MySQL Value");
map.put("Redis", "Redis Value");
return map;
}
2.3.4 请求转发或请求重定向
1)forward 请求转发;
2)redirect 请求重定向。
// 请求重定向
@RequestMapping("/index")
public String index(){
return "redirect:/index.html";
}
// 请求转发
@RequestMapping("/index2")
public String index2(){
return "forward:/index.html";
}
转发和重定向的区别:转发是服务器帮转的,而重定向是让浏览器重新请求另⼀个地址。
forward 和 redirect 具体区别:
1.
请求重定向(redirect)将请求重新定位到资源;请求转发(forward)服务器端转发。
2.
请求重定向地址发⽣变化,请求转发地址不发⽣变化。
3.
请求重定向与直接访问新地址效果⼀致,不存在原来的外部资源不能访问;请求转发服务器端转发有可能造成原外部资源不能访问。
请求转发 forward 导致问题演示
请求转发如果资源和转发的⻚⾯不在⼀个⽬录下,会导致外部资源不可访问
controller 示例代码:
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping(value = "/index")
public String sayHi(){
return "forward:/index.html";
}
}
程序的⽬录如下:
尝试将转发 foward 换成重定向 redirect:
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping(value = "/index")
public String sayHi(){
return "redirect:/index.html";
}
}
页面就可以正常获取到外部资源 js 了
2.3.5 @ResponseBody 说明
@ResponseBody 返回的值如果是字符会转换成 text/html,如果返回的是对象会转换成application/json 返回给前端。
@ResponseBody 可以⽤来修饰⽅法或者是修饰类,修饰类表示类中的所有⽅法都会返回 html 或者 json,而不是视图。
2.3
.6 组合注解:@RestController
@RestController = @Controller + @ResponseBody