MaxUploadSizeExceededException не вызывает метод обработки исключений в Spring
Я использую Spring 3.2.0. Согласно этому ответу, у меня есть тот же метод в моем аннотированном контроллере, который реализует HandlerExceptionResolver
интерфейс, такой как,
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception exception) {
Map<String, Object> model = new HashMap<String, Object>(0);
if (exception instanceof MaxUploadSizeExceededException) {
model.put("msg", exception.toString());
model.put("status", "-1");
} else {
model.put("msg", "Unexpected error : " + exception.toString());
model.put("status", "-1");
}
return new ModelAndView("admin_side/ProductImage");
}
и конфигурация Spring включает в себя,
<bean id="filterMultipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize">
<value>10000</value>
</property>
</bean>
Когда размер файла превышает, предыдущий метод должен быть вызван, и он должен автоматически обработать исключение, но это не происходит вообще. Метод resolveException()
никогда не вызывается, хотя возникает исключение. Как справиться с этим исключением? Я что-то пропустил?
То же самое указано и здесь. Я не уверен, почему это не работает в моем случае.
Я попробовал следующий подход с @ControllerAdvice
но это тоже не сработало.
package exceptionhandler;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.multipart.MaxUploadSizeExceededException;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
@ControllerAdvice
public final class RestResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {
@ExceptionHandler(value = {MaxUploadSizeExceededException.class})
protected ResponseEntity<Object> handleConflict(RuntimeException ex, WebRequest request) {
String bodyOfResponse = "This should be application specific";
return handleExceptionInternal(ex, bodyOfResponse, new HttpHeaders(), HttpStatus.CONFLICT, request);
}
}
Я также попытался поставить подробный - Exception
,
@ExceptionHandler(value={Exception.class})
Метод ResponseEntity()
никогда не вызывается в любом случае.
В общем, я хочу обработать это исключение для каждой базы контроллера (уровень контроллера), если это возможно. Для этого один @ExceptionHandler
аннотированный метод должен быть активным только для этого конкретного контроллера, а не глобально для всего приложения, так как в моем приложении есть только несколько веб-страниц, которые обрабатывают загрузку файлов. Когда это исключение вызвано, я просто хочу показать удобное сообщение об ошибке на текущей странице, а не перенаправлять на страницу ошибки, настроенную в web.xml
файл. Если это даже невозможно, то это исключение должно быть обработано в любом случае без каких-либо специальных требований, которые я только что высказал.
Ни один из подходов не работал для меня. Больше ничего об обработке этого исключения я не смог найти. Требуется ли дополнительная настройка где-нибудь в файлах XML или иным образом?
То, что я получаю после исключения, можно увидеть на следующем снимке.
6 ответов
Согласно вашей опубликованной трассировке MaxUploadSizeExceeded
Выдается исключение до того, как запрос достиг сервлета диспетчера. Поэтому ваш обработчик исключений не вызывается, потому что в момент, когда выдается исключение, целевой контроллер еще не определен.
Если вы посмотрите на трассировку стека, вы увидите, что исключение выдается в HiddenHttpMethodFilter
он получает все параметры вашего multipart-запроса, а также ваш параметр "to big" upload-data.
Это HiddenHttpMethodFilter
нужен для вашего контроллера, обрабатывающего multipart-upload? Если нет, исключите этот фильтр из ваших контроллеров обработки загрузки.
Вы можете настроить свойство CommonsMultipartResolver resolLazily на true так:
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="resolveLazily" value="true"/>
</bean>
Из ответа, опубликованного Дирком Лачовски, я исключил некоторые страницы, которые используются для многочастной загрузки из HiddenHttpMethodFilter
,
HiddenHttpMethodFilter
Первоначально был задан шаблон URL, как /*
, Поэтому было утомительно перемещать эти страницы в отдельный каталог / папку и указывать другой шаблон URL, например /xxx/*
, Чтобы избежать этого, я унаследовал OncePerRequestFilter
в моем собственном классе и исключил эти страницы, используемые для многоэтапной загрузки, которая работала как ожидалось, показывая удобное сообщение об ошибке на текущей странице.
package filter;
import java.io.IOException;
import java.util.Locale;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
public final class HiddenHttpMethodFilter extends OncePerRequestFilter {
/**
* Default method parameter: <code>_method</code>
*/
public static final String DEFAULT_METHOD_PARAM = "_method";
private String methodParam = DEFAULT_METHOD_PARAM;
/**
* Set the parameter name to look for HTTP methods.
*
* @see #DEFAULT_METHOD_PARAM
*/
public void setMethodParam(String methodParam) {
Assert.hasText(methodParam, "'methodParam' must not be empty");
this.methodParam = methodParam;
}
private boolean excludePages(String page) {
//Specifically, in my case, this many pages so far have been excluded from processing avoiding the MaxUploadSizeExceededException in this filter. One could use a RegExp or something else as per requirements.
if (page.equalsIgnoreCase("Category.htm") || page.equalsIgnoreCase("SubCategory.htm") || page.equalsIgnoreCase("ProductImage.htm") || page.equalsIgnoreCase("Banner.htm") || page.equalsIgnoreCase("Brand.htm")) {
return false;
}
return true;
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String servletPath = request.getServletPath();
if (excludePages(servletPath.substring(servletPath.lastIndexOf("/") + 1, servletPath.length()))) {
String paramValue = request.getParameter(this.methodParam);
//The MaxUploadSizeExceededException was being thrown at the preceding line.
if ("POST".equals(request.getMethod()) && StringUtils.hasLength(paramValue)) {
String method = paramValue.toUpperCase(Locale.ENGLISH);
HttpServletRequest wrapper = new filter.HiddenHttpMethodFilter.HttpMethodRequestWrapper(request, method);
filterChain.doFilter(wrapper, response);
} else {
filterChain.doFilter(request, response);
}
} else {
filterChain.doFilter(request, response);
}
}
/**
* Simple {@link HttpServletRequest} wrapper that returns the supplied
* method for {@link HttpServletRequest#getMethod()}.
*/
private static class HttpMethodRequestWrapper extends HttpServletRequestWrapper {
private final String method;
public HttpMethodRequestWrapper(HttpServletRequest request, String method) {
super(request);
this.method = method;
}
@Override
public String getMethod() {
return this.method;
}
}
}
И по моему web.xml
файл, этот фильтр - filter.HiddenHttpMethodFilter
был указан вместо org.springframework.web.filter.HiddenHttpMethodFilter
следующее.
<filter>
<filter-name>multipartFilter</filter-name>
<filter-class>org.springframework.web.multipart.support.MultipartFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>multipartFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>httpMethodFilter</filter-name>
<filter-class>filter.HiddenHttpMethodFilter</filter-class>
<!--<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class> This was removed replacing with the preceding one-->
</filter>
<filter-mapping>
<filter-name>httpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Я все еще надеюсь, что должен / может быть справедливый способ обработки рассматриваемого исключения вместе с org.springframework.web.filter.HiddenHttpMethodFilter
Ваш @ExcpetionHandler не работает, потому что эти аннотированные методы позволяют только возвращать типы ModelAndView или String из того, что я помню. Смотрите эту публикацию для получения дополнительной информации.
Мое решение: сначала определите бин для класса, который реализует HandlerExceptionResolver .
<bean id="classForBeanException" class="XXXX.path.To.classForBeanException" />
В вашем ControllerAdvice, который обрабатывает исключение, вы можете иметь такой код. Это сработало для меня. Это весной 4.0+
@ExceptionHandler(Exception.class)
public @ResponseBody BaseResponse onException(Exception e, HttpServletResponse response) {
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
BaseResponse resp = new BaseResponse();
if(e instanceof MaxUploadSizeExceededException){
resp.setCode(FileUploadFailed.SIZE_EXCEED);
resp.setMessage("Maximum upload size exceeded");
}
return resp;
}
Есть ли способ получить аргументы @RequestParam, определенные в методе контроллера в ExceptionHandler, который управляет MaxUploadSizeExceededException? Кажется, что его бросили перед тем, как перейти к методу контроллера.