mirror of https://github.com/halo-dev/halo
parent
7166829d87
commit
f4a4d5f250
|
@ -13,19 +13,22 @@ import org.springframework.lang.NonNull;
|
|||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
|
||||
import run.halo.app.model.dto.CategoryDTO;
|
||||
import run.halo.app.model.entity.Category;
|
||||
import run.halo.app.model.entity.Post;
|
||||
import run.halo.app.model.enums.PostStatus;
|
||||
import run.halo.app.model.vo.PostDetailVO;
|
||||
import run.halo.app.service.CategoryService;
|
||||
import run.halo.app.service.OptionService;
|
||||
import run.halo.app.service.PostCategoryService;
|
||||
import run.halo.app.service.PostService;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
|
||||
import static org.springframework.data.domain.Sort.Direction.DESC;
|
||||
|
@ -39,15 +42,27 @@ import static org.springframework.data.domain.Sort.Direction.DESC;
|
|||
public class ContentFeedController {
|
||||
|
||||
private final static String UTF_8_SUFFIX = ";charset=UTF-8";
|
||||
|
||||
private final static String XML_MEDIA_TYPE = MediaType.APPLICATION_XML_VALUE + UTF_8_SUFFIX;
|
||||
|
||||
private final PostService postService;
|
||||
|
||||
private final CategoryService categoryService;
|
||||
|
||||
private final PostCategoryService postCategoryService;
|
||||
|
||||
private final OptionService optionService;
|
||||
|
||||
private final FreeMarkerConfigurer freeMarker;
|
||||
|
||||
public ContentFeedController(PostService postService,
|
||||
CategoryService categoryService,
|
||||
PostCategoryService postCategoryService,
|
||||
OptionService optionService,
|
||||
FreeMarkerConfigurer freeMarker) {
|
||||
this.postService = postService;
|
||||
this.categoryService = categoryService;
|
||||
this.postCategoryService = postCategoryService;
|
||||
this.optionService = optionService;
|
||||
this.freeMarker = freeMarker;
|
||||
}
|
||||
|
@ -56,9 +71,9 @@ public class ContentFeedController {
|
|||
* Get post rss
|
||||
*
|
||||
* @param model model
|
||||
* @return String
|
||||
* @throws IOException IOException
|
||||
* @throws TemplateException TemplateException
|
||||
* @return rss xml content
|
||||
* @throws IOException throw IOException
|
||||
* @throws TemplateException throw TemplateException
|
||||
*/
|
||||
@GetMapping(value = {"feed", "feed.xml", "rss", "rss.xml"}, produces = XML_MEDIA_TYPE)
|
||||
@ResponseBody
|
||||
|
@ -68,11 +83,31 @@ public class ContentFeedController {
|
|||
return FreeMarkerTemplateUtils.processTemplateIntoString(template, model);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get category post rss.
|
||||
*
|
||||
* @param model model
|
||||
* @param slugName slugName
|
||||
* @return rss xml content
|
||||
* @throws IOException throw IOException
|
||||
* @throws TemplateException throw TemplateException
|
||||
*/
|
||||
@GetMapping(value = {"feed/categories/{slugName}", "feed/categories/{slugName}.xml"}, produces = XML_MEDIA_TYPE)
|
||||
@ResponseBody
|
||||
public String feed(Model model, @PathVariable(name = "slugName") String slugName) throws IOException, TemplateException {
|
||||
Category category = categoryService.getBySlugNameOfNonNull(slugName);
|
||||
CategoryDTO categoryDTO = categoryService.convertTo(category);
|
||||
model.addAttribute("category", categoryDTO);
|
||||
model.addAttribute("posts", buildCategoryPosts(buildPostPageable(optionService.getRssPageSize()), categoryDTO));
|
||||
Template template = freeMarker.getConfiguration().getTemplate("common/web/rss.ftl");
|
||||
return FreeMarkerTemplateUtils.processTemplateIntoString(template, model);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get atom.xml
|
||||
*
|
||||
* @param model model
|
||||
* @return String
|
||||
* @return atom xml content
|
||||
* @throws IOException IOException
|
||||
* @throws TemplateException TemplateException
|
||||
*/
|
||||
|
@ -84,11 +119,31 @@ public class ContentFeedController {
|
|||
return FreeMarkerTemplateUtils.processTemplateIntoString(template, model);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get category posts atom.xml
|
||||
*
|
||||
* @param model model
|
||||
* @param slugName slugName
|
||||
* @return atom xml content
|
||||
* @throws IOException throw IOException
|
||||
* @throws TemplateException throw TemplateException
|
||||
*/
|
||||
@GetMapping(value = {"atom/categories/{slugName}", "atom/categories/{slugName}.xml"}, produces = XML_MEDIA_TYPE)
|
||||
@ResponseBody
|
||||
public String atom(Model model, @PathVariable(name = "slugName") String slugName) throws IOException, TemplateException {
|
||||
Category category = categoryService.getBySlugNameOfNonNull(slugName);
|
||||
CategoryDTO categoryDTO = categoryService.convertTo(category);
|
||||
model.addAttribute("category", categoryDTO);
|
||||
model.addAttribute("posts", buildCategoryPosts(buildPostPageable(optionService.getRssPageSize()), categoryDTO));
|
||||
Template template = freeMarker.getConfiguration().getTemplate("common/web/atom.ftl");
|
||||
return FreeMarkerTemplateUtils.processTemplateIntoString(template, model);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get sitemap.xml.
|
||||
*
|
||||
* @param model model
|
||||
* @return String
|
||||
* @return sitemap xml content.
|
||||
* @throws IOException IOException
|
||||
* @throws TemplateException TemplateException
|
||||
*/
|
||||
|
@ -105,7 +160,7 @@ public class ContentFeedController {
|
|||
* Get sitemap.html.
|
||||
*
|
||||
* @param model model
|
||||
* @return String
|
||||
* @return template path: common/web/sitemap_html
|
||||
*/
|
||||
@GetMapping(value = "sitemap.html")
|
||||
public String sitemapHtml(Model model,
|
||||
|
@ -115,10 +170,10 @@ public class ContentFeedController {
|
|||
}
|
||||
|
||||
/**
|
||||
* Get robots.
|
||||
* Get robots.txt
|
||||
*
|
||||
* @param model model
|
||||
* @return String
|
||||
* @return robots.txt content
|
||||
* @throws IOException IOException
|
||||
* @throws TemplateException TemplateException
|
||||
*/
|
||||
|
@ -141,22 +196,32 @@ public class ContentFeedController {
|
|||
}
|
||||
|
||||
/**
|
||||
* Build posts for feed
|
||||
* Build posts.
|
||||
*
|
||||
* @param pageable pageable
|
||||
* @return List<Post>
|
||||
* @return list of post detail vo
|
||||
*/
|
||||
private List<PostDetailVO> buildPosts(@NonNull Pageable pageable) {
|
||||
Assert.notNull(pageable, "Pageable must not be null");
|
||||
|
||||
Page<Post> postPage = postService.pageBy(PostStatus.PUBLISHED, pageable);
|
||||
Page<PostDetailVO> posts = postService.convertToDetailVo(postPage);
|
||||
posts.getContent().forEach(postListVO -> {
|
||||
try {
|
||||
// Encode post url
|
||||
postListVO.setUrl(URLEncoder.encode(postListVO.getUrl(), StandardCharsets.UTF_8.name()));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
log.warn("Failed to encode url: " + postListVO.getUrl(), e);
|
||||
}
|
||||
});
|
||||
return posts.getContent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Build category posts.
|
||||
*
|
||||
* @param pageable pageable must not be null.
|
||||
* @param slugName slugName must not be null.
|
||||
* @return list of post detail vo.
|
||||
*/
|
||||
private List<PostDetailVO> buildCategoryPosts(@NonNull Pageable pageable, @NonNull CategoryDTO category) {
|
||||
Assert.notNull(pageable, "Pageable must not be null");
|
||||
Assert.notNull(category, "Slug name must not be null");
|
||||
|
||||
Page<Post> postPage = postCategoryService.pagePostBy(category.getId(), PostStatus.PUBLISHED, pageable);
|
||||
Page<PostDetailVO> posts = postService.convertToDetailVo(postPage);
|
||||
return posts.getContent();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,32 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<feed xmlns="http://www.w3.org/2005/Atom">
|
||||
<title type="text">${blog_title!}</title>
|
||||
<#if user.description??>
|
||||
<subtitle type="text">${user.description!}</subtitle>
|
||||
<#if category??>
|
||||
<title type="text">分类:${category.name!} - ${blog_title!}</title>
|
||||
<#else>
|
||||
<title type="text">${blog_title!}</title>
|
||||
</#if>
|
||||
<#if category??>
|
||||
<#if category.description?? && category.description!=''>
|
||||
<subtitle type="text">${category.description!}</subtitle>
|
||||
</#if>
|
||||
<#else>
|
||||
<#if user.description?? && user.description!=''>
|
||||
<subtitle type="text">${user.description!}</subtitle>
|
||||
</#if>
|
||||
</#if>
|
||||
<updated>${.now?iso_local}</updated>
|
||||
<id>${blog_url!}</id>
|
||||
<link rel="alternate" type="text/html" href="${blog_url!}" />
|
||||
<link rel="self" type="application/atom+xml" href="${atom_url!}" />
|
||||
<#if category??>
|
||||
<id>${category.fullPath!}</id>
|
||||
<#else>
|
||||
<id>${blog_url!}</id>
|
||||
</#if>
|
||||
<#if category??>
|
||||
<link rel="alternate" type="text/html" href="${category.fullPath!}" />
|
||||
<link rel="self" type="application/atom+xml" href="${blog_url!}/feed/categories/${category.slugName}.xml" />
|
||||
<#else>
|
||||
<link rel="alternate" type="text/html" href="${blog_url!}" />
|
||||
<link rel="self" type="application/atom+xml" href="${atom_url!}" />
|
||||
</#if>
|
||||
<rights>Copyright © ${.now?string('yyyy')}, ${blog_title!}</rights>
|
||||
<generator uri="https://halo.run/" version="${version!}">Halo</generator>
|
||||
<#if posts?? && posts?size gt 0>
|
||||
|
|
|
@ -1,10 +1,24 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<rss version="2.0">
|
||||
<channel>
|
||||
<title>${blog_title!}</title>
|
||||
<link>${blog_url!}</link>
|
||||
<#if user.description??>
|
||||
<description>${user.description!}</description>
|
||||
<#if category??>
|
||||
<title>分类:${category.name!} - ${blog_title!}</title>
|
||||
<#else>
|
||||
<title>${blog_title!}</title>
|
||||
</#if>
|
||||
<#if category??>
|
||||
<link>${category.fullPath!}</link>
|
||||
<#else>
|
||||
<link>${blog_url!}</link>
|
||||
</#if>
|
||||
<#if category??>
|
||||
<#if category.description?? && category.description!=''>
|
||||
<description>${category.description!}</description>
|
||||
</#if>
|
||||
<#else>
|
||||
<#if user.description?? && user.description!=''>
|
||||
<description>${user.description!}</description>
|
||||
</#if>
|
||||
</#if>
|
||||
<language>zh-CN</language>
|
||||
<generator>Halo ${version!}</generator>
|
||||
|
|
Loading…
Reference in New Issue