我正在开发基于Spring 3.2的RESTful服务。我正面临一个控制器处理混合多部分HTTP请求的问题,第二部分使用XML或JSON格式化数据,第二部分使用图像文件。
我正在使用@RequestPart annotation 来接收请求
@RequestMapping(value = "/User/Image", method = RequestMethod.POST, consumes = {"multipart/mixed"},produces="applcation/json")
public
ResponseEntity<List<Map<String, String>>> createUser(
@RequestPart("file") MultipartFile file, @RequestPart(required=false) User user) {
System.out.println("file" + file);
System.out.println("user " + user);
System.out.println("received file with original filename: "
+ file.getOriginalFilename());
// List<MultipartFile> files = uploadForm.getFiles();
List<Map<String, String>> response = new ArrayList<Map<String, String>>();
Map<String, String> responseMap = new HashMap<String, String>();
List<String> fileNames = new ArrayList<String>();
if (null != file) {
// for (MultipartFile multipartFile : files) {
String fileName = file.getOriginalFilename();
fileNames.add(fileName);
try {
file.transferTo(new File("C:/" + file.getOriginalFilename()));
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
responseMap.put("displayText", file.getOriginalFilename());
responseMap.put("fileSize", "" + file.getSize());
response.add(responseMap);
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add("Accept", "application/json");
return new ResponseEntity<List<Map<String, String>>>(response,
httpHeaders, HttpStatus.OK);
}
User.java就像这样 -
@XmlRootElement(name = "User")
public class User implements Serializable {
private static final long serialVersionUID = 1L;
private int userId;
private String name;
private String email;
private String company;
private String gender;
//getter setter of the data members
}
根据我的理解,使用@RequestPart注释我希望根据其Content-Type评估XML多部分部分,最后将其编组到我的User类中(我使用的是Jaxb2,marshaller / unmarhaller是正确的在应用程序上下文中配置,当我将XML数据作为正文传递并使用@RequestBody注释时,该过程适用于所有其他控制器方法。
但实际发生的情况是,虽然文件被正确找到并解析为MultipartFile,但“用户”部分从未见过,请求总是失败,与控制器方法签名不匹配。
我用几种客户端类型重现了这个问题,我相信多部分请求的格式是可以的。
请帮我解决这个问题,也许会有一些解决方法来接收混合/多部分请求。
谢谢和问候,
Raghvendra
答案 0 :(得分:8)
不确定您是否修复了问题,但我也遇到了类似的问题,即在将@RequestPart和MultipartFile混合在一起时,我的控制器无法获取我的JSON对象。
您的通话方法签名看起来是正确的:
public ResponseEntity<List<Map<String, String>>> createUser(
@RequestPart("file") MultipartFile file, @RequestPart(required=false) User user) {
// ... CODE ...
}
但请确保您的请求看起来像这样:
POST /createUser
Content-Type: multipart/mixed; boundary=B0EC8D07-EBF1-4EA7-966C-E492A9F2C36E
--B0EC8D07-EBF1-4EA7-966C-E492A9F2C36E
Content-Disposition: form-data; name="user";
Content-Type: application/xml; charset=UTF-8
<user><!-- your user xml --></user>
--B0EC8D07-EBF1-4EA7-966C-E492A9F2C36E
Content-Disposition: form-data; name="file"; filename="A551A700-46D4-470A-86E7-52AD2B445847.dat"
Content-Type: application/octet-stream
/// FILE DATA
--B0EC8D07-EBF1-4EA7-966C-E492A9F2C36E--
答案 1 :(得分:2)
我设法解决了问题
端点示例:
@PostMapping("/")
public Document create(@RequestPart Document document,
@RequestPart(required = false) MultipartFile file) {
log.debug("#create: document({}), file({})", delegation, file);
//custom logic
return document;
}
例外:
"error_message": "Content type 'application/octet-stream' not supported"
从下一个方法引发异常:
org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver.readWithMessageConverters(HttpInputMessage,MethodParameter,Type)
解决方案:
我们必须创建自定义转换器@Component,该转换器实现 HttpMessageConverter 或 HttpMessageConverter ,并且了解 MediaType.APPLICATION_OCTET_STREAM 。对于简单的解决方法,只需扩展 AbstractJackson2HttpMessageConverter
@Component
public class MultipartJackson2HttpMessageConverter extends AbstractJackson2HttpMessageConverter {
/**
* Converter for support http request with header Content-Type: multipart/form-data
*/
public MultipartJackson2HttpMessageConverter(ObjectMapper objectMapper) {
super(objectMapper, MediaType.APPLICATION_OCTET_STREAM);
}
@Override
public boolean canWrite(Class<?> clazz, MediaType mediaType) {
return false;
}
@Override
public boolean canWrite(Type type, Class<?> clazz, MediaType mediaType) {
return false;
}
@Override
protected boolean canWrite(MediaType mediaType) {
return false;
}
}
答案 2 :(得分:0)
您可以从以下位置使用@RequestPart org.springframework.web.bind.annotation.RequestPart; 用作结合@RequestBody和文件上传。
像这样使用@RequestParam @RequestParam(“ file”)MultipartFile文件 您只能上传文件和多个单个数据(键值) 喜欢
@RequestMapping(value = "/uploadFile", method = RequestMethod.POST, consumes = { MediaType.MULTIPART_FORM_DATA_VALUE }, produces = { MediaType.APPLICATION_JSON_VALUE })
public void saveFile(
@RequestParam("userid") String userid,
@RequestParam("file") MultipartFile file) {
}
您可以使用@RequestPart之类的方式发布JSON对象数据和和文件
@RequestMapping(value = "/patientp", method = RequestMethod.POST, consumes = { MediaType.MULTIPART_FORM_DATA_VALUE }, produces = { MediaType.APPLICATION_JSON_VALUE })
public ResponseEntity<?> insertPatientInfo(
@RequestPart PatientInfoDTO patientInfoDTO,
@RequestPart("file") MultipartFile file) {
}
您不仅限于直接将分段文件上传用作控制器方法参数。您的表单对象可以包含Part或MultipartFile字段,并且Spring自动知道它必须从文件部分获取值并适当地转换值。
上述方法可以响应先前演示的包含单个文件的多部分请求。之所以可行,是因为Spring具有一个内置的HTTP消息转换器,可以识别文件部分。除了javax.servlet.http.Part类型之外,您还可以将文件上传转换为org.springframework.web.multipart.MultipartFile。如第二个multipart请求所示,如果file字段允许上传多个文件,则只需使用数组或Parts集合或MultipartFiles。
@RequestMapping(value = "/patientp", method = RequestMethod.POST, consumes = { MediaType.MULTIPART_FORM_DATA_VALUE }, produces = { MediaType.APPLICATION_JSON_VALUE })
public ResponseEntity<?> insertPatientInfo(
@RequestPart PatientInfoDTO patientInfoDTO,
@RequestPart("files") List<MultipartFile> files) {
}
乐于助人...
答案 3 :(得分:0)
我设法解决了问题:
@SuppressWarnings("rawtypes")
@RequestMapping(value = "/DataTransfer", method = RequestMethod.POST, produces = {
MediaType.APPLICATION_JSON_UTF8_VALUE }, consumes = { MediaType.MULTIPART_FORM_DATA_VALUE, MediaType.APPLICATION_JSON_UTF8_VALUE} )
@ApiOperation(value = "Sbm Data Transfer Service", response = Iterable.class)
@ApiResponses(value = { @ApiResponse(code = 200, message = "Successfully find."),
@ApiResponse(code = 400, message = "There has been an error."),
@ApiResponse(code = 401, message = "You are not authorized to save the resource"),
@ApiResponse(code = 403, message = "Accessing the resource you were trying to reach is forbidden"),
@ApiResponse(code = 404, message = "The resource you were trying to reach is not found") })
ResponseEntity processDataTransfer(@RequestPart(name="file") MultipartFile file, @RequestPart(name="param") DataTransferInputDto param);
答案 4 :(得分:-4)
你试过吗
ResponseEntity<List<Map<String, String>>> createUser(
@RequestPart("file") MultipartFile file, @RequestBody(required=false) User user) {
或
ResponseEntity<List<Map<String, String>>> createUser(
@RequestPart("file") MultipartFile file, @RequestParam(required=false) User user) {
如果这不起作用,您可以向我们展示mapping.xml