Spring(MVC)架构简述

MVC架构

学过中间件的人都应该知道MVC架构的意思,即model、view、和controller的缩写

  • Model(模型) - 模型代表一个存取数据的对象或 JAVA POJO。它也可以带有逻辑,在数据变化时更新控制器。
  • View(视图) - 视图代表模型包含的数据的可视化。
  • Controller(控制器) - 控制器作用于模型和视图上。它控制数据流向模型对象,并在数据变化时更新视图。它使视图与模型分离开。

SpringMVC其实就一种基于Servlet的MVC模型

SpringMVC三层架构

SpringMVC的工程结构一般来说分为三层,自上而下是

  • View层(视图,页面显示层)
  • Cotroller层(控制,逻辑控制层)
  • Modle层(模型,数据访问层)

其中Modle层分为两层:

  • Service层(业务层,用来实现业务逻辑)
  • DAO层(负责访问数据库进行数据的操作,之后将结果返回给service层)

Springboot Controller

如前文所说,控制器用来处理前端(视图层)的请求。比如浏览器中最常见的get请求。

前端通过某个地址比如localhost:8080/hello访问服务器后,服务器应该做出什么响应、进行什么操作、返回什么结果给前端就是控制器的任务。

@Controller 注解

因为Springboot有自动扫描,所以我们只需要在类上添加注解即可注册一个控制器。

对于要响应应页面内容使用@Controller注解

对于前后端分离架构,一般不返回页面(返回数据)使用@RestController注解

一般我们会创建controller包,在controller包中建立controller类

Untitled

使用@RequestMapping 对某个路由对应的注解进行映射例如

1
2
3
4
@RequestMapping(value = "/hello1",method = RequestMethod.GET)
public String hello1() {
return "Hello World 1!";
}

value 是访问的路由,method表示允许的http方法

Untitled

@GetMapping,@PostMapping

对于上面的写法,也可以简写为@GetMapping("/hello")

1
2
3
4
@GetMapping("/hello")
public String hello() {
return "Hello World!";
}

Untitled

请求参数

调用api时可能会伴随一些请求的参数(查询参数)

spring可以使用@RequestParam(value = "xxx")注解来映射变量

我们使用一个ota的接口例子

1
2
3
4
5
6
7
8
@GetMapping("/firmware")
public String firmware(
@RequestParam(value = "ver") String version,
@RequestParam(value = "did") String deviceid,
@RequestParam(value = "rid") String repoid
) {
return "Fake Query for firmware of repo [" + repoid + "] @Ver [ " + version + "] BY device [" + deviceid + "].";
}

访问http://localhost:8080/firmware?ver=1.0&did=d0001&rid=r1234

得到结果

1
Fake Query for firmware of repo [r1234]@Ver[1.0] BY device [d0001].

同样的,如果请求的名称和方法内的变量名一样的话可以省略注解

1
2
3
4
@GetMapping("/firmwaresimple")
public String firmwaresimple(String ver,String did,String rid) {
return "Fake Query for firmware of repo [" + rid + "]@Ver[" + ver + "] BY device [" + did + "].";
}

访问http://localhost:8080/firmware?ver=1.0&did=d0001&rid=r1234

得到结果

1
Fake Query for firmware of repo [r1234]@Ver[1.0] BY device [d0001].

对象化

前面我们通过参数进行请求,同时返回的也是纯文本,这被认为是效率低下的。

在现代的前后端数据交互中,json文件经常被使用。json是一个对象化的文件,非常巧的是Java也是一个面向对象的语言。那我们能不能使用对象的方式来进行数据的解析而避免使用很长的参数呢?

肯定能啊。。

首先我们需要在Java中创建这个对象。

比如我们前面说的ota接口,他除了处理查询(下载)的请求外还有一类请求就是处理上传的固件。

我们先不管文件上传的过程,想象我们需要一个对象来描述一个固件(就像在数据库里那样)我们需要一个固件id(主键),所属的仓库id,版本和文件路径(通常在云上)

@Data

我们新建一个固件描述类,写出我们需要的变量

通常我们在entity包中新建各种数据类

1
2
3
4
5
6
7
8
9
public class firmwareDescriptor {
private String firmwareId;
private String version;
private String repoId;
private String url;

public firmwareDescriptor() {
// ...
}

同时也要写好这些属性的getter setter方法和构造器。

或者使用Lombok注解 @Data 来自动实现

1
2
3
4
5
6
7
@Data
public class firmwareDescriptor {
private String firmwareId;
private String version;
private String repoId;
private String url;
}

下面是Lombok编译后反编译的结果示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
public class firmwareDescriptor {
private String firmwareId;
private String version;
private String repoId;
private String url;

public firmwareDescriptor() {
}

public String getFirmwareId() {
return this.firmwareId;
}

public String getVersion() {
return this.version;
}

public String getRepoId() {
return this.repoId;
}

public String getUrl() {
return this.url;
}

public void setFirmwareId(final String firmwareId) {
this.firmwareId = firmwareId;
}

public void setVersion(final String version) {
this.version = version;
}

public void setRepoId(final String repoId) {
this.repoId = repoId;
}

public void setUrl(final String url) {
this.url = url;
}

public boolean equals(final Object o) {
// ...
}

protected boolean canEqual(final Object other) {
// ...
}

public int hashCode() {
// ...
}

public String toString() {
// ...
}
}

@RequestBody

就像前面我们使用@RequestParam一样,我们需要用@RequestBody注解来定义接收前端请求体的对象。

最后我们写好对应的控制器

1
2
3
4
5
@PostMapping("/firmwareRegister")
public String firmwareRegister(@RequestBody FirmwareDescriptor fDesc) {
System.out.println(fDesc.toString());
return "Add firmware " + fDesc.getFirmwareId() + " success.";
}

测试请求

因为我们这次使用了Post请求,浏览器已经无法调试,我们可以使用一些api工具进行测试

Untitled

测试结果符合我们预期,同时控制台也受到打印信息

1
FirmwareDescriptor(firmwareId=3001, version=1.0, repoId=r1234, url=http://jcpdpeigyg.ck/tqipk)

这是Lombok的Data注解帮我们自动生成的toString函数