Spring Web MVC~

一、认识Spring Web MVC

它是 Spring 框架的一部分,主要用于构建基于 MVC 设计模式的 Web 应用程序

1. MVC 定义

MVC 是 Model View Controller 的缩写,它是软件工程中的一种软件架构设计模式,它把软件系统分为模型、视图和控制器三个基本部分

2. 什么是Spring MVC?

MVC 是一种架构设计模式,也是一种思想,而 Spring MVC 是对 MVC 思想的具体实现,除此之外,Spring MVC还是一个Web框架,总结来说,Spring MVC 是一个实现了 MVC 模式的 Web 框架

所以,Spring MVC主要关注有两个点:

  1. MVC
  2. Web框架

Spring MVC 我们在前面已经用过了,在创建 Spring Boot 项目时,我们勾选的 Spring Web 框架,其实就是 Spring MVC 框架

二、 学习Spring MVC

主要分以下三个方面:

  1. 建立连接:将用户(浏览器)和 Java 程序连接起来,也就是访问一个地址能够调用到我们的Spring 程序
  2. 请求: 用户请求的时候会带一些参数,在程序中要想办法获取到参数,所以请求这块主要是获取参数的功能
  3. 响应: 执行了业务逻辑之后,要把程序执行的结果返回给用户,也就是响应

1. 项目准备

Spring MVC 项目创建和 Spring Boot 创建项目相同,在创建的时候选择 Spring Web 就相当于创建了Spring MVC 的项目

2. 建立连接

在 Spring MVC 中使用 @RequestMapping 来实现 URL 路由映射 ,也就是浏览器连接程序的作用


@RequestMapping 注解

1)@RequestMapping 是 Spring Web MVC 应用程序中最常被用到的注解之一,它是用来注册接口的路由映射的,表示服务收到请求时, 路径为 /request/r1 的请求就会调用 r1 这个方法的代码

@RequestMapping 既可修饰类,也可以修饰方法 ,当修饰类和方法时,访问的地址是类路径 + 方法路径

java 复制代码
@RestController
@RequestMapping("/request")
public class RequestController {
    //http://localhost:8080/request/r1?s1=hello
    @RequestMapping("/r1")
    public String r1(String s1) {
        return "接受到的参数:" + s1;
    }

**

2)@RequestMapping 是 GET 还是 POST 请求?

GET请求:

浏览器发送的请求类型都是get,通过以上案例,可以看出来 @RequestMapping 支持get请求

POST 请求:

我们通过form表单来构造请求

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="/request/r1" method="post">
    <input type="submit" value="提交">
</form>
</body>
</html>

访问此URL

点击提交

从运行结果可以看出: @RequestMapping 既支持Get请求,又支持Post请求,同理,也支持其他的请求方式

3)指定GET/POST方法类型

java 复制代码
@RequestMapping(value = "/hello2", method = {RequestMethod.GET, RequestMethod.POST})
    public String hello2(){
        return "hello, springmvc222";
    }

3. 创建请求(使用postman)

postman下载地址

1.普通传参,也就是通过查询字符串来传参

2.form-data

3.x-www-form-urlencoded

4.raw

4. 请求

访问不同的路径,就是发送不同的请求,在发送请求时,可能会带一些参数,所以学习Spring的请求,主要是学习如何传递参数到后端以及后端如何接收

1. 传递单个参数

java 复制代码
 @RequestMapping("/r3")
    public String r3(Boolean flag) {
        return "接受到的参数:" + flag;
    }


注意:

使用基本类型来接收参数时,参数必须传(除boolean类型),否则会报500错误

类型不匹配时,会报400错误

2. 传递多个参数

java 复制代码
@RequestMapping("/r4")
    public String r4(String name, Integer age, Boolean flag) {
        return "接受到的参数:" + name + " " + age + " " + flag;
    }


3. 传递对象

java 复制代码
public class Person {
    private String name;
    private Integer age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Integer getGender() {
        return gender;
    }

    public void setGender(Integer gender) {
        this.gender = gender;
    }

    private Integer gender;

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", gender=" + gender +
                '}';
    }
}
java 复制代码
@RequestMapping("/r5")
    public String r5(Person person) {
        return "接受到的参数:" + person;
    }

4. 后端参数重命名

某些特殊的情况下,前端传递的参数 key 和我们后端接收的 key 可以不一致,比如前端传递了一个time 给后端,而后端是使用 createtime 字段来接收的,这样就会出现参数接收不到的情况,如果出现这种情况,我们就可以使用 @RequestParam 来重命名前后端的参数值

java 复制代码
 @RequestMapping("/r6")
    public String r6(@RequestParam(value = "sa", required = false) String name) {
        return "接受到的参数:" + name;
    }

5. 传递数组

java 复制代码
@RequestMapping("/r7")
    public String r7(String[] array) {
        return "接受到的参数:" + Arrays.toString(array);
    }

6. 传递集合

集合参数:和数组类似,同一个请求参数名有为多个,且需要使用@RequestParam 绑定参数关系

java 复制代码
@RequestMapping("/r8")
    public String r8(@RequestParam List<String> list) {
        return "接受到的参数:" + list;
    }

7. 传递JSON数据

JSON是一种轻量级的数据交换格式。它基于 JavaScript 编程语言的一个子集,但它是完全独立于语言的,被几乎所有现代编程语言所支持和使用,JSON 是一个字符串,其格式非常类似于 JavaScript 对象字面量的格式
JSON字符串和Java对象互转

java 复制代码
void contextLoads() throws JsonProcessingException {
		ObjectMapper mapper = new ObjectMapper();
		//对象转json
		Person person = new Person();
		person.setName("张三");
		person.setAge(18);
		person.setGender(1);
		String json = mapper.writeValueAsString(person);
		System.out.println(json);

		//json转对象
		mapper.readValue(json, Person.class);
		System.out.println(person);

	}


传递JSON对象

接收JSON对象, 需要使用 @RequestBody 注解

java 复制代码
@RequestMapping("/r9")

    public String r9(@RequestBody Person person) {
        return "接受到的参数:" + person;
    }


8. 获取URL中参数@PathVariable

path variable: 路径变量

和字面表达的意思一样,这个注解主要作用在请求URL路径上的数据绑定

java 复制代码
@RequestMapping("/{acticleID}")
    public String r10(@PathVariable("acticleID") Integer acticleID) {
        return "接受到的参数:" + acticleID;
    }
java 复制代码
@RequestMapping("/{type}/{acticleID}")
    public String r11(@PathVariable String type, @PathVariable Integer acticleID) {
        return "接受到的参数:" + type + " " + acticleID;
    }

如果方法参数名称和需要绑定的URL中的变量名称一致时,可以简写,不用给@PathVariable的属性赋值

9. 上传文件@RequestPart

java 复制代码
 @RequestMapping("/r12")
    public String r12(MultipartFile file) throws IOException {
        String name = file.getName();
        String originalFilename = file.getOriginalFilename();
        System.out.println(originalFilename);
        String contentType = file.getContentType();
        System.out.println(contentType);
        file.transferTo(new File("D:\\课件" + originalFilename));
        return "接受的文件: " + name;
    }


10. 获取Cookie/Session

HTTP 协议自身是属于 "无状态" 协议

"无状态" 的含义指的是:

默认情况下 HTTP 协议的客户端和服务器之间的这次通信,和下次通信之间没有直接的联系

但是实际开发中,我们很多时候是需要知道请求之间的关联关系的。

例如登陆网站成功后,第二次访问的时候服务器就能知道该请求是否是已经登陆过了
Cookie 是服务器发送到用户浏览器并存储在客户端(浏览器)的一小块文本数据

Session 是一种在服务器端存储用户特定数据的机制

区别总结

Session 依赖于 Cookie 来工作。服务器会将一个名为 Session ID 的小令牌存储在 Cookie 中,发送给浏览器。浏览器在每次请求时带着这个 Session ID Cookie,服务器接收到 ID 后,就能在自己的 Session 存储区中找到对应的完整用户数据
获取Cookie

传统获取Cookie

java 复制代码
@RequestMapping("/getCookie")
    public String getCookie(HttpServletRequest request, HttpServletResponse response){
        Cookie[] cookies = request.getCookies();
        if (cookies != null) {
            for (Cookie cookie : cookies) {
                System.out.println(cookie.getName() + "=" + cookie.getValue());
            }
        }
        return "获取成功";

    }

此时没有设置Cookie,我们设置一下Cookie的值

查看日志

简洁获取Cookie

java 复制代码
@RequestMapping("/getCookie2")
    public String getCookie2(@CookieValue("flower") String flower){
        System.out.println(flower);
        return flower;
    }


获取Session

Session 存储和获取

Session 是服务器端的机制,我们需要先存储,才能再获取

Session 也是基于HttpServletRequest 来存储和获取的
Session存储

java 复制代码
@RequestMapping("/setSession")
    public String setSession(HttpServletRequest request, String name){
        HttpSession session = request.getSession();
        session.setAttribute("name", "zhangsan");
        session.setAttribute("age", "18");
        session.setAttribute("userInfo", new Person("zhangsan", 18, 1));
        return "设置成功" + name;
    }

这个代码中看不到 SessionId 这样的概念的,getSession 操作内部提取到请求中的 Cookie 里的 SessionId,然后根据SessionId获取到对应的Session 对象,Session 对象用 HttpSession来描述

Session读取

java 复制代码
@RequestMapping("/getSession")
    public String getSession(HttpServletRequest request){
        HttpSession session = request.getSession(false);
        if (session != null) {
            Object name = session.getAttribute("name");
            Object age = session.getAttribute("age");
            Object userInfo = session.getAttribute("userInfo");
            System.out.println(name);
            System.out.println(age);
            System.out.println(userInfo);
            return "获取成功";
        }
        return "获取失败";
    }


简洁获取 Session(1)

java 复制代码
@RequestMapping("/getSession2")
    public String getSession2(@SessionAttribute("name") String name){
        return name;
    }

简洁获取 Session(2)

java 复制代码
@RequestMapping("/getSession3")
    public String getSession3(HttpSession session){
        return (String) session.getAttribute("name");
    }

11. 获取Header

传统获取 header

java 复制代码
@RequestMapping("/getHeader")
    public String getHeader(HttpServletRequest request){
        return request.getHeader("user-agent");
    }


简洁获取 Header

java 复制代码
@RequestMapping("/getHeader2")
    public String getHeader2(@RequestHeader("user-agent") String userAgent){
        return userAgent;
    }

@RequestHeader注解的参数值为HTTP请求报头中的Key

5. 响应

在我们前面的代码例子中,都已经设置了响应数据,Http 响应结果可以是数据,也可以是静态页面,可以针对响应设置状态码,Header信息等

1. 返回静态页面

创建前端页面 index.html

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
我是一个index页面
</body>
</html>
java 复制代码
@RequestMapping("/returnPage")
//    @ResponseBody
    public String returnPage(){
//        List<Integer> list = List.of(1, 2, 3);
        return "/index.html";
    }


@Controller(返回页面) 等价于 @ResponseBody + @RestController(返回数据)

2. 返回数据@ResponseBody

java 复制代码
 @Controller
 @RequestMapping("/returnPage")
    @ResponseBody
    public String returnPage(){
//        List<Integer> list = List.of(1, 2, 3);
        return "/index.html";
    }

@ResponseBody 既是类注解,又是方法注解

如果作用在类上,表示该类的所有方法,返回的都是数据,如果作用在方法上,表示该方法返回的是数据

多个注解没有先后顺序

如果想返回视图的话,只需要把 @ResponseBody 去掉就可以了,也就是 @Controller

3. 返回HTML代码片段

java 复制代码
 @RequestMapping("/returnHtml")
    @ResponseBody
    public String returnHtml(){
        return "<h1>hello world</h1>";
    }


响应中的 Content-Type 常见取值有以下几种:

  • text/html : body 数据格式是 HTML
  • text/css : body 数据格式是 CSS
  • application/javascript : body 数据格式是 JavaScript
  • application/json : body 数据格式是 JSON

4. 返回JSON

java 复制代码
@ResponseBody
    @RequestMapping("/returnJson")
    public Person returnJson(){
        return new Person("张三", 18, 1);
    }


java 复制代码
@ResponseBody
    @RequestMapping("/returnJson2")
    public Map<String, String> returnJson2(){
        Map<String, String> map = new HashMap<>();
        map.put("name", "张三");
        map.put("age", "18");
        return map;
    }


5. 设置状态码

Spring MVC会根据我们方法的返回结果自动设置响应状态码,程序员也可以手动指定状态码

java 复制代码
 @ResponseBody
    @RequestMapping("/setStatus")
    public String setStatus(HttpServletResponse response){
        response.setStatus(400);
        return "设置状态码成功";
    }


6. 设置Header

Http响应报头也会向客户端传递一些附加信息,比如服务程序的名称,请求的资源已移动到新地址等,如:Content-Type, Local等

这些信息通过 @RequestMapping 注解的属性来实现

@RequestMapping 的源码:

  1. value: 指定映射的URL
  2. method: 指定请求的method类型,如GET,POST等
  3. consumes: 指定处理请求(request)的提交内容类型(Content-Type),例如application/json,text/html
  4. produces: 指定返回的内容类型,还可以同时设置返回值的字符编码
  5. Params: 指定request中必须包含某些参数值时,才让该方法处理
  6. headers: 指定request中必须包含某些指定的header值,才能让该方法处理请求

7. 设置Content-Type

java 复制代码
@ResponseBody
     @RequestMapping(value = "/setContentType", produces = "application/json")
    public String setContentType(){
        return "{\"OK\":1}";
    }


8. 设置其他Header

设置其他Header的话,需要使用Spring MVC的内置对象HttpServletResponse 提供的方法来进行设置

java 复制代码
@ResponseBody
    @RequestMapping("/setHeader")
    public String setHeader(HttpServletResponse response){
        response.setHeader("MyHeader","MyHeaderValue");
        return "设置响应头成功";
    }


三、综合性练习

1. 加法计算器

需求: 输入两个整数,点击"点击相加"按钮,显示计算结果

1. 准备工作

创建SpringBoot项目: 引入Spring Web依赖, 把前端页面放在项目中

2. 约定前后端交互接口

需求分析

加法计算器功能,对两个整数进行相加,需要客户端提供参与计算的两个数,服务端返回这两个整数计算的结果
接口定义

请求路径:calc/sum

请求方式:GET/POST

接口描述:计算两个整数相加
请求参数

参数名 类型 是否必须 备注
num1 Integer 参与计算的第一个数
num2 Integer 参与计算的第二个数

响应数据

Content-Type: text/html

3. 服务器代码

java 复制代码
@RestController
@RequestMapping("/calc")
public class CalcController {
    @RequestMapping("/sum")
    public String sum(Integer num1,Integer num2){
        Integer sum = num1+num2;
        return "<h1>计算机计算结果: "+sum+"</h1>";
    }
}

4. 调整前端页面代码

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
     <form action="calc/sum" method="post">
        <h1>计算器</h1>
        数字1:<input name="num1" type="text"><br>
        数字2:<input name="num2" type="text"><br>
        <input type="submit" value=" 点击相加 ">
    </form>
</body>

</html>

5. 运行测试


本期内容到此为止,喜欢的话请点个赞,谢谢观看!!!

相关推荐
fruge1 小时前
大流量场景踩坑:前端如何应对秒杀活动的并发请求
前端
IT_陈寒2 小时前
Vue 3.4 性能优化实战:7个被低估的Composition API技巧让你的应用提速30%
前端·人工智能·后端
鹏多多2 小时前
React的useRef的深度解析与应用指南
前端·javascript·react.js
a***97682 小时前
使用 Logback 的最佳实践:`logback.xml` 与 `logback-spring.xml` 的区别与用法
xml·spring·logback
你说啥名字好呢2 小时前
【Vue 渲染流程揭秘】
前端·javascript·vue.js·vue3·源码分析
rit84324992 小时前
配置Spring框架以连接SQL Server数据库
java·数据库·spring
艾小码2 小时前
Vue表单组件进阶:打造属于你的自定义v-model
前端·javascript·vue.js
Alang2 小时前
【LM-PDF】一个大模型时代的 PDF 极速预览方案是如何实现的?
前端·人工智能·后端
lcc1873 小时前
Vue mixin混入
前端·vue.js