diff --git a/README.md b/README.md index 5bbaed04..2ee2713e 100644 --- a/README.md +++ b/README.md @@ -75,6 +75,8 @@ * [Mqtt消息服务器EMQX4.0](https://github.com/emqx/emqx) * [ESP8266 Core For Arduino](https://github.com/esp8266/Arduino) * [uCharts高性能跨平台图表库](https://www.ucharts.cn) +* [TDengine时序数据库](https://www.taosdata.com/?zh) + ##### Docker快速安装 * Mysql中创建wumei-smart数据库,[导入Sql脚本](https://gitee.com/kerwincui/wumei-smart/tree/master/springboot/sql) * 修改命令中的Mysql配置,并执行 @@ -110,6 +112,9 @@ kerwincui/wumei-smart:1.1 | [SXH](https://gitee.com/sixiaohu) | [Redamancy_zxp](https://gitee.com/redamancy-zxp) | [LEE](https://gitee.com/yueming188) | [LemonTree](https://gitee.com/fishhunterplus) | [Tang](https://gitee.com/mexiaotang) |--|--|--|--|--| +| [xxmfl](https://gitee.com/xxmfl) | +|--| + ### 九、部分图片 diff --git a/springboot/wumei-admin/src/main/resources/application-druid.yml b/springboot/wumei-admin/src/main/resources/application-druid.yml index 9578e066..f8135ae5 100644 --- a/springboot/wumei-admin/src/main/resources/application-druid.yml +++ b/springboot/wumei-admin/src/main/resources/application-druid.yml @@ -16,6 +16,17 @@ spring: url: username: password: + + # TDengine数据库 + tdengine-server: + # 默认不启用TDengine,true=启用,false=不启用 + enabled: false + driverClassName: com.taosdata.jdbc.TSDBDriver + url: jdbc:TAOS://127.0.0.1:6030/wumei_smart_log?timezone=Asia/Beijing&charset=utf-8 + username: root + password: taosdata + dbName: wumei_smart_log + # 初始连接数 initialSize: 5 # 最小连接池数量 diff --git a/springboot/wumei-admin/src/main/resources/application.yml b/springboot/wumei-admin/src/main/resources/application.yml index a99c9bb5..60297c88 100644 --- a/springboot/wumei-admin/src/main/resources/application.yml +++ b/springboot/wumei-admin/src/main/resources/application.yml @@ -8,7 +8,7 @@ ruoyi: copyrightYear: 2021 # 实例演示开关 demoEnabled: true - # 文件路径 示例( Windows配置D:/wumei-smart/uploadPath,Linux配置 /var/wumei-smart/java/uploadPath) + # 文件路径,以uploadPath结尾 示例( Windows配置D:/wumei-smart/uploadPath,Linux配置 /var/wumei-smart/java/uploadPath) profile: /var/wumei-smart/java/uploadPath # 获取ip地址开关 addressEnabled: true diff --git a/springboot/wumei-framework/src/main/java/com/ruoyi/framework/config/MyBatisConfig.java b/springboot/wumei-framework/src/main/java/com/ruoyi/framework/config/MyBatisConfig.java index 057c9419..56463e7a 100644 --- a/springboot/wumei-framework/src/main/java/com/ruoyi/framework/config/MyBatisConfig.java +++ b/springboot/wumei-framework/src/main/java/com/ruoyi/framework/config/MyBatisConfig.java @@ -9,10 +9,13 @@ import javax.sql.DataSource; import org.apache.ibatis.io.VFS; import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spring.SqlSessionFactoryBean; +import org.mybatis.spring.SqlSessionTemplate; import org.mybatis.spring.boot.autoconfigure.SpringBootVFS; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; import org.springframework.core.env.Environment; import org.springframework.core.io.DefaultResourceLoader; import org.springframework.core.io.Resource; @@ -21,12 +24,13 @@ import org.springframework.core.io.support.ResourcePatternResolver; import org.springframework.core.type.classreading.CachingMetadataReaderFactory; import org.springframework.core.type.classreading.MetadataReader; import org.springframework.core.type.classreading.MetadataReaderFactory; +import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.util.ClassUtils; import com.ruoyi.common.utils.StringUtils; /** * Mybatis支持*匹配扫描包 - * + * * @author ruoyi */ @Configuration @@ -113,7 +117,8 @@ public class MyBatisConfig return resources.toArray(new Resource[resources.size()]); } - @Bean + @Bean(name = "mysqlSessionFactory") + @Primary public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception { String typeAliasesPackage = env.getProperty("mybatis.typeAliasesPackage"); @@ -129,4 +134,16 @@ public class MyBatisConfig sessionFactory.setConfigLocation(new DefaultResourceLoader().getResource(configLocation)); return sessionFactory.getObject(); } + + @Bean(name = "mysqlTransactionManager") + @Primary + public DataSourceTransactionManager mysqlTransactionManager(@Qualifier("dynamicDataSource") DataSource dataSource) { + return new DataSourceTransactionManager(dataSource); + } + + @Bean(name = "mysqlSqlSessionTemplate") + @Primary + public SqlSessionTemplate mysqlSqlSessionTemplate(@Qualifier("mysqlSessionFactory") SqlSessionFactory sqlSessionFactory) { + return new SqlSessionTemplate(sqlSessionFactory); + } } \ No newline at end of file diff --git a/springboot/wumei-iot/pom.xml b/springboot/wumei-iot/pom.xml index f0d12628..c716b72a 100644 --- a/springboot/wumei-iot/pom.xml +++ b/springboot/wumei-iot/pom.xml @@ -89,6 +89,15 @@ + + + com.taosdata.jdbc + taos-jdbcdriver + 2.0.38 + + + + \ No newline at end of file diff --git a/springboot/wumei-iot/src/main/java/com/ruoyi/iot/domain/DeviceLog.java b/springboot/wumei-iot/src/main/java/com/ruoyi/iot/domain/DeviceLog.java index b2909ef8..83f9c7c8 100644 --- a/springboot/wumei-iot/src/main/java/com/ruoyi/iot/domain/DeviceLog.java +++ b/springboot/wumei-iot/src/main/java/com/ruoyi/iot/domain/DeviceLog.java @@ -5,9 +5,11 @@ import org.apache.commons.lang3.builder.ToStringStyle; import com.ruoyi.common.annotation.Excel; import com.ruoyi.common.core.domain.BaseEntity; +import java.util.Date; + /** * 设备日志对象 iot_device_log - * + * * @author kerwincui * @date 2022-01-13 */ @@ -15,6 +17,8 @@ public class DeviceLog extends BaseEntity { private static final long serialVersionUID = 1L; + @Excel(name = "时间戳") + private Date ts; /** 设备日志ID */ private Long logId; @@ -46,6 +50,15 @@ public class DeviceLog extends BaseEntity @Excel(name = "是否监测数据", readConverterExp = "1==是,0=否") private Integer isMonitor; + + public Date getTs() { + return ts; + } + + public void setTs(Date ts) { + this.ts = ts; + } + public String getSerialNumber() { return serialNumber; } diff --git a/springboot/wumei-iot/src/main/java/com/ruoyi/iot/mapper/DeviceLogMapper.java b/springboot/wumei-iot/src/main/java/com/ruoyi/iot/mapper/DeviceLogMapper.java index 619d0d57..73b66fc9 100644 --- a/springboot/wumei-iot/src/main/java/com/ruoyi/iot/mapper/DeviceLogMapper.java +++ b/springboot/wumei-iot/src/main/java/com/ruoyi/iot/mapper/DeviceLogMapper.java @@ -4,11 +4,12 @@ import com.ruoyi.iot.domain.DeviceLog; import com.ruoyi.iot.model.MonitorModel; import org.springframework.stereotype.Repository; +import java.util.Date; import java.util.List; /** * 设备日志Mapper接口 - * + * * @author kerwincui * @date 2022-01-13 */ @@ -17,7 +18,7 @@ public interface DeviceLogMapper { /** * 查询设备日志 - * + * * @param logId 设备日志主键 * @return 设备日志 */ @@ -25,7 +26,7 @@ public interface DeviceLogMapper /** * 查询设备日志列表 - * + * * @param deviceLog 设备日志 * @return 设备日志集合 */ @@ -41,7 +42,7 @@ public interface DeviceLogMapper /** * 新增设备日志 - * + * * @param deviceLog 设备日志 * @return 结果 */ @@ -49,7 +50,7 @@ public interface DeviceLogMapper /** * 修改设备日志 - * + * * @param deviceLog 设备日志 * @return 结果 */ @@ -57,7 +58,7 @@ public interface DeviceLogMapper /** * 删除设备日志 - * + * * @param logId 设备日志主键 * @return 结果 */ @@ -65,7 +66,7 @@ public interface DeviceLogMapper /** * 批量删除设备日志 - * + * * @param logIds 需要删除的数据主键集合 * @return 结果 */ @@ -78,4 +79,7 @@ public interface DeviceLogMapper * @return 结果 */ public int deleteDeviceLogByDeviceIds(Long[] deviceIds); + + +// List selectLogList(Long deviceId,String serialNumber,Long isMonitor,Long logType, Date beginDate, Date endDate); } diff --git a/springboot/wumei-iot/src/main/java/com/ruoyi/iot/mqtt/EmqxService.java b/springboot/wumei-iot/src/main/java/com/ruoyi/iot/mqtt/EmqxService.java index 98de2000..bca6e263 100644 --- a/springboot/wumei-iot/src/main/java/com/ruoyi/iot/mqtt/EmqxService.java +++ b/springboot/wumei-iot/src/main/java/com/ruoyi/iot/mqtt/EmqxService.java @@ -10,6 +10,7 @@ import com.ruoyi.iot.model.ThingsModels.ThingsModelValueRemarkItem; import com.ruoyi.iot.model.ThingsModels.ThingsModelValuesInput; import com.ruoyi.iot.service.IDeviceLogService; import com.ruoyi.iot.service.IDeviceService; +import com.ruoyi.iot.tdengine.service.ILogService; import org.eclipse.paho.client.mqttv3.MqttAsyncClient; import org.eclipse.paho.client.mqttv3.MqttClient; import org.eclipse.paho.client.mqttv3.MqttException; @@ -32,8 +33,11 @@ public class EmqxService { @Autowired private IDeviceService deviceService; +// @Autowired +// private IDeviceLogService deviceLogService; + @Autowired - private IDeviceLogService deviceLogService; + private ILogService logService; /** * 订阅的主题 @@ -190,7 +194,8 @@ public class EmqxService { deviceLog.setIdentity(thingsModelValueRemarkItems.get(i).getId()); deviceLog.setLogType(3); deviceLog.setIsMonitor(0); - deviceLogService.insertDeviceLog(deviceLog); +// deviceLogService.insertDeviceLog(deviceLog); + logService.saveDeviceLog(deviceLog); } } catch (Exception e) { logger.error("接收事件,解析数据时异常 message={}", e.getMessage()); diff --git a/springboot/wumei-iot/src/main/java/com/ruoyi/iot/service/impl/DeviceLogServiceImpl.java b/springboot/wumei-iot/src/main/java/com/ruoyi/iot/service/impl/DeviceLogServiceImpl.java index c0fbd020..54a9ef64 100644 --- a/springboot/wumei-iot/src/main/java/com/ruoyi/iot/service/impl/DeviceLogServiceImpl.java +++ b/springboot/wumei-iot/src/main/java/com/ruoyi/iot/service/impl/DeviceLogServiceImpl.java @@ -2,6 +2,7 @@ package com.ruoyi.iot.service.impl; import com.ruoyi.common.utils.DateUtils; import com.ruoyi.iot.domain.DeviceLog; +import com.ruoyi.iot.tdengine.service.ILogService; import com.ruoyi.iot.mapper.DeviceLogMapper; import com.ruoyi.iot.model.MonitorModel; import com.ruoyi.iot.service.IDeviceLogService; @@ -22,6 +23,9 @@ public class DeviceLogServiceImpl implements IDeviceLogService @Autowired private DeviceLogMapper deviceLogMapper; + @Autowired + private ILogService logService; + /** * 查询设备日志 * @@ -43,7 +47,8 @@ public class DeviceLogServiceImpl implements IDeviceLogService @Override public List selectDeviceLogList(DeviceLog deviceLog) { - return deviceLogMapper.selectDeviceLogList(deviceLog); +// deviceLogMapper.selectDeviceLogList(deviceLog); + return logService.selectDeviceLogList(deviceLog); } /** @@ -55,7 +60,8 @@ public class DeviceLogServiceImpl implements IDeviceLogService @Override public List selectMonitorList(DeviceLog deviceLog) { - return deviceLogMapper.selectMonitorList(deviceLog); +// return deviceLogMapper.selectMonitorList(deviceLog); + return logService.selectMonitorList(deviceLog); } /** @@ -68,7 +74,8 @@ public class DeviceLogServiceImpl implements IDeviceLogService public int insertDeviceLog(DeviceLog deviceLog) { deviceLog.setCreateTime(DateUtils.getNowDate()); - return deviceLogMapper.insertDeviceLog(deviceLog); +// return deviceLogMapper.insertDeviceLog(deviceLog); + return logService.saveDeviceLog(deviceLog); } /** diff --git a/springboot/wumei-iot/src/main/java/com/ruoyi/iot/service/impl/DeviceServiceImpl.java b/springboot/wumei-iot/src/main/java/com/ruoyi/iot/service/impl/DeviceServiceImpl.java index 91235878..26f52715 100644 --- a/springboot/wumei-iot/src/main/java/com/ruoyi/iot/service/impl/DeviceServiceImpl.java +++ b/springboot/wumei-iot/src/main/java/com/ruoyi/iot/service/impl/DeviceServiceImpl.java @@ -11,13 +11,13 @@ import com.ruoyi.common.utils.ip.IpUtils; import com.ruoyi.iot.domain.Device; import com.ruoyi.iot.domain.DeviceLog; import com.ruoyi.iot.domain.Product; +import com.ruoyi.iot.tdengine.service.ILogService; import com.ruoyi.iot.mapper.DeviceLogMapper; import com.ruoyi.iot.mapper.DeviceMapper; import com.ruoyi.iot.mapper.DeviceUserMapper; import com.ruoyi.iot.model.*; import com.ruoyi.iot.model.ThingsModelItem.*; import com.ruoyi.iot.model.ThingsModels.*; -import com.ruoyi.iot.service.IDeviceLogService; import com.ruoyi.iot.service.IDeviceService; import com.ruoyi.iot.service.IProductService; import com.ruoyi.iot.service.IToolService; @@ -73,8 +73,11 @@ public class DeviceServiceImpl implements IDeviceService { @Autowired private ISysUserService userService; +// @Autowired +// private IDeviceLogService deviceLogService; + @Autowired - private IDeviceLogService deviceLogService; + private ILogService logService; /** * 查询设备 @@ -196,7 +199,8 @@ public class DeviceServiceImpl implements IDeviceService { deviceLog.setCreateTime(DateUtils.getNowDate()); deviceLog.setIsMonitor(valueList.get(k).getIsMonitor()); deviceLog.setLogType(type); - deviceLogMapper.insertDeviceLog(deviceLog); + logService.saveDeviceLog(deviceLog); +// deviceLogMapper.insertDeviceLog(deviceLog); break; } } @@ -591,7 +595,8 @@ public class DeviceServiceImpl implements IDeviceService { deviceLog.setIdentity("offline"); deviceLog.setLogType(6); } - deviceLogService.insertDeviceLog(deviceLog); + logService.saveDeviceLog(deviceLog); +// deviceLogService.insertDeviceLog(deviceLog); return result; } diff --git a/springboot/wumei-iot/src/main/java/com/ruoyi/iot/tdengine/config/TDengineConfig.java b/springboot/wumei-iot/src/main/java/com/ruoyi/iot/tdengine/config/TDengineConfig.java new file mode 100644 index 00000000..c71a0812 --- /dev/null +++ b/springboot/wumei-iot/src/main/java/com/ruoyi/iot/tdengine/config/TDengineConfig.java @@ -0,0 +1,93 @@ +package com.ruoyi.iot.tdengine.config; + +import com.alibaba.druid.pool.DruidDataSource; +import com.ruoyi.common.utils.StringUtils; +import org.apache.ibatis.session.SqlSessionFactory; +import org.mybatis.spring.SqlSessionFactoryBean; +import org.mybatis.spring.SqlSessionTemplate; +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.io.Resource; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; +import org.springframework.core.io.support.ResourcePatternResolver; + +import javax.sql.DataSource; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * 类名: TDengineConfig + * 描述: TDengine配置类 + * 时间: 2022/5/13,0016 1:14 + * 开发人: wxy + */ +@Configuration +@MapperScan(basePackages = {"com.ruoyi.iot.tdengine.dao"}, sqlSessionTemplateRef = "tdengineSqlSessionTemplate") +@ConditionalOnProperty(name = "spring.datasource.druid.tdengine-server.enabled", havingValue = "true") +public class TDengineConfig { + + @Value("${spring.datasource.druid.tdengine-server.dbName}") + private String dbName; + + + @Bean(name = "tDengineDataSource") + @ConfigurationProperties(prefix = "spring.datasource.druid.tdengine-server") + public DataSource tdengineDataSource() { + return new DruidDataSource(); + } + + + + @Bean(name = "tDengineSqlSessionFactory") + public SqlSessionFactory tDengineSqlSessionFactory(@Qualifier("tDengineDataSource") DataSource dataSource) throws Exception { + SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean(); + sqlSessionFactoryBean.setMapperLocations(resolveMapperLocations(StringUtils.split("classpath:mapper/tdengine/*Mapper.xml", ","))); + sqlSessionFactoryBean.setDataSource(dataSource); + return sqlSessionFactoryBean.getObject(); + } + + + @Bean(name = "tdengineSqlSessionTemplate") + public SqlSessionTemplate tdengineSqlSessionTemplate(@Qualifier("tDengineSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception { + return new SqlSessionTemplate(sqlSessionFactory); + } + + public String getDbName() { + return dbName; + } + + public void setDbName(String dbName) { + this.dbName = dbName; + } + public Resource[] resolveMapperLocations(String[] mapperLocations) + { + ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver(); + List resources = new ArrayList(); + if (mapperLocations != null) + { + for (String mapperLocation : mapperLocations) + { + try + { + Resource[] mappers = resourceResolver.getResources(mapperLocation); + resources.addAll(Arrays.asList(mappers)); + } + catch (IOException e) + { + // ignore + } + } + } + return resources.toArray(new Resource[resources.size()]); + } + + +} diff --git a/springboot/wumei-iot/src/main/java/com/ruoyi/iot/tdengine/dao/DatabaseDAO.java b/springboot/wumei-iot/src/main/java/com/ruoyi/iot/tdengine/dao/DatabaseDAO.java new file mode 100644 index 00000000..3044d692 --- /dev/null +++ b/springboot/wumei-iot/src/main/java/com/ruoyi/iot/tdengine/dao/DatabaseDAO.java @@ -0,0 +1,25 @@ +package com.ruoyi.iot.tdengine.dao; + +import org.springframework.stereotype.Repository; + +/** + * @package com.ruoyi.mysql.mysql.tdengine + * 类名: DatabaseMapper + * 描述: TODO + * 时间: 2022/5/16,0016 1:27 + * 开发人: wxy + */ +@Repository +public interface DatabaseDAO { + + int createDB(); + + int dropDatabase(); + + int useDatabase(); + + int createTable(); + + + +} diff --git a/springboot/wumei-iot/src/main/java/com/ruoyi/iot/tdengine/dao/TDDeviceLogDAO.java b/springboot/wumei-iot/src/main/java/com/ruoyi/iot/tdengine/dao/TDDeviceLogDAO.java new file mode 100644 index 00000000..b4907756 --- /dev/null +++ b/springboot/wumei-iot/src/main/java/com/ruoyi/iot/tdengine/dao/TDDeviceLogDAO.java @@ -0,0 +1,41 @@ +package com.ruoyi.iot.tdengine.dao; + +import com.ruoyi.iot.domain.DeviceLog; +import com.ruoyi.iot.model.MonitorModel; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Repository; + +import java.util.Date; +import java.util.List; + +/** + * @package com.ruoyi.mysql.mysql.tdengine + * 类名: DatabaseMapper + * 描述: TODO + * 时间: 2022/5/16,0016 1:27 + * 开发人: wxy + */ +@Repository +public interface TDDeviceLogDAO { + + + int createDB( String database); + + int createSTable(String database); + + int createTable(String database,String deviceId); + + int save(@Param("database") String database,@Param("device") DeviceLog deviceLog); + + List selectSTable(String database,DeviceLog deviceLog); + + int delete(String dbName, DeviceLog deviceLog); + +// List selectLogListByPage(String dbName, Integer pageSize, Integer pageNum, String deviceNum, Date beginDate, Date endDate); + + List selectLogList(String dbName, Long deviceId, String serialNumber, Long isMonitor, Long logType, Date beginDate, Date endDate); + + List selectMonitorList(@Param("database") String database, @Param("device") DeviceLog deviceLog); + + List selectDeviceLogList(@Param("database") String database,@Param("device") DeviceLog deviceLog); +} diff --git a/springboot/wumei-iot/src/main/java/com/ruoyi/iot/tdengine/init/ApplicationStarted.java b/springboot/wumei-iot/src/main/java/com/ruoyi/iot/tdengine/init/ApplicationStarted.java new file mode 100644 index 00000000..7d38f986 --- /dev/null +++ b/springboot/wumei-iot/src/main/java/com/ruoyi/iot/tdengine/init/ApplicationStarted.java @@ -0,0 +1,79 @@ +package com.ruoyi.iot.tdengine.init; + + +import com.ruoyi.iot.tdengine.config.TDengineConfig; +import com.ruoyi.iot.tdengine.dao.TDDeviceLogDAO; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; +import org.springframework.context.ApplicationContext; +import org.springframework.lang.Nullable; +import org.springframework.stereotype.Component; + +/** + * 类名: ApplicationStarted + * 描述: TODO + * 时间: 2022/5/18,0018 1:41 + * 开发人: wxy + */ +@Component +public class ApplicationStarted implements ApplicationRunner { + + private static final Logger LOGGER = LoggerFactory.getLogger(ApplicationStarted.class); + + @Autowired + private ApplicationContext applicationContext; + + @Override + public void run(ApplicationArguments args) { + //先获取TDengine的配置,检测TDengine是否已经配置 + if (containBean(TDengineConfig.class)) { + TDengineConfig tDengineConfig = applicationContext.getBean(TDengineConfig.class); + TDDeviceLogDAO tDDeviceLogDAO = applicationContext.getBean(TDDeviceLogDAO.class); + initTDengine(tDengineConfig, tDDeviceLogDAO); + LOGGER.info("使用TDengine存储设备数据,初始化成功"); + }else{ + LOGGER.info("使用MySql存储设备数据,初始化成功"); + } + } + + /** + * @return + * @Method + * @Description 开始初始化加载系统参数, 创建数据库和超级表 + * @Param null + * @date 2022/5/22,0022 14:27 + * @author wxy + */ + public void initTDengine(TDengineConfig dengineConfig, TDDeviceLogDAO deviceLogMapper) { + try { + String dbName = dengineConfig.getDbName(); + // TODO 目前还不支持自动创建数据库 + int db = deviceLogMapper.createDB(dbName); + deviceLogMapper.createSTable(dbName); + } catch (Exception e) { + LOGGER.info("错误",e.getMessage()); + e.printStackTrace(); + } + + } + + /** + * @return + * @Method containBean + * @Description 根据类判断是否有对应bean + * @Param 类 + * @date 2022/5/22,0022 14:12 + * @author wxy + */ + private boolean containBean(@Nullable Class T) { + String[] beans = applicationContext.getBeanNamesForType(T); + if (beans == null || beans.length == 0) { + return false; + } else { + return true; + } + } +} diff --git a/springboot/wumei-iot/src/main/java/com/ruoyi/iot/tdengine/service/ILogService.java b/springboot/wumei-iot/src/main/java/com/ruoyi/iot/tdengine/service/ILogService.java new file mode 100644 index 00000000..f775ade5 --- /dev/null +++ b/springboot/wumei-iot/src/main/java/com/ruoyi/iot/tdengine/service/ILogService.java @@ -0,0 +1,25 @@ +package com.ruoyi.iot.tdengine.service; + +import com.ruoyi.iot.domain.DeviceLog; + +import com.ruoyi.iot.model.MonitorModel; +import org.springframework.stereotype.Service; + +import java.util.Date; +import java.util.List; + +/** + * @package iot.iot.log + * 类名: LogService + * 描述: 设备日志记录接口 + * 时间: 2022/5/19,0019 18:04 + * 开发人: admin + */ +public interface ILogService { + + int saveDeviceLog(DeviceLog deviceLog); + + List selectDeviceLogList(DeviceLog deviceLog); + + List selectMonitorList(DeviceLog deviceLog); +} diff --git a/springboot/wumei-iot/src/main/java/com/ruoyi/iot/tdengine/service/factory/LogServiceFactory.java b/springboot/wumei-iot/src/main/java/com/ruoyi/iot/tdengine/service/factory/LogServiceFactory.java new file mode 100644 index 00000000..49500315 --- /dev/null +++ b/springboot/wumei-iot/src/main/java/com/ruoyi/iot/tdengine/service/factory/LogServiceFactory.java @@ -0,0 +1,63 @@ +package com.ruoyi.iot.tdengine.service.factory; + +import com.ruoyi.framework.config.MyBatisConfig; +import com.ruoyi.iot.tdengine.service.impl.MySqlLogServiceImpl; +import com.ruoyi.iot.tdengine.service.impl.TdengineLogServiceImpl; +import com.ruoyi.iot.tdengine.config.TDengineConfig; +import com.ruoyi.iot.tdengine.service.ILogService; +import com.ruoyi.iot.mapper.DeviceLogMapper; +import com.ruoyi.iot.tdengine.dao.TDDeviceLogDAO; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.lang.Nullable; +import org.springframework.stereotype.Component; + +/** + * 类名: DeviceLogServiceImpl + * 描述: TODO + * 时间: 2022/5/19,0019 18:09 + * 开发人: wxy + */ +@Component +public class LogServiceFactory { + + @Autowired + private ApplicationContext applicationContext; + + @Bean + public ILogService getLogService() { + //先获取TDengine的配置,检测TDengine是否已经配置 + if (containBean(TDengineConfig.class)) { + TDengineConfig tDengineConfig = applicationContext.getBean(TDengineConfig.class); + TDDeviceLogDAO tDDeviceLogDAO = applicationContext.getBean(TDDeviceLogDAO.class); + ILogService logService = new TdengineLogServiceImpl(tDengineConfig, tDDeviceLogDAO); + return logService; + } else if (containBean(MyBatisConfig.class)) { + //没有配置TDengine,那么使用MySQL的日志配置 + DeviceLogMapper deviceLogMapper = applicationContext.getBean( DeviceLogMapper.class); + ILogService logService = new MySqlLogServiceImpl(deviceLogMapper); + return logService; + } else { + return null; + } + } + + /** + * @Method containBean + * @Description 根据类判断是否有对应bean + * @Param 类 + * @return + * @date 2022/5/22,0022 14:12 + * @author wxy + * + */ + private boolean containBean(@Nullable Class T) { + String[] beans = applicationContext.getBeanNamesForType(T); + if (beans == null || beans.length == 0) { + return false; + } else { + return true; + } + } +} diff --git a/springboot/wumei-iot/src/main/java/com/ruoyi/iot/tdengine/service/impl/MySqlLogServiceImpl.java b/springboot/wumei-iot/src/main/java/com/ruoyi/iot/tdengine/service/impl/MySqlLogServiceImpl.java new file mode 100644 index 00000000..ecd4719b --- /dev/null +++ b/springboot/wumei-iot/src/main/java/com/ruoyi/iot/tdengine/service/impl/MySqlLogServiceImpl.java @@ -0,0 +1,37 @@ +package com.ruoyi.iot.tdengine.service.impl; + +import com.ruoyi.iot.domain.DeviceLog; +import com.ruoyi.iot.tdengine.service.ILogService; +import com.ruoyi.iot.mapper.DeviceLogMapper; +import com.ruoyi.iot.model.MonitorModel; + +import java.util.List; + +/** + * 类名: MySqlLogServiceImpl + * 描述: MySQL存储日志实现类 + * 时间: 2022/5/22,0022 13:37 + * 开发人: admin + */ +public class MySqlLogServiceImpl implements ILogService { + + private DeviceLogMapper deviceLogMapper; + + public MySqlLogServiceImpl(DeviceLogMapper _deviceLogMapper){ + this.deviceLogMapper=_deviceLogMapper; + } + @Override + public int saveDeviceLog(DeviceLog deviceLog) { + return deviceLogMapper.insertDeviceLog(deviceLog); + } + + @Override + public List selectDeviceLogList(DeviceLog deviceLog) { + return deviceLogMapper.selectDeviceLogList(deviceLog); + } + + @Override + public List selectMonitorList(DeviceLog deviceLog) { + return deviceLogMapper.selectMonitorList(deviceLog); + } +} diff --git a/springboot/wumei-iot/src/main/java/com/ruoyi/iot/tdengine/service/impl/TdengineLogServiceImpl.java b/springboot/wumei-iot/src/main/java/com/ruoyi/iot/tdengine/service/impl/TdengineLogServiceImpl.java new file mode 100644 index 00000000..01322450 --- /dev/null +++ b/springboot/wumei-iot/src/main/java/com/ruoyi/iot/tdengine/service/impl/TdengineLogServiceImpl.java @@ -0,0 +1,54 @@ +package com.ruoyi.iot.tdengine.service.impl; + +import com.ruoyi.iot.domain.DeviceLog; +import com.ruoyi.iot.tdengine.service.ILogService; +import com.ruoyi.iot.model.MonitorModel; +import com.ruoyi.iot.tdengine.config.TDengineConfig; +import com.ruoyi.iot.tdengine.dao.TDDeviceLogDAO; +import com.ruoyi.iot.util.SnowflakeIdWorker; +import org.springframework.context.ApplicationContext; + +import java.util.List; + +/** + * 类名: TdengineLogServiceImpl + * 描述: TDengine存储日志数据实现类 + * 时间: 2022/5/22,0022 13:38 + * 开发人: admin + */ +public class TdengineLogServiceImpl implements ILogService { + + private ApplicationContext applicationContext; + + private TDDeviceLogDAO tdDeviceLogDAO; + + private TDengineConfig tDengineConfig; + + private SnowflakeIdWorker snowflakeIdWorker; + + private String dbName; + + public TdengineLogServiceImpl(TDengineConfig _tDengineConfig, TDDeviceLogDAO _tdDeviceLogDAO) { + this.tdDeviceLogDAO = _tdDeviceLogDAO; + this.tDengineConfig = _tDengineConfig; + snowflakeIdWorker=new SnowflakeIdWorker(1); + this.dbName=_tDengineConfig.getDbName(); + } + + @Override + public int saveDeviceLog(DeviceLog deviceLog) { + long logId = snowflakeIdWorker.nextId(); + deviceLog.setLogId(logId); + return tdDeviceLogDAO.save(dbName,deviceLog); + } + + @Override + public List selectDeviceLogList(DeviceLog deviceLog) { + return tdDeviceLogDAO.selectDeviceLogList(dbName,deviceLog); + } + + @Override + public List selectMonitorList(DeviceLog deviceLog) { + return tdDeviceLogDAO.selectMonitorList(dbName,deviceLog); + } +} diff --git a/springboot/wumei-iot/src/main/java/com/ruoyi/iot/util/SnowflakeIdWorker.java b/springboot/wumei-iot/src/main/java/com/ruoyi/iot/util/SnowflakeIdWorker.java new file mode 100644 index 00000000..ff5a11d3 --- /dev/null +++ b/springboot/wumei-iot/src/main/java/com/ruoyi/iot/util/SnowflakeIdWorker.java @@ -0,0 +1,104 @@ +package com.ruoyi.iot.util; + +public class SnowflakeIdWorker { + /** + * 开始时间:2020-01-01 00:00:00 + */ + private final long beginTs = 1577808000000L; + + private final long workerIdBits = 10; + + /** + * 2^10 - 1 = 1023 + */ + private final long maxWorkerId = -1L ^ (-1L << workerIdBits); + + private final long sequenceBits = 12; + + /** + * 2^12 - 1 = 4095 + */ + private final long maxSequence = -1L ^ (-1L << sequenceBits); + + /** + * 时间戳左移22位 + */ + private final long timestampLeftOffset = workerIdBits + sequenceBits; + + /** + * 业务ID左移12位 + */ + private final long workerIdLeftOffset = sequenceBits; + + /** + * 合并了机器ID和数据标示ID,统称业务ID,10位 + */ + private long workerId; + + /** + * 毫秒内序列,12位,2^12 = 4096个数字 + */ + private long sequence = 0L; + + /** + * 上一次生成的ID的时间戳,同一个worker中 + */ + private long lastTimestamp = -1L; + + public SnowflakeIdWorker(long workerId) { + if (workerId > maxWorkerId || workerId < 0) { + throw new IllegalArgumentException(String.format("WorkerId必须大于或等于0且小于或等于%d", maxWorkerId)); + } + + this.workerId = workerId; + } + + public synchronized long nextId() { + long ts = System.currentTimeMillis(); + if (ts < lastTimestamp) { + throw new RuntimeException(String.format("系统时钟回退了%d毫秒", (lastTimestamp - ts))); + } + + // 同一时间内,则计算序列号 + if (ts == lastTimestamp) { + // 序列号溢出 + if (++sequence > maxSequence) { + ts = tilNextMillis(lastTimestamp); + sequence = 0L; + } + } else { + // 时间戳改变,重置序列号 + sequence = 0L; + } + + lastTimestamp = ts; + + // 0 - 00000000 00000000 00000000 00000000 00000000 0 - 00000000 00 - 00000000 0000 + // 左移后,低位补0,进行按位或运算相当于二进制拼接 + // 本来高位还有个0<<63,0与任何数字按位或都是本身,所以写不写效果一样 + return (ts - beginTs) << timestampLeftOffset | workerId << workerIdLeftOffset | sequence; + } + + /** + * 阻塞到下一个毫秒 + * + * @param lastTimestamp + * @return + */ + private long tilNextMillis(long lastTimestamp) { + long ts = System.currentTimeMillis(); + while (ts <= lastTimestamp) { + ts = System.currentTimeMillis(); + } + + return ts; + } + + public static void main(String[] args) { + SnowflakeIdWorker snowflakeIdWorker = new SnowflakeIdWorker(7); + for (int i = 0; i < 10; i++) { + long id = snowflakeIdWorker.nextId(); + System.out.println(id); + } + } +} \ No newline at end of file diff --git a/springboot/wumei-iot/src/main/resources/mapper/tdengine/DatabaseMapper.xml b/springboot/wumei-iot/src/main/resources/mapper/tdengine/DatabaseMapper.xml new file mode 100644 index 00000000..f5a6853a --- /dev/null +++ b/springboot/wumei-iot/src/main/resources/mapper/tdengine/DatabaseMapper.xml @@ -0,0 +1,40 @@ + + + + + + + create database if not exists ${dbName}; + + + + + DROP database if exists ${dbName}; + + + + + use ${dbName}; + + + + create stable if not exists ${tableName} + (ts timestamp, + log_id BIGINT, + identity NCHAR(100), + log_type NCHAR(20), + log_value NCHAR(100), + device_id BIGINT, + device_name NCHAR(100), + serial_number NCHAR(100), + is_monitor int, + create_by NCHAR(100), + create_time timestamp, + remark NCHAR(1000), + ); + + + + \ No newline at end of file diff --git a/springboot/wumei-iot/src/main/resources/mapper/tdengine/TDDeviceLogMapper.xml b/springboot/wumei-iot/src/main/resources/mapper/tdengine/TDDeviceLogMapper.xml new file mode 100644 index 00000000..1bf0071b --- /dev/null +++ b/springboot/wumei-iot/src/main/resources/mapper/tdengine/TDDeviceLogMapper.xml @@ -0,0 +1,139 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + create database if not exists ${database}; + + + + + create STABLE if not exists ${database}.device_log + ( + ts timestamp, + log_id BIGINT, + log_type TINYINT, + `identity` BINARY(100), + `log_value` BINARY(100), + is_monitor TINYINT, + create_by BINARY(100), + create_time timestamp, + remark BINARY(500) + + ) + TAGS( + device_id BIGINT, + device_name BINARY(100), + serial_number BINARY(50)); + + + + create TABLE if not exists ${database}.${tableName} + USING ${database}.device_${deviceId} TAGS(log_type,is_monitor,create_by,create_time,remark) + (ts2 timestamp, + log_type BINARY(100) + ); + + + + + + INSERT INTO ${database}.device_${device.serialNumber} USING device_log + TAGS (#{device.deviceId},#{device.deviceName},#{device.serialNumber}) + VALUES (now, #{device.logId}, #{device.logType},#{device.identity},#{device.logValue},#{device.isMonitor},#{device.createBy},now,#{device.remark} ); + + + + delete from ${database}.device_${device.serialNumber} + + + log_id = #{logId} + + + device_id = #{deviceId} + + + serial_number = #{serialNumber} + + + + + + + + + + + \ No newline at end of file