Android客户端的UI与《Android 上传图片到服务器(单文件上传)》唯一区别增加了多文件上传的功能。
* 多文件上传
* @param view
*/
public void multiUpload(View view){
List<File> fileList = new ArrayList<>();
for (ItemBean itemBean : list) {
if (itemBean.isButton()) continue;
fileList.add(itemBean.getImageFileBean().getFile());
itemBean.getImageFileBean().setStartUpload(true);
adapter.notifyDataSetChanged();
}
// 用上传的文件生成RequestBody
if(fileList == null || fileList.size() == 0)return;
//创建MultipartBody.Builder,用于添加请求的数据
MultipartBody.Builder builder = new MultipartBody.Builder();
for (int i = 0; i < fileList.size(); i++) { //对文件进行遍历
//根据文件的后缀名,获得文件类型
builder.setType(MultipartBody.FORM)
.addFormDataPart("name",fileList.get(i).getName())// 其他信息
.addFormDataPart("id","12,13,14")// 其他信息
.addFormDataPart("type","2"+i)// 其他信
.addFormDataPart( //给Builder添加上传的文件
"images", //请求的名字
fileList.get(i).getName(), //文件的文字,服务器端用来解析的
RequestBody.Companion.create(fileList.get(i),MediaType.parse("multipart/form-data"))//创建RequestBody,把上传的文件放入
);
}
RequestBody requestBody = builder.build();//根据Builder创建请求
Request request = new Request.Builder()
.url(Global.MULTI_FILE_UPLOAD_URL)
.post(requestBody)
.addHeader("user-agent", "PDA")
.addHeader("x-userid", "752332")// 添加x-userid请求头
.addHeader("x-sessionkey", "kjhsfjkaskfashfuiwf")// 添加x-sessionkey请求头
.addHeader("x-tonce", Long.valueOf(System.currentTimeMillis()).toString())// 添加x-tonce请求头
.addHeader("x-timestamp", Long.valueOf(System.currentTimeMillis()).toString())// 添加x-timestamp请求头
.build();
final Message msg = myHandler.obtainMessage();
OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.newCall(request)
.enqueue(new Callback() {
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
msg.obj = list;
msg.what =0;
myHandler.sendMessage(msg);
}
@Override
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
String result = response.body().string();
Log.i("上传图片结果:", result);
msg.obj = list;
if (!response.isSuccessful()) {
Log.i("响应失败:", response.code() + "");
msg.what =1;
return;
}
msg.what = 3;
myHandler.sendMessage(msg);
}
});
}
/**
* 多文件上传
*
* @param files
* @param model
* @param request
* @return
*/
@PostMapping("/api/multi_upload")
public String multiFileUpload(@RequestParam(value = "images") MultipartFile[] files, Model model, HttpServletRequest request, @RequestParam(value = "type") int[] type, @RequestHeader(value = "user-agent") String userAgent) {
if (files != null && files.length > 0) {
System.out.println("文件为空空");
}
for (int i : type) {
logger.info("获得的其他参数type=" + i);
}
logger.info("获得的Header user-agent=" + userAgent);
// 如果参数比较少可以直接在方法上使用注解@RequestParam来映射到不同的名称上获得,当然如果不用此注解,也可以定义一个与传过来的参数名一样的形参来获得
// 蒜从客户端传过来的其他参数
Enumeration names = request.getParameterNames();
while (names.hasMoreElements()) {
String key = names.nextElement().toString();
String[] values = request.getParameterValues(key);
for(String str: values){
String info = "客户端传过来的参数:key=" + key + ",value=" + str;
logger.info(info);
}
}
Enumeration headers = request.getHeaderNames();
while (headers.hasMoreElements()) {
String key = headers.nextElement().toString();
String info = "客户端传过来的Header参数:key=" + key + ",value=" + request.getHeader(key);
logger.info(info);
}
for (MultipartFile file : files) {
saveFile(file);
}
return "上传成功";
}
private String saveFile(MultipartFile file) {
// BMP、JPG、JPEG、PNG、GIF
String fileName = file.getOriginalFilename(); // 文件名
logger.info("上传文件名:" + fileName);
String suffixName = fileName.substring(fileName.lastIndexOf(".")); // 后缀名
// 验证上传的文件是否图片
if (!".bmp".equalsIgnoreCase(suffixName) && !".jpg".equalsIgnoreCase(suffixName)
&& !".jpeg".equalsIgnoreCase(suffixName)
&& !".png".equalsIgnoreCase(suffixName)
&& !".gif".equalsIgnoreCase(suffixName)) {
return "上传失败,请选择BMP、JPG、JPEG、PNG、GIF文件!";
}
fileName = UUID.randomUUID() + suffixName; // 新文件名
File dest = new File(fileName);
// 如果文件的父路径不存在,则创建
if (fileName.startsWith("/") && !dest.getParentFile().exists()) {
dest.getParentFile().mkdirs();
}
// 开始存放文件到指定目录去
try {
file.transferTo(dest);
return "上传成功";
} catch (IOException e) {
e.printStackTrace();
return "上传失败";
}
}
Android客户端
文件上传服务器
Android客户端上传多文件时的HTTP报文如下:
Hypertext Transfer Protocol
POST /api/multi_upload HTTP/1.1\r\n
[Expert Info (Chat/Sequence): POST /api/multi_upload HTTP/1.1\r\n]
[POST /api/multi_upload HTTP/1.1\r\n]
[Severity level: Chat]
[Group: Sequence]
Request Method: POST
Request URI: /api/multi_upload
Request Version: HTTP/1.1
user-agent: PDA\r\n
x-userid: 752332\r\n
x-sessionkey: kjhsfjkaskfashfuiwf\r\n
x-tonce: 1592183885988\r\n
x-timestamp: 1592183885988\r\n
Content-Type: multipart/form-data; boundary=0d03917a-192a-4b48-91b3-cae54dcbd929\r\n
Content-Length: 59249\r\n
[Content length: 59249]
Host: 192.168.43.120:8080\r\n
Connection: Keep-Alive\r\n
Accept-Encoding: gzip\r\n
\r\n
[Full request URI: http://192.168.43.120:8080/api/multi_upload]
[HTTP request 1/1]
[Response in frame: 270]
File Data: 59249 bytes
MIME Multipart Media Encapsulation, Type: multipart/form-data, Boundary: "0d03917a-192a-4b48-91b3-cae54dcbd929"
[Type: multipart/form-data]
First boundary: --0d03917a-192a-4b48-91b3-cae54dcbd929\r\n
Encapsulated multipart part:
Content-Disposition: form-data; name="name"\r\n
Content-Length: 36\r\n\r\n
Data (36 bytes)
Data: 313330633133303932316632343839663930663261656436…
[Length: 36]
Boundary: \r\n--0d03917a-192a-4b48-91b3-cae54dcbd929\r\n
Encapsulated multipart part:
Content-Disposition: form-data; name="id"\r\n
Content-Length: 8\r\n\r\n
Data (8 bytes)
Data: 31322c31332c3134
[Length: 8]
Boundary: \r\n--0d03917a-192a-4b48-91b3-cae54dcbd929\r\n
Encapsulated multipart part:
Content-Disposition: form-data; name="type"\r\n
Content-Length: 2\r\n\r\n
Data (2 bytes)
Data: 3230
[Length: 2]
Boundary: \r\n--0d03917a-192a-4b48-91b3-cae54dcbd929\r\n
Encapsulated multipart part: (multipart/form-data)
Content-Disposition: form-data; name="images"; filename="130c130921f2489f90f2aed6551f2c5f.jpg"\r\n
Content-Type: multipart/form-data\r\n
Content-Length: 47952\r\n\r\n
The multipart dissector could not find a required parameter.
[Expert Info (Error/Protocol): The multipart dissector could not find a required parameter.]
[The multipart dissector could not find a required parameter.]
[Severity level: Error]
[Group: Protocol]
Data (47952 bytes)
Data: ffd8ffe12ee245786966000049492a00080000000b001001…
[Length: 47952]
Boundary: \r\n--0d03917a-192a-4b48-91b3-cae54dcbd929\r\n
Encapsulated multipart part:
Content-Disposition: form-data; name="name"\r\n
Content-Length: 36\r\n\r\n
Data (36 bytes)
Data: 306432643236353564363332346234656238626235333763…
[Length: 36]
Boundary: \r\n--0d03917a-192a-4b48-91b3-cae54dcbd929\r\n
Encapsulated multipart part:
Content-Disposition: form-data; name="id"\r\n
Content-Length: 8\r\n\r\n
Data (8 bytes)
Data: 31322c31332c3134
[Length: 8]
Boundary: \r\n--0d03917a-192a-4b48-91b3-cae54dcbd929\r\n
Encapsulated multipart part:
Content-Disposition: form-data; name="type"\r\n
Content-Length: 2\r\n\r\n
Data (2 bytes)
Data: 3231
[Length: 2]
Boundary: \r\n--0d03917a-192a-4b48-91b3-cae54dcbd929\r\n
Encapsulated multipart part: (multipart/form-data)
Content-Disposition: form-data; name="images"; filename="0d2d2655d6324b4eb8bb537cac083cd0.jpg"\r\n
Content-Type: multipart/form-data\r\n
Content-Length: 6149\r\n\r\n
The multipart dissector could not find a required parameter.
[Expert Info (Error/Protocol): The multipart dissector could not find a required parameter.]
[The multipart dissector could not find a required parameter.]
[Severity level: Error]
[Group: Protocol]
Data (6149 bytes)
Data: ffd8ffe10ad745786966000049492a00080000000b001001…
[Length: 6149]
Boundary: \r\n--0d03917a-192a-4b48-91b3-cae54dcbd929\r\n
Encapsulated multipart part:
Content-Disposition: form-data; name="name"\r\n
Content-Length: 36\r\n\r\n
Data (36 bytes)
Data: 316431313536643461386238343033343839393963366464…
[Length: 36]
Boundary: \r\n--0d03917a-192a-4b48-91b3-cae54dcbd929\r\n
Encapsulated multipart part:
Content-Disposition: form-data; name="id"\r\n
Content-Length: 8\r\n\r\n
Data (8 bytes)
Data: 31322c31332c3134
[Length: 8]
Boundary: \r\n--0d03917a-192a-4b48-91b3-cae54dcbd929\r\n
Encapsulated multipart part:
Content-Disposition: form-data; name="type"\r\n
Content-Length: 2\r\n\r\n
Data (2 bytes)
Data: 3232
[Length: 2]
Boundary: \r\n--0d03917a-192a-4b48-91b3-cae54dcbd929\r\n
Encapsulated multipart part: (multipart/form-data)
Content-Disposition: form-data; name="images"; filename="1d1156d4a8b840348999c6ddd050df76.jpg"\r\n
Content-Type: multipart/form-data\r\n
Content-Length: 3407\r\n\r\n
The multipart dissector could not find a required parameter.
[Expert Info (Error/Protocol): The multipart dissector could not find a required parameter.]
[The multipart dissector could not find a required parameter.]
[Severity level: Error]
[Group: Protocol]
Data (3407 bytes)
Data: ffd8ffe000104a46494600010100000100010000ffdb0043…
[Length: 3407]
Last boundary: \r\n--0d03917a-192a-4b48-91b3-cae54dcbd929--\r\n