你知道的越多,你不知道的越多
点赞再看,养成习惯
如果您有疑问或者见解,或者没有积分想获取项目和定制项目,欢迎指教:
企鹅:869192208
文章目录
需求
根据对接的需要,需要请求一个使用 SSM 框架编写的文件上传的接口,该接口的请求方式为Post请求,请求参数全部是以 form-data 表单形式进行提交,包含多个参数,且方法中,文件是由 request 中获取到,示例代码如下:
@RequestMapping(value = "uploadAttach")
public void uploadAttach(@RequestParam(value = "tableName", required = false) String tableName,
@RequestParam(value = "tableCode", required = false) String tableCode,
@RequestParam(value = "configCode", required = false) String configCode,
@RequestParam(value = "tableColumn", required = false) String tableColumn,
HttpServletResponse response, HttpServletRequest request) {
Map<String, Object> rtn = new HashMap<String, Object>();
try {
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
Map<String, List<MultipartFile>> multipartFiles = multipartRequest.getMultiFileMap();
/**业务操作**/
} catch (Exception e) {
rtn.put("success", false);
}
}
下面提供三种解决方案
方式一:使用 RestTemplate 进行调用
public Object uploadAttach(String tableName, String tableCode, String configCode, String tableColumn, File img) {
try {
String uploadAttach = "http://xxx/uploadAttach";
FileInputStream fileInputStream=new FileInputStream(img);
//请求头设置为MediaType.MULTIPART_FORM_DATA类型
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.setContentType(MediaType.MULTIPART_FORM_DATA);
//构建请求体
MultiValueMap<String, Object> requestBody = new LinkedMultiValueMap<>();
CommonInputStreamResource commonInputStreamResource = null;
try {
commonInputStreamResource = new CommonInputStreamResource(fileInputStream,img.length(),img.getName());
} catch (Exception e) {
log.error("文件输入流转换错误",e);
}
requestBody.add("tableName", tableName);
requestBody.add("tableCode", tableCode);
requestBody.add("configCode", configCode);
requestBody.add("tableColumn", tableColumn);
requestBody.add("file",commonInputStreamResource);
HttpEntity<MultiValueMap> requestEntity = new HttpEntity<MultiValueMap>(requestBody, requestHeaders);
//直接调用远程接口
ResponseEntity<String> entity = restTemplate.postForEntity(uploadAttach,requestEntity, String.class);
String responseValue = (String)entity.getBody();
log.info("---->响应值为:" + responseValue);
} catch (Exception e) {
log.error("上传文件接口调用失败",e);
}
}
class CommonInputStreamResource extends InputStreamResource {
private long length;
private String fileName;
public CommonInputStreamResource(InputStream inputStream, long length, String fileName) {
super(inputStream);
this.length = length;
this.fileName = fileName;
}
/**
* 覆写父类方法
* 如果不重写这个方法,并且文件有一定大小,那么服务端会出现异常
* {@code The multi-part request contained parameter data (excluding uploaded files) that exceeded}
*/
@Override
public String getFilename() {
return fileName;
}
/**
* 覆写父类 contentLength 方法
* 因为 {@link org.springframework.core.io.AbstractResource#contentLength()}方法会重新读取一遍文件,
* 而上传文件时,restTemplate 会通过这个方法获取大小。然后当真正需要读取内容的时候,发现已经读完,会报如下错误。
*/
@Override
public long contentLength() {
long estimate = length;
return estimate == 0 ? 1 : estimate;
}
public void setLength(long length) {
this.length = length;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
}
如果使用 RestTemplate 调用远程接口需要添加请求头,示例如下:
// 获取第三方的authorization
String auth= OAuthContentHelper.getAuthorizationHeader();
HttpHeaders requestHeader=new HttpHeaders();
// 将获取到的authorization添加到请求头
requestHeader.add(AuthConstants.AUTHORIZATION_HEADER,auth);
// 构建请求实体
HttpEntity<Object> requestEntity=new HttpEntity(requestParam,requestHeaders);
// 使用restTemplate调用第三方接口
restTemplate.exchage(url,HttpMethod.POST,requestEntity,responseClass);
方式二:Spring Cloud Feign组件 + MultiValueMap + CommonInputStreamResource
- feign 接口
@Component
@FeignClient(name = "common", url = "${url}", qualifier = "commonFeignClient",fallback = commonFallBack.class)
public interface CommonFeignClient {
/**
* 附件上传
*/
@PostMapping(value = "/xxx/uploadAttach",consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
String attachFileUpload(MultiValueMap<String, Object> multiValueMap);
}
- 请求部分
@PostMapping("/uploadAttach")
public void uploadAttach(){
try {
File file=new File("D:/1.png");
FileInputStream fileInputStream=new FileInputStream(file);
CommonInputStreamResource commonInputStreamResource = null;
try {
commonInputStreamResource = new CommonInputStreamResource(fileInputStream,fileInputStream.available(),file.getName());
} catch (Exception e) {
log.error("文件输入流转换错误:",e);
}
MultiValueMap<String, Object> requestBody = new LinkedMultiValueMap<String, Object>();
requestBody.add("tableName", tableName);
requestBody.add("tableCode", tableCode);
requestBody.add("configCode", configCode);
requestBody.add("tableColumn", tableColumn);
requestBody.add("file",commonInputStreamResource);
String returnInfo = commonFeignClient.attachFileUpload(requestBody);
JSONObject responseValue = JSONObject.parseObject(returnInfo);
log.info("---->响应值为:" + responseValue);
}catch (Exception e){
log.error("异常:",e);
}
}
class CommonInputStreamResource extends InputStreamResource {
private long length;
private String fileName;
public CommonInputStreamResource(InputStream inputStream, long length, String fileName) {
super(inputStream);
this.length = length;
this.fileName = fileName;
}
/**
* 覆写父类方法
* 如果不重写这个方法,并且文件有一定大小,那么服务端会出现异常
* {@code The multi-part request contained parameter data (excluding uploaded files) that exceeded}
*/
@Override
public String getFilename() {
return fileName;
}
/**
* 覆写父类 contentLength 方法
* 因为 {@link org.springframework.core.io.AbstractResource#contentLength()}方法会重新读取一遍文件,
* 而上传文件时,restTemplate 会通过这个方法获取大小。然后当真正需要读取内容的时候,发现已经读完,会报如下错误。
*/
@Override
public long contentLength() {
long estimate = length;
return estimate == 0 ? 1 : estimate;
}
public void setLength(long length) {
this.length = length;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
}
方式三:传统方式
/**
* post请求
* @param url 请求url
* @param params 普通参数
* @param file 上传的文件
* @return
*/
public static String doPost(String url, Map<String, String> params, File file) throws Exception {
if (org.apache.commons.lang3.StringUtils.isBlank(url)) {
return null;
}
String resutString;
HttpClient httpClient = HttpClients.createDefault();
Charset charset = Charset.forName("UTF-8");//设置编码
HttpPost httpPost = new HttpPost(url);
try {
log.info("finally request url:" + url);
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.addPart("file", new FileBody(file));
// 普通字段,指定编码
for (Map.Entry<String, String> param : params.entrySet()) {
builder.addPart(param.getKey(), new StringBody(param.getValue(), ContentType.APPLICATION_JSON));// 普通字段,指定编码
}
httpPost.setEntity(builder.build());
HttpResponse httpResponse = httpClient.execute(httpPost);
/* 读取返回数据 */
if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
resutString = EntityUtils.toString(httpResponse.getEntity(), "UTF-8");
} else {
throw new Exception("发送失败:" + httpResponse.getStatusLine().getStatusCode() + " url :" + url);
}
} catch (Exception e) {
throw e;
}
return resutString;
}
public Object uploadAttach(String tableName, String tableCode, String configCode, String tableColumn, File img) {
try{
String uploadAttach = "http://xxx/uploadAttach";
Map<String, String> postParams = new HashMap<>();
postParams.put("tableName", tableName);
postParams.put("tableCode", tableCode);
postParams.put("configCode", configCode);
postParams.put("tableColumn", tableColumn);
log.info("-->请求地址:{},请求参数:{}", uploadAttach, postParams);
responseValue = HttpClientUtil.doPost(uploadAttach, postParams, img);
} catch (Exception e) {
log.error("上传失败",e);
}
}