0%

springcloud业务演示

说明

  • 上篇文章 主要介绍了spring cloud的基本概念和工程结构,本编开始实践演练

业务场景

下单服务:

  • 前端传递用户id和商品id

  • 判断用户是否存在以及账户是否有足够的金额

  • 判断商品是否存在以及库存是否足够

  • 生成订单

创建APP模块

  • pom.xml
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
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.example</groupId>
<artifactId>shop-parent</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>

<artifactId>shop-app</artifactId>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.example</groupId>
<artifactId>shop-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

  • 配置文件:src-resource-application.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
spring:
application:
name: shop-app
datasource:
password: root
username: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/shop?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
server:
port: 8004

mybatis-plus:
global-config:
db-config:
table-prefix: shop_xxxxxxxxxx spring: application:   name: shop-app datasource:   password: root   username: 123456   driver-class-name: com.mysql.cj.jdbc.Driver   url: jdbc:mysql://localhost:3306/shop?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTCserver: port: 8004mybatis-plus: global-config:   db-config:     table-prefix: shop_spring: application:   name: shop-appserver: port: 8004
  • 启动类
1
2
3
4
5
6
7
8
9
10
11
12
package xyz.shi.shop.app;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class App {

public static void main(String[] args) {
SpringApplication.run(App.class,args);
}
}

用户微服务 提供用户查询服务

dao

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package xyz.shi.shop.user.config;

import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@MapperScan("xyz.shi.shop.user.mapper")
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return mybatisPlusInterceptor;
}
}

1
2
3
4
5
6
7
8
package xyz.shi.shop.user.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import xyz.shi.shop.user.pojo.User;

public interface UserMapper extends BaseMapper<User> {
}

service层

1
2
3
4
5
6
7
8
package xyz.shi.shop.user.service;

import xyz.shi.shop.common.Result;

public interface UserService {

Result findUser(Long id);
}
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
package xyz.shi.shop.user.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import xyz.shi.shop.common.Result;
import xyz.shi.shop.common.user.UserBO;
import xyz.shi.shop.user.mapper.UserMapper;
import xyz.shi.shop.user.pojo.User;
import xyz.shi.shop.user.service.UserService;

@Service
public class UserServiceImpl implements UserService {

@Autowired
private UserMapper userMapper;

@Override
public Result findUser(Long id) {
User user = userMapper.selectById(id);
if (user == null){
return Result.success(null);
}
UserBO userBO = new UserBO();
userBO.setAccount(user.getAccount());
userBO.setId(user.getId());
return Result.success(userBO);
}
}
  • common模块下:
1
2
3
4
5
6
7
8
9
package xyz.shi.shop.common.user;
import lombok.Data;
import java.math.BigDecimal;

@Data
public class UserBO {
private Long id;
private BigDecimal account;
}

Controller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package xyz.shi.shop.user.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import xyz.shi.shop.common.Result;
import xyz.shi.shop.user.service.UserService;

@RestController
@RequestMapping("user")
public class UserController {

@Autowired
private UserService userService;

@GetMapping("findUser/{id}")
public Result findUser(@PathVariable("id") Long id) {
return userService.findUser(id);
}
}

商品微服务,提供商品查询服务

dao

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package xyz.shi.shop.goods.config;

import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@MapperScan("xyz.shi.shop.goods.mapper")
public class MybatisPlusConfig {

@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return mybatisPlusInterceptor;
}
}

1
2
3
4
5
6
7
package xyz.shi.shop.goods.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import xyz.shi.shop.goods.pojo.Goods;

public interface GoodsMapper extends BaseMapper<Goods> {
}

service层

1
2
3
4
5
6
7
8
package xyz.shi.shop.goods.service;

import xyz.shi.shop.common.Result;

public interface GoodsService {

Result findGoodsById(Long id);
}
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
package xyz.shi.shop.goods.service.impl;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import xyz.shi.shop.common.Result;
import xyz.shi.shop.common.goods.GoodsBO;
import xyz.shi.shop.goods.mapper.GoodsMapper;
import xyz.shi.shop.goods.pojo.Goods;
import xyz.shi.shop.goods.service.GoodsService;

@Service
public class GoodsServiceImpl implements GoodsService {

@Autowired
private GoodsMapper goodsMapper;

@Override
public Result findGoodsById(Long id) {
Goods goods = goodsMapper.selectById(id);
GoodsBO goodsBO = new GoodsBO();
BeanUtils.copyProperties(goods,goodsBO);
return Result.success(goodsBO);
}
}
  • common模块下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package xyz.shi.shop.common.goods;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.math.BigDecimal;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class GoodsBO {

private Long id;

private String goodsName;

private BigDecimal goodsPrice;

private Integer goodsStock;
}

Controller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package xyz.shi.shop.goods.Controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import xyz.shi.shop.common.Result;
import xyz.shi.shop.goods.service.GoodsService;

@RestController
@RequestMapping("goods")
public class GoodsController {

@Autowired
private GoodsService goodsService;

@GetMapping("findGoods/{id}")
public Result findGoods(@PathVariable("id") Long id){
return goodsService.findGoodsById(id);
}
}

订单微服务,提供生成订单服务

dao

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package xyz.shi.shop.order.config;

import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@MapperScan("xyz.shi.shop.order.mapper")
public class MybatisPlusConfig {

@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return mybatisPlusInterceptor;
}
}
1
2
3
4
5
6
7
package xyz.shi.shop.order.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import xyz.shi.shop.order.pojo.Order;

public interface OrderMapper extends BaseMapper<Order> {
}

service

1
2
3
4
5
6
7
8
9
10
package xyz.shi.shop.order.service;


import xyz.shi.shop.common.Result;
import xyz.shi.shop.order.pojo.Order;

public interface OrderService {

public Result createOrder(Order orderParams);
}
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
package xyz.shi.shop.order.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import xyz.shi.shop.common.Result;
import xyz.shi.shop.order.mapper.OrderMapper;
import xyz.shi.shop.order.pojo.Order;
import xyz.shi.shop.order.service.OrderService;
import org.apache.commons.lang3.RandomUtils;

@Service
public class OrderServiceImpl implements OrderService {

@Autowired
private OrderMapper orderMapper;
@Override
public Result createOrder(Order orderParams) {
Order order = new Order();
order.setCreateTime(System.currentTimeMillis());
order.setGoodsId(orderParams.getGoodsId());
order.setUserId(orderParams.getUserId());
order.setOrderPrice(orderParams.getOrderPrice());
order.setOrderId(System.currentTimeMillis()+""+orderParams.getUserId()+ ""+RandomUtils.nextInt(1000,9999));
order.setOrderStatus(0);
order.setPayStatus(0);
order.setPayTime(-1L);
this.orderMapper.insert(order);
return Result.success(order.getOrderId());
}
}

下单业务

1
2
3
4
5
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.76</version>
</dependency>

dao

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package xyz.shi.shop.app.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

@Configuration
public class RestTemplateConfig {

@Bean
public RestTemplate restTemplate(ClientHttpRequestFactory requestFactory){
return new RestTemplate(requestFactory);
}

@Bean
public ClientHttpRequestFactory requestFactory(){
return new SimpleClientHttpRequestFactory();
}
}

service

1
2
3
4
5
6
7
8
package xyz.shi.shop.app.service;

import xyz.shi.shop.app.popj.BuyParams;
import xyz.shi.shop.common.Result;

public interface BuyService {
Result submitOrder(BuyParams buyParams);
}
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
58
59
60
61
package xyz.shi.shop.app.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import xyz.shi.shop.app.popj.BuyParams;
import xyz.shi.shop.app.service.BuyService;
import xyz.shi.shop.common.Result;
import xyz.shi.shop.common.goods.GoodsBO;
import xyz.shi.shop.common.user.UserBO;
import xyz.shi.shop.order.pojo.Order;

import java.math.BigDecimal;
import java.util.Map;

@Service
public class BuyServiceImpl implements BuyService {
@Autowired
private RestTemplate restTemplate;

@Override
public Result submitOrder(BuyParams buyParams) {
String userResult = restTemplate.getForObject("http://localhost:8001/user/findUser/" + buyParams.getUserId(), String.class);
Result<UserBO> userBOResult = JSON.parseObject(userResult,new TypeReference<Result<UserBO>>(){});
if (userBOResult == null || !userBOResult.isSuccess() || userBOResult.getData() == null){
return Result.fail(10001,"用户不存在");
}
UserBO userBO = userBOResult.getData();

String goodsResult = restTemplate.getForObject("http://localhost:8002/goods/findGoods/" + buyParams.getGoodsId(), String.class);
Result<GoodsBO> goodsBOResult = JSON.parseObject(goodsResult,new TypeReference<Result<GoodsBO>>(){});

if (goodsBOResult == null || !goodsBOResult.isSuccess() || goodsBOResult.getData() == null){
return Result.fail(10002,"商品不存在");
}
GoodsBO goodsBO = (GoodsBO) goodsBOResult.getData();
Integer goodsStock = goodsBO.getGoodsStock();
if (goodsStock < 0){
return Result.fail(10003,"商品库存不足");
}
BigDecimal goodsPrice = goodsBO.getGoodsPrice();
BigDecimal account = userBO.getAccount();
if (account.compareTo(goodsPrice) < 0){
return Result.fail(10004,"余额不足");
}
Order orderParams = new Order();
orderParams.setUserId(userBO.getId());
orderParams.setGoodsId(goodsBO.getId());
orderParams.setOrderPrice(goodsBO.getGoodsPrice());
String orderResult = restTemplate.postForObject("http://localhost:8003/order/createOrder", orderParams, String.class);
Result<String> orderResultString = JSON.parseObject(orderResult,new TypeReference<Result<String>>(){});
if (orderResultString == null || !orderResultString.isSuccess()){
return Result.fail(10005,"下单失败");
}
String orderId = orderResultString.getData();

return Result.success(orderId);
}
}

Controller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package xyz.shi.shop.app.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import xyz.shi.shop.app.popj.BuyParams;
import xyz.shi.shop.app.service.BuyService;
import xyz.shi.shop.common.Result;

@RestController
@RequestMapping("buy")
public class BuyController {

@Autowired
private BuyService buyService;

@PostMapping("submit")
private Result submitOrder(@RequestBody BuyParams buyParams){
return buyService.submitOrder(buyParams);
}
}

  • 实体类
1
2
3
4
5
6
7
8
9
10
11
package xyz.shi.shop.app.popj;

import lombok.Data;

@Data
public class BuyParams {

private Long userId;

private Long goodsId;
}

测试

  • 分别把各自模块下的XXApp.java启动,在idea中就可启动

image-20240327170052020

  • 测试结果如下
1
2
3
4
5
6
7
8
9
10
11
import requests

header = {"content-type": "application/json",}
data = {"userId": 1, "goodsId": 1111}
t = requests.post("http://localhost:8004/buy/submit", json=data, headers=header)
s = t.text
print(s)


{"success":true,"code":10001,"msg":"用户不存在","data":null}

总结

  • 本次代码在这里
  • 从上述的代码 可以看出,下单业务 调用各个微服务的时候 极其不方便。一旦服务提供方 更改ip,端口,接口名称等,服务消费方 也需要跟着变,如果服务提供方有多台服务器呢?服务消费方还得需要维护这些ip信息,甚至自己实现负载均衡。这时候 就需要 服务治理