如何将 Spring 控制器从 POJO 转换为 return CSV?
How to make Spring Controller to return CSV from a POJO?
给定一个简单的 Java 对象:
public class Pojo {
private String x;
private String y;
private String z;
//... getters/setters ...
}
是否有一些我可以放在我的项目中的库来制作这样的控制器:
@RequestMapping(value="/csv", method=RequestMethod.GET, produces= MediaType.TEXT_PLAIN)
@ResponseBody
public List<Pojo> csv() {
//Some code to get a list of Pojo objects
//...
return myListOfPojos;
}
要生成我的 Pojos 的 csv 文件?对于 Json 结果,我使用 Jackson 库。我需要另一个库来获取 CSV 结果。
作为一个简单的变体。您可以通过任何您想要的方式生成 csv,并且 return 它作为字符串。
像这样:
@RequestMapping(value="/csv", method=RequestMethod.GET)
@ResponseBody
public String csv() {
//Some code to get a list of Pojo objects
//...
StringBuilder sb = new StringBuilder();
for (Pojo pojo: myListOfPojos){
sb.append(pojo.getX());
sb.append(",");
sb.append(pojo.getY());
sb.append(",");
sb.append(pojo.getZ());
sb.append("\n");
}
return sb.toString;
}
应该可以。
通过反射自动生成这个字符串看起来也很简单。
根据另一个问题,我为 Tsv 响应做了自己的 HTTPMessageConverter。
TsvMessageConverter.java
public class TsvMessageConverter extends AbstractHttpMessageConverter<TsvResponse> {
public static final MediaType MEDIA_TYPE = new MediaType("text", "tsv", Charset.forName("utf-8"));
private static final Logger logger = LoggerFactory.getLogger(TsvMessageConverter.class);
public TsvMessageConverter() {
super(MEDIA_TYPE);
}
protected boolean supports(Class<?> clazz) {
return TsvResponse.class.equals(clazz);
}
@Override
protected TsvResponse readInternal(Class<? extends TsvResponse> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
return null;
}
protected void writeInternal(TsvResponse tsvResponse, HttpOutputMessage output) throws IOException, HttpMessageNotWritableException {
output.getHeaders().setContentType(MEDIA_TYPE);
output.getHeaders().set("Content-Disposition", "attachment; filename=\"" + tsvResponse.getFilename() + "\"");
final OutputStream out = output.getBody();
writeColumnTitles(tsvResponse, out);
if (tsvResponse.getRecords() != null && tsvResponse.getRecords().size() != 0) {
writeRecords(tsvResponse, out);
}
out.close();
}
private void writeRecords(TsvResponse response, OutputStream out) throws IOException {
List<String> getters = getObjectGetters(response);
for (final Object record : response.getRecords()) {
for (String getter : getters) {
try {
Method method = ReflectionUtils.findMethod(record.getClass(), getter);
out.write(method.invoke(record).toString().getBytes(Charset.forName("utf-8")));
out.write('\t');
} catch (IllegalAccessException | InvocationTargetException e) {
logger.error("Erro ao transformar em CSV", e);
}
}
out.write('\n');
}
}
private List<String> getObjectGetters(TsvResponse response) {
List<String> getters = new ArrayList<>();
for (Method method : ReflectionUtils.getAllDeclaredMethods(response.getRecords().get(0).getClass())) {
String methodName = method.getName();
if (methodName.startsWith("get") && !methodName.equals("getClass")) {
getters.add(methodName);
}
}
sort(getters);
return getters;
}
private void writeColumnTitles(TsvResponse response, OutputStream out) throws IOException {
for (String columnTitle : response.getColumnTitles()) {
out.write(columnTitle.getBytes());
out.write('\t');
}
out.write('\n');
}
}
TsvResponse.java
public class TsvResponse {
private final String filename;
private final List records;
private final String[] columnTitles;
public TsvResponse(List records, String filename, String ... columnTitles) {
this.records = records;
this.filename = filename;
this.columnTitles = columnTitles;
}
public String getFilename() {
return filename;
}
public List getRecords() {
return records;
}
public String[] getColumnTitles() {
return columnTitles;
}
}
并在 SpringContext.xml 上添加以下内容:
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
<bean class="com.mypackage.TsvMessageConverter"/>
</mvc:message-converters>
</mvc:annotation-driven>
因此,您可以像这样在控制器上使用:
@RequestMapping(value="/tsv", method= RequestMethod.GET, produces = "text/tsv")
@ResponseBody
public TsvResponse tsv() {
return new TsvResponse(myListOfPojos, "fileName.tsv",
"Name", "Email", "Phone", "Mobile");
}
给定一个简单的 Java 对象:
public class Pojo {
private String x;
private String y;
private String z;
//... getters/setters ...
}
是否有一些我可以放在我的项目中的库来制作这样的控制器:
@RequestMapping(value="/csv", method=RequestMethod.GET, produces= MediaType.TEXT_PLAIN)
@ResponseBody
public List<Pojo> csv() {
//Some code to get a list of Pojo objects
//...
return myListOfPojos;
}
要生成我的 Pojos 的 csv 文件?对于 Json 结果,我使用 Jackson 库。我需要另一个库来获取 CSV 结果。
作为一个简单的变体。您可以通过任何您想要的方式生成 csv,并且 return 它作为字符串。
像这样:
@RequestMapping(value="/csv", method=RequestMethod.GET)
@ResponseBody
public String csv() {
//Some code to get a list of Pojo objects
//...
StringBuilder sb = new StringBuilder();
for (Pojo pojo: myListOfPojos){
sb.append(pojo.getX());
sb.append(",");
sb.append(pojo.getY());
sb.append(",");
sb.append(pojo.getZ());
sb.append("\n");
}
return sb.toString;
}
应该可以。
通过反射自动生成这个字符串看起来也很简单。
根据另一个问题,我为 Tsv 响应做了自己的 HTTPMessageConverter。
TsvMessageConverter.java
public class TsvMessageConverter extends AbstractHttpMessageConverter<TsvResponse> {
public static final MediaType MEDIA_TYPE = new MediaType("text", "tsv", Charset.forName("utf-8"));
private static final Logger logger = LoggerFactory.getLogger(TsvMessageConverter.class);
public TsvMessageConverter() {
super(MEDIA_TYPE);
}
protected boolean supports(Class<?> clazz) {
return TsvResponse.class.equals(clazz);
}
@Override
protected TsvResponse readInternal(Class<? extends TsvResponse> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
return null;
}
protected void writeInternal(TsvResponse tsvResponse, HttpOutputMessage output) throws IOException, HttpMessageNotWritableException {
output.getHeaders().setContentType(MEDIA_TYPE);
output.getHeaders().set("Content-Disposition", "attachment; filename=\"" + tsvResponse.getFilename() + "\"");
final OutputStream out = output.getBody();
writeColumnTitles(tsvResponse, out);
if (tsvResponse.getRecords() != null && tsvResponse.getRecords().size() != 0) {
writeRecords(tsvResponse, out);
}
out.close();
}
private void writeRecords(TsvResponse response, OutputStream out) throws IOException {
List<String> getters = getObjectGetters(response);
for (final Object record : response.getRecords()) {
for (String getter : getters) {
try {
Method method = ReflectionUtils.findMethod(record.getClass(), getter);
out.write(method.invoke(record).toString().getBytes(Charset.forName("utf-8")));
out.write('\t');
} catch (IllegalAccessException | InvocationTargetException e) {
logger.error("Erro ao transformar em CSV", e);
}
}
out.write('\n');
}
}
private List<String> getObjectGetters(TsvResponse response) {
List<String> getters = new ArrayList<>();
for (Method method : ReflectionUtils.getAllDeclaredMethods(response.getRecords().get(0).getClass())) {
String methodName = method.getName();
if (methodName.startsWith("get") && !methodName.equals("getClass")) {
getters.add(methodName);
}
}
sort(getters);
return getters;
}
private void writeColumnTitles(TsvResponse response, OutputStream out) throws IOException {
for (String columnTitle : response.getColumnTitles()) {
out.write(columnTitle.getBytes());
out.write('\t');
}
out.write('\n');
}
}
TsvResponse.java
public class TsvResponse {
private final String filename;
private final List records;
private final String[] columnTitles;
public TsvResponse(List records, String filename, String ... columnTitles) {
this.records = records;
this.filename = filename;
this.columnTitles = columnTitles;
}
public String getFilename() {
return filename;
}
public List getRecords() {
return records;
}
public String[] getColumnTitles() {
return columnTitles;
}
}
并在 SpringContext.xml 上添加以下内容:
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
<bean class="com.mypackage.TsvMessageConverter"/>
</mvc:message-converters>
</mvc:annotation-driven>
因此,您可以像这样在控制器上使用:
@RequestMapping(value="/tsv", method= RequestMethod.GET, produces = "text/tsv")
@ResponseBody
public TsvResponse tsv() {
return new TsvResponse(myListOfPojos, "fileName.tsv",
"Name", "Email", "Phone", "Mobile");
}