從零開始搭建部落格02----發表部落格個人中心
頭部登入狀態
shiro標籤的引用
由於shiro標籤不是html的原生標籤,所有我們需要先引入一個額外的依賴,shiro的標籤庫(thymeleaf的拓展標籤)。
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
依賴新增好之後,然後,我們需要在com.fly.config.ShiroConfig
//用於thymeleaf模板使用shiro標籤,shiro方言標籤
@Bean
public ShiroDialect shiroDialect() {
return new ShiroDialect();
}
然後在需要使用shiro標籤的html 檔案的頭部新增
<html xmlns:th="http://www.thymeleaf.org"
xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
新增好之後,就可以使用<shiro:user></shiro:user>
使用者資訊存到session中
使用者登入成功之後需要將使用者的資訊儲存的session中。我們只需要在使用者認證的方法中com.fly.shiro.OAuth2Realm
類的doGetAuthenticationInfo
方法中加上如下語句:
// 將登陸資訊放在session
SecurityUtils.getSubject().getSession().setAttribute("profile",profile);
經過如下如上設定我們就實現了登入頭部狀態的控制
完善個人資訊
使用者中心
使用者中心主要就兩個,我發的貼和我收藏的貼
我發的帖子,在這裡插入程式碼片com.homework.controller.CenterController#center
查詢條件只有使用者id
QueryWrapper<Post> wrapper = new QueryWrapper<Post>().eq("user_id", getProfileId())
.orderByDesc("created");
IPage<Map<String, Object>> pageData = postService.pageMaps(page, wrapper);
request.setAttribute("pageData", pageData);
我的收藏
IPage<Map<String, Object>> pageData = userCollectionService.
pageMaps(page, new QueryWrapper<UserCollection>()
.eq("user_id", getProfileId()).orderByDesc("created"));
postService.join(pageData, "post_id");
request.setAttribute("pageData", pageData);
基本設定
- tab 切換回顯的問題,一個頁面有多個tab,如何讓在選中tab 之後重新整理不丟失原來的tab選中選項呢?答案是在url 後面加上#,這相當於標籤的效果。
當前tab頁標籤定義:
在static/mods/user.js
有如下語句:
//顯示當前tab
if(location.hash){
element.tabChange('user', location.hash.replace(/^#/, ''));
}
element.on('tab(user)', function(){
var othis = $(this), layid = othis.attr('lay-id');
if(layid){
location.hash = layid;
}
});
我們在templates/common/static.html
放入瞭如下程式碼,並修改下資訊
<script th:inline="javascript" th:if="${session.profile != null}">
layui.cache.page = '';
layui.cache.user = {
username: [[${session.profile.username}]]
,uid: [[${session.profile.id}]]
,avatar: [[${session.profile.avatar}]]
,experience: 0
,sex: [[${session.profile.gender}]]
};
layui.config({
version: "3.0.0",
base: '/mods/' //這裡實際使用時,建議改成絕對路徑
}).extend({
fly: 'index'
}).use('fly');
</script>
通過上面程式碼,我們把初始化layui的部分js程式碼,頁面中很多class或id 的div 就擁有了特定的監聽或其他。其中就報貨擷取url 獲取#後面的標籤用於tab 回顯功能,還有頭像的上傳功能封裝等。
加上了上面程式碼之後你會發現經常會有個異常的彈框,那是瀏覽器控制檯發現去訪問/message/nums
的連結,在index.js 檔案中找到 新訊息通知,按照介面要求我們修改地址為/user/message/nums
並在新增該介面
@ResponseBody
@PostMapping("/message/nums")
public Object getMessNums() {
Map<Object, Object> result = new HashMap<>();
result.put("status", 0);
result.put("count", 3);
return result;
}
- 頭像
頭像上傳介面com.fly.controller.CenterController#upload
,
頭像上傳核心程式碼
String orgName = file.getOriginalFilename();
log.info("上傳檔名為:" + orgName);
// 獲取字尾名
String suffixName = orgName.substring(orgName.lastIndexOf("."));
log.info("上傳的字尾名為:" + suffixName);
// 檔案上傳後的路徑
String filePath = Constant.uploadDir;
if ("avatar".equalsIgnoreCase(type)) {
fileName = "/avatar/avatar_" + getProfileId() + suffixName;
} else if ("post".equalsIgnoreCase(type)) {
fileName = "post/post_" + DateUtil.format(new Date(), DatePattern.PURE_DATETIME_MS_FORMAT) + suffixName;
}
File dest = new File(filePath + fileName);
// 檢查目錄是否存在
if (!dest.getParentFile().exists()) {
dest.getParentFile().mkdir();
}
//上傳檔案
file.transferTo(dest);
log.info("上傳成功之後檔案的路徑={}", dest.getPath());
目前上傳的圖片我們是到了一個指定目錄,然後nginx或者tomcat是可以讀取這個目錄的,所以可以通過url來訪問,一般來說我們把圖片上傳到雲端儲存服務上。這裡先這樣弄了。
頭像上傳之後,更新shiro 中的頭像資訊
AccountProfile profile = getProfile();
profile.setAvatar(url);
圖片上傳之後更新影象資訊
- 密碼
密碼重置介面com.fly.controller.CenterController#resetPwd
介面程式碼比較簡單:
@ResponseBody
@PostMapping("/resetPwd")
public R restPwd(String nowpass, String pass) {
//查詢使用者
User user = userService.getById(getProfileId());
if (user == null || !nowpass.equals(user.getPassword())) {
return R.failed("密碼不正確");
}
user.setPassword(pass);
boolean result = userService.updateById(user);
return R.ok(result);
}
前端頁面在 /user/setting.html
中
發表,編輯部落格
發表和編輯部落格是同一個頁面,前端頁面展示
ajax 請求程式碼:
$(function() {
layui.use('form', function() {
var form = layui.form;
//監聽提交
form.on('submit(post)', function (data) {
$.ajax({
url: '/user/post',
type: "POST",
data: data.field,
success: function (res) {
if (res.code == 0) {
layer.msg("操作成功");
setTimeout(function () {
location.href="/post/" + res.data;
}, 1000);
} else {
layer.msg(res.msg);
}
}
});
return false;
});
});
});
後臺介面在com.fly.controller.PostController
類中:
@ResponseBody
@PostMapping("/user/post")
public R postArticle(@Valid Post post, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
return R.failed(bindingResult.getFieldError().getDefaultMessage());
}
// 新增文章
if (post.getId() == null) {
post.setUserId(getProfileId());
post.setModified(new Date());
post.setCreated(new Date());
post.setCommentCount(0);
post.setEditMode(Constant.EDIT_HTML_MODEL);
post.setLevel(0);
post.setRecommend(false);
post.setViewCount(0);
post.setVoteDown(0);
post.setVoteUp(0);
post.setStatus(Constant.NORMAL_STATUS);
} else {
Post tempPost = postService.getById(post.getId());
if (tempPost.getUserId().equals(getProfileId())) {
return R.failed("不是自己的帖子");
}
}
postService.saveOrUpdate(post);
// TODO: 2018/12/13 給所有訂閱人傳送訊息
return R.ok(post.getId());
}
博文回顯
使用者編輯完部落格之後,點選提交儲存之後就可以 呼叫/user/post
進行博文回顯,部落格的地址com.fly.controller.PostController#index
, 博文回顯主要博文,使用者,分類以及評論資訊,核心程式碼如下:
Map<String, Object> post = postService.getMap(new QueryWrapper<Post>().eq("id", id));
userService.join(post, "user_id");
categoryService.join(post, "category_id");
Assert.notNull(post, "該文章已被刪除");
req.setAttribute("post", post);
req.setAttribute("currentCategoryId", post.get("category_id"));
Page<Comment> page = new Page<>();
page.setCurrent(current);
page.setSize(size);
IPage<Map<String, Object>> pageData = commentService.pageMaps(page, new QueryWrapper<Comment>()
.eq("post_id", id)
.orderByDesc("created"));
userService.join(pageData, "user_id");
commentService.join(pageData, "parent_id");
req.setAttribute("pageData", pageData);
前端頁面在 templates/post/index.html
部分程式碼如下:
頁面效果如下:
使用者主頁
部落格評論功能
使用者評論表:
CREATE TABLE `comment` (
`id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '主鍵ID',
`content` longtext NOT NULL COMMENT '評論的內容',
`parent_id` bigint(32) DEFAULT NULL COMMENT '回覆的評論ID',
`post_id` bigint(32) NOT NULL COMMENT '評論的內容ID',
`user_id` bigint(32) NOT NULL COMMENT '評論的使用者ID',
`vote_up` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '“頂”的數量',
`vote_down` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '“踩”的數量',
`level` tinyint(2) unsigned NOT NULL DEFAULT '0' COMMENT '置頂等級',
`status` tinyint(2) DEFAULT NULL COMMENT '評論的狀態',
`created` datetime NOT NULL COMMENT '評論的時間',
`modified` datetime DEFAULT NULL COMMENT '評論的更新時間',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4;
後端介面程式碼在在這裡插入程式碼片
@ResponseBody
@PostMapping("/user/post/comment")
public R commentAdd(@Valid Comment comment, BindingResult bindingResult) {
Post post = postService.getById(comment.getPostId());
Assert.isTrue(post != null, "該帖子已被刪除");
comment.setUserId(getProfileId());
comment.setCreated(new Date());
comment.setModified(new Date());
comment.setStatus(Constant.NORMAL_STATUS);
// TODO 記錄動作
// TODO 通知作者
commentService.save(comment);
return R.ok(null);
}
前端頁面在 templates/post/index.html
提交評論程式碼如下:
參考程式碼:
https://github.com/XWxiaowei/FlyBlog/tree/v5-collection-center