首页 > 其他分享 >30分钟内搞定 50张表的 CRUD,666!

30分钟内搞定 50张表的 CRUD,666!

时间:2023-06-11 23:04:01浏览次数:37  
标签:function CRUD 666 30 sysTest res var data id


大家好,我是田哥

前面我跟大家分享小伙伴正在用它来练练手,其中,有个非常聪明的小伙伴发现了个问题:大量类似的代码,差不多一样的CRUD.

30分钟内搞定 50张表的 CRUD,666!_html

医院项目里确实存在大量的CRUD,其实嘛,医院项目毕竟还是重点偏向于后台管理系统,不过,我前段时间增加了外网预约挂号功能,但再怎么说,也还是偏向于后台,比较主要的工作量都在后台。做过后台系统的都知道,后台系统会存在大量的CRUD。但话又说回来,不是后台系统也存在大部分功能都是CRUD的。

于是,来找我能不能搞一个就可以了,其他的复制过去,再改改就成了。

想想也是哈,那么多重复的CRUD,只是字段不同而已。

但,也别小看这个改字段的过程,或许因为你改错一个、少改一个字段,你需要花时间去排查的。

所以,我觉得很有必要搞一个代码生成工具,一次性把controller、service、mappper代码生成,甚至把HTML、数据导出、权限控制、swagger文档都给生成出来。


演示

我们只要创建好我们的业务表,即可搞定代码生成。比如:我们来建个表:sys_test,三个字段,主键自增。

CREATE TABLE `sys_test` (
  `id` int NOT NULL,
  `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
  `create_time` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

然后到代码生成页面,把系统数据库表全部查出来。

30分钟内搞定 50张表的 CRUD,666!_开发语言_02

点击生成按钮,或者可以选多张表,一次性全部生成好。

技术栈:Spring Boot +shiro+thymeleaf+MyBatis-plus+MySQL

我们来看看,这个工具生成出来的代码长什么样。

controller层:页面跳转、swagger API 、分页查询....

@Controller
@RequestMapping("/")
public class SysTestController {
    @Autowired
    private SysTestService sysTestService;


    /**
    * 跳转到页面
    */
    @GetMapping("/index/sysTest")
    public String sysTest() {
        return "systest/list";
        }

    @ApiOperation(value = "新增")
    @PostMapping("sysTest/add")
    @RequiresPermissions("sysTest:add")
    @ResponseBody
    public DataResult add(@RequestBody SysTestEntity sysTest){
        sysTestService.save(sysTest);
        return DataResult.success();
    }

    @ApiOperation(value = "删除")
    @DeleteMapping("sysTest/delete")
    @RequiresPermissions("sysTest:delete")
    @ResponseBody
    public DataResult delete(@RequestBody @ApiParam(value = "id集合") List<String> ids){
        sysTestService.removeByIds(ids);
        return DataResult.success();
    }

    @ApiOperation(value = "更新")
    @PutMapping("sysTest/update")
    @RequiresPermissions("sysTest:update")
    @ResponseBody
    public DataResult update(@RequestBody SysTestEntity sysTest){
        sysTestService.updateById(sysTest);
        return DataResult.success();
    }

    @ApiOperation(value = "查询分页数据")
    @PostMapping("sysTest/listByPage")
    @RequiresPermissions("sysTest:list")
    @ResponseBody
    public DataResult findListByPage(@RequestBody SysTestEntity sysTest){
        Page page = new Page(sysTest.getPage(), sysTest.getLimit());
        LambdaQueryWrapper<SysTestEntity> queryWrapper = Wrappers.lambdaQuery();
        //查询条件示例
        //queryWrapper.eq(SysTestEntity::getId, sysTest.getId());
        IPage<SysTestEntity> iPage = sysTestService.page(page, queryWrapper);
        return DataResult.success(iPage);
    }

}

entity代码:

@Data
@TableName("sys_test")
public class SysTestEntity extends BaseEntity implements Serializable {
 private static final long serialVersionUID = 1L;

 /**
  * 
  */
 @TableId("id")
 private Integer id;

 /**
  * 
  */
 @TableField("name")
 private String name;

 /**
  * 
  */
 @TableField("create_time")
 private Date createTime;


}

mapper代码:

/**
 *  
 * @author tiange 
 * @date 2022-11-15 22:15:56
 */
public interface SysTestMapper extends BaseMapper<SysTestEntity> {
 
}

service接口层代码:

public interface SysTestService extends IService<SysTestEntity> {

}

service实现层代码:

@Service("sysTestService")
public class SysTestServiceImpl extends ServiceImpl<SysTestMapper, SysTestEntity> implements SysTestService {

}

SysTestMapper.xml代码:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.company.project.mapper.SysTestMapper">

 <!-- 可根据自己的需求,是否要使用 -->
    <resultMap type="com.company.project.entity.SysTestEntity" id="sysTestMap">
        <result property="id" column="id"/>
        <result property="name" column="name"/>
        <result property="createTime" column="create_time"/>
    </resultMap>


</mapper>

html代码:

<!DOCTYPE html>
<html lang="en" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro"
      xmlns:th="http://www.thymeleaf.org">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <link rel="stylesheet" th:href="@{/layui/css/layui.css}"/>
  <link rel="stylesheet" th:href="@{/css/custom.form.css}">
    <style id="layuimini-bg-color">
    </style>
<body>
<div class="panel panel-default operation" hidden>
  <div class="panel-heading title"></div>
<div class="layui-card-body">
<form class="layui-form " action="" lay-filter="info" style="width: 700px;margin-top: 10px">
      <input name="id" hidden/>
        <div class="layui-form-item">
      <label class="layui-form-label"></label>
      <div class="layui-input-block">
        <input type="name" name="name" placeholder="请输入" autocomplete="off" class="layui-input">
      </div>
    </div>
        <div class="layui-form-item">
      <label class="layui-form-label"></label>
      <div class="layui-input-block">
        <input type="createTime" name="createTime" placeholder="请输入" autocomplete="off" class="layui-input">
      </div>
    </div>
  <div class="layui-form-item">
  <div class="layui-input-block">
    <button type="submit" class="layui-btn" lay-submit="" lay-filter="submit">保存</button>
    <button  class="layui-btn layui-btn-primary" id="btn_cancel">返回</button>
  </div>
</div>
</form>
</div>
</div>

<div class="table_div">
  <div id="searchParam"  shiro:hasPermission="sysTest:list">
    <form class="layui-form ">
      <div class="layui-form-item">
        <div class="layui-input-inline">
          <input type="text" id="key" class="layui-input"  autocomplete="off" placeholder="请输入">
        </div>

        <div class="layui-input-inline ">
          <button class="layui-btn" onclick="search()"  id="search">查询</button>
          <button class="layui-btn"   id="export">导出全部</button>
        </div>
      </div>
    </form>
  </div>
  <table class="layui-table" id="showTable" lay-filter="showTable" ></table>
</div>
<script type="text/html" id="toolbar">
  <div class="layui-btn-container">
    <button class="layui-btn layui-btn-sm" lay-event="add"  shiro:hasPermission="sysTest:add">添加</button>
    <button class="layui-btn layui-btn-sm" lay-event="batchDeleted" shiro:hasPermission="sysTest:delete">删除</button>
  </div>
</script>
<script type="text/html" id="tool">
  <a class="layui-btn layui-btn-xs" lay-event="edit" shiro:hasPermission="sysTest:update">编辑</a>
  <a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del" shiro:hasPermission="sysTest:delete">删除</a>
</script>

</body>
</html>
<script th:inline="javascript" type="text/javascript">
  var ctx = '[[@{/}]]'.replaceAll("\"", "").replace('//', '/');
</script>
<script th:src="@{/layui/layui.all.js}"></script>
<script th:src="@{/js/core.util.js}"></script>
<script>
  //获取token
  var token = CoreUtil.getData("access_token");
  //地址栏转义token中的#号
  var tokenQuery = token.replace("#", "%23");
  var tableIns1;
  var table = layui.table;
  var form = layui.form;
  var layer = layui.layer;
  var $ = jQuery = layui.jquery;
  var laydate = layui.laydate;

  layui.use(['table', 'layer', 'laydate'], function () {

    //加载table
    tableIns1 = table.render({
      elem: '#showTable'
      , contentType: 'application/json'
      , headers: {"authorization": token}
      , page: true //开启分页
      , url: ctx + 'sysTest/listByPage' //数据接口
      , method: 'POST'
      , parseData: function (res) { //将原始数据解析成 table 组件所规定的数据
        return {
          "code": res.code, //解析接口状态
          "msg": res.msg, //解析提示文本
          "count": CoreUtil.isEmpty(res.data) ? 0 : res.data.total, //解析数据长度
          "data": CoreUtil.isEmpty(res.data) ? null : res.data.records //解析数据列表
        }
      }
      , cols: [
        [
          {type: 'checkbox', fixed: 'left'},
          {field: 'id', title: '', sort: true},
          {field: 'name', title: '', sort: true},
          {field: 'createTime', title: '', sort: true},
          {width: 120, toolbar: "#tool", title: '操作'}
        ]
      ]
      , toolbar: '#toolbar'
    });


    //表头工具
    table.on('toolbar(showTable)', function(obj){
      switch(obj.event){
        case 'batchDeleted':
          var checkStatus = table.checkStatus(obj.config.id);
          var data = checkStatus.data;
          if(data.length==0){
            layer.msg("请选择要批量删除的列");
          }else {
            var ids = [];
            $(data).each(function (index,item) {
              ids.push(item.id);
            });
            tipDialog(ids);
          }
          break;
        case 'add':
          $(".table_div").hide();
          $(".operation").show();
          $(".title").html("新增");
          setTimeout(function () {
            form.val('info', {
              "test": "test"
              , "id": ""
              , "name": ""
              , "createTime": ""
            });
          }, 200);
          break;
      };
    });
    //列操作
    table.on('tool(showTable)',function (obj) {
      var data = obj.data;
      switch (obj.event) {
        case 'del':
          var ids=[];
          ids.push(data.id);
          tipDialog(ids);
          break;
        case 'edit':
          $(".table_div").hide();
          $(".operation").show();
          $(".title").html("编辑");
          setTimeout(function () {
            form.val('info', {
              "test": "test"
                , "id": data.id
                , "name": data.name
                , "createTime": data.createTime
            });
          }, 200);
          break;
      }
    });

    //导出
    $('#export').on('click', function () {
      //原先分页limit
      var exportParams = {
        limit: 10000,
        key: $("#key").val()
      };
      CoreUtil.sendPost(ctx + "sysTest/listByPage", exportParams, function (res) {
        //初始化渲染数据
        if (res.data != null && res.data.records != null) {
          table.exportFile(tableIns1.config.id, res.data.records, 'xls');
        }
      });
    });

    //删除
    var tipDialog=function (ids) {
      layer.open({
        content: "确定要删除么?",
        yes: function(index, layero){
          layer.close(index); //如果设定了yes回调,需进行手工关闭
          CoreUtil.sendDelete(ctx + "sysTest/delete",ids,function (res) {
            layer.msg(res.msg, {time:1000},function () {
              search();
            });
          });
        }
      });
    };

    //返回
    $("#btn_cancel").click(function() {
      $(".table_div").show();
      $(".operation").hide();
      return false;
    });

    //监听保存
    form.on('submit(submit)', function(data){
      if(data.field.id===undefined || data.field.id===null || data.field.id===""){
        CoreUtil.sendPost(ctx + "sysTest/add",data.field,function (res) {
          $(".table_div").show();
          $(".operation").hide();
          search();
        });
      }else {
        CoreUtil.sendPut(ctx + "sysTest/update",data.field,function (res) {
          $(".table_div").show();
          $(".operation").hide();
          search();
        });
      }

      return false;
    });
  });

  //执行查询
  function search() {
    //这里以搜索为例
    tableIns1.reload({
      where: { //设定异步数据接口的额外参数,任意设
        key: $("#key").val()
      }
      , page: {
        curr: 1 //重新从第 1 页开始
      }
    });
  };
</script>

以上代码,既然代码生成了,我们接着就是把这些代码放到对应的包目录下就完事了,一个CRUD就搞定了。

不需要咱们动手写一行代码,是不是很爽?

我们在回头去看看医院项目,其实不管是医院项目,很多后台管理项目都是这个样,大部分功能都是CRUD。另外,这个代码生成还有其他功能:导出Excel功能、权限控制、swagger API文档。

关于后台项目,我们只要把以上这些功能搞定,剩下的工作量还能有多少?

所以嘛,如果你每天还在搞后台管理这种系统,那你完全可以使用这种方式来节约自己的时间,把更多时间留给自己学习其他技术。

按照这种方法,不说50张表,就算是100张表,你也可以轻松搞定的。

再说几句

以上说的代码生成,只能说实现了一些简单的CRUD,因为业务中肯定没那么简单的,很多一个增加功能可能会关联很多表。

比如说:挂号功能,哪个科室?挂号类型?医生是否在岗、每天每个时间段医生预约人数是否已满?等问题。

最后来说说医院项目,医院项目的外网预约挂号功能设计和开发已经完成。

30分钟内搞定 50张表的 CRUD,666!_Test_03

同时,医院项目拆分成多个项目,也就是很多人所谓的分布式项目,目前项目基本结构已搞定。

新医院项目技术栈:

Spring Boot + Dubbo +Nacos +RabbitMQ +Redis +MyBatis+MySQL+Thmeleaf+shiro

项目整体结构,暂定,后期可能会变动:

30分钟内搞定 50张表的 CRUD,666!_html_04

后面继续迭代,争取把分库分表、分布式事务也落实到这个项目中来。


标签:function,CRUD,666,30,sysTest,res,var,data,id
From: https://blog.51cto.com/u_11702014/6459239

相关文章

  • Docker runc容器逃逸漏洞(CVE-2021-30465)
    --原文件的名称并授权cd/tmpmvrunc.amd64runc&&chmod+xrunc--查看runc的位置whichrunc--将备份runc文件cd/usr/bincpruncrunc.bak--复制新的runc到usr/bincp/tmp/runc/usr/bin/systemctlstopdockersystemctlstartdocker......
  • P1306 斐波那契公约数 题解
    请求出\(f_n\)与\(f_m\)的最大公约数,即\(\gcd(f_n,f_m)\),答案对\(10^8\)取模。结论:\(\gcd(f_n,f_m)=f_{\gcd(n,m)}\)证明如下:首先引理1:\[f_{n+m}=f_{n-1}\timesf_{m}+f_{n}\timesf_{m+1}\]运用归纳法,可以简单证明,此处略去。引理2:\[\gcd(f_n,f_......
  • 202306112142-《最近开发心得...》
     没有心得就是在瞎搞,写心得就是“埋头耕耕,抬头看看”,看看自己做了什么......    心得就是心的感受,并非得到了什么,我以前是搞前端开发,仅仅4-5年时间,见证Angular市场份额的减少,backbone还嫌有耳闻,鲜有招聘;React框架从耳闻到霸屏;个人沐浴jquery的春风,枯于市场类似Vue......
  • 使用外置存储设备扩展exroot(MT1300)
    环境说明:GL-INETMT1300设备一台8GU盘一个,已经格式化文件系统为EXT41.安装相关工具opkgupdateopkginstallblock-mountkmod-fs-ext4e2fsprogsfdisk 2.修改fstab配置文件,更改现有文件系统的挂载点DEVICE="$(sed-n-e"/\s\/overlay\s.*$/s///p"/etc/mtab)"uci-q......
  • AtCoder Beginner Contest 305 题解
    https://atcoder.jp/contests/abc305/tasks_printE-ArtGalleryonGraph冷知识:md这题赛时没做出来/cy刚看到题:这是什么题啊,\(K,h\)都\(1e5\)能做吗/fn确实能做。考虑类似SPFA的操作。设\(a_x\)表示\(x\)还可以对距离最多为\(a_x\)的点产生贡献,然后就直接......
  • 算法学习day52动态规划part13-674、300、718
    packageLeetCode.DPpart13;/***674.最长连续递增序列*给定一个未经排序的整数数组,找到最长且连续递增的子序列,并返回该序列的长度。*连续递增的子序列可以由两个下标l和r(l<r)确定,*如果对于每个l<=i<r,都有nums[i]<nums[i+1],*那么子序列[nums[......
  • Spring Boot实现高质量的CRUD-1
    1、前言​ 在SpringBoot的SMM框架(SpringBoot+Mysql+Mybatis)的WEB项目中,CRUD(增删改查)大致占了50%-70%左右的工作量。提高CRUD的代码质量,提高CRUD的开发效率,是一件值得探讨的事项。​ 一般认为,CRUD是一件体力活。在SMM框架项目开发中,项目团队通常将这类CRUD的开发任务交由知道如......
  • sb+activiti7实例<二>20230424
    一、版本问题原Activiti的TijsRademakers团队去开发Flowable框架。现Activiti7是Salaboy团队开发的,内核使用的还是Activiti6,扩展了云化。Activiti5、Activiti6代码目前由Salaboy团队代为维护,目前官宣已经暂停维护  Activiti:Activiti在目前来看有点不思进取,核心功能和内核的优......
  • 回归生活常识-230610
    台湾崔介忱两轮日月何奔忙,百年弹指如虚度。如果没有健康的身体,晚年生活必然一片凄凉。认真量身定制健康计划,设置小目标,人最大的靠山,永远是自己。 常识判断:1、作息规律、饮食有节、情志有度、生活有趣 110岁高龄:健康的体魄,充沛的精神、通透的思想,才是自己快乐生活的硬实力......
  • AtCoder Beginner Contest 305
    A-WaterStation(abc305a)题目大意给定一个数字\(x\),输出一个数字,它是最接近\(x\)的\(5\)的倍数。解题思路令\(y=x\%5\),如果\(y\leq2\),那答案就是\(x-y\),否则就是\(x+5-y\)。神奇的代码#include<bits/stdc++.h>usingnamespacestd;usingLL=long......