借出,归还,管理
学生和管理员登录分离
学生登录到用户界面
管理员到后台
后台和用户分离
添加代码
sems-server/src/main/java/com/ljc/controller/user/UserStudentController.java
package com.ljc.controller.user;
import com.ljc.constant.JwtClaimsConstant;
import com.ljc.dto.StudentLoginDTO;
import com.ljc.entity.Student;
import com.ljc.properties.JwtProperties;
import com.ljc.result.Result;
import com.ljc.service.UserStudentService;
import com.ljc.utils.JwtUtil;
import com.ljc.vo.StudentLoginVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/user")
@Slf4j
@Api(tags = "用户界面")
public class UserStudentController {
@Autowired
private JwtProperties jwtProperties;
@Autowired
private UserStudentService userStudentService;
/**
* 登录
*
* @param studentLoginDTO
* @return
*/
@ApiOperation("用户登录")
@PostMapping("/login")
public Result<StudentLoginVO> login(@RequestBody StudentLoginDTO studentLoginDTO) {
log.info("学生登录:{}", studentLoginDTO);
Student student = userStudentService.login(studentLoginDTO);
//登录成功后,生成jwt令牌
Map<String, Object> claims = new HashMap<>();
claims.put(JwtClaimsConstant.EMP_ID, student.getId());
String token = JwtUtil.createJWT(
jwtProperties.getAdminSecretKey(),
jwtProperties.getAdminTtl(),
claims);
StudentLoginVO studentLoginVO = StudentLoginVO.builder()
.id(student.getId())
.userName(student.getUsername())
.name(student.getName())
.token(token)
.build();
return Result.success(studentLoginVO);
}
/**
* 退出
*
* @return
*/
@ApiOperation("用户退出")
@PostMapping("/logout")
public Result<String> logout() {
return Result.success();
}
}
sems-server/src/main/java/com/ljc/service/UserStudentService.java
package com.ljc.service;
import com.ljc.dto.StudentLoginDTO;
import com.ljc.entity.Student;
import org.springframework.stereotype.Service;
public interface UserStudentService {
Student login(StudentLoginDTO studentLoginDTO);
}
sems-server/src/main/java/com/ljc/service/impl/UserStudentServiceImpl.java
package com.ljc.service.impl;
import com.ljc.constant.MessageConstant;
import com.ljc.constant.StatusConstant;
import com.ljc.dto.StudentLoginDTO;
import com.ljc.entity.Student;
import com.ljc.exception.AccountLockedException;
import com.ljc.exception.AccountNotFoundException;
import com.ljc.exception.PasswordErrorException;
import com.ljc.mapper.UserStudentMapper;
import com.ljc.service.UserStudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import java.util.Objects;
@Service
public class UserStudentServiceImpl implements UserStudentService {
@Autowired
private UserStudentMapper userStudentMapper;
/**
* 学生登录
*
* @param studentLoginDTO
* @return
*/
public Student login(StudentLoginDTO studentLoginDTO) {
String username = studentLoginDTO.getUsername();
String password = studentLoginDTO.getPassword();
//1、根据用户名查询数据库中的数据
Student student = userStudentMapper.getByUsername(username);
//2、处理各种异常情况(用户名不存在、密码不对、账号被锁定)
if (student == null) {
//账号不存在
throw new AccountNotFoundException(MessageConstant.ACCOUNT_NOT_FOUND);
}
//密码比对
// 进行md5加密,然后再进行比对
password = DigestUtils.md5DigestAsHex(password.getBytes());
if (!password.equals(student.getPassword())) {
//密码错误
throw new PasswordErrorException(MessageConstant.PASSWORD_ERROR);
}
if (Objects.equals(student.getStatus(), StatusConstant.DISABLE)) {
//账号被锁定
throw new AccountLockedException(MessageConstant.ACCOUNT_LOCKED);
}
//3、返回实体对象
return student;
}
}
sems-server/src/main/java/com/ljc/mapper/UserStudentMapper.java
package com.ljc.service.impl;
import com.ljc.constant.MessageConstant;
import com.ljc.constant.StatusConstant;
import com.ljc.dto.StudentLoginDTO;
import com.ljc.entity.Student;
import com.ljc.exception.AccountLockedException;
import com.ljc.exception.AccountNotFoundException;
import com.ljc.exception.PasswordErrorException;
import com.ljc.mapper.UserStudentMapper;
import com.ljc.service.UserStudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import java.util.Objects;
@Service
public class UserStudentServiceImpl implements UserStudentService {
@Autowired
private UserStudentMapper userStudentMapper;
/**
* 学生登录
*
* @param studentLoginDTO
* @return
*/
public Student login(StudentLoginDTO studentLoginDTO) {
String username = studentLoginDTO.getUsername();
String password = studentLoginDTO.getPassword();
//1、根据用户名查询数据库中的数据
Student student = userStudentMapper.getByUsername(username);
//2、处理各种异常情况(用户名不存在、密码不对、账号被锁定)
if (student == null) {
//账号不存在
throw new AccountNotFoundException(MessageConstant.ACCOUNT_NOT_FOUND);
}
//密码比对
// 进行md5加密,然后再进行比对
password = DigestUtils.md5DigestAsHex(password.getBytes());
if (!password.equals(student.getPassword())) {
//密码错误
throw new PasswordErrorException(MessageConstant.PASSWORD_ERROR);
}
if (Objects.equals(student.getStatus(), StatusConstant.DISABLE)) {
//账号被锁定
throw new AccountLockedException(MessageConstant.ACCOUNT_LOCKED);
}
//3、返回实体对象
return student;
}
}
测试
创建数据库表
借还表
编号 | 姓名 | 学号 | 借用器材 | 器材数量 | 借用时间 | 归还时间 |
id | name | stu_id | equipment | number | borrow_time | end_time |
int | varchar(10) | int | varchar(20) | int | time | time |
CREATE TABLE borrowing (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(10) NOT NULL,
stu_id INT NOT NULL,
equipment VARCHAR(20) NOT NULL,
number INT NOT NULL,
borrow_time TIMESTAMP NOT NULL,
end_time TIMESTAMP
);
借用—新增数据
请求路径:/admin/borrow
请求方法:POST
请求参数:请求头:Headers:"Content-Type": "application/json"
请求体:Body:
学生姓名;
学号;
借用器材名字;
数量;
返回数据:Result
代码开发
创建实体类和DTO类
sems-pojo/src/main/java/com/ljc/dto/BorrowDTO.java
package com.ljc.dto;
import lombok.Data;
import java.io.Serializable;
@Data
public class BorrowDTO implements Serializable {
/*编号*/
private Integer id;
/*学生姓名*/
private String name;
/*学生学号*/
private long stuId;
/*器材名字*/
private String equipment;
/*器材数量*/
private long number;
}
sems-pojo/src/main/java/com/ljc/entity/Borrow.java
package com.ljc.entity;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.time.LocalDateTime;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Borrow implements Serializable {
private static final long serialVersionUID = 1L;//告诉Java虚拟机(JVM)这个类的对象是可以被序列化的。
/*编号*/
private Integer id;
/*学生姓名*/
private String name;
/*学生学号*/
private long stuId;
/*器材名字*/
private String equipment;
/*器材数量*/
private long number;
/*借用时间*/
private LocalDateTime borrowTime;
/*归还时间*/
private LocalDateTime endTime;
}
controller层
sems-server/src/main/java/com/ljc/controller/user/UserBorrowController.java
package com.ljc.controller.user;
import com.ljc.dto.BorrowDTO;
import com.ljc.dto.EquipmentDTO;
import com.ljc.result.Result;
import com.ljc.service.BorrowService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/borrow")
@Slf4j
@Api(tags = "借用器材界面")
public class UserBorrowController {
@Autowired
private BorrowService borrowService;
/**
* 新增器材
* @param borrowDTO
* @return
*/
@PostMapping
@ApiOperation("新增器材")
public Result save(@RequestBody BorrowDTO borrowDTO){
log.info("借用器材:{}", borrowDTO);
borrowService.save(borrowDTO);
return Result.success();
}
}
service
sems-server/src/main/java/com/ljc/service/BorrowService.java
package com.ljc.service;
import com.ljc.dto.BorrowDTO;
public interface BorrowService {
void save(BorrowDTO borrowDTO);
}
sems-server/src/main/java/com/ljc/service/impl/BorrowServiceImpl.java
package com.ljc.service.impl;
import com.ljc.dto.BorrowDTO;
import com.ljc.entity.Borrow;
import com.ljc.mapper.BorrowMapper;
import com.ljc.service.BorrowService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
@Service
public class BorrowServiceImpl implements BorrowService {
@Autowired
private BorrowMapper borrowMapper;
@Override
public void save(BorrowDTO borrowDTO) {
Borrow borrow = new Borrow();
BeanUtils.copyProperties(borrowDTO,borrow);
borrow.setBorrowTime(LocalDateTime.now());
borrowMapper.insert(borrow);
}
}
mapper
sems-server/src/main/java/com/ljc/mapper/BorrowMapper.java
package com.ljc.mapper;
import com.ljc.entity.Borrow;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface BorrowMapper {
@Insert("INSERT INTO borrowing (id, name, stu_id, equipment, number, borrow_time, end_time) " +
"VALUES " +
"(#{id},#{name},#{stuId},#{equipment},#{number},#{borrowTime},#{endTime})")
void insert(Borrow borrow);
}
sems-server/src/main/resources/mapper/BorrowMapper.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.ljc.mapper.BorrowMapper">
</mapper>
测试
http://localhost:8080/doc.html
细节优化
会发现没有设置外键,equipment是外键,还有学号在学生表不合适,将学生表中的id列改为学生学号列;然后和这个表进行连接,id也成功外键;
改student表
因为之前id字段是自增的,得把这个修改掉
#取消id所包含的外键约束
ALTER TABLE equipment
DROP FOREIGN KEY equipment_ibfk_1;
ALTER TABLE equipment
DROP FOREIGN KEY equipment_ibfk_2;
#删除原来的id字段
alter table student drop column id;
#执行之前把student表只剩下admin一行数据,把其他的先删除,添加字段成功之后再补充回来
ALTER TABLE student
ADD id INT PRIMARY KEY;
之前相关代码修改
数据库
sems-server/src/main/java/com/ljc/mapper/StudentMapper.java
加了个字段id
/**
* 新增学生
* @param student
*/
@Insert("insert into student (id,name, username, password, phone, sex, id_number, create_time, update_time, create_user, update_user,status) " +
"values " +
"(#{id},#{name},#{username},#{password},#{phone},#{sex},#{idNumber},#{createTime},#{updateTime},#{createUser},#{updateUser},#{status})")
void insert(Student student);
前端部分
然后去前端修改,新增的时候得传递学号:
src/views/student/addStudent.vue(全部代码)
<template>
<div class="form-container">
<el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">
<el-form-item label="学号" prop="id">
<el-input v-model="ruleForm.id"></el-input>
</el-form-item>
<el-form-item label="账号用户名" prop="username">
<el-input v-model="ruleForm.username"></el-input>
</el-form-item>
<el-form-item label="姓名" prop="name">
<el-input v-model="ruleForm.name"></el-input>
</el-form-item>
<el-form-item label="手机号" prop="phone">
<el-input v-model="ruleForm.phone"></el-input>
</el-form-item>
<el-form-item label="性别" prop="sex">
<el-radio-group v-model="ruleForm.sex">
<el-radio label="1">男</el-radio>
<el-radio label="2">女</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="身份证号" prop="idNumber">
<el-input v-model="ruleForm.idNumber"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm('ruleForm')">保存</el-button>
<el-button @click="$router.push('/student');">返回</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
import { addStudent, queryStudentById, updateStudent } from '@/api/Student';
export default {
data() {
return {
optType: '',//当前操作的类型:add还是update
ruleForm: {
id: '',
username: '',
name: '',
phone: '',
sex: '1',
idNumber: ''
},
rules: {
id: [
{ required: true, message: '请输入学号', trigger: 'blur' },
],
username: [
{ required: true, message: '请输入用户名', trigger: 'blur' },//trigger: 'blur'意味着验证或更新操作将在输入字段失去焦点(即用户点击了输入框之外的区域,或切换到另一个输入框)时触发。
],
name: [
{ required: true, message: '请输入学生姓名', trigger: 'blur' }
],
phone: [
{
required: true, trigger: 'blur', validator: (rule, value, callback) => {
if (value === '' || (!/^1[3-9]\d{9}$/.test(value))) {
callback(new Error("请输入正确的电话号码!"))
} else {
callback()
}
}
}
],
idNumber: [
{
required: true, trigger: 'blur', validator: (rule, value, callback) => {
if (value === '' || (!/^[1-9]\d{5}(18|19|20)\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}(\d|X|x)$/.test(value))) {
callback(new Error("请输入正确的身份证号!"))
} else {
callback()
}
}
}
],
}
};
},
created() {
//获取路由参数,如果有就是修改,没有就是新增操作
this.optType = this.$route.query.id ? 'update' : 'add'
if (this.optType === 'update') {
//修改操作,根据id查询原始数据,用于回显
queryStudentById(this.$route.query.id)
.then((res) => {
if (res.data.code === 1) {
this.ruleForm = res.data.data
}
})
}
},
methods: {
submitForm(formName) {
if (this.optType === 'add') {
this.$refs[formName].validate((valid) => {
if (valid) {
addStudent(this.ruleForm)
.then((res) => {
if (res.data.code === 1) {
this.$message.success("添加成功!")
this.$router.push('/student')
} else {
this.$message.error("res.data.msg")
}
})
} else {
console.log('error submit!!');
return false;
}
});
} else {
this.$refs[formName].validate((valid) => {
if (valid) {
updateStudent(this.ruleForm)
.then(res => {
if (res.data.code === 1) {
this.$message.success("修改成功!")
this.$router.push('/student')
} else {
this.$message.error("res.data.msg")
}
})
} else {
console.log('error submit!!');
return false;
}
})
}
},
}
}
</script>
<style scoped>
.form-container {
display: flex;
justify-content: center;
align-items: center;
height: 70vh;
/* 或者你想要的任何高度 */
width: 100%;
max-width: 600px;
/* 限制最大宽度以适应较小的屏幕 */
margin: 0 auto;
/* 水平居中 */
padding: 20px;
/* 内边距 */
background-color: #ffffff;
/* 背景颜色 */
border-radius: 8px;
/* 圆角 */
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
/* 阴影效果 */
}
.demo-ruleForm {
max-width: 500px;
/* 根据需要调整宽度 */
width: 100%;
/* 可选,确保在较窄的屏幕上也能适应 */
}
</style>
src/views/student/Student.vue(全部代码)
<template>
<div>
<el-form :inline="true" class="demo-form-inline">
<div style="float: left">
<label style="margin-right: 5px">学生姓名: </label>
<el-input v-model="name" placeholder="请输入学生姓名" style="width: 40%" />
<el-button type="primary" style="margin-left: 20px" @click="pageQuery()">查询</el-button>
</div>
<div>
<el-button type="primary" style="float: right" @click="handleAddStu">+添加学生</el-button>
</div>
</el-form>
<br>
<br>
<br>
<div>
<el-table :data="records" stripe style="width: 100%">
<el-table-column prop="id" label="学号" width="180" align="center">
</el-table-column>
<el-table-column prop="name" label="学生姓名" width="180" align="center">
</el-table-column>
<el-table-column prop="username" label="账号" width="180" align="center">
</el-table-column>
<el-table-column prop="phone" label="手机号" align="center">
</el-table-column>
<el-table-column prop="status" label="账号状态" align="center">
<template slot-scope="scope">{{ scope.row.status === 0 ? "禁用" : "启用" }}</template>
</el-table-column>
<el-table-column prop="updateTime" label="最后操作时间" align="center">
</el-table-column>
<el-table-column label="操作" align="center">
<template slot-scope="scope">
<el-button type="text" @click="handleUpdateStu(scope.row)">修改</el-button>
<el-button type="text" @click="handleStartOrStop(scope.row)">{{ scope.row.status === 0 ? "启用" :
"禁用"
}}</el-button>
</template>
</el-table-column>
</el-table>
</div>
<br>
<div>
<el-pagination class="pageList" @size-change="handleSizeChange" @current-change="handleCurrentChange"
:current-page="page" :page-sizes="[10, 20, 30, 40]" :page-size="pageSize"
layout="total, sizes, prev, pager, next, jumper" :total="total">
</el-pagination>
</div>
</div>
</template>
<script>
// import request from '@/utils/request'
import { page, startOrStopStatus } from '@/api/Student'
export default {
data() {
return {
id:'',
name: '', //学生姓名,对应上面的输入框
page: 1, //页码
pageSize: 10, // 每页记录数
total: 0, //总记录数
records: [] //当前页要展示的数据集合
}
},
created() {
this.pageQuery()
},
methods: {
pageQuery() {
//准备参数
const params = {
page: this.page,
pageSize: this.pageSize,
name: this.name
}
/* request({
url: "/api/admin/student/page", // 请求地址
method: "get", // 请求方法
params: params,
headers: { // 请求头
"Content-Type": "application/json",
},
}) */
page(params)
.then((res) => {
//解析结果
if (res.data.code === 1) {
this.total = res.data.data.total
this.records = res.data.data.records
}
}).catch(()=> {
this.$router.push("/login");
})
},
//每页记录数发生变化时触发
handleSizeChange(pageSize) {
this.pageSize = pageSize
this.pageQuery()
},
//page发生变化时触发
handleCurrentChange(page) {
this.page = page
this.pageQuery()
},
//新增员工
handleAddStu() {
this.$router.push('/student/addStudent')
},
//启用禁用员工状态
handleStartOrStop(row) {
//判断账号是否是管理员账号,不能更改管理员账号
if (row.username === 'admin') {
this.$message.error("这是管理员账号,不允许更改!")
return
}
this.$confirm('是否确认修改员工状态?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
const p = {
id: row.id,
status: !row.status ? 1 : 0
}
startOrStopStatus(p)
.then(res =>{
if(res.data.code === 1){
this.$message.success("状态修改成功!")
this.pageQuery()
}
})
})
},
//修改编辑学生信息
handleUpdateStu(row){
if(row.username === 'admin'){
this.$message.error("这是管理员账号,不允许修改!!")
return
}
//跳转到修改页面,通过地址栏传递参数
this.$router.push({ path: '/student/addStudent', query: {id: row.id}})
}
}
}
</script>
测试
改equipment表和borrowing表
/*器材表操作*/
alter table equipment drop column id;
ALTER TABLE equipment
ADD id INT;
/*记得在新的equipment表里面完善id字段然后再执行下列语句*/
ALTER TABLE equipment
ADD primary key(id);
/*给借用表加一列数据*/
ALTER TABLE borrowing
ADD column equ_id int;
代码修改
sems-pojo/src/main/java/com/ljc/entity/Borrow.java
package com.ljc.entity;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.time.LocalDateTime;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Borrow implements Serializable {
private static final long serialVersionUID = 1L;//告诉Java虚拟机(JVM)这个类的对象是可以被序列化的。
/*编号*/
private Integer id;
/*学生姓名*/
private String name;
/*学生学号*/
private long stuId;
/*器材编号*/
private long equId;
/*器材名字*/
private String equipment;
/*器材数量*/
private long number;
/*借用时间*/
private LocalDateTime borrowTime;
/*归还时间*/
private LocalDateTime endTime;
}
sems-pojo/src/main/java/com/ljc/dto/BorrowDTO.java
package com.ljc.dto;
import lombok.Data;
import java.io.Serializable;
@Data
public class BorrowDTO implements Serializable {
/*编号*/
private Integer id;
/*学生姓名*/
private String name;
/*学生学号*/
private long stuId;
/*器材编号*/
private long equId;
/*器材名字*/
private String equipment;
/*器材数量*/
private long number;
}
添加外键
ALTER TABLE borrowing
ADD CONSTRAINT fk_borrowing_student
FOREIGN KEY (stu_id)
REFERENCES student(id)
ON DELETE CASCADE
ON UPDATE CASCADE;
ALTER TABLE borrowing
ADD CONSTRAINT fk_borrowing_equipment
FOREIGN KEY (equ_id)
REFERENCES equipment(id)
ON DELETE CASCADE
ON UPDATE CASCADE;
测试
其实还有问题,就是不知道怎么解决:如何在一个表里面学生和学号对应,器材和器材编号对应,现在学生和编号不一样也是可以插入进去数据的,后面研究研究;
2024.8.23
未完