时序数据库influxdb Java

spring接入influxdb记录日志。

docker-compose 安装 influxdb

version: '2'
services:
  influxdb:
    image: influxdb
    container_name: influxdb
    volumes:
      - /data/influxdb/conf:/etc/influxdb
      - /data/influxdb/data:/var/lib/influxdb/data
      - /data/influxdb/meta:/var/lib/influxdb/meta
      - /data/influxdb/wal:/var/lib/influxdb/wal
    ports:
      - "8086:8086"
    restart: always

maven依赖:

        <!-- https://mvnrepository.com/artifact/org.influxdb/influxdb-java -->
        <dependency>
            <groupId>org.influxdb</groupId>
            <artifactId>influxdb-java</artifactId>
            <version>2.19</version>
        </dependency>
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
        </dependency>
    </dependencies>

参考的开源项目:

https://github.com/ashishdoneriya/influxdb-java

 

1

设置好数据库连接设置

influx:
  username: admin
  password: admin
  host: 127.0.0.1
  port: 8086
  database: logs

2

将Configuration注册到spring容器

package com.wooki.feature.influxdb.entity;

import com.wooki.feature.influxdb.constant.Constants;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Data
@Component
public class Configuration {
	
	private String protocol = Constants.HTTP;
	@Value("${influx.host}")
	private String host;
	@Value("${influx.port}")
	private String port;
	@Value("${influx.username}")
	private String username;
	@Value("${influx.password}")
	private String password;
	@Value("${influx.database}")
	private String database;

	public Configuration() {
	}

	public Configuration(String host, String port, String username, String password, String database) {
		this.host = host.toLowerCase();
		this.port = port;
		this.username = username;
		this.password = password;
		this.database = database;
	}
	
	public Configuration(String protocol, String host, String port, String username, String password, String database) {
		this(host, port, username, password, database);
		this.protocol = protocol;
	}

}

3

自己写service,使用MySQL语法,拼接sql语句,实现insert、query基本功能,批量插入写的较简单

package com.wooki.feature.influxdb.service.impl;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.plugins.Page;
import com.wooki.feature.influxdb.util.Utilities;
import com.wooki.feature.influxdb.entity.*;
import com.wooki.feature.influxdb.service.InfluxDBService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.net.URISyntaxException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author aobs
 * @date 2020-06-22 17:28
 */
@Service
public class InfluxDBServiceImpl implements InfluxDBService {

    @Autowired
    Configuration configuration;

    @Override
    public void createDatabase(String name) throws Exception {
        configuration.setDatabase(name);
        Utilities.createDatabase(configuration);
    }

    @Override
    public void insert(InfluxDBInsert influxDBInsert) throws Exception {
        DataWriter writer = new DataWriter(configuration);
        // 数据库
        writer.setMeasurement(influxDBInsert.getType());
        // Default is in seconds
        writer.setTimeUnit(TimeUnit.MILLISECONDS);
        writer.addField("deviceName" , influxDBInsert.getDeviceName());
        writer.addField("msg" , influxDBInsert.getMsg());
        writer.addField("body" , influxDBInsert.getBody());
        // 企业id 做索引
        writer.addTag("enterpriseId", String.valueOf(influxDBInsert.getEnterpriseId()));
        // If we'll set time it will set automatically
        writer.setTime(influxDBInsert.getTime().getTime());
        writer.writeData();
    }

    @Override
    public void insertBatch(List<InfluxDBInsert> influxDBInserts) throws Exception {
        DataWriter writer = new DataWriter(configuration);
        writer.setTimeUnit(TimeUnit.MILLISECONDS);
        for (InfluxDBInsert influxDBInsert : influxDBInserts) {
            // Influxdb saves one point at one time. To add another point at same
            // time we can use tags otherwise it will override the previous point.
            writer.setMeasurement(influxDBInsert.getType());
            writer.addField("deviceName" , influxDBInsert.getDeviceName());
            writer.addField("msg" , influxDBInsert.getMsg());
            writer.addTag("enterpriseId", String.valueOf(influxDBInsert.getEnterpriseId()));
            writer.setTime(influxDBInsert.getTime().getTime());
            writer.writeData();
        }
    }

    @Override
    public InfluxResultSet query(InfluxDBQuery influxDBQuery) throws IOException, URISyntaxException {
        Integer current = influxDBQuery.getCurrent();
        if (current == null) {
            current = 1;
            influxDBQuery.setCurrent(current);
        }
        Integer influxDBQuerySize = influxDBQuery.getSize();
        if (influxDBQuerySize == null) {
            influxDBQuerySize = 10;
            influxDBQuery.setSize(influxDBQuerySize);
        }
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(DatePattern.NORM_DATETIME_PATTERN);
        String condition = " * ";
        String countPagesCondition = " count(msg) ";
        StringBuffer querySQL = new StringBuffer("select "+condition+" from ");
        StringBuffer queryCount = new StringBuffer("select " + countPagesCondition + " from ");
        String type = influxDBQuery.getType();
        // 类型
        querySQL.append("\""+type+"\"").append(" where 1 = 1 ");
        queryCount.append("\""+type+"\"").append(" where 1 = 1 ");
        /**
         * tag索引存储类型为string,使用单引号查值
         */
        querySQL.append(" and enterpriseId = '" + influxDBQuery.getEnterpriseId() + "' ");
        queryCount.append(" and enterpriseId = '" + influxDBQuery.getEnterpriseId() + "' ");
        // 设备名称
        String deviceName = influxDBQuery.getDeviceName();
        if (deviceName != null) {
            querySQL.append(" and deviceName=~/"+deviceName+"/ ");
            queryCount.append(" and deviceName=~/"+deviceName+"/ ");
        }
        // 时间范围
        Date beginTime = influxDBQuery.getBeginTime();
        Date endTime = influxDBQuery.getEndTime();
        if (beginTime == null) {
            beginTime = DateUtil.beginOfDay(new Date());
        }
        if (endTime == null) {
            endTime = DateUtil.endOfDay(new Date());
        }
        querySQL.append(" and time >= " + "'"+simpleDateFormat.format(beginTime)+"'");
        queryCount.append(" and time >= " + "'"+simpleDateFormat.format(beginTime)+"'");
        querySQL.append(" and time <= " + "'"+simpleDateFormat.format(endTime) + "'");
        queryCount.append(" and time <= " + "'"+simpleDateFormat.format(endTime) + "'");
        /**
         * 分页,offset从0开始
         * 排序
         */
        influxDBQuery = countPage(influxDBQuery);
        querySQL.append(" ORDER BY time DESC ");
        querySQL.append(" LIMIT "+influxDBQuery.getCurrent() +" OFFSET " + influxDBQuery.getSize());
        // pages 总页数
        Query queryPages = new Query();
        queryPages.setCustomQuery(String.valueOf(queryCount));
        DataReader readerPages = new DataReader(queryPages, configuration);
        InfluxResultSet result = readerPages.getResult();
        List<InfluxResultSet.Result> results = result.getResults();
        InfluxResultSet.Result result1 = results.get(0);
        List<InfluxResultSet.Result.Series> series = result1.getSeries();
        InfluxResultSet.Result.Series series1 = series.get(0);
        List<List<Object>> values = series1.getValues();
        List<Object> list = values.get(0);
        Object o = list.get(1);
        Double sizeDoube = (Double) o;
        int size = sizeDoube.intValue();
        // 时间时区函数,放最后
        querySQL.append(" tz('Asia/Shanghai')");
        Query query = new Query();
        query.setCustomQuery(String.valueOf(querySQL));
        DataReader dataReader = new DataReader(query, configuration);
        InfluxResultSet resultSet = dataReader.getResult();
        resultSet.setTotal(size);
        resultSet.setPages(size % influxDBQuerySize == 0 ? size / influxDBQuerySize : size / influxDBQuerySize + 1);
        resultSet.setCurrent(current);
        resultSet.setSize(influxDBQuerySize);
        return resultSet;
    }

    private InfluxDBQuery countPage(InfluxDBQuery influxDBQuery){
        int current = influxDBQuery.getCurrent();
        int size = influxDBQuery.getSize();
        int limit = size;
        int offset = (current-1) * limit;
        influxDBQuery.setCurrent(limit);
        influxDBQuery.setSize(offset);
        return influxDBQuery;
    }

}

4

写入数据时指定编码格式,参考的开源项目为老外写的,此处改为utf-8,否则存入的中文乱码

package com.wooki.feature.influxdb.entity;

import cn.hutool.core.util.CharsetUtil;
import com.google.gson.Gson;
import com.wooki.feature.influxdb.constant.Constants;
import com.wooki.feature.influxdb.util.TimeUtil;
import org.apache.http.HttpEntity;
import org.apache.http.StatusLine;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.TimeUnit;

import static com.wooki.feature.influxdb.constant.Constants.*;

public class DataWriter {

	private Configuration configuration;

	private String tableName;

	private Map<String, Object> fields;
	
	private Map<String, String> tags;

	private TimeUnit timeUnit;

	private Long time;

	public DataWriter(Configuration configuration) throws Exception {
		this.configuration = configuration;
	}

	public void writeData() throws Exception {
		if (tableName == null || tableName.isEmpty() || fields == null || fields.isEmpty()) {
			throw new Exception(INSUFFICIENT_INFORMATION_TO_WRITE_DATA);
		}
		// Sending data in the format of
		// tableName,tag_key1=tag_value1,tag_key2=tag_value2 column1=value1,column2=value2,column3=value3 timestamp
		StringBuffer sb = new StringBuffer(tableName);
		
		// Adding Tags
		if (tags != null && !tags.isEmpty()) {
			for (Entry<String, String> tag : tags.entrySet()) {
				sb.append(COMMA).append(tag.getKey()).append(EQUAL).append(tag.getValue());
			}
		}
		sb.append(Constants.SPACE);
		Entry<String, Object> e;
		// Adding Columns
		Iterator<Entry<String, Object>> fieldsIterator = fields.entrySet().iterator();
		if (fieldsIterator.hasNext()) {
			e = fieldsIterator.next();
			sb.append(e.getKey()).append(EQUAL).append(parseValue(e.getValue()));
		}
		while (fieldsIterator.hasNext()) {
			e = fieldsIterator.next();
			sb.append(COMMA).append(e.getKey()).append(EQUAL).append(parseValue(e.getValue()));
		}
		sb.append(SPACE);
		if (time != null) {
			sb.append(time);
		} else {
			sb.append(System.currentTimeMillis() / 1000);
		}
		CloseableHttpClient httpClient = null;
		try {
			// Sending data
			httpClient = HttpClients.createDefault();
			HttpPost httpPost = new HttpPost(getURL());
			httpPost.setEntity(new StringEntity(sb.toString(), CharsetUtil.charset("UTF-8")));
			CloseableHttpResponse response = httpClient.execute(httpPost);
			StatusLine statusLine = response.getStatusLine();
			if (statusLine.getStatusCode() != 204) {
				HttpEntity responseEntity = response.getEntity();
				if (responseEntity != null) {
					InfluxResultSet influxResultSet = new Gson().fromJson(EntityUtils.toString(responseEntity), InfluxResultSet.class);
					String error = influxResultSet.getError();
					if (error != null && !error.isEmpty()) {
						throw new Exception(error);
					}
				}
			}
		} finally {
			fields.clear();
			if (tags != null) {
				tags.clear();
			}
			if (httpClient != null) {
				httpClient.close();
			}
		}
	}
	
	private String parseValue(Object value) {
		if (value instanceof Integer) {
			return String.valueOf(value) + Constants.I;
		} else if (value instanceof Double || value instanceof Float) {
			return String.valueOf(value);
		} else if (value instanceof Boolean) {
			return String.valueOf((boolean) value);
		} else {
			return BACKSLASH_QUOTATION + value + BACKSLASH_QUOTATION;
		}
	}
	
	// create and get url to send post request
	private URI getURL() throws URISyntaxException {
		URIBuilder uriBuilder = new URIBuilder();
		int port = Integer.parseInt(configuration.getPort());
		if (timeUnit == null) {
			timeUnit = TimeUnit.SECONDS;
		}
		uriBuilder.setScheme(configuration.getProtocol()).setHost(configuration.getHost())
				.setPort(port).setPath(Constants.WRITE)
				.setParameter(Constants.DB, configuration.getDatabase())
				.setParameter(Constants.U, configuration.getUsername())
				.setParameter(Constants.P, configuration.getPassword())
				.setParameter(Constants.PRECISION, TimeUtil.toTimePrecision(timeUnit));
		return uriBuilder.build();
	}
	
	public void setMeasurement(String measurementName) {
		this.tableName = measurementName;
	}

	@Deprecated
	public void setTableName(String tableName) {
		this.tableName = tableName;
	}

	public void setFields(Map<String, Object> fields) {
		this.fields = fields;
	}

	public Map<String, String> getTags() {
		return tags;
	}

	public void setTags(Map<String, String> tags) {
		this.tags = tags;
	}
	
	public void addTag(String tagKey, String tagValue) {
		if (tags == null) {
			tags = new HashMap<String, String>();
		}
		tags.put(tagKey, tagValue);
	}

	public void setTime(Long time, TimeUnit timeUnit) {
		this.time = time;
		this.setTimeUnit(timeUnit);
	}

	/**
	 * Set time unit, Default is in seconds.
	 * @param timeUnit
	 */
	public void setTimeUnit(TimeUnit timeUnit) {
		this.timeUnit = timeUnit;
	}

	public void setTime(Long time) {
		this.time = time;
	}

	public void addField(String columnName, Object value) {
		if (fields == null) {
			fields = new HashMap<String, Object>();
		}
		fields.put(columnName, value);
	}

}

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值