diff --git a/pom.xml b/pom.xml index b21416366..7a53b326f 100755 --- a/pom.xml +++ b/pom.xml @@ -34,7 +34,6 @@ 0.0.4 1.18.4 3.6.3 - 1.0 4.4.2 4.0.1 7.2.18 @@ -120,13 +119,6 @@ ${ehcache.version} - - - rome - rome - ${rome.version} - - cn.hutool diff --git a/src/main/java/cc/ryanc/halo/config/WebMvcAutoConfiguration.java b/src/main/java/cc/ryanc/halo/config/WebMvcAutoConfiguration.java index 621ffe815..27e4737c8 100644 --- a/src/main/java/cc/ryanc/halo/config/WebMvcAutoConfiguration.java +++ b/src/main/java/cc/ryanc/halo/config/WebMvcAutoConfiguration.java @@ -83,8 +83,7 @@ public class WebMvcAutoConfiguration implements WebMvcConfigurer { registry.addResourceHandler("/static/**") .addResourceLocations("classpath:/static/"); registry.addResourceHandler("/**") - .addResourceLocations("classpath:/templates/themes/") - .addResourceLocations("classpath:/robots.txt"); + .addResourceLocations("classpath:/templates/themes/"); registry.addResourceHandler("/upload/**") .addResourceLocations("file:///" + System.getProperties().getProperty("user.home") + "/halo/upload/"); registry.addResourceHandler("/favicon.ico") diff --git a/src/main/java/cc/ryanc/halo/service/PostService.java b/src/main/java/cc/ryanc/halo/service/PostService.java index 2a5bd1131..f35acaa36 100755 --- a/src/main/java/cc/ryanc/halo/service/PostService.java +++ b/src/main/java/cc/ryanc/halo/service/PostService.java @@ -248,22 +248,6 @@ public interface PostService { */ Integer getCountByStatus(Integer status); - /** - * 生成rss - * - * @param posts posts - * @return String - */ - String buildRss(List posts); - - /** - * 生成sitemap - * - * @param posts posts - * @return String - */ - String buildSiteMap(List posts); - /** * 缓存阅读数 * 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 7c86b09d9..ca127cc43 100755 --- a/src/main/java/cc/ryanc/halo/service/impl/PostServiceImpl.java +++ b/src/main/java/cc/ryanc/halo/service/impl/PostServiceImpl.java @@ -508,36 +508,6 @@ public class PostServiceImpl implements PostService { return postRepository.countAllByPostStatusAndPostType(status, PostTypeEnum.POST_TYPE_POST.getDesc()); } - /** - * 生成rss - * - * @param posts posts - * - * @return String - */ - @Override - public String buildRss(List posts) { - String rss = ""; - try { - rss = HaloUtils.getRss(posts); - } catch (Exception e) { - e.printStackTrace(); - } - return rss; - } - - /** - * 生成sitemap - * - * @param posts posts - * - * @return String - */ - @Override - public String buildSiteMap(List posts) { - return HaloUtils.getSiteMap(posts); - } - /** * 缓存阅读数 * diff --git a/src/main/java/cc/ryanc/halo/utils/HaloUtils.java b/src/main/java/cc/ryanc/halo/utils/HaloUtils.java index a2d31b04f..381df8fe2 100755 --- a/src/main/java/cc/ryanc/halo/utils/HaloUtils.java +++ b/src/main/java/cc/ryanc/halo/utils/HaloUtils.java @@ -1,19 +1,11 @@ package cc.ryanc.halo.utils; -import cc.ryanc.halo.model.domain.Post; import cc.ryanc.halo.model.dto.BackupDto; import cc.ryanc.halo.model.dto.Theme; -import cc.ryanc.halo.model.enums.BlogPropertiesEnum; import cc.ryanc.halo.model.enums.CommonParamsEnum; -import cn.hutool.core.date.DateUtil; import cn.hutool.core.io.FileUtil; import cn.hutool.core.text.StrBuilder; import cn.hutool.core.util.StrUtil; -import com.sun.syndication.feed.rss.Channel; -import com.sun.syndication.feed.rss.Content; -import com.sun.syndication.feed.rss.Item; -import com.sun.syndication.io.FeedException; -import com.sun.syndication.io.WireFeedOutput; import io.github.biezhi.ome.OhMyEmail; import lombok.extern.slf4j.Slf4j; import org.springframework.util.Assert; @@ -32,8 +24,6 @@ import java.nio.file.attribute.BasicFileAttributeView; import java.nio.file.attribute.BasicFileAttributes; import java.util.*; -import static cc.ryanc.halo.model.dto.HaloConst.OPTIONS; - /** *
  * 常用工具
@@ -285,84 +275,6 @@ public class HaloUtils {
         }
     }
 
-    /**
-     * 生成rss
-     *
-     * @param posts posts
-     *
-     * @return String
-     *
-     * @throws FeedException FeedException
-     */
-    public static String getRss(List posts) throws FeedException {
-        Assert.notEmpty(posts, "posts must not be empty");
-
-        final Channel channel = new Channel("rss_2.0");
-        if (null == OPTIONS.get(BlogPropertiesEnum.BLOG_TITLE.getProp())) {
-            channel.setTitle("");
-        } else {
-            channel.setTitle(OPTIONS.get(BlogPropertiesEnum.BLOG_TITLE.getProp()));
-        }
-        if (null == OPTIONS.get(BlogPropertiesEnum.BLOG_URL.getProp())) {
-            channel.setLink("");
-        } else {
-            channel.setLink(OPTIONS.get(BlogPropertiesEnum.BLOG_URL.getProp()));
-        }
-        if (null == OPTIONS.get(BlogPropertiesEnum.SEO_DESC.getProp())) {
-            channel.setDescription("");
-        } else {
-            channel.setDescription(OPTIONS.get(BlogPropertiesEnum.SEO_DESC.getProp()));
-        }
-        channel.setLanguage("zh-CN");
-        final List items = new ArrayList<>();
-        for (Post post : posts) {
-            final Item item = new Item();
-            item.setTitle(post.getPostTitle());
-            final Content content = new Content();
-            String value = post.getPostContent();
-            final char[] xmlChar = value.toCharArray();
-            for (int i = 0; i < xmlChar.length; ++i) {
-                if (xmlChar[i] > 0xFFFD) {
-                    xmlChar[i] = ' ';
-                } else if (xmlChar[i] < 0x20 && xmlChar[i] != 't' & xmlChar[i] != 'n' & xmlChar[i] != 'r') {
-                    xmlChar[i] = ' ';
-                }
-            }
-            value = new String(xmlChar);
-            content.setValue(value);
-            item.setContent(content);
-            item.setLink(OPTIONS.get(BlogPropertiesEnum.BLOG_URL.getProp()) + "/archives/" + post.getPostUrl());
-            item.setPubDate(post.getPostDate());
-            items.add(item);
-        }
-        channel.setItems(items);
-        final WireFeedOutput out = new WireFeedOutput();
-        return out.outputString(channel);
-    }
-
-    /**
-     * 获取sitemap
-     *
-     * @param posts posts
-     *
-     * @return String
-     */
-    public static String getSiteMap(List posts) {
-        Assert.notEmpty(posts, "post mut not be empty");
-        final StrBuilder head = new StrBuilder("\n");
-        final StrBuilder urlBody = new StrBuilder();
-        final String urlPath = OPTIONS.get(BlogPropertiesEnum.BLOG_URL.getProp()) + "/archives/";
-        for (Post post : posts) {
-            urlBody.append("");
-            urlBody.append(urlPath);
-            urlBody.append(post.getPostUrl());
-            urlBody.append("");
-            urlBody.append(DateUtil.format(post.getPostDate(), "yyyy-MM-dd'T'HH:mm:ss.SSSXXX"));
-            urlBody.append("");
-        }
-        return head.append(urlBody).append("").toString();
-    }
-
     /**
      * 配置邮件
      *
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 474ba865d..956914b9f 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
@@ -1,23 +1,28 @@
 package cc.ryanc.halo.web.controller.front;
 
 import cc.ryanc.halo.model.domain.Post;
-import cc.ryanc.halo.model.dto.HaloConst;
 import cc.ryanc.halo.model.enums.BlogPropertiesEnum;
 import cc.ryanc.halo.model.enums.PostTypeEnum;
 import cc.ryanc.halo.service.PostService;
 import cn.hutool.core.util.StrUtil;
+import freemarker.template.Template;
+import freemarker.template.TemplateException;
 import org.springframework.beans.factory.annotation.Autowired;
 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.ui.freemarker.FreeMarkerTemplateUtils;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
 
+import java.io.IOException;
 import java.util.List;
 
-import static cc.ryanc.halo.model.dto.HaloConst.*;
+import static cc.ryanc.halo.model.dto.HaloConst.OPTIONS;
 
 /**
  * 
@@ -33,51 +38,102 @@ public class FrontOthersController {
     @Autowired
     private PostService postService;
 
+    @Autowired
+    private FreeMarkerConfigurer freeMarker;
+
     /**
      * 获取文章rss
      *
-     * @return rss
+     * @param model model
+     *
+     * @return String
+     *
+     * @throws IOException       IOException
+     * @throws TemplateException TemplateException
      */
     @GetMapping(value = {"feed", "feed.xml", "atom", "atom.xml"}, produces = "application/xml;charset=UTF-8")
     @ResponseBody
-    public String feed() {
+    public String feed(Model model) throws IOException, TemplateException {
         String rssPosts = OPTIONS.get(BlogPropertiesEnum.RSS_POSTS.getProp());
         if (StrUtil.isBlank(rssPosts)) {
             rssPosts = "20";
         }
-        //获取文章列表并根据时间排序
         final Sort sort = new Sort(Sort.Direction.DESC, "postDate");
         final Pageable pageable = PageRequest.of(0, Integer.parseInt(rssPosts), sort);
         final Page postsPage = postService.findPostByStatus(0, PostTypeEnum.POST_TYPE_POST.getDesc(), pageable).map(post -> {
-            if(StrUtil.isNotEmpty(post.getPostPassword())){
+            if (StrUtil.isNotEmpty(post.getPostPassword())) {
                 post.setPostContent("该文章为加密文章");
                 post.setPostSummary("该文章为加密文章");
             }
             return post;
         });
         final List posts = postsPage.getContent();
-        return postService.buildRss(posts);
+        model.addAttribute("posts", posts);
+        final Template template = freeMarker.getConfiguration().getTemplate("common/web/rss.ftl");
+        return FreeMarkerTemplateUtils.processTemplateIntoString(template, model);
     }
 
     /**
-     * 获取sitemap
+     * 获取 XML 格式的站点地图
      *
-     * @return sitemap
+     * @param model model
+     *
+     * @return String
+     *
+     * @throws IOException       IOException
+     * @throws TemplateException TemplateException
      */
     @GetMapping(value = {"sitemap", "sitemap.xml"}, produces = "application/xml;charset=UTF-8")
     @ResponseBody
-    public String siteMap() {
-        //获取文章列表并根据时间排序
-        final Sort sort = new Sort(Sort.Direction.DESC, "postDate");
-        final Pageable pageable = PageRequest.of(0, 999, sort);
-        final Page postsPage = postService.findPostByStatus(0, PostTypeEnum.POST_TYPE_POST.getDesc(), pageable).map(post -> {
-            if(StrUtil.isNotEmpty(post.getPostPassword())){
+    public String sitemapXml(Model model) throws IOException, TemplateException {
+        final Page postsPage = postService.findPostByStatus(0, PostTypeEnum.POST_TYPE_POST.getDesc(), null).map(post -> {
+            if (StrUtil.isNotEmpty(post.getPostPassword())) {
                 post.setPostContent("该文章为加密文章");
                 post.setPostSummary("该文章为加密文章");
             }
             return post;
         });
         final List posts = postsPage.getContent();
-        return postService.buildSiteMap(posts);
+        model.addAttribute("posts", posts);
+        final Template template = freeMarker.getConfiguration().getTemplate("common/web/sitemap_xml.ftl");
+        return FreeMarkerTemplateUtils.processTemplateIntoString(template, model);
+    }
+
+    /**
+     * 获取 HTML 格式的站点地图
+     *
+     * @param model model
+     *
+     * @return String
+     */
+    @GetMapping(value = "sitemap.html", produces = {"text/html"})
+    public String sitemapHtml(Model model) {
+        final Page postsPage = postService.findPostByStatus(0, PostTypeEnum.POST_TYPE_POST.getDesc(), null).map(post -> {
+            if (StrUtil.isNotEmpty(post.getPostPassword())) {
+                post.setPostContent("该文章为加密文章");
+                post.setPostSummary("该文章为加密文章");
+            }
+            return post;
+        });
+        final List posts = postsPage.getContent();
+        model.addAttribute("posts", posts);
+        return "common/web/sitemap_html";
+    }
+
+    /**
+     * robots
+     *
+     * @param model model
+     *
+     * @return String
+     *
+     * @throws IOException       IOException
+     * @throws TemplateException TemplateException
+     */
+    @GetMapping(value = "robots.txt", produces = {"text/plain"})
+    @ResponseBody
+    public String robots(Model model) throws IOException, TemplateException {
+        final Template template = freeMarker.getConfiguration().getTemplate("common/web/robots.ftl");
+        return FreeMarkerTemplateUtils.processTemplateIntoString(template, model);
     }
 }
diff --git a/src/main/resources/robots.txt b/src/main/resources/robots.txt
deleted file mode 100644
index f9b88f793..000000000
--- a/src/main/resources/robots.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-User-agent: *
-Disallow: /admin/
-Sitemap: /sitemap.xml
\ No newline at end of file
diff --git a/src/main/resources/templates/common/web/robots.ftl b/src/main/resources/templates/common/web/robots.ftl
new file mode 100644
index 000000000..e7bfbaab7
--- /dev/null
+++ b/src/main/resources/templates/common/web/robots.ftl
@@ -0,0 +1,4 @@
+User-agent: *
+Disallow: /admin/
+Sitemap: ${options.blog_url!}/sitemap.xml
+Sitemap: ${options.blog_url!}/sitemap.html
\ No newline at end of file
diff --git a/src/main/resources/templates/common/web/rss.ftl b/src/main/resources/templates/common/web/rss.ftl
new file mode 100644
index 000000000..27e709958
--- /dev/null
+++ b/src/main/resources/templates/common/web/rss.ftl
@@ -0,0 +1,21 @@
+
+
+    
+        ${options.blog_title!}
+        ${options.blog_url!}
+        <#if user.userDesc??>
+            ${user.userDesc!}
+        
+        zh-CN
+        <#if posts?? && posts?size gt 0>
+            <#list posts as post>
+                
+                    ${post.postTitle!}
+                    ${options.blog_url}/archives/${post.postUrl!}
+                    ${post.postContent!}
+                    ${post.postDate}
+                
+            
+        
+    
+
\ No newline at end of file
diff --git a/src/main/resources/templates/common/web/sitemap_html.ftl b/src/main/resources/templates/common/web/sitemap_html.ftl
new file mode 100644
index 000000000..7577bbf25
--- /dev/null
+++ b/src/main/resources/templates/common/web/sitemap_html.ftl
@@ -0,0 +1,201 @@
+<#--
+see https://gitee.com/yadong.zhang/DBlog/blob/master/blog-web/src/main/java/com/zyd/blog/controller/RestWebSiteController.java
+-->
+<#compress >
+
+
+
+    
+    
+    ${options.blog_title!} 网站地图
+    
+    
+
+
+

${options.blog_title!} 网站地图

+ +
+

最新文章

+ +
+
+

分类目录

+
    + <@commonTag method="categories"> + <#if categories?? && categories?size gt 0> + <#list categories as cate> +
  • + +
    ${options.blog_start!}
    +
    daily
    +
    0.6
    +
  • +
    + + + +
+
+
+

标签目录

+ +
+ + + + \ No newline at end of file diff --git a/src/main/resources/templates/common/web/sitemap_xml.ftl b/src/main/resources/templates/common/web/sitemap_xml.ftl new file mode 100644 index 000000000..732d7ed52 --- /dev/null +++ b/src/main/resources/templates/common/web/sitemap_xml.ftl @@ -0,0 +1,11 @@ + + + <#if posts?? && posts?size gt 0> + <#list posts as post> + + ${options.blog_url!}/archives/${post.postUrl!} + ${post.postDate?iso_local} + + + + \ No newline at end of file