博主随记供大家参考
目录
前言
由于之前几天忙于过年、串门。文章的更新是在是很难挤出时间来,再加上因为一个案例的项目出现了各种各样的问题使得效率真的是非常非常的低,在这几天练习“科目二”之后的空闲时间终于将这个demo案例给写完了,真的是非常非常的不容易!!!
话不多说,进入正题,上菜!!!
一、案例的基本结构
使用springcloud架构,使用Feign进行远程调用,使用jdbc驱动通过mybatisplus连接数据库,同时项目集成nacos,使用了lombok中间件。
二、案例的基本内容
(图片来自于黑马程序员springcloud课程)
三、项目框架的搭建
首先需要搭建一个maven项目命名为Trade-demo,在建立子项目Account-service、Order-service、Storage-service三个,这一步很简单,大家自行搭建,此处讲的粗略一点,因为真的是有亿点点简单。
1.Trade-demo依赖pom文件内容:
代码如下(示例):
<dependencyManagement>
<dependencies>
<!--alibaba的包管理器-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2021.0.1.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--springCloud的包管理器-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>2021.0.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--springBoot的启动器的包管理器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.6.5</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.6.5</version>
</plugin>
</plugins>
</build>
2.Account-service依赖pom文件内容
<dependencies>
<!--springboot启动器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!--alibaba的服务发现,注意一定要是alibaba包下的-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-nacos-discovery</artifactId>
<version>2.2.0.RELEASE</version>
</dependency>
<!--springboot web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--服务之间的调用 openfeign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>3.1.1</version>
</dependency>
<!--jdbc驱动的依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--mybtisplus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.2</version>
</dependency>
<!--lombok依赖-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
</dependency>
</dependencies>
3.Storage-service依赖pom文件
<dependencies>
<!--springboot启动器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!--alibaba的服务发现,注意一定要是alibaba包下的-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-nacos-discovery</artifactId>
<version>2.2.0.RELEASE</version>
</dependency>
<!--springboot web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--服务之间的调用 openfeign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>3.1.1</version>
</dependency>
<!--jdbc驱动的依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--mybtisplus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.2</version>
</dependency>
<!--lombok依赖-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
</dependency>
</dependencies>
4.Order-service依赖pom文件
<dependencies>
<!--springboot启动器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!--alibaba的服务发现,注意一定要是alibaba包下的-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-nacos-discovery</artifactId>
<version>2.2.0.RELEASE</version>
<exclusions>
<exclusion>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--loadbalancer-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-loadbalancer</artifactId>
</dependency>
<!--springboot web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--服务之间的调用 openfeign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>3.1.1</version>
</dependency>
<!--jdbc驱动的依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--mybtisplus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.2</version>
</dependency>
<!--lombok依赖-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
</dependency>
5.注意事项
其实在依赖的配置方面,博主建议大家自行配置。适当的参考我的配置,其实当你自己进行配置的时候可以发现很多的问题,也能够学到很多的东西。本文的配置由博主查阅自行配置。在起初我进行配置的时候引入的是mybatis的依赖,后来发现报错mapper层的依赖注入为空,含泪解决问题花了半个小时,发现是依赖的问题应该是mybatisplus的依赖,真的是拴扣。但我觉得通过这种自己配置会让我对项目有更深的理解和帮助。
注意jdbc驱动需要自行下载!!
四、建立数据库
1.新建数据库
新建数据库为springcloud-demo
2.新建数据表
(建表资源内容来自于黑马课程资料,博主自己写的没有记下来)
/*
Navicat Premium Data TransferSource Server : local
Source Server Type : MySQL
Source Server Version : 50622
Source Host : localhost:3306
Source Schema : seata_demoTarget Server Type : MySQL
Target Server Version : 50622
File Encoding : 65001Date: 24/06/2021 19:55:35
*/SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;-- ----------------------------
-- Table structure for account_tbl
-- ----------------------------
DROP TABLE IF EXISTS `account_tbl`;
CREATE TABLE `account_tbl` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`money` int(11) UNSIGNED NULL DEFAULT 0,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = COMPACT;-- ----------------------------
-- Records of account_tbl
-- ----------------------------
INSERT INTO `account_tbl` VALUES (1, 'user202103032042012', 1000);-- ----------------------------
-- Table structure for order_tbl
-- ----------------------------
DROP TABLE IF EXISTS `order_tbl`;
CREATE TABLE `order_tbl` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`commodity_code` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`count` int(11) NULL DEFAULT 0,
`money` int(11) NULL DEFAULT 0,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = COMPACT;-- ----------------------------
-- Records of order_tbl
-- ------------------------------ ----------------------------
-- Table structure for storage_tbl
-- ----------------------------
DROP TABLE IF EXISTS `storage_tbl`;
CREATE TABLE `storage_tbl` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`commodity_code` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`count` int(11) UNSIGNED NULL DEFAULT 0,
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `commodity_code`(`commodity_code`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = COMPACT;-- ----------------------------
-- Records of storage_tbl
-- ----------------------------
INSERT INTO `storage_tbl` VALUES (1, '100202003032041', 10);SET FOREIGN_KEY_CHECKS = 1;
四、编写Account-service项目内容
1.编写配置文件application.yml
server:
port: 8886 #启动端口
spring:
application:
name: account-service #服务名
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848 #nacos注册中心地址
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql:///springboot_demo?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&useSSL=false
username: root
password: 123456
mybatis-plus:
configuration:
map-underscore-to-camel-case: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
logging:
level:
org.springframework.cloud.alibaba.seata.web: debug
pattern:
dateformat: MM-dd HH:mm:ss:SSS
2.编写controller层
新建类AccountController内容如下:
package flypig.controller;
import flypig.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class AccountController {
//依赖注入
@Autowired
private AccountService accountService;
//这里要注意使用requestParam注解进行映射,因为如果不指定映射,在你启动项目
//访问路径的时候会发生报错money的值为空,系统会混淆不知道路径参数userId对应的
//是形参userId还是形参money
@PutMapping("/{userId}/{money}")
public ResponseEntity<Void> duct(@RequestParam("userId") String userId,@RequestParam("money") Integer money){
accountService.ductMoney(userId,money);
return ResponseEntity.noContent().build();
}
}
3.编写service层
新建接口为:AccountService
package flypig.service;
public interface AccountService {
void ductMoney(String userId, Integer money);
}
新街类为:AccountServiceImpl
package flypig.service.serviceimpl;
import flypig.mapper.AccountMapper;
import flypig.service.AccountService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Slf4j
@Service
//注意service的注解是加在实现类上面而不是接口上面
public class AccountServiceImpl implements AccountService {
//进行mapper的依赖注入
@Autowired
private AccountMapper accountMapper;
@Override
public void ductMoney(String userId, Integer money) {
log.info("扣款开始");
try {
accountMapper.ductMoneyImplement(userId,money);
} catch (Exception e) {
throw new RuntimeException("扣款失败",e);
}
log.info("扣款成功");
}
}
4.编写mapper层
新建接口为AccountMapper
package flypig.mapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Update;
@Mapper
public interface AccountMapper {
//这里也一定要使用param注解指定映射,不然会报错,因为系统不知道参数占位符应该匹配的是哪个形参
@Update("update account_tbl set money = money - ${money} where user_id = #{userId}")
void ductMoneyImplement(@Param("userId") String userId,@Param("money") Integer money);
}
五、编写Storage-service项目内容
1.编写配置文件application.yml
server:
port: 8887 #启动端口
spring:
application:
name: storage-service #服务名
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848 #nacos注册中心地址
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql:///springboot_demo?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&useSSL=false
username: root
password: 123456
mybatis-plus:
configuration:
map-underscore-to-camel-case: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
logging:
level:
org.springframework.cloud.alibaba.seata.web: debug
pattern:
dateformat: MM-dd HH:mm:ss:SSS
2.编写controller层
新建类为StorageController
package flypig.controller;
import flypig.service.StorageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class StorageController {
@Autowired
private StorageService storageService;
@RequestMapping("/{commodityCode}/{count}")
public ResponseEntity<Void> ductStorage(@RequestParam("commodityCode") String commodityCode,
@RequestParam("count") Integer count){
storageService.ductStorageService(commodityCode,count);
return ResponseEntity.noContent().build();
}
}
3.编写service层
新建接口StorageService
public interface StorageService {
void ductStorageService(String commodityCode,Integer count);
}
新建类StorageServiceImpl实现接口Storageservice
package flypig.service.serviceImpl;
import flypig.mapper.StorageMapper;
import flypig.service.StorageService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
@Slf4j
public class StorageServiceImpl implements StorageService {
@Autowired
private StorageMapper storageMapper;
@Override
public void ductStorageService(String commodityCode, Integer count) {
log.info("扣减库存开始");
try {
storageMapper.ductStorageMapper(commodityCode,count);
} catch (Exception e) {
throw new RuntimeException("扣减库存出现错误",e);
}
log.info("扣减库存成功");
}
}
4.编写mapper层
新建接口StorageMapper
package flypig.mapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Update;
import org.springframework.web.bind.annotation.RequestParam;
@Mapper
public interface StorageMapper {
@Update("update storage_tbl set count = count - ${count} where commodity_code = #{commodityCode}")
void ductStorageMapper(@Param("commodityCode") String commodityCode,
@Param("count") Integer count);
}
六、编写Order-service项目内容
1.编写配置文件application.yml
server:
port: 8888 #启动端口
spring:
application:
name: order-service #服务名
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848 #注册中心地址,nacos服务
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql:///springboot_demo?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&useSSL=false
username: root
password: 123456
mybatis-plus:
configuration:
map-underscore-to-camel-case: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
logging:
level:
org.springframework.cloud.alibaba.seata.web: debug
pattern:
dateformat: MM-dd HH:mm:ss:SSS
2.新建实体类Order
package flypig.entity;
import lombok.Data;
@Data
public class Order {
private Long id;
private String userId;
private String commodityCode;
private Integer count;
private Integer money;
}
3.编写Feign远程调用接口AccountClient
新建Feign远程调用接口AccountClient
package flypig.client;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestParam;
@FeignClient(value = "account-service")
public interface AccountClient {
@PutMapping("/{userId}/{money}")
ResponseEntity<Void> duct(@RequestParam("userId") String userId,@RequestParam("money") Integer money);
}
4.编写Feign远程调用接口StorageClient
新建接口StorageClient
package flypig.client;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
@FeignClient(value = "storage-service")
public interface StorageClient {
@RequestMapping("/{commodityCode}/{count}")
public ResponseEntity<Void> ductStorage(@RequestParam("commodityCode") String commodityCode,
@RequestParam("count") Integer count);
}
5.编写controller层
新建类OrderController内容如下:
package flypig.controller;
import flypig.entity.Order;
import flypig.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class OrderController {
@Autowired
private OrderService orderService;
@GetMapping("/order")
public ResponseEntity<Long> createOrder(Order order){
Long result = orderService.createOrderService(order);
return ResponseEntity.status(200).body(result);
}
}
6.编写service层
新建接口为:OrderService
package flypig.service;
import flypig.entity.Order;
import org.springframework.stereotype.Service;
public interface OrderService {
Long createOrderService(Order order);
}
新建类为:OrderServiceImpl
package flypig.service.impl;
import flypig.client.AccountClient;
import flypig.client.StorageClient;
import flypig.entity.Order;
import flypig.mapper.OrderMapper;
import flypig.service.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Slf4j
@Service
public class OrderServiceImpl implements OrderService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private AccountClient accountClient;
@Autowired
private StorageClient storageClient;
@Override
public Long createOrderService(Order order) {
orderMapper.createOrderMapper(order);
log.info("订单插入完成,开始扣款");
try {
accountClient.duct(order.getUserId(),order.getMoney());
} catch (Exception e) {
throw new RuntimeException("用户扣款出现问题",e);
}
log.info("用户扣款成功,开始扣减库存");
try {
storageClient.ductStorage(order.getCommodityCode(),order.getCount());
} catch (Exception e) {
throw new RuntimeException("扣减库存出现问题",e);
}
log.info("扣减库存成功");
return order.getId();
}
}
7.编写mapper层
新建接口为OrderMapper
package flypig.mapper;
import flypig.entity.Order;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface OrderMapper {
//在配置文件中进行配置,进行了下换线的转换,直接使用类进行封装,更加的优雅
@Insert("insert into order_tbl (id,user_id,commodity_code,count,money)" +
" values (#{id},#{userId},#{commodityCode},#{count},#{money})")
void createOrderMapper(Order order);
}
七、使用postman进行测试
启动服务测试之前需要先启动nacos客户端,否则在项目启动时会进行报错。
使用如下参数进行测试,测试成功后会返回id的值。
总结
经过漫长的编写,也是终于完成了demo案例的搭建,属实是不易,因为还有好多好多细节和需要注意的点,但是文章已经很长了所以就不在添加负担了,主要太晚了,博主想要早一点睡觉,今天与商店老爷爷(老deng)唠嗑花费了太长的时间,要不然十点就能竣工,结果硬生生十一点才记录完,真的是裂开!!!!
峰回路转,本文内容简单,博主随记,供大家参考,肯定存在很多的不足,希望大家不要在意,有什么问题和指教可以评论,博主会及时回复的殴。