我使用spring jdbctemplate与Oracle数据库进行交互。 为了获取给定条件的多行,我想将结果存储在以列名作为标题的csv文件中。
我尝试了几种方法 -
List<Bean> list = jdbcTemplate.query('query','parameters',customizedrowmapper);
在customizerowmapper中,我从结果集中获取行并在Bean类中设置字段。我找不到任何简单的方法从bean转换为csv文件。因为我没有访问bean类代码。
我找到的第二种方法是使用opencsv库直接将ResultSet编写到csv文件中。
CSVWriter wr = new CSVWriter(new FileWriter("Report.csv"), ',');
wr.writeAll(rs, true);
wr.flush();
wr.close();
这样做没问题,但是在写入csv时它正在跳过一行。我试了几个查询。手动,我可以在结果中看到4行,但在CSV中,它只存储三行。有人遇到过类似的问题吗?
或者我们可以实现相同的任何其他方式,无需手动从ResultSet获取每个记录并使其以逗号分隔的字符串并存储在文件中。
答案 0 :(得分:2)
此代码保存查询结果并将其作为csv文件返回(您可以使用端点下载它)。但是,如果您不需要将其返回给控制器中的用户,则可以轻松地将所有数据转发到FileOutputStream
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.ResultSetExtractor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
@RestController
@RequestMapping("/api/report")
public class UserReportController {
private JdbcTemplate jdbcTemplate;
public UserReportController(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
private static String ALL_USERS_QUERY = "select * from users";
@GetMapping("/all-users")
public void allUsers(HttpServletResponse response) throws IOException {
response.setContentType("text/csv");
jdbcTemplate.query(ALL_USERS_QUERY, new StreamingCsvResultSetExtractor(response.getOutputStream()));
}
class StreamingCsvResultSetExtractor
implements ResultSetExtractor<Void> {
private char DELIMITER = ',';
private final OutputStream os;
public StreamingCsvResultSetExtractor(final OutputStream os) {
this.os = os;
}
@Override
public Void extractData(final ResultSet rs) {
try (PrintWriter pw = new PrintWriter(os, true)) {
final ResultSetMetaData rsmd = rs.getMetaData();
final int columnCount = rsmd.getColumnCount();
writeHeader(rsmd, columnCount, pw);
while (rs.next()) {
for (int i = 1; i <= columnCount; i++) {
final Object value = rs.getObject(i);
String strValue = value == null ? "" : value.toString();
pw.write(strValue.contains(",") ? "\"" + strValue+ "\"" : strValue);
if (i != columnCount) {
pw.append(DELIMITER);
}
}
pw.println();
}
pw.flush();
} catch (final SQLException e) {
throw new RuntimeException(e);
}
return null;
}
private void writeHeader(final ResultSetMetaData rsmd,
final int columnCount, final PrintWriter pw) throws SQLException {
for (int i = 1; i <= columnCount; i++) {
pw.write(rsmd.getColumnName(i));
if (i != columnCount) {
pw.append(DELIMITER);
}
}
pw.println();
}
}
}
答案 1 :(得分:0)
请注意,当jdbcTemplate将ResultSet传递给RowCallbackHandler或Mapper时,它已经定位在第一条记录上(已调用rs.next())。 CSVWriter在处理任何记录之前再次调用rs.next(),因此永远不会写入第一条记录。 您需要自己编写数据,例如:
public class CustomRowCallbackHandler implements RowCallbackHandler {
@Override
public void processRow(ResultSet rs) throws SQLException {
try {
CSVWriter w = new CSVWriter(new FileWriter("Report.csv"), ',');
int columnCount = rs.getMetaData().getColumnCount();
//Write column names
String[] ssn = new String[columnCount];
for(int i = 1; i < columnCount; i++){
ssn[i - 1] = rs.getMetaData().getColumnName(i);
}
w.writeNext(ssn);
//Write data
do{
String[] ss = new String[columnCount];
for(int i = 1; i < columnCount; i++){
ss[i - 1] = rs.getString(i);
}
w.writeNext(ss);
}while(rs.next());
w.flush();
w.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
希望它有所帮助。