play framework 1.2.x 处理全局异常
采用@Catch标签,在处理统一异常的方法上添加此标签,用于捕获程序抛出的异常
如果有Action方法抛出了异常,那么使用@Catch注解的方法就会执行,且抛出的异常会以参数的形式传递到@Catch注解的方法中。
编写自定义ServiceException 类。
public class ServiceException extends RuntimeException {
private String msg = "unknow error";
public ServiceException(Exception e) {
super(e);
}
public ServiceException(String msg) {
super(msg);
}
public ServiceException(Exception e, String msg) {
super(e);
e.printStackTrace();
this.setMsg(msg);
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
编写一个简单的控制器测试类 TestExceptionController.java ,在控制器层添加抛出自定义异常方法:
public class TestExceptionController extends BaseController {
public static void test1() { //不可修改为throws ServiceException
try {
int ka = 2 / 0;
renderJSON(ka);
} catch (Exception e) {
throw new ServiceException(e, "数据格式错误");
}
}
}
添加路由 route,否则无法访问新增的action
GET /testA test.TestExceptionController.test1
编写一个统一处理异常的类 MyExceptionHandler.java,用于捕获到的异常
public class MyExceptionHandler extends Controller {
/**
* 统一错误处理
*
* @param se
*/
@Catch(ServiceException.class)
public static void operateExp(ServiceException se) {
Logger.error(se.getMessage());
String accept = request.headers.get("accept").toString();
String s[] = accept.split(",");
if (s[0].equalsIgnoreCase("[text/html")) {
render("@Application.errorFront");
} else if (s[0].equalsIgnoreCase("[application/json")) {
String err = se.getMessage();
renderJSON(err);
} else {
render("@Application.errorFront");
}
}
}
本例子中未区普通text/html和json等请求,实际中可根据不用的请求类型,进行不同的异常捕获处理
使用@Catch注解和普通的Java异常处理程序一样,捕获父类往往可以获得更多的异常类型。如果拥有多个需要捕获的方法,可以通过指定优先级来确定他们的执行顺序。通过@Catch中的priority来定义
查看@Catch标签的源码发现:
第一个vlaue数组表示可以传入多个异常类型,第二个int类型的用来标示优先级,0最高
/**
* Mark this method as @Catch interceptor
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Catch {
Class<?>[] value() default {};
/**
* Interceptor priority (0 is high priority)
*/
int priority() default 0;
}
好了,开始测试。。。。
等等。。。千万不要以为完事了,可以运行了。。。现在这样无法捕获到 test1()中抛出的ServiceException
因为没有MyExceptionHandler中用来捕获自定义异常ServiceException并处理方法并没有被调用,或者说并不会起作用。如何解决?有两种方法:
- 删掉 MyExceptionHandler.java,把里面的operateExp方法放到TestExceptionController.java 中,并在方法头上添加@Catch标签
public class TestExceptionController extends BaseController { /** * 统一错误处理 * * @param se */ @Catch(ServiceException.class) public static void operateExp(ServiceException se) { Logger.error(se.getMessage()); String accept = request.headers.get("accept").toString(); String s[] = accept.split(","); if (s[0].equalsIgnoreCase("[text/html")) { render("@Application.errorFront"); } else if (s[0].equalsIgnoreCase("[application/json")) { String err = se.getMessage(); renderJSON(err); } else { render("@Application.errorFront"); } } public static void test1() { try { int ka = 2 / 0; renderJSON(ka); } catch (Exception e) { throw new ServiceException(e, "数据格式错误"); } } }
这样,控制器中的捕获自定义异常的方法operateExp就能生效,打开浏览器,访问http://localhost:9001/testA,会发现页面被跳转到了定义好的错误页面
-
利用@With标签
-
使用@with注解增加更多拦截器
如果某个控制器是其他一些类的父类,那么该控制器中定义的所有拦截器会影响到所有子类。由于Java不允许多重继承,对单纯通过继承来使用拦截器造成了一定的局限性。Play可以通过@With注解,调用其他控制器中已经定义好的拦截方法,从而突破这一局限。
-
在TestExceptionController.java中,添加@With标签。@With标签只能添加在类上,不能添加在方法/构造器中
-
import play.mvc.With; @With(MyExceptionHandler.class) public class TestExceptionController extends BaseController { public static void test1() { try { int ka = 2 / 0; renderJSON(ka); } catch (Exception e) { throw new ServiceException(e, "数据格式错误"); } } }
通过添加了@With标签就可以调用到MyExceptionHandler中的处理异常的方法.
打开浏览器,输入同样地址,同样,页面也被跳转到了指定错误页面。。。
-
写的不是很详细,就大致说明了下思路。。。有空补上详细