Java Spring returning CSV file encoded in UTF-8 with BOM
显然,对于excel来说,它很好地打开了CSV文件,它的开头应该有字节顺序标记。 CSV的下载是通过在控制器中写入
有问题的控制器方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | @RequestMapping("/monthly/list") public List<MonthlyDetailsItem> queryDetailsItems( MonthlyDetailsItemQuery query, @RequestParam(value ="format", required = false) String format, @RequestParam(value ="attachment", required = false, defaultValue="false") Boolean attachment, HttpServletResponse response) throws Exception { // load item list List<MonthlyDetailsItem> list = detailsSvc.queryMonthlyDetailsForList(query); // adjust format format = format != null ? format.toLowerCase() :"json"; if (!Arrays.asList("json","csv").contains(format)) format ="json"; // modify common response headers response.setCharacterEncoding("UTF-8"); if (attachment) response.setHeader("Content-Disposition","attachment;filename=duomenys." + format); // build csv if ("csv".equals(format)) { response.setContentType("text/csv; charset=UTF-8"); response.getOutputStream().print("\\ufeff"); response.getOutputStream().write(buildMonthlyDetailsItemCsv(list).getBytes("UTF-8")); return null; } return list; } |
我刚刚遇到了同样的问题。对我有用的解决方案是从响应对象获取输出流,并按如下方式对其进行写入
1 2 3 4 5 6 7 8 9 10 11 12 | // first create an array for the Byte Order Mark final byte[] bom = new byte[] { (byte) 239, (byte) 187, (byte) 191 }; try (OutputStream os = response.getOutputStream()) { os.write(bom); final PrintWriter w = new PrintWriter(new OutputStreamWriter(os,"UTF-8")); w.print(data); w.flush(); w.close(); } catch (IOException e) { // logit } |
因此,在OutputStreamWriter上指定了UTF-8。
作为补充,我应该补充一点,同一应用程序需要允许用户上传文件,这些文件可能带有或不带有BOM。这可以通过使用类
BOMInputStream包括方法
我首先陷入的一个陷阱是
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | try (InputStream is = uploadFile.getInputStream(); BufferedInputStream buffIs = new BufferedInputStream(is); BOMInputStream bomIn = new BOMInputStream(buffIs);) { buffIs.mark(LOOKAHEAD_LENGTH); // this should allow us to deal with csv's with or without BOMs final boolean hasBOM = bomIn.hasBOM(); final BufferedReader buffReadr = new BufferedReader( new InputStreamReader(hasBOM ? bomIn : buffIs, StandardCharsets.UTF_8)); // if this stream does not have a BOM, then we must reset the stream as the test // for a BOM will have consumed some bytes if (!hasBOM) { buffIs.reset(); } // collect the validated entity details final CSVParser parser = CSVParser.parse(buffReadr, CSVFormat.DEFAULT.withFirstRecordAsHeader()); // Do stuff with the parser ... // Catch and clean up |
希望这对某人有帮助。
这没有多大意义:BOM适用于UTF-16。 UTF-8没有字节顺序。您使用setCharacterEncoding设置的编码用于getWriter,而不用于getOutputStream。
更新:
OK,试试这个:
1 2 3 4 5 6 7 | if ("csv".equals(format)) { response.setContentType("text/csv; charset=UTF-8"); PrintWriter out = response.getWriter(); out.print("\\uFEFF"); out.print(buildMonthlyDetailsItemCsv(list)); return null; } |
我假设该方法buildMonthlyDetailsItemCsv返回一个字符串。