Java服务器项目分类

现在市面上常见的java开发的项目可以分为两大类

1.企业级应用

一般指一个企业或机构内部使用的网站或服务器应用程序

包括的领域很多,包括并不限于:商业,企事业单位,医疗,军事,政府,金融等

这种项目的特征是访问人数不多,不是全国乃至全世界都需要使用的网站

因为人数比较少又没有替代品,所以不强烈要求三高

但是企业级项目一般会有比较复杂的权限设置和业务流程

2.互联网应用

指对全国乃至全世界开放的网站或服务器引用程序

我们手机中安装的app大部分都是互联网应用

微信,支付宝,京东,淘宝,饿了么,美团,抖音,qq音乐,爱奇艺,高德地图等

他们因为商业竞争等各种原因,对服务器性能有要求,也就是前面提到的"三高"

及时并发量非常大,程序也要正常运行,迅速响应

互联网应用一般业务和权限相对简单,但是要求"三高"

因为上述java项目的分类偏重点不同

在当今java开发的业界中,有下面的基本规律

  • 如果开发的是企业级应用,使用单体架构的情况比较多
  • 如果开发的是互联网应用,使用微服务架构的情况比较多

什么是微服务

微服务是由以单一应用程序构成的小服务,自己拥有自己的行程与轻量化处理,服务依业务功能设计,以全自动的方式部署,与其他服务使用 HTTP API 通信。同时服务会使用最小的规模的集中管理能力,服务可以用不同的编程语言与数据库等组件实现。

简单来说,微服务就是将一个大型项目的各个业务代码,拆分成多个互不干扰的小项目,而这些小项目专心完成自己的功能,而且可以调用别的小项目的方法,从而完成整体功能

京东\淘宝这样的大型互联网应用程序,基本每个操作都是一个单独的微服务在支持:

  • 登录服务器
  • 搜索服务器
  • 商品信息服务器
  • 购物车服务器
  • 订单服务器
  • 支付服务器
  • 物流服务器
  • .....

 为什么使用微服务

左侧小餐馆就像单体项目

一旦服务器忙,所有业务都无法快速响应

即使添加了服务器,也不能很好的解决这个问题

不能很好的实现"高并发,高可用,高性能"

但是因为服务器数量少,所以成本低,适合并发访问少的项目

右侧的大餐厅就是微服务项目

每个业务有专门一批人负责,业务之间互不影响

能够针对的在性能不足的业务上添加服务器来改善性能,同时万一一个服务器异常,不会影响整体功能

但是服务器数量多,成本高,适合要要求"高并发,高可用,高性能"的项目

怎么搭建微服务项目

在微服务概念提出之前(2014年),每个厂商都有自己的解决方案

但是Martin Fowler(马丁·福勒)提出了微服务的标准之后,为了技术统一和兼容性,很多企业开始支持这个标准

现在业界中开发微服务项目,大多数都是在这个标准下的

如果我们自己编写支持这个标准的代码是不现实的,必须通过现成的框架或组件完成满足这个微服务标准的项目结构和格式

当今程序员要想快速完成微服务标准的程序,首选SpringCloud

Spring Cloud

什么是Spring Cloud

SpringCloud是由Spring提供的一套能够快速搭建微服务架构程序的框架集

框架集表示SpringCloud不是一个框架,而是很多框架的统称

SpringCloud是为了搭建微服务架构的程序而出现的

有人将SpringCloud称之为"Spring全家桶",广义上指代所有Spring的产品

SpringCloud的内容

从内容提供者角度

  • Spring自己编写的框架和软件
  • Netflix(奈非):早期提供了很多(全套)微服务架构组件
  • alibaba(阿里巴巴):新版本SpringCloud推荐使用(正在迅速占领市场)

课程中大量使用alibaba的微服务组件

从功能上分类

  • 微服务的注册中心
  • 微服务间的调用
  • 微服务的分布式事务
  • 微服务的限流
  • 微服务的网关

安装启动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,才能真正是微服务项目

所谓注册中心,其实是分布式架构演进过程中的产物,在系统中充当一个协调者的角色。但是,为什么需要这样一个协调者的角色呢?我们先来看一个例子,以便理解为什么分布式架构中需要有注册中心。

案例

小明和小新住在同一家沃尔玛超市附近,他俩都办了会员,经常关注超市的一些优惠活动,元宵节快到了,沃尔玛准备搞一个元宵节特惠活动,需要通知到附近的住户。对于沃尔玛来说,可以安排工作人员电话通知到小明和小新;而对于小明和小新来说,可以去超市咨询相关信息。

那么问题来了,住在超市附近的,不只有小明和小新两个消费者,如果每个人都打电话去通知就显得太麻烦了,小明和小新提前在超市了解了相关信息,可是不巧的是,由于各种原因,沃尔玛元宵特惠活动要从上午改到下午才开始,他们又该从何得知呢?

其实,沃尔玛关心的是通知能不能传达到附近的住户,小明和小新关心的是沃尔玛优惠活动的详情动态。沃尔玛不必给每个住户挨个电话通知,它只需要在它的微信公众号上推送一条消息即可,小明和小新也不用去超市咨询,只要随时关注沃尔玛公众号的推送消息即可。

在上面这个例子中,沃尔玛就是服务提供者,小明和小新是服务消费者,微信公众号类似于注册中心,沃尔玛将“服务”发布到注册中心,小明和小新作为消费者,订阅注册中心上沃尔玛提供的“服务”,通过微信公众号,沃尔玛(服务方)和小明、小新(消费方)就“解耦”了。

用这个例子来解释注册中心未必恰当,毕竟系统中的服务既可以是服务提供者(Provider),也可以是服务消费者(Consumer),但我想的是以一种更加通俗的方式来解释它,技术日新月异,各种技术、术语层出不穷,容易让人头晕眼花,但万变不离其宗,技术源于现实世界,亦服务于现实世界,在现实世界中,我们思考如何解决问题,技术也必然以同样的思路去解决问题。

业务概述

这个项目作为学习微服务组件使用

我们需要完成一个添加订单的业务

模拟用户选中购物车中商品并且确定了数量的情况下点击提交订单时后端的操作

1.减少选中商品sku的库存数

2.删除用户再购物车中勾选的商品

3.生成订单,将订单信息保存到数据库

上面三个步骤分别由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.tedu</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.tedu</groupId><artifactId>csmall</artifactId><version>0.0.1-SNAPSHOT</version></parent><groupId>cn.tedu</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.tedu.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;// 用户idprivate 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.tedu.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.tedu.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;}
}

创建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.tedu</groupId><artifactId>csmall</artifactId><version>0.0.1-SNAPSHOT</version></parent><groupId>cn.tedu</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.tedu</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/123321username: root# 密码password: root
spring:profiles:active: dev

创建application-dev.yml文件以备后续配置使用,现在为空即可

删除项目中src下的test测试文件夹

创建config包,添加一些必要配置

创建CommonsConfiguration

创建Knife4jConfiguration

(直接复制即可)

@Configuration
@EnableSwagger2WebMvc
public class Knife4jConfiguration {/*** 【重要】指定Controller包路径*/private String basePackage = "cn.tedu.csmall.business.controller";/*** 分组名称*/private String groupName = "base-business";/*** 主机名*/private String host = "http://java.tedu.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.tedu.cn";/*** 联系邮箱*/private String contactEmail = "java@tedu.cn";/*** 版本号*/private String version = "1.0-SNAPSHOT";@Autowiredprivate OpenApiExtensionResolver openApiExtensionResolver;@Beanpublic 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();}}
// 当前项目默认情况下不会扫描commons项目中的资源和内容,编写这个类,配置扫描commons
@Configuration // 所有配置Spring的配置类必须添加这个注解
@ComponentScan(basePackages = "cn.tedu.csmall.commons.exception")
public class CommonsConfiguration {
}

编写业务

因为business是业务的触发者,不需要连接数据库,所以从业务逻辑层开始写即可

创建service包

包中创建接口IBusinessService

public interface IBusinessService {// business业务触发购买下订单的方法声明void buy();
}

业务逻辑层实现

创建包service.impl

创建类BusinessServiceImpl

代码如下

@Service
@Slf4j
public class BusinessServiceImpl implements IBusinessService {@Overridepublic 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 {@Autowiredprivate 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-businesscloud:nacos:discovery:# 定义nacos运行的路径server-addr: localhost:8848

做完上面的配置

我们在保证nacos已经启动的前提下,我们启动business项目

启动之后,business一切功能正常,而且可以在nacos的服务列表中看到nacos-business的名称

Nacos心跳机制

Nacos内部注册的服务分为两大类

1.临时实例(默认)

2.持久化实例(永久实例)

我们可以通过设置属性来确定它是临时还是永久

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启动的过程

创建cart子模块(项目)

项目配置

创建csmall-cart子项目

父项目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>cn.tedu</groupId><artifactId>csmall</artifactId><version>0.0.1-SNAPSHOT</version></parent><groupId>cn.tedu</groupId><artifactId>csmall-cart</artifactId><version>0.0.1-SNAPSHOT</version><name>csmall-cart</name><description>Demo project for Spring Boot</description><dependencies><!--web实例--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--mybatis整合springboot--><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId></dependency><!--alibaba 数据源德鲁伊--><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId></dependency><!--mysql驱动--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><!--all-common依赖--><dependency><groupId>cn.tedu</groupId><artifactId>csmall-commons</artifactId><version>0.0.1-SNAPSHOT</version></dependency><!--在线api文档--><dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-spring-boot-starter</artifactId></dependency></dependencies></project>
</project>

删除test文件夹

删除application.properties

创建application.yml内容如下

server:port: 20001
#公共配置
mybatis:configuration:cache-enabled: falsemap-underscore-to-camel-case: truelog-impl: org.apache.ibatis.logging.stdout.StdOutImpl
knife4j:# 开启增强配置enable: true# 生产环境屏蔽,开启将禁止访问在线API文档production: false# Basic认证功能,即是否需要通过用户名、密码验证后才可以访问在线API文档basic:# 是否开启Basic认证enable: false# 用户名,如果开启Basic认证却未配置用户名与密码,默认是:admin/123321username: root# 密码password: root
spring:profiles:active: dev

创建application-dev.yml文件

因为cart模块真连接数据库

所以dev文件中,添加连库配置信息

准备数据

我们cart模块要操作数据库,首先保证要有数据

所以我们要创建需要的表和添加表中的数据

sql代码已经发送在项目的node文件夹中

运行其中的sql代码即可

CREATE DATABASE `csmall_db`;
USE `csmall_db`;/*Table structure for table `cart_tbl` */DROP TABLE IF EXISTS `cart_tbl`;CREATE TABLE `cart_tbl` (`id` int NOT NULL AUTO_INCREMENT COMMENT '购物车id',`commodity_code` varchar(255) DEFAULT NULL COMMENT '商品编码',`price` int DEFAULT '0' COMMENT '商品单价',`count` int DEFAULT '0' COMMENT '购买数量',`user_id` varchar(255) DEFAULT NULL COMMENT '用户id',PRIMARY KEY (`id`),UNIQUE KEY `commodity_code` (`commodity_code`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb3;/*Data for the table `cart_tbl` */insert  into `cart_tbl`(`id`,`commodity_code`,`price`,`count`,`user_id`) values
(1,'PU201',500,10,'UU100');/*Table structure for table `order_tbl` */DROP TABLE IF EXISTS `order_tbl`;CREATE TABLE `order_tbl` (`id` int NOT NULL AUTO_INCREMENT COMMENT '订单id',`user_id` varchar(255) DEFAULT NULL COMMENT '用户id',`commodity_code` varchar(255) DEFAULT NULL COMMENT '商品编码,也可以是商品id',`count` int DEFAULT '0' COMMENT '购买这个商品的数量',`money` int DEFAULT '0' COMMENT '订单金额',PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8mb3;/*Data for the table `order_tbl` */insert  into `order_tbl`(`id`,`user_id`,`commodity_code`,`count`,`money`) values
(22,'UU100','PU201',10,200),
(23,'UU100','PU201',10,200),
(24,'UU100','PU201',10,200),
(25,'UU100','PU201',10,200);/*Table structure for table `stock_tbl` */DROP TABLE IF EXISTS `stock_tbl`;CREATE TABLE `stock_tbl` (`id` int NOT NULL AUTO_INCREMENT COMMENT '商品id',`commodity_code` varchar(255) DEFAULT NULL COMMENT '商品编码',`count` int DEFAULT '0' COMMENT '商品库存',PRIMARY KEY (`id`),UNIQUE KEY `commodity_code` (`commodity_code`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb3;/*Data for the table `stock_tbl` */insert  into `stock_tbl`(`id`,`commodity_code`,`count`) values
(1,'PU201',990);/*Table structure for table `undo_log` */DROP TABLE IF EXISTS `undo_log`;CREATE TABLE `undo_log` (`id` bigint NOT NULL AUTO_INCREMENT,`branch_id` bigint NOT NULL,`xid` varchar(100) NOT NULL,`context` varchar(128) NOT NULL,`rollback_info` longblob NOT NULL,`log_status` int NOT NULL,`log_created` datetime NOT NULL,`log_modified` datetime NOT NULL,PRIMARY KEY (`id`),UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=68 DEFAULT CHARSET=utf8mb3;

运行完毕之后,会出现csmall_db数据库

其中有4个表

表中有少量数据

后面会使用

编写配置类

和business模块一样,cart模块也需要config包中的类

可以直接从business模块的config包复制过来

@Configuration // 所有配置Spring的配置类必须添加这个注解
@ComponentScan(basePackages = "cn.tedu.csmall.commons.exception")
public class CommonsConfiguration {
}

knife4j配置

@Configuration
@EnableSwagger2WebMvc
public class Knife4jConfiguration {/*** 【重要】指定Controller包路径*/private String basePackage = "cn.tedu.csmall.cart.controller";/*** 分组名称*/private String groupName = "base-cart";/*** 主机名*/private String host = "http://java.tedu.cn";/*** 标题*/private String title = "酷鲨商城项目案例在线API文档--基础cart-web实例";/*** 简介*/private String description = "构建基础cart-web项目,实现购物车维护";/*** 服务条款URL*/private String termsOfServiceUrl = "http://www.apache.org/licenses/LICENSE-2.0";/*** 联系人*/private String contactName = "项目研发部";/*** 联系网址*/private String contactUrl = "http://java.tedu.cn";/*** 联系邮箱*/private String contactEmail = "java@tedu.cn";/*** 版本号*/private String version = "1.0-SNAPSHOT";@Autowiredprivate OpenApiExtensionResolver openApiExtensionResolver;@Beanpublic 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();}}

当前cart模块除了上述配置之外还要添加一个Mybatis扫描的配置

config包中再创建一个MybatisConfiguration类代码如下、

@Configuration
// Mybatis扫描必须指定到mapper包
@MapperScan("cn.tedu.csmall.cart.mapper")
public class MybatisConfiguration {}

配置nacos的pom

<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

application-dev.yml配置注册到nacos的信息

spring:datasource:url: jdbc:mysql://localhost:3306/csmall_db?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&allowMultiQueries=trueusername: rootpassword: rootapplication:name: nacos-cartcloud:nacos:discovery:server-addr: localhost:8848

在nacos启动的前提下,我们的cart模块就可以启动并注册到nacos了

编写cart项目的业务内容

cart模块能够正常启动,但是还没有任何业务

结合我们最终生成订单的业务

当前cart模块需要开发如下两个功能

1.新增购物车中商品

2.删除购物车中商品

开发持久层

创建mapper包

mapper包中创建CartMapper接口

public interface CartMapper {// 新增购物车中商品的方法@Insert("insert into cart_tbl(commodity_code,user_id,price,count) " +"values(#{commodityCode},#{userId},#{price},#{count})")void insertCart(Cart cart);// 删除购物车中商品的方法@Delete("delete from cart_tbl where user_id=#{userId} and commodity_code=#{commodityCode}")void deleteCartByUserIdAndCommodityCode(@Param("userId") String userid,@Param("commodityCode") String commodityCode);}

开发业务逻辑层

创建service包

先在包中创建接口ICartService

接口中应该包含新增和删除购物车的业务逻辑层方法声明开发实现类

public interface ICartService {// 新增购物车的业务逻辑层方法void cartAdd(CartAddDTO cartAddDTO);// 删除购物车的业务逻辑层方法void deleteUserCart(String userId,String commodityCode);
}

开发实现类

@Service
@Slf4j
public class CartServiceImpl implements ICartService {@Autowiredprivate CartMapper cartMapper;@Overridepublic void cartAdd(CartAddDTO cartAddDTO) {// 实例化一个Cart对象Cart cart=new Cart();// 利用工具类,将cartAddDTO中的属性值赋值到cart对象的同名属性中BeanUtils.copyProperties(cartAddDTO,cart);// 调用cartMapper对象实现新增功能cartMapper.insertCart(cart);log.info("新增购物车商品成功!{}",cart);}@Overridepublic void deleteUserCart(String userId, String commodityCode) {// 直接调用mapper删除购物车商品的方法即可cartMapper.deleteCartByUserIdAndCommodityCode(userId,commodityCode);log.info("购物车商品删除成功");}
}

开发控制层

创建controller包

包中创建CartController类

@RestController
@RequestMapping("/base/cart")
@Api(tags="购物车模块")
public class CartController {@Autowiredprivate ICartService cartService;@PostMapping("/add")@ApiOperation("新增购物车商品")public JsonResult cartAdd(CartAddDTO cartAddDTO){cartService.cartAdd(cartAddDTO);return JsonResult.ok("新增购物车商品完成");}@PostMapping("/delete")@ApiOperation("删除购物车中商品")@ApiImplicitParams({@ApiImplicitParam(value = "用户id",name="userId",example = "UU100",required = true),@ApiImplicitParam(value = "商品编号",name="commodityCode",example = "PC100",required = true)})public JsonResult deleteUserCart(String userId,String commodityCode){// 调用业务逻辑层删除购物车商品的方法cartService.deleteUserCart(userId,commodityCode);return JsonResult.ok("删除购物车商品成功");}}

创建order模块

项目搭建

创建csmall-order

父子相认

子项目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.tedu</groupId><artifactId>csmall</artifactId><version>0.0.1-SNAPSHOT</version></parent><groupId>cn.tedu</groupId><artifactId>csmall-order</artifactId><version>0.0.1-SNAPSHOT</version><name>csmall-order</name><description>Demo project for Spring Boot</description><dependencies><!--web实例--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--mybatis整合springboot--><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId></dependency><!--alibaba 数据源德鲁伊--><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId></dependency><!--mysql驱动--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><!--all-common依赖--><dependency><groupId>cn.tedu</groupId><artifactId>csmall-commons</artifactId><version>0.0.1-SNAPSHOT</version></dependency><!--在线api文档--><dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-spring-boot-starter</artifactId></dependency><!-- nacos注册中心依赖 --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency></dependencies></project>

删除test文件夹

删除application.properties文件

可以将cart模块的application.yml文件和application-dev.yml赋值过来

但是要修改需要变化的属性

application.yml端口号修改

server:port: 20002

application-dev.yml修改项目名称

application:name: nacos-order

config配置

下面将cart模块的config包直接复制到order模块

knife4j配置主要修改:

/*** 【重要】指定Controller包路径*/
private String basePackage = "cn.tedu.csmall.order.controller";
/*** 分组名称*/
private String groupName = "base-order";

Mybatis配置

@Configuration
// Mybatis扫描必须指定到mapper包
@MapperScan("cn.tedu.csmall.order.mapper")
public class MybatisConfiguration {}

编写新增订单功能

开发持久层

创建mapper包

创建OrderMapper接口

添加新增订单方法

@Repository
public interface OrderMapper {// 新增订单的mapper方法@Insert("insert into order_tbl(user_id,commodity_code,count,money) " +"values(#{userId},#{commodityCode},#{count},#{money})")void insertOrder(Order order);
}

开发业务逻辑层

创建service包

包中创建IOrderService

public interface IOrderService {// 新增订单到数据库的业务逻辑层方法void orderAdd(OrderAddDTO orderAddDTO);
}

创建service.impl包

包中创建OrderServiceImpl

@Service
@Slf4j
public class OrderServiceImpl implements IOrderService {@Autowiredprivate OrderMapper orderMapper;@Overridepublic void orderAdd(OrderAddDTO orderAddDTO) {// 1.减少订单商品的库存(要调用stock模块的方法)// 2.删除订单中购物车商品的信息(要调用cart模块的方法)// 3.新增订单// 实例化订单对象Order order=new Order();// 赋值同名属性BeanUtils.copyProperties(orderAddDTO,order);// 调用持久层方法orderMapper.insertOrder(order);log.info("新增订单完成:{}",order);}

开发控制层

创建controller包

创建OrderController类

启动项目

检查nacos注册状态和knife4j测试新增订单效果

先启动nacos再启动order

@RestController
@RequestMapping("/base/order")
@Api(tags="订单模块")
public class OrderController {@Autowiredprivate IOrderService orderService;@ApiOperation("新增订单")@PostMapping("/add")public JsonResult orderAdd(OrderAddDTO orderAddDTO){// 调用业务逻辑层方法orderService.orderAdd(orderAddDTO);return JsonResult.ok("新增订单完成");}
}

创建stock模块

项目搭建

创建csmall-stock

修改父项目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>cn.tedu</groupId><artifactId>csmall</artifactId><version>0.0.1-SNAPSHOT</version></parent><groupId>cn.tedu</groupId><artifactId>csmall-stock</artifactId><version>0.0.1-SNAPSHOT</version><name>csmall-stock</name><description>Demo project for Spring Boot</description><dependencies><!--web实例--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--mybatis整合springboot--><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId></dependency><!--alibaba 数据源德鲁伊--><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId></dependency><!--mysql驱动--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><!--all-common依赖--><dependency><groupId>cn.tedu</groupId><artifactId>csmall-commons</artifactId><version>0.0.1-SNAPSHOT</version></dependency><!--在线api文档--><dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-spring-boot-starter</artifactId></dependency><!-- nacos注册中心依赖 --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency></dependencies></project>

删除test测试文件夹

删除application.properties文件

复制order\cart模块的application.yml和application-dev.yml文件

修改端口号和项目名称

config配置

从order\cart模块复制config包

修改对应的包名

编写减少库存功能

开发持久层

mapper包下StockMapper

@Repository
public interface StockMapper {// 减少指定商品库存的方法@Update("update stock_tbl set count=count-#{reduceCount} " +" where commodity_code=#{commodityCode} and count>=#{reduceCount}")void updateStockByCommodityCode(@Param("commodityCode") String commodityCode,@Param("reduceCount") Integer reduceCount);
}

开发业务层

在service包下创建IStockService

public interface IStockService {// 减少库存数的业务逻辑层方法void reduceCommodityCount(StockReduceCountDTO stockReduceCountDTO);
}

service.impl包下

@Service
@Slf4j
public class StockServiceImpl implements IStockService {@Autowiredprivate StockMapper stockMapper;@Overridepublic void reduceCommodityCount(StockReduceCountDTO stockReduceCountDTO) {stockMapper.updateStockByCommodityCode(stockReduceCountDTO.getCommodityCode(), // 第一个参数是商品编号stockReduceCountDTO.getReduceCount());  // 第二个参数是减少的库存数log.info("库存减少完成!");}
}

开发控制层

controller包

StockContrller类

@RestController
@RequestMapping("/base/stock")
@Api(tags = "库存管理")
public class StockController {@Autowiredprivate IStockService stockService;@PostMapping("/reduce/count")@ApiOperation("减少商品库存业务")public JsonResult reduceCommodityCount(StockReduceCountDTO stockReduceCountDTO){stockService.reduceCommodityCount(stockReduceCountDTO);return JsonResult.ok("商品库存减少完成!");}}

启动服务测试成功即可

微服务Spring Cloud相关推荐

  1. 消息驱动 微服务器,消息驱动的微服务-Spring Cloud Stream整合RocketMQ

    系列文章导航: Spring Cloud Alibaba微服务解决方案 常用MQ产品的选择 目前主流的MQ产品有kafka.RabbitMQ.ActiveMQ.RocketMQ等.在MQ选型时可以参照 ...

  2. 基于微服务spring cloud+vue+spring boot在线聊天交友软件的设计与实现

    针对企业和机构在聊天通讯软件中的的信息管理监控困难.系统稳定性不足.二次开发困难.部署运维困难问题,对一个自主可控,安全稳定的通讯系统进行分析设计. 采用前后端分离的开发模式,前端基于WEB端,采用基 ...

  3. 干货实操:微服务Spring Cloud 系列(二) Eureka服务发现与服务注册(strand alone)

    此篇主要实操Eureka 服务端的服务注册,以及服务发现,并需要认证才能访问控制中心. 分五个部分说明: 一.  认识 Eureka 二.  Eureka  服务端开发 三.  Eureka 客户端开 ...

  4. 微服务 Spring Cloud Alibaba 项目搭建(七、RocketMQ 集成)

    RocketMQ介绍 RocketMQ 是一个 队列模型 的消息中间件,具有高性能.高可靠.高实时.分布式 的特点.它是一个采用 Java 语言开发的分布式的消息系统,由阿里巴巴团队开发,在2016年 ...

  5. 微服务Spring Cloud Eureka 服务端-基本配置(eureka.server.xxx)

    2019独角兽企业重金招聘Python工程师标准>>> Eureka配置系列: Eureka 客户端-基本配置 https://my.oschina.net/langxSpirit/ ...

  6. 微服务 Spring Cloud Alibaba 项目搭建(三、common通用模块创建)

    一.项目 - New - Module 二.选择Maven - jdk- Next 三.修改Name为common - 查看GroupId是否正确 - Finish 四.修改pom.xml文件,放入通 ...

  7. 微服务Spring Boot 整合 Redis 实现 好友关注

    文章目录 ⛅引言 一.Redis 实现好友关注 -- 关注与取消关注 二.Redis 实现好友关注 -- 共同关注功能 ⛵小结 ⛅引言 本博文参考 黑马 程序员B站 Redis课程系列 在点评项目中, ...

  8. 猿创征文 | 微服务 Spring Boot 整合Redis 实战开发解决高并发数据缓存

    文章目录 一.什么是 缓存? ⛅为什么用缓存? ⚡如何使用缓存 二.实现一个商家缓存 ⌛环境搭建 ♨️核心源码 ✅测试接口 三.采用 微服务 Spring Boot 注解开启缓存 ✂️@CacheEn ...

  9. java版b2b2c社交电商分布式微服务-Spring Cloud Netflix

    该项目通过自动配置为Spring Boot应用程序提供Netflix OSS集成,并绑定到Spring环境和其他Spring编程模型成语.通过几个简单的注释,您可以快速启用和配置应用程序中的常见模式, ...

最新文章

  1. 解决Linux安装过程中不能安装Grub的问题
  2. ArduinoIDE安装与配置与第一个程序的烧录和运行——人人都能玩硬件
  3. freopen()的重定向打开或者关闭
  4. 作为一个有理想的程序员,必读的书都有哪些?
  5. Activiti中的高级脚本:自定义配置注入
  6. 注册assembly的问题
  7. 左右xcode的重构选项的一些理解
  8. download在线下载源码
  9. Python之路,Day2 - Python基础,列表,循环
  10. 在构造函数中的setData和getData
  11. sharepoint搭建文档服务器,SharePoint Server教程
  12. MSFConsole 学习记录
  13. EXCEL表格中数字金额很大时后面零很多,如何设置直接以万元为单位显示,不显示后面的零
  14. 4.Scanner类、Random类、ArrayList 类
  15. obj-c编程11:内存管理和ARC(自动引用计数)
  16. JSON学习思维导图
  17. 2023年 ZZU ACM 招新赛暨选拔赛题解
  18. Gym - 101853E E. Maximum Sum (状压DP)
  19. 西门子S7-1200系列PLC定时器指令
  20. XSS跨站脚本攻击与CSRF跨站请求伪造攻击的学习总结

热门文章

  1. 关键字 常量 (注意事项)
  2. 一看就懂的ReactJs入门教程(精华版)
  3. 通过docker安装ElasticSearch并与PHP结合使用
  4. 数据中心冷却的绿色解决方案
  5. 基于深度学习的高精度牙齿健康检测识别系统(PyTorch+Pyside6+YOLOv5模型)
  6. css修改input样式
  7. Linux(二十)服务器网络知识- 网络配置
  8. 等保测评2.0—防火墙测评记录
  9. JS 中原型和原型链深入理解
  10. 在视频的左上角动态显示帧数、参看帧率