手把手教你拥有自己的代码生成器-------->坑居多

tech2022-12-08  102

手把手教你拥有自己的代码生成器

哈哈,猿设计终于讲完了,接下来的一段时间,工厂君打算和大家一起来实现我们之间的设计——构建一个自己的电商系统来玩耍。嗯,这个可是一个大工程,代码量很大,业务也比较复杂,要搞就好好搞,代码方面还是需要一些规范的。

在这个背景下,工厂君为了解决代码的编写速度,也差点被逼上梁山——一个人的力量实在太有限了。工厂君灵机一动,决定搞一个适合项目开发的利器出来——pz-cg。在它的帮帮助下,工厂君节约了开发时间,大大地提高了工作效率。

其实对于新手而言,过度的依赖这类工具,深受其害的事情是大概率事件,如果你是一个新手,希望你在以后的学习中,尽量的去手写代码。虽然会吃力一些,遇到各种稀奇古怪的问题,但这是你的猿人生涯中,必须去面对和解决的事情。言尽于此,不再絮叨。

其实代码生成器有很多,网络上也有各种各样的版本,自然是各有各的好处,也各有各的弊端,今天工厂君会带着大家去造轮子——造一个符合大多数公司编码规范,也能够支持你快速修改的代码生成轮子。造轮子其实也是快速提升你技术实力的一种方式,你经常吐槽CRUD没技术含量,那么你就写个制造CRUD的代码机器出来如何?这个过程也是能提高你的技术实力的,准备好你的收藏,今天的东西,以后你大概率用得上,能够帮你解决实际问题。

既然要搞一个轮子,我们还是希望这个轮子相对通用,不但可以支持springMVC、Spring、Mybatis,在SpringBoot,SpringCloud的框架下依然可用才是硬道理_

既然是代码生成器,那么我们不妨来想一想,我们要生成什么样的代码?什么样的代码是需要我们去生成的?我们要搞的代码生成的本质是什么?关于这个答案,我们需要从一些需要去完成的功能中,管中窥豹一番。就以我们后续会讲到的品牌管理为例吧。

上图的功能就是一个较为典型的管理功能,像这一类功能,都有一些共同的特点——新增、修改、删除、列表查询(包括分页功能)。这些功能是相对固定的,代码的编写方式也相对有一定的痕迹可以寻觅。我们先一起来看一看后端的代码。

一般来说,在使用SpringMVC、Spring、Mybatis框架,进行开发的方式,像上述这样一个比较基本的页面,对应的后端代码,会分为Controller、service、dao三个层面。Controller层负责页面数据的封装、service层负责组织业务逻辑,dao层负责持久化数据。当然,如果你要分得细一点,会加入一个manager层面,用于组织数据持久层的代码,将业务逻辑交由service进行管控也是常见的做法。考虑到这个功能比较简单,我们并没有使用manager层,稍微简单一些,我们先看代码。

/** * Copyright(c) 2004-2020 pangzi *com.pz.basic.mall.controller.sys.MallBrandController.java */ package com.pz.basic.mall.controller.sys; import com.pz.basic.mall.domain.base.Result; import com.pz.basic.mall.dmain.base.enums.DataActiveStatusEnum; import com.pz.basic.mall.domain.base.enums.DataStatusEnum; import com.pz.basic.mall.domain.sys.MallBrand; import com.pz.basic.mall.domain.sys.query.QueryMallBrand; import com.pz.basic.mall.service.sys.MallBrandService; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.List; /** * * @author pangzi * @date 2020-06-22 20:47:27 * * */ @RestController @RequestMapping("/brandManage") public class MallBrandController { private MallBrandService mallBrandService; public void setMallBrandService(MallBrandService mallBrandService) { this.mallBrandService =mallBrandService; } /** * 新增品牌 * @param mallBrand * @return */ @RequestMapping("/addMallBrand") public Result<MallBrand> addMallBrand(@RequestBody MallBrandmallBrand){ try{ return mallBrandService.addMallBrand(mallBrand); }catch(Exception e){ e.printStackTrace(); return new Result(false); } } /** * 修改品牌 * @param mallBrand * @return */ @RequestMapping("/updateMallBrand") public Result updateMallBrand(@RequestBodyMallBrand mallBrand){ try{ return mallBrandService.updateMallBrandById(mallBrand); }catch(Exception e){ e.printStackTrace(); return new Result(false); } } /** * 删除品牌 * @param mallBrand * @return */ @RequestMapping("/deleteMallBrand") public Result deleteMallBrand(@RequestBodyMallBrand mallBrand){ try{ return mallBrandService.deleteMallBrandById(mallBrand); }catch(Exception e){ e.printStackTrace(); return new Result(false); } } /** * 分页返回品牌列表 * @param queryMallBrand * @return */ @RequestMapping("/findByPage") public Result<List<MallBrand>> findByPage(@RequestBody QueryMallBrand queryMallBrand){ returnmallBrandService.getMallBrandsByPage(queryMallBrand); } } /** * Copyright(c) 2004-2020 pangzi *com.pz.basic.mall.service.sys.MallBrandService.java */ package com.pz.basic.mall.service.sys; import java.util.List; import com.pz.basic.mall.domain.base.Result; import com.pz.basic.mall.domain.sys.query.QueryMallBrand; import com.pz.basic.mall.domain.sys.MallBrand; import java.util.Map; import java.io.Serializable; /** * service层,组装外部接口 和 本地业务,为本业务 或者其他业务提供服务,统一返回Result * 通过Result.isSuccess判断调用是否成功 * 此类中新增业务接口设计(接口命令,入参数据,返回值)要 能尽量完整的表达业务 含义 * @author pangzi * @date 2020-06-26 11:20:40 */ public interface MallBrandService { /** * 新增 mallBrand * 返回result,通过result.isSuccess()判断服务调用是否成功 * 通过result.getModel()得到新增mallBrand * @param mallBrand * @return */ public Result<MallBrand> addMallBrand(MallBrand mallBrand) ; /** * 按照主键id更新mallBrand,请重新newMallBrand 的更新对象,设置要更新的字段 * 返回result,通过result.isSuccess()判断更新是否成功 * @param id * @param mallBrand * @return */ public Result updateMallBrandById(MallBrandmallBrand); /** * 按照主键id 删除 记录 * 返回result,通过result.isSuccess()判断删除是否成功 * @param id * @return */ public Result deleteMallBrandById(MallBrandmallBrand); /** * 查询列表,此接口不包含分页查询 * 返回result,通过result.isSuccess()判断服务调用是否成功 * 通过result.getModel()得到列表信息 * @param queryMallBrand * @return */ public Result<List<MallBrand>> getMallBrandsByQuery(QueryMallBrand queryMallBrand); /** * 通过主键id查询MallBrand * 返回result,通过result.isSuccess()判断服务调用是否成功 * 通过result.getModel()得到查询的单条mallBrand信息 * @param id * @return */ public Result<MallBrand> getMallBrandById(long id); /** * 查询列表,包含分页查询 * 查询分页信息,请设置 * QueryMallBrand.setIndex(设置当前页数) * QueryMallBrand.setPageSize(设置当前页面数据行数) * 返回result,通过result.isSuccess()判断服务调用是否成功 * 通过result.getTotal()返回结果总数 * 通过result.getModel()得到查询的单页列表信息 * @param queryMallBrand * @return */ public Result<List<MallBrand>> getMallBrandsByPage(QueryMallBrand queryMallBrand); /** * 查询总数 * @param queryMallBrand * @return */ public Result<Long>count(QueryMallBrand queryMallBrand); } /** * Copyright(c) 2004-2020 pangzi *com.pz.basic.mall.service.sys.impl.MallBrandService.java */ package com.pz.basic.mall.service.sys.impl; import com.pz.basic.mall.dao.sys.MallBrandDao; import java.util.ArrayList; import java.util.List; import com.pz.basic.mall.domain.base.Result; import com.pz.basic.mall.domain.base.enums.DataActiveStatusEnum; import com.pz.basic.mall.domain.base.enums.DataStatusEnum; import com.pz.basic.mall.domain.sys.query.QueryMallBrand; import com.pz.basic.mall.service.sys.MallBrandService; import com.pz.basic.mall.domain.sys.MallBrand; /** * * @author pangzi * @date 2020-06-26 11:25:00 */ public class MallBrandServiceImpl implements MallBrandService { private MallBrandDao mallBrandDao; public void setMallBrandDao (MallBrandDaomallBrandDao) { this.mallBrandDao = mallBrandDao; } public Result<MallBrand>addMallBrand(MallBrand mallBrand) { Result<MallBrand>result = new Result<MallBrand>(); try { QueryMallBrand query= new QueryMallBrand(); query.setBrandName(mallBrand.getBrandName()); long count =mallBrandDao.countByQuery(query); if(count>0){ result.setSuccess(false); result.setMessage("品牌名已存在"); returnresult; } mallBrand.setStatus(DataStatusEnum.STATUS_ENABLE.getStatusValue()); mallBrand.setActive(DataActiveStatusEnum.STATUS_ACTIVE.getStatusValue()); mallBrandDao.insertMallBrand(mallBrand); result.addDefaultModel(mallBrand); } catch(Exception e) { result.setSuccess(false); } return result; } public Result updateMallBrandById(MallBrandmallBrand) { Result result = new Result(); try { int count=mallBrandDao.updateMallBrandByIdModified(mallBrand); if(count>0){ result.setSuccess(true); } } catch(Exception e) { result.setSuccess(false); } return result; } public Result deleteMallBrandById(MallBrandmallBrand) { Result result = new Result(); try { int count=0; MallBrandmodifiedMallBrand = new MallBrand(); modifiedMallBrand.setId(mallBrand.getId()); modifiedMallBrand.setActive(DataActiveStatusEnum.STATUS_DELETED.getStatusValue()); count=mallBrandDao.updateMallBrandByIdModified(modifiedMallBrand); if(count>0){ result.setSuccess(true); } } catch(Exception e) { result.setSuccess(false); } return result; } public Result<List<MallBrand>>getMallBrandsByQuery(QueryMallBrand queryMallBrand) { Result<List<MallBrand>>result = new Result<List<MallBrand>>(); try { queryMallBrand.setActive(DataActiveStatusEnum.STATUS_ACTIVE.getStatusValue()); result.addDefaultModel("MallBrands",mallBrandDao.selectMallBrandByQuery(queryMallBrand)); } catch(Exception e) { result.setSuccess(false); } return result; } public Result<MallBrand>getMallBrandById(long id) { Result<MallBrand>result = new Result<MallBrand>(); try { result.addDefaultModel("MallBrand",mallBrandDao.selectMallBrandById(id)); } catch(Exception e) { result.setSuccess(false); } return result; } public Result<List<MallBrand>>getMallBrandsByPage(QueryMallBrand queryMallBrand) { Result<List<MallBrand>>result = new Result<List<MallBrand>>(); queryMallBrand.setActive(DataActiveStatusEnum.STATUS_ACTIVE.getStatusValue()); long totalItem =mallBrandDao.countByQuery(queryMallBrand); queryMallBrand.setTotalItem(totalItem); queryMallBrand.repaginate(); if (totalItem > 0) { result.addDefaultModel(mallBrandDao.selectMallBrandByPage(queryMallBrand)); } else { result.addDefaultModel(newArrayList<MallBrand>()); } result.setTotalItem(totalItem); result.setPageSize(queryMallBrand.getPageSize()); result.setPage(queryMallBrand.getPage()); return result; } public Result<Long>count(QueryMallBrand queryMallBrand) { Result<Long> result =new Result<Long>(); queryMallBrand.setActive(DataActiveStatusEnum.STATUS_ACTIVE.getStatusValue()); try { result.addDefaultModel(mallBrandDao.countByQuery(queryMallBrand)); } catch(Exception e) { result.setSuccess(false); } return result; } } /** * Copyright(c) 2004-2020 pangzi * com.pz.basic.mall.dao.sys.MallBrandDao.java */ package com.pz.basic.mall.dao.sys; import java.util.List; import com.pz.basic.mall.domain.sys.MallBrand; import com.pz.basic.mall.domain.sys.query.QueryMallBrand; import java.util.Map; import java.io.Serializable; /** * * @author pangzi * @date 2020-06-26 10:56:01 */ public interfaceMallBrandDao { /** * 根据条件查询总数 * @param QueryMallBrand query * @return */ long countByQuery(QueryMallBrand query); /** * 根据条件删除记录 * @param MallBrandQuery query * @return */ int deleteMallBrandByQuery(QueryMallBrandquery); /** * 根据ID删除记录 * @param id * @return */ int deleteMallBrandById(long id); /** * 新增记录 * @param MallBrand record * @return */ long insertMallBrand(MallBrand record); /** * 新增记录 注意:有值的记录才新增 * @param MallBrand record * @return */ long insertMallBrandModified(MallBrandrecord); /** * 根据查询条件返回列表 * @param QueryMallBrand query * @return */ List<MallBrand>selectMallBrandByQuery(QueryMallBrand query); /** * 根据查询条件返回列表 * @param QueryMallBrand query * @return */ List<MallBrand> selectMallBrandByPage(QueryMallBrandquery); /** * 根据ID查询对象 * @param Long id * @return */ MallBrand selectMallBrandById(long id); /** * 根据id修改记录 注意:有值的字段才更新 * @param MallBrand record * @return */ int updateMallBrandByIdModified(MallBrandrecord); }

Mapper文件:

<?xmlversion="1.0" encoding="UTF-8" ?> <!DOCTYPEmapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mappernamespace="com.pz.basic.mall.dao.sys.MallBrandDao"> <resultMap id="ResultMap"type="MallBrand"> <idproperty="id" column="id"/> <idproperty="brandName" column="brand_name"/> <idproperty="logo" column="logo"/> <idproperty="firstChar" column="first_char"/> <idproperty="status" column="status"/> <idproperty="active" column="active"/> <idproperty="createUser" column="create_user"/> <idproperty="modifyUser" column="modify_user"/> <idproperty="created" column="created"/> <idproperty="modified" column="modified"/> </resultMap> <sql id="ALL_TABLE_COLOUM"> id, brand_name, logo, first_char, status, active, create_user, modify_user, created, modified </sql> <sqlid="Query_Where_Clause" > <where > 1=1 <choose> <when test="id != null and id !=''"> and id = #{id} </when> <whentest="brandName != null and brandName != ''"> and brand_name = #{brandName} </when> <whentest="logo != null and logo != ''"> and logo = #{logo} </when> <whentest="firstChar != null and firstChar != ''"> and first_char = #{firstChar} </when> <whentest="status != null and status != ''"> and status = #{status} </when> <whentest="active != null and active != ''"> and active = #{active} </when> <whentest="createUser != null and createUser != ''"> and create_user = #{createUser} </when> <whentest="modifyUser != null and modifyUser != ''"> and modify_user = #{modifyUser} </when> <whentest="created != null and created != ''"> and created = #{created} </when> <whentest="modified != null and modified != ''"> and modified = #{modified} </when> </choose> </where> </sql> <select id="selectMallBrandByQuery" resultMap="ResultMap"parameterType="QueryMallBrand" > select <includerefid="ALL_TABLE_COLOUM" /> from mall_brand <if test="page != null" > <include refid="Query_Where_Clause"/> </if> </select> <select id="selectMallBrandByPage" resultMap="ResultMap"parameterType="QueryMallBrand" > select <includerefid="ALL_TABLE_COLOUM" /> from mall_brand <if test="page != null"> <includerefid="Query_Where_Clause" /> </if> LIMIT #{startRow},#{pageSize} </select> <select id="selectMallBrandById"resultMap="ResultMap" parameterType="java.lang.Long" > select <include refid="ALL_TABLE_COLOUM"/> from mall_brand where id = #{id} </select> <delete id="deleteMallBrandById"parameterType="java.lang.Integer" > delete from mall_brand where id = #{id} </delete> <delete id="deleteMallBrandByQuery" parameterType= "QueryMallBrand"> delete from mall_brand <if test="page != null" > <includerefid="Query_Where_Clause" /> </if> </delete> <insert id="insertMallBrand"parameterType="MallBrand" > INSERT INTO mall_brand(id,brand_name,logo,first_char,status,active,create_user,modify_user,created,modified) VALUES(#{id},#{brandName},#{logo},#{firstChar},#{status},#{active},#{createUser},#{modifyUser},#{created},#{modified}) <selectKey resultType="long"keyProperty="id"> SELECT @@IDENTITY AS ID </selectKey> </insert> <insert id="insertMallBrandModified" parameterType="MallBrand" > insert into mall_brand <trim prefix="("suffix=")" suffixOverrides="," > <if test="id != null"> id, </if> <if test="brandName !=null" > brand_name, </if> <if test="logo !=null" > logo, </if> <if test="firstChar !=null" > first_char, </if> <if test="status !=null" > status, </if> <if test="active !=null" > active, </if> <if test="createUser !=null" > create_user, </if> <if test="modifyUser !=null" > modify_user, </if> <if test="created !=null" > created, </if> <if test="modified !=null" > modified, </if> </trim> <trim prefix="values ("suffix=")" suffixOverrides="," > <if test="id != null" > #{id}, </if> <if test="brandName != null" > #{brandName}, </if> <if test="logo != null" > #{logo}, </if> <if test="firstChar != null" > #{firstChar}, </if> <if test="status != null" > #{status}, </if> <if test="active != null" > #{active}, </if> <if test="createUser != null" > #{createUser}, </if> <if test="modifyUser != null" > #{modifyUser}, </if> <if test="created != null" > now(), </if> <if test="modified != null" > now(), </if> </trim> <selectKey resultType="long"keyProperty="id"> SELECT @@IDENTITY AS ID </selectKey> </insert> <select id="countByQuery"parameterType="QueryMallBrand" resultType="java.lang.Long" > select count(*) from mall_brand <if test="page != null" > <includerefid="Query_Where_Clause" /> </if> </select> <update id="updateMallBrandByIdModified" parameterType="MallBrand"> update mall_brand <set > <iftest="brandName != null" > brand_name = #{brandName}, </if> <iftest="logo != null" > logo = #{logo}, </if> <iftest="firstChar != null" > first_char = #{firstChar}, </if> <iftest="status != null" > status = #{status}, </if> <iftest="active != null" > active = #{active}, </if> <iftest="createUser != null" > create_user = #{createUser}, </if> <iftest="modifyUser != null" > modify_user = #{modifyUser}, </if> <iftest="created != null" > created = #{created}, </if> <iftest="modified != null" > modified=now(), </if> </set> where id = #{id} </update> </mapper>

以上就是品牌管理功能的基本代码,看上去,这些代码确实很多,而且mapper文件的编写,往往容易出错,当然,mybatis也提供了官方工具——Mybatis Genrator帮你生成代码。但是Mybatis Genrator生成的东西,在命名上有些固定,而且会生成的查寻类太过冗余,生成的痕迹太强,真拿那样的代码用到工作中去,容易被吐槽的。

废话不多说了,我们先观察这中基础类别代码的一个规律——根据数据库字段,进行简单的新增,编辑,删除功能。对于数据操作,持久时离不开数据实体,也就是我们常常说的domain类,而为了数据查询,会往往需要一个单独的查询类进行封装。从某个层面来讲,这种代码生成程序的基本思路就找到了——查询数据库表结构->生成对应实体->生成dao需要的mapper->生成dao接口。

如何才能做到这些事情呢?还记得猿思考系列里,工厂君给你提及的一些事情吗?DatabaseMetaData这个东西还记得吗?为了在命名时更加规范,方法名可以更加灵活,还记得动态模板技术吗?现在前后端分离了,JSP、velocity、freemarker这类后端渲染技术是用得少了一些,但是不是说就没有使用场景了噢。你可以使用这些东西来生成HTML页面返回给浏览器,为什么就不能使用这些东西输出成你需要的.java文件还有.xml文件呢?技术这玩意儿,有时候还是需要一点想象力哒。

嗯,工厂君这套代码生成轮子,基本上就是这个套路了,DatabaseMetaData来解决数据库字段和java字段的映射问题,使用velocity的模板技术来渲染生成需要的代码文件。我们可以一起来看下。

数据库里的字段名,和java种的字段名往往不一致,要实现,数据库字段,到domain字段的映射,我们需要先对字段进行抽象,那么字段这个类自然会具有以下几个属性。

package com.pz.cg.gen; import java.net.MalformedURLException; import java.net.URL; public class CgTest { } /** * Copyright(c) 2004-2020 pangzi * GenerateEngine.java */ package com.pz.cg; import com.pz.cg.db.ConnectionPool; import com.pz.cg.db.Field; import com.pz.cg.db.util.MetaDataUtil; import com.pz.cg.gen.CgTest; import org.apache.commons.io.FileUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.time.DateFormatUtils; import org.apache.log4j.Logger; import org.apache.velocity.Template; import org.apache.velocity.VelocityContext; import org.apache.velocity.app.Velocity; import java.io.*; import java.sql.*; import java.util.*; public class GenerateEngine { protected static final String FIELDS ="fields"; protected static final String PACKAGE_NAME = "package"; protected static final String CLASS_NAME = "className"; protected static final String QUERY_CLASS_NAME = "queryClassName"; protected static final String TABLE_NAME = "tableName"; protected static final String INST_NAME= "instName"; protected static final String QUERY_INST_NAME = "queryInstName"; protected static final String IMPORTS ="imports"; protected static final String AUTHOR ="author"; protected static final String PK_ID ="pkid"; protected static final String PK_TYPE="pkType"; protected static final String PK_FILED="pkFiled"; protected static final String PK_SIMPLE_TYPE= "pkSimpleType"; protected static final String PK_NAME ="pkname"; public static final String configFile ="config.properties"; protected static Properties prop = new Properties(); protected static Map<String,Object> context = null; protected static Map<String,Object> commonContext = null; protected String tableName; protected String className =""; public String classType = ""; protected String queryClassType =""; protected static final String ANOTATION= "annotation"; protected static final String DOMAIN ="domain"; protected static final String DAO ="dao"; protected static final String DAO_IMPL= "dao.impl"; protected static final String DAO_TEST= "dao.test"; protected static final String MANAGER ="manager"; protected static final String MANAGER_IMPL = "manager.impl"; protected static final String SERVICE ="service"; protected static final String SERVICE_IMPL = "service.impl"; protected static final String SQL_MAP ="sqlmap"; protected static final String QUERYDOMAIN = "querydomain"; private String location; private String fileName; private String packagee; private Set<String> imports = new HashSet<String>(); private String template; private static Logger log =Logger.getLogger(GenerateEngine.class); protected String getSecondDir() { if(StringUtils.isEmpty(prop.getProperty(PACKAGE_NAME + ".catalog"))) { return ""; } else { return "."+ prop.getProperty(PACKAGE_NAME + ".catalog"); } } static { try { log.info("正在初始化环境..."); context = new HashMap<String, Object>(); File file =FileUtils.toFile(CgTest.class.getResource("/conf/config-local.properties")); prop.load(new FileInputStream(file)); } catch (IOException e) { e.printStackTrace(); log.info("始化环境失败",e); } } protected void init(String classType) { this.classType = classType; this.queryClassType ="query"+classType; if (commonContext == null) { initCommonContext(); } initClassMetaInfo(); intitLocation(); this.setTemplate(prop.getProperty(classType)); } //根据配置完成数据库到字段的映射 protected void initCommonContext() { commonContext = new HashMap<String, Object>(); List<Field> fields =new ArrayList<Field>(); Connection conn = null; Statement st = null; ResultSet rs = null; Set<String> ip = null; Field pkField = new Field(); String pkId = ""; String pkName = ""; String pkType = ""; String pkSimpleType =""; Map<String, String>comment = new HashMap<String, String>(); try { log.info("正在初始化表:"+ tableName + "元数据..."); conn =ConnectionPool.getConnection(); DatabaseMetaData dmd= conn.getMetaData(); rs =dmd.getPrimaryKeys(null, null, tableName); if (rs.next()) { pkId =rs.getString("COLUMN_NAME"); pkName =rs.getString("PK_NAME"); } // 获取得列的注释 rs =dmd.getColumns(null, null, tableName, null); int ix = 1; while(rs.next()) { comment.put(String.valueOf(ix),rs.getString("REMARKS")); ix += 1; } st =conn.createStatement(); rs =st.executeQuery("select * from " + tableName); ResultSetMetaData meta = rs.getMetaData(); Field field = null; String propertyName= ""; String fieldName =""; String javaType =""; ip = new HashSet<String>(); System.out.println(meta.getColumnCount()); for (int i = 1; i<= meta.getColumnCount(); i++) { fieldName =meta.getColumnName(i); javaType =meta.getColumnClassName(i); propertyName= MetaDataUtil.fieldToProperty(fieldName); field = new Field(); field.setPropertyName(propertyName); field.setFieldName(meta.getColumnName(i)); field.setSetterName(MetaDataUtil.createSetterName(propertyName)); field.setGetterName(MetaDataUtil.createGetterName(propertyName)); field.setJavaType(MetaDataUtil.createJavaType(meta.getColumnClassName(i))); field.setJdbcType(meta.getColumnTypeName(i)); field.setJavaFullType(meta.getColumnClassName(i)); field.setComment(comment.get(String.valueOf(i))); fields.add(field); if(field.getJavaFullType().indexOf("java.lang") == -1) { ip.add(field.getJavaFullType()); } //一定要放在最后 if(pkId.equals(fieldName)) { pkType= javaType; pkSimpleType= MetaDataUtil.createJavaType(meta.getColumnClassName(i)); if(pkSimpleType.equals("Integer")) { pkSimpleType= "int"; }else if (pkSimpleType.equals("Long")) { pkSimpleType= "long"; } pkField= field; } } } catch (Exception e) { e.printStackTrace(); log.info("初始化表:" +tableName + "元数据失败", e); } finally { ConnectionPool.close(rs); ConnectionPool.close(st); ConnectionPool.close(conn); } commonContext.put(CLASS_NAME,className); commonContext.put(TABLE_NAME,tableName); commonContext.put(INST_NAME,className.substring(0, 1).toLowerCase() + className.substring(1)); commonContext.put(QUERY_INST_NAME,"query"+className); commonContext.put(INST_NAME,className.substring(0, 1).toLowerCase() + className.substring(1)); commonContext.put(FIELDS,fields); commonContext.put(PK_ID,pkId); commonContext.put(PK_SIMPLE_TYPE,pkSimpleType); commonContext.put(PK_NAME,pkName); commonContext.put(PK_TYPE,pkType); commonContext.put(PK_FILED,pkField); context.putAll(commonContext); if("true".equals(prop.getProperty(ANOTATION))) { context.put("Resource","@Resource"); context.put("Component","@Component"); } this.setImports(ip); log.info("元数据初始化完成."); System.out.println(); } public void intitLocation() { String path =this.getPackagee(); location =prop.getProperty(this.classType + ".out.path"); // 为减少配置,config.properties中并没有配置impl的输出位置 // 因此在生成impl类时需要替换其中中impl获取得其接口的输出位置 if(StringUtils.isBlank(location)) { String str =""; // 替换掉impl用接口的输出位置 // 如:在生成dao.impl时,实际上取的是配置文件中 // dao.out.path的值 if(this.classType.indexOf(".impl") != -1) { str =this.classType.substring(0, this.classType.indexOf(".impl")); } location =prop.getProperty(str + ".out.path"); } // 除了sqlmap之外其它文件的输出位置均与package有关 if(StringUtils.isNotBlank(path)) { path =path.replace(".", System.getProperty("file.separator")); location += System.getProperty("file.separator") + path; } location += System.getProperty("file.separator"); try { FileUtils.forceMkdir(new File(location)); } catch (IOException e) { e.printStackTrace(); } } public void initClassMetaInfo() { context.put(PACKAGE_NAME,this.getPackagee()); context.put(AUTHOR,prop.getProperty("class.author")); context.put("year",DateFormatUtils.format(System.currentTimeMillis(), "yyyy")); context.put("dateTime",DateFormatUtils.format(System.currentTimeMillis(), "yyyy-MM-ddHH:mm:ss")); } public void generate() { try { log.info("正在生成 " +context.get(CLASS_NAME) + " -> " + this.classType + "代码..."); Properties p = new Properties(); p.put("resource.loader","file"); p.put("file.resource.loader.class","org.apache.velocity.runtime.resource.loader.FileResourceLoader"); p.put("file.resource.loader.path",FileUtils.toFile(CgTest.class.getResource("/com/pz/cg/vm/")).getAbsolutePath()); p.put("input.encoding",prop.getProperty("in.encoding")); p.put("output.encoding",prop.getProperty("out.encoding")); Velocity.init(p); //Template template= Velocity.getTemplate("./resources/com/pz/cg/vm/" +this.getTemplate()); Template template =Velocity.getTemplate(this.getTemplate()); VelocityContext ctx= new VelocityContext(context); //Writer writer =new StringWriter(); Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new File(this.getLocation() + "/" + this.getFileName())),prop.getProperty("out.encoding"))); template.merge(ctx,writer); writer.flush(); writer.close(); log.info("生成 " +context.get(CLASS_NAME) + " -> " + this.classType + "代码结束."); log.info("输出位置:" +this.getLocation() + this.getFileName()); System.out.println(); } catch (Exception e) { e.printStackTrace(); } } protected String getLocation() { return location; } protected void setLocation(String location) { this.location = location; } protected String getFileName() { return this.fileName; } protected void setFileName(String fileName) { this.fileName = fileName; } protected String getPackagee() { return packagee; } public void setPackagee(String packagee) { this.packagee = packagee; } protected Set<String>getImports() { return imports; } protected void setImports(Set<String> imports) { this.imports = imports; } protected String getTemplate() { return template; } protected void setTemplate(String template) { this.template = template; } public static Properties getProp() { return prop; } //清理common上下文 public static void clearContext() { commonContext = null; } } /** * Copyright(c) 2004-2020 pangzi * Field.java */ package com.pz.cg.db; public class Field { //java属性名 private String propertyName; //字段名 private String fieldName; //java数据完整类型 private String javaFullType; //java数据类型 private String javaType; //数据库字段类型 private String jdbcType; //getter名 private String getterName; //setter名 private String setterName; //数据库字段注释 private String comment; //长度 private int length; }

既然已经提及到了需要通过数据库的来生成我们需要的代码,对于数据库的访问自然是少不了的,我们简单封装一个数据库连接池的工具类。

/** * Copyright(c) 2004-2020 pangzi * ConnectionPool.java */ package com.pz.cg.db; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.Statement; import java.util.Properties; import com.pz.cg.GenerateEngine; import org.apache.log4j.Logger; public class ConnectionPool { private static Properties prop = newProperties(); private static String userName; private static String password; private static String url; private static String driver; private static Logger log =Logger.ge tLogger(GenerateEngine.class); static { try { prop =GenerateEngine.getProp(); userName =prop.getProperty("jdbc.username"); password =prop.getProperty("jdbc.password"); url =prop.getProperty("jdbc.url"); driver =prop.getProperty("jdbc.driver"); } catch (Exception ex) { ex.printStackTrace(); } } public static void close(Connectionconn) { try { if (conn != null) { conn.close(); conn =null; } } catch (Exception e) { e.printStackTrace(); } } public static void close(Statement st){ try { if (st != null) { st.close(); st = null; } } catch (Exception e) { e.printStackTrace(); } } public static void close(ResultSet rs){ try { if (rs != null) { rs.close(); rs = null; } } catch (Exception e) { e.printStackTrace(); } } public static ConnectiongetConnection() { Connection con = null; log.info("正在连接到数据库..."); try { Class.forName(driver); con =DriverManager.getConnection(url, userName, password); } catch (Exception e) { e.printStackTrace(); log.info("连接数据库失败",e); } return con; } }

我们都知道,数据库字段的命名规范,往往是英文单词加下划线的形式出现的,而java字段的命名规范,往往是驼峰式的命名。为此了方便我们进行数据处理,我们封装一个工具类吧。

/** * Copyright(c) 2004-2020 pangzi * MetaDataUtil.java */ package com.pz.cg.db.util; import java.sql.Connection; import java.util.HashMap; import java.util.Map; import org.apache.commons.lang.CharUtils; import org.apache.commons.lang.StringUtils; public class MetaDataUtil { public static Map<String, String>getTableColumns(Connection con, String tableName) { Map<String, String>columns = new HashMap<String, String>(); return columns; } public static String createSetterName(StringfieldName) { return "set" +fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1); } public static StringcreateGetterName(String fieldName) { return "get" +fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1); } public static StringcreateJavaType(String dbJavaType) { String javaType =dbJavaType.substring(dbJavaType.lastIndexOf(".") + 1); //将jdbc的Timedstamp变为Date类型 if("Timestamp".equals(javaType)) { javaType ="Date"; } return javaType; } public static String propertyToField(Stringproperty) { if (null == property) { return ""; } char[] chars =property.toCharArray(); StringBuffer sb = newStringBuffer(); for (char c : chars) { if (CharUtils.isAsciiAlphaUpper(c)){ sb.append("_" +StringUtils.lowerCase(CharUtils.toString(c))); } else { sb.append(c); } } return sb.toString(); } public static String fieldToProperty(Stringfield) { if (null == field) { return ""; } char[] chars =field.toCharArray(); StringBuffer sb = newStringBuffer(); for (int i = 0; i < chars.length;i++) { char c = chars[i]; if (c == '_') { int j = i + 1; if (j < chars.length) { sb.append(StringUtils.upperCase(CharUtils.toString(chars[j]))); i++; } } else { sb.append(c); } } return sb.toString(); } }

好了,接下来,我们就要为生成代码做一些准备了,编写我们需要的核心代码了。不过在这之前,还有一些问题需要解决。比如,我们需要连接的数据库实例在哪里?我们需要生成的代码存放在哪里?代码的包结构如何定义?这些东西,为了灵活起见,我们定义一个配置文件吧。我们在resoures目录下建立一个conf/config-local.properties的配置文件。

## databaseconnection setting jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://127.0.0.1:3306/pz_mall_basic?characterEncoding=utf-8 jdbc.username=root jdbc.password=13456 ## encodingsetting ## in.encoding=utf-8 out.encoding=utf-8 ## class metadata setting ## class.author=pangzi package=com.pz.basic.mall ##package.catalog= ## packagesetting ## package.domain=domain.brand package.dao=dao.brand package.manager=manager.brand package.service=service.brand package.action=controller.brand package.querydomain=domain.brand.query ## file out pathsetting ## domain.out.path=D:/workspace-pangzi/pangzi-client/src/main/java querydomain.out.path=D:/workspace-pangzi/pangzi-client/src/main/java dao.out.path=D:/workspace-pangzi/pangzi-dao/src/main/java manager.out.path=D:/workspace-pangzi/pangzi-manager/src/main/java sqlmap.out.path=D:/workspace-pangzi/pangzi-dao/src/main/resources/sqlmap service.out.path=D:/workspace-pangzi/pangzi-service/src/main/java action.out.path=D:/workspace-pangzi/pangzi-controller/src/main/java ## code templatesetting ## ## domain ## domain=pojo.vm ## query## querydomain=querypojo.vm ##分页## querybase=PaginateBaseDO.vm ##dao## dao=dao.vm ##dao实现类## dao.impl=dao.impl.vm ##测试类## dao.test= ##manager## manager=manager.vm ##manager实现## manager.impl=manager.impl.vm ##service## service=service.vm ##service实现## service.impl=service.impl.vm ##mapper## sqlmap=sql_map.vm /** * Copyright(c) 2004-2020 pangzi * GenerateEngine.java */ package com.pz.cg; import com.pz.cg.db.ConnectionPool; import com.pz.cg.db.Field; import com.pz.cg.db.util.MetaDataUtil; import com.pz.cg.test.CgTest; import org.apache.commons.io.FileUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.time.DateFormatUtils; import org.apache.log4j.Logger; import org.apache.velocity.Template; import org.apache.velocity.VelocityContext; import org.apache.velocity.app.Velocity; import java.io.*; import java.sql.*; import java.util.*; public classGenerateEngine { protected static final String FIELDS ="fields"; protected static final StringPACKAGE_NAME = "package"; protected static final StringCLASS_NAME = "className"; protected static final StringQUERY_CLASS_NAME = "queryClassName"; protected static final StringTABLE_NAME = "tableName"; protected static final String INST_NAME= "instName"; protected static final StringQUERY_INST_NAME = "queryInstName"; protected static final String IMPORTS ="imports"; protected static final String AUTHOR ="author"; protected static final String PK_ID ="pkid"; protected static final String PK_TYPE="pkType"; protected static final String PK_FILED="pkFiled"; protected static final StringPK_SIMPLE_TYPE= "pkSimpleType"; protected static final String PK_NAME ="pkname"; public static final String configFile ="config.properties"; protected static Properties prop = newProperties(); protected static Map<String,Object> context = null; protected static Map<String,Object> commonContext = null; protected String tableName; protected String className =""; public String classType = ""; protected String queryClassType =""; protected static final String ANOTATION= "annotation"; protected static final String DOMAIN ="domain"; protected static final String DAO ="dao"; protected static final String DAO_IMPL= "dao.impl"; protected static final String DAO_TEST= "dao.test"; protected static final String MANAGER ="manager"; protected static final StringMANAGER_IMPL = "manager.impl"; protected static final String SERVICE ="service"; protected static final StringSERVICE_IMPL = "service.impl"; protected static final String SQL_MAP ="sqlmap"; protected static final StringQUERYDOMAIN = "querydomain"; private String location; private String fileName; private String packagee; private Set<String> imports = newHashSet<String>(); private String template; private static Logger log =Logger.getLogger(GenerateEngine2.class); protected String getSecondDir() { if(StringUtils.isEmpty(prop.getProperty(PACKAGE_NAME + ".catalog"))) { return ""; } else { return "."+ prop.getProperty(PACKAGE_NAME + ".catalog"); } } static { try { log.info("正在初始化环境..."); context = newHashMap<String, Object>(); File file =FileUtils.toFile(CgTest.class.getResource("/conf/config-local.properties")); prop.load(newFileInputStream(file)); } catch (IOException e) { e.printStackTrace(); log.info("始化环境失败",e); } } protected void init(String classType) { this.classType = classType; this.queryClassType ="query"+classType; if (commonContext == null) { initCommonContext(); } initClassMetaInfo(); intitLocation(); this.setTemplate(prop.getProperty(classType)); } //根据配置完成数据库到字段的映射 protected void initCommonContext() { commonContext = newHashMap<String, Object>(); List<Field> fields =new ArrayList<Field>(); Connection conn = null; Statement st = null; ResultSet rs = null; Set<String> ip = null; Field pkField = new Field(); String pkId = ""; String pkName = ""; String pkType = ""; String pkSimpleType =""; Map<String, String>comment = new HashMap<String, String>(); try { log.info("正在初始化表:"+ tableName + "元数据..."); conn =ConnectionPool.getConnection(); DatabaseMetaData dmd= conn.getMetaData(); rs =dmd.getPrimaryKeys(null, null, tableName); if (rs.next()) { pkId =rs.getString("COLUMN_NAME"); pkName =rs.getString("PK_NAME"); } // 获取得列的注释 rs =dmd.getColumns(null, null, tableName, null); int ix = 1; while(rs.next()) { comment.put(String.valueOf(ix),rs.getString("REMARKS")); ix += 1; } st =conn.createStatement(); rs =st.executeQuery("select * from " + tableName); ResultSetMetaDatameta = rs.getMetaData(); Field field = null; String propertyName= ""; String fieldName =""; String javaType =""; ip = newHashSet<String>(); System.out.println(meta.getColumnCount()); for (int i = 1; i<= meta.getColumnCount(); i++) { fieldName =meta.getColumnName(i); javaType =meta.getColumnClassName(i); propertyName= MetaDataUtil.fieldToProperty(fieldName); field = newField(); field.setPropertyName(propertyName); field.setFieldName(meta.getColumnName(i)); field.setSetterName(MetaDataUtil.createSetterName(propertyName)); field.setGetterName(MetaDataUtil.createGetterName(propertyName)); field.setJavaType(MetaDataUtil.createJavaType(meta.getColumnClassName(i))); field.setJdbcType(meta.getColumnTypeName(i)); field.setJavaFullType(meta.getColumnClassName(i)); field.setComment(comment.get(String.valueOf(i))); fields.add(field); if(field.getJavaFullType().indexOf("java.lang") == -1) { ip.add(field.getJavaFullType()); } //一定要放在最后 if(pkId.equals(fieldName)) { pkType= javaType; pkSimpleType= MetaDataUtil.createJavaType(meta.getColumnClassName(i)); if(pkSimpleType.equals("Integer")) { pkSimpleType= "int"; }else if (pkSimpleType.equals("Long")) { pkSimpleType= "long"; } pkField= field; } } } catch (Exception e) { e.printStackTrace(); log.info("初始化表:" +tableName + "元数据失败", e); } finally { ConnectionPool.close(rs); ConnectionPool.close(st); ConnectionPool.close(conn); } commonContext.put(CLASS_NAME,className); commonContext.put(TABLE_NAME,tableName); commonContext.put(INST_NAME,className.substring(0, 1).toLowerCase() + className.substring(1)); commonContext.put(QUERY_INST_NAME,"query"+className); commonContext.put(INST_NAME,className.substring(0, 1).toLowerCase() + className.substring(1)); commonContext.put(FIELDS,fields); commonContext.put(PK_ID,pkId); commonContext.put(PK_SIMPLE_TYPE,pkSimpleType); commonContext.put(PK_NAME,pkName); commonContext.put(PK_TYPE,pkType); commonContext.put(PK_FILED,pkField); context.putAll(commonContext); if("true".equals(prop.getProperty(ANOTATION))) { context.put("Resource","@Resource"); context.put("Component","@Component"); } this.setImports(ip); log.info("元数据初始化完成."); System.out.println(); } public void intitLocation() { String path =this.getPackagee(); location =prop.getProperty(this.classType + ".out.path"); // 为减少配置,config.properties中并没有配置impl的输出位置 // 因此在生成impl类时需要替换其中中impl获取得其接口的输出位置 if(StringUtils.isBlank(location)) { String str =""; // 替换掉impl用接口的输出位置 // 如:在生成dao.impl时,实际上取的是配置文件中 // dao.out.path的值 if(this.classType.indexOf(".impl") != -1) { str =this.classType.substring(0, this.classType.indexOf(".impl")); } location =prop.getProperty(str + ".out.path"); } // 除了sqlmap之外其它文件的输出位置均与package有关 if(StringUtils.isNotBlank(path)) { path =path.replace(".", System.getProperty("file.separator")); location += System.getProperty("file.separator") + path; } location += System.getProperty("file.separator"); try { FileUtils.forceMkdir(newFile(location)); } catch (IOException e) { e.printStackTrace(); } } public void initClassMetaInfo() { context.put(PACKAGE_NAME,this.getPackagee()); context.put(AUTHOR,prop.getProperty("class.author")); context.put("year",DateFormatUtils.format(System.currentTimeMillis(), "yyyy")); context.put("dateTime",DateFormatUtils.format(System.currentTimeMillis(), "yyyy-MM-ddHH:mm:ss")); } public void generate() { try { log.info("正在生成 " +context.get(CLASS_NAME) + " -> " + this.classType + "代码..."); Properties p = newProperties(); p.put("resource.loader","file"); p.put("file.resource.loader.class","org.apache.velocity.runtime.resource.loader.FileResourceLoader"); p.put("file.resource.loader.path",FileUtils.toFile(CgTest.class.getResource("/com/pz/cg/vm/")).getAbsolutePath()); p.put("input.encoding",prop.getProperty("in.encoding")); p.put("output.encoding",prop.getProperty("out.encoding")); Velocity.init(p); //Template template= Velocity.getTemplate("./resources/com/pz/cg/vm/" +this.getTemplate()); Template template =Velocity.getTemplate(this.getTemplate()); VelocityContext ctx= new VelocityContext(context); //Writer writer =new StringWriter(); Writer writer = newBufferedWriter(new OutputStreamWriter(new FileOutputStream(newFile(this.getLocation() + "/" + this.getFileName())),prop.getProperty("out.encoding"))); template.merge(ctx,writer); writer.flush(); writer.close(); log.info("生成 " +context.get(CLASS_NAME) + " -> " + this.classType + "代码结束."); log.info("输出位置:" +this.getLocation() + this.getFileName()); System.out.println(); } catch (Exception e) { e.printStackTrace(); } } protected String getLocation() { return location; } protected void setLocation(Stringlocation) { this.location = location; } protected String getFileName() { return this.fileName; } protected void setFileName(StringfileName) { this.fileName = fileName; } protected String getPackagee() { return packagee; } public void setPackagee(Stringpackagee) { this.packagee = packagee; } protected Set<String>getImports() { return imports; } protected voidsetImports(Set<String> imports) { this.imports = imports; } protected String getTemplate() { return template; } protected void setTemplate(Stringtemplate) { this.template = template; } public static Properties getProp() { return prop; } //清理common上下文 public static void clearContext() { commonContext = null; } }

输入输出的核心问题解决了,我们可以看看具体到每一种类型的代码生成了,我们为每一种需要的类型,编写一种具体的生成器就可以了。

package com.pz.cg.gen; import java.util.HashSet; import java.util.Set; import com.pz.cg.CodeGenerator; import com.pz.cg.GenerateEngine; /** * 生成一些基本类,例如queryDO,resultDO等 * @author pangzi * */ public class BaseGenerator extends GenerateEngine implements CodeGenerator { public void generate(String tableName,String className) { //由PaginateBaseDO.vm生成PaginateBaseDO.java this.classType = QUERYDOMAIN; this.setTemplate("PaginateBaseDO.vm"); this.setFileName("PaginateBaseDO.java"); this.setPackagee(prop.getProperty(GenerateEngine.PACKAGE_NAME)+ "." + prop.getProperty("package.querydomain")); initClassMetaInfo(); intitLocation(); this.generate(); //由Result.vm生成Result.java this.classType = DOMAIN; this.setTemplate("Result.vm"); this.setFileName("Result.java"); this.setPackagee(prop.getProperty(GenerateEngine.PACKAGE_NAME)+ ".domain.base" ); this.setImports(getResultImport()); initClassMetaInfo(); intitLocation(); this.generate(); //生成BaseDO this.classType = DOMAIN; this.setTemplate("BaseDO.vm"); this.setFileName("BaseDO.java"); this.setPackagee(prop.getProperty(GenerateEngine.PACKAGE_NAME)+ ".domain.base"); this.setImports(getResultImport()); initClassMetaInfo(); intitLocation(); this.generate(); //生成输出文件格式 this.classType = DOMAIN; this.setTemplate("NoNullFieldStringStyle.vm"); this.setFileName("NoNullFieldStringStyle.java"); this.setPackagee(prop.getProperty(GenerateEngine.PACKAGE_NAME)+ ".domain.base" ); this.setImports(getResultImport()); initClassMetaInfo(); intitLocation(); this.generate(); } public Set<String>getResultImport() { Set<String> imports =new HashSet<String>(); imports.add(prop.getProperty(PACKAGE_NAME)+ ".domain.base" +".PaginateBaseDO" ); context.put(IMPORTS,imports); return imports; } } /** * Copyright(c) 2004-2020 pangzi * com.pz.cg.gen.PojoCodeGenerator.java */ package com.pz.cg.gen; import java.util.HashSet; import java.util.Set; import com.pz.cg.CodeGenerator; import com.pz.cg.GenerateEngine; /** * @author pangzi * */ public class PojoGenerator extends GenerateEngine implements CodeGenerator { public void generate(String tableName,String className) { this.tableName = tableName; this.className = className; this.setFileName(this.className+ ".java"); this.setPackagee(prop.getProperty(PACKAGE_NAME)+ "." + prop.getProperty("package.domain") +this.getSecondDir()); this.init(DOMAIN); context.put(IMPORTS,this.getPojoImports()); this.generate(); } protected Set<String>getPojoImports() { Set<String> imports =new HashSet<String>(); imports.add(prop.getProperty(PACKAGE_NAME) + ".domain.base.BaseDO"); return imports; } } /** * */ package com.pz.cg.gen; import java.util.HashSet; import java.util.Set; import com.pz.cg.CodeGenerator; import com.pz.cg.GenerateEngine; /** * @author pangzi * */ public class QueryPojoGenerator extends GenerateEngine implements CodeGenerator { public void generate(String tableName,String className) { this.tableName = tableName; this.className = className; this.setFileName("Query"+this.className + ".java"); this.setPackagee(prop.getProperty(PACKAGE_NAME)+ "." + prop.getProperty("package.querydomain") + this.getSecondDir()); this.setImports(getImport()); this.init(QUERYDOMAIN); context.put(IMPORTS,this.getImports()); this.generate(); } public Set<String> getImport() { Set<String> imports =new HashSet<String>(); imports.add(prop.getProperty(PACKAGE_NAME)+ ".domain.base.PaginateBaseDO" ); context.put(IMPORTS,imports); return imports; } } /** * Copyright(c) 2004-2020 pangzi * com.pz.cg.gen.DaoCodeGenerator.java */ package com.pz.cg.gen; import java.util.HashSet; import java.util.Set; import com.pz.cg.CodeGenerator; import com.pz.cg.GenerateEngine; public class DaoGenerator extends GenerateEngine implements CodeGenerator { public void generate(String tableName,String className) { this.tableName = tableName; this.className = className; this.setFileName(this.className+ "Dao" + ".java"); this.setPackagee(prop.getProperty(PACKAGE_NAME)+ "." + prop.getProperty("package.dao") +this.getSecondDir()); this.setImports(this.getDaoImport()); this.init(DAO); this.generate(); this.generateImpl(tableName,className); } private void generateImpl(StringtableName, String className) { this.tableName = tableName; this.className = className; this.setFileName(this.className+ "DaoImpl" + ".java"); this.setPackagee(prop.getProperty(PACKAGE_NAME)+ "." + prop.getProperty("package.dao") + this.getSecondDir() + ".impl"); this.setTemplate(prop.getProperty("dao.impl")); this.setImports(this.getDaoImplImport()); this.init(DAO_IMPL); this.generate(); } public Set<String> getDaoImport(){ Set<String> imports =new HashSet<String>(); imports.add("java.util.List"); imports.add(prop.getProperty(PACKAGE_NAME)+ "." + prop.getProperty("package.querydomain")+this.getSecondDir() + "."+"Query"+ className); imports.add(prop.getProperty(PACKAGE_NAME)+ "." + prop.getProperty("package.domain") +this.getSecondDir() + "." +className); context.put(IMPORTS,imports); return imports; } public Set<String>getDaoImplImport() { Set<String> imports =new HashSet<String>(); imports.add("java.util.List"); imports.add(prop.getProperty(PACKAGE_NAME)+ "." + prop.getProperty("package.domain") + this.getSecondDir() + "." + className); imports.add(prop.getProperty(PACKAGE_NAME)+ "." + prop.getProperty("package.querydomain")+this.getSecondDir() + ".Query"+ className); imports.add(prop.getProperty(PACKAGE_NAME)+ "." + prop.getProperty("package.dao") + this.getSecondDir() + "." + className +"Dao"); context.put(IMPORTS,imports); return imports; } } package com.pz.cg.gen; import java.util.HashSet; import java.util.Set; import com.pz.cg.CodeGenerator; import com.pz.cg.GenerateEngine; public class ServiceGenerator extends GenerateEngine implements CodeGenerator { public void generate(String tableName,String className) { this.tableName = tableName; this.className = className; this.setFileName(this.className+ "Service" + ".java"); this.setPackagee(prop.getProperty(PACKAGE_NAME)+ "." + prop.getProperty("package.service") +this.getSecondDir()); this.setImports(this.getServiceImport()); this.init(SERVICE); this.generate(); this.generateImpl(tableName,className); } private void generateImpl(StringtableName, String className) { this.tableName = tableName; this.className = className; this.setFileName(this.className+ "ServiceImpl" + ".java"); this.setPackagee(prop.getProperty(PACKAGE_NAME)+ "." + prop.getProperty("package.service") + this.getSecondDir() + ".impl"); this.setTemplate(prop.getProperty("service.impl")); this.setImports(this.getServiceImplImport()); this.init(SERVICE_IMPL); this.generate(); } public Set<String>getServiceImport() { Set<String> imports =new HashSet<String>(); imports.add("java.util.List"); imports.add(prop.getProperty(PACKAGE_NAME)+ "." + prop.getProperty("package.domain") +".Result" ); imports.add(prop.getProperty(PACKAGE_NAME)+ "." + prop.getProperty("package.domain") +this.getSecondDir() + "." +className); imports.add(prop.getProperty(PACKAGE_NAME)+ "." + prop.getProperty("package.querydomain")+this.getSecondDir() + ".Query"+ className); context.put(IMPORTS,imports); return imports; } public Set<String>getServiceImplImport() { Set<String> imports =new HashSet<String>(); imports.add("java.util.List"); imports.add(prop.getProperty(PACKAGE_NAME)+ "." + prop.getProperty("package.domain") +".Result" ); imports.add(prop.getProperty(PACKAGE_NAME)+ "." + prop.getProperty("package.domain") +this.getSecondDir() + "." +className); imports.add(prop.getProperty(PACKAGE_NAME)+ "." + prop.getProperty("package.querydomain")+this.getSecondDir() + ".Query"+ className); imports.add(prop.getProperty(PACKAGE_NAME)+ "." + prop.getProperty("package.dao") +this.getSecondDir() + "." +className + "Dao"); imports.add(prop.getProperty(PACKAGE_NAME)+ "." + prop.getProperty("package.service") +this.getSecondDir() + "." + className + "Service"); context.put(IMPORTS,imports); return imports; } } package com.pz.cg.gen; import com.pz.cg.CodeGenerator; import com.pz.cg.GenerateEngine; public class SqlMapGenerator extends GenerateEngine implements CodeGenerator { public static String SQL_DOMAIN ="sqlDomain"; public static String SQL_QUERYDOMAIN ="sqlQueryDomain"; public static String DAO_DOMAIN ="daoDomain"; public void generate(String tableName,String className) { this.tableName = tableName; this.className = className; this.setFileName(this.className+ "Mapper.xml"); //设置sqlmap的domain和querydomain 的package context.put(SQL_DOMAIN,prop.getProperty(PACKAGE_NAME) + "." +prop.getProperty("package.domain") + this.getSecondDir() + "." + className); context.put(SQL_QUERYDOMAIN,prop.getProperty(PACKAGE_NAME) + "." +prop.getProperty("package.querydomain")+ this.getSecondDir() + ".Query" + className); context.put(DAO_DOMAIN,prop.getProperty(PACKAGE_NAME) + "." +prop.getProperty("package.dao") + this.getSecondDir() + "." + className); this.init(SQL_MAP); this.generate(); } }

接下来就是你的重中之重的事情来了——为每一种你需要的代码,编写具体的vm模板文件。

Domian的基类模板 BaseDO.vm: /** * Copyright(c) 2004-$!year pangzi * $!{package}.$!{className}.java */ package $!package; import java.io.Serializable; import org.apache.commons.lang3.builder.ToStringBuilder; import $!{package}.NoNullFieldStringStyle; /** * * @author $!author * @date $!dateTime * * */ public class BaseDO implements Serializable { private static final longserialVersionUID = 1L; /** * 如果字段值为null将不包含在toString中 */ @Override public String toString() { returnToStringBuilder.reflectionToString(this); } }

查询基础类 模板 PaginateBaseDO.vm:

/** * Copyright(c)2004-$!year pangzi *$!{package}.PaginateBaseDO.java */ package $!{package}; import java.io.Serializable; /** * * @author$!author * @date$!dateTime * * */ public class PaginateBaseDO{ /** * 默认每页的记录数量 */ public staticfinal int PAGESIZE_DEFAULT = 20; /** * 每页大小 */ private int pageSize; /** * 当前页。第一页是1 */ private int index; /** * 总记录数 */ private int totalItem; /** * 总页数 */ private int totalPage; /** * 分页后的记录开始的地方 * 第一条记录是1 */ private int startRow; /** * 分页后的记录结束的地方 */ private int endRow; /**排序字段**/ private String orderField; /**升序 还是 降序,true为升序,false为降序*/ private Boolean isAsc; /** * 默认构造方法 */ public PaginateBaseDO() { repaginate(); } /** * 带当前页和页大小的构造方法 * @param index 当前页 * @parampageSize 页大小 */ public PaginateBaseDO(int index, int pageSize) { this.index =index; this.pageSize =pageSize; repaginate(); } public void setStartRow(int startRow) { this.startRow =startRow; } public void setEndRow(int endRow) { this.endRow =endRow; } /** * 表示是不是第一页 * @return true 是; false 不是 */ public boolean isFirstPage(){ return index<= 1; } public boolean isMiddlePage() { return!(isFirstPage() || isLastPage()); } public boolean isLastPage() { return index>= totalPage; } public boolean isNextPageAvailable() { return!isLastPage(); } public boolean isPreviousPageAvailable() { return!isFirstPage(); } /** * 下一页号 * @return 取得下一页号 */ public int getNextPage() { if(isLastPage()){ returntotalItem; } else { return index+1; } } public int getPreviousPage() { if(isFirstPage()){ return 1; } else { return index -1; } } /** * MethodgetPageSize returns the pageSize of this PaginatedArrayList object. * * 每页大小 * * @return thepageSize (type int) of this PaginatedArrayList object. */ public int getPageSize() { return pageSize; } /** * MethodsetPageSize sets the pageSize of this PaginatedArrayList object. * * 每页大小 * * @parampageSize the pageSize of this PaginatedArrayList object. * */ public void setPageSize(int pageSize) { this.pageSize =pageSize; repaginate(); } /** * MethodgetIndex returns the index of this PaginatedArrayList object. * * 当前页。第一页是1 * * @return theindex (type int) of this PaginatedArrayList object. */ public int getIndex() { return index; } /** * MethodsetIndex sets the index of this PaginatedArrayList object. * * 当前页。第一页是1 * * @param indexthe index of this PaginatedArrayList object. * */ public void setIndex(int index) { this.index =index; repaginate(); } /** * MethodgetTotalItem returns the totalItem of this PaginatedArrayList object. * * 总记录数 * * @return thetotalItem (type int) of this PaginatedArrayList object. */ public int getTotalItem() { returntotalItem; } /** * MethodsetTotalItem sets the totalItem of this PaginatedArrayList object. * * 总记录数 * * @paramtotalItem the totalItem of this PaginatedArrayList object. * */ public void setTotalItem(int totalItem) { this.totalItem =totalItem; if(this.totalItem <= 0){ totalPage = 0; index = 1; startRow = 0; } repaginate(); } /** * MethodgetTotalPage returns the totalPage of this PaginatedArrayList object. * * 总页数 * * @return thetotalPage (type int) of this PaginatedArrayList object. */ public int getTotalPage() { return totalPage; } /** * MethodgetStartRow returns the startRow of this PaginatedArrayList object. * * 分页后的记录开始的地方 * * @return thestartRow (type int) of this PaginatedArrayList object. */ public int getStartRow() { if (startRow> 0) { return startRow; } if (index <=0) { index = 1; } return (index -1) * pageSize; } /** * MethodgetEndRow returns the endRow of this PaginatedArrayList object. * * 分页后的记录结束的地方 * * @return theendRow (type int) of this PaginatedArrayList object. */ public int getEndRow() { if (endRow >0) { return endRow; } return index *pageSize; } public String getOrderField() { returnorderField; } public void setOrderField(String orderField) { this.orderField= orderField; } public Boolean getIsAsc() { return isAsc; } public void setIsAsc(Boolean isAsc) { this.isAsc =isAsc; } /** * Methodrepaginate ... */ public void repaginate() { if (pageSize< 1) { //防止程序偷懒,list和分页的混合使用 pageSize =PAGESIZE_DEFAULT; } if (index <1) { index = 1;//恢复到第一页 } if (totalItem> 0) { totalPage =totalItem / pageSize + (totalItem % pageSize > 0 ? 1 : 0); if(index >totalPage) { index =totalPage; //最大页 } endRow = index *pageSize; startRow =(index - 1) * pageSize; if(endRow>totalItem){ endRow =totalItem; } } } }

Domain 模板 pojo.vm:

/** * Copyright(c) 2004-$!year pangzi * $!{package}.$!{className}.java */ package $!package; import java.util.Date; #foreach($importin $imports) import $import; #end /** * * @author $!author * @date $!dateTime * */ public class $!className extends BaseDO { #foreach($fieldin $fields) /**$!field.comment**/ private $!field.javaType$!field.propertyName; #end public $!className() { } #foreach($fieldin $fields) public $!field.javaType$field.getGetterName()() { return $field.propertyName; } public void $field.getSetterName()($!field.javaType $!field.propertyName) { this.$!field.propertyName =$!field.propertyName; } #end }

Query 模板 querypojo.vm:

/** * Copyright(c) 2004-$!year pangzi * $!{package}.$!{className}.java */ package $!package; import java.util.Date; #foreach($importin $imports) import $import; #end /** * * @author $!author * @date $!dateTime * * */ public class Query$!className extends PaginateBaseDO { #foreach($fieldin $fields) /**$!field.comment**/ private $!field.javaType$!field.propertyName; #end #foreach($fieldin $fields) public $!field.javaType$field.getGetterName()() { return $field.propertyName; } public void $field.getSetterName()($!field.javaType $!field.propertyName) { this.$!field.propertyName =$!field.propertyName; } #end }

Dao 模板 dao.vm:

/** * Copyright(c) 2004-$!year pangzi * $!{package}.$!{className}Dao.java */ package $!{package}; #foreach($importin $imports) import $import; #end import java.util.Map; import java.io.Serializable; /** * * @author $!author * @date $!dateTime */ public interface $!{className}Dao { /** * 根据条件查询总数 * @param Query$!{className} query * @return */ $!pkSimpleType countByQuery(Query$!{className} query); /** * 根据条件删除记录 * @param $!{className}Query query * @return */ int delete$!{className}ByQuery(Query$!{className} query); /** * 根据ID删除记录 * @param id * @return */ int delete$!{className}ById($!pkSimpleType$!{pkid}); /** * 新增记录 * @param $!{className} record * @return */ $!pkSimpleType insert$!{className}($!{className} record); /** * 新增记录 注意:有值的记录才新增 * @param $!{className} record * @return */ $!pkSimpleType insert$!{className}Modified($!{className} record); /** * 根据查询条件返回列表 * @param Query$!{className} query * @return */ List<$!{className}> select$!{className}ByQuery(Query$!{className} query); /** * 根据查询条件返回列表 * @param Query$!{className} query * @return */ List<$!{className}> select$!{className}ByPage(Query$!{className} query); /** * 根据ID查询对象 * @param Long id * @return */ $!{className} select$!{className}ById($!pkSimpleType $!{pkid}); /** * 根据id修改记录 注意:有值的字段才更新 * @param $!{className} record * @return */ int update$!{className}ByIdModified($!{className}record); }

mapper 模板sql_map.vm:

#set($mapName ="$!{className.toUpperCase()}-MAP") #set($insertSql= "") #set($insertFields= "") #set($pageCommonSql= "PAGE-COMMON") #set($queryCommonSql= "QUERY-COMMON") #set($exampleCommonSql= "EXAMPLE-COMMON") <?xmlversion="1.0" encoding="UTF-8" ?> <!DOCTYPEmapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mappernamespace="$!{daoDomain}Dao"> <typeAliasalias="$!{className}" type="$!{sqlDomain}"/> <typeAliasalias="Query$!{className}" type="$!{sqlQueryDomain}"/> <resultMap id="ResultMap"type="$!{className}"> #foreach($field in $fields) <id property="$!{field.propertyName}"column="$!{field.fieldName}"/> #set($insertSql =$insertSql + "#{" + $!{field.propertyName} + "}" +",") #set($insertFields =$insertFields + $!{field.fieldName} + ",") #end #if($!$insertSql.endsWith(",")) #set($insertSql =$!insertSql.substring(0, $insertSql.lastIndexOf(","))) #end #if($!$insertFields.endsWith(",")) #set($insertFields =$!insertFields.substring(0, $insertFields.lastIndexOf(","))) #end </resultMap> <sqlid="ALL_TABLE_COLOUM"> #set($index=1) #foreach($field in $fields) #if($index==$fields.size()) $!{field.fieldName} #else $!{field.fieldName}, #end #set($index =$index+1) #end </sql> <sqlid="Query_Where_Clause" > <where > 1=1 #foreach($field in $fields) <iftest="$!{field.propertyName} != null and $!{field.propertyName} !=''"> and $!field.fieldName = #{$!{field.propertyName}} </if> #end </where> </sql> <select id="select$!{className}ByQuery"resultMap="ResultMap" parameterType="Query$!{className}"> select <includerefid="ALL_TABLE_COLOUM" /> from $!{tableName} <if test="page != null" > <includerefid="Query_Where_Clause" /> </if> </select> <selectid="select$!{className}ByPage" resultMap="ResultMap"parameterType="Query$!{className}" > select <includerefid="ALL_TABLE_COLOUM" /> from $!{tableName} <if test="page != null"> <includerefid="Query_Where_Clause" /> </if> LIMIT #{startRow},#{pageSize} </select> <selectid="select$!{className}ById" resultMap="ResultMap"parameterType="$!pkSimpleType" > select <includerefid="ALL_TABLE_COLOUM" /> from $!{tableName} where $!pkFiled.fieldName =#{$!pkFiled.propertyName} </select> <deleteid="delete$!{className}ById" parameterType="$!pkSimpleType"> delete from $!{tableName} where $!pkFiled.fieldName =#{$!pkFiled.propertyName} </delete> <deleteid="delete$!{className}ByQuery" parameterType="Query$!{className}" > delete from $!{tableName} <if test="page != null" > <includerefid="Query_Where_Clause" /> </if> </delete> <insert id="insert$!{className}"parameterType="$!{className}" > INSERT INTO $!{tableName}($!insertFields) VALUES($!insertSql) <selectKeyresultType="$!pkSimpleType"keyProperty="$!pkFiled.propertyName"> SELECT @@IDENTITY AS ID </selectKey> </insert> <insertid="insert$!{className}Modified"parameterType="$!{className}" > insert into $!{tableName} <trim prefix="("suffix=")" suffixOverrides="," > #foreach($field in $fields) #if($!field.propertyName=='created'||$!field.propertyName=='modified') <iftest="$!field.propertyName == null" > $!{field.fieldName}, </if> #else <iftest="$!field.propertyName != null" > $!{field.fieldName}, </if> #end #end </trim> <trim prefix="values ("suffix=")" suffixOverrides="," > #foreach($field in $fields) #if($!field.propertyName=='created'||$!field.propertyName=='modified') <iftest="$!field.propertyName == null" > now(), </if> #else <iftest="$!field.propertyName != null" > #{$!{field.propertyName}}, </if> #end #end </trim> <selectKeyresultType="$!pkSimpleType"keyProperty="$!pkFiled.propertyName"> SELECT @@IDENTITY AS ID </selectKey> </insert> <select id="countByQuery"parameterType="Query$!{className}" resultType="java.lang.Long" > select count(*) from $!{tableName} <if test="page != null" > <includerefid="Query_Where_Clause" /> </if> </select> <update id="update$!{className}ByIdModified"parameterType="$!{className}" > update $!{tableName} <set > #foreach($field in $fields) #if($!field.fieldName!=$!pkFiled.fieldName) #if($!field.propertyName=='modified') <if test="$!field.propertyName!= null" > $!field.fieldName=now(), </if> #else <iftest="$!field.propertyName != null" > $!field.fieldName = #{$!{field.propertyName}}, </if> #end #end #end </set> where $!pkFiled.fieldName =#{$!pkFiled.propertyName} </update> </mapper>

以上的模板,基本上解决了实际开发的需要。由于Mybatis框架使用代理模式的特性,无需再编写对应的实现类了。不过需要注意的是,dao接口中的方法名,需要于mapper文件中的id保持一致,如果因为需要,需要更换命名规范,同步修改即可_

Dao层之上的代码,比如service,比如manager这类代码是需要根据业务代码来具体编写的,一些简单的封装我们还是可以做的,比如说分页这类事情。为此,我们为了返回结果的需要,需要定义一个通用点的返回类,模板如下。

结果返回模板:Result.vm

/** * Copyright(c) 2004-$!year pangzi * $!{package}.Result.java */ package $!{package}; import java.io.Serializable; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Set; #foreach($importin $imports) import $import; #end /** * * @author $!author * @date $!dateTime * * */ public class Result<T> extends PaginateBaseDO implements Serializable { /** * */ private static final longserialVersionUID = 6028636097083630372L; /** * 是否成功 */ private boolean success = true; /** * service返回的对象 */ private Map<String, Object>result = new HashMap<String, Object>(); /** * 默认的key */ public static final StringDEFAULT_MODEL_KEY = "value"; /** * 当前的key */ private String modelKey =DEFAULT_MODEL_KEY; private T module; /** * 返回码 */ private String resultCode; private String[] resultCodeParams; /** * 带是否成功的构造方法 * * @param success */ public Result(boolean success) { this.success = success; } /** * 默认构造方法 */ public Result() { } /** * 新增一个返回结果 * * @param obj * @return */ public Object addDefaultModel(T obj) { return module = obj; } /** * 得到默认的模型 * @return */ public T getModel(){ return module; } /** * 新增一个带key的返回结果 * * @param key * @param obj * @return */ public Object addDefaultModel(Stringkey, Object obj) { modelKey = key; return result.put(key, obj); } /** * 取出所有的key * * @return */ public Set<String> keySet() { return result.keySet(); } /** * 取出默认的值 * * @return */ public Object get() { return result.get(modelKey); } /** * 取出值 * * @param key * @return */ public Object get(String key) { return result.get(key); } /** * 取出值集合 * * @return */ public Collection values() { return result.values(); } /** * 返回是否成功 * * @return */ public boolean getSuccess() { return success; } public boolean isSuccess() { return success; } /** * 设置返回是否成功 * * @param success */ public void setSuccess(boolean success){ this.success = success; } public String getResultCode() { return resultCode; } public void setResultCode(StringresultCode) { this.resultCode = resultCode; } public void setResultCode(StringresultCode, String... args) { this.resultCode = resultCode; this.resultCodeParams = args; } public String[] getResultCodeParams() { return resultCodeParams; } public void setResultCodeParams(String[] resultCodeParams) { this.resultCodeParams =resultCodeParams; } }

service层的代码,对于业务相对简单来说的系统来说,主要解决的是一个分页的问题,我们看看如下图所示。

我们可以十分方便的将MallBrand替换成我们需要的实体就可以了,于是我们可以较为快速的编写初需要的模板。

Service 模板service.vm:

/** * Copyright(c) 2004-$!year pangzi * $!{package}.$!{className}Service.java */ package $!{package}; #foreach($importin $imports) import $import; #end import java.util.Map; import java.io.Serializable; /** * service层,组装外部接口 和 本地业务,为本业务 或者其他业务提供服务,统一返回Result * 通过Result.isSuccess判断调用是否成功 * 此类中新增业务接口设计(接口命令,入参数据,返回值)要 能尽量完整的表达业务 含义 * @author $!author * @date $!dateTime */ public interface $!{className}Service { /** * 新增 $!instName * 返回result,通过result.isSuccess()判断服务调用是否成功 * 通过result.getModel()得到新增$!instName * @param $!instName * @return */ public Result<$!className> add$!{className}($!className $!instName) ; /** * 按照主键id更新$!instName,请重新new$!className 的更新对象,设置要更新的字段 * 返回result,通过result.isSuccess()判断更新是否成功 * @param id * @param $!instName * @return */ public Result update$!{className}ById($!className $!instName); /** * 按照主键id 删除 记录 * 返回result,通过result.isSuccess()判断删除是否成功 * @param id * @return */ public Result delete$!{className}ById($!pkSimpleType $!{pkid}); /** * 查询列表,此接口不包含分页查询 * 返回result,通过result.isSuccess()判断服务调用是否成功 * 通过result.getModel()得到列表信息 * @param $!queryInstName * @return */ publicResult<List<$!className>> get$!{className}sByQuery(Query$!className$!queryInstName); /** * 通过主键id查询$!className * 返回result,通过result.isSuccess()判断服务调用是否成功 * 通过result.getModel()得到查询的单条$!instName信息 * @param id * @return */ public Result<$!className> get$!{className}ById($!pkSimpleType $!{pkid}); /** * 查询列表,包含分页查询 * 查询分页信息,请设置 * Query$!{className}.setIndex(设置当前页数) * Query$!{className}.setPageSize(设置当前页面数据行数) * 返回result,通过result.isSuccess()判断服务调用是否成功 * 通过result.getTotal()返回结果总数 * 通过result.getModel()得到查询的单页列表信息 * @param $!queryInstName * @return */ public Result<List<$!className>> get$!{className}sByPage(Query$!className$!queryInstName); /** * 查询总数 * @param $!queryInstName * @return */ public Result<$!pkType> count(Query$!className $!queryInstName); }

Service.impl模板service.impl.vm:

#set($managerName= "$!{instName}Manager") #set($daoName ="$!{instName}Dao") /** * Copyright(c) 2004-$!year pangzi * $!{package}.$!{className}Service.java */ package $!{package}; #foreach($importin $imports) import $import; #end import java.util.ArrayList; #if($!{Resource}) import javax.annotation.Resource; import org.springframework.stereotype.Component; #end import java.util.Map; import java.io.Serializable; /** * * @author $!author * @date $!dateTime */ #if($!{Resource}) $!Component #end public class $!{className}ServiceImpl implements $!{className}Service { $!{Resource} private $!{className}Dao $!{daoName}; #if(!$!{Resource}) public void set$!{className}Dao($!{className}Dao $!{daoName}) { this.$!{daoName} = $!{daoName}; #end public Result<$!className> add$!{className}($!className $!instName) { Result<$!className>result = new Result<$!className>(); try { $!{daoName}.insert$!{className}Modified($!instName); result.addDefaultModel($!instName); } catch(Exception e) { result.setSuccess(false); } return result; } public Result update$!{className}ById($!className $!instName) { Result result = new Result(); try { int count=$!{daoName}.update$!{className}ByIdModified($!instName); if(count>0){ result.setSuccess(true); } } catch(Exception e) { result.setSuccess(false); } return result; } public Result delete$!{className}ById($!pkSimpleType $!{pkid}) { Result result = new Result(); try { int count=$!{daoName}.delete$!{className}ById($!{pkid}); if(count>0){ result.setSuccess(true); } } catch(Exception e) { result.setSuccess(false); } return result; } public Result<List<$!className>> get$!{className}sByQuery(Query$!className$!queryInstName) { Result<List<$!className>> result = new Result<List<$!className>>(); try { result.addDefaultModel($!{daoName}.select$!{className}ByQuery($!queryInstName)); } catch(Exception e) { result.setSuccess(false); } return result; } public Result<$!className> get$!{className}ById($!pkSimpleType $!{pkid}) { Result<$!className> result = new Result<$!className>(); try { result.addDefaultModel($!{daoName}.select$!{className}ById($!{pkid})); } catch(Exception e) { result.setSuccess(false); } return result; } public Result<List<$!className>> get$!{className}sByPage(Query$!className$!queryInstName) { Result<List<$!className>> result = new Result<List<$!className>>(); $!pkSimpleType totalItem =$!{daoName}.countByQuery($!queryInstName); $!{queryInstName}.setTotalItem(totalItem); $!{queryInstName}.repaginate(); if (totalItem > 0) { result.addDefaultModel($!{daoName}.select$!{className}ByPage($!queryInstName)); } else { result.addDefaultModel(newArrayList<$!className>()); } result.setTotalItem(totalItem); result.setPageSize($!{queryInstName}.getPageSize()); result.setPage($!{queryInstName}.getPage()); return result; } public Result<$!pkType> count(Query$!className $!queryInstName) { Result<$!pkType> result= new Result<$!pkType>(); try { result.addDefaultModel($!{daoName}.countByQuery($!queryInstName)); } catch(Exception e) { result.setSuccess(false); } return result; } }

看起来咱们的代码生成器就要编写完成了,但是还有一点点问题,每中类别的代码生成入口在哪里?既然没有,那么就去编写一个就好了——针对每一种类别,编写一个即可,编写方式都大同小异。给你两个核心一点的就好了,剩下的自己去完善吧(至少domain dao mapper )。

package com.pz.cg.gen; import java.util.HashSet; import java.util.Set; import com.pz.cg.CodeGenerator; import com.pz.cg.GenerateEngine; /** * 生成一些基本类,例如queryDO,resultDO等 * @author pangzi * */ public class BaseGenerator extends GenerateEngine implements CodeGenerator { public void generate(String tableName,String className) { //由PaginateBaseDO.vm生成PaginateBaseDO.java this.classType = QUERYDOMAIN; this.setTemplate("PaginateBaseDO.vm"); this.setFileName("PaginateBaseDO.java"); this.setPackagee(prop.getProperty(GenerateEngine.PACKAGE_NAME)+ "." + prop.getProperty("package.querydomain")); initClassMetaInfo(); intitLocation(); this.generate(); //由Result.vm生成Result.java this.classType = DOMAIN; this.setTemplate("Result.vm"); this.setFileName("Result.java"); this.setPackagee(prop.getProperty(GenerateEngine.PACKAGE_NAME)+ ".domain.base" ); this.setImports(getResultImport()); initClassMetaInfo(); intitLocation(); this.generate(); //生成BaseDO this.classType = DOMAIN; this.setTemplate("BaseDO.vm"); this.setFileName("BaseDO.java"); this.setPackagee(prop.getProperty(GenerateEngine.PACKAGE_NAME)+ ".domain.base"); this.setImports(getResultImport()); initClassMetaInfo(); intitLocation(); this.generate(); //生成输出文件格式 this.classType = DOMAIN; this.setTemplate("NoNullFieldStringStyle.vm"); this.setFileName("NoNullFieldStringStyle.java"); this.setPackagee(prop.getProperty(GenerateEngine.PACKAGE_NAME)+ ".domain.base" ); this.setImports(getResultImport()); initClassMetaInfo(); intitLocation(); this.generate(); } public Set<String> getResultImport() { Set<String> imports =new HashSet<String>(); imports.add(prop.getProperty(PACKAGE_NAME)+ ".domain.base" +".PaginateBaseDO" ); context.put(IMPORTS,imports); return imports; } } package com.pz.cg.gen; import java.util.HashSet; import java.util.Set; import com.pz.cg.CodeGenerator; import com.pz.cg.GenerateEngine; /** * 生成一些基本类,例如queryDO,resultDO等 * @author pangzi * */ public class BaseGenerator extends GenerateEngine implements CodeGenerator { public void generate(String tableName,String className) { //由PaginateBaseDO.vm生成PaginateBaseDO.java this.classType = QUERYDOMAIN; this.setTemplate("PaginateBaseDO.vm"); this.setFileName("PaginateBaseDO.java"); this.setPackagee(prop.getProperty(GenerateEngine.PACKAGE_NAME)+ "." + prop.getProperty("package.querydomain")); initClassMetaInfo(); intitLocation(); this.generate(); //由Result.vm生成Result.java this.classType = DOMAIN; this.setTemplate("Result.vm"); this.setFileName("Result.java"); this.setPackagee(prop.getProperty(GenerateEngine.PACKAGE_NAME)+ ".domain.base" ); this.setImports(getResultImport()); initClassMetaInfo(); intitLocation(); this.generate(); //生成BaseDO this.classType = DOMAIN; this.setTemplate("BaseDO.vm"); this.setFileName("BaseDO.java"); this.setPackagee(prop.getProperty(GenerateEngine.PACKAGE_NAME)+ ".domain.base"); this.setImports(getResultImport()); initClassMetaInfo(); intitLocation(); this.generate(); //生成输出文件格式 this.classType = DOMAIN; this.setTemplate("NoNullFieldStringStyle.vm"); this.setFileName("NoNullFieldStringStyle.java"); this.setPackagee(prop.getProperty(GenerateEngine.PACKAGE_NAME)+ ".domain.base" ); this.setImports(getResultImport()); initClassMetaInfo(); intitLocation(); this.generate(); } public Set<String>getResultImport() { Set<String> imports =new HashSet<String>(); imports.add(prop.getProperty(PACKAGE_NAME)+ ".domain.base" +".PaginateBaseDO" ); context.put(IMPORTS,imports); return imports; } } /** * Copyright(c) 2004-2020 pangzi * com.pz.cg.gen.PojoCodeGenerator.java */ package com.pz.cg.gen; import java.util.HashSet; import java.util.Set; import com.pz.cg.CodeGenerator; import com.pz.cg.GenerateEngine; public class PojoGenerator extends GenerateEngine implements CodeGenerator { public void generate(String tableName,String className) { this.tableName = tableName; this.className = className; this.setFileName(this.className+ ".java"); this.setPackagee(prop.getProperty(PACKAGE_NAME)+ "." + prop.getProperty("package.domain") +this.getSecondDir()); this.init(DOMAIN); context.put(IMPORTS,this.getPojoImports()); this.generate(); } protected Set<String>getPojoImports() { Set<String> imports =new HashSet<String>(); imports.add(prop.getProperty(PACKAGE_NAME) + ".domain.base.BaseDO"); return imports; } } /** * */ package com.pz.cg.gen; import java.util.HashSet; import java.util.Set; import com.pz.cg.CodeGenerator; import com.pz.cg.GenerateEngine; /** * @author pangzi * */ public class QueryPojoGenerator extends GenerateEngine implements CodeGenerator { public void generate(String tableName,String className) { this.tableName = tableName; this.className = className; this.setFileName("Query"+this.className + ".java"); this.setPackagee(prop.getProperty(PACKAGE_NAME)+ "." + prop.getProperty("package.querydomain") + this.getSecondDir()); this.setImports(getImport()); this.init(QUERYDOMAIN); context.put(IMPORTS,this.getImports()); this.generate(); } public Set<String> getImport() { Set<String> imports =new HashSet<String>(); imports.add(prop.getProperty(PACKAGE_NAME)+ ".domain.base.PaginateBaseDO" ); context.put(IMPORTS,imports); return imports; } }

嗯,最后,咱们的生成器当然是使用maven的方式编写的啦,不看到最后,不想坚持的人,自然是得不到好东西的。

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.pz</groupId> <artifactId>pz-cg</artifactId> <version>0.0.1-SNAPSHOT</version> <dependencies> <dependency> <groupId>commons-beanutils</groupId> <artifactId>commons-beanutils</artifactId> <version>1.8.3</version> </dependency> <dependency> <groupId>commons-collections</groupId> <artifactId>commons-collections</artifactId> <version>3.2.1</version> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>1.3.2</version> </dependency> <dependency> <groupId>commons-lang</groupId> <artifactId>commons-lang</artifactId> <version>2.5</version> </dependency> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.1.1</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.5</version> </dependency> <dependency> <groupId>velocity-tools</groupId> <artifactId>velocity-tools</artifactId> <version>1.2</version> </dependency> <dependency> <groupId>org.apache.velocity</groupId> <artifactId>velocity</artifactId> <version>1.6.3</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.15</version> <exclusions> <exclusion> <groupId>javax.jms</groupId> <artifactId>jms</artifactId> </exclusion> <exclusion> <groupId>com.sun.jdmk</groupId> <artifactId>jmxtools</artifactId> </exclusion> <exclusion> <groupId>com.sun.jmx</groupId> <artifactId>jmxri</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring</artifactId> <version>2.5.6</version> </dependency> </dependencies> </project>

猿人君并没有把完整的东西放出来,因为猿人君是真心希望你认真去思考,完善一些东西,剩下的已经不多了,service的生成器并没有什么特别,只是希望你自己稍微完善下即可,如果实在想不出来,可以加猿人君的微信shangaladepangzi,暗号:代码生成获取。

最新回复(0)