闸瓦实训

我发现,这网页(cmd.dayi.ink)好卡啊。

目前进度:1.0(也没想到有这么多内容)

我知道你想要什么:这里 https://ghproxy.com/https://github.com/magical-rabbit/java-spring/archive/refs/heads/main.zip

这里可能更好的浏览体验哦(也不一定,这个文件是我写过最大的啦123kb了已经)

Github: https://github.com/magical-rabbit/java-spring/blob/main/docs/Rabbit.md

老博客:https://type.dayiyi.top/index.php/archives/206/

2023年10月7日23:10:56
好啦,写完啦。基本的功能实现啦。剩下的就是完善下文档啦。

0.代码维护等相关。

0.0 胡萝卜!

这里是一根胡萝北

0.1 项目在线Demo!

你想看项目什么样子吗?这里是docker部署的Demo!

【域名】

0.2 感慨

因为第一次写Spring boot的框架,所以用了Git来进行维护代码(方便回溯,万一写炸了很快就可以回到原先的地方)

而且整个实训过程中,一直用的远程桌面,还是效率有点点低(电脑坏了,售后还推人,然后到现在没修好,一直在青岛,7月修到现在了),如果有什么疏忽的地方,还请多多谅解。

0.3 Git代码维护

直接用了公开仓库,也没啥隐私。(虽然数据库不小心PUSH上好几次,到现在干脆直接塞上(希望不要有人打),不过也没事啦)

打开缓慢:可以用Steam++来加速访问(选github)

Steam++下载(https://steampp.net/ 下载:选蓝奏云 https://wwn.lanzouy.com/imM6D19nxt9a 密码1234 )

都在这里:https://github.com/magical-rabbit/java-spring

镜像仓库(国内-不建议):GITEE:https://gitee.com/idayi/java-spring

镜像

如何下载Github代码?点这里就好

image-20231006125304164

直接下载?这里!直链:https://github.com/magical-rabbit/java-spring/archive/refs/heads/main.zip


用这个来维护,下面是部分实验过程哦

1. 配置mvn

创建仓库文件夹(不要带中文就好)

<!-- 你的不一定是 -->
<localRepository>F:/zhawa_/lib_repo/repository</localRepository>
mvn 文件夹

File -> Settings -> Build tools -> Maven

2. new project

新建项目啦。这里是之前选修课的经验。

3. 项目结构

pom.xml包管理文件哦

结构

如果遇到,resource失效的情况,请从这里重新mark哦

4. 依赖

微信群文件pom.xml

复制过来就好

复制2

重新load(重新加载一下)

(如果失败了,试试把那个repository全删掉试试)

目前xml



    <!-- 引入springboot的父工程 -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.2</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>


    <!--ovo?依赖-->
    <dependencies>
        <!-- springboot的web模块,接收请求和响应请求 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>


</project>

5. 启动

新建class,试试能不能启动成功

package net.dabbit.skd21;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class App {
    public static void main(String[] args) {
        SpringApplication.run(App.class);
    }
}

看看启动时间和端口

新建包com.exam.controller,这个包后来是改成了net.dabbit.skd21.exam.controller

新建文件

package net.dabbit.skd21.exam.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class DemoController {
    /*
    * localhost:8080/index
    * */
    @RequestMapping("/index")
    @ResponseBody // 返回值是一个具体的值(非路径)
    public String index(){
        return "你好";
    }
}

差不多这样

重启

重启后:

尝试访问:http://localhost:8080/index

5.1 BookController

写一个controller!

·book!


package net.dabbit.skd21.exam.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping("/book")
public class BookController {
    @RequestMapping("/index")
    @ResponseBody
    public String index(){
        return "book";
    }
}

5.2 DemoController

demo!

package net.dabbit.skd21.exam.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping("/demo")
public class DemoController {
    /*
    * localhost:8080/demo/index
    * */
    @RequestMapping("/index")
    @ResponseBody // 返回值是一 个具体的值(非路径)
    public String index(){
        return "你好";
    }

    /*
    * name
    * age
    * */
    @RequestMapping("/add")
    @ResponseBody // 返回值是一 个具体的值(非路径)
    public String add(String name,Integer age){
        return name + ","+age;
    }
}

带参数

http://localhost:8080/demo/add?name=ck&age=112

生成实体

然后全选(ctrl键)

确定

最后的代码
dir

测试demo2

http://localhost:8080/demo/add1?name=ck&age=112

demo.java

package net.dabbit.skd21.exam.controller;

import net.dabbit.skd21.exam.entity.DemoEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping("/demo")
public class DemoController {
    /*
    * localhost:8080/demo/index
    * */
    @RequestMapping("/index")
    @ResponseBody // 返回值是一 个具体的值(非路径)
    public String index(){
        return "你好";
    }

    /*
    * name
    * age
    * */
    @RequestMapping("/add")
    @ResponseBody // 返回值是一 个具体的值(非路径)
    public String add(String name,Integer age){
        return name + ","+age;
    }

    /*
     * 实体类对象
     * 实体名
     * */
    @RequestMapping("/add1")
    @ResponseBody // 返回值是一 个具体的值(非路径)
    public String add1(DemoEntity demoEntity){
        return demoEntity.getName()+"--"+demoEntity.getAge();
    }
}

5.3 Entity-Demo

DemoEntity.java

package net.dabbit.skd21.exam.entity;

public class DemoEntity {
    private String name;
    private Integer age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}

6. 静态文件

静态文件不会自动加载?请从这里!

6.1 Demo.html

demo.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--
localhost:8080/pages/demo.html
-->

<script src="../js/jquery-3.4.1.js"></script>
<script src="../js/demo.js"></script>

<h1 id="h1">demo1111页</h1>
<input type="text" id="name">
<input type="password" id="pwd">

<input type="button" value="测试" onclick="test()">


</body>
</html>

6.2 demo.js

demo.js

$(function(){
    //页面自动执行
    console.log(123);
    var v = $("#h1").html();
    console.log(v)
})


var test  =  function (){
    var name =  $("#name").val();//.val()获得表单元素的值 //input select textarea(文本域)
    var pwd = $("#pwd").val();

    console.log(name+" , ",pwd)
}

6.3 查找和替换?

复制文件之后

ctrl+r替换

7. 代码

7.1 index.js

index.js

$(function () {
  //自动执行的逻辑
  $.ajax({
    type: "get",
    url: "./footer.html",
    success:function(data){//data是读取到的页面的html
      console.log(data)  
    }
  });
})

这样底部就可以有999啦!

7.2 头部

$(function () {
  //自动执行的逻辑
  $.ajax({
    type: "get",
    url: "./footer.html",
    success:function(data){//data是读取到的页面的html
      // console.log(data)
      // data+="999"
      $("#footer").html(data);
      
    }
  });


  $.ajax({
    type: "get",
    url: "./header.html",
    success:function(data){//data是读取到的页面的html
      // console.log(data)
      // data+="233"
      $("#header").html(data);

    }
  });

  $.ajax({
    type: "get",
    url: "./left-menu.html",
    success:function(data){//data是读取到的页面的html
      // console.log(data)
      // data+="233"
      $("#left-menu").html(data);

    }
  });


  $.ajax({
    type: "get",
    url: "./welcome.html",
    success:function(data){//data是读取到的页面的html
      // console.log(data)
      // data+="233"
      $("#content").html(data);

    }
  });

})

7.3 全部的index.html

index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>AdminLTE 3 | Dashboard</title>

  <!-- Google Font: Source Sans Pro -->
  <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,400i,700&display=fallback">
  <!-- Font Awesome -->
  <link rel="stylesheet" href="../plugins/fontawesome-free/css/all.min.css">
  <!-- Ionicons -->
  <link rel="stylesheet" href="https://code.ionicframework.com/ionicons/2.0.1/css/ionicons.min.css">
  <!-- Tempusdominus Bootstrap 4 -->
  <link rel="stylesheet" href="../plugins/tempusdominus-bootstrap-4/css/tempusdominus-bootstrap-4.min.css">
  <!-- iCheck -->
  <link rel="stylesheet" href="../plugins/icheck-bootstrap/icheck-bootstrap.min.css">
  <!-- JQVMap -->
  <link rel="stylesheet" href="../plugins/jqvmap/jqvmap.min.css">
  <!-- Theme style -->
  <link rel="stylesheet" href="../dist/css/adminlte.min.css">
  <!-- overlayScrollbars -->
  <link rel="stylesheet" href="../plugins/overlayScrollbars/css/OverlayScrollbars.min.css">
  <!-- Daterange picker -->
  <link rel="stylesheet" href="../plugins/daterangepicker/daterangepicker.css">
  <!-- summernote -->
  <link rel="stylesheet" href="../plugins/summernote/summernote-bs4.min.css">
</head>
<body class="hold-transition sidebar-mini layout-fixed">
<div class="wrapper">

  <!-- Navbar头部 -->
  <nav id="header" class="main-header navbar navbar-expand navbar-white navbar-light">

  </nav>
  <!-- /.navbar -->

  <!-- Main Sidebar Container左侧 -->
  <aside class="main-sidebar sidebar-dark-primary elevation-4">
    <!-- Brand Logo -->
    <a href="index3.html" class="brand-link">
      <img src="../dist/img/AdminLTELogo.png" alt="AdminLTE Logo" class="brand-image img-circle elevation-3" style="opacity: .8">
      <span class="brand-text font-weight-light">AdminLTE 3</span>
    </a>

    <!-- Sidebar -->
    <div class="sidebar">
      <!-- Sidebar user panel (optional) -->
      <div class="user-panel mt-3 pb-3 mb-3 d-flex">
        <div class="image">
          <img src="../dist/img/user2-160x160.jpg" class="img-circle elevation-2" alt="User Image">
        </div>
        <div class="info">
          <a href="#" class="d-block">Alexander Pierce</a>
        </div>
      </div>

      <!-- SidebarSearch Form -->
      <div class="form-inline">
        <div class="input-group" data-widget="sidebar-search">
          <input class="form-control form-control-sidebar" type="search" placeholder="Search" aria-label="Search">
          <div class="input-group-append">
            <button class="btn btn-sidebar">
              <i class="fas fa-search fa-fw"></i>
            </button>
          </div>
        </div>
      </div>

      <!-- Sidebar Menu -->
      <nav class="mt-2">
        <ul id="left-menu" class="nav nav-pills nav-sidebar flex-column" data-widget="treeview" role="menu" data-accordion="false">
          <!-- Add icons to the links using the .nav-icon class
               with font-awesome or any other icon font library -->






        </ul>
      </nav>
      <!-- /.sidebar-menu -->
    </div>
    <!-- /.sidebar -->
  </aside>
  <!-- Main Sidebar Container -->

  <!-- Content Wrapper. Contains page content中间正文 -->

  <div id="content" class="content-wrapper"></div>

  <!-- /.content-wrapper -->

  <!-- mian-footer页脚  -->
  <footer id="footer" class="main-footer">

  </footer>
  <!-- mian-footer -->

  <!-- Control Sidebar -->
  <aside class="control-sidebar control-sidebar-dark">
    <!-- Control sidebar content goes here -->
  </aside>
  <!-- /.control-sidebar -->
</div>
<!-- ./wrapper -->

<!-- jQuery -->
<script src="../plugins/jquery/jquery.min.js"></script>
<!-- jQuery UI 1.11.4 -->
<script src="../plugins/jquery-ui/jquery-ui.min.js"></script>
<!-- Resolve conflict in jQuery UI tooltip with Bootstrap tooltip -->
<script>
  $.widget.bridge('uibutton', $.ui.button)
</script>
<!-- Bootstrap 4 -->
<script src="../plugins/bootstrap/js/bootstrap.bundle.min.js"></script>
<!-- ChartJS -->
<script src="../plugins/chart.js/Chart.min.js"></script>
<!-- Sparkline -->
<script src="../plugins/sparklines/sparkline.js"></script>
<!-- JQVMap -->
<script src="../plugins/jqvmap/jquery.vmap.min.js"></script>
<script src="../plugins/jqvmap/maps/jquery.vmap.usa.js"></script>
<!-- jQuery Knob Chart -->
<script src="../plugins/jquery-knob/jquery.knob.min.js"></script>
<!-- daterangepicker -->
<script src="../plugins/moment/moment.min.js"></script>
<script src="../plugins/daterangepicker/daterangepicker.js"></script>
<!-- Tempusdominus Bootstrap 4 -->
<script src="../plugins/tempusdominus-bootstrap-4/js/tempusdominus-bootstrap-4.min.js"></script>
<!-- Summernote -->
<script src="../plugins/summernote/summernote-bs4.min.js"></script>
<!-- overlayScrollbars -->
<script src="../plugins/overlayScrollbars/js/jquery.overlayScrollbars.min.js"></script>
<!-- AdminLTE App -->
<script src="../dist/js/adminlte.js"></script>
<!-- AdminLTE for demo purposes -->
<script src="../dist/js/demo.js"></script>
<!-- AdminLTE dashboard demo (This is only for demo purposes) -->
<script src="../dist/js/pages/dashboard.js"></script>
<script src="../js/index.js"></script>

</body>
</html>

7.4 project-add.html

project-add.html

7.5 周二下午的内容

7.5.1 首先是把包导入

首先是把包导入!

<?xml version="1.0" encoding="UTF-8"?>
<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.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>net.dabbit.skd21</groupId>
    <artifactId>emis</artifactId>
    <version>1.0-SNAPSHOT</version>

    <!-- 引入springboot的父工程 -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.2</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <!--ovo?依赖-->
    <dependencies>
        <!-- springboot的web模块,接收请求和响应请求 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- mybatis与springboot整合依赖 -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.2.1</version>
        </dependency>

        <!-- mysql驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

        <!-- mybatis逆向工程依赖 -->
        <dependency>
            <groupId>org.mybatis.generator</groupId>
            <artifactId>mybatis-generator-core</artifactId>
            <version>1.4.0</version>
        </dependency>

        <!-- 数据库连接池 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.23</version>
        </dependency>

        <!-- json 相关工具类 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.73</version>
        </dependency>

        <!-- poi解析Excel文件的依赖 -->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>3.14</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>3.14</version>
        </dependency>
    </dependencies>


</project>

7.5.2 连接数据库!

连接数据库!

jdbc:mysql://192.168.83.132:3306/ovo?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true

  • ovo是你的数据库名

7.6 登录相关的代码

这里是登录的代码(实际上逻辑有点问题,就是传了个表单,然后返回了个值,并没有真的是登录)

为什么是繁体中文?这得问远程桌面(我现在写这个文档还是用的远程桌面www)

7.6.1 login.js

var login = function (){

    //獲取輸入的用戶名密碼
    var username = $("#username").val()
    var password = $("#password").val()

    console.log(`${username} , ${password}`)

    if(!username){
        alert("用戶名不能為空")
        return false
    }

    if(!password){
        alert("密碼不能為空")
        return false
    }

    //請求後端
    $.ajax({
        type: "post",
        url : "",
        data:{
            "username" : username,
            "password" : password
        },
        //指定後端返回的數據類型
        //json xml html text
        dataType:"json",

        // 參數data是後端的返回值
        success: function (data){
            /*
            * ajax異步請求
            *
            * */
            console.log(data)
        }
    })
}

7.6.2 login.html

<input id="password" type="password" class="form-control" placeholder="密码">

 <input id="username" type="text" class="form-control" placeholder="用户名">

<button type="button" class="btn btn-primary btn-block" onclick="login()">登录</button>

7.7 周三上午的内容

用了MVC框架,所以这里要定义实体哦。

7.7.1 User.java (entity)

package net.dabbit.skd21.exam.entity;

import java.util.Date;

public class User {
    private Integer id;
    private String username;
    private String password;
    private String realName;
    private String sex;
    private String sno;
    private Date admissionDate;
    private Integer facultyId;
    private Integer majorId;
    private Integer classId;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getRealName() {
        return realName;
    }

    public void setRealName(String realName) {
        this.realName = realName;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getSno() {
        return sno;
    }

    public void setSno(String sno) {
        this.sno = sno;
    }

    public Date getAdmissionDate() {
        return admissionDate;
    }

    public void setAdmissionDate(Date admissionDate) {
        this.admissionDate = admissionDate;
    }

    public Integer getFacultyId() {
        return facultyId;
    }

    public void setFacultyId(Integer facultyId) {
        this.facultyId = facultyId;
    }

    public Integer getMajorId() {
        return majorId;
    }

    public void setMajorId(Integer majorId) {
        this.majorId = majorId;
    }

    public Integer getClassId() {
        return classId;
    }

    public void setClassId(Integer classId) {
        this.classId = classId;
    }

7.7.2 23.9.20_上午第二节课

实现了这个前端!

7.7.3 2023年9月20日_下午

7.7.4 user-list.js

这里是部分代码了,这个是获得用户列表的脚本。

后来用了dayi-lib来简化了一次。

$(function () {
    load_page()
});

var load_page=function (){
    $("#jsGrid1").jsGrid({
        width: "100%",
        height: "auto",
        sorting: true,
        paging: true,
        pageLoading: true,
        autoload: true,

        controller: {
            loadData: function (filter) {

                filter["search"]= $("#search").val()

                return $.ajax({
                    type: "post",
                    url: "/user/list",
                    dataType: "json",
                    data: filter
                });
            }
        },
        pageIndex: 1,
        pageSize: 3,

        pageButtonCount: 10,
        pagePrevText: "上一页",
        pageNextText: "下一页",
        pageFirstText: "首页",
        pageLastText: "尾页",

        fields: [
            { title: "ID",name:"id", type: "text", width: 150 },
            { title: "用户名",name:"username", type: "text", width: 150 },
            { title: "真是姓名",name:"realName", type: "text", width: 150 },
            { title: "学号",name:"sno", type: "text", width: 150 },

            { title: "性别",name:"sex", type: "text", width: 150,
                itemTemplate: function (value, item) {
                    if (item.sex == "1") {
                        return "女";
                    }
                    return "男";
                }
            },
            { name: "入学日期", type: "text", width: 150,
                itemTemplate: function (value, item) {
                    // 创建一个新的日期对象,将时间戳作为参数传递给构造函数
                    // debugger;
                    var timestamp = item['admissionDate']; // 例如,您的时间戳(以毫秒为单位)
                    var date = new Date(timestamp);// 去除毫秒部分
                    if(date instanceof Date && isNaN(date.getTime())){
                        console.log(`[sys-error]解析时间失败,原始数据:${item['admissionDate']}`)
                        return `[Err]解析时间失败,原始数据:${item['admissionDate']}`
                    }
                    date.setMilliseconds(0);
                    var year = date.getFullYear();
                    var month = (date.getMonth() + 1).toString().padStart(2, '0'); // 月份从0开始,需要加1
                    var day = date.getDate().toString().padStart(2, '0'); // 天数
                    var hours = date.getHours().toString().padStart(2, '0'); // 小时
                    var minutes = date.getMinutes().toString().padStart(2, '0'); // 分钟
                    var seconds = date.getSeconds().toString().padStart(2, '0'); // 秒
                    var formattedDate = year + '-' + month + '-' + day + ' ' + hours + ':' + minutes + ':' + seconds;
                    // console.log()
                    return formattedDate;
                }
            }
        ]
    });
}

7.8 周四的内容23.9.21

这里已经是部分代码啦,当时上课的时候跟着很紧,所以没来得及写文档。

后端写好接口之后,前端进行引用。

7.8.1 user-add.js

user-add.js

var mysubmit = function () {
    //获取所有的输入的值,组装成json对象
    var params = {
        username: $("#username").val(),
        password: $("#password").val(),
        realName: $("#realName").val(),
        sex: $("#sex").val(),
        sno: $("#sno").val(),
        facultyId: $("#facultyId").val(),
        majorId: $("#majorId").val(),
        classId: $("#classId").val()
    };

    //使用ajax提交
    $.ajax({
        type: "post",
        url: "/user/add",
        data: params,
        dataType: "json",
        success:function (data){
            if(data.code === "200"){
                alert("新增成功");
            }
            else{
                alert("新增失败");
            }
        }
    });
};

具体从数据库中查询的代码XML

7.8.2 UserMapper.xml

UserMapper.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="net.dabbit.skd21.exam.mapper.UserMapper">

    <resultMap id="BaseResultMap" type="net.dabbit.skd21.exam.entity.User">
        <id column="id" property="id"></id>
        <result column="username" property="username"></result>
        <result column="password" property="password"></result>
        <result column="real_name" property="realName"></result>
        <result column="sex" property="sex"></result>
        <result column="sno" property="sno"></result>
        <result column="admission_date" property="admissionDate"></result>
        <result column="faculty_id" property="facultyId"></result>
        <result column="major_id" property="majorId"></result>
        <result column="class_id" property="classId"></result>
    </resultMap>


<!--    <resultMap id="" type=""-->

    <select id="login" parameterType="net.dabbit.skd21.exam.entity.User" resultMap="BaseResultMap">
        SELECT * FROM user WHERE username = #{username} AND password = #{password}
    </select>


<!--
#{offset}
调用了getter方法

#{属性名} 如果是字符串,自动补充一个单引号
${属性名} 原样输出

-->
    <select id="list" parameterType="net.dabbit.skd21.exam.entity.JsGridData" resultMap="BaseResultMap">
        SELECT * FROM user
        <if test="search != ''">
            where real_name like '%${search}%'
        </if>
        limit #{offset},#{pageSize}
    </select>


<!--    返回值能直接被result接受的用resulttype, 不行的用map做中转-->
    <select id="count" parameterType="net.dabbit.skd21.exam.entity.JsGridData" resultType="java.lang.Long">
        SELECT count(*) FROM user
        <if test="search != ''">
            where real_name like '%${search}%'
        </if>
    </select>



    <delete id="del" parameterType="java.lang.Integer">
        delete from user where
        id = #{id}
    </delete>

    <insert id="add" parameterType="net.dabbit.skd21.exam.entity.User">
        INSERT INTO user (
        <if test="username != null">`username`,</if>
        <if test="password != null">`password`,</if>
        <if test="realName != null">`real_name`,</if>
        <if test="sex != null">`sex`,</if>
        <if test="sno != null">`sno`,</if>
        `admission_date`,
        <if test="facultyId != null">`faculty_id`,</if>
        <if test="majorId != null">`major_id`,</if>
        <if test="classId != null">`class_id`</if>
        )
        VALUES (
        <if test="username != null">#{username},</if>
        <if test="password != null">#{password},</if>
        <if test="realName != null">#{realName},</if>
        <if test="sex != null">#{sex},</if>
        <if test="sno != null">#{sno},</if>
        NOW(),
        <if test="facultyId != null">#{facultyId},</if>
        <if test="majorId != null">#{majorId},</if>
        <if test="classId != null">#{classId}</if>
        )
    </insert>



</mapper>

8.实训的文件下载

到这里是老师带着做的项目,具体的实训文件在这里:下载(从dayi的小图床下载)

9. Mybatis 逆向工程

这一步可以自动生成一些类,项目计划书上有的,跟着照做也可以,但是推荐你包名不一样,或者先把项目备份(复制粘贴)一下,防止替换。

其实后期发现这个还是很有用的,真的省了一些事情,提升了编码的幸福感)

9.1 创建账号

数据库创建账号:

直接写SQL吧(Navicat执行)

CREATE USER 'mybatis'@'%' IDENTIFIED BY '123456';
GRANT SELECT ON `ovo`.* TO 'mybatis'@'%' WITH GRANT OPTION;
FLUSH PRIVILEGES;

这样就可以啦,新建了一个用户

  • 用户名: mybatis
  • 密码: 123456

9.2 添加依赖

<dependency>
   <groupId>org.mybatis.generator</groupId>
   <artifactId>mybatis-generator-core</artifactId>
   <version>1.4.0</version>
</dependency>

9.3 generatorConfig.xml

源文件从项目书上复制就好啦。

这里我把源文件,放在resources里了。

但感觉老师都是手写的sql,不知道这样会发生什么,先备个份。

这里原文的好像多了几个空格

9.4 新建类Generator.java

文件也是复制的那个项目书的文件(package 不用复制)

这里,选择绝对路径,然后放到这里

9.5 运行类

说实在我也不知道会发生什么

然后他在这个包(文件夹里)生成了好多文件。

如果你的包名也是这样(com.test.emis)我不太建议你运行,有可能会替换你的文件,但如果你的包名不是这个,我觉得可以试试,感觉里面的文件可以参考。

到此,本步结束。

10. springboot项目中是使用myBatis

这里其实都已经做啦,为了跟文档对起来,稍微解释下。

10.1 三层架构

UI(用户交互)+BLL(业务逻辑,验证、计算、业务规则。)+DAL(数据访问层)

使用三层结构,写一大堆来实现一个sql语句),但可以进行代码维护。

MVC

前端—>controller —>service->dao

前端:html+css+js
controller : springboot controller
service:面向接口
dao: mybatis

10.2.1 pom.xml

pom.xml前文有啦,这里再复制一遍。

<?xml version="1.0" encoding="UTF-8"?>
<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.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>net.dabbit.skd21</groupId>
    <artifactId>emis</artifactId>
    <version>1.0-SNAPSHOT</version>

    <!-- 引入springboot的父工程 -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.2</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <!--ovo?依赖-->
    <dependencies>
        <!-- springboot的web模块,接收请求和响应请求 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- mybatis与springboot整合依赖 -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.2.1</version>
        </dependency>

        <!-- mysql驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

        <!-- mybatis逆向工程依赖 -->
        <dependency>
            <groupId>org.mybatis.generator</groupId>
            <artifactId>mybatis-generator-core</artifactId>
            <version>1.4.0</version>
        </dependency>

        <!-- 数据库连接池 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.23</version>
        </dependency>

        <!-- json 相关工具类 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.73</version>
        </dependency>

        <!-- poi解析Excel文件的依赖 -->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>3.14</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>3.14</version>
        </dependency>

        <dependency>
            <groupId>org.mybatis.generator</groupId>
            <artifactId>mybatis-generator-core</artifactId>
            <version>1.4.0</version>
        </dependency>

    </dependencies>

    <build>
        <!--
        springboot项目启动时,默认过滤掉src/main/java下的所有xml文件
        我们要使用mybatis,mybatis的xml文件在mapper包下,mapper在src/main/java下
        需要通过以下配置,指定pringboot项目启动时,不过滤src/main/java下的所有xml文件
        -->
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
                <filtering>false</filtering>
            </resource>
        </resources>
    </build>
</project>

10.2.2 application.yml

同理同理,这里就是相关的信息。

spring:
  mvc:
    view:
      # 如果属性后面有值,类似prefix: /pages/,:后面需要有一个空格
      prefix: /pages/
      suffix: .html
  datasource:
    # mysql5.x,以下被注释的url和driver-class-name
    #url: jdbc:mysql://master:3306/reclamation?useUnicode=true&characterEncoding=UTF-8
    #driver-class-name: com.mysql.jdbc.Driver
    # mysql8,用以下的url和driver-class-name
    url: jdbc:mysql://192.168.83.132:3306/ovo?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true
    driver-class-name: com.mysql.cj.jdbc.Driver
    # 这里的用户名密码,不要使用之前逆向工程的那个用户名和密码(之前的用户只能查询),去使用正常的用户
    username: root
    password: "123456"
    # 数据库连接池
    type: com.alibaba.druid.pool.DruidDataSource

都说的很明白啦。而且还用了数据库pool

Dao

接口上加上注解@Mapper

service

Mapper.xml

service实现类

controller

11 功能实现

11.1 菜单

我觉得写一个新的类和controller吧。

11.1.1 后端实现

Menu.java

  1. java类
package net.dabbit.skd21.exam.entity;

public class Menu {
    private Integer id;

    private String menuCode;

    private String menuName;

    private String menuUrl;

    private String menuLevel;

    private Integer parentId;

    private Integer sort;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getMenuCode() {
        return menuCode;
    }

    public void setMenuCode(String menuCode) {
        this.menuCode = menuCode;
    }

    public String getMenuName() {
        return menuName;
    }

    public void setMenuName(String menuName) {
        this.menuName = menuName;
    }

    public String getMenuUrl() {
        return menuUrl;
    }

    public void setMenuUrl(String menuUrl) {
        this.menuUrl = menuUrl;
    }

    public String getMenuLevel() {
        return menuLevel;
    }

    public void setMenuLevel(String menuLevel) {
        this.menuLevel = menuLevel;
    }

    public Integer getParentId() {
        return parentId;
    }

    public void setParentId(Integer parentId) {
        this.parentId = parentId;
    }

    public Integer getSort() {
        return sort;
    }

    public void setSort(Integer sort) {
        this.sort = sort;
    }
}

  1. 服务类

MenuService.java

package net.dabbit.skd21.exam.service;

import net.dabbit.skd21.exam.entity.JsGridData;
import org.springframework.stereotype.Service;

@Service
public interface MenuService {
    String list(JsGridData jsGridData);
}
  1. 服务实现

MenuServiceImpl

package net.dabbit.skd21.exam.service.impl;

import com.alibaba.fastjson.JSONObject;
import net.dabbit.skd21.exam.entity.JsGridData;
import net.dabbit.skd21.exam.entity.Menu;
import net.dabbit.skd21.exam.mapper.MenuMapper;  
import net.dabbit.skd21.exam.service.MenuService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class MenuServiceImpl implements MenuService{
    @Autowired
    MenuMapper menuMapper;

    @Override
    public String list(JsGridData jsGridData) {
        List<Menu> ls = menuMapper.list(jsGridData);
        Long cnt = menuMapper.count(jsGridData);
        jsGridData.setItemsCount(cnt);
        jsGridData.setData(ls);
        return JSONObject.toJSONString(jsGridData);
    }
}
  1. SQL查询实现

MenuMapper.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="net.dabbit.skd21.exam.mapper.MenuMapper">
    <resultMap id="BaseResultMap" type="net.dabbit.skd21.exam.entity.Menu">
        <id column="id" jdbcType="INTEGER" property="id" />
        <result column="menu_code" jdbcType="VARCHAR" property="menuCode" />
        <result column="menu_name" jdbcType="VARCHAR" property="menuName" />
        <result column="menu_url" jdbcType="VARCHAR" property="menuUrl" />
        <result column="menu_level" jdbcType="VARCHAR" property="menuLevel" />
        <result column="parent_id" jdbcType="INTEGER" property="parentId" />
        <result column="sort" jdbcType="INTEGER" property="sort" />
    </resultMap>
    <select id="list" parameterType="net.dabbit.skd21.exam.entity.JsGridData" resultMap="BaseResultMap">
        select * from menu
    </select>

    <select id="count" parameterType="net.dabbit.skd21.exam.entity.JsGridData" resultType="java.lang.Long">
        select count(*) from menu
    </select>

</mapper>

  1. 传参可能会发生空指针错误

然后这里小修一下:

防止空指针报错。

  1. 测试请求(后端)

测试下请求:(工具APIFOX、POSTMAN)

这样前端就可以拿菜单了。

11.1.2 前端实现

  1. 这个文件里添加一行这个,等会动态显示目录。

left-menu.html

<div id="show-menu">

</div>

这样写一个div

  1. JS代码(能用,但是有BUG)
js(能用,但是不完全能用,目录树解析还有问题,没解析完美)

```javascript=
function generateMenu(menuData) {
    var menuContainer = document.getElementById("show-menu");
    var ul = document.createElement("ul");
    ul.classList.add("nav", "nav-sidebar");

    // Sort the menu items based on the 'sort' property
    menuData.data.sort(function (a, b) {
        return a.sort - b.sort;
    });

    menuData.data.forEach(function (menuItem) {
        var li = document.createElement("li");
        li.classList.add("nav-item");

        var a = document.createElement("a");
        a.href = menuItem.menuUrl;
        a.classList.add("nav-link");

        var i = document.createElement("i");
        i.classList.add("nav-icon", "fas", "fa-circle");

        var p = document.createElement("p");
        p.textContent = menuItem.menuName;

        a.appendChild(i);
        a.appendChild(p);
        li.appendChild(a);

        // Check if there are submenus (menuLevel 2 or 3)
        var submenus = menuData.data.filter(function (submenu) {
            return submenu.parentId === menuItem.id;
        });

        if (submenus.length > 0) {
            var submenuUl = document.createElement("ul");
            submenuUl.classList.add("nav", "nav-treeview");

            submenus.forEach(function (submenuItem) {
                var submenuLi = document.createElement("li");
                submenuLi.classList.add("nav-item");

                var submenuA = document.createElement("a");
                submenuA.href = submenuItem.menuUrl;
                submenuA.classList.add("nav-link");

                var submenuI = document.createElement("i");
                submenuI.classList.add("far", "fa-circle", "nav-icon");

                var submenuP = document.createElement("p");
                submenuP.textContent = submenuItem.menuName;

                submenuA.appendChild(submenuI);
                submenuA.appendChild(submenuP);
                submenuLi.appendChild(submenuA);
                submenuUl.appendChild(submenuLi);
            });

            li.appendChild(submenuUl);
        }

        ul.appendChild(li);
    });

    menuContainer.appendChild(ul);
}
function getMenuDataAndGenerateMenu() {
    $.ajax({
        type: "GET",
        url: "/menu/list",
        dataType: "json",
        success: function (data) {
            if (data && data.data) {
                generateMenu(data); // Call the generateMenu function with the received data
            } else {
                console.log("[dayi-error]获得菜单数据失败");
            }
        },
        error: function () {
            console.log("[dayi-error]An error occurred while retrieving menu data.");
        },
    });
}

$(document).ready(function () {
    getMenuDataAndGenerateMenu(); // Fetch and generate menu data on page load
});
//后面这里的代码已经修好了!,但还是想记录下过程
function createNavItemWithLink(text, iconClass, link, onClick) {
    // 创建 <li> 元素
    var listItem = document.createElement("li");
    listItem.classList.add("nav-item");

    // 创建 <a> 元素
    var linkElement = document.createElement("a");
    linkElement.setAttribute("href", link);
    linkElement.classList.add("nav-link");
    linkElement.addEventListener("click", onClick);

    // 创建 <i> 元素
    var icon = document.createElement("i");
    icon.classList.add(iconClass);
    icon.classList.add("nav-icon");

    // 创建 <p> 元素
    var linkText = document.createElement("p");
    linkText.innerText = text;

    // 把 <i> 元素添加到 <a> 元素中
    linkElement.appendChild(icon);

    // 把 <p> 元素添加到 <a> 元素中
    linkElement.appendChild(linkText);

    // 把 <a> 元素添加到 <li> 元素中
    listItem.appendChild(linkElement);

    // 返回生成的 <li> 元素
    return listItem;
}

/*
使用方法:

var listItem1 = createNavItemWithLink("新增頁", "far fa-circle", "javascript:void(0)", function() {
  load_content('project-add.html');
});

var listItem2 = createNavItemWithLink("列表", "far fa-circle", "javascript:void(0)", function() {
  load_content('project-list.html');
});

*/


function createMenuItems(menuData, parentMenuId, menuContainer) {
    // Filter out the submenu items for the specified parent menu
    var subMenuItems = menuData.filter(function (menu) {
        return menu.parentId === parentMenuId;
    });

    // Iterate over the submenu items
    for (var i = 0; i < subMenuItems.length; i++) {
        var menu = subMenuItems[i];
        
        //一级菜单
        var listItem = document.createElement("li");
        listItem.classList.add("nav-item");

        var arror = document.createElement("a");
        //<i class="right fas fa-angle-left"></i>
        arror.classList.add("right");
        arror.classList.add("fas");
        arror.classList.add("fa-angle-left");
        
        // listItem.appendChild(arror);

        //链接
        var linkElement = document.createElement("a");
        linkElement.setAttribute("href", "#");
        linkElement.classList.add("nav-link");


        //如果链接不为空,则进行访问
        if(menu.menuUrl){
            linkElement.setAttribute("onclick", `load_content("${menu.menuUrl}")`);
        }
        
        linkElement.textContent = menu.menuName;

        listItem.appendChild(linkElement);

        //添加
        menuContainer.appendChild(listItem);

        //递归菜单
        var subMenuContainer = document.createElement("ul");

        //class
        // subMenuContainer.classList.add("nav");
        // subMenuContainer.classList.add("nav-treeview");
        
        //添加
        listItem.appendChild(subMenuContainer);
        createMenuItems(menuData, menu.id, subMenuContainer);
    }
}

function generateMenu(menuData) {
    //处理一下data
    menuData = { "data": menuData.data };
    var menuContainer = document.getElementById("show-menu");
    createMenuItems(menuData.data, 0, menuContainer);
}


function getMenuDataAndGenerateMenu() {
    $.ajax({
        type: "GET",
        url: "/menu/list",
        data: { "pageSize": 114514 },
        dataType: "json",
        success: function (data) {
            if (data && data.data) {
                generateMenu(data); // Call the generateMenu function with the received data
            } else {
                console.log("[dayi-error]获得菜单数据失败");
            }
        },
        error: function () {
            console.log("[dayi-error]An error occurred while retrieving menu data.");
        },
    });
}

$(document).ready(function () {
    getMenuDataAndGenerateMenu(); // Fetch and generate menu data on page load
});
  1. 前端真要命

差不多这个效果。

11.1.1 新增菜单-功能实现

下拉选项从数据库查询,写个新增菜单功能。
  1. 先来个列表

11.1.1.1 menu-list.html

代码直接从user-list.html

去拿。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>AdminLTE 3 | jsGrid</title>

    <!-- Google Font: Source Sans Pro -->
    <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,400i,700&display=fallback">
    <!-- Font Awesome -->
    <link rel="stylesheet" href="../plugins/fontawesome-free/css/all.min.css">
    <!-- jsGrid -->
    <link rel="stylesheet" href="../plugins/jsgrid/jsgrid.min.css">
    <link rel="stylesheet" href="../plugins/jsgrid/jsgrid-theme.min.css">
    <!-- Theme style -->
    <link rel="stylesheet" href="../dist/css/adminlte.min.css">
</head>
<body class="hold-transition sidebar-mini">

<!-- Content Wrapper. Contains page content -->

<!-- Content Header (Page header) -->
<section class="content-header">
    <div class="container-fluid">
        <div class="row mb-2">
            <div class="col-sm-6">
                <h1>jsGrid</h1>
            </div>
            <div class="col-sm-6">
                <ol class="breadcrumb float-sm-right">
                    <li class="breadcrumb-item"><a href="#">Home</a></li>
                    <li class="breadcrumb-item active">jsGrid</li>
                </ol>
            </div>
        </div>
    </div><!-- /.container-fluid -->
</section>

<!-- Main content -->
<section class="content">
    <div class="card">
        <div class="card-header">
            <!-- 查询框 -->
            <div class="input-group">
                <input type="search" id="search" class="form-control form-control-lg" placeholder="请输入姓名关键字">
                <div class="input-group-append">
                    <button type="button" class="btn btn-lg btn-default" onclick="load_page()">
                        <i class="fa fa-search"></i>
                    </button>
                </div>
            </div>
        </div>
        <!-- /.card-header -->
        <div class="card-body">
            <div id="jsGrid1"></div>
        </div>
        <!-- /.card-body -->
    </div>
    <!-- /.card -->
</section>
<!-- /.content -->
<!-- jQuery -->
<script src="../plugins/jquery/jquery.min.js"></script>
<!-- Bootstrap 4 -->
<script src="../plugins/bootstrap/js/bootstrap.bundle.min.js"></script>
<!-- jsGrid -->
<script src="../plugins/jsgrid/demos/db.js"></script>
<script src="../plugins/jsgrid/jsgrid.min.js"></script>
<!-- AdminLTE App -->
<script src="../dist/js/adminlte.min.js"></script>
<!-- AdminLTE for demo purposes -->
<script src="../dist/js/demo.js"></script>


<!--菜单列表管理:-->
<script src="../js/menu-list.js"></script>

<script>

</script>
</body>
</html>

你需要修改的差不多就是这个图的 9和 12 行,剩下的找JS去实现。(不是图中这么简单)

  1. 写个JS

11.1.1.2 menu-add.js

这里直接复制文档的就可以。

$(function () {
    $("#jsGrid1").jsGrid({
//        height: "100%",
        width: "100%",
        height: "auto",
//        width: "auto",
        sorting: true, // 排序
        paging: true, // 分页计算,底部上一页下一页展示
        pageLoading: true, //启动后台加载分页数据
        autoload: true, //自动加载
        controller:{
            loadData: function(filter){
//            alert(filter.pageIndex);
                return $.ajax({
                    type: "post",
                    url: "/menu/list",
                    dataType: "json",
                    data: filter
                });
            }
        },
        pageIndex: 1, // 当前页数,是第几页
        pageSize: 3, // 每页数据条数
        pageButtonCount: 10, // 展示可选页码数量
        pagePrevText: "上一页",
        pageNextText: "下一页",
        pageFirstText: "首页",
        pageLastText: "尾页",
        fields: [
            {
                title: "", name: "id", type: "text", width: 20, align: "center",
                itemTemplate: function(value, item){
                    return "<input type='checkbox' value='" + value + "'>";
                }
            },
            { title: "菜单名", name: "menuName", type: "text", width: 100 },
            { title: "菜单编码", name: "menuCode", type: "text", width: 80 },
            { title: "菜单url", name: "menuUrl", type: "text", width: 80 },
            { title: "上级菜单", name: "parentMenu", type: "text", width: 80 },
            {
                title: "操作", name: "id", type: "text", width: 60, align: "center",
                itemTemplate: function(value, item){
                    return "<a href='javascript:void(0)' onclick='alert("+value+");'>修改</a>"
                        + "&nbsp;&nbsp;&nbsp;&nbsp;<a href='javascript:void(0)' onclick='alert("+value+");'>删除</a>";
                }
            }
        ]
    });
});

11.1.1.3 MenuController.java

之前写的就可以,返回的请求信息是符合文档的。

11.1.2 菜单列表

在mapper里添加

limit #{offset},#{pageSize}

这样限制条数。

11.1.2.1. 为了防止出现空指针问题,如果PageSize==null的话,就返回一个5

修改在: JsGridData.java

这样GET请求就没问题了

11.1.2.2. 前端默认会传递一个参数PageSize=3,请求方式为POST

用POSTMAN 模拟下请求(APIFOX,虽然有协作功能,但是好卡)

11.1.2.3. 菜单列表这样就可以啦

访问地址: http://localhost:8080/pages/menu-list.html

11.1.1 新增菜单

  1. 写一个新增菜单,直接从project-add.html复制就好

    menu-add.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>AdminLTE 3 | Project Add</title>
    
        <!-- Google Font: Source Sans Pro -->
        <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,400i,700&display=fallback">
        <!-- Font Awesome -->
        <link rel="stylesheet" href="../plugins/fontawesome-free/css/all.min.css">
        <!-- Theme style -->
        <link rel="stylesheet" href="../dist/css/adminlte.min.css">
    </head>
    <body class="hold-transition sidebar-mini">
    <!-- Site wrapper -->
    
    <!-- Navbar -->
    
    <!-- /.navbar -->
    
    <!-- Main Sidebar Container -->
    
    <!-- Content Wrapper. Contains page content -->
    
    <!-- Content Header (Page header) -->
    <section class="content-header">
        <div class="container-fluid">
            <div class="row mb-2">
                <div class="col-sm-6">
                    <h1>Project Add</h1>
                </div>
                <div class="col-sm-6">
                    <ol class="breadcrumb float-sm-right">
                        <li class="breadcrumb-item"><a href="#">Home</a></li>
                        <li class="breadcrumb-item active">Project Add</li>
                    </ol>
                </div>
            </div>
        </div><!-- /.container-fluid -->
    </section>
    
    <!-- Main content -->
    <section class="content">
        <div class="row">
            <div class="col-md-8 offset-md-2">
                <div class="card card-primary">
                    <div class="card-header">
                        <h3 class="card-title">General</h3>
    
                        <div class="card-tools">
                            <button type="button" class="btn btn-tool" data-card-widget="collapse" title="Collapse">
                                <i class="fas fa-minus"></i>
                            </button>
                        </div>
                    </div>
                    <div class="card-body">
    <!--菜单名-->
                        <div class="form-group">
                            <label for="menuName">菜单名</label>
                            <input type="text" id="menuName" class="form-control">
                        </div>
    <!--菜单代码-->
                        <div class="form-group">
                            <label for="menuCode">菜单代码</label>
                            <input id="menuCode" class="form-control">
                        </div>
    <!--菜单等级-->
                        <div class="form-group">
                            <label for="menuLevel">菜单Level</label>
                            <input type="text" id="menuLevel" class="form-control">
                        </div>
    
    <!--菜单URL-->
                        <div class="form-group">
                            <label for="menuUrl">菜单URL</label>
                            <input type="text" id="menuUrl" class="form-control">
                        </div>
    <!--父节点ID-->
                        <!--      学号    -->
                        <div class="form-group">
                            <label for="parentId">上级菜单(父节点ID)</label>
                            <input type="text" id="parentId" class="form-control">
                        </div>
    <!--排序-->
                        <div class="form-group">
                            <label for="sort">排序</label>
                            <input type="text" id="sort" class="form-control">
                        </div>
                        
                                        </div>
                    <!-- /.card-body -->
                </div>
                <!-- /.card -->
            </div>
    
        </div>
    
        <div class="row">
            <div class="col-md-8 offset-md-2">
                <a href="#" class="btn btn-secondary">Cancel</a>
                <input type="button" value="大白兔" class="btn btn-success float-right" onclick="mysubmit()">
            </div>
        </div>
    </section>
    <!-- jQuery -->
    <script src="../plugins/jquery/jquery.min.js"></script>
    <!-- Bootstrap 4 -->
    <script src="../plugins/bootstrap/js/bootstrap.bundle.min.js"></script>
    <!-- AdminLTE App -->
    <script src="../dist/js/adminlte.min.js"></script>
    <!-- AdminLTE for demo purposes -->
    <script src="../dist/js/demo.js"></script>
    <!--dayi_js-->
    <!--js-->
    <script src="../js/menu-add.js"></script>
    <!--js-->
    
    </body>
    </html>
    
    对着菜单信息进行改一下:
    
    ![](https://cmd.dayi.ink/uploads/upload_6d480b03928fac7303bfa8c3370b9d60.png)
    
    效果差不多这个样子:
    
    ![](https://cmd.dayi.ink/uploads/upload_014845f3023cbf338b33dc4044718b37.png)
    
    
  2. 然后写menu-add.js

    var menu_add_submit = function () {
        //获取所有的输入的值,组装成json对象
        var params = {
            menuName: $("#menuName").val(),
            menuCode: $("#menuCode").val(),
            menuLevel: $("#menuLevel").val(),
            menuUrl: $("#menuUrl").val(),
            parentId: $("#parentId").val(),
            sort: $("#sort").val()
        };
        //使用ajax提交
        $.ajax({
            type: "post",
            url: "/menu/add",
            data: params,
            dataType: "json",
            success:function (data){
                if(data.code === "200"){
                    alert("新增成功");
                }
                else{
                    alert("新增失败");
                }
            }
        });
    };
  3. 写后端 controller

    @RequestMapping(value = "/add",produces = "application/json; charset=utf-8")
        @ResponseBody
        public String add(JsGridData jsGridData){
            String res = menuService.add(jsGridData);
            return res;
        }
  4. service

    String add(JsGridData jsGridData);
    @Override
        public String add(JsGridData jsGridData) {
            int add_ = menuMapper.add(jsGridData);
            Map<String,String> msg = new HashMap<>();
            msg.put("msg","999");
    
            if(add_>0){
                msg.put("code","200");
            }
    
            return JSONObject.toJSONString(msg);
    
    }
  5. 写个mapper

    public interface MenuMapper {
        List<Menu> list(JsGridData jsGridData);
        Long count(JsGridData jsGridData);
        Integer add(JsGridData jsGridData);
    }
  6. mapper xml

    这样写,方便加表,也能防止一些错误。相关代码都在github上(文章末尾),请直接看最新的就好。

       <insert id="add" parameterMap="net.dabbit.skd21.exam.entity.Menu" resultType="java.lang.Integer">
        insert into menu
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <if test="id != null">
                id,
            </if>
            <if test="menuCode != null">
                menu_code,
            </if>
            <if test="menuName != null">
                menu_name,
            </if>
            <if test="menuUrl != null">
                menu_url,
            </if>
            <if test="menuLevel != null">
                menu_level,
            </if>
            <if test="parentId != null">
                parent_id,
            </if>
            <if test="sort != null">
                sort,
            </if>
        </trim>
        <trim prefix="values (" suffix=")" suffixOverrides=",">
            <if test="id != null">
                #{id,jdbcType=INTEGER},
            </if>
            <if test="menuCode != null">
                #{menuCode,jdbcType=VARCHAR},
            </if>
            <if test="menuName != null">
                #{menuName,jdbcType=VARCHAR},
            </if>
            <if test="menuUrl != null">
                #{menuUrl,jdbcType=VARCHAR},
            </if>
            <if test="menuLevel != null">
                #{menuLevel,jdbcType=VARCHAR},
            </if>
            <if test="parentId != null">
                #{parentId,jdbcType=INTEGER},
            </if>
            <if test="sort != null">
                #{sort,jdbcType=INTEGER},
            </if>
        </trim>
    </insert>

  1. 测试添加是否成功

  1. 看看数据库

成功插入

11.1.3 菜单删除

  1. 先写后端
  2. Controller

  1. mapper service

service

  1. 实现类

  1. Mapper XML

  1. POST请求测试

成功啦,这样再写前端JS就行了

  1. JS

上面的修改部分:

res_str = `<a href='javascript:void(0)' onclick='modify_menu_func(${value});'>修改</a>`
                        + "&nbsp;&nbsp;&nbsp;&nbsp;"+`<a href='javascript:void(0)' onclick="del_menu_fuc(${value});">删除</a>`;
                    return res_str

下面的函数如图:

var del_menu_fuc = function (del_id) {
    $.ajax({
        type:"post",
        url:"/menu/del",
        data:{"id":del_id},
        dataType: "json",
        success:function (data){
            if(data.code!="200"){
                alert("删除失败")
                console.log(`[sys]Del ${del_id} failed.`)
            }
            if(data.code=="200"){
                alert("删除成功")
                console.log(`[sys]Del ${del_id} succeed.`)
            }
        }
    })
}
  1. 测试:

呃呃?

再试试

CTRL+F5强制加载JS

这样就可以了。

11.1.4 菜单修改

  1. controller

  1. service

  1. service impl

  1. mapper

  1. mapper xml

<update id="updateByPrimaryKeySelective" parameterType="net.dabbit.skd21.exam.entity.Menu">
        update menu
        <set>
            <if test="menuCode != null">
                menu_code = #{menuCode,jdbcType=VARCHAR},
            </if>
            <if test="menuName != null">
                menu_name = #{menuName,jdbcType=VARCHAR},
            </if>
            <if test="menuUrl != null">
                menu_url = #{menuUrl,jdbcType=VARCHAR},
            </if>
            <if test="menuLevel != null">
                menu_level = #{menuLevel,jdbcType=VARCHAR},
            </if>
            <if test="parentId != null">
                parent_id = #{parentId,jdbcType=INTEGER},
            </if>
            <if test="sort != null">
                sort = #{sort,jdbcType=INTEGER},
            </if>
        </set>
        where id = #{id,jdbcType=INTEGER}
    </update>

相关代码复制在github中(文章末尾)。

  1. 测试一下


修改成功

  1. 前端:

改的内容不少,新增页面要判断是否为新增模式。也要判断是否为修改模式。

这样就JS实现一下,把按钮换掉就好。

menu-list.js

menu-add.js

完整:

mode_label = "add"

var menu_add_submit = function () {
    //获取所有的输入的值,组装成json对象
    var params = {
        menuName: $("#menuName").val(),
        menuCode: $("#menuCode").val(),
        menuLevel: $("#menuLevel").val(),
        menuUrl: $("#menuUrl").val(),
        parentId: $("#parentId").val(),
        sort: $("#sort").val()
    };
    //使用ajax提交
    $.ajax({
        type: "post",
        url: "/menu/add",
        data: params,
        dataType: "json",
        success:function (data){
            if(data.code === "200"){
                alert("新增成功");
            }
            else{
                alert("新增失败");
            }
        }
    });
};


var modify_menu_func =  function () {
    //获取id
    var id = $("#id").val();
    //使用ajax提交
    $.ajax({
        type: "post",
        url: "/menu/modify",
        data: {
            id: id,
            menuName: $("#menuName").val(),
            menuCode: $("#menuCode").val(),
            menuLevel: $("#menuLevel").val(),
            menuUrl: $("#menuUrl").val(),
            parentId: $("#parentId").val(),
            sort: $("#sort").val()
        },
        dataType: "json",
        success:function (data){
            if(data.code === "200"){
                alert("修改成功");
                console.log('[sys]success edit')
            }
            else{
                alert("修改失败");
                console.log('[sys]fail edit')
            }
        }
    });
}


//加载完成判断有没有值
$( document ).ready(function() {
    //检查id是否有值
    get_id = $("#id").val();
    if(get_id!= ""){
        //修改模式
        mode_label = "edit"
        //获得dayi-button
        var dayi_button = document.getElementById("dayi-button");
        //给dayi-button添加点击事件
        dayi_button.addEventListener("click",modify_menu_func);
        //命名
        $("#dayi-button").val('大白兔-修改')
        return
    }

    //新增模式
    mode_label = "add"
    //获得dayi-button
    var dayi_button = document.getElementById("dayi-button");
    //给dayi-button添加点击事件
    dayi_button.addEventListener("click",menu_add_submit);
    //命名
    $("#dayi-button").val('大白兔-新增')
});

menu-add.html

有点丑,改成这样:

  1. 动态加载菜单修复代码之前临时写一下:

不然加载不上。

  1. 查看效果

菜单倒是没问题了,但是后端炸了,估计传参的时候掉了,两个都是正常的功能。

  1. 改bug

好像载荷不对劲

JS在这里改一下

OK ,修好了。

最新代码见文件末尾

11.1.5 左边的菜单

从数据库中更新:

这个实现起来JS写吐了

差不多这个样子

JS还要改,先这样放上,临时够用了。

文件见:

left-list.js

//不完善版本0.5
function createNavItemWithLink(text, iconClass, link, onClick) {
    // 创建 <li> 元素
    var listItem = document.createElement("li");
    listItem.classList.add("nav-item");

    // 创建 <a> 元素
    var linkElement = document.createElement("a");
    linkElement.setAttribute("href", link);
    linkElement.classList.add("nav-link");
    linkElement.addEventListener("click", onClick);

    // 创建 <i> 元素
    var icon = document.createElement("i");
    icon.classList.add(iconClass);
    icon.classList.add("nav-icon");

    // 创建 <p> 元素
    var linkText = document.createElement("p");
    linkText.innerText = text;

    // 把 <i> 元素添加到 <a> 元素中
    linkElement.appendChild(icon);

    // 把 <p> 元素添加到 <a> 元素中
    linkElement.appendChild(linkText);

    // 把 <a> 元素添加到 <li> 元素中
    listItem.appendChild(linkElement);

    // 返回生成的 <li> 元素
    return listItem;
}

/*
使用方法:

var listItem1 = createNavItemWithLink("新增頁", "far fa-circle", "javascript:void(0)", function() {
  load_content('project-add.html');
});

var listItem2 = createNavItemWithLink("列表", "far fa-circle", "javascript:void(0)", function() {
  load_content('project-list.html');
});

*/


function createMenuItems(menuData, parentMenuId, menuContainer) {
    // Filter out the submenu items for the specified parent menu
    var subMenuItems = menuData.filter(function (menu) {
        return menu.parentId === parentMenuId;
    });

    // Iterate over the submenu items
    for (var i = 0; i < subMenuItems.length; i++) {
        var menu = subMenuItems[i];
        
        //一级菜单
        var listItem = document.createElement("li");
        listItem.classList.add("nav-item");

        var arror = document.createElement("a");
        //<i class="right fas fa-angle-left"></i>
        arror.classList.add("right");
        arror.classList.add("fas");
        arror.classList.add("fa-angle-left");
        
        // listItem.appendChild(arror);

        //链接
        var linkElement = document.createElement("a");
        linkElement.setAttribute("href", "#");
        linkElement.classList.add("nav-link");


        //如果链接不为空,则进行访问
        if(menu.menuUrl){
            linkElement.setAttribute("onclick", `load_content("${menu.menuUrl}")`);
        }
        
        linkElement.textContent = menu.menuName;

        listItem.appendChild(linkElement);

        //添加
        menuContainer.appendChild(listItem);

        //递归菜单
        var subMenuContainer = document.createElement("ul");

        //class
        // subMenuContainer.classList.add("nav");
        // subMenuContainer.classList.add("nav-treeview");
        
        //添加
        listItem.appendChild(subMenuContainer);
        createMenuItems(menuData, menu.id, subMenuContainer);
    }
}

function generateMenu(menuData) {
    //处理一下data
    menuData = { "data": menuData.data };
    var menuContainer = document.getElementById("show-menu");
    createMenuItems(menuData.data, 0, menuContainer);
}


function getMenuDataAndGenerateMenu() {
    $.ajax({
        type: "GET",
        url: "/menu/list",
        data: { "pageSize": 114514 },
        dataType: "json",
        success: function (data) {
            if (data && data.data) {
                generateMenu(data); // Call the generateMenu function with the received data
            } else {
                console.log("[dayi-error]获得菜单数据失败");
            }
        },
        error: function () {
            console.log("[dayi-error]An error occurred while retrieving menu data.");
        },
    });
}

$(document).ready(function () {
    getMenuDataAndGenerateMenu(); // Fetch and generate menu data on page load
});

目前版本:

https://github.com/magical-rabbit/java-spring/commit/2117709371bab8669b08f1acc491a39c52361e92

11.2 角色管理

OK 下一部分

11.2.1 新增角色

  1. 先复制他要求的css和js,从那个ztree文件里解压
zTree_v3-master\js下的文件都放到webapp/js/ztree下
zTree_v3-master\css下的文件都放到webapp/css下

  1. 新建role-add.html

内容先直接复制ztree示例.html

复制这俩到head标签里,然后原先的就没有用了,直接删掉就好

<link rel="stylesheet" href="../css/zTreeStyle/zTreeStyle.css" type="text/css">
<script src="../js/ztree/jquery.ztree.all.min.js"></script>

  1. 我也不知道下来列表是什么

就直接这样复制上了。

<div class="form-group">
  <label for="menuTree">菜单列表</label>
  <ul id="menuTree" class="ztree"></ul>
  <input type="hidden" id="menuIds" class="form-control">
</div>

  1. 我打开这个页面的时候会报错

  1. 先把JS复制上
这个参照文档 59-60 页

  1. 改了改代码跑起来了,但是不知道怎么用

相关代码,见github


目前没做出来, 我有点理解不了他的内容

现在做出来啦!


这里更新一下,ROLE一样的实现:

然后是前端

看样子没问题啦

角色树

11.3 用户管理

11.3.1 新增用户

咱们之前就写完了,但是之前的文件名叫project-add.html

这里咱们直接复制一个文件

11.3.2 用户列表

也写完啦

但是左边的菜单不会自动出现,所以写sql语句(添加到数据库)

左边的用户管理,应该对应的是user-list.html,他也写错了。

(见项目文件tools/sql_fix.sql)

INSERT INTO `menu` (`menu_code`, `menu_name`, `menu_url`, `menu_level`, `parent_id`, `sort`) VALUES ('user-add', '新增用户', 'user-add.html', '2', 28, 2);
UPDATE `menu` SET `menu_url` = 'user-list.html' WHERE `id` = 36

11.3.3 修改用户

逻辑实现了

可以完善一下,但是也可以用

11.3.4 删除用户

逻辑没问题

11.4 模板管理

11.4.1 新建模板-前端部分

我复制来了,你看这个条子,多好看,能跑不就行PVP

丑对不对,来行这个

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/picnic">

这样就更丑啦!

加点CSS

这样还可以能看。

11.4.1 新建模板-后端

  1. 我找到对应的数据库了

image-20231005211001736

2.这样根据这个数据库写就好。

还是老套路

  1. 实体类

    QuestionTemplate.java

    image-20231005211246318

  2. 这次反着写 mapper
    QuestionTemplateMapper

    因为后面还有,这里就直接一起写了

    11.4.2 模板列表
    11.4.3 修改模板
    11.4.4 删除模板

    image-20231005215755229

  3. 然后来写mapper xml

    排版原因,请看GITHUB上的源码

    image-20231005212910907

  4. 再写service

    image-20231005215551357

    实现类:

    image-20231005215539930

    package net.dabbit.skd21.exam.service.impl;
    
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    import com.alibaba.fastjson.JSONObject;
    
    import net.dabbit.skd21.exam.entity.JsGridData;
    import net.dabbit.skd21.exam.entity.QuestionTemplate;
    import net.dabbit.skd21.exam.mapper.QuestionTemplateMapper;
    import net.dabbit.skd21.exam.service.QuestionTemplateService;
    
    
    @Service
    public class QuestionTemplateServiceImpl implements QuestionTemplateService{
        @Autowired
        QuestionTemplateMapper questionTemplateMapper;
    
        @Override
        public String add(QuestionTemplate questionTemplate) {
            Map<String,String> msg = new HashMap<String,String>();
            msg.put("msg","2333");
    
            int add_ = questionTemplateMapper.add(questionTemplate);
            if(add_>0){
                msg.put("code","200");
            }else{
                msg.put("code","401");
                msg.put("info", "添加失败,修改条数小于1");
            }
            return JSONObject.toJSONString(msg);
        }
    
        @Override
        public String list(JsGridData jsdata) {
            long cnt = questionTemplateMapper.count(jsdata);
            List<QuestionTemplate> list = questionTemplateMapper.list(jsdata);
    
            //设置数据,设置列表数量
            jsdata.setData(list);
            jsdata.setItemsCount(cnt);
    
            //返回数据
    
            return JSONObject.toJSONString(jsdata);
        }
    
        @Override
        public String update(QuestionTemplate questionTemplate) {
    
            Map<String,String> msg = new HashMap<String,String>();
            msg.put("msg","2333");
            int update_ = questionTemplateMapper.update(questionTemplate);
            if(update_>0){
                msg.put("code","200");
            }else{
                msg.put("code","401");
                msg.put("info", "修改失败,修改条数小于1");
            }
            return JSONObject.toJSONString(msg);
        }
    
        @Override
        public String del(Integer id) {
            Map<String,String> msg = new HashMap<String,String>();
            msg.put("msg","2333");
            int del_ = questionTemplateMapper.del(id);
            if(del_>0){
                msg.put("code","200");
            }else{
                msg.put("code","401");
                msg.put("info", "删除失败,修改条数小于1");
            }
            return JSONObject.toJSONString(msg);
        }
    
    }
  5. controller

    image-20231005215456151

  1. 测试一下

image-20231005220636560

要哭了

  1. 出来了,呜呜呜

    image-20231005223254448

  2. 真的写哭了

​ 具体代码看github的源码bia

11.4.1 新建模板-前端2

  • 院系、专业、学期、科目四个下拉列表,是一个三级联动
  • 然后就写)
  • 不是,学期是啥啊?
  • 我在数据库里没找到学期这个东西,有个是school_year,但是没有单独的表。
  • 补:他在html叫这个

    image-20231006003319141

    数据库里的表:

    image-20231006003308930

  • 把两个写上就跑路。(没有学期,没有科目,怎么加载)
  • JS如下

    
    //加载院系函数
    var load_faculty_list = function (){
     $.ajax({
         type: "post",
         url: "/faculty/getAllFaculty",
         dataType: "json",
         success:function (data){
             console.log(data)
             var opts = `<option value="">--请选择--</option>`
             $.each(data,function(index,obj){
                 opts+=`<option value="${obj.id}">${obj.facultyName}</option>`
             })
    
             $("#faculty_id").html(opts)
         }
     })
    }
    
    //加载专业
    var load_major_options = function (){
     var FacultyId = $("#faculty_id").val()
     $.ajax({
         type: "post",
         url: "/major/getByFacultyId",
         data: {"FacultyId":FacultyId},
         dataType: "json",
         success:function (data){
             console.log(data)
             var opts = `<option value="">--请选择--</option>`
             $.each(data,function(index,obj){
                 opts+=`<option value="${obj.id}">${obj.majorName}</option>`
             })
    
             $("#major_id").html(opts)
         }
     })
    }
    
    
    //加载班级
    var load_class_options = function(){
     // 获取当前选中的专业
     var majorId = $("#major_id").val();
     $.ajax({
         type: "post",
         url: "/class/getByMajorId",
         data: {"majorId": majorId},
         dataType: "json",
         success: function(data){
             console.log(data);
             var opts = '<option value="">--请选择--</option>';
             $.each(data, function(index, obj){
                 opts += '<option value="$id">$text</option>'.replace("$id", obj.id).replace("$text", obj.className)
             });
             // 把选项放到下拉列表
             $("#major_semester_id").html(opts);
         }
     });
    }
    
    
    //页面加载完成,自动加载
    
    $(document).ready(function () {
     //加载院系
     load_faculty_list();
    });

    image-20231006003052816

  • 能跑了

    image-20231006003414114

  • 但,我发现他好像用CLASS应付的

    image-20231006003027722

  • 那就把学期当做班级,先写上,占上位置。
  • 效果这样,但是有问题

    image-20231006003621343

    这个必须做完之后的才能正常,要么就随便填个假的。

11.4.1【dayi函数库-测试版本】

因为重复性工作实在是太多啦,这样把前端简化,功能不变的同时,可以更快的修改各种各样的前端!

实际上用的过程中,只需要改10行以内的(主要是字段和中文),就可以完全生成一个前端!相关代码塞附录啦。

  1. dayi函数库

    image-20231006005320111

    感觉重复性的工作太多了,想直接写个库,这样就可以直接获得表单的数据啦。

image-20231006005210783

  1. 添加功能:

    image-20231006005946677

    写个按钮

  2. 使用袋一函数库,两行解决问题,你值得拥有

    image-20231006011056397

  3. 贴心报错提示,随时告诉你后端爆炸

    image-20231006010522708

  4. 我发现数据库,这个实体压根没有院系

    image-20231006011344921

  5. dayi-LIB 自动驼峰命名,你值得拥有

    image-20231006011728628

    image-20231006011910196

  6. dayi-lib可以在最新代码那个地方下载。
  7. 已经添加成功了

    image-20231006012020340

11.4.2 模板列表

  1. 又是一个列表啊

    又是重复工作

    没关系,dayi-lib会尝试拯救你(2023年10月6日01:24:32,但没法拯救dayi)

  2. 你只需要复制这么一点,就可以自动加载列表

    image-20231006012925736

  3. 好像效果也不是特别好,还得优化一下,但是问题不大

    image-20231006013831698

  4. 写列表加载

写到这里,代码已经push到github


改为写完一个章节,再写这个文档,错误太多了,代码请直接从github上复制。


image-20231006112710066

  1. 列表加载写完啦

    就写这点就可以自动加载啦(快夸夸我)

    image-20231006113532309估计可以用啦,这样就把基本的lib库函数写完啦。

    这个样子:

    image-20231006115513147

11.4.3 【dayi-函数库 ver1.0】更新列表-前端-dayi lib库的完善

测试库的开发
  1. 直接写成脚本库

image-20231006121720433

image-20231006121728445

  1. 被迫用了点异步,因为表单会提前加载,需要等待完成。

image-20231006123043086

  1. 效果这个样子

    image-20231006123823776

  2. 好累)

    image-20231006130652617

  3. 传参试试

    image-20231006134737018

image-20231006134811743

  1. 修改成功wwwimage-20231006134912661
  2. 然后把要修改的数据传过来
  3. 直接写一个新函数填表吧

    回填

    用了点异步,来调整顺序

    image-20231006135507445

  4. 回填成功!

    image-20231006135614284

    好开心)))

    image-20231006135749318

  5. 剩下的就是删除了,这个简单

    image-20231006140358203

  6. 最后就是封装

    这点点代码就可以把整个重复逻辑给实现啦

    image-20231006140606151

  7. 试试

    image-20231006140908145

    好好好

    是后端炸了

    image-20231006141001024

  8. 写成delete了

    image-20231006141115724

  9. 成功啦

    image-20231006141156641

这样就算完成啦

11.4.4 删除模板

写完啦!

上面都有图啦

image-20231006141501417

11.5 题库管理

先把代码复制上,看看是什么bia

这个样子诶(文件test-upload.html

image-20231006144858593

11.5.1 题库管理-前端

  1. 复制上HTML代码之后
  2. 左侧连接直接去数据库添加条目就可以

    INSERT INTO `menu` (`id`, `menu_code`, `menu_name`, `menu_level`, `parent_id`, `sort`) VALUES ('43', 'exam', '试题管理', '1', '0', '1');
    
    INSERT INTO `menu` (`id`, `menu_code`, `menu_name`, `menu_url`, `menu_level`, `parent_id`, `sort`) VALUES ('44', 'exam-uploader', '试题上传', 'test-upload.html', '2', '43', '1');
    

    image-20231006145828879

  3. 这样侧边栏就会有菜单了

    image-20231006150704508

11.5.2 题库管理-后端

  1. 依赖文件

    复制上就好

            <dependency>
                <groupId>org.apache.poi</groupId>
                <artifactId>poi</artifactId>
                <version>3.14</version>
            </dependency>
            <dependency>
                <groupId>org.apache.poi</groupId>
                <artifactId>poi-ooxml</artifactId>
                <version>3.14</version>
            </dependency>

    image-20231006150820612

  2. 记得点那个小蓝,同步下仓库
  3. 然后把他的库粘贴上,大概这个样子,依赖库

    import org.apache.poi.hssf.usermodel.HSSFWorkbook;
    import org.apache.poi.ss.usermodel.Cell;
    import org.apache.poi.ss.usermodel.Row;
    import org.apache.poi.ss.usermodel.Sheet;
    import org.apache.poi.ss.usermodel.Workbook;
    
    import java.io.InputStream;
    import java.util.*;

    image-20231006151213192

  4. 写controller

    我看他URL用的是

    这样表单直接飞上来的。

    /test/upload

    image-20231006152040352

  5. 这样照着写一个
  6. 好奇怪

    image-20231006153126864

  7. 然后要保存,就要写数据库了
  8. 但是dayi也很想吐槽:

    image-20231006153424896

数据库这个应该就是

image-20231006153617973

  1. Question.java

    image-20231006153729124

  2. QuestionOptions.java

    image-20231006154027090

  3. 然后是mapper

    我觉得这两个写一个mapper就可以

    image-20231006154124413

    问题和选项添加:

    image-20231006161319616

    查询问题:

    image-20231006161303019

  4. 连接表,但好像没什么用,可以直接后端拉信息,然后再去查具体的题目选项。

    SELECT * 
    FROM question_bank inner join question_options on question_bank.question_code=question_options.question_code

    image-20231006160340198

    所以并不需要直接在数据库里合并表格

    image-20231006160813565

  5. 然后是mapper

    image-20231006161551317

  6. 服务接口

    image-20231006162135666

  7. 服务实现:

    image-20231006163704149

    image-20231006164429913

  8. 写完了,试一试

    image-20231006164638570

  9. 有个Autowire要这么写

    然后不是这里的问题,是impl没写@service(找了3个小时的BUG)

    image-20231006173202759

  10. 试一试

    image-20231006173151882

  11. 要命,改了4个小时了

    image-20231006190033679

  12. 心态爆炸

    image-20231006190153295

  13. 不插入了,先这样吧

11.5.3 修改的文件:

image-20231006191311028

11.6 院系管理

11.6.1 新建院系

11.6.2 院系列表

11.6.3 修改院系

11.6.4 删除院系

这些分一个做完就好,很简单啦。

11.6.1 院系管理-后端

因为之前写了一部分了:

image-20231006191721339

然后开始写:

  1. mapper xml

    image-20231006192646440

  2. mapper

    image-20231006192656597

  3. service

    image-20231006194418709

  4. controller

    image-20231006194356737

  5. 测试:

    image-20231006194514535

  6. 好累,我让这个东西,那个叫mybatis生成器,生成了一点文件

image-20231006193154894

11.6.2 院系管理-前端

dayi-lib库,你只需要几行就可以完成整个前端!

1.列表:

这样改一下就好:

image-20231006194858706

  1. 新增:

    也是,有了lib,直接去生成就好。

    image-20231006195120563

  2. 这样用dayilib 轻松解决问题:

    image-20231006195423240

  3. 你看怎么样?

    image-20231006195440962

  4. 轻松新增

    image-20231006195634304

  5. 修改代码不足20行

    image-20231006195856530

    image-20231006195911996

    image-20231006195928519

  6. 轻松添加猴子系,你还在等什么?

    image-20231006200025963

  7. 轻松删除猴子系,你还在等什么?

    image-20231006200118809

  8. 轻松修改猴子系,你还在等什么?

    image-20231006200204093

相关文件:

image-20231006202601893

11.7 专业管理

11.7.1 后端

  1. controller

    image-20231006205134308

  2. mapper

    image-20231006205153455

  3. mapper xml

    image-20231006205207607

  4. service impl

    image-20231006205242579

  5. service

    image-20231006205301485

  6. POSTMAN测试

    image-20231006205316821

11.7.2 前端

image-20231006205646644

image-20231006205558937

image-20231006205632306

新增专业测试:人生是没有回头路的。

image-20231006210452341

然后我们可以找到:

image-20231006210525062

保存成功

image-20231006210617615

删除成功:

image-20231006210736394

本章节修改的文件:

image-20231006210834092

11.8 班级管理

11.8.1 后端

  • mapper xml
  • controller
  • service
  • serviceImpl

都差不多啦

image-20231006215146623

11.8.2 前端

前段也是,复制两个html文件,稍微改一改就好。

image-20231006220537850

image-20231006220548669

image-20231006220600257

image-20231006220702200

image-20231006220719581

image-20231006220741609

image-20231006220750177

11.8.3 本章节修改的文件

image-20231006220848434

11.9 科目管理

11.9.1 后端

感觉没什么好说的啦, 就是发现生成的xml又生成了一次,导致报错了。

11.9.2 前端

还是用了dayi-lib的JS库,这样你就额可以10行写一个前端啦。

列表:

修改:

删除:

11.10 专业学期管理

11.10.1 后端

专业学期增删改查

老样子

服务

实现:

controller:

测试:

11.10.2 前端

还是用超级dayi库

  1. 文件1:


  1. 文件2:

新增功能:

把url提炼出来,这样就只需要修改一个地方啦。

  1. 测试

数据库:(修改菜单)

增加:

列表:

列表2:(刚才新增的地方写错了一点)

修改:

删除:

11.10.3 本次修改的文件:

11.10.4 目前的menu数据库:


SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for menu
-- ----------------------------
DROP TABLE IF EXISTS `menu`;
CREATE TABLE `menu`  (
  `id` int NOT NULL AUTO_INCREMENT,
  `menu_code` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `menu_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `menu_url` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `menu_level` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `parent_id` int NULL DEFAULT NULL,
  `sort` int NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 60 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of menu
-- ----------------------------
INSERT INTO `menu` VALUES (25, 'menu-1-template', '一级菜单', '', '1', 0, 1);
INSERT INTO `menu` VALUES (27, 'role', '角色管理', '', '1', 0, 3);
INSERT INTO `menu` VALUES (28, 'user', '用户管理', '', '1', 0, 4);
INSERT INTO `menu` VALUES (29, 'project-add', '二级菜单-新增/修改模板', 'project-add.html', '2', 25, 1);
INSERT INTO `menu` VALUES (30, 'project-list', '二级菜单-数据列表模板', 'project-list.html', '2', 25, 2);
INSERT INTO `menu` VALUES (31, 'choose', '二级菜单-在线考试模板', 'choose.html', '2', 25, 3);
INSERT INTO `menu` VALUES (32, 'menu-add', '新增菜单', 'menu-add.html', '2', 26, 1);
INSERT INTO `menu` VALUES (33, 'menu-list', '菜单列表', 'menu-list.html', '2', 26, 2);
INSERT INTO `menu` VALUES (34, 'role-add', '新增角色', 'role-add.html', '2', 27, 1);
INSERT INTO `menu` VALUES (35, 'role-list', '角色列表', 'role-list.html', '2', 27, 2);
INSERT INTO `menu` VALUES (36, 'user-add', '用户管理', 'user-add.html', '2', 28, 1);
INSERT INTO `menu` VALUES (37, 'questions', '题库管理', '', '1', 0, 5);
INSERT INTO `menu` VALUES (38, 'file-upload', '试题上传', 'file-upload.html', '2', 37, 1);
INSERT INTO `menu` VALUES (39, '', '', '', '', NULL, NULL);
INSERT INTO `menu` VALUES (40, 'template', '模板管理', '', '1', 0, 1);
INSERT INTO `menu` VALUES (41, 'template-list', '模板列表', 'template-list.html', '2', 40, 1);
INSERT INTO `menu` VALUES (42, 'template-add', '模板新增', 'template.html', '2', 40, 2);
INSERT INTO `menu` VALUES (43, 'exam', '试题管理', NULL, '1', 0, 1);
INSERT INTO `menu` VALUES (44, 'exam-uploader', '试题上传', 'test-upload.html', '2', 43, 1);
INSERT INTO `menu` VALUES (45, 'faculty', '院系管理', NULL, '1', 0, 1);
INSERT INTO `menu` VALUES (46, 'faculty-add', '院系添加', 'faculty-add.html', '2', 45, 1);
INSERT INTO `menu` VALUES (47, 'faculty-list', '院系列表', 'faculty-list.html', '2', 45, 2);
INSERT INTO `menu` VALUES (48, 'major', '专业', NULL, '1', 0, 1);
INSERT INTO `menu` VALUES (49, 'major-add', '专业-添加', 'major-add.html', '2', 48, 1);
INSERT INTO `menu` VALUES (50, 'major-list', '专业列表', 'major-list.html', '2', 48, 2);
INSERT INTO `menu` VALUES (51, 'class', '班级管理', NULL, '1', 0, 1);
INSERT INTO `menu` VALUES (52, 'class-add', '班级新增', 'class-add.html', '2', 51, 1);
INSERT INTO `menu` VALUES (53, 'class-list', '班级列表', 'class-list.html', '2', 51, 2);
INSERT INTO `menu` VALUES (54, 'subject', '课程管理', NULL, '1', 0, 1);
INSERT INTO `menu` VALUES (55, 'subject-add', '课程添加', 'subject-add.html', '2', 54, 1);
INSERT INTO `menu` VALUES (56, 'subject-list', '课程列表', 'subject-list.html', '2', 54, 2);
INSERT INTO `menu` VALUES (57, 'major-semester', '专业学年管理', NULL, '1', 0, 1);
INSERT INTO `menu` VALUES (58, 'major-semester-add', '专业学年增加', 'major-semester-add.html', '2', 57, 1);
INSERT INTO `menu` VALUES (59, 'major-semester-list', '专业学年列表', 'major-semester-list.html', '2', 57, 2);

SET FOREIGN_KEY_CHECKS = 1;

11.11 试卷管理

11.11.1 复制类

但是有个包导入失败

pom.xml

<dependency>
    <groupId>com.mchange</groupId>
    <artifactId>c3p0</artifactId>
    <version>0.9.5.5</version> <!-- 或者您需要的版本号 -->
</dependency>

但是有个包导入失败

pom.xml

<dependency>
    <groupId>com.mchange</groupId>
    <artifactId>c3p0</artifactId>
    <version>0.9.5.5</version> <!-- 或者您需要的版本号 -->
</dependency>

直接把类重新生成了一下

可以正常抽题了。

11.11.2 干脆把给的代码重写了一下,然后直接塞controller了,就跑起来啦!

这里是controller

简陋,但是实现了功能。具体的规范性如果还有时间再来规范。

{
    "EASY": [
        37,
        34,
        51,
        44,
        24,
        20,
        41,
        22,
        29,
        38,
        35,
        40,
        27,
        30
    ],
    "MEDIUM": [
        62,
        59,
        89,
        68,
        32,
        51,
        95,
        33
    ],
    "HARD": [
        27,
        114
    ],
    "VERY_HARD": [
        109,
        120
    ]
}

11.11.3 然后是根据题目编号获得题目

随便写写,就这个样子

image-20231008003003231

返回的json

这里答案肯定是应该要隐藏的,但是实际上,某些平台的好像也就这样,直接能拿答案)

主要是内容有点多,先实现功能,然后是能跑。

{
    {
        "answer": "D ",
        "createTime": 1639065652000,
        "difficulty": 0,
        "id": 19,
        "questionCode": "0-f1dad818-5c94-4a27-b071-f1582652e7df",
        "questionName": "资本主义经济危机的根源在于( )。",
        "subjectId": 1,
        "type": 0
    }: [
        {
            "id": 73,
            "optionsCode": "A",
            "optionsText": " 生产和消费的矛盾  ",
            "questionCode": "0-f1dad818-5c94-4a27-b071-f1582652e7df"
        },
        {
            "id": 74,
            "optionsCode": "B",
            "optionsText": " 劳动人民的消费不足 ",
            "questionCode": "0-f1dad818-5c94-4a27-b071-f1582652e7df"
        },
        {
            "id": 75,
            "optionsCode": "C",
            "optionsText": " 消费需求和投资需求的不足 ",
            "questionCode": "0-f1dad818-5c94-4a27-b071-f1582652e7df"
        },
        {
            "id": 76,
            "optionsCode": "D",
            "optionsText": " 资本主义基本矛盾 ",
            "questionCode": "0-f1dad818-5c94-4a27-b071-f1582652e7df"
        }
    ]
}

11.11.4 前端

生成啦一个,还可以

这样可以直接做题并且自动打分。

(就当练习啦)

然后再美化下CSS

效果图2:

11.11.5 前端倒计时,时间到了自动提交代码

倒计时:

11.12 在线考试

11.12.1 在线考试

我觉得已经差不多实现了。剩下的就是完善功能了。

考虑到时间关系,先实现功能,然后再慢慢完善,光这个markdown文件也4204行了。

11.12.2 成绩查询

根据院系、专业、学期、科目、当前登录的用户id,查询当前登录用户的指定科目的成绩。

11.12.2 成绩查询

11.12.2 后端

根据院系、专业、学期、科目、当前登录的用户id,查询当前登录用户的指定科目的成绩。
  1. 实现逻辑:
  • 从后端获得当前登录的用户。
  • 很遗憾,我们的登录功能是假的。
  • 所以要写一个登录功能,并且存cookie
  • 好像时间有点来不及了,所以,我们将错就错,直接登录,然后返回成绩。
  • 这样就简单多了。
  1. 开始实现。
  • 成绩是有一个实体,叫score。
  • 先写mapper
  1. mapper 和 xml

这里直接用他的库,所以,我们直接修改一下,然后直接写servcie就可以。

  1. service
  • 我们需要一个能够实现按用户id查询成绩就可以了。
  • 根据实体,传入的参数有,科目名,用户id。

  1. 开始实现
  • mapper xml

  • mapper

  • service

因为分数这种东西,肯定是只能增加,不能修改!

所以,只写了查询和新增,从根本上杜绝修改分数(才不是懒)

  • controller

要实现:用户登录,验证身份成功后,给他分数!

大概就是这样子,别怪咱写的太少,呜呜呜,实在是写不完了。

稍微改改,把他全部的都返回bia

感觉应该差不多了。

试一试bia

没有用户名密码:

好的,获得500

好好好

拿错变量了。


场外话:

这是题目练习结束自动提交PVP


看样子是可以啦:

11.12.3 前端

  1. 生成一个前端

  1. 加数据库

  1. 试一试

  1. 出错啦

  1. 没问题啦(还挺好看)

这个answer我一开始以为是答案。

11.13 统计信息

11.13.1 统计成绩

汇总学生成绩,进行相应的统计,通过图表展示。

就写一个bia。

这样就是管理端直接获取全部的Score。

其实也蛮简单的。

直接去刚才的地方的数据库表改一下就好PVP

写一个mapper:

我想了想,直接写个分数管理就好啦呀。

分数添加,分数查询,分数删除,分数修改。

就这些就够啦。

说干就干。

并且!你想都别想改分数

真男人是无法修改分数的!

他真的改了吗?

如改!

mapper剩下的直接跟之前的一样就可以。

controller:

测试:

数据不对

改过来啦。

11.13.1.1 统计成绩-前端

还是一样,利用dayijs只需要改几行即可完成。

维护下菜单数据库

  1. 新增分数

分数当然是不可以新增的啦。
给你留接口,你能填进去Date类,就去改分数吧。

  1. 列表

ok,这样子就差不多啦。(超级超级累,一个人肝出来真的要命)

11.14 小修

有些内容还是要修改一下,记录一下。

11.14.1 index重定向

image-20231008110456879

12. 菜单数据库

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for menu
-- ----------------------------
DROP TABLE IF EXISTS `menu`;
CREATE TABLE `menu`  (
  `id` int NOT NULL AUTO_INCREMENT,
  `menu_code` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `menu_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `menu_url` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `menu_level` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `parent_id` int NULL DEFAULT NULL,
  `sort` int NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 66 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of menu
-- ----------------------------
INSERT INTO `menu` VALUES (25, 'menu-1-template', '一级菜单', '', '1', 0, 1);
INSERT INTO `menu` VALUES (27, 'role', '角色管理', '', '1', 0, 3);
INSERT INTO `menu` VALUES (28, 'user', '用户管理', '', '1', 0, 4);
INSERT INTO `menu` VALUES (29, 'project-add', '二级菜单-新增/修改模板', 'project-add.html', '2', 25, 1);
INSERT INTO `menu` VALUES (30, 'project-list', '二级菜单-数据列表模板', 'project-list.html', '2', 25, 2);
INSERT INTO `menu` VALUES (31, 'role-tree', '角色树', 'role-tree.html', '2', 25, 3);
INSERT INTO `menu` VALUES (32, 'menu-add', '新增菜单', 'menu-add.html', '2', 26, 1);
INSERT INTO `menu` VALUES (33, 'menu-list', '菜单列表', 'menu-list.html', '2', 26, 2);
INSERT INTO `menu` VALUES (34, 'role-add', '新增角色', 'role-add.html', '2', 27, 1);
INSERT INTO `menu` VALUES (35, 'role-list', '角色列表', 'role-list.html', '2', 27, 2);
INSERT INTO `menu` VALUES (36, 'user-add', '用户管理', 'user-add.html', '2', 28, 1);
INSERT INTO `menu` VALUES (37, 'questions', '题库管理', '', '1', 0, 5);
INSERT INTO `menu` VALUES (38, 'file-upload', '试题上传', 'file-upload.html', '2', 37, 1);
INSERT INTO `menu` VALUES (40, 'template', '模板管理', '', '1', 0, 1);
INSERT INTO `menu` VALUES (41, 'template-list', '模板列表', 'template-list.html', '2', 40, 1);
INSERT INTO `menu` VALUES (42, 'template-add', '模板新增', 'template.html', '2', 40, 2);
INSERT INTO `menu` VALUES (43, 'exam', '试题管理', NULL, '1', 0, 1);
INSERT INTO `menu` VALUES (44, 'exam-uploader', '试题上传', 'test-upload.html', '2', 43, 1);
INSERT INTO `menu` VALUES (45, 'faculty', '院系管理', NULL, '1', 0, 1);
INSERT INTO `menu` VALUES (46, 'faculty-add', '院系添加', 'faculty-add.html', '2', 45, 1);
INSERT INTO `menu` VALUES (47, 'faculty-list', '院系列表', 'faculty-list.html', '2', 45, 2);
INSERT INTO `menu` VALUES (48, 'major', '专业', NULL, '1', 0, 1);
INSERT INTO `menu` VALUES (49, 'major-add', '专业-添加', 'major-add.html', '2', 48, 1);
INSERT INTO `menu` VALUES (50, 'major-list', '专业列表', 'major-list.html', '2', 48, 2);
INSERT INTO `menu` VALUES (51, 'class', '班级管理', NULL, '1', 0, 1);
INSERT INTO `menu` VALUES (52, 'class-add', '班级新增', 'class-add.html', '2', 51, 1);
INSERT INTO `menu` VALUES (53, 'class-list', '班级列表', 'class-list.html', '2', 51, 2);
INSERT INTO `menu` VALUES (54, 'subject', '课程管理', NULL, '1', 0, 1);
INSERT INTO `menu` VALUES (55, 'subject-add', '课程添加', 'subject-add.html', '2', 54, 1);
INSERT INTO `menu` VALUES (56, 'subject-list', '课程列表', 'subject-list.html', '2', 54, 2);
INSERT INTO `menu` VALUES (57, 'major-semester', '专业学年管理', NULL, '1', 0, 1);
INSERT INTO `menu` VALUES (58, 'major-semester-add', '专业学年增加', 'major-semester-add.html', '2', 57, 1);
INSERT INTO `menu` VALUES (59, 'major-semester-list', '专业学年列表', 'major-semester-list.html', '2', 57, 2);
INSERT INTO `menu` VALUES (60, 'for-exam', '考试', 'letmegodie.html', '1', 0, 1);
INSERT INTO `menu` VALUES (61, 'show-my-score', '查询分数', 'show-my-score.html', '1', 0, 1);
INSERT INTO `menu` VALUES (62, 'score', '分数管理', NULL, '1', 0, 1);
INSERT INTO `menu` VALUES (63, 'score-add', '新增分数(确定吗)', 'score-add.html', '2', 62, 1);
INSERT INTO `menu` VALUES (64, 'score-list', '分数列表', 'score-list.html', '2', 62, 1);

SET FOREIGN_KEY_CHECKS = 1;

13. 项目结构

还是不少内容的)

13.1 看这一堆咖啡豆子

image-20231008003234600

13.2 数不清的接口

image-20231008003308470

image-20231008003318095

发现一个可以用AI生成COMMIT的,结果他跟我说我修改的内容太多了,GPT处理不过来)

image-20231008003731263

13.3 dayi小功能库

image-20231008094624655

14. 项目构建

image-20231008004638619

14.1 试试打包:

image-20231008005136671

14.2没有主属性

image-20231008005050868

14.3 用这个插件试一试:

试一试:

image-20231008005538502

image-20231008005616661

14.4 原神!启动!

image-20231008005646533

15.1 封装docker

15.2 指定生成文件名

    <build>
        <!-- 指定生成文件名 -->
        <finalName>skd21_dayi_springboot</finalName>
    </build>

image-20231008011005845

15.3 Dockerfile

用最新的镜像就好

image-20231008011417620

自动构建就行,省事。

FROM maven:latest as builder
WORKDIR /app
COPY ./src /app/src
COPY pom.xml /app/pom.xml
RUN mvn package

FROM openjdk:8u342-jdk-oracle
WORKDIR /opt/dayi/
COPY --from=builder /app/target/skd21_dayi_springboot.jar /opt/dayi/skd21_dayi_springboot.jar
CMD ["java", "-jar","skd21_dayi_springboot.jar"]

image-20231008011755929

15.3 docker-compose.yaml

version: '3'
services:
  web:
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - 14001:8080
    depends_on:
      - db
      - phpmyadmin
    environment:
      - mysql_host=db
      - mysql_database=product
  db:
    image: mysql:5.7
    environment:
      - MYSQL_ROOT_PASSWORD=123456
    volumes:
      - ./_data:/var/lib/mysql
      - ./sql.sql:/docker-entrypoint-initdb.d/sql.sql
  phpmyadmin:
    image: phpmyadmin/phpmyadmin
    ports:
      - 14002:80
    depends_on:
      - db
    environment:
      - PMA_HOST=db
      - PMA_USER=root
      - PMA_PASSWORD=123456

sql文件需要注意一点点

image-20231008012227486

15.4 启动试试?

image-20231008014813554

image-20231008014851733

image-20231008014952927

image-20231008015036892

没想到端口被占用了

image-20231008015139597

成功啦!

image-20231008015236156

库有点问题,明天修,忘了USE database了。

image-20231008015430035

15.4.1 有可能需要改镜像源

换了个国内服务器,构建失败hhh

image-20231008141846959

这样就好啦。

image-20231008143135014

15.5 完整的部署方法!

#复制文件后
unzip java-spring_docker_final.zip
cd java-spring/
sudo docker-compose up -d

等一会就会在14101端口上部署啦

image-20231008145452435

image-20231008145702593


16. 最新代码

也可也见附录

都在这里:

打开缓慢:可以用Steam++来加速访问(选github)(https://steampp.net/ 下载:选蓝奏云 https://wwn.lanzouy.com/imM6D19nxt9a 密码1234 )

代码:在这里👇,打开慢请用steam++试试。

https://github.com/magical-rabbit/java-spring

https://github.com/magical-rabbit/java-spring/tree/main/src/main/java/net/dabbit/skd21/exam

如何下载?

17. 工具:

数据库:

host:a.dayiyi.top
port:3306
database:dayi_spr_bo_em
username:dayi_spr_bo_em
password:cC865eHwSAKsydEx

18. 附录

这里,只包含一点写的新的东东,其他的就不写啦

18.1 dayi-libs

前端快速库

目录:java-spring\src\main\resources\static\js

18.1.1 更新模板update.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <!-- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/picnic"> -->
    <style>
        body {
            margin: 0;
            padding: 20px;
            font-family: Arial, sans-serif;
            background-color: #f2f2f2;
        }

        .card-body {
            background-color: #fff;
            padding: 20px;
            border-radius: 5px;
            box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
        }

        .form-group {
            margin-bottom: 20px;
        }

        .form-group label {
            display: block;
            font-weight: bold;
            margin-bottom: 5px;
        }

        .form-control {
            width: 100%;
            padding: 10px;
            border: 1px solid #ccc;
            border-radius: 5px;
            font-size: 14px;
        }

        .custom-select {
            height: 35px;
        }

        .form-group input[type="text"] {
            height: 35px;
        }
    </style>
</head>

<body>
    <!-- 新增就不写了 -->
    <!-- 直接写修改 -->
    <div id="dayi-form">
        <div class="card-body" id="card-body">
            <div class="form-group">
                <label for="multiple_difficulty_proportion">我是可爱的修改模板--来自dayi-lib库</label>
                <input type="text" id="multiple_difficulty_proportion" readonly="readonly" class="form-control" placeholder="你好呀OVO,下面的内容是动态生成的哦!如果没有表示出现问题啦">
            </div>
        </div>
    </div>
    <!-- jQuery -->
    <script src="../plugins/jquery/jquery.min.js"></script>
    <!-- Bootstrap 4 -->
    <script src="../plugins/bootstrap/js/bootstrap.bundle.min.js"></script>
    <!-- AdminLTE App -->
    <script src="../dist/js/adminlte.min.js"></script>
    <!-- AdminLTE for demo purposes -->
    <script src="../dist/js/demo.js"></script>
</body>
</html>

18.1.2 依赖库检查

function check_(){
    if (typeof jQuery === 'undefined') {
        console.error('[dayi-lib]jQuery is not loaded. Make sure it is included before jsGrid.');
        
        return;
    }
    console.log('[dayi-lib-check]jQuery loaded.🔊')

    if (typeof jQuery.fn.jsGrid === 'undefined') {
        console.error('[dayi-lib]jsGrid is not loaded or not defined.');
        return;
    }
    console.log('[dayi-lib-check]jsGrid loaded.🔊')
}

18.1.3 改删查

// 初始化全局变量

async function load_page() {
    try {
        const response = await fetch('../js/dayi-lib/template/update.html');
        if (response.ok) {
            const html = await response.text();
            document.getElementById('content').innerHTML = html;
        } else {
            console.error('[dayi-lib-page]Failed to fetch the HTML:', response.status);
        }
    } catch (error) {
        console.error('[dayi-lib-load-page]An error occurred while fetching the HTML:', error);
    }
}



function get_data() {
    document.getElementById("card-body")
}


function toCamelCase(str) {
    return str.replace(/_([a-z])/g, function (match, letter) {
        return letter.toUpperCase();
    });
}

//获得表单数据
function collectFormData(parentElementSelector) {
    var formData = {};
    $(parentElementSelector).find('input, select').each(function() {
        var $this = $(this);
        if($this.attr('type') !== 'submit') {
            var camelCaseName = toCamelCase($this.attr('id'));
            formData[camelCaseName] = $this.val();
        }
    });
    return formData;
}


//发送到后端
function sendDataToBackend(endpoint, data, successCallback, errorCallback) {
    $.ajax({
        type: "post",
        url: endpoint,
        data: data,
        dataType: "json",
        success: function(response) {
            if(response.code === "200") {
                console.log("[dayi-lib]成功发送到后端,数据:");
                console.log(data)
                successCallback(response);
            } else {
                console.log("[dayi-lib-error]发送到后端失败,数据:"+data+",错误码:"+response.code);
                errorCallback(response);
            }
        },
        error: function(response) {
            console.log("[dayi-lib-error]发送到后端失败,数据:");
            console.log(data)
            alert("[dayi-lib-error]后端炸啦!或者网络原因请求发送失败")
            errorCallback(response);
        }
    });
}


//提交数据
async function dayi_update_data(update_url){
    //表单数据获得
    form_data = collectFormData(".card-body")
    console.log("[dayi-lib]from_data:")
    console.log(form_data);

    // debugger
    //发送到后端
    sendDataToBackend(update_url, form_data, function(response) {alert("修改成功");}, function(response) {alert("修改失败");});
}

//生成表单
async function gen_html(form_arr,nowdata_id,update_url){
    // debugge
    const formContainer = document.getElementById("card-body");


    // 生成ID
    const div = document.createElement("div");
    div.classList.add("form-group");
    const label = document.createElement("label");
    label.setAttribute("for", "ID");
    label.textContent = "ID(信息不可修改,但是不给你隐藏,哼OVO)";
    const input = document.createElement("input");
    input.setAttribute("type", "text");
    input.setAttribute("id", "id");
    input.setAttribute("name", "id");
    input.setAttribute("class", "form-control");
    input.setAttribute("readonly", "readonly");
    input.value = nowdata_id;
    input.style.width = `${300}px`;
    div.appendChild(label);
    div.appendChild(input);
    formContainer.appendChild(div);
    // 生成ID

    form_arr.forEach(field => {
        if(field.name=="id"){
            //跳过ID
            return
        }

        const div = document.createElement("div");
        div.classList.add("form-group");
        const label = document.createElement("label");
        label.setAttribute("for", field.name);
        label.textContent = field.title;
        const input = document.createElement("input");
        input.setAttribute("type", field.type);
        input.setAttribute("id", field.name);
        input.setAttribute("name", field.name);
        input.setAttribute("class", "form-control");
        //提示词
        input.setAttribute("placeholder", `${field.title}`);
        input.style.width = `${field.width*4}px`;
        div.appendChild(label);
        div.appendChild(input);
        formContainer.appendChild(div);
    });

    const buttonDiv = document.createElement("div");
    buttonDiv.classList.add("form-group");

    const saveButton = document.createElement("button");
    saveButton.setAttribute("type", "button");
    saveButton.setAttribute("class", "btn btn-primary");
    saveButton.setAttribute("onclick", `dayi_update_data("${update_url}");`);
    saveButton.textContent = "保存";
    // saveButton.onclick = dayi_update_data;

    buttonDiv.appendChild(saveButton);
    formContainer.appendChild(buttonDiv);
    
}





async function dayi_update_init(form_arr,nowdata_id,update_url,successCallback,errorCallback) {
    //加载模板文件
    await load_page();
    // 获得表单数据
    // 应该手动生成表单
    // form_arr = [
    //     { title: "ID",name:"id", type: "text", width: 150 },
    //     { title: "用户名",name:"username", type: "text", width: 150 },
    //     { title: "真是姓名",name:"realName", type: "text", width: 150 },
    //     { title: "学号",name:"sno", type: "text", width: 150 }
    // ]
    // 生成前端
    await gen_html(form_arr,nowdata_id,update_url);
}


async function upup_(form_arr,now_id,update_url,tmp_arr){
    // load_page()
    await dayi_update_init(form_arr,now_id,update_url);
    await fillfill_(tmp_arr[now_id])
}


async function fillfill_(item){
    console.log("[dayi-lib]尝试自动回填数据..")
    for (var key in item) {
        if (item.hasOwnProperty(key)) {
            // 构造对应表单字段的ID
            var fieldId = "#" + key;
            // 检查表单中是否存在具有相同ID的元素
            if ($(fieldId).length) {
                // 如果存在,设置其值为相应属性的值
                $(fieldId).val(item[key]);
            }
        }
    }
    console.log("[dayi-lib]自动回填数据完成..(不一定成功)")
}

//删除

//使用:
// id , "/class/del"  , 两个回调函数
async function deldel_(id,del_url,successCallback,errorCallback) {
    console.log(`[dayi-lib]尝试删除数据.. ${id}`)
    data = {"id": id};
    $.ajax({
        type: "post",
        url: del_url,
        data: data,
        dataType: "json",
        success: function(response) {
            if(response.code === "200") {
                console.log("[dayi-lib]成功发送到后端,数据:");
                console.log(data)
                successCallback(response);
            } else {
                console.log("[dayi-lib-error]发送到后端失败,数据:"+data+",错误码:"+response.code);
                errorCallback(response);
            }
        },
        error: function(response) {
            console.log("[dayi-lib-error]发送到后端失败,数据:");
            console.log(data)
            alert("[dayi-lib-error]后端炸啦!或者网络原因请求发送失败")
            errorCallback(response);
        }
    });
}

18.1.4 增,自动骆驼命名,获得表单数据,发送后端


// this_is => thisIs
function toCamelCase(str) {
    return str.replace(/_([a-z])/g, function (match, letter) {
        return letter.toUpperCase();
    });
}



//获得表单数据
function collectFormData(parentElementSelector) {
    var formData = {};

    $(parentElementSelector).find('input, select').each(function() {
        var $this = $(this);
        if($this.attr('type') !== 'submit') {
            var camelCaseName = toCamelCase($this.attr('id'));
            formData[camelCaseName] = $this.val();
        }
    });

    return formData;
}


//发送到后端
function sendDataToBackend(endpoint, data, successCallback, errorCallback) {
    $.ajax({
        type: "post",
        url: endpoint,
        data: data,
        dataType: "json",
        success: function(response) {
            if(response.code === "200") {
                console.log("[dayi-lib]成功发送到后端,数据:");
                console.log(data)
                successCallback(response);
            } else {
                console.log("[dayi-lib-error]发送到后端失败,数据:"+data+",错误码:"+response.code);
                errorCallback(response);
            }
        },
        error: function(response) {
            console.log("[dayi-lib-error]发送到后端失败,数据:"+data.tostring());
            alert("[dayi-lib-error]后端炸啦!或者网络原因请求发送失败")
            errorCallback(response);
        }
    });
}

18.1.5 加载jsGrid

支持引用回调函数

//存放当前列表数据的数组
dayi_tmp_arr = {};


function loadDayiList() {
    // const xhr = new XMLHttpRequest();
    // // xhr.open('GET', '../js/dayi-lib/list-template.html', true);
    // xhr.onreadystatechange = function() {
    //     if (this.readyState === 4 && this.status === 200) {
    //         document.getElementById('dayi-list').innerHTML = this.responseText;
    //     }
    // };
    // xhr.send();
}


function dayi_load_list(fields=[{ title: "ID",name:"id", type: "text", width: 150 }],post_url="/user/list",object_="#jsGrid1",pageSize=3){
    initializePageGrid(fields,post_url,object_,pageSize)
}


function initializePageGrid(fields=[{ title: "ID",name:"id", type: "text", width: 150 }],post_url="/user/list",object_="#jsGrid1",pageSize=3) {
    const jsgrid = document.getElementById("jsGrid1")

    $("#jsGrid1").jsGrid({
        width: "100%",
        height: "auto",
        sorting: true,
        paging: true,
        pageLoading: true,
        autoload: true,
        controller: {
            loadData: function (filter) {
                tmp_arr = {}; // 初始化
                filter["search"] = $("#search").val();
                return $.ajax({
                    type: "post",
                    url: post_url,
                    dataType: "json",
                    data: filter
                });
            }
        },
        pageIndex: 1,
        pageSize: 3,
        pageButtonCount: 10,
        pagePrevText: "上一页",
        pageNextText: "下一页",
        pageFirstText: "首页",
        pageLastText: "尾页",
        fields: fields
    })
}

18.1.6 新增引用

image-20231008014311499

    <script src="../js/dayi-lib/libs-1.js"></script>


    <script>
        var add_template_func = function () {
            var formData = collectFormData('.card-body');
            sendDataToBackend("/faculty/add", formData, function (response) { alert("新增成功"); }, function (response) { alert("新增失败"); });
        }
    </script>

18.1.7 删改查引用

仅修改这两部分

image-20231008014458688


    <script src="../js/dayi-lib/check_.js"></script>
    <script src="../js/dayi-lib/load_list.js"></script>


    <script src="../js/dayi-lib/dayi_update.js"></script>
    <script>
        fields = [
            { title: "ID", name: "id", type: "text", width: 150 },
            { title: "角色代码", name: "roleCode", type: "text", width: 150 },
            { title: "角色名字", name: "roleName", type: "text", width: 150 },
            {
                title: "操作", name: "id", type: "text", width: 150,
                itemTemplate: function (value, item) {
                    dayi_tmp_arr[value] = item;
                    return `<a href='javascript:void(0)' onclick='dayi_update(${item["id"]})'>修改</a>`
                        + `&nbsp;&nbsp;&nbsp;&nbsp;<a href='javascript:void(0)' onclick='dayi_del(${item["id"]})'>删除</a>`;
                }
            }
        ]
        url_fst = "role"

        $(document).ready(function() {
            check_();
            loadDayiList();
            // 这里带斜杠哦
            dayi_load_list(fields, `/${url_fst}/list`, "jsGrid1")  
        })

        function dayi_update(id) {
            upup_(fields,id,`/${url_fst}/update`,dayi_tmp_arr)
        }

        function dayi_del(id){
            deldel_(id,`/${url_fst}/del`,function (response){
                alert("删除成功")
            },function (response){
                alert("删除失败")
            })
        }
    </script>
最后修改:2023 年 10 月 08 日
如果觉得我的文章对你有用,请随意赞赏