什么NacosNacos是Spring Cloud Alibaba提供的一个软件这个软件主要具有注册中心和配置中心的功能我们先学习它注册中心的功能微服务中所有项目都必须注册到注册中心才能成为微服务的一部分注册中心和企业中的人力资源管理部门有相似注册Nacos的启动我们要启动Nacos必须保证当前系统配置了java环境变量简单来说就是要环境变量中,有JAVA_HOME的配置,指向安装jdk的路径确定
什么Nacos
Nacos是Spring Cloud Alibaba提供的一个软件
这个软件主要具有注册中心和配置中心的功能
我们先学习它注册中心的功能
微服务中所有项目都必须注册到注册中心才能成为微服务的一部分
注册中心和企业中的人力资源管理部门有相似
Nacos的启动
我们要启动Nacos必须保证当前系统配置了java环境变量
简单来说就是要环境变量中,有JAVA_HOME的配置,指向安装jdk的路径
确定了支持java后,可以通过下面路径下载
https://github.com/alibaba/nacos/releases/download/1.4.3/nacos-server-1.4.3.zip
安装启动Nacos
将下载好的Nacos压缩包解压
将压缩包解压(注意不要有中文路径或空格)
打开解压得到的文件夹后打开bin目录会有如下内容
- cmd结尾的文件是windows版本的
- sh结尾的文件是linux和mac版本的
startup是启动文件,shutdown是停止文件
Windows下启动Nacos不能直接双击cmd文件
需要进入dos命令运行
在当前资源管理器地址栏输入cmd
G:\pgm\nacos\bin>startup.cmd -m standalone
- -m是设置启动方式参数
- standalone翻译为标准的孤独的
- 意思是单机模式标准运行
- 运行成功默认占用8848端口,并且在代码中提示
如果不输入standalone运行会失败
startup.cmd -m standalone
验证Nacos的运行状态
打开浏览器输入http://localhost:8848/nacos
如果是首次访问,会出现这个界面
登录系统
- 用户名:nacos
- 密码:nacos
登录之后可以进入后台列表
不能关闭启动nacos的dos窗口
我们要让我们编写的项目注册到Nacos,才能真正是微服务项目
csmall项目案例
业务概述
这个项目作为学习微服务组件使用
我们需要完成一个添加订单的业务
模拟用户选中购物车中商品并且确定了数量的情况下点击提交订单时后端的操作
- 减少选中商品sku的库存数
- 删除用户再购物车中勾选的商品
- 生成订单,将订单信息保存到数据库
上面三个步骤分别由3个模块完成
- 库存模块:减少库存
- 购物车模块:删除购物车信息
- 订单模块:新增订单
创建csmall父项目
创建项目名称csmall
首先删除项目的src目录,因为我们使用不到
其次,pom文件有大量配置
直接从提供给大家的完整版中复制
其中的内容,我们会随着后面学习,逐一给大家讲解
最终的pom文件内容为
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>cn.celinf</groupId>
<artifactId>csmall</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>csmall</name>
<description>微服务框架演示案例</description>
<packaging>pom</packaging>
<modules>
<!-- <module>csmall-business</module>-->
<!-- <module>csmall-commons</module>-->
<!-- <module>csmall-cart</module>-->
<!-- <module>csmall-order</module>-->
<!-- <module>csmall-stock</module>-->
</modules>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>2020.0.3</Spring-cloud.version>
<spring-cloud-alibaba.version>2.2.2.RELEASE</spring-cloud-alibaba.version>
<spring-boot.version>2.5.4</spring-boot.version>
<spring-boot-configuration-processor.version>
2.3.0.RELEASE
</spring-boot-configuration-processor.version>
<spring-security-jwt.version>1.0.10.RELEASE</spring-security-jwt.version>
<MyBatis-spring-boot.version>2.2.0</mybatis-spring-boot.version>
<mybaits-plus.version>3.4.1</mybaits-plus.version>
<pagehelper-spring-boot.version>1.4.0</pagehelper-spring-boot.version>
<MySQL.version>8.0.26</mysql.version>
<lombok.version>1.18.20</lombok.version>
<knife4j-spring-boot.version>2.0.9</knife4j-spring-boot.version>
<spring-rabbit-test.version>2.3.10</spring-rabbit-test.version>
<spring-security-test.version>5.5.2</spring-security-test.version>
<fastjson.version>1.2.45</fastjson.version>
<druid.version>1.1.20</druid.version>
<jjwt.version>0.9.0</jjwt.version>
<seata-server.version>1.4.2</seata-server.version>
</properties>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
<!-- 依赖管理 -->
<dependencyManagement>
<dependencies>
<!--seata-all-->
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-all</artifactId>
<version>${seata-server.version}</version>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
<!-- MySQL -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
<scope>runtime</scope>
</dependency>
<!-- Alibaba Druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>${druid.version}</version>
</dependency>
<!-- MyBatis Spring Boot:数据访问层MyBatis编程 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis-spring-boot.version}</version>
</dependency>
<!-- MyBatis Plus Spring Boot:MyBatis增强 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybaits-plus.version}</version>
</dependency>
<!-- MyBatis Plus Generator:代码生成器 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>${mybaits-plus.version}</version>
</dependency>
<!-- PageHelper Spring Boot:MyBatis分页 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>${pagehelper-spring-boot.version}</version>
</dependency>
<!-- Spring Boot:基础框架 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<!-- Spring Boot Web:WEB应用 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<!-- Spring Boot Freemarker:MyBaits Plus Generator的辅助项 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<!-- Spring Boot Validation:验证请求参数 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<!-- Spring Boot Security:认证授权 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<!-- Spring Boot Oauth2:认证授权 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<!-- Spring Boot配置处理器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>${spring-boot-configuration-processor.version}</version>
</dependency>
<!-- Spring Security JWT -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-jwt</artifactId>
<version>${spring-security-jwt.version}</version>
</dependency>
<!-- Knife4j Spring Boot:在线API -->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>${knife4j-spring-boot.version}</version>
</dependency>
<!-- Spring Boot Data Redis:缓存 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<!-- Spring Boot Data MongoDB:缓存 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<!-- Spring Boot Data Elasticsearch:文档搜索 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<!-- Spring Boot AMQP:消息队列 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<!-- Spring Boot Actuator:健康监测 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<!-- Spring Cloud家族 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- Spring Cloud Alibaba -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- Alibaba FastJson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<!-- JJWT -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>${jjwt.version}</version>
</dependency>
<!-- Spring Boot Test:测试 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>${spring-boot.version}</version>
<scope>test</scope>
</dependency>
<!-- Spring Rabbit Test:消息队列测试 -->
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit-test</artifactId>
<version>${spring-rabbit-test.version}</version>
<scope>test</scope>
</dependency>
<!-- Spring Security Test:Security测试 -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<version>${spring-security-test.version}</version>
<scope>test</scope>
</dependency>
<!--seata整合springboot-->
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
<version>${seata-server.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
创建通用项目commons
创建好之后
- 删除test测试文件夹
- 删除resources目录
- 删除SpringBoot启动类
这些都用不到
编写父项目的module配置
<module>csmall-commons</module>
在修改子项目pom文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.celinf</groupId>
<artifactId>csmall</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<groupId>cn.celinf</groupId>
<artifactId>csmall-commons</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>csmall-commons</name>
<description>Demo project for Spring Boot</description>
<dependencies>
<!--在线api文档-->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
</dependency>
<!-- Spring Boot Web:WEB应用 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-json</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</project>
创建包
cn.celinf.csmall.commons.pojo.cart.dto包
包中创建类CartAddDTO
//这个类就是新增购物车商品使用的类
@ApiModel("购物车新增DTO")
@Data
public class CartAddDTO implements Serializable {
@ApiModelProperty(value = "商品编号",name = "commodityCode",example = "PC100")
private String commodityCode;
@ApiModelProperty(value = "商品单价",name = "price",example = "188")
private Integer price;
@ApiModelProperty(value = "商品个数",name = "count",example = "5")
private Integer count;
@ApiModelProperty(value = "用户ID",name = "userId",example = "UU100")
private String userId;
}
创建实体类
创建包 pojo.cart.entity 包中创建类Cart
@Data
public class Cart implements Serializable {
private Integer id;
// 商品编号
private String commodityCode;
// 价格
private Integer price;
// 数量
private Integer count;
// 用户id
private Integer userId;
}
下面创建订单模块需要的类
pojo.order.dto.OrderAddDTO
@ApiModel("新增订单的DTO")
@Data
public class OrderAddDTO implements Serializable {
@ApiModelProperty(value = "用户id",name="userId",example = "UU100")
private String userId;
@ApiModelProperty(value = "商品编号",name="commodityCode",example = "PC100")
private String commodityCode;
@ApiModelProperty(value = "商品数量",name="count",example = "5")
private Integer count;
@ApiModelProperty(value = "总金额",name="money",example = "50")
private Integer money;
}
pojo.order.entity.Order
@Data
public class Order implements Serializable {
private Integer id;
private String userId;
private String commodityCode;
private Integer count;
private Integer money;
}
最后是库存相关的类
pojo.stock.dto.StockReduceCountDTO
@ApiModel("商品减少库存DTO")
@Data
public class StockReduceCountDTO implements Serializable {
@ApiModelProperty(value = "商品编号",name="commodityCode",example = "PC100")
private String commodityCode;
@ApiModelProperty(value = "减库存数",name="reduceCount",example = "5")
private Integer reduceCount;
}
pojo.stock.entity.Stock
@Data
public class Stock implements Serializable {
private Integer id;
private String commodityCode;
private Integer reduceCount;
}
创建异常相关类
commons项目除了实体类之外
项目使用到的所有异常相关类,也统一编写在这个类中
创建cn.celinf.csmall.commons.restful包
首先创建常见响应状态码的枚举
// 错误代码枚举类型
public enum ResponseCode {
OK(200),
BAD_REQUEST(400),
UNAUTHORIZED(401),
FORBIDDEN(403),
NOT_FOUND(404),
NOT_ACCEPTABLE(406),
CONFLICT(409),
INTERNAL_SERVER_ERROR(500);
private Integer value;
ResponseCode(Integer value) {
this.value = value;
}
public Integer getValue() {
return value;
}
}
下面创建自定义异常类
创建包cn.celinf.csmall.commons.exception
包中创建类CoolSharkServiceException
@Data
@EqualsAndHashCode(callSuper = false)
public class CoolSharkServiceException extends RuntimeException {
private ResponseCode responseCode;
public CoolSharkServiceException(ResponseCode responseCode, String message) {
super(message);
setResponseCode(responseCode);
}
}
将restful包中用于控制器返回的JsonResult类复制
@Data
public class JsonResult<T> implements Serializable {
/**
* 状态码
*/
@ApiModelProperty(value = "业务状态码", position = 1, example = "200, 400, 401, 403, 404, 409, 500")
private Integer state;
/**
* 消息
*/
@ApiModelProperty(value = "业务消息", position = 2, example = "登录失败!密码错误!")
private String message;
/**
* 数据
*/
@ApiModelProperty(value = "业务数据", position = 3)
private T data;
/**
* 创建响应结果对象,表示"成功",不封装其它任何数据
* @return 响应结果对象
*/
public static JsonResult<Void> ok() {
return ok("OK");
}
public static JsonResult ok(String message){
JsonResult jsonResult=new JsonResult();
jsonResult.setState(ResponseCode.OK.getValue());
jsonResult.setMessage(message);
jsonResult.setData(null);
return jsonResult;
}
/**
* 创建响应结果对象,表示"成功",且封装客户端期望响应的数据
* @param data 客户端期望响应的数据
* @return 响应结果对象
*/
public static <T> JsonResult<T> ok(String message,T data) {
JsonResult<T> jsonResult = new JsonResult<>();
jsonResult.setState(ResponseCode.OK.getValue());
jsonResult.setData(data);
return jsonResult;
}
/**
* 创建响应结果对象,表示"失败",且封装"失败"的描述
*
* @param e CoolSharkServiceException异常对象
* @return 响应结果对象
*/
public static JsonResult<Void> failed(CoolSharkServiceException e) {
return failed(e.getResponseCode(), e);
}
/**
* 创建响应结果对象,表示"失败",且封装"失败"的描述
*
* @param responseCode "失败"的状态码
* @param e "失败"时抛出的异常对象
* @return 响应结果对象
*/
public static JsonResult<Void> failed(ResponseCode responseCode, Throwable e) {
return failed(responseCode, e.getMessage());
}
/**
* 创建响应结果对象,表示"失败",且封装"失败"的描述
*
* @param responseCode "失败"的状态码
* @param message "失败"的描述文本
* @return 响应结果对象
*/
public static JsonResult<Void> failed(ResponseCode responseCode, String message) {
JsonResult<Void> jsonResult = new JsonResult<>();
jsonResult.setState(responseCode.getValue());
jsonResult.setMessage(message);
return jsonResult;
}
}
exception包下最后创建复制统一异常处理类
/**
* 全局异常处理器
*/
@RestControllerAdvice
@Slf4j
public class GlobalControllerExceptionHandler {
/**
* 处理业务异常
*/
@ExceptionHandler({CoolSharkServiceException.class})
public JsonResult<Void> handleCoolSharkServiceException(CoolSharkServiceException e) {
log.debug("出现业务异常,业务错误码={},描述文本={}", e.getResponseCode().getValue(), e.getMessage());
e.printStackTrace();
JsonResult<Void> result = JsonResult.failed(e);
log.debug("即将返回:{}", result);
return result;
}
/**
* 处理绑定异常(通过Validation框架验证请求参数时的异常)
*/
@ExceptionHandler(BindException.class)
public JsonResult<Void> handleBindException(BindException e) {
log.debug("验证请求数据时出现异常:{}", e.getClass().getName());
e.printStackTrace();
String message = e.getBindingResult().getFieldError().getDefaultMessage();
JsonResult<Void> result = JsonResult.failed(ResponseCode.BAD_REQUEST, message);
log.debug("即将返回:{}", result);
return result;
}
/**
* 处理系统(其它)异常
*/
@ExceptionHandler({Throwable.class})
public JsonResult<Void> handleSystemError(Throwable e) {
log.debug("出现系统异常,异常类型={},描述文本={}", e.getClass().getName(), e.getMessage());
e.printStackTrace();
JsonResult<Void> result = JsonResult.failed(ResponseCode.INTERNAL_SERVER_ERROR, e);
log.debug("即将返回:{}", result);
return result;
}
}
commons项目编写内容到此结束
创建business模块
搭建基本结构
business可以理解为业务的
我们创建这个模块是为了触发订单生成业务的
创建csmall-business 也要父子相认
最终子项目pom文件为:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.celinf</groupId>
<artifactId>csmall</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<groupId>cn.celinf</groupId>
<artifactId>csmall-business</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>csmall-business</name>
<description>Demo project for Spring Boot</description>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>cn.celinf</groupId>
<artifactId>csmall-commons</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
创建application.yml文件
server:
port: 20000
#公共配置
mybatis:
configuration:
# 禁用缓存
cache-enabled: false
# 配置映射驼峰命名法,数据库中user_name的字段,会映射在java的userName属性上
map-underscore-to-camel-case: true
# 将运行的sql语句输出到控制台
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
knife4j:
# 开启增强配置
enable: true
# 生产环境屏蔽,开启将禁止访问在线API文档
production: false
# Basic认证功能,即是否需要通过用户名、密码验证后才可以访问在线API文档
basic:
# 是否开启Basic认证
enable: false
# 用户名,如果开启Basic认证却未配置用户名与密码,默认是:admin/123321
username: root
# 密码
password: root
spring:
profiles:
active: dev
创建application-dev.yml文件以备后续配置使用,现在为空即可
删除项目中src下的test测试文件夹
创建config包,添加一些必要配置
创建CommonsConfiguration
// 当前项目默认情况下不会扫描commons项目中的资源和内容,编写这个类,配置扫描commons
@Configuration // 所有配置Spring的配置类必须添加这个注解
@ComponentScan(basePackages = "cn.celinf.csmall.commons.exception")
public class CommonsConfiguration {
}
创建Knife4jConfiguration
(直接复制即可)
@Configuration
@EnableSwagger2WebMvc
public class Knife4jConfiguration {
/**
* 【重要】指定Controller包路径
*/
private String basePackage = "cn.celinf.csmall.business.controller";
/**
* 分组名称
*/
private String groupName = "base-business";
/**
* 主机名
*/
private String host = "http://java.celinf.cn";
/**
* 标题
*/
private String title = "酷鲨商城项目案例在线API文档--基础business-web实例";
/**
* 简介
*/
private String description = "构建基础business-web项目,实现购买";
/**
* 服务条款URL
*/
private String termsOfServiceUrl = "http://www.apache.org/licenses/LICENSE-2.0";
/**
* 联系人
*/
private String contactName = "项目研发部";
/**
* 联系网址
*/
private String contactUrl = "http://java.celinf.cn";
/**
* 联系邮箱
*/
private String contactEmail = "java@celinf.cn";
/**
* 版本号
*/
private String version = "1.0-SNAPSHOT";
@Autowired
private OpenApiExtensionResolver openApiExtensionResolver;
@Bean
public Docket docket() {
String groupName = "1.0-SNAPSHOT";
Docket docket = new Docket(DocumentationType.SWAGGER_2)
.host(host)
.apiInfo(apiInfo())
.groupName(groupName)
.select()
.apis(RequestHandlerSelectors.basePackage(basePackage))
.paths(PathSelectors.any())
.build()
.extensions(openApiExtensionResolver.buildExtensions(groupName));
return docket;
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title(title)
.description(description)
.termsOfServiceUrl(termsOfServiceUrl)
.contact(new Contact(contactName, contactUrl, contactEmail))
.version(version)
.build();
}
}
编写业务
因为business是业务的触发者,不需要连接数据库,所以从业务逻辑层开始写即可
创建service包 包中创建接口IBusinessService
public interface IBusinessService {
// business业务触发购买下订单的方法声明
void buy();
}
业务逻辑层实现
创建包service.impl 创建类BusinessServiceImpl
@Service
@Slf4j
public class BusinessServiceImpl implements IBusinessService {
@Override
public void buy() {
// 暂时模拟一个下单业务
// 创建OrderAddDTO类,赋值并输出信息
OrderAddDTO orderAddDTO=new OrderAddDTO();
orderAddDTO.setCommodityCode("PC100");
orderAddDTO.setUserId("UU100");
orderAddDTO.setMoney(500);
orderAddDTO.setCount(5);
// 因为没有持久层,只能输出一下,表示运行正常
log.info("新增订单信息为:{}",orderAddDTO);
}
}
控制层代码
创建controller 包中创建BusinessController类
@RestController
@RequestMapping("/base/business")
// knife4j介绍当前控制器作用
@Api(tags = "购买业务开始模块")
public class BusinessController {
@Autowired
private IBusinessService businessService;
@PostMapping("/buy") // localhost:20000/base/business/buy
@ApiOperation("发起购买")
public JsonResult buy(){
// 调用业务逻辑层方法即可
businessService.buy();
return JsonResult.ok("购买完成");
}
}
可以启动当前项目 http://localhost:20000/doc.html
点击测试,观察输出结果和控制台输出内容是否正常
注册到Nacos
我们的项目要想称为微服务项目必须注册到nacos
做具体配置之前,要明确,启动business之前,一定保证nacos在运行状态,否则启动business会报错的
首先在business的pom文件中添加依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
然后再application-dev.yml文件中添加当前项目对nacos注册的配置
spring:
application:
# 当前Springboot项目的名称,用作注册中心服务的名称
name: nacos-business
cloud:
nacos:
discovery:
# 定义nacos运行的路径
server-addr: localhost:8848
做完上面的配置
我们在保证nacos已经启动的前提下,我们启动business项目
启动之后,business一切功能正常,而且可以在nacos的服务列表中看到nacos-business的名称
Nacos心跳机制
常见面试题
Nacos内部注册的服务分为两大类
- 临时实例(默认)
- 持久化实例(永久实例)
我们可以通过设置属性来确定它是临时还是永久
cloud:
nacos:
discovery:
# ephemeral设置当前项目启动时注册到nacos的类型 true(默认):临时实例 false:永久实例
ephemeral: true
临时实例和永久实例的区别
临时实例
默认情况下,启动服务后,每隔5秒会向nacos发送一个"心跳包",这个心跳包中包含了当前服务的基本信息
Nacos收到这个"心跳包"如果发现这个服务的信息不在注册列表中,就进行注册,如果这个服务的信息在注册列表中就表明这个服务还是健康的
如果Nacos15秒内没接收到某个服务的心跳包,Nacos会将这个服务标记为不健康的状态
如果30秒内没有接收到这个服务的心跳包,Nacos会将这个服务从注册列表中剔除
这些时间都是可以通过配置修改的
持久化实例(永久实例)
持久化实例启动时向nacos注册,nacos会对这个实例进行持久化处理
心跳包的规则和临时实例一致,只是不会将该服务从列表中剔除
各类型使用时机
一般情况下,我们创建的服务都是临时实例
只有项目的主干业务才会设置为永久实例
使用Idea启动Nacos
我们每次开机都要先启动nacos才能启动其他服务
我们使用dos窗口敲代码启动nacos还是比较麻烦的
我们可以使用idea提供的功能,简化nacos启动的过程
配置完成后,就可以在idea中启动nacos
其余几个模块也如这个模块一样的。所以就不一一粘贴了。
- cart 购物车模块(修改pom.xml、链接数据库yml文件)
- order订单模块(修改pom.xml、链接数据库yml文件)
- stock库存模块(修改pom.xml、链接数据库yml文件)
学习记录,如有侵权请联系删除。