对接金蝶上传附件接口

背景:因为前端调金蝶上传附件接口会报跨域,所以使用后端进行转发。

以下是核心功能代码

java 复制代码
@Override
	public R<Object> uploadAttachmentFile(MultipartFile file, AttachmentUploadFileArgsDTO attachmentUploadFileArgs) {
		try {
			// 1. 严格参数校验:文件非空+文件名非空+附件参数非空
			AssertUtils.isTrue(!file.isEmpty(), "上传文件不能为空");
			AssertUtils.isTrue(StrUtil.isNotBlank(file.getOriginalFilename()), "文件名称不能为空");
			AssertUtils.notNull(attachmentUploadFileArgs, "附件业务参数不能为空");
			log.info("开始转发文件到中台,文件名:{},业务参数:{}", file.getOriginalFilename(), JSON.toJSONString(attachmentUploadFileArgs));

			// 2. 构建请求头:自动生成分隔符(boundary),禁止手动设置Content-Type
			HttpHeaders headers = getHeaders(); // 继承中台基础头(accessToken、x-acgw-identity)
			headers.setAccept(Collections.singletonList(MediaType.ALL)); // 接收所有响应类型
			headers.setContentType(MediaType.MULTIPART_FORM_DATA); // 显式声明多表单类型(RestTemplate仍会自动加boundary)

			// 3. 构建多表单请求体:文件+业务参数
			MultiValueMap<String, Object> requestBody = new LinkedMultiValueMap<>();
			// 3.1 添加上传业务参数:转为JSON字符串,适配中台参数格式
			requestBody.add("attachmentUploadFileArgs", JSON.toJSONString(attachmentUploadFileArgs));
			// 3.2 添加文件:使用ByteArrayResource包装,避免InputStream流关闭问题,处理文件名中文编码
			String originalFilename = file.getOriginalFilename();
			ByteArrayResource fileResource = new ByteArrayResource(file.getBytes()) {
				@Override
				public String getFilename() {
					return originalFilename; // 重写获取文件名,确保中台能正确解析
				}
			};
			requestBody.add("file", fileResource);

			// 4. 构建请求实体(请求体+请求头)
			HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(requestBody, headers);

			// 5. 拼接中台接口地址,发起POST请求
			String uploadUrl = middlegroundProperties.getDomain() + attachmentUploadUri;

			ResponseEntity<JSONObject> response = restTemplate.postForEntity(uploadUrl, requestEntity, JSONObject.class);

			log.info("文件转发中台请求完成,URL:{},响应状态码:{}", uploadUrl, response.getStatusCodeValue());
			if (!response.getStatusCode().is2xxSuccessful()) {
				String errorMsg = String.format("文件转发中台失败,HTTP状态码:%d", response.getStatusCodeValue());
				log.error(errorMsg);
				return R.fail(errorMsg);
			}

			JSONObject responseBody = response.getBody();
			AssertUtils.notNull(responseBody, "中台返回空响应,转发失败");
			log.info("文件转发中台成功,中台原始响应:{}", responseBody.toJSONString());

			// 透传中台完整响应(也可按需提取data字段:responseBody.getString("data"))
			UploadAttachmentFileResultVO uploadAttachmentFileResultVO = JSON.parseObject(responseBody.toJSONString(), new TypeReference<UploadAttachmentFileResultVO>() {
			});
			return R.data(uploadAttachmentFileResultVO);

		} catch (IOException e) {
			// 文件读取异常:如文件损坏、流读取失败
			String errorMsg = "读取上传文件失败,原因:" + e.getMessage();
			log.error(errorMsg, e);
			return R.fail(errorMsg);
		} catch (IllegalArgumentException e) {
			// 参数校验异常:如文件空、参数空
			log.warn("文件上传参数校验失败:{}", e.getMessage());
			return R.fail(e.getMessage());
		} catch (Exception e) {
			// 全局异常:如中台接口不可达、网络异常、序列化失败
			String errorMsg = "文件转发中台异常,系统内部错误:" + e.getMessage();
			log.error(errorMsg, e);
			return R.fail(errorMsg);
		}
	}
相关推荐
咩咩啃树皮6 小时前
第40篇:Vue3组件化开发精讲——组件拆分、复用、父子通信、工程化架构
java·前端·架构
灯澜忆梦7 小时前
GO_并发编程---定时器
开发语言·后端·golang
鱟鲥鳚7 小时前
Spring Boot 集成 LangChain4j:从模型调用到 Tool Calling(Demo版)
java·spring boot
-银雾鸢尾-7 小时前
C#中的StringBuilder相关方法
开发语言·c#
-银雾鸢尾-7 小时前
C#中结构体与类的区别;抽象类与接口的区别
开发语言·c#
大模型码小白8 小时前
【Python零基础教程】继承、多态与魔法函数:面向对象编程三大核心特性详解
java·大数据·开发语言·人工智能·python·ai编程
腾渊信息科技公司9 小时前
Spring Boot对接MES实战:视觉检测数据自动同步方案
java·人工智能·spring boot·后端·计算机视觉·ai·软件需求
爱笑的源码基地10 小时前
高并发 Redis 缓存门诊HIS系统源码,含财务统计药房进销存
java·程序·门诊系统·诊所系统·云诊所源码
wuqingshun31415910 小时前
TCP超时重传机制是为了解决什么问题?
java
段一凡-华北理工大学10 小时前
向量数据库实战:选型、调优与落地~系列文章12:文本分块策略实战:chunk_size 怎么选?重叠多少?
开发语言·数据库·后端·oracle·rust·工业智能体·高炉智能化