I have a simple REST controller that I use for accepting a file being uploaded from a HTML form. The project is Spring Boot 2.6.1 and Java 17. But the problem was also to be found in Spring Boot 2.3.7 and Java 15.
@PostMapping(path = "/file", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public void handleFileUpload(@RequestParam("file") MultipartFile file) {
fileService.upload(file.getInputStream(), file.getOriginalFilename());
}
The problem is file
is always NULL. I found a lot of different answers about setting a MultipartResolver
bean or enabling spring.http.multipart.enabled = true
but nothing helped. I have a logging filter as one of the first filters in the chain. After debugging in the filter chain I found out that making a call to request.getParts()
made everything work. My filter look like this:
public class LoggingFilter extends GenericFilterBean {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
BufferedRequestWrapper bufferedRequest = new BufferedRequestWrapper(httpServletRequest);
BufferedResponseWrapper bufferedResponse = new BufferedResponseWrapper((HttpServletResponse) response);
filterChain.doFilter(bufferedRequest, bufferedResponse);
logRequest(httpServletRequest, bufferedRequest);
logResponse(httpServletRequest, bufferedResponse);
}
I changed the filter to:
public class LoggingFilter extends GenericFilterBean {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
if (request.getContentType() != null && request.getContentType().startsWith("multipart/form-data")) {
httpServletRequest.getParts(); // Trigger initialization of multi-part.
}
BufferedRequestWrapper bufferedRequest = new BufferedRequestWrapper(httpServletRequest);
BufferedResponseWrapper bufferedResponse = new BufferedResponseWrapper((HttpServletResponse) response);
filterChain.doFilter(bufferedRequest, bufferedResponse);
logRequest(httpServletRequest, bufferedRequest);
logResponse(httpServletRequest, bufferedResponse);
}
and everything was working. My question is; why is this needed? And is there a better way of doing this?
CodePudding user response:
Please consider using ContentCachingRequestWrapper.
It's built-in of spring which help you can read caches all content read from the input stream and reader.
Be aware, with multipart file, spring already have a wrapper ... MultipartHttpServletRequest