# project-builder **Repository Path**: binarylei/project-builder ## Basic Information - **Project Name**: project-builder - **Description**: 基于当前最流行的技术栈编写的项目构建框架,用于项目急速构建及开发。 - **Primary Language**: Java - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 3 - **Created**: 2020-11-13 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # project-builder #### 介绍 对常用开源技术封装后组建而成的一套项目构建基础框架,核心依赖为springboot并整合了springcloud等微服务开发常用技术,适用于快速搭建项目及开发。 #### 软件架构 组件库主要提供了以下组件及模块 | 组件名 | 功能 | | --- | --- | | project-builder-component-amqp | 消息队列集成及工具类,实现了从系统管理服务获取服务器地址配置。 | | project-builder-component-consul | 服务注册组件,支持consul作为注册中心。 | | project-builder-component-mybatisplus | 数据库操作组件,基于mybatisplus实现了双数据源切换。 | | project-builder-component-remote | 远端服务的调用,已经集成了系统服务管理的字典、用户、附件、组织架构接口,引入该组件后程序里面可以直接调用。 | | project-builder-component-web | 集成了springmvc提供了请求安全过滤、swagger、跨域等支持 | | project-builder-component-zuul | 集成了zuul,实现了本地接口代理功能。 | | project-builder-component-apm | 应用性能监控组件,封装了Elastic APM | | project-builder-component-basedatacache | 通用缓存组件,封装了常用的基础数据缓存,支持自定义扩展。 | |project-builder-component-config|配置管理组件,用于微服务自动注册及管理其程序配置。| |project-builder-component-elasticsearch| 封装了集成elasticsearch的代码。| |project-builder-component-excelparser| 封装了操作excel的代码,基于注解和poi实现。| |project-builder-component-kafka| 封装了集成kafka的代码。| |project-builder-component-logging| 日志管理组件,支持程序运行中动态调整日志级别| |project-builder-component-memcache| 封装了操作memcache的代码。| |project-builder-component-msgbus| 封装了操作消息队列的代码。| |project-builder-component-nacos| 服务注册组件,支持nacos作为注册中心。| |project-builder-component-nacos-config| 基于nacos实现的配置中心| |project-builder-component-neo4j| 封装了操作neo4j的代码。| |project-builder-component-redis | 封装了操作redis的代码,包含分布式锁及批量操作redis功能。| |project-builder-component-swagger| 用于集成swagger。 |project-builder-component-syslog| 操作日志管理组件,用于记录应用操作日志。| |project-builder-common| 通用的工具类、异常类、缓存类、接口返回类。| |project-builder-component-parent| 项目的parent依赖| |project-builder-dependencies| 组件库统一维护jar包依赖的模块| #### 安装教程 1. git clone https://gitee.com/dhq/project-builder.git 2. mvn clean package 3. mvn deploy 项目代码到maven 4. 其他项目引入本项目发布后的依赖,具体使用方法见使用说明。 #### 使用说明 使用方式同springboot使用starter的方式非常接近,项目里面需要使用什么组件,直接在pom文件里面添加相关的依赖然后在配置文件里面添加相应的配置即可,可以自由的选择需使用的组件,以微服务注册组件的使用为例进行说明: 2.1引入依赖 ``` <-- parent 部分--> com.denghq project-builder-component-parent 0.0.1-SNAPSHOT <-- dependencies 部分--> com.denghq project-builder-component-consul ``` 2.2 添加配置 ``` spring: profiles: active: prod application: name: consul_test cloud: consul: #微服务注册中心地址 host: 192.168.0.x port: 8500 discovery: instance-id: ${spring.application.name}:${spring.cloud.client.ip-address}:${server.port} service-name: ${spring.application.name} health-check-interval: 10s register: false tags: xx服务,swagger=swagger-ui.html,application=${spring.application.name} prefer-ip-address: true healthCheckPath: /actuator/health ``` ##### 组件说明 **消息总线组件开发文档** 如何使用? 一、项目中添加maven依赖 ``` com.denghq project-builder-component-msgbus ``` 二、yml文件中添加配置 ``` com: denghq: component: msgbus: rabbitmq: #目前只支持了rabbitmq,已经预留了接口后面再扩展kafaka enable: true #是否启用rabbitmq消息总线,不设置不会加载rabbitmq消息总线 queueList: # queue声明队列,支持声明多个队列 - name: denghq.fmw.192.168.7.96:12001 #队列名称,规范: denghq.${服务标识}.${ip}:${port} durable: true #是否持久化,含义同spring相关参数配置,默认:true autoDelete: false #是否自动删除,含义同spring相关参数配置,默认:false exchangeBinder: #声明交换机 - name: denghq.Exchange.TianjinEPPV5 #交换机名称 type: topic #交换机类型,含义同spring相关参数配置,默认:topic durable: true #是否持久化,含义同spring相关参数配置,默认:true autoDelete: true #是否自动删除,含义同spring相关参数配置,默认:false bindings: #绑定路由键,用于消息监听,queueName:队列名称,routingKey:路由键 - { queueName: queueForMsgBus, routingKey: topic1.# } - { queueName: queueForMsgBus, routingKey: topic2.# } - { queueName: queueForMsgBus, routingKey: topic2 } sender: defaultExchange: exchangeForMsgBus # 消息默认发送到的交换机 topics: #配置某个主题的消息发送到的交换机,如果跟defaultExchange相同可省略,name:消息的主题,支持“#”通配符,exchange:交换机名称 - {name: topic1.#,exchange: exchangeForMsgBus} - {name: topic2,exchange: exchangeForMsgBus} msgReceiver: maxMsgProcessThreadNum: 10 #调用消息处理启用的最大线程数,默认:10 maxConcurrentConsumers: 1 #消息处理最大消费者数量,默认:1 concurrentConsumers: 1 #消息处理最大消费者数量,默认:1 ``` 三、代码中使用 3.1 发送消息到主题(对于rabbitmq主题对应路由键) 方式一(推荐): 1> 代码中注入工具类rabbitMqMsgBusUtil。 ``` @Autowired private RabbitMqMsgBusUtil rabbitMqMsgBusUtil; ``` 2> 构建规范格式的消息内容,发送消息。 ``` @Test public void testUtilSendMsg() { //构建消息内容 List data = Lists.newArrayList(); data.add(new MsgDecoratorData(MqChangeTypeEnum.Insert.name(), "11111_demo")); MsgDecorator.Builder msgBuilder = MsgDecorator.build(); MsgDecorator msg = msgBuilder .setData(data) .setDataType("TestRabbitMqMsgBusUtil send msg") .setReportedTime(new Date()) .build(); //发送消息 rabbitMqMsgBusUtil.sendMsg("topic2", msg); //发送消息,携带消息id(用于做消息发送确认,后面有介绍) rabbitMqMsgBusUtil.sendMsg("topic2","msgId",msg); } ``` 方式二: 1> 直接注入消息总线 ``` @Autowired private RabbitMqMsgBus rabbitMqMsgBus; ``` 2> 发送任意格式的消息 ``` @Test public void testSendMsg() { //发送消息 rabbitMqMsgBus.publish("topic2xx", "111"); //发送消息,携带消息id(用于做消息发送确认) rabbitMqMsgBus.publish("topic2xx", new SimpleMsg("----msg----", "111")); } ``` 3.2 消息确认机制(防消息发送丢失) > 发送消息时携带msgId。 > spring中添加监听器,demo: ``` @Component public class MsgSendEventHandlerDemo implements IMsgSendEventHandler { /** * 消息丢失 * @param event 消息事件 */ @Override public void onSuccessEvent(IMsgSendEvent event) { System.out.println("发送成功(到交换机),msgId" + event.getMsgId()); //TODO根据msgId进行相关逻辑处理 } @Override public void onFailEvent(IMsgSendEvent event) { System.out.println("发送失败(未发送到交换机),msgId" + event.getMsgId()); //TODO根据msgId进行相关逻辑处理,比如重发 } @Override public void onMissEvent(IMsgSendEvent event) { System.out.println("消息丢失(交换机未能发送到队列),msgId" + event.getMsgId()); //TODO根据msgId进行相关逻辑处理 } } ``` 3.3监听主题上的消息(对于rabbitmq,主题对应路由键) > spring中添加消息处理器bean,消息总线监听到相关主题的消息,即会调用相关的消息处理器,demo: ``` // topic :监听的主题 @RabbitMsgBusProcessor(topic = "topic2.#") @Component public class SimpleRabbitMsgBusProcessor implements IMsgProcessor{ //topic :具体的主题,如:topic2.demo , msg: 收到的消息内容 @Override public void execute(String topic, String msg) { Arrays.asList("SimpleRabbitMsgBusProcessor process msg:" + topic,msg).stream().forEach(System.out::println); } } ``` 说明: bean上必须添加@RabbitMsgBusProcessor注解并指定topic(支持#通配符) **通用缓存组件开发文档** 如何使用? 一、项目中添加maven依赖 ``` com.denghq project-builder-component-basedatacache ``` 二、yml文件中添加配置 ``` com: denghq: component: basedatacache: failRetry: 3 #加载缓存失败重试次数,默认3 cacheTimeOutMin: 10 #缓存失效时间,单位:分,默认30分钟 maxThreadNum: 10 #加载缓存最大启动线程数,默认10 failRetryMaxSecond: 5 #加载缓存失败重试最大时间间隔,单位:秒,默认10秒 failRetryMinSecond: 2 #加载缓存失败重试最小时间间隔,单位:秒,默认3秒 useCache: #需加载的通用缓存数据 - AllDevice - SomeDict dictCodes: #字典缓存加载的字典项,如果不配置,不会加载 - 4 msgbus: rabbitmq: #目前只支持了rabbitmq,已经预留了接口后面再扩展kafaka enable: true #是否启用rabbitmq消息总线,不设置不会加载rabbitmq消息总线 queueList: # queue声明队列,支持声明多个队列 - name: denghq.${spring.application.name}.${spring.cloud.consul.discovery.ipAddress}:${server.port} #队列名称,规范: denghq.${服务标识}.${ip}:${port} durable: true #是否持久化,含义同spring相关参数配置,默认:true autoDelete: false #是否自动删除,含义同spring相关参数配置,默认:false exchangeBinder: #声明交换机 # - name: denghq.Exchange.TianjinEPPV5 #交换机名称 - type: topic #交换机类型,含义同spring相关参数配置,默认:topic durable: true #是否持久化,含义同spring相关参数配置,默认:true autoDelete: true #是否自动删除,含义同spring相关参数配置,默认:false bindings: #绑定路由键,用于消息监听,queueName:队列名称,routingKey:路由键 - queueName: denghq.${spring.application.name}.${spring.cloud.consul.discovery.ipAddress}:${server.port} routingKey: ParsedData.Passing.# - queueName: denghq.${spring.application.name}.${spring.cloud.consul.discovery.ipAddress}:${server.port} routingKey: Database.Changed.FrontDevice - queueName: denghq.${spring.application.name}.${spring.cloud.consul.discovery.ipAddress}:${server.port} routingKey: Database.Changed.Dictionary # sender: # defaultExchange: ${com.denghq.component.msgbus.rabbitmq.exchangeBinder[0].name} # 消息默认发送到的交换机 #topics: #配置某个主题的消息发送到的交换机,如果跟defaultExchange相同可省略,name:消息的主题,支持“#”通配符,exchange:交换机名称 # - {name: topic1.#,exchange: exchangeForMsgBus} #- {name: topic2,exchange: exchangeForMsgBus} msgReceiver: maxMsgProcessThreadNum: 10 #调用消息处理启用的最大线程数,默认:10 maxConcurrentConsumers: 1 #消息处理最大消费者数量,默认:1 concurrentConsumers: 1 #消息处理最大消费者数量,默认:1 ``` 说明: 1. 因缓存组件需监听数据变更消息,故依赖消息总线组件,需配置消息总线,确保能监听到对应主题的消息,配置方法参考消息总线开发文档。 2. 目前已支持的缓存枚举信息如下: /** * 通用缓存信息枚举 */ ``` public enum CacheTypeEnum { AllUser("Database.Changed.User", "所有用户信息缓存"), AllDevice("Database.Changed.FrontDevice","所有设备信息"), AllSpotting("Database.Changed.Spotting","所有路口信息"), SomeDict("Database.Changed.Dictionary","字典数据信息"), AllDeviceGroup("Database.Changed.FrontdeviceGroup","所有设备组信息" ), AllSpottingGroup("Database.Changed.SpottingGroup","所有路口组信息" ), AllVehicleRedlist("Database.Changed.VehicleRedlist","所有红名单信息" ), ; private final String topic; private final String cacheName; CacheTypeEnum(String topic, String cacheName) { this.topic = topic; this.cacheName = cacheName; } public String getCacheName() { return this.cacheName; } public String getTopic() { return this.topic; } } ``` 三、代码中使用 1、注入需要使用的缓存bean(bean信息参考java doc),如需获取红名单,demo: ``` @Autowired private VehicleRedlistCache vehicleRedlistCache; ``` 2、调用缓存bean的getLoadedCacheData方法,完整demo如下: ``` @RunWith(SpringRunner.class) @SpringBootTest(classes = {App.class})// 指定启动类 public class TestBC { @Autowired private VehicleRedlistCache vehicleRedlistCache; @Test public void testBaseDataCacheHolder() { System.out.println(vehicleRedlistCache.getLoadedCacheData()); //baseDataCacheHolder.getAllCache().forEach(System.out::println); } } ``` 执行结果: 四、如何扩展 对于缓存组件未支持的缓存信息,缓存组件支持扩展自定义缓存,方法如下: 1、编写缓存对象,实现ICustomCacheDomain接口,并继承AbstractCacheDomain抽象类,添加到spring容器。demo: ``` /** * 设备缓存 */ @Data @Component public class DeviceCache extends AbstractCacheDomain> implements ICustomCacheDomain> { private String cacheName;//缓存名称 private String cacheKey;//缓存标识 private Boolean loadSuccess;//是否成功加载过数据 private String topicName;//监听的变更消息主题 private final List cacheData;//存放缓存数据 @Autowired private CommonFrontDeviceService commonFrontDeviceService; public DeviceCache(){ this.cacheName = CacheTypeEnum.AllDevice.getCacheName(); this.cacheKey = CacheTypeEnum.AllDevice.name(); this.topicName = CacheTypeEnum.AllDevice.getTopic(); this.loadSuccess = false; cacheData = Lists.newArrayList(); } @Override public int initLoad() { List all = commonFrontDeviceService.simpleAll(); this.cacheData.clear(); this.cacheData.addAll(all); return all.size(); } @Override public int update() { return initLoad(); } } ``` 2、使用 直接在需要使用的地方注入该bean,调用其getLoadedCacheData方法即可获取数据,缓存组件会自动加载缓存数据及监听变更消息刷新该缓存。 ``` @RunWith(SpringRunner.class) @SpringBootTest(classes = {App.class})// 指定启动类 public class TestBC { @Autowired private DeviceCache deviceCache; @Test public void testBaseDataCacheHolder() { System.out.println(deviceCache.getLoadedCacheData()); } } ``` **配置管理组件开发文档** 一、如何使用? 1、添加maven依赖 ``` com.denghq project-builder-component-consul-config ``` 2、在原springboot配置类中添加@Category、@ConfigAttribute注解 ex: ``` @Component @ConfigurationProperties(prefix = "com.denghq.tdm") @Category(projectName = "校时管理", categoryNo = "tdm/TDMProperties1", categoryName = "校时管理") @Data public class TDMProperties { /** * 时间源服务器地址配置 */ @ConfigAttribute(name = "时间源服务器地址", valueType = ConfigValueTypeEnum.DATA_LIST) private List ntpServerUrl; /** * 时间源服务器时间相差阈值(ms),超过阈值发送阻断消息 */ @ConfigAttribute(name = "时间源相差阈值(ms)") private Long remoteTimeDiffThreshold = 1000L; /** * 本地和校时服务器时间相差阈值(ms),超过阈值则需重置本地时间为校时服务器的时间 */ @ConfigAttribute(name = "本地时间相差阈值(ms)") private Long localTimeDiffThreshold = 1500L; /** * 校准的时间间隔 (ms) */ @ConfigAttribute(name = "校准的时间间隔(ms)") private Long syncInterval = 2000L; /** * 连接ntp服务的超时时间设置 */ @ConfigAttribute(name = "连接ntp服务超时时间(ms)") private Integer ntpClientDefaultTimeout = 800; /** * 连接ntp服务的重试次数 */ @ConfigAttribute(name = "连接ntp服务的重试次数") private Integer ntpClientRetry = 1; /** * 当前是否已阻断 */ @ConfigAttribute(name = "是否全局阻断") private Boolean blocked; } ``` 3、直接注入配置类到spring 的bean中使用 ex: ``` /** * 校时任务 */ @Component @Slf4j public class SyncTimeTask { @Autowired private TDMProperties properties; ``` 二、详细说明 1、功能说明 配置管理组件主要实现配置类的自动注册、在线编辑及实时同步的功能,实现微服务架构中参数配置的统一管理及简化代码开发。 2、注解说明 @Category注解用于描述配置的分类信息,相同分类的配置会显示在配置管理页面同一个栏目下。 |参数名称|含义|是否必填 |说明| | --- | --- | --- | --- | |configType| 配置类型| 否| 不填默认为业务类型配置,可选值见枚举。| |autoRegiste| 是否注册到配置中心| 否| 不填默认为注册,只能注册appNo为当前微服务标识的配置,其他服务的配置只读。| |projectName| 所属项目名称| 是| 管理页面显示的一级栏目名称,用于管理页面分栏目展示。| |appNo| 所属微服务标识| 否| 默认为程序所在微服务的标识。| |categoryNo| 分类唯一标识| 是| 全局唯一不可重复,以服务标识开头,ex: tdm/TDMProperties。| |categoryName| 分类名称| 是| 配置的名称信息。| |saveVerifyApi| 数据校验http请求地址| 否| 不填不进行数据校验。| @ConfigAttribute注解用于描述配置的配置项信息,用于实现在配置管理页面展示和编辑配置内容。 |参数名称| 含义| 是否必填| 说明| | --- | --- | --- | --- | |key| 配置项唯一标识| 否| 不填默认为配置类对应属性名。| |name| 配置项名称| 是| 配置管理页面显示的配置项label。| |remark| 备注| 否| | |valueType| 值类型| 否| 不填注册时通过上下文及java类型自动推测| |dateFormat| 日期格式化| 否| 日期类型数据适用,可选值见枚举| |dataSource| 非日期类型值来源| 否| 默认为直接录入,可选值见枚举| |customDataList |自定义数据源 | 否| 配置的值从限定列表下拉选择时适用。| |dataSourceValue| 数据源里面的Key字段| 否| 默认为 value 指定DataSourceApi时生效| |dataSourceText| 数据源里面的Text字段| 否| 默认为 text 指定DataSourceApi时生效,多个逗号分隔会按照顺序拼接 如配置了A,B两个字段显示为A--B| |dataSourceValueFormat| 下拉选择后显示的字段| 否| 下拉选择后显示的字段,比如下拉里面是abc-11111,但是选中后只想显示abc,此时可以用该字段| |dataSourceApi| 下拉数据源的API接口地址| 否| 只支持get请求 dataSource为从接口获取结果时生效| |parentKey| 父级key| 否| 用于配置项联动的显示隐藏控制| |parentValue| 父级value| 否| 用于配置项联动的显示隐藏控制| |customPage| 自定义配置页面地址| 否| 当ValueType为url时,对应的自定义配置页面地址,用于复杂个性化配置项| 3、枚举 配置类型 ``` /** * 配置类型 */ public enum ConfigTypeEnum { BUSINESS(1, "业务逻辑配置"), PROGRAM(2, "程序本身的配置"); private final int value; private final String description; ConfigTypeEnum(int value, String description) { this.value = value; this.description = description; } public int getValue() { return value; } public String getDescription() { return description; } } ``` 配置值类型 ``` /** * 配置值类型 */ public enum ConfigValueTypeEnum { NUMBER(1, "数值类型"), STRING(2, "字符串"), BOOLEAN(3, "布尔型"), DATE(4, "日期类型"), DATE_RANGE(5, "日期区间"), ARRAY(6, "数组类型"), DATA_LIST(7, "数据列表"), URL(8, "自定义页面"), OBJECT(9,"对象类型"), NULL(-1,"未指定,自动推测") ; private final int value; private final String description; ConfigValueTypeEnum(int value, String description) { this.value = value; this.description = description; } public int getValue() { return value; } public String getDescription() { return description; } } ``` 非日期类型值来源 /** * 非日期类型值来源 *默认1 */ ``` public enum DataSourceEnum { INPUT(1, "直接录入"), SELECT(2, "从限定列表下拉选择"), API(3, "从接口获取结果中下拉选择"), TEXT_EDITER(4,"大文本编辑器") ; private final int value; private final String description; DataSourceEnum(int value, String description) { this.value = value; this.description = description; } public int getValue() { return value; } public String getDescription() { return description; } } ``` 日期格式化 ``` package com.denghq.component.config.metadata.enums; /** * 日期格式化 */ public enum DateFormatEnum { DATETIME(1, "年月日时分秒"), DATE(2, "年月日"), YEAR_MONTH(3, "年月"), YEAR(4, "年"), TIME(5, "时分秒"), HOUR_MIN(6, "时分"), NULL(-1,"未指定" ); private final int value; private final String description; DateFormatEnum(int value, String description) { this.value = value; this.description = description; } public int getValue() { return value; } public String getDescription() { return description; } } ``` 三、其他说明 为了实现跟springcloud的整合,对于老的项目需要把application_prod.yml更名为bootstrap.yml。 Excel解析组件开发文档 一、如何使用? 1、添加maven依赖 ``` com.denghq project-builder-component-excelparser ``` 2、程序中使用(推荐使用sax解析) 组件支持了dom和sax两种方式解析excel2003及excel2007文档,推荐使用sax解析,比较省内存。 Dom解析 > 使用dom解析excel 文档 ``` private IExcelParser parser; @Test public void testDomXlsx() { parser = new ExcelDomParser<>(); IParserParam parserParam = DefaultParserParam .builder() .excelInputStream(Thread.currentThread() //要解析的文件流 .getContextClassLoader() .getResourceAsStream("test01.xlsx")) .columnSize(4)//解析的列数 .sheetNum(IParserParam.FIRST_SHEET) // 解析的工作薄索引 .targetClass(User.class) // 需解析出的对象 .header(User.getHeader())// 校验标题,不传表示不校验标题 .firstRow(0) // 解析开始行 .build(); List> user = parser.parse(parserParam); System.out.println(user); } ``` > Sax解析 使用sax解析excel文档 使用方法同dom解析完全相同,除了创建的IExcelParser对象不同,dom解析对象为ExcelDomParser,sax解析对象为ExcelSaxParser。 ``` @Test public void testSheet02Xlsx() { parser = new ExcelSaxParser<>(); IParserParam parserParam = DefaultParserParam.builder() .excelInputStream(Thread.currentThread() .getContextClassLoader().getResourceAsStream("test02.xlsx")) .columnSize(4) .sheetNum(IParserParam.FIRST_SHEET + 1) .targetClass(User.class) //被解析对象 .header(User.getHeader()) .firstRow(0) .build(); List> obj = parser.parse(parserParam); obj.forEach(o -> { System.out.println(o.getRowNo()); System.out.println(o.getData()); }); } ``` > 说明 组件提供了ExcelField注解来对excel的解析方式进行描述,@ExcelField的字段具体含义如下: Index: 对应excel的列号(从0开始)。 Type: 对应excel单元格值的类型,用来做数据格式化,目前支持日期/普通字符串。 被解析对象的属性只能是String类型,获取数据后需自行处理,一般用来进行数据校验,返回对应字段的错误提示。 #### 参与贡献 1. Fork 本仓库 2. 新建 Feat_xxx 分支 3. 提交代码 4. 新建 Pull Request #### 码云特技 1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md 2. 码云官方博客 [blog.gitee.com](https://blog.gitee.com) 3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解码云上的优秀开源项目 4. [GVP](https://gitee.com/gvp) 全称是码云最有价值开源项目,是码云综合评定出的优秀开源项目 5. 码云官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help) 6. 码云封面人物是一档用来展示码云会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)