初始化第一版influxORM

This commit is contained in:
2023-04-21 13:23:33 +08:00
parent 00731b674f
commit 8aeb21265c
18 changed files with 730 additions and 22 deletions

51
.gitignore vendored
View File

@@ -1,26 +1,33 @@
# ---> Java
# Compiled class file
*.class
HELP.md
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
# Log file
*.log
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
# BlueJ files
*.ctxt
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
replay_pid*
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/

78
pom.xml Normal file
View File

@@ -0,0 +1,78 @@
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.njcn</groupId>
<artifactId>influxdb-springboot-starter</artifactId>
<version>1.0.0</version>
<name>influxdb-springboot-starter</name>
<description>封装influxdb的orm工具</description>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<configuration-processor.version>2.3.12.RELEASE</configuration-processor.version>
<autoconfigure.version>2.0.0.RELEASE</autoconfigure.version>
<influxdb-java.version>2.18</influxdb-java.version>
</properties>
<developers>
<developer>
<name>hongawen</name>
<email>83944980@qq.com</email>
</developer>
</developers>
<dependencies>
<dependency>
<groupId>com.njcn</groupId>
<artifactId>common-core</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
<version>${configuration-processor.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>${autoconfigure.version}</version>
</dependency>
<dependency>
<groupId>org.influxdb</groupId>
<artifactId>influxdb-java</artifactId>
<version>${influxdb-java.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.sonatype.plugins</groupId>
<artifactId>nexus-staging-maven-plugin</artifactId>
<version>1.6.7</version>
<extensions>true</extensions>
<configuration>
<serverId>ossrh</serverId>
<nexusUrl>https://s01.oss.sonatype.org/</nexusUrl>
<autoReleaseAfterClose>false</autoReleaseAfterClose>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,27 @@
package com.njcn.influx.ano;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 删除记录注解
* @author hongawen
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Delete {
/**
* 用于传参
* @return String 参数内容
*/
String value();
/***
* 数据库名
* todo... 处理成获取配置文件内的,减少开发人员编码输出
*/
String database();
}

View File

@@ -0,0 +1,15 @@
package com.njcn.influx.ano;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 插入注解
* @author hongawen
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Insert {
}

View File

@@ -0,0 +1,14 @@
package com.njcn.influx.ano;
import java.lang.annotation.*;
/**
* 便于将方法中的参数赋值进注解内容中,通过#{paramName}
* @author hongawen
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
public @interface Param {
String value();
}

View File

@@ -0,0 +1,25 @@
package com.njcn.influx.ano;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 查询记录
* @author hongawen
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Select {
/***
* 查询sql
*/
String value();
/***
* 返回映射的实体对象
*/
Class resultType();
}

View File

@@ -0,0 +1,26 @@
package com.njcn.influx.base;
import com.njcn.influx.ano.Insert;
import java.util.List;
/**
* @author hongawen
*/
public interface InfluxDbBaseMapper<T> {
/***
* 插入数据
* @param entity 数据
*/
@Insert
void insertOne(T entity);
/***
* 批量插入数据
* @param entityList 数据
*/
@Insert
void insertBatch(List<T> entityList);
}

View File

@@ -0,0 +1,33 @@
package com.njcn.influx.base;
import com.njcn.influx.core.InfluxExecutor;
import com.njcn.influx.core.ParameterHandler;
import com.njcn.influx.core.ResultSetHandler;
import org.springframework.beans.factory.FactoryBean;
import javax.annotation.Resource;
import java.lang.reflect.Proxy;
public class InfluxProxyMapperFactory<T> implements FactoryBean {
@Resource
InfluxExecutor executor;
private Class<T> interfaceClass;
public InfluxProxyMapperFactory(Class<T> interfaceClass) {
this.interfaceClass = interfaceClass;
}
@Override
public Object getObject() throws Exception {
Object proxyInstance = Proxy.newProxyInstance(
interfaceClass.getClassLoader(), new Class[]{interfaceClass}, new ProxyMapper(new ParameterHandler(), executor, new ResultSetHandler()));
return proxyInstance;
}
@Override
public Class<?> getObjectType() {
return interfaceClass;
}
}

View File

@@ -0,0 +1,68 @@
package com.njcn.influx.base;
import com.njcn.influx.ano.Delete;
import com.njcn.influx.ano.Select;
import com.njcn.influx.ano.Insert;
import com.njcn.influx.core.InfluxExecutor;
import com.njcn.influx.core.ParameterHandler;
import com.njcn.influx.core.ResultSetHandler;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.List;
public class ProxyMapper implements InvocationHandler {
private ParameterHandler parameterHandler;
private InfluxExecutor executor;
private ResultSetHandler resultSetHandler;
public ProxyMapper(ParameterHandler parameterHandler, InfluxExecutor executor, ResultSetHandler resultSetHandler) {
this.parameterHandler = parameterHandler;
this.executor = executor;
this.resultSetHandler = resultSetHandler;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Annotation[] annotations = method.getAnnotations();
if (annotations.length == 1) {
Annotation annotation = annotations[0];
Class<? extends Annotation> annotationType = annotation.annotationType();
//是查询的
if (annotationType == Select.class) {
Select selectAnnotation = method.getAnnotation(Select.class);
//拼接sql
String sql = selectAnnotation.value();
Parameter[] parameters = method.getParameters();
sql = parameterHandler.handleParameter(parameters, args, sql);
//查询结果
Class resultType = selectAnnotation.resultType();
List<Object> list = executor.select(sql, resultType);
//根据返回类型返回结果
Class<?> returnType = method.getReturnType();
return resultSetHandler.handleResultSet(list, returnType);
}
//是插入的
if (annotationType == Insert.class) {
executor.insert(args);
}
//是删除的
if (annotationType == Delete.class) {
Delete deleteAnnotation = method.getAnnotation(Delete.class);
//拼接sql
String sql = deleteAnnotation.value();
Parameter[] parameters = method.getParameters();
String database = deleteAnnotation.database();
sql = parameterHandler.handleParameter(parameters, args, sql);
//执行sql
executor.delete(sql, database);
}
}
return null;
}
}

View File

@@ -0,0 +1,70 @@
package com.njcn.influx.base;
import com.njcn.influx.utils.InfluxStrUtil;
import com.njcn.influx.utils.ManualRegisterBeanUtil;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternUtils;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.util.ClassUtils;
import org.springframework.util.SystemPropertyUtils;
import javax.annotation.PostConstruct;
import java.io.IOException;
import java.util.HashSet;
public class ProxyMapperRegister {
private String mapperLocation;
ConfigurableApplicationContext applicationContext;
ResourceLoader resourceLoader;
public ProxyMapperRegister(String mapperLocation, ConfigurableApplicationContext applicationContext, ResourceLoader resourceLoader) {
this.mapperLocation = mapperLocation;
this.applicationContext = applicationContext;
this.resourceLoader = resourceLoader;
}
@PostConstruct
public void afterInit() {
//获取mapper包下所有的Mapper
HashSet<Class<?>> classes = new HashSet<>();
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX
.concat(ClassUtils.convertClassNameToResourcePath(SystemPropertyUtils.resolvePlaceholders(mapperLocation))
.concat("/**/*.class"));
ResourcePatternResolver resolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resourceLoader);
MetadataReader metadataReader;
try {
Resource[] resources = resolver.getResources(packageSearchPath);
for (Resource resource : resources) {
if (resource.isReadable()) {
metadataReader = metadataReaderFactory.getMetadataReader(resource);
String className = metadataReader.getClassMetadata().getClassName();
Class<?> aClass = Class.forName(className);
//当这个Mapper实现InfluxBaseMapper时加集合
Class<?>[] interfaces = aClass.getInterfaces();
for (Class<?> anInterface : interfaces) {
if (anInterface == InfluxDbBaseMapper.class) {
classes.add(aClass);
}
}
}
}
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
for (Class<?> aClass : classes) {
//注册接口类至工厂Bean再用动态代理生成对应Mapper
ManualRegisterBeanUtil.registerBean(applicationContext, InfluxStrUtil.captureName(aClass.getSimpleName()), InfluxProxyMapperFactory.class, aClass);
}
}
}

View File

@@ -0,0 +1,44 @@
package com.njcn.influx.config;
import com.njcn.influx.base.ProxyMapperRegister;
import com.njcn.influx.core.InfluxExecutor;
import org.influxdb.InfluxDB;
import org.influxdb.impl.InfluxDBMapper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ResourceLoader;
/**
* @author hongawen
* @version 1.0.0
*/
@Configuration
public class InfluxDbConfig {
/***
* influxMapper存放路径
*/
@Value("${spring.influx.mapper-location}")
private String mapperLocation;
@Bean(name = "influxDbMapper")
public InfluxDBMapper influxDBMapper(InfluxDB influxDb) {
influxDb.setLogLevel(InfluxDB.LogLevel.BASIC);
return new InfluxDBMapper(influxDb);
}
@Bean(name = "influxDbExecutor")
public InfluxExecutor executor(InfluxDB influxDb, InfluxDBMapper influxDbMapper) {
return new InfluxExecutor(influxDb, influxDbMapper);
}
@Bean(name = "proxyMapperRegister")
public ProxyMapperRegister proxyMapperRegister(ConfigurableApplicationContext applicationContext, ResourceLoader resourceLoader) {
return new ProxyMapperRegister(mapperLocation, applicationContext, resourceLoader);
}
}

View File

@@ -0,0 +1,107 @@
package com.njcn.influx.constant;
import cn.hutool.core.text.StrPool;
/**
* 拼接influx查询语句相关常量
*
* @author hongawen
* @version 1.0.0
* @date 2022年10月14日 14:02
*/
public interface InfluxDbSqlConstant {
/**
* "SELECT "
*/
String SELECT = "SELECT" + StrPool.C_SPACE;
/**
* "* "
*/
String ALL = "*" + StrPool.C_SPACE;
/**
* "FROM "
*/
String FROM = "FROM" + StrPool.C_SPACE;
/**
* " WHERE "
*/
String WHERE = StrPool.C_SPACE + "WHERE" + StrPool.C_SPACE;
/**
* " AND "
*/
String AND = StrPool.C_SPACE + "AND" + StrPool.C_SPACE;
/**
* " OR "
*/
String OR = StrPool.C_SPACE + "OR" + StrPool.C_SPACE;
/**
* " GROUP BY "
*/
String GB = StrPool.C_SPACE + "GROUP BY" + StrPool.C_SPACE;
/**
* " ORDER BY "
*/
String OB = StrPool.C_SPACE + "ORDER BY" + StrPool.C_SPACE;
/**
* “DESC ”
*/
String DESC = "DESC" + StrPool.C_SPACE;
/**
* " as value "
*/
String AS_VALUE = StrPool.C_SPACE + "as value" + StrPool.C_SPACE;
String EQ = "=";
String QM = "'";
String LBK = "(";
String RBK = ")";
String GT = ">";
String GE = ">=";
String LT = "<";
String LE = "<=";
/**
* influxDB函数拼接
*/
String MAX = "MAX";
String MIN = "MIN";
String AVG = "MEAN";
String NUM_95 = ",95";
String CP95 = "PERCENTILE";
/**
* “ tz('Asia/Shanghai')”
*/
String TZ = StrPool.C_SPACE + "tz('Asia/Shanghai')";
String TIME_AREA = "Asia/Shanghai";
/**
* 日起始时间
*/
String START_TIME = " 00:00:00";
/**
* 日结束时间
*/
String END_TIME = " 23:59:59";
/**
* 时间
*/
String TIME = "time" + StrPool.C_SPACE;
}

View File

@@ -0,0 +1,90 @@
package com.njcn.influx.core;
import com.njcn.influx.constant.InfluxDbSqlConstant;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import org.influxdb.InfluxDB;
import org.influxdb.annotation.Measurement;
import org.influxdb.dto.BatchPoints;
import org.influxdb.dto.Point;
import org.influxdb.dto.Query;
import org.influxdb.impl.InfluxDBMapper;
import java.util.ArrayList;
import java.util.List;
/**
* @author hongawen
*/
@NoArgsConstructor
@AllArgsConstructor
public class InfluxExecutor {
InfluxDB influxDb;
InfluxDBMapper influxDbMapper;
/***
* 查询数据方法
* @author hongawen
* @param sql 查询语句
* @param domainClass 映射实体
*/
public <E> List<E> select(String sql, Class domainClass) {
List<E> results = influxDbMapper.query(new Query(dealTimeZone(sql)), domainClass);
return results;
}
/***
* 插入数据
* @author hongawen
* @param args 数据内容
*/
public void insert(Object args[]) {
if (args.length != 1) {
throw new RuntimeException();
}
Object obj = args[0];
//插入的是集合类型的
if (obj instanceof List) {
List list = (ArrayList) obj;
if (list.size() > 0) {
Object firstObj = list.get(0);
Class<?> domainClass = firstObj.getClass();
List<Point> pointList = new ArrayList<>();
for (Object o : list) {
Point point = Point
.measurementByPOJO(domainClass)
.addFieldsFromPOJO(o)
.build();
pointList.add(point);
}
//获取数据库名和rp
Measurement measurement = firstObj.getClass().getAnnotation(Measurement.class);
String database = measurement.database();
String retentionPolicy = measurement.retentionPolicy();
BatchPoints batchPoints = BatchPoints
.builder()
.points(pointList)
.retentionPolicy(retentionPolicy).build();
influxDb.setDatabase(database);
influxDb.write(batchPoints);
}
} else {
//插入单个
influxDbMapper.save(obj);
}
}
/***
* 删除操作
* @author hongawen
* @param sql 数据库语句
* @param database 数据库名称
*/
public void delete(String sql, String database) {
influxDb.query(new Query(dealTimeZone(sql), database));
}
private String dealTimeZone(String originalSql){
return originalSql + InfluxDbSqlConstant.TZ;
}
}

View File

@@ -0,0 +1,41 @@
package com.njcn.influx.core;
import com.njcn.influx.ano.Param;
import java.lang.reflect.Parameter;
/**
* 参数处理器
*/
public class ParameterHandler {
/**
* 拼接sql
*
* @param parameters 参数名
* @param args 参数实际值
* @param sql 未拼接参数的sql语句
* @return 拼接好的sql
*/
public String handleParameter(Parameter[] parameters, Object[] args, String sql) {
for (int i = 0; i < parameters.length; i++) {
Class<?> parameterType = parameters[i].getType();
String parameterName = parameters[i].getName();
Param param = parameters[i].getAnnotation(Param.class);
if (param != null) {
parameterName = param.value();
}
if (parameterType == String.class) {
sql = sql.replaceAll("\\#\\{" + parameterName + "\\}", "'" + args[i] + "'");
sql = sql.replaceAll("\\$\\{" + parameterName + "\\}", args[i].toString());
} else {
sql = sql.replaceAll("\\#\\{" + parameterName + "\\}", args[i].toString());
sql = sql.replaceAll("\\$\\{" + parameterName + "\\}", args[i].toString());
}
}
return sql;
}
}

View File

@@ -0,0 +1,20 @@
package com.njcn.influx.core;
import java.util.List;
/**
* 结果集处理器
*/
public class ResultSetHandler {
public Object handleResultSet(List<Object> list, Class returnType) {
if (returnType == List.class) {
return list;
}
if (returnType != List.class) {
if (list.size() > 0) {
return list.get(0);
}
}
return null;
}
}

View File

@@ -0,0 +1,12 @@
package com.njcn.influx.utils;
/**
* @author hongawen
*/
public class InfluxStrUtil {
public static String captureName(String name) {
//UpperCase大写
name = name.substring(0, 1).toLowerCase() + name.substring(1);
return name;
}
}

View File

@@ -0,0 +1,30 @@
package com.njcn.influx.utils;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.ConfigurableApplicationContext;
/**
* 手动将类加入到spring容器中
* @author hongawen
*/
public class ManualRegisterBeanUtil {
public static void registerBean(ConfigurableApplicationContext applicationContext, String name, Class clazz,
Object... args) {
if (applicationContext.containsBean(name)) {
Object bean = applicationContext.getBean(name);
if (!bean.getClass().isAssignableFrom(clazz)) {
throw new RuntimeException("BeanName 重复 " + name);
}
}
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(clazz);
for (Object arg : args) {
beanDefinitionBuilder.addConstructorArgValue(arg);
}
BeanDefinition beanDefinition = beanDefinitionBuilder.getRawBeanDefinition();
BeanDefinitionRegistry beanFactory = (BeanDefinitionRegistry) applicationContext.getBeanFactory();
beanFactory.registerBeanDefinition(name, beanDefinition);
}
}

View File

@@ -0,0 +1 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.njcn.influx.config.InfluxDbConfig