【JavaEE进阶】SpringMVC中的常用注解和用法

目录

[学习Spring MVC](#学习Spring MVC)

建立连接

[@RequestMapping 注解介绍](#@RequestMapping 注解介绍)

[@RequestMapping 使用](#@RequestMapping 使用)

传参介绍

传递单个参数

传递多个参数

传递对象

后端参数重命名(后端参数映射)@RequestParam

非必传参数设置

传递数组

传递集合

传递JSON数据

获取URL中参数@PathVariable

上传文件@RequestPart

获取Cookie/Session

响应

返回静态页面

返回数据@ResponseBody

返回HTML代码片段

返回JSON

设置状态码

设置Content-Type

总结


学习Spring MVC

当我们在浏览器中输入了url之后, Spring MVC项目就可以感知到用户的请求, 并给予响应.

学习Spring MVC, 重点也就是学习如何通过浏览器和用户程序进行交互.

主要分以下三个方面:

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

建立连接

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

我们先来看看代码怎么写

创建一个UserController类,实现用户通过浏览器和程序的交互,具体实现代码如下:

java 复制代码
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {
    @RequestMapping("sayHi")
    public String hello() {
        return "Hello SpringMVC!";
    }
}

@RequestMapping 注解介绍

@RequestMapping 是 Spring Web MVC 应用程序中最常被用到的注解之一, 它是用来注册接口的路由映射的.

表示服务收到请求时, 路径为 /sayHi 的请求就会调用 sayHi 这个方法的代码.
路由映射: 当用户访问一个URL时,将用户的请求对应到程序中某个类的某个方法的过程就叫路由映射.

既然 @RequestMapping 已经可以达到我们的⽬的了, 我们为什么还要加 @RestController 呢? 我们把 @RestController 去掉, 再来访问⼀次:

可以看到, 程序报了404, 找不到该页⾯.

这就是 @RestController 起到的作用.

一个项目中,会有很多类,每个类可能有很多的方法, Spring 程序怎么知道要执行哪个方法呢?
Spring 会对所有的类进行扫描,如果类加了注解 @RestController , Spring 才会去看这个类里面的方法有没有加 @RequestMapping 这个注解, 当然他的作用不止这一点,我们先学会用.

@RequestMapping 使用

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

法路径.
@RequestMapping 标识一个类: 设置映射请求的请求路径的初始信息
@RequestMapping 标识一个方法: 设置映射请求请求路径的具体信息

java 复制代码
@RestController
@RequestMapping("/user")
public class UserController {
    @RequestMapping("sayHi")
    public String hello() {
        return "Hello SpringMVC!";
    }
}

访问地址:http://127.0.0.1:8080/user/sayHi

注意: @RequestMapping 的 URL 路径最前面加不加 / (斜杠)都可以, Spring 程序启动时,会进行判断,如果前面没有加 / , Spring会拼接上一个 / , 通常情况下, 我们加上/

@RequestMapping 的 URL 路径也可以是多层路径, 最终访问时, 依然是 类路径 + 方法路径

@RequestMapping 既支持Get请求,又支持Post请求.同理,也支持其他的请求方式.

那如何指定GET或者POST类型呢?

我们可以显示的指定@RequestMapping来接收POST的情况,如下所示:

java 复制代码
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {
    @RequestMapping(value = "/getRequest",method= RequestMethod.POST)
    public String sayHi(){
        return "get request...";
    }
}

传参介绍

在测试传参时, 我们需要借助一个后端开发常用的接口测试工具 Postman , 这里就不对其进行过多的介绍了.

下载连接: https://www.postman.com/downloads/

为了方便演示, 下面的传参只放了其中核心部分的代码, 如下图红色框内部分:

传递单个参数

接收单个参数,在Spring MVC中直接用方法中的参数就可以,比如以下代码:

java 复制代码
    @RequestMapping("/r1")
    public String r1(String name) {
        return "接收到参数, name= " + name;
    }

使用 Postman 进行传参测试:

也可使用浏览器发送请求并传参: http://127.0.0.1:8080/request/r1?name=zhangsan

可以看到,后端程序正确拿到了name参数的值.

Spring MVC会根据方法的参数名,找到对应的参数,赋值给方法
如果参数不一致, 是获取不到参数的. 比如:

注意事项

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

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

传递多个参数

如何接收多个参数呢?

和接收单个参数一样,直接使用方法的参数接收即可.使用多个形参.

java 复制代码
    @RequestMapping("/r4")
    public String r4(String name, Integer age) {
        return "接收到参数, name= " + name + ", age = " + age;
    }

使用 Postman 测试:

当有多个参数时,前后端进行参数匹配时,是以参数的名称进行匹配的,因此参数的位置是不影响后端获取参数的结果.

传递对象

如果参数比较多时,方法声明就需要有很多形参. 并且后续每次新增一个参数, 也需要修改方法声明. 我们不妨把这些参数封装为一个对象.

SpringMVC 也可以自动实现对象参数的赋值,比如Student对象:

java 复制代码
class Student {
    private Integer id;
    private String name;
    private Integer age;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    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;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

传递对象代码实现:

java 复制代码
    @RequestMapping("/r5")
    public String r5(Student student) {
        return "接收到参数: " + student.toString();
    }

使用 Postman 测试:

Spring 会根据参数名称自动绑定到对象的各个属性上, 如果某个属性未传递, 则赋值为 null (基本类型则赋值为默认初识值, 比如 int类型的属性, 会被赋值为 0)

后端参数重命名(后端参数映射)@RequestParam

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

java 复制代码
    @RequestMapping("/r6")
    public String r6(@RequestParam("name") String username, Integer age) {
        return "接收到参数, name= " + username + ", age = " + age;
    }

使用 Postman 测试:

可以看到, Spring 可以正确的把浏览器传递的参数 time 绑定到了后端参数 caretetime 参数. 上

此时,如果使用 caretetime 进行参数传递呢?

使用 Postman 测试:

错误日志信息为:

控制台打印日志显示:请求参数 'username' 不存在

可以得出结论:

1.使用 @RequestParam 进行参数重命名时,请求参数只能和 @RequestParam 声明的名称一

致,才能进行参数绑定和赋值.

2.使用 @RequestParam 进行参数重命名时,参数就变成了必传参数.

非必传参数设置

如果我们的实际业务前端的参数是一个非必传的参数, 针对上述问题, 如何解决呢?

先来了解下参数必传的原因,我们查看 @RequestParam 注解的实现细节就可以发现端倪,注解实现如下:

可以看到 required 的默认值为 true ,表示含义就是:该注解修饰的参数默认为必传, 既然如此, 我们可以通过设置 @RequestParam 中的 required=false 来避免不传递时报错.

具体实现如下:

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

可以看到,添加 required=false 之后,time 前面也加了 key ,变成了 value = "time"

注解属性赋值时,没有指明 key 的话,默认为 value 属性.

如果需要有多个属性进行赋值时,需要写上 key

传递数组

Spring MVC 可以自动绑定数组参数的赋值

后端实现代码:

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

使用 Postman 测试:

传递集合

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

默认情况下,请求中参数名相同的多个值,是封装到数组.如果要封装到集合,要使用@RequestParam 绑定参数关系

请求方式和数组类似:

后端接收代码:

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

使用 Postman 测试:

传递JSON数据

JSON的语法:

  1. 数据在键值对 (Key/Value) 中
  2. 数据由逗号,分隔
  3. 对象用 { } 表示
  4. 数组用 [ ] 表示
  5. 值可以为对象, 也可以为数组,数组中可以包含多个对象

JSON的两种结构

1.对象: 大括号 { } 保存的对象是一个无序的键值对集合. 一个对象以左括号 { 开始,右括号 } 结束。每个"键"后跟一个冒号 : ,键值对使用逗号,分隔

2.数组: 中括号 [ ] 保存的数组是值(value) 的有序集合.一个数组以左中括号 [ 开始,右中括号 ] 结束,值之间使用逗号,分隔。

传递JSON对象

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

RequestBody: 请求正文,意思是这个注解作用在请求正文的数据绑定,请求参数必须在写在请求正文中.

后端实现:

java 复制代码
    @RequestMapping("/r10")
    public String r10(@RequestBody Student student) {
        return "接收到参数: " + student.toString();
    }

使用 Postman 来发送 json 请求参数:

可以看到,后端正确接收了

通过 Fiddler 观察一下请求参数:

如果去除掉 @RequestBody , 后端会无法给 Student 对象赋值. 这里就不给大家演示了.

获取URL中参数@PathVariable

path variable: 路径变量

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

默认传递参数写在 URL 上,SpringMVC 就可以获取到

后端实现代码:

java 复制代码
    @RequestMapping("/article/{articleId}/{name}")
    public String r12(@PathVariable("articleId") Integer articleId, @PathVariable("name") String name) {
        return "接收到参数, articleId:" + articleId + " , name: " + name;
    }

使用 Postman 测试:

可以看到,后端正确获取到了URL中的参数

参数对应关系如下:

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

如果方法参数名称和需要绑定的 URL 中的变量名称不一致时, 需要 @PathVariable 的属性 value赋值,如上述例子中的 articleName 变量.

上传文件@RequestPart

后端实现代码:

java 复制代码
    @RequestMapping("/r13")
    public String r13(@RequestPart("file") MultipartFile imgFile) {
        String originalFilename = imgFile.getOriginalFilename();
        return "接收到文件, 文件名: " + originalFilename;
    }

使用 Postman 测试:

获取Cookie/Session

这部分的内容比较多, 详细介绍在下一篇文章.

响应

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

返回静态页面

创建前端页面index.html(注意路径)

后端代码:

运行结果:

结果却发现,页面未正确返回, http 响应把 " / index. html" 当做了 http 响应正文的数据

那 Spring MVC 如何才能识别出来 index.html 是一个静态页面,并进行返回呢?

我们需要把 @RestController 改为@Controller

正确代码如下:

发现页面正确展示了:

@RestController和@Controller有着什么样的关联和区别呢?

咱们前面讲了MVC模式,后端会返回视图,这是早期时的概念

随着互联网的发展,目前项目开发流行"前后端分离"模式, Java主要是用来做后端项目的开发,所以也就不再处理前端相关的内容了

MVC 的概念也逐渐发生了变化,View 不再返回视图,而是返回显示视图时需要的数据.

所以前面使用的 @RestController 其实是返回的数据.

@RestController = @Controller + @ResponseBody

@Controller: 定义一个控制器, Spring 框架启动时加载,把这个对象交给 Spring 管理.
@ResponseBody: 定义返回的数据格式为非视图,返回一个 text/html 信息

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

返回数据@ResponseBody

我们上面讲到, @ResponseBody 表示返回数据.

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

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

也就是说: 在类上添加 @ResponseBody 就相当于在所有的方法上添加了 @ResponseBody 注解.

同样,如果类.上有@RestController 注解时:表示所有的方法上添加了 @ResponseBody 注解,也就是当前类下所有的方法返回值做为响应数据

如果一个类的方法里,既有返回数据的,又有返回页面的,就把 @ResponseBody 注解添加到对应的方法上即可.

返回HTML代码片段

后端返回数据时,如果数据中有HTML代码,也会被浏览器解析

java 复制代码
    @ResponseBody
    @RequestMapping("/indexData2")
    public String indexData2() {
        return "<h1>我是中国人</h1>";
    }

运行结果:

通过Fiddler观察响应结果,Content-Type为text/html

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

● text/html|: body数据格式是 HTML

● text/css : body数据格式是 CSS

● application/j avascript : body 数据格式是 JavaScript

● application/json : body 数据格式是 JSON

返回JSON

Spring MVC 也可以返回 JSON

后端方法返回结果为对象

java 复制代码
    @ResponseBody
    @RequestMapping("/getMap")
    public HashMap<String,String> getMap() {
        HashMap<String,String> map = new HashMap<>();
        map.put("k1","v1");
        map.put("k2","v2");
        map.put("k3","v3");
        map.put("k4","v4");
        return map;
    }

运行结果:

设置状态码

Spring MVC 会根据我们方法的返回结果自动设置响应状态码,程序员也可以手动指定状态码通过Spring MVC 内置对象 HttpServletResponse 提供的方法来进行设置

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

状态码不会影响页面展示, 通过 FIddler 来观察设置的结果:

设置Content-Type

我们通过设置 produces 属性的值,设置响应的报头Content-Type

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

总结

相关推荐
点点滴滴的记录13 分钟前
Java的CompletableFuture实现原理
java·开发语言·javascript
xiaolingting14 分钟前
Java 引用是4个字节还是8个字节?
java·jvm·引用·指针压缩
一只傻小白,19 分钟前
JAVA项目中freemarker静态模板技术
java·开发语言
袁庭新19 分钟前
Spring Boot项目接收前端参数的11种方式
java·springboot·袁庭新·如何接收前端数据·boot接收数据
机跃21 分钟前
递归算法常见问题(Java)
java·开发语言·算法
IT 古月方源26 分钟前
ospf 的 状态机详解
运维·网络·tcp/ip·智能路由器
dog25030 分钟前
UDP 比 TCP 更快吗?
网络·tcp/ip·udp
程序员-小李41 分钟前
餐厅下单助手系统(Java+MySQL)
java·开发语言·mysql
开心工作室_kaic1 小时前
springboot496基于java手机销售网站设计和实现(论文+源码)_kaic
java·开发语言·智能手机
一勺汤1 小时前
YOLO11改进-模块-引入星型运算Star Blocks
网络·yolo·目标检测·改进·魔改·yolov11·yolov11改进