闸瓦实训
我发现,这网页(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代码?点这里就好
直接下载?这里!直链: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的小图床下载)
- 周一上午 : https://pic.icee.top/blog/pic_bed/2023/09/emis_23_9_18_周一上午.7z
- 周一下午 :https://pic.icee.top/blog/pic_bed/2023/09/emis23_9_18_周一下午.7z
- 周二上午:https://pic.icee.top/blog/pic_bed/2023/09/static_small_23_9_19.zip
- 周二晚上:https://pic.icee.top/blog/pic_bed/2023/09/emis_23_9_19周二晚上.zip
- 周三上午10点 :https://pic.icee.top/blog/pic_bed/2023/09/emis_23_9_20_周三上午10点.zip
- 周三上午11点:https://pic.icee.top/blog/pic_bed/2023/09/emis_23_9_20_周三上午11点.zip
- 周三上午12点:https://pic.icee.top/blog/pic_bed/2023/09/emis_23_9_20_周三上午12点.zip
- 周三下午3点: https://pic.icee.top/blog/pic_bed/2023/09/emis_23_9_20_周三下午3点.zip
- 周四上午9点: https://pic.icee.top/blog/pic_bed/2023/09/emis_23_9_20_周四上午9点.zip
- 周四上午12点: https://pic.icee.top/blog/pic_bed/2023/09/emis_23_9_20_周四上午12点.zip
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
类
- 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;
}
}
- 服务类
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);
}
- 服务实现
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);
}
}
- 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>
- 传参可能会发生空指针错误
然后这里小修一下:
防止空指针报错。
- 测试请求(后端)
测试下请求:(工具APIFOX、POSTMAN)
这样前端就可以拿菜单了。
11.1.2 前端实现
- 这个文件里添加一行这个,等会动态显示目录。
left-menu.html
<div id="show-menu">
</div>
这样写一个div
- 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
});
- 前端真要命
差不多这个效果。
11.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去实现。(不是图中这么简单)
- 写个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>"
+ " <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 新增菜单
写一个新增菜单,直接从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)
然后写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("新增失败"); } } }); };
写后端 controller
@RequestMapping(value = "/add",produces = "application/json; charset=utf-8") @ResponseBody public String add(JsGridData jsGridData){ String res = menuService.add(jsGridData); return res; }
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); }
写个mapper
public interface MenuMapper { List<Menu> list(JsGridData jsGridData); Long count(JsGridData jsGridData); Integer add(JsGridData jsGridData); }
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>
- 测试添加是否成功
- 看看数据库
成功插入
11.1.3 菜单删除
- 先写后端
- Controller
- mapper service
service
- 实现类
- Mapper XML
- POST请求测试
成功啦,这样再写前端JS就行了
- JS
上面的修改部分:
res_str = `<a href='javascript:void(0)' onclick='modify_menu_func(${value});'>修改</a>`
+ " "+`<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.`)
}
}
})
}
- 测试:
呃呃?
再试试
CTRL+F5强制加载JS
这样就可以了。
11.1.4 菜单修改
- controller
- service
- service impl
- mapper
- 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中(文章末尾)。
- 测试一下
修改成功
- 前端:
改的内容不少,新增页面要判断是否为新增模式。也要判断是否为修改模式。
这样就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
有点丑,改成这样:
- 动态加载菜单修复代码之前临时写一下:
不然加载不上。
- 查看效果
菜单倒是没问题了,但是后端炸了,估计传参的时候掉了,两个都是正常的功能。
- 改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 新增角色
- 先复制他要求的css和js,从那个ztree文件里解压
zTree_v3-master\js下的文件都放到webapp/js/ztree下
zTree_v3-master\css下的文件都放到webapp/css下
- 新建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>
- 我也不知道下来列表是什么
就直接这样复制上了。
<div class="form-group">
<label for="menuTree">菜单列表</label>
<ul id="menuTree" class="ztree"></ul>
<input type="hidden" id="menuIds" class="form-control">
</div>
- 我打开这个页面的时候会报错
- 先把JS复制上
这个参照文档 59-60 页
- 改了改代码跑起来了,但是不知道怎么用
相关代码,见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 新建模板-后端
- 我找到对应的数据库了
2.这样根据这个数据库写就好。
还是老套路
实体类
QuestionTemplate.java
这次反着写 mapper
QuestionTemplateMapper因为后面还有,这里就直接一起写了
11.4.2 模板列表 11.4.3 修改模板 11.4.4 删除模板
然后来写mapper xml
排版原因,请看GITHUB上的源码
再写service
实现类:
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); } }
controller
- 测试一下
要哭了
出来了,呜呜呜
- 真的写哭了
具体代码看github的源码bia
11.4.1 新建模板-前端2
- 院系、专业、学期、科目四个下拉列表,是一个三级联动
- 然后就写)
- 不是,学期是啥啊?
- 我在数据库里没找到
学期
这个东西,有个是school_year
,但是没有单独的表。 补:他在html叫这个
数据库里的表:
- 把两个写上就跑路。(没有学期,没有科目,怎么加载)
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(); });
能跑了
但,我发现他好像用CLASS应付的
- 那就把学期当做班级,先写上,占上位置。
效果这样,但是有问题
这个必须做完之后的才能正常,要么就随便填个假的。
11.4.1【dayi函数库-测试版本】
因为重复性工作实在是太多啦,这样把前端简化,功能不变的同时,可以更快的修改各种各样的前端!
实际上用的过程中,只需要改10行以内的(主要是字段和中文),就可以完全生成一个前端!相关代码塞附录啦。
dayi函数库
感觉重复性的工作太多了,想直接写个库,这样就可以直接获得表单的数据啦。
添加功能:
写个按钮
使用袋一函数库,两行解决问题,你值得拥有
贴心报错提示,随时告诉你后端爆炸
我发现数据库,这个实体压根没有院系
dayi-LIB 自动驼峰命名,你值得拥有
- dayi-lib可以在最新代码那个地方下载。
已经添加成功了
11.4.2 模板列表
又是一个列表啊
又是重复工作
没关系,dayi-lib会尝试拯救你(2023年10月6日01:24:32,但没法拯救dayi)
你只需要复制这么一点,就可以自动加载列表
好像效果也不是特别好,还得优化一下,但是问题不大
- 写列表加载
写到这里,代码已经push到github
改为写完一个章节,再写这个文档,错误太多了,代码请直接从github上复制。
列表加载写完啦
就写这点就可以自动加载啦(快夸夸我)
估计可以用啦,这样就把基本的lib库函数写完啦。
这个样子:
11.4.3 【dayi-函数库 ver1.0】更新列表-前端-dayi lib库的完善
测试库的开发
- 直接写成脚本库
- 被迫用了点异步,因为表单会提前加载,需要等待完成。
效果这个样子
好累)
传参试试
- 修改成功www
- 然后把要修改的数据传过来
直接写一个新函数填表吧
回填
用了点异步,来调整顺序
回填成功!
好开心)))
剩下的就是删除了,这个简单
最后就是封装
这点点代码就可以把整个重复逻辑给实现啦
试试
好好好
是后端炸了
写成delete了
成功啦
这样就算完成啦
11.4.4 删除模板
写完啦!
上面都有图啦
11.5 题库管理
先把代码复制上,看看是什么bia
这个样子诶(文件test-upload.html
)
11.5.1 题库管理-前端
- 复制上HTML代码之后
左侧连接直接去数据库添加条目就可以
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');
这样侧边栏就会有菜单了
11.5.2 题库管理-后端
依赖文件
复制上就好
<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>
- 记得点那个小蓝,同步下仓库
然后把他的库粘贴上,大概这个样子,依赖库
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.*;
写controller
我看他URL用的是
这样表单直接飞上来的。
/test/upload
- 这样照着写一个
好奇怪
- 然后要保存,就要写数据库了
但是dayi也很想吐槽:
数据库这个应该就是
Question.java
QuestionOptions.java
然后是mapper
我觉得这两个写一个mapper就可以
问题和选项添加:
查询问题:
连接表,但好像没什么用,可以直接后端拉信息,然后再去查具体的题目选项。
SELECT * FROM question_bank inner join question_options on question_bank.question_code=question_options.question_code
所以并不需要直接在数据库里合并表格
然后是mapper
服务接口
服务实现:
写完了,试一试
有个Autowire要这么写
然后不是这里的问题,是impl没写@service(找了3个小时的BUG)
试一试
要命,改了4个小时了
心态爆炸
不插入了,先这样吧
11.5.3 修改的文件:
11.6 院系管理
11.6.1 新建院系
11.6.2 院系列表
11.6.3 修改院系
11.6.4 删除院系
这些分一个做完就好,很简单啦。
11.6.1 院系管理-后端
因为之前写了一部分了:
然后开始写:
mapper xml
mapper
service
controller
测试:
- 好累,我让这个东西,那个叫mybatis生成器,生成了一点文件
11.6.2 院系管理-前端
dayi-lib库,你只需要几行就可以完成整个前端!
1.列表:
这样改一下就好:
新增:
也是,有了lib,直接去生成就好。
这样用dayilib 轻松解决问题:
你看怎么样?
轻松新增
修改代码不足20行
轻松添加猴子系,你还在等什么?
轻松删除猴子系,你还在等什么?
轻松修改猴子系,你还在等什么?
相关文件:
11.7 专业管理
11.7.1 后端
controller
mapper
mapper xml
service impl
service
POSTMAN测试
11.7.2 前端
新增专业测试:人生是没有回头路的。
然后我们可以找到:
保存成功
删除成功:
本章节修改的文件:
11.8 班级管理
11.8.1 后端
- mapper xml
- controller
- service
- serviceImpl
都差不多啦
11.8.2 前端
前段也是,复制两个html文件,稍微改一改就好。
11.8.3 本章节修改的文件
11.9 科目管理
11.9.1 后端
感觉没什么好说的啦, 就是发现生成的xml又生成了一次,导致报错了。
11.9.2 前端
还是用了dayi-lib的JS库,这样你就额可以10行写一个前端啦。
列表:
修改:
删除:
11.10 专业学期管理
11.10.1 后端
专业学期增删改查
老样子
服务
实现:
controller:
测试:
11.10.2 前端
还是用超级dayi库
- 文件1:
- 文件2:
新增功能:
把url提炼出来,这样就只需要修改一个地方啦。
- 测试
数据库:(修改菜单)
增加:
列表:
列表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 然后是根据题目编号获得题目
随便写写,就这个样子
返回的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,查询当前登录用户的指定科目的成绩。
- 实现逻辑:
- 从后端获得当前登录的用户。
- 很遗憾,我们的登录功能是假的。
- 所以要写一个登录功能,并且存cookie
- 好像时间有点来不及了,所以,我们将错就错,直接登录,然后返回成绩。
- 这样就简单多了。
- 开始实现。
- 成绩是有一个实体,叫score。
- 先写mapper
- mapper 和 xml
这里直接用他的库,所以,我们直接修改一下,然后直接写servcie就可以。
- service
- 我们需要一个能够实现按用户id查询成绩就可以了。
- 根据实体,传入的参数有,科目名,用户id。
- 开始实现
- mapper xml
- mapper
- service
因为分数这种东西,肯定是只能增加,不能修改!
所以,只写了查询和新增,从根本上杜绝修改分数(才不是懒)
- controller
要实现:用户登录,验证身份成功后,给他分数!
大概就是这样子,别怪咱写的太少,呜呜呜,实在是写不完了。
稍微改改,把他全部的都返回bia
感觉应该差不多了。
试一试bia
没有用户名密码:
好的,获得500
好好好
拿错变量了。
场外话:
这是题目练习结束自动提交PVP
看样子是可以啦:
11.12.3 前端
- 生成一个前端
- 加数据库
- 试一试
- 出错啦
- 没问题啦(还挺好看)
这个answer我一开始以为是答案。
11.13 统计信息
11.13.1 统计成绩
汇总学生成绩,进行相应的统计,通过图表展示。
就写一个bia。
这样就是管理端直接获取全部的Score。
其实也蛮简单的。
直接去刚才的地方的数据库表改一下就好PVP
写一个mapper:
我想了想,直接写个分数管理就好啦呀。
分数添加,分数查询,分数删除,分数修改。
就这些就够啦。
说干就干。
并且!你想都别想改分数
真男人是无法修改分数的!
他真的改了吗?
如改!
mapper剩下的直接跟之前的一样就可以。
controller:
测试:
数据不对
改过来啦。
11.13.1.1 统计成绩-前端
还是一样,利用dayijs只需要改几行即可完成。
维护下菜单数据库
- 新增分数
分数当然是不可以新增的啦。
给你留接口,你能填进去Date类,就去改分数吧。
- 列表
ok,这样子就差不多啦。(超级超级累,一个人肝出来真的要命)
11.14 小修
有些内容还是要修改一下,记录一下。
11.14.1 index重定向
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 看这一堆咖啡豆子
13.2 数不清的接口
发现一个可以用AI生成COMMIT的,结果他跟我说我修改的内容太多了,GPT处理不过来)
13.3 dayi小功能库
14. 项目构建
14.1 试试打包:
14.2没有主属性
14.3 用这个插件试一试:
试一试:
14.4 原神!启动!
15.1 封装docker
15.2 指定生成文件名
<build>
<!-- 指定生成文件名 -->
<finalName>skd21_dayi_springboot</finalName>
</build>
15.3 Dockerfile
用最新的镜像就好
自动构建就行,省事。
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"]
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文件需要注意一点点
15.4 启动试试?
没想到端口被占用了
成功啦!
库有点问题,明天修,忘了USE database了。
15.4.1 有可能需要改镜像源
换了个国内服务器,构建失败hhh
这样就好啦。
15.5 完整的部署方法!
#复制文件后
unzip java-spring_docker_final.zip
cd java-spring/
sudo docker-compose up -d
等一会就会在14101端口上部署啦
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. 工具:
- POSTMAN(好像也不如APIfox): https://dl.pstmn.io/download/latest/win64
- JAVA中文报错:
https://www.cnblogs.com/jayworld/p/8495174.html
数据库:
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 新增引用
<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 删改查引用
仅修改这两部分
<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>`
+ ` <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>