部落格開發總結之後臺程式碼
寫這個部落格專案也是我第一次使用Spring Boot框架,用過之後,發現真的回不去了。省去了一大堆配置檔案,簡直不能再爽。之前用Spring MVC,Spring,Hibernate,MyBatis等框架,繁瑣的配置檔案,每一個專案都是那一套,感覺不是在學框架內容,而是在學寫配置檔案。Spring Boot成功解決了這一難題,所以上手後寫起來也很順利。
專案搭建初期,就是構思資料庫的表結構。因為是第一次獨自開發專案,很多地方都沒有考慮到,建表時也一再回憶資料庫的一、二、三正規化,而表也是在開發過程中修改了好幾次。因為使用的是MyBatis,為了方便和避免重複造輪子,直接使用逆向工程生成實體類、介面和配置檔案,而每一次修改表結構,都要再重新生成。但是在Service層個別方法中,已經用到了Dao的屬性,如果想要大改資料表,很多程式碼就都要重寫,所以有一些表還是沒有達到滿意的程度。希望在下次寫專案之前,先把整體架構和需求明確。
資料庫的表生成用的是powerdesigner,表結構如下:
CREATE TABLE `blog_category` ( `id` tinyint(4) NOT NULL, `name` varchar(255) NOT NULL, `status` tinyint(4) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `blog_category_dictionary` ( `id` tinyint(4) NOT NULL, `parent_id` tinyint(4) NOT NULL DEFAULT '0', `name` varchar(255) NOT NULL, `status` tinyint(4) NOT NULL DEFAULT '1', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `blog_content` ( `id` int(11) NOT NULL AUTO_INCREMENT, `category` varchar(128) NOT NULL, `author` varchar(32) NOT NULL, `title` varchar(32) NOT NULL, `content` text NOT NULL, `abstracts` varchar(255) DEFAULT NULL, `tags` varchar(8) NOT NULL, `createtime` datetime NOT NULL, `updatetime` datetime NOT NULL, `readtimes` int(32) unsigned NOT NULL DEFAULT '0', `status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '-1 下架 0 待審 1 釋出 ', PRIMARY KEY (`id`), KEY `category` (`category`), KEY `author` (`author`), KEY `tags` (`tags`) USING BTREE ) ENGINE=InnoDB AUTO_INCREMENT=2030 DEFAULT CHARSET=utf8; CREATE TABLE `blog_index_content` ( `id` int(11) NOT NULL AUTO_INCREMENT, `url` varchar(255) NOT NULL, `filename` varchar(255) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `blog_tag` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(255) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=28 DEFAULT CHARSET=utf8; CREATE TABLE `blog_timeline` ( `id` int(16) NOT NULL AUTO_INCREMENT, `event_name` varchar(32) DEFAULT NULL, `event_content` varchar(64) DEFAULT NULL, `event_date` date DEFAULT NULL, `event_time` time DEFAULT NULL, `user` char(32) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=26 DEFAULT CHARSET=utf8; CREATE TABLE `blog_user` ( `id` char(32) NOT NULL, `username` varchar(128) NOT NULL, `password` varchar(128) NOT NULL, `email` varchar(128) DEFAULT NULL, `address` varchar(128) DEFAULT NULL, `age` tinyint(4) DEFAULT NULL, `createtime` varchar(32) DEFAULT NULL, `profile` text, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
根據需求確定表結構之後就開始寫程式碼,首先是Controller層,起碼要可以顯示頁面。
@Controller
@RequestMapping("/admin")
public class ShowPageController {
@GetMapping({"", "/index"})
public String showIndex() {
return "admin/index";
}
}
有 @GetMapping 和 @PostMapping ,分別用來接收兩種不同的 request請求 ,在類上加 @RequestMapping("/admin")
其他增刪改查的方法無非Controller呼叫Service,Service呼叫Dao,不再贅述。
有一個插入資料後需要獲取自增長id的需求。
在釋出新文章時,需要給文章新增標籤,因為標籤被拆分為單獨的一個表blog_tag,在blog_content表中儲存的是blog_tag的主鍵值,當發表文章輸入標籤時,如果標籤已經存在,就直接返回標籤id,如果id不存在,就插入一個標籤然後返回id。
public Integer getTagIdByName(String tagName) {
BlogTagExample tagExample = new BlogTagExample();
BlogTagExample.Criteria criteria = tagExample.createCriteria();
criteria.andNameEqualTo(tagName);
List<BlogTag> tags = tagMapper.selectByExample(tagExample);
if (tags.size() == 0) {
BlogTag newTag = new BlogTag();
newTag.setName(tagName);
tagMapper.insertAndGetId(newTag);
return newTag.getId();
}
return tags.get(0).getId();
}
BlogTagMapper.xml : insertAndGetId()
<insert id="insertAndGetId" parameterType="com.myblog.website.entity.BlogTag">
<selectKey keyColumn="id" resultType="int" order="AFTER" keyProperty="id">
SELECT LAST_INSERT_ID()
</selectKey>
insert into blog_tag(name) values(#{name})
</insert>
Spring Boot定時器功能:
在使用者訪問文章時,當每次傳送請求,文章的閱讀數就會加1,如果不加以限制,頁面一直重新整理數量就一致增長。這不符合平常的使用場景,想到一個解決辦法就是用HashMap物件,key為當前使用者的 ip + 文章id ,value為最後一次訪問時間,當用戶再次訪問同一文章時,如果最後一次訪問的時間與當前時間的差值小於規定時間,則更新value為當前時間,文章閱讀數不會增加;反之,文章閱讀數加1,更新value為當前時間。
ContentUtils.setReadTimes(request.getRemoteAddr() + "-" + id, contentService, new ReadTimesEntity(content.getId(), content.getReadtimes()));
public static void setReadTimes(String ip, ContentService contentService,,IndexController.ReadTimesEntity entity) {
if (!lookContent.containsKey(ip)) {
contentService.updateReadtimes(entity.getId(), entity.getReadtimes());
}
lookContent.put(ip, new Date());
}
@Scheduled(cron = "0 0/10 * * * ? ")
private static void clearLookContent(){
Set<Map.Entry<String, Date>> entries = lookContent.entrySet();
Iterator<Map.Entry<String, Date>> iterator = entries.iterator();
while (iterator.hasNext()) {
Map.Entry<String, Date> ele = iterator.next();
Date preDate = ele.getValue();
if (System.currentTimeMillis() - preDate.getTime() >= 3600000) {
iterator.remove();
}
}
}
上述程式碼中,當key不存在,新建key,並把當前時間作為value,如果key存在,則更新當前時間為value。
clearLookContent()方法,每十分鐘執行一次,遍歷HashMap,當value中的時間與當前時間相差一小時以上,就清除這個鍵值對,這樣當用戶下次訪問時,與如果間隔超過一個小時,文章的閱讀數就會加一。