手写java通用curd_你还在手写crud吗,看完这篇文章,绝对赚了

一、介绍

我记得最早刚步入互联网行业的时候,当时按照 MVC 的思想和模型,每次开发新功能,会依次编写 dao、service、controller相关服务类,包括对应的 dto、entity、vo 等等实体类,如果有多张单表,也会重复的编写相似的代码,现在回想起来,感觉当时自己好像处于石器时代!

实际上,当仔细的总结一下,对于任何一张单表的操作,基本都是围绕增(Create )、删(Delete )、改(Update )、查(Retrieve )四个方向进行数据操作,简称 CRUD!

他们除了表名和存储空间不一样,基本的 CRUD 思路基本都是一样的。

为了解决这些重复劳动的痛点,业界逐渐开源了一批代码生成器,目的也很简单,就是为了减少手工操作的繁琐,集中精力在业务开发上,提升开发效率。

而今天,我们所要介绍的也是代码生成器,很多初学者可能觉得代码生成器很高深。代码生成器其实是一个很简单的东西,一点都不高深。

当你看完本文的时候,你会完全掌握代码生成器的逻辑,甚至可以根据自己的项目情况,进行深度定制。

二、实现思路

下面我们就以SpringBoot项目为例,数据持久化操作采用Mybatis,数据库采用Mysql,编写一个自动生成增、删、改、查等基础功能的代码生成器,内容包括controller、service、dao、entity、dto、vo等信息。

实现思路如下:第一步:获取表字段名称、类型、表注释等信息

第二步:基于 freemarker 模板引擎,编写相应的模板

第三步:根据对应的模板,生成相应的 java 代码

2.1、获取表结构

首先我们创建一张test_db表,脚本如下:

CREATE TABLE test_db (

id bigint(20) unsigned NOT NULL COMMENT '主键ID',

name varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '名称',

is_delete tinyint(4) NOT NULL DEFAULT '0' COMMENT '是否删除 1:已删除;0:未删除',

create_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',

update_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',

PRIMARY KEY (id),

KEY idx_create_time (create_time) USING BTREE

) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='测试表';

表创建完成之后,基于test_db表,我们查询对应的表结果字段名称、类型、备注信息,这些关键信息将用于后续进行代码生成器所使用!

# 获取对应表结构

SELECT column_name, data_type, column_comment FROM information_schema.columns WHERE tab

同时,获取对应表注释,用于生成备注信息!

# 获取对应表注释

SELECT TABLE_COMMENT FROM INFORMATION_SCHEMA.TABLES WHERE table_schema = 'yjgj_base' AND table_na

2.2、编写模板编写mapper.ftl模板,涵盖新增、修改、删除、查询等信息

#if>

#list>

${pro.fieldName},${pro.fieldName}#if>

#list>

insert into ${tableName} (

${pro.fieldName},${pro.fieldName},${pro.fieldName}#if>

#list>

)

values

${r"#{obj." + pro.proName + r"}"},

#list>

insert into ${tableName}

${pro.fieldName},

#list>

${r"#{" + pro.proName + r",jdbcType=" + pro.fieldType +r"}"},

#list>

update ${tableName}

${pro.fieldName} = ${r"#{" + pro.proName + r",jdbcType=" + pro.fieldType +r"}"},

#if>

#list>

where ${primaryId} = ${r"#{" + "${primaryId}" + r",jdbcType=BIGINT}"}

update ${tableName}

when id = ${r"#{" + "obj.id" + r"}"}

then ${r"#{obj." + pro.proName + r",jdbcType=" + pro.fieldType +r"}"}

#if>

#list>

where

id = ${r"#{" + "obj.id" + r"}"}

delete from ${tableName}

where ${primaryId} = ${r"#{" + "${primaryId}" + r",jdbcType=BIGINT}"}

select

from ${tableName}

where ${primaryId} = ${r"#{" + "${primaryId}" + r",jdbcType=BIGINT}"}

select

from ${tableName}

select

from ${tableName}

and ${primaryId} in

${r"#{" + "item" + r"}"}

select

from ${tableName}

select count(${primaryId})

from ${tableName}

select

from ${tableName}

limit ${r"#{" + "start,jdbcType=INTEGER" + r"}"},${r"#{" + "end,jdbcType=INTEGER" + r"}"}

编写dao.ftl数据访问模板

package ${daoPackageName};

import com.example.generator.core.BaseMapper;

import java.util.List;

import ${entityPackageName}.${entityName};

import ${dtoPackageName}.${dtoName};

/**** @ClassName: ${daoName}* @Description: 数据访问接口* @author ${authorName}* @date ${currentTime}**/

public interface ${daoName} extends BaseMapper{

int countPage(${dtoName} ${dtoName?uncap_first});

List selectPage(${dtoName} ${dtoName?uncap_first});

}编写service.ftl服务接口模板

package ${servicePackageName};

import com.example.generator.core.BaseService;

import com.example.generator.common.Pager;

import ${voPackageName}.${voName};

import ${dtoPackageName}.${dtoName};

import ${entityPackageName}.${entityName};

/**** @ClassName: ${serviceName}* @Description: ${entityName}业务访问接口* @author ${authorName}* @date ${currentTime}**/

public interface ${serviceName} extends BaseService {

/*** 分页列表查询* @param request*/

Pager getPage(${dtoName} request);

}编写serviceImpl.ftl服务实现类模板

package ${serviceImplPackageName};

import com.example.generator.common.Pager;

import com.example.generator.core.BaseServiceImpl;

import com.example.generator.test.service.TestEntityService;

import org.springframework.beans.BeanUtils;

import org.springframework.stereotype.Service;

import org.springframework.util.CollectionUtils;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import java.util.ArrayList;

import java.util.List;

import ${daoPackageName}.${daoName};

import ${entityPackageName}.${entityName};

import ${dtoPackageName}.${dtoName};

import ${voPackageName}.${voName};

@Service

public class ${serviceImplName} extends BaseServiceImpl implements ${serviceName} {

private static final Logger log = LoggerFactory.getLogger(${serviceImplName}.class);

/*** 分页列表查询* @param request*/

public Pager getPage(${dtoName} request) {

List resultList = new ArrayList();

int count = super.baseMapper.countPage(request);

List dbList = count > 0 ? super.baseMapper.selectPage(request) : new ArrayList<>();

if(!CollectionUtils.isEmpty(dbList)){

dbList.forEach(source->{

${voName} target = new ${voName}();

BeanUtils.copyProperties(source, target);

resultList.add(target);

});

}

return new Pager(request.getCurrPage(), request.getPageSize(), count, resultList);

}

}编写controller.ftl控制层模板

package ${controllerPackageName};

import com.example.generator.common.IdRequest;

import com.example.generator.common.Pager;

import org.springframework.beans.BeanUtils;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.web.bind.annotation.PostMapping;

import org.springframework.web.bind.annotation.RequestBody;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;

import java.util.Objects;

import ${servicePackageName}.${serviceName};

import ${entityPackageName}.${entityName};

import ${dtoPackageName}.${dtoName};

import ${voPackageName}.${voName};

/**** @ClassName: ${controllerName}* @Description: 外部访问接口* @author ${authorName}* @date ${currentTime}**/

@RestController

@RequestMapping("/${entityName?uncap_first}")

public class ${controllerName} {

@Autowired

private ${serviceName} ${serviceName?uncap_first};

/*** 分页列表查询* @param request*/

@PostMapping(value = "/getPage")

public Pager getPage(@RequestBody ${dtoName} request){

return ${serviceName?uncap_first}.getPage(request);

}

/*** 查询详情* @param request*/

@PostMapping(value = "/getDetail")

public ${voName} getDetail(@RequestBody IdRequest request){

${entityName} source = ${serviceName?uncap_first}.selectById(request.getId());

if(Objects.nonNull(source)){

${voName} result = new ${voName}();

BeanUtils.copyProperties(source, result);

return result;

}

return null;

}

/*** 新增操作* @param request*/

@PostMapping(value = "/save")

public void save(${dtoName} request){

${entityName} entity = new ${entityName}();

BeanUtils.copyProperties(request, entity);

${serviceName?uncap_first}.insert(entity);

}

/*** 编辑操作* @param request*/

@PostMapping(value = "/edit")

public void edit(${dtoName} request){

${entityName} entity = new ${entityName}();

BeanUtils.copyProperties(request, entity);

${serviceName?uncap_first}.updateById(entity);

}

/*** 删除操作* @param request*/

@PostMapping(value = "/delete")

public void delete(IdRequest request){

${serviceName?uncap_first}.deleteById(request.getId());

}

}编写entity.ftl实体类模板

package ${entityPackageName};

import java.io.Serializable;

import java.math.BigDecimal;

import java.util.Date;

/**** @ClassName: ${entityName}* @Description: ${tableDes!}实体类* @author ${authorName}* @date ${currentTime}**/

public class ${entityName} implements Serializable {

private static final long serialVersionUID = 1L;

&& pro.proName != 'remarks'

&& pro.proName != 'createBy'

&& pro.proName != 'createDate'

&& pro.proName != 'updateBy'

&& pro.proName != 'updateDate'

&& pro.proName != 'delFlag'

&& pro.proName != 'currentUser'

&& pro.proName != 'page'

&& pro.proName != 'sqlMap'

&& pro.proName != 'isNewRecord'

>#if>-->

/*** ${pro.proDes!}*/

private ${pro.proType} ${pro.proName};

#list>

public ${pro.proType} get${pro.proName?cap_first}() {

return this.${pro.proName};

}

public ${entityName} set${pro.proName?cap_first}(${pro.proType} ${pro.proName}) {

this.${pro.proName} = ${pro.proName};

return this;

}

#list>

}编写dto.ftl实体类模板

package ${dtoPackageName};

import com.example.generator.core.BaseDTO;

import java.io.Serializable;

/*** @ClassName: ${dtoName}* @Description: 请求实体类* @author ${authorName}* @date ${currentTime}**/

public class ${dtoName} extends BaseDTO {

}编写vo.ftl视图实体类模板

package ${voPackageName};

import java.io.Serializable;

/*** @ClassName: ${voName}* @Description: 返回视图实体类* @author ${authorName}* @date ${currentTime}**/

public class ${voName} implements Serializable {

private static final long serialVersionUID = 1L;

}

可能细心的网友已经看到了,在模板中我们用到了BaseMapper、BaseService、BaseServiceImpl等等服务类。

之所以有这三个类,是因为在模板中,我们有大量的相同的方法名包括逻辑也相似,除了所在实体类不一样以外,其他都一样,因此我们可以借助泛型类来将这些服务抽成公共的部分。BaseMapper,主要负责将dao层的公共方法抽出来

package com.example.generator.core;

import org.apache.ibatis.annotations.Param;

import java.io.Serializable;

import java.util.List;

import java.util.Map;

/*** @author pzblog* @Description* @since 2020-11-11*/

public interface BaseMapper {

/*** 批量插入* @param list* @return*/

int insertList(@Param("list") List list);

/*** 按需插入一条记录* @param entity* @return*/

int insertPrimaryKeySelective(T entity);

/*** 按需修改一条记录(通过主键ID)* @return*/

int updatePrimaryKeySelective(T entity);

/*** 批量按需修改记录(通过主键ID)* @param list* @return*/

int updateBatchByIds(@Param("list") List list);

/*** 根据ID删除* @param id 主键ID* @return*/

int deleteByPrimaryKey(Serializable id);

/*** 根据ID查询* @param id 主键ID* @return*/

T selectByPrimaryKey(Serializable id);

/*** 按需查询* @param entity* @return*/

List selectByPrimaryKeySelective(T entity);

/*** 批量查询* @param ids 主键ID集合* @return*/

List selectByIds(@Param("ids") List extends Serializable> ids);

/*** 查询(根据 columnMap 条件)* @param columnMap 表字段 map 对象* @return*/

List selectByMap(Map columnMap);

}BaseService,主要负责将service层的公共方法抽出来

package com.example.generator.core;

import java.io.Serializable;

import java.util.List;

import java.util.Map;

/*** @author pzblog* @Description 服务类* @since 2020-11-11*/

public interface BaseService {

/*** 新增* @param entity* @return boolean*/

boolean insert(T entity);

/*** 批量新增* @param list* @return boolean*/

boolean insertList(List list);

/*** 通过ID修改记录(如果想全部更新,只需保证字段都不为NULL)* @param entity* @return boolean*/

boolean updateById(T entity);

/*** 通过ID批量修改记录(如果想全部更新,只需保证字段都不为NULL)* @param list* @return boolean*/

boolean updateBatchByIds(List list);

/*** 根据ID删除* @param id 主键ID* @return boolean*/

boolean deleteById(Serializable id);

/*** 根据ID查询* @param id 主键ID* @return*/

T selectById(Serializable id);

/*** 按需查询* @param entity* @return*/

List selectByPrimaryKeySelective(T entity);

/*** 批量查询* @param ids* @return*/

List selectByIds(List extends Serializable> ids);

/*** 根据条件查询* @param columnMap* @return*/

List selectByMap(Map columnMap);

}BaseServiceImpl,service层的公共方法具体实现类

package com.example.generator.core;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;

import java.util.List;

import java.util.Map;

/*** @author pzblog* @Description 实现类( 泛型说明:M 是 mapper 对象,T 是实体)* @since 2020-11-11*/

public abstract class BaseServiceImpl, T> implements BaseService{

@Autowired

protected M baseMapper;

/*** 新增* @param entity* @return boolean*/

@Override

@Transactional(rollbackFor = {Exception.class})

public boolean insert(T entity){

return returnBool(baseMapper.insertPrimaryKeySelective(entity));

}

/*** 批量新增* @param list* @return boolean*/

@Override

@Transactional(rollbackFor = {Exception.class})

public boolean insertList(List list){

return returnBool(baseMapper.insertList(list));

}

/*** 通过ID修改记录(如果想全部更新,只需保证字段都不为NULL)* @param entity* @return boolean*/

@Override

@Transactional(rollbackFor = {Exception.class})

public boolean updateById(T entity){

return returnBool(baseMapper.updatePrimaryKeySelective(entity));

}

/*** 通过ID批量修改记录(如果想全部更新,只需保证字段都不为NULL)* @param list* @return boolean*/

@Override

@Transactional(rollbackFor = {Exception.class})

public boolean updateBatchByIds(List list){

return returnBool(baseMapper.updateBatchByIds(list));

}

/*** 根据ID删除* @param id 主键ID* @return boolean*/

@Override

@Transactional(rollbackFor = {Exception.class})

public boolean deleteById(Serializable id){

return returnBool(baseMapper.deleteByPrimaryKey(id));

}

/*** 根据ID查询* @param id 主键ID* @return*/

@Override

public T selectById(Serializable id){

return baseMapper.selectByPrimaryKey(id);

}

/*** 按需查询* @param entity* @return*/

@Override

public List selectByPrimaryKeySelective(T entity){

return baseMapper.selectByPrimaryKeySelective(entity);

}

/*** 批量查询* @param ids* @return*/

@Override

public List selectByIds(List extends Serializable> ids){

return baseMapper.selectByIds(ids);

}

/*** 根据条件查询* @param columnMap* @return*/

@Override

public List selectByMap(Map columnMap){

return baseMapper.selectByMap(columnMap);

}

/*** 判断数据库操作是否成功* @param result 数据库操作返回影响条数* @return boolean*/

protected boolean returnBool(Integer result) {

return null != result && result >= 1;

}

}

在此,还封装来其他的类,例如 dto 公共类BaseDTO,分页类Pager,还有 id 请求类IdRequest。BaseDTO公共类

public class BaseDTO implements Serializable {

/*** 请求token*/

private String token;

/*** 当前页数*/

private Integer currPage = 1;

/*** 每页记录数*/

private Integer pageSize = 20;

/*** 分页参数(第几行)*/

private Integer start;

/*** 分页参数(行数)*/

private Integer end;

/*** 登录人ID*/

private String loginUserId;

/*** 登录人名称*/

private String loginUserName;

public String getToken() {

return token;

}

public BaseDTO setToken(String token) {

this.token = token;

return this;

}

public Integer getCurrPage() {

return currPage;

}

public BaseDTO setCurrPage(Integer currPage) {

this.currPage = currPage;

return this;

}

public Integer getPageSize() {

return pageSize;

}

public BaseDTO setPageSize(Integer pageSize) {

this.pageSize = pageSize;

return this;

}

public Integer getStart() {

if (this.currPage != null && this.currPage > 0) {

start = (currPage - 1) * getPageSize();

return start;

}

return start == null ? 0 : start;

}

public BaseDTO setStart(Integer start) {

this.start = start;

return this;

}

public Integer getEnd() {

return getPageSize();

}

public BaseDTO setEnd(Integer end) {

this.end = end;

return this;

}

public String getLoginUserId() {

return loginUserId;

}

public BaseDTO setLoginUserId(String loginUserId) {

this.loginUserId = loginUserId;

return this;

}

public String getLoginUserName() {

return loginUserName;

}

public BaseDTO setLoginUserName(String loginUserName) {

this.loginUserName = loginUserName;

return this;

}

}Pager分页类

public class Pager implements Serializable {

private static final long serialVersionUID = -6557244954523041805L;

/*** 当前页数*/

private int currPage;

/*** 每页记录数*/

private int pageSize;

/*** 总页数*/

private int totalPage;

/*** 总记录数*/

private int totalCount;

/*** 列表数据*/

private List list;

public Pager(int currPage, int pageSize) {

this.currPage = currPage;

this.pageSize = pageSize;

}

public Pager(int currPage, int pageSize, int totalCount, List list) {

this.currPage = currPage;

this.pageSize = pageSize;

this.totalPage = (int) Math.ceil((double) totalCount / pageSize);;

this.totalCount = totalCount;

this.list = list;

}

public int getCurrPage() {

return currPage;

}

public Pager setCurrPage(int currPage) {

this.currPage = currPage;

return this;

}

public int getPageSize() {

return pageSize;

}

public Pager setPageSize(int pageSize) {

this.pageSize = pageSize;

return this;

}

public int getTotalPage() {

return totalPage;

}

public Pager setTotalPage(int totalPage) {

this.totalPage = totalPage;

return this;

}

public int getTotalCount() {

return totalCount;

}

public Pager setTotalCount(int totalCount) {

this.totalCount = totalCount;

return this;

}

public List getList() {

return list;

}

public Pager setList(List list) {

this.list = list;

return this;

}

}IdRequest公共请求类

public class IdRequest extends BaseDTO {

private Long id;

public Long getId() {

return id;

}

public IdRequest setId(Long id) {

this.id = id;

return this;

}

}

2.3、编写代码生成器

前两部分主要介绍的是如何获取对应的表结构,以及代码器运行之前的准备工作。

其实代码生成器,很简单,其实就是一个main方法,没有想象中的那么复杂。

处理思路也很简单,过程如下:1、定义基本变量,例如包名路径、模块名、表名、转换后的实体类、以及数据库连接配置,我们可以将其写入配置文件

2、读取配置文件,封装对应的模板中定义的变量

3、根据对应的模板文件和变量,生成对应的java文件

2.3.1、创建配置文件,定义变量

小编我用的是application.properties配置文件来定义变量,这个没啥规定,你也可以自定义文件名,内容如下:

#包前缀

packageNamePre=com.example.generator

#模块名称

moduleName=test

#表

tableName=test_db

#实体类名称

entityName=TestEntity

#主键ID

primaryId=id

#作者

authorName=pzblog

#数据库名称

databaseName=yjgj_base

#数据库服务器IP地址

ipName=127.0.0.1

#数据库服务器端口

portName=3306

#用户名

userName=root

#密码

passWord=123456

#文件输出路径,支持自定义输出路径,如果为空,默认取当前工程的src/main/java路径

outUrl=

2.3.2、根据模板生成对应的java代码首先,读取配置文件变量

public class SystemConstant {

private static Properties properties = new Properties();

static {

try {

// 加载上传文件设置参数:配置文件 properties.load(SystemConstant.class.getClassLoader().getResourceAsStream("application.properties"));

} catch (IOException e) {

e.printStackTrace();

}

}

public static final String tableName = properties.getProperty("tableName");

public static final String entityName = properties.getProperty("entityName");

public static final String packageNamePre = properties.getProperty("packageNamePre");

public static final String outUrl = properties.getProperty("outUrl");

public static final String databaseName = properties.getProperty("databaseName");

public static final String ipName = properties.getProperty("ipName");

public static final String portName = properties.getProperty("portName");

public static final String userName = properties.getProperty("userName");

public static final String passWord = properties.getProperty("passWord");

public static final String authorName = properties.getProperty("authorName");

public static final String primaryId = properties.getProperty("primaryId");

public static final String moduleName = properties.getProperty("moduleName");

}然后,封装对应的模板中定义的变量

public class CodeService {

public void generate(Map templateData) {

//包前缀 String packagePreAndModuleName = getPackagePreAndModuleName(templateData);

//支持对应实体插入在前面,需要带上%s templateData.put("entityPackageName", String.format(packagePreAndModuleName + ".entity",

templateData.get("entityName").toString().toLowerCase()));

templateData.put("dtoPackageName", String.format(packagePreAndModuleName + ".dto",

templateData.get("entityName").toString().toLowerCase()));

templateData.put("voPackageName", String.format(packagePreAndModuleName + ".vo",

templateData.get("entityName").toString().toLowerCase()));

templateData.put("daoPackageName", String.format(packagePreAndModuleName + ".dao",

templateData.get("entityName").toString().toLowerCase()));

templateData.put("mapperPackageName", packagePreAndModuleName + ".mapper");

templateData.put("servicePackageName", String.format(packagePreAndModuleName + ".service",

templateData.get("entityName").toString().toLowerCase()));

templateData.put("serviceImplPackageName", String.format(packagePreAndModuleName + ".service.impl",

templateData.get("entityName").toString().toLowerCase()));

templateData.put("controllerPackageName", String.format(packagePreAndModuleName + ".web",

templateData.get("entityName").toString().toLowerCase()));

templateData.put("apiTestPackageName", String.format(packagePreAndModuleName + ".junit",

templateData.get("entityName").toString().toLowerCase()));

templateData.put("currentTime", new SimpleDateFormat("yyyy-MM-dd").format(new Date()));

//======================生成文件配置====================== try {

// 生成Entity String entityName = String.format("%s", templateData.get("entityName").toString());

generateFile("entity.ftl", templateData, templateData.get("entityPackageName").toString(), entityName+".java");

// 生成dto String dtoName = String.format("%sDTO", templateData.get("entityName").toString());

templateData.put("dtoName", dtoName);

generateFile("dto.ftl", templateData, templateData.get("dtoPackageName").toString(),

dtoName + ".java");

// 生成VO String voName = String.format("%sVO", templateData.get("entityName").toString());

templateData.put("voName", voName);

generateFile("vo.ftl", templateData, templateData.get("voPackageName").toString(),

voName + ".java");

// 生成DAO String daoName = String.format("%sDao", templateData.get("entityName").toString());

templateData.put("daoName", daoName);

generateFile("dao.ftl", templateData, templateData.get("daoPackageName").toString(),

daoName + ".java");

// 生成Mapper String mapperName = String.format("%sMapper", templateData.get("entityName").toString());

generateFile("mapper.ftl", templateData, templateData.get("mapperPackageName").toString(),

mapperName+".xml");

// 生成Service String serviceName = String.format("%sService", templateData.get("entityName").toString());

templateData.put("serviceName", serviceName);

generateFile("service.ftl", templateData, templateData.get("servicePackageName").toString(),

serviceName + ".java");

// 生成ServiceImpl String serviceImplName = String.format("%sServiceImpl", templateData.get("entityName").toString());

templateData.put("serviceImplName", serviceImplName);

generateFile("serviceImpl.ftl", templateData, templateData.get("serviceImplPackageName").toString(),

serviceImplName + ".java");

// 生成Controller String controllerName = String.format("%sController", templateData.get("entityName").toString());

templateData.put("controllerName", controllerName);

generateFile("controller.ftl", templateData, templateData.get("controllerPackageName").toString(),

controllerName + ".java");

// // 生成junit测试类// String apiTestName = String.format("%sApiTest", templateData.get("entityName").toString());// templateData.put("apiTestName", apiTestName);// generateFile("test.ftl", templateData, templateData.get("apiTestPackageName").toString(),// apiTestName + ".java");

} catch (Exception e) {

e.printStackTrace();

}

}

/*** 生成文件* @param templateName 模板名称* @param templateData 参数名* @param packageName 包名* @param fileName 文件名*/

public void generateFile(String templateName, Map templateData, String packageName, String fileName) {

templateData.put("fileName", fileName);

DaseService dbService = new DaseService(templateData);

// 获取数据库参数 if("entity.ftl".equals(templateName) || "mapper.ftl".equals(templateName)){

dbService.getAllColumns(templateData);

}

try {

// 默认生成文件的路径 FreeMakerUtil freeMakerUtil = new FreeMakerUtil();

freeMakerUtil.generateFile(templateName, templateData, packageName, fileName);

} catch (Exception e) {

e.printStackTrace();

}

}

/*** 封装包名前缀* @return*/

private String getPackagePreAndModuleName(Map templateData){

String packageNamePre = templateData.get("packageNamePre").toString();

String moduleName = templateData.get("moduleName").toString();

if(StringUtils.isNotBlank(moduleName)){

return packageNamePre + "." + moduleName;

}

return packageNamePre;

}

}接着,获取模板文件,并生成相应的模板文件

public class FreeMakerUtil {

/*** 根据Freemark模板,生成文件* @param templateName:模板名* @param root:数据原型* @throws Exception*/

public void generateFile(String templateName, Map root, String packageName, String fileName) throws Exception {

FileOutputStream fos=null;

Writer out =null;

try {

// 通过一个文件输出流,就可以写到相应的文件中,此处用的是绝对路径 String entityName = (String) root.get("entityName");

String fileFullName = String.format(fileName, entityName);

packageName = String.format(packageName, entityName.toLowerCase());

String fileStylePackageName = packageName.replaceAll("\\.", "/");

File file = new File(root.get("outUrl").toString() + "/" + fileStylePackageName + "/" + fileFullName);

if (!file.getParentFile().exists()) {

file.getParentFile().mkdirs();

}

file.createNewFile();

Template template = getTemplate(templateName);

fos = new FileOutputStream(file);

out = new OutputStreamWriter(fos);

template.process(root, out);

out.flush();

} catch (Exception e) {

e.printStackTrace();

} finally {

try {

if (fos != null){

fos.close();

}

if(out != null){

out.close();

}

} catch (IOException e) {

e.printStackTrace();

}

}

}

/**** 获取模板文件** @param name* @return*/

public Template getTemplate(String name) {

try {

Configuration cfg = new Configuration(Configuration.VERSION_2_3_23);

cfg.setClassForTemplateLoading(this.getClass(), "/ftl");

Template template = cfg.getTemplate(name);

return template;

} catch (IOException e) {

e.printStackTrace();

}

return null;

}

}最后,我们编写一个main方法,看看运行之后的效果

public class GeneratorMain {

public static void main(String[] args) {

System.out.println("生成代码start......");

//获取页面或者配置文件的参数 Map templateData = new HashMap();

templateData.put("tableName", SystemConstant.tableName);

System.out.println("表名=="+ SystemConstant.tableName);

templateData.put("entityName", SystemConstant.entityName);

System.out.println("实体类名称=="+ SystemConstant.entityName);

templateData.put("packageNamePre", SystemConstant.packageNamePre);

System.out.println("包名前缀=="+ SystemConstant.packageNamePre);

//支持自定义输出路径 if(StringUtils.isNotBlank(SystemConstant.outUrl)){

templateData.put("outUrl", SystemConstant.outUrl);

} else {

String path = GeneratorMain.class.getClassLoader().getResource("").getPath() + "../../src/main/java";

templateData.put("outUrl", path);

}

System.out.println("生成文件路径为=="+ templateData.get("outUrl"));

templateData.put("authorName", SystemConstant.authorName);

System.out.println("以后代码出问题找=="+ SystemConstant.authorName);

templateData.put("databaseName", SystemConstant.databaseName);

templateData.put("ipName", SystemConstant.ipName);

templateData.put("portName", SystemConstant.portName);

templateData.put("userName", SystemConstant.userName);

templateData.put("passWord", SystemConstant.passWord);

//主键ID templateData.put("primaryId", SystemConstant.primaryId);

//模块名称 templateData.put("moduleName", SystemConstant.moduleName);

CodeService dataService = new CodeService();

try {

//生成代码文件 dataService.generate(templateData);

} catch (Exception e) {

e.printStackTrace();

}

System.out.println("生成代码end......");

}

}

结果如下:生成的 Controller 层代码如下

/**

*

* @ClassName: TestEntityController

* @Description: 外部访问接口

* @author pzblog

* @date 2020-11-16

*

*/

@RestController

@RequestMapping("/testEntity")

public class TestEntityController {

@Autowired

private TestEntityService testEntityService;

/**

* 分页列表查询

* @param request

*/

@PostMapping(value = "/getPage")

public Pager getPage(@RequestBody TestEntityDTO request){

return testEntityService.getPage(request);

}

/**

* 查询详情

* @param request

*/

@PostMapping(value = "/getDetail")

public TestEntityVO getDetail(@RequestBody IdRequest request){

TestEntity source = testEntityService.selectById(request.getId());

if(Objects.nonNull(source)){

TestEntityVO result = new TestEntityVO();

BeanUtils.copyProperties(source, result);

return result;

}

return null;

}

/**

* 新增操作

* @param request

*/

@PostMapping(value = "/save")

public void save(TestEntityDTO request){

TestEntity entity = new TestEntity();

BeanUtils.copyProperties(request, entity);

testEntityService.insert(entity);

}

/**

* 编辑操作

* @param request

*/

@PostMapping(value = "/edit")

public void edit(TestEntityDTO request){

TestEntity entity = new TestEntity();

BeanUtils.copyProperties(request, entity);

testEntityService.updateById(entity);

}

/**

* 删除操作

* @param request

*/

@PostMapping(value = "/delete")

public void delete(IdRequest request){

testEntityService.deleteById(request.getId());

}

}

至此,一张单表的90%的基础工作量全部开发完毕!

三、总结

代码生成器,在实际的项目开发中应用非常的广,本文主要以freemaker模板引擎为基础,开发的一套全自动代码生成器,一张单表的CRUD,只需要5秒钟就可以完成!

最后多说一句,如果你是项目负责人,那么代码生成器会是一个比较好的提升项目开发效率的工具,希望能帮到各位!原作者:鸭血粉丝

原文链接:【非广告】你还在手写crud吗,看完这篇文章,绝对赚了

原出处: Java极客技术

侵删

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值