JSON解析入库,MYSQL

需要将json格式的报文存到mysql中,支持后期从mysql恢复成json

支持表自动创建(含表说明),表字段自动创建(类型、长度自动扩展)

用到Jfinal,mysql

需要有一个表clientlog存原始报文,还需要有一个表存表关系sys_tbl_tree(mysql表名有长度限制,所以会用到真实表名与原始表名)

CREATE TABLE `sys_tbl_tree` (
  `ID` int(11) NOT NULL AUTO_INCREMENT,
  `TABLE_NAME` varchar(500) DEFAULT NULL COMMENT '真实表名',
  `ORG_NAME` varchar(500) DEFAULT NULL COMMENT 'table原始表名',
  `PARENT` varchar(500) DEFAULT NULL,
  `TYPE` int(1) DEFAULT '1' COMMENT '1多对1 2 1对1',
  PRIMARY KEY (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=161 DEFAULT CHARSET=utf8 COMMENT='系统-表结构关系';

CREATE TABLE `clientlog` (
  `ID` int(11) NOT NULL AUTO_INCREMENT,
  `method` varchar(50) DEFAULT NULL COMMENT '接口方法',
  `params` longtext,
  PRIMARY KEY (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=3509 DEFAULT CHARSET=utf8 COMMENT='系统-报文日志';

解析报文入库

1.先将原始报文存到clientlog表中(Clientlog model请用jfinal官方提供的工具生成)

2.MysqlTableColumnUtil.init();全局的只需要调用一次,我放在JFinalConfig的onStart方法中了

3.new MysqlTableColumnUtil().apiDataInDo(data, bean);data为json报文,bean为CheckUserBean

public class CheckUserBean extends LanlinUtil {
    /**
     * 请求方法中文描述
     */
    public String portInfoName;
     /**
     * json报文
     */
    public String params;
     /**
     * json报文存库
     */
    public Clientlog clientlog;

}
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import bean.CheckUserBean;
import com.jfinal.kit.HashKit;
import com.jfinal.kit.PropKit;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Record;

public class MysqlTableColumnUtil extends LanlinUtil {

    public static final String VARCHAR = "VARCHAR";
    public static final String TEXT = "TEXT";
    public static final String LONGTEXT = "LONGTEXT";
    
    /**
     * 自动处理表全部用这个做主键
     */
    public static final String CDEC_UUID = "CDEC_UUID";

    public static synchronized void init() {
        String table_schema = PropKit.get("table_schema");
        List<Record> tables = Db.use("information_schema").find("select TABLE_NAME from TABLES where TABLE_SCHEMA = '" + table_schema + "'");
        List<Record> colomns = Db.use("information_schema").find("select TABLE_NAME, COLUMN_NAME, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH, NUMERIC_PRECISION, NUMERIC_SCALE from COLUMNS where TABLE_SCHEMA = '" + table_schema + "'");
        for(Record table : tables) {
            String TABLE_NAME = table.getStr("TABLE_NAME");
            List<Record> childs = new LinkedList<Record>();
            for(Record cl : colomns) {
                String t = cl.getStr("TABLE_NAME");
                if(null != t && t.equals(TABLE_NAME)) {
                    cl.remove("TABLE_NAME");
                    childs.add(cl);
                }
            }
            table.set("COLOMNS", childs);
        }
        MysqlTableColumnUtil.tables = tables;
    }

    // "TABLE_NAME","TABLE_COMMENT", "COLOMNS" : List<Record> {"DATA_TYPE","CHARACTER_MAXIMUM_LENGTH","NUMERIC_PRECISION","NUMERIC_SCALE"}

    /**
     * TINYINT 1 字节 (-128,127) SMALLINT 2 字节 (-32 768,32 767) MEDIUMINT 3 字节 (-8 388 608,8 388 607) INT或INTEGER 4 字节 (-2 147 483 648,2 147 483 647)
     * BIGINT 8 字节 (-9 233 372 036 854 775 808,9 223 372 036 854 775 807) FLOAT 4 字节 (-3.402 823 466 E+38,1.175 494 351 E-38),0,(1.175 494 351
     * E-38,3.402 823 466 351 E+38) DOUBLE 8 字节 (1.797 693 134 862 315 7 E+308,2.225 073 858 507 201 4 E-308),0,(2.225 073 858 507 201 4 E-308,1.797
     * 693 134 862 315 7 E+308) DECIMAL 对DECIMAL(M,D) ,如果M>D,为M+2否则为D+2
     */

    /**
     * DATE 3字节 TIME 3字节 YEAR 1字节 DATETIME 8字节 TIMESTAMP 8字节
     */

    /**
     * CHAR 255字节 VARCHAR 65535字节 TINYTEXT 255字节 TEXT 65535字节 LONGTEXT 4294967295字节
     */

    /**
     * {
     *  "TABLE_NAME" : "表名", 
     *  "TABLE_COMMENT" : "备注",
     *  "COLOMNS" : { 
     *      "COLUMN_NAME" : "字段名",
     *      "DATA_TYPE" : "字段类型"
     *      "CHARACTER_MAXIMUM_LENGTH" : "varchar,text等最大长度"
     *      "NUMERIC_PRECISION" : "数值型的长度", "NUMERIC_SCALE" : "数值型的小数位" 
     *    } 
     * } 
     * 所有字段统一处理成VARCHAR,TEXT,LONGTEXT
     */
    public static List<Record> tables;
    
    /**
     * @param tableName
     * @return 根据表名获取相关表
     */
    public static Record getTable(String tableName) {
        tableName = doTblName(tableName);
        Record rc = null;
        for(Record rr : tables) {
            if(rr.getStr("TABLE_NAME").equals(tableName)) {
                rc = rr;
                break;
            }
        }
        return rc;
    }
    
    /**
     * @param tableName
     * @return 根据字段名获取相关字段
     */
    public static Record colomnsHasColomn(List<Record> COLOMNS, String colomn) {
        for(Record col : COLOMNS) {
            if(col.getStr("COLUMN_NAME").equals(colomn)) {
                return col;
            }
        }
        return null;
    }
    
    /**
     * @param name
     * @param length
     * @param COLOMNS
     * CHAR 255字节 VARCHAR 65535字节 TINYTEXT 255字节 TEXT 65535字节 LONGTEXT 4294967295字节
     */
    public void addColomn(String name, Integer length, Record table) {
        String tblName = table.getStr("TABLE_NAME");
        List<Record> COLOMNS = table.get("COLOMNS");
        Record r = new Record();
        r.set("COLUMN_NAME", name);
        r.set("DATA_TYPE", "varchar");
        r.set("CHARACTER_MAXIMUM_LENGTH", length);
        COLOMNS.add(r);
        if(!name.equals(CDEC_UUID)) {
            addTableFieldType(tblName, name, VARCHAR + "(" + length + ")");
        }
    }
    
    public Object[] getLength(Object value) {
        Integer length = null;
        try {
            length = value.toString().getBytes("UTF-8").length;
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        if(length < 400) {
            return new Object[]{VARCHAR, 200};
        } else if(length < 800) {
            return new Object[]{VARCHAR, 400};
        } else if(length < 2000) {
            return new Object[]{VARCHAR, 1000};
        } else if(length < 4000) {
            return new Object[]{VARCHAR, 2000};
        } else if(length < 65535) {
            return new Object[]{TEXT, null};
        } else if(length < 4294967295l) {
            return new Object[]{LONGTEXT, null};
        }
        return new Object[]{VARCHAR, 200};
    }
    
    /**
     * @param name
     * @param type
     * CHAR 255字节 VARCHAR 65535字节 TINYTEXT 255字节 TEXT 65535字节 LONGTEXT 4294967295字节
     * @throws Exception 
     */
    public void addColomn(String key, Object value, Record table) {
        String tblName = table.getStr("TABLE_NAME");
        List<Record> COLOMNS = table.get("COLOMNS");
        Record r = new Record();
        Object[] xx = getLength(value);
        r.set("COLUMN_NAME", key);
        r.set("DATA_TYPE", xx[0]);
        r.set("CHARACTER_MAXIMUM_LENGTH", xx[1]);
        COLOMNS.add(r);
        addTableFieldType(tblName, key, xx[0].toString().equals(VARCHAR) ? VARCHAR + "(" + xx[1] + ")" : xx[0].toString());
    }

    public void apiDataInDo(Object data, CheckUserBean bean) {
        apiDataInDo(data, bean.getMethod(), null, null, false, bean);
    }
    
    /**
     * @param data 数据
     * @param tblName 表名
     * @param parTblName 上级表名
     * @param parentKey 上级主键
     * @param isArray 是否1对多
     * @param clientLogId  log id
     * @param portInfoName 请求接口方法备注,放在表备注里面
     */
    public void apiDataInDo(Object data, String tblName, String parTblName, String parentKey, 
            Boolean isArray, CheckUserBean bean) {
        tblName = tblName.toLowerCase();
        if(null != parTblName) {
            parTblName = parTblName.toLowerCase();
        }
        //数组,继续递归
        if (data instanceof JSONArray) {
            JSONArray dataArr = (JSONArray) data;
            for (int i = 0; i < dataArr.size(); i++) {
                Object job = dataArr.get(i);
                apiDataInDo(job, tblName, parentKey, parTblName, true, bean);
            }

        } else if (data instanceof JSONObject) {
            Record table = getTable(tblName);
            List<Record> COLOMNS = null;
            
            //处理表   不存在新增
            if(null == table) {//表不存在
                table = new Record();
                table.set("TABLE_NAME", doTblName(tblName));
                table.set("TABLE_COMMENT", "");
                createTable(tblName, parTblName, isArray, bean.portInfoName);//新建一个表
                
                COLOMNS = new ArrayList<Record>();
                table.set("COLOMNS", COLOMNS);
                addColomn(CDEC_UUID, 50, table);//主键不会新建字段
                addColomn("CDEC_PARENTUUID", 50, table);//上级id
                addColomn("CDEC_CLIENTLOGID", 50, table);//clientLogId id
                
                tables.add(table);
            } else {
                COLOMNS = table.get("COLOMNS");
            }
            //处理表 end
            
            String uuid = UUID();
            JSONObject dataObj = (JSONObject) data;
            Iterator<?> iterator = dataObj.keys();
            
            Record saveObj = new Record();
            saveObj.set(CDEC_UUID, uuid);
            saveObj.set("CDEC_CLIENTLOGID", bean.clientlog.getID());
            saveObj.set("CDEC_PARENTUUID", parentKey);
            
            while (iterator.hasNext()) {
                String key = (String) iterator.next();
                Object value = dataObj.get(key);
                if(null == value) {
                    
                } else if (value instanceof JSONArray) {
                    JSONArray dataArr = (JSONArray) value;
                    for (int i = 0; i < dataArr.size(); i++) {
                        Object job = dataArr.get(i);
                        apiDataInDo(job, tblName + "_" + key, tblName, uuid, true, bean);
                    }
                } else if (value instanceof JSONObject) {
                    if(((JSONObject)value).isNullObject()) {//null
                        return;
                    }
                    apiDataInDo(value, tblName + "_" + key, tblName, uuid, false, bean);
                } else {//字段
                    saveObj.set(key, value);
                    
                    //处理字段 存在、类型、长度start
                    Record colomn = colomnsHasColomn(COLOMNS, key);
                    if(null == colomn) {//没有该字段
                        addColomn(key, value, table);
                    } else {
                        Object[] xx = getLength(value);
                        String type = colomn.getStr("DATA_TYPE");
                        switch (type.toUpperCase()) {
                            case "LONGTEXT":
                                break;
                            case "TEXT":
                                if(xx[0].toString().equals("LONGTEXT")) {//更改字段类型
                                    modifyTableFieldType(tblName, key, "LONGTEXT");
                                }
                                break;
                            case "VARCHAR":
                                if(!xx[0].toString().equals("VARCHAR")) {//更改字段类型
                                    modifyTableFieldType(tblName, key, xx[0].toString());
                                } else {//判断字段长度
                                    Integer CHARACTER_MAXIMUM_LENGTH = colomn.getInt("CHARACTER_MAXIMUM_LENGTH");
                                    Integer x1 = (Integer)xx[1];
                                    if(CHARACTER_MAXIMUM_LENGTH.compareTo(x1) < 0) {//更改字段长度
                                        modifyTableFieldType(tblName, key, "VARCHAR(" + x1 + ")");
                                    }
                                }
                                break;
                            default:
                                break;
                        }
                    }
                    
                  //处理字段 存在、类型、长度end
                }
            }
            
            //需要保存
            if(null != saveObj) {
                Db.save(doTblName(tblName), CDEC_UUID, saveObj);
            }
        }
    }

    /**
     * 更改字段类型,长度等
     */
    static String modifyTableFieldType = "ALTER TABLE `%s` MODIFY COLUMN `%s` %s CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL;";
    public void modifyTableFieldType(String table, String field, String type) {
        Db.update(String.format(modifyTableFieldType, doTblName(table), field, type));
    }
    /**
     * 新增字段
     */
    static String addTableFieldType = "ALTER TABLE `%s` ADD COLUMN `%s` %s NULL DEFAULT NULL;;";
    public void addTableFieldType(String table, String field, String type) {
        Db.update(String.format(addTableFieldType, doTblName(table), field, type));
    }
    /**
     * 新增空表,主键CDEC_UUID
     */
    static String addTable = "CREATE TABLE `%s` (`CDEC_UUID`  varchar(50) NOT NULL ,PRIMARY KEY (`CDEC_UUID`)) COMMENT='%s';";
    public void createTable(String tblName,String parTblName, Boolean isArray, String portInfoMemo) {
        String realTblName = doTblName(tblName);
        Db.update(String.format(addTable, realTblName, portInfoMemo + "_" + tblName));
        //处理表tree结构
        Record tblTree = new Record();
        tblTree.set("TABLE_NAME", realTblName);
        tblTree.set("PARENT", parTblName);
        tblTree.set("ORG_NAME", tblName);
        tblTree.set("TYPE", isArray ? 1 : 2);
        Db.save("sys_tbl_tree", "ID", tblTree);
    }

    /**
     * @param mysql 表最多64字节,超长特殊处理
     * @return
     */
    public static String doTblName(String tblName) {
        if(tblName.getBytes().length > 64) {
            tblName = tblName.replace("_", "");
        }
        if(tblName.getBytes().length > 64) {
            tblName = new String(HashKit.sha1(tblName));
        }
        return tblName;
    }
}

效果如下

 

猜你喜欢

转载自blog.csdn.net/cgf_01/article/details/102497404