一、业务需求

根据api接口返回的数据进行自动解析,将解析的数据自动生成数据库的建表和插入数据的sql语句同时自动执行操作生成数据表和插入api接口的数据

二、技术架构和实现

1.技术架构

spring cloud微服务框架、Mybatis、MySQL数据库

2.实现思路

1)调用HttpClientUtil访问第三方api接口并返回json数据

2)将数据通过json解析工具进行解析,采用的是递归方式解数据结构

3)将解析好的数据结构保存到实体类,主要有json的kev和value及value的数据类型

4)将实体类进行遍历解析生成数据库表的建表和插入数据的sql语句

5)通过mybatis执行建表和插入数据的sql来完成在MySQL数据库中建表和插入数据的操作

三、核心代码

1.生成sql语句工具

import com.juncdt.platform.grab.dao.SqlMapper;
import com.juncdt.platform.grab.entity.JsonMetaNode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;

/**
 * @Auther: yaohongan
 * @Description //生成sql语句工具类
 * @Date: 2021/3/29 18:25
 */
@Service
public class GenerationSQLUtil {
    @Resource
   private SqlMapper sqlMapping;

    public static String INTEGER = "java.lang.Integer";
    public static String LONG = "java.lang.Long";
    public static String STRING = "java.lang.String";
    public static String JSONOBJECT = "com.alibaba.fastjson.JSONObject";
    public static String FLOAT = "java.lang.Float";
    public static String DOUBLE = "java.lang.Double";
    public static String BIG_DECIMAL = "java.math.BigDecimal";
    public static String DATE = "java.util.Date";




    /**
     * @Auther: yaohongan
     * @Description //建表语句
     * @Date: 2021/4/8 11:18
     */
    public  void createTable(String tableName, List<JsonMetaNode> jsonMetaNodeList) {
        String sqlCreate = "CREATE TABLE " + tableName + "(\n" + getRowName(jsonMetaNodeList)+");";
        //检查数据库表是否存在
        Map<String,String> sqlMap = sqlMapping.checkTableExistsWithShow(tableName);
        //数据库表不存在创建表
        if(sqlMap==null) {
            sqlMapping.jsontosql(sqlCreate);
        }else {
            insertSql(tableName,jsonMetaNodeList);
        }
        System.out.println(sqlCreate);
    }
    /**
     * @Auther: yaohongan
     * @Description //获取插入sql语句
     * @Date: 2021/4/2 15:32
     */
    public void insertSql(String tableName,List<JsonMetaNode> jsonMetaNodeList){
        String insertSql ="";
        insertSql = "INSERT INTO " + tableName + " (\n"+getColumnName(jsonMetaNodeList)+")VALUES(\n"+getValue(jsonMetaNodeList)+");";
        sqlMapping.jsontosql(insertSql);
        System.out.println(insertSql);
    }

    /**
     * 获取建表语句的列名
     *
     * @author sql
     * @date 10/23/17 3:43 PM
     */
    public  String getRowName(List<JsonMetaNode> jsonMetaNodeList) {
        StringBuffer sqlRowNameBuffer = new StringBuffer();
        boolean hasId = false;
        for (JsonMetaNode jsonMetaNode : jsonMetaNodeList) {
            String key = jsonMetaNode.getKey();
            String valueType = jsonMetaNode.getValueType();
            String type = "";
            //判断id是否存在
            if (key.equals("id")){
                hasId = true;
            }
            if (INTEGER.equals(valueType)) {
                type = "int(10) NULL";
            } else if (LONG.equals(valueType)) {
                type = "bigint(100)";
            } else if (STRING.equals(valueType)) {
                type = "varchar(255)";
            } else if (BIG_DECIMAL.equals(valueType)) {
                type = "decimal(18,8)";
            } else if (FLOAT.equals(valueType)) {
                type = "float(100,10)";
            } else if (DOUBLE.equals(valueType)) {
                type = "double(100,10)";
            } else if (DATE.equals(valueType)) {
                type = "datetime";
            } else {
                type = "varchar(255)";
            }
            sqlRowNameBuffer.append(key).append(" ").append(type);
            sqlRowNameBuffer.append(",");
        }
        if (!hasId){
            sqlRowNameBuffer.append("id").append(" ").append("int(10)").append(" ").append("NOT NULL").append(" ").append("AUTO_INCREMENT,").append(" PRIMARY KEY (`id`)\n");
        }
        if(sqlRowNameBuffer!=null&&sqlRowNameBuffer.length()>0){
            sqlRowNameBuffer.deleteCharAt(sqlRowNameBuffer.length() - 1);
        }
        String sqlRowName = sqlRowNameBuffer.toString();
        return sqlRowName;
    }

   /**
    * @Auther: yaohongan
    * @Description //获取插入数据表列名语句
    * @Date: 2021/4/6 10:49
    */
   public  String getColumnName(List<JsonMetaNode> jsonMetaNodes) {
        StringBuffer sqlColumnNameBuffer = new StringBuffer();
        for (JsonMetaNode jsonMetaNode : jsonMetaNodes) {
            String key = jsonMetaNode.getKey();
            sqlColumnNameBuffer.append(key).append(",");
        }
       if(sqlColumnNameBuffer!=null&&sqlColumnNameBuffer.length()>0){
           sqlColumnNameBuffer.deleteCharAt(sqlColumnNameBuffer.length() - 1);
       }
        String sqlRowName = sqlColumnNameBuffer.toString();
        return sqlRowName;
    }

        /**
         * @Auther: yaohongan
         * @Description //获取插入数据表数据语句
         * @Date: 2021/4/6 10:49
         */
        public  String getValue(List<JsonMetaNode> jsonMetaNodeList) {
            StringBuffer sqlValueBuffer = new StringBuffer();
            for (JsonMetaNode jsonMetaNode : jsonMetaNodeList) {
                Object value = jsonMetaNode.getValue();
                String valueType = jsonMetaNode.getValueType();
                String type = "";
                if (INTEGER.equals(valueType)) {
                    type = "int(10) NULL";
                } else if (LONG.equals(valueType)) {
                    type = "bigint(100)";
                } else if (STRING.equals(valueType)) {
                    type = "varchar(255)";
                } else if (BIG_DECIMAL.equals(valueType)) {
                    type = "decimal(18,8)";
                } else if (FLOAT.equals(valueType)) {
                    type = "float(100,10)";
                } else if (DOUBLE.equals(valueType)) {
                    type = "double(100,10)";
                } else if (DATE.equals(valueType)) {
                    type = "datetime";
                } else {
                    type = "varchar(255)";
                }
                if(type.equals("varchar(255)")){
                    sqlValueBuffer.append("'"+value+"'").append(",");
                }else{
                    sqlValueBuffer.append(value).append(",");
                }

            }
            if(sqlValueBuffer!=null&&sqlValueBuffer.length()>0){
                sqlValueBuffer.deleteCharAt(sqlValueBuffer.length() - 1);
            }
            String sqlRowName = sqlValueBuffer.toString();
            return sqlRowName;
        }

}

2.调用三方api接口http工具

import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class HttpClientUtil {

    /**
     * 带参数的get请求
     * @param url
     * @param param
     * @return String
     */
    public static String doGet(String url, Map<String, String> param) {
        // 创建Httpclient对象
        CloseableHttpClient httpclient = HttpClients.createDefault();

        String resultString = "";
        CloseableHttpResponse response = null;
        try {
            // 创建uri
            URIBuilder builder = new URIBuilder(url);
            if (param != null) {
                for (String key : param.keySet()) {
                    builder.addParameter(key, param.get(key));
                }
            }
            URI uri = builder.build();
            // 创建http GET请求
            HttpGet httpGet = new HttpGet(uri);
            // 执行请求
            response = httpclient.execute(httpGet);
            // 判断返回状态是否为200
            if (response.getStatusLine().getStatusCode() == 200) {
                resultString = EntityUtils.toString(response.getEntity(), "UTF-8");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (response != null) {
                    response.close();
                }
                httpclient.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return resultString;
    }

    /**
     * 不带参数的get请求
     * @param url
     * @return String
     */
    public static String doGet(String url) {
        return doGet(url, null);
    }

    /**
     * 带参数的post请求
     * @param url
     * @param param
     * @return String
     */
    public static String doPost(String url, Map<String, String> param) {
        // 创建Httpclient对象
        CloseableHttpClient httpClient = HttpClients.createDefault();
        CloseableHttpResponse response = null;
        String resultString = "";
        try {
            // 创建Http Post请求
            HttpPost httpPost = new HttpPost(url);
            // 创建参数列表
            if (param != null) {
                List<NameValuePair> paramList = new ArrayList<>();
                for (String key : param.keySet()) {
                    paramList.add(new BasicNameValuePair(key, param.get(key)));
                }
                // 模拟表单
                UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList);
                httpPost.setEntity(entity);
            }
            // 执行http请求
            response = httpClient.execute(httpPost);
            resultString = EntityUtils.toString(response.getEntity(), "utf-8");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                response.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return resultString;
    }

    /**
     * 不带参数的post请求
     * @param url
     * @return String
     */
    public static String doPost(String url) {
        return doPost(url, null);
    }

    /**
     * 传送json类型的post请求
     * @param url
     * @param json
     * @return String
     */
    public static String doPostJson(String url, String json) {
        // 创建Httpclient对象
        CloseableHttpClient httpClient = HttpClients.createDefault();
        CloseableHttpResponse response = null;
        String resultString = "";
        try {
            // 创建Http Post请求
            HttpPost httpPost = new HttpPost(url);
            // 创建请求内容
            StringEntity entity = new StringEntity(json, ContentType.APPLICATION_JSON);
            httpPost.setEntity(entity);
            // 执行http请求
            response = httpClient.execute(httpPost);
            resultString = EntityUtils.toString(response.getEntity(), "utf-8");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                response.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return resultString;
    }
}

3.字段实体类

import lombok.Data;

import java.util.List;

/**
 * @Auther: yaohongan
 * @Date: 2021/3/29 18:11
 * @Description:
 */
@Data
public  class JsonMetaNode {
    private String key;
    private Object value;
    private String valueType;
    //数据库中的列名
    private String dbColName;
    private List<JsonMetaNode> children;

}

4.JSON解析工具

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.juncdt.platform.api.utils.HttpClientUtil;
import com.juncdt.platform.grab.entity.JsonMetaNode;
import com.juncdt.platform.grab.service.JsonParsingService;
import com.juncdt.platform.grab.service.WmDataService;
import com.juncdt.platform.grab.util.GenerationSQLUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * @Auther: yaohongan
 * @Date: 2021/4/7 10:21
 * @Description:JSON解析工具类
 */
@Service
public class JsonParsingServiceImpl {
    @Autowired
    GenerationSQLUtil generationSQLUtil;
    @Autowired
    WmDataService wmDataService;
    @Autowired
    RedisTemplate<String,Object> redisTemplate;

    /**
     * @Auther: yaohongan
     * @Description //根据api接口数据创建数据库表和插入数据
     * @Date: 2021/4/1 15:15
     */
    public JSONObject getJsonData(String url, String tableName, String code, String json) {
        //获取access_token
        String data = (String) redisTemplate.opsForValue().get(code);
        JSONObject jsonObject1 = JSONObject.parseObject(data);
        String accessToken = jsonObject1.getString("access_token");
        //1.调用API接口,获取到数据
        String str = HttpClientUtil.doPostJson(url+accessToken,json);
        JSONObject jsonObject = JSON.parseObject(str);
        //2.将获取到的数据转换为JSONObject格式
        //JSONObject jsonObject = JSON.parseObject("{\"code\":{\"errcode\":\"0\",\"errmsg\":\"处理成功\"},\"data\":{\"pageList\":[{\"goodsId\":44640100,\"isPutAway\":0,\"isExistEmptyStock\":false,\"salesNum\":0,\"isAllStockEmpty\":false,\"maxPrice\":100,\"sortNum\":0,\"title\":\"商品测试\",\"avaliableStockNum\":12,\"putAwayDate\":1514629080000,\"defaultImageUrl\":\"https://image-c-dev.weimobwmc.com/dev-saas-wxbiz/a28337e179d64b90a539f41c0cf19b54.jpg\",\"isMultiSku\":0,\"minPrice\":100}],\"totalCount\":1,\"pageNum\":1}}");
        //3.拿到data数据层
        JSONObject dataJson = (JSONObject) jsonObject.get("data");
        //4.创建数据库表
        List<JsonMetaNode> jsonMetaNodeList = new ArrayList<>();
        jsonMetaNodeList = analysisJsonKey(dataJson,jsonMetaNodeList);
        Set<JsonMetaNode> jsonMetaNodeHashSet = new HashSet<>(jsonMetaNodeList);
        List<JsonMetaNode> list = new ArrayList<>(jsonMetaNodeHashSet);
        generationSQLUtil.createTable(tableName,list);
        //5.插入数据
        analysisJsonValue(dataJson,tableName);
        return jsonObject;
    }

    /**
     * @Auther: yaohongan
     * @Description //解析json取出kev创建数据库表
     * @Date: 2021/4/9 14:54
     */
    public List<JsonMetaNode> analysisJsonKey(JSONObject jsonObject,List<JsonMetaNode> jsonMetaNodeList) {
        Set<String> strings = jsonObject.keySet();
        for (String str : strings) {
            //获取value值
            Object o = jsonObject.get(str);
            JsonMetaNode jsonMetaNode = new JsonMetaNode();
            jsonMetaNode.setKey(str);
            //存入value值的类型
            String name = "";
            if(o!=null){
                name = o.getClass().getName();
            }
            if(name.equals("com.alibaba.fastjson.JSONArray")||name.equals("com.alibaba.fastjson.JSONObject")){
                jsonMetaNode.setValueType("java.lang.String");
            }else{
                jsonMetaNode.setValueType(name);
            }

            //将数据存入list中
            jsonMetaNodeList.add(jsonMetaNode);

            if(isJson(o)) {
                jsonMetaNodeList=recursionKey(o, jsonMetaNodeList);
            }
        }
        return jsonMetaNodeList;
    }
    /**
     * @Auther: yaohongan
     * @Description //判断json类型
     * @Date: 2021/4/9 14:55
     */
    public boolean isJson(Object o){
        if(o instanceof JSONObject){
            return true;
        }else if(o instanceof JSONArray){
            return true;
        }
        return false;
    }
    /**
     * @Auther: yaohongan
     * @Description //递归遍历
     * @Date: 2021/4/9 14:56
     */
    public  List<JsonMetaNode> recursionKey(Object o,List<JsonMetaNode> jsonMetaNodeList){
        if(o instanceof JSONObject){
            jsonMetaNodeList=analysisJsonKey((JSONObject) o,jsonMetaNodeList);
        }else{
            jsonMetaNodeList=paseArray(o,jsonMetaNodeList);
        }
        return jsonMetaNodeList;
    }
    /**
     * @Auther: yaohongan
     * @Description //解析jsonArray
     * @Date: 2021/4/9 14:59
     */
    public List<JsonMetaNode> paseArray(Object o, List<JsonMetaNode> jsonMetaNodeList){
        JSONArray jsonArray = (JSONArray) o;
        for (int i = 0; i < jsonArray.size(); i++){
            JSONObject jsonObject = (JSONObject) jsonArray.get(i);
            if(jsonObject!=null){
                jsonMetaNodeList=analysisJsonKey(jsonObject,jsonMetaNodeList);
            }
        }
        return jsonMetaNodeList;
    }




    /**
     * @Auther: yaohongan
     * @Description //解析json插入数据
     * @Date: 2021/4/2 14:05
     */
    public void analysisJsonValue(JSONObject jsonObject, String tableName) {
        List<JsonMetaNode> jsonMetaNodeList = new ArrayList<>();
        Set<String> strings = jsonObject.keySet();
        for (String str : strings) {
            JsonMetaNode jsonMete = new JsonMetaNode();
            //获取value值
            Object o = jsonObject.get(str);
            if (recursion(o, tableName)) {
                if(str!=null&&str!="null"){
                    //存入key值
                    jsonMete.setKey(str);
                }
                if(o!=null&&o!="null"){
                    //存入value值的类型
                    String name = o.getClass().getName();
                    jsonMete.setValueType(name);
                    jsonMete.setValue(o);
                }
                if(str!=null&&str!="null" &&o!=null&&o!="null"){
                    jsonMetaNodeList.add(jsonMete);
                }

            }
        }
        generationSQLUtil.insertSql(tableName,jsonMetaNodeList);
    }

    /**
     * @Auther: yaohongan
     * @Description //递归解析json
     * @Date: 2021/4/2 14:03
     */
    public  boolean recursion(Object o,String tableName){
        if(o instanceof JSONObject){
            analysisJsonValue((JSONObject) o,tableName);
            return false;
        }else if(o instanceof JSONArray){
            paseArray(o,tableName);
            return false;
        }
        return true;
    }



    /**
     * @Auther: yaohongan
     * @Description //解析 jsonArray
     * @Date: 2021/4/2 14:04
     */
    public  void paseArray(Object o, String tableName){
        JSONArray jsonArray = (JSONArray) o;
        for (int i = 0; i < jsonArray.size(); i++){
            JSONObject jsonObject = (JSONObject) jsonArray.get(i);
            if(jsonObject!=null){
                analysisJsonValue(jsonObject,tableName);
            }
        }
    }



}

5.sql执行接口

import org.apache.ibatis.annotations.Mapper;

import javax.annotation.Resource;
import java.util.Map;

/**
 * @Auther: yaohongan
 * @Date: 2021/3/31 15:35
 * @Description:
 */
@Mapper
public interface SqlMapper {

    //创建数据库表
    void jsontosql(String sql);

    //检查数据库表是否存在
    Map<String, String> checkTableExistsWithShow(String tableName);

}

6.sql执行映射xml文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="xxx.dao.SqlMapper">

    <select id="jsontosql"  resultType="java.lang.Integer">
        ${sql}
    </select>

    <select id="checkTableExistsWithShow"
            resultType="java.util.Map">
        show tables like #{tableName}
    </select>



</mapper>

7.业务外层

import com.alibaba.fastjson.JSONObject;
import com.juncdt.platform.api.utils.R;
import com.juncdt.platform.grab.service.JsonParsingService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.Map;

/**
 * @Auther: yaohongan
 * @Date: 2021/4/8 14:50
 * @Description:
 */
@RestController
@RequestMapping("json")
@Api(value = "json解析",tags = "json解析")
public class AnalysisJsonController {
    @Autowired
    private JsonParsingServiceImpl jsonParsingService;


    /**
     * @Auther: yaohongan
     * @Description //解析Json
     * @Date: 2021/4/8 14:52
     */
    @PostMapping("/info")
    @ApiOperation(value = "json解析",notes = "json解析")
    public R info(String url, String tableName, String code, @RequestBody String map){
        JSONObject jsonObject = jsonParsingService.getJsonData(url,tableName,code,map);
        return R.ok().put("data", jsonObject);
    }
}