1. 程式人生 > >從零開始搭建部落格02----發表部落格個人中心

從零開始搭建部落格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

中初始化一下,注入對應的Bean, 頁面才能渲染出來

    //用於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>

將要許可權控制的內容包起來,當然shiro 標籤還有很多
在這裡插入圖片描述

使用者資訊存到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);

基本設定

  1. 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;
    }
  1. 頭像
    頭像上傳介面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);

圖片上傳之後更新影象資訊
在這裡插入圖片描述

  1. 密碼
    密碼重置介面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