From d82f3847c269f97aeccfaa14013c8f456f04030d Mon Sep 17 00:00:00 2001 From: Ryan Wang Date: Wed, 4 Mar 2020 20:03:08 +0800 Subject: [PATCH] feat: support meta_keywords and meta_description in every page. (#612) --- .../content/ContentContentController.java | 7 +++-- .../content/ContentSearchController.java | 2 ++ .../content/model/CategoryModel.java | 18 +++++++++++ .../content/model/JournalModel.java | 2 ++ .../controller/content/model/LinkModel.java | 31 +++++++++++++++++++ .../controller/content/model/PhotoModel.java | 2 ++ .../controller/content/model/PostModel.java | 19 ++++++++++++ .../controller/content/model/SheetModel.java | 28 ++++++++++++++++- .../controller/content/model/TagModel.java | 4 +++ .../run/halo/app/model/dto/CategoryDTO.java | 3 -- .../java/run/halo/app/model/dto/TagDTO.java | 3 -- .../model/dto/post/BasePostMinimalDTO.java | 7 +++-- .../app/model/dto/post/BasePostSimpleDTO.java | 3 -- .../run/halo/app/model/entity/BasePost.java | 27 ++++++++-------- .../halo/app/model/enums/PostCreateFrom.java | 30 ------------------ .../converter/PostCreateFromConverter.java | 19 ------------ .../halo/app/model/params/CategoryParam.java | 3 -- .../run/halo/app/model/params/PostParam.java | 8 ++--- .../run/halo/app/model/params/SheetParam.java | 11 ++++--- .../run/halo/app/model/params/TagParam.java | 3 -- .../run/halo/app/service/OptionService.java | 14 +++++++++ .../app/service/base/BasePostService.java | 8 +++++ .../app/service/impl/BasePostServiceImpl.java | 15 +++++++++ .../app/service/impl/OptionServiceImpl.java | 10 ++++++ ...__migrate_1.3.0-beta.1_to_1.3.0-beta.2.sql | 1 + src/main/resources/templates/themes/anatole | 2 +- 26 files changed, 186 insertions(+), 94 deletions(-) create mode 100644 src/main/java/run/halo/app/controller/content/model/LinkModel.java delete mode 100644 src/main/java/run/halo/app/model/enums/PostCreateFrom.java delete mode 100644 src/main/java/run/halo/app/model/enums/converter/PostCreateFromConverter.java diff --git a/src/main/java/run/halo/app/controller/content/ContentContentController.java b/src/main/java/run/halo/app/controller/content/ContentContentController.java index 4f6af7d23..e9cfee3ea 100644 --- a/src/main/java/run/halo/app/controller/content/ContentContentController.java +++ b/src/main/java/run/halo/app/controller/content/ContentContentController.java @@ -45,6 +45,8 @@ public class ContentContentController { private final PhotoModel photoModel; + private final LinkModel linkModel; + private final OptionService optionService; private final PostService postService; @@ -61,6 +63,7 @@ public class ContentContentController { TagModel tagModel, JournalModel journalModel, PhotoModel photoModel, + LinkModel linkModel, OptionService optionService, PostService postService, SheetService sheetService, @@ -72,6 +75,7 @@ public class ContentContentController { this.tagModel = tagModel; this.journalModel = journalModel; this.photoModel = photoModel; + this.linkModel = linkModel; this.optionService = optionService; this.postService = postService; this.sheetService = sheetService; @@ -93,8 +97,7 @@ public class ContentContentController { } else if (optionService.getPhotosPrefix().equals(prefix)) { return photoModel.list(1, model); } else if (optionService.getLinksPrefix().equals(prefix)) { - model.addAttribute("is_links", true); - return themeService.render("links"); + return linkModel.list(model); } else { throw new NotFoundException("Not Found"); } diff --git a/src/main/java/run/halo/app/controller/content/ContentSearchController.java b/src/main/java/run/halo/app/controller/content/ContentSearchController.java index f4bf8e8da..0e6fc7565 100644 --- a/src/main/java/run/halo/app/controller/content/ContentSearchController.java +++ b/src/main/java/run/halo/app/controller/content/ContentSearchController.java @@ -116,6 +116,8 @@ public class ContentSearchController { model.addAttribute("rainbow", rainbow); model.addAttribute("nextPageFullPath", nextPageFullPath.toString()); model.addAttribute("prePageFullPath", prePageFullPath.toString()); + model.addAttribute("meta_keywords", optionService.getSeoKeywords()); + model.addAttribute("meta_description", optionService.getSeoDescription()); return themeService.render("search"); } } diff --git a/src/main/java/run/halo/app/controller/content/model/CategoryModel.java b/src/main/java/run/halo/app/controller/content/model/CategoryModel.java index b1381cf1d..3057ff924 100644 --- a/src/main/java/run/halo/app/controller/content/model/CategoryModel.java +++ b/src/main/java/run/halo/app/controller/content/model/CategoryModel.java @@ -43,11 +43,27 @@ public class CategoryModel { this.optionService = optionService; } + /** + * List categories. + * + * @param model model + * @return template name + */ public String list(Model model) { model.addAttribute("is_categories", true); + model.addAttribute("meta_keywords", optionService.getSeoKeywords()); + model.addAttribute("meta_description", optionService.getSeoDescription()); return themeService.render("categories"); } + /** + * List category posts. + * + * @param model model + * @param slug slug + * @param page current page + * @return template name + */ public String listPost(Model model, String slug, Integer page) { // Get category by slug final Category category = categoryService.getBySlugOfNonNull(slug); @@ -82,6 +98,8 @@ public class CategoryModel { model.addAttribute("category", categoryDTO); model.addAttribute("nextPageFullPath", nextPageFullPath.toString()); model.addAttribute("prePageFullPath", prePageFullPath.toString()); + model.addAttribute("meta_keywords", optionService.getSeoKeywords()); + model.addAttribute("meta_description", optionService.getSeoDescription()); return themeService.render("category"); } } diff --git a/src/main/java/run/halo/app/controller/content/model/JournalModel.java b/src/main/java/run/halo/app/controller/content/model/JournalModel.java index cf71b5910..0d459f411 100644 --- a/src/main/java/run/halo/app/controller/content/model/JournalModel.java +++ b/src/main/java/run/halo/app/controller/content/model/JournalModel.java @@ -82,6 +82,8 @@ public class JournalModel { model.addAttribute("rainbow", rainbow); model.addAttribute("nextPageFullPath", nextPageFullPath.toString()); model.addAttribute("prePageFullPath", prePageFullPath.toString()); + model.addAttribute("meta_keywords", optionService.getSeoKeywords()); + model.addAttribute("meta_description", optionService.getSeoDescription()); return themeService.render("journals"); } } diff --git a/src/main/java/run/halo/app/controller/content/model/LinkModel.java b/src/main/java/run/halo/app/controller/content/model/LinkModel.java new file mode 100644 index 000000000..95d3e3465 --- /dev/null +++ b/src/main/java/run/halo/app/controller/content/model/LinkModel.java @@ -0,0 +1,31 @@ +package run.halo.app.controller.content.model; + +import org.springframework.stereotype.Component; +import org.springframework.ui.Model; +import run.halo.app.service.OptionService; +import run.halo.app.service.ThemeService; + +/** + * @author ryanwang + * @date 2020-03-04 + */ +@Component +public class LinkModel { + + private final ThemeService themeService; + + private final OptionService optionService; + + public LinkModel(ThemeService themeService, + OptionService optionService) { + this.themeService = themeService; + this.optionService = optionService; + } + + public String list(Model model) { + model.addAttribute("is_links", true); + model.addAttribute("meta_keywords", optionService.getSeoKeywords()); + model.addAttribute("meta_description", optionService.getSeoDescription()); + return themeService.render("links"); + } +} diff --git a/src/main/java/run/halo/app/controller/content/model/PhotoModel.java b/src/main/java/run/halo/app/controller/content/model/PhotoModel.java index cff115d6c..91757a48f 100644 --- a/src/main/java/run/halo/app/controller/content/model/PhotoModel.java +++ b/src/main/java/run/halo/app/controller/content/model/PhotoModel.java @@ -76,6 +76,8 @@ public class PhotoModel { model.addAttribute("photos", photos); model.addAttribute("nextPageFullPath", nextPageFullPath.toString()); model.addAttribute("prePageFullPath", prePageFullPath.toString()); + model.addAttribute("meta_keywords", optionService.getSeoKeywords()); + model.addAttribute("meta_description", optionService.getSeoDescription()); return themeService.render("photos"); } } diff --git a/src/main/java/run/halo/app/controller/content/model/PostModel.java b/src/main/java/run/halo/app/controller/content/model/PostModel.java index 18a3c1795..678d8c3b0 100644 --- a/src/main/java/run/halo/app/controller/content/model/PostModel.java +++ b/src/main/java/run/halo/app/controller/content/model/PostModel.java @@ -24,6 +24,7 @@ import run.halo.app.service.*; import run.halo.app.utils.MarkdownUtils; import java.util.List; +import java.util.stream.Collectors; /** * Post Model @@ -104,6 +105,20 @@ public class PostModel { List tags = postTagService.listTagsBy(post.getId()); List metas = postMetaService.listBy(post.getId()); + // Generate meta keywords. + if (StringUtils.isNotEmpty(post.getMetaKeywords())) { + model.addAttribute("meta_keywords", post.getMetaKeywords()); + } else { + model.addAttribute("meta_keywords", tags.stream().map(Tag::getName).collect(Collectors.joining(","))); + } + + // Generate meta description. + if (StringUtils.isNotEmpty(post.getMetaDescription())) { + model.addAttribute("meta_description", post.getMetaDescription()); + } else { + model.addAttribute("meta_description", postService.generateDescription(post.getFormatContent())); + } + model.addAttribute("is_post", true); model.addAttribute("post", postService.convertToDetailVo(post)); model.addAttribute("categories", categoryService.convertTo(categories)); @@ -159,6 +174,8 @@ public class PostModel { model.addAttribute("pageRainbow", rainbow); model.addAttribute("nextPageFullPath", nextPageFullPath.toString()); model.addAttribute("prePageFullPath", prePageFullPath.toString()); + model.addAttribute("meta_keywords", optionService.getSeoKeywords()); + model.addAttribute("meta_description", optionService.getSeoDescription()); return themeService.render("index"); } @@ -209,6 +226,8 @@ public class PostModel { model.addAttribute("pageRainbow", rainbow); model.addAttribute("nextPageFullPath", nextPageFullPath.toString()); model.addAttribute("prePageFullPath", prePageFullPath.toString()); + model.addAttribute("meta_keywords", optionService.getSeoKeywords()); + model.addAttribute("meta_description", optionService.getSeoDescription()); return themeService.render("archives"); } } diff --git a/src/main/java/run/halo/app/controller/content/model/SheetModel.java b/src/main/java/run/halo/app/controller/content/model/SheetModel.java index f6c83f1e3..c5cc80788 100644 --- a/src/main/java/run/halo/app/controller/content/model/SheetModel.java +++ b/src/main/java/run/halo/app/controller/content/model/SheetModel.java @@ -11,6 +11,7 @@ import run.halo.app.model.enums.PostEditorType; import run.halo.app.model.enums.PostStatus; import run.halo.app.model.support.HaloConst; import run.halo.app.model.vo.SheetDetailVO; +import run.halo.app.service.OptionService; import run.halo.app.service.SheetService; import run.halo.app.service.ThemeService; import run.halo.app.utils.MarkdownUtils; @@ -30,12 +31,23 @@ public class SheetModel { private final ThemeService themeService; - public SheetModel(SheetService sheetService, StringCacheStore cacheStore, ThemeService themeService) { + private final OptionService optionService; + + public SheetModel(SheetService sheetService, StringCacheStore cacheStore, ThemeService themeService, OptionService optionService) { this.sheetService = sheetService; this.cacheStore = cacheStore; this.themeService = themeService; + this.optionService = optionService; } + /** + * Sheet content. + * + * @param sheet sheet + * @param token token + * @param model model + * @return template name + */ public String content(Sheet sheet, String token, Model model) { if (StringUtils.isEmpty(token)) { @@ -58,6 +70,20 @@ public class SheetModel { SheetDetailVO sheetDetailVO = sheetService.convertToDetailVo(sheet); + // Generate meta keywords. + if (StringUtils.isNotEmpty(sheet.getMetaKeywords())) { + model.addAttribute("meta_keywords", sheet.getMetaKeywords()); + } else { + model.addAttribute("meta_keywords", optionService.getSeoKeywords()); + } + + // Generate meta description. + if (StringUtils.isNotEmpty(sheet.getMetaDescription())) { + model.addAttribute("meta_description", sheet.getMetaDescription()); + } else { + model.addAttribute("meta_description", sheetService.generateDescription(sheet.getFormatContent())); + } + // sheet and post all can use model.addAttribute("sheet", sheetDetailVO); model.addAttribute("post", sheetDetailVO); diff --git a/src/main/java/run/halo/app/controller/content/model/TagModel.java b/src/main/java/run/halo/app/controller/content/model/TagModel.java index 76ddba286..cff8804c1 100644 --- a/src/main/java/run/halo/app/controller/content/model/TagModel.java +++ b/src/main/java/run/halo/app/controller/content/model/TagModel.java @@ -45,6 +45,8 @@ public class TagModel { public String list(Model model) { model.addAttribute("is_tags", true); + model.addAttribute("meta_keywords", optionService.getSeoKeywords()); + model.addAttribute("meta_description", optionService.getSeoDescription()); return themeService.render("tags"); } @@ -82,6 +84,8 @@ public class TagModel { model.addAttribute("tag", tagDTO); model.addAttribute("nextPageFullPath", nextPageFullPath.toString()); model.addAttribute("prePageFullPath", prePageFullPath.toString()); + model.addAttribute("meta_keywords", optionService.getSeoKeywords()); + model.addAttribute("meta_description", optionService.getSeoDescription()); return themeService.render("tag"); } } diff --git a/src/main/java/run/halo/app/model/dto/CategoryDTO.java b/src/main/java/run/halo/app/model/dto/CategoryDTO.java index a4cfd6231..697035b16 100644 --- a/src/main/java/run/halo/app/model/dto/CategoryDTO.java +++ b/src/main/java/run/halo/app/model/dto/CategoryDTO.java @@ -24,9 +24,6 @@ public class CategoryDTO implements OutputConverter { private String name; - @Deprecated - private String slugName; - private String slug; private String description; diff --git a/src/main/java/run/halo/app/model/dto/TagDTO.java b/src/main/java/run/halo/app/model/dto/TagDTO.java index 3843ef65f..cb197980a 100644 --- a/src/main/java/run/halo/app/model/dto/TagDTO.java +++ b/src/main/java/run/halo/app/model/dto/TagDTO.java @@ -20,9 +20,6 @@ public class TagDTO implements OutputConverter { private String name; - @Deprecated - private String slugName; - private String slug; private String thumbnail; diff --git a/src/main/java/run/halo/app/model/dto/post/BasePostMinimalDTO.java b/src/main/java/run/halo/app/model/dto/post/BasePostMinimalDTO.java index d561b35ae..449175399 100644 --- a/src/main/java/run/halo/app/model/dto/post/BasePostMinimalDTO.java +++ b/src/main/java/run/halo/app/model/dto/post/BasePostMinimalDTO.java @@ -28,9 +28,6 @@ public class BasePostMinimalDTO implements OutputConverter { - - /** - * 发布来源:管理后台 - */ - ADMIN(0), - - /** - * 发布来源:微信 - */ - WECHAT(1); - - private final Integer value; - - PostCreateFrom(Integer value) { - this.value = value; - } - - @Override - public Integer getValue() { - return value; - } -} diff --git a/src/main/java/run/halo/app/model/enums/converter/PostCreateFromConverter.java b/src/main/java/run/halo/app/model/enums/converter/PostCreateFromConverter.java deleted file mode 100644 index 6a4095f64..000000000 --- a/src/main/java/run/halo/app/model/enums/converter/PostCreateFromConverter.java +++ /dev/null @@ -1,19 +0,0 @@ -package run.halo.app.model.enums.converter; - -import run.halo.app.model.enums.PostCreateFrom; - -import javax.persistence.Converter; - -/** - * Post create from converter. - * - * @author johnniang - * @date 3/27/19 - */ -@Converter(autoApply = true) -public class PostCreateFromConverter extends AbstractConverter { - - public PostCreateFromConverter() { - super(PostCreateFrom.class); - } -} diff --git a/src/main/java/run/halo/app/model/params/CategoryParam.java b/src/main/java/run/halo/app/model/params/CategoryParam.java index c13761ce4..f789a7ea9 100644 --- a/src/main/java/run/halo/app/model/params/CategoryParam.java +++ b/src/main/java/run/halo/app/model/params/CategoryParam.java @@ -23,9 +23,6 @@ public class CategoryParam implements InputConverter { @Size(max = 255, message = "分类名称的字符长度不能超过 {max}") private String name; - @Deprecated - private String slugName; - @Size(max = 255, message = "分类别名的字符长度不能超过 {max}") private String slug; diff --git a/src/main/java/run/halo/app/model/params/PostParam.java b/src/main/java/run/halo/app/model/params/PostParam.java index 09befd8d3..0b94aa23d 100644 --- a/src/main/java/run/halo/app/model/params/PostParam.java +++ b/src/main/java/run/halo/app/model/params/PostParam.java @@ -6,7 +6,6 @@ import org.springframework.util.CollectionUtils; import run.halo.app.model.dto.base.InputConverter; import run.halo.app.model.entity.Post; import run.halo.app.model.entity.PostMeta; -import run.halo.app.model.enums.PostCreateFrom; import run.halo.app.model.enums.PostEditorType; import run.halo.app.model.enums.PostStatus; import run.halo.app.utils.SlugUtils; @@ -35,9 +34,6 @@ public class PostParam implements InputConverter { private PostStatus status = PostStatus.DRAFT; - @Deprecated - private String url; - @Size(max = 255, message = "文章别名的字符长度不能超过 {max}") private String slug; @@ -63,7 +59,9 @@ public class PostParam implements InputConverter { private Date createTime; - private PostCreateFrom createFrom = PostCreateFrom.ADMIN; + private String metaKeywords; + + private String metaDescription; private Set tagIds; diff --git a/src/main/java/run/halo/app/model/params/SheetParam.java b/src/main/java/run/halo/app/model/params/SheetParam.java index bc67f4027..0f1176bcb 100644 --- a/src/main/java/run/halo/app/model/params/SheetParam.java +++ b/src/main/java/run/halo/app/model/params/SheetParam.java @@ -33,9 +33,6 @@ public class SheetParam implements InputConverter { private PostStatus status = PostStatus.DRAFT; - @Deprecated - private String url; - @Size(max = 255, message = "页面别名的字符长度不能超过 {max}") private String slug; @@ -50,8 +47,6 @@ public class SheetParam implements InputConverter { private Boolean disallowComment = false; - private Date createTime; - @Size(max = 255, message = "页面密码的字符长度不能超过 {max}") private String password; @@ -61,6 +56,12 @@ public class SheetParam implements InputConverter { @Min(value = 0, message = "Post top priority must not be less than {value}") private Integer topPriority = 0; + private Date createTime; + + private String metaKeywords; + + private String metaDescription; + private Set sheetMetas; @Override diff --git a/src/main/java/run/halo/app/model/params/TagParam.java b/src/main/java/run/halo/app/model/params/TagParam.java index daf5bbcbb..6792c6db7 100644 --- a/src/main/java/run/halo/app/model/params/TagParam.java +++ b/src/main/java/run/halo/app/model/params/TagParam.java @@ -23,9 +23,6 @@ public class TagParam implements InputConverter { @Size(max = 255, message = "标签名称的字符长度不能超过 {max}") private String name; - @Deprecated - private String slugName; - @Size(max = 255, message = "标签别名的字符长度不能超过 {max}") private String slug; diff --git a/src/main/java/run/halo/app/service/OptionService.java b/src/main/java/run/halo/app/service/OptionService.java index 6044435fc..ac8f8bcd8 100755 --- a/src/main/java/run/halo/app/service/OptionService.java +++ b/src/main/java/run/halo/app/service/OptionService.java @@ -354,6 +354,20 @@ public interface OptionService extends CrudService { @NonNull String getBlogTitle(); + /** + * Gets global seo keywords. + * + * @return keywords + */ + String getSeoKeywords(); + + /** + * Get global seo description. + * + * @return description + */ + String getSeoDescription(); + /** * Gets blog birthday. * diff --git a/src/main/java/run/halo/app/service/base/BasePostService.java b/src/main/java/run/halo/app/service/base/BasePostService.java index e97da584f..6b01128f9 100644 --- a/src/main/java/run/halo/app/service/base/BasePostService.java +++ b/src/main/java/run/halo/app/service/base/BasePostService.java @@ -308,4 +308,12 @@ public interface BasePostService extends CrudService replaceUrl(@NonNull String oldUrl, @NonNull String newUrl); + + /** + * Generate description. + * + * @param content html content must not be null. + * @return description + */ + String generateDescription(@NonNull String content); } diff --git a/src/main/java/run/halo/app/service/impl/BasePostServiceImpl.java b/src/main/java/run/halo/app/service/impl/BasePostServiceImpl.java index d6c3ce1b1..ce3590281 100644 --- a/src/main/java/run/halo/app/service/impl/BasePostServiceImpl.java +++ b/src/main/java/run/halo/app/service/impl/BasePostServiceImpl.java @@ -425,6 +425,21 @@ public abstract class BasePostServiceImpl extends Abstrac return updated.stream().map(this::convertToDetail).collect(Collectors.toList()); } + @Override + public String generateDescription(String content) { + Assert.notNull(content, "html content must not be null"); + + String text = HaloUtils.cleanHtmlTag(content); + + Matcher matcher = summaryPattern.matcher(text); + text = matcher.replaceAll(""); + + // Get summary length + Integer summaryLength = optionService.getByPropertyOrDefault(PostProperties.SUMMARY_LENGTH, Integer.class, 150); + + return StringUtils.substring(text, 0, summaryLength); + } + @Override public POST create(POST post) { // Check title diff --git a/src/main/java/run/halo/app/service/impl/OptionServiceImpl.java b/src/main/java/run/halo/app/service/impl/OptionServiceImpl.java index 853b227d6..adb0ed538 100644 --- a/src/main/java/run/halo/app/service/impl/OptionServiceImpl.java +++ b/src/main/java/run/halo/app/service/impl/OptionServiceImpl.java @@ -469,6 +469,16 @@ public class OptionServiceImpl extends AbstractCrudService impl return getByProperty(BlogProperties.BLOG_TITLE).orElse("").toString(); } + @Override + public String getSeoKeywords() { + return getByProperty(SeoProperties.KEYWORDS).orElse("").toString(); + } + + @Override + public String getSeoDescription() { + return getByProperty(SeoProperties.DESCRIPTION).orElse("").toString(); + } + @Override public long getBirthday() { return getByProperty(PrimaryProperties.BIRTHDAY, Long.class).orElseGet(() -> { diff --git a/src/main/resources/migration/V3__migrate_1.3.0-beta.1_to_1.3.0-beta.2.sql b/src/main/resources/migration/V3__migrate_1.3.0-beta.1_to_1.3.0-beta.2.sql index 4c78843db..81414c7d7 100644 --- a/src/main/resources/migration/V3__migrate_1.3.0-beta.1_to_1.3.0-beta.2.sql +++ b/src/main/resources/migration/V3__migrate_1.3.0-beta.1_to_1.3.0-beta.2.sql @@ -4,6 +4,7 @@ update posts set `slug`=`url`; alter table posts modify slug varchar(255) not null; alter table posts modify url varchar(255) null; +alter table posts modify summary longtext default ''; -- Migrate categories Table update categories set `slug`=`slug_name`; diff --git a/src/main/resources/templates/themes/anatole b/src/main/resources/templates/themes/anatole index b50e52376..a25940ca7 160000 --- a/src/main/resources/templates/themes/anatole +++ b/src/main/resources/templates/themes/anatole @@ -1 +1 @@ -Subproject commit b50e52376237f47b9da289d8feafe891332e0943 +Subproject commit a25940ca70146600bbf371386f9e9a87948f3e6f