SaaS平台开发实战(三):用户服务模块

在上一章我们创建了基础服务模块,为其他模块提供基础支撑,包括日志、标签、租户、系统设置、数据字典等基础服务。

这一章我们将创建用户服务模块,主要提供客户、平台管理账户、商户等服务。

创建saasdemo-user模块

创建saasdemo-user模块

修改user模块pom.xml

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

    <artifactId>saasdemo-user</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.example</groupId>
            <artifactId>saasdemo-core</artifactId>
            <version>${project.version}</version>
        </dependency>
    </dependencies>
    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                    <configuration>
                        <jvmArguments>-Dfile.encoding=UTF-8</jvmArguments>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
</project>

创建namespace

创建user模块namespace

创建应用入口

package org.example.saas.user;

import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
@EnableDiscoveryClient
@ComponentScan(value = {
        "com.chia.multienty.core",
        "org.example.saas.core",
        "org.example.saas.user",
})
@EnableDubbo
@MapperScan(value={"com.chia.multienty.core.mapper","org.example.saas.core.mapper"})
public class UserApplication {
    public static void main(String[] args) {
        System.setProperty("dubbo.application.logger","slf4j");
        ConfigurableApplicationContext context = SpringApplication.run(UserApplication.class, args);

    }
}

创建dubbo配置

首先在saasdemo-core中增加如下空接口,后面再填充

创建DubboReferenceConfiguration

package org.example.saas.user.config;

import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.spring.ReferenceBean;
import org.example.saas.core.dubbo.service.DubboMasterService;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@ConditionalOnProperty(prefix = "dubbo", name = "enabled", havingValue = "true")
public class DubboReferenceConfiguration {

    @Bean
    @DubboReference(timeout = 5000)
    public ReferenceBean<DubboMasterService> dubboMasterServiceReferenceBean() {
        return new ReferenceBean<>();
    }

    @Bean
    public DubboMasterService dubboMasterService(ReferenceBean<DubboMasterService> dubboMasterServiceReferenceBean) {
        DubboMasterService dubboMasterService = dubboMasterServiceReferenceBean.getObject();
        return dubboMasterService;
    }
}

在saasdemo-master模块中实现dubboMasterService接口

实现DubboMasterServiceImpl

package org.example.saas.master.dubbo.service.impl;

import lombok.RequiredArgsConstructor;
import org.apache.dubbo.config.annotation.DubboService;
import org.example.saas.core.dubbo.service.DubboMasterService;


@DubboService
@RequiredArgsConstructor
public class DubboMasterServiceImpl implements DubboMasterService {

}

Ok, 现在用户模块构造完成,开始添加配置


切换到nacos后台

创建saasdemo-user-dev.yml

spring:
    shardingSphere:
        # 开启分片
        enabled: true
    rabbitmq:
        # 禁用rabbitmq, 后面章节需要用到的时候再开放
        enabled: false
    datasource:
        type: com.alibaba.druid.pool.DruidDataSource
        dynamic:
            enabled: true
            # 设置默认数据源为分片数据源
            primary: ds_master
            datasource:
                ds_master:
                    driver-class-name: com.mysql.cj.jdbc.Driver
                    url: jdbc:mysql://xxx.cn:3301/saas_master?autoReconnect=true&useUnicode=true&allowMultiQueries=true&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true
                    username: saas_master
                    password: xxxxx
                # root帐号主要用于flyway进行数据迁移时自动授权,也可以不配置,但是需要先手动授权,否则会报错
                ds_root:
                    driver-class-name: com.mysql.cj.jdbc.Driver
                    url: jdbc:mysql://xxxx.com:3333/mysql?autoReconnect=true&useUnicode=true&allowMultiQueries=true&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true
                    username: root
                    password: xxxxxxx


    kuta:
        multi-tenant:
            user-module-enabled: true
            domain: user.xxx.com
            security:
                auth:
                    header: X-TOKEN
                    token-prefix: USER
                    base64-secret: 5LmQ6IGa5oOg5piv5LiA5Liq5aW9563667uf5ZWK5aW957O757uf6K+35rOf7zSP5LiN6KaB5Zyo5LiK6Z2i5Y+R5biD6L+d5rOV5L+h5oGv6L+Z5qC3566h55CG5ZGY5Lmf5LiN5aW95aSE55CG55qE
                    # 令牌持有时间(秒)
                    token-holding-time: 86400
                    # 客户持有令牌时间,-1永久
                    customer-token-time: 86400
                    # 续期时长
                    renew-time: 86400
                    # 是否支持多点登陆
                    multipoint-login-enabled: true
                    ignore-paths:
                        - /file/upload
                rsa:
                    # 请根据自身情况设置
                    private-key: xxxxxx
                    public-key: xxxx==
            file:
                # 大写
                storage-mode: LOCAL
                custom:
                    custom-file-upload-service-impl-class: org.example.saas.core.strategy.file.impl.QNYFileUploadServiceImpl
                local:
                    path-prefix: C:\projects\multienty\store
                    url-prefix: https://${spring.kuta.multi-tenant.domain}/local/

        code-generator:
            author: "Multi Tenant Auto Generator"
            root-package: org.example.saas
            common-module-name: saasdemo-core
            table-prefix: saas_
            # 设置controller类放置模块名称
            controller-module-name: saasdemo-user
            # controller save path=project-path(user.dir) + "/" + controller-module-name + controller-file-path-suffix
            controller-file-path-suffix: /src/main/java/org/example/saas/user/controller
            dto-file-path-suffix: /src/main/java/org/example/saas
            # AUTO, NONE, INPUT, ASSIGN_ID, ASSIGN_UUID
            id-type: INPUT
            logic-delete-column-name: deleted
            dto-full-package-name: org.example.saas.core.domain.dto
            table-fills:
                version: INSERT
                create_time: INSERT
                update_time: UPDATE
                deleted: INSERT
                status: INSERT
            packages:
                controller: user.controller
                entity: core.pojo
                service: core.service.user
                mapper: core.mapper
                service-impl: core.service.user.impl
                dto: core.domain.dto
                parameter: core.parameter
            formatter:
                controller: "%sController"
                entity: "%s"
                service: "%sService"
                service-impl: "%sServiceImpl"
                mapper: "%sMapper"
                xml: "%sMapper"
            database:
                host: xxxx.com
                port: 3333
                db-name: saas_user_1
                username: saas_user_1
                password: xxxxx
            package-merge-mapping:
                Customer: user
                CustomerWx: user
                CustomerAddress: user
                CustomerBalance: user
                BalanceBill: user
            tables:
                - saas_customer
                - saas_customer_wx
                - saas_customer_address
                - saas_customer_balance
                - saas_balance_bill

创建shardingsphere-saasdemo-user.yml

spring:
    shardingsphere:
        enabled: true
        dataSource:
            common:
                type: com.alibaba.druid.pool.DruidDataSource
                validationQuery: SELECT 1 FROM DUAL
            names:
                ds_user_1, ds_user_2
            ds_user_1:
                type: com.alibaba.druid.pool.DruidDataSource
                driverClassName: com.mysql.cj.jdbc.Driver
                url: jdbc:mysql://xxxx:3333/saas_user_1?autoReconnect=true&useUnicode=true&allowMultiQueries=true&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true
                username: saas_user_1
                password: xxxxx
            ds_user_2:
                type: com.alibaba.druid.pool.DruidDataSource
                driverClassName: com.mysql.cj.jdbc.Driver
                url: jdbc:mysql://xxxx:3333/saas_user_2?autoReconnect=true&useUnicode=true&allowMultiQueries=true&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true
                username: saas_user_2
                password: xxxxx
        rules:
            sharding:
                tables:
                    saas_customer:
                        actualDataNodes: ds_user_${1..2}.saas_customer
                    saas_balance_bill:
                        actualDataNodes: ds_user_${1..2}.saas_balance_bill
                    saas_customer_address:
                        actualDataNodes: ds_user_${1..2}.saas_customer_address
                    saas_customer_balance:
                        actualDataNodes: ds_user_${1..2}.saas_customer_balance
                    saas_customer_wx:
                        actualDataNodes: ds_user_${1..2}.saas_customer_wx
                shardingAlgorithms:
                    user-db-inline:
                        type: INLINE
                        props: 
                            algorithm-expression: ds_user_${tenant_id % 2 + 1 }

                defaultDatabaseStrategy:
                    standard:
                        shardingColumn: tenant_id
                        shardingAlgorithmName: user-db-inline
                bindingTables:
                    - saas_customer, saas_customer_address, saas_customer_balance, saas_customer_wx
        props:
            sql-show: true

在前期我们并未开启调试,所以有一些公用配置并未配置,现在我们将这些公用配置都配置一下

sms.yml

spring:
    sms:
        enabled: true
        active: aliyun
        #阿里云短信
        aliyun:
            #区域id,参考 https://help.aliyun.com/document_detail/40654.html?spm=a2c6h.13066369.0.0.c85c7eecnh6fH6
            region-id: cn-chengdu
            #产品名称:云通信短信API产品,开发者无需替换
            name: Dysmsapi
            #产品域名,开发者无需替换
            domain: dysmsapi.aliyuncs.com
            #产品keyid
            key-id: XXXXX
            #产品keysecret
            key-secret: XXXXX
            #短信签名
            sign-name: 百灵鸟
            #读取超时时间
            read-timeout: 10000
            #连接超时时间
            connect-timeout: 10000
            #运行模式 debug:调试模式(返回9999),release:发布模式,将实际发送短信
            running-mode: release
            #短信模板编号
            templates:
                #登陆验证码
                verification-code: SMS_26700XXXX

rabbitmq.yml

  spring:
    rabbitmq:
      host: xxx.xxx.xxx.xxx
      port: 10086
      username: xxxx
      password: xxxxx
      virtual-host: /
      publisher-confirm-type: correlated
      publisher-returns: true
      retry-execute-cron: "0 0/1 * * * ? "
      # 每三分钟从数据库加载需要发送的Rabbit消息
      reload-from-db-interval: 180000
      retry-running: true
      # 每超过1分钟重发一次
      resubmit-threshold: 60000
      # 重试的时候从缓存中删除阈值,超过(N * retry-threshold)则从缓存中删除
      retry-remove-threshold: 5
      #虚拟主机,使用server默认host
      #virtual-host: JCcccHost
      listener:
        simple:
          # 并行消费数量 格式:N/M-N
          concurrency: 1
          #手动确认模式
          acknowledge-mode: manual
          retry:
            enabled: true
            #最大重试次数
            max-attempts: 10
            # 重试最大间隔时间
            max-interval: 10000
            # 重试初始间隔时间
            initial-interval: 2000
            # 间隔时间乘子,间隔时间*乘子=下一次的间隔时间,最大不能超过设置的最大间隔时间
            multiplier: 2

redis.yml

spring:
    redis:
        enabled: true
        host: xxx.xxx.xxx.xxx
        port: 8165
        password: xxxxx
        database: 0
        timeout: 10000
        runningRedisInitialize: false
        pingConnectionInterval: 1000
        globalPrefix: KS-
        jedis:
            pool:
                max-active: 6000
                max-wait: 1000
                max-idle: 400
                min-idle: 0

以上公用配置的host、port、username 、password等均替换成您自己的配置即可

现在回到idea,创建以下文件和目录

saasdemo-user配置文件

application.yml

spring:
  profiles:
    active: dev

dubbo.application.logger: slf4j

bootstrap.yml

server:
  port: 8881

spring:
  application:
    name: saasdemo-user
  cloud:
    nacos:
      discovery:
        server-addr: nacos.xxx.com:xxxx
        namespace: xxxxx
        username: xxxx
        password: xxxx
      config:
        server-addr: nacos.xxxx.cn:xxxx
        namespace: xxxxx
        username: xxxx
        password: xxxx
        file-extension: yml
        extension-configs[0]:
          data-id: shardingsphere-saasdemo-user.yml
          group: DEFAULT_GROUP
          refresh: true
        extension-configs[1]:
          data-id: kuta-multi-tenant.yml
          group: DEFAULT_GROUP
          refresh: true
        extension-configs[2]:
          data-id: redis.yml
          group: DEFAULT_GROUP
          refresh: true
        extension-configs[3]:
          data-id: rabbitmq.yml
          group: DEFAULT_GROUP
          refresh: true
seata:
  enabled: true
  application-id: seata-server
  # 客户端和服务端在同一个事务组; Seata 事务组编号,用于 TC 集群名, 一定要和 config.tx(nacos) 中配置的相同
  tx-service-group: tx_user_group
  # 自动数据源代理
  enable-auto-data-source-proxy: false
  # 数据源代理模式(分布式事务方案)
  data-source-proxy-mode: AT
  service:
    vgroup-mapping:
      tx_user_group: default
  config:
    # support: nacos, consul, apollo, zk, etcd3, file
    type: nacos
    nacos:
      server-addr: xxxx
      namespace: xxxx
      group: SEATA_GROUP
      username: xxxx
      password: xxxxx
      data-id: seata-server.properties
      cluster: default
  registry:
    # support: nacos, eureka, redis, zk, consul, etcd3, sofa
    type: nacos
    nacos:
      server-addr: nacos.xxxx.cn:xxxx
      namespace: xxxx
      group: SEATA_GROUP
      username: xxxx
      password: xxxxx
      # 默认TC集群名
      cluster: default
      # 服务名,与服务端中registry.conf配置要一致
      application: seata-server
      context-path:

dubbo:
  enabled: true
  metadata-report:
    address: nacos://xxxx.cn:xxxx?username=${dubbo.metadata-report.username}&password=${dubbo.metadata-report.password}
    username: xxxx
    password: xxxx
    parameters:
      namespace: xxxxx
    retry-times: 30  #重试次数,默认100
    cycle-report: false #关闭定时刷新
  application:
    name: user-provider
    # 禁用QOS同一台机器可能会有端口冲突现象
    qos-enable: false
    qos-accept-foreign-ip: false
    service-discovery:
      migration: FORCE_APPLICATION # FORCE_APPLICATION,只消费应用级地址,如无地址则报错,单订阅 3.x 地址
  protocol:
    name: dubbo
    port: -1
  scan:
    base-packages: org.example.saas.user.dubbo.service.impl
  cloud:
    subscribed-services: saasdemo-master

  registry:
    address: nacos://xxxx.cn:xxxx?username=${dubbo.metadata-report.username}&password=${dubbo.metadata-report.password}
    parameters:
      namespace: xxxxxx
  consumer:
    check: false

logback-spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <!-- 日志文件存放路径 -->
    <property name="log.path" value="./logs"/>
    <!-- 日志文件输出格式 -->
    <property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger - [%method,%line] - %msg%n"/>

    <!-- 控制台输出 -->
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>${log.pattern}</pattern>
        </encoder>
    </appender>

    <!-- 系统日志输出 -->
    <appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${log.path}/sys-info.log</file>
        <!-- 循环政策:基于时间创建日志文件 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 日志文件名格式 -->
            <fileNamePattern>${log.path}/sys-info.%d{yyyy-MM-dd}.log</fileNamePattern>
            <!-- 日志最大的历史 30天 -->
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>${log.pattern}</pattern>
        </encoder>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <!-- 过滤的级别 -->
            <level>INFO</level>
            <!-- 匹配时的操作:接收(记录) -->
            <onMatch>ACCEPT</onMatch>
            <!-- 不匹配时的操作:拒绝(不记录) -->
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${log.path}/sys-error.log</file>
        <!-- 循环政策:基于时间创建日志文件 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 日志文件名格式 -->
            <fileNamePattern>${log.path}/sys-error.%d{yyyy-MM-dd}.log</fileNamePattern>
            <!-- 日志最大的历史 30天 -->
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>${log.pattern}</pattern>
        </encoder>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <!-- 过滤的级别 -->
            <level>ERROR</level>
            <!-- 匹配时的操作:接收(记录) -->
            <onMatch>ACCEPT</onMatch>
            <!-- 不匹配时的操作:拒绝(不记录) -->
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!-- 用户访问日志输出  -->
    <appender name="sys-user" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${log.path}/sys-user.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 按天回滚 daily -->
            <fileNamePattern>${log.path}/sys-user.%d{yyyy-MM-dd}.log</fileNamePattern>
            <!-- 日志最大的历史 30天 -->
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>${log.pattern}</pattern>
        </encoder>
    </appender>

    <!-- 系统模块日志级别控制  -->
    <logger name="com.chia.multienty.core" level="debug"/>
    <!-- Spring日志级别控制  -->
    <logger name="org.springframework" level="warn" />
    <!-- mybatis-plus控制日志级别 -->
    <logger name="com.baomidou.mybatisplus" level="error" />

    <root level="info">
        <appender-ref ref="console"/>
    </root>

    <!--系统操作日志-->
    <root level="info">
        <appender-ref ref="file_info"/>
        <appender-ref ref="file_error"/>
    </root>

    <!--系统用户操作日志-->
    <logger name="sys-user" level="info">
        <appender-ref ref="sys-user"/>
    </logger>
</configuration>

V1.0.0__init_ddl.sql

/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!50503 SET NAMES utf8 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;

--
-- Table structure for table `saas_customer`
--
DROP TABLE IF EXISTS `saas_customer`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `saas_customer` (
  `customer_id` bigint NOT NULL COMMENT '客户编号',
  `tenant_id` bigint NOT NULL COMMENT '租户编号',
  `nick_name` varchar(32) NOT NULL COMMENT '昵称',
  `sex` tinyint(4) DEFAULT NULL COMMENT '性别',
  `birthday` DATETIME DEFAULT NULL COMMENT '生日',
  `phone_number` varchar(11) DEFAULT NULL COMMENT '电话号码',
  `avatar_url` varchar(256) DEFAULT NULL COMMENT '头像地址',
  `in_black_list` bit(1) NOT NULL COMMENT '是否已被拉黑',
  `is_member` bit(1) NOT NULL COMMENT '是否会员',
  `member_source_type` tinyint(4) NOT NULL COMMENT '会员来源类型',
  `member_id` bigint DEFAULT NULL COMMENT '会员编号',
  `growth` int NOT NULL COMMENT '成长值',
  `credit` int NOT NULL COMMENT '积分',
  `status` varchar(32) DEFAULT NULL COMMENT '状态',
  `version` bigint NOT NULL COMMENT '乐观锁版本号',
  `create_time` datetime NOT NULL COMMENT '创建时间',
  `update_time` datetime DEFAULT NULL COMMENT '更新时间',
  PRIMARY KEY (`customer_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='客户';
/*!40101 SET character_set_client = @saved_cs_client */;




--
-- Table structure for table `saas_customer_wx`
--
DROP TABLE IF EXISTS `saas_customer_wx`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `saas_customer_wx` (
  `customer_id` bigint NOT NULL COMMENT '客户编号',
  `tenant_id` bigint NOT NULL COMMENT '租户编号',
  `wx_open_id` varchar(64) DEFAULT NULL COMMENT '微信openid',
  `wx_union_id` varchar(64) DEFAULT NULL COMMENT '微信unionid',
  `wx_nick_name` varchar(32) DEFAULT NULL COMMENT '微信昵称',
  `wx_id` varchar(48) DEFAULT NULL COMMENT '微信id',
  `access_token` varchar(128) DEFAULT NULL COMMENT '执行令牌',
  `refresh_token` varchar(128) DEFAULT NULL COMMENT '刷新令牌',
  `status` varchar(32) NOT NULL COMMENT '状态',
  `version` bigint NOT NULL COMMENT '乐观锁版本号',
  `create_time` datetime NOT NULL COMMENT '创建时间',
  `update_time` datetime DEFAULT NULL COMMENT '更新时间',
  PRIMARY KEY (`customer_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='客户微信';
/*!40101 SET character_set_client = @saved_cs_client */;


--
-- Table structure for table `saas_customer_address`
--
DROP TABLE IF EXISTS `saas_customer_address`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `saas_customer_address` (
  `address_id` bigint NOT NULL COMMENT '客户地址编号',
  `customer_id` bigint NOT NULL COMMENT '客户编号',
  `tenant_id` bigint NOT NULL COMMENT '租户编号',
  `name` varchar(32) NOT NULL COMMENT '收货人姓名',
  `phone_number` varchar(11) NOT NULL COMMENT '收货人电话',
  `region` varchar(64) NOT NULL COMMENT '地域',
  `province` varchar(64) NOT NULL COMMENT '省份',
  `city` varchar(64) NOT NULL COMMENT '城市',
  `district` varchar(64) NOT NULL COMMENT '区县',
  `street` varchar(64) DEFAULT NULL COMMENT '街道',
  `house_number` varchar(64) NOT NULL COMMENT '门牌号',
  `status` varchar(32) NOT NULL COMMENT '状态',
  `version` bigint NOT NULL COMMENT '乐观锁版本号',
  `create_time` datetime NOT NULL COMMENT '创建时间',
  `update_time` datetime DEFAULT NULL COMMENT '更新时间',
  PRIMARY KEY (`address_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='客户地址';
/*!40101 SET character_set_client = @saved_cs_client */;


--
-- Table structure for table `saas_customer_balance`
--
DROP TABLE IF EXISTS `saas_customer_balance`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `saas_customer_balance` (
  `customer_id` bigint NOT NULL COMMENT '客户编号',
  `tenant_id` bigint NOT NULL COMMENT '租户编号',
  `total` decimal(12,2) NOT NULL COMMENT '总余额',
  `usable` decimal(12,2) NOT NULL COMMENT '可用的余额',
  `frozen` decimal(12,2) NOT NULL COMMENT '冻结的余额',
  `hidden` bit(1) NOT NULL COMMENT '是否隐藏余额',
  `status` varchar(32) NOT NULL COMMENT '状态',
  `version` bigint NOT NULL COMMENT '乐观锁版本号',
  `create_time` datetime NOT NULL COMMENT '创建时间',
  `update_time` datetime DEFAULT NULL COMMENT '更新时间',
  PRIMARY KEY (`customer_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='客户余额';
/*!40101 SET character_set_client = @saved_cs_client */;



--
-- Table structure for table `saas_balance_bill`
--
DROP TABLE IF EXISTS `saas_balance_bill`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `saas_balance_bill` (
  `bill_id` bigint NOT NULL COMMENT '余额变更记录编号',
  `customer_id` bigint NOT NULL COMMENT '客户编号',
  `tenant_id` bigint DEFAULT NULL COMMENT '租户编号',
  `amount` decimal(12,2) DEFAULT NULL COMMENT '变动金额',
  `operator` bigint DEFAULT NULL COMMENT '操作者',
  `reason` varchar(50) DEFAULT NULL COMMENT '原因',
  `remark` varchar(255) DEFAULT NULL COMMENT '备注',
  `trigger` tinyint(4) DEFAULT NULL COMMENT '触发应用编号',
  `trade_id` bigint DEFAULT NULL COMMENT '交易编号',
  `before` decimal(12,2) DEFAULT NULL COMMENT '变动前余额',
  `after` decimal(12,2) DEFAULT NULL COMMENT '变动后余额',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  PRIMARY KEY (`bill_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='余额账单';
/*!40101 SET character_set_client = @saved_cs_client */;


/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

OK, 用户模块配置完成, 由于篇幅原因,这一章就不再加入调试部分章节,可能会有部分错误,下一章我们将开始自动生成用户模块的表,自动生成代码,使用postman调试接口, 敬请关注!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Multienty

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值