【发布时间】:2025-12-30 02:00:06
【问题描述】:
我正在使用 Spring 的 Content Negotiation 和 OpenCSV 将 CSV 文件输出到客户端。
所以我有这个控制器:
@RequestMapping(value = { "", "/" }, method = RequestMethod.GET, produces = "text/csv")
@esponseStatus(HttpStatus.OK)
public Model getCustomersView(HttpServletRequest request, Model model)
throws InvalidBusinessContractDataException {
Customer[] customers = customerService.findCustomers();
return model.addAttribute("customers", customers);
}
还有这个媒体类型转换器:
@Component("viewNameTranslator")
public final class MediaTypeRequestToViewTranslator implements
RequestToViewNameTranslator {
@Autowired
private ContentNegotiationManager contentNegotiationManager;
private DefaultRequestToViewNameTranslator defaultTranslator = new DefaultRequestToViewNameTranslator();
// a list of media types to ignore - not output on the translated view
private List<String> ignoredTypes = Arrays.asList("text/html");
@Override
public String getViewName(HttpServletRequest request) {
// first resolve the media type (see below)
String mediaType = resolveMediaType(request);
// delegate to the default translator to get the view name
String viewName = defaultTranslator.getViewName(request);
// concatenate the resolved media type to the default name and return it
return viewName + mediaType;
}
private String resolveMediaType(HttpServletRequest request) {
try {
// use the content negotiation manager to resolve the media type
// from the request. The manager does it
// according to its own search path and preferences - using the
// suffix, using the Accept header and
// preferring one of them. The result would always be a single type
// or none at all, but it returns a list
List<MediaType> types = contentNegotiationManager
.resolveMediaTypes(new ServletWebRequest(request));
// resolve to a single type
String type = types == null || types.size() == 0 ? "" : types
.get(0).toString();
// if it's not in the ignored media types - prepend a semi-colon and
// return it
return ignoredTypes.contains(type) ? "" : ";" + type;
} catch (HttpMediaTypeNotAcceptableException e) {
return "";
}
}
}
还有这个观点:
@Component("customers;text/csv")
public final class CustomerCsvView implements View {
@Override
public String getContentType() {
return "text/csv";
}
@Override
public void render(Map<String, ?> model, HttpServletRequest request,
HttpServletResponse response) throws Exception {
response.setContentType("text/csv");
Customer[] customers = (Customer[]) model.get("customers");
CSVWriter writer = new CSVWriter(new OutputStreamWriter(response
.getOutputStream()));
writer.writeNext(new String[] {"id", "fName", "lName"});
for (Customer c : customers) {
System.out.println("FOO");
writer.writeNext(new String[] {
new Long(c.getCustomerId()).toString(), c.getFirstName(), c.getLastName() });
}
}
}
当我用浏览器点击此控制器时,“FOO”出现在我的控制台中两次,弹出一个文件保存对话框,其中包含要下载的 test/csv 文件,它是 0 字节。
就像没有保留对响应的更改。
怎么了?
【问题讨论】:
-
你用的是spring 3