项目拆分思想


1. 单体项目拆分

项目拆分的思想:在一个完整的项目中,虽然我们利用了 maven 的『多模块』知识点,将一个项目(project)拆分成了多个模块(module),各个模块单独打包,但是,整个项目的最终的『成果』、产出仍然是一个 spring boot 的 jar 包。

整个项目
│   
│── 前端项目(vue-cli 项目)
│   
└── 后端项目
    │   
    ├── web 项目(整个后端项目的入口和最终代码成果)
    │   
    │── xxx 模块
    │   │── service
    │   └── dao
    │   
    │── yyy 模块
    │   │── service
    │   └── dao
    │   
    └── zzz 模块
        │── service
        └── dao

整个项目的『代码成果』有 2 个:

  1. 前端项目执行 build 命令后生成的 dist 目录下的 html、css、js 等文件;
  2. web 项目执行 build 命令后生成的 target 中生成的 web.jar 包。逻辑上,它是一个 war 包。

而在微服务的架构思想中,我们一个项目会被『真正地』拆分成几个项目,每个项目都有独立的 MVC 三层。那么,原来的『每个模块』,现在就变成了真正意义上的『每个项目』。

整个项目
│   
│── 前端项目 - vue 项目
│   
│── 后端项目 - xxx 项目(入口1和成果1)
│   ├── web 
│   │── service
│   └── dao
│   
│── 后端项目 - yyy 项目(入口2和成果2)
│   ├── web 
│   │── service
│   └── dao
│   
└── 后端项目 - zzz 项目(入口3和成果3)
    ├── web 
    │── service
    └── dao

整个项目的『代码成果』有 N 个:

  1. 前端项目执行 build 命令后生成的 dist 目录下的 html、css、js 等文件;

  2. xxx 项目执行 build 命令后生成的 target 中生成的 xxx.jar 包。逻辑上,它是一个 war 包。

  3. yyy 项目执行 build 命令后生成的 target 中生成的 yyy.jar 包。逻辑上,它是一个 war 包。

  4. zzz 项目执行 build 命令后生成的 target 中生成的 zzz.jar 包。逻辑上,它是一个 war 包。

那么,在涉及到跨模块调用时,我们就无法像以前一样从代码层面直接调用。那么怎么办?在 xxx 项目的代码中编写代码,向 B 项目发起 HTTP 请求。

#2. RestTemplate 发起 HTTP 请求

说明

你的项目只要直接或间接引入了 spring-web 包,你就可以使用 RestTemplate 。

RestTemplate 类似于 Slf4J,它本身并没有做『更多』的什么事情,它的主要功能和目的是对背后真正干活的“人”做二次包装,以提供统一的、简洁的使用方式。

在默认的(未引入其它包的)情况下,在 RestTemplate 背后真正干活的是 JDK 中的网络相关类:HttpURLConnection 。如此之外,RestTemplate 还支持使用 HttpClient 和 OkHTTP 库,前提是,你要额外引入这两个包

Spring RestTemplate 是 Spring 提供的用于访问 Rest 服务的客端。 RestTemplate 提供了多种便捷访问远程 HTTP 服务的方法,能够大大提高客户端的编写效率,所以很多客户端比如 Android 或者第三方服务商都是使用 RestTemplate 请求 restful 服务。

在以前的 Spring Boot 版本中,Spring IoC 容器中已经有一个创建好了的 RestTemplate 供我们使用,不过到了新版本的 Spring Boot 中,需要我们自己创建 RestTemplate 的单例对象

@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
    return builder.build();
}

2.1 API 方法介绍

常见方法有:

请求类型API说明
GET 请求 getForEntity 方法 返回的 ResponseEntity 包含了响应体所映射成的对象
GET 请求 getForObject 方法 返回的请求体将映射为一个对象
POST 请求 postForEntity 方法 返回包含一个对象的 ResponseEntity ,这个对象是从响应体中映射得到的
POST 请求 postForObject 方法 返回根据响应体匹配形成的对象
PUT 请求 put 方法 PUT 资源到特定的 URL
DELETE 请求 delete 方法 对资源执行 HTTP DELETE 操作
任何请求 exchange 方法 返回包含对象的 ResponseEntity ,这个对象是从响应体中映射得到的
任何请求 execute 方法 返回一个从响应体映射得到的对象

2.2 发起 GET 请求

回顾一下 GET 请求的特点:

  • GET 请求不用『管』header 中的 content-type 的值。

  • GET 请求的参数是『追加』到 URL 中,而不是附带在请求的 body 部分的。

因此,如果没有其他的设置请求头的要求,GET 请求在调用 exchange() 方法时,不需要 HttpEntity 参数,因为它就是用来封装请求 body 和请求 header 的。

无参情况:

@Resource
private RestTemplate restTemplate;

@Test
public void test1() {
  String url = "http://localhost:8080/get1";
  // RestTemplate template = new RestTemplate();
  ResponseEntity responseEntity = template.exchange(url, HttpMethod.GET, null, String.class);

  log.info("{}", responseEntity.getStatusCode());
  log.info("{}", responseEntity.getHeaders());
  log.info("{}", responseEntity.getBody());
}

有参情况传值:

//写法一:
String url1 = "http://localhost:8080/get2?username={1}&password={2}"; ResponseEntity responseEntity1 = template.exchange(url1, HttpMethod.GET, null, String.class, "tom", 10); log.info("{}", responseEntity1.getBody());

//写法二:

 String url2 = "http://localhost:8080/get2?username={xxx}&password={yyy}";

 Map map = new HashMap<>();
 map.put("xxx", "tom");
 map.put("yyy", 20);
 ResponseEntity responseEntity2 = template.exchange(url2, HttpMethod.GET, null, String.class, map);
 log.info("{}", responseEntity2.getBody());

2.3 发起 POST 请求

回顾一下 POST 请求的特点:

  • POST 请求的 header 中的 content-type 的值是 application/x-www-form-urlencoded 。

  • POST 请求的参数是附加到请求的 body 部分的。

因此,在调用 exchange() 方法时,需要为其提供一个 HttpEntity 类型参数。

无参情况:

String url = "http://localhost:8080/post1";

// 准备请求头部信息
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

// 无参数情况下,不需要设置请求 body 部分
HttpEntity<?> entity = new HttpEntity<>(null, headers);

ResponseEntity responseEntity = template.exchange(url, HttpMethod.POST, entity, String.class);

log.warn("{}", responseEntity.getStatusCode());
log.warn("{}", responseEntity.getHeaders());
log.warn("{}", responseEntity.getBody());

有参情况:

// 准备请求头部信息
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

// 准备要提交的数据
MultiValueMap parameters = new LinkedMultiValueMap<>();
parameters.add("username", "tom");
parameters.add("age", 20);

HttpEntity> entity = new HttpEntity<>(parameters, headers);

String url = "http://localhost:8080/post2";
ResponseEntity responseEntity = template.exchange(url, HttpMethod.POST, entity, String.class);
log.warn("{}", responseEntity.getBody());

相关