TDengine与springboot集成,TDengine的jdbc的工具

TDengine 官方没有windows下的dll库,需要自行编译源码。

在linux下安装之后有现成so库,可以供jdbc的dirver连接需要使用。

TDengine 和springboot集成,如果使用mybaties,查询会出错,没有数据。

但是处理TDengine的数据一般只有新增和查询操作。

代码参见 https://github.com/yz4322gly/TDengineUtil.git

封装代码如下:

package cn.netuo.util;

import com.taosdata.jdbc.TSDBDriver;
import net.sf.cglib.beans.BeanMap;

import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author guolinyuan
 */
public class TDengineUtil
{
    private Connection connection;
    private boolean databaseColumnHumpToLine;

    /**
     *
     * @param url url 例如 : "jdbc:TAOS://127.0.0.1:6020/netuo_iot"
     * @param username 例如: "root"
     * @param password 例如: "taosdata"
     * @param databaseColumnHumpToLine 是否需要数据库列名下划线转驼峰
     */
    public TDengineUtil(String url, String username, String password, boolean databaseColumnHumpToLine) throws ClassNotFoundException, SQLException
    {
        Class.forName("com.taosdata.jdbc.TSDBDriver");
        String jdbcUrl = url;
        Properties connProps = new Properties();
        connProps.setProperty(TSDBDriver.PROPERTY_KEY_USER, username);
        connProps.setProperty(TSDBDriver.PROPERTY_KEY_PASSWORD, password);
        connProps.setProperty(TSDBDriver.PROPERTY_KEY_CONFIG_DIR, "/etc/taos");
        connProps.setProperty(TSDBDriver.PROPERTY_KEY_CHARSET, "UTF-8");
        connProps.setProperty(TSDBDriver.PROPERTY_KEY_LOCALE, "en_US.UTF-8");
        connProps.setProperty(TSDBDriver.PROPERTY_KEY_TIME_ZONE, "UTC-8");
        this.connection = DriverManager.getConnection(jdbcUrl, connProps);
        this.databaseColumnHumpToLine = databaseColumnHumpToLine;
    }

    /**
     *
     * @param connection
     * @param databaseColumnHumpToLine
     */
    public TDengineUtil(Connection connection, boolean databaseColumnHumpToLine)
    {
        this.connection = connection;
        this.databaseColumnHumpToLine = databaseColumnHumpToLine;
    }



    /**
     * 执行sql(无论是否返回结果),将结果注入到指定的类型实例中,且返回
     * 当查询到的数据大于一个时,取第一个
     * 

* 对象遵从以下说明
* 1.对象字段为String类型,数据库类型(通过jdbc读取到的)无论什么类型,都将调用Object.toString方法注入值
* 2.对象字段为数据库类型(通过jdbc读取到的)一致的情况下,将会直接注入
* 3.对象字段与数据库类型(通过jdbc读取到的)不一致的情况下,将尝试使用{@link Class#cast(Object)}方法转型,失败此值会是类型默认值(故实体推荐使用封装类型)
* 4.对象字段为{@link Date}时,数据库类型为Date才可以注入,如果为long(例如TDengine)将会被当作毫秒的时间戳注入
* * @param sql 要执行的sql * @param clazz 要注入的实体类型 * @param 要注入的实体类型 * @return * @throws IllegalAccessException * @throws InstantiationException * @throws SQLException */ public T getOne(String sql, Class clazz) throws IllegalAccessException, InstantiationException, SQLException { Method[] setterMethods = getSetterMethods(clazz); ResultSet resultSet = connection.createStatement().executeQuery(sql); //只有一个结果直接下一个就行 resultSet.next(); return resultSetToObject(resultSet, setterMethods, clazz); } /** * 执行sql(无论是否返回结果),将结果注入到指定的类型实例中,且返回 * 当查询到的结果没有时,返回一个大小为0的list; *

* 对象遵从以下说明
* 1.对象字段为String类型,数据库类型(通过jdbc读取到的)无论什么类型,都将调用Object.toString方法注入值
* 2.对象字段为数据库类型(通过jdbc读取到的)一致的情况下,将会直接注入
* 3.对象字段与数据库类型(通过jdbc读取到的)不一致的情况下,将尝试使用{@link Class#cast(Object)}方法转型,失败此值会是类型默认值(故实体推荐使用封装类型)
* 4.对象字段为{@link Date}时,数据库类型为Date才可以注入,如果为long(例如TDengine)将会被当作毫秒的时间戳注入
* * @param sql 要执行的sql * @param clazz 要注入的实体类型 * @param 要注入的实体类型 * @return * @throws IllegalAccessException * @throws InstantiationException * @throws SQLException */ public List getList(String sql, Class clazz) throws IllegalAccessException, InstantiationException, SQLException { List list = new ArrayList<>(); Method[] setterMethods = getSetterMethods(clazz); ResultSet resultSet = connection.createStatement().executeQuery(sql); while (resultSet.next()) { list.add(resultSetToObject(resultSet, setterMethods, clazz)); } return list; } /** * 插入对象到指定的表里面 * @param tableName * @param o * @return * @throws SQLException */ @SuppressWarnings("all") public boolean insert(String tableName,Object o) throws SQLException { Class clazz = o.getClass(); Map map = BeanMap.create(o); String sql = createInsertSql(tableName,map); return connection.createStatement().execute(sql); } /** * 生成插入sql语句 * @param tableName * @param map * @return */ public static String createInsertSql(String tableName,Map map) { StringBuilder buffer = new StringBuilder(); buffer.append("INSERT INTO ").append(tableName).append(" ("); Set> set = map.entrySet(); StringBuilder keys = new StringBuilder(" "); StringBuilder value = new StringBuilder(" "); for (Map.Entry entry : set) { keys.append(humpToLine(entry.getKey())).append(","); try { if (entry.getValue().getClass().equals(Date.class)) { Date d = (Date)entry.getValue(); value.append(d.getTime()).append(","); } else { value.append("'").append(entry.getValue()).append("'").append(","); } } catch (Exception ignored) { } } keys.deleteCharAt(keys.length()-1); value.deleteCharAt(value.length()-1); buffer.append(keys).append(") VALUES( ").append(value).append(")"); return buffer.toString(); } /** * 将resultSet注入到指定的类型实例中,且返回 * 对象遵从以下说明
* 1.对象字段为String类型,数据库类型(通过jdbc读取到的)无论什么类型,都将调用Object.toString方法注入值
* 2.对象字段为数据库类型(通过jdbc读取到的)一致的情况下,将会直接注入
* 3.对象字段与数据库类型(通过jdbc读取到的)不一致的情况下,将尝试使用{@link Class#cast(Object)}方法转型,失败此值会是类型默认值(故实体推荐使用封装类型)
* 4.对象字段为{@link Date}时,数据库类型为Date才可以注入,如果为long(例如TDengine)将会被当作毫秒的时间戳注入
*

* 注意,此方法只会注入一个结果,不会循环{@link ResultSet#next()}方法,请从外部调用。
* 传入setterMethods的目的是为了方便外部循环使用此方法,这样方法内部不会重复调用,提高效率
* * @param resultSet 查询结果,一定要是{@link ResultSet#next()}操作过的,不然没有数据 * @param setterMethods clazz对应的所有setter方法,可以使用{@link this#getSetterMethods(Class)}获取 * @param clazz 注入对象类型 * @param 注入对象类型 * @return * @throws IllegalAccessException * @throws InstantiationException */ public T resultSetToObject(ResultSet resultSet, Method[] setterMethods, Class clazz) throws IllegalAccessException, InstantiationException { T result; try { result = clazz.newInstance(); } catch (InstantiationException e) { System.out.println("请检查类" + clazz.getCanonicalName() + "是否有无参构造方法"); throw e; } for (Method method : setterMethods) { try { String fieldName = getFieldNameBySetter(method); //因为标准的setter方法只会有一个参数,所以取一个就行了 Class getParamClass = method.getParameterTypes()[0]; //获得查询的结果 Object resultObject; //是否启用驼峰转下划线规则获得数据库字段名 if (databaseColumnHumpToLine) { resultObject = resultSet.getObject(humpToLine(fieldName)); } else { resultObject = resultSet.getObject(fieldName); } //如果实体类的类型是String类型,那么无论x数据库类型是什么,都调用其toString方法获取值 if (getParamClass.equals(String.class)) { method.invoke(result, resultObject.toString()); } else if (getParamClass.equals(Date.class) && resultObject.getClass().equals(Long.class)) { method.invoke(result, new Date((Long) resultObject)); } else { try { method.invoke(result, resultObject); } catch (IllegalArgumentException e) { //对象字段与数据库类型(通过jdbc读取到的)不一致的情况下,将尝试强制转型 method.invoke(result, getParamClass.cast(resultObject)); } } } catch (Exception ignored) { //所有的转型都失败了,则使用默认值 } } return result; } /** * 通过setter method,获取到其对应的属性名 * * @param method * @return */ public static String getFieldNameBySetter(Method method) { return toLowerCaseFirstOne(method.getName().substring(3)); } /** * 获取指定类型方法的所有的setter方法 * 方法属性名为key,对应的方法为value * * @param clazz * @return */ public static Map getSetterMethodsMap(Class clazz) { Method[] methods = clazz.getMethods(); Map setterMethods = new HashMap<>(methods.length / 2); for (Method m : methods) { if (m.getName().startsWith("set")) { setterMethods.put(toLowerCaseFirstOne(m.getName().substring(3)), m); } } return setterMethods; } /** * 获取指定类型方法的所有的setter方法 * * @param clazz * @return */ public static Method[] getSetterMethods(Class clazz) { Method[] methods = clazz.getMethods(); Method[] setterMethods = new Method[methods.length / 2]; int i = 0; for (Method m : methods) { if (m.getName().startsWith("set")) { setterMethods[i] = m; i++; } } return setterMethods; } /** * 首字母转小写 */ public static String toLowerCaseFirstOne(String s) { if (Character.isLowerCase(s.charAt(0))) { return s; } else { return Character.toLowerCase(s.charAt(0)) + s.substring(1); } } /** * 首字母转大写 */ public static String toUpperCaseFirstOne(String s) { if (Character.isUpperCase(s.charAt(0))) { return s; } else { return Character.toUpperCase(s.charAt(0)) + s.substring(1); } } private static Pattern linePattern = Pattern.compile("_(\\w)"); /** 下划线转驼峰 */ public static String lineToHump(String str) { str = str.toLowerCase(); Matcher matcher = linePattern.matcher(str); StringBuffer sb = new StringBuffer(); while (matcher.find()) { matcher.appendReplacement(sb, matcher.group(1).toUpperCase()); } matcher.appendTail(sb); return sb.toString(); } private static Pattern humpPattern = Pattern.compile("[A-Z]"); /** * 驼峰转下划线,效率比上面高 */ public static String humpToLine(String str) { Matcher matcher = humpPattern.matcher(str); StringBuffer sb = new StringBuffer(); while (matcher.find()) { matcher.appendReplacement(sb, "_" + matcher.group(0).toLowerCase()); } matcher.appendTail(sb); return sb.toString(); } }

实例代码如下

package cn.netuo.util;

import java.util.List;


public class Main
{
    public static void main(String[] args) throws Exception
    {
        TDengineUtil util = new TDengineUtil("jdbc:TAOS://127.0.0.1:6020/netuo_iot","root","taosdata",true);

//        util.insert("v1_001",new cn.netuo.util.IotReceiptUploadDataEntity(new Date(),null,"33.3",true,"12","1234",12,"22.3","30","14",new Date()));
        List list = util.getList("select * from  v1_001",IotReceiptUploadDataEntity.class);
        System.out.println(list);
    }
}

实体类如下

package cn.netuo.util;

import java.util.Date;

/**
 * @author guolinyuan
 */
public class IotReceiptUploadDataEntity
{

    /**
     * lng : 经纬度
     * lat : 经纬度
     * isCharging : 电池是否在充电
     * battery : 电池电量
     * workingTime : 连续开机时间
     * ei : 业务电流(A)
     * ep : 业务功率(W)
     * tmp : 温度
     * humidity : 湿度
     * downtime : 上次停机时间,时间戳,精确到毫秒的(本文时间戳均为精确到毫秒的)
     */
    private Date ts;
    private String lng;
    private String lat;
    private Boolean isCharging;
    private String battery;
    private String workingTime;
    private Integer ei;
    private String ep;
    private String tmp;
    private String humidity;
    private Date downtime;

    public IotReceiptUploadDataEntity()
    {
    }

    public IotReceiptUploadDataEntity(Date ts, String lng, String lat, Boolean isCharging, String battery, String workingTime, Integer ei, String ep, String tmp, String humidity, Date downtime)
    {
        this.ts = ts;
        this.lng = lng;
        this.lat = lat;
        this.isCharging = isCharging;
        this.battery = battery;
        this.workingTime = workingTime;
        this.ei = ei;
        this.ep = ep;
        this.tmp = tmp;
        this.humidity = humidity;
        this.downtime = downtime;
    }

    public void setEi(Integer ei)
    {
        this.ei = ei;
    }

    public Date getTs()
    {
        return ts;
    }

    public void setTs(Date ts)
    {
        this.ts = ts;
    }

    public String getLng()
    {
        return lng;
    }

    public void setLng(String lng)
    {
        this.lng = lng;
    }

    public String getLat()
    {
        return lat;
    }

    public void setLat(String lat)
    {
        this.lat = lat;
    }

    public Boolean getIsCharging()
    {
        return isCharging;
    }

    public void setIsCharging(Boolean isCharging)
    {
        this.isCharging = isCharging;
    }

    public String getBattery()
    {
        return battery;
    }

    public void setBattery(String battery)
    {
        this.battery = battery;
    }

    public String getWorkingTime()
    {
        return workingTime;
    }

    public void setWorkingTime(String workingTime)
    {
        this.workingTime = workingTime;
    }


    public String getEp()
    {
        return ep;
    }

    public void setEp(String ep)
    {
        this.ep = ep;
    }

    public String getTmp()
    {
        return tmp;
    }

    public void setTmp(String tmp)
    {
        this.tmp = tmp;
    }

    public String getHumidity()
    {
        return humidity;
    }

    public void setHumidity(String humidity)
    {
        this.humidity = humidity;
    }

    public Date getDowntime()
    {
        return downtime;
    }

    public void setDowntime(Date downtime)
    {
        this.downtime = downtime;
    }

    @Override
    public String toString()
    {
        return "cn.netuo.util.IotReceiptUploadDataEntity{" +
                "ts=" + ts +
                ", lng='" + lng + '\'' +
                ", lat='" + lat + '\'' +
                ", isCharging='" + isCharging + '\'' +
                ", battery='" + battery + '\'' +
                ", workingTime='" + workingTime + '\'' +
                ", ei='" + ei + '\'' +
                ", ep='" + ep + '\'' +
                ", tmp='" + tmp + '\'' +
                ", humidity='" + humidity + '\'' +
                ", downtime='" + downtime + '\'' +
                '}';
    }
}

 

你可能感兴趣的:(java,TDengine,springboot,mybaties,大数据,数据库)