缘起

咱们好呀,我是大鹅

最近在做一个项目,需要新建20多张表

信任大多数同学应该和我相同,都是比较讨厌创立新表这个作业的,因为每创立一张表,都要去创立实体类、创立增修正查的接口、编写增修正查的SQL代码等等,把这些事情做完,2个小时也就过去了

我就在思考啊,每一张表,就要耗费两个小时,20多张表,那便是40多个小时,一周的时刻就这样过去了。

我写了个工具,让CRUD开发效率提升100倍

这谁受得了呀,所以我计划写一个东西,把这些代码都主动生成出来!

我写了个工具,让CRUD开发效率提升100倍

在接连爆肝了5个晚上之后,我做出了这款主动生成事务代码的东西!

我写了个工具,让CRUD开发效率提升100倍

我把它放在了我的东西站上,咱们能够拜访这个域名直接运用

utilsbox.cn/?app=bizcod…

运用演示

下面给咱们演示一下

假定咱们现在创立一个商品表

首要填写表名和表的中文名称

然后咱们增加商品表对应的字段,这些操作和咱们日常运用的数据库东西差不多

把字段填写好了之后,点击“一键生成代码”

我写了个工具,让CRUD开发效率提升100倍

高潮的当地来了

DB层、事务层、甚至是controller层的代码,东西都帮咱们主动生成了!

来看下代码,建表sql、增修正查sql、表对应的实体类、DB层的接口类、事务层的实体类、事务层的接口类、事务接口的完成类、事务层实体类和db层实体类的转换器,最终是controller层,这些代码全都帮咱们生成好了。

我写了个工具,让CRUD开发效率提升100倍

这是什么概念呢

现在咱们只需要把这些代码拷贝到项目里,简略设置一下类的引证,增修正查这些根本功用,就现已能够直接给前端去调用了。

我写了个工具,让CRUD开发效率提升100倍

许多同学或许会问,假如是现有的数据表,再来这儿增加一次感觉太麻烦了

这个问题我也遇到了,所以我做了一个辨认建表SQL的功用,常见的数据库东西关于现已创立好的表,都供给建表语句的复制功用,只需要把建表SQL粘贴到这个文本框里。

点击“辨认”按钮,这个SQL的信息会主动辨认过来,这时候只需要把表的中文名称填写上去,点击“一键生成代码”,就能够立刻得到这个表的事务代码。

我写了个工具,让CRUD开发效率提升100倍

通用性的思考

不知道咱们觉得怎样样哈,假如仅仅我自己用,我觉着现已非常好了,但既然是敞开出来给咱们用,通用性肯定还是不够的。

因为现在看到的这一套主动生成的代码,或许仅仅合适我,但不同的人、不同的公司,它们项目结构的分层、代码的细节,都是不相同的

所以,我还开发了代码模版装备的功用

点击“代码模版装备”按钮,在这个弹窗里,咱们能够新增、删去代码的分类。同样的,也能够新增、删去和修正具体的代码模版。

我写了个工具,让CRUD开发效率提升100倍

代码生成的原理

在说代码模版具体怎样装备之前,先给咱们讲一下代码主动生成的原理

它由代码模版和动态参数组成,核心便是匹配 – 替换

首要,东西供给了许多动态参数,这些动态参数,对应的是咱们填写的表名、字段名等等这些信息的原始值,或许处理往后的值。

然后,代码模版由用户自行界说,在代码的关键方位,刺进动态参数,即可构成一份代码模版。

最终,东西通过匹配和替换动态参数,最终生成了代码。

理论上,不论什么语言,你都能够装备专属于你自己的代码模版。

举个简略的栗子:

咱们装备了一份这样的代码模版,如下:

/**
 * $table_desc$Model模型
 * Created by 创立人 on $current_time$.
 */
public class $table_name_hump_A$Model extends ToString{
}

能够看到,模版里分别运用了$table_desc$(表中文名)$current_time$(当时时刻)$table_name_hump_A$(表名转首字母大写驼峰) 这三个动态参数。

当咱们设置 表名 = goods_order、表中文名 = 商品订单 时,代码生成的成果如下所示:

/**
 * 商品订单Model模型
 * Created by 创立人 on 2023-02-05 17:12:32.
 */
public class GoodsOrderModel extends ToString{
}

动态参数部分,悉数替换成了咱们输入的表信息。

最终希望这个项目对咱们有用,之后我会开发更多有意思的项目。

因为这个项目都是晚上加班肝出来的,或许会存在一些BUG,发现了我会尽快修正的,也请咱们多多包涵。

这几天我会收拾一下代码,把注释什么的都写好,然后把代码完完整整的开源给咱们,感谢咱们的观看,咱们下期见。

我写了个工具,让CRUD开发效率提升100倍

代码模版参阅

以下是当时东西里默认的代码模版,你能够通过参阅这些模版,举一反三,装备出专属于你自己的代码模版。

东西供给了模版的导入和导出功用,假如你创立好了一份非常满意的模版,能够导出,然后发给你的搭档直接运用,这样它就不必重复创立了,你也能够忽悠你的搭档来创立,然后共享给你。

建表SQL模版

CREATE TABLE `$table_name$` (
  $create_table_field_list$
  PRIMARY KEY (`$primary_key$`)
) ENGINE=$db_engine$ DEFAULT CHARSET=$db_encoded$;

实体类模版

主体

/**
 * $table_desc$DTO模型
 * Created by 创立人 on $current_time$.
 */
public class $table_name_hump_A$DO {
    $member_param_list$
    $get_set_method_list$
}

成员代码块 成员变量列表(member_param_list)

    /** $field_comment$ */
    private $field_type_java$ $field_name_hump$;

成员代码块 GetSet办法列表(get_set_method_list)

    public $field_type_java$ get$field_name_hump_A$() {
        return $field_name_hump$;
    }
    public void set$field_name_hump_A$($field_type_java$ $field_name_hump$) {
        this.$field_name_hump$ = $field_name_hump$;
    }

接口类模版(DB层)

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
/**
 * $table_desc$DB接口
 * Created by 创立人 on $current_time$
 */
@Mapper
public interface $table_name_hump_A$DAO {
    /**
     * 增加
     * @param data
     * return 影响行数
     */
    int insert($table_name_hump_A$DO data);
    /**
     * 修正
     * @param data
     * return 影响行数
     */
    int update($table_name_hump_A$DO data);
    /**
     * 分页查询
     * @param param
     * return 成果列表
     */
    List<$table_name_hump_A$DO> pageQuery(Map param);
    /**
     * 查询count
     * @param param
     * return count条数
     */
    Long pageQueryCount(Map param);
    /**
     * 依据ID查询
     * @param id
     * return 成果DO对象
     */
    $table_name_hump_A$DO queryById(@Param("$primary_key_hump$") $primary_key_type_java$ $primary_key_hump$);
    /**
     * 依据ID查询(带锁)
     * @param id
     * return 成果DO对象
     */
    $table_name_hump_A$DO queryByIdLock(@Param("$primary_key_hump$") $primary_key_type_java$ $primary_key_hump$);
}

CRUD SQL模版

<?xml version="1.0" encoding="UTF-8"?>
<!-- $table_name_hump_A$Mapper.xml -->
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xxx.$table_name_hump_A$DAO">
    <insert id="insert" useGeneratedKeys="true" keyProperty="id">
        INSERT INTO $table_name$($insert_field_name_list$)
        VALUES ($insert_field_value_list$);
    </insert>
    <update id="update">
        UPDATE $table_name$ SET
            $update_field_list$
        WHERE $primary_key$ = #{$primary_key_hump$};
    </update>
    <select id="pageQuery" resultType="com.xxx.$table_name_hump_A$DO">
        SELECT $select_field_list$ FROM $table_name$
        WHERE 1=1
        $while_field_list$
        ORDER BY $primary_key$ DESC
        <if test="pageIndex != null and pageSize != null">
            LIMIT #{offset},#{rows}
        </if>
    </select>
    <select id="pageQueryCount" resultType="java.lang.Long">
        SELECT COUNT(1) as total FROM $table_name$
        WHERE 1=1
        $while_field_list$
    </select>
    <select id="queryById" resultType="com.xxx.$table_name_hump_A$DO">
        SELECT $select_field_list$ FROM $table_name$
        WHERE $primary_key$ = #{$primary_key_hump$};
    </select>
    <select id="queryByIdLock" resultType="com.xxx.$table_name_hump_A$DO">
        SELECT $select_field_list$ FROM $table_name$
        WHERE $primary_key$ = #{$primary_key_hump$} FOR UPDATE;
    </select>
</mapper>

模型转换器模版

不同层级间,或许会有不同的实体类,那么它们相互之间的数据转换,也是一个重复且浪费时刻的作业,所以也能够装备一个模版。

import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.List;
/**
 * $table_desc$模型转换器
 * Created by 创立人 on $current_time$
 */
public class $table_name_hump_A$Converter {
    /**
     * dto转do
     * @param source
     * return do模型
     */
    public static $table_name_hump_A$DO toDo($table_name_hump_A$DTO source){
        $table_name_hump_A$DO target = new $table_name_hump_A$DO();
        $converter_source_to_target_params_list$
        return target;
    }
    /**
     * do转dto
     * @param source
     * return dto模型
     */
    public static $table_name_hump_A$DTO toDto($table_name_hump_A$DO source){
        $table_name_hump_A$DTO target = new $table_name_hump_A$DTO();
        $converter_source_to_target_params_list$
        return target;
    }
    /**
     * do list 转 dto
     * @param data
     * return list dto模型
     */
    public static List<$table_name_hump_A$DTO> toDtoList(List<$table_name_hump_A$DO> data){
        if (CollectionUtils.isEmpty(data)){
            return null;
        }
        List<$table_name_hump_A$DTO> list = new ArrayList<>();
        for ($table_name_hump_A$DO item : data){
            list.add($table_name_hump_A$Converter.toDto(item));
        }
        return list;
    }
}

成员代码块 模型转换器参数列表(converter_source_to_target_params_list)

        target.set$field_name_hump_A$(source.get$field_name_hump_A$());

事务接口完成类模版

import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
/**
 * $table_desc$事务完成
 * Created by 创立人 on $current_time$
 */
@Service
public class $table_name_hump_A$ServiceImpl implements $table_name_hump_A$Service {
    private static final Logger LOGGER = LoggerFactory.getLogger($table_name_hump_A$ServiceImpl.class);
    @Resource
    private $table_name_hump_A$DAO $table_name_hump$DAO;
    @Override
    public CommonResult create(JSONObject request) {
        // 入参转成对应类型
        CommonAssert.isNoEmptyObj(request, "恳求参数不行空");
        $table_name_hump_A$DTO dto = JSON.toJavaObject(request, $table_name_hump_A$DTO.class);
        // 参数校验
    	$biz_check_required_params$
        // 转成do模型
        $table_name_hump_A$DO dataDo = $table_name_hump_A$Converter.toDo(dto);
        // 落库
        int count = $table_name_hump$DAO.insert(dataDo);
        CommonAssert.isTrue(count > 0, "创立失败,请重试");
        // 回来创立成功的ID数据
        return new CommonResult(dataDo.get$primary_key_hump_A$());
    }
    @Override
    public CommonResult modify(JSONObject request) {
        // 入参转成对应类型
        CommonAssert.isNoEmptyObj(request, "恳求参数不行空");
        $table_name_hump_A$DTO dto = JSON.toJavaObject(request, $table_name_hump_A$DTO.class);
        // 参数校验
    	$biz_check_required_params$
        // 转成do模型
        $table_name_hump_A$DO dataDo = $table_name_hump_A$Converter.toDo(dto);
        // 落库
        int count = $table_name_hump$DAO.update(dataDo);
        CommonAssert.greaterThanZero(count, "修正失败,请重试");
        // 回来修正成功的ID数据
        return new CommonResult(dataDo.get$primary_key_hump_A$());
    }
    @Override
    public CommonResult pageQuery(JSONObject request) {
        // 入参根本校验
        CommonAssert.isNoEmptyObj(request, "恳求参数不行空");
        // 分页信息校验
        PaginationDO pagination = PaginationDO.setRequestOffsetAndRows(request);
        CommonAssert.isNoEmptyObj(pagination, "分页参数 $pageIndex、$pageSize 不行空");
        CommonAssert.isTrue(pagination.getPageSize() <= 100, "单次查询条数不行超过100条");
        // 取分页列表数据
        List<$table_name_hump_A$DO> dbResult = $table_name_hump$DAO.pageQuery(request);
        // 取count数据
        long count = $table_name_hump$DAO.pageQueryCount(request);
        // 空回来
        if (CollectionUtils.isEmpty(dbResult)){
            return new CommonResult(new PaginationResult(null, request, count));
        }
        // 模型转换
        List<$table_name_hump_A$DTO> list = $table_name_hump_A$Converter.toDtoList(dbResult);
        // 回来分页成果
        return new CommonResult(new PaginationResult(list, request, count));
    }
    @Override
    public CommonResult queryById(JSONObject request) {
        // 取入参
        CommonAssert.isNoEmptyObj(request, "恳求参数不行空");
        // 依据ID获取数据
        $primary_key_type_java$ $primary_key_hump$ = request.get$primary_key_type_java$("$primary_key_hump$");
        CommonAssert.isNoEmptyObj($primary_key_hump$, "参数错误,无法履行查询");
        $table_name_hump_A$DO dbResult = $table_name_hump$DAO.queryById($primary_key_hump$);
        // 未查询到成果,回来
        if (null == dbResult){
            return new CommonResult();
        }
        // 模型转换
        $table_name_hump_A$DTO result = $table_name_hump_A$Converter.toDto(dbResult);
        // 回来成果对象
        return new CommonResult(result);
    }
}

成员代码块 必填项事务校验(biz_check_required_params)

        CommonAssert.$java_type_adapter_assert_method$(dto.get$field_name_hump_A$(), "$field_comment$不行空");

Controller模版

import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
/**
 * $table_desc$HTTP恳求控制器
 * Created by 创立人 on $current_time$.
 */
@CrossOrigin
@RestController
@RequestMapping(value = "/$table_name_hump$/")
public class $table_name_hump_A$Controller {
    private static final Logger LOGGER = LoggerFactory.getLogger($table_name_hump_A$Controller.class);
    @Resource
    private $table_name_hump_A$Service $table_name_hump$Service;
    /**
     * 创立
     * @param request
     * @return
     */
    @RequestMapping(value = "create.json", method = {RequestMethod.GET, RequestMethod.POST})
    @ResponseBody
    public Object create(@RequestBody JSONObject request){
        return CommonTemplate.run(LOGGER, new CommonTemplate() {
            @Override
            protected Object business() {
                return $table_name_hump$Service.create(request);
            }
        }, request);
    }
    /**
     * 修正
     * @param request
     * @return
     */
    @RequestMapping(value = "modify.json", method = {RequestMethod.GET, RequestMethod.POST})
    @ResponseBody
    public Object modify(@RequestBody JSONObject request){
        return CommonTemplate.run(LOGGER, new CommonTemplate() {
            @Override
            protected Object business() {
                return $table_name_hump$Service.modify(request);
            }
        }, request);
    }
    /**
     * 分页查询
     * @param request
     * @return
     */
    @RequestMapping(value = "pageQuery.json", method = {RequestMethod.GET, RequestMethod.POST})
    @ResponseBody
    public Object pageQuery(@RequestBody JSONObject request){
        return CommonTemplate.run(LOGGER, new CommonTemplate() {
            @Override
            protected Object business() {
                return $table_name_hump$Service.pageQuery(request);
            }
        }, request);
    }
    /**
     * 通过主键查询
     * @param request
     * @return
     */
    @RequestMapping(value = "queryById.json", method = {RequestMethod.GET, RequestMethod.POST})
    @ResponseBody
    public Object queryById(@RequestBody JSONObject request){
        return CommonTemplate.run(LOGGER, new CommonTemplate() {
            @Override
            protected Object business() {
                return $table_name_hump$Service.queryById(request);
            }
        }, request);
    }
}

动态参数

原始表名 $table_name$

用户输入的表名,不做任何处理。

表名驼峰首字母小写 $table_name_hump$

用户输入的表名,通过驼峰处理。例如输入:goods_order ,输出:goodsOrder

表名驼峰首字母大写 $table_name_hump_A$

用户输入的表名,通过驼峰处理。例如输入:goods_order ,输出:GoodsOrder

原始字段名 $field_name$

用户输入的表字段名,不做任何处理。

字段名驼峰首字母小写 $field_name_hump$

用户输入的表字段名,通过驼峰处理。例如输入:order_number ,输出:orderNumber

字段名驼峰首字母大写 $field_name_hump_A$

用户输入的表字段名,通过驼峰处理。例如输入:order_number ,输出:OrderNumber

字段说明 $field_comment$

用户输入的表字段说明,不做任何处理。

字段数据类型(对应DB)$field_type_db$

用户挑选的表字段类型,不做任何处理。

字段数据类型(对应Java)$field_type_java$

用户挑选的表字段类型,会主动匹配对应的Java类型。例如输入:VARCHAR(),输出:String

主键字段名 $primary_key$

用户挑选的主键字段,不做任何处理。例如用户界说的主键是id,那么输出便是:id

主键字段名驼峰首字母小写 $primary_key_hump$

用户挑选的主键字段,通过驼峰处理。例如输入:order_number ,输出:orderNumber

主键字段名驼峰首字母大写 $primary_key_hump_A$

用户挑选的主键字段,通过驼峰处理。例如输入:order_number ,输出:OrderNumber

主键字段数据类型(对应Java)$primary_key_type_java$

用户挑选的主键字段类型,会主动匹配对应的Java类型。例如输入:VARCHAR(),输出:String

刺进数据sql,字段名列表 $insert_field_name_list$

例如表中有三个字段:id(主键)、goods_name、price,输出:goods_name,price 。会主动扫除主键 不只刺进数据时可用,任何需要扫除ID,然后运用英文逗号拼接表一切字段信息的当地,都能够运用它

刺进数据sql,字段值列表 $insert_field_value_list$

例如表中有三个字段:id(主键)、goods_name、price,输出:#{goodsName},#{price} 。会主动扫除主键 不只刺进数据时可用,任何需要扫除ID,然后运用英文逗号拼接表一切字段信息的当地,都能够运用它

修正数据sql,字段名列表 $update_field_list$

例如表中有三个字段:id(主键)、goods_name、price 输出(会主动换行,会带着以下缩进,会主动扫除主键):

            goods_name = #{goodsName},
            price = #{price}

查询数据sql,字段名列表 $select_field_list$

例如表中有三个字段:id(主键)、goods_name、price,输出:id,goods_name,price 。带主键

whele字段条件sql,字段名列表 $whele_field_list$

例如表中有三个字段:id(主键)、goods_name、price, 输出(会主动换行,会带着以下缩进):

        <if test="id != null">
            AND id = #{id}
        </if>
        <if test="goodsName != null">
            AND goods_name = #{goodsName}
        </if>
        <if test="price != null">
            AND price = #{price}
        </if>

创立表-表字段列表 $create_table_field_list$

例如表中有三个字段:id(自增主键)、goods_name、price 输出(会主动换行,会带着以下缩进):

  `id` INT(11) NOT NULL AUTO_INCREMENT,
  `goods_name` VARCHAR(128) NOT NULL DEFAULT 'NULL',
  `price` DECIMAL(10,2) NOT NULL DEFAULT 'NULL'

当时时刻 $current_time$

主动获取当时时刻,格局:yyyy-MM-DD hh:mm:ss,示例值:2023-02-05 17:31:18

主动依据数据类型,匹配断言办法 $java_type_adapter_assert_method$

关于Java数据类型等于String的字段,运用isNoBlankStr办法,其他的类型都运用isNoEmptyObj办法 这是一个定制化很高的动态参数,可疏忽它。

动态代码块

动态代码块由用户自行界说,代码块中也能够设置动态参数,现在仅供给4种明确的动态代码块

成员变量列表 $member_param_list$

例如表中有三个字段:id(主键)、goods_name、price

假定用户界说了如下代码块内容:

    /** $field_comment$ */
    private $field_type_java$ $field_name_hump$;

输出(会主动依据字段数量,累加输出自界说代码块内容):

    /** id */
    private Integer id;
    /** 商品名称 */
    private String goodsName;
    /** 商品价格 */
    private String price;

GetSet办法列表 $get_set_method_list$

例如表中有三个字段:id(主键)、goods_name、price

假定用户界说了如下代码块内容:

    public $field_type_java$ get$field_name_hump_A$() {
        return $field_name_hump$;
    }
    public void set$field_name_hump_A$($field_type_java$ $field_name_hump$) {
        this.$field_name_hump$ = $field_name_hump$;
    }

输出(会主动依据字段数量,累加输出自界说代码块内容):

    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getGoodsName() {
        return goodsName;
    }
    public void setGoodsName(String goodsName) {
        this.goodsName = goodsName;
    }
    public String getPrice() {
        return price;
    }
    public void setPrice(String price) {
        this.price = price;
    }

模型转换器参数列表 $converter_source_to_target_params_list$

例如表中有三个字段:id(主键)、goods_name、price

假定用户界说了如下代码块内容:

        target.set$field_name_hump_A$(source.get$field_name_hump_A$());

输出(会主动依据字段数量,累加输出自界说代码块内容):

        target.setId(source.getId());
        target.setGoodsName(source.getGoodsName());
        target.setPrice(source.getPrice());

必填项事务校验 $biz_check_required_params$

例如表中有三个字段:id(主键)、goods_name、price

假定用户界说了如下代码块内容:

        CommonAssert.$java_type_adapter_assert_method$(dto.get$field_name_hump_A$(), "$field_comment$不行空");

输出(会主动依据字段数量,累加输出自界说代码块内容):

        CommonAssert.isNoBlankStr(dto.getGoodsName(), "goodsName不行空");
        CommonAssert.isNoBlankStr(dto.getPrice(), "price不行空");