一、底层异常
严格来讲,一个系统通常是有服务端和客户端之分,当然通俗来讲也可说成是上层部分和底层部分
但无论怎么讲,层与层之间、端与端之间少不了交互,交互通常是可以拿到数据或正常完成操作,但有时也未必(例如:传入的帐号不存在,插入数据库不成功等),这时底层模块就要做一些特殊提示。通常,在系统中我们会自定义一些异常,也就是基于这个原因。
public class ServiceException extends Exception {
// 错误码
private ErrorCodeEnum errorCode;
// 错误信息
private String errorMessage;
public ServiceException(){
}
}
其中ErrorCodeEnum是一个枚举类,作用相当一个数据字典,所有的异常信息都会在里面预定义,当程序运行时,如果抛出一个ServiceException实例,里面会具体封装一个异常信息。
errorMessage就比较简单,里面会有针对性封装一些错误提示信息,类似于备注的性质,可理解为错误码的补充
注意:该 异常信息通常是由底层代码定义并抛出,而上层代码及调用方则在调用接口或方法时,对这些异常捕获,并根据异常的类型,有针对性的错误提示,当然该错误提示更多 是用户可以直接阅读的。
二、上层错误信息
表现方式:
1> 增加错误页面。上层端调用时,如果捕获取了异常,可以考虑内部或者外部重定向到错误页面,友好提示。该方式的适用面较广,可以直接错误信息提示(如:抱歉,系统繁忙,请稍后再试);也可以引导性提示,(如:当前帐号没有绑定支付宝,并且下方提供绑定的超链接)
2> 表单的错误提示。当用户添写了表单并点击提交按钮时,后台通常会首先进行表单字段校验,对于不满足条件的字段,会记录预定义的Message错误信息,只要有一个字段校验不过,整个表单都认为是不过,会返回到提交页面,并在对应字段的下方或右方错误提示。
这种方式还是挺常见的,但有一个前提,必须是有表单提交
3> 纯错误信息提示。错误信息只有一个字段,通常是String类型,并且在页面会有编码,加载页面时通过判读是否为空,决定其是否显示。
该方式比较灵活,适用在页面的任何位置。通常是作为表单校验的补充,比如表单校验通过后,后面有一个插入数据库的操作,此时如果插入失败,便会给此errorMsg赋值,不进行页面跳转,而返回当前页面,且在指定位置错误提示。
实例步骤:
3.1 客户端发起http请求到服务端,server接收请求,进行screen类渲染,将数据存入context,由velocity引擎merge出一个页面输出流,传给client,再由浏览器解析出一个可视化页面
3.2 用户填写表单信息,提交,由后台的Action类处理,在操作过程中由于异常中断(假设操作成功后会重定向),将错误信息存入context
3.3 然后根据提交前Form表单中的action属性值,以及3.2发起的request请求信息由对应的screen类重新渲染页面,界面与3.1基本相同(数据与表单提交前一样),但是在指定位置会显示第二步的错误信息
3.4 用户可以再一次提交表单,操作同3.2
这种错误提示的适用面相当广,本文将重点介绍。
上图是webx框架下加载错误信息的类图 ,重点是ResultCode和ResultCode.xml,具体可参阅源码。
由于该错误信息可能涉及不同语言,所以还引入了国际资源化
>>Locale 表示特定的地理、政治和文化地区。显示一个数值就是语言环境敏感的操作,应该根据用户的国家、地区或文化的风俗/传统来格式化该数值。
构造方法:
Locale(String language)
Locale(String language, String country)
Locale(String language, String country, String variant)
>>ResourceBundle本质上和Properties一样也是一个映射,都是以键值对的形式保存信息,但是其显得更加灵活,当调用ResourceBundle res=ResourceBu
ndle.getBundle("area", Locale.CHINA);
String input= res.getString("25");
由于webx框架支持国际资源化,涉及的类较多,里面的信息加载也较复杂,为了便于学习和局部借鉴,我将错误提示相关代码从webx框架剥离出来。
定义一个错误枚举类
public enum MessageResultCode {
/**
* 该产品需供应商授权才可在线订购,请先申请授权!
*/
PRIVATE_NO_AUTH,
/**
* 抱歉,系统繁忙,请稍后重试!
*/
SYSTEM_ERROR;
}
定义错误提示信息。特别注意message标签的id值要与上面的枚举变量值保持一致
<?xml version="1.0" encoding="GB2312"?>
<resource-bundle name="MessageResultCode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<message id="PRIVATE_NO_AUTH">
<data><![CDATA[该产品需供应商授权才可在线订购,请先申请授权!]]></data>
</message>
<message id="SYSTEM_ERROR">
<data><![CDATA[抱歉,系统繁忙,请稍后重试!]]></data>
</message>
</resource-bundle>
配置文件加载及获取提示信息
/**
* 类TF.java的实现描述:错误信息提示
*
* @author onlyone 2012-6-6 下午10:07:49
*/
public class TF {
// 类加载器
private ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
/**
* 获取错误提示文件路径
*
* @param bundleName
* @return
*/
protected String getFilename(String bundleName) {
return bundleName.replace('.', '/') + ".xml";
}
/**
* 取的文件的读入流
*
* @param bundleFilename
* @return
*/
public InputStream openStream(final String bundleFilename) {
URL url = classLoader.getResource(bundleFilename);
// 如果资源不存在, 则返回null
if (url == null) {
return null;
}
try {
return url.openStream();
} catch (IOException e) {
// TODO log
e.printStackTrace();
}
return null;
}
/**
* 以XML格式解析输入流, 并创建<code>ResourceBundle
*
* @param stream
* @param systemId
* @return
*/
protected ResourceBundle parse(InputStream stream, String systemId) {
try {
ResourceBundle resourceBundle;
SAXReader reader = new SAXReader();
Document doc = reader.read(stream, systemId);
resourceBundle = new XMLResourceBundle(doc);
return resourceBundle;
} catch (DocumentException e) {
} catch (ResourceBundleCreateException e) {
// TODO log
e.printStackTrace();
}
return null;
}
/**
* 从ResourceBundle中提取错误提示
*
* @param bundle
* @param key
* @return
*/
public static String getMessage(ResourceBundle bundle, String key) {
if ((bundle == null) || (key == null)) {
return key;
}
try {
String message = bundle.getString(key);
return message;
} catch (MissingResourceException e) {
// TODO log
return "";
}
}
public static void main(String[] args) {
MessageResultCode pr = MessageResultCode.SYSTEM_ERROR;
String file = pr.getClass().getName();
String key = ();
TF tf = new TF();
String fileName = tf.getFilename(file);
InputStream is = tf.openStream(fileName);
ResourceBundle rb = tf.parse(is, null);
String result = tf.getMessage(rb, key);
System.out.println(result);
}
}
结果:
抱歉,系统繁忙,请稍后重试!