spring mvc捕获异常时,如何判断应该返回json还是跳转错误页面
在异常捕获handler BusinessExceptionHandlerAdvice中
判断控制器的方法是否有ResponseBody注解,如果有,则返回json,
关键问题是:
如何判断控制器的方法是否有ResponseBody注解
我们先看看@ExceptionHandler方法中注入的参数有哪些?
1. ServletResponse.class 2. OutputStream.class 3. Writer.class 4. WebRequest.class 5. ServletRequest.class 6. MultipartRequest.class 7. HttpSession.class 8. Principal.class 9. Locale.class 10. InputStream.class 11. Reader.class
直接获取控制器方法(java.lang.reflect.Method)的计划破灭了,
那么还有没有其他方法呢?
有!通过异常的堆栈 StackTraceElement
那么StackTraceElement有哪些信息呢?
所以我们可以通过反射获取控制器方法,然后判断是否有注解ResponseBody.class
具体实现(直接上代码):
package oa.web.controller.handler; import com.common.bean.BaseResponseDto; import com.common.bean.exception.LogicBusinessException; import com.common.util.ReflectHWUtils; import com.common.util.SystemHWUtil; import com.common.util.WebServletUtil; import com.string.widget.util.ValueWidget; import org.apache.log4j.Logger; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.io.IOException; import java.io.PrintWriter; import java.io.UnsupportedEncodingException; import java.lang.reflect.Method; import java.net.URLEncoder; /** * Created by whuanghkl on 3/30/16. * 注意使用注解@ControllerAdvice作用域是全局Controller范围 * 可应用到所有@RequestMapping类或方法上的@ExceptionHandler、@InitBinder、@ModelAttribute,在这里是@ExceptionHandler<br /> * 用于检测第三方接口,比如bsvc或cia的504,502等异常<br /> * 这些异常均属于非业务异常,与业务毫无关系,所以单独处理<br /> * 注意:StoreBusinessException 不要捕获,否则无法被BusinessExceptionHandlerAdvice 截获<br /> * 注意:传递url中的参数如果可能包含中文一定要URL编码, */ @ControllerAdvice public class BusinessExceptionHandlerAdvice { public static Logger logger = Logger.getLogger(BusinessExceptionHandlerAdvice.class); /*** * 判断接口的注解是否是ResponseBody,是,那么返回json,而不是跳转错误页面 * @param stackTraceElement * @return */ public static boolean isControllerAction(StackTraceElement stackTraceElement) { String className = stackTraceElement.getClassName(); if (className.endsWith("Controller")) { try { Class controllerClass = Class.forName(className); Method actionMethod = ReflectHWUtils.getMethod(controllerClass, stackTraceElement.getMethodName(), ResponseBody.class); if (null == actionMethod) { return false; } return true; } catch (ClassNotFoundException e) { e.printStackTrace(); } } return false; } /*** * 判断接口的注解是否是ResponseBody,是,那么返回json,而不是跳转错误页面<br /> * 限制最多循环4次,否则影响性能 * @param stackTraceElements * @return */ public static boolean isControllerAction(StackTraceElement[] stackTraceElements) { int length = stackTraceElements.length; if (length > 4) { length = 4; } for (int i = 0; i < length; i++) { StackTraceElement stackTraceElement = stackTraceElements[i]; if (isControllerAction(stackTraceElement)) { return true; } } return false; } @ExceptionHandler(LogicBusinessException.class) // @RESPONSE_CONTENTTYPE_JSON_UTFStatus(HttpStatus.BAD_REQUEST) // @ResponseBody public String handleBusinessException(LogicBusinessException ex, HttpSession session, HttpServletRequest request, HttpServletResponse response) { // return ClassUtils.getShortName(ex.getClass()) + ex.getMessage(); logger.error(ex);//{errorCode='1021', errorMessage='用户不在组织的企业客户身份中'} logger.error("old url:" + request.getRequestURL()); logger.error("query string:" + request.getQueryString()); StackTraceElement[] stackTraceElements = ex.getStackTrace(); if (!ex.isWap()) { boolean isControllerAction = isControllerAction(stackTraceElements); System.out.println("isControllerAction :" + isControllerAction); if (isControllerAction) { ex.setWap(true);//表示返回json } } if (ex.isWap() || WebServletUtil.getMobileOsInfo(request).isMobile()) {//如果是手机端 PrintWriter out = null; try { out = response.getWriter(); } catch (IOException e) { e.printStackTrace(); } if (ValueWidget.isNullOrEmpty(ex.getResponseBody())) { out.print(new BaseResponseDto(ex.getErrorCode(), ex.getErrorMessage()).toJson()); } else { out.print(ex.getResponseBody()); } out.flush(); } else { String redirectUrl = null; if (ValueWidget.isNullOrEmpty(ex.getRedirectUrl())) { String message = null; message = getMessage(ex); redirectUrl = "/error.html?error=" + ex.getErrorCode() + "&errorMessage=" + message; } else { redirectUrl = ex.getRedirectUrl(); } logger.error("redirect url:" + redirectUrl); try { response.sendRedirect(redirectUrl); } catch (IOException e) { e.printStackTrace(); } } return null; } /*** * * @param ex * @param message :中文已经经过url 编码 * @return */ private static String getMessage(LogicBusinessException ex) { String message = null; if (ValueWidget.isNullOrEmpty(ex.getErrorMessage())) { message = SystemHWUtil.EMPTY; } else { try { message = URLEncoder.encode(ex.getErrorMessage(), "UTF-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } return message; } }
简单说明下:
先判断isWap是否为true,如果为true,说明已经手动指定返回json了,那么就不用判断了.
否则才需要通过StackTraceElement判断
相关推荐
### Spring MVC 教程知识点详解 #### 一、Spring MVC 概述 Spring MVC 是 Spring 框架的一部分,主要用于构建基于 Java 的 Web 应用...无论是从快速入门还是深入研究的角度来看,Spring MVC 都是一个值得推荐的选择。
Spring MVC是Spring框架的一个核心模块,用于构建Web应用程序。它提供了模型-视图-控制器(MVC)架构,使得开发者可以将业务逻辑、数据处理和用户界面清晰地分离,从而提高代码的可维护性和可测试性。这个压缩包中...
Spring MVC 是一款强大的Java Web开发框架,用于构建高效、可维护的Web应用程序。在这个简单的Spring MVC登录案例中,我们主要关注的是如何利用注解(Annotation)来实现用户登录功能。注解是Spring MVC中的一种元...
Spring MVC 提供了多种方式来处理Ajax请求,包括使用`@ResponseBody`注解直接返回JSON或XML格式的数据。 #### 十四、多视图控制器 通过定义多个控制器类或使用`@RequestMapping`注解的不同配置来实现多视图控制。 ...
### Spring MVC 数据跳转 在 Spring MVC 中,数据跳转主要指的是控制器(Controller)处理完请求后,将数据转发到视图(View)进行展示的过程。这里的“跳转”实际上是指请求处理后的视图重定向或转发。 #### 转发与...
Spring MVC和MyBatis是Java开发中常用的两个框架,它们分别负责Web层和持久层的管理。Spring MVC作为Spring框架的一部分,提供了强大的Model-View-Controller(MVC)架构模式,使得开发人员能够轻松地处理HTTP请求和...
6. **前端响应处理**:JavaScript接收到响应后,根据结果显示相应的提示,如登录成功跳转到主页面,失败则显示错误信息。 **4. 增删改查功能** 在用户管理中,增删改查是基本操作: - **添加用户**:用户填写信息...
### 精通Spring MVC 4 - 关键知识点解析 #### 一、Spring MVC框架简介与Spring Tool Suite的使用 **Spring MVC**是Spring框架的一部分,专注于构建Web应用程序中的Model-View-Controller(MVC)架构。Spring MVC 4...
Spring MVC可以无缝处理AJAX请求,通过配置和注解来定义JSON或XML的响应格式。 十一、配置文件: SpringMVC.xml是核心配置文件,用于配置DispatcherServlet、拦截器、视图解析器等组件。 十二、获取Spring管理的...
例如,如果控制器方法返回 "index",那么 Spring MVC 将会跳转到名为 "index" 的视图。同时,String 类型的返回值也可以带有前缀和后缀,例如 "redirect:success",这将会跳转到名为 "success" 的视图,并带有 ...
成功时可能跳转到主页面,失败则显示错误信息。 在实际开发中,我们还需要了解Spring MVC的其他特性,如拦截器(Interceptor)、异常处理、局部变量和模型数据传递、上传下载支持等。同时,结合源码阅读,可以帮助...
总结,Spring MVC处理器方法的返回值多种多样,可以根据需求选择合适的返回类型来控制响应内容、视图跳转或数据绑定。理解并熟练运用这些返回类型是构建高效、灵活的Spring MVC应用程序的关键。
当发生未捕获的异常时,系统会自动跳转到错误页面或返回错误响应。同时,Spring Boot的日志配置使得我们能够跟踪和调试应用运行时的问题。 总的来说,Spring PetClinic是一个综合性的学习资源,涵盖了Spring框架的...
本篇将详细介绍如何在SpringBoot项目中实现JSP的跳转以及接口的Json返回。 首先,SpringBoot默认不支持JSP是因为其主要设计理念是简化配置和提高开发效率,它倾向于使用更加现代化的模板引擎。然而,如果你的项目中...
在Java Web开发中,Maven、Spring MVC和Mybatis是三个非常重要的技术栈。Maven是一个项目管理和集成工具,Spring MVC是Spring框架的一部分,用于构建Web应用程序,而Mybatis则是一个轻量级的持久层框架,它简化了...
在Spring Boot框架中,开发Web应用时,我们通常会用到Thymeleaf、Freemarker或者JSP作为视图层技术。本实例主要聚焦于使用JSP进行页面跳转,这在传统的Java Web开发中非常常见。Spring Boot虽然默认不推荐使用JSP,...
在现代Web应用开发中,Ajax(Asynchronous JavaScript and XML)技术和Spring框架的结合使用是常见的交互方式,尤其在实现页面无刷新更新时。本主题主要探讨如何通过Ajax与Spring互相传递JSON(JavaScript Object ...
例如,一个登录功能,用户通过表单提交时可以跳转到JSP页面显示结果,而API则提供无状态的JSON响应。 - 对于返回JSP的情况,使用`ModelAndView`或者`RedirectAttributes`跳转到指定的JSP页面。 - 对于API接口,...
通过这种方式,我们可以捕获并处理特定的异常,返回合适的错误页面或者JSON响应,提供给用户友好的错误信息。 `@ExceptionHandler`注解允许我们在控制器方法上声明,该方法将在特定类型的异常发生时被调用。例如,...