项目设计-基于SpringBoot和Vue开发的图书管理系统

前言

​ 希望本文对这些即将毕业的学弟学妹们、以及刚入门java不久并即将就业的同学们有所帮助,本文将以最简单的业务模型来讲解企业级的java开发是怎么玩的。

image-20221105140541700

功能设计

image-20221105133028870

领域模型

  • DO(DataObject):与数据库表结构一一对应,通过DAO层向上传输数据源对象

  • BO(BusinessObject):业务对象。由Service层输出的封装业务逻辑的对象

  • VO(View Object):显示层对象,通常是Web向模板渲染引擎层传输的对象

    BO和VO领域模型又分为BoRequest(输入模型)、BoResponse(输出模型)、VoRequest(输入模型)、VoResponse(输出模型)

技术栈

  1. 整体架构:前后端分离项目,前端基于Vue全家桶+Element开发,后端基于SpringBoot框架开发,JDK版本1.8;
  2. 权限管理:基于Spring-Security、Spring-Session 和 Redis实现精细化到按钮级别的分布式权限管理;
  3. 接口风格:接口设计采用restful风格,接口文档基于swagger,每个接口都有详细的接口文档说明;
  4. 数据库:MySQL
  5. 日志采集:基于slf4j和Log4j2实现系统运行日志采集,基于切面实现系统操作日志采集
  6. 依赖管理:使用Maven进行项目多模块依赖管理
  7. 基于Spring Profile实现多环境配置文件管理

系统设计

表结构设计

CREATE TABLE `account` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `passport` varchar(16) NOT NULL COMMENT '账号',
  `name` varchar(6) NOT NULL COMMENT '名称',
  `password` varchar(64) NOT NULL COMMENT '密码',
  `status` int(11) NOT NULL DEFAULT '0' COMMENT '用户状态',
  `role_id` bigint(20) NOT NULL COMMENT '角色',
  `email` varchar(32) NOT NULL COMMENT '邮箱',
  `phone` varchar(16) NOT NULL COMMENT '手机号',
  `address` varchar(64) DEFAULT NULL COMMENT '地址',
  `sex` int(11) NOT NULL DEFAULT '0' COMMENT '性别 0:女;1:男',
  `description` varchar(128) DEFAULT NULL COMMENT '备注',
  `last_login_time` bigint(20) DEFAULT '0' COMMENT '最近登录时间',
  `create_time` bigint(20) NOT NULL DEFAULT '0' COMMENT '创建时间',
  `update_time` bigint(20) DEFAULT '0' COMMENT '更新时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `passport_UNIQUE` (`passport`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='账号表'
CREATE TABLE `role` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `name` varchar(32) NOT NULL COMMENT '角色名称',
  `description` varchar(128) DEFAULT NULL COMMENT '备注',
  `authorities` varchar(1024) NOT NULL COMMENT '权限列表',
  `create_time` bigint(20) NOT NULL DEFAULT '0' COMMENT '创建时间',
  `update_time` bigint(20) DEFAULT '0' COMMENT '更新时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='角色表'
CREATE TABLE `book` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `name` varchar(32) NOT NULL COMMENT '书名',
  `author` varchar(32) NOT NULL COMMENT '作者',
  `publish` varchar(32) NOT NULL COMMENT '出版社',
  `publish_time` bigint(20) DEFAULT '0' COMMENT '出版时间',
  `language` varchar(16) NOT NULL COMMENT '语言',
  `price` decimal(2,0) DEFAULT '0' COMMENT '价格',
  `book_class_id` bigint(20) NOT NULL COMMENT '图书分类',
  `stock` int(11) NOT NULL DEFAULT '0' COMMENT '库存',
  `introduction` text COMMENT '简介',
  `create_time` bigint(20) NOT NULL DEFAULT '0' COMMENT '创建时间',
  `update_time` bigint(20) DEFAULT '0' COMMENT '更新时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8 COMMENT='图书表'
CREATE TABLE `book_class` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `name` varchar(32) NOT NULL COMMENT '分类名',
  `description` varchar(256) DEFAULT NULL COMMENT '备注',
  `create_time` bigint(20) NOT NULL DEFAULT '0' COMMENT '创建时间',
  `update_time` bigint(20) DEFAULT '0' COMMENT '更新时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='图书分类表'
CREATE TABLE `borrow_record` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `book_id` bigint(20) NOT NULL COMMENT '图书',
  `passport` varchar(128) NOT NULL COMMENT '账号',
  `borrow_time` bigint(20) NOT NULL COMMENT '借书时间',
  `expected_back_time` bigint(20) NOT NULL DEFAULT '0' COMMENT '计划还书时间',
  `back_time` bigint(20) DEFAULT NULL COMMENT '还书时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=18 DEFAULT CHARSET=utf8 COMMENT='借阅信息表'
CREATE TABLE `sys_log` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `passport` varchar(128) DEFAULT NULL COMMENT '账号',
  `url` varchar(255) DEFAULT NULL COMMENT '请求URL',
  `method` varchar(255) DEFAULT NULL COMMENT '请求方法',
  `params` varchar(2048) DEFAULT NULL COMMENT '请求参数',
  `ip` varchar(255) DEFAULT NULL COMMENT '请求ip',
  `cost` bigint(20) DEFAULT NULL COMMENT '请求耗时(单位毫秒)',
  `create_time` bigint(20) NOT NULL COMMENT '创建时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='系统日志'

运行效果

系统登录

image-20221105133111709

dashboard

image-20221105133149853

图书分类管理

image-20221105133225153

图书管理

​ 为了让系统更像一个真实的“图书管理系统”,学长写了个脚本,特地从网上爬了10个分类,近600本书,包括书名、作者、简介等信息

​ 这里特地标了“查询、新建、详情、借阅、编辑、删除”几个按钮,因为是admin超级管理员,系统内置的超管权限是拥有所有权限的,实际上这里的每一个按钮都进行权限管理,可以进行自由组合,比如普通读者角色,只需要给读者分配“查询、详细、借阅”三个权限就够了。权限还是非常灵活的。

​ 这里借阅其实也是相对复杂一点的地方,主要是两点:一个是库存小于0的时候不能借阅吧?看下面截图的第四条数据,因为库存是0,所以是不会展示借阅按钮的;另一个是库存只有5本书,但是20个人同时点了借阅,这时候你不能超过库存数吧?也就是你最多只能借出去5本书才对,这里采用的是数据库乐观锁的简单方式实现。

image-20221105133257874

借阅

​ 借阅必须填写计划归还时间,最多是借阅一个月(参数校验做得还算很细的,这里控件只能选一个月内的时间,另外多说一句,前端页面和后端接口,几乎每个字段都做了参数校验,正常公司里也是这么做的)。同一本书一次只能借阅一本,只有归还后才能继续借阅这本书。

image-20221105133344744

借阅管理

​ 借阅管理分为三个tab页,“所有借阅”tab页是可以查询到所有历史借阅信息的,“待还借阅”指的是还未归还的借阅记录,“逾期借阅”指的是当前时间大于预计归还时间的借阅记录。这里逾期后系统是没做额外惩罚逻辑处理的,实际上管理员在逾期用户还书的时候可以线下罚款,或者一个季度内超过三次逾期将不能继续借书,或者在逾期前一天给用户发邮件等,思路有很多,这一块个人觉得不是重点,大家有好的点子可以自由发挥~~~

image-20221105133424172

还书

​ 读者还书时将书籍当面交给图书管理员,图书管理确认后,在借阅记录的待还借阅tab页,通过读者的账号搜索,然后点击还书操作,还书后这本书的借阅记录会从待还借阅tab页移除,同时这本书的库存会加1,到这里其实核心逻辑就走完了。(至于新增图书分类、新增书籍、下架书籍等操作,这都是管理员的活,对应的无法就是新增和编辑、删除按钮)

image-20221105133506908

image-20221105133524443

image-20221105133545796

image-20221105133616380

日志管理

​ 日志管理默认是开给管理员的,在系统中的所有操作都会被记录,在系统出现异常时也便于管理员进行问题排查。

image-20221105133642727

用户管理

​ 默认也是只有管理员拥有用户管理菜单的权限,可以新建/编辑用户、分配用户角色、禁用/启用等操作

image-20221105133704530

编辑用户信息

image-20221105133728836

角色管理

​ 默认也是只有管理员拥有角色管理菜单的权限,这里的权限是细粒度到按钮权限的,每个按钮都可以进行权限管理,假如给读者只分配了书籍的“查询”权限,但是这个读者也是个程序员,他想通过接口请求直接访问图书修改接口,这时候后端是会权限校验的,返回“未授权”的错误码,然后前端根据“未授权”错误码会重定向到一个403页面(这也是为什么说只有前端校验是不安全的,后端也必须得校验,这在实际企业里开发也是这样的,还没有实际开发经验的学弟学妹拿个小本本记一记,哈哈哈)

image-20221105133747260

image-20221105133803683

普通读者登录

​ 系统默认会创建两个角色,一个是超管角色,另一个则是普通读者角色(当然角色大家可以按前面说的自定义)。普通读者登录的菜单以及菜单中的按钮权限都会少很多,截图如下:

image-20221105133918086

我的借阅

image-20221105133934808

个人信息修改

image-20221105133951204

密码修改

​ 管理员创建完用户之后的默认密码是“123456”,用户可以登录系统自己修改密码

image-20221105134006414

权限设计

​ 权限基于security和spring-session实现。权限可以分为认证和授权,认证其实就是登录,用户登录时会进行账号密码的校验,校验成功后会,会把session存入redis中。授权指的是用户是否拥有访问后端资源的权限,每个新用户在创建后都会分配角色,角色其实就是一个权限集合,这里的权限可以理解为访问后端一个个接口(资源)的权限。

​ 这里权限设计的非常灵活,细粒度到按钮级别,比如图书的新增、删除、修改、查询、借阅动作,普通读者可能就只有图书的查询和借阅权限,图书管理员则拥有新增、删除、修改的权限。普通用户访问图书管理模块则只展示查询和借阅按钮,即使通过接口直接访问后端的修改或者删除接口,后端也会返回授权失败错误,因为后端每个需要权限的接口都打了权限标识,只有拥有资源权限用户才能访问。

​ 比如下面的图书修改接口,只有拥有“BOOK_UPDATE”这个权限标识的用户才能访问这个接口,否则返回“未授权”的错误。

@PutMapping("/{id}")
@PreAuthorize("hasAuthority(T(com.senior.book.console.api.security.Authority).BOOK_UPDATE.name())")
    public Result<Boolean> update(@PathVariable("id") Long id, @Valid @RequestBody BookUpdateVoRequest request) {
        
}

日志方案

​ 日志采用lombok注解+slf4j+log4j2的实现方案,基于profile实现了多环境的日志配置,因为不同环境的日志打印策略是不一样,比如开发环境我可能需要打印到console控制台,需要debug级别的日志以便于本地开发调试,测试环境可能就需要打印到日志文件里,线上环境可能需要打印到文件的同时将日志发送到kafka然后收集到es中,这样当线上部署了多台机器后我们查日志不用一台一台机器去查日志了,因为都收集到es了,我们只需要登录kibana去搜索,这样就非常方便。这里说到的kafka+es+kibana这样一套日志解决方案也是目前互联网公司比较常用的一套解决方案。如果你动手能力够强,你可以本地搭一套kafka、es、kibana,然后只需要在配置文件中加入几行配置就实现了这么一套企业级的日志解决方案(默认是输出到日志文件)。

下面是部分关键配置,如果要配置kafka,只需要在标签中配置配置即可

    <?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN"  xmlns:xi="http://www.w3.org/2001/XInclude">
    <Properties>
        <Property name="LOG_FILE">system.log</Property>
        <Property name="LOG_PATH">./logs</Property>
        <Property name="PID">????</Property>
        <Property name="LOG_EXCEPTION_CONVERSION_WORD">%xwEx</Property>
        <Property name="LOG_LEVEL_PATTERN">%5p</Property>
        <Property name="LOG_DATE_FORMAT_PATTERN">yyyy-MM-dd HH:mm:ss.SSS</Property>
        <Property name="CONSOLE_LOG_PATTERN">%clr{%d{${LOG_DATE_FORMAT_PATTERN}}}{faint} %clr{${LOG_LEVEL_PATTERN}} %clr{${sys:PID}}{magenta} %clr{---}{faint} %clr{[%15.15t]}{faint} %clr{%-40.40c{1.}}{cyan} %clr{:}{faint} %m%n${sys:LOG_EXCEPTION_CONVERSION_WORD}
        </Property>
        <Property name="FILE_LOG_PATTERN">%d{${LOG_DATE_FORMAT_PATTERN}} ${LOG_LEVEL_PATTERN} ${sys:PID} --- [%t] %-40.40c{1.}:%L : %m%n${sys:LOG_EXCEPTION_CONVERSION_WORD}
        </Property>
    </Properties>
    <Appenders>
        <xi:include href="log4j2/file-appender.xml"/>
    </Appenders>
    <Loggers>
        <logger name="com.senior.book" level="info"/>
        <Root level="info">
            <AppenderRef ref="FileAppender"/>
        </Root>
    </Loggers>
</Configuration>

服务监控

​ 朋友们,马上2021年了,别再让你的服务光着屁屁在服务器上“罗.奔”了

​ 服务监控基于 Actuator + Prometheus + Grafana 实现,代码侵入很小,只需要在pom中加入依赖。数据大盘Dashboard可以自己设置,也可以去Dashboard市场下载你想要的模板,总之,这块完全是看动手能力,大家自己玩吧~~~

		<!--服务监控-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>io.micrometer</groupId>
            <artifactId>micrometer-registry-prometheus</artifactId>
        </dependency>
  • 2
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值