22

作为使用 JDBC 连接器的 MySQL 查询的结果,我有一个结果集。所以我的工作是将结果集转换为 JSON 格式。这样我就可以将它作为 AJAX 响应发送到客户端。有人可以解释如何转换为 JSON 格式,因为我对 Java 和 JSON 的概念都是新手

4

10 回答 10

16

很多人都正确回答了这个问题。但是,我认为我可以使用以下一小段代码为帖子添加更多价值。它使用Apache-DBUtilsGson库。

public static String resultSetToJson(Connection connection, String query) {
        List<Map<String, Object>> listOfMaps = null;
        try {
            QueryRunner queryRunner = new QueryRunner();
            listOfMaps = queryRunner.query(connection, query, new MapListHandler());
        } catch (SQLException se) {
            throw new RuntimeException("Couldn't query the database.", se);
        } finally {
            DbUtils.closeQuietly(connection);
        }
        return new Gson().toJson(listOfMaps);
    }
于 2014-12-27T17:50:51.173 回答
9

如果您使用 JSON,我推荐 Jackson JSON 库。

http://wiki.fasterxml.com/JacksonHome

jar 文件可以在这里找到:

http://wiki.fasterxml.com/JacksonDownload

这是我用来将任何结果集转换为 Map<> 或 List< Map<> > 使用 JacksonJSON 将其转换为 JSON 的通用代码非常简单(见下文)。

package com.naj.tmoi.entity;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class EntityFactory {

    public EntityFactory(Connection connection, String queryString) {
        this.queryString = queryString;
        this.connection = connection;
    }

    public Map<String, Object> findSingle(Object[] params) throws SQLException {
        List<Map<String, Object>> objects = this.findMultiple(params);

        if (objects.size() != 1) {
            throw new SQLException("Query did not produce one object it produced: " + objects.size() + " objects.");
        }

        Map<String, Object> object = objects.get(0);  //extract only the first item;

        return object;
    }

    public List<Map<String, Object>> findMultiple(Object[] params) throws SQLException {
        ResultSet rs = null;
        PreparedStatement ps = null;
        try {
            ps = this.connection.prepareStatement(this.queryString);
            for (int i = 0; i < params.length; ++i) {
                ps.setObject(1, params[i]);
            }

            rs = ps.executeQuery();
            return getEntitiesFromResultSet(rs);
        } catch (SQLException e) {
            throw (e);
        } finally {
            if (rs != null) {
                rs.close();
            }
            if (ps != null) {
                ps.close();
            }
        }
    }

    protected List<Map<String, Object>> getEntitiesFromResultSet(ResultSet resultSet) throws SQLException {
        ArrayList<Map<String, Object>> entities = new ArrayList<>();
        while (resultSet.next()) {
            entities.add(getEntityFromResultSet(resultSet));
        }
        return entities;
    }

    protected Map<String, Object> getEntityFromResultSet(ResultSet resultSet) throws SQLException {
        ResultSetMetaData metaData = resultSet.getMetaData();
        int columnCount = metaData.getColumnCount();
        Map<String, Object> resultsMap = new HashMap<>();
        for (int i = 1; i <= columnCount; ++i) {
            String columnName = metaData.getColumnName(i).toLowerCase();
            Object object = resultSet.getObject(i);
            resultsMap.put(columnName, object);
        }
        return resultsMap;
    }
    private final String queryString;
    protected Connection connection;
}

在 servlet 中,我使用 com.fasterxml.jackson.databind.ObjectMapper 将列表转换为 JSON,它将 Java 泛型转换为 JSON 字符串。

    Connection connection = null;
    try {
        connection = DataSourceSingleton.getConnection();
        EntityFactory nutrientEntityFactory = new EntityFactory(connection, NUTRIENT_QUERY_STRING);
        List<Map<String, Object>> nutrients = nutrientEntityFactory.findMultiple(new Object[]{});

        ObjectMapper mapper = new ObjectMapper();

        String json = mapper.writeValueAsString(nutrients);


        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().write(json);
    } catch (SQLException e) {
        throw new ServletException(e);
    } finally {
        if (connection != null) {
            try {
                connection.close();
            } catch (SQLException e) {
                throw new ServletException(e);
            }
        }
    }

您可以像这样将参数传递给 PreparedStatement:

String name = request.getHeader("name");
EntityFactory entityFactory = new EntityFactory(DataSourceSingleton.getConnection(), QUERY_STRING);
Map<String, Object> object = entityFactory.findSingle(new String[]{name});


private static final String QUERY_STRING = "SELECT NAME, PASSWORD, TOKEN, TOKEN_EXPIRATION FROM USER WHERE NAME = ?";

}

于 2013-09-23T13:35:54.970 回答
5

我使用了 Google GSON 库,它是一个很小的 ​​gson-2.2.4.jar 190KB 库,位于 mywebapp/WEB-INF/lib 文件夹中。 http://code.google.com/p/google-gson/

import com.google.gson.stream.JsonWriter;
---
httpres.setContentType("application/json; charset=UTF-8");
httpres.setCharacterEncoding("UTF-8");
JsonWriter writer = new JsonWriter(new OutputStreamWriter(httpres.getOutputStream(), "UTF-8"));
while(rs.next()) {
   writer.beginObject();
   // loop rs.getResultSetMetadata columns
   for(int idx=1; idx<=rsmd.getColumnCount(); idx++) {
     writer.name(rsmd.getColumnLabel(idx)); // write key:value pairs
     writer.value(rs.getString(idx));
   }
   writer.endObject();
}
writer.close();
httpres.getOutputStream().flush();

如果您想要键入 JSON 键:值对,则有 writer.value(String,long,integer,etc..) 设置器。在 foreach rsmd 循环中执行 switch-case 并为编号的 sql 类型使用适当的设置器。默认可以使用 writer.value(rs.getString(idx)) 设置器。

使用 JsonWriter 可以有效地编写大型 json 回复 CPU+RAM。您不需要先循环 sqlresultset 并在 RAM 中创建大量列表。然后在编写 json 文档时再次循环列表。这个例子顺其自然,http 回复被分块,而剩余的数据仍被写入 servlet 输出。

围绕 GSON+Sql 结果集创建更高级别的包装器工具相对容易。jsp 页面在编写 http 回复时可以使用 SqlIterator(sqlquery) 方法(.next()、getColumnCount()、getType(idx)、.getString(idx)、.getLong(idx) ...)。它在没有中间列表的情况下循环原始 sql。这对于较小的应用程序无关紧要,但重度使用的应用程序必须更仔细地考虑 cpu+ram 使用模式。或者更好的做法是使用 SqlToJson(httpresponse, sqlrs) 助手然后 jsp 或 servlet 代码噪音最小。

于 2013-09-23T14:16:09.537 回答
4

您可以使用任何 JSON 库。

下面是一个实现,返回一个列表,每个元素都是一个 JSON 对象:

/*
 * Convert ResultSet to a common JSON Object array
 * Result is like: [{"ID":"1","NAME":"Tom","AGE":"24"}, {"ID":"2","NAME":"Bob","AGE":"26"}, ...]
 */
public static List<JSONObject> getFormattedResult(ResultSet rs) {
    List<JSONObject> resList = new ArrayList<JSONObject>();
    try {
        // get column names
        ResultSetMetaData rsMeta = rs.getMetaData();
        int columnCnt = rsMeta.getColumnCount();
        List<String> columnNames = new ArrayList<String>();
        for(int i=1;i<=columnCnt;i++) {
            columnNames.add(rsMeta.getColumnName(i).toUpperCase());
        }

        while(rs.next()) { // convert each object to an human readable JSON object
            JSONObject obj = new JSONObject();
            for(int i=1;i<=columnCnt;i++) {
                String key = columnNames.get(i - 1);
                String value = rs.getString(i);
                obj.put(key, value);
            }
            resList.add(obj);
        }
    } catch(Exception e) {
        e.printStackTrace();
    } finally {
        try {
            rs.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    return resList;
}
于 2015-05-27T09:10:56.533 回答
1

如果你想使用 Spring,这很容易:

@RestController
public class MyController

  @Autowired
  private JdbcTemplate jdbcTemplate;

  @RequestMapping("/")
  List<Map<String,Object>> getAll() {
    return jdbcTemplate.queryForList("select * from my_table");
  }
}

在 mvc-dispatcher-servlet.xml 中,您可以像这样设置 JdbcTemplate:

<bean class="org.springframework.jdbc.core.JdbcTemplate" id="jdbcTemplate">
  <property name="dataSource">
    ...data source config...
  </property>
</bean>

Jackson 应该在您的类路径中(即 Maven 依赖项)。

于 2014-10-03T23:03:30.327 回答
1
  • 将结果集转换为List<Map<String, Object>>(每个映射包含以列名作为键、以列内容作为值的行,List 是此类行的列表)
  • 使用 Gson 或 Jackson 库将此对象转换为 JSON。
于 2013-09-23T14:01:33.407 回答
0

jsonlib用于 Java。遍历结果集并将所需的属性添加为JSONObjectjsonlib 中的对象。

于 2013-09-23T13:27:00.527 回答
0

我在这里找到了最好的解决方案。

import org.json.JSONArray;
import org.json.JSONObject;
import java.sql.ResultSet;

/**
 * Convert a result set into a JSON Array
 * @param resultSet
 * @return a JSONArray
 * @throws Exception
 */
public static JSONArray convertToJSON(ResultSet resultSet)
        throws Exception {
    JSONArray jsonArray = new JSONArray();
    while (resultSet.next()) {
        int total_rows = resultSet.getMetaData().getColumnCount();
        for (int i = 0; i < total_rows; i++) {
            JSONObject obj = new JSONObject();
            obj.put(resultSet.getMetaData().getColumnLabel(i + 1)
                    .toLowerCase(), resultSet.getObject(i + 1));
            jsonArray.put(obj);
        }
    }
    return jsonArray;
}
于 2019-06-08T13:22:58.120 回答
0

在我的应用程序(浏览器上的 MySQL/java servlet/javascript)中,我使用了一个带有快速 stringbuilder 方法和一个通用 rs.getObject() 的字符串函数。我认为这是完成这项工作的最优雅的方式:

public  String rStoJason(ResultSet rs) throws SQLException 
{
  if(rs.first() == false) {return "[]";} else {rs.beforeFirst();} // empty rs
  StringBuilder sb=new StringBuilder();
  Object item; String value;
  java.sql.ResultSetMetaData rsmd = rs.getMetaData();
  int numColumns = rsmd.getColumnCount();

  sb.append("[{");
  while (rs.next()) {

    for (int i = 1; i < numColumns + 1; i++) {
        String column_name = rsmd.getColumnName(i);
        item=rs.getObject(i);
        if (item !=null )
           {value = item.toString(); value=value.replace('"', '\'');}
        else 
           {value = "null";}
        sb.append("\"" + column_name+ "\":\"" + value +"\",");

    }                                   //end For = end record

    sb.setCharAt(sb.length()-1, '}');   //replace last comma with curly bracket
    sb.append(",{");
 }                                      // end While = end resultset

 sb.delete(sb.length()-3, sb.length()); //delete last two chars
 sb.append("}]");

 return sb.toString();
}
于 2016-02-29T15:23:32.483 回答
0

如果您使用 Spring 的 JDBCTemplate 来执行存储函数,该函数将光标作为表条目列表返回,并且您希望将其映射为指定 bean 的列表,那么有最简洁的解决方案:

import com.fasterxml.jackson.databind.ObjectMapper;

...

final static ObjectMapper mapper = new ObjectMapper();

...

<T> List<T> populateExecuteRetrieve(SimpleJdbcCall call, Map inputParameters, Class<T> outputClass) {
    List<?> sqlResult;
    sqlResult = call.executeFunction(ArrayList.class, parameter);
    return sqlResult
            .stream()
            .map(entry -> mapper.convertValue(entry, outputBeanClass))
            .collect(Collectors.toList());
}

不客气!

快乐编码!

于 2019-08-09T10:26:04.193 回答