项目场景:
业务服务通过RestTemplate调用文件上传服务。(
<java.version>1.8</java.version>
<spring.cloud.version>Hoxton.SR12</spring.cloud.version>
<spring.cloud.alibaba.version>2.2.9.RELEASE</spring.cloud.alibaba.version>
<spring.boot.version>2.3.12.RELEASE</spring.boot.version>
)
问题描述
由于restTemplate中引入了FormHttpMessageConverter消息转换器,在调用过程中,无法解析java.lang.Long类型,报错:org.springframework.http.converter.HttpMessageNotWritableException: Could not write request: no suitable HttpMessageConverter found for request type [java.lang.Long]
Controller:
/**
* @description: 文件上传
* @param file
* @return
* @throws
* @author menshaojing
* @date 2021/11/22 10:21
*/
@PostMapping("/upload")
@ApiOperation(value = "文件上传")
public ResultVo upload(@RequestBody MultipartFile file, HttpServletRequest request) throws BaseException {
return ResultUtils.success(supplementaryZuoyeService.upload(file, request));
}
service:
/**
* @description: 文件上传
* @param file
* @return
* @throws
* @author menshaojing
* @date 2021/11/18 15:51
*/
public StorePathVo upload(MultipartFile file, HttpServletRequest request) {
String filename = FileUtils.getFilename(file);
String suffix = filename.substring(filename.lastIndexOf('.') + 1);
//校验文件格式
if (!"pdf".equalsIgnoreCase(suffix) && !"docx".equalsIgnoreCase(suffix) && !"doc".equalsIgnoreCase(suffix)) {
throw new BaseException(201, "文件格式错误");
}
filename = filename.substring(0, filename.lastIndexOf('.')) + ".pdf";
FileUploadRequest fileUploadRequest = new FileUploadRequest();
fileUploadRequest.setObjtype(FastfileTypeEnum.ACTION_FILE.getCode());
fileUploadRequest.setFilename(file.getOriginalFilename());
fileUploadRequest.setMimeType(file.getContentType());
fileUploadRequest.setFilesize(file.getSize());
fileUploadRequest.setToken(request.getParameter("token"));
StorePathVo storeVo = null;
try {
storeVo = fileServerUtils.fileUpload(fileUploadRequest, file);
} catch (IOException e) {
throw new BaseException(ResultEnum.UPLOAD_FILE_FAIL);
}
if (null == storeVo) {
throw new BaseException(ResultEnum.UPLOAD_FILE_FAIL);
}
''''''''''''''
}
}
FileServerUtils类:
/**
* @param fileUploadRequest
* @throws BaseException
* @Description: 跨服务调用文件服务器上传文件
* @author menshaojing
* @date 13:22 2020/7/9
*/
private StorePathVo upload(FileUploadRequest fileUploadRequest, Resource resource) throws BaseException {
MultiValueMap<String, Object> paramMap = new LinkedMultiValueMap<>(1);
paramMap.add("filesize", fileUploadRequest.getFilesize());
paramMap.add("filesize", fileUploadRequest.getFilesize());
paramMap.add("gradeid", fileUploadRequest.getGradeid());
paramMap.add("subjectid", fileUploadRequest.getSubjectid());
paramMap.add("duration", fileUploadRequest.getDuration());
paramMap.add("mimeType", fileUploadRequest.getMimeType());
paramMap.add("nodeid", fileUploadRequest.getNodeid());
paramMap.add("objtype", fileUploadRequest.getObjtype());
paramMap.add("objid", fileUploadRequest.getObjid());
paramMap.add("filename", fileUploadRequest.getFilename());
paramMap.add("addflag", fileUploadRequest.getAddflag());
paramMap.add("file", resource);
HttpHeaders headers = new HttpHeaders();
MediaType type = MediaType.parseMediaType("multipart/form-data; charset=UTF-8");
headers.setContentType(type);
HttpEntity<MultiValueMap<String, Object>> formData = new HttpEntity<>(paramMap, headers);
Integer uploadflag = fileUploadRequest.getUploadflag();
String uploadpath = defaultpath;
if (uploadflag == 1) {
uploadpath = fastpath;
} else if (uploadflag == 2) {
uploadpath = osspath;
}
String url =buildURL(RestConstant.fileService + uploadpath, null == fileUploadRequest.getToken() ? "" : fileUploadRequest.getToken());
log.info("跨服务调用文件服务器上传>>>:url={}", url);
ResultVo result = restTemplate.postForObject(url, formData, ResultVo.class);
if (result.getCode() != 200) {
throw new BaseException(205, "跨服务调用文件服务器上传文件有误!");
}
log.info("上传成功!!!");
return JSONObject.parseObject(JSONObject.toJSONString(result.getData()), StorePathVo.class);
}
public static String buildURL(String orignalURL, String token) {
if (!orignalURL.contains("?")) {
return orignalURL + "?token=" + token;
} else {
return orignalURL + "&token=" + token;
}
}
FileUploadRequest 类:
import lombok.Data;
/**
* @author menshaojing
* @Description: 文件上传服务器参数封装
* @date 13:33 2020/7/9
*/
@Data
public class FileUploadRequest {
/**
* 课本ID
*/
private Integer bookid;
/**
* 时长
*/
private Integer duration;
/**
* 年级ID
*/
private Integer gradeid;
/**
* 章节ID
*/
private Integer nodeid;
/**
* 类型
*/
private Byte objtype;
/**
* 某资源ID,例如导学ID,作业ID,资源库ID等
*/
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long objid;
/**
* 科目ID
*/
private Integer subjectid;
/**
* 文件类型
*/
private String mimeType;
/**
* 文件大小
*/
private Long filesize;
/**
* token
*/
private String token;
/**
* 文件名
*/
private String filename;
/**
* 不传默认新建fastfile记录,传0表示不操作fastfile表
*/
private Integer addflag;
/**
* 上传方式 0 默认上传 1 fast上传 2 oss上传
*/
private Integer uploadflag = 0;
}
上传服务实现的方法:
public StorePathVo uploadFile(HttpServletRequest request, AbstractUpload abstractUpload) throws Exception {
UserRelationInfo userInfo = (UserRelationInfo) request.getAttribute("user");
StorePath storePath = null;
String fileName = "";
StorePathVo storePathVo = new StorePathVo();
UploadFileRequest uploadFileRequest = new UploadFileRequest();
String ext = "";
try {
StandardMultipartHttpServletRequest standardMultipartHttpServletRequest=
new StandardMultipartHttpServletRequest(request);
final Map<String, String[]> parameterMap = standardMultipartHttpServletRequest.getParameterMap();
final MultiValueMap<String, MultipartFile> multiFileMap = standardMultipartHttpServletRequest.getMultiFileMap();
for (Map.Entry<String,String[]> entry:parameterMap.entrySet()) {
String itemKey = entry.getKey();
String itemVal = entry.getValue()[0];
switch (itemKey) {
case "bookid":
uploadFileRequest.setBookid(Integer.parseInt(itemVal));
break;
case "nodeid":
uploadFileRequest.setNodeid(Integer.parseInt(itemVal));
break;
case "gradeid":
uploadFileRequest.setGradeid(Integer.parseInt(itemVal));
break;
case "subjectid":
uploadFileRequest.setSubjectid(Integer.parseInt(itemVal));
break;
case "duration":
uploadFileRequest.setDuration(Integer.parseInt(itemVal));
break;
case "objid":
uploadFileRequest.setObjid(Long.parseLong(itemVal));
break;
case "objtype":
uploadFileRequest.setObjtype(Byte.parseByte(itemVal));
break;
case "filesize":
uploadFileRequest.setFilesize(Integer.parseInt(itemVal));
break;
case "mimeType":
uploadFileRequest.setMimeType(itemVal);
break;
case "addflag":
uploadFileRequest.setAddflag(Byte.parseByte(itemVal));
break;
case "uuid":
uploadFileRequest.setUuid(itemVal);
if (!org.apache.commons.lang.StringUtils.isBlank(itemVal) &&
redisTemplate.opsForValue().get(itemVal) == null) {
throw new BaseException(ResultEnum.NO_AUTHORITY_TO_OPERATE_RESOURCE);
}
break;
default:
break;
}
}
final Set<String> fileNames = multiFileMap.keySet();
for (String file:fileNames) {
if (uploadFileRequest.getFilesize() <= 0) {
throw new BaseException(ResultEnum.UPLOAD_FILE_ISEMPTY);
}
checkUploadFileSize(uploadFileRequest, request);
final List<MultipartFile> multipartFiles = multiFileMap.get(file);
for (MultipartFile multipartFile: multipartFiles) {
final InputStream inputStream = multipartFile.getInputStream();
if (inputStream != null) {
fileName =URLDecoder.decode(multipartFile.getOriginalFilename(), "UTF-8");;
ext = fileName.substring(fileName.lastIndexOf(".") + 1, fileName.length()).toLowerCase();
if (uploadFileRequest.getMimeType() == null) {
uploadFileRequest.setMimeType(multipartFile.getContentType());
}
if (null != abstractUpload) {
storePath = abstractUpload.uploadFile(inputStream, uploadFileRequest.getFilesize(), ext);
} else {
storePath = uploadAdapter.uploadFile(inputStream, uploadFileRequest.getFilesize(), ext);
}
inputStream.close();
}
}
}
} catch (FileUploadException e) {
throw (FileUploadException) e.getCause();
} catch (IOException e) {
throw new FileUploadIOException(new FileUploadException(String.format("Processing of %s request failed. %s",
ServletFileUpload.MULTIPART_FORM_DATA, e.getMessage()), e));
} catch (Exception e) {
log.error("上传文件失败,error:{}", e);
throw new BaseException(ResultEnum.UPLOAD_FILE_FAIL);
}
if (null == storePath) {
log.error("上传文件失败,storePath=null,uploadFileRequest:{}", uploadFileRequest);
throw new BaseException(ResultEnum.UPLOAD_FILE_FAIL);
}
storePathVo.setFullPath(storePath.getFullPath());
storePathVo.setPath(storePath.getPath());
storePathVo.setHasDomainPath(fastDfsUploadUtils.getFastfileWebPath(storePath.getFullPath()));
storePathVo.setCreatedAt(new Date());
storePathVo.setGroup(storePath.getGroup());
storePathVo.setFname(fileName);
if (uploadFileRequest.getAddflag().equals((byte) 0)) {
return storePathVo;
}
//写入数据库
String tableName = "";
Long objid = 0L;
if (StringUtils.isNullOrBlank(uploadFileRequest.getUuid())) {
tableName = tableUtil.getTableName(request, SplitTableNameEnum.FASTFILE.getSchema(), SplitTableNameEnum.FASTFILE.getName());
objid = uploadFileRequest.getObjid();
} else {
tableName = tableUtil.getUUIDTableName(uploadFileRequest.getUuid());
objid = (long) uploadFileRequest.getUuid().hashCode();
}
Fastfile fastfile = new Fastfile();
fastfile.setFfid(IdWorker.getId());
fastfile.setSchoolid(userInfo.getSchoolid());
fastfile.setCampusid(userInfo.getCampusid());
fastfile.setGradeid(uploadFileRequest.getGradeid());
fastfile.setTermid(userInfo.getTermid());
fastfile.setSubjectid(uploadFileRequest.getSubjectid());
fastfile.setDuration(uploadFileRequest.getDuration());
fastfile.setBookid(uploadFileRequest.getBookid());
fastfile.setNodeid(uploadFileRequest.getNodeid());
fastfile.setObjid(objid);
fastfile.setObjtype(uploadFileRequest.getObjtype());
fastfile.setCreateby(userInfo.getUid());
fastfile.setFilesize(uploadFileRequest.getFilesize() / 1024);
fastfile.setMimetype(uploadFileRequest.getMimeType());
fastfile.setFname(fileName);
fastfile.setRemark("");
// if("cos".equals(storageType)) {
// fastfile.setFullpath(ossUtils.converUrl(storePath.getFullPath(), fileName));
// } else {
fastfile.setFullpath(storePath.getFullPath());
// }
fastfile.setFgroup(storePath.getGroup());
fastfile.setPath(storePath.getPath());
fastfile.setCreatedAt(new Date());
fastfile.setUpdatedAt(new Date());
fastfile.setStatus((byte) 1);
fastfile.setOriginalvideo((byte) 1);
//fastfile.setCanplay((byte) 1);
fastfileMapper.insertByTablename(fastfile, tableName);
storePathVo.setFfid(fastfile.getFfid());
return storePathVo;
}
原因分析:
我们远程调用时设置的MediaType type = MediaType.parseMediaType(“multipart/form-data; charset=UTF-8”);,当restTemplate.postForObject(url, formData, ResultVo.class)调用时,代码跟踪至org.springframework.web.client.RestTemplate类的934行处,这里我们看到有调用相关的数据包装转换类,我们看构造函数中,注册好多转换类,这一块就会调用multipart/form-data类型的消息转换器,也就是FormHttpMessageConverter
这是我初始化的restTemplate,添加了FormHttpMessageConverter 。
@Bean
@LoadBalanced
RestTemplate restTemplate(RestHeaderInterceptor restHeaderInterceptor) {
RestTemplate restTemplate = new RestTemplate();
restTemplate.setErrorHandler(new RestTemplateResponseErrorHandler());
List<HttpMessageConverter<?>> messageConverters = restTemplate.getMessageConverters();
List<HttpMessageConverter<?>> updateMessageConverters=new ArrayList<>();
// restTemplate对中文格式数据进行处理 解决中文乱码 menshaojing 2023年3月21日13:16:09
FormHttpMessageConverter formHttpMessageConverter = new FormHttpMessageConverter();
partConverters.add(new ObjectToStringHttpMessageConverter(new DefaultConversionService(),StandardCharsets.UTF_8));
formHttpMessageConverter.setPartConverters(partConverters);
updateMessageConverters.add(formHttpMessageConverter);
for (HttpMessageConverter<?> messageConverter : messageConverters) {
if (messageConverter instanceof StringHttpMessageConverter) {
StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter(StandardCharsets.UTF_8);
updateMessageConverters.add(stringHttpMessageConverter);
}else {
updateMessageConverters.add(messageConverter);
}
}
restTemplate.setMessageConverters(updateMessageConverters);
restTemplate.setInterceptors(Collections.singletonList(new RestTemplateTraceIdInterceptor()));
restTemplate.setInterceptors(Collections.singletonList(restHeaderInterceptor));
return restTemplate;
}
然而FormHttpMessageConverter 中,对于数据字段转换仅支持byte[]、string、Resource的数据转换,没有我们常见的其他类型。
在进行源码分析时,发现有个类ObjectToStringHttpMessageConverter,这意思很明显就是将其他类型转换成string类型。我们再看它的构造函数,有一个必须参数ConversionService类(转换服务),
我们点进去看一下都有哪些实现类,发现有一个以Default开头的类DefaultConversionService
再次去查看DefaultConversionService的构造函数,发现它内置好多的数据转换类,这说明可以使用该类,进行各个类型之间的转换。
解决方案:
从原因分析中我们可以得知,只要在FormHttpMessageConverter中添加ObjectToStringHttpMessageConverter,ObjectToStringHttpMessageConverter中引入DefaultConversionService就可以实现其他类型数据转换成string类型。
解决方法1:文章来源:https://www.toymoban.com/news/detail-759195.html
@Bean
@LoadBalanced
RestTemplate restTemplate(RestHeaderInterceptor restHeaderInterceptor) {
RestTemplate restTemplate = new RestTemplate();
restTemplate.setErrorHandler(new RestTemplateResponseErrorHandler());
List<HttpMessageConverter<?>> messageConverters = restTemplate.getMessageConverters();
List<HttpMessageConverter<?>> updateMessageConverters=new ArrayList<>();
// restTemplate对中文格式数据进行处理 解决中文乱码 menshaojing 2023年3月21日13:16:09
FormHttpMessageConverter formHttpMessageConverter = new FormHttpMessageConverter();
List<HttpMessageConverter<?>> partConverters = new ArrayList<>();
partConverters.add(new ByteArrayHttpMessageConverter());
partConverters.add(new StringHttpMessageConverter());
partConverters.add(new ResourceHttpMessageConverter());
// 解决org.springframework.http.converter.HttpMessageNotWritableException: Could not write request: no suitable HttpMessageConverter found for request type [java.lang.Long]...
//将所有类型转换成string类型
// menshaojing 2023年4月12日15:18:58
partConverters.add(new ObjectToStringHttpMessageConverter(new DefaultConversionService(),StandardCharsets.UTF_8));
formHttpMessageConverter.setPartConverters(partConverters);
updateMessageConverters.add(formHttpMessageConverter);
for (HttpMessageConverter<?> messageConverter : messageConverters) {
if (messageConverter instanceof StringHttpMessageConverter) {
StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter(StandardCharsets.UTF_8);
updateMessageConverters.add(stringHttpMessageConverter);
}else {
updateMessageConverters.add(messageConverter);
}
}
restTemplate.setMessageConverters(updateMessageConverters);
restTemplate.setInterceptors(Collections.singletonList(new RestTemplateTraceIdInterceptor()));
restTemplate.setInterceptors(Collections.singletonList(restHeaderInterceptor));
return restTemplate;
}
解决方法2:
我直接从restTemplate初始化配置中删除FormHttpMessageConverter ,发现数据可以正常转换了,说明了restTemplate中其他内置的消息转换器也能对multipart/form-data类型的数据进行转换。文章来源地址https://www.toymoban.com/news/detail-759195.html
到了这里,关于解决 Could not write request: no suitable HttpMessageConverter found for request type [java.lang.Long]的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!