【课程设计/毕业设计】Java图书借阅管理系统源码+开发文档

2024-06-25 1429阅读

项目介绍

一直想做一款图书借阅管理系统,看了很多优秀的开源项目但是发现没有合适的。于是利用空闲休息时间开始自己写了一套管理系统。学习过程中遇到问题可以咨询留言。

在线体验

http://book.gitapp.cn/

源码地址

https://github.com/geeeeeeeek/java_book

界面预览

【课程设计/毕业设计】Java图书借阅管理系统源码+开发文档

【课程设计/毕业设计】Java图书借阅管理系统源码+开发文档

【课程设计/毕业设计】Java图书借阅管理系统源码+开发文档

功能介绍

系统分为后台和前台两部分。

后台的主要功能:

  • 图书管理:管理系统可以录入、修改和查询图书的基本信息,如图书名称、isbn、简介、备注等。
  • 类型管理:系统可以管理图书的类型信息,包括类型的名称等。
  • 标签管理:管理标签录入、修改和查询标签的信息。
  • 评论管理:管理和浏览整个网站的评论信息。
  • 用户管理:管理和浏览网站的用户信息,可以新增、编辑和删除用户。
  • 统计分析:系统可以根据图书的活动数据和会员参与度进行统计和分析,帮助管理员了解整个系统的状况。
  • 消息管理:图书管理员可以在系统上发布消息,整个网站的用户都能收到。
  • 系统信息:管理员可以查看系统的基本信息,包括系统名称、服务器信息、内存信息、cpu信息、软件信息等。

    前台的主要功能:

    • 注册登录:用户通过注册和登录后,才能使用网站。
    • 门户浏览:用户进入首页后,可以浏览图书列表信息,包括最新、最热、推荐。
    • 智能推荐:详情页右侧的热门推荐。
    • 用户中心:包括用户基本资料修改、用户邮箱推送、消息。
    • 我的借阅:包括我借阅的图书的信息。
    • 模糊搜索:顶部搜索功能,支持模糊搜索图书信息。
    • 图书评论:详情页下侧用户可以评论图书。

      开发环境

      • 后端: Java 1.8 + SpringBoot + MyBatis
      • 前端: Javascript + Vue
      • 数据库:MySQL 5.7
      • 开发平台:Idea 2021 + vscode
      • 运行环境:Windows 10/11

        关键技术

        • 前端技术栈 ES6、vue、vuex、vue-router、vue-cli、axios、antd
        • 后端技术栈 SpringBoot、MyBatis、Maven

          后端技术

          Springboot框架

          Spring Boot是一款开箱即用框架,提供各种默认配置来简化项目配置。让我们的Spring应用变的更轻量化、更快的入门。 在主程序执行main函数就可以运行。你也可以打包你的应用为jar并通过使用java -jar来运行你的Web应用。它遵循"约定优先于配置"的原则, 使用SpringBoot只需很少的配置,大部分的时候直接使用默认的配置即可。同时可以与Spring Cloud的微服务无缝结合。

          优点:

          • 使编码变得简单: 推荐使用注解。
          • 使配置变得简单: 自动配置、快速集成新技术能力 没有冗余代码生成和XML配置的要求
          • 使部署变得简单: 内嵌Tomcat、Jetty、Undertow等web容器,无需以war包形式部署
          • 使监控变得简单: 提供运行时的应用监控
          • 使集成变得简单: 对主流开发框架的无配置集成。
          • 使开发变得简单: 极大地提高了开发快速构建项目、部署效率。

            前端技术

            • npm:node.js的包管理工具,用于统一管理我们前端项目中需要用到的包、插件、工具、命令等,便于开发和维护。
            • ES6:Javascript的新版本,ECMAScript6的简称。利用ES6我们可以简化我们的JS代码,同时利用其提供的强大功能来快速实现JS逻辑。
            • vue-cli:Vue的脚手架工具,用于自动生成Vue项目的目录及文件。
            • vue-router: Vue提供的前端路由工具,利用其我们实现页面的路由控制,局部刷新及按需加载,构建单页应用,实现前后端分离。
            • vuex:Vue提供的状态管理工具,用于统一管理我们项目中各种数据的交互和重用,存储我们需要用到数据对象。
            • Ant-design:基于MVVM框架Vue开源出来的一套前端ui组件。

              运行步骤

              后端运行步骤

              (1) 下载代码后,使用IntelliJ IDEA打开server目录

              (2) 配置application.yml文件,配置数据库DB_NAME和BASE_LOCATION

              (3) 安装mysql 5.7数据库后,创建数据库,创建SQL如下:

              CREATE DATABASE IF NOT EXISTS java_book DEFAULT CHARSET utf8 COLLATE utf8_general_ci
              

              (4) 恢复sql数据。在mysql下依次执行如下命令:

              mysql> use java_book;
              mysql> source D:/xxx/xxx/java_book.sql;
              

              (5) 启动后端服务:点击IDEA顶部run按钮

              前端运行步骤

              (1) 安装node 16

              (2) cmd进入web目录下,安装依赖,执行:

              npm install 
              

              (3) 运行项目

              npm run dev
              

              代码结构

              后端结构

              com.gk.study  
              ├── common            // 工具类
              │       └── APIResponse                   // 返回体
              │       └── ResponseCode                  // 状态码
              ├── controller         // 业务接口
              │       └── ThingController               // 图书业务
              │       └── ClassificationController      // 分类
              │       └── TagController                 // 标签
              │       └── CommentController             // 评论
              │       └── UserController                // 用户
              │       └── NoticeController              // 通知
              │       └── OpLogController               // 日志
              ├── entity            // 实体类
              ├── interceptor       // 拦截器
              ├── mapper            // 数据库映射
              ├── service           // 服务实现
              ├── utils             // 辅助代码
              

              前端结构

              ├── build                      // 构建相关  
              ├── public                     // 公共文件
              │   ├── favicon.ico            // favicon图标
              │   └── index.html             // html模板
              ├── src                        // 源代码
              │   ├── api                    // 所有请求
              │   ├── assets                 // 主题 字体等静态资源
              │   ├── router                 // 路由
              │   ├── store                  // 全局 store管理
              │   ├── utils                  // 全局公用方法
              │   ├── views                  // view界面
              │   ├── App.vue                // 入口页面
              │   ├── main.js                // 入口 加载组件 初始化等
              │   └── settings.js            // 系统配置
              ├── .eslintignore              // 忽略语法检查
              ├── .eslintrc.js               // eslint 配置项
              ├── .gitignore                 // git 忽略项
              ├── babel.config.js            // babel.config.js
              ├── package.json               // package.json
              └── vite.config.js             // vue配置
              

              数据库设计

              需求分析

              在图书管理系统中,需要存储和管理图书信息、评论信息、分类信息、标签信息、用户信息、通知信息、日志信息。

              实体设计如下:

              • 图书(thing)
              • 分类(classification)
              • 标签(tag)
              • 用户(user)
              • 评价(comment)
              • 日志(log)
              • 通知(notice)

                关系如下:

                • 用户可以借阅多个图书
                • 图书可以被多个用户借阅
                • 一个图书有一个分类
                • 一个分类可以对应多个图书
                • 一个图书有多个标签
                • 一个标签可以对应多个图书

                  数据表设计如下:

                  // 图书
                  Table book {
                      book_id int [pk]
                      classification_id int [ref: > C.classification_id]
                      tag_id int [ref:  tag.tag_id]
                      title varchar // 图书名称
                      original_title varchar // 原书名
                      cover varchar // 封面
                      author varchar
                      translator varchar
                      press varchar
                      page_count int
                      price varchar
                      isbn varchar
                      pub_date varchar
                      online_time varchar
                      status int
                      repertory int
                      score varchar
                      layout varchar // 装帧
                      description text
                      create_time datetime
                      pv int
                      wish_count int
                      recommend_count int
                      wish int [ref:  user.user_id]
                      collect int [ref:  user.user_id]
                   }
                   // 分类
                   Table classification as C {
                     classification_id int [pk]
                     pid int
                     title varchar
                     create_time datetime
                   }
                   // 标签
                   Table tag {
                     tag_id int [pk]
                     title varchar
                     create_time datetime
                   }
                   // 评论
                   Table comment {
                     comment_id int [pk]
                     content varchar
                     user_id int [ref: > user.user_id]
                     book_id int [ref: > book.book_id]
                     comment_time datetime
                     like_count int
                   }
                   // 用户
                   Table user {
                     user_id int [pk]
                     role varchar // 1管理员 2普通用户 3演示帐号
                     status int // 0正常 1封号
                     username varchar
                     password varchar
                     nickname varchar
                     avatar varchar
                     description varchar
                     wish int [ref:  book.book_id]
                     email varchar
                     mobile varchar
                     score int // 积分
                     push_email varchar // 推送邮箱
                     push_switch int  // 推送开关
                     token varchar
                     admin_token varchar
                   }
                   
                   // 登录日志
                   Table login_log {
                     log_id int [pk]
                     username varchar
                     ip varchar
                     log_time datetime
                   }
                   
                   // 操作日志
                   Table op_log {
                     id int [pk]
                     re_ip varchar
                     re_time datetime
                     re_url varchar
                     re_method varchar
                     re_content varchar
                     access_time varchar
                   }
                   
                   // 异常日志
                   Table error_log {
                     id int [pk]
                     ip varchar
                     method varchar
                     content varchar
                     log_time varchar
                   }
                   // 借阅表
                   Table borrow {
                     borrow_id int [pk]
                     user_id int [ref: > user.user_id]
                     book_id int [ref: > book.book_id]
                     status varchar // 1借出 2已还
                     borrow_time datetime
                     expect_time datetime // 应还时间
                     delayed boolean // 是否点击延期了 1已延期
                   }
                   // 通知表
                   Table notice {
                     id int [pk]
                     content varchar
                     create_time datetime
                   }
                   
                   
                   
                  

                  开发过程

                  无论是图书管理、用户管理、标签管理、分类管理、评价管理、日志管理、消息管理等功能都是基于springboot+vue框架开发的,开发流程是:

                  • 第一步:编写实体类
                  • 第二步:编写mapper数据库映射
                  • 第三步:编写service层
                  • 第四步:编写controller层
                  • 第五步:编写界面和API

                    下面用图书管理功能来演绎这个流程,其它的管理功能都是这个流程。

                    第一步:编写实体类

                    在server的entity文件夹中,新建Thing.java文件。并写入如下代码:

                    @Data
                    @TableName("b_thing")
                    public class Thing implements Serializable {
                        @TableId(value = "id",type = IdType.AUTO)
                        public Long id;
                        @TableField
                        public String title;
                        @TableField
                        public String cover;
                        @TableField
                        public String description;
                        @TableField
                        public String status;
                        @TableField
                        public String createTime;
                        @TableField
                        public String mobile;
                        @TableField
                        public String email;
                        @TableField
                        public String location;
                        @TableField
                        public String pv;
                        @TableField
                        public String recommendCount;
                        @TableField
                        public String wishCount;
                        @TableField
                        public String collectCount;
                        @TableField
                        public Long classificationId;
                        @TableField(exist = false)
                        public List tags; // 标签
                        @TableField(exist = false)
                        public MultipartFile imageFile;
                        @TableField
                        public String userId;
                    }
                    

                    第二步:编写mapper数据库映射

                    在server的mapper文件夹下,新建ThingMapper.java文件,并写入代码:

                    // Mapper是mybatis里面的技术,用于操作mysql中的数据
                    @Mapper
                    public interface ThingMapper extends BaseMapper {
                    }
                    

                    第三步:编写service层

                    在server的service文件夹中,新建ThingService.java代码,并写入代码:

                    public interface ThingService {
                        List getThingList(String keyword, String sort, String c, String tag); // 查
                        void createThing(Thing thing);  // 增
                        void deleteThing(String id);    // 删
                        void updateThing(Thing thing);  // 改
                        Thing getThingById(String id);
                        void addWishCount(String thingId);
                        void addCollectCount(String thingId);
                        List getUserThing(String userId);
                    }
                    

                    并在impl中编写它的实现类ThingServiceImpl.java

                    第四步: 编写controller层

                    在server的controller文件夹新建ThingController.java文件,实现增删改查接口,并编写代码:

                    @RestController
                    @RequestMapping("/thing")
                    public class ThingController {
                        private final static Logger logger = LoggerFactory.getLogger(ThingController.class);
                        @Autowired
                        ThingService service;
                        @Value("${File.uploadPath}")
                        private String uploadPath;
                        @RequestMapping(value = "/list", method = RequestMethod.GET)
                        public APIResponse list(String keyword, String sort, String c, String tag){
                            List list =  service.getThingList(keyword, sort, c, tag);
                            return new APIResponse(ResponeCode.SUCCESS, "查询成功", list);
                        }
                        @RequestMapping(value = "/detail", method = RequestMethod.GET)
                        public APIResponse detail(String id){
                            Thing thing =  service.getThingById(id);
                            return new APIResponse(ResponeCode.SUCCESS, "查询成功", thing);
                        }
                        @Access(level = AccessLevel.ADMIN)
                        @RequestMapping(value = "/create", method = RequestMethod.POST)
                        @Transactional
                        public APIResponse create(Thing thing) throws IOException {
                            String url = saveThing(thing);
                            if(!StringUtils.isEmpty(url)) {
                                thing.cover = url;
                            }
                            service.createThing(thing);
                            return new APIResponse(ResponeCode.SUCCESS, "创建成功");
                        }
                        @Access(level = AccessLevel.ADMIN)
                        @RequestMapping(value = "/delete", method = RequestMethod.POST)
                        public APIResponse delete(String ids){
                            System.out.println("ids===" + ids);
                            // 批量删除
                            String[] arr = ids.split(",");
                            for (String id : arr) {
                                service.deleteThing(id);
                            }
                            return new APIResponse(ResponeCode.SUCCESS, "删除成功");
                        }
                        @Access(level = AccessLevel.ADMIN)
                        @RequestMapping(value = "/update", method = RequestMethod.POST)
                        @Transactional
                        public APIResponse update(Thing thing) throws IOException {
                            System.out.println(thing);
                            String url = saveThing(thing);
                            if(!StringUtils.isEmpty(url)) {
                                thing.cover = url;
                            }
                            service.updateThing(thing);
                            return new APIResponse(ResponeCode.SUCCESS, "更新成功");
                        }
                        public String saveThing(Thing thing) throws IOException {
                            MultipartFile file = thing.getImageFile();
                            String newFileName = null;
                            if(file !=null && !file.isEmpty()) {
                                // 存文件
                                String oldFileName = file.getOriginalFilename();
                                String randomStr = UUID.randomUUID().toString();
                                newFileName = randomStr + oldFileName.substring(oldFileName.lastIndexOf("."));
                                String filePath = uploadPath + File.separator + "image" + File.separator + newFileName;
                                File destFile = new File(filePath);
                                if(!destFile.getParentFile().exists()){
                                    destFile.getParentFile().mkdirs();
                                }
                                file.transferTo(destFile);
                            }
                            if(!StringUtils.isEmpty(newFileName)) {
                                thing.cover = newFileName;
                            }
                            return newFileName;
                        }
                        @RequestMapping(value = "/listUserThing", method = RequestMethod.GET)
                        public APIResponse listUserThing(String userId){
                            List list =  service.getUserThing(userId);
                            return new APIResponse(ResponeCode.SUCCESS, "查询成功", list);
                        }
                    }
                    

                    第五步:编写界面和API

                    打开前端web工程,在views文件夹下新建thing.vue文件,并编写代码:

                      
                        
                        
                          
                            
                              新增
                              批量删除
                              
                            
                          
                           (data.page = current),
                              showSizeChanger: false,
                              showTotal: (total) => `共${total}条数据`,
                            }"
                          >
                            
                              
                                
                                  编辑
                                  
                                  
                                    删除
                                  
                                
                              
                            
                          
                        
                        
                        
                          
                            
                              
                                
                                  
                                    
                                      
                                    
                                  
                                  
                                    
                                      
                                    
                                  
                                  
                                    
                                      
                                        
                                          {{ item.title }}
                                        
                                      
                                    
                                  
                                  
                                    
                                      
                                        

                    请选择要上传的封面图片

                    平装 精装 其它 上架 下架 import { FormInstance, message, SelectProps } from 'ant-design-vue'; import { createApi, listApi, updateApi, deleteApi } from '/@/api/thing'; import {listApi as listClassificationApi} from '/@/api/classification' import {listApi as listTagApi} from '/@/api/tag' import {BASE_URL} from "/@/store/constants"; import { FileImageOutlined } from '@ant-design/icons-vue'; const columns = reactive([ { title: '序号', dataIndex: 'index', key: 'index', width: 60 }, { title: '名称', dataIndex: 'title', key: 'title' }, { title: '作者', dataIndex: 'author', key: 'author' }, { title: 'isbn', dataIndex: 'isbn', key: 'isbn' }, { title: '出版社', dataIndex: 'press', key: 'press' }, { title: '装帧', dataIndex: 'layout', key: 'layout' }, { title: '库存', dataIndex: 'repertory', key: 'repertory' }, { title: '简介', dataIndex: 'description', key: 'description', customRender: ({ text, record, index, column }) => text ? text.substring(0, 10) + '...' : '--' }, { title: '状态', dataIndex: 'status', key: 'status', customRender: ({ text, record, index, column }) => text === '0' ? '上架' : '下架' }, { title: '操作', dataIndex: 'action', key: 'operation', align: 'center', fixed: 'right', width: 140, }, ]); const beforeUpload = (file: File) => { // 改文件名 const fileName = new Date().getTime().toString() + '.' + file.type.substring(6); const copyFile = new File([file], fileName); console.log(copyFile); modal.form.imageFile = copyFile; return false; }; // 文件列表 const fileList = ref([]); // 页面数据 const data = reactive({ dataList: [], loading: false, keyword: '', selectedRowKeys: [] as any[], pageSize: 10, page: 1, }); // 弹窗数据源 const modal = reactive({ visile: false, editFlag: false, title: '', cData: [], tagData: [{}], form: { id: undefined, title: undefined, classificationId: undefined, tags: [], repertory: undefined, author: undefined, translator: undefined, isbn: undefined, press: undefined, price: undefined, pubDate: undefined, pageCount: undefined, status: undefined, cover: undefined, coverUrl: undefined, imageFile: undefined }, rules: { title: [{ required: true, message: '请输入名称', trigger: 'change' }], classificationId: [{ required: true, message: '请选择分类', trigger: 'change' }], repertory: [{ required: true, message: '请输入库存', trigger: 'change' }], price: [{ required: true, message: '请输入定价', trigger: 'change' }], status: [{ required: true, message: '请选择状态', trigger: 'change' }] }, }); const myform = ref(); onMounted(() => { getDataList(); getCDataList(); getTagDataList(); }); const getDataList = () => { data.loading = true; listApi({ keyword: data.keyword, }) .then((res) => { data.loading = false; console.log(res); res.data.forEach((item: any, index: any) => { item.index = index + 1; }); data.dataList = res.data; }) .catch((err) => { data.loading = false; console.log(err); }); } const getCDataList = () => { listClassificationApi({}).then(res => { modal.cData = res.data }) } const getTagDataList = ()=> { listTagApi({}).then(res => { res.data.forEach((item, index) => { item.index = index + 1 }) modal.tagData = res.data }) } const onSearchChange = (e: Event) => { data.keyword = e?.target?.value; console.log(data.keyword); }; const onSearch = () => { getDataList(); }; const rowSelection = ref({ onChange: (selectedRowKeys: (string | number)[], selectedRows: DataItem[]) => { console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows); data.selectedRowKeys = selectedRowKeys; }, }); const handleAdd = () => { resetModal(); modal.visile = true; modal.editFlag = false; modal.title = '新增'; // 重置 for (const key in modal.form) { modal.form[key] = undefined; } modal.form.cover = undefined }; const handleEdit = (record: any) => { resetModal(); modal.visile = true; modal.editFlag = true; modal.title = '编辑'; // 重置 for (const key in modal.form) { modal.form[key] = undefined; } for (const key in record) { if(record[key]) { modal.form[key] = record[key]; } } if(modal.form.cover) { modal.form.coverUrl = BASE_URL + '/api/staticfiles/image/' + modal.form.cover modal.form.cover = undefined } }; const confirmDelete = (record: any) => { console.log('delete', record); deleteApi({ ids: record.id }) .then((res) => { getDataList(); }) .catch((err) => { message.error(err.msg || '操作失败'); }); }; const handleBatchDelete = () => { console.log(data.selectedRowKeys); if (data.selectedRowKeys.length { message.success('删除成功'); data.selectedRowKeys = []; getDataList(); }) .catch((err) => { message.error(err.msg || '操作失败'); }); }; const handleOk = () => { myform.value ?.validate() .then(() => { const formData = new FormData(); if(modal.editFlag) { formData.append('id', modal.form.id) } formData.append('title', modal.form.title) if (modal.form.classificationId) { formData.append('classificationId', modal.form.classificationId) } if (modal.form.tags) { modal.form.tags.forEach(function (value) { if(value){ formData.append('tags[]', value) } }) } if (modal.form.imageFile) { formData.append('imageFile', modal.form.imageFile) } formData.append('description', modal.form.description || '') formData.append('author', modal.form.author || '') formData.append('translator', modal.form.translator || '') formData.append('isbn', modal.form.isbn || '') formData.append('layout', modal.form.layout || '') formData.append('press', modal.form.press || '') formData.append('pubDate', modal.form.pubDate || '') formData.append('pageCount', modal.form.pageCount || '') if (modal.form.repertory >= 0) { formData.append('repertory', modal.form.repertory) } if (modal.form.status) { formData.append('status', modal.form.status) } if (modal.editFlag) { updateApi(formData) .then((res) => { hideModal(); getDataList(); }) .catch((err) => { console.log(err); message.error(err.msg || '操作失败'); }); } else { createApi(formData) .then((res) => { hideModal(); getDataList(); }) .catch((err) => { console.log(err); message.error(err.msg || '操作失败'); }); } }) .catch((err) => { console.log('不能为空'); }); }; const handleCancel = () => { hideModal(); }; // 恢复表单初始状态 const resetModal = () => { myform.value?.resetFields(); fileList.value = [] }; // 关闭弹窗 const hideModal = () => { modal.visile = false; }; .page-view { min-height: 100%; background: #fff; padding: 24px; display: flex; flex-direction: column; } .table-operations { margin-bottom: 16px; text-align: right; } .table-operations > button { margin-right: 8px; }

                    这就是图书管理功能的实现流程,其它的功能管理实现一模一样的。按照这个流程编写即可。

                    重要模块实现

                    分页实现

                    基于ant-design框架的a-table的分页插件。

                    // 分页变量
                      const data = reactive({
                        dataList: [],
                        loading: false,
                        keyword: '',
                        selectedRowKeys: [] as any[],
                        pageSize: 10,
                        page: 1,
                      });
                      
                    // 分页插件
                    :pagination="{
                              size: 'default',
                              current: data.page,
                              pageSize: data.pageSize,
                              onChange: (current) => (data.page = current),
                              showSizeChanger: false,
                              showTotal: (total) => `共${total}条数据`,
                            }"
                    

                    请求工具实现

                    前端的请求工具是基于axios开发的,位于utils的http文件夹中。封装了request请求和拦截器。

                    const service: AxiosInstance = axios.create({
                      // baseURL: import.meta.env.BASE_URL + '',
                      baseURL: BASE_URL + '',
                      timeout: 15000,
                    });
                    // axios实例拦截请求
                    service.interceptors.request.use(
                      (config: InternalAxiosRequestConfig) => {
                        config.headers.ADMINTOKEN = localStorage.getItem(ADMIN_USER_TOKEN);
                        config.headers.TOKEN = localStorage.getItem(USER_TOKEN);
                        return config;
                      },
                      (error: AxiosError) => {
                        return Promise.reject(error);
                      },
                    );
                    // axios实例拦截响应
                    service.interceptors.response.use(
                      (response: AxiosResponse) => {
                        if (response.status == 200) {
                          if (response.data.code == 0 || response.data.code == 200) {
                            return response;
                          } else {
                            return Promise.reject(response.data);
                          }
                        } else {
                          return Promise.reject(response.data);
                        }
                      },
                      // 请求失败
                      (error: any) => {
                        console.log(error.response.status);
                        if (error.response.status == 404) {
                          // todo
                        } else if (error.response.status == 403) {
                          // todo
                        }
                        return Promise.reject(error);
                      },
                    );
                    

                    权限控制模块

                    权限控制使用了Access和AccessLevel注解实现的,通过设置访问常量实现访问权限的控制,

                    // 关键代码
                    public enum AccessLevel {
                        LOGIN(1, "all"), // 登录用户
                        DEMO(2, "demo"), // 演示账号
                        ADMIN(3, "admin"), // 管理员
                        SUPER(4, "super"); // 超级管理员
                    

                    每次使用的时候,可以在controller接口上面加入相应的注解来实现权限控制,例如下面加入了@Access(level = AccessLevel.ADMIN)

                    注解,表明当前接口只能管理员调用。

                        @Access(level = AccessLevel.ADMIN)
                        @RequestMapping(value = "/update", method = RequestMethod.POST)
                        @Transactional
                        public APIResponse update(Thing thing) throws IOException {
                            System.out.println(thing);
                            String url = saveThing(thing);
                            if(!StringUtils.isEmpty(url)) {
                                thing.cover = url;
                            }
                            service.updateThing(thing);
                            return new APIResponse(ResponeCode.SUCCESS, "更新成功");
                        }
                    

                    底层原理实现是通过实现HandlerInterceptorAdapter接口来运行的。参见interceptor文件夹下的AccessInterceptor.java

                    @Component
                    public class AccessInterceptor extends HandlerInterceptorAdapter {
                        private Logger logger = LoggerFactory.getLogger(AccessInterceptor.class);
                        private static OpLogService service;
                        private static UserService userService;
                        @Autowired
                        public void setOpLogService( OpLogService service) {
                            // 为解决先@Component 后@Autowired失效的方案
                            AccessInterceptor.service = service;
                        }
                        @Autowired
                        public void setUserService( UserService userService) {
                            // 为解决先@Component 后@Autowired失效的方案
                            AccessInterceptor.userService = userService;
                        }
                        @Override
                        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
                                throws Exception {
                                // 权限判断
                        }   
                    

                    路由模块实现

                    前端的路由是基于vue-router框架实现的,路由文件位于src的rooter的root.js文件中。预览如下:

                      {
                        path: '/admin',
                        name: 'admin',
                        redirect: '/admin/thing',
                        component: () => import('/@/views/admin/main.vue'),
                        children: [
                          { path: 'overview', name: 'overview', component: () => import('/@/views/admin/overview.vue') },
                          { path: 'order', name: 'order', component: () => import('/@/views/admin/order.vue') },
                          { path: 'thing', name: 'thing', component: () => import('/@/views/admin/thing.vue') },
                          { path: 'comment', name: 'comment', component: () => import('/@/views/admin/comment.vue') },
                          { path: 'user', name: 'user', component: () => import('/@/views/admin/user.vue') },
                          { path: 'classification', name: 'classification', component: () => import('/@/views/admin/classification.vue') },
                          { path: 'tag', name: 'tag', component: () => import('/@/views/admin/tag.vue') },
                          { path: 'ad', name: 'ad', component: () => import('/@/views/admin/ad.vue') },
                          { path: 'notice', name: 'notice', component: () => import('/@/views/admin/notice.vue') },
                          { path: 'loginLog', name: 'loginLog', component: () => import('/@/views/admin/login-log.vue') },
                          { path: 'opLog', name: 'opLog', component: () => import('/@/views/admin/op-log.vue') },
                          { path: 'errorLog', name: 'errorLog', component: () => import('/@/views/admin/error-log.vue') },
                          { path: 'sysInfo', name: 'sysInfo', component: () => import('/@/views/admin/sys-info.vue') },
                        ]
                      },
                    

                    常见问题

                    • 数据库版本有要求吗?

                      需要mysql 5.7以上

                      • 前端 npm install 失败怎么办?

                        使用国内镜像安装,设置命令为:

                        npm config set registry https://registry.npm.taobao.org
                        
                        • 提示"演示账号无法操作",怎么办?

                          将用户的权限提高,修改b_user表的role字段

                          • 如何更换后端请求地址

                            修改store文件夹下的constants.js文件中的BASE_URL,改成你自己的后端地址

                            • 如何新增页面

                              在views文件夹下创建新的vue文件,写入界面代码,然后在router的root.js中添加路由即可。

VPS购买请点击我

免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们,邮箱:ciyunidc@ciyunshuju.com。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!

目录[+]