达实AIoT
文档中心
快速开始
  • 单点登录对接
  • 开放接口对接
  • 领域模型事件对接
  • 私有部署
  • 应用开发指南
  • DASDesign
IoT平台
应用平台
  • 低代码工具
  • 基础服务
  • 系统运维
  • 场景模型
应用
  • 物业管理
  • 数据中心
  • 智慧园区IPS
  • 园区服务
  • 物业管理
  • 场景模型
  • 会议
  • 门禁
  • 停车场
文档中心
快速开始
  • 单点登录对接
  • 开放接口对接
  • 领域模型事件对接
  • 私有部署
  • 应用开发指南
  • DASDesign
IoT平台
应用平台
  • 低代码工具
  • 基础服务
  • 系统运维
  • 场景模型
应用
  • 物业管理
  • 数据中心
  • 智慧园区IPS
  • 园区服务
  • 物业管理
  • 场景模型
  • 会议
  • 门禁
  • 停车场
期待您的声音
  1. 应用开发指南
  • 前端Web指南
  • 后端开发部署指南
  • 第三方h5应用嵌入开发指南
    • 准备工作
    • 调用宿主能力
      • 准备工作
      • 参数说明
      • API总览
      • 路由
      • 订阅消息
      • 微信支付
      • 支付宝支付
      • 通讯录
      • 分享
      • 打电话
      • 扫一扫
      • 轻提示
      • 屏幕
      • 剪切板
      • 分享图片弹窗
      • 获取位置
      • 宿主卸载队列方法
  1. 应用开发指南

后端开发部署指南

服务开发流程#

一、新建gitlab代码仓#

1. 仓库规范(推荐):#

DasAIoT(组)/EnterpriseAdmin(组)/{应用名称}(组)/{前后端}(组)/{微服务名称}(git仓库)
注意
应用名称:大的应用名称,一个应用下可能有多个git仓库
前后端:分Back-end(后端代码)和Fron-end(前端代码)
微服务名称:微服务名称
信息
以车位引导举例 ParkingGuidance
后端代码仓库:
http://gitlab.com/DasAIoT/EnterpriseAdmin/ParkingGuidance/Back-end/ParkingGuidance.git
前端代码仓库:
http://gitlab.com/DasAIoT/EnterpriseAdmin/ParkingGuidance/Fron-end/ParkingGuidance.git

2. 仓库代码推送步骤#

Git 全局设置#

创建一个新仓库#

推送现有文件夹#

推送现有的 Git 仓库#

二、项目搭建#

1. 统一版本管理#

1. 项目pom.xml#

声明版本统一由dependency进行控制
     <parent>        
        <groupId>com.das</groupId>
        <artifactId>dependency</artifactId>
        <version>3.0.0</version>
     </parent>
目前稳定版本 3.0.0

2. maven配置#

3. 直接依赖脚手架#

指定脚手架功能模块版本.项目pom.xml parent非dependency时
maven仓库地址

2. 创建业务模块#

3. 依赖脚手架功能#

3.1 基础包#

    <dependency>  
        <groupId>com.das.libcore</groupId>
        <artifactId>commons-base</artifactId>
        <version>3.0.0</version>
    </dependency>
功能简介#
简介:存放各种公共的且和Spring无关的方法类定义
使用说明#
常用公共类用处
R供Feign统一返回使用以及controller错误返回信息包装
ResultCode常用API返回对象,目前code和httpstatus绑定不能随意添加
GlobalRequestConstant全局请求信息相关key常量
ResultConstantR 字段对应字符常量
GlobalInstanceContext用来存储全局唯一实例!多个线程可共享, 主要用来解耦Spring
GlobalRequestDTO全局请求参数
TaskProgressDTO任务实体类,进度条
TaskStatusEnum进度条统一状态
ApplicationEnum应用类型枚举
UserGroupTagType用户组类型
UserTagEnum用户标签枚举
ApiException自定义API异常
BizException业务异常
AuthorizationDataUtil请求参数传递辅助类

3.2 spring封装包#

    <dependency>  
        <groupId>com.das.libcore</groupId>
        <artifactId>web-spring-boot-starter</artifactId>
        <version>3.0.0</version>
    </dependency>
功能简介#
用处:存放各种公共的且和Spring相关的方法类定义
提供功能:包括异常拦截、统一返回类R、ip工具、Spring工具、servlet工具、解析jwt载荷工具等
使用说明#
引入common-spring-boot-starter核心包依赖
相关公共类说明
类说明
IpUtilsip相关工具类,可以获取请求真实IP地址
JwtBuilderjwt工具类,可以构建jwt,目前载荷内容包括租户,用户id,姓名,是否是服务,flag
JwtInfoUtilsjwt工具类,获取全局请求参数以及进行鉴权处理
ModelUtil基本模型数据填充工具类
PageUtils分页工具类
SecureUtils加解密工具类
SensitiveInfoUtil脱敏工具类,目前只有手机号脱敏方法
ServletUtils客户端工具类
SpringUtilsspring工具类,方便在非spring管理环境中获取bean
SqlUtilsql操作工具类
StringUtils字符串工具类,包括判空 去空格 截取等字符串相关操作
TimeZoneUtils时区时间转换,针对前端时间以及后端时间响应进行转换
ActionResult返回工具类,统一使用该类进行请求结果返回
CustomMsgResultCode参数校验抛出的异常,可自定义错误描述的ResultCode
提供注解说明
注解说明
@EnableJwtInfoAnnotation在启动类或者配置类上加上注解标识需要解析jwt信息的功能,因为放在common包里,避免只需要引入common其他功能但是不需要jwt解析功能
@Sensitive用于controller层或者service层的方法上面,判断返回数据是否需要脱敏相关处理
@SensitiveInfo用于属性上面,判断相关数据是否需要加密或脱敏相关处理
@SensitiveInput用于controller层或者service层的方法上面,判断入参数据是否需要加密处理
@WebLog用于方法上面,描述日志信息
@AllowableValues状态值校验工具
@XssCheckValidXss校验
部分工具类使用说明
分页功能
在需要分页的地方使用工具类方法返回一个Page对象
com.das.libcore.web.utils.PageUtils的bulidPage(Integer pageNo, Integer pageSize)

参数说明:
     pageNo   页码(不传有默认值1)
     pageSize 页量(不传有默认值10)
数据脱敏、编解码

3.3 自动生成代码包#

    <dependency>  
        <groupId>com.das.libcore</groupId>
        <artifactId>das-generator</artifactId>
        <version>3.0.0</version>
    </dependency>
功能简介#
用处:用于根据表一键生成controller、entity、service、serviceImpl、mapper、mapper.xml等基础的类
使用说明#
1.
引入das-generator核心包依赖
2.
代码使用
3.
参数说明
参数说明
String url数据库连接url
String username数据库用户名
String password数据库密码
String schema指定的schema
String tableName表名(多个用逗号分隔)
String moduleName模块名(用于controller上面的api拼接的module,可以为空)
String middlePath中间路径 文件生成的路径是定位在项目根路径的,需要指定到具体模块下的路径
String packagePath包路径 文件生成路径 /项目路径/模块路径/包路径/
String tablePrefix忽略表前缀 例如表为das_xxx 不想要加上 das_ 则值为 das_
String tableSuffix忽略表后缀 例如表为xxx_info 不想要加上 _info 则值为 _info
4.
生成文件说明

3.4 规则引擎#

    <dependency>  
        <groupId>com.das.libcore</groupId>
        <artifactId>drools-spring-boot-starter</artifactId>
        <version>3.0.0</version>
    </dependency>
功能简介#
用处:对规则引擎的封装,存放加载规则引擎的包
使用说明#
引入drools核心包依赖
相关类说明
类说明
RuleHelper可检测规则语法规范,获取指定的规则session
RuleLoader规则加载器,动态加载规则
RuleInfoModel规则信息实体类
动态加载规则
动态检测规则
执行规则

3.5 全球化#

    <dependency>  
        <groupId>com.das.libcore</groupId>
        <artifactId>globalization-spring-boot-starter</artifactId>
        <version>3.0.0</version>
    </dependency>
功能简介#
用处:提供全球化功能
使用说明#
引入globalization-spring-boot-starter核心包依赖
需要实现获取全球化资源的接口,然后注入到Spring中,这里可以具体定义全球化资源存储方式如:mysql,redis等,现在默认实现是sqlite,可以直接使用
全球化修改返回值是通过在通用返回类设置扩展接口实现的,相关默认实现在 DefaultUpdateResultAwareImpl 类中
默认只对错误msg进行了国际化,如需要序列化特定地方的常量数据,可自行注入messageSource然后取得locale进行手动国际化

3.6 Kafka服务#

    <dependency>  
        <groupId>com.das.libcore</groupId>
        <artifactId>kafka-spring-boot-starter</artifactId>
        <version>3.0.0</version>
    </dependency>
功能简介#
用处:对kafka进行封装
使用说明#
引入kafka核心包依赖
配置kafka连接
注入Kafka工具类
发送数据
接受数据
首先加上注解@EnableKafka("alarmEventConsumer") 开启kafka,EnableKafka中的value是group,但是KafkaListenter中的group优先级更高

3.7 mqtt#

    <dependency>  
        <groupId>com.das.libcore</groupId>
        <artifactId>mqtt-spring-boot-starter</artifactId>
        <version>3.0.0</version>
    </dependency>
功能简介#
用处:对mqtt进行了封装,提供mqtt连接功能
使用说明#
引入mqtt-spring-boot-starter核心包依赖
相关类说明
类说明
MsgHandle使用订阅功能时需要继承实现的接口类,重写MsgHandle#handleMsg方法
MqttConfigurationmqtt配置类
MyMqttCallbackmqtt回调
MqttService对mqttClient简单封装,其中包括连接方法connect(),设置连接参数setMqttConnectOptions(),发布消息publish(),订阅主题subscribe(),取消订阅主题cleanTopic()
配置连接信息
使用方式
直接在需要的地方注入mqttService即可,但是如果需要使用订阅功能需要实现MsgHandler并通过mqttService.setMsgHandle(MsgHandle msgHandle)在容器启动完成注入到mqttService中如下:

3.8 pulsar消息队列#

    <dependency>  
        <groupId>com.das.libcore</groupId>
        <artifactId>pulsar-spring-boot-starter</artifactId>
        <version>3.0.0</version>
    </dependency>
功能简介#
用处:对pulsar进行了封装,提供pulsar消息队列使用
关于topic的前置说明:
pulsar的topic规范格式为:{是否持久化消息标识}://{租户}/{命名空间}/{自定义部分}
文档中提到的租户、命名空间 与pulsar中的topic规范格式相对应,文档中的topic通常指的为{自定义部分}
使用说明#
1. 引入pulsar-spring-boot-starter核心包依赖#
2. 配置#
脚手架重写了pulsar连接url, 脚手架连接串的格式为:pulsar://{pulsar服务}?auth={认证方式},{认证信息},admin-port={pulsar admin api端口},其他和pulsar原生配置一致。
认证方式:
token, 认证信息为:token={token值}
basic, 认证信息为: u={账号},p={密码}
pulsar.tenant 下配置为请求pulsarcheck服务的配置信息
namespace-var: 为注解 @PulsarConsumer namespace中自定义配置的变量
配置参考:
3. 发送消息#
1.
脚手架发送消息相关的方法位于PulsarTemplate类中, 可根据数据类型不同调用PulsarTemplate不同方法。
2.
SendMsgMata 可配置生产者发送消息时的一些配置。参数说明:
tenant: 消息的租户, 默认public
nameSpace: 消息的命名空间,默认default
topic: 业务topic定义
key: 指定消息key
messageTTLInSecond: 消息ttl时间,单位秒
delaySendTime:消息延时发送时间(毫秒)
delayTime:消息延时时间(毫秒),延时到指定时间发送
注:messageTTLInSecond 支持需开启服务端配置
配置文件:conf/broker.conf、conf/standalone.conf
配置项: topicLevelPoliciesEnabled=true
systemTopicEnabled=true
4. 生产者脚手架默认实现功能#
4.1. 租户和命名空间自动创建: 调用PulsarTemplate 发送消息会自动检查租户和命名空间是否存在,不存在会调用pulsar admin api创建。
4.2. 发送json消息转换:调用PulsarTemplate发送json消息, 实体对象会先转json字符串,然后以Schema.BYTES方式发送给pulsar。脚手架json格式消费者会逆向序列化为实体(原因pulsar client对嵌套复杂的JSON实体以Schema.JSON 方式消费者无法正常反序列化,需手动处理)
4.3. 脚手架发送的消息默认都为持久化的消息
5. 拓展脚手架发送配置#
当默认实现的发送消息配置无法满足需求,可通过如下方式自定义发送。
5.1. 通过调用PulsarTemplate.getMessageBuilder 获取消息发送的Builder
5.2. 调用发送方法
示例:
6. 原生生产者开发#
当对生产者有特殊需求,脚手架实现无法满足时可基于pulsar原生client 进行自定义生产开发。(脚手架默认实现功能需自己处理)
示例:
7. 消费者消费消息#
7.1.消费者类添加注解 @PulsarConsumer
    @PulsarConsumer 注解说明
    - topic:消费者订阅业务主题(无需租户和命名空间), 通配符匹配订阅需使用${xxx}格式(但不能以正则开头)
    - subscriptionName: 消费订阅的名称, 类似于kafka 消费者组group,不指定客户端会自动生成。
    - subscriptionType: 消费订阅类型, Exclusive一个订阅名只能有一个消费者订阅、 Shared可供多个消费者消费,多topic 默认按轮流方式分配,
    不能保证消息顺序、Key_Shared 按消息键分配,保证同一键的消息按顺序分配到同一消费者、Failover可允许备用消费者订阅,只能主消费者消费. 默认Shared.
    - initCount: 创建消费者数量,默认1 (Exclusive模式下不要配置)
    - tenant:指定某个租户订阅, 不配置或配置*则订阅所有租户(包括public)。
    - initialPosition:指定消息从什么位置消费(默认最早未消费SubscriptionInitialPosition.Earliest)
    - namespace: 指定某个命名空间订阅,不配置或配置*则订阅所有命名空间, 支持${xxx}变量配置(变量配置需放入pular.namespace-var下,变量名建议用消费者类)
    - nameSpacePrefix: 订阅指定命名空间前缀,不指定默认为公共业务没有前缀(前缀枚举: NameSpacePrefix), 指定前缀则不能配置nameSpacePrefix 
      - 实例相关:IOT("iot_")
      - 项目相关:PROJ("proj_")
      - 公共:NONE("")
7.2.根据不同序列化方式实现不同的IConsumer
示例:
8. 消费者脚手架默认实现功能#
1、租户|命名空间自动匹配订阅: 新增租户或命名空间,如果消费者注解 没有配置tenant或namespace(订阅所有租户|命名空间)或nameSpacePrefix指定命名空间前缀, 当pulsar租户或命名空间改变消费者会自动订阅
2、失败重试: 默认开启重试, 消费失败(handleMessage方法抛出异常),重试5次后未成功确认消费移入死信队列。 重试队列重试延迟间隔默认1秒 (延迟重试的乘数因子为2. 因此默认重试间隔为1, 2, 4, 8, 16)
9. 拓展脚手架消费者配置#
当脚手架消费者注解配置无法满足时,重写脚手架创建pulsar消费者拓展点(consumerBuilder方法),允许自定义配置消费者。
示例: 配置消费者确认超时与重试机制
配置官方文档:https://pulsar.apache.org/docs/3.0.x/concepts-messaging/
 /**
   * 当脚手架消费者配置无法满足时,允许自定义配置消费者
   * 脚手架创建pulsar消费者拓展点
   *
   * @param consumerBuilder  脚手架根据注解配置生成的ConsumerBuilder
   * @return
   */
    default ConsumerBuilder consumerBuilder(ConsumerBuilder consumerBuilder){
        
        consumerBuilder.ackTimeout(10, TimeUnit.SECONDS)
        .ackTimeoutRedeliveryBackoff(MultiplierRedeliveryBackoff.builder()
                .minDelayMs(1000)
                .maxDelayMs(60 * 1000)
                .multiplier(2)
                .build());
                
        return consumerBuilder;
    }
10. 原生消费者开发#
当有特殊需求,上述脚手架消费者实现都无法满足时可基于pulsar原生client 进行自定义消费开发。(脚手架默认实现功能需自己处理)
示例:
11. 认证授权#
pulsar内部支持:TLS、JWT、Athenz、Kerberos、OAuth 2.0、basic
自定义拓展:客户端服务端实现插件接口,服务端的插件类放入broker的classpath. https://pulsar.apache.org/docs/2.10.x/security-extending/
现状:授权采用账号名密码授权,内部使用一个拥有全部权限的账号登录。 待外部需要时再创建租户对应账号,并给该账号授予租户下所有命名空间的权限。
认证方式一:账号名密码
官方文档:https://pulsar.apache.org/docs/2.10.x/security-basic-auth/
1.
利用账号密码生成认证文件内容(md5的那种方式),可利用htpasswd 命令,也可在该网站生成http://www.jsons.cn/htpasswd/,多个账号在文件中换行存储
2.
broker 开启认证和授权,standalone的配置文件conf/standalone.conf。 若集群则是conf/standalone.conf
    authenticationEnabled=true
    authenticationProviders=org.apache.pulsar.broker.authentication.AuthenticationProviderBasic
    basicAuthConf=file:///path/to/.htpasswd
    brokerClientAuthenticationPlugin=org.apache.pulsar.client.impl.auth.AuthenticationBasic
    brokerClientAuthenticationParameters={"userId":"superuser","password":"admin"}
    authenticateOriginalAuthData=true
3.
配置 conf/proxy.conf
    authenticationEnabled=true
    authenticationProviders=org.apache.pulsar.broker.authentication.AuthenticationProviderBasic
    basicAuthConf=file:///path/to/.htpasswd
    brokerClientAuthenticationPlugin=org.apache.pulsar.client.impl.auth.AuthenticationBasic
    brokerClientAuthenticationParameters={"userId":"superuser","password":"admin"}
    forwardAuthorizationCredentials=true
4.
配置客户端工具认证,conf/client.conf (命令行客户端工具会用到)
    authPlugin=org.apache.pulsar.client.impl.auth.AuthenticationBasic
    authParams={"userId":"superuser","password":"admin"}
java 客户端配置
    AuthenticationBasic auth = new AuthenticationBasic();
    auth.configure("{\"userId\":\"superuser\",\"password\":\"admin\"}");
    PulsarClient client = PulsarClient.builder()
    .serviceUrl("pulsar://broker.example.com:6650")
    .authentication(auth)
    .build();
Pulsar restful api请求: 添加Basic auth认证参数(base64(用户名:密码))
token 方式认证
pulsar 服务支持配置多种认证 可以在现在有的basic上再加上token认证
官方文档:[https://pulsar.apache.org/docs/2.11.x/security-jwt/]
1.
创建token密钥:
bin/pulsar tokens create-secret-key --output my-secret.key
2.
生成token:
bin/pulsar tokens create --secret-key file:///path/to/my-secret.key --subject superuser
3.
配置token 认证(添加token认证插件)
  配置文件:conf/standalone.conf:
  authenticationProviders=org.apache.pulsar.broker.authentication.AuthenticationProviderToken
  tokenSecretKey=file:///path/to/my-secret.key

3.9 RabbitMQ服务#

    <dependency>  
        <groupId>com.das.libcore</groupId>
        <artifactId>rabbitmq</artifactId>
        <version>3.0.0</version>
    </dependency>
功能简介#
用处:对rabbitmq进行了封装
使用说明#
引入rabbitmq核心包依赖
配置rabbitmq连接
注入RabbitMQ工具类
1.
发送数据
注入RabbitMQHelper并调用send方法进行数据发送
@Resource
RabbitMQHelper rabbitMQHelper;

//交换机名称,路由键以及值
rabbitMQHelper.send(RabbitMqConfig.DEAD_LETTER_EXCHANGE,RabbitMqConfig.RK_POINT_RULE_METCHES,"ss");
2.
接受数据继承 MessageListenter
@Component
public class PointRuleMatchesMessageListener implements MessageListener {
    private static final Logger logger  = LoggerFactory.getLogger(PointRuleMatchesMessageListener.class);


    @Override
    public void onMessage(Message message) {
        logger.info("PointRuleMatchesMessageListener 开始消费");
        String body = new String(message.getBody());
        logger.info("获取的body为{}",body);
    }
}

3.10 Redis集成#

    <dependency>  
        <groupId>com.das.libcore</groupId>
        <artifactId>redis-spring-boot-starter</artifactId>
        <version>3.0.0</version>
    </dependency>
功能简介#
用处:对redis进行了封装
使用说明#
使用:
引入redis核心包依赖
配置redis连接
代码示例
单数据源使用
多数据源使用

3.11 签名校验功能#

    <dependency>  
        <groupId>com.das.libcore</groupId>
        <artifactId>sign-spring-boot-starter</artifactId>
        <version>3.0.0</version>
    </dependency>
功能简介#
用处:签名验证工具包
使用说明#
使用:
引入sign-spring-boot-starter核心包依赖
在使用的Controller上添加注解@Sign则每个方法都会进行签名校验,如果哪个方法不需要则加上 @IgnoreSign
@Sign
@Validated
@Controller
@RequestMapping("/sign")
public class SignDemoController {
    @GetMapping(value = "/test/get/1")
    @ResponseBody
    public String testGetSignWithoutParam() {
        return ActionResult.ok("OK");
    }

    @PostMapping(value = "/test/post/2")
    @ResponseBody
    public UserVO testPostSignWithBody(@RequestBody @Validated UserVO userVO, @RequestParam String name) {
        return ActionResult.ok(userVO);
    }

    @IgnoreSign
    @PostMapping(value = "/test/ignore")
    @ResponseBody
    public String testIgnoreSign() {
        return ActionResult.ok("OK");
    }
}
签名校验功能说明
后端会对参数包括QueryParam参数和Path参数名称和值进行排序包含appid,timestamp,sign_method但是不包含sign,如果有请求体必须是json,则json的body放在最前为空则丢弃,示例如下
http://localhost:8080/sign/test/get/1?timestamp=1666668081091&appid=tang&sign=4462488eabe48476213f5f2d04b46564&sign_method=md5&name=tang&age=26
age=26&appid=tang&name=tang&sign_method=md5&timestamp=1666668081091

http://localhost:8080/sign/test/post/2?timestamp=1666668081091&appid=tang&sign=07c6eb5e4dc2540cb9bf54e860f88626&sign_method=md5&name=tang
body={"userId":1,"username":"zhangsan"}&appid=tang&name=tang&sign_method=md5&timestamp=1666668081091

然后根据传过来的appId查询secret,同时根据sign_method方法类型选用不同算法进行加密,规则如下

当sign_method = hmac_sha256
HMACSHA256( "body={"police":"noPo"}&appid=knasdfnas&age=17&name=yuhun&timestamp=111111" , secret )

当sign_method = md5
md5( "body={"police":"noPo"}&appid=knasdfnas&age=17&name=yuhun&timestamp=111111" + secret )
签名Secret获取接口,实现SignAccess的getSignSecret方法然后注入到容器中即可

3.12 文件处理功能#

    <dependency>  
        <groupId>com.das.libcore</groupId>
        <artifactId>file-spring-boot-starter</artifactId>
        <version>3.0.0</version>
    </dependency>
功能简介#
用处:文件导入导出工具包
使用说明#
1.
引入file-spring-boot-starter核心包依赖
2.
服务类说明
类说明
FileExportService文件导出服务类
FileImportService文件导入服务类
//通过调用FileExportService#exportFile方法进行文件导出
FileExportService#exportFile(String taskId, String taskKey, String bucket, String objectPathAndName, WriteFileCallback writeFileCallback)
参数说明
参数说明
taskId任务id
taskKey任务key
bucket存储桶名称
objectPathAndName对象路径和名称
writeFileCallback写数据回调
//通过调用FileExportService#exportFile方法进行文件导出
FileImportService#importFile(String taskId, String taskKey, String bucket, String objectPathAndName, WriteFileCallback writeFileCallback)
参数说明
参数说明
taskId任务id
taskKey任务key
bucket存储桶名称
uploadFilePathAndName上传文件路径和名称
errorFilePathAndName错误文件路径和名称
readDataCallback读取数据回调
insertDataCallback插入数据回调
handlerErrorDataCallback处理错误数据回调
3.
回调说明
回调说明
HandlerErrorDataCallback处理错误数据文件回调
InsertDataCallback插入数据回调
InsertDataEnhancerCallback插入数据回调
ReadDataCallback从excel读取数据回调
WriteFileCallback文件导入服务类

3.13 多租户功能#

    <dependency>  
        <groupId>com.das.libcore</groupId>
        <artifactId>schema-spring-boot-starter</artifactId>
        <version>3.0.0</version>
    </dependency>
功能简介#
简介:支持多租户功能,租户下表结构初始化功能
使用说明#
如果采用mybatisplus自动配置不用自己注入mybatis插件
但是重写了mybatisplus配置就需要手动注入插件
默认schema是_,需要事先建立名为_的schema并将表复制到_下

3.14 系统日志记录功能#

     <dependency>  
        <groupId>com.das.libcore</groupId>
        <artifactId>svclog-spring-boot-starter</artifactId>
        <version>3.0.0</version>
    </dependency>
功能简介#
为各服务提供服务的业务日志记录能力
使用说明#
1.
引入svclog-spring-boot-starter核心包依赖
2.
发送日志
3.
注意事项
此示例为在Spring Boot中使用的示例,使用此组件的项目需引入并正确配置pulsar-spring-boot-starter
在非Spring Boot中,可以通过传入一个可用的PulsarClient实例的方式,显式初始化SvcLog:
4.
其他例如用户操作事件,用户信息,IP地址,租户,项目等信息,均会从当前请求的GlobalRequestDTO中获取(自动填充所有留空的公共字段),通常不需要显式指定这些内容,但是在子线程或者长时间运行的后台任务服务中,需要显式填充这些值,有两种方式:

3.15 分布式任务#

     <dependency>  
        <groupId>com.das.libcore</groupId>
        <artifactId>xxljob-spring-boot-starter</artifactId>
        <version>3.0.0</version>
    </dependency>
功能简介#
简介:分布式任务统一处理
使用说明#
1.
引入SDK
2.
说明:目前支持定时corn http任务,业务侧抛弃以往开发spring-boot 定时任务的方式,直接将逻辑通过rest api的方式暴露,通过创建 xxl-job 定时任务来请求业务接口完成定时逻辑。需要注意的是,业务侧有必要保存任务的相关参数
3.
示例:
4.
参数说明
HttpJobInfo参数说明如下,SDK代码中也有详细的注释说明
image.png

3.16 apollo服务#

     <dependency>  
        <groupId>com.das.libcore</groupId>
        <artifactId>apollo-client</artifactId>
        <version>3.0.0</version>
    </dependency>

    <dependency>  
        <groupId>com.das.libcore</groupId>
        <artifactId>apollo-spring-boot-starter</artifactId>
        <version>3.0.0</version>
    </dependency>
功能简介#
存放加载apollo的包,涉及后续使用apollo做配置中心的相关内容
管理应用需要连接的namespace名称
命名空间名称:NameSpace
key:namespace
value:namespace1,namespace2,namespace3
使用说明#
1.
引入apollo-client,apollo-spring-boot-starter核心包依赖
2.
使用
在apollo添加应用
img.png
绑定公共Namespace NameSpace、BasicConfig
img_1.png
新增配置文件
注意:文件名称需要携带后缀
img_2.png
在application.yml文件中增加apollo配置
img_3.png
不同的环境,通过环境变量来配置
env=dev

3.17 feign服务#

     <dependency>  
        <groupId>com.das.libcore</groupId>
        <artifactId>feign-spring-boot-starter</artifactId>
        <version>3.0.0</version>
    </dependency>
功能简介#
封装了openfeign功能,在feign发起请求时添加对应的请求头及参数,并进行相关请求的日志打印以及对feign返回数据解码至对应的数据格式
使用说明#
与openfeign使用流程一致

3.18 授权平台服务#

    <dependency>
        <groupId>com.das.libcore</groupId>
        <artifactId>justauth-spring-boot-starter</artifactId>
        <version>3.0.0</version>
    </dependency>
功能简介#
集成了JustAuth功能,涉及平台授权的相关内容
使用说明#
1.
添加配置,在 application.yml 中添加配置配置信息
2.
定义接口
通过AuthRequestFactory以及type类型参数来获取对应的AuthRequest请求,然后通过authRequest调用指定接口来实现指定功能

3.19 minio服务#

    <dependency>
        <groupId>com.das.libcore</groupId>
        <artifactId>minio-spring-boot-starter</artifactId>
        <version>3.0.0</version>
    </dependency>
功能简介#
封装了minio功能,通过调用MinIO工具类中的相关方法实现创建minio客户端、判断、查询、删除、下载、上传等文件处理相关功能,主要用于资源文件的存储,包括导入导出,头像上传,文档上传等业务中的静态文件
使用说明#
1.
使用
后端直接通过minio的SDK客户端将文件传输到minio服务器上,再根据业务需要,将minio地址(相对路径)返回到前端或保存至数据库
2.
MinioUtil工具类部分说明
方法说明
createBucket创建Bucket
createBucketAndSetPolicy创建Bucket,并且设置其权限为公共可读
bucketExists判断Bucket是否存在
getAllBuckets获得所有Bucket列表
getBucket根据存储桶名称获取其相关信息
removeBucket根据存储桶名称删除Bucket,true:删除成功;false:删除失败,文件或已不存在
isObjectExist判断文件是否存在
getAllObjectsByPrefix根据文件前缀查询文件
getObject获取文件/断点下载
uploadFile文件上传
getFileStatusInfo获取文件信息, 如果抛出异常则说明文件不存在
copyFile拷贝文件
removeFiles批量删除文件
getPreSignedObjectUrl获取文件外链
getUtf8ByDecoder将URLDecoder编码转成UTF8
3.
Minio文件层级
临时目录(主要用于导入导出):temp/租户/服务名 存储桶:temp
静态模板目录(主要用于静态模板的下载):template/服务名/ 存储桶:template
租户级别业务目录(主要用于业务上传文件):租户Id/服务名/ 存储桶:租户Id(t 开头)
项目级别业务目录(主要用于业务上传文件):p项目Id/服务名/ 存储桶:项目Id(p 开头)
IoT 级别业务目录(主要用于业务上传文件):iot-{IoT 实例 Id}/服务名/ 存储桶:iotId(iot 开头)
前端静态资源:resource/front-end/ 如存储css的目录为resource/front-end/css
业务静态资源:resource/业务/ 如企管的菜单目录为:resource/enterpriseAdmin/menu
划分依据:以租户或者项目维度进行管理资源,精确控制每个项目或者每个租户消耗的空间大小
服务名:由后端明确告诉前端,上传到所在服务下,方便管理
注意: 业务产生的文件,文件名不允许有规律,如按数字有规律递增或者时间戳等,防止拖库
建议:在现有文件层级后以 yyyy/MM/dd 创建 年月日或者年月层级的文件夹,方便业务统一处理和管理,如按时间清除文件
4.
IoT 平台设备文件存储
IoT 的设备文件由于外放到边缘上传,不可控性增加,并且业务上对于单个实例下设备文件上传资源占用需要精确计算以做限制或者计费,上传规范以此为准 租户-实例/设备Id/:
租户_实例为存储桶
设备Id/后的路径或者文件由边缘设备开发者自行定义,建议设备上传时遵循一定层级

服务部署流程#

jenkins 插件示例#

pipeline {
    agent{ label 'node22||node24||node25' }
    options {
        buildDiscarder logRotator(artifactDaysToKeepStr: '', artifactNumToKeepStr: '', daysToKeepStr: '300', numToKeepStr: '36500')
    }
    environment {
        Hub_Docker_Server='192.168.100.28:8088'
    }
    parameters {
        string(name: 'ImageTag', defaultValue: 'default',description: '默认情况下不用改动,定版时填写版本号。镜像标签,不能填写中文、空格和特殊字符')
        string(name: 'GitAddr',defaultValue: 'http://das-git.chn-das.com', description: '代码git地址')
        string(name: 'GitBranch',defaultValue: 'dev', description: '代码分支')
        string(name: 'AppPath',defaultValue: 'xxx', description: '程序入口文件夹。')
        booleanParam defaultValue: true, description: '是否发布,不发布的话就只打包镜像不更新环境', name: 'Release'
        string(name: 'DockerfilePath',defaultValue: '', description: '默认情况为空,有特殊服务需要自定义Dockerfile的服务填写Dockerfile文件路径。(不用填写Dockerfile文件名)')
        choice choices: ['192.168.100.26','192.168.100.21','192.168.100.22','192.168.100.23','192.168.100.27','192.168.100.29','192.168.100.30','192.168.100.32','192.168.100.33','192.168.100.191','192.168.100.193','192.168.100.194','192.168.100.195','192.168.100.196','192.168.100.197','192.168.100.198','192.168.100.199','192.168.100.204','192.168.100.210','192.168.100.211','192.168.100.212','192.168.100.213','192.168.100.214','192.168.100.215','192.168.100.216','192.168.100.217','192.168.100.218','192.168.100.219','192.168.100.220','192.168.100.221','192.168.100.222'], description: '选择发布的服务器', name: 'RemoteIP'
        booleanParam defaultValue: false, description: '清除缓存das/libcore', name: 'ClearCache'
        choice choices: ['amd64','arm64'], description: '选择处理器架构', name: 'Architecture'
    }

    stages {
      stage("start"){
        steps{
          script{
            deleteDir()
            if("${params.ClearCache}" == "true" )
            {
              sh 'rm -rf /root/.m2/repository/com/das/libcore/'
            }
            ## 拉取代码
            checkout([$class: 'GitSCM', branches: [[name: "${GitBranch}"]], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: 'b94e7780-10e7-4dde-9c66-60b2615902f4', url: "${GitAddr}"]]])
              AppName=sh(returnStdout: true, script: 'echo ${AppPath}|tr "/" " "|awk \'{print $NF}\'|tr "." "-"|tr [A-Z] [a-z]').trim()
              Group_Name=sh(returnStdout: true, script: 'echo ${GitAddr}|sed "s#http://das-git.chn-das.com/##g"|awk -F"/" \'{print $2}\'|tr [A-Z] [a-z]').trim()
              ServerName="${Group_Name}-${AppName}"
              if (fileExists('./.k8s-servername')) {
                  ServerName=sh(returnStdout: true, script: 'cat ./.k8s-servername').trim()
              }
              imageTag="${params.ImageTag}"
              if(imageTag=="default")
              {
                imageTag = sh(returnStdout: true, script: 'git rev-parse --short HEAD').trim()
                CreateTime = sh(returnStdout: true, script: 'date +%s').trim()
                imageTag = "${GitBranch}-${imageTag}-${CreateTime}"
              }

              ImageName = "${Hub_Docker_Server}/dasaiot/${ServerName}:${imageTag}"
              LatestImageName = "${Hub_Docker_Server}/dasaiot/${ServerName}:latest"

              sh """
                echo ${params.AppPath}
                echo ${ServerName}
                echo ${imageTag}
                ## 打包操作
                mvn clean package -U
                ls ${params.AppPath}/target/
                cp ${params.AppPath}/target/${params.AppPath}.jar ./
                """
                ## amd64 - 标准, arm64 - 国产化环境
              if("${params.Architecture}" == "amd64" )
              {
              sh """
                if [ -z "${params.DockerfilePath}" ];
                then
                    export ServerName=${ServerName}
                    export AppPath=${params.AppPath}
                    jar ufe ${params.AppPath}.jar org.springframework.boot.loader.PropertiesLauncher
                    wget -O Dockerfile_java http://minio.rd.chn-das.com/cicd/dockerfile_template/Dockerfile_java
                    envsubst < Dockerfile_java > ./Dockerfile
                else
                    cp ${params.DockerfilePath}/Dockerfile ./
                    if cat Dockerfile | grep -q "PropertiesLauncher"; then
                        sed  -i /PropertiesLauncher/d Dockerfile
                        jar ufe ${params.AppPath}.jar org.springframework.boot.loader.PropertiesLauncher
                    fi
                fi
                docker build --no-cache -t ${ImageName} .
                docker tag ${ImageName} ${LatestImageName}
                ## 发布镜像
                docker push ${ImageName}
                docker push ${LatestImageName}
              """
             } else if("${params.Architecture}" == "arm64" )
             {
               sh """
                if [ -z "${params.DockerfilePath}" ];
                then
                    export ServerName=${ServerName}
                    export AppPath=${params.AppPath}
                    jar ufe ${params.AppPath}.jar org.springframework.boot.loader.PropertiesLauncher
                    wget -O Dockerfile_javaarm64 http://minio.rd.chn-das.com/cicd/dockerfile_template/Dockerfile_javaarm64
                    envsubst < Dockerfile_javaarm64 > ./Dockerfile
                else
                    cp ${params.DockerfilePath}/Dockerfilearm64 ./Dockerfile
                    if cat Dockerfile | grep -q "PropertiesLauncher"; then
                        sed  -i /PropertiesLauncher/d Dockerfile
                        jar ufe ${params.AppPath}.jar org.springframework.boot.loader.PropertiesLauncher
                    fi
                fi
                 docker build --no-cache -t ${ImageName} .
                 ## 发布镜像
                 docker push ${ImageName}
               """
             }


              echo "是否发布"
              if ( Release == "true" )
              {sh """
                  if [ -z "`ssh -i /root/.ssh/jenkins -o StrictHostKeyChecking=no -tt root@${RemoteIP} "kubectl get deploy| grep ${ServerName}"`" ];
                  then
                        wget -O Javatemplate.yaml http://minio.rd.chn-das.com/cicd/k8s_template/Javatemplate.yaml
                        export ServerName=${ServerName}
                        export ImageName=${ImageName}
                        envsubst < Javatemplate.yaml > ./${ServerName}.yaml

                        scp -i /root/.ssh/jenkins -o StrictHostKeyChecking=no ${ServerName}.yaml root@${RemoteIP}:/opt/data/appdata/yaml/${ServerName}.yaml
                        ssh -i /root/.ssh/jenkins -o StrictHostKeyChecking=no -tt root@${RemoteIP} "kubectl apply -f /opt/data/appdata/yaml/${ServerName}.yaml"
                        curl -X 'POST' 'http://webhook-api.rd.chn-das.com/api/webhook/v1/wechat/notice?token={token}&users=all'   -H 'accept: */*'   -H 'Content-Type: application/json' -d '"'${RemoteIP}环境新增java服务${ServerName}'"'
                  else
                        ssh -i /root/.ssh/jenkins -o StrictHostKeyChecking=no -tt root@${RemoteIP} "kubectl  set image deployment/${ServerName} ${ServerName}=${ImageName}"
                  fi
              """
              echo "ServerName=${ServerName}"
              echo "ImageName=${ImageName}"
            }
          }
        }
      }
    }
}

1. 拉取代码#

2. 服务打包#

  mvn clean package -U

3. 发布镜像#

    ## 创建镜像
    docker build --no-cache -t ${ImageName} .
    ## 标记本地镜像。归档至某个仓库
    docker tag ${ImageName} ${LatestImageName}
    ## 发布镜像至镜像仓库
    docker push ${ImageName}
    docker push ${LatestImageName}

4. 服务启动#

## 找到已部署的服务(判断服务是否存在)
kubectl get deploy| grep ${ServerName}
## 更新deploy配置(服务不存在时)
kubectl apply -f /opt/data/appdata/yaml/${ServerName}.yaml
## 更新当前服务的镜像(服务存在时)
kubectl  set image deployment/${ServerName} ${ServerName}=${ImageName}

注意事项#

超管菜单#

1. 菜单维护#

维护地址: 菜单工具

2. 菜单导出并归档#

3. 缺少该步骤问题现象:证书下发无法下发新增应用#

企管菜单#

1. 菜单维护#

维护地址: 菜单工具

2. 菜单导出并归档#

初始化脚本 必须指定数据库 permission,租户 public

3. 缺少该步骤问题现象:证书下发后 企管未展示新增应用且无法授权#

消息模板#

1. 消息模板维护#

达实租户-消息管理维护消息类型、消息模板

2. 消息模板脚本#

数据库(message_center)-租户(admin) 找到待归档的消息模板、消息类型 导出sql进行归档
注意 built_in(系统内置) 必须声明为 true

3. 缺少该步骤问题现象: 新环境发送消息无消息模板#

期待您的宝贵建议

微信扫描二维码,为我们的AIoT产品提出您的宝贵建议,用户体验是我们坚持不懈的追求。

微信扫描二维码
修改于 2024-01-19 07:04:00
上一页
前端Web指南
下一页
准备工作
Built with