feat: support meta_keywords and meta_description in every page. (#612)

pull/619/head
Ryan Wang 2020-03-04 20:03:08 +08:00 committed by GitHub
parent a9fedef8b2
commit d82f3847c2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 186 additions and 94 deletions

View File

@ -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");
}

View File

@ -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");
}
}

View File

@ -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");
}
}

View File

@ -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");
}
}

View File

@ -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");
}
}

View File

@ -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");
}
}

View File

@ -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<Tag> tags = postTagService.listTagsBy(post.getId());
List<PostMeta> 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");
}
}

View File

@ -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);

View File

@ -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");
}
}

View File

@ -24,9 +24,6 @@ public class CategoryDTO implements OutputConverter<CategoryDTO, Category> {
private String name;
@Deprecated
private String slugName;
private String slug;
private String description;

View File

@ -20,9 +20,6 @@ public class TagDTO implements OutputConverter<TagDTO, Tag> {
private String name;
@Deprecated
private String slugName;
private String slug;
private String thumbnail;

View File

@ -28,9 +28,6 @@ public class BasePostMinimalDTO implements OutputConverter<BasePostMinimalDTO, B
private PostStatus status;
@Deprecated
private String url;
private String slug;
private PostEditorType editorType;
@ -41,5 +38,9 @@ public class BasePostMinimalDTO implements OutputConverter<BasePostMinimalDTO, B
private Date editTime;
private String metaKeywords;
private String metaDescription;
private String fullPath;
}

View File

@ -3,7 +3,6 @@ package run.halo.app.model.dto.post;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import run.halo.app.model.enums.PostCreateFrom;
/**
* Base page simple output dto.
@ -29,7 +28,5 @@ public class BasePostSimpleDTO extends BasePostMinimalDTO {
private Integer topPriority = 0;
private PostCreateFrom createFrom;
private Long likes = 0L;
}

View File

@ -3,7 +3,6 @@ package run.halo.app.model.entity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import run.halo.app.model.enums.PostCreateFrom;
import run.halo.app.model.enums.PostEditorType;
import run.halo.app.model.enums.PostStatus;
@ -44,7 +43,7 @@ public class BasePost extends BaseEntity {
* Post url.
*/
@Deprecated
@Column(name = "url", columnDefinition = "varchar(255) not null", unique = true)
@Column(name = "url", columnDefinition = "varchar(255) not null")
private String url;
/**
@ -76,7 +75,7 @@ public class BasePost extends BaseEntity {
/**
* Post summary.
*/
@Column(name = "summary", columnDefinition = "varchar(500) default ''")
@Column(name = "summary", columnDefinition = "longtext default ''")
private String summary;
/**
@ -115,12 +114,6 @@ public class BasePost extends BaseEntity {
@Column(name = "top_priority", columnDefinition = "int default 0")
private Integer topPriority;
/**
* Create from,server or WeChat.
*/
@Column(name = "create_from", columnDefinition = "int default 0")
private PostCreateFrom createFrom;
/**
* Likes
*/
@ -134,6 +127,18 @@ public class BasePost extends BaseEntity {
@Temporal(TemporalType.TIMESTAMP)
private Date editTime;
/**
* Meta keywords.
*/
@Column(name = "meta_keywords", columnDefinition = "varchar(500) default ''")
private String metaKeywords;
/**
* Meta description.
*/
@Column(name = "meta_description", columnDefinition = "varchar(1023) default ''")
private String metaDescription;
@Override
public void prePersist() {
super.prePersist();
@ -172,10 +177,6 @@ public class BasePost extends BaseEntity {
topPriority = 0;
}
if (createFrom == null) {
createFrom = PostCreateFrom.ADMIN;
}
if (visits == null || visits < 0) {
visits = 0L;
}

View File

@ -1,30 +0,0 @@
package run.halo.app.model.enums;
/**
* Post create from type.
*
* @author johnniang
*/
public enum PostCreateFrom implements ValueEnum<Integer> {
/**
*
*/
ADMIN(0),
/**
*
*/
WECHAT(1);
private final Integer value;
PostCreateFrom(Integer value) {
this.value = value;
}
@Override
public Integer getValue() {
return value;
}
}

View File

@ -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<PostCreateFrom, Integer> {
public PostCreateFromConverter() {
super(PostCreateFrom.class);
}
}

View File

@ -23,9 +23,6 @@ public class CategoryParam implements InputConverter<Category> {
@Size(max = 255, message = "分类名称的字符长度不能超过 {max}")
private String name;
@Deprecated
private String slugName;
@Size(max = 255, message = "分类别名的字符长度不能超过 {max}")
private String slug;

View File

@ -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<Post> {
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<Post> {
private Date createTime;
private PostCreateFrom createFrom = PostCreateFrom.ADMIN;
private String metaKeywords;
private String metaDescription;
private Set<Integer> tagIds;

View File

@ -33,9 +33,6 @@ public class SheetParam implements InputConverter<Sheet> {
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<Sheet> {
private Boolean disallowComment = false;
private Date createTime;
@Size(max = 255, message = "页面密码的字符长度不能超过 {max}")
private String password;
@ -61,6 +56,12 @@ public class SheetParam implements InputConverter<Sheet> {
@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<SheetMetaParam> sheetMetas;
@Override

View File

@ -23,9 +23,6 @@ public class TagParam implements InputConverter<Tag> {
@Size(max = 255, message = "标签名称的字符长度不能超过 {max}")
private String name;
@Deprecated
private String slugName;
@Size(max = 255, message = "标签别名的字符长度不能超过 {max}")
private String slug;

View File

@ -354,6 +354,20 @@ public interface OptionService extends CrudService<Option, Integer> {
@NonNull
String getBlogTitle();
/**
* Gets global seo keywords.
*
* @return keywords
*/
String getSeoKeywords();
/**
* Get global seo description.
*
* @return description
*/
String getSeoDescription();
/**
* Gets blog birthday.
*

View File

@ -308,4 +308,12 @@ public interface BasePostService<POST extends BasePost> extends CrudService<POST
*/
@NonNull
List<BasePostDetailDTO> replaceUrl(@NonNull String oldUrl, @NonNull String newUrl);
/**
* Generate description.
*
* @param content html content must not be null.
* @return description
*/
String generateDescription(@NonNull String content);
}

View File

@ -425,6 +425,21 @@ public abstract class BasePostServiceImpl<POST extends BasePost> 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

View File

@ -469,6 +469,16 @@ public class OptionServiceImpl extends AbstractCrudService<Option, Integer> 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(() -> {

View File

@ -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`;

@ -1 +1 @@
Subproject commit b50e52376237f47b9da289d8feafe891332e0943
Subproject commit a25940ca70146600bbf371386f9e9a87948f3e6f