首先先来讲讲上个章节的,修正了2个bug:1、自读字段不用disabled而是用readonly;2、修正了parseAttr默认值覆盖当前值的bug。
上个章节的效果图补在这:
这个章节,由于我考虑到的是,我在后台进行操作时可能需要给后台反馈许多信息,例如操作的成功与否、是否出现程序异常等,而这些信息都需要通过CtrlResult的实例返回,这样才能够正确的与我前台封装的控件挂上勾来。但是如果我们每次都手动的new一个CtrlResult的实例,然后去设置值,未免显得有些太粗糙了,在加上异常信息的处理,每次都去try catch之后再包裹信息,多烦啊。
因此,nutz默认为我们提供的json视图已经不能满足我的需求了。于是我用了nutz的自定义视图。我写的时候,其实只是把nutz源码中的json的视图拿过来做做修改而已。
我定义了两个视图(只贴主要部分):
public void render(HttpServletRequest req, HttpServletResponse resp, Object obj) throws IOException { if(obj!=null){//如果不为空 if(obj instanceof TPager) {//分页数据 CtrlResult cr = new CtrlResult(); cr.setValue(obj); Mvcs.write(resp, cr, format); }else {//直接返回当前数据。 Mvcs.write(resp, obj, format); } }else{//void形式时,返回提示信息“操作成功!” CtrlResult cr = new CtrlResult(); cr.setMsg("操作成功!"); Mvcs.write(resp, cr, format); } }
public void render(HttpServletRequest req, HttpServletResponse resp, Object obj) throws IOException { if(obj!=null){ CtrlResult cr = new CtrlResult(); if(obj instanceof RuntimeException){//运行时异常 cr.setMsgType(CtrlResult.MSG_TYPE_ERR); cr.setValue(obj); RuntimeException re = (RuntimeException) obj; cr.setMsg(re.getMessage()); }else{ cr.setMsgType(CtrlResult.MSG_TYPE_ERR); cr.setValue(obj); Exception re = (Exception) obj; cr.setMsg(re.getMessage()); } Mvcs.write(resp, cr, format); }else{ Mvcs.write(resp, data, format); } }
public View make(Ioc ioc, String type, String value) { type = type.toLowerCase(); if (VIEW_EXCEPTION.equals(type))//异常 if (Strings.isBlank(value)) return new ExceptionView(JsonFormat.compact()); else return new ExceptionView(Json.fromJson(JsonFormat.class, value)); else if (VIEW_SUCCESS.equals(type))//成功 if (Strings.isBlank(value)) return new SuccessView(JsonFormat.compact()); else return new SuccessView(Json.fromJson(JsonFormat.class, value)); return null; }
然后在MainModule中修改annotation配置:
@Modules(scanPackage=true) @Views(TViewMaker.class) @Ok("success") @Fail("exception") @IocBy(type=ComboIocProvider.class, args={ "*org.nutz.ioc.loader.json.JsonLoader", "cfg/ioc/", "*org.nutz.ioc.loader.annotation.AnnotationIocLoader", "com.tt" }) @SetupBy(value=TSetup.class) public class MainModule { }
这样,在成功情况下,我的ctrl可以不设置返回值,那么前台默认提示“操作成功!”
@At("/create") public void create(@Param("..")Curd curd){ //插入操作 }
如果返回值为TPager,我将视为分页数据,因此为自动为其包裹在CtrlResult实例中:
@At("/query4Page") public TPager query4Page(){ List<Curd> list = new ArrayList<Curd>(); for(int i = 0; i < 10; i++){ Curd curd = new Curd(i, "name" + i, "address" + i, i); list.add(curd); } return new TPager(list, list.size()); }
除以上情况,我将直接将对象返回给前台。
为了方便返回成功状态下的CtrlResult实例,在TUtils中封装了getOk方法。
当系统的提示信息一多时,如果用String写死在每段业务代码中的话,那么后期维护起来肯定会吐血的,所以建议要嘛通过配置文件管理,要嘛通过数据库管理。严禁直接写死在代码中(我目前在写的一些例子可能还是会出现直接写死的情况,1是做测试而已比较懒,你们不能学的哈;2、是为了写博客的时候方便大家直接了解意思,喷我吧~~)。至于是采用文件还是数据库,这个可能就要看具体的项目要求了,因此我定义了一个IMsgLoader接口:
/** * DESC:通过信息编码获取到对应的提示信息,并为占位符填充相应信息。 * @author Small * @Email [email protected] * @since 2013-5-20 * * @param msgCode * @param args * @return */ public String getMsg(String msgCode, Object... args);
默认的,我定义了一个通过properties文件配置消息码的,采用了ResourceBundle实现,具体代码我就不贴了。然后在cfg.ioc下面新增一个app.js,用来放置一些注入实例,在其中添加对IMsgLoader的注入:
msgLoader : { type : "com.tt.pub.msg.impl.MsgLoader4Prop" }
如果要切换实现方式,只需要在这个配置中改就可以了。
接着,我将msgLoader缓存在TCache中,设置的代码在TInit中实现。然后在TUtils中实现了getMsg方法,用于公共获取消息。这部分实现之后,我们就可以来设计一个属于自己的异常类了。
异常类我定义为MsgException:
public class MsgException extends RuntimeException { /** * */ private static final long serialVersionUID = 1L; /** 消息码 */ protected String msgCode = ""; /** 传参 */ protected Object[] args; /** * @param e 异常类 * @param msgCode 消息码 * @param args 传参 */ public MsgException(Throwable e, String msgCode, Object... args){ super(e); this.msgCode = msgCode; this.args = args; } /** * @param msgCode 消息码 * @param args 传参 */ public MsgException(String msgCode, Object... args){ this.msgCode = msgCode; this.args = args; } /** * Desc:获取消息。 * @author Small * @Email [email protected] * @since 2013-5-20 * * @return */ public String getMsg(){ return TUtils.getMsg(msgCode, args); } public String getMessage(){ return TUtils.getMsg(msgCode, args); } }其实也就是重写了getMessage方法,这时候就与ExceptionView中的内容相结合了。我们用这个异常类来返回我们的业务异常提示信息。
通常我们在进行一些业务操作时,会进行一些判断,如果判断不通过则终断并返回给前台信息。在没有这个异常类前,我们可能会这么处理:
public CtrlResult oper(){ //TODO 业务操作1 if(用户不存在) return 用户不存在 //TODO 业务操作2 return 成功 }但是这种操作会产生很多问题,代码量多时一回事,有时还得自己做事务回滚操作。
于是我们有了通过异常的解决方案:
public CtrlResult oper(){ //TODO 业务操作1 if(用户不存在) throw new MsgException("用户不存在"); //TODO 业务操作2 return 成功 }
如此,通过异常我们就可以很容易来操作了。但是这还不满我意。于是我在TUtils中定义了一个pass方法。当第一个参数为ture时表示通过,否则将抛出异常:
public static void pass(boolean judge, String msgCode, Object... args){ if(!judge){ throw new MsgException(msgCode, args); } }
获取你们会觉得有些多余,但这是我个人的习惯,觉得这样挺好理逻辑的,个人相对比较喜欢这样的代码:
public CtrlResult oper(){ //TODO 业务操作1 TUtils.pass(用户存在, "用户不存在"); //TODO 业务操作2 return 成功 }
当然,你有权不按我这么做,也可以喷我哈~~
至此,今天的内容就结束了。值得说的是,nutz的视图实在给力!
源码还是传不上去,明天传,睡觉去了,明天还得上班呢~~