SpringBoot + vue 管理系统

ops/2025/2/7 22:53:13/
SpringBoot + vue 管理系统

文章目录
      • SpringBoot + vue 管理系统
        • 1、成品效果展示
        • 2、项目准备
        • 3、项目开发
          • 3.1、部门管理
            • 3.1.1、前端核心代码
            • 3.1.2、后端代码实现
          • 3.2、员工管理
            • 3.2.1、前端核心代码
            • 3.2.2、后端代码实现
          • 3.3、班级管理
            • 3.3.1、前端核心代码
            • 3.3.2、后端代码实现
          • 3.4、学生管理
            • 3.4.1、前端核心代码
            • 3.4.2、后端代码实现
          • 3.5、数据统计
            • 3.5.1、前端核心代码
            • 3.5.2、后端代码实现
          • 3.6、登录功能
            • 3.6.1、前端核心代码
            • 3.6.2、后端代码实现
1、成品效果展示

SpringBoot + vue 管理系统

2、项目准备

环境准备

image-20240714203052876

步骤:

  1. 准备数据库表

  2. 创建springboot工程,引入对应的起步依赖(web、mybatis、mysql驱动、lombok)

  3. 配置文件application.properties中引入mybatis的配置信息,准备对应的实体类

  4. 准备对应的Mapper、Service(接口、实现类)、Controller基础结构

    – 部门管理
    create table dept(
    id int unsigned primary key auto_increment comment ‘主键ID’,
    name varchar(10) not null unique comment ‘部门名称’,
    create_time datetime not null comment ‘创建时间’,
    update_time datetime not null comment ‘修改时间’
    ) comment ‘部门表’;

    insert into dept (id, name, create_time, update_time) values(1,‘学工部’,now(),now()),
    (2,‘教研部’,now(),now()),
    (3,‘咨询部’,now(),now()),
    (4,‘就业部’,now(),now()),
    (5,‘人事部’,now(),now());

    – 员工管理(带约束)
    create table emp (
    id int unsigned primary key auto_increment comment ‘ID’,
    username varchar(20) not null unique comment ‘用户名’,
    password varchar(32) default ‘123456’ comment ‘密码’,
    name varchar(10) not null comment ‘姓名’,
    gender tinyint unsigned not null comment ‘性别, 说明: 1 男, 2 女’,
    image varchar(300) comment ‘图像’,
    job tinyint unsigned comment ‘职位, 说明: 1 班主任,2 讲师, 3 学工主管, 4 教研主管, 5 咨询师’,
    entrydate date comment ‘入职时间’,
    dept_id int unsigned comment ‘部门ID’,
    create_time datetime not null comment ‘创建时间’,
    update_time datetime not null comment ‘修改时间’
    ) comment ‘员工表’;

    INSERT INTO emp
    (id, username, password, name, gender, image, job, entrydate,dept_id, create_time, update_time) VALUES
    (1,‘jinyong’,‘123456’,‘金庸’,1,‘1.jpg’,4,‘2000-01-01’,2,now(),now()),
    (2,‘zhangwuji’,‘123456’,‘张无忌’,1,‘2.jpg’,2,‘2015-01-01’,2,now(),now()),
    (3,‘yangxiao’,‘123456’,‘杨逍’,1,‘3.jpg’,2,‘2008-05-01’,2,now(),now()),
    (4,‘weiyixiao’,‘123456’,‘韦一笑’,1,‘4.jpg’,2,‘2007-01-01’,2,now(),now()),
    (5,‘changyuchun’,‘123456’,‘常遇春’,1,‘5.jpg’,2,‘2012-12-05’,2,now(),now()),
    (6,‘xiaozhao’,‘123456’,‘小昭’,2,‘6.jpg’,3,‘2013-09-05’,1,now(),now()),
    (7,‘jixiaofu’,‘123456’,‘纪晓芙’,2,‘7.jpg’,1,‘2005-08-01’,1,now(),now()),
    (8,‘zhouzhiruo’,‘123456’,‘周芷若’,2,‘8.jpg’,1,‘2014-11-09’,1,now(),now()),
    (9,‘dingminjun’,‘123456’,‘丁敏君’,2,‘9.jpg’,1,‘2011-03-11’,1,now(),now()),
    (10,‘zhaomin’,‘123456’,‘赵敏’,2,‘10.jpg’,1,‘2013-09-05’,1,now(),now()),
    (11,‘luzhangke’,‘123456’,‘鹿杖客’,1,‘11.jpg’,5,‘2007-02-01’,3,now(),now()),
    (12,‘hebiweng’,‘123456’,‘鹤笔翁’,1,‘12.jpg’,5,‘2008-08-18’,3,now(),now()),
    (13,‘fangdongbai’,‘123456’,‘方东白’,1,‘13.jpg’,5,‘2012-11-01’,3,now(),now()),
    (14,‘zhangsanfeng’,‘123456’,‘张三丰’,1,‘14.jpg’,2,‘2002-08-01’,2,now(),now()),
    (15,‘yulianzhou’,‘123456’,‘俞莲舟’,1,‘15.jpg’,2,‘2011-05-01’,2,now(),now()),
    (16,‘songyuanqiao’,‘123456’,‘宋远桥’,1,‘16.jpg’,2,‘2007-01-01’,2,now(),now()),
    (17,‘chenyouliang’,‘123456’,‘陈友谅’,1,‘17.jpg’,NULL,‘2015-03-21’,NULL,now(),now());

    CREATE TABLE clazz (
    id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT COMMENT ‘ID,主键’,
    name varchar(30) NOT NULL UNIQUE COMMENT ‘班级名称’,
    room varchar(20) DEFAULT NULL COMMENT ‘班级教室’,
    begin_date date NOT NULL COMMENT ‘开课时间’,
    end_date date NOT NULL COMMENT ‘结课时间’,
    master_id int unsigned NOT NULL COMMENT ‘班主任ID, 关联员工表ID’,
    create_time datetime NOT NULL COMMENT ‘创建时间’,
    update_time datetime NOT NULL COMMENT ‘修改时间’
    ) COMMENT ‘班级表’;

    INSERT INTO clazz VALUES (1,‘黄埔班一期’,‘212’,‘2023-04-30’,‘2023-06-29’,10,‘2023-06-01 17:08:23’,‘2023-06-01 17:39:58’),
    (2,‘黄埔班二期’,‘211’,‘2023-06-25’,‘2023-12-31’,1,‘2023-06-01 17:34:16’,‘2023-06-01 17:43:43’),
    (3,‘黄埔班三期’,‘210’,‘2023-07-10’,‘2024-01-20’,3,‘2023-06-01 17:45:12’,‘2023-06-01 17:45:12’),
    (4,‘JavaEE就业165期’,‘108’,‘2023-06-15’,‘2023-12-25’,6,‘2023-06-01 17:45:40’,‘2023-06-01 17:45:40’),
    (5,‘JavaEE就业166期’,‘105’,‘2023-07-20’,‘2024-02-20’,20,‘2023-06-01 17:46:10’,‘2023-06-01 17:46:10’),
    (6,‘黄埔四期’,‘209’,‘2023-08-01’,‘2024-02-15’,7,‘2023-06-01 17:51:21’,‘2023-06-01 17:51:21’);

    CREATE TABLE student (
    id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT COMMENT ‘ID,主键’,
    name varchar(10) NOT NULL COMMENT ‘姓名’,
    no char(10) NOT NULL UNIQUE COMMENT ‘学号’,
    gender tinyint unsigned NOT NULL COMMENT ‘性别, 1: 男, 2: 女’,
    phone varchar(11) NOT NULL UNIQUE COMMENT ‘手机号’,
    degree tinyint unsigned DEFAULT NULL COMMENT ‘最高学历, 1:初中, 2:高中, 3:大专, 4:本科, 5:硕士, 6:博士’,
    violation_count tinyint unsigned NOT NULL DEFAULT ‘0’ COMMENT ‘违纪次数’,
    violation_score tinyint unsigned NOT NULL DEFAULT ‘0’ COMMENT ‘违纪扣分’,
    clazz_id int unsigned NOT NULL COMMENT ‘班级ID, 关联班级表ID’,
    create_time datetime NOT NULL COMMENT ‘创建时间’,
    update_time datetime NOT NULL COMMENT ‘修改时间’
    ) COMMENT ‘学生表’;

    INSERT INTO student VALUES (1,‘Tom’,‘2023001001’,1,‘18909091212’,4,0,0,1,‘2023-06-01 18:28:58’,‘2023-06-01 18:28:58’),
    (2,‘Cat’,‘2023001002’,2,‘18909092345’,3,0,0,1,‘2023-06-01 18:34:57’,‘2023-06-01 18:34:57’),
    (3,‘Lily’,‘2023001003’,2,‘13309230912’,4,2,5,1,‘2023-06-01 18:35:23’,‘2023-06-01 19:37:42’),
    (4,‘Jerry’,‘2023001004’,1,‘15309232323’,4,1,2,1,‘2023-06-01 18:35:48’,‘2023-06-01 19:37:35’),
    (6,‘Nacos’,‘2023002001’,1,‘18809091212’,1,3,10,2,‘2023-06-01 18:57:32’,‘2023-06-01 19:37:29’);

生成的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 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.tlias</groupId><artifactId>web-tlias</artifactId><version>0.0.1-SNAPSHOT</version><name>web-tlias</name><description>web-tlias</description><properties><java.version>1.8</java.version><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><spring-boot.version>2.7.6</spring-boot.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.3.0</version></dependency><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><scope>runtime</scope></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency>
<!--        pagehelper分页查询插件--><dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper-spring-boot-starter</artifactId><version>1.4.2</version></dependency><!--        阿里云oss依赖--><dependency><groupId>com.aliyun.oss</groupId><artifactId>aliyun-sdk-oss</artifactId><version>3.15.2</version></dependency>
<!--        jwt依赖--><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.76</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>${spring-boot.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.8.1</version><configuration><source>1.8</source><target>1.8</target><encoding>UTF-8</encoding></configuration></plugin><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>${spring-boot.version}</version><configuration><mainClass>com.tlias.WebTliasApplication</mainClass><skip>true</skip></configuration><executions><execution><id>repackage</id><goals><goal>repackage</goal></goals></execution></executions></plugin></plugins></build>
</project>

创建项目工程目录结构

image-20240714203628782

配置文件application.yml

server:port: 8080mybatis:mapper-locations: classpath:mappers/*xmltype-aliases-package: com.tlias.entityconfiguration:log-impl: org.apache.ibatis.logging.stdout.StdOutImplmap-underscore-to-camel-case: truespring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/tliasusername: rootpassword: 123456servlet:multipart:max-file-size: 10MBmax-request-size: 100MBpagehelper:reasonable: truealiyun:oss:endpoint: https://oss-cn-beijing.aliyuncs.comaccessKeyId: you_acesskeyaccessKeySecret: you_accessKeySecretbucketName: tlias-lwj

设置统一返回数据

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Result {private int code;private String msg;private Object data;public static Result success() {return new Result(1, "success", null);}public static Result success(Object data) {return new Result(1, "success", data);}public static  Result error(String msg) {return new Result(0,msg,null);}}

构建一个vue项目

image-20240714203803145

3、项目开发

功能模块分为六部分:班级管理、学员管理、部门管理、员工管理、员工信息统计、学员信息统计

3.1、部门管理

开发的部门管理功能包含:

  1. 查询部门
  2. 删除部门
  3. 新增部门
  4. 更新部门
3.1.1、前端核心代码
<template><div style="margin-top: 20px; margin: 50px; margin-right: 100px"><!-- 按钮 --><el-row><el-buttonstyle="float: right"type="primary"@click="dialogFormVisible = true; dept={}">+ 新增部门</el-button></el-row><br><!-- 数据表格 --><template><el-tablehighlight-current-rowref="multipleTable":data="tableData"tooltip-effect="dark"style="width: 100%"border><el-table-column type="index" width="100" label="序号" header-align="center" align="center"> </el-table-column><el-table-column prop="name" label="部门名称" header-align="center" align="center"></el-table-column><el-table-column label="最后操作时间" header-align="center" align="center"><template slot-scope="scope">{{scope.row.updateTime ? scope.row.updateTime.replace('T',' '):''}}</template></el-table-column><el-table-column label="操作" width="420" header-align="center" align="center"><template slot-scope="scope"><el-buttonsize="mini"type="primary"plain@click="selectById(scope.row.id)">编辑</el-button><el-buttonsize="mini"type="danger"plain@click="deleteById(scope.row.id)">删除</el-button></template></el-table-column></el-table></template><!-- 新建对话框 --><el-dialog title="保存部门" :visible.sync="dialogFormVisible" ><el-form :model="dept" :rules="rules" ref="dept"><el-form-item label="部门名称" :label-width="formLabelWidth" prop="name"><el-input v-model="dept.name"  placeholder="请输入部门名称" autocomplete="off"></el-input></el-form-item></el-form><div slot="footer" class="dialog-footer"><el-button @click="cancel('dept')">取 消</el-button><el-button type="primary" @click="save('dept')">确 定</el-button></div></el-dialog></div>
</template><script>
import { findAll, add, update, deleteById, selectById } from "@/api/dept.js";export default {data() {return {formLabelWidth: "120px",dialogFormVisible: false, //控制对话框是否可见dept: {name: "",},tableData: [],rules: {name: [{ required: true, message: '请输入部门名称', trigger: 'blur' },{ min: 2, max: 10, message: '长度在 2 到 10 个字符', trigger: 'blur' }]}    };},methods: {//删除部门deleteById(id) {this.$confirm("确认删除?", "提示", {confirmButtonText: "确定",cancelButtonText: "取消",type: "warning",}).then(() => {deleteById(id).then((result) => {if(result.data.code == 1){this.$message({message: "恭喜你,删除成功",type: "success",});}else{this.$message.error(result.data.msg);}//重新查询数据this.init();});}).catch(() => {this.$message({type: "info",message: "已取消删除",});});},//根据ID查询部门 -- 回显selectById(id) {this.dialogFormVisible = true;selectById(id).then((result) => {this.dept = result.data.data;});},//保存方法save(formName) {this.$refs[formName].validate((valid) => {if(valid){let operator ;if (this.dept.id) {operator = update(this.dept); // 修改}else{operator = add(this.dept); //添加 }operator.then((result) => {if (result.data.code == 1) {//修改成功this.$message.success("恭喜你,保存成功");//重新查询数据this.init();// 关闭新建窗口this.dialogFormVisible = false;// 清空模型数据this.dept = {};} else {this.$message.error(result.data.msg);}});}})},//初始化 - 查询全部init() {findAll().then((result) => {console.log(result);if (result.data.code == 1) {this.tableData = result.data.data;}});},cancel(formName){this.dialogFormVisible = false;this.$refs[formName].resetFields();}},mounted() {//当页面加载完成后自动执行。this.init();},
};
</script>
3.1.2、后端代码实现

实体类

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Dept {private Integer id;private String name;private LocalDateTime createTime;private LocalDateTime updateTime;
}

controller层

@RestController
@RequestMapping("depts")
@Slf4j
public class DeptController {@Autowiredprivate DeptService service;/*** 查询部门* @return*/@GetMappingpublic Result getDept(){log.info("查询部门数据");List<Dept> list = service.getDeptList();return Result.success(list);}/*** 根据id删除部门* @param id* @return*/@DeleteMapping("/{id}")public Result deleteDeptById(@PathVariable("id") Integer id){log.info("删除部门id {}",id);service.deleteDeptById(id);return Result.success();}/*** 新增部门* @param dept* @return*/@PostMappingpublic Result save(@RequestBody Dept dept){log.info("新增部门 {}",dept);service.save(dept);return Result.success();}/*** 根据id查询部门* @param id* @return*/@GetMapping("/{id}")public Result selectDeptById(@PathVariable("id") Integer id){log.info("根据id查询部门{}",id);Dept dept = service.selectDeptById(id);return Result.success(dept);}/*** 修改部门* @param dept* @return*/@PutMappingpublic Result update(@RequestBody Dept dept){log.info("修改部门信息{}",dept);service.update(dept);return Result.success();}
}

service层

service接口

public interface DeptService {/*** 查询部门* @return*/List<Dept> getDeptList();/*** 删除部门* @param id*/void deleteDeptById(Integer id);/*** 新增部门* @param dept*/void save(Dept dept);/*** 根据id查询部门* @param id* @return*/Dept selectDeptById(Integer id);/*** 修改部门信息* @param dept*/void update(Dept dept);
}

serviceImpl

@Service
public class DeptServiceImpl implements DeptService {@Autowiredprivate DeptMapper deptMapper;@Autowiredprivate EmpMapper empMapper;/*** 查询部门** @return*/@Overridepublic List<Dept> getDeptList() {List<Dept> list =  deptMapper.getDeptList();return list;}/*** 删除部门** @param id*/@Overridepublic void deleteDeptById(Integer id) {Integer result = empMapper.selectEmpByDeptId(id);if (result < 1 ){throw new RuntimeException("不能删除部门,部门下面存在员工");}deptMapper.deleteDeptById(id);}/*** 新增部门** @param dept*/@Overridepublic void save(Dept dept) {//添加修改时间dept.setCreateTime(LocalDateTime.now());dept.setUpdateTime(LocalDateTime.now());deptMapper.save(dept);}/*** 根据id查询部门** @param id* @return*/@Overridepublic Dept selectDeptById(Integer id) {Dept dept =  deptMapper.selectDeptById(id);return dept;}/*** 修改部门信息** @param dept*/@Overridepublic void update(Dept dept) {dept.setUpdateTime(LocalDateTime.now());deptMapper.update(dept);}
}

mapper层

@Mapper
public interface DeptMapper {/*** 查询部门* @return*/@Select("select * from dept")List<Dept> getDeptList();/*** 删除部门* @param id*/@Delete("delete from dept where id = #{id}")void deleteDeptById(Integer id);/*** 新增部门* @param dept*/@Insert("insert into dept values (null,#{name},#{createTime},#{updateTime})")void save(Dept dept);/*** 根据id查询部门* @param id* @return*/@Select("select * from dept where id = #{id}")Dept selectDeptById(Integer id);/*** 修改部门信息* @param dept*/@Update("update dept set name = #{name},update_time = #{updateTime} where id = #{id}")void update(Dept dept);
}
3.2、员工管理

我们可以把员工管理功能分为:

  1. 分页查询
  2. 带条件的分页查询
  3. 删除员工
  4. 新增员工
  5. 修改员工
3.2.1、前端核心代码
<template><div class="app-container"><!--搜索表单--><el-form :inline="true" :model="searchEmp" class="demo-form-inline"><el-form-item label="姓名"><el-inputv-model="searchEmp.name"placeholder="请输入员工姓名"></el-input></el-form-item><el-form-item label="性别"><el-select v-model="searchEmp.gender" placeholder="请选择"><el-option label="男" value="1"></el-option><el-option label="女" value="2"></el-option></el-select></el-form-item><el-form-item label="入职时间"><el-date-pickerv-model="entrydate"clearablevalue-format="yyyy-MM-dd"type="daterange"placeholder="选择日期"range-separator="至"start-placeholder="开始日期"end-placeholder="结束日期"style="width: 400px; margin-left: 20px"></el-date-picker></el-form-item><el-form-item><el-button type="primary" @click="onSubmit">查询</el-button><el-button type="info" @click="clear">清空</el-button></el-form-item></el-form><!--按钮--><el-row><el-button type="danger" size="medium" @click="deleteByIds">- 批量删除</el-button><el-button type="primary" size="medium" @click="dialogVisible = true; emp = { image: ''};" >+ 新增员工</el-button></el-row><!--添加数据对话框表单--><el-dialog ref="form" title="编辑员工" :visible.sync="dialogVisible" width="30%"><el-form :model="emp" :rules="rules" ref="emp" label-width="80px" size="mini"><el-form-item label="用户名" prop="username"><el-input v-model="emp.username"></el-input></el-form-item><el-form-item label="员工姓名"  prop="name"><el-input v-model="emp.name"></el-input></el-form-item><el-form-item label="性别"  prop="gender"><el-select v-model="emp.gender" placeholder="请选择" style="width:100%" ><el-optionv-for="item in genderList":key="item.value":label="item.name":value="item.id"/></el-select></el-form-item><el-form-item label="头像"><el-uploadclass="avatar-uploader"action="/api/upload":headers="token"name="image":show-file-list="false":on-success="handleAvatarSuccess":before-upload="beforeAvatarUpload"><img v-if="emp.image" :src="emp.image" class="avatar" /><i v-else class="el-icon-plus avatar-uploader-icon"></i></el-upload></el-form-item><el-form-item label="职位"><el-select v-model="emp.job" placeholder="请选择" value-key="emp.job" style="width:100%"><el-optionv-for="item in jobList":key="item.value":label="item.name":value="item.id"/></el-select></el-form-item><el-form-item label="入职日期"><el-date-pickerv-model="emp.entrydate"clearabletype="date"value-format="yyyy-MM-dd" placeholder="选择日期"size="small"style="width:100%"></el-date-picker></el-form-item><el-form-item label="归属部门"><el-select v-model="emp.deptId" placeholder="请选择" style="width:100%"><!-- <el-option label="学工部" value="1"></el-option><el-option label="教研部" value="2"></el-option>--><el-optionv-for="item in deptList":key="item.value":label="item.name":value="item.id"/></el-select></el-form-item><el-form-item><el-button type="primary" @click="save('emp')">提交</el-button><el-button @click="cancel('emp')">取消</el-button></el-form-item></el-form></el-dialog><br><!--表格--><template><el-table :data="tableData" style="width: 100%" border @selection-change="handleSelectionChange"><el-table-column type="selection" width="55"  align="center"></el-table-column><el-table-column  prop="name"  label="姓名"  align="center"></el-table-column><el-table-column prop="image" label="头像" align="center"><template slot-scope="{ row }"><el-image style="width: auto; height: 40px; border: none; cursor: pointer" :src="row.image"></el-image></template></el-table-column><el-table-column align="center" label="性别"><template slot-scope="scope"><span style="margin-right: 10px">{{scope.row.gender == "1" ? "男" : "女"}}</span></template></el-table-column><el-table-column align="center" label="职位"><template slot-scope="scope"><span style="margin-right: 10px" v-if="scope.row.job == 1">班主任</span><span style="margin-right: 10px" v-if="scope.row.job == 2">讲师</span><span style="margin-right: 10px" v-if="scope.row.job == 3">学工主管</span><span style="margin-right: 10px" v-if="scope.row.job == 4">教研主管</span></template></el-table-column><el-table-column align="center" label="日职日期"><template slot-scope="scope">{{ scope.row.entrydate }}</template></el-table-column><el-table-column align="center" label="最后操作时间"><template slot-scope="scope">{{scope.row.updateTime ? scope.row.updateTime.replace('T',' '):''}}</template></el-table-column><el-table-column align="center" label="操作"><template slot-scope="scope"><el-button type="primary" size="small" @click="update(scope.row.id)">编辑</el-button><el-button type="danger" size="small" @click="deleteById(scope.row.id)">删除</el-button></template></el-table-column></el-table></template><br><!--分页工具条--><el-pagination@size-change="handleSizeChange"@current-change="handleCurrentChange":background="background":current-page="currentPage":page-sizes="[5, 10, 15, 20]":page-size="5"layout="total, sizes, prev, pager, next, jumper":total="totalCount"></el-pagination></div>
</template><script>
import { page, add, update, deleteById, selectById } from "@/api/emp.js";
import { findAll } from "@/api/dept.js";
import { getToken } from '@/utils/auth';export default {data() {return {background: true,// 每页显示的条数pageSize: 5,// 总记录数totalCount: 100,// 当前页码currentPage: 1,// 添加数据对话框是否展示的标记dialogVisible: false,// 品牌模型数据searchEmp: {name: "",gender: "",},emp: {username: "",name: "",gender: "",image: "",job: "",entrydate: "",deptId: ""},deptList: [],genderList: [{id: 1,name: "男"},{id: 2,name: "女"}],jobList: [{id: 1,name: "班主任"},{id: 2,name: "讲师"},{id: 3, name: "学工主管"},{id: 4,name: "教研主管"}],beginTime: "",endTime: "",entrydate: "",// 被选中的id数组selectedIds: [],// 复选框选中数据集合multipleSelection: [],// 表格数据tableData: [],token: {token: getToken()},rules: {username: [{required: true, message: '请输入用户名', trigger: 'blur' },{min: 2, max: 20, message: '长度在 2 到 20 个字符', trigger: 'blur' }],name: [{required: true, message: '请输入姓名', trigger: 'blur' },{min: 2, max: 10, message: '长度在 2 到 10 个字符', trigger: 'blur' }],gender: [{required: true, message: '请选择性别', trigger: 'change' }]}};},mounted() {this.page(); //当页面加载完成后,发送异步请求,获取数据findAll().then((result) => {this.deptList = result.data.data;});},methods: {// 查询分页数据page() {page(this.searchEmp.name,this.searchEmp.gender,this.beginTime,this.endTime,this.currentPage,this.pageSize).then((res) => {this.totalCount = res.data.data.total;this.tableData = res.data.data.rows;});},// 复选框选中后执行的方法handleSelectionChange(val) {this.multipleSelection = val;},// 查询方法onSubmit() {this.currentPage = 1;this.page();},clear(){this.searchEmp = {name: "", gender: ""};this.beginTime = "",this.endTime = "";this.entrydate = "";this.page();},// 添加数据save(formName) {//校验表单this.$refs[formName].validate((valid) => {if (valid) {let operator;if (this.emp.id) {//修改operator = update(this.emp);} else { //新增operator = add(this.emp);}operator.then((resp) => {if (resp.data.code == 1) {this.dialogVisible = false;this.page();this.$message({ message: "恭喜你,保存成功", type: "success" });this.emp = { image: "" };} else {this.$message.error(resp.data.msg);}});}});},update(id) {//1. 打开窗口this.dialogVisible = true;//2. 发送请求selectById(id).then((result) => {if (result.data.code == 1) {this.emp = result.data.data;this.emp;}});},//分页handleSizeChange(val) {// 重新设置每页显示的条数this.pageSize = val;this.page();},handleCurrentChange(val) {// 重新设置当前页码this.currentPage = val;this.page();},//删除员工信息deleteById(id){this.$confirm("此操作将删除该数据, 是否继续?", "提示", {confirmButtonText: "确定",cancelButtonText: "取消",type: "warning",}).then(() => {//2. 发送AJAX请求deleteById(id).then((resp) => {if (resp.data.code == 1) {//删除成功this.$message.success("恭喜你,删除成功");this.page();} else {this.$message.error(resp.data.msg);}});}).catch(() => {//用户点击取消按钮this.$message.info("已取消删除");});},// 批量删除员工信息deleteByIds() {// 弹出确认提示框this.$confirm("此操作将删除该数据, 是否继续?", "提示", {confirmButtonText: "确定",cancelButtonText: "取消",type: "warning",}).then(() => {//用户点击确认按钮//1. 创建id数组, 从 this.multipleSelection 获取即可for (let i = 0; i < this.multipleSelection.length; i++) {this.selectedIds[i] = this.multipleSelection[i].id;}//2. 发送AJAX请求deleteById(this.selectedIds).then((resp) => {if (resp.data.code == "1") {//删除成功this.$message.success("恭喜你,删除成功");this.page();} else {this.$message.error(resp.data.msg);}});}).catch(() => {//用户点击取消按钮this.$message.info("已取消删除");});},cancel(formName){this.dialogVisible = false;this.$refs[formName].resetFields();},//文件上传相关handleAvatarSuccess(res, file) {this.emp.image = res.data;},beforeAvatarUpload(file) {const isJPG = file.type === "image/jpeg";const isLt2M = file.size / 1024 / 1024 < 2;if (!isJPG) {this.$message.error("上传头像图片只能是 JPG 格式!");}if (!isLt2M) {this.$message.error("上传头像图片大小不能超过 2MB!");}return isJPG && isLt2M;},},watch: {entrydate(val) {if (val && val.length >= 2) {this.beginTime = val[0];this.endTime = val[1];} else {this.beginTime = "";this.endTime = "";}},},
};
</script>
<style>
.avatar-uploader .el-upload {border: 1px dashed #d9d9d9;border-radius: 6px;cursor: pointer;position: relative;overflow: hidden;
}
.avatar-uploader .el-upload:hover {border-color: #409eff;
}
.avatar-uploader-icon {font-size: 28px;color: #8c939d;width: 100px;height: 100px;line-height: 100px;text-align: center;
}
.avatar {width: 100px;height: 100px;display: block;
}
</style>
3.2.2、后端代码实现

实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Emp {private Integer id;private String username;private String password;private String name;private Short gender;private String image;private Short job;private LocalDate entrydate;private Integer deptId;private LocalDateTime createTime;private LocalDateTime updateTime;
}

controller

@RestController
@RequestMapping("/emps")
@Slf4j
public class EmpController {@Autowiredprivate EmpService service;/*** 分页查询* @param page* @param pageSize* @param name* @param gender* @param begin* @param end* @return*/@GetMappingpublic Result page(@RequestParam(defaultValue = "1") Integer page,@RequestParam(defaultValue = "10") Integer pageSize,String name, Short gender,@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate begin,@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end){log.info("员工分页查询 page = {},pageSize = {}", page, pageSize);PageBean pageBean = service.page(page,pageSize,name,gender,begin,end);return Result.success(pageBean);}/*** 删除* @param ids* @return*/@DeleteMapping("/{ids}")public Result deleteByIds(@PathVariable("ids") List<Integer> ids){log.info("删除 ids = {}", ids);service.deleteByIds(ids);return Result.success();}/*** 新增员工* @param emp* @return*/@PostMappingpublic Result save(@RequestBody Emp emp){log.info("新增员工 {}", emp);service.save(emp);return Result.success();}/*** 根据id查询员工* @param id* @return*/@GetMapping("/{id}")public Result selectById(@PathVariable Integer id){log.info("根据id查询员工");Emp emp = service.selectById(id);return Result.success(emp);}@PutMappingpublic Result update(@RequestBody Emp emp){log.info("修改员工{}",emp);service.update(emp);return Result.success();}@GetMapping("/list")public Result selectAll(){log.info("查询全部员工");List<Emp> list = service.selectAll();return Result.success(list);}
}

service层

public interface EmpService {/*** 员工分页查询** @param page* @param pageSize* @param name* @param gender* @param begin* @param end* @return*/PageBean page(Integer page, Integer pageSize, String name, Short gender, LocalDate begin, LocalDate end);/*** 删除* @param ids*/void deleteByIds(List<Integer> ids);/*** 新增员工* @param emp*/void save(Emp emp);/*** 根据id查询员工* @param id* @return*/Emp selectById(Integer id);/*** 修改员工* @param emp*/void update(Emp emp);/*** 查询全部员工* @return*/List<Emp> selectAll();/*** 员工登录* @param emp* @return*/Emp login(Emp emp);
}@Service
public class EmpServiceImpl implements EmpService {@Autowiredprivate EmpMapper empMapper;@Overridepublic PageBean page(Integer page, Integer pageSize, String name, Short gender, LocalDate begin, LocalDate end) {//设置分页参数PageHelper.startPage(page,pageSize);//进行查询List<Emp> list = empMapper.list(name,gender,begin,end);//获取分页结果Page<Emp> empPage = (Page<Emp>) list;return new PageBean(empPage.getTotal(),empPage.getResult());}/*** 删除** @param ids*/@Overridepublic void deleteByIds(List<Integer> ids) {empMapper.deleteByIds(ids);}/*** 新增员工** @param emp*/@Overridepublic void save(Emp emp) {emp.setCreateTime(LocalDateTime.now());emp.setUpdateTime(LocalDateTime.now());empMapper.save(emp);}/*** 根据id查询员工** @param id* @return*/@Overridepublic Emp selectById(Integer id) {Emp emp = empMapper.selectById(id);return emp;}/*** 修改员工** @param emp*/@Overridepublic void update(Emp emp) {emp.setUpdateTime(LocalDateTime.now());empMapper.update(emp);}/*** 查询全部员工** @return*/@Overridepublic List<Emp> selectAll() {List<Emp> list = empMapper.selectAll();return list;}/*** 员工登录** @param emp* @return*/@Overridepublic Emp login(Emp emp) {return empMapper.getEmpByUsernameAndPassword(emp);}
}

mapper层

@Mapper
public interface EmpMapper {/*** 查询部门下是否有员工* @param id* @return*/@Select("select  count(*) from emp where dept_id = #{id}")Integer selectEmpByDeptId(Integer id);/*** 查询*/
//    @Select("select * from emp")List<Emp> list(@Param("name") String name,@Param("gender") Short gender,@Param("begin") LocalDate begin,@Param("end") LocalDate end);/*** 删除* @param ids*/void deleteByIds(@Param("ids") List<Integer> ids);/*** 新增员工* @param emp*/@Insert("insert into emp values (null,#{username},#{password},#{name},#{gender}" +",#{image},#{job},#{entrydate},#{deptId},#{createTime},#{updateTime})")void save(Emp emp);/*** 根据id查询员工* @param id* @return*/@Select("select * from emp where id = #{id}")Emp selectById(Integer id);/*** 修改员工* @param emp*/@Update("update emp set username = #{username},password = #{password}," +"name = #{name},gender = #{gender},image = #{image},job = #{job}," +"entrydate = #{entrydate},dept_id = #{deptId},create_time = #{createTime}," +"emp.update_time = #{updateTime} where id = #{id}")void update(Emp emp);/*** 查询全部员工* @return*/@Select("select * from emp")List<Emp> selectAll();/*** 员工性别统计* @return*/List<PieChartData> getEmpGenderData();/*** 员工职位统计* @return*/@Select("select (case job
" +"            when 1 then '班主任'" +"            when 2 then '讲师'" +"            when 3 then '学工主管'" +"            when 4 then '教研主管'" +"            when 4 then '咨询师'" +"            else '无' end) as job," +"       count(*) as jobcount" +" from emp" +" group by job")List<Map<String,Object>> getEmpJobData();/*** 员工登录* @param emp* @return*/@Select("select * from emp where username = #{username} and  password = #{password}")Emp getEmpByUsernameAndPassword(Emp emp);
}

mapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.tlias.mapper.EmpMapper"><delete id="deleteByIds">delete from empwhere id in<foreach collection="ids" open="(" close=")" item="id" separator=",">#{id}</foreach></delete><select id="list" resultType="com.tlias.entity.Emp">select * from emp<where><if test="name != null and name != ''">name like concat('%',#{name},'%')</if><if test="gender != null">and gender = #{gender}</if><if test="begin != null and end != null">and entrydate between #{begin} and #{end}</if></where>order by update_time desc</select><select id="getEmpGenderData" resultType="com.tlias.entity.PieChartData">select if(gender = 1,'男性员工','女性员工') as 'name',count(*) as 'value' from emp group by gender;</select></mapper>

因为需要涉及到oss文件上传所以我们还需要整合

@Data
@Component
@ConfigurationProperties(prefix = "aliyun.oss")
public class aliyunOssProperties {private String endpoint;private String accessKeyId;private String accessKeySecret;private String bucketName;
}@Component
public class aliyunUtils {@Autowiredprivate aliyunOssProperties properties;public String upload(MultipartFile multipartFile) throws IOException {String endpoint = properties.getEndpoint();String accessKeyId = properties.getAccessKeyId();String accessKeySecret = properties.getAccessKeySecret();String bucketName = properties.getBucketName();//生成上传名称String originalFilename = multipartFile.getOriginalFilename();String objectName = UUID.randomUUID().toString() + originalFilename.substring(originalFilename.lastIndexOf("."));// 创建OSSClient实例。OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId,accessKeySecret);try {InputStream inputStream = multipartFile.getInputStream();// 创建PutObjectRequest对象。PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, inputStream);// 上传文件。PutObjectResult result = ossClient.putObject(putObjectRequest);return endpoint.split("//")[0] + "//" + bucketName + "." + endpoint.split("//")[1] + "//" +objectName;} finally {if (ossClient != null) {ossClient.shutdown();}}}
}
3.3、班级管理

开发的班级管理功能包含:

  1. 查询班级
  2. 删除班级
  3. 新增班级
  4. 更新班级
3.3.1、前端核心代码
<template><div style="margin-top: 20px; margin: 50px; margin-right: 100px"><!-- 按钮 --><el-row><el-button style="float: right" type="primary" @click="dialogFormVisible = true; dept = {}">+ 新增班级</el-button></el-row><br><!-- 数据表格 --><template><el-table highlight-current-row ref="multipleTable" :data="tableData" tooltip-effect="dark" style="width: 100%"border><el-table-column type="index" width="100" label="序号" header-align="center" align="center"> </el-table-column><el-table-column prop="name" label="班级名称" header-align="center" align="center"></el-table-column><el-table-column prop="room" label="上课教室" header-align="center" align="center"></el-table-column><el-table-column label="开课时间" header-align="center" align="center"><template slot-scope="scope">{{ scope.row.beginDate ? scope.row.beginDate.replace('T', ' ') : '' }}</template></el-table-column><el-table-column label="结课时间" header-align="center" align="center"><template slot-scope="scope">{{ scope.row.endDate ? scope.row.endDate.replace('T', ' ') : '' }}</template></el-table-column><el-table-column label="创建时间" header-align="center" align="center"><template slot-scope="scope">{{ scope.row.createTime ? scope.row.createTime.replace('T', ' ') : '' }}</template></el-table-column><el-table-column label="最后操作时间" header-align="center" align="center"><template slot-scope="scope">{{ scope.row.updateTime ? scope.row.updateTime.replace('T', ' ') : '' }}</template></el-table-column><!-- <el-table-column prop="masterId" label="教师id" header-align="center" align="center"></el-table-column> --><el-table-column label="操作" width="420" header-a lign="center" align="center"><template slot-scope="scope"><el-button size="mini" type="primary" plain @click="selectById(scope.row.id)">编辑</el-button><el-button size="mini" type="danger" plain @click="deleteById(scope.row.id)">删除</el-button></template></el-table-column></el-table></template><!-- 新建对话框 --><el-dialog title="保存班级" :visible.sync="dialogFormVisible"><el-form :model="clazz" :rules="rules" ref="clazz"><el-form-item label="班级名称"  prop="name"><el-input v-model="clazz.name" placeholder="请输入班级名称" autocomplete="off"></el-input></el-form-item><el-form-item label="教室" prop="room"><el-input v-model="clazz.room" placeholder="请输入教室" autocomplete="off"></el-input></el-form-item><el-form-item label="开始日期" prop="beginDate"><el-date-picker v-model="clazz.beginDate" type="date" placeholder="选择开始日期"></el-date-picker></el-form-item><el-form-item label="结束日期" prop="endDate"><el-date-picker v-model="clazz.endDate" type="date" placeholder="选择结束日期"></el-date-picker></el-form-item><!-- <el-form-item label="班主任ID" prop="masterId"><el-input v-model="clazz.masterId" placeholder="请输入班主任ID" autocomplete="off"></el-input></el-form-item> --></el-form><div slot="footer" class="dialog-footer"><el-button @click="cancel('clazz')">取 消</el-button><el-button type="primary" @click="save('clazz')">确 定</el-button></div></el-dialog></div>
</template><script>
import { findAll, add, update, deleteById, selectById } from "@/api/clazz.js";export default {data() {return {formLabelWidth: "120px",dialogFormVisible: false, //控制对话框是否可见clazz: {name: "",room: "",beginDate: "",endDate: "",masterId: ""},tableData: [],rules: {name: [{ required: true, message: '请输入部门名称', trigger: 'blur' },{ min: 2, max: 20, message: '长度在 2 到 10 个字符', trigger: 'blur' }],room: [{ required: true, message: '请输入教室', trigger: 'blur' }],beginDate: [{ required: true, message: '请选择开始日期', trigger: 'change' }],endDate: [{ required: true, message: '请选择结束日期', trigger: 'change' }],// masterId: [//   { required: true, message: '请输入班主任ID', trigger: 'blur' }// ]}};},methods: {//删除部门deleteById(id) {this.$confirm("确认删除?", "提示", {confirmButtonText: "确定",cancelButtonText: "取消",type: "warning",}).then(() => {deleteById(id).then((result) => {if (result.data.code == 1) {this.$message({message: "恭喜你,删除成功",type: "success",});} else {this.$message.error(result.data.msg);}//重新查询数据this.init();});}).catch(() => {this.$message({type: "info",message: "已取消删除",});});},//根据ID查询部门 -- 回显selectById(id) {this.dialogFormVisible = true;selectById(id).then((result) => {this.clazz = result.data.data;});},//保存方法save(formName) {this.$refs[formName].validate((valid) => {if (valid) {let operator;if (this.clazz.id) {operator = update(this.clazz); // 修改} else {operator = add(this.clazz); //添加 }operator.then((result) => {if (result.data.code == 1) {//修改成功this.$message.success("恭喜你,保存成功");//重新查询数据this.init();// 关闭新建窗口this.dialogFormVisible = false;// 清空模型数据this.clazz = {};} else {this.$message.error(result.data.msg);}});}})},//初始化 - 查询全部init() {findAll().then((result) => {console.log(result);if (result.data.code == 1) {this.tableData = result.data.data;}});},cancel(formName) {this.dialogFormVisible = false;this.$refs[formName].resetFields();}},mounted() {//当页面加载完成后自动执行。this.init();},
};
</script>
<style></style>
3.3.2、后端代码实现

实体类

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Clazz {private Integer id;private String name;private String room;private LocalDate beginDate;private LocalDate endDate;private Integer masterId;private LocalDateTime createTime;private LocalDateTime updateTime;
}

controller层

@RestController
@RequestMapping("/clazzs")
@Slf4j
public class ClazzController {@Autowiredprivate ClazzService clazzService;/*** 查询所有* @return*/@GetMappingpublic Result findAll(){log.info("findAll...");List<Clazz> list = clazzService.findAll();return Result.success(list);}/*** 新增班级* @param clazz* @return*/@PostMappingpublic Result save(@RequestBody Clazz clazz){log.info("save{}",clazz);clazzService.save(clazz);return Result.success();}/*** 根据id删除班级* @param id* @return*/@DeleteMapping("/{id}")public Result deleteById(@PathVariable Long id){log.info("deleteById...{}",id);clazzService.deleteById(id);return Result.success();}/*** 根据id查询班级*/@GetMapping("/{id}")public Result findById(@PathVariable Long id){log.info("findById...{}",id);Clazz clazz = clazzService.findById(id);return Result.success(clazz);}/*** 更新班级* @param clazz* @return*/@PutMappingpublic Result update(@RequestBody Clazz clazz){log.info("update...{}",clazz);clazzService.update(clazz);return Result.success();}
}

service

public interface ClazzService {/*** 查询所有班级* @return*/List<Clazz> findAll();/*** 新增班级* @param clazz*/void save(Clazz clazz);/*** 根据id删除班级* @param id*/void deleteById(Long id);/*** 根据id查询班级* @param id* @return*/Clazz findById(Long id);/*** 更新班级* @param clazz*/void update(Clazz clazz);
}@Service
public class ClazzServiceImpl implements ClazzService {@Autowiredprivate ClazzMapper clazzMapper;/*** 查询所有班级** @return*/@Overridepublic List<Clazz> findAll() {List<Clazz> clazzList = clazzMapper.findAll();return clazzList;}/*** 新增班级** @param clazz*/@Overridepublic void save(Clazz clazz) {clazz.setCreateTime(LocalDateTime.now());clazz.setUpdateTime(LocalDateTime.now());clazzMapper.save(clazz);}/*** 根据id删除班级** @param id*/@Overridepublic void deleteById(Long id) {clazzMapper.deleteById(id);}/*** 根据id查询班级** @param id* @return*/@Overridepublic Clazz findById(Long id) {Clazz clazz = clazzMapper.findById(id);return clazz;}/*** 更新班级** @param clazz*/@Overridepublic void update(Clazz clazz) {clazz.setUpdateTime(LocalDateTime.now());clazzMapper.update(clazz);}
}

mapper层

@Mapper
public interface ClazzMapper {/*** 查询所有班级* @return*/@Select("select * from clazz")List<Clazz> findAll();/*** 新增班级* @param clazz*/@Insert("insert into clazz values (null,#{name},#{room},#{beginDate},#{endDate},#{masterId}," +"#{createTime},#{updateTime})")void save(Clazz clazz);/*** 根据id删除班级* @param id*/@Delete("delete from clazz where id = #{id}")void deleteById(Long id);/*** 根据id查询班级* @param id* @return*/@Select("select * from clazz where id = #{id};")Clazz findById(Long id);/*** 更新班级* @param clazz*/@Update("update clazz set name = #{name},room = #{room},begin_date = #{beginDate}," +"end_date = #{endDate},master_id = #{masterId} where id = #{id}")void update(Clazz clazz);
}
3.4、学生管理

我们可以把员工管理功能分为:

  1. 分页查询
  2. 带条件的分页查询
  3. 删除员工
  4. 新增员工
  5. 修改员工
3.4.1、前端核心代码
<template><div class="app-container"><!--搜索表单--><el-form :inline="true" :model="searchStudent" class="demo-form-inline"><el-form-item label="姓名"><el-inputv-model="searchStudent.name"placeholder="请输入学生姓名"></el-input></el-form-item><el-form-item label="性别"><el-select v-model="searchStudent.gender" placeholder="请选择"><el-option label="男" value="1"></el-option><el-option label="女" value="2"></el-option></el-select></el-form-item><el-form-item><el-button type="primary" @click="onSubmit">查询</el-button><el-button type="info" @click="clear">清空</el-button></el-form-item></el-form><!--按钮--><el-row><el-button type="danger" size="medium" @click="deleteByIds">- 批量删除</el-button><el-button type="primary" size="medium" @click="dialogVisible = true; student = { image: ''};" >+ 新增学生</el-button></el-row><!--添加数据对话框表单--><el-dialog ref="form" title="编辑学生" :visible.sync="dialogVisible" width="30%"><el-form :model="student" :rules="rules" ref="student" label-width="80px" size="mini"><el-form-item label="姓名" prop="name"><el-input v-model="student.name"></el-input></el-form-item><el-form-item label="学号"  prop="no"><el-input v-model="student.no"></el-input></el-form-item><el-form-item label="性别"  prop="gender"><el-select v-model="student.gender" placeholder="请选择" style="width:100%" ><el-optionv-for="item in genderList":key="item.value":label="item.name":value="item.id"/></el-select></el-form-item><el-form-item label="手机"  prop="phone"><el-input v-model="student.phone"></el-input></el-form-item><el-form-item label="班级"  prop="phone"><el-input v-model="student.clazzId"></el-input></el-form-item><!-- <el-form-item label="头像"><el-uploadclass="avatar-uploader"action="/api/upload":headers="token"name="image":show-file-list="false":on-success="handleAvatarSuccess":before-upload="beforeAvatarUpload"><img v-if="emp.image" :src="emp.image" class="avatar" /><i v-else class="el-icon-plus avatar-uploader-icon"></i></el-upload></el-form-item> --><!-- <el-form-item label="职位"><el-select v-model="emp.job" placeholder="请选择" value-key="emp.job" style="width:100%"><el-optionv-for="item in jobList":key="item.value":label="item.name":value="item.id"/></el-select></el-form-item> -->
<!-- <el-form-item label="入职日期"><el-date-pickerv-model="emp.entrydate"clearabletype="date"value-format="yyyy-MM-dd" placeholder="选择日期"size="small"style="width:100%"></el-date-picker></el-form-item> --><!-- <el-form-item label="班级"><el-select v-model="student.clazzId" placeholder="请选择" style="width:100%"><el-optionv-for="item in clazzList":key="item.value":label="item.name":value="item.id"/></el-select></el-form-item> --><el-form-item><el-button type="primary" @click="save('student')">提交</el-button><el-button @click="cancel('student')">取消</el-button></el-form-item></el-form></el-dialog><br><!--表格--><template><el-table :data="tableData" style="width: 100%" border @selection-change="handleSelectionChange"><el-table-column type="selection" width="55"  align="center"></el-table-column><el-table-column  prop="name"  label="姓名"  align="center"></el-table-column><!-- <el-table-column prop="image" label="头像" align="center"><template slot-scope="{ row }"><el-image style="width: auto; height: 40px; border: none; cursor: pointer" :src="row.image"></el-image></template></el-table-column> --><el-table-column  prop="no"  label="学号"  align="center"></el-table-column><el-table-column  prop="phone"  label="手机"  align="center"></el-table-column><el-table-column align="center" label="性别"><template slot-scope="scope"><span style="margin-right: 10px">{{scope.row.gender == "1" ? "男" : "女"}}</span></template></el-table-column><!-- <el-table-column  prop="degree"  label="学年"  align="center"></el-table-column> --><!-- <el-table-column  prop="violationCount"  label="违纪总数"  align="center"></el-table-column> --><!-- <el-table-column  prop="violationScore"  label="违纪分数"  align="center"></el-table-column> --><el-table-column  prop="clazzId"  label="班级"  align="center"></el-table-column><!-- <el-table-column align="center" label="职位"><template slot-scope="scope"><span style="margin-right: 10px" v-if="scope.row.job == 1">班主任</span><span style="margin-right: 10px" v-if="scope.row.job == 2">讲师</span><span style="margin-right: 10px" v-if="scope.row.job == 3">学工主管</span><span style="margin-right: 10px" v-if="scope.row.job == 4">教研主管</span></template></el-table-column> --><el-table-column align="center" label="入学日期"><template slot-scope="scope">{{ scope.row.createTime ? scope.row.createTime.replace('T', ' ') : '' }}</template></el-table-column><!-- <el-table-column align="center" label="最后操作时间"><template slot-scope="scope">{{scope.row.updateTime ? scope.row.updateTime.replace('T',' '):''}}</template></el-table-column> --><el-table-column align="center" label="操作"><template slot-scope="scope"><el-button type="primary" size="small" @click="update(scope.row.id)">编辑</el-button><el-button type="danger" size="small" @click="deleteById(scope.row.id)">删除</el-button></template></el-table-column></el-table></template><br><!--分页工具条--><el-pagination@size-change="handleSizeChange"@current-change="handleCurrentChange":background="background":current-page="currentPage":page-sizes="[5, 10, 15, 20]":page-size="5"layout="total, sizes, prev, pager, next, jumper":total="totalCount"></el-pagination></div>
</template><script>
import { page, add, update, deleteById, selectById , findAll} from "@/api/student.js";
// import { findAll } from "@/api/dept.js";
import { getToken } from '@/utils/auth';export default {data() {return {background: true,// 每页显示的条数pageSize: 5,// 总记录数totalCount: 100,// 当前页码currentPage: 1,// 添加数据对话框是否展示的标记dialogVisible: false,// 模型数据searchStudent: {name: "",gender: ""},student: {name: "",no: "",gender: "",phone: "",degree: "",violationCount: "",violationScore: "",clazzId: ""},clazzList: [],genderList: [{id: 1,name: "男"},{id: 2,name: "女"}],selectedIds: [],// 复选框选中数据集合multipleSelection: [],// 表格数据tableData: [],token: {token: getToken()},rules: {name: [{required: true, message: '请输入姓名', trigger: 'blur' },{min: 2, max: 10, message: '长度在 2 到 10 个字符', trigger: 'blur' }],gender: [{required: true, message: '请选择性别', trigger: 'change' }]}};},mounted() {this.page(); //当页面加载完成后,发送异步请求,获取数据findAll().then((result) => {this.deptList = result.data.data;});},methods: {// 查询分页数据page() {page(this.searchStudent.name,this.searchStudent.gender,// this.beginTime,// this.endTime,this.currentPage,this.pageSize).then((res) => {this.totalCount = res.data.data.total;this.tableData = res.data.data.rows;});},// 复选框选中后执行的方法handleSelectionChange(val) {this.multipleSelection = val;},// 查询方法onSubmit() {this.currentPage = 1;this.page();},clear(){this.searchStudent = {name: "", gender: ""};this.page();},// 添加数据save(formName) {//校验表单this.$refs[formName].validate((valid) => {if (valid) {let operator;if (this.student.id) {//修改operator = update(this.student);} else { //新增operator = add(this.student);}operator.then((resp) => {if (resp.data.code == 1) {this.dialogVisible = false;this.page();this.$message({ message: "恭喜你,保存成功", type: "success" });this.student = { image: "" };} else {this.$message.error(resp.data.msg);}});}});},update(id) {//1. 打开窗口this.dialogVisible = true;//2. 发送请求selectById(id).then((result) => {if (result.data.code == 1) {this.student = result.data.data;this.student;}});},//分页handleSizeChange(val) {// 重新设置每页显示的条数this.pageSize = val;this.page();},handleCurrentChange(val) {// 重新设置当前页码this.currentPage = val;this.page();},//删除员工信息deleteById(id){this.$confirm("此操作将删除该数据, 是否继续?", "提示", {confirmButtonText: "确定",cancelButtonText: "取消",type: "warning",}).then(() => {//2. 发送AJAX请求deleteById(id).then((resp) => {if (resp.data.code == 1) {//删除成功this.$message.success("恭喜你,删除成功");this.page();} else {this.$message.error(resp.data.msg);}});}).catch(() => {//用户点击取消按钮this.$message.info("已取消删除");});},// 批量删除员工信息deleteByIds() {// 弹出确认提示框this.$confirm("此操作将删除该数据, 是否继续?", "提示", {confirmButtonText: "确定",cancelButtonText: "取消",type: "warning",}).then(() => {//用户点击确认按钮//1. 创建id数组, 从 this.multipleSelection 获取即可for (let i = 0; i < this.multipleSelection.length; i++) {this.selectedIds[i] = this.multipleSelection[i].id;}//2. 发送AJAX请求deleteById(this.selectedIds).then((resp) => {if (resp.data.code == "1") {//删除成功this.$message.success("恭喜你,删除成功");this.page();} else {this.$message.error(resp.data.msg);}});}).catch(() => {//用户点击取消按钮this.$message.info("已取消删除");});},cancel(formName){this.dialogVisible = false;this.$refs[formName].resetFields();},//文件上传相关handleAvatarSuccess(res, file) {this.student.image = res.data;},beforeAvatarUpload(file) {const isJPG = file.type === "image/jpeg";const isLt2M = file.size / 1024 / 1024 < 2;if (!isJPG) {this.$message.error("上传头像图片只能是 JPG 格式!");}if (!isLt2M) {this.$message.error("上传头像图片大小不能超过 2MB!");}return isJPG && isLt2M;},},watch: {entrydate(val) {if (val && val.length >= 2) {this.beginTime = val[0];this.endTime = val[1];} else {this.beginTime = "";this.endTime = "";}},},
};
</script>
<style>
.avatar-uploader .el-upload {border: 1px dashed #d9d9d9;border-radius: 6px;cursor: pointer;position: relative;overflow: hidden;
}
.avatar-uploader .el-upload:hover {border-color: #409eff;
}
.avatar-uploader-icon {font-size: 28px;color: #8c939d;width: 100px;height: 100px;line-height: 100px;text-align: center;
}
.avatar {width: 100px;height: 100px;display: block;
}
</style>
3.4.2、后端代码实现

实体类

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student {private Integer id;private String name;private String no;private Short gender;private String phone;private Short degree;private Short violationCount;private Short violationScore;private Short clazzId;private LocalDateTime createTime;private LocalDateTime updateTime;
}@Data
@NoArgsConstructor
@AllArgsConstructor
public class StudentData {private List categoryList;private List dataList;
}

controller

package com.tlias.controller;import com.github.pagehelper.Page;
import com.tlias.entity.PageBean;
import com.tlias.entity.Student;
import com.tlias.result.Result;
import com.tlias.service.StudentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;import java.util.List;@RestController
@RequestMapping("/students")
@Slf4j
public class StudentController {@Autowiredprivate StudentService studentService;@GetMappingpublic Result page(String name, Short gender,@RequestParam(defaultValue = "1") Integer page,@RequestParam(defaultValue = "10") Integer pageSize){log.info("员工分页查询 page={},pageSize={}", page, pageSize);PageBean pageBean = studentService.page(page,pageSize,name,gender);return Result.success(pageBean);}/*** 查询全部* @return*/@GetMapping("/list")public Result findAll(){log.info("findAll...");List<Student> studentList = studentService.findAll();return Result.success(studentList);}/*** 新增学生* @param student* @return*/@PostMapping()public Result save(@RequestBody Student student){log.info("save student...{}",student);studentService.save(student);return Result.success();}/*** 根据id查询学生* @param id* @return*/@GetMapping("/{id}")public Result findById(@PathVariable Long id){log.info("findById...{}",id);Student student = studentService.findById(id);return Result.success(student);}/*** 修改学生* @param student* @return*/@PutMappingpublic Result update(@RequestBody Student student){log.info("update student...{}",student);studentService.update(student);return Result.success();}/*** 删除* @param ids* @return*/@DeleteMapping("/{ids}")public Result deleteById(@PathVariable List<Integer> ids){log.info("deleteById...{}",ids);studentService.deleteById(ids);return Result.success();}}

service

public interface StudentService {/*** 分页查询* @param page* @param pageSize* @param name* @param gender* @return*/PageBean page(Integer page, Integer pageSize, String name, Short gender);/*** 查询全部* @return*/List<Student> findAll();/*** 新增学生* @param student*/void save(Student student);/*** 根据id查询学生* @param id* @return*/Student findById(Long id);/*** 修改学生* @param student*/void update(Student student);/*** 根据id删除* @param ids*/void deleteById(List<Integer> ids);
}@Service
public class StudentServiceImpl implements StudentService {@Autowiredprivate StudentMapper studentMapper;/*** 分页查询** @param page* @param pageSize* @param name* @param gender* @return*/@Overridepublic PageBean page(Integer page, Integer pageSize, String name, Short gender) {PageHelper.startPage(page,pageSize);List<Student> list = studentMapper.page(name,gender);Page<Student> studentPage = (Page<Student>) list;return new PageBean(studentPage.getTotal(),studentPage.getResult());}/*** 查询全部** @return*/@Overridepublic List<Student> findAll() {List<Student> studentList = studentMapper.findAll();return studentList;}/*** 新增学生** @param student*/@Overridepublic void save(Student student) {student.setCreateTime(LocalDateTime.now());student.setUpdateTime(LocalDateTime.now());studentMapper.save(student);}/*** 根据id查询学生** @param id* @return*/@Overridepublic Student findById(Long id) {return studentMapper.findById(id);}/*** 修改学生** @param student*/@Overridepublic void update(Student student) {student.setUpdateTime(LocalDateTime.now());studentMapper.update(student);}/*** 根据id删除** @param ids*/@Overridepublic void deleteById(List<Integer> ids) {studentMapper.deleteById(ids);}}

mapper

@Mapper
public interface StudentMapper {@Select("SELECT clazz.`name` as 'class',COUNT(student.clazz_id) as 'classcount' " +"FROM clazz LEFT JOIN student ON student.clazz_id = clazz.id GROUP BY clazz.`name` ;")List<Map<String, Object>> getStudentData();/*** 分页查询* @param name* @param gender* @return*/List<Student> page(@Param("name") String name,@Param("gender") Short gender);/*** 查询全部* @return*/@Select("select * from student")List<Student> findAll();/*** 新增学生* @param student*/@Insert("insert into student(name, no, gender, phone,clazz_id, create_time, update_time) " +"value(#{name},#{no},#{gender},#{phone},#{clazzId},#{createTime},#{updateTime})")void save(Student student);/*** 根据id查询学生* @param id* @return*/@Select("select * from student where id = #{id};")Student findById(Long id);/*** 修改学生* @param student*/@Update("update student set name = #{name},no = #{no},gender = #{gender}," +"phone = #{phone},clazz_id = #{clazzId} where id = #{id}")void update(Student student);/*** 根据id删除* @param ids*/void deleteById(@Param("ids") List<Integer> ids);
}<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.tlias.mapper.StudentMapper"><delete id="deleteById">delete from student where id in<foreach collection="ids" item="id" separator="," open="(" close=")">#{id}</foreach></delete><select id="page" resultType="com.tlias.entity.Student">select * from student<where><if test="name != null and name != ''">name like concat('%',#{name},'%')</if><if test="gender != null">and gender != #{gender}</if></where></select>
</mapper>
3.5、数据统计
3.5.1、前端核心代码
<template><div class="chart-container"><div  style="width: 50%; "><h1>员工性别统计</h1> <br><div id="myChart1"  style="width: 100%; height: 500px"></div></div><div  style="width: 50%; "><h1>员工职位统计</h1> <br><div id="myChart2"  style="width: 100%; height: 500px"></div></div></div>
</template><script>
import * as echarts from 'echarts'
import { getGenderData, getJobData } from "@/api/report.js";export default {data() {return {genderCountList: [],jobCategoryList:[],jobDataList:[]}},mounted() { this.getGenderData(); //获取员工性别统计数据this.getJobData(); //获取员工职位统计数据},methods: {//获取员工性别统计数据getGenderData(){getGenderData().then((result) => {if(result.data.code == 1){this.genderCountList = result.data.data;this.initChart1();}});},//获取员工职位统计数据getJobData(){getJobData().then((result) => {if(result.data.code == 1){this.jobCategoryList = result.data.data.categoryList;this.jobDataList = result.data.data.dataList;this.initChart2();}});},initChart1() {// 获取图表容器, 创建图表实例let myChart = echarts.init(document.querySelector('#myChart1'));let option = {tooltip: {trigger: 'item'},legend: {top: '5%',left: 'center'},series: [{name: '员工性别统计',type: 'pie',radius: ['40%', '70%'],avoidLabelOverlap: false,itemStyle: {borderRadius: 10,borderColor: '#fff',borderWidth: 2},label: {show: false,position: 'center'},emphasis: {label: {show: true,fontSize: 40,fontWeight: 'bold'}},labelLine: {show: false},data: this.genderCountList}]};// 绘制图表myChart.setOption(option);},initChart2() {// 获取图表容器, 创建图表实例let myChart = echarts.init(document.querySelector('#myChart2'));let option = {xAxis: {type: 'category',data: this.jobCategoryList},yAxis: {type: 'value'},series: [{data: this.jobDataList,type: 'bar'}]};// 绘制图表myChart.setOption(option);}}
};
</script><style>h1 {text-align: center;}.chart-container {display: flex;}.chart-container > div {flex: 1;}
</style>
3.5.2、后端代码实现

实体类

@Data
public class PieChartData {private String name;private String value;
}@Data
@NoArgsConstructor
@AllArgsConstructor
public class StudentData {private List categoryList;private List dataList;
}

controller

@RestController
@RequestMapping("/report")
@Slf4j
public class ReportController {@Autowiredprivate ReportService service;@GetMapping("/empGenderData")public Result getEmpGenderData(){log.info("员工性别信息信息");List<PieChartData> list = service.getEmpGenderData();return Result.success(list);}@GetMapping("/empJobData")public Result getEmpJobData(){log.info("员工职位信息");JobData jobData  = service.getEmpJobData();return Result.success(jobData);}@GetMapping("/studentData")public Result getStudentData(){log.info("学员人数统计");StudentData studentData = service.getStudentData();return Result.success(studentData);}
}

service层

public interface ReportService {/*** 员工性别统计* @return*/List<PieChartData> getEmpGenderData();/*** 员工职位信息统计* @return*/JobData getEmpJobData();/*** 学员统计* @return*/StudentData getStudentData();
}@Service
public class ReportServiceImpl implements ReportService {@Autowiredprivate EmpMapper empMapper;@Autowiredprivate StudentMapper studentMapper;/*** 员工性别统计** @return*/@Overridepublic List<PieChartData> getEmpGenderData() {List<PieChartData> list = empMapper.getEmpGenderData();return list;}/*** 员工职位信息统计** @return*/@Overridepublic JobData getEmpJobData() {List<Map<String,Object>> mapList = empMapper.getEmpJobData();System.out.println(mapList);if (!CollectionUtils.isEmpty(mapList)) {List<Object> categoryList = mapList.stream().map(map -> {return map.get("job");}).collect(Collectors.toList());List<Object> dataList = mapList.stream().map(map -> {return map.get("jobcount");}).collect(Collectors.toList());JobData jobData = new JobData();jobData.setCategoryList(categoryList);jobData.setDataList(dataList);System.out.println(jobData);return jobData;}return null;}/*** 学员统计** @return*/@Overridepublic StudentData getStudentData() {List<Map<String,Object>> mapList = studentMapper.getStudentData();System.out.println(mapList);if (!CollectionUtils.isEmpty(mapList)){List<Object> categoryList = mapList.stream().map(map -> {return map.get("class");}).collect(Collectors.toList());List<Object> dataList = mapList.stream().map(map -> {return map.get("classcount");}).collect(Collectors.toList());return new StudentData(categoryList,dataList);}return null;}
}
3.6、登录功能

我们已经实现了部门管理、员工管理的基本功能,但是大家会发现,我们并没有登录,就直接访问到了后台。 这是不安全的,所以要做登录认证。 最终我们要实现的效果就是用户必须登录之后,才可以访问后台系统中的功能

JWT令牌最典型的应用场景就是登录认证:

  1. 在浏览器发起请求来执行登录操作,此时会访问登录的接口,如果登录成功之后,我们需要生成一个jwt令牌,将生成的 jwt令牌返回给前端。
  2. 前端拿到jwt令牌之后,会将jwt令牌存储起来。在后续的每一次请求中都会将jwt令牌携带到服务端。
  3. 服务端统一拦截请求之后,先来判断一下这次请求有没有把令牌带过来,如果没有带过来,直接拒绝访问,如果带过来了,还要校验一下令牌是否是有效。如果有效,就直接放行进行请求的处理。

在JWT登录认证的场景中我们发现,整个流程当中涉及到两步操作:

  1. 在登录成功之后,要生成令牌。
  2. 每一次请求当中,要接收令牌并对令牌进行校验。
3.6.1、前端核心代码
<template><div class="login-container"><el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form" auto-complete="on" label-position="left"><div class="title-container"><h3 class="title">Tlias智能学习辅助系统</h3></div><el-form-item prop="username"><span class="svg-container"><svg-icon icon-class="user" /></span><el-inputref="username"v-model="loginForm.username"placeholder="Username"name="username"type="text"tabindex="1"auto-complete="on"/></el-form-item><el-form-item prop="password"><span class="svg-container"><svg-icon icon-class="password" /></span><el-input:key="passwordType"ref="password"v-model="loginForm.password":type="passwordType"placeholder="Password"name="password"tabindex="2"auto-complete="on"@keyup.enter.native="handleLogin"/><span class="show-pwd" @click="showPwd"><svg-icon :icon-class="passwordType === 'password' ? 'eye' : 'eye-open'" /></span></el-form-item><el-button :loading="loading" type="primary" style="width:100%;margin-bottom:30px;" @click.native.prevent="handleLogin">Login</el-button></el-form></div>
</template><script>
import { validUsername } from '@/utils/validate'
import { login } from '@/api/user'
import { setToken } from '@/utils/auth'
export default {name: 'Login',data() {//用户名校验规则const validateUsername = (rule, value, callback) => {if (!validUsername(value)) {callback(new Error('请输入正确的用户名'))} else {callback()}}//用户名校验规则const validatePassword = (rule, value, callback) => {if (value.length < 6) {callback(new Error('密码长度至少为6位'))} else {callback()}}//数据模型return {loginForm: {username: 'jinyong',password: '123456'},loginRules: {username: [{ required: true, trigger: 'blur', validator: validateUsername }],password: [{ required: true, trigger: 'blur', validator: validatePassword }]},loading: false,passwordType: 'password',redirect: undefined}},methods: {//展示密码showPwd() {if (this.passwordType === 'password') {this.passwordType = ''} else {this.passwordType = 'password'}this.$nextTick(() => {this.$refs.password.focus()})},//登录方法handleLogin() {this.$refs.loginForm.validate(valid => {if (valid) {this.loading = true//调用登录后端接口login(this.loginForm).then((result) => {console.log(result)if (result.data.code == 1) {setToken(result.data.data);console.log('login success');this.$router.push('/');} else {this.$message.error(result.data.msg);this.loading = false}});} else {console.log('error submit!!')return false}})}}
}
</script><style lang="scss">
/* 修复input 背景不协调 和光标变色 */
/* Detail see https://github.com/PanJiaChen/vue-element-admin/pull/927 */$bg:#283443;
$light_gray:#fff;
$cursor: #fff;@supports (-webkit-mask: none) and (not (cater-color: $cursor)) {.login-container .el-input input {color: $cursor;}
}/* reset element-ui css */
.login-container {.el-input {display: inline-block;height: 47px;width: 85%;input {background: transparent;border: 0px;-webkit-appearance: none;border-radius: 0px;padding: 12px 5px 12px 15px;color: $light_gray;height: 47px;caret-color: $cursor;&:-webkit-autofill {box-shadow: 0 0 0px 1000px $bg inset !important;-webkit-text-fill-color: $cursor !important;}}}.el-form-item {border: 1px solid rgba(255, 255, 255, 0.1);background: rgba(0, 0, 0, 0.1);border-radius: 5px;color: #454545;}
}
</style><style lang="scss" scoped>
$bg:#2d3a4b;
$dark_gray:#889aa4;
$light_gray:#eee;.login-container {min-height: 100%;width: 100%;background-color: $bg;overflow: hidden;.login-form {position: relative;width: 520px;max-width: 100%;padding: 160px 35px 0;margin: 0 auto;overflow: hidden;}.tips {font-size: 14px;color: #fff;margin-bottom: 10px;span {&:first-of-type {margin-right: 16px;}}}.svg-container {padding: 6px 5px 6px 15px;color: $dark_gray;vertical-align: middle;width: 30px;display: inline-block;}.title-container {position: relative;.title {font-size: 26px;color: $light_gray;margin: 0px auto 40px auto;text-align: center;font-weight: bold;font-family: '楷体';}}.show-pwd {position: absolute;right: 10px;top: 7px;font-size: 16px;color: $dark_gray;cursor: pointer;user-select: none;}
}
</style>
3.6.2、后端代码实现

创建工具类,实现jwt令牌的发放和解析

public class JwtUtils {private static String signKey = "jwtHelloWorld";private static Long expire = 60 * 60 * 1000L;public static String generateToken(Map<String, Object> claims) {String token = Jwts.builder().setClaims(claims).signWith(SignatureAlgorithm.HS256, signKey).setExpiration(new Date(System.currentTimeMillis() + expire)).compact();return token;}public static Claims parseToken(String token) {Claims claims = Jwts.parser().setSigningKey(signKey).parseClaimsJws(token).getBody();return claims;}
}

创建拦截器,进行拦截

/*** 自定义拦截器*/
@Component
@Slf4j
public class LoginCheckInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//1、获取请求urlString url = request.getRequestURI().toString();//3、获取请求头中的tokenString token = request.getHeader("token");if (!StringUtils.hasLength(token)){ //不存在log.info("获取令牌为空");Result notLogin = Result.error("NOT_LOGIN");String json = JSONObject.toJSONString(notLogin);response.getWriter().write(json);return false;}//4、解析token,失败则未登录try {Claims claims = JwtUtils.parseToken(token);} catch (Exception e) {log.info("解析令牌错误");Result notLogin = Result.error("NOT_LOGIN");String json = JSONObject.toJSONString(notLogin);response.getWriter().write(json);return false;}//5、放行return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("postHandle");}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("afterCompletion");}
}

controller层

@RestController
@Slf4j
public class LoginController {@Autowiredprivate EmpService empService;@PostMapping("/login")public Result login(@RequestBody Emp emp){log.info("员工登录{}",emp);Emp empLogin = empService.login(emp);if (empLogin != null){Map<String, Object> map = new HashMap<>();map.put("id", empLogin.getId());map.put("username", empLogin.getUsername());String token = JwtUtils.generateToken(map);return Result.success(token);}return Result.error("查无此用户");}
}

http://www.ppmy.cn/ops/156567.html

相关文章

Flink2支持提交StreamGraph到Flink集群

最近研究Flink源码的时候&#xff0c;发现Flink已经支持提交StreamGraph到集群了&#xff0c;替换掉了原来的提交JobGraph。 新增ExecutionPlan接口&#xff0c;将JobGraph和StreamGraph作为实现。 Flink集群Dispatcher也进行了修改&#xff0c;从JobGraph改成了接口Executio…

3. 【.NET Aspire 从入门到实战】--理论入门与环境搭建--环境搭建

构建现代云原生应用程序时&#xff0c;开发环境的搭建至关重要。NET Aspire 作为一款专为云原生应用设计的开发框架&#xff0c;提供了一整套工具、模板和集成包&#xff0c;旨在简化分布式系统的构建和管理。开始项目初始化之前&#xff0c;确保开发环境的正确配置是成功的第一…

Macos安装APOC拓展库

文章目录 说明错误提示原因分析解决方法 说明 Macos安装APOC核心库 错误提示 There is no procedure with the name apoc.generate.ba registered for this database instance. Please ensure youve spelled the procedure name correctly and that the procedure is prope…

肝了半年,我整理出了这篇云计算学习路线(新手必备,从入门到精通)

大家好&#xff01;我是凯哥&#xff0c;今天给大家分享一下云计算学习路线图。这是我按照自己最开始学习云计算的时候的学习路线&#xff0c;并且结合自己从业多年所涉及的知识精心总结的云计算的思维导图。这是凯哥精心总结的&#xff0c;花费了不少精力哦&#xff0c;希望对…

HAL库 Systick定时器 基于STM32F103EZT6 野火霸道,可做参考

目录 1.时钟选择(这里选择高速外部时钟) ​编辑 2.调试模式和时基源选择: 3.LED的GPIO配置 这里用板子的红灯PB5 4.工程配置 5.1ms的systick中断实现led闪烁 源码: 6.修改systick的中断频率 7.systick定时原理 SysTick 定时器的工作原理 中断触发机制 HAL_SYSTICK_Co…

Nginx 请求超时

Nginx 请求超时详解 在现代 Web 服务中&#xff0c;Nginx 作为一个高效的 Web 服务器和反向代理服务器&#xff0c;广泛应用于处理大量的 HTTP 请求。随着 Web 应用和服务的复杂性增加&#xff0c;Nginx 在处理客户端请求时&#xff0c;可能会出现超时问题。请求超时是指当客户…

使用Selenium和Jsoup框架进行Java爬虫

Java爬虫示例&#xff1a;使用Selenium和Jsoup框架爬取NASA网站 在Java中使用Selenium和Jsoup框架编写爬虫&#xff0c;可以结合Selenium模拟浏览器行为获取动态加载的内容&#xff0c;然后利用Jsoup解析HTML结构并抽取所需数据。基本步骤如下&#xff1a; 步骤1&#xff1a;…

什么是图神经网络?

一、概念 图神经网络&#xff08;Graph Neural Network, GNN&#xff09;是一类专门用于处理图结构数据的神经网络。图结构数据广泛存在于各种实际应用中&#xff0c;如社交网络、分子结构、知识图谱等。GNN通过在图的节点和边上进行信息传递和聚合&#xff0c;能够有效地捕捉图…