Spring MVC

本文详细介绍了SpringMVC的核心功能,包括URL路由映射、参数获取(非对象、对象、JSON和文件)、请求头和Cookie处理、Session管理以及返回数据(HTML、JSON)和文件上传。
摘要由CSDN通过智能技术生成

什么是 Spring MVC

Spring Web MVC 是基于 Servlet API 构建的原始 Web 框架,从⼀开始就包含在 Spring 框架中。它的正式名称“Spring Web MVC”来自其源模块的名称(Spring-webmvc),但它通常被称为“Spring MVC”。

它是软件工程中的一种软件架构模式,现在市面上绝⼤部分的 Java 项目约等于 Spring MVC 项目。

创建 Spring MVC 项目只需要在创建 Spring Boot 项目的时候选择添加 Spring Web框架即可

image-20240128154137768

学习 Spring MVC 主要掌握3个功能

  1. 连接功能:将用户(浏览器)和程序连接起来
  2. 获取参数的功能:获取用户访问所带的参数
  3. 输出数据的功能:执行业务逻辑之后将结果返回给用户

Spring MVC的连接

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

例如:现在创建一个控制器类

@RestController // 启动框架时,自动加载
@RequestMapping("/user") // 路由器规则注册,也就是访问的地址
public class UserController {
    @RequestMapping(value = "/hello") // 路由器规则注册,也就是访问的地址
    public String print(){
        return "hello world";
    }
}

当启动项目后,通过访问地址:http://127.0.0.1:8080/user/hello,就可以得到函数中所返回的值

image-20240128154751167

@RequestMapping 注解

用来注册接口的路由映射。

所谓的路由映射指的是,当用户访问一个 url 时,将用户的请求对应到程序中某个类的某个方法的过程就叫路由映射

@RequestMapping 即可修饰类,也可以修饰方法,如果同时修饰了类和方法,那么访问的地址就是 类+方法

指定请求方式

如上述代码,如果使用 Get 方式请求可以访问成功,那么使用 Post 方式请求同样也是可以访问成功的

image-20240128155129823

@RequestMapping 注解默认是两种方式都可以访问

那么有些场景下,指定只能使用 Get或Post 一种方式访问,也是可以做到的。@RequestMapping 注解可是设置参数,比如映射地址为一个参数,还可以设置第二个参数,例如:

@RestController // 启动框架时,自动加载
public class UserController {
    @RequestMapping(value = "/hello", method = RequestMethod.GET) // 路由器规则注册,也就是访问的地址
    public String print(){
        return "hello world";
    }
}

设置了 method 参数就是指定该访问只能通过某种方式访问,参数的值是一个 enum 枚举类型。

**注意:当 @RestController 注解只有一个参数时,前面的参数类型名可以缺省。多个参数时必须执行参数类型,例如上述的映射地址前需要加上 value = **

image-20240128155602428

可以看到指定了 Get 方式后,使用 Post 请求就会失败

@GetMapping 和 @PostMapping

除了上述使用 @RequestMapping 注解外,还可以使用 @GetMapping 和 @PostMapping 这两个注解去指定

@RestController // 启动框架时,自动加载
public class UserController {
    @PostMapping("/hello") // 路由器规则注册,也就是访问的地址
    public String print(){
        return "hello world";
    }

    @GetMapping ("/hello2") // 路由器规则注册,也就是访问的地址
    public String print2(){
        return "hello world";
    }
}

Spring MVC的获取参数

获取非对象参数

在 Spring MVC 中可以直接使用方法中的参数来实现传参

@RestController // 启动框架时,自动加载
public class UserController {
    @RequestMapping("hello")
    public String print(String name){
        return "hello " + name;
    }
}

这时只需要在访问的 url 后面直接传参即可收到

image-20240128160200087

当然使用浏览器直接输入 url 中带参数也是可以的

image-20240128160307445

接收多个参数也是同理,并且在 url 中的顺序是不要求的

@RestController // 启动框架时,自动加载
public class UserController {
    @RequestMapping("hello")
    public String print(String name, String password){
        return "hello " + name + ": " + password;
    }
}

image-20240128160524282

对于传递参数有需要注意的事项:

  1. 在后端方法中传递的参数类型推荐使用包装类的类型而不是使用基本数据类型,假如使用了基本数据类型例如int,那么如果 url 中没有指定参数值则会报错。但是使用包装类则不会报错,因为其默认值为 null
  2. 如果像上述代码为例:则在前端 url 访问中,url中参数的名称必须与后端方法中的名称一样才能被接收到,例如上述的方法中参数名称为name,则url中的参数名称也要为name才能被接收到。下文会提到如何更改

获取 Request 和 Response 对象

在Spring MVC 中有两个接口,HttpServletRequest 和 HttpServletResponse,这两个接口的对象就是分别对应着处理请求和响应。

@RestController // 启动框架时,自动加载
public class UserController {
    @RequestMapping("/user")
    public String print(HttpServletRequest request, HttpServletResponse response){
        return "name: " + request.getParameter("name");
    }
}

当使用 HttpServletRequest 接口对象时,可以通过其 getParameter方法去获取指定的参数值的

image-20240128221330980

而使用 HttpServletResponse 接口对象时,则可指定响应的形式,例如调用其方法可以设置响应属性

获取对象参数

并且 Spring MVC 可以自动实现参数对象的赋值,例如现在有一个用户类

@Getter
@Setter
public class User {
    private int id;
    private String name;
    private String password;
    private int age;
}

则在方法中就可以直接通过这个实体类去接收参数数据

@RestController // 启动框架时,自动加载
public class UserController {
    @RequestMapping("user")
    public Object print(User user){
        return user;
    }
}

image-20240128161557524

可以看到确实是接收到了参数

后端参数重命名

上面提到了关于参数名的匹配,那么在 Spring MVC 中也可以去修改指定 url中所传参数的名字,通过**@RequestParam** 注解去指定

@RestController // 启动框架时,自动加载
public class UserController {
    @RequestMapping("user")
    public String print(@RequestParam("username")String name, String password){
        return name + ": " + password;
    }
}

像上述设置了之后,在 url 中就需要传递username才能被后端的 name 所接收

image-20240128162121544

参数必传

如果像上述代码中使用了 @RequestParam 注解去重命名,那么默认这个参数就是必须要传的,如果不传就会报错

image-20240128162259766

设置参数非必传

这个参数是可以设置为非必传的,也就是@RequestParam 注解中可以设置其参数,例如:

@RestController // 启动框架时,自动加载
public class UserController {
    @RequestMapping("user")
    public String print(@RequestParam(value = "username", required = false)String name, String password){
        return name + ": " + password;
    }
}

加上 required = false 后这个参数就变成了非必传参数

image-20240128162511366

不传 username 参数后就会变成默认值 null

@RequestBody 接收JSON对象

默认的接收方式是不可以接收到 JSON对象的

@RestController // 启动框架时,自动加载
public class UserController {
    @RequestMapping("user")
    public Object print(User user){
        return user;
    }
}

image-20240128163648261

可以看到传递值和打印出来的根本不一致。

那么要想让参数可以接收到 JSON 对象就需要在前面加上 @RequestBody 注解

@RestController // 启动框架时,自动加载
public class UserController {
    @RequestMapping("user")
    public Object print(@RequestBody User user){
        return user;
    }
}

image-20240128163812503

这样子就可以接收到了

获取URL中参数@PathVariable

上面所讲的接收都是需要在 url 中指定参数的,但是有些场景下是直接将参数写为地址的。例如我的博客系统就可以直接通过 XXX/10101 这样去获取一篇文章,而后面的10101就可以是我这篇文章的编号。

@RestController // 启动框架时,自动加载
public class UserController {
    @RequestMapping("user/{id}")
    public String print(@PathVariable String id){
        return "id: " + id;
    }
}

注意 路由映射地址的格式,加上{}的就代表可以获取的参数,然后接收的对象名需要一致。或者@PathVariable 注解也支持重命名和非必传的

image-20240128164613725

上传文件@RequestPart

上传一个图片

分为几个步骤

  1. 将方法的参数使用 @RequestPart 注解,这个注解需要指定参数名,并且参数必须为 MultipartFile 接口的对象
  2. 创建 Java 的文件 IO 对象并指明需要上传的地址
  3. 执行 MultipartFile 接口对象的方法 transferTo()
@RestController // 启动框架时,自动加载
public class UserController {
    @RequestMapping("upload")
    public Object Load(@RequestPart("file")MultipartFile file){
        File save = new File("D:\\my.png");
        try{
            file.transferTo(save);
            return true;
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

image-20240128171213734

image-20240128171245819

这种方式默认是有文件大小限制的,需要在配置文件中设置:

spring:
  servlet:
    multipart:
      max-request-size: 100MB
      max-file-size: 100MB

上述的代码还是会有问题,如果保存的位置里有和设置的文件名同名的话就会覆盖到原有的文件。因此可以使用 UUID 的方式去取文件名,而在使用UUID 前得想获取到文件的后缀名,这样才能确保文件格式。

@RestController // 启动框架时,自动加载
public class UserController {
    @RequestMapping("upload")
    public Object Load(@RequestPart("file")MultipartFile file){
        // 获取文件名
        String filename = file.getOriginalFilename();
        // 截取文件后缀名
        int pos = filename.lastIndexOf(".");
        filename = filename.substring(pos);

        // 使用UUID + 后缀名作为文件名并加上路径
        String path = "D://" + UUID.randomUUID() + filename;

        // 保存文件
        try {
            file.transferTo(new File(path));
            return true;
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

获取Cookie/header

传统获取 header/cookie

直接使用 HttpServletResponse 接口对象

@RequestMapping("/user")
public String print(HttpServletRequest request, HttpServletResponse response) throws IOException {
    // 获取所有cookie
    Cookie[] cookies = request.getCookies();
    // 获取指定header
    String userAgent = request.getHeader("User-Agent");
}

使用@CookieValue 注解获取

上面的代码是获取到了全部的cookie

使用@CookieValue 注解可以获取指定的cookie

@RequestMapping("/cookie")
public String cookie(@CookieValue("java") String java) {
	return "cookie:" + java;
}

这个注解默认是必传的,所以可以设置为非必传

@RequestMapping("/cookie")
public String cookie(@CookieValue("java", required = false) String java) {
	return "cookie:" + java;
}

使用@RequestHeader 注解获取

@RequestMapping("/cookie")
public String header(@RequestHeader("User-Agent") String userAgent) {
	return "userAgent:"+userAgent;
}

同样可以设置非必传

Session 存储和获取

Session 获取和Servlet 类似,可以使用 HttpServletRequest 接口的 getSession 方法去获取,如果该方法的参数设置为 true 则代表没有Session时自动创建一个session。设置为false则不会自动创建。默认是true。然后通过 setAttribute 方法去设置session。这也就是存储的方法

如果确定了这个session是存在的则可以使用 @SessionAttribute 注解去获取指定的session,这个注解同样可以设置非必传。

因此可以演示以下,访问一个地址去创建session,再去访问另一个地址获取session

@RestController // 启动框架时,自动加载
public class UserController {
    @RequestMapping("/set")
    public void setSess(HttpServletRequest request) {
        HttpSession session = request.getSession();
        session.setAttribute("username", "zhangsan");
    }

    @RequestMapping("/get")
    public String getSess(@SessionAttribute("username")String name) {
       return "username: " + name;
    }
}

首先访问/set去创建,再访问/get获取

image-20240128223819175

image-20240128223830835

返回数据

@Controller 和 @ResponseBody 和 @RestController

了解返回数据前需要先知道这三个注解的区别:

  1. @ResponseBody 返回的值如果是字符会转换成 text/html,如果返回的是对象会转换成 application/json 返回给前端

  2. @ResponseBody 可以用来修饰方法或者是修饰类,修饰类表示类中的所有方法都会返回 html 或者 json,而不是视图

  3. @RestController 是前面两个注解的结合,也就是一个注释包含了两个注解的功能

  4. 所以如果想返回一个静态资源则不能使用@ResponseBody 或者 @RestController注解

返回静态页面

也就是可以返回项目中的 html文件。首先新建一个简单的html文件,注意这种静态文件需要放到/src/main/resources/static 目录下

image-20240128224134845

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
</head>
<body>
<h1>你好</h1>
</body>
</html>

然后在控制类返回这个静态资源

@Controller
public class TestController {
    @RequestMapping("index")
    public Object index(){
        return "/index.html";
    }
}

返回/index就会显示刚刚index.html这个静态页面

image-20240128224944308

注意:在返回值那里需要加上 / 。如果不加上 / 就会报错,因为加上 / 才说明是在项目的根目录下去找这个静态资源,不加的话就是在访问的/index下面去找

  1. 加了:/static/index.html
  2. 不加:127.0.0.1:8080/index/index.html

直接输出文本类型显示页面

如果不返回文件的话也是可以显示页面的,返回 text/html 形式。也就是直接将html文件以字符串的形式返回,那么浏览器会自动识别并显示。这时候就得使用@RestController或者@ResponseBody注解了

@RestController
public class TestController {
    @RequestMapping("index")
    public String index(){
        return "<h1>你好</h1>";
    }
}

image-20240128225511122

可以看到效果都是一样的

实现简单计算器

通过上面的方式,就可以实现一个前后端联合的简单计算器了。

前端使用form表单提交参数,后端直接返回结果

前端代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
</head>
<body>
<form action="http://localhost:8080/sum">
    <h1>加法计算器</h1>
    数字1:<input type="text" name="num1"><br>
    数字2:<input type="text" name="num2"><br>
    <input type="submit" value="提交">
</form>
</body>
</html>

注意这个form跳转的地址需要与后端执行方法的地址相同才能调用到方法

@Controller
public class TestController {
    @RequestMapping("index")
    public Object index(){
        return "/index.html";
    }

    @RequestMapping("sum")
    @ResponseBody
    public String Sum(Integer num1, Integer num2){
        return String.format("<h1>结果为: %d</h1>", num1 + num2);
    }
}

通过访问/index去访问到前端,然后前端提交后将参数传递给sum方法,sum方法再将结果以 text/html 的形式返回

image-20240128230502010

image-20240128230533965

返回 JSON 对象

JSON 对象在后端可以使用哈希表去存储,例如:

@Controller
public class TestController {
    @RequestMapping("index")
    @ResponseBody
    public HashMap<String, String> index(){
        HashMap<String, String> res = new HashMap<>();
        res.put("zhangsan", "123");
        res.put("lisi", "123");
        res.put("wangwu", "123");
        return res;
    }
}

这样去访问的话就可以得到这个哈希表转换为 JSON后的数据

image-20240128231256816

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CHJBL

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值