用于从服务器到客户端的json通信的公共java类

用于从服务器到客户端的json通信的公共java类,java,json,stored-procedures,Java,Json,Stored Procedures,我目前正在将一个项目迁移到java,保持数据完整(数据库)。大多数数据是通过存储过程(SP)获取的,数据库中有大量SP。 因此,在执行每个SP时,我必须为此编写一个类,这将建立一大堆类 因此,是否有任何方法来泛化该类,以便我可以将每个SP结果转换为该类,然后转换为客户端(如json)? 以下场景是隐藏的n ma qn: 动态字段数 动态字段名 类型可以是字符串 (我们可以解决这个问题) 我曾尝试以java.util.List的形式发送数据,但格式不太好。必须采用假设索引的数据 PS:我已经搜索过

我目前正在将一个项目迁移到java,保持数据完整(数据库)。大多数数据是通过存储过程(SP)获取的,数据库中有大量SP。 因此,在执行每个SP时,我必须为此编写一个类,这将建立一大堆类

因此,是否有任何方法来泛化该类,以便我可以将每个SP结果转换为该类,然后转换为客户端(如
json
)?

以下场景是隐藏的n ma qn:

  • 动态字段数
  • 动态字段名
  • 类型可以是字符串 (我们可以解决这个问题)
  • 我曾尝试以
    java.util.List
    的形式发送数据,但格式不太好。必须采用假设索引的数据


    PS:我已经搜索过了,但是没有找到。如果我要求的太多,我也很抱歉。

    是的,应该可以编写这样一个泛型类。这里有一个小示例类作为您的起点。我将Firebird用于示例数据库
    employee.fdb
    ,因为已经定义了一些存储过程

    因此,为了连接Firebird服务器,我使用并包含
    jaybird-full-2.2.5.jar
    jar文件

    JAVA有几种不同的JSON库。我在流模式下使用here(如StaX for XML)。所以这里的第二个外部JAR是
    javax.json-1.0.4.JAR

    我的示例仅适用于返回结果集的存储过程。对于具有输出参数的存储过程,应使用
    CallableStatement
    ,而不是
    PreparedStatement

    首先,为特定存储过程及其输入参数创建一个通用SQL语句。要调用存储过程,请使用
    PreparedStatemend
    。参数根据各个参数类型进行设置。(过程
    createSql()
    createStatement()

    在过程
    convertToJson()
    中,方法
    ResultSet.getMetaData()
    用于获取结果集的列信息(列数、列名和列类型)

    executeStoredProcedure()
    方法是要调用的公共API方法

    main()
    方法连接到
    èemployee.fdb
    数据库并调用三个存储过程:
    GET_EMP_PROJ
    MAIL_LABEL
    ORG_CHART

    package com.genericsptojson;
    
    import java.io.ByteArrayOutputStream;
    import java.io.OutputStream;
    import java.io.UnsupportedEncodingException;
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.ResultSetMetaData;
    import java.sql.SQLException;
    import java.sql.Types;
    import java.util.HashMap;
    import java.util.Map;
    
    import javax.json.Json;
    import javax.json.stream.JsonGenerator;
    import javax.json.stream.JsonGeneratorFactory;
    
    public class GenericSpToJson {
    
      private static final String DB_URL = "jdbc:firebirdsql:localhost/3050:/var/lib/firebird/2.5/data/employee.fdb";
      private static final String DB_USER = "SYSDBA";
      private static final String DB_PWD = "***";
    
      private Connection con;
    
      public GenericSpToJson(Connection con) {
        this.con = con;
      }
    
      /**
       * Creates the SQL to call the stored procedure. 
       * 
       * @param spName
       *          Name of stored procecdure to call
       * @param paramCount
       *          number of input parameters
       * @return SQL with placeholders for input parameters
       */
      private String createSql(String spName, int paramCount) {
        if(paramCount > 0) {
          final StringBuilder params = new StringBuilder();
          boolean isFirst = true;
          for(int i = 0; i < paramCount; i++) {
            if(isFirst) {
              isFirst = false;
            } else {
              params.append(", ");
            }
            params.append('?');
          }
          return String.format("SELECT * FROM %s (%s)", spName, params.toString());
        } else {
          return String.format("SELECT * FROM %s", spName);
        }
      }
    
      /**
       * Creates a PreparedStatement to call the stored procedure. This works only
       * for stored procedures creating result sets. Stored procedures with OUT
       * parameters should be handled by a CallableStatement instead.
       * 
       * @param spName
       *          The stored procedure name to be called.
       * @param params
       *          The input parameters.
       * @return A prepared statement. All parameters are set.
       * @throws SQLException
       */
      private PreparedStatement createStatement(String spName, Object... params) throws SQLException {
        final PreparedStatement stmt = con.prepareStatement(createSql(spName, params.length));
        for(int i = 0; i < params.length; i++) {
          final Object param = params[i];
          if(param instanceof String) {
            stmt.setString(i + 1, (String) param);
          } else if(param instanceof Integer) {
            stmt.setInt(i + 1, ((Integer) param).intValue());
          } else {
            // Handle other param types ...
          }
        }
        return stmt;
      }
    
      /**
       * Converts the result set to JSON in streaming mode.
       * 
       * @param spName
       *          The stored procedure name.
       * @param rs
       *          The result set of the stored procedure call.
       * @param out
       *          The output stream to write the JSON into.
       * @throws SQLException
       */
      private void convertToJson(String spName, ResultSet rs, OutputStream out) throws SQLException {
        // Get the result set meta data to obtain column information on the fly. 
        final ResultSetMetaData metaData = rs.getMetaData();
    
        // Create the JSON generator with pretty printing
        final Map<String, Object> properties = new HashMap<String, Object>(1);
        properties.put(JsonGenerator.PRETTY_PRINTING, true);
        final JsonGeneratorFactory jsonGeneratorFactory = Json.createGeneratorFactory(properties);
        final JsonGenerator generator = jsonGeneratorFactory.createGenerator(out);
        generator.writeStartObject(); // root object
    
        generator.write("storedProcedureName", spName);
        generator.write("columnCount", metaData.getColumnCount());
        generator.writeStartArray("records"); // records array
        while(rs.next()) {
          generator.writeStartObject(); // record object
          // Each record object contains one field for every column.
          // The field name is the columns name.
          for(int col = 1; col <= metaData.getColumnCount(); col++) {
            final String fieldName = metaData.getColumnName(col);
            switch(metaData.getColumnType(col)) {
              case Types.INTEGER:
                final int intValue = rs.getInt(col);
                if(rs.wasNull()) {
                  generator.writeNull(fieldName);
                } else {
                  generator.write(fieldName, intValue);
                }
                break;
              case Types.VARCHAR:
              case Types.CHAR:
                String stringValue = rs.getString(col);
                if(rs.wasNull()) {
                  generator.writeNull(fieldName);
                } else {
                  if(metaData.getColumnType(col) == Types.CHAR) {
                    stringValue = stringValue.trim();
                  }
                  generator.write(fieldName, stringValue);
                }
                break;
              // Handle other types here
              default:
                System.out.println(String.format("Unhandled SQL type: %s", metaData.getColumnTypeName(col)));
            }
          }
          generator.writeEnd(); // record object
        }
        generator.writeEnd(); // records array
        generator.writeEnd(); // root object
        generator.flush();
        generator.close();
      }
    
      /**
       * Executes the stored procedures with the given input parameters and creates
       * JSON in streaming mode.
       * 
       * @param spName
       *          The name of the stored procedure.
       * @param out
       *          The output stream to write the generated JSON into.
       * @param params
       *          The stored procedure's parameters.
       */
      public void executeStoredProcedure(String spName, OutputStream out, Object... params) {
        PreparedStatement stmt = null;
        ResultSet rs = null;
        try {
          stmt = createStatement(spName, params);
          rs = stmt.executeQuery();
          convertToJson(spName, rs, out);
        } catch (SQLException e) {
          e.printStackTrace();
        } finally {
          // Cleaning up ...
          if(stmt != null) {
            try {
              stmt.close();
            } catch (SQLException e) {
              e.printStackTrace();
            }
          }
          if(rs != null) {  
            try {
              rs.close();
            } catch (SQLException e) {
              e.printStackTrace();
            }   
          }
        }
      }
    
      /**
       * Convenience method to call the stored procedure and create a JSON string.
       * This should only be called for short result sets. For longer result sets
       * use {@link #executeStoredProcedure(String, OutputStream, Object...)} where
       * it is not necessary to hold the entire JSON document in memory.
       * 
       * @param spName
       *          The name of the stored procedure to call.
       * @param params
       *          The stored procedure's parameters
       * @return The stored procedure's call result as a JSON string.
       * @throws UnsupportedEncodingException
       */
      public String executeStoredProcedure(String spName, Object... params) throws UnsupportedEncodingException {
        final ByteArrayOutputStream out = new ByteArrayOutputStream();
        executeStoredProcedure(spName, out, params);
        return out.toString("UTF-8");
      }
    
    
      public static void main(String[] args) {
        Connection con = null;
        try {
          Class.forName("org.firebirdsql.jdbc.FBDriver");
          con = DriverManager.getConnection(DB_URL, DB_USER, DB_PWD);
    
          final GenericSpToJson converter = new GenericSpToJson(con);
    
          System.out.println("Executing stored procedure GET_EMP_PROJ (8):\n"
              + converter.executeStoredProcedure("GET_EMP_PROJ", 8));
          System.out.println("\n\nExecuting stored procedure MAIL_LABEL (1015):\n"
              + converter.executeStoredProcedure("MAIL_LABEL", 1015));
          System.out.println("\n\nExecuting stored procedure ORG_CHART:\n"
              + converter.executeStoredProcedure("ORG_CHART"));
        } catch (ClassNotFoundException e) {
          e.printStackTrace();
        } catch (SQLException e) {
          e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }
        if(con != null) {
          try {
            con.close();
          } catch (SQLException e) {
            e.printStackTrace();
          }
        }
      }    
    }
    
    Executing stored procedure GET_EMP_PROJ (8):
    
    {
        "storedProcedureName":"GET_EMP_PROJ",
        "columnCount":1,
        "records":[
            {
                "PROJ_ID":"VBASE"
            },
            {
                "PROJ_ID":"GUIDE"
            },
            {
                "PROJ_ID":"MKTPR"
            }
        ]
    }
    
    
    Executing stored procedure MAIL_LABEL (1015):
    
    {
        "storedProcedureName":"MAIL_LABEL",
        "columnCount":6,
        "records":[
            {
                "LINE1":"GeoTech Inc.",
                "LINE2":"K.M. Neppelenbroek",
                "LINE3":"P.0.Box 702",
                "LINE4":"",
                "LINE5":null,
                "LINE6":"Netherlands    2514"
            }
        ]
    }
    
    
    Executing stored procedure ORG_CHART:
    
    {
        "storedProcedureName":"ORG_CHART",
        "columnCount":5,
        "records":[
            {
                "HEAD_DEPT":null,
                "DEPARTMENT":"Corporate Headquarters",
                "MNGR_NAME":"Bender, Oliver H.",
                "TITLE":"CEO",
                "EMP_CNT":2
            },
            {
                "HEAD_DEPT":"Corporate Headquarters",
                "DEPARTMENT":"Sales and Marketing",
                "MNGR_NAME":"MacDonald, Mary S.",
                "TITLE":"VP",
                "EMP_CNT":2
            },
            // ... SNIP ...
            {
                "HEAD_DEPT":"Corporate Headquarters",
                "DEPARTMENT":"Finance",
                "MNGR_NAME":"Steadman, Walter",
                "TITLE":"CFO",
                "EMP_CNT":2
            }
        ]
    }