一个SpringBoot项目首先会引入的依赖就是SpringMVC
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webmvc</artifactId> </dependency>一、SpringMVC模型
所谓MVC就是:Model、View、Controller三层。
Model作为数据的载体,View作为视图层,负责给客户端返回包装好的数据,Controller负责接收View发来的请求,调用Model并协调View和Model的关系。
那么前端在哪个范围呢,前端不在上述三个范围中的任何一个里!前端是专门发起请求向后端请求数据的,与前端直接交互的是浏览器。
其关系大致是这样的:
那么作为后端开发人员,掌握SpringMVC模型是十分有必要的。
这篇博客就和博主来挖掘一下SpringMVC模型的常用开发注解吧。
二、View层
视图层,可以向浏览器返回一个页面,也可以返回一段打包好的数据。
但是,现代开发模式(前后端分离),前端变得越来越复杂那么就需要有专门的开发者去做,并且两种开发方式和思维都有所不同。前端主要就是做数据渲染处理和请求的发起和响应。
那么在这种情况下,后端的View层就被完全弱化,只希望返回纯数据,而非渲染好的页面。
因此View就没有必要单独新建一个软件包了,所有View层的操作和Controller层合并为同一层。
那么我们以此给项目分层,先做如下分层:
在controller层写一个Person类,等下需要演示注解。
2.1@ResponseBody
这个注解表示:标记方法/类的返回值不经过视图解析器,直接以HTTP响应体的形式返回(如JSON/字符串),跳过View层渲染。
如果加在类上,则表示该类中的所有方法返回值都是纯数据;加在方法上则表示该方法返回的纯数据。这个注解是弱化View层的核心注解。
这个注解最爱和谁搭配呢?@RestController = @ResponseBody + @Controller
这是个类注解,需要加在类上。
我们前面讲了,View层的工作和Controller层合并在一起,那么我是用@RestController这个注解就两全其美了。即能将controller标注出来,而且可以将类中的所有方法的返回值跳过View解析器直接返回给浏览器。
目前还不能举例子,我们看完Controller层就可以了。
三、Controller层
前面讲到,现代开发模式实行的是“前后端分离”,后端弱化View层。
因此View的一些工作就和Controller合并在一起了。
3.1核心控制器注解
3.1.1@Controller
这个注解是类注解,用于标记一个类为控制器组件,使其被SpringIoC容器扫描并管理。该类中的方法可以通过注解映射HTTP请求,接收前端请求和协调业务层处理逻辑,返回视图名。
但是如果加了@ResponseBody则是返回数据。
3.1.2@RequestMapping
浏览器发起了请求后端怎么接收并作出对应的响应呢?这就需要思考浏览器是怎么获取后端服务的。
浏览器中有一个一个网址,形如:http://127.0.0.1:8080/index.html
或者形如:http://127.0.0.1:8034/people/getPeople?name='zhangsan'
两种URL不同之处在于前者请求的是一个HTML页面,这个HTML页面是提前写好的,作为一种静态资源存储在服务器中。
后者有一个访问的路径,在people目录下的getPeople资源,然后跟一个简单的参数。
前端在请求资源时,一定要知道资源的准确位置,例如/index.html,/people/getPeople
那么,SpringMVC就将每个资源用目录来建立逻辑关系。
使用@RequestMapping("/逻辑目录")用于将后端接口(资源,接口也是资源的一部分)映射到指定的URL路径,前端就需要根据这个逻辑目录来发起HTTP请求来访问对应资源。因此前端开发人员要和后端开发人员密切配合确保资源的位置是准确无误的,同时这样定位资源的文档应该在接口文档中明确规定好的。
现在举个例子:
先给这个类加上“/person”根目录。
类中有一个方法getPeople,这个方法没有参数,并且使用@RequestMapping("/getPeople")将这个接口映射到/person/getPeople这个URL上。前端只需要指定这个目录,无需参数发起请求,后端便会执行对应的方法。
运行程序后,在浏览器输入对应的URL即可访问。
URL:http://localhost:8080/person/getPerson
也可以是:htpp://127.0.0.1:8080/person/getPerson
因为目前项目在我们本机上运行,因此IP地址填写自己的即可,这里采用一个特殊的IP127.0.0.1来快速表示自己(也可以用localhost),紧跟着的就是端口号。8080是SpringBoot项目启动的默认端口,可以更改,但在只有一个项目时可以不用管。
3.1.3@RestController
正如前面讲到:@RestController = @ResponseBody + @Controller
前面的例子中,我们并没有加@Controller注解,而是使用的是@RestController注解。那么我如果将其修改成@Controller会怎么样?
运行程序。
404,找不到资源。为什么?如果不加@ResponseBody则SpringBoot会自动去将其解析成视图,找不到对应的视图与之对应,就会报错。
我们在resources/templates文件夹下创建一个HTML文件,这个目录时SpringBoot和Thymeleaf的默认约定,专门存放需要后端渲染的动态HTML页面,这个目录和存放纯静态资源的目录resources/static有本质区别。
然后引入一个视图解析器Thymeleaf依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency>新建一个Controller,然后写获取Html页面的方法,返回值为String。
这样就会根据返回的字符串查找视图名称,并返回匹配的视图。
3.2请求映射注解
前面我们讲到浏览器会发出一个携带URL的请求,同时还有一个重要的请求方式。
有Post,Get、Delete、Put,每种请求的格式大题上是一致的,从某种程度上来说每种请求方式是通用的,但是出于标准我们重点区分Post和Get。
浏览器默认发出的是什么请求呢?
答案是Get请求,@RequestMapping注解是一个通用的注解,会响应所有类型的请求。
但是我们还有更加细致的注解,分别是:@GetMapping 和 @PostMapping
浏览器的请求方式要和后端设置的接收请求方式一致,否则就不能成功响应。
但是如果改成@PostMaping则不能请求成功
浏览器报错显示请求方式不被允许。
3.3请求参数获取
3.3.1@RequestParam
这个注解用前端携带参数请求后端时,协调前后端参数名不一致问题。
正常情况下,如果前后端参数需要约定成一致的,但如果处于某种原因没法达成一致,则可以这个注解把前端的参数正确映射到后端参数上,如:
但是如果前端不知道每个参数的准确名称,那么就会和后端接口的参数匹配不上,从而匹配失败,a ,b 会为空,制造问题。
报错500,后端错误。
那么就可以使用这种方式来达成一致:
第一个参数为c,仅供前端使用。
3.3.2@PathVariable
获取URL路径变量,如people/{id}
3.3.3@RequestBody
这个注解常用来接收前端传来的Json/XML格式的参数,自动封装成对象。为了能传递Json格式的参数,我们最方便的是使用postman来模拟发送请求。
此时前端必须发送Post请求,因为Get请求没有请求体。
后端可以采用Map或者对应的实体来接收,如果采用实体接收,那么实体属性必须有相应的Setter和Getter方法,否则会参数绑定失败。此外,采用实体接收如果Json有多余的字段则会被舍弃,实体的属性没有被赋值的则是null。
Person实体
package com.miao.springmvcannotationdemo.model; public class Person { private String name; private Integer age; public Person(){ } public Person(String name,int age){ this.name = name; this.age = age; } public void setName(String name){ this.name = name; } public void setAge(int age){ this.age = age; } public String getName(){ return this.name; } public Integer getAge(){ return this.age; } @Override public String toString(){ return this.name+" "+this.age; } }后端
postman请求及响应如下:
但是如果缺少@RequestBody则会请求失败。
四、Model层
Model也可以成为DAO层,或者是Entity实体层,用来存放实体类其与数据库表对应。就相当于是一个中间层,每次查询时会把查到的数据填充到我们的实体类中,这样就可以被Java操作使用。
例如有这样一张User表(简化):
| id | bigint |
| user_name | varchar(50) |
| age | tinyint unsigned |
那么可以构建出一个与之对应的实体类:
public class User { private Long id; private String userName; private Integer age; }注意mysql中的字段是蛇形命名法,在Java中的属性则是使用小驼峰命名法。
这是命名规范,如果刻意追求两者完全一致也行,因为最后在数据填充时就是根据属性一一匹配的。我们后面可以利用mybatis的驼峰映射功能解决,所以不用为此担心。
现在我们有了这样一个实体类,但是缺少对应的set和get方法。我们可以选择手动添加,注意set和get的方法名必须按照setId()、setUserName()等小驼峰命名方式。否则后面因为方法名的错误会导致数据填充失败。
前面也讲到使用实体类接收对象时,必须有对应的set和get方法,其次就是方法名要正确。
五、总结
以上就是作者对SpringMVC的理解,后续学习mybatis时我们有Lombok依赖,使用@Data注解可以不用手动设置set和get方法。