后端代码生成工具SDP系列五(10分钟写一个学生课程管理系统)

创建数据库(建议使用mysql8数据库)

标题要大,其实十分钟可能都没法将本文仔细看完。10分钟其实指的是实际操作,至于真正地生成所有的代码需要做的可能1分钟都不到。
这个demo仅有几个数据表,其中3个表:学生、课程和选课关系表,参考自《数据库系统概论》第五版 +学习笔记总目录中的“chp3-1.ppt”第30、31、32页。

另外,表、字段都以下划线进行了分割。原因是个人习惯,另外也是为了统一管理,因为前后端通讯时会统一使用下划线规则(ajax规则),而后端java内部会使用驼峰规则,驼峰和ajax规则使用下划线进行区分会更简单易记。

CREATE TABLE sc_dept
	( d_no   VARCHAR(9) primary key comment '班级编号',
      d_name  VARCHAR(20) UNIQUE comment '班级名称',
      updated_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP comment '更新时间',
      updated_by VARCHAR(45) comment '更新人'
    ) comment '班级';
CREATE TABLE sc_student
	( s_no   VARCHAR(9) primary key comment '学号',
      s_name  VARCHAR(20) UNIQUE comment '学生姓名',
      s_password VARCHAR(45) comment '密码',
      s_sex    VARCHAR(2) comment '性别',
      s_birthday   DATETIME comment '生日',
      d_no VARCHAR(9) comment '班级编号',
      updated_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP comment '更新时间',
      updated_by VARCHAR(45) comment '更新人',
      FOREIGN KEY (d_no) REFERENCES sc_dept(d_no)
    ) comment '学生';
CREATE TABLE sc_teacher
	( t_no   VARCHAR(9) primary key comment '教师编号',
      t_name  VARCHAR(20) UNIQUE comment '教师姓名',
      t_password VARCHAR(45) comment '密码',
      t_sex    VARCHAR(2) comment '性别',
      t_birthday   DATETIME comment '生日',
      t_is_admin SMALLINT comment '是否为管理员',
      updated_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP comment '更新时间',
      updated_by VARCHAR(45) comment '更新人'
    ) comment '教师';
CREATE TABLE  sc_course
    ( c_no       VARCHAR(9) PRIMARY KEY comment '课程编号',
      c_name  VARCHAR(20) comment '课程名称',
      c_pno     VARCHAR(9) comment '先修课程',                      
      c_credit  SMALLINT comment '学分',
      updated_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP comment '更新时间',
      updated_by VARCHAR(45) comment '更新人',
      FOREIGN KEY (c_pno) REFERENCES  sc_course(c_no) 
) comment '课程'; 
CREATE TABLE  sc
    ( s_no  VARCHAR(9) comment '学号',
      c_no  VARCHAR(9) comment '课程编号',
      approve_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP comment '批准时间',
      approve_t_no VARCHAR(9) comment '批准选课的教师编号',
      updated_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP comment '更新时间',
      updated_by VARCHAR(45) comment '更新人',
      PRIMARY KEY (s_no, c_no),
      FOREIGN KEY (s_no) REFERENCES sc_student(s_no),
      FOREIGN KEY (approve_t_no) REFERENCES sc_teacher(t_no),
      FOREIGN KEY (c_no) REFERENCES sc_course(c_no)
) comment '选课';
CREATE TABLE  tc
    ( t_no  VARCHAR(9) comment '教师编号',
      c_no  VARCHAR(4) comment '课程编号',
      updated_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP comment '更新时间',
      updated_by VARCHAR(45) comment '更新人',
      PRIMARY KEY (t_no, c_no),
      FOREIGN KEY (t_no) REFERENCES sc_teacher(t_no),
      FOREIGN KEY (c_no) REFERENCES sc_course(c_no)
) comment '执课';

数据库ER模型及业务简单介绍

系统有3个角色:学生、教师、管理员(也是教师,但是属性t_is_admin为1)。
1)学生角色:学生可以自主选择课程,并存入sc表,即学生可以对sc表进行insert操作。
2)教师角色:教师负责对sc表进行审批操作,审批通过后,sc表的approve_time和approve_t_no会设置为对应的审批时间和审批教师。只有tc表(教师-课程关系表)中有关联记录的教师才能对相应的sc表记录进行审核。
3)管理员(t_is_admin属性为1的老师):管理员有所有权限,包括新建班级、学生、教师,以及维护tc表(即教师-课程关系表)、申请课程、审批课程。

步骤一:新建数据库

在mysql8中先创建好database,例如sc,然后将上述sql语句在数据库工具中执行。

步骤二:下载SDP工具和模板文件

本文使用的版本是1.5,从https://pan.baidu.com/s/1J0PjXcbxUVmQRZzRUAs1kg?pwd=7hn4下载打包好的SDP工具,或到github下载源代码编译运行。
本文中使用到的SDP模板文件从这里下载:https://pan.baidu.com/s/10bJJYK_gxN2o5qbverVUtQ?pwd=x9as

步骤三:运行SDP工具

解压下载好的文件,执行其中的startup.bat,会启动一个命令窗口,内容如下图所示:
启动SDP工具的界面

步骤四:启动前端管理工具并导入模板

在浏览器中输入http://localhost:9999,待页面显示后,点击“导入”按钮,如下图所示:
在这里插入图片描述
在“文件”项里,选择“点击上传”,找到SDP下载文件中的sdp_demo_sc.txt文件。然后点击“开始导入”。如下图所示:
在这里插入图片描述

步骤五:修改数据库配置信息

为了安全起见,即便是在同一台机器、同一个环境下,SDP工具在导出和导入时,也不处理已经配置的数据库密码。所以导入后,需要手工修改数据库密码。导入后的页面信息如下,选择“demo_sc”工程,然后点击“修改”按钮,页面如下:
在这里插入图片描述
在“修改”页面中,输入正确的信息,然后可以点击“测试连接”按钮,看到“成功”提示,即表示数据库配置正确,如下图所示:
在这里插入图片描述

步骤六.1:创建源代码目录,并生成所有的前、后端代码

切换到sdp3_project页面,并设置源代码主目录,如下图所示:
在这里插入图片描述
SDP工具为了安全起见,要求“路径”必须存在,才可以在对应的目录中生成文件。我们可以点击“设置(root)目录”按钮,设置代码的主目录。
目录建立好以后,需要选中一条数据,或在“工作区”查询条件中选择"demo_sc",然后点击“执行”按钮。即可自动生成所有的文件。执行成功的页面如下图所示:
在这里插入图片描述

步骤六.2 为什么project页面的“表”有区别

SDP工程生成的文件数量是以project的记录为分组的条件,每条project中的“表”可以包含0到任意多个表,多个表以英文逗号分隔。每个表都会和template中的记录进行关联,例如project中server_api类型在template中对应9个模板文件,server_controller在template中对应3个模板文件。如果我们在server_api和server_controller中都设置了6个表,那么最后我们通过“执行”,就可以自动得到9乘6+3乘6个源代码文件。当然,可能会多于这个数量,因为SDP工具提供了自动处理复杂select语句的功能,允许额外针对定制的select生成对应的api request文件、api response文件、dao层实体文件、dao层Mybatis example文件等。
project中两个特殊的记录:server_static和web_static仅对应了一个sc表,这个sc表仅仅用于占位,其实这两个project对应的template与表无任何关系,均为一些基础代码、配置文件,例如pom.xml等。如果不配置,那么就不会生成这些基础表,如果配置了多个,那么其实也只是重复覆盖。

步骤六.3 允许生成的文件和表名不一样

在融合多个系统,或改造原有系统时,我们可能已经有了很多表,但是这些表在新系统中已经有对应的表、对象,那么我们就可以通过在sdp3_project的“表”中使用:a as b的方式,将数据库中的a表生成的文件替换为b。

步骤七.1 查看生成的结果

“执行”后,可以到对应的目录中查看SDP工具根据“sdp_demo_sc.txt”这个模板生成的所有代码。后端代码是标准的spring boot工程,基础的架构是分成3层:controller、service、dao。前端代码使用了vue3技术。

步骤七.2 SDP如何巧妙地实现了定制化业务代码和自动生成代码的融合

在sdp4_template中,每个模板文件都有一个属性:“不覆盖生成”,这个属性如果为1,那么就表示文件仅生成一次,例如所有的custom controller和custom server,以及所有的static_server、static_web文件,这些文件一旦生成后,开发者可以继续修改,SDP工具不会再对这些文件进行覆盖。
SDP工具在后端架构中增加了两层:custom controller和custom service层,他们通过继承(上有老、下有小)的方式,将定制化业务拆分到了独立的文件中。
demo生成的前端代码也采用了类似的技术,除了生成基本的页面外,对应地提供了简易的定制化方案。
需要说明的是,后端的5层已经非常成熟,基本可以应对所有的spring boot开发场景。前端由于其开发特性和大量的交互、展示需求,所以基本无法实现简单的分层开发方法。本demo中提供的更偏向于类似简单的企业管理系统、后台管理系统的前端框架。
另外,可以通过demo提供的前端框架,快速搭建可视化的接口测试页面,效果和效率比postman要好很多。

步骤八 打开后端工程,并执行

打开Idea(社区版即可):Idea下载地址
步骤如下:

8.1打开Idea,点击“Open or Import”:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
打开工程后,如果是第一次打开后台工程,需要耐心等待idea下载对应的依赖文件,可以点开右下角的"processes running…"查看下载的进度。
如果Idea没有配置过lombok插件,那么需要安装lombok插件,具体方法自行搜索。。。

8.2 修改数据库配置

为了安全,demo生成的server\src\main\resources\application.yml文件中没有数据库密码,所以需要手工修改数据库密码,页面如下:
在这里插入图片描述

8.3 启动后端服务

修改好数据库密码后,找到server\src\main\java\org.example\MyApplication.java,选择这个文件,点击鼠标右键,选择“Debug ‘MyApplication.main()’”,如下图所示:
在这里插入图片描述
运行后,Idea会自动打开“Debug”面板,可以看到控制台输出“Started MyApplication。。。”,就代表后端已经成功启动。如下图所示:
在这里插入图片描述

步骤九 测试后端服务

测试之前,我们先要了解后端提供了哪些接口。回顾步骤6,sdp3_project中的server_controller对应的每个表,都会生成对应的若干标准接口,这些接口都在对应的server\src\main\java\org\example\controller目录中,例如sc_dept表对应的ScDeptController.java内容如下:

package org.example.controller;


import org.example.controller.custom.*;
import org.example.dto.request.*;
import org.example.dto.response.*;
import java.util.List;
import org.springframework.web.bind.annotation.*;

/**
 * @ClassName: ScDeptController
 * @Description: 
 * @Author: SDP
 * @Date: 2022-01-08
 * @Version: 1.0
 * Table: sc_dept
 * Comment:
 * 班级
 */
@RestController
@RequestMapping(value = "/sc_dept")
public class ScDeptController extends ScDeptCustomController {
    @PostMapping("/add")
    public int addScDept(@RequestBody ScDeptAddRequest request) throws Exception {
        super.fixRequest("sc_dept", "add", request);
        return super.addScDept(request);
    }

    @PostMapping("/update")
    public int updateScDept(@RequestBody ScDeptUpdateRequest request) throws Exception {
        super.fixRequest("sc_dept", "update", request);
        return super.updateScDept(request);
    }

    @PostMapping("/delete")
    public int deleteScDept(@RequestBody ScDeptDeleteRequest request) throws Exception {
        super.fixRequest("sc_dept", "delete", request);
        return super.deleteScDept(request);
    }

    @PostMapping("/query")
    public ScDeptQueryResponse queryScDept(@RequestBody ScDeptQueryRequest request) throws Exception {
        super.fixRequest("sc_dept", "query", request);
        return super.queryScDept(request);
    }

    @PostMapping("/list")
    public List<ScDeptQueryResponse> listScDept(@RequestBody ScDeptQueryRequest request) throws Exception {
        super.fixRequest("sc_dept", "list", request);
        return super.listScDept(request);
    }

    @PostMapping("/count")
    public int countScDept(@RequestBody ScDeptQueryRequest request) throws Exception {
        super.fixRequest("sc_dept", "count", request);
        return super.countScDept(request);
    }

}

每个表都包含和3个基础的DML接口:add、update、delete,一个query接口(以primary key为条件的唯一性查询),一个count接口(计数),一个list接口(单表查询)。
我们可以使用postman来测试sc_dept的这些接口。也可以通过demo提供的前端,来更直观的测试这些接口。

步骤十 启动前端

首先,我们需要先安装好node开发环境:下载NodeJS
然后双击生成的前端代码(web目录)下的install.bat。或手动启动命令窗口,切换到生成的d:\git\sc\web目录,执行npm install。
准备工作结束后,我们可以双击web目录下的startup.bat。或在命令窗口中输入npm run dev。等待前端启动完成,由于demo使用了vue3的vite作为开发、打包工具,所以启动、打包速度飞快。感谢“vue-manage-system”工程:vue-manage-system地址,本demo中的基础框架使用了这个工程的代码构建。启动成功的页面如下图所示:
在这里插入图片描述

步骤十一 开始使用

启动浏览器,输入http://localhost:3000,即可看到页面了。所有的表、每个表对应的增删改查都可以正常测试。图示:
在这里插入图片描述

在这里插入图片描述

后续:定制化页面、定制化接口

这个demo目前仅展示了SDP工具的基础功能:生成标准的代码、标准的增删改查接口。下一次,我们将继续这个demo,讲述如何定制前端页面、定制后端复杂接口。