mirror of
https://gitee.com/durcframework/SOP.git
synced 2025-08-11 21:57:56 +08:00
1.8.0
This commit is contained in:
@@ -1,26 +1,27 @@
|
|||||||
* [首页](/?t=1557833057337)
|
* [首页](/?t=1557902036067)
|
||||||
* 开发文档
|
* 开发文档
|
||||||
* [快速体验](files/10010_快速体验.md?t=1557833057339)
|
* [快速体验](files/10010_快速体验.md?t=1557902036070)
|
||||||
* [项目接入到SOP](files/10011_项目接入到SOP.md?t=1557833057355)
|
* [项目接入到SOP](files/10011_项目接入到SOP.md?t=1557902036086)
|
||||||
* [新增接口](files/10020_新增接口.md?t=1557833057355)
|
* [新增接口](files/10020_新增接口.md?t=1557902036086)
|
||||||
* [业务参数校验](files/10030_业务参数校验.md?t=1557833057355)
|
* [业务参数校验](files/10030_业务参数校验.md?t=1557902036086)
|
||||||
* [错误处理](files/10040_错误处理.md?t=1557833057355)
|
* [错误处理](files/10040_错误处理.md?t=1557902036086)
|
||||||
* [编写文档](files/10041_编写文档.md?t=1557833057355)
|
* [编写文档](files/10041_编写文档.md?t=1557902036086)
|
||||||
* [接口交互详解](files/10050_接口交互详解.md?t=1557833057355)
|
* [接口交互详解](files/10050_接口交互详解.md?t=1557902036087)
|
||||||
* [easyopen支持](files/10070_easyopen支持.md?t=1557833057356)
|
* [easyopen支持](files/10070_easyopen支持.md?t=1557902036087)
|
||||||
* [使用签名校验工具](files/10080_使用签名校验工具.md?t=1557833057356)
|
* [使用签名校验工具](files/10080_使用签名校验工具.md?t=1557902036087)
|
||||||
* [ISV管理](files/10085_ISV管理.md?t=1557833057356)
|
* [ISV管理](files/10085_ISV管理.md?t=1557902036087)
|
||||||
* [路由授权](files/10090_路由授权.md?t=1557833057356)
|
* [路由授权](files/10090_路由授权.md?t=1557902036087)
|
||||||
* [接口限流](files/10092_接口限流.md?t=1557833057356)
|
* [接口限流](files/10092_接口限流.md?t=1557902036087)
|
||||||
* [SDK开发](files/10095_SDK开发.md?t=1557833057356)
|
* [SDK开发](files/10095_SDK开发.md?t=1557902036087)
|
||||||
* [使用SpringCloudGateway](files/10096_使用SpringCloudGateway.md?t=1557833057356)
|
* [使用SpringCloudGateway](files/10096_使用SpringCloudGateway.md?t=1557902036087)
|
||||||
* [应用授权](files/10097_应用授权.md?t=1557833057356)
|
* [应用授权](files/10097_应用授权.md?t=1557902036087)
|
||||||
* [更改数据节点名称](files/10099_更改数据节点名称.md?t=1557833057356)
|
* [更改数据节点名称](files/10099_更改数据节点名称.md?t=1557902036087)
|
||||||
* [对接前端](files/10100_对接前端.md?t=1557833057356)
|
* [对接前端](files/10100_对接前端.md?t=1557902036087)
|
||||||
* [自定义过滤器](files/10102_自定义过滤器.md?t=1557833057356)
|
* [自定义过滤器](files/10102_自定义过滤器.md?t=1557902036088)
|
||||||
|
* [文件上传](files/10104_文件上传.md?t=1557902036088)
|
||||||
* 原理分析
|
* 原理分析
|
||||||
* [原理分析之@ApiMapping](files/90010_原理分析之@ApiMapping.md?t=1557833057357)
|
* [原理分析之@ApiMapping](files/90010_原理分析之@ApiMapping.md?t=1557902036088)
|
||||||
* [原理分析之路由存储](files/90011_原理分析之路由存储.md?t=1557833057357)
|
* [原理分析之路由存储](files/90011_原理分析之路由存储.md?t=1557902036088)
|
||||||
* [原理分析之如何路由](files/90012_原理分析之如何路由.md?t=1557833057357)
|
* [原理分析之如何路由](files/90012_原理分析之如何路由.md?t=1557902036088)
|
||||||
* [原理分析之文档归纳](files/90013_原理分析之文档归纳.md?t=1557833057357)
|
* [原理分析之文档归纳](files/90013_原理分析之文档归纳.md?t=1557902036088)
|
||||||
* [常见问题](files/90100_常见问题.md?t=1557833057357)
|
* [常见问题](files/90100_常见问题.md?t=1557902036088)
|
||||||
|
109
doc/docs/files/10104_文件上传.md
Normal file
109
doc/docs/files/10104_文件上传.md
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
# 文件上传
|
||||||
|
|
||||||
|
请求接口时带上文件
|
||||||
|
|
||||||
|
## 客户端调用
|
||||||
|
|
||||||
|
```java
|
||||||
|
DemoFileUploadRequest request = new DemoFileUploadRequest();
|
||||||
|
|
||||||
|
DemoFileUploadModel model = new DemoFileUploadModel();
|
||||||
|
model.setRemark("上传文件参数");
|
||||||
|
request.setBizModel(model);
|
||||||
|
|
||||||
|
List<UploadFile> files = new ArrayList<>();
|
||||||
|
String root = System.getProperty("user.dir");
|
||||||
|
System.out.println(root);
|
||||||
|
// 这里演示将resources下的两个文件上传到服务器
|
||||||
|
files.add(new UploadFile("file1", new File(root + "/src/main/resources/file1.txt")));
|
||||||
|
files.add(new UploadFile("file2", new File(root + "/src/main/resources/file2.txt")));
|
||||||
|
request.setFiles(files);
|
||||||
|
|
||||||
|
DemoFileUploadResponse response = client.execute(request);
|
||||||
|
|
||||||
|
System.out.println("--------------------");
|
||||||
|
if (response.isSuccess()) {
|
||||||
|
List<DemoFileUploadResponse.FileMeta> responseFiles = response.getFiles();
|
||||||
|
System.out.println("您上传的文件信息:");
|
||||||
|
responseFiles.stream().forEach(file->{
|
||||||
|
System.out.println(file);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
System.out.println("errorCode:" + response.getCode() + ",errorMsg:" + response.getMsg());
|
||||||
|
}
|
||||||
|
System.out.println("--------------------");
|
||||||
|
```
|
||||||
|
|
||||||
|
客户端使用`UploadFile`添加上传文件
|
||||||
|
|
||||||
|
```java
|
||||||
|
/**
|
||||||
|
* @param name 表单名称,不能重复
|
||||||
|
* @param file 文件
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public UploadFile(String name, File file) throws IOException {
|
||||||
|
this(name, file.getName(), FileUtil.toBytes(file));
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
其中`name`表示字段名称,相当于`<input type="file" name="file1"/>`中的name
|
||||||
|
|
||||||
|
源码详见sop-sdk
|
||||||
|
|
||||||
|
## 服务端接收文件
|
||||||
|
|
||||||
|
- 方式1
|
||||||
|
|
||||||
|
```java
|
||||||
|
/**
|
||||||
|
* 方式1:将文件写在参数中,可直接获取。好处是可以校验是否上传
|
||||||
|
* @param param
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@ApiMapping(value = "demo.file.upload")
|
||||||
|
public FileUploadVO file1(FileUploadParam param) {
|
||||||
|
System.out.println(param.getRemark());
|
||||||
|
// 获取上传的文件
|
||||||
|
MultipartFile file1 = param.getFile1();
|
||||||
|
MultipartFile file2 = param.getFile2();
|
||||||
|
...
|
||||||
|
return vo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class FileUploadParam {
|
||||||
|
private String remark;
|
||||||
|
|
||||||
|
// 上传文件,字段名称对应表单中的name属性值
|
||||||
|
@NotNull(message = "文件1不能为空")
|
||||||
|
private MultipartFile file1;
|
||||||
|
|
||||||
|
@NotNull(message = "文件2不能为空")
|
||||||
|
private MultipartFile file2;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
方式1的好处是可以使用`JSR-303`校验文件是否上传
|
||||||
|
|
||||||
|
- 方式2
|
||||||
|
|
||||||
|
```java
|
||||||
|
/**
|
||||||
|
* 方式2:从request中获取上传文件
|
||||||
|
*
|
||||||
|
* @param param
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@ApiMapping(value = "demo.file.upload2")
|
||||||
|
public FileUploadVO file2(FileUploadParam2 param, HttpServletRequest request) {
|
||||||
|
System.out.println(param.getRemark());
|
||||||
|
FileUploadVO vo = new FileUploadVO();
|
||||||
|
// 获取上传的文件
|
||||||
|
Collection<MultipartFile> uploadFiles = UploadUtil.getUploadFiles(request);
|
||||||
|
...
|
||||||
|
return vo;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
微服务端源码参考`FileUploadDemoController.java`
|
@@ -16,7 +16,11 @@ public class FormBodyWrapperFilterExt extends FormBodyWrapperFilter {
|
|||||||
public boolean shouldFilter() {
|
public boolean shouldFilter() {
|
||||||
RequestContext ctx = RequestContext.getCurrentContext();
|
RequestContext ctx = RequestContext.getCurrentContext();
|
||||||
HttpServletRequest request = ctx.getRequest();
|
HttpServletRequest request = ctx.getRequest();
|
||||||
// 不是上传文件请求,则进行包装
|
// 如果是文件上传请求,不需要包装
|
||||||
return !RequestUtil.isMultipart(request);
|
if (RequestUtil.isMultipart(request)) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return super.shouldFilter();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -14,7 +14,11 @@ public class Servlet30WrapperFilterExt extends Servlet30WrapperFilter {
|
|||||||
public boolean shouldFilter() {
|
public boolean shouldFilter() {
|
||||||
RequestContext ctx = RequestContext.getCurrentContext();
|
RequestContext ctx = RequestContext.getCurrentContext();
|
||||||
HttpServletRequest request = ctx.getRequest();
|
HttpServletRequest request = ctx.getRequest();
|
||||||
// 不是上传文件请求,则进行包装
|
// 如果是文件上传请求,不需要包装
|
||||||
return !RequestUtil.isMultipart(request);
|
if (RequestUtil.isMultipart(request)) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return super.shouldFilter();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -7,10 +7,13 @@ import com.gitee.sop.servercommon.annotation.ApiMapping;
|
|||||||
import com.gitee.sop.servercommon.bean.ParamNames;
|
import com.gitee.sop.servercommon.bean.ParamNames;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import org.springframework.core.MethodParameter;
|
import org.springframework.core.MethodParameter;
|
||||||
|
import org.springframework.util.ReflectionUtils;
|
||||||
import org.springframework.web.bind.support.WebDataBinderFactory;
|
import org.springframework.web.bind.support.WebDataBinderFactory;
|
||||||
import org.springframework.web.context.request.NativeWebRequest;
|
import org.springframework.web.context.request.NativeWebRequest;
|
||||||
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
|
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
|
||||||
import org.springframework.web.method.support.ModelAndViewContainer;
|
import org.springframework.web.method.support.ModelAndViewContainer;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
import org.springframework.web.multipart.support.StandardMultipartHttpServletRequest;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@@ -49,8 +52,9 @@ public class ApiArgumentResolver implements HandlerMethodArgumentResolver {
|
|||||||
protected Object getParamObject(MethodParameter methodParameter, NativeWebRequest nativeWebRequest) {
|
protected Object getParamObject(MethodParameter methodParameter, NativeWebRequest nativeWebRequest) {
|
||||||
String bizContent = nativeWebRequest.getParameter(ParamNames.BIZ_CONTENT_NAME);
|
String bizContent = nativeWebRequest.getParameter(ParamNames.BIZ_CONTENT_NAME);
|
||||||
Class<?> parameterType = methodParameter.getParameterType();
|
Class<?> parameterType = methodParameter.getParameterType();
|
||||||
|
Object bizObj = null;
|
||||||
if (bizContent != null) {
|
if (bizContent != null) {
|
||||||
return JSON.parseObject(bizContent, parameterType);
|
bizObj = JSON.parseObject(bizContent, parameterType);
|
||||||
} else {
|
} else {
|
||||||
Map<String, String[]> parameterMap = nativeWebRequest.getParameterMap();
|
Map<String, String[]> parameterMap = nativeWebRequest.getParameterMap();
|
||||||
JSONObject result = new JSONObject();
|
JSONObject result = new JSONObject();
|
||||||
@@ -60,10 +64,33 @@ public class ApiArgumentResolver implements HandlerMethodArgumentResolver {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (result.size() > 0) {
|
if (result.size() > 0) {
|
||||||
return result.toJavaObject(parameterType);
|
bizObj = result.toJavaObject(parameterType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
this.bindUploadFile(bizObj, nativeWebRequest);
|
||||||
|
return bizObj;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将文件绑定到
|
||||||
|
* @param bizObj 业务参数
|
||||||
|
* @param nativeWebRequest
|
||||||
|
*/
|
||||||
|
protected void bindUploadFile(Object bizObj, NativeWebRequest nativeWebRequest) {
|
||||||
|
if (bizObj == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Object nativeRequest = nativeWebRequest.getNativeRequest();
|
||||||
|
if (nativeRequest instanceof StandardMultipartHttpServletRequest) {
|
||||||
|
StandardMultipartHttpServletRequest request = (StandardMultipartHttpServletRequest) nativeRequest;
|
||||||
|
Class<?> bizClass = bizObj.getClass();
|
||||||
|
ReflectionUtils.doWithFields(bizClass, field -> {
|
||||||
|
ReflectionUtils.makeAccessible(field);
|
||||||
|
String name = field.getName();
|
||||||
|
MultipartFile multipartFile = request.getFile(name);
|
||||||
|
ReflectionUtils.setField(field, bizObj, multipartFile);
|
||||||
|
}, field -> field.getType() == MultipartFile.class);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@@ -0,0 +1,38 @@
|
|||||||
|
package com.gitee.sop.servercommon.util;
|
||||||
|
|
||||||
|
import org.apache.commons.fileupload.servlet.ServletFileUpload;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
import org.springframework.web.multipart.MultipartHttpServletRequest;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件上传工具类
|
||||||
|
*
|
||||||
|
* @author tanghc
|
||||||
|
*/
|
||||||
|
public class UploadUtil {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取上传文件
|
||||||
|
*
|
||||||
|
* @param request
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static Collection<MultipartFile> getUploadFiles(HttpServletRequest request) {
|
||||||
|
Map<String, MultipartFile> fileMap = null;
|
||||||
|
//检查form中是否有enctype="multipart/form-data"
|
||||||
|
if (ServletFileUpload.isMultipartContent(request)) {
|
||||||
|
//将request变成多部分request
|
||||||
|
MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request;
|
||||||
|
fileMap = multiRequest.getFileMap();
|
||||||
|
}
|
||||||
|
return Optional.ofNullable(fileMap)
|
||||||
|
.map(map -> map.values())
|
||||||
|
.orElse(Collections.emptyList());
|
||||||
|
}
|
||||||
|
}
|
@@ -1,56 +1,78 @@
|
|||||||
package com.gitee.sop.storyweb.controller;
|
package com.gitee.sop.storyweb.controller;
|
||||||
|
|
||||||
import com.gitee.sop.servercommon.annotation.ApiMapping;
|
import com.gitee.sop.servercommon.annotation.ApiMapping;
|
||||||
|
import com.gitee.sop.servercommon.util.UploadUtil;
|
||||||
import com.gitee.sop.storyweb.controller.param.FileUploadParam;
|
import com.gitee.sop.storyweb.controller.param.FileUploadParam;
|
||||||
|
import com.gitee.sop.storyweb.controller.param.FileUploadParam2;
|
||||||
import com.gitee.sop.storyweb.vo.FileUploadVO;
|
import com.gitee.sop.storyweb.vo.FileUploadVO;
|
||||||
import org.apache.commons.fileupload.servlet.ServletFileUpload;
|
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
import org.springframework.web.multipart.MultipartHttpServletRequest;
|
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Map;
|
import java.util.Collection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 演示文件上传
|
* 演示文件上传
|
||||||
|
*
|
||||||
* @author tanghc
|
* @author tanghc
|
||||||
*/
|
*/
|
||||||
@RestController
|
@RestController
|
||||||
public class FileUploadDemoController {
|
public class FileUploadDemoController {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 接收客户端上传的文件,然后把文件信息返回给客户端
|
* 方式1:将文件写在参数中,可直接获取。好处是可以校验是否上传
|
||||||
* @param param
|
* @param param
|
||||||
* @param request
|
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@ApiMapping(value = "demo.file.upload", ignoreValidate = true)
|
@ApiMapping(value = "demo.file.upload")
|
||||||
public FileUploadVO file(FileUploadParam param, HttpServletRequest request) {
|
public FileUploadVO file1(FileUploadParam param) {
|
||||||
|
System.out.println(param.getRemark());
|
||||||
|
// 获取上传的文件
|
||||||
|
MultipartFile file1 = param.getFile1();
|
||||||
|
MultipartFile file2 = param.getFile2();
|
||||||
|
|
||||||
|
FileUploadVO vo = new FileUploadVO();
|
||||||
|
FileUploadVO.FileMeta fileMeta1 = buildFileMeta(file1);
|
||||||
|
FileUploadVO.FileMeta fileMeta2 = buildFileMeta(file2);
|
||||||
|
|
||||||
|
vo.getFiles().add(fileMeta1);
|
||||||
|
vo.getFiles().add(fileMeta2);
|
||||||
|
return vo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 方式2:从request中获取上传文件
|
||||||
|
*
|
||||||
|
* @param param
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@ApiMapping(value = "demo.file.upload2")
|
||||||
|
public FileUploadVO file2(FileUploadParam2 param, HttpServletRequest request) {
|
||||||
System.out.println(param.getRemark());
|
System.out.println(param.getRemark());
|
||||||
FileUploadVO vo = new FileUploadVO();
|
FileUploadVO vo = new FileUploadVO();
|
||||||
//检查form中是否有enctype="multipart/form-data"
|
// 获取上传的文件
|
||||||
if (ServletFileUpload.isMultipartContent(request)) {
|
Collection<MultipartFile> uploadFiles = UploadUtil.getUploadFiles(request);
|
||||||
//将request变成多部分request
|
for (MultipartFile multipartFile : uploadFiles) {
|
||||||
MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request;
|
FileUploadVO.FileMeta fileMeta = buildFileMeta(multipartFile);
|
||||||
Map<String, MultipartFile> fileMap = multiRequest.getFileMap();
|
vo.getFiles().add(fileMeta);
|
||||||
fileMap.entrySet()
|
|
||||||
.stream()
|
|
||||||
.forEach(entry->{
|
|
||||||
MultipartFile multipartFile = entry.getValue();
|
|
||||||
try {
|
|
||||||
String fileName = multipartFile.getOriginalFilename();
|
|
||||||
long size = multipartFile.getSize();
|
|
||||||
String fileContent = IOUtils.toString(multipartFile.getInputStream(), "UTF-8");
|
|
||||||
FileUploadVO.FileMeta fileMeta = new FileUploadVO.FileMeta(fileName, size, fileContent);
|
|
||||||
vo.getFiles().add(fileMeta);
|
|
||||||
System.out.println(fileContent);
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
return vo;
|
return vo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private FileUploadVO.FileMeta buildFileMeta(MultipartFile multipartFile) {
|
||||||
|
// 文件名
|
||||||
|
String fileName = multipartFile.getOriginalFilename();
|
||||||
|
// 文件大小
|
||||||
|
long size = multipartFile.getSize();
|
||||||
|
// 文件内容
|
||||||
|
String fileContent = null;
|
||||||
|
try {
|
||||||
|
fileContent = IOUtils.toString(multipartFile.getInputStream(), "UTF-8");
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return new FileUploadVO.FileMeta(fileName, size, fileContent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,9 @@
|
|||||||
package com.gitee.sop.storyweb.controller.param;
|
package com.gitee.sop.storyweb.controller.param;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author tanghc
|
* @author tanghc
|
||||||
@@ -8,4 +11,11 @@ import lombok.Data;
|
|||||||
@Data
|
@Data
|
||||||
public class FileUploadParam {
|
public class FileUploadParam {
|
||||||
private String remark;
|
private String remark;
|
||||||
|
|
||||||
|
// 上传文件,字段名称对应表单中的name属性值
|
||||||
|
@NotNull(message = "文件1不能为空")
|
||||||
|
private MultipartFile file1;
|
||||||
|
|
||||||
|
@NotNull(message = "文件2不能为空")
|
||||||
|
private MultipartFile file2;
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,12 @@
|
|||||||
|
package com.gitee.sop.storyweb.controller.param;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author tanghc
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class FileUploadParam2 {
|
||||||
|
private String remark;
|
||||||
|
|
||||||
|
}
|
@@ -21,6 +21,7 @@ namespace SDKCSharp.Client
|
|||||||
{
|
{
|
||||||
|
|
||||||
private static OpenConfig DEFAULT_CONFIG = new OpenConfig();
|
private static OpenConfig DEFAULT_CONFIG = new OpenConfig();
|
||||||
|
private const String ERROR_RESPONSE_KEY = "error_response";
|
||||||
|
|
||||||
private Dictionary<string, string> header = new Dictionary<string, string>();
|
private Dictionary<string, string> header = new Dictionary<string, string>();
|
||||||
|
|
||||||
@@ -137,6 +138,11 @@ namespace SDKCSharp.Client
|
|||||||
string method = request.Method;
|
string method = request.Method;
|
||||||
string dataName = this.dataNameBuilder.Build(method);
|
string dataName = this.dataNameBuilder.Build(method);
|
||||||
Dictionary<string, object> jsonObject = JsonUtil.ParseToDictionary(resp);
|
Dictionary<string, object> jsonObject = JsonUtil.ParseToDictionary(resp);
|
||||||
|
bool errorResponse = jsonObject.ContainsKey(ERROR_RESPONSE_KEY);
|
||||||
|
if (errorResponse)
|
||||||
|
{
|
||||||
|
dataName = ERROR_RESPONSE_KEY;
|
||||||
|
}
|
||||||
object data = jsonObject[dataName];
|
object data = jsonObject[dataName];
|
||||||
string jsonData = data == null ? "{}" : data.ToString();
|
string jsonData = data == null ? "{}" : data.ToString();
|
||||||
T t = JsonUtil.ParseObject<T>(jsonData);
|
T t = JsonUtil.ParseObject<T>(jsonData);
|
||||||
|
@@ -131,6 +131,7 @@ namespace SDKCSharp.Client
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// post请求,并且文件上传
|
/// post请求,并且文件上传
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -141,77 +142,126 @@ namespace SDKCSharp.Client
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public string PostFile(string url, Dictionary<string, string> form, Dictionary<string, string> header, List<UploadFile> files)
|
public string PostFile(string url, Dictionary<string, string> form, Dictionary<string, string> header, List<UploadFile> files)
|
||||||
{
|
{
|
||||||
Encoding ENCODING_UTF8 = Encoding.UTF8;
|
HttpWebRequest request = CreateWebRequest(url, header);
|
||||||
|
request.Method = METHOD_POST;
|
||||||
|
// 分隔符
|
||||||
|
string boundary = "----" + DateTime.Now.Ticks.ToString("x");
|
||||||
|
request.ContentType = string.Format("multipart/form-data; boundary={0}", boundary);
|
||||||
|
|
||||||
using (MemoryStream memoryStream = new MemoryStream())
|
// 请求流
|
||||||
|
var postStream = new MemoryStream();
|
||||||
|
#region 处理Form表单请求内容
|
||||||
|
// 文件数据模板
|
||||||
|
string fileFormdataTemplate =
|
||||||
|
"\r\n--" + boundary +
|
||||||
|
"\r\nContent-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"" +
|
||||||
|
"\r\nContent-Type: application/octet-stream" +
|
||||||
|
"\r\n\r\n";
|
||||||
|
// 文本数据模板
|
||||||
|
string dataFormdataTemplate =
|
||||||
|
"\r\n--" + boundary +
|
||||||
|
"\r\nContent-Disposition: form-data; name=\"{0}\"" +
|
||||||
|
"\r\n\r\n{1}";
|
||||||
|
|
||||||
|
// 是否有上传文件
|
||||||
|
bool hasFile = files != null && files.Count > 0;
|
||||||
|
if (hasFile)
|
||||||
{
|
{
|
||||||
// 1.分界线
|
// 处理上传文件
|
||||||
string boundary = string.Format("----{0}", DateTime.Now.Ticks.ToString("x")), // 分界线可以自定义参数
|
foreach (var fileItem in files)
|
||||||
appendBoundary = string.Format("--{0}\r\n", boundary),
|
|
||||||
endBoundary = string.Format("\r\n--{0}--\r\n", boundary);
|
|
||||||
|
|
||||||
byte[] beginBoundaryBytes = ENCODING_UTF8.GetBytes(appendBoundary),
|
|
||||||
endBoundaryBytes = ENCODING_UTF8.GetBytes(endBoundary);
|
|
||||||
|
|
||||||
|
|
||||||
StringBuilder payload = new StringBuilder();
|
|
||||||
|
|
||||||
// 2.组装 上传文件附加携带的参数 到内存流中
|
|
||||||
if (form != null && form.Count > 0)
|
|
||||||
{
|
{
|
||||||
ICollection<string> keys = form.Keys;
|
string formdata = null;
|
||||||
foreach (string key in keys)
|
// 上传文件
|
||||||
|
formdata = string.Format(
|
||||||
|
fileFormdataTemplate,
|
||||||
|
fileItem.Name, //表单键
|
||||||
|
fileItem.FileName);
|
||||||
|
|
||||||
|
byte[] formdataBytes = null;
|
||||||
|
// 第一行不需要换行
|
||||||
|
if (postStream.Length == 0)
|
||||||
{
|
{
|
||||||
string boundaryBlock = string.Format("{0}Content-Disposition: form-data; name=\"{1}\"\r\n\r\n{2}\r\n", appendBoundary, key, form[key]);
|
formdataBytes = Encoding.UTF8.GetBytes(formdata.Substring(2, formdata.Length - 2));
|
||||||
byte[] boundaryBlockBytes = ENCODING_UTF8.GetBytes(boundaryBlock);
|
}
|
||||||
memoryStream.Write(boundaryBlockBytes, 0, boundaryBlockBytes.Length);
|
else
|
||||||
|
{
|
||||||
|
formdataBytes = Encoding.UTF8.GetBytes(formdata);
|
||||||
|
}
|
||||||
|
postStream.Write(formdataBytes, 0, formdataBytes.Length);
|
||||||
|
|
||||||
|
// 写入文件内容
|
||||||
|
if (fileItem.FileData != null && fileItem.FileData.Length > 0)
|
||||||
|
{
|
||||||
|
postStream.Write(fileItem.FileData, 0, fileItem.FileData.Length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// 3.组装文件头数据体 到内存流中
|
// 处理文本字段
|
||||||
foreach (UploadFile uploadFile in files)
|
foreach (var fieldItem in form)
|
||||||
|
{
|
||||||
|
string formdata = null;
|
||||||
{
|
{
|
||||||
string boundaryBlock = string.Format("{0}Content-Disposition: form-data; name=\"{1}\"; filename=\"{2}\"\r\nContent-Type: application/octet-stream\r\n\r\n", appendBoundary, uploadFile.Name, uploadFile.FileName);
|
// 上传文本
|
||||||
byte[] boundaryBlockBytes = ENCODING_UTF8.GetBytes(boundaryBlock);
|
formdata = string.Format(
|
||||||
memoryStream.Write(boundaryBlockBytes, 0, boundaryBlockBytes.Length);
|
dataFormdataTemplate,
|
||||||
memoryStream.Write(uploadFile.FileData, 0, uploadFile.FileData.Length);
|
fieldItem.Key,
|
||||||
|
fieldItem.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4.组装结束分界线数据体 到内存流中
|
byte[] formdataBytes = null;
|
||||||
memoryStream.Write(endBoundaryBytes, 0, endBoundaryBytes.Length);
|
// 第一行不需要换行
|
||||||
|
if (postStream.Length == 0)
|
||||||
// 5.获取二进制数据,最终需要发送给服务器的数据
|
|
||||||
byte[] postBytes = memoryStream.ToArray();
|
|
||||||
|
|
||||||
// 6.HttpWebRequest 组装
|
|
||||||
HttpWebRequest webRequest = CreateWebRequest(url, header);
|
|
||||||
webRequest.Method = METHOD_POST;
|
|
||||||
webRequest.ContentType = string.Format("multipart/form-data; boundary={0}", boundary);
|
|
||||||
webRequest.ContentLength = postBytes.Length;
|
|
||||||
BindHeader(webRequest, header);
|
|
||||||
if (Regex.IsMatch(url, "^https://"))
|
|
||||||
{
|
{
|
||||||
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls;
|
formdataBytes = Encoding.UTF8.GetBytes(formdata.Substring(2, formdata.Length - 2));
|
||||||
ServicePointManager.ServerCertificateValidationCallback = CheckValidationResult;
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
formdataBytes = Encoding.UTF8.GetBytes(formdata);
|
||||||
|
}
|
||||||
|
postStream.Write(formdataBytes, 0, formdataBytes.Length);
|
||||||
|
}
|
||||||
|
// 结尾
|
||||||
|
var footer = Encoding.UTF8.GetBytes("\r\n--" + boundary + "--\r\n");
|
||||||
|
postStream.Write(footer, 0, footer.Length);
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
request.ContentLength = postStream.Length;
|
||||||
|
|
||||||
|
#region 输入二进制流
|
||||||
|
if (postStream != null)
|
||||||
|
{
|
||||||
|
postStream.Position = 0;
|
||||||
|
// 直接写入流
|
||||||
|
Stream requestStream = request.GetRequestStream();
|
||||||
|
|
||||||
|
byte[] buffer = new byte[1024];
|
||||||
|
int bytesRead = 0;
|
||||||
|
while ((bytesRead = postStream.Read(buffer, 0, buffer.Length)) != 0)
|
||||||
|
{
|
||||||
|
requestStream.Write(buffer, 0, bytesRead);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 7.写入上传请求数据
|
////debug
|
||||||
using (Stream requestStream = webRequest.GetRequestStream())
|
//postStream.Seek(0, SeekOrigin.Begin);
|
||||||
{
|
//StreamReader sr = new StreamReader(postStream);
|
||||||
requestStream.Write(postBytes, 0, postBytes.Length);
|
//var postStr = sr.ReadToEnd();
|
||||||
}
|
postStream.Close();//关闭文件访问
|
||||||
// 8.获取响应
|
}
|
||||||
using (HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse())
|
#endregion
|
||||||
{
|
|
||||||
using (StreamReader reader = new StreamReader(webResponse.GetResponseStream(), ENCODING_UTF8))
|
|
||||||
{
|
|
||||||
string body = reader.ReadToEnd();
|
|
||||||
return body;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
|
||||||
|
if (cookieContainer != null)
|
||||||
|
{
|
||||||
|
response.Cookies = cookieContainer.GetCookies(response.ResponseUri);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
using (Stream responseStream = response.GetResponseStream())
|
||||||
|
{
|
||||||
|
using (StreamReader myStreamReader = new StreamReader(responseStream, Encoding.UTF8))
|
||||||
|
{
|
||||||
|
return myStreamReader.ReadToEnd();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
|
static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
|
||||||
|
11
sop-sdk/sdk-csharp/SDKCSharp/Model/DemoFileUploadModel.cs
Normal file
11
sop-sdk/sdk-csharp/SDKCSharp/Model/DemoFileUploadModel.cs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
using System;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace SDKCSharp.Model
|
||||||
|
{
|
||||||
|
public class DemoFileUploadModel
|
||||||
|
{
|
||||||
|
[JsonProperty("remark")]
|
||||||
|
public string Remark { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using SDKCSharp.Client;
|
using SDKCSharp.Client;
|
||||||
using SDKCSharp.Common;
|
using SDKCSharp.Common;
|
||||||
using SDKCSharp.Model;
|
using SDKCSharp.Model;
|
||||||
@@ -27,8 +28,9 @@ namespace SDKTest
|
|||||||
|
|
||||||
public static void Main(string[] args)
|
public static void Main(string[] args)
|
||||||
{
|
{
|
||||||
TestGet();
|
//TestGet();
|
||||||
TestCommon();
|
//TestCommon();
|
||||||
|
TestUpload();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 标准用法
|
// 标准用法
|
||||||
@@ -90,5 +92,41 @@ namespace SDKTest
|
|||||||
response.Code, response.Msg, response.SubCode, response.SubMsg);
|
response.Code, response.Msg, response.SubCode, response.SubMsg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void TestUpload()
|
||||||
|
{
|
||||||
|
DemoFileUploadRequest request = new DemoFileUploadRequest();
|
||||||
|
|
||||||
|
DemoFileUploadModel model = new DemoFileUploadModel
|
||||||
|
{
|
||||||
|
Remark = "上传文件参数"
|
||||||
|
};
|
||||||
|
request.BizModel = model;
|
||||||
|
|
||||||
|
string root = Environment.CurrentDirectory;
|
||||||
|
Console.WriteLine("当前目录{0}", root);
|
||||||
|
|
||||||
|
// 文件上传
|
||||||
|
// 将当前目录下的两个文件上传到服务器
|
||||||
|
request.AddFile(new UploadFile("file1", root + "/file1.txt"));
|
||||||
|
request.AddFile(new UploadFile("file2", root + "/file2.txt"));
|
||||||
|
|
||||||
|
DemoFileUploadResponse response = client.Execute(request);
|
||||||
|
if (response.IsSuccess())
|
||||||
|
{
|
||||||
|
List<DemoFileUploadResponse.FileMeta> responseFiles = response.Files;
|
||||||
|
Console.WriteLine("您上传的文件信息:");
|
||||||
|
responseFiles.ForEach(file =>
|
||||||
|
{
|
||||||
|
Console.WriteLine("上传的文件名:{0},文件大小:{1},文件内容:{2}", file.Filename, file.Size, file.Content);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.WriteLine("错误, code:{0}, msg:{1}, subCode:{2}, subMsg:{3}",
|
||||||
|
response.Code, response.Msg, response.SubCode, response.SubMsg);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -60,6 +60,18 @@ namespace SDKCSharp.Request
|
|||||||
this.version = version == null ? SdkConfig.DEFAULT_VERSION : version;
|
this.version = version == null ? SdkConfig.DEFAULT_VERSION : version;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 添加上传文件
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="file">File.</param>
|
||||||
|
public void AddFile(UploadFile file)
|
||||||
|
{
|
||||||
|
if(this.files == null)
|
||||||
|
{
|
||||||
|
this.files = new List<UploadFile>();
|
||||||
|
}
|
||||||
|
this.files.Add(file);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 创建请求表单
|
/// 创建请求表单
|
||||||
|
@@ -0,0 +1,13 @@
|
|||||||
|
using System;
|
||||||
|
using SDKCSharp.Response;
|
||||||
|
|
||||||
|
namespace SDKCSharp.Request
|
||||||
|
{
|
||||||
|
public class DemoFileUploadRequest : BaseRequest<DemoFileUploadResponse>
|
||||||
|
{
|
||||||
|
public override string GetMethod()
|
||||||
|
{
|
||||||
|
return "demo.file.upload";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,39 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace SDKCSharp.Response
|
||||||
|
{
|
||||||
|
public class DemoFileUploadResponse : BaseResponse
|
||||||
|
{
|
||||||
|
[JsonProperty("files")]
|
||||||
|
private List<FileMeta> files = new List<FileMeta>();
|
||||||
|
|
||||||
|
public List<FileMeta> Files { get => files; set => files = value; }
|
||||||
|
|
||||||
|
public class FileMeta
|
||||||
|
{
|
||||||
|
|
||||||
|
public FileMeta(String filename, long size, String content)
|
||||||
|
{
|
||||||
|
this.Filename = filename;
|
||||||
|
this.Size = size;
|
||||||
|
this.Content = content;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FileMeta()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[JsonProperty("filename")]
|
||||||
|
public String Filename { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("size")]
|
||||||
|
public long Size { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("content")]
|
||||||
|
public String Content { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1
sop-sdk/sdk-csharp/SDKCSharp/file1.txt
Normal file
1
sop-sdk/sdk-csharp/SDKCSharp/file1.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
file1 content,内容1
|
1
sop-sdk/sdk-csharp/SDKCSharp/file2.txt
Normal file
1
sop-sdk/sdk-csharp/SDKCSharp/file2.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
file2 content,内容2
|
@@ -25,7 +25,7 @@ public class OpenClient {
|
|||||||
private static final Log log = LogFactory.getLog(OpenClient.class);
|
private static final Log log = LogFactory.getLog(OpenClient.class);
|
||||||
|
|
||||||
private static final OpenConfig DEFAULT_CONFIG = new OpenConfig();
|
private static final OpenConfig DEFAULT_CONFIG = new OpenConfig();
|
||||||
public static final String ERROR_RESPONSE_KEY = "error_response";
|
private static final String ERROR_RESPONSE_KEY = "error_response";
|
||||||
|
|
||||||
private String url;
|
private String url;
|
||||||
private String appId;
|
private String appId;
|
||||||
|
@@ -9,6 +9,7 @@ import com.gitee.sop.sdk.response.BaseResponse;
|
|||||||
import com.gitee.sop.sdk.util.ClassUtil;
|
import com.gitee.sop.sdk.util.ClassUtil;
|
||||||
|
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -71,6 +72,17 @@ public abstract class BaseRequest<T extends BaseResponse> {
|
|||||||
return SdkConfig.DEFAULT_VERSION;
|
return SdkConfig.DEFAULT_VERSION;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加上传文件
|
||||||
|
* @param file
|
||||||
|
*/
|
||||||
|
public void addFile(UploadFile file) {
|
||||||
|
if (this.files == null) {
|
||||||
|
this.files = new ArrayList<>();
|
||||||
|
}
|
||||||
|
this.files.add(file);
|
||||||
|
}
|
||||||
|
|
||||||
public RequestForm createRequestForm(OpenConfig openConfig) {
|
public RequestForm createRequestForm(OpenConfig openConfig) {
|
||||||
// 公共请求参数
|
// 公共请求参数
|
||||||
Map<String, String> params = new HashMap<String, String>();
|
Map<String, String> params = new HashMap<String, String>();
|
||||||
|
@@ -1 +1 @@
|
|||||||
file1 content
|
file1 content,内容1
|
@@ -1 +1 @@
|
|||||||
file2 content...
|
file2 content,内容2
|
@@ -17,7 +17,6 @@ import org.junit.Test;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -87,12 +86,11 @@ public class SdkTest extends TestCase {
|
|||||||
model.setRemark("上传文件参数");
|
model.setRemark("上传文件参数");
|
||||||
request.setBizModel(model);
|
request.setBizModel(model);
|
||||||
|
|
||||||
List<UploadFile> files = new ArrayList<>();
|
|
||||||
String root = System.getProperty("user.dir");
|
String root = System.getProperty("user.dir");
|
||||||
System.out.println(root);
|
System.out.println(root);
|
||||||
files.add(new UploadFile("file1", new File(root + "/src/main/resources/file1.txt")));
|
// 这里演示将resources下的两个文件上传到服务器
|
||||||
files.add(new UploadFile("file2", new File(root + "/src/main/resources/file2.txt")));
|
request.addFile(new UploadFile("file1", new File(root + "/src/main/resources/file1.txt")));
|
||||||
request.setFiles(files);
|
request.addFile(new UploadFile("file2", new File(root + "/src/main/resources/file2.txt")));
|
||||||
|
|
||||||
DemoFileUploadResponse response = client.execute(request);
|
DemoFileUploadResponse response = client.execute(request);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user