由于之前文件传输到OA采用的方式都是前端a标签在表单展示,但是发现在移动端无法展示,于是近期在调试泛微OA-E9版本的文件上传接口。在调试并封装接口的过程中遇到一些问题。
1、首先在获取了泛微OA的一些认证参数后,先在接口调用工具ApiFox上调用。
这是他的接口文档,最开始他的类型误导了我,我以为他需要的二进制文件流,然后就各种尝试失败,然后给泛微提了个工单。给的答复是在apifox调用时,用form-data的file类型。。。
2、然后在apifox就顺利调用成功了,然后我就开始封装接口。刚开始我的想法是在服务里写一个接口,直接供其他接口调用,但是牵扯到文件流的传输不太合适,就编写为一个前端调用的上传文件接口。对了其中的解析返回参数json字符串的方法还挺好用的:
ObjectMapper mapper = new ObjectMapper();
JsonNode node = mapper.readTree(responseBody);
node.get("data").get("fileid").asText();
/**
* OA上传附件
* @param category 目录id
* @param multipartFile 文件
* @param userId 用户id
* @return 文件id
* @throws IOException 异常
*/
@GetMapping("/uploadFile2Doc")
@ApiOperation("OA上传附件")
public R<String> uploadFile2Doc(@RequestParam("category") String category
,@RequestParam("multipartFile") MultipartFile multipartFile
,@RequestParam("userId") String userId) throws IOException {
File tempFile = null;
try {
// 生成一个临时文件名
String fileName = multipartFile.getOriginalFilename();
// 创建临时文件路径
Path tempFilePath = Files.createTempFile(Paths.get(System.getProperty("java.io.tmpdir")),
fileName.substring(0, fileName.indexOf('.')),
fileName.substring(fileName.indexOf('.')));
tempFile = tempFilePath.toFile();
// 检查文件是否存在,如果存在则删除
if (tempFile.exists()) {
tempFile.delete();
}
// 将MultipartFile内容写入临时文件
multipartFile.transferTo(tempFile);
//获取接口请求头认证参数
OaInterfaceHeaderDTO oaInterfaceHeaderDTO = oaInterfaceToken.getOaInterfaceHeaderDTO(userId);
//E9创建OA流程接口
String api = "/api/doc/upload/uploadFile2Doc";
// 目标API的URL
String url = oaInterfaceHeaderDTO.getAddress()+ "/api/doc/upload/uploadFile2Doc";
// 准备文件和额外的表单字段
String fileNameParam = "file"; // 文件参数名
String textParamNameOne = "name";
String textParamValueOne = multipartFile.getOriginalFilename(); // 文本字段值1
String textParamNameTwo = "category";
String textParamValueTwo = category; // 文本字段值2
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
HttpPost httpPost = new HttpPost(url);
// 添加请求头
httpPost.setHeader("appid", oaInterfaceHeaderDTO.getAppid());
httpPost.setHeader("token", oaInterfaceHeaderDTO.getToken()); // 注意,这个头部通常不需要手动设置,因为MultipartEntityBuilder会处理
httpPost.setHeader("userid", oaInterfaceHeaderDTO.getUserid());
// 构建表单实体
HttpEntity multiPartEntity = MultipartEntityBuilder.create()
.setMode(HttpMultipartMode.RFC6532)
.addBinaryBody(fileNameParam, tempFile, ContentType.APPLICATION_OCTET_STREAM, multipartFile.getOriginalFilename())
.addTextBody(textParamNameOne, textParamValueOne, ContentType.TEXT_PLAIN)
.addTextBody(textParamNameTwo, textParamValueTwo, ContentType.create("text/plain", StandardCharsets.UTF_8))
.build();
httpPost.setEntity(multiPartEntity);
// 发送请求并获取响应
try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
System.out.println("Response Status Code: " + response.getStatusLine().getStatusCode());
// 处理响应实体(如果需要)
HttpEntity responseEntity = response.getEntity();
if (responseEntity != null) {
String responseBody = EntityUtils.toString(responseEntity, StandardCharsets.UTF_8);
ObjectMapper mapper = new ObjectMapper();
JsonNode node = mapper.readTree(responseBody);
return R.data(node.get("data").get("fileid").asText());
}
}
}
} catch (IOException e) {
// 如果在转换过程中出现异常,删除已创建的临时文件
if (tempFile != null) {
tempFile.delete();
}
// 处理可能的I/O异常
throw new RuntimeException("Failed to convert MultipartFile to File", e);
} finally {
// 删除临时文件
if (tempFile != null) {
tempFile.delete();
}
}
return R.data("上传失败!");
}
3、大概的处理思路你们可以参考一下。在测试的时候,接口调用成功,但是发现一个问题,就是文件名的中文会乱码。之后排查问题发现是在上传的时候造成的乱码,以及逐步调试,锁定了问题。之前默认设置为BROWSER_COMPATIBLE。修改为RFC6532,就解决了乱码问题。
4、后面去了解了下这两种模式:
技术领域不同:RFC6532关注的是电子邮件地址的国际化,而BROWSER_COMPATIBLE关注的是Web上传请求的兼容性。
应用场景不同:一个是电子邮件通信的标准,另一个是Web通信中文件上传的兼容性模式。
目的不同:RFC6532旨在支持非ASCII字符的电子邮件地址,而BROWSER_COMPATIBLE旨在保证上传请求能被广泛接受,特别是在老式或兼容性要求高的Web服务器上。
了解下来,其实一般还是采用BROWSER_COMPATIBLE这种模式,在这种模式下保持编码的一致性,但是由于时间原因,我决定采用RFC6532解决问题,希望有缘人在正确处理这种问题后,可以答疑一下。