feat: optimize source project pages and SEO
This commit is contained in:
@@ -14,6 +14,7 @@ import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.framework.web.service.SysPermissionService;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
@@ -66,7 +67,7 @@ public class CmsBlogController extends BaseController
|
||||
startPage();
|
||||
//状态为发布
|
||||
cmsBlog.setStatus("1");
|
||||
List<CmsBlog> list = cmsBlogService.selectCmsBlogList(cmsBlog);
|
||||
List<CmsBlog> list = cmsBlogService.selectCmsBlogCardList(cmsBlog);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
@@ -74,7 +75,7 @@ public class CmsBlogController extends BaseController
|
||||
* 首页获取文章详细信息
|
||||
*/
|
||||
@GetMapping(value = { "/cms/detail/", "/cms/detail/{id}" })
|
||||
public AjaxResult getInfoDetail(@PathVariable(value = "id", required = false) Long id)
|
||||
public ResponseEntity<AjaxResult> getInfoDetail(@PathVariable(value = "id", required = false) Long id)
|
||||
{
|
||||
AjaxResult ajax = AjaxResult.success();
|
||||
CmsType cmsType = new CmsType();
|
||||
@@ -83,9 +84,14 @@ public class CmsBlogController extends BaseController
|
||||
ajax.put("tags", cmsTagService.selectCmsTagList(cmsTag));
|
||||
if (StringUtils.isNotNull(id))
|
||||
{
|
||||
ajax.put(AjaxResult.DATA_TAG, cmsBlogService.selectCmsBlogById(id));
|
||||
CmsBlog blog = cmsBlogService.selectPublishedCmsBlogById(id);
|
||||
if (blog == null)
|
||||
{
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
ajax.put(AjaxResult.DATA_TAG, blog);
|
||||
}
|
||||
return ajax;
|
||||
return ResponseEntity.ok(ajax);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -127,14 +133,18 @@ public class CmsBlogController extends BaseController
|
||||
* 首页增加阅读量
|
||||
*/
|
||||
@GetMapping("/cms/addBlogViews/{id}")
|
||||
public AjaxResult addBlogViews(@PathVariable(value = "id", required = false) Long id)
|
||||
public ResponseEntity<AjaxResult> addBlogViews(@PathVariable(value = "id", required = false) Long id)
|
||||
{
|
||||
CmsBlog cmsBlog = cmsBlogService.selectCmsBlogById(id);
|
||||
CmsBlog cmsBlog = cmsBlogService.selectPublishedCmsBlogById(id);
|
||||
if (cmsBlog == null)
|
||||
{
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
Long views = cmsBlog.getViews();
|
||||
views+=Long.parseLong("1");
|
||||
views = views == null ? 1L : views + 1L;
|
||||
cmsBlog.setViews(views);
|
||||
cmsBlogService.updateCmsBlog(cmsBlog);
|
||||
return AjaxResult.success(id);
|
||||
return ResponseEntity.ok(AjaxResult.success(id));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -8,6 +8,7 @@ package com.ruoyi.cms.blog.domain;
|
||||
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
import com.ruoyi.cms.tag.domain.CmsTag;
|
||||
|
||||
/**
|
||||
* @Author: WangNing
|
||||
@@ -18,6 +19,7 @@ public class CmsBlogTag {
|
||||
private Long tagId;
|
||||
private Long blogId;
|
||||
private Long[] tagIds;
|
||||
private CmsTag tag;
|
||||
|
||||
public Long getTagId() {
|
||||
return tagId;
|
||||
@@ -43,6 +45,14 @@ public class CmsBlogTag {
|
||||
this.tagIds = tagIds;
|
||||
}
|
||||
|
||||
public CmsTag getTag() {
|
||||
return tag;
|
||||
}
|
||||
|
||||
public void setTag(CmsTag tag) {
|
||||
this.tag = tag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
|
||||
|
||||
@@ -8,6 +8,7 @@ package com.ruoyi.cms.blog.domain;
|
||||
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
import com.ruoyi.cms.type.domain.CmsType;
|
||||
|
||||
/**
|
||||
* @Author: WangNing
|
||||
@@ -18,6 +19,7 @@ public class CmsBlogType {
|
||||
private Long typeId;
|
||||
private Long blogId;
|
||||
private Long[] typeIds;
|
||||
private CmsType type;
|
||||
|
||||
public Long getTypeId() {
|
||||
return typeId;
|
||||
@@ -43,6 +45,14 @@ public class CmsBlogType {
|
||||
this.typeIds = typeIds;
|
||||
}
|
||||
|
||||
public CmsType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(CmsType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
|
||||
|
||||
@@ -20,6 +20,11 @@ public interface CmsBlogMapper
|
||||
*/
|
||||
public CmsBlog selectCmsBlogById(Long id);
|
||||
|
||||
/**
|
||||
* Query a public detail page. Drafts must behave like missing pages.
|
||||
*/
|
||||
public CmsBlog selectPublishedCmsBlogById(Long id);
|
||||
|
||||
/**
|
||||
* 查询文章管理列表
|
||||
*
|
||||
@@ -28,6 +33,16 @@ public interface CmsBlogMapper
|
||||
*/
|
||||
public List<CmsBlog> selectCmsBlogList(CmsBlog cmsBlog);
|
||||
|
||||
/**
|
||||
* 查询首页卡片所需的轻量字段
|
||||
*/
|
||||
public List<CmsBlog> selectCmsBlogCardList(CmsBlog cmsBlog);
|
||||
|
||||
/**
|
||||
* 批量读取缺少封面的文章正文,用于提取首图
|
||||
*/
|
||||
public List<CmsBlog> selectCmsBlogContentByIds(List<Long> ids);
|
||||
|
||||
public List<CmsBlog> selectCmsBlogListBetweenCreateTime(@Param("title") String title,@Param("type") String type,@Param("top") String top,@Param("status") String status,@Param("createTimeBegin") String createTimeBegin,@Param("createTimeEnd") String createTimeEnd,@Param("createBy") String createBy);
|
||||
|
||||
/**
|
||||
|
||||
@@ -27,6 +27,10 @@ public interface CmsBlogTagMapper {
|
||||
* 查询文件列表
|
||||
*/
|
||||
public List<CmsBlogTag> selectBlogTagList(Long blogId);
|
||||
/**
|
||||
* 批量查询博客及其标签,避免列表页逐条查询
|
||||
*/
|
||||
public List<CmsBlogTag> selectBlogTagsByBlogIds(List<Long> blogIds);
|
||||
/**
|
||||
* 通过tagId删除blog文件关联
|
||||
*/
|
||||
|
||||
@@ -27,6 +27,10 @@ public interface CmsBlogTypeMapper {
|
||||
* 查询博客列表
|
||||
*/
|
||||
public List<CmsBlogType> selectBlogTypeList(Long blogId);
|
||||
/**
|
||||
* 批量查询博客及其分类,避免列表页逐条查询
|
||||
*/
|
||||
public List<CmsBlogType> selectBlogTypesByBlogIds(List<Long> blogIds);
|
||||
/**
|
||||
* 通过typeId删除blog文件关联
|
||||
*/
|
||||
|
||||
@@ -19,6 +19,14 @@ public interface ICmsBlogService
|
||||
*/
|
||||
public CmsBlog selectCmsBlogById(Long id);
|
||||
|
||||
/**
|
||||
* Query an indexable public detail page.
|
||||
*
|
||||
* @param id content primary key
|
||||
* @return published content, or null when it must not be indexed
|
||||
*/
|
||||
public CmsBlog selectPublishedCmsBlogById(Long id);
|
||||
|
||||
/**
|
||||
* 查询文章管理列表
|
||||
*
|
||||
@@ -27,6 +35,11 @@ public interface ICmsBlogService
|
||||
*/
|
||||
public List<CmsBlog> selectCmsBlogList(CmsBlog cmsBlog);
|
||||
|
||||
/**
|
||||
* 查询首页项目卡片列表
|
||||
*/
|
||||
public List<CmsBlog> selectCmsBlogCardList(CmsBlog cmsBlog);
|
||||
|
||||
/**
|
||||
* 查询推荐文章列表
|
||||
*/
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package com.ruoyi.cms.blog.service.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@@ -54,6 +56,10 @@ public class CmsBlogServiceImpl implements ICmsBlogService
|
||||
public CmsBlog selectCmsBlogById(Long id)
|
||||
{
|
||||
CmsBlog blog = cmsBlogMapper.selectCmsBlogById(id);
|
||||
if (blog == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
//查询标签列表
|
||||
List<CmsBlogTag> blogTagList = cmsBlogTagMapper.selectBlogTagList(id);
|
||||
Long[] tagIds = new Long[blogTagList.size()];
|
||||
@@ -83,6 +89,13 @@ public class CmsBlogServiceImpl implements ICmsBlogService
|
||||
return blog;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CmsBlog selectPublishedCmsBlogById(Long id)
|
||||
{
|
||||
CmsBlog blog = selectCmsBlogById(id);
|
||||
return blog != null && "1".equals(blog.getStatus()) ? blog : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询文章管理列表
|
||||
*
|
||||
@@ -103,18 +116,19 @@ public class CmsBlogServiceImpl implements ICmsBlogService
|
||||
return blogList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CmsBlog> selectCmsBlogCardList(CmsBlog cmsBlog)
|
||||
{
|
||||
return prepareBlogCards(cmsBlogMapper.selectCmsBlogCardList(cmsBlog));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询推荐文章列表
|
||||
*/
|
||||
@Override
|
||||
public List<CmsBlog> selectCmsBlogListRecommend(CmsBlog cmsBlog) {
|
||||
List<CmsBlog> cmsBlogList = cmsBlogMapper.selectCmsBlogListRecommend(cmsBlog);
|
||||
// 为每个博客设置首页图片(如果为空,则从content中提取)
|
||||
for (CmsBlog blog : cmsBlogList) {
|
||||
setDefaultBlogPicFromContent(blog);
|
||||
}
|
||||
List<CmsBlog> blogList = BlogListAddTypeAndTag(cmsBlogList);
|
||||
return blogList;
|
||||
return prepareBlogCards(cmsBlogList);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -123,12 +137,7 @@ public class CmsBlogServiceImpl implements ICmsBlogService
|
||||
@Override
|
||||
public List<CmsBlog> selectCmsBlogListByTypeId(Long id) {
|
||||
List<CmsBlog> cmsBlogList = cmsBlogMapper.selectCmsBlogListByTypeId(id);
|
||||
// 为每个博客设置首页图片(如果为空,则从content中提取)
|
||||
for (CmsBlog blog : cmsBlogList) {
|
||||
setDefaultBlogPicFromContent(blog);
|
||||
}
|
||||
List<CmsBlog> blogList = BlogListAddTypeAndTag(cmsBlogList);
|
||||
return blogList;
|
||||
return prepareBlogCards(cmsBlogList);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -137,12 +146,7 @@ public class CmsBlogServiceImpl implements ICmsBlogService
|
||||
@Override
|
||||
public List<CmsBlog> selectCmsBlogListByTagId(Long id) {
|
||||
List<CmsBlog> cmsBlogList = cmsBlogMapper.selectCmsBlogListByTagId(id);
|
||||
// 为每个博客设置首页图片(如果为空,则从content中提取)
|
||||
for (CmsBlog blog : cmsBlogList) {
|
||||
setDefaultBlogPicFromContent(blog);
|
||||
}
|
||||
List<CmsBlog> blogList = BlogListAddTypeAndTag(cmsBlogList);
|
||||
return blogList;
|
||||
return prepareBlogCards(cmsBlogList);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -307,30 +311,71 @@ public class CmsBlogServiceImpl implements ICmsBlogService
|
||||
return null;
|
||||
}
|
||||
|
||||
private List<CmsBlog> BlogListAddTypeAndTag(List<CmsBlog> cmsBlogList){
|
||||
if (cmsBlogList==null||cmsBlogList.size()<0){
|
||||
/**
|
||||
* 列表不返回正文;仅对没有独立封面的项目批量读取正文并提取首图。
|
||||
*/
|
||||
private List<CmsBlog> prepareBlogCards(List<CmsBlog> cmsBlogList) {
|
||||
if (cmsBlogList == null || cmsBlogList.isEmpty()) {
|
||||
return cmsBlogList;
|
||||
}
|
||||
|
||||
Map<Long, CmsBlog> missingCoverBlogs = new HashMap<>();
|
||||
for (CmsBlog blog : cmsBlogList) {
|
||||
Long blogId = blog.getId();
|
||||
//查询标签列表
|
||||
List<CmsBlogTag> blogTagList = cmsBlogTagMapper.selectBlogTagList(blogId);
|
||||
List<CmsTag> cmsTagList = new ArrayList<>();
|
||||
blogTagList.forEach((CmsBlogTag cmsBlogTag)->{
|
||||
Long tagId = cmsBlogTag.getTagId();
|
||||
CmsTag cmsTag = cmsTagMapper.selectCmsTagByTagId(tagId);
|
||||
cmsTagList.add(cmsTag);
|
||||
});
|
||||
blog.setTags(cmsTagList);
|
||||
//查询分类列表
|
||||
List<CmsBlogType> blogTypeList = cmsBlogTypeMapper.selectBlogTypeList(blogId);
|
||||
List<CmsType> cmsTypeList = new ArrayList<>();
|
||||
blogTypeList.forEach((CmsBlogType cmsBlogType)->{
|
||||
Long typeId = cmsBlogType.getTypeId();
|
||||
CmsType cmsType = cmsTypeMapper.selectCmsTypeByTypeId(typeId);
|
||||
cmsTypeList.add(cmsType);
|
||||
});
|
||||
blog.setTypes(cmsTypeList);
|
||||
boolean hasCover = (blog.getBlogPic() != null && !blog.getBlogPic().trim().isEmpty())
|
||||
|| (blog.getBlogPicLink() != null && !blog.getBlogPicLink().trim().isEmpty());
|
||||
if (!hasCover) {
|
||||
missingCoverBlogs.put(blog.getId(), blog);
|
||||
}
|
||||
}
|
||||
|
||||
if (!missingCoverBlogs.isEmpty()) {
|
||||
List<Long> ids = new ArrayList<>(missingCoverBlogs.keySet());
|
||||
for (CmsBlog contentBlog : cmsBlogMapper.selectCmsBlogContentByIds(ids)) {
|
||||
CmsBlog targetBlog = missingCoverBlogs.get(contentBlog.getId());
|
||||
if (targetBlog == null || contentBlog.getContent() == null) {
|
||||
continue;
|
||||
}
|
||||
String firstImageUrl = extractFirstImageFromContent(contentBlog.getContent());
|
||||
if (firstImageUrl != null && !firstImageUrl.trim().isEmpty()) {
|
||||
targetBlog.setBlogPicType("0");
|
||||
targetBlog.setBlogPicLink(firstImageUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return BlogListAddTypeAndTag(cmsBlogList);
|
||||
}
|
||||
|
||||
private List<CmsBlog> BlogListAddTypeAndTag(List<CmsBlog> cmsBlogList){
|
||||
if (cmsBlogList == null || cmsBlogList.isEmpty()) {
|
||||
return cmsBlogList;
|
||||
}
|
||||
|
||||
List<Long> blogIds = new ArrayList<>();
|
||||
Map<Long, List<CmsTag>> tagsByBlogId = new HashMap<>();
|
||||
Map<Long, List<CmsType>> typesByBlogId = new HashMap<>();
|
||||
for (CmsBlog blog : cmsBlogList) {
|
||||
blogIds.add(blog.getId());
|
||||
tagsByBlogId.put(blog.getId(), new ArrayList<>());
|
||||
typesByBlogId.put(blog.getId(), new ArrayList<>());
|
||||
}
|
||||
|
||||
for (CmsBlogTag relation : cmsBlogTagMapper.selectBlogTagsByBlogIds(blogIds)) {
|
||||
List<CmsTag> tags = tagsByBlogId.get(relation.getBlogId());
|
||||
if (tags != null && relation.getTag() != null) {
|
||||
tags.add(relation.getTag());
|
||||
}
|
||||
}
|
||||
for (CmsBlogType relation : cmsBlogTypeMapper.selectBlogTypesByBlogIds(blogIds)) {
|
||||
List<CmsType> types = typesByBlogId.get(relation.getBlogId());
|
||||
if (types != null && relation.getType() != null) {
|
||||
types.add(relation.getType());
|
||||
}
|
||||
}
|
||||
|
||||
for (CmsBlog blog : cmsBlogList) {
|
||||
blog.setTags(tagsByBlogId.get(blog.getId()));
|
||||
blog.setTypes(typesByBlogId.get(blog.getId()));
|
||||
}
|
||||
return cmsBlogList;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.ruoyi.cms.sitemap.controller;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import com.ruoyi.cms.sitemap.service.SitemapService;
|
||||
import org.springframework.http.CacheControl;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* Public XML sitemap endpoint.
|
||||
*/
|
||||
@RestController
|
||||
public class SitemapController
|
||||
{
|
||||
private static final MediaType APPLICATION_XML_UTF8 =
|
||||
new MediaType("application", "xml", StandardCharsets.UTF_8);
|
||||
|
||||
private final SitemapService sitemapService;
|
||||
|
||||
public SitemapController(SitemapService sitemapService)
|
||||
{
|
||||
this.sitemapService = sitemapService;
|
||||
}
|
||||
|
||||
@GetMapping(value = "/sitemap.xml", produces = MediaType.APPLICATION_XML_VALUE)
|
||||
public ResponseEntity<String> sitemap()
|
||||
{
|
||||
return ResponseEntity.ok()
|
||||
.contentType(APPLICATION_XML_UTF8)
|
||||
.cacheControl(CacheControl.maxAge(10, TimeUnit.MINUTES).cachePublic())
|
||||
.body(sitemapService.buildSitemap());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.ruoyi.cms.sitemap.domain;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* A canonical, indexable URL source used to build the public sitemap.
|
||||
*/
|
||||
public class SitemapUrl
|
||||
{
|
||||
private Long id;
|
||||
|
||||
private String pageType;
|
||||
|
||||
private Date lastModified;
|
||||
|
||||
public Long getId()
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id)
|
||||
{
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getPageType()
|
||||
{
|
||||
return pageType;
|
||||
}
|
||||
|
||||
public void setPageType(String pageType)
|
||||
{
|
||||
this.pageType = pageType;
|
||||
}
|
||||
|
||||
public Date getLastModified()
|
||||
{
|
||||
return lastModified;
|
||||
}
|
||||
|
||||
public void setLastModified(Date lastModified)
|
||||
{
|
||||
this.lastModified = lastModified;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.ruoyi.cms.sitemap.mapper;
|
||||
|
||||
import java.util.List;
|
||||
import com.ruoyi.cms.sitemap.domain.SitemapUrl;
|
||||
|
||||
/**
|
||||
* Queries only URLs that have a real, published public page.
|
||||
*/
|
||||
public interface SitemapMapper
|
||||
{
|
||||
public List<SitemapUrl> selectIndexableCategories();
|
||||
|
||||
public List<SitemapUrl> selectIndexableContent();
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
package com.ruoyi.cms.sitemap.service;
|
||||
|
||||
import java.io.StringWriter;
|
||||
import java.net.URI;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.xml.stream.XMLOutputFactory;
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import javax.xml.stream.XMLStreamWriter;
|
||||
import com.ruoyi.cms.sitemap.domain.SitemapUrl;
|
||||
import com.ruoyi.cms.sitemap.mapper.SitemapMapper;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* Builds the UTF-8 sitemap from canonical URLs backed by published data.
|
||||
*/
|
||||
@Service
|
||||
public class SitemapService
|
||||
{
|
||||
private static final String SITEMAP_NAMESPACE = "http://www.sitemaps.org/schemas/sitemap/0.9";
|
||||
|
||||
private final SitemapMapper sitemapMapper;
|
||||
|
||||
private final String siteUrl;
|
||||
|
||||
public SitemapService(SitemapMapper sitemapMapper,
|
||||
@Value("${seo.site-url:https://www.yidaima.cn}") String siteUrl)
|
||||
{
|
||||
this.sitemapMapper = sitemapMapper;
|
||||
this.siteUrl = normalizeSiteUrl(siteUrl);
|
||||
}
|
||||
|
||||
public String buildSitemap()
|
||||
{
|
||||
Map<String, SitemapUrl> canonicalUrls = new LinkedHashMap<>();
|
||||
addUrls(canonicalUrls, sitemapMapper.selectIndexableCategories());
|
||||
addUrls(canonicalUrls, sitemapMapper.selectIndexableContent());
|
||||
|
||||
try
|
||||
{
|
||||
StringWriter output = new StringWriter();
|
||||
XMLStreamWriter xml = XMLOutputFactory.newFactory().createXMLStreamWriter(output);
|
||||
xml.writeStartDocument("UTF-8", "1.0");
|
||||
xml.writeStartElement("urlset");
|
||||
xml.writeDefaultNamespace(SITEMAP_NAMESPACE);
|
||||
|
||||
for (Map.Entry<String, SitemapUrl> entry : canonicalUrls.entrySet())
|
||||
{
|
||||
xml.writeStartElement("url");
|
||||
writeElement(xml, "loc", siteUrl + entry.getKey());
|
||||
if (entry.getValue().getLastModified() != null)
|
||||
{
|
||||
writeElement(xml, "lastmod",
|
||||
DateTimeFormatter.ISO_INSTANT.format(entry.getValue().getLastModified().toInstant()));
|
||||
}
|
||||
xml.writeEndElement();
|
||||
}
|
||||
|
||||
xml.writeEndElement();
|
||||
xml.writeEndDocument();
|
||||
xml.close();
|
||||
return output.toString();
|
||||
}
|
||||
catch (XMLStreamException exception)
|
||||
{
|
||||
throw new IllegalStateException("Unable to generate sitemap XML", exception);
|
||||
}
|
||||
}
|
||||
|
||||
private void addUrls(Map<String, SitemapUrl> canonicalUrls, List<SitemapUrl> urls)
|
||||
{
|
||||
if (urls == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (SitemapUrl url : urls)
|
||||
{
|
||||
if (url == null || url.getId() == null || !isSupportedPageType(url.getPageType()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
canonicalUrls.putIfAbsent("/" + url.getPageType() + "/" + url.getId(), url);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isSupportedPageType(String pageType)
|
||||
{
|
||||
return "category".equals(pageType) || "source".equals(pageType) || "article".equals(pageType);
|
||||
}
|
||||
|
||||
private void writeElement(XMLStreamWriter xml, String name, String value) throws XMLStreamException
|
||||
{
|
||||
xml.writeStartElement(name);
|
||||
xml.writeCharacters(value);
|
||||
xml.writeEndElement();
|
||||
}
|
||||
|
||||
private String normalizeSiteUrl(String configuredSiteUrl)
|
||||
{
|
||||
String value = configuredSiteUrl == null ? "" : configuredSiteUrl.trim();
|
||||
while (value.endsWith("/"))
|
||||
{
|
||||
value = value.substring(0, value.length() - 1);
|
||||
}
|
||||
|
||||
URI uri;
|
||||
try
|
||||
{
|
||||
uri = URI.create(value);
|
||||
}
|
||||
catch (IllegalArgumentException exception)
|
||||
{
|
||||
throw new IllegalStateException("seo.site-url must be an absolute HTTP(S) URL", exception);
|
||||
}
|
||||
|
||||
if (uri.getHost() == null
|
||||
|| (!"http".equalsIgnoreCase(uri.getScheme()) && !"https".equalsIgnoreCase(uri.getScheme()))
|
||||
|| uri.getQuery() != null || uri.getFragment() != null)
|
||||
{
|
||||
throw new IllegalStateException("seo.site-url must be an absolute HTTP(S) URL without query or fragment");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -47,12 +47,7 @@ public class CmsTagServiceImpl implements ICmsTagService
|
||||
@Override
|
||||
public List<CmsTag> selectCmsTagList(CmsTag cmsTag)
|
||||
{
|
||||
List<CmsTag> cmsTagList = cmsTagMapper.selectCmsTagList(cmsTag);
|
||||
for (CmsTag tag : cmsTagList) {
|
||||
int blogNum = cmsBlogTagMapper.countBlogByTagId(tag.getTagId());
|
||||
tag.setBlogNum(blogNum);
|
||||
}
|
||||
return cmsTagList;
|
||||
return cmsTagMapper.selectCmsTagList(cmsTag);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -51,12 +51,7 @@ public class CmsTypeServiceImpl implements ICmsTypeService
|
||||
@Override
|
||||
public List<CmsType> selectCmsTypeList(CmsType cmsType)
|
||||
{
|
||||
List<CmsType> cmsTypeList = cmsTypeMapper.selectCmsTypeList(cmsType);
|
||||
for (CmsType type : cmsTypeList) {
|
||||
int blogNum = cmsBlogTypeMapper.countBlogByTypeId(type.getTypeId());
|
||||
type.setBlogNum(blogNum);
|
||||
}
|
||||
return cmsTypeList;
|
||||
return cmsTypeMapper.selectCmsTypeList(cmsType);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -29,6 +29,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
select id, create_by, create_time, update_by, update_time, title, type, content, content_type, content_markdown, Top, views, status, blog_pic_type, blog_pic, blog_pic_link, blog_desc, blog_files from cms_blog
|
||||
</sql>
|
||||
|
||||
<sql id="selectCmsBlogCardVo">
|
||||
select id, create_by, create_time, update_time, title, type, Top, views, status,
|
||||
blog_pic_type, blog_pic, blog_pic_link, blog_desc
|
||||
from cms_blog
|
||||
</sql>
|
||||
|
||||
<select id="selectCmsBlogList" parameterType="CmsBlog" resultMap="CmsBlogResult">
|
||||
<include refid="selectCmsBlogVo"/>
|
||||
<where>
|
||||
@@ -42,25 +48,55 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
</where>
|
||||
ORDER BY Top DESC, create_time DESC
|
||||
</select>
|
||||
|
||||
<select id="selectCmsBlogCardList" parameterType="CmsBlog" resultMap="CmsBlogResult">
|
||||
<include refid="selectCmsBlogCardVo"/>
|
||||
<where>
|
||||
<if test="title != null and title != ''"> and title like concat('%', #{title}, '%')</if>
|
||||
<if test="type != null and type != ''"> and type = #{type}</if>
|
||||
<if test="top != null and top != ''"> and Top = #{top}</if>
|
||||
<if test="views != null "> and views = #{views}</if>
|
||||
<if test="status != null and status != ''"> and status = #{status}</if>
|
||||
<if test="createBy != null and createBy != ''"> and create_by = #{createBy}</if>
|
||||
</where>
|
||||
ORDER BY Top DESC, create_time DESC
|
||||
</select>
|
||||
|
||||
<select id="selectCmsBlogContentByIds" resultMap="CmsBlogResult">
|
||||
select id, content
|
||||
from cms_blog
|
||||
where id in
|
||||
<foreach collection="list" item="id" open="(" separator="," close=")">
|
||||
#{id}
|
||||
</foreach>
|
||||
</select>
|
||||
|
||||
<select id="selectCmsBlogById" parameterType="Long" resultMap="CmsBlogResult">
|
||||
<include refid="selectCmsBlogVo"/>
|
||||
where id = #{id}
|
||||
</select>
|
||||
<select id="selectCmsBlogListByTypeId" parameterType="Long" resultMap="CmsBlogResult">
|
||||
<select id="selectPublishedCmsBlogById" parameterType="Long" resultMap="CmsBlogResult">
|
||||
<include refid="selectCmsBlogVo"/>
|
||||
where id = #{id} and status = '1'
|
||||
</select>
|
||||
<select id="selectCmsBlogListByTypeId" parameterType="Long" resultMap="CmsBlogResult">
|
||||
<include refid="selectCmsBlogCardVo"/>
|
||||
<where>
|
||||
<if test="id != null and id != ''"> and id in (SELECT blog_id FROM cms_blog_type WHERE type_id = #{id})</if>
|
||||
and status = '1'
|
||||
</where>
|
||||
ORDER BY Top DESC, create_time DESC
|
||||
</select>
|
||||
<select id="selectCmsBlogListByTagId" parameterType="Long" resultMap="CmsBlogResult">
|
||||
<include refid="selectCmsBlogVo"/>
|
||||
<include refid="selectCmsBlogCardVo"/>
|
||||
<where>
|
||||
<if test="id != null and id != ''"> and id in (SELECT blog_id FROM cms_blog_tag WHERE tag_id = #{id})</if>
|
||||
and status = '1'
|
||||
</where>
|
||||
ORDER BY Top DESC, create_time DESC
|
||||
</select>
|
||||
<select id="selectCmsBlogListRecommend" parameterType="CmsBlog" resultMap="CmsBlogResult">
|
||||
<include refid="selectCmsBlogVo"/>
|
||||
<include refid="selectCmsBlogCardVo"/>
|
||||
<where>
|
||||
<if test="title != null and title != ''"> and title like concat('%', #{title}, '%')</if>
|
||||
<if test="type != null and type != ''"> and type = #{type}</if>
|
||||
@@ -188,4 +224,4 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<if test="createBy != null and createBy != ''"> and create_by = #{createBy}</if>
|
||||
</where>
|
||||
</select>
|
||||
</mapper>
|
||||
</mapper>
|
||||
|
||||
@@ -5,6 +5,14 @@
|
||||
<result property="tagId" column="tag_id" />
|
||||
<result property="blogId" column="blog_id" />
|
||||
</resultMap>
|
||||
<resultMap type="cmsBlogTag" id="blogTagWithTagResult">
|
||||
<result property="tagId" column="tag_id" />
|
||||
<result property="blogId" column="blog_id" />
|
||||
<association property="tag" javaType="com.ruoyi.cms.tag.domain.CmsTag">
|
||||
<id property="tagId" column="tag_id" />
|
||||
<result property="tagName" column="tag_name" />
|
||||
</association>
|
||||
</resultMap>
|
||||
|
||||
<insert id="batchBlogTag">
|
||||
insert into cms_blog_tag(tag_id, blog_id) values
|
||||
@@ -30,7 +38,16 @@
|
||||
<select id="selectBlogTagList" parameterType="Long" resultMap="blogTagResult">
|
||||
select tag_id, blog_id from cms_blog_tag where blog_id = #{blogId}
|
||||
</select>
|
||||
<select id="selectBlogTagsByBlogIds" resultMap="blogTagWithTagResult">
|
||||
select bt.blog_id, t.tag_id, t.tag_name
|
||||
from cms_blog_tag bt
|
||||
inner join cms_tag t on t.tag_id = bt.tag_id
|
||||
where bt.blog_id in
|
||||
<foreach collection="list" item="blogId" open="(" separator="," close=")">
|
||||
#{blogId}
|
||||
</foreach>
|
||||
</select>
|
||||
<select id="countBlogByTagId" parameterType="Long" resultType="java.lang.Integer">
|
||||
select count(*) from cms_blog_tag where tag_id=#{tagId}
|
||||
</select>
|
||||
</mapper>
|
||||
</mapper>
|
||||
|
||||
@@ -5,6 +5,14 @@
|
||||
<result property="typeId" column="type_id" />
|
||||
<result property="blogId" column="blog_id" />
|
||||
</resultMap>
|
||||
<resultMap type="CmsBlogType" id="blogTypeWithTypeResult">
|
||||
<result property="typeId" column="type_id" />
|
||||
<result property="blogId" column="blog_id" />
|
||||
<association property="type" javaType="com.ruoyi.cms.type.domain.CmsType">
|
||||
<id property="typeId" column="type_id" />
|
||||
<result property="typeName" column="type_name" />
|
||||
</association>
|
||||
</resultMap>
|
||||
|
||||
<insert id="batchBlogType">
|
||||
insert into cms_blog_type(type_id, blog_id) values
|
||||
@@ -30,7 +38,16 @@
|
||||
<select id="selectBlogTypeList" parameterType="Long" resultMap="blogTypeResult">
|
||||
select type_id, blog_id from cms_blog_type where blog_id = #{blogId}
|
||||
</select>
|
||||
<select id="selectBlogTypesByBlogIds" resultMap="blogTypeWithTypeResult">
|
||||
select bt.blog_id, t.type_id, t.type_name
|
||||
from cms_blog_type bt
|
||||
inner join cms_type t on t.type_id = bt.type_id
|
||||
where bt.blog_id in
|
||||
<foreach collection="list" item="blogId" open="(" separator="," close=")">
|
||||
#{blogId}
|
||||
</foreach>
|
||||
</select>
|
||||
<select id="countBlogByTypeId" parameterType="Long" resultType="java.lang.Integer">
|
||||
select count(*) from cms_blog_type where type_id=#{typeId}
|
||||
</select>
|
||||
</mapper>
|
||||
</mapper>
|
||||
|
||||
@@ -11,6 +11,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<result property="updateBy" column="update_by" />
|
||||
<result property="updateTime" column="update_time" />
|
||||
<result property="tagName" column="tag_name" />
|
||||
<result property="blogNum" column="blog_num" />
|
||||
</resultMap>
|
||||
|
||||
<sql id="selectCmsTagVo">
|
||||
@@ -18,12 +19,16 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
</sql>
|
||||
|
||||
<select id="selectCmsTagList" parameterType="CmsTag" resultMap="CmsTagResult">
|
||||
<include refid="selectCmsTagVo"/>
|
||||
select t.tag_id, t.create_by, t.create_time, t.update_by, t.update_time, t.tag_name,
|
||||
count(bt.blog_id) as blog_num
|
||||
from cms_tag t
|
||||
left join cms_blog_tag bt on bt.tag_id = t.tag_id
|
||||
<where>
|
||||
<if test="tagName != null and tagName != ''"> and tag_name like concat('%', #{tagName}, '%')</if>
|
||||
<if test="createBy != null and createBy != ''"> and create_by = #{createBy}</if>
|
||||
<if test="tagName != null and tagName != ''"> and t.tag_name like concat('%', #{tagName}, '%')</if>
|
||||
<if test="createBy != null and createBy != ''"> and t.create_by = #{createBy}</if>
|
||||
</where>
|
||||
ORDER BY create_time DESC
|
||||
group by t.tag_id, t.create_by, t.create_time, t.update_by, t.update_time, t.tag_name
|
||||
ORDER BY t.create_time DESC
|
||||
</select>
|
||||
|
||||
<select id="selectCmsTagByTagId" parameterType="Long" resultMap="CmsTagResult">
|
||||
@@ -75,4 +80,4 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
#{tagId}
|
||||
</foreach>
|
||||
</delete>
|
||||
</mapper>
|
||||
</mapper>
|
||||
|
||||
@@ -14,6 +14,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<result property="typePicType" column="type_pic_type" />
|
||||
<result property="typePic" column="type_pic" />
|
||||
<result property="typePicLink" column="type_pic_link" />
|
||||
<result property="blogNum" column="blog_num" />
|
||||
</resultMap>
|
||||
|
||||
<sql id="selectCmsTypeVo">
|
||||
@@ -21,13 +22,18 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
</sql>
|
||||
|
||||
<select id="selectCmsTypeList" parameterType="CmsType" resultMap="CmsTypeResult">
|
||||
<include refid="selectCmsTypeVo"/>
|
||||
select t.type_id, t.create_by, t.create_time, t.update_by, t.update_time, t.type_name,
|
||||
t.type_pic_type, t.type_pic, t.type_pic_link, count(bt.blog_id) as blog_num
|
||||
from cms_type t
|
||||
left join cms_blog_type bt on bt.type_id = t.type_id
|
||||
<where>
|
||||
<if test="typeName != null and typeName != ''"> and type_name like concat('%', #{typeName}, '%')</if>
|
||||
<if test="typePic != null and typePic != ''"> and type_pic = #{typePic}</if>
|
||||
<if test="createBy != null and createBy != ''"> and create_by = #{createBy}</if>
|
||||
<if test="typeName != null and typeName != ''"> and t.type_name like concat('%', #{typeName}, '%')</if>
|
||||
<if test="typePic != null and typePic != ''"> and t.type_pic = #{typePic}</if>
|
||||
<if test="createBy != null and createBy != ''"> and t.create_by = #{createBy}</if>
|
||||
</where>
|
||||
ORDER BY create_time DESC
|
||||
group by t.type_id, t.create_by, t.create_time, t.update_by, t.update_time, t.type_name,
|
||||
t.type_pic_type, t.type_pic, t.type_pic_link
|
||||
ORDER BY t.create_time DESC
|
||||
</select>
|
||||
|
||||
<select id="selectCmsTypeByTypeId" parameterType="Long" resultMap="CmsTypeResult">
|
||||
@@ -88,4 +94,4 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
#{typeId}
|
||||
</foreach>
|
||||
</delete>
|
||||
</mapper>
|
||||
</mapper>
|
||||
|
||||
46
ruoyi-cms/src/main/resources/mapper/cms/SitemapMapper.xml
Normal file
46
ruoyi-cms/src/main/resources/mapper/cms/SitemapMapper.xml
Normal file
@@ -0,0 +1,46 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.ruoyi.cms.sitemap.mapper.SitemapMapper">
|
||||
|
||||
<resultMap type="com.ruoyi.cms.sitemap.domain.SitemapUrl" id="SitemapUrlResult">
|
||||
<result property="id" column="id" />
|
||||
<result property="pageType" column="page_type" />
|
||||
<result property="lastModified" column="last_modified" />
|
||||
</resultMap>
|
||||
|
||||
<!-- Empty categories do not have an indexable category page. -->
|
||||
<select id="selectIndexableCategories" resultMap="SitemapUrlResult">
|
||||
SELECT
|
||||
t.type_id AS id,
|
||||
'category' AS page_type,
|
||||
CASE
|
||||
WHEN COALESCE(t.update_time, t.create_time) > MAX(COALESCE(b.update_time, b.create_time))
|
||||
THEN COALESCE(t.update_time, t.create_time)
|
||||
ELSE MAX(COALESCE(b.update_time, b.create_time))
|
||||
END AS last_modified
|
||||
FROM cms_type t
|
||||
INNER JOIN cms_blog_type bt ON bt.type_id = t.type_id
|
||||
INNER JOIN cms_blog b ON b.id = bt.blog_id AND b.status = '1'
|
||||
GROUP BY t.type_id, t.update_time, t.create_time
|
||||
ORDER BY t.type_id
|
||||
</select>
|
||||
|
||||
<!-- Published content has exactly one article or source canonical URL. -->
|
||||
<select id="selectIndexableContent" resultMap="SitemapUrlResult">
|
||||
SELECT
|
||||
b.id,
|
||||
CASE
|
||||
WHEN b.blog_files IS NOT NULL
|
||||
AND LOWER(REPLACE(TRIM(b.blog_files), ' ', '')) NOT IN ('', '[]', 'null')
|
||||
THEN 'source'
|
||||
ELSE 'article'
|
||||
END AS page_type,
|
||||
COALESCE(b.update_time, b.create_time) AS last_modified
|
||||
FROM cms_blog b
|
||||
WHERE b.status = '1'
|
||||
ORDER BY b.id
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
Reference in New Issue
Block a user