????? Flex与服务器交互一般需要监听ResultEvent.RESULT事件和FaultEvent.FAULT事件。很多时候关注的是RESULT事件,FAULT事件在出现异常的情况下显得很有用。FAULT事件分为客户端和服务器端两大类。
????? 下图是一个客户端的错误信息,代码如下:
??????
- private function onFault(event:FaultEvent):void{?
- ??????????? Alert.show(event.toString());?
- }?
private function onFault(event:FaultEvent):void{
Alert.show(event.toString());
}
??????

???
?? 从弹出的信息中可以看出是因为amf的url地址不对造成的。
?? 下面来分析下FaultEvent对象。
??? FaultEvent对象的一个重要属性就是fault,Fault 类表示远程过程调用 (RPC) 服务调用中存在错误。
??? Fault的常用属性如下表:
???

????? 下面是服务器端的异常信息。
??????

???? 与客户端异常信息对比可以发现:客户端的faultCode以Client开头,服务器端的faultCode以Server开头。
???? 在java端可能用的比较多的异常处理类似于:new Exception("用户ID不能为空");这些异常是受检验的异常,用户很容易知道该如何办,但是如果抛出一个运行时异常,例如:java.lang.NullPointerException。用户就傻了,我改如何处理呢?是我操作有误还是系统出现问题了。业务用户现在能做的就是在bug系统上报一个bug。
???? 一个好的异常处理架构应遵循以下规则:
??? 1 任何异常都不会导致应用系统的崩溃。
??? 2 在发生异常时,允许应用程序进行相应的处理。
??? 3 显示给用户的错误信息要清晰的描述发生了什么错误以及应该采取什么样的处理。
??? 4 如果需要辅助信息,错误信息还要帮助用户与帮助部门交互,为帮助部门团队提供必要的信息, 使他们能够快速的容易的重现错误。
??? 5 日志信息能为开发团队人员在识别错误、在应用程序代码中定位错误产生的位置以及修正错误提供必要的信息。
??? 6 错误处理代码不会降低应用程序代码的可读性。我们经常在网上查询oracle错误代码的处理方法。????
?
?? 在来回顾下,Fault对象的faultCode、faultDetail、faultString、rootCause。可以根据错误代码(faultCode)让用户做不同的处理,当然系统也可以记录下一些重要的异常信息作为系统优化的依据,文本说明(faultString)表示那个字段不能为空等提示信息,详细错误信息(faultDetail)可以知道错误更详细的信息,那个类的那个方法发生了什么异常。堆栈信息(rootCause)可以让我们更加清晰的看到错误的堆栈信息。
?? 下面是一个很常用的异常信息提示框,点击详细信息的时候,开发人员可以很容易的定位异常。
??

??? 我们知道了客户端Fault对象的数据结构后,就需要知道java端如何将java.lang.Exception转化为Fault的。以下主要说的是blazeds。
??? flex.messaging.MessageException继承自LocalizedException,LocalizedException继承自RuntimeException。
???
????
- public class LocalizedException extends RuntimeException?
- {?
- ??? ?
- ??? protected transient ResourceLoader resourceLoader;?
- ??? ?
- ??? protected int number;?
- ??? ?
- ??? protected String message;?
- ??? ?
- ??? protected String details;?
- ??? ?
- ??? protected Throwable rootCause;?
- ?
- }?
public class LocalizedException extends RuntimeException
{
/** @exclude - transient,the resourceLoader for localized strings doesn't need to serialize. */
protected transient ResourceLoader resourceLoader;
/** @exclude */
protected int number;
/** @exclude */
protected String message;
/** @exclude */
protected String details;
/** @exclude */
protected Throwable rootCause;
}
? 可以很清晰的看到message对应Fault对象的faultString,details对应Fault对象的faultDetail,rootCause对应Fault对象的rootCause,number和Fault对象的code的对应还需要ResourceLoader从blazeds的errors.properties文件中加载相应的错误代码信息。例如:
?
- 10000=There was an unhandled failure on the server. {0}?
- 10001=Null endpoint id arrived on message.?
- 10002=No such endpoint: {0}?
- 10003=No configured channel has an endpoint path ''{0}''.?
- 10004=No destination with id ''{0}'' is registered with any service.?
- 10005=Destination ''{0}'' not accessible over channel ''{1}''.?
- 10006=Error occurred while attempting to convert an input argument''s type.?
- 10007=Cannot invoke method ''{0}''.?
- 10007-0-details=Method ''{0}'' not found.?
- 10007-1-details={0} arguments were sent but {1} were expected.?
- 10007-2-details=The expected argument types are ({0}) but the supplied types were ({1}) and converted to ({2}).?
- 10007-3-details=The expected argument types are ({0}) but the supplied types were ({1}) with none successfully converted.?
- 10007-4-details=The expected argument types are ({0}) but no arguments were provided.?
- 10007-5-details=No arguments were expected but the following types were supplied ({0}).?
- 10008=Cannot create class of type ''{0}''.?
- 10008-0-details=Type ''{0}'' not found.?
10000=There was an unhandled failure on the server. {0}
10001=Null endpoint id arrived on message.
10002=No such endpoint: {0}
10003=No configured channel has an endpoint path ''{0}''.
10004=No destination with id ''{0}'' is registered with any service.
10005=Destination ''{0}'' not accessible over channel ''{1}''.
10006=Error occurred while attempting to convert an input argument''s type.
10007=Cannot invoke method ''{0}''.
10007-0-details=Method ''{0}'' not found.
10007-1-details={0} arguments were sent but {1} were expected.
10007-2-details=The expected argument types are ({0}) but the supplied types were ({1}) and converted to ({2}).
10007-3-details=The expected argument types are ({0}) but the supplied types were ({1}) with none successfully converted.
10007-4-details=The expected argument types are ({0}) but no arguments were provided.
10007-5-details=No arguments were expected but the following types were supplied ({0}).
10008=Cannot create class of type ''{0}''.
10008-0-details=Type ''{0}'' not found.
将整个系统的异常进行分类是一个很难的事情,优秀的异常分类能让我们快速的定位错误发生的位置,该如何处理。
如果系统中用到了spring那么很容易的用ApplicationContext加载资源文件,从资源文件中获得相应code的值。
知道了以上的知识后,我们就可以很容易的实现flex的异常处理了,new出一个MessageException,设置messageException的各个属性就可以了。简单的代码如下;
- MessageException flex=new MessageException();?
- flex.setCode("错误代码");?
- flex.setMessage("我的测试数据");?
- flex.setDetails("详细信息");?
- flex.setRootCause(flex.getCause());?
- throw flex;?
MessageException flex=new MessageException();
flex.setCode("错误代码");
flex.setMessage("我的测试数据");
flex.setDetails("详细信息");
flex.setRootCause(flex.getCause());
throw flex;
如果你的系统用到了SPRING BLAZEDS INTEGRATION,那么请继续往下看。
我们的系统中也许有自己的异常处理类,不想每次抛出异常都是flex的MessageException,如果有一个转化器将会大大降低j2ee与blazeds的耦合度。
其实在SPRING BLAZEDS INTEGRATION中我们很容易实现异常信息转化。
配置如下:
- <bean id="sdpExceptionTranslator" class="org.sdp.flex.SdpExceptionTranslator"/>?
- ??? <flex:message-broker id="_messageBroker"?
- ??????? services-config-path="/WEB-INF/flex/services-config.xml">?
- ??????? ?
- ??????? <flex:exception-translator ref="sdpExceptionTranslator" />?
- ??? </flex:message-broker>?
<bean id="sdpExceptionTranslator" class="org.sdp.flex.SdpExceptionTranslator"/>
<flex:message-broker id="_messageBroker"
services-config-path="/WEB-INF/flex/services-config.xml">
<!-- 异常转化类 -->
<flex:exception-translator ref="sdpExceptionTranslator" />
</flex:message-broker>
exception-translator 属性定义了异常转化类的bean。该java只需要实现ExceptionTranslator 接口就可以了。handles方法判断要拦截的异常类,translate方法负责将一个java异常转化为blazeds异常。
- public class SdpExceptionTranslator implements ExceptionTranslator {?
- ?
- ????
-
- ?
- ??? public boolean handles(Class<?> clazz) {?
- ??????? ?
- ??????? return ClassUtils.isAssignable(SdpException.class,clazz);?
- ??? }?
- ?
- ???
-
- ?
- ??? public MessageException translate(Throwable t) {?
- ??????? if (t instanceof SdpException) {?
- ??????????? SdpException sdp=(SdpException) t;?
- ??????????? MessageException se = new MessageException();?
- ??????????? se.setCode(""+sdp.getNumber());?
- ??????????? se.setMessage(sdp.getMessage());?
- ??????????? se.setDetails(sdp.getDetails());?
- ??????????? se.setRootCause(t);?
- ??????????? return se;?
- ??????? }?
- ??????? return null;?
- ??? }?
- ?
- }?
public class SdpExceptionTranslator implements ExceptionTranslator {
/**
*
* {@inheritDoc}
*/
public boolean handles(Class<?> clazz) {
//判断要拦截的exception类型
return ClassUtils.isAssignable(SdpException.class,clazz);
}
/**
*
* {@inheritDoc}
*/
public MessageException translate(Throwable t) {
if (t instanceof SdpException) {
SdpException sdp=(SdpException) t;
MessageException se = new MessageException();
se.setCode(""+sdp.getNumber());
se.setMessage(sdp.getMessage());
se.setDetails(sdp.getDetails());
se.setRootCause(t);
return se;
}
return null;
}
}
?? 限于时间限制,flex异常就先写到这里,有什么疑问可以给我留言。以后我会将自己的flex4+blazeds4+SPRING BLAZEDS INTEGRATION1.5+spring开发平台贡献出来,当然里面有更加详细的异常处理方法了,请大家多多关注我的博客。