一、底层异常
严格来讲,一个系统通常是有服务端和客户端之分,当然通俗来讲也可说成是上层部分和底层部分
但无论怎么讲,层与层之间、端与端之间少不了交互,交互通常是可以拿到数据或正常完成操作,但有时也未必(例如:传入的帐号不存在,插入数据库不成功等),这时底层模块就要做一些特殊提示。通常,在系统中我们会自定义一些异常,也就是基于这个原因。
public class ServiceException extends Exception { // 错误码 private ErrorCodeEnum errorCode; // 错误信息 private String errorMessage; public 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=ResourceBundle.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 = pr.name(); 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); } }结果:
抱歉,系统繁忙,请稍后重试!