最近刚刚接手了泛微OA的项目,项目代码简直是一座庞大的屎山。不得不说,习惯了Spring的生态以后,再去适应其他的框架简直是一种折磨。尤其是这种连JavaBean都不用的项目,所有的参数处理全都是用json和map进行接收和响应……
最让我难以忍受的是,所有和数据库交互的地方全都是在Java代码里面直接嵌入的,代码读起来太阳穴突突跳动,咖啡在胃里翻涌成酸。
所以被逼无奈,只能亲手封装了一个工具类,简直是优雅极了!

package com.api.zp.interfaces.util;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import weaver.conn.RecordSet;
import weaver.general.BaseBean;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * @Author zF.
 * @ClassName JsonToDbUtil.java
 * @ProjectName 通用json数据入库处理工具类
 */
public class JsonToDbUtil {
    private static BaseBean base = new BaseBean();

    /**
     * 按数据库字段顺序将JSONObject写入指定表
     * @param tableName 目标数据库表名
     * @param json 待写入的JSON对象
     * @param customJson 增自定义JSON参数,优先级高于原始json
     * @param uniqueField 唯一字段,数据去重使用,避免重复落库
     */
    public static void insertByDbFieldOrder(String tableName, JSONObject json, JSONObject customJson, String uniqueField) {
        RecordSet rs = new RecordSet();
        // 获取数据库字段列表(按表定义顺序)
        System.out.println(json);
        // 合并原始JSON与自定义JSON(自定义优先级更高)
        JSONObject mergedJson = new JSONObject(json);
        // 把json的所有key都转换成大写
        JSONObject convertedJson = convertKeysToUpperCase(mergedJson);
        if(customJson != null) {
            convertedJson.putAll(customJson); // 自定义JSON的键会覆盖原始JSON的相同键
        }
        // 获取唯一字段值(转换为大写匹配数据库字段)
        String upperUniqueField = uniqueField.toUpperCase();
        Object uniqueValue = convertedJson.get(upperUniqueField);
        if(uniqueValue == null) {
            base.writeLog("错误:唯一字段[" + upperUniqueField + "]在JSON中不存在,插入终止!");
            return;
        }
        // 检查唯一字段是否已存在
        RecordSet checkRs = new RecordSet();
        String checkSql = "SELECT " + upperUniqueField + " FROM " + tableName + " WHERE " + upperUniqueField + " IS NOT NULL";
        try {
            checkRs.execute(checkSql);
            // 数据库中是否已经存在当的json
            List array = checkRs.getArray();
            List<String> newMergeList = mergeList(array);
            if (newMergeList.contains(uniqueValue.toString())) {
                base.writeLog("唯一字段[" + upperUniqueField + "]值[" + uniqueValue + "]已存在,不重复插入!");
                return;
            }
        } catch (Exception e) {
            base.writeLog("唯一字段检查失败!表[" + tableName + "],错误:" + e.getMessage());
            throw new RuntimeException("唯一字段检查异常!", e);
        }

        List<String> dbFields = getTableFields(tableName, convertedJson);
        if (dbFields.isEmpty()) {
            base.writeLog("警告:表 [" + tableName + "] 无有效字段信息,插入终止!");
            return;
        }

        // 按字段顺序收集参数值(过滤JSON中不存在的字段)
        List<Object> params = new ArrayList<>();
        for (String field : dbFields) {
            Object value = convertedJson.get(field); // 从合并后的JSON获取值(包含自定义字段)
            // 处理日期类型自动转换(示例)
//            if(value instanceof String && field.contains("DATE")){
//                try{
//                    value = new java.sql.Date(new java.text.SimpleDateFormat("yyyy-MM-dd").parse((String)value).getTime());
//                }catch (Exception ignored){}
//            }
            params.add(value != null ? value : null); // 显式处理null
        }

        // 构造预编译SQL
        String fieldsClause = String.join(", ", dbFields);
        String placeholders = String.join(", ", Collections.nCopies(dbFields.size(), "?"));
        String sql = "INSERT INTO " + tableName + "(" + fieldsClause + ") VALUES(" + placeholders + ")";

        // 执行数据库插入
        try {
            rs.executeUpdate(sql, params.toArray());
            base.writeLog("成功插入表 [" + tableName + "],数据:" + json.toJSONString());
        } catch (Exception e) {
            base.writeLog("插入失败!表 [" + tableName + "],错误信息:" + e.getMessage());
            throw new RuntimeException("数据库插入异常", e);
        }
    }


    /**
     * 获取列表内部所有字符串并合并成新的列表
     * @param array 目标列表
     * @return 新的列表
     */
    public static List<String> mergeList(List<Object[]> array) { // 明确参数类型
        List<String> stringList = new ArrayList<>();
        for (Object[] item : array) { // 直接遍历Object数组
            if (item.length > 0) { // 先检查数组长度
                Object element = item[0];
                if (element instanceof String) {
                    String strElement = (String) element;
                    stringList.add(strElement); // 实际添加到结果列表
                    System.out.println("字符串内容: " + strElement);
                }
            }
        }
        return stringList;
    }


    /**
     * 获取数据库表的字段列表(按定义顺序)
     * @param tableName 目标表名
     * @return 字段列表(有序)
     */
    private static List<String> getTableFields(String tableName, JSONObject json ) {
        List<String> fields = new ArrayList<>();
        RecordSet metaRs = new RecordSet();
        // Oracle专用元数据查询(使用ALL_TAB_COLUMNS视图)
        String metaSql = "SELECT COLUMN_NAME FROM ALL_TAB_COLUMNS " +
                         "WHERE TABLE_NAME = '" + tableName + "' AND OWNER = USER " +
                         "ORDER BY COLUMN_ID";
        try {
            metaRs.execute(metaSql);  // Oracle表名默认大写存储
            while (metaRs.next()) {
                String field = metaRs.getString("COLUMN_NAME");
                if(json.containsKey(field)){  // 检查JSON中key转换为全大写后是否存在该字段
                    fields.add(field);
                }
            }
            if(fields.isEmpty()){
                base.writeLog("警告:表 [" + tableName + "] 无JSON中存在的有效字段,插入终止!");
            }
        } catch (Exception e) {
            base.writeLog("获取表字段失败!表 [" + tableName + "],错误:" + e.getMessage());
            throw new RuntimeException("元数据查询异常!", e);
        }
        return fields;
    }


    /**
     * 递归转换JSON对象的所有key为大写
     * @param json 原始JSON对象
     * @return 所有key大写的JSON对象(其他内容不变)
     */
    public static JSONObject convertKeysToUpperCase(JSONObject json) {
        if (json == null) {
            return null;
        }
        JSONObject result = new JSONObject();
        // 遍历原始JSON的所有键
        for (Object ikey : json.keySet()) {
            String key = StrUtil.toString(ikey);
            Object value = json.get(key);
            String upperKey = key.toUpperCase();
            // 递归处理不同类型的值
            result.put(upperKey, processValue(value));
        }
        return result;
    }

    private static Object processValue(Object value) {
        if (value instanceof JSONObject) {
            // 递归处理嵌套JSON对象
            return convertKeysToUpperCase((JSONObject) value);
        } else if (value instanceof JSONArray) {
            // 处理JSON数组
            JSONArray array = (JSONArray) value;
            JSONArray newArray = new JSONArray();
            array.forEach(item ->
                    newArray.add(processValue(item))
                    );
            return newArray;
        }
        // 基础类型直接返回
        return value;
    }
}

使用前(例如):

    private static void saveToUF_JYYQZL(String requestId, String[] fields) {
        RecordSet rs = new RecordSet();
        try {
            String rzh = getField(fields, 5);
            String querySelect = "select rzh from uf_jyyqzl where rzh ='" + rzh + "'";
            baseBean.writeLog("查询明细是否存在:");
            baseBean.writeLog(querySelect);
            rs.execute(querySelect);
            if (rs.next()) {
                return;
            }
            // SQL(表结构为43个字段)
            String sql = "INSERT INTO UF_JYYQZL(" +
                    // 按数据库字段顺序严格排列(共43个字段)
                    "ID,REQUESTID,FORMMODEID,MODEDATACREATER,MODEDATACREATERTYPE," +
                    "MODEDATACREATEDATE,MODEDATACREATETIME,MODEDATAMODIFIER,MODEDATAMODIFYDATETIME,MODEUUID," +
                    "SSDM,ZH,HBM,JYRQ,JYSJ,RZH,JYLX,JYXH,HM,FSEBZ," +
                    "DFZHSSDM,DFZH,DFZHHBM,DFZHHM,DFZHKHX,XZBZ,CZRQ,CZCPH," +
                    "JYJE,ZHYE,SBYE,SXFZE,PZZL,PZSSDH,PZPCH,PZH," +
                    "KHCKH,JYM,GYH,CPH,ZY,FY,JYLY) " +

                    "VALUES(" +
                    "uf_jyyqzl_Id.nextval,?,?,?,?,TO_CHAR(SYSDATE,'YYYYMMDD'),TO_CHAR(SYSDATE,'HH24MISS'),?,?,?," + // ID(1)由序列生成
                    "?,?,?,?,?,?,?,?,?,?," +  // 10-19
                    "?,?,?,?,?,?,?,?,?,?," +  // 20-29
                    "?,?,?,?,?,?,?,?,?,?," +  // 30-39
                    "?,?,?)"; // 40-43

            Object[] params = new Object[]{
                    // REQUESTID(字段2)
                    requestId,

                    // 系统字段(3个)
                    154512,                  // FORMMODEID(字段3)
                    0,                  // MODEDATACREATER(字段4)
                    1,                  // MODEDATACREATERTYPE(字段5)

                    // 修改信息(2个)
                    0,                  // MODEDATAMODIFIER(字段8)
                    "",                 // MODEDATAMODIFYDATETIME(字段9)
                    "",                 // MODEUUID(字段10)

                    // 业务字段(按数据库顺序)
                    getField(fields, 0), // SSDM(字段11)
                    getField(fields, 1), // ZH(字段12)
                    getField(fields, 2), // HBM(字段13)
                    getField(fields, 3), // JYRQ(字段14)
                    getField(fields, 4), // JYSJ(字段15)
                    getField(fields, 5), // RZH(字段16)
                    getField(fields, 6), // JYLX(字段17)
                    getField(fields, 7), // JYXH(字段18)
                    getField(fields, 8), // HM(字段19)
                    getField(fields, 9), // FSEBZ(字段20)
                    getField(fields, 10),// DFZHSSDM(字段21)
                    getField(fields, 11),// DFZH(字段22)
                    getField(fields, 12),// DFZHHBM(字段23)
                    getField(fields, 13),// DFZHHM(字段24)
                    getField(fields, 14),// DFZHKHX(字段25)
                    getField(fields, 15),// XZBZ(字段26)
                    getField(fields, 16),// CZRQ(字段27)
                    getField(fields, 17),// CZCPH(字段28)
                    parseDecimal(getField(fields, 18)), // JYJE(字段29)
                    parseDecimal(getField(fields, 19)), // ZHYE(字段30)
                    parseDecimal(getField(fields, 20)), // SBYE(字段31)
                    parseDecimal(getField(fields, 21)), // SXFZE(字段32)
                    getField(fields, 22),// PZZL(字段33)
                    getField(fields, 23),// PZSSDH(字段34)
                    getField(fields, 24),// PZPCH(字段35)
                    getField(fields, 25),// PZH(字段36)
                    getField(fields, 26),// KHCKH(字段37)
                    getField(fields, 27),// JYM(字段38)
                    getField(fields, 28),// GYH(字段39)
                    getField(fields, 29),// CPH(字段40)
                    getField(fields, 30),// ZY(字段41)
                    parseDecimal(getField(fields, 31)), // FY(字段42)
                    getField(fields, 32) // JYLY(字段43)
            };

            baseBean.writeLog("参数数量验证:" + params.length); // 必须输出42(ID由序列生成,占位符少1个)

            // 在executeUpdate之前
            baseBean.writeLog("===== 参数详情 =====");
            for (int i = 0; i < params.length; i++) {
                System.out.printf("参数 %2d: %s%n", i + 1, params[i]);
            }

            System.out.println("字段映射关系:");
            String[] fieldNames = new String[]{"SSDM", "ZH", "HBM", "JYRQ", "JYSJ", "RZH", "JYLX", "JYXH", "HM", "FSEBZ",
                    "DFZHSSDM", "DFZH", "DFZHHBM", "DFZHHM", "DFZHKHX", "XZBZ", "CZRQ", "CZCPH",
                    "JYJE", "ZHYE", "SBYE", "SXFZE", "PZZL", "PZSSDH", "PZPCH", "PZH",
                    "KHCKH", "JYM", "GYH", "CPH", "ZY", "FY", "JYLY"};

            for (int i = 0; i < fields.length; i++) {
                System.out.printf("%s(%d) => %s%n",
                        (i < fieldNames.length) ? fieldNames[i] : "未知字段",
                        i,
                        fields[i]);
            }

            rs.executeUpdate(sql, params);
        } catch (Exception e) {
            baseBean.writeLog("保存失败:" + e.getMessage());
            e.printStackTrace();
        }
    }

每个类都要单独创建一遍数据库映射关系,然后手动加很多占位符。这是历史遗留代码,虽然一眼Ai,但是依然需要人工核对修正。

使用后(例如):

            JSONObject obj = JSONObject.parseObject(e.toString());
            // UUID
            String randomUUID = IdUtil.randomUUID();
            // 需要插入字段的表名
            String tableName = "UF_ZJJSYQ";
            // 新建自定义json(存入自定义字段)
            JSONObject customJson = new JSONObject();
            customJson.put("REQUESTID", requestId);
            customJson.put("FORMMODEID", 158512);
            customJson.put("MODEDATACREATER", 1);
            customJson.put("MODEDATACREATERTYPE", 0);
            customJson.put("MODEDATACREATEDATE", date);
            customJson.put("MODEDATACREATETIME", time);
            customJson.put("MODEUUID", randomUUID);
            // 唯一字段(数据去重使用)
            String uniqueField = "serialId";
            // 数据入库
            JsonToDbUtil.insertByDbFieldOrder(tableName, obj, customJson, uniqueField);

由于工具类直接从数据库获取字段列表,优雅的省掉了映射关系配置和手动给SQL设置数量占位符,你不需要再关注数据入库的底层逻辑,只需要确认想要入库的数据。如果数据库字段和接收的字段不匹配,则可以通过自定义json来实现无缝替换。还可以手动指定唯一字段(主键),避免数据重复入库。

最后修改:2025 年 06 月 05 日
给我一点小钱钱也很高兴啦!o(* ̄▽ ̄*)ブ