“一锅端“ Spring MVC 常见使用大全(下)

简介: “一锅端“ Spring MVC 常见使用大全(下)

3.4 获取 JSON 对象


前面获取的参数, 都是 URL 的形式获取的参数, 哪前端传来的是 JSON 对象, 那么该如何接受获取呢 ?

对于 UserInfo 这个对象, 如果传入的是一个 JSON 格式的 UserInfo, 在用之前的获取方式还能行得通吗 ?

@RequestMapping("/reg")
    public Object reg(UserInfo userInfo) {
        System.out.println(userInfo);
        return userInfo;
    }


利用 Postman 构造请求提交一个 UserInfo 到后端 :


21a6bec71076b8b57a2bb8dc6b6b0fdd.png可以看到, 虽然传入了一个 UserInfo 对象, 但是后端根本没有收到正确的对象, 该怎么解决这问题呢 ?

6314b5928e6d4c10cc6fbc948b9613a3.png

3.4.1 @RequestBody 注解


在 Spring MVC 里提供了 @RequestBody 注解来接收传来的 JSON 对象

@RequestMapping("/reg3")
public Object reg3(@RequestBody UserInfo userInfo) {
    return userInfo;
}


利用 Postman 构造请求 :

d5c3af2589703766b418fca486a6a5b5.png

可以看到, 后端是成功的拿取到了前端传来的这个 JSON 格式的对象

d62babccdf79530244dbf5db89704fff.png


对于前端传来的 JSON 对象, Spring Boot 框架和之前一样, 会将拿到的信息赋值给参数, 并自动适配数据格式


3.5 路径传参


3.5.1 @PathVariable 注解


这样传入参数, 和之前 URL 传参中 user?username=张三&password=123 来说, 搜索引擎抓取关键字的权重更高, 能让人更多的搜索到. 同时当传入的参数更多时, Path 传参的 URL 更简洁.

@RequestMapping("/reg4/{username}/{password}")
public String reg3(@PathVariable String username, @PathVariable String password) {
    return "username : " + username + " password : " + password;
}

dc4965c8b5417c6a73f22862a1cac009.png

通过 path : reg/4/zhangsan/123 访问, 此处username 就对应到了 zhangsan, password 就对应到了 123, 但这里并不是键值的关系, 因此它对位置是非常敏感的, 无法调换位置, 比如下面这段代码, 此时在去通过刚刚的 Path 获取是无法正确获取的


5786960c3cac52498c26f7e2e37def57.png


可以看到, 此时username=123, 而password=zhangsan, 所以 Path 路径的参数它不是键值的关系, 受到 URL 位置对应影响, 这点需要注意

fb20b7f0605ec9eb9c79239d8af15892.png

3.5.2 @PathVariable 注解的重命名


对于 @PathVariable 也是有重命名规则的, 并且它还和我们之前的 @RequestParam 注解一样, 有则必传参数的原则, 当设置了 @PathVariable 注解后, 该参数就为必传参数, 如果不需要可以将 required 属性设置为 false.

@RequestMapping("/reg4/{username}/{password}")
public String reg3(@PathVariable String username, @PathVariable String password) {
    return "username : " + username + " password : " + password;
}


当我们不传入password 时, 再去访问就会报错, 想要 password 不传, 在 @PathVariable 参数后面设置 required 属性为 false 即可

54855afc21ca4a8c55c90d953dc7a8ae.png


在来看看 @PathVariable 重命名, 还是和前面的重命名一样的

c3a35135d216ed34de8b604653e4ca9f.png


同样还是重命名后, 将获取到的 name 的属性值赋值给 username 使用


fce6a32bda2f3f0dd584dcc3ed270331.png


3.6 获取上传文件


前端除了传来参数、对象意外, 还会传来一些文件, 因此对于如何获取上传的文件也是非常重要的


3.6.1 MultipartFile 对象


@RequestParam 注解中, 可以设置参数名称, 例如我设置的 myimg, 而 MultipartFile 接口代表了上传文件, 用于处理 HTTP 请求中上传文件的相关操作, 在 Spring MVC 中通常会将上传文件包装成 MultipartFile 对象进行处理

@RequestMapping("/upload")
public String upLoad(@RequestParam("myimg") MultipartFile file) throws IOException {
    File saveFile = new File("E:\\Javacode\\spring\\spring-mvc\\myimg.png"); // 文件保存的路径
    try {
        file.transferTo(saveFile); // 上传文件 - 本身是没有返回值的, 通过 try catch 来检验是否上传成功
        return "文件上传成功! ";
    }catch (IOException e) {
        e.printStackTrace();
    }
    return "文件上传失败 !";
}

利用 Postman 构造上传文件

4e3fa9f591c7baa1d6bf0f714d9a179e.png

当上传成功后, 可以在之间设置的保存文件路径中查看是否成功上传保存

d95b4574668db575afbb7889fbcb34c3.png65ed7469a6bf2e4872fe400a9adf6c1b.png


同样, 该图片是可以正常打开的

3e4b298fc94f95a90384eca979874867.png


PS : 需要注意的是, 图片上传的单次文件默认最大大小为 1MB, 单次请求默认最大大小为 10MB, 如果需要上传更大的, 可以在配置文件中进行设置

# 设置单次图片最大大小
spring.servlet.multipart.max-file-size=100MB
# 设置单次请求最大大小
spring.servlet.multipart.max-request-size=100MB


虽然上面的代码是成功的获取了前端传来的文件, 但是它并不适用于生产之中, 原因在于每次上次的文件都会进行覆盖上一个文件, 因为它的名称是一样的, 会在相同路径下保存同一个名称的文件而覆盖上一个文件, 因此不具备生产能力. 那么, 要如何解决这个问题, 让每次生产的文件都不一样呢 ?


想要不重覆, 可以用时间戳、 时间戳加随机数、系统时间等方法, 但是尽管时间戳在不断变化, 但是当并发量够大时, 总有可能出现二者相同时间上传文件, 导致其重复的. 为了更好地解决上面问题, 我们引入了 UUID( 通用唯一标识符 ) .


文件名解决后, 还需要解决一件事, 那就是文件的后缀名, 之前我们用的是固定的文件后缀名 .png, 但是用户上传的文件是很多的, 后缀名不是固定的, 因此我们要想办法获取到用户上传的后缀名并且将获取到的后缀名添加到保存的文件后缀中.


@RequestMapping("upload2")
public String upload2(@RequestParam("myimg") MultipartFile file) {
    // 创建文件名名称
    String fileName = UUID.randomUUID() + //文件名
            file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".")); // 后缀名
            // lastIndexOf 左闭右开需要注意, 包含分割后的 . 的
    File saveFile = new File("E:\\Javacode\\spring\\spring-mvc\\" + fileName); // 保存文件
    try {
        file.transferTo(saveFile); // 上传文件
        return "上传文件成功 !";
    }catch (IOException e) {
        e.printStackTrace();
    }
    return "上传文件失败";
}


启动后用 Postman 构建表达请求发送文件

6d0744116cc97016671cb49f0686f9e7.png

查看是否发送成功


image.png

同时检查我们的文件是否保存在对应路径之中, 可以看到此时文件名已经正确保存并且生成了一串文件名非常复杂的名称, 这个就是 UUID 生成的

image.png


即使多次上传同一文件, 它也不会覆盖

image.png


3.7 获取 Cookie (@CookieValue 注解)


之前说过, Spring MVC 是基于 Servlet API 的, 因此之前的获取 Cookie 的方法任然可以用, 不同的是用 Servlet 里的 request 去获取 Cookie 获取的是整个页面的所有 Cookie, 也就是得到的是一个 Cookie 数组

@RequestMapping("getCK")
public void getCookie(HttpServletRequest request) {
    Cookie[] cookies = request.getCookies();
}


如果想要去获取指定的某个 Cookie, 还需要去遍历这个 Cookie 数组去拿取指定的 Cookie, 会比较麻烦, 因此在 Spring MVC 中提供了 @CookieValue 注解, 该注解添加后, 一样是一个必传参数, 并且前端必须有这个 Cookie 否则会错误, 也可以通过设置 required 属性来解决这个问题

@RequestMapping("getCK2")
public String getCookie(@CookieValue("spring") String spring) {
    return spring;
}


由于并没有事先在浏览器中构造一个名为 spring 的 cookie, 因此此时直接去访问时获取不到的


9ad3545a0ae8190ee82f0c029fd482b5.png

32a3b2e694ec90c8dd885d25695ca025.png


构造好后, 再去获取就可以成功拿取到了


2b5638c745e222871c6d0cb839192add.png


3.8 获取 Header (@RequestHeader 注解)


请求头里面包含了许多信息, 通过@RequestHeader 注解也是很容易获取到的, 先来回顾一下 Header 请求头中都有哪些字段 ( 下面是我的浏览器中的请求字段 )

af606f8a62bddaf68612c2698ef80c78.png


这些字段都是可以通过 @RequestHeader 注解来获取的, 尝试获取一下当前的 Host, 还和之前一样, 获取注解里面指定的 Host 属性后赋值给 host 变量

@RequestMapping("getHD")
public String getHeader(@RequestHeader("Host") String host) {
    return host;
}


可以看到, 我当前的 Host 如下 :


0b8743e25765d417420aa6dbb46e7ade.png

其他的字段也是同样的获取方法, 只需修改获取的指定属性就行, 大家可以试试 !


3.9 获取 Session (@RequestAttribute 注解)


在那之前, 先回顾之前 Servlet 如何创建会话, 由于此处我没有具体的业务代码, 因此我手动建立一个会话 SESSION_KEY

private static final String SESSION_KEY = "DEFAULT_VALUE";
    @RequestMapping("/createSession")
    public void CreateSession(HttpServletRequest request) {
        HttpSession session = request.getSession(true); // 没有 session 就创建 session
        session.setAttribute(SESSION_KEY, "username"); // 将username存入到会话中
    }


通过 Servlet 来获取 Session, 在获取之前先要运行建立会话路由方法才能有会话可获取

@RequestMapping("/getSession")
    public String getSession2(HttpServletRequest request) {
        HttpSession session = request.getSession(false); // 有则获取, 没有就不建立
        return " Servlet 获取 : " + (String) session.getAttribute(SESSION_KEY);
    }


访问 Servlet 获取 Session 的路由方法

68a1eba788e8916ed6119eb03e746ccf.png

访问注解方式获取 Session 的路由方法

d903181471bbdfaa83dff860152f9b88.png

4. 返回数据


获取前端的参数非常重要, 但是给前端返还数据一样是很重要的, 下面就来看几个常见的返回数据


4.1 返回静态页面


static 包底下创建一个 spring.html 文件, 并在文件中写一个 < h1 > Spring MVC < /h1 > 标签

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>Spring MVC</h1>
</body>
</html>


之前我们返回的都是数据, 而并非页面, 因此我们使用了 @RestBody 注解 或者 @RestController 注解, 但此处我们要返回的就是一个静态页面, 而并非数据, 因此此处不需要在加上面的注解了

@Controller
@RequestMapping("/test")
public class ControllerDemo {
    @RequestMapping("/getHtml/test2")
    public String getHtml() {
        return "spring.html"; // 返回的液面必须与创建的静态页面名称一致
    }
}


根据路由方法访问, 结果出现了 404, 根本获取不到对应的页面

53b4d94c8020459ab9d37074cff00719.png

这是为什么 ? 当我们在返回的 spring.html 中不加上斜杠, 也就是 “/spring.html” 时, 去访问路由方法并不会在根目录底下去获取, 因此获取不到指定页面, 当我们加上 " / " 以后, 就会让它在根目录底下去获取, 从而可以正确拿到返回的页面

e997152f3fc9a3967addd6c83502fdd9.png

4.2 返回 JSON 对象


除了静态页面, 后端也会经常给前端返回 JSON 格式的对象

@RestController
@RequestMapping("/resJson")
public HashMap<String, String> resJson() {
    HashMap<String, String> map = new HashMap<>();
    map.put("zhangsan", "1");
    map.put("lisi", "2");
    return map;
}


还是一样的, 加了注解以后, Spring Boot 框架会自动将你返回的数据进行包装.

b7ff8b130820b05dec652a39d8b918bb.png


4.3 请求转发和请求重定向


Spring MVC 天生就是返回静态页面的, 因此对于重定向、转发等返回是很容易的.

@Controller
public class ControllerDemo {
    // 请求转发
    @RequestMapping("/fw")
    public String index2() {
        return "forward: /spring.html";
    }
}


6c96855519a04b5f848fcf996749e90f.png

有没有发现, 这和我们之前返回静态页面好像是一样的 ? 其实不然, 当我们访问路由返回的是一个静态页面时, 由于我们访问的是接口, 而你要返回一个静态页面, 实际上就是一个请求转发的过程.


看看请求重定向 :

@Controller
public class ControllerDemo {
    // 请求重定向
    @RequestMapping("/re")
    public String index() {
        return "redirect: /spring.html";
    }
}


adc10a8956cd9ebc02d8a2e214f62c20.png


惊奇的发现, 我们访问重定向的路由地址不是 localhost:8080/re 嘛 ? 怎么页面展示出来结果后, URL 就变成了 localhost:8080/spring.html, 我们可以抓包看看

image.png



可以看到, 当访问路由地址时, 它直接 302 给我们跳转到了 spring.html 页面.

那么, 请求转发和请求重定向有什么区别呢 ?

  • 请求转发地址没变, 而请求重定向后地址会发生改变
  • 请求转发由服务端转发, 而请求重定向重新定位到资源
  • 请求转发由服务端转发, 有可能造成原外部资源不能访问; 而请求重定向与直接访问新地址效果一样, 不存在原来外部资源不能访问


请求转发由服务器内部进行转发, 用户的感知是不明显的, 因为它的地址并没有发生变化, 但是给你展示的是你想要的页面; 但是重定向用户感知是比较明显的, 它类似于通过他人之手, 直接让你去找谁谁谁( 你重定向的位置 ).


外部资源不能访问 : 经过服务器进行转发的, 服务器并不像你重定向一样明确的知道你要的是什么, 有可能会出错, 并不觉得清楚你需要什么. 当层级目录过多, 服务器去转发一个静态页面的时候有可能就会出错.

相关文章
|
4天前
|
XML JSON 数据库
SpringMVC入门到实战------七、RESTful的详细介绍和使用 具体代码案例分析(一)
这篇文章详细介绍了RESTful的概念、实现方式,以及如何在SpringMVC中使用HiddenHttpMethodFilter来处理PUT和DELETE请求,并通过具体代码案例分析了RESTful的使用。
SpringMVC入门到实战------七、RESTful的详细介绍和使用 具体代码案例分析(一)
|
1天前
|
前端开发 应用服务中间件 数据库
SpringMVC入门到实战------八、RESTful案例。SpringMVC+thymeleaf+BootStrap+RestFul实现员工信息的增删改查
这篇文章通过一个具体的项目案例,详细讲解了如何使用SpringMVC、Thymeleaf、Bootstrap以及RESTful风格接口来实现员工信息的增删改查功能。文章提供了项目结构、配置文件、控制器、数据访问对象、实体类和前端页面的完整源码,并展示了实现效果的截图。项目的目的是锻炼使用RESTful风格的接口开发,虽然数据是假数据并未连接数据库,但提供了一个很好的实践机会。文章最后强调了这一章节主要是为了练习RESTful,其他方面暂不考虑。
SpringMVC入门到实战------八、RESTful案例。SpringMVC+thymeleaf+BootStrap+RestFul实现员工信息的增删改查
|
17天前
|
JSON 前端开发 Java
Spring MVC返回JSON数据
综上所述,Spring MVC提供了灵活、强大的方式来支持返回JSON数据,从直接使用 `@ResponseBody`及 `@RestController`注解,到通过配置消息转换器和异常处理器,开发人员可以根据具体需求选择合适的实现方式。
41 4
|
17天前
|
XML 前端开发 Java
Spring MVC接收param参数(直接接收、注解接收、集合接收、实体接收)
Spring MVC提供了灵活多样的参数接收方式,可以满足各种不同场景下的需求。了解并熟练运用这些基本的参数接收技巧,可以使得Web应用的开发更加方便、高效。同时,也是提高代码的可读性和维护性的关键所在。在实际开发过程中,根据具体需求选择最合适的参数接收方式,能够有效提升开发效率和应用性能。
43 3
|
18天前
|
XML 前端开发 Java
Spring MVC接收param参数(直接接收、注解接收、集合接收、实体接收)
Spring MVC提供了灵活多样的参数接收方式,可以满足各种不同场景下的需求。了解并熟练运用这些基本的参数接收技巧,可以使得Web应用的开发更加方便、高效。同时,也是提高代码的可读性和维护性的关键所在。在实际开发过程中,根据具体需求选择最合适的参数接收方式,能够有效提升开发效率和应用性能。
41 2
|
1月前
|
前端开发 Java 应用服务中间件
我以为我对Spring MVC很了解,直到我遇到了...
所有人都知道Spring MVC是是开发的,却鲜有人知道Spring MVC的理论基础来自于1978 年提出MVC模式的一个老头子,他就是Trygve Mikkjel Heyerdahl Reenskaug,挪威计算机科学家,名誉教授。Trygve Reenskaug的MVC架构思想早期用于图形用户界面(GUI) 的软件设计,他对MVC是这样解释的。MVC 被认为是解决用户控制大型复杂数据集问题的通用解决方案。最困难的部分是为不同的架构组件想出好的名字。模型-视图-编辑器是第一个。
我以为我对Spring MVC很了解,直到我遇到了...
|
22天前
|
前端开发 Java API
Spring Boot 中的 MVC 支持
### Spring Boot 注解摘要 - **@RestController** - **@RequestMapping** - **@PathVariable** - **@RequestParam** - **@RequestBody**
21 2
|
7天前
|
前端开发 Java Spring
Java 新手入门:Spring Boot 轻松整合 Spring 和 Spring MVC!
Java 新手入门:Spring Boot 轻松整合 Spring 和 Spring MVC!
18 0
|
22天前
|
JSON 前端开发 Java
Spring Boot中的MVC支持
本节课主要讲解了 Spring Boot 中对 MVC 的支持,分析了 @RestController、 @RequestMapping、@PathVariable、 @RequestParam 和 @RequestBody 四个注解的使用方式,由于 @RestController 中集成了 @ResponseBody 所以对返回 json 的注解不再赘述。以上四个注解是使用频率很高的注解,在所有的实际项目中基本都会遇到,要熟练掌握。
|
1月前
|
XML 前端开发 Java
Spring Boot与Spring MVC的区别和联系
Spring Boot与Spring MVC的区别和联系