webx—错误信息提示

一、底层异常

严格来讲,一个系统通常是有服务端和客户端之分,当然通俗来讲也可说成是上层部分和底层部分

但无论怎么讲,层与层之间、端与端之间少不了交互,交互通常是可以拿到数据或正常完成操作,但有时也未必(例如:传入的帐号不存在,插入数据库不成功等),这时底层模块就要做一些特殊提示。通常,在系统中我们会自定义一些异常,也就是基于这个原因。

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—错误信息提示_第1张图片

上图是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);

    }

}
结果:

抱歉,系统繁忙,请稍后重试!


你可能感兴趣的:(ClassLoader,properties,String,Stream,velocity,null)