在自己项目中有涉及到CSV导入导出的功能,自己通过查询资料和修改,总结了一份使用模板,仅作为参考。
导入
<div>
<input name="file" id="file" type="file" accept=".csv" onchange="changeFile" style="display: none;">
<button type="button" class="btn btn-default " onclick="$('#file').click()">上传文件</button>
</div>
@change 方法是使用的vue监听了文件改变事件,可以做一些类似于文件大小判断的操作等。
function changeFile(event){
if(event.target.files[0].size>1024*1024*2){
alert("单个文件不超过2M");
return;
}
console.log(event.target.files[0].name+"("+bytesToSize(event.target.files[0].size)+")");
}
//根据byte 转换容量
function bytesToSize(bytes) {
if (bytes === 0) return '0 B';
var k = 1024, // or 1024
sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'],
i = Math.floor(Math.log(bytes) / Math.log(k));
return (bytes / Math.pow(k, i)).toPrecision(3) + sizes[i];
}
科普一下files都包含哪些内容
name: 本地文件的名称
size: 文件的字节大小
type: 字符、文件的MIME类型
lastModifiedDate: 文件上次修改的时间(chrome实现了这属性)
Files api 可以参考这篇博文https://blog.csdn.net/jyy_12/article/details/9851349
言归正传,接下来是js上传文件的操作
var $form = new FormData($('#form')[0]);
$.ajax({
url: 'xxx/importCsv' ,
type: 'post',
data: $form,
processData:false,
contentType:false,
success:function(data){
//根据自己情况修改返回参数和做处理
if (data.code == '500') {
$("#file").val("");
alert(data.msg);
} else if (data.code == '0') {
alert("成功!");
}
},
error:function(e){
alert("读取失败");
}
});
formdata用法详解请参考 https://blog.csdn.net/zqian1994/article/details/79635413
Java部分
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.lang.reflect.Method;
import java.util.*;
public class CSVUtils {
/**
* @param response
* @param map 对应的列标题
* @param exportData 需要导出的数据
* @param fileds 列标题对应的实体类的属性
* @throws IOException
*/
@SuppressWarnings({ "resource", "rawtypes", "unchecked" })
public static void exportFile(HttpServletResponse response, HashMap map, List exportData, String[] fileds)throws IOException {
try {
// 写入临时文件
File tempFile = File.createTempFile("vehicle", ".csv");
BufferedWriter csvFileOutputStream = null;
// UTF-8使正确读取分隔符","
csvFileOutputStream = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(tempFile), "GBK"), 1024);
// 写入文件头部
for (Iterator propertyIterator = map.entrySet().iterator(); propertyIterator.hasNext();) {
java.util.Map.Entry propertyEntry = (java.util.Map.Entry) propertyIterator.next();
csvFileOutputStream.write((String) propertyEntry.getValue() != null ? new String(((String) propertyEntry.getValue()).getBytes("GBK"), "GBK") : "");
if (propertyIterator.hasNext()) {
csvFileOutputStream.write(",");
}
}
csvFileOutputStream.write("\r\n");
// 写入文件内容,
// ============ //:Arraylist<实体类>填充实体类的基本信息==================
for (int j = 0; exportData != null && !exportData.isEmpty() && j < exportData.size(); j++) {
Class clazz = exportData.get(j).getClass();
String[] contents = new String[fileds.length];
for (int i = 0; fileds != null && i < fileds.length; i++) {
String filedName = toUpperCaseFirstOne(fileds[i]);
Object obj = null;
try {
Method method = clazz.getMethod(filedName);
method.setAccessible(true);
obj = method.invoke(exportData.get(j));
} catch (Exception e) {
}
String str = String.valueOf(obj);
if (str == null || str.equals("null")) {
str = "";
}
contents[i] = str;
}
for (int n = 0; n < contents.length; n++) {
// 将生成的单元格添加到工作表中
csvFileOutputStream.write(contents[n]);
csvFileOutputStream.write(",");
}
csvFileOutputStream.write("\r\n");
}
csvFileOutputStream.flush();
/**
* 写入csv结束,写出流
*/
java.io.OutputStream out = response.getOutputStream();
byte[] b = new byte[10240];
java.io.File fileLoad = new java.io.File(tempFile.getCanonicalPath());
response.reset();
response.setContentType("application/csv");
String trueCSVName= UUID.randomUUID()+ ".csv";
response.setHeader("Content-Disposition", "attachment; filename="+ new String(trueCSVName.getBytes("GBK"), "ISO8859-1"));
long fileLength = fileLoad.length();
String length1 = String.valueOf(fileLength);
response.setHeader("Content_Length", length1);
java.io.FileInputStream in = new java.io.FileInputStream(fileLoad);
int n;
while ((n = in.read(b)) != -1) {
// 每次写入out1024字节
out.write(b, 0, n);
}
in.close();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
private static String toUpperCaseFirstOne(String origin) {
StringBuffer sb = new StringBuffer(origin);
sb.setCharAt(0, Character.toUpperCase(sb.charAt(0)));
sb.insert(0, "get");
return sb.toString();
}
/**
* 导入
*
* @param file
* csv文件(路径+文件)
* @return
*/
public static List<String> importCsv(MultipartFile file){
List<String> dataList = new ArrayList<String>();
BufferedReader br = null;
try{
br = new BufferedReader(new InputStreamReader(file.getInputStream(), "UTF-8"));
String line ;
while((line = br.readLine()) != null)
{
dataList.add(line);
}
}catch(Exception e){
e.printStackTrace();
}finally{
if (br != null){
try{
br.close();
}catch(IOException e){
e.printStackTrace();
}
}
}
return dataList;
}
}
@RequestMapping("importCsv")
@ResponseBody
public ProtocolResponse importCsv(MultipartFile file)throws ServletException,IOException{
try {
List<String> lineList= CSVUtils.importCsv(file);
if(null==lineList||!lineList.get(0).split(",")[0].equals("DeviceName")){
//此处做了一个标头判断 判断第一个名称是不是DeviceName
return ProtocolResponse.errorResponse("文件无数据或格式错误!");
}
//移除表头
lineList.remove(0);
if(lineList.size()>max){
return ProtocolResponse.errorResponse("文件数据最多包含1000条记录!");
}
for (String s:lineList){//遍历每一行的数据
//每一行的数据都是以逗号区分,所以可以通过这种方式获取到每一个导入数据
String[] name=s.split(",");
//其他数据操作,比如判断数据合不合标准,错误数据的数量等等,最后以map形式返回出去
}
return ProtocolResponse.successResponse("操作成功");
}catch (Exception e){
e.printStackTrace();
return ProtocolResponse.errorResponse(MsgConstant.MSG_OPERATION_FAILED);
}
}
导出
Java导出
@RequestMapping(path="/export")
public void export(HttpServletRequest request, HttpServletResponse response) {
String ids=request.getParameter("ids");
if(StringUtils.isEmpty(ids)){
return;
}
try {
List<DeviceEntity> exportData= deviceManager.select(ids);
if(null==exportData){
return;
}
HashMap map = new LinkedHashMap();
//表头
map.put("1", "名称");
map.put("2", "描述");
//对应字段
String[] fileds = new String[] { "name", "des"};
CSVUtils.exportFile(response, map, exportData, fileds);
}catch (Exception e){
e.printStackTrace();
return;
}
}
js代码导出模板
<a onclick="model" style="color: #5bc0de;cursor: pointer;">下载.csv模板</a>
function model(){
var str = "Name,Id";
str = encodeURIComponent(str);
var aLink = document.createElement("a");
aLink.href = "data:text/csv;charset=utf-8,\ufeff"+str;
aLink.download="Template.csv";
aLink.click();
aLink.remove();
}
js导出的时候每一行的数据用逗号间隔,不同行数据用"\n"间隔,切记切记!