1.客户端
法1)html协议_File控件
enctype="multipart/form-data"
input type="file"
enctype="multipart/form-data"的作用:
设定了上报数据的格式是multipart(多部分实体);默认是kv键值对格式。
法2)vue+ElementUI中的使用
<!-- 批量创建单据:导入整机代码,创建单据
name =上传的文件对应的参数名,供后台获取
:headers=设置上传的请求头部
:action =上传的地址
:data =上传时附带的额外参数
-->
<el-upload
name="uploadMobilecode"
class="upload-demo"
:headers="uploadReqHeader()" //html请求头部信息,这里用来获取token
:action="uploadUrlMobilecode()" //请求的url
:data="uploadParam"
multiple
:disabled="disableImport"
:file-list="fileList"
:show-file-list="false"
:on-success="handleUploadSuccess"
:before-upload="beforeUpload"
:on-error="handleUploadFailed"
>
<el-button type="primary" @click="beforeImport"
>批量创建单据</el-button
>
</el-upload>
ps:elementUI还是包含基本要素:multiple、多段式file(给了参数名称,方便后台获取)、url
2)数据报送的格式
Content-Type:multipart/form-data; boundary=---------------------------95934521623339693873125739649
-----------------------------95934521623339693873125739649
Content-Disposition: form-data; name="extraParam"
{"mod":"Bonding","reqId":"b955b24e-c7ef-402e-ade5-757245a86d10"}
-----------------------------95934521623339693873125739649
Content-Disposition: form-data; name="uploadMobilecode"; filename="0902整机代ç 导å
¥.xlsx"
Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
-----------------------------95934521623339693873125739649--
1)告知服务器内容格式:多段式和分割符;
2)通过分割符分割的多段内容。
2.服务器端
法1:当前项目的用法
1)通过参数名称,获取浏览器发送的multipart实体(实际是字节流)
2)获取multipart的InputStream实体(可操作的对象)
3)创建Excel文件XSSFWorkbook实体,把inputStream转换成Excel(本来字节流就是Excel解析生成的)。至此Excel文件已经从浏览器传递到服务器。
4)解析Excel的内容:读取Excel的行,与Entity的字段注解匹配,转换成Entity list。
Controler接收请求
@RequestMapping(value = "/import-mobilecode-file")
public CommonResult importMobilecodeExcel(
@RequestParam(value="uploadMobilecode", required = false) MultipartFile file,
@RequestParam(value="extraParam", required = false) String par
){
log.info("----- upload file -----");
ObjectMapper objectMapper = new ObjectMapper();
Map<String, String> m = null;
log.info(file.toString());
log.info(par.toString());
try{
m = objectMapper.readValue(par, new TypeReference<Map<String, String>>(){});
List<CaMobilecodeImport> list = ExcelUtil.readExcel("", CaMobilecodeImport.class, file, "yyyy/MM/dd");
ArrayList<String> itemcodes = new ArrayList<>();
for (CaMobilecodeImport mbc:list
) {
log.info("========导入的整机代码:"+mbc.toString());
itemcodes.add(mbc.getMobilecode());
}
return caItemPriceService.batchCreate(itemcodes,m.getOrDefault("reqId",""));
}catch (Exception e){
return CommonResult.failed("失败原因: " + e.getMessage());
}
}
工具类:把InputStream转换成并解析Excel实体
//把InputStream转换成Excel实体
InputStream is = file.getInputStream();
if (fileName.endsWith(EXCEL2007)) {
// FileInputStream is = new FileInputStream(new File(path));
workbook = new XSSFWorkbook(is);
}
//解析Excel实体内容,转换成pojo
//默认读取第一个sheet
Sheet sheet = workbook.getSheetAt(0);
boolean firstRow = true;
for (int i = sheet.getFirstRowNum(); i <= sheet.getLastRowNum(); i++) {
Row row = sheet.getRow(i);
//首行 提取注解
if (firstRow) {
for (int j = row.getFirstCellNum(); j <= row.getLastCellNum(); j++) {
Cell cell = row.getCell(j);
String cellValue = getCellValue(cell, "");
//手动去掉标题行里的换行符,防止用户设置excel设置自动换行干扰解析
cellValue = cellValue.replaceAll("\\n", "");
if (classMap.containsKey(cellValue)) {
reflectionMap.put(j, classMap.get(cellValue));
}
}
firstRow = false;
}
法2:FileUpload
真的接收文件,在服务器转储1份,然后按本地文件解析。
3.总结
1)客户端:html组件(input type=file),给了浏览器指令,让浏览器去读取本地文件为字节流,并发送到Server。
因为字节流太大,约定了multipart的格式(分隔符)。
2)服务器端:接收客户端消息,抽取字节流,并把字节流InputStream转换成java对象(Excel型实体)
3)用工具类,解析Excel内容,并转化成java pojo。
4.扩展:
1)form表单enctype的属性
enctype:规定了form表单在发送到服务器时候编码方式,有如下的三个值。
application/x-www-form-urlencoded:默认的编码方式。但在用文本的传输和MP3等大型文件的时候,使用这种编码就显得效率低下。
multipart/form-data:指定传输数据为二进制类型,比如图片,mp3,文件
text/plain:纯文本的传输。空格转换为"+"号,但不对特殊字符编码。
2)数据报送的格式种类
3)SpringMVC中获取参数的方式
在SpringMVC web应用中,对于一个rest接口,获取请求参数我们一般使用@requestParam、@requestBody等注解 。对于表单类型的请求参数,有一下几种获取方式
@requestParam注解方式
request.getParameter(String name)
request.getInputStream()
4)inputStream:java程序与外界交互基础类。入就是inputStream、出就是outputStream。
以java程序(Java内存)为主体视角,输入可以是文件、socket网络。
Stream,流?。输入输出很好理解,流就魔幻了,可以理解为字节串、字符串。
序列化、反序列化。
字节流,读取到java程序(java内存)字节流,读取到java程序(java内存)