畢業(yè)設計-圖書管理系統(tǒng)

圖書管理系統(tǒng)

前言

? 馬上年底了,對于即將畢業(yè)的學弟學妹來說,過完年應該是最忙的時候,既要為3-4月份的校園春季招聘做準備,同時又要準備畢業(yè)設計。希望本文對這些即將畢業(yè)的學弟學妹們、以及剛入門java不久并即將就業(yè)的同學們有所幫助,本文將以最簡單的業(yè)務模型來講解企業(yè)級的java開發(fā)是怎么玩的。

? (想要源碼的同學請私信我。這里打個廣告,學長多年bat工作經(jīng)驗,常年負責校招和社招面試,有興趣的同學可以私信我,我可以提供簡歷輔導和內(nèi)推~~~)

工程架構

應用分層

上面的分層架構摘自阿里巴巴java開發(fā)手冊,我對此做了一些調整,實際分層結構如下:

image-20201226112801771

領域模型

  • DO(DataObject):與數(shù)據(jù)庫表結構一一對應,通過DAO層向上傳輸數(shù)據(jù)源對象

  • BO(BusinessObject):業(yè)務對象。由Service層輸出的封裝業(yè)務邏輯的對象

  • VO(View Object):顯示層對象,通常是Web向模板渲染引擎層傳輸?shù)膶ο?/p>

    BO和VO領域模型又分為BoRequest(輸入模型)、BoResponse(輸出模型)、VoRequest(輸入模型)、VoResponse(輸出模型)

技術棧

前端:vue + element

后端:jdk1.8 + springboot + redis + mysql

系統(tǒng)設計

表結構設計

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 '用戶狀態(tài)',
  `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 '創(chuàng)建時間',
  `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 '創(chuàng)建時間',
  `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 '創(chuàng)建時間',
  `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 '創(chuàng)建時間',
  `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 '請求參數(shù)',
  `ip` varchar(255) DEFAULT NULL COMMENT '請求ip',
  `cost` bigint(20) DEFAULT NULL COMMENT '請求耗時(單位毫秒)',
  `create_time` bigint(20) NOT NULL COMMENT '創(chuàng)建時間',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='系統(tǒng)日志'

接口設計

? 整個項目接口采用的目前互聯(lián)網(wǎng)比較流行的restful風格設計,每個接口、每個參數(shù)都有詳細的文檔說明。因為企業(yè)中開發(fā)必然是團隊協(xié)作,必然前后端分離的開發(fā)模式,你得先把接口定義出來,然后前端可以和后端同步開發(fā)。還有一種就是對外提供接口,比如你們隔壁團隊也想調用你這個服務的接口,但是你兩排期是同一周,這時候你得先把接口定義出來給人家,然后大家同步開發(fā),開發(fā)完了之后再進行聯(lián)調。

運行效果

系統(tǒng)登錄

image

dashboard

圖書分類管理

圖書管理

? 為了讓系統(tǒng)更像一個真實的“圖書管理系統(tǒng)”,學長寫了個腳本,特地從網(wǎng)上爬了10個分類,近600本書,包括書名、作者、簡介等信息

? 這里特地標了“查詢、新建、詳情、借閱、編輯、刪除”幾個按鈕,因為是admin超級管理員,系統(tǒng)內(nèi)置的超管權限是擁有所有權限的,實際上這里的每一個按鈕都進行權限管理,可以進行自由組合,比如普通讀者角色,只需要給讀者分配“查詢、詳細、借閱”三個權限就夠了。權限還是非常靈活的。

? 這里借閱其實也是相對復雜一點的地方,主要是兩點:一個是庫存小于0的時候不能借閱吧?看下面截圖的第四條數(shù)據(jù),因為庫存是0,所以是不會展示借閱按鈕的;另一個是庫存只有5本書,但是20個人同時點了借閱,這時候你不能超過庫存數(shù)吧?也就是你最多只能借出去5本書才對,這里采用的是數(shù)據(jù)庫樂觀鎖的簡單方式實現(xiàn)。

借閱

? 借閱必須填寫計劃歸還時間,最多是借閱一個月(參數(shù)校驗做得還算很細的,這里控件只能選一個月內(nèi)的時間,另外多說一句,前端頁面和后端接口,幾乎每個字段都做了參數(shù)校驗,正常公司里也是這么做的)。同一本書一次只能借閱一本,只有歸還后才能繼續(xù)借閱這本書。

借閱管理

? 借閱管理分為三個tab頁,“所有借閱”tab頁是可以查詢到所有歷史借閱信息的,“待還借閱”指的是還未歸還的借閱記錄,“逾期借閱”指的是當前時間大于預計歸還時間的借閱記錄。這里逾期后系統(tǒng)是沒做額外懲罰邏輯處理的,實際上管理員在逾期用戶還書的時候可以線下罰款,或者一個季度內(nèi)超過三次逾期將不能繼續(xù)借書,或者在逾期前一天給用戶發(fā)郵件等,思路有很多,這一塊個人覺得不是重點,大家有好的點子可以自由發(fā)揮~~~

還書

? 讀者還書時將書籍當面交給圖書管理員,圖書管理確認后,在借閱記錄的待還借閱tab頁,通過讀者的賬號搜索,然后點擊還書操作,還書后這本書的借閱記錄會從待還借閱tab頁移除,同時這本書的庫存會加1,到這里其實核心邏輯就走完了。(至于新增圖書分類、新增書籍、下架書籍等操作,這都是管理員的活,對應的無法就是新增和編輯、刪除按鈕)

日志管理

? 日志管理默認是開給管理員的,在系統(tǒng)中的所有操作都會被記錄,在系統(tǒng)出現(xiàn)異常時也便于管理員進行問題排查。

用戶管理

? 默認也是只有管理員擁有用戶管理菜單的權限,可以新建/編輯用戶、分配用戶角色、禁用/啟用等操作

編輯用戶信息

角色管理

? 默認也是只有管理員擁有角色管理菜單的權限,這里的權限是細粒度到按鈕權限的,每個按鈕都可以進行權限管理,假如給讀者只分配了書籍的“查詢”權限,但是這個讀者也是個程序員,他想通過接口請求直接訪問圖書修改接口,這時候后端是會權限校驗的,返回“未授權”的錯誤碼,然后前端根據(jù)“未授權”錯誤碼會重定向到一個403頁面(這也是為什么說只有前端校驗是不安全的,后端也必須得校驗,這在實際企業(yè)里開發(fā)也是這樣的,還沒有實際開發(fā)經(jīng)驗的學弟學妹拿個小本本記一記,哈哈哈)

普通讀者登錄

? 系統(tǒng)默認會創(chuàng)建兩個角色,一個是超管角色,另一個則是普通讀者角色(當然角色大家可以按前面說的自定義)。普通讀者登錄的菜單以及菜單中的按鈕權限都會少很多,截圖如下:

我的借閱

個人信息修改

密碼修改

? 管理員創(chuàng)建完用戶之后的默認密碼是“123456”,用戶可以登錄系統(tǒng)自己修改密碼

權限設計

? 權限基于security和spring-session實現(xiàn)。權限可以分為認證和授權,認證其實就是登錄,用戶登錄時會進行賬號密碼的校驗,校驗成功后會,會把session存入redis中。授權指的是用戶是否擁有訪問后端資源的權限,每個新用戶在創(chuàng)建后都會分配角色,角色其實就是一個權限集合,這里的權限可以理解為訪問后端一個個接口(資源)的權限。

? 這里權限設計的非常靈活,細粒度到按鈕級別,比如圖書的新增、刪除、修改、查詢、借閱動作,普通讀者可能就只有圖書的查詢和借閱權限,圖書管理員則擁有新增、刪除、修改的權限。普通用戶訪問圖書管理模塊則只展示查詢和借閱按鈕,即使通過接口直接訪問后端的修改或者刪除接口,后端也會返回授權失敗錯誤,因為后端每個需要權限的接口都打了權限標識,只有擁有資源權限用戶才能訪問。

? 比如下面的圖書修改接口,只有擁有“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的實現(xiàn)方案,基于profile實現(xiàn)了多環(huán)境的日志配置,因為不同環(huán)境的日志打印策略是不一樣,比如開發(fā)環(huán)境我可能需要打印到console控制臺,需要debug級別的日志以便于本地開發(fā)調試,測試環(huán)境可能就需要打印到日志文件里,線上環(huán)境可能需要打印到文件的同時將日志發(fā)送到kafka然后收集到es中,這樣當線上部署了多臺機器后我們查日志不用一臺一臺機器去查日志了,因為都收集到es了,我們只需要登錄kibana去搜索,這樣就非常方便。這里說到的kafka+es+kibana這樣一套日志解決方案也是目前互聯(lián)網(wǎng)公司比較常用的一套解決方案。如果你動手能力夠強,你可以本地搭一套kafka、es、kibana,然后只需要在配置文件中加入幾行配置就實現(xiàn)了這么一套企業(yè)級的日志解決方案(默認是輸出到日志文件)。

下面是部分關鍵配置,如果要配置kafka,只需要在<Appenders>標簽中配置<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>

服務監(jiān)控

? 朋友們,馬上2021年了,別再讓你的服務光著屁屁在服務器上“羅.奔”了

? 服務監(jiān)控基于 Actuator + Prometheus + Grafana 實現(xiàn),代碼侵入很小,只需要在pom中加入依賴。數(shù)據(jù)大盤Dashboard可以自己設置,也可以去Dashboard市場下載你想要的模板,總之,這塊完全是看動手能力,大家自己玩吧~~~

        <!--服務監(jiān)控-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>io.micrometer</groupId>
            <artifactId>micrometer-registry-prometheus</artifactId>
        </dependency>
最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容