前端:Vue
后端:Java
1、csv的文件中文内容 excel打开是乱码,wps没问题(wps会进行不同的编码转换,excel不会)
2、其他未出现但潜在的问题(文件名中带空格,xxx xxx.csv最后变成的xxx+xxx.csv)
3、文件名是中文,出现乱码
1、文件名为中文
2、文件名中有空格
3、文件内容有中文
以上问题都需要处理
对于文件名的处理:
把从content-disposition里面获取的fileName进行decodeURI处理
对于中文内容乱码的处理:
httprequest的responseType要添加为blob responseType: 'blob’
- _this.$axios({
- method: 'get',
- url: origin + url,
- params,
- headers,
- responseType: 'blob', //重点代码
- timeout: 30000
- }).then(res => {
-
- const disposition = res.headers['content-disposition']
- let fName = decodeURI(disposition.substring(disposition.indexOf('filename=') + 9, disposition.length))
- fName = fName.replace(/"/g, '')
- link.download = fName
-
- import env from '../env'
-
- /**
- * 导出 CSV 文件下载
- * @param _this 上下文
- * @param url 请求地址
- * @param params 请求参数
- * @param fileName 文件名(需要带后缀, 如果传 false/null/undefined 可直接使用后台返回的文件名)
- * @param loadingName loading 挂载在 _this 上的名字
- */
- export const downloadCSV = (_this, url, params, fileName, loadingName) => {
- _this[loadingName] = true
- const origin = process.env.NODE_ENV === 'localDevelopment' ? process.env.BASE_URL : window.location.origin + process.env.BASE_URL
- const headers = {}
- let downloadUrl = ''
- if (_this.$store.state.user.token) {
- headers.userId = _this.$store.state.user.userId // 登录中,默认带用户ID
- headers.Token = _this.$store.state.user.token // 请求接口决定是否带Token
- }
- _this.$axios({
- method: 'get',
- url: origin + url,
- params,
- headers,
- responseType: 'blob',
- timeout: 30000
- }).then(res => {
- downloadUrl = window.URL.createObjectURL(new Blob([res.data]))
- const link = document.createElement('a')
- link.style.display = 'none'
- link.href = downloadUrl
- if (fileName) {
- link.download = fileName
- } else {
- const disposition = res.headers['content-disposition']
- let fName = decodeURI(disposition.substring(disposition.indexOf('filename=') + 9, disposition.length))
- fName = fName.replace(/"/g, '')
- link.download = fName
- }
- document.body.appendChild(link)
- link.click()
- }).finally(() => {
- _this[loadingName] = false
- window.URL.revokeObjectURL(downloadUrl)
- })
- }
-
-
对于文件名处理:
里面fileName需要UrlEncoder进行url转义处理
且对于文件名中有空格而言,会转为%x%x+%x%x.csv 这里会替换+为%20
- @Override
- public ResponseEntity<byte[]> toResponse() {
- this.close();
- try {
- FileInputStream fis = new FileInputStream(this.csvFile);
- ByteArrayOutputStream bos = new ByteArrayOutputStream();
- byte[] b = new byte[1024];
- int n;
- while ((n = fis.read(b)) != -1) {
- bos.write(b, 0, n);
- }
- fis.close();
- bos.close();
- HttpHeaders httpHeaders = new HttpHeaders();
- String encodeName = URLEncoder.encode(this.name + SUFFIX, "UTF-8");
- String fileName = encodeName.replace("+", "%20");
- httpHeaders.setContentDispositionFormData("attachment", fileName);
- httpHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM);
- httpHeaders.setAccessControlExposeHeaders(Collections.singletonList("Content-Disposition"));
- return new ResponseEntity<>(bos.toByteArray(), httpHeaders, HttpStatus.CREATED);
- } catch (IOException e) {
- throw new BaseException(CSV_IO_EXCEPTION);
- }
- }
-
- import lombok.Getter;
- import org.apache.commons.csv.CSVFormat;
- import org.apache.commons.csv.CSVPrinter;
- import org.springframework.http.HttpHeaders;
- import org.springframework.http.HttpStatus;
- import org.springframework.http.MediaType;
- import org.springframework.http.ResponseEntity;
-
- import java.io.*;
- import java.net.URLEncoder;
- import java.util.Arrays;
- import java.util.Collection;
- import java.util.Collections;
- import java.util.stream.Stream;
-
-
- /**
- * Csv文件导出工具实现类
- *
- * @author hx
- * @version 1.0
- * @date 2021/5/25 16:45
- */
-
-
- @Getter
- public class CsvUtil implements FileUtil {
- private static final String PREFIX = "vehicle";
- private static final String SUFFIX = ".csv";
- private final String name;
- private String[] headers;
- private FileOutputStream fos;
- private File csvFile;
- private String inCharset;
- private String outCharset;
- private OutputStreamWriter osw;
- private CSVPrinter csvPrinter;
-
- public CsvUtil(String name) {
- this(name, "UTF-8", "iso-8859-1");
- }
-
- public CsvUtil(String name, String inCharset, String outCharset) {
- this.name = name;
- this.inCharset = inCharset;
- this.outCharset = outCharset;
- }
-
- @Override
- public void setHeader(String... headers) {
- this.setHeaders(headers);
- }
-
- @Override
- public void setHeaders(String[] headers) {
- this.headers = headers;
- this.initPrinter();
- }
-
- @Override
- public void setHeaders(Collection<String> row) {
- this.setHeaders(row.toArray(new String[0]));
- }
-
- @Override
- public void writeVaried(Iterable<?> row) {
- try {
- this.csvPrinter.printRecord(row);
- } catch (IOException e) {
- throw new BaseException(CSV_IO_EXCEPTION);
- } catch (NullPointerException e) {
- this.initPrinter();
- this.writeVaried(row);
- }
- }
-
-
- @Override
- public void writeRow(Object[] row) {
- try {
- this.csvPrinter.printRecord(row);
- } catch (IOException e) {
- throw new BaseException(CSV_IO_EXCEPTION);
- } catch (NullPointerException e) {
- this.initPrinter();
- this.writeRow(row);
- }
- }
-
-
- @Override
- public void writeFeed() {
- try {
- this.csvPrinter.println();
- } catch (IOException e) {
- throw new BaseException(CSV_IO_EXCEPTION);
- } catch (NullPointerException e) {
- this.initPrinter();
- this.writeFeed();
- }
- }
-
- @Override
- public void writeEmptyLine() {
- try {
- this.csvPrinter.println();
- } catch (IOException e) {
- this.writeLine("");
- } catch (NullPointerException e) {
- this.initPrinter();
- this.writeEmptyLine();
- }
- }
-
- @Override
- public void writeLine(Object... line) {
- this.writeRow(line);
- }
-
- @Override
- public void writeStrLine(String... line) {
- Stream<String> stream = Arrays.stream(line);
- this.writeVaried(FileUtil.filterStrStream(stream));
- }
-
- @Override
- public void writeStrRow(String[] row) {
- Stream<String> stream = Arrays.stream(row);
- this.writeVaried(FileUtil.filterStrStream(stream));
- }
-
- @Override
- public void writeList(Collection<?> row) {
- this.writeVaried(row);
- }
-
- @Override
- public void writeStrList(Collection<String> row) {
- this.writeVaried(FileUtil.filterStrStream(row.stream()));
- }
-
-
- @Override
- public ResponseEntity<byte[]> toResponse() {
- this.close();
- try {
- FileInputStream fis = new FileInputStream(this.csvFile);
- ByteArrayOutputStream bos = new ByteArrayOutputStream();
- byte[] b = new byte[1024];
- int n;
- while ((n = fis.read(b)) != -1) {
- bos.write(b, 0, n);
- }
- fis.close();
- bos.close();
- HttpHeaders httpHeaders = new HttpHeaders();
- String encodeName = URLEncoder.encode(this.name + SUFFIX, "UTF-8");
- String fileName = encodeName.replace("+", "%20");
- httpHeaders.setContentDispositionFormData("attachment", fileName);
- httpHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM);
- httpHeaders.setAccessControlExposeHeaders(Collections.singletonList("Content-Disposition"));
- return new ResponseEntity<>(bos.toByteArray(), httpHeaders, HttpStatus.CREATED);
- } catch (IOException e) {
- throw new BaseException(CSV_IO_EXCEPTION);
- }
- }
-
- @Override
- public void close() {
- FileUtil.close(csvPrinter, osw, fos);
- }
-
- private void initPrinter() {
- CSVFormat csvFormat = CSVFormat.DEFAULT;
- if (this.headers != null) {
- csvFormat = csvFormat.withHeader(this.headers);
- }
- try {
- this.csvFile = File.createTempFile(PREFIX, SUFFIX);
- this.fos = new FileOutputStream(this.csvFile);
- this.osw = new OutputStreamWriter(fos);
- //防止excel中文乱码
- this.osw.write('\ufeff');
- this.osw.flush();
- this.csvPrinter = new CSVPrinter(this.osw, csvFormat);
- } catch (IOException e) {
- this.close();
- throw new BaseException(CSV_IO_EXCEPTION);
- }
- }
-
- public void setInCharset(String inCharset) {
- this.inCharset = inCharset;
- }
-
- public void setOutCharset(String outCharset) {
- this.outCharset = outCharset;
- }
- }
-
-
以上问题,不仅针对于导出csv,一切导出下载文件,皆可适用,仅供参考