SpringBoot技術棧搭建個人博客【項目準備】
前言:很早之前就想要寫一個自己的博客了,趁著現在學校安排的實習有很多的空檔,決定把它給做出來,也順便完成實習的任務(搞一個項目出來...)
需求分析
總體目標:設計一套自適應/簡潔/美觀/易於文章管理發布的一個屬於我個人的博客,最後一頁能展示我個人的簡歷,因為大三快結束了馬上就該去找工作了...哦忘了,最重要的還是要支持Markdown才行,因為已經習慣了...
前端需求分析
首先,前端的頁面要求是:
- ①簡潔/美觀——個人很喜歡像Mac那樣的簡潔風,越簡單越好,當然也得好看;
- ②最好是單頁面——單頁面的目的一方面是為了簡潔,另一方面也是為了實現起來比較簡單;
- ③自適應——至少能適配常見的手機分辨率吧,我可不希望自己的博客存在顯示差異性的問題;
然後,思考了一下可能出現的頁面:
1)首頁:
- 最新的文章——我可以搞一個輪播之類的東西用來顯示最新的幾篇博文;
- 頂部導航——導航欄可以要有,而且可以提出來搞成通用的;
- 聯系方式——首頁最好再有能一眼找到我的聯系方式,比如簡書/博客園/微信公眾號之類的;
- 時間——摁,時間;
2)文章頁:
- 分類欄——左側應該有文章的分類,記得要有一個全部文章;
- 文章列表——分類欄的右邊就應該是該分類下的所有文章;
- 分頁欄——考慮到現在我的Java Web分欄下的文章已經有那麽多了,還是有必要搞個分頁;
3)簡歷頁:
這是預留的頁面,到時候用來顯示個人的簡歷;
4)關於頁:
用來介紹項目的搭建編寫過程,還有使用的技術棧啊之類的,然後留下個人的聯系方式,Nice;
5)留言頁:
因為是個人的博客,所以我並不想要限制看官們留言的權利,我希望他們能自己能定義用於顯示的用戶名,但是需要填寫一個Email,不然搞得我不能回復,那搞個啥...當然也可以不留Email,也就是不希望得到回復唄(那可能有些留言會讓我難受死吧..思考...)...
後臺需求分析:
最初的思考是這樣的:
後來一想,文章置頂這個都給忘了...然後發現其實有一個很關鍵的問題就是Markdown的文章應該怎樣保存?一開始還是想要保存為.md文件保存在服務器的硬盤上的,但想想直接保存在數據庫裏也不錯,省的麻煩,而且我很明確一點的是:我並不會直接在博客上寫Markdown,因為有許許多多成熟的產品能讓我寫的舒心的多,我沒必要去搞這麽麻煩復雜繁瑣,而且不一定好,所以我只需要用博客來展示我寫的Markdown格式的博文
順著這樣的思路,我通常寫文都是先在簡書上寫好的,並且簡書有一個特點是所有的圖片,不管是已經發布的文章還是沒有發布的私人文章,都能通過地址取得,可以利用這一點讓簡書當個圖床,誒又少弄了一部分代碼,然後分析分析著就把需求搞成下面這樣了:
1)博文管理:
這個比較常規,就不說了;
2)網站數據統計:
作為網站的擁有者和設計者,我當然希望能希望知道這些數據了,然後單獨作為擁有者來說,最好再分為日訪問量/月訪問量/總訪問量這樣子顯示出來,再搞搞樣式,簡直不要太爽;
3)緩存管理:
圖片就沒緩存了,因為保存文章內容我需要保存md源碼,所以可能需要在Redis裏緩存最近常訪問的文章的md轉HTML後渲染好的HTML源碼;
4)系統設置:
網站標題可以改呀,然後導航欄的名字也可以弄弄呀,其實這個也可以不用去搞,只是以防有時候心情不好給一整搗鼓可能心情就好了,hhhhh....;
5)留言管理:
有一些流氓留言可以刪掉,最近學習到的比較好的方法是讓該條數據的狀態為置為0,而不是直接刪除該條數據,這個設計數據庫的時候就需要多設計一個字段,也可以通過用戶留下的Email地址進行回復,最好搞一個自動通知,完美;
表結構設計
通過需求分析,然後嚴格按照《阿裏巴巴Java開發手冊》(下面所說的規範均來自於此)反復分析了很多遍,最終確定了如下的幾張表:
然後來具體說一下各個表:
1)日誌表(sys_log):
CREATE TABLE `sys_log` (
`id` bigint(40) NOT NULL AUTO_INCREMENT COMMENT ‘主鍵‘,
`ip` varchar(20) NOT NULL DEFAULT ‘‘ COMMENT ‘操作地址的IP‘,
`create_by` datetime NOT NULL COMMENT ‘操作時間‘,
`remark` varchar(255) NOT NULL DEFAULT ‘‘ COMMENT ‘操作內容‘,
`operate_url` varchar(50) NOT NULL DEFAULT ‘‘ COMMENT ‘操作的訪問地址‘,
`operate_by` varchar(20) DEFAULT ‘‘ COMMENT ‘操作的瀏覽器‘,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
這張表就是拿來保存日誌,用來記錄每一個用戶訪問了哪些地址,使用了什麽樣的瀏覽器,操作內容可以作為一個保留字段,如果以後想要監控用戶行為,那也是可以的~
這裏首先遵守的規範是(下面雷同則不再重復贅述):
- 第五章第一節第2條(強制)——表名、字段名必須使用小寫字母或數字,禁止出現數字開頭,禁止兩個下劃線中間只出現數字。數據庫字段名的修改代價很大,因為無法進行預發布,所以字段名稱需要慎重考慮;
- 第五章第一節第3條(強制)——表名不使用復數名詞;
- 第五章第一節第10條(推薦)——表的命名最好加上“業務名稱_表的作用”
想要拿出來跟大家討論的一則規範是:
- 第五章第9條(強制)——表必備三個字段:id(unsigned bigint自增),gmt_create(date_time),gmt_modified(date_time)
像如上設計的日誌表,它插入進去了就不會再更新了,而且對於我這個系統也很大概率不會有趣操作這個表的可能,那麽對於這樣不會更新和操作的表,gmt_modified這個字段還有必要存在嗎?
emmm..事實上我問了孤盡大大本人,他回答的簡潔有力:“要的,以備不時之需;”然而原諒我還是沒有聽話,hhhhh,另外一點我想說的是,我忘了是在哪裏看到的了,但是像gmt_create這樣的字段最好設計成create_by這樣,字段本身就是很好的註釋,摁,就喜歡這樣滿滿的細節...
2)瀏覽量表(sys_view):
CREATE TABLE `sys_view` (
`id` bigint(40) NOT NULL AUTO_INCREMENT,
`ip` varchar(20) NOT NULL COMMENT ‘訪問IP‘,
`create_by` datetime NOT NULL COMMENT ‘訪問時間‘,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
這張表用於保存每一次訪問主頁的記錄,我想的是每訪問主頁就記錄增加一條數據,簡單同時也增加訪問量嘛,hhhhh,也是不會更新的一張表,所以沒modifield_by字段;
3)留言/評論表(tbl_message)
CREATE TABLE `tbl_message` (
`id` bigint(40) NOT NULL AUTO_INCREMENT COMMENT ‘主鍵‘,
`content` varchar(200) NOT NULL DEFAULT ‘‘ COMMENT ‘留言/評論內容‘,
`create_by` datetime NOT NULL COMMENT ‘創建日期‘,
`email` varchar(20) NOT NULL DEFAULT ‘‘ COMMENT ‘郵箱,用於回復消息‘,
`name` varchar(20) NOT NULL DEFAULT ‘‘ COMMENT ‘用戶自己定義的名稱‘,
`ip` varchar(20) NOT NULL DEFAULT ‘‘ COMMENT ‘留言/評論IP‘,
`is_effective` tinyint(1) NOT NULL DEFAULT ‘1‘ COMMENT ‘是否有效,默認為1為有效,0為無效‘,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT=‘因為message分為兩種,一種是留言,一種是評論,這裏搞成一張表是因為它們幾乎是擁有相同的字段,我覺得沒必要分成兩張表來進行維護‘;
這是評論/留言表,因為考慮到留言和評論有幾乎相同的字段,所以給弄成了一張表,這張表同樣的不需要更新沒有modifield_by字段,這裏遵守的規範是:
- 第五章第一節第1條(強制)——表達是與否概念的字段,必須使用 is_xxx 的方式命名,數據類型是 unsigned tinyint(1表示是,0表示否)
- 第五章第一節第15條(參考)——設置合適的字段存儲長度,不但可以節約數據庫表控件和索引存儲,更重要的事能夠提升檢索速度;
4)分類信息表(tbl_sort_info):
CREATE TABLE `tbl_sort_info` (
`id` bigint(40) NOT NULL AUTO_INCREMENT,
`name` varchar(20) NOT NULL COMMENT ‘分類名稱‘,
`number` tinyint(10) NOT NULL DEFAULT ‘0‘ COMMENT ‘該分類下的文章數量‘,
`create_by` datetime NOT NULL COMMENT ‘分類創建時間‘,
`modified_by` datetime NOT NULL COMMENT ‘分類修改時間‘,
`is_effective` tinyint(1) NOT NULL DEFAULT ‘1‘ COMMENT ‘是否有效,默認為1有效,為0無效‘,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
這張表是文章的分類,一開始都忘記設計了....
5)文章信息表(tbl_article_info):
CREATE TABLE `tbl_article_info` (
`id` bigint(40) NOT NULL AUTO_INCREMENT COMMENT ‘主鍵‘,
`title` varchar(50) NOT NULL DEFAULT ‘‘ COMMENT ‘文章標題‘,
`summary` varchar(300) NOT NULL DEFAULT ‘‘ COMMENT ‘文章簡介,默認100個漢字以內‘,
`is_top` tinyint(1) NOT NULL DEFAULT ‘0‘ COMMENT ‘文章是否置頂,0為否,1為是‘,
`traffic` int(10) NOT NULL DEFAULT ‘0‘ COMMENT ‘文章訪問量‘,
`create_by` datetime NOT NULL COMMENT ‘創建時間‘,
`modified_by` datetime NOT NULL COMMENT ‘修改日期‘,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
這是文章信息表,都是一些基礎常用的字段就不再多做解釋了
6)文章內容表(tbl_article_content):
CREATE TABLE `tbl_article_content` (
`id` bigint(40) NOT NULL AUTO_INCREMENT,
`content` text NOT NULL,
`article_id` bigint(40) NOT NULL COMMENT ‘對應文章ID‘,
`create_by` datetime NOT NULL COMMENT ‘創建時間‘,
`modifield_by` datetime NOT NULL COMMENT ‘更新時間‘,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
這是文章內容表,我們並沒有直接把內容字段設計在文章信息表裏,而是單獨建了一個表用來保存文章的內容,然後使用主鍵來關聯,我們這裏遵守的規範是:
- 第五章第一節第8條(強制)——varchar是可變長字符串,不預先分配存儲空間,長度不要超過5000個字符。如果存儲長度大於此值,則應定義字段類型為text,獨立出來一張表,用主鍵來對應,避免影響其他字段的索引效率;
- 第五章第三節第6條(強制)——不得使用外鍵與級聯,一切外鍵概念必須在應用層解決;
我試過我現在最長的一篇文章長度大概能存儲8W長度的varchar,所以我就給單獨建一個表分離出來了,使用text類型來保存文章的md源碼
7)文章評論表(tbl_article_message):
CREATE TABLE `tbl_article_message` (
`id` bigint(40) NOT NULL AUTO_INCREMENT,
`article_id` bigint(40) NOT NULL COMMENT ‘文章ID‘,
`message_id` bigint(40) NOT NULL COMMENT ‘對應的留言ID‘,
`create_by` datetime NOT NULL COMMENT ‘創建時間‘,
`is_effective` tinyint(1) NOT NULL DEFAULT ‘1‘ COMMENT ‘是否有效,默認為1有效,置0無效‘,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
這其實是一個關聯表,關聯了文章和tbl_message表,用於專門存儲某個文章下的評論信息
8)文章分類表(tbl_article_sort):
CREATE TABLE `tbl_article_sort` (
`id` bigint(40) NOT NULL AUTO_INCREMENT,
`sort_id` bigint(40) NOT NULL COMMENT ‘分類id‘,
`article_id` bigint(40) NOT NULL COMMENT ‘文章id‘,
`create_by` datetime NOT NULL COMMENT ‘創建時間‘,
`modified_by` datetime NOT NULL COMMENT ‘更新時間‘,
`is_effective` tinyint(1) DEFAULT ‘1‘ COMMENT ‘表示當前數據是否有效,默認為1有效,0則無效‘,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
同樣是一張關聯表,連接了文章和分類,並且同一篇文章能屬於多個分類;
9)文章題圖表(tbl_article_picture):
CREATE TABLE `tbl_article_picture` (
`id` bigint(40) NOT NULL AUTO_INCREMENT,
`article_id` bigint(40) NOT NULL COMMENT ‘對應文章id‘,
`picture_url` varchar(100) NOT NULL DEFAULT ‘‘ COMMENT ‘圖片url‘,
`create_by` datetime NOT NULL COMMENT ‘創建時間‘,
`modified_by` datetime NOT NULL COMMENT ‘更新時間‘,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT=‘這張表用來保存題圖url,每一篇文章都應該有題圖‘;
這個是保存每一篇文章的題圖,每一篇文章都因該有題圖;
原型設計
事實上,我是直接先去找的原型,去參考了一下大概我需要做成什麽樣子...
前端原型參考
在這裏先給大家推薦一個設計網站吧,找素材啊之類的還挺方便的:
站酷:http://www.zcool.com.cn/
所以我在裏面找到了我想要的前端原型,大概就像這個樣子:
1)首頁:
2)博客頁:
3)博文詳情頁:
4)博文列表頁:
不能再酷了..
後端原型參考
emmmm...大概就像這樣了吧,具體的樣式可以到時候再調...
總體是酷的就行!
項目搭建
先來介紹一下這次想要使用的一些技術:
- SpringBoot / Spring 來編寫後臺
- Vue 來寫頁面,準備拋棄一下JSP,雖然現在Vue還啥都不懂,學唄
- MyBatis 用於ORM,喜歡這玩意兒的逆向工程
- RESTful API / JSON 交互
Redis 可能還會使用這個來緩存一下md轉換之後的html源碼
SpringBoot 工程搭建
SpringBoot 項目搭建過程就不再贅述了,不熟悉的童鞋戳這邊:https://www.jianshu.com/p/70963ab49f8c,這裏就簡單給一下配置信息:
後臺肯定是需要加安全驗證的,要簡單點我可以搞一個攔截器來簡單弄弄,也可以用現有的安全框架,這裏暫時就不加入這方面的東西了,把基本的弄進來就OK,然後它默認加入的東西不能夠支持我們的業務,所以還需要手動添加進一些包:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.wmyskxz</groupId>
<artifactId>blog</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>blog</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--MyBatis-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<!--MyBatis逆向工程-->
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.6</version>
</dependency>
<!--SpringBoot測試支持-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--MySQL-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!--SpringBoot熱部署-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional> <!-- 這個需要為 true 熱部署才有效 -->
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
熱部署還是要的呀,然後再在【resrouces】下新建一個【banner.txt】文件,修改一下SpringBoot啟動的提示信息:
__ __ __
/\ \ __/\ \ /\ \
\ \ \/\ \ \ \ ___ ___ __ __ ____\ \ \/‘\ __ _ ____
\ \ \ \ \ \ \ /‘ __` __`\ /\ \/\ \ /‘,__\\ \ , < /\ \/‘\/\_ ,`\
\ \ \_/ \_\ \/\ \/\ \/\ \\ \ \_\ \ /\__, `\\ \ \\`\ \/> </\/_/ /_
\ `\___x___/\ \_\ \_\ \_\\/`____ \\/\____/ \ \_\ \_\/\_/\_\ /\____ ‘\/__//__/ \/_/\/_/\/_/ `/___/> \\/___/ \/_/\/_/\//\/_/ \/____/
/\___/
\/__/
弄弄結構,最後整個項目的目錄看起來大概是這個樣子:
下面對這些目錄進行一些簡要的說明:
- controller:控制器
- dao:實際上這個包可以改名叫mapper,因為裏面放的應該是MyBatis逆向工程自動生成之後的mapper類,還是叫dao吧,傳統...
- entity:實體類,還會有一些MyBatis生成的example
- generator:MyBatis逆向工程生成類
- interceptor:SpringBoot 攔截器
- service:Service層,裏面還有一層impl目錄
- util:一些工具類可以放在裏面
- mapper:用於存放MyBatis逆向工程生成的.xml映射文件
- static:這個目錄存放一些靜態文件,簡單了解了一下Vue的前後端分離,前臺文件以後也需要放在這個目錄下面
然後我使用application.yml文件代替了application.properties,這個東西結構清晰一點兒,反正用哪個都無所謂,配置好就OK了:
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/blog?characterEncoding=UTF-8
username: root
password: 123456
driver-class-name: com.mysql.jdbc.Driver
#Druid連接池配置相關
druid:
# 初始大小,最大,最小
initial-size: 5
min-idle: 5
max-active: 20
# 配置獲取連接等待超時的時間
max-wait: 60000
# 配置間隔多久才進行一次檢測,檢測需要關閉的空閑連接,單位是毫秒
time-between-eviction-runs-millis: 60000
# 配置一個連接在池中最小生存的時間,單位是毫秒
min-evictable-idle-time-millis: 300000
不需要檢測數據庫,不要整這麽復雜,不過倒是需要給數據庫密碼加個密,明文的配置實在不安全,但是現在先不搞了;
MyBatis 逆向工程
使用過MyBatis逆向工程的朋友都應該知道,這東西有個BUG,就是重復生成的時候它並不會覆蓋掉原來的內容(特指xml映射文件),而是會在後面重新生成一遍,這有點兒頭疼,所以首先需要解決這個問題:
首先在【util】包下新建一個【OverIsMergeablePlugin】工具類:
package cn.wmyskxz.blog.util;
import org.mybatis.generator.api.GeneratedXmlFile;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.PluginAdapter;
import java.lang.reflect.Field;
import java.util.List;
/**
* 避免MyBatiis重復生成的工具類
*
* @author:wmyskxz
* @create:2018-06-14-上午 9:50
*/
public class OverIsMergeablePlugin extends PluginAdapter {
@Override
public boolean validate(List<String> warnings) {
return true;
}
@Override
public boolean sqlMapGenerated(GeneratedXmlFile sqlMap, IntrospectedTable introspectedTable) {
try {
Field field = sqlMap.getClass().getDeclaredField("isMergeable");
field.setAccessible(true);
field.setBoolean(sqlMap, false);
} catch (Exception e) {
e.printStackTrace();
}
return true;
}
}
然後在【generatorConfig.xml】中配置上該工具類:
<plugin type="cn.wmyskxz.blog.util.OverIsMergeablePlugin"/>
好的這樣就搞定了,我們就正式開始我們的逆向工程:
1)編寫generatorConfig.xml逆向工程配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<context id="DB2Tables" targetRuntime="MyBatis3">
<!--避免生成重復代碼的插件-->
<plugin type="cn.wmyskxz.blog.util.OverIsMergeablePlugin"/>
<!--是否在代碼中顯示註釋-->
<commentGenerator>
<property name="suppressDate" value="true"/>
<property name="suppressAllComments" value="true"/>
</commentGenerator>
<!--數據庫鏈接地址賬號密碼-->
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://127.0.0.1:3306/blog?characterEncoding=UTF-8" userId="root"
password="123456">
</jdbcConnection>
<!--生成pojo類存放位置-->
<javaModelGenerator targetPackage="cn.wmyskxz.blog.entity" targetProject="src/main/java">
<property name="enableSubPackages" value="true"/>
<property name="trimStrings" value="true"/>
</javaModelGenerator>
<!--生成xml映射文件存放位置-->
<sqlMapGenerator targetPackage="mapper" targetProject="src/main/resources">
<property name="enableSubPackages" value="true"/>
</sqlMapGenerator>
<!--生成mapper類存放位置-->
<javaClientGenerator type="XMLMAPPER" targetPackage="cn.wmyskxz.blog.dao" targetProject="src/main/java">
<property name="enableSubPackages" value="true"/>
</javaClientGenerator>
<!--生成對應表及類名-->
<table tableName="sys_log" domainObjectName="SysLog" enableCountByExample="false"
enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="true"
selectByExampleQueryId="false">
<!--使用自增長鍵-->
<property name="my.isgen.usekeys" value="true"/>
<!--使用數據庫中實際的字段名作為生成的實體類的屬性-->
<property name="useActualColumnNames" value="true"/>
<generatedKey column="id" sqlStatement="JDBC"/>
</table>
<table tableName="sys_view" domainObjectName="SysView" enableCountByExample="false"
enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="true"
selectByExampleQueryId="false">
<property name="my.isgen.usekeys" value="true"/>
<property name="useActualColumnNames" value="true"/>
<generatedKey column="id" sqlStatement="JDBC"/>
</table>
<table tableName="tbl_article_content" domainObjectName="ArticleContent" enableCountByExample="false"
enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="true"
selectByExampleQueryId="false">
<property name="my.isgen.usekeys" value="true"/>
<property name="useActualColumnNames" value="true"/>
<generatedKey column="id" sqlStatement="JDBC"/>
</table>
<table tableName="tbl_article_info" domainObjectName="ArticleInfo" enableCountByExample="false"
enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="true"
selectByExampleQueryId="false">
<property name="my.isgen.usekeys" value="true"/>
<property name="useActualColumnNames" value="true"/>
<generatedKey column="id" sqlStatement="JDBC"/>
</table>
<table tableName="tbl_article_message" domainObjectName="ArticleMessage" enableCountByExample="false"
enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="true"
selectByExampleQueryId="false">
<property name="my.isgen.usekeys" value="true"/>
<property name="useActualColumnNames" value="true"/>
<generatedKey column="id" sqlStatement="JDBC"/>
</table>
<table tableName="tbl_message" domainObjectName="Message" enableCountByExample="false"
enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="true"
selectByExampleQueryId="false">
<property name="my.isgen.usekeys" value="true"/>
<property name="useActualColumnNames" value="true"/>
<generatedKey column="id" sqlStatement="JDBC"/>
</table>
<table tableName="tbl_sort_info" domainObjectName="SortInfo" enableCountByExample="false"
enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="true"
selectByExampleQueryId="false">
<property name="my.isgen.usekeys" value="true"/>
<property name="useActualColumnNames" value="true"/>
<generatedKey column="id" sqlStatement="JDBC"/>
</table>
<table tableName="tbl_article_sort" domainObjectName="ArticleSort" enableCountByExample="false"
enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="true"
selectByExampleQueryId="false">
<property name="my.isgen.usekeys" value="true"/>
<property name="useActualColumnNames" value="true"/>
<generatedKey column="id" sqlStatement="JDBC"/>
</table>
</context>
</generatorConfiguration>
註意表名/生成目標目錄之類的有沒有寫錯,表名最好就直接去復制數據庫中的名稱;
2)編寫逆向工程生成類:
package cn.wmyskxz.blog.generator;
import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.exception.XMLParserException;
import org.mybatis.generator.internal.DefaultShellCallback;
import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* MyBatis逆向工程生成類
*
* @author:wmyskxz
* @create:2018-06-14-上午 10:10
*/
public class MybatisGenerator {
public static void main(String[] args) throws Exception {
String today = "2018-6-14";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date now = sdf.parse(today);
Date d = new Date();
if (d.getTime() > now.getTime() + 1000 * 60 * 60 * 24) {
System.err.println("——————未成成功運行——————");
System.err.println("——————未成成功運行——————");
System.err.println("本程序具有破壞作用,應該只運行一次,如果必須要再運行,需要修改today變量為今天,如:" + sdf.format(new Date()));
return;
}
if (false)
return;
List<String> warnings = new ArrayList<String>();
boolean overwrite = true;
InputStream is = MybatisGenerator.class.getClassLoader().getResource("generatorConfig.xml").openStream();
ConfigurationParser cp = new ConfigurationParser(warnings);
Configuration config = cp.parseConfiguration(is);
is.close();
DefaultShellCallback callback = new DefaultShellCallback(overwrite);
MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
myBatisGenerator.generate(null);
System.out.println("生成代碼成功,只能執行一次,以後執行會覆蓋掉mapper,pojo,xml 等文件上做的修改");
}
}
這個是參考自how2j.cn的逆向工程,這個可以說是很成熟的模塊了,寫的很棒,考慮了安全方面的一些東西,鏈接在這裏:http://how2j.cn/k/tmall_ssm/tmall_ssm-1547/1547.html
3)點擊運行:
控制臺看到成功的信息之後,就能看到項目中自動多了一堆文件了:
RESTful API 設計
為了實現前後端分離,好的RESTful API是離不開的,正好前一段時間學習了這方面的知識,所以決定先來設計一套RESTful API,之前學習的文章鏈接在這裏:https://www.jianshu.com/p/91600da4df95
1)引入Swagger2來構造RESTful API:
既然想弄一下前後端分離,那就徹底一點兒,寫後臺完全不管前臺,前後臺的交互靠一套RESTful API和JSON數據來弄,所以需要一個文檔來瞅瞅,首先在pox.xml添加相關依賴:
<!--Swagger2支持-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.2.2</version>
</dependency>
2)創建Swagger2配置類:
在SpringBoot啟動類的同級目錄下創建Swagger2的配置類【Swagger2】:
/**
* Swagger2 配置類
*
* @author:wmyskxz
* @create:2018-06-14-上午 10:40
*/
@Configuration
@EnableSwagger2
public class Swagger2 {
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("cn.wmyskxz.blog"))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("Wmyskxz個人博客RESTful APIs")
.description("原文地址鏈接:http://blog.didispace.com/springbootswagger2/")
.termsOfServiceUrl("http://blog.didispace.com/")
.contact("@我沒有三顆心臟")
.version("1.0")
.build();
}
}
這樣,就可以在我們啟動項目之後,訪問http://localhost:8080/swagger-ui.html
地址來查看當前項目中的RESTful風格的API:
3)設計RESTful API:
好的,搗鼓了半天,終於有了一些雛形:
但是這也只是設計了API,具體都還沒有實現,這些就在寫後臺的時候來完善了,具體的這些內容怎麽顯示出來的,我給一個【SortController】的參考類:
/**
* 分類信息控制器
*
* @author:wmyskxz
* @create:2018-06-14-下午 13:25
*/
@RestController
@RequestMapping("/api/sort")
public class SortController {
/**
* 獲取所有分類信息
*
* @return
*/
@ApiOperation("獲取所有分類信息")
@GetMapping("/list")
public List<SortInfo> listAllSortInfo() {
return null;
}
/**
* 通過id獲取一條分類信息
*
* @param id
* @return
*/
@ApiOperation("獲取某一條分類信息")
@ApiImplicitParam(name = "id", value = "分類ID", required = true, dataType = "Long")
@GetMapping("/{id}")
public SortInfo getSortInfoById(@PathVariable Long id) {
return null;
}
/**
* 增加一條分類信息數據
*
* @return
*/
@ApiOperation("增加分類信息")
@ApiImplicitParam(name = "name", value = "分類名稱", required = true, dataType = "String")
@PostMapping("")
public String addSortInfo() {
return null;
}
/**
* 更新/編輯一條數據
*
* @param id
* @return
*/
@ApiOperation("更新/編輯分類信息")
@ApiImplicitParam(name = "id", value = "分類ID", required = true, dataType = "Long")
@PutMapping("/{id}")
public String updateSortInfo(@PathVariable Long id) {
return null;
}
/**
* 根據ID刪除分類信息
*
* @param id
* @return
*/
@ApiOperation("刪除分類信息")
@ApiImplicitParam(name = "id", value = "分類ID", required = true, dataType = "Long")
@DeleteMapping("/{id}")
public String deleteSortInfo(@PathVariable Long id) {
return null;
}
}
簡單介紹一下這些Swagger2的註解吧:
- @ApiOperation:用於給API設置提示信息,就上圖中右邊顯示的那些,默認不寫的情況下是value屬性,還可以多寫一個notes屬性,用於詳細的描述API,這裏就不需要了,都還比較簡單;
- @ApiImplicaitParam:用於說明API的參數信息,加了s的註解同理,寫了這個之後呢,我們就可以利用Swagger2給我們的信息頁面進行測試了,當然這裏沒有具體實現,也可以來看一下(下圖);
這裏沒有具體實現所以就不足以完成測試,等到後臺編寫的時候再進行測試吧...
總結
至此呢,我們項目所需要的準備就差不多完成了,想要去做一個東西必須要清楚的知道要的是一個什麽東西,這樣才能更加好的完成我們的產品,這也是我喜歡和堅信的事情:方向永遠比努力重要!(強行有聯系..hhhh)
另外一個問題: 我在想文章信息和內容分成了兩個表的問題,這樣的設計我覺得是沒有問題的,但是作為前端並不關心這些數據庫的設計,他只要能拿到對象就可以了,在設計 API 的時候,就發現獲得一篇文章,需要從三個表(文章信息/文章內容/評論)去獲取信息並封裝返回前端,這就需要自己在後臺另外寫一個實體類去封裝這些信息,這無疑增加了我們的代碼工作量,有沒有什麽好的方法解決呢?
歡迎轉載,轉載請註明出處!
簡書ID:@我沒有三顆心臟
github:wmyskxz
歡迎關註公眾微信號:wmyskxz_javaweb
分享自己的Java Web學習之路以及各種Java學習資料
SpringBoot技術棧搭建個人博客【項目準備】