钢炮级 持久层 —— 中篇 博客分类: 持久层 javaVO实体类代码自动生成
程序员文章站
2024-02-12 15:47:10
...
Title:VO的封装
我在上一篇博客(http://tan4836128.iteye.com/blog/1152147)介绍了一个小型的持久层处理类,一个可以兼容各类数据操作的方法。其中最主要的方法,就是构建各类数据操作的SQL,和解析查询结果并返回的数据集合。本文主要针对这个解析后返回的数据集合,做实体类与之耦合的需求进行讨论。
为了实现自动化匹配,我设置几个对VO类编码的基本要求:
1. 数据库表理论上对应一个实体类VO,表中每一个字段都能在VO中找到对应变量,附带表名、字段名、主键名等各返回名称的方法。
2. 实体类VO应针对表中每一个字段,都提供一个返回字段名称的方法,这个用于自动匹配查询返回的数据集合(因为,在返回的数据集中对表字段名做了记录)。
3. 为了方便阅读,VO类中方法、变量应有足够的注释
为了不再重复对VO进行编码,我设计了一个生成实体类代码的小程序,这个程序辅助我设计实体类VO,它本身并不是持久层的一部分。但是由它(按照一定规范和要求)生成的实体类VO是持久层的重要数据传输对象,由这些VO搭建起跟执行查询后返回的数据集的耦合关系。
首先看一个生成出来的VO类,Role.java
该类包含字段对应的变量、表名和表字段名称以及主键名称的返回方法,这些都是通过读取数据库自动生成的,包括数据类型、字段注释等,再看表结构,如下:
注:没有对get/set方法做自动生成,Eclipse有这功能,so...
好,现在VO类有了,再看看怎样与查询得到的数据集合自动装配,先看代码:
得到SQL:
我们先到数据库里查询一下看看情况:
有图才有真相:
到此,就可以返回这个List<Role>对象了,传递到表示层该怎么读取就怎么读,数据从数据库,经持久层封装,再到VO封装出来,这个流程其实很简单,有了固定的持久不变的持久层API,有了可以自动生成VO的小程序,一下子模型层,持久层代码都不用关心,你只需要分析需求、设计好表结构,其他的就剩下表示层的业务逻辑了。
另外,VO类中还有getPrimaryKey,getPrimaryKeyValue,setPrimaryKeyValue等方法,这些方法用于数据的删除和修改操作,用起来也很简单,比如删除:
新增或修改数据,如下:
总结,实体类的自动装配跟VO类的映射就需要有这样高耦合度,为满足数据传输,这是必须的。VO类中设置getTableName、getPrimaryKey等方法能够参与业务逻辑,给编码带来的好处还是有的,起码在需要获取主键值得时候,你不再需要关心某张表的主键到底是谁,而直接拿来就用。当然也有问题,这些问题都可以通过建单扩展既可以解决,比如:
1. 多主键的处理,返回数组
2. (多)外键的处理,返回数组
3. VO中加入表索引信息
同前一篇一样,这样的思路也只是基于一些简单的小型项目,应用到大项目中,需要不停的扩展VO的功能,比如加入索引,在业务逻辑层面,你可以通过指定索引,直接优化一些大型的、复杂的SQL查询,提升效率,当然,这就要求前一篇中PublicDao类的createSql方法更高了,实现也更复杂了。
最后,附上我自己写的一个VO类的代码生成类。
文中有任何大小问题,请各位不吝赐教,我会在日后继续改进。
我在上一篇博客(http://tan4836128.iteye.com/blog/1152147)介绍了一个小型的持久层处理类,一个可以兼容各类数据操作的方法。其中最主要的方法,就是构建各类数据操作的SQL,和解析查询结果并返回的数据集合。本文主要针对这个解析后返回的数据集合,做实体类与之耦合的需求进行讨论。
为了实现自动化匹配,我设置几个对VO类编码的基本要求:
1. 数据库表理论上对应一个实体类VO,表中每一个字段都能在VO中找到对应变量,附带表名、字段名、主键名等各返回名称的方法。
2. 实体类VO应针对表中每一个字段,都提供一个返回字段名称的方法,这个用于自动匹配查询返回的数据集合(因为,在返回的数据集中对表字段名做了记录)。
3. 为了方便阅读,VO类中方法、变量应有足够的注释
为了不再重复对VO进行编码,我设计了一个生成实体类代码的小程序,这个程序辅助我设计实体类VO,它本身并不是持久层的一部分。但是由它(按照一定规范和要求)生成的实体类VO是持久层的重要数据传输对象,由这些VO搭建起跟执行查询后返回的数据集的耦合关系。
首先看一个生成出来的VO类,Role.java
package com.accout.role.pojo; /*** * 角色 * @author db2admin * 2010-12-23 */ public class Role implements java.io.Serializable { /**角色ID*/ private int RoleId; /**角色名称*/ private String RoleName; /**角色等级:1为普通员工、2为经理用户、3为系统管理员*/ private String RoleLevel; /**角色资源,当前角色对应的浏览权限*/ private String RoleResource; /***/ private String Remark; /*** * 字段代理方法:role_id * 角色ID * @return */ public static String RoleId(){ return "role_id"; } /*** * 字段代理方法:role_name * 角色名称 * @return */ public static String RoleName(){ return "role_name"; } /*** * 字段代理方法:role_level * 角色等级:1为普通员工、2为经理用户、3为系统管理员 * @return */ public static String RoleLevel(){ return "role_level"; } /*** * 字段代理方法:role_resource * 角色资源,当前角色对应的浏览权限 * @return */ public static String RoleResource(){ return "role_resource"; } /*** * 字段代理方法:remark * * @return */ public static String Remark(){ return "remark"; } /*** * 实体类对应表:role * @return */ public static String getTableName(){ return "role"; } /*** * 表主键:role_id * @return */ public String getPrimaryKey(){ return "role_id"; }/*** * 设置主键值:RoleId * @return */ public void setPrimaryKeyValue(int value){ this.RoleId = value; }/*** * 获取主键值:RoleId * @return */ public int getPrimaryKeyValue(){ return this.RoleId; } }
该类包含字段对应的变量、表名和表字段名称以及主键名称的返回方法,这些都是通过读取数据库自动生成的,包括数据类型、字段注释等,再看表结构,如下:
注:没有对get/set方法做自动生成,Eclipse有这功能,so...
好,现在VO类有了,再看看怎样与查询得到的数据集合自动装配,先看代码:
public static void main(String[] args) { PublicDao dao = new PublicDao(); Map<Object, String> mk = new HashMap<Object, String>(); Map<Object, Object> mv = new HashMap<Object, Object>(); //设置要查询的列 mk.put(1, Role.RoleId()); mk.put(2, Role.RoleLevel()); mk.put(3, Role.RoleName()); mk.put(4, Role.RoleResource()); mk.put(5, Role.Remark()); /**单表查询测试*/ String sql = dao.createSql(PublicDao.SELECT, Role.getTableName(), mk, mv, ""); System.out.println(sql); List list = dao.executeSql(PublicDao.SELECT, sql); }
得到SQL:
select role_id,role_level,role_name,role_resource,remark from role
我们先到数据库里查询一下看看情况:
//执行查询之后,list中就有3条数据了,接下来遍历list,取出数据 List list = dao.executeSql(PublicDao.SELECT, sql); //用于封装并返回数据的集合对象 List<Role> list_t = new ArrayList<Role>(); //取出列名Map Map mk_n = (Map) list.get(0); //取出每一行数据 List list_mv = (List) list.get(1); //封装的对象 Role role = null; for(int i=0;i<list_mv.size();i++){ Map mv_n = (Map) list_mv.get(i); //这里每循环一次代表每一行数据,即一个对象 role = new Role(); for(int j=1;j<=mk_n.size();j++){ Object temp = mv_n.get(mk_n.get(j)); if(Role.RoleId().equals(mk_n.get(j))){ role.setRoleId(temp==null?null:(Integer)temp); } if(Role.RoleName().equals(mk_n.get(j))){ role.setRoleName(temp==null?"":temp.toString()); } if(Role.RoleResource().equals(mk_n.get(j))){ role.setRoleResource(temp==null?"":temp.toString()); } if(Role.RoleLevel().equals(mk_n.get(j))){ role.setRoleLevel(temp==null?"":temp.toString()); } } list_t.add(role); }
有图才有真相:
到此,就可以返回这个List<Role>对象了,传递到表示层该怎么读取就怎么读,数据从数据库,经持久层封装,再到VO封装出来,这个流程其实很简单,有了固定的持久不变的持久层API,有了可以自动生成VO的小程序,一下子模型层,持久层代码都不用关心,你只需要分析需求、设计好表结构,其他的就剩下表示层的业务逻辑了。
另外,VO类中还有getPrimaryKey,getPrimaryKeyValue,setPrimaryKeyValue等方法,这些方法用于数据的删除和修改操作,用起来也很简单,比如删除:
/*** * 如果使用Struts 1.x,这里的keyId可以直接通过request.getParameter()方法获取,不需要传递参数 * 当然,方法就应该改为 * public ActionForward deleteRole(ActionMapping mapping, ActionForm form, * HttpServletRequest request, HttpServletResponse response){。。。} * @param keyId */ public void deleteRole(String keyId){ Map<Object,String> mk = new HashMap<Object,String>(); Map<Object,Object> mv = new HashMap<Object,Object>(); //设置主键、主键值 mk.put(1, Role.getPrimaryKey()); //request.getParameter("keyId") mv.put(mk.get(1), "="+keyId); PublicDao dao = new PublicDao(); String sql = dao.createSql(PublicDao.DELETE, Role.getTableName(), mk, mv, ""); dao.executeSql(PublicDao.DELETE, sql); }
新增或修改数据,如下:
/*** * 这里的type、Role对象封装的值,可以直接通过request.getParameter()方法获取,不需要传递这两个参数 * 当然,方法就应该改为 * public ActionForward addAndUpdateRole(ActionMapping mapping, ActionForm form, * HttpServletRequest request, HttpServletResponse response){。。。} * @param type * @param role */ public void addAndUpdateRole(String type, Role role){ Map<Object,String> mk = new HashMap<Object,String>(); Map<Object,Object> mv = new HashMap<Object,Object>(); mk.put(1, Role.RoleName()); mk.put(2, Role.RoleResource()); mk.put(3, Role.RoleLevel()); mv.put(mk.get(1), role.getRoleName()); //request.getParameter("RoleName") mv.put(mk.get(2), role.getRoleResource()); //request.getParameter("RoleResource") //request.getParameter("RoleLevel") mv.put(mk.get(3), role.getRoleLevel()); PublicDao dao = new PublicDao(); String sql = ""; //request.getParameter("type") if("Add".equals(type)){ sql = dao.createSql(PublicDao.ADD, Role.getTableName(), mk, mv, ""); dao.executeSql(PublicDao.ADD, sql); } else if("Update".equals(type)) { //设置条件 String condition = Role.getPrimaryKey()+"="+role.getPrimaryKeyValue(); sql = dao.createSql(PublicDao.UPDATE, Role.getTableName(), mk, mv, condition); dao.executeSql(PublicDao.UPDATE, sql); } }
总结,实体类的自动装配跟VO类的映射就需要有这样高耦合度,为满足数据传输,这是必须的。VO类中设置getTableName、getPrimaryKey等方法能够参与业务逻辑,给编码带来的好处还是有的,起码在需要获取主键值得时候,你不再需要关心某张表的主键到底是谁,而直接拿来就用。当然也有问题,这些问题都可以通过建单扩展既可以解决,比如:
1. 多主键的处理,返回数组
2. (多)外键的处理,返回数组
3. VO中加入表索引信息
同前一篇一样,这样的思路也只是基于一些简单的小型项目,应用到大项目中,需要不停的扩展VO的功能,比如加入索引,在业务逻辑层面,你可以通过指定索引,直接优化一些大型的、复杂的SQL查询,提升效率,当然,这就要求前一篇中PublicDao类的createSql方法更高了,实现也更复杂了。
最后,附上我自己写的一个VO类的代码生成类。
文中有任何大小问题,请各位不吝赐教,我会在日后继续改进。
上一篇: 请注意PHP程序里的敏感信息