2021-6-28:开发小而美的博客(博客详情)
文章目录
首页展示
1. 博客列表
2. top分类
3. top标签
4. 最新博客推荐
5. 博客详情
1、实现功能
1.1、处理数据
@GetMapping("/blog/{id}")
public String blog(@PathVariable Long id,Model model) {
model.addAttribute("blog", blogService.getAndConvert(id));
return "blog";
}
1.2、获取数据
打开blog页面
获取作者头像
2、Markdown转换HTML
网址;https://github.com/atlassian/commonmark-java
pom.xml应用commonmark和扩展插件
在pom.xml引入架包
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>net.lhf</groupId>
<artifactId>blog</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>blog</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-tools</artifactId>
<version>2.0</version>
</dependency>
<dependency>
<groupId>xml-apis</groupId>
<artifactId>xml-apis</artifactId>
<version>1.3.04</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-el</artifactId>
<version>9.0.46</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>com.atlassian.commonmark</groupId>
<artifactId>commonmark</artifactId>
<version>0.10.0</version>
</dependency>
<dependency>
<groupId>com.atlassian.commonmark</groupId>
<artifactId>commonmark-ext-heading-anchor</artifactId>
<version>0.10.0</version>
</dependency>
<dependency>
<groupId>com.atlassian.commonmark</groupId>
<artifactId>commonmark-ext-gfm-tables</artifactId>
<version>0.10.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.xmlunit</groupId>
<artifactId>xmlunit-core</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
3、新建MarkdownUtils工具类
package net.lhf.util;
import org.commonmark.Extension;
import org.commonmark.ext.gfm.tables.TableBlock;
import org.commonmark.ext.gfm.tables.TablesExtension;
import org.commonmark.ext.heading.anchor.HeadingAnchorExtension;
import org.commonmark.node.Link;
import org.commonmark.node.Node;
import org.commonmark.parser.Parser;
import org.commonmark.renderer.html.AttributeProvider;
import org.commonmark.renderer.html.AttributeProviderContext;
import org.commonmark.renderer.html.AttributeProviderFactory;
import org.commonmark.renderer.html.HtmlRenderer;
import java.util.*;
/**
* 功能:
* 作者:李红芙
* 日期:2021年6月23日
*/
public class MarkdownUtils {
/**
* markdown格式转换成HTML格式
* @param markdown
* @return
*/
public static String markdownToHtml(String markdown) {
Parser parser = Parser.builder().build();
Node document = parser.parse(markdown);
HtmlRenderer renderer = HtmlRenderer.builder().build();
return renderer.render(document);
}
/**
* 增加扩展[标题锚点,表格生成]
* Markdown转换成HTML
* @param markdown
* @return
*/
public static String markdownToHtmlExtensions(String markdown) {
//h标题生成id
Set<Extension> headingAnchorExtensions = Collections.singleton(HeadingAnchorExtension.create());
//转换table的HTML
List<Extension> tableExtension = Arrays.asList(TablesExtension.create());
Parser parser = Parser.builder()
.extensions(tableExtension)
.build();
Node document = parser.parse(markdown);
HtmlRenderer renderer = HtmlRenderer.builder()
.extensions(headingAnchorExtensions)
.extensions(tableExtension)
.attributeProviderFactory(new AttributeProviderFactory() {
public AttributeProvider create(AttributeProviderContext context) {
return new CustomAttributeProvider();
}
})
.build();
return renderer.render(document);
}
/**
* 处理标签的属性
*/
static class CustomAttributeProvider implements AttributeProvider {
@Override
public void setAttributes(Node node, String tagName, Map<String, String> attributes) {
//改变a标签的target属性为_blank
if (node instanceof Link) {
attributes.put("target", "_blank");
}
if (node instanceof TableBlock) {
attributes.put("class", "ui celled table");
}
}
}
public static void main(String[] args) {
String table = "| hello | hi | 哈哈哈 |\n" +
"| ----- | ---- | ----- |\n" +
"| 斯维尔多 | 士大夫 | f啊 |\n" +
"| 阿什顿发 | 非固定杆 | 撒阿什顿发 |\n" +
"\n";
String a = "[imCoding 爱编程](http://www.lirenmi.cn)";
System.out.println(markdownToHtmlExtensions(a));
}
}
4、优化BlogService代码
package net.lhf.service;
import net.lhf.po.Blog;
import net.lhf.vo.BlogQuery;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import java.util.List;
import java.util.Map;
/**
* 功能:
* 作者:李红芙
* 日期:2021年6月23日
*/
public interface BlogService {
Blog getBlog(Long id);
Blog getAndConvert(Long id);
Page<Blog> listBlog(Pageable pageable,BlogQuery blog);
Page<Blog> listBlog(Pageable pageable);
Page<Blog> listBlog(Long tagId,Pageable pageable);
Page<Blog> listBlog(String query,Pageable pageable);
List<Blog> listRecommendBlogTop(Integer size);
Map<String,List<Blog>> archiveBlog();
Long countBlog();
Blog saveBlog(Blog blog);
Blog updateBlog(Long id,Blog blog);
void deleteBlog(Long id);
}
5、优化BlogServiceImpl代码
@Transactional
@Override
public Blog getAndConvert(Long id) {
Blog blog = blogRepository.getOne(id);
if (blog == null) {
throw new NotFoundException("该博客不存在");
}
Blog b = new Blog();
BeanUtils.copyProperties(blog,b);
String content = b.getContent();
b.setContent(MarkdownUtils.markdownToHtmlExtensions(content));
blogRepository.updateViews(id);
return b;
}
6、优化IndexController代码
package net.lhf.web;
import net.lhf.service.BlogService;
import net.lhf.service.TagService;
import net.lhf.service.TypeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.web.PageableDefault;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
/**
* 功能:
* 作者:李红芙
* 日期:2021年6月23日
*/
@Controller
public class IndexController {
@Autowired
private BlogService blogService;
@Autowired
private TypeService typeService;
@Autowired
private TagService tagService;
@GetMapping("/")
public String index(@PageableDefault(size = 8, sort = {"updateTime"}, direction = Sort.Direction.DESC) Pageable pageable,
Model model) {
model.addAttribute("page",blogService.listBlog(pageable));
model.addAttribute("types", typeService.listTypeTop(6));
model.addAttribute("tags", tagService.listTagTop(10));
model.addAttribute("recommendBlogs", blogService.listRecommendBlogTop(8));
return "index";
}
@PostMapping("/search")
public String search(@PageableDefault(size = 8, sort = {"updateTime"}, direction = Sort.Direction.DESC) Pageable pageable,
@RequestParam String query, Model model) {
model.addAttribute("page", blogService.listBlog("%"+query+"%", pageable));
model.addAttribute("query", query);
return "search";
}
@GetMapping("/blog/{id}")
public String blog(@PathVariable Long id,Model model) {
model.addAttribute("blog", blogService.getAndConvert(id));
return "blog";
}
@GetMapping("/footer/newblog")
public String newblogs(Model model) {
model.addAttribute("newblogs", blogService.listRecommendBlogTop(3));
return "_fragments :: newblogList";
}
}
7、运行项目,测试效果
8、二维码
var url = /*[[@{/blog/{id}(id=${blog.id})}]]*/"";
var qrcode = new QRCode("qrcode", {
text: serurl+url,
width: 110,
height: 110,
colorDark : "#000000",
colorLight : "#ffffff",
correctLevel : QRCode.CorrectLevel.H
});
指定一下