假设有这样一个业务逻辑,用户登录时需要输入:用户名、密码、邮箱地址、真实姓名等信息,通过验证后才算登录成功,
而且当验证失败后,要提示用户是哪一项错了。如:
1、当用户名错误,则提示“用户名错误”,或页面是显示一张用户名错误的图片,而不是单单个文字信息
2、当邮箱地十与真实姓名错误时,要提示用户“邮箱地址和真实姓名错误”,或显示一张特殊图片
3、当密码错误时,要提示“密码错误”
等等情况
public class User {
private String loginName;
private String password;
private String email;
private String realName;

...
}public class UserServiceImpl implements UserService {

// 下面这个方法要怎么声明与实现?
public User login(User user) {
// do something
}
}
1、如果是每一个业务处理结果抛出一个指定异常,那一个项目中必定会出现数不清的异常,而且这些异常也只是继承了RuntimeException,没什么特别用处2、如果将所有的业务逻辑异常封装成BusinessException,然后处理业务逻辑结果时,throw new BusinessException("用户名错误")或throw new BusinessException("密码错误"),那么上层调用程序又怎么样知道是哪种错误?(需要根据错误来做特殊显示)
3、难道要设计成public int login(User user),然后根据返回int值不同判断?这又怎样面向对象了?而且又如何提取用户的信息放到session中?我想说的是怎样设计一个业务逻辑中有多个结果出现的接口请求高手指点!!谢谢!!

解决方案 »

  1.   

     // 下面这个方法要怎么声明与实现?
        public User login(User user) {
            // do something
        }那至少要改成一个可以标识的吧可以改成 public int login(User user) {
         //查询数据库
    }1、当用户名错误,则提示“用户名错误”,或页面是显示一张用户名错误的图片,而不是单单个文字信息 
    2、当邮箱地十与真实姓名错误时,要提示用户“邮箱地址和真实姓名错误”,或显示一张特殊图片 
    3、当密码错误时,要提示“密码错误” 
    如果无错返回0
     如果用户名错误,则返回1
    当邮箱地与真实姓名错误时 则返回2当密码错误时,返回3而提示信息你可以根据返回的值(1,2,3)来判断给什么提示信息就可以了
      

  2.   

    楼主学struts没有?如果你,只是客户端验证,js就ok。如果是要服务器端验证,struts不管是1.x 还是2.x都我完整的验证。
      

  3.   

    可以先声明异常呀 用 throws 
      

  4.   

    2楼与4楼,我现在是不用ajax验证,是要在业务层做判断,再加上使用ajax判断的话,也不可能根据做错误做不同特效,假如我页面是采用flash或flex呢?
    3楼,这个返回int值判断,那不就要判断N次?就假设五个问题要验证来说就有
    C5取1+C5取2+C5取3+C5取4+C5取5种情况,以后扩展了,又要继续增加判断
      

  5.   

    关于异常,自定义异常吧。。写一个checkUser的方法,返回一个boolean 类型。(检查用户输入的登录信息是否正确)
    public boolean login(User user) {
         ……………
         ……………
         if(checkUser) {     }else {
             throw "自定义异常,用户名或密码错误"
         }
    }以此推类,应用层谁调用该方法谁就捕获相应异常。给出相应操作try catch 可以多个catch块吧。
      

  6.   

    这个问题问的很好啊,涉及到异常设计,转一篇文章楼主看看,要是对异常设计有什么新理解的话可以大家一起讨论一下http://www.blogjava.net/bonny/archive/2007/05/11/116747.html
      

  7.   

     js,dwr,jquery,struts验证框架validator
      

  8.   

    是不是我题目中说不不清楚呢?我在这里再描述下:假设有这样一个业务逻辑,用户登录时需要输入:用户名、密码、邮箱地址、真实姓名等信息(以后的系统中可能还要增加更多更多的验证信息,如性别、登录保护问题等等),要全部通过验证后才算登录成功, 
    否则要根据不同的错误提示特殊的信息(如播放一小段flash动画,或显示一个特殊图片),而不是单纯的在网页上显示错误信息。(反正就是上层调用程序要根据业务逻辑错误作不同的动作)如: 
    1、当用户名错误,则提示“用户名错误”,或页面是显示一张用户名错误的图片,而不是单单个文字信息 
    2、当邮箱地十与真实姓名错误时,要提示用户“邮箱地址和真实姓名错误”,或显示一张特殊图片 
    3、当密码错误时,要提示“密码错误” 
    等等情况 /**
     * 用户类
     * @author 
     *
     */
    public class User {
        private String loginName;
        private String password;
        private String email;
        private String realName;
        
        // constructors
        // setters and getters
        // methods
    }/**
     * 用户业务逻辑具体实现类
     * @author 
     *
     */
    public class UserServiceImpl implements UserService {    
        // 下面这个方法要怎么声明与实现?
        public User login(User user) {
            // do something
        }
        
        // others methods
    }
    我想到的方案有几下几种:
    1、为每一个业务逻辑错误定义一个unchecked Exception。如下代码:
    /**
     * 用户业务逻辑具体实现类
     * @author 
     *
     */
    public class UserServiceImpl implements UserService { 
        public User login(User user) {
            if (用户名验证失败) {
             throw new UserNameIncorrectException();
            }
            if (密码错误) {
             throw new PasswordIncorrectException();
            }        
            if (邮箱地址错误) {
             throw new EmailIncorrectException();
            }        
            if (真实姓名错误) {
             throw new RealNameIncorrectException();
            }
            // ...等等
            return user;
        }
        
        // others methods
    }这里UserNameIncorrectException、PasswordIncorrectException、EmailIncorrectException、RealNameIncorrectException都继承RuntimeException上层调用程序public class Controller {
    public void login() {
    try {
    User u = userServiceImpl.login(user);
    session.setAttrebute("LoginUser", u);
    } catch (UserNameIncorrectException ex) {
    // 做特殊的处理
    } catch (PasswordIncorrectException ex) {
    // 做特殊的处理
    } catch (EmailIncorrectException ex) {
    // 做特殊的处理
    } catch {RealNameIncorrectException ex) {
    // 做特殊的处理
    }
    }
    }但这样的话,会使项目中存在N多异常类(所谓的类爆炸),而这些异常类除了指定是哪个业务逻辑错误外,没其他用处
    2、将所有业务错误封装到BusinessException,错误信息封装作为BusinessException的异常信息,然后在上层调用时,直接捕获BusinessException,将其信息显示在页面上。(我在做J2EE开发时就是这样做的)。代码如下/**
     * 用户业务逻辑具体实现类
     * @author 
     *
     */
    public class UserServiceImpl implements UserService { 
        public User login(User user) {
            if (用户名验证失败) {
             throw new BusinessException("用户名错误");
            }
            if (密码错误) {
             throw new BusinessException("密码错误");
            }        
            if (邮箱地址错误) {
             throw new BusinessException("邮箱地址错误");
            }        
            if (真实姓名错误) {
             throw new BusinessException("真实姓名错误");
            }
            // ...等等
        }
        
        // others methods
    }这里BusinessException继承自RuntimeException,为所有业务错误的异常封装类上层调用程序public class Controller {
    public void login() {
    try {
    User u = userServiceImpl.login(user);
    session.setAttrebute("LoginUser", u);
    } catch (BusinessException ex) {
    // 将ex.getMessage()显示到页面上
    }
    }
    }但是这样的话,就不可以做特殊效果了,如“用户名错误”逻辑中,我要显示一个flash动画,而不是单纯的“用户名错误”信息;又或者我要显示“用户名验证失败”
    3、将login方法原型设置为:public int login(User user),然后根据每个逻辑错误,返回不同的值。如下代码/**
     * 用户业务逻辑具体实现类
     * @author 
     *
     */
    public class UserServiceImpl implements UserService { 
        public int login(User user) {
            if (用户名验证失败) {
             return 1;
            }
            if (密码错误) {
             return 2;
            }        
            if (邮箱地址错误) {
             return 3;
            }        
            if (真实姓名错误) {
             return 4;
            }
            // ...等等
            
            // 正确时, return 0
            return 0;
        }
        
        // others methods
    }这里BusinessException继承自RuntimeException,为所有业务错误的异常封装类上层调用程序public class Controller {
    public void login() {
    int result = userServiceImpl.login(user);
    if (result == 0) {
    //  登录成功,做特殊处理
    } else if (result == 1) {
    //  用户名验证失败,做特殊处理
    } else if (result == 2) {
    //  密码错误,做特殊处理
    } else if (result == 3) {
    //  邮箱地址错误,做特殊处理
    } else if (result == 4) {
    //  真实姓名错误,做特殊处理
    }
    // else if (result == 5) {
        // }

    session.setAttrebute("LoginUser", ???); // 这里又要保存什么?
    }
    }这样做的话,可以解决当前问题,但像别人说的那样,不面向对象了,对以后系统扩展也不好
    4、login()方法的返回类型设为Map<Integer, List<Integer>,如下所示/**
     * 用户业务逻辑具体实现类
     * @author 
     *
     */
    public class UserServiceImpl implements UserService {    
        /**
         * 
         * @param user
         * @return Map<Integer, List<Integer>>,结构说明:
         *         键 值
         *         1 验证通过的列表
         *         2 验证失败的列表
         *         
         *         List<Integer>结构说明:保存需要验证的问题
         *         1-用户名 2-密码 3-邮箱地址 4-真实姓名 等等
         */
        public Map<Integer, List<Integer>> login(User user) {
         Map<Integer, List<Integer>> map = new HashMap<Integer, List<Integer>>();
         List<Integer> passedArray = new ArrayList<Integer>();
         List<Integer> failArray = new ArrayList<Integer>();
         passedArray.add(new Integer(1));
         passedArray.add(new Integer(2));
         passedArray.add(new Integer(3));
         passedArray.add(new Integer(4));
        
            if (用户名验证失败) {
             failArray.add(new Integer(1));
             passedArray.remove(new Integer(1));
            }
            if (密码错误) {
             failArray.add(new Integer(2));
             passedArray.remove(new Integer(2));
            }        
            if (邮箱地址错误) {
             failArray.add(new Integer(3));
             passedArray.remove(new Integer(3));
            }        
            if (真实姓名错误) {
             failArray.add(new Integer(4));
             passedArray.remove(new Integer(4));
            }
            // ...等等
            
            return amp;
        }
        
        // others methods
    }
    上层调用程序public class Controller {
    public void login() {
    Map<Integer, List<Integer>> map = userServiceImpl.login(user);
    if (map.size() == 0) {
    //  登录成功,做特殊处理
    } else {
    // 验证通过的列表
    if (map.contains(new Integer(1))) {
    Iterator iterator = map.get(new Integer(1)).values.iterator();
    while (iteraotr.hasNext()) {
    Integer i = iterator.next();
    if (i == 1) {
    // do something
    } else if (i == 2) {
    // do something
    } else if (i == 3) {
    // do something
    } else if (i == 4) {
    // do something
    }
    }
    }

    // 验证失败的列表
    if (map.contains(new Integer(2))) {
    Iterator iterator = map.get(new Integer(2)).values.iterator();
    while (iteraotr.hasNext()) {
    Integer i = iterator.next();
    if (i == 1) {
    //  用户名验证失败,做特殊处理
    } else if (i == 2) {
    //  密码错误,做特殊处理
    } else if (i == 3) {
    //  邮箱地址错误,做特殊处理
    } else if (i == 4) {
    //  真实姓名错误,做特殊处理
    }
    }
    }
    }

    session.setAttrebute("LoginUser", ???); // 这里又要保存什么?
    }
    }这样做的话,不仅可以解决当前问题,还可以获取验证通过的项,不过大家看起来都觉得,好辛苦,太复杂了,对以后扩展也不好在现实在也经常出现这种有多种业务逻辑错误的时候,我是个菜菜还望高手给出个好的解决方案,谢谢
      

  9.   

    遇到过类似情况。用的方法和楼主上面的第二种方案类似。不同的是那个BusinessException("密码错误")的constructor的参数不是String而是自己定义的枚举。这样上层代码可用switch来操作这个枚举。
      

  10.   

    看来LZ没有用到Struts
    如果是Struts服务端有validator
    客户端有JS
    自己写也是一样
    差不多就是那样了
      

  11.   

    自定义错误的话,也完全可以,抛出一个固定的code,根据这个号区资源文件查找对应的错误消息。
      

  12.   

    写一个  propertie 文件 ,有 code 与 error message 的mapping, 还有一个ErrorCodeMapper
    的类, 在这个类中作 ErrorMapping 的工作, 这样每次新增加error类型的时候只要添加 这个properties文件就可以 ,和修改 code 的地方
      

  13.   

    OK,谢谢大家的对这个问题的探讨,我现在总结出了最后处理方法,如下:业务逻辑异常类:/**
     * 项目中业务逻辑错误封装类。当处理业务逻辑出现错误时,将错误代码封装到该Runtime异常类中,错误代码被封装至enum枚举类中。
     * 
     * @version 1.0 2009-08-31
     * @author 2zc
     */
    public class BusinessException extends RuntimeException {
    private static final long serialVersionUID = -3202020199818916364L;

    /* fields */
    private Enum<?> errorCode;

    /* constructors */
    /**
     * 构造一个指定业务逻辑代码的RuntimeException
     * 
     * @param errorCode
     */
    public BusinessException(Enum<?> errorCode) {
    this.errorCode = errorCode;
    } /* setters and getters */
    /**
     * 返回业务逻辑错误代码
     * 
     * @return 业务逻辑错误代码
     */
    public Enum<?> getErrorCode() {
    return errorCode;
    }
    }
    用户业务逻辑错误代码枚举类/**
     * 用户业务逻辑错误代码枚举类,包括了处理用户业务逻辑时出现的错误对应的代码
     * 
     * @version 1.0 2009-08-31
     * @author 2zc
     *
     */
    public enum BusinessUserErrorCode {
    LOGINNAMEINCORRECT(10), /* 用户名错误 */
    PASSWORDINCORRECT(11), /* 密码错误 */
    EMAILINCORRECT(12), /* Email地址错误 */
    REALNAMEINCORRECT(13), /* 真实姓名错误 */

    LOGINNAMEALREADYEXISTS(16); /* 用户名已经存在 */
    // ...

    /* 存放枚举的序号 */
    private int code;

    /*  构造指定序号的枚举 */
    private BusinessUserErrorCode(int code) {
    this.code = code;
    }

    /**
     * 返回枚举的序号
     */
    @Override
        public String toString(){
            return String.valueOf(code);
        }
    }可以将该类中的枚举作为错误名称,枚举的序号作为错误代码,与xml资源文件关联起来,如下所示:<business-error-mapping>
    <business-error>
    <business-error-code>10</business-error-code>
    <business-error-name>LOGINNAMEINCORRECT</business-error-name>
    <business-error-message>用户名错误</business-error-message>
    </buciness-error>
    <business-error>
    <business-error-code>11</business-error-code>
    <business-error-name>PASSWORDINCORRECT</business-error-name>
    <business-error-message>密码错误</business-error-message>
    </buciness-error>
    <business-error>
    <business-error-code>12</business-error-code>
    <business-error-name>EMAILINCORRECT/business-error-name>
    <business-error-message>Email地址错误</business-error-message>
    </buciness-error>
    <business-error>
    <business-error-code>13</business-error-code>
    <business-error-name>REALNAMEINCORRECT</business-error-name>
    <business-error-message>真实姓名错误</business-error-message>
    </buciness-error>
    <business-error>
    <business-error-code>16</business-error-code>
    <business-error-name>LOGINNAMEALREADYEXISTS</business-error-name>
    <business-error-message>用户名已经存在</business-error-message>
    </buciness-error>
    </business-error-mapping>在上层程序中根据error-code读出现xml文件中的提示信息用户业务逻辑具体实现类/**
     * 用户业务逻辑具体实现类
     * @author 
     *
     */
    public class UserServiceImpl implements UserService { 
        public User login(User user) {
            if (用户名验证失败) {
                throw new BusinessException(BusinessUserErrorCode.LOGINNAMEINCORRECT);
            }
            if (密码错误) {
                throw new BusinessException(BusinessUserErrorCode.PASSWORDINCORRECT);
            }        
            if (邮箱地址错误) {
                throw new BusinessException(BusinessUserErrorCode.EMAILINCORRECT);
            }        
            if (真实姓名错误) {
                throw new BusinessException(BusinessUserErrorCode.REALNAMEINCORRECT);
            }
            // ...等等
        }
        
        // others methods
    }
    上层调用程序:public class Controller {
        public void login() {
    try {
                            User u = userServiceImpl.login(user);
                            session.setAttrebute("LoginUser", u);
    } catch (BusinessException ex) {
    switch ((BusinessUserErrorCode) ex.getErrorCode()) {
    case LOGINNAMEINCORRECT:
    /* do something */
    break;
    case PASSWORDINCORRECT:
    /* do something */
    break;
    case EMAILINCORRECT:
    /* do something */
    break;
    case REALNAMEINCORRECT:
    /* do something */
    break;
    }
    }
    }
    }如果有什么建议,可以继续讨论,谢谢.现在先结贴!