diff --git a/src/main/java/cc/ryanc/halo/model/domain/Post.java b/src/main/java/cc/ryanc/halo/model/domain/Post.java index b3da107be..777b85641 100755 --- a/src/main/java/cc/ryanc/halo/model/domain/Post.java +++ b/src/main/java/cc/ryanc/halo/model/domain/Post.java @@ -1,7 +1,6 @@ package cc.ryanc.halo.model.domain; import com.fasterxml.jackson.annotation.JsonFormat; -import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.Data; import javax.persistence.*; @@ -130,6 +129,11 @@ public class Post implements Serializable { */ private Integer allowComment = 0; + /** + * 文章访问密码 + */ + private String postPassword; + /** * 指定渲染模板 */ diff --git a/src/main/java/cc/ryanc/halo/service/impl/PostServiceImpl.java b/src/main/java/cc/ryanc/halo/service/impl/PostServiceImpl.java index 41287659d..e4fb1ab3d 100755 --- a/src/main/java/cc/ryanc/halo/service/impl/PostServiceImpl.java +++ b/src/main/java/cc/ryanc/halo/service/impl/PostServiceImpl.java @@ -149,7 +149,7 @@ public class PostServiceImpl implements PostService { */ @Override public Page searchPosts(String keyword, String postType, Integer postStatus, Pageable pageable) { - return postRepository.findByPostTypeAndPostStatusAndPostTitleLikeOrPostTypeAndPostStatusAndPostContentLike( + Page posts = postRepository.findByPostTypeAndPostStatusAndPostTitleLikeOrPostTypeAndPostStatusAndPostContentLike( postType, postStatus, "%" + keyword + "%", @@ -158,6 +158,12 @@ public class PostServiceImpl implements PostService { "%" + keyword + "%", pageable ); + for (Post post : posts.getContent()) { + if (StrUtil.isNotEmpty(post.getPostPassword())) { + post.setPostSummary("该文章为加密文章"); + } + } + return posts; } /** @@ -170,7 +176,13 @@ public class PostServiceImpl implements PostService { */ @Override public Page findPostByStatus(Integer status, String postType, Pageable pageable) { - return postRepository.findPostsByPostStatusAndPostType(status, postType, pageable); + Page posts = postRepository.findPostsByPostStatusAndPostType(status, postType, pageable); + for (Post post : posts.getContent()) { + if (StrUtil.isNotEmpty(post.getPostPassword())) { + post.setPostSummary("该文章为加密文章"); + } + } + return posts; } /** @@ -182,7 +194,13 @@ public class PostServiceImpl implements PostService { @Override @Cacheable(value = POSTS_CACHE_NAME, key = "'posts_page_'+#pageable.pageNumber") public Page findPostByStatus(Pageable pageable) { - return postRepository.findPostsByPostStatusAndPostType(PostStatusEnum.PUBLISHED.getCode(), PostTypeEnum.POST_TYPE_POST.getDesc(), pageable); + Page posts = postRepository.findPostsByPostStatusAndPostType(PostStatusEnum.PUBLISHED.getCode(), PostTypeEnum.POST_TYPE_POST.getDesc(), pageable); + for (Post post : posts.getContent()) { + if (StrUtil.isNotEmpty(post.getPostPassword())) { + post.setPostSummary("该文章为加密文章"); + } + } + return posts; } /** @@ -367,7 +385,13 @@ public class PostServiceImpl implements PostService { */ @Override public Page findPostByYearAndMonth(String year, String month, Pageable pageable) { - return postRepository.findPostByYearAndMonth(year, month, null); + Page posts = postRepository.findPostByYearAndMonth(year, month, null); + for (Post post : posts.getContent()) { + if (StrUtil.isNotEmpty(post.getPostPassword())) { + post.setPostSummary("该文章为加密文章"); + } + } + return posts; } /** @@ -381,7 +405,13 @@ public class PostServiceImpl implements PostService { @Override @CachePut(value = POSTS_CACHE_NAME, key = "'posts_category_'+#category.cateId+'_'+#pageable.pageNumber") public Page findPostByCategories(Category category, Pageable pageable) { - return postRepository.findPostByCategoriesAndPostStatus(category, PostStatusEnum.PUBLISHED.getCode(), pageable); + Page posts = postRepository.findPostByCategoriesAndPostStatus(category, PostStatusEnum.PUBLISHED.getCode(), pageable); + for (Post post : posts.getContent()) { + if (StrUtil.isNotEmpty(post.getPostPassword())) { + post.setPostSummary("该文章为加密文章"); + } + } + return posts; } /** @@ -395,7 +425,13 @@ public class PostServiceImpl implements PostService { @Override @CachePut(value = POSTS_CACHE_NAME, key = "'posts_tag_'+#tag.tagId+'_'+#pageable.pageNumber") public Page findPostsByTags(Tag tag, Pageable pageable) { - return postRepository.findPostsByTagsAndPostStatus(tag, PostStatusEnum.PUBLISHED.getCode(), pageable); + Page posts = postRepository.findPostsByTagsAndPostStatus(tag, PostStatusEnum.PUBLISHED.getCode(), pageable); + for (Post post : posts.getContent()) { + if (StrUtil.isNotEmpty(post.getPostPassword())) { + post.setPostSummary("该文章为加密文章"); + } + } + return posts; } /** diff --git a/src/main/java/cc/ryanc/halo/web/controller/admin/PostController.java b/src/main/java/cc/ryanc/halo/web/controller/admin/PostController.java index 393f4c6ca..273b57b6d 100755 --- a/src/main/java/cc/ryanc/halo/web/controller/admin/PostController.java +++ b/src/main/java/cc/ryanc/halo/web/controller/admin/PostController.java @@ -18,6 +18,7 @@ import cc.ryanc.halo.web.controller.core.BaseController; import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.RandomUtil; import cn.hutool.core.util.StrUtil; +import cn.hutool.crypto.SecureUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.propertyeditors.CustomDateEditor; @@ -120,7 +121,7 @@ public class PostController extends BaseController { //排序规则 final Sort sort = new Sort(Sort.Direction.DESC, "postId"); final Pageable pageable = PageRequest.of(page, size, sort); - model.addAttribute("posts", postService.searchPosts(keyword,PostTypeEnum.POST_TYPE_POST.getDesc(),PostStatusEnum.PUBLISHED.getCode(),pageable)); + model.addAttribute("posts", postService.searchPosts(keyword, PostTypeEnum.POST_TYPE_POST.getDesc(), PostStatusEnum.PUBLISHED.getCode(), pageable)); } catch (Exception e) { log.error("未知错误:{}", e.getMessage()); } @@ -186,6 +187,9 @@ public class PostController extends BaseController { post.setUser(user); post = postService.buildCategoriesAndTags(post, cateList, tagList); post.setPostUrl(urlFilter(post.getPostUrl())); + if (StrUtil.isNotEmpty(post.getPostPassword())) { + post.setPostPassword(SecureUtil.md5(post.getPostPassword())); + } //当没有选择文章缩略图的时候,自动分配一张内置的缩略图 if (StrUtil.equals(post.getPostThumbnail(), BlogPropertiesEnum.DEFAULT_THUMBNAIL.getProp())) { post.setPostThumbnail("/static/halo-frontend/images/thumbnail/thumbnail-" + RandomUtil.randomInt(1, 10) + ".jpg"); @@ -223,6 +227,9 @@ public class PostController extends BaseController { post.setPostDate(new Date()); } post = postService.buildCategoriesAndTags(post, cateList, tagList); + if (StrUtil.isNotEmpty(post.getPostPassword())) { + post.setPostPassword(SecureUtil.md5(post.getPostPassword())); + } //当没有选择文章缩略图的时候,自动分配一张内置的缩略图 if (StrUtil.equals(post.getPostThumbnail(), BlogPropertiesEnum.DEFAULT_THUMBNAIL.getProp())) { post.setPostThumbnail("/static/halo-frontend/images/thumbnail/thumbnail-" + RandomUtil.randomInt(1, 10) + ".jpg"); diff --git a/src/main/java/cc/ryanc/halo/web/controller/front/FrontArchiveController.java b/src/main/java/cc/ryanc/halo/web/controller/front/FrontArchiveController.java index d0f036151..32b3e8072 100644 --- a/src/main/java/cc/ryanc/halo/web/controller/front/FrontArchiveController.java +++ b/src/main/java/cc/ryanc/halo/web/controller/front/FrontArchiveController.java @@ -13,19 +13,22 @@ import cc.ryanc.halo.web.controller.core.BaseController; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.PageUtil; import cn.hutool.core.util.StrUtil; +import cn.hutool.crypto.SecureUtil; +import cn.hutool.extra.servlet.ServletUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.annotation.CacheEvict; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.*; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; import java.util.ArrayList; import java.util.Date; import java.util.List; @@ -43,9 +46,9 @@ import java.util.List; @RequestMapping(value = "/archives") public class FrontArchiveController extends BaseController { + private static final String POSTS_CACHE_NAME = "posts"; @Autowired private PostService postService; - @Autowired private CommentService commentService; @@ -53,7 +56,6 @@ public class FrontArchiveController extends BaseController { * 文章归档 * * @param model model - * * @return 模板路径 */ @GetMapping @@ -66,7 +68,6 @@ public class FrontArchiveController extends BaseController { * * @param model model * @param page page 当前页码 - * * @return 模板路径/themes/{theme}/archives */ @GetMapping(value = "page/{page}") @@ -91,7 +92,6 @@ public class FrontArchiveController extends BaseController { * @param model model * @param year year 年份 * @param month month 月份 - * * @return 模板路径/themes/{theme}/archives */ @GetMapping(value = "{year}/{month}") @@ -112,12 +112,12 @@ public class FrontArchiveController extends BaseController { * * @param postUrl 文章路径名 * @param model model - * * @return 模板路径/themes/{theme}/post */ @GetMapping(value = "{postUrl}") public String getPost(@PathVariable String postUrl, @RequestParam(value = "cp", defaultValue = "1") Integer cp, + HttpServletRequest request, Model model) { final Post post = postService.findByPostUrl(postUrl, PostTypeEnum.POST_TYPE_POST.getDesc()); if (null == post || !post.getPostStatus().equals(PostStatusEnum.PUBLISHED.getCode())) { @@ -130,12 +130,12 @@ public class FrontArchiveController extends BaseController { if (null != prePost) { //兼容老版本主题 model.addAttribute("beforePost", prePost); - model.addAttribute("prePost",prePost); + model.addAttribute("prePost", prePost); } if (null != nextPost) { //兼容老版本主题 model.addAttribute("afterPost", nextPost); - model.addAttribute("nextPost",nextPost); + model.addAttribute("nextPost", nextPost); } List comments = null; if (StrUtil.equals(HaloConst.OPTIONS.get(BlogPropertiesEnum.NEW_COMMENT_NEED_CHECK.getProp()), TrueFalseEnum.TRUE.getDesc()) || HaloConst.OPTIONS.get(BlogPropertiesEnum.NEW_COMMENT_NEED_CHECK.getProp()) == null) { @@ -161,12 +161,44 @@ public class FrontArchiveController extends BaseController { final ListPage commentsPage = new ListPage(CommentUtil.getComments(comments), cp, size); final int[] rainbow = PageUtil.rainbow(cp, commentsPage.getTotalPage(), 3); model.addAttribute("is_post", true); - model.addAttribute("post", post); model.addAttribute("comments", commentsPage); model.addAttribute("commentsCount", comments.size()); model.addAttribute("rainbow", rainbow); model.addAttribute("tagWords", CollUtil.join(tagWords, ",")); postService.cacheViews(post.getPostId()); + + //判断文章是否有加密 + if (StrUtil.isNotEmpty(post.getPostPassword())) { + Cookie cookie = ServletUtil.getCookie(request, "halo-post-password-" + post.getPostId()); + if (null == cookie) { + post.setPostSummary("该文章为加密文章"); + post.setPostContent("

该文章为加密文章,输入正确的密码即可访问。

"); + } + } + model.addAttribute("post", post); return this.render("post"); } + + /** + * 验证文章密码 + * + * @param postId postId + * @param postPassword postPassword + * @param response response + * @return String + */ + @PostMapping(value = "/verifyPostPassword") + @CacheEvict(value = POSTS_CACHE_NAME, allEntries = true, beforeInvocation = true) + public String verifyPostPassword(@RequestParam(value = "postId") Long postId, + @RequestParam(value = "postPassword") String postPassword, + HttpServletResponse response) { + final Post post = postService.findByPostId(postId, PostTypeEnum.POST_TYPE_POST.getDesc()); + if (null == post) { + return this.renderNotFound(); + } + if (SecureUtil.md5(postPassword).equals(post.getPostPassword())) { + ServletUtil.addCookie(response, "halo-post-password-" + post.getPostId(), SecureUtil.md5(postPassword)); + } + return "redirect:/archives/" + post.getPostUrl(); + } } diff --git a/src/main/java/cc/ryanc/halo/web/controller/front/FrontOthersController.java b/src/main/java/cc/ryanc/halo/web/controller/front/FrontOthersController.java index 5090cda14..4b3001046 100644 --- a/src/main/java/cc/ryanc/halo/web/controller/front/FrontOthersController.java +++ b/src/main/java/cc/ryanc/halo/web/controller/front/FrontOthersController.java @@ -48,6 +48,11 @@ public class FrontOthersController { final Pageable pageable = PageRequest.of(0, Integer.parseInt(rssPosts), sort); final Page postsPage = postService.findPostByStatus(0, PostTypeEnum.POST_TYPE_POST.getDesc(), pageable); final List posts = postsPage.getContent(); + for (Post post : posts) { + if(StrUtil.isNotEmpty(post.getPostPassword())){ + post.setPostContent("该文章为加密文章"); + } + } return postService.buildRss(posts); } @@ -64,6 +69,11 @@ public class FrontOthersController { final Pageable pageable = PageRequest.of(0, 999, sort); final Page postsPage = postService.findPostByStatus(0, PostTypeEnum.POST_TYPE_POST.getDesc(), pageable); final List posts = postsPage.getContent(); + for (Post post : posts) { + if(StrUtil.isNotEmpty(post.getPostPassword())){ + post.setPostContent("该文章为加密文章"); + } + } return postService.buildSiteMap(posts); } } diff --git a/src/main/resources/templates/admin/admin_post_edit.ftl b/src/main/resources/templates/admin/admin_post_edit.ftl index b11def893..3bc3272c5 100644 --- a/src/main/resources/templates/admin/admin_post_edit.ftl +++ b/src/main/resources/templates/admin/admin_post_edit.ftl @@ -67,6 +67,10 @@ +
+ + +
@@ -297,7 +301,8 @@ 'cateList' : cateList.toString(), 'tagList' : $('#tagList').tagEditor('getTags')[0].tags.toString(), 'allowComment' : $('#allowComment').val(), - 'postDate' : $("#postDate").val() + 'postDate' : $("#postDate").val(), + 'postPassword' : $("#postPassword").val() },function (data) { if(data.code === 1){ //清除自动保存的内容 diff --git a/src/main/resources/templates/admin/admin_post_new.ftl b/src/main/resources/templates/admin/admin_post_new.ftl index 006d87acf..d08ca0dab 100644 --- a/src/main/resources/templates/admin/admin_post_new.ftl +++ b/src/main/resources/templates/admin/admin_post_new.ftl @@ -65,6 +65,10 @@
+
+ + +