我正在使用SpringMVC开发一个REST服务,我在类和方法级别有@RequestMapping。
此应用程序当前配置为返回在web.xml中配置的错误页面jsp。
<error-page>
<error-code>404</error-code>
<location>/resourceNotFound</location>
</error-page>
但我希望返回自定义JSON而不是此错误页面。
我能够处理异常并返回json以获取其他异常,通过在控制器中编写它,但不确定当url根本不存在时,如何以及在何处编写逻辑以返回JSON。
@ExceptionHandler(TypeMismatchException.class)
@ResponseStatus(value=HttpStatus.NOT_FOUND)
@ResponseBody
public ResponseEntity<String> handleTypeMismatchException(HttpServletRequest req, TypeMismatchException ex) {
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", "application/json; charset=utf-8");
Locale locale = LocaleContextHolder.getLocale();
String errorMessage = messageSource.getMessage("error.patient.bad.request", null, locale);
errorMessage += ex.getValue();
String errorURL = req.getRequestURL().toString();
ErrorInfo errorInfo = new ErrorInfo(errorURL, errorMessage);
return new ResponseEntity<String>(errorInfo.toJson(), headers, HttpStatus.BAD_REQUEST);
}
我试过@ControllerAdvice,它适用于其他异常情况,但不适用于映射不可用的情况
@ControllerAdvice
public class RestExceptionProcessor {
@Autowired
private MessageSource messageSource;
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
@ResponseStatus(value=HttpStatus.NOT_FOUND)
@ResponseBody
public ResponseEntity<String> requestMethodNotSupported(HttpServletRequest req, HttpRequestMethodNotSupportedException ex) {
Locale locale = LocaleContextHolder.getLocale();
String errorMessage = messageSource.getMessage("error.patient.bad.id", null, locale);
String errorURL = req.getRequestURL().toString();
ErrorInfo errorInfo = new ErrorInfo(errorURL, errorMessage);
return new ResponseEntity<String>(errorInfo.toJson(), HttpStatus.BAD_REQUEST);
}
@ExceptionHandler(NoSuchRequestHandlingMethodException.class)
@ResponseStatus(value=HttpStatus.NOT_FOUND)
@ResponseBody
public ResponseEntity<String> requestHandlingMethodNotSupported(HttpServletRequest req, NoSuchRequestHandlingMethodException ex) {
Locale locale = LocaleContextHolder.getLocale();
String errorMessage = messageSource.getMessage("error.patient.bad.id", null, locale);
String errorURL = req.getRequestURL().toString();
ErrorInfo errorInfo = new ErrorInfo(errorURL, errorMessage);
return new ResponseEntity<String>(errorInfo.toJson(), HttpStatus.BAD_REQUEST);
}
}
答案 0 :(得分:24)
在SpringFramework中挖掘DispatcherServlet和HttpServletBean.init()之后,我发现它在Spring 4中是可行的。
<强> org.springframework.web.servlet.DispatcherServlet 强>
/** Throw a NoHandlerFoundException if no Handler was found to process this request? **/
private boolean throwExceptionIfNoHandlerFound = false;
protected void noHandlerFound(HttpServletRequest request, HttpServletResponse response) throws Exception {
if (pageNotFoundLogger.isWarnEnabled()) {
String requestUri = urlPathHelper.getRequestUri(request);
pageNotFoundLogger.warn("No mapping found for HTTP request with URI [" + requestUri +
"] in DispatcherServlet with name '" + getServletName() + "'");
}
if(throwExceptionIfNoHandlerFound) {
ServletServerHttpRequest req = new ServletServerHttpRequest(request);
throw new NoHandlerFoundException(req.getMethod().name(),
req.getServletRequest().getRequestURI(),req.getHeaders());
} else {
response.sendError(HttpServletResponse.SC_NOT_FOUND);
}
}
throwExceptionIfNoHandlerFound 默认为false,我们应该在 web.xml
中启用它<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>throwExceptionIfNoHandlerFound</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
<async-supported>true</async-supported>
</servlet>
然后您可以使用此方法在使用 @ControllerAdvice 注释的类中捕获它。
@ExceptionHandler(NoHandlerFoundException.class)
@ResponseStatus(value=HttpStatus.NOT_FOUND)
@ResponseBody
public ResponseEntity<String> requestHandlingNoHandlerFound(HttpServletRequest req, NoHandlerFoundException ex) {
Locale locale = LocaleContextHolder.getLocale();
String errorMessage = messageSource.getMessage("error.bad.url", null, locale);
String errorURL = req.getRequestURL().toString();
ErrorInfo errorInfo = new ErrorInfo(errorURL, errorMessage);
return new ResponseEntity<String>(errorInfo.toJson(), HttpStatus.BAD_REQUEST);
}
这允许我为没有映射的坏URL返回JSON响应,而不是重定向到JSP页面:)
{"message":"URL does not exist","url":"http://localhost:8080/service/patientssd"}
答案 1 :(得分:7)
如果您使用的是Spring Boot,请设置以下两个属性:
private static bool IsValidPath(string input)
{
bool isValid = false;
try
{
var fullPath = Path.GetFullPath(input);
return input.Equals(fullPath, StringComparison.InvariantCultureIgnoreCase);
}
catch (Exception)
{
isValid = false;
}
return isValid;
}
现在你的@ControllerAdvice注释类可以处理“NoHandlerFoundException”,如下所示。
spring.resources.add-mappings=false
spring.mvc.throw-exception-if-no-handler-found=true
请注意,仅指定此属性是不够的:
@ControllerAdvice
@RequestMapping(produces = "application/json")
@ResponseBody
public class RestControllerAdvice {
@ExceptionHandler(NoHandlerFoundException.class)
public ResponseEntity<Map<String, Object>> unhandledPath(final NoHandlerFoundException e) {
Map<String, Object> errorInfo = new LinkedHashMap<>();
errorInfo.put("timestamp", new Date());
errorInfo.put("httpCode", HttpStatus.NOT_FOUND.value());
errorInfo.put("httpStatus", HttpStatus.NOT_FOUND.getReasonPhrase());
errorInfo.put("errorMessage", e.getMessage());
return new ResponseEntity<Map<String, Object>>(errorInfo, HttpStatus.NOT_FOUND);
}
}
,默认情况下,Spring会将未知的网址映射到/ **,因此确实没有“找不到处理程序”。
要禁用未知网址映射到/ **,您需要
spring.mvc.throw-exception-if-no-handler-found=true
这就是两个属性一起产生所需行为的原因。
答案 2 :(得分:-1)
如果您使用的是Spring 3.2或更高版本,则可以使用控制器建议(@ControllerAdvice
)来处理映射错误(404)。你可以找到documentation here。看看第17.11节。例如,您可以使用此方法提供更详细的日志记录,说明您的请求绑定未与特定网址匹配的原因,或仅返回比通用404更具体的响应。
答案 3 :(得分:-3)
你可以在下面的位置返回json, / handle / 404 。
<error-page>
<error-code>404</error-code>
<location>/handle/404</location>
</error-page>
在web.xml中配置后,404错误将重定向到 / handle / 404 ,您可以使用此映射创建控制器并返回json结果。例如。
@RestController
@RequestMapping(value = "handle")
public class HttpErrorController {
@RequestMapping(value = "404")
public String handle404() {
return "404 error";
}
}