图书管理借阅系统(SpringBoot项目)

前后端分离项目

一:效果展示

图书借阅系统效果展示

二:代码实现

一、设计数据库(表的设计)

1、首先我们要进入图书系统必须要登录,验证身份之后才可进入,角色有:普通用户、管理员

2、其次是图书表

3、图书属于哪个出版社我们也单独设计了一张表

4、然后是借阅表,用户借阅图书的记录

5、最后当用户没有归还图书时,管理员可以进行催还的操作

一共是五张表:

用户表:

CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(255) DEFAULT NULL,
  `password` varchar(255) DEFAULT NULL,
  `type` int(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;

图书表:

CREATE TABLE `book` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `author` varchar(255) DEFAULT NULL,
  `pid` int(255) DEFAULT NULL,
  `number` int(11) DEFAULT NULL,
  `status` int(11) DEFAULT NULL,
  `is_del` int(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8;

出版社表:

CREATE TABLE `press` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;

借阅表:

CREATE TABLE `borrow` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `bid` int(255) DEFAULT NULL,
  `uid` int(255) DEFAULT NULL,
  `j_time` datetime DEFAULT NULL,
  `g_time` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;

消息表:

CREATE TABLE `mq` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `msg` varchar(255) DEFAULT NULL,
  `time` datetime DEFAULT NULL,
  `uid` int(11) DEFAULT NULL,
  `status` int(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8;

以上就是该项目中所需的表

二、登录权限

登录页,用户输入用户名和密码,后端校验用户名和密码是否匹配,若匹配则返回登录成功信息,并显示当前登录成功的用户身份 (普通用户 或 管理员),登录后跳转到图书列表页,否则返回登录失败信息

三、图书管理页面

根据角色的不同,显示不同的内容,管理员登陆,可以显示所有图书的信息,但不能显示借阅按钮,可以对图书进行,增删改查。普通用户登陆,可以查询图书信息,并只显示未借阅的图书。并显示借阅按钮。

四、借阅操作

普通用户,点击借阅按钮之后,确定图书的借阅时间,并将图书状态设置为“已借阅”状态,当借阅成功之后,对数据的借阅次数进行+1操作。

五、借阅列表

普通用户,只能看到,自己借阅的书单,并显示“归还”按钮,如果书没有归还,显示归还按钮。当用户点击“归还”按钮之后,将归还时间设置为点击归还的时间。将书的状态,设置为“未借阅”。当管理员进入到借阅列表页面,可以看到所有的借阅记录。催书功能。管理员可以指定某一个未归还的书本信息,并通过RabbitMQ,模拟发送短信,给用户。当用户登陆之后,可以接收发送过来的短信消息。

另外该项目中额外增加了导入导出功能

代码

登录前端:

<template>
  <div class="home">
    <el-form v-model="login">
      用户名:<el-input type="text" v-model="login.username" style="width: 300px"></el-input><br>
      账号:<el-input type="text" style="width: 300px" v-model="login.password"></el-input><br>
      <el-button type="primary" @click="toLogin()">登录</el-button>
    </el-form>

  </div>
</template>

<script>
export default {
  data(){
    return{
      login:{}

    }
  },
  methods:{
    toLogin(){
      this.axios.post("/user/login",this.login).then(res=>{
        if(res.data.code==0){
          this.$message.error(res.data.msg);
        }else{
          localStorage.setItem("user",JSON.stringify(res.data.data));
          alert("欢迎回来:"+(res.data.data.type==1?"管理员":"普通用户"));
          this.$router.push("/book");
        }
      })
    }
  }


}
</script>

登录后端:

package cn.jiyun.controlller;

import cn.jiyun.commons.Results;
import cn.jiyun.mapper.UserMapper;
import cn.jiyun.pojo.User;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.google.gson.JsonObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@CrossOrigin
@RestController
@RequestMapping("user")
public class UserController {
    @Autowired
    UserMapper userMapper;
    @Autowired
    RedisTemplate redisTemplate;
    @RequestMapping("login")
    public Results login(@RequestBody User user){
        LambdaQueryWrapper<User> qw = new LambdaQueryWrapper<>();
        qw.eq(User::getUsername,user.getUsername());
        qw.eq(User::getPassword,user.getPassword());
        User user1 = userMapper.selectOne(qw);
        if(user1==null){
            return Results.error("账号或密码错误,请重试!");
        }
        redisTemplate.boundValueOps("BookUser").set(JSONObject.toJSONString(user1));
        return Results.success(user1);
    }
}

图书列表展示前端:

<template>
  <div>
    <h1>当前登录的用户是:{{this.login.type==1?'管理员':'普通用户'}}</h1>
    书名:
    <el-input v-model="requestParam.name" style="width: 200px" placeholder="请输入内容"></el-input>
    作者:
    <el-input v-model="requestParam.author" style="width: 200px" placeholder="请输入内容"></el-input>
    出版社:
    <el-select v-model="requestParam.pid" placeholder="请选择">
    <el-option
        v-for="item in pressList"
        :key="item.id"
        :label="item.name"
        :value="item.id">
    </el-option>
  </el-select>
    <el-button type="primary" size="mini" @click="findList">搜索</el-button>
    <el-button type="primary" size="mini" @click="borrowList">借阅列表</el-button>
    <el-button type="primary" v-if="login.type==1" size="mini" @click="daochu">导出</el-button>
    <el-upload
        class="avatar-uploader"
        action="http://localhost:82/book/daoru"
        :show-file-list="false"
      :on-success="handleAvatarSuccess">
<!--      :before-upload="beforeAvatarUpload">-->
      <el-button type="primary" size="mini">导入</el-button>
    </el-upload>

    <el-button type="primary" v-if="login.type!=1" size="mini" @click="xiaoxi">消息列表</el-button>
    <el-dialog title="消息" :visible.sync="dialogxiaoxiVisible">
      <el-table
          :data="mqList"
          stripe
          style="width: 100%">
        <el-table-column
            prop="msg"
            label="消息">
        </el-table-column>
        <el-table-column
            prop="time"
            label="时间">
        </el-table-column>
        <el-table-column
            prop="status"
            label="状态">
          <template slot-scope="scope">
            {{scope.row.status==1?'未读':'已读'}}
          </template>
        </el-table-column>
        <el-table-column label="操作">
          <template slot-scope="scope">
            <el-button v-if="scope.row.status==1"
                       size="mini"
                       @click="yidu(scope.row.id)">已读
            </el-button>

          </template>
        </el-table-column>
      </el-table>
    </el-dialog>
    <el-table
        :data="page.records"
        stripe
        style="width: 100%">
      <el-table-column
          prop="id"
          label="编号">
      </el-table-column>
      <el-table-column
          prop="name"
          label="姓名">
      </el-table-column>
      <el-table-column
          prop="author"
          label="作者">
      </el-table-column>
      <el-table-column
          prop="pname"
          label="出版社">
      </el-table-column>
      <el-table-column
          prop="number"
          label="借阅次数">
      </el-table-column>
      <el-table-column
          prop="status"
          label="当前借阅状态">
        <!--template:模板 自定义展示内容-->
        <template slot-scope="scope">
          {{ scope.row.status == 1 ? '借阅中' : '未借阅' }}
        </template>
      </el-table-column>
      <el-table-column label="操作">
        <template slot-scope="scope">
          <el-button v-if="login.type==1"
              size="mini"
              @click="handleEdit(scope.row)">修改
          </el-button>
          <el-button v-if="login.type==1"
              type="danger"
              size="mini"
              @click="handleDel(scope.row.id)">删除
          </el-button>
          <el-button v-if="login.type!=1"
              type="danger"
              size="mini"
              @click="handleJieShu(scope.row.id)">借阅
          </el-button>
        </template>
      </el-table-column>
    </el-table>
    <!--分页-->
    <el-pagination
        @size-change="handleSizeChange"
        @current-change="handleCurrentChange"
        :current-page="page.current"
        :page-sizes="[4, 6, 8, 10]"
        :page-size="page.size"
        layout="total, sizes, prev, pager, next, jumper"
        :total="page.total">
    </el-pagination>
<!--    修改弹窗-->
    <el-dialog title="修改书籍" :visible.sync="dialogFormVisible">
      <el-form :model="form">
        <el-form-item label="活动名称" :label-width="formLabelWidth">
          <el-input v-model="form.name" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item label="作者" :label-width="formLabelWidth">
          <el-input v-model="form.author" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item label="借阅次数" :label-width="formLabelWidth">
          <el-input v-model="form.number" type="number" autocomplete="off"></el-input>
        </el-form-item>

        <el-form-item label="出版社" :label-width="formLabelWidth">
          <el-select v-model="form.pid" placeholder="请选择">
            <el-option
                v-for="item in pressList"
                :key="item.id"
                :label="item.name"
                :value="item.id">
            </el-option>
          </el-select>
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button @click="dialogFormVisible = false">取 消</el-button>
        <el-button type="primary" @click="updateBook()">确 定</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
import axios from "axios";

export default {
  data(){
    return{
      login:{},
      pressList:[],
      requestParam:{},
      pageParam:{
        current:1,
        size:2,
      },
      page:{},
      dialogFormVisible:false,
      form:{},
      formLabelWidth:"200px",
      mqList:[],
      dialogxiaoxiVisible:false,
      mqLen:0,

    }
  },
  methods:{
    yidu(id){
      this.axios.post("/book/yidu?id="+id).then(res=>{
        this.findMQList();
      })
    },
    borrowList(){
      this.$router.push("/borrowList");

    },
    handleJieShu(id){
      this.axios.post("/book/jieyue?id="+id).then(res=>{
        if(res.data.code!=0){
          this.$message.success(res.data.msg);
          this.findList();
        }
      })
    },
    handleDel(id){
      this.$confirm('此操作将永久删除该文件, 是否继续?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        this.axios.post("/book/delBookById?id="+id).then(res=>{
          if(res.data.code!=0){
            this.$message.success(res.data.msg);
            this.findList();
          }
        })
      }).catch(() => {
        this.$message({
          type: 'info',
          message: '已取消删除'
        });
      });

    },
    updateBook(){
      this.axios.post("/book/updateBook",this.form).then(res=>{
        if(res.data.code!=0){
          this.$message.success(res.data.msg);
          this.findList();
          this.dialogFormVisible=false;
        }
      })
    },
    handleAvatarSuccess(){
      this.findList();
    },
    handleEdit(t){
      this.form=t;
      this.dialogFormVisible=true;

    },
    handleSizeChange(val) {
      this.pageParam.size=val;
      this.findList();
    },
    handleCurrentChange(val) {
      this.pageParam.current=val;
      this.findList();
    },
    findList(){
      this.axios.post(`/book/bookList?current=${this.pageParam.current}&size=${this.pageParam.size}`,this.requestParam).then(res=>{

         this.page=res.data.data;


      })
    },
    findPressList(){
      this.axios.post(`/book/findPressList`).then(res=>{
        this.pressList=res.data;
      })
    },
    daochu(){
      location.href="http://localhost:82/book/daochu";
    },
    findMQList(){
      this.axios.post(`/book/findMQList`).then(res=>{
        this.mqList=res.data;
        // this.mqLen=this.mqList.length;
        // alert(this.mqList[0].msg)
        if(this.mqList.length>0){
          this.dialogxiaoxiVisible=true;
        }
      })
    },
    xiaoxi(){
      this.dialogxiaoxiVisible=true;
    }
  },
  created() {
    this.login=JSON.parse(localStorage.getItem("user"));
    this.findPressList();
    this.findList();
      this.findMQList();
  }
}
</script>

图书列表展示、借阅记录展示后端:

package cn.jiyun.controlller;

import cn.jiyun.commons.Results;
import cn.jiyun.excel.BookExcel;
import cn.jiyun.mapper.BorrowMapper;
import cn.jiyun.mapper.MQMapper;
import cn.jiyun.mapper.PressMapper;
import cn.jiyun.mapper.UserMapper;
import cn.jiyun.pojo.*;
import cn.jiyun.service.BookService;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.api.R;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import jdk.nashorn.internal.parser.TokenStream;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import reactor.core.publisher.Flux;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@CrossOrigin
@RestController
@RequestMapping("book")
public class BookController {
    @Autowired
    BookService bookService;
    @Autowired
    PressMapper pressMapper;
    @Autowired
    RedisTemplate redisTemplate;
    @Autowired
    private BorrowMapper borrowMapper;
    @Autowired
    MQMapper mqMapper;
    @Autowired
    UserMapper userMapper;
    @RequestMapping("bookList")
    public Results bookList(int current, int size, @RequestBody Book book){
        User bookUser = JSONObject.parseObject(redisTemplate.boundValueOps("BookUser").get().toString(), User.class);

        if (bookUser.getType()==2) {
            book.setStatus(2);
        }
        Page<Book> bookPage = bookService.bookList(current, size, book);
        return Results.success(bookPage);
    }

    @RequestMapping("findPressList")
    public List<Press> findPressList(){
        return pressMapper.selectList(null);
    }
    @RequestMapping("updateBook")
    public Results updateBook(@RequestBody Book book){
        return bookService.updateBook(book);
    }
    @RequestMapping("delBookById")
    public Results delBookById(Integer id){
        return bookService.delBookById(id);
    }
    @RequestMapping("jieyue")
    public Results jieyue(Integer id){
        User bookUser = JSONObject.parseObject(redisTemplate.boundValueOps("BookUser").get().toString(), User.class);
        Book book=bookService.findBookById(id);
        Borrow borrow = new Borrow();
        borrow.setBid(book.getId());
        borrow.setUid(bookUser.getId());
//        borrow.setGTime();
        borrow.setJTime(LocalDateTime.now());
        borrowMapper.insert(borrow);
        book.setNumber(book.getNumber()+1);
        book.setStatus(1);
        bookService.updateBook(book);
        return Results.success("借阅"+book.getName()+"成功");
    }
    @RequestMapping("borrowList")
    public Results borrowList(int current,int size){
        User bookUser = JSONObject.parseObject(redisTemplate.boundValueOps("BookUser").get().toString(), User.class);
        Borrow borrow = new Borrow();

        if(bookUser.getType()!=1){
            borrow.setFlag(bookUser.getId());
        }
        Page<Borrow> borrowPage1 = new Page<>(current, size);
        borrowPage1 = borrowMapper.selectFindAll(borrowPage1,borrow);
        return Results.success(borrowPage1);
    }
    @RequestMapping("guiHuan")
    public Results guiHuan(Integer id){

        Borrow borrow = borrowMapper.selectById(id);
        Book book = bookService.findBookById(borrow.getBid());
        book.setStatus(2);
        bookService.updateBook(book);
        borrow.setGTime(LocalDateTime.now());
        borrowMapper.updateById(borrow);
        return Results.success("归还成功");
    }
    @RequestMapping("cuiHuan")
    public Results cuiHuan(Integer id){
        Borrow borrow = borrowMapper.selectById(id);
        Book book = bookService.findBookById(borrow.getBid());
        MQ mq = new MQ();
        User user = userMapper.selectById(borrow.getUid());
        User bookUser = JSONObject.parseObject(redisTemplate.boundValueOps("BookUser").get().toString(), User.class);
        mq.setMsg(user.getUsername()+"你好,您借阅的《"+book.getName()+"》图书请尽快归还");
        mq.setTime(LocalDateTime.now());
        mq.setUid(borrow.getUid());
        mq.setStatus(1);//1未读,2已读
        mqMapper.insert(mq);
        return Results.success("催还成功");
    }
    @RequestMapping("findMQList")
    public List<MQ> mqList(){
        User bookUser = JSONObject.parseObject(redisTemplate.boundValueOps("BookUser").get().toString(), User.class);
        MQ mq = new MQ();
        mq.setUid(bookUser.getId());
        return mqMapper.selectLis(mq);
    }
    @RequestMapping("yidu")
    public Results yidu(Integer id){
        MQ mq = mqMapper.selectById(id);
        mq.setStatus(2);
        mqMapper.updateById(mq);
        return Results.success("");
    }
    @RequestMapping("daochu")
    public void daochu(HttpServletResponse response) throws IOException {
        List<Book> records = bookService.bookList(1, 10000, new Book()).getRecords();
        List<BookExcel> bookExcels = new ArrayList<>();
        for (Book boo : records) {
            BookExcel bookExcel = new BookExcel();
            bookExcel.setId(boo.getId());
            bookExcel.setName(boo.getName());
            bookExcel.setPname(boo.getPname());
            bookExcel.setStatus(boo.getStatus()==1?"借阅中":"未借阅");
            bookExcel.setNumber(boo.getNumber());
            bookExcel.setAuthor(boo.getAuthor());
            bookExcels.add(bookExcel);
        }
        response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("玩家列表.xlsx", "UTF-8"));
        response.setHeader("Connection", "close");
        response.setHeader("Content-Type", "application/octet-stream");
        EasyExcel.write(response.getOutputStream())
                .excelType(ExcelTypeEnum.XLSX)
                .head(BookExcel.class)
                .sheet("图书列表")
                .doWrite(bookExcels);
    }
@RequestMapping("daoru")
public void daoru(MultipartFile file) throws IOException {
//        先得到文件的输入流
//        需要从ecxel中获取数据存入该实体类中\
    System.out.println(file.getSize());
    InputStream inputStream = file.getInputStream();
    EasyExcel.read(inputStream, BookExcel.class, new ReadListener<BookExcel>(){

        @Override
        public void invoke(BookExcel bookExcel, AnalysisContext analysisContext) {
            Book book = new Book();
            book.setName(bookExcel.getName());
            int status=bookExcel.getStatus().equals("借阅中")?1:2;
            LambdaQueryWrapper<Press> qw = new LambdaQueryWrapper<>();
            qw.eq(Press::getName, bookExcel.getPname());
            Press press = pressMapper.selectOne(qw);
            book.setStatus(status);
            book.setPid(press.getId());
            book.setAuthor(bookExcel.getAuthor());
            book.setNumber(bookExcel.getNumber());
            book.setIsDel(0);
            bookService.add(book);
        }
        @Override
        public void doAfterAllAnalysed(AnalysisContext analysisContext) {

        }
    }).excelType(ExcelTypeEnum.XLSX).sheet(0).doRead();


}

}

借阅记录展示前端:

<template>
  <div class="home">
    <el-table
        :data="page.records"
        stripe
        style="width: 100%">
      <el-table-column
          prop="bname"
          label="图书">
      </el-table-column>
      <el-table-column
          prop="username"
          label="借阅人">
      </el-table-column>
      <el-table-column
          prop="jTime"
          label="借阅时间">
      </el-table-column>
      <el-table-column
          prop="gTime"
          label="归还时间">
      </el-table-column>
      <el-table-column label="操作">
        <template slot-scope="scope">
          <el-button
                     type="danger" v-if="loginUser.type==2&&scope.row.gTime==null"
                     size="mini"
                     @click="guiHuan(scope.row.id)">归还
          </el-button>
          <el-button
              type="danger" v-if="loginUser.type==1&&scope.row.gTime==null"
              size="mini"
              @click="cuiHuan(scope.row.id)">催还
          </el-button>
        </template>
      </el-table-column>
    </el-table>
    <!--分页-->
    <el-pagination
        @size-change="handleSizeChange"
        @current-change="handleCurrentChange"
        :current-page="page.current"
        :page-sizes="[4, 6, 8, 10]"
        :page-size="page.size"
        layout="total, sizes, prev, pager, next, jumper"
        :total="page.total">
    </el-pagination>

  </div>
</template>

<script>
export default {
  data(){
    return{
      page:{},
      pageParam:{
        current:1,
        size:3,
      },
      loginUser:{}
    }
  },
  methods:{
    guiHuan(id){
      this.axios.post(`/book/guiHuan?id=`+id).then(res=>{
        this.$message.success(res.data.msg);
        this.borrowList();
      })
    },
    cuiHuan(id){
      this.axios.post(`/book/cuiHuan?id=`+id).then(res=>{
        this.$message.success(res.data.msg);
        this.borrowList();
      })
    },
    handleSizeChange(val) {
      this.pageParam.size=val;
      this.borrowList();
    },
    handleCurrentChange(val) {
      this.pageParam.current=val;
      this.borrowList();
    },
    borrowList(){
      this.axios.post(`/book/borrowList?current=${this.pageParam.current}&size=${this.pageParam.size}`).then(res=>{
        this.page=res.data.data;
      })
    }

  },
  created() {
    this.loginUser = JSON.parse(localStorage.getItem("user"));
    this.borrowList();
  }


}
</script>

以上就是项目的完整代码,希望对每一个在Java道路上努力的人有帮助

  • 8
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

橘猫_A

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值