博客系統項目之實現邏輯與參考文檔

有關項目的介紹及相關說明請查看博客:blogs博客系統項目介紹


該博客系統實現了一些常用的博客功能。對於這些功能的實現邏輯大概是這樣的:

一、用戶認證及權限管理

這個功能是基於SpringSecurity框架實現的,SpringSecurity本身就是負責認證和授權,它爲我們提供了很多API支持,有一些核心類以及規範。

首先,我們定義了用戶(User)這個實體,實現了Spring Security中的UserDetails這個接口。UserDetails是Spring Security中的一個核心接口,其中定義了一些可以獲取用戶名、密碼、權限與認證信息相關的方法。Spring Security內部有一些的UserDetils的實現類。但這裏我們對其進行擴展,因爲我們的用戶類,它不僅包含了這些認證的信息,還有一些如郵箱、頭像等。同時我們還需要將該實體映射到數據庫中,便於我們直接使用Spring Data JPA來進行Dao層操作。所以定義這樣一個實體,並添加了一些JPA的註解。其中定義了一個權限字段

    @ManyToMany(cascade = CascadeType.DETACH, fetch = FetchType.EAGER)
    @JoinTable(name = "user_authority", joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"),
            inverseJoinColumns = @JoinColumn(name = "authority_id", referencedColumnName = "id"))
    private List<Authority> authorities;

這個字段就是用來說明該用戶具有的權限。Authority代表權限類,實現了GrantedAuthority接口,該實體包含了id和name,name就是我們權限名,如ROLE_ADMIN或者ROLE_USER。我們需要去實現getAuthority方法。然後我們在WebSecurityConfigurerAdapter中配置了formlogin,在認證的時候通過表單去進行登錄。Spring Security會先去調用userDetailsService中的loadUserByUsername查出UserDetails,通過用戶名就可以獲得我們的用戶信息,這些用戶信息包含了用戶名,密碼、郵箱、權限等等。它可以查出User的所有屬性,包含定義的這種主外鍵關聯的信息。然後將用戶信息寫入到Security的上下文中,即SecurityContext,具體來說最終還是以session進行存儲。然後sessionid以cookie形式寫入瀏覽器。這樣用戶在登錄後,就可以進行一些後續操作。security也可以根據sessionid從上下文中獲取到seesion,結合我們的代碼做一些權限的判斷。

Spring Security提供了一些很方便的註解,如@PreAuthorize("authentication.name.equals(#username)")標記在Controller上,當該Controller被調用的時候,會先取出上下文session中的用戶名與當前接收到的用戶名參數值是否一致,一致纔可以調用。通過這種方式,就可以實現一些僅用戶本人才能執行的操作,如編輯刪除博客等。

以後臺管理來說,管理員新增用戶時,會爲用戶分配權限,這裏只有博主或者管理員兩種。頁面會將用戶信息包括權限名傳入後臺,最終會被存入庫中,我們在配置權限的時候,會通過hasRole這個方法去分配權限。

.antMatchers("/admins/**").hasRole("ADMIN")

上面就代表“/admin/”下的所有資源,僅ROLE_ADMIN權限的用戶操作。注意我們的權限名必須符合Spring Security的規範,也就ROLE_ADMIN這種命名。

當然Spring Security還提供了一些其他API,如rememberMe用來達到記住用戶信息的作用,這樣用戶在下次進入系統後,無須再次登錄操作,系統會自動登錄。其實就是在退出系統時,session是不會銷燬的。另外還有一些對CSRF的防範,會話管理等等。

二、博客的相關功能實現

定義了一個博客實體類,這個博客實體類,包含了標題、摘要,內容,標籤、評論以及點贊等等。

首先內容分爲了兩種字段,一個是HTML內容進行存儲,一個是Markdown格式的內容,當用戶編輯完成後點擊保存時,前臺頁面將參數傳入後臺,後臺會通過markdwon jar的一個api將Markdown格式的內容轉成HTML內容。以兩種形式存儲的目的在於,當用戶再次進行編輯的時候,將Markdwn內容展示,閱覽的話,將HTML內容展示。

對於標籤來水,一篇博客,它可能有多個標籤,所以這個字段是集合類型。我們在存儲以及展示的時候都是集合操作。對於首頁中的熱門標籤來說,會額外定義一個es中存儲的博客實體。我們會將數據庫的對應博客實體轉成es博客實體,存入es中,其中標籤會被存儲並分詞索引。這樣就可以快速地去查出前30個出現次數最多的標籤。

對於評論來說,它也是一個集合類型,因爲一篇博客同樣可能有多條評論。但是評論會被定義成一個額外的實體,它包含了這條評論的id,評論內容,以及userid。userid與user中id是一對一主外鍵關係。而博客blogid與評論id又是一對多的關係。需要明確JPA對一對一是會建立主外鍵,對於一對多或者多對多都是建立中間表。

我們會在blog實體中維護這樣一個評論集合,當需要展示一篇博客的時候,會查出這個集合,其實就是通過blog的id去評論表中查出blogid=id的所有評論記錄。對於添加和刪除評論來說既要維護這個集合,還要維護評論數,如在刪除評論的時候,我需要先從blog實體的評論集合中remove該評論記錄,然後再評論數-1,最後save。

注意JPA的操作是很方便的,如我想新增一條評論,如果是MyBatis的話,我可能需要先在comment表中新增一個一條記錄,然後再blog_comment中間表中再新增一條,寫兩句sql。如果使用JPA,我們只需要將你需要添加的需要添加的comment實體信息設到blog實體上,然後save即可。由jpa幫我們去完成插入的操作。

        Comment comment = new Comment(user, commentContent);
        originalBlog.addComment(comment);
        saveBlog(originalBlog);

但需要注意的是,如果刪除評論的話,按照我們上面重新save的思路的話,jpa只能幫我們刪除blog_comment中間表的記錄,並不能刪除comment中的記錄(新增會在comment中插入,是因爲需要先建立comment與user的關係,然後再建立comment與blog的關係。而在未刪除blog的情況下,save就是update操作,它只能更新掉blog與comment的關係,它並不知道comment與user的關係,所以它不會刪除comment中的記錄,但我們邏輯上是需要刪除的)所以還需要額外刪除comment中的記錄。


下面列出相關技術或功能實現上可以參考的文檔(博客)

Spring Security

初始Spring Security(W3C的教程):https://www.w3cschool.cn/springsecurity/cdz11ihv.html

初步理解Spring Security並實踐(一篇質量很好的博客,有助於理解):https://www.jianshu.com/p/e6655328b211

Spring Security Remember-Me功能(闡述的很清楚):https://elim.iteye.com/blog/2163997

Thymeleaf

Thymeleaf官方文檔:https://www.thymeleaf.org/doc/tutorials/2.1/usingthymeleaf.html

Thymeleaf 3學習筆記(一篇SF上的好文):https://segmentfault.com/a/1190000009903821

H2

H2 Database 教程(一篇git上的博文):https://github.com/waylau/h2-database-doc

MongoDB

MongoDB教程(非常全面且通俗理解的教程):http://www.runoob.com/mongodb/mongodb-tutorial.html

基於 MongoDB 及 Spring Boot 的文件服務器的實現(該項目中使用到的開源文件服務器實現邏輯):https://www.imooc.com/article/18443

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章