Blog address: ONESTAR Inn
Source code access method 1:
- Scan the qr code at the end of the article, pay attention to the public number [programming Daily], background reply [blog], you can get the source code
Source code access method two:
Front-end page source address: github.com/oneStarLR/m…
Jpa as a persistent layer source address: github.com/oneStarLR/m…
Mybatis as a persistent layer source address: github.com/oneStarLR/m…
Welcome to give encouragement to star
Blog details page includes articles and reviews, this article from the article content and comments to tell SpringBoot structures, details of the personal blog page displays, because the blog details and classification function are independent, it will comment separately written in a class to interface, query blog details directly on the front page of the controller for processing
Analysis:
Q: the blog details page contains the article content and comments section, how to deal with
A: When jumping to the blog details page, you can return two models, one for the details of the article and one for the list of comments
Q: How to handle article details and what interfaces are required? How are comments handled and what interfaces are required?
A: Article details define getDetailedBlog blog details interface, need to define a query entity class to encapsulate the query content, and also include the classification information; For the comment function, you need to define the listCommentByBlogId interface for querying the comment list, saveComment interface for adding and saving comments, and deleteComment interface for deleting comments
First, article content display
Analysis:
Q: in the blog details page, how to deal with the display format of articles, how to deal with the number of articles visited, how to deal with the number of comments?
A: This is all implemented in the getDetailedBlog interface implementation class
- Article display format: Use the open source Markdown Editor: Editor to add extensions by calling utility class methods
- Number of visits: In the persistence layer, the interface defines the method updateViews to update the number of visits to the article. After clicking the article, the value increases
- Number of comments: In the persistence layer the interface definition method getCommentCountById is used to query the number of comments by blog ID
1. Blog details entity class
In queryvo, create the DetailedBlog blog detail entity class as follows (omit the get, set, and toString methods) :
package com.star.queryvo;
import java.util.Date;
/ * * *@Description: Blog details entity class *@Date: Created in 10:10 2020/6/19
* @Author: ONESTAR
* @QQGroup: 530311074 *@URL: https://onestar.newstar.net.cn/
*/
public class DetailedBlog {
// Blog info
private Long id;
private String firstPicture;
private String flag;
private String title;
private String content;
private Integer views;
private Integer commentCount;
private Date updateTime;
private boolean commentabled;
private boolean shareStatement;
private boolean appreciation;
private String nickname;
private String avatar;
// Class name
private String typeName;
}
Copy the code
2. Markdown editor tool class
- Add dependency Editor-related dependencies
Add in pom.xml
<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>
Copy the code
- Add the MarkdownUtils utility class
Add the MarkdownUtils utility class under the Util toolkit:
package com.star.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.*;
/ * * *@Description: Markdown editor *@Author: ONESTAR
* @Date: Created in 13:24 2020/4/5
* @QQGroup: 530311074 *@URL: https://onestar.newstar.net.cn/
*/
public class MarkdownUtils {
/** * Markdown format is converted to HTML format *@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);
}
/** * added extension [title anchor points, table generation] * Markdown conversion to HTML *@param markdown
* @return* /
public static String markdownToHtmlExtensions(String markdown) {
//h title generates id
Set<Extension> headingAnchorExtensions = Collections.singleton(HeadingAnchorExtension.create());
// Convert 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);
}
/** * handles the attribute */ of the tag
static class CustomAttributeProvider implements AttributeProvider {
@Override
public void setAttributes(Node node, String tagName, Map<String, String> attributes) {
// Change the target attribute of a tag to _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 ha ha ha | \ n" +
"| ----- | ---- | ----- |\n" +
"How | | si, scholar-bureaucrat | | o f \ n" +
"| | ashton hair without a fixed rod send | | and ashton \ n" +
"\n";
String a = "[ONESTAR](https://onestar.newstar.net.cn/)"; System.out.println(markdownToHtmlExtensions(a)); }}Copy the code
3. Interfaces at the persistence layer
Post content is displayed by clicking on the title or image on the front page and then jumping to the blog details page, so put the code in the blog business section here
BlogDao interface added to query blog details, article access updates, query the number of comments interface
// Check blog details
DetailedBlog getDetailedBlog(Long id);
// Article access updates
int updateViews(Long id);
// Query the number of comments by blog id
int getCommentCountById(Long id);
Copy the code
4. mapper
According to the persistence layer interface, write the following SQL: query blog details, article access updates, query the number of comments, where the blog details need to be encapsulated
<resultMap id="detailedBlog" type="com.star.queryvo.DetailedBlog">
<id property="id" column="bid"/>
<result property="firstPicture" column="first_picture"/>
<result property="flag" column="flag"/>
<result property="title" column="title"/>
<result property="content" column="content"/>
<result property="typeName" column="name"/>
<result property="views" column="views"/>
<result property="commentCount" column="comment_count"/>
<result property="updateTime" column="update_time"/>
<result property="commentabled" column="commentabled"/>
<result property="shareStatement" column="share_statement"/>
<result property="appreciation" column="appreciation"/>
<result property="nickname" column="nickname"/>
<result property="avatar" column="avatar"/>
</resultMap>
<! -- Blog details -->
<select id="getDetailedBlog" resultMap="detailedBlog">select b.id bid,b.first_picture,b.flag,b.title,b.content,b.views,b.comment_count,b.update_time,b.commentabled,b.share_statement,b.ap preciation, u.nickname,u.avatar,t.name from myblog.t_blog b,myblog.t_user u, myblog.t_type t where b.user_id = u.id and b.type_id = t.id and b.id = #{id}</select>
<! -- Article access increment -->
<update id="updateViews" parameterType="com.star.entity.Blog">
update myblog.t_blog b set b.views = b.views+1 where b.id = #{id}
</update>
<! Select * from comment count and update -->
<update id="getCommentCountById" parameterType="com.star.entity.Blog">
update myblog.t_blog b set b.comment_count = (
select count(*) from myblog.t_comment c where c.blog_id = #{id} and b.id = #{id}
) WHERE b.id = #{id}
</update>
Copy the code
5. The persistence layer
- Persistence layer interface
Add a method to query blog details in the BlogService interface:
// Check blog details
DetailedBlog getDetailedBlog(Long id);
Copy the code
- Interface implementation
The sub-interface implementation is mainly to set the article display format, article access increment and article comment statistics, add implementation methods in the BlogServiceImpl class, as follows:
@Override
public DetailedBlog getDetailedBlog(Long id) {
DetailedBlog detailedBlog = blogDao.getDetailedBlog(id);
if (detailedBlog == null) {
throw new NotFoundException("The blog does not exist.");
}
String content = detailedBlog.getContent();
detailedBlog.setContent(MarkdownUtils.markdownToHtmlExtensions(content));
// The number of article visits increases
blogDao.updateViews(id);
// The number of comments on the article is updated
blogDao.getCommentCountById(id);
return detailedBlog;
}
Copy the code
6. The controller
Add a method to the IndexController class that calls the business layer interface:
// Jump to blog details page
@GetMapping("/blog/{id}")
public String blog(@PathVariable Long id, Model model) {
DetailedBlog detailedBlog = blogService.getDetailedBlog(id);
model.addAttribute("blog", detailedBlog);
return "blog";
}
Copy the code
Second, comment function
Because comments are a little more complex, they will be placed in a separate business layer
Analysis:
Q: What interfaces are required for the comment business layer?
A: Comments are operated directly on the front page without background management. They are only distinguished by administrators and ordinary users. Administrators can delete comments. Therefore, you need to query the comment list (listCommentByBlogId), add the saveComment (saveComment), and deleteComment (deleteComment) interfaces
Q: These interfaces are enough for the business layer, but are they enough for the persistence layer? What SQL do you need, what persistence layer interfaces do you need?
A: Persistent layer interface is not enough, mainly when querying the comment list, we need to distinguish the comment and reply. According to the comment function, there are parent comments, child comments (reply), and the position of the parent and child comments in the front display is different. Here is a detailed query:
- Select * from parent comment where id = ‘-1’ and blog id = ‘-1’
- Query primary child responses based on the ID of the parent comment
- All subsets of responses are queried iteratively according to the ID loop of subresponses
- Put the queried child responses into a collection
So comment query information needs: query the parent comment (findByBlogIdParentIdNull), query response (findByBlogIdParentIdNotNull), query the secondary response (findByBlogIdAndReplayId)
1. Interfaces at the persistence layer
Create the CommentDao interface in the DAO package and add the following interface:
package com.star.dao;
import com.star.entity.Comment;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
/ * * *@Description: Comment persistence layer interface *@Date: Created in 9:21 2020/6/23
* @Author: ONESTAR
* @QQGroup: 530311074 *@URL: https://onestar.newstar.net.cn/
*/
@Mapper
@Repository
public interface CommentDao {
// Query parent comments
List<Comment> findByBlogIdParentIdNull(@Param("blogId") Long blogId, @Param("blogParentId") Long blogParentId);
// Query a level 1 reply
List<Comment> findByBlogIdParentIdNotNull(@Param("blogId") Long blogId, @Param("id") Long id);
// Query secondary response
List<Comment> findByBlogIdAndReplayId(@Param("blogId") Long blogId,@Param("childId") Long childId);
// Add a comment
int saveComment(Comment comment);
// Delete comments
void deleteComment(Long id);
}
Copy the code
2.mapper
Create a file called Commentdao.xml in the mapper directory and add the following:
<?xml version="1.0" encoding="utf-8" ? >
<mapper namespace="com.star.dao.CommentDao">
<! -- Add comments -->
<insert id="saveComment" parameterType="com.star.entity.Comment">
insert into myblog.t_comment (nickname,email,content,avatar,create_time,blog_id,parent_comment_id,admin_comment)
values (#{nickname},#{email},#{content},#{avatar},#{createTime},#{blogId},#{parentCommentId},#{adminComment});
</insert>
<! -- query parent comment -->
<select id="findByBlogIdParentIdNull" resultType="com.star.entity.Comment">
select *
from myblog.t_comment c
where c.blog_id = #{blogId} and c.parent_comment_id = #{blogParentId}
order by c.create_time desc
</select>
<! -- Query subcomment level -->
<select id="findByBlogIdParentIdNotNull" resultType="com.star.entity.Comment">
select *
from myblog.t_comment c
where c.blog_id = #{blogId} and c.parent_comment_id = #{id}
order by c.create_time desc
</select>
<! -- Query subcomment -->
<select id="findByBlogIdAndReplayId" resultType="com.star.entity.Comment">select * from myblog.t_comment c where c.blog_id = #{blogId} and c.parent_comment_id = #{childId} order by c.create_time desc</select>
<! -- Delete comment -->
<delete id="deleteComment" >
delete from myblog.t_comment where id = #{id}
</delete>
</mapper>
Copy the code
Explanation:
Add and delete: You can add and delete directly using INSERT and DELETE
Query:
- FindByBlogIdParentIdNull: Query all parent comments based on blog ID ‘-1’ (parent comment ID ‘-1’)
- FindByBlogIdParentIdNotNull: according to the parent comment id of the level of response
- FindByBlogIdAndReplayId: Iterates to find all subsets of replies based on the ID loop of sub-replies
3. The business layer
- Business layer interface:
Create the CommentService interface under the service package as follows:
package com.star.service;
import com.star.entity.Comment;
import java.util.List;
/ * * *@Description: Comment on the business layer interface *@Date: Created in 10:22 2020/6/23
* @Author: ONESTAR
* @QQGroup: 530311074 *@URL: https://onestar.newstar.net.cn/
*/
public interface CommentService {
// Query comment information by blog id
List<Comment> listCommentByBlogId(Long blogId);
// Add save comments
int saveComment(Comment comment);
// Delete comments
void deleteComment(Comment comment,Long id);
}
Copy the code
- Interface implementation:
Create an interface implementation class under the Impl package: CommentServiceImpl, where the functionality is implemented
package com.star.service.Impl;
import com.star.dao.BlogDao;
import com.star.dao.CommentDao;
import com.star.entity.Comment;
import com.star.service.CommentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/ * * *@Description: Blog comments business layer interface implementation class *@Date: Created in 10:23 2020/6/23
* @Author: ONESTAR
* @QQGroup: 530311074 *@URL: https://onestar.newstar.net.cn/
*/
@Service
public class CommentServiceImpl implements CommentService {
@Autowired
private CommentDao commentDao;
@Autowired
private BlogDao blogDao;
// Store the set of all the children found by the iteration
private List<Comment> tempReplys = new ArrayList<>();
/ * * *@Description: Query comments *@Auther: ONESTAR
* @Date: himself 2020/6/23 *@Param: blogId: blogId *@Return: Comment message */
@Override
public List<Comment> listCommentByBlogId(Long blogId) {
// Query the parent node
List<Comment> comments = commentDao.findByBlogIdParentIdNull(blogId, Long.parseLong("1"));
for(Comment comment : comments){
Long id = comment.getId();
String parentNickname1 = comment.getNickname();
List<Comment> childComments = commentDao.findByBlogIdParentIdNotNull(blogId,id);
// Query subcomments
combineChildren(blogId, childComments, parentNickname1);
comment.setReplyComments(tempReplys);
tempReplys = new ArrayList<>();
}
return comments;
}
/ * * *@Description: Query for sub-comment *@Auther: ONESTAR
* @Date: 10:43 2020/6/23
* @Param: childComments: all childComments *@Param: parentNickname1: parent comment name *@Return: * /
private void combineChildren(Long blogId, List<Comment> childComments, String parentNickname1) {
// Determine if there is a sub-comment level
if(childComments.size() > 0) {// Loop to find the id of the child comment
for(Comment childComment : childComments){
String parentNickname = childComment.getNickname();
childComment.setParentNickname(parentNickname1);
tempReplys.add(childComment);
Long childId = childComment.getId();
// Query sublevel commentsrecursively(blogId, childId, parentNickname); }}}/ * * *@Description: Loop over to find subset responses *@Auther: ONESTAR
* @Date: 10:44 2020/6/23
* @Param: chileId: sub-comment ID *@Param: parentNickname1: indicates the child comment name *@Return: * /
private void recursively(Long blogId, Long childId, String parentNickname1) {
// Find the sub-level comment based on the sub-level comment ID
List<Comment> replayComments = commentDao.findByBlogIdAndReplayId(blogId,childId);
if(replayComments.size() > 0) {for(Comment replayComment : replayComments){ String parentNickname = replayComment.getNickname(); replayComment.setParentNickname(parentNickname1); Long replayId = replayComment.getId(); tempReplys.add(replayComment); recursively(blogId,replayId,parentNickname); }}}// Add a comment
@Override
public int saveComment(Comment comment) {
comment.setCreateTime(new Date());
int comments = commentDao.saveComment(comment);
// Article comment count
blogDao.getCommentCountById(comment.getBlogId());
return comments;
}
// Delete comments
@Override
public void deleteComment(Comment comment,Long id) { commentDao.deleteComment(id); blogDao.getCommentCountById(comment.getBlogId()); }}Copy the code
4. The controller
- Add the following configuration to the application.yml file:
comment.avatar: /images/avatar.png
message.avatar: /images/avatar.png
Copy the code
Create the CommentController class under the Controller package as follows:
package com.star.controller;
import com.star.entity.Comment;
import com.star.entity.User;
import com.star.queryvo.DetailedBlog;
import com.star.service.BlogService;
import com.star.service.CommentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
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.servlet.mvc.support.RedirectAttributes;
import javax.servlet.http.HttpSession;
import java.util.List;
/ * * *@Description: Comment controller *@Date: Created in 10:25 2020/6/23
* @Author: ONESTAR
* @QQGroup: 530311074 *@URL: https://onestar.newstar.net.cn/
*/
@Controller
public class CommentController {
@Autowired
private CommentService commentService;
@Autowired
private BlogService blogService;
@Value("${comment.avatar}")
private String avatar;
// Query the comment list
@GetMapping("/comments/{blogId}")
public String comments(@PathVariable Long blogId, Model model) {
List<Comment> comments = commentService.listCommentByBlogId(blogId);
model.addAttribute("comments", comments);
return "blog :: commentList";
}
// Add a comment
@PostMapping("/comments")
public String post(Comment comment, HttpSession session, Model model) {
Long blogId = comment.getBlogId();
User user = (User) session.getAttribute("user");
if(user ! =null) {
comment.setAvatar(user.getAvatar());
comment.setAdminComment(true);
} else {
// Set the profile picture
comment.setAvatar(avatar);
}
if(comment.getParentComment().getId() ! =null) {
comment.setParentCommentId(comment.getParentComment().getId());
}
commentService.saveComment(comment);
List<Comment> comments = commentService.listCommentByBlogId(blogId);
model.addAttribute("comments", comments);
return "blog :: commentList";
}
// Delete comments
@GetMapping("/comment/{blogId}/{id}/delete")
public String delete(@PathVariable Long blogId, @PathVariable Long id, Comment comment, RedirectAttributes attributes, Model model){
commentService.deleteComment(comment,id);
DetailedBlog detailedBlog = blogService.getDetailedBlog(blogId);
List<Comment> comments = commentService.listCommentByBlogId(blogId);
model.addAttribute("blog", detailedBlog);
model.addAttribute("comments", comments);
return "blog"; }}Copy the code
Explanation:
Query the comment list: Invoke the interface to query the comment list and partially refresh the comment information
New comments: Judge comments and distinguish between visitors and administrators
Delete comments: blog comment id and id parameter into the, judgment, which is to delete the comments, there is no delete child do iteration reviews, if removed contains reply comments, according to the previous query, reply on the front end will not query, but reply is not deleted, still in the database, just delete the parent comment
5. Front – end interaction
Give part of the front-end code, for reference only, to learn more you can view the entire project source: github.com/oneStarLR/m…
Submit comments
- HTML
<input type="hidden" name="blogId" th:value="${blog.id}">
<input type="hidden" name="parentComment.id" value="1">
<div class="field">
<textarea name="content" placeholder="Please enter comment information..."></textarea>
</div>
<div class="fields">
<div class="field m-mobile-wide m-margin-bottom-small">
<div class="ui left icon input">
<i class="user icon"></i>
<input type="text" name="nickname" placeholder="Name" th:value="${session.user}! =null ? ${session.user.nickname}">
</div>
</div>
<div class="field m-mobile-wide m-margin-bottom-small">
<div class="ui left icon input">
<i class="mail icon"></i>
<input type="text" name="email" placeholder="Email" th:value="${session.user}! =null ? ${session.user.email}">
</div>
</div>
<div class="field m-margin-bottom-small m-mobile-wide">
<button id="commentpost-btn" type="button" class="ui teal button m-mobile-wide"><i class="edit icon"></i>release</button>
</div>
</div>
Copy the code
- JS
$('#commentpost-btn').click(function () {
var boo = $('.ui.form').form('validate form');
if (boo) {
console.log('Verification successful');
postData();
} else {
console.log('Verification failed'); }});function postData() {$("#comment-container").load(/*[[@{/comments}]]*/"", {"parentComment.id" : $("[name='parentComment.id']").val(),
"blogId" : $("[name='blogId']").val(),
"nickname": $("[name='nickname']").val(),
"email" : $("[name='email']").val(),
"content" : $("[name='content']").val()
},function (responseTxt, statusTxt, xhr) {$(window).scrollTo($('#goto'),500);
clearContent();
});
}
Copy the code
Comment on the list
<div id="comment-container" class="ui teal segment">
<div th:fragment="commentList">
<div class="ui threaded comments" style="max-width: 100%;">
<h3 class="ui dividing header">comments</h3>
<div class="comment" th:each="comment : ${comments}">
<a class="avatar">
<img src="https://unsplash.it/100/100? image=1005" th:src="@{${comment.avatar}}">
</a>
<div class="content">
<a class="author" >
<span th:text="${comment.nickname}">Matt</span>
<div class="ui mini basic teal left pointing label m-padded-mini" th:if="${comment.adminComment}">The stack master</div>
</a>
<div class="metadata">
<span class="date" th:text="${#dates.format(comment.createTime,'yyyy-MM-dd HH:mm')}">Today at 5:42PM</span>
</div>
<div class="text" th:text="${comment.content}">
How artistic!
</div>
<div class="actions">
<a class="reply" data-commentid="1" data-commentnickname="Matt" th:attr="data-commentid=${comment.id},data-commentnickname=${comment.nickname}" onclick="reply(this)">reply</a>
<a class="delete" href="#" th:href="@{/comment/{param1}/{param2}/delete(param1=${comment.blogId},param2=${comment.id})}" onclick="Return Confirm (' Are you sure you want to delete this comment? Think again! If you delete it, it's gone! ')" th:if="${session.user}">delete</a>
<! --<a class="delete" href="#" th:href="@{/comment/{id}/delete(id=${comment.id})}" onclick="return confirm(' Do you want to delete this comment? Think again! If you delete it, it's gone! ')" th:if="${session. User}"> delete </a>-->
</div>
</div>
<! -- Subset comment -->
<div class="comments" th:if="${#arrays.length(comment.replyComments)}>0">
<div class="comment" th:each="reply : ${comment.replyComments}">
<a class="avatar">
<img src="https://unsplash.it/100/100? image=1005" th:src="@{${reply.avatar}}">
</a>
<div class="content">
<a class="author" >
<span th:text="${reply.nickname}">The little red</span>
<div class="ui mini basic teal left pointing label m-padded-mini" th:if="${reply.adminComment}">The stack master</div>
<span th:text="|@ ${reply.parentNickname}|" class="m-teal">@ small white</span>
</a>
<div class="metadata">
<span class="date" th:text="${#dates.format(reply.createTime,'yyyy-MM-dd HH:mm')}">Today at 5:42PM</span>
</div>
<div class="text" th:text="${reply.content}">
How artistic!
</div>
<div class="actions">
<a class="reply" data-commentid="1" data-commentnickname="Matt" th:attr="data-commentid=${reply.id},data-commentnickname=${reply.nickname}" onclick="reply(this)">reply</a>
<a class="delete" href="#" th:href="@{/comment/{param1}/{param2}/delete(param1=${reply.blogId},param2=${reply.id})}" onclick="Return Confirm (' Are you sure you want to delete this comment? Think again! If you delete it, it's gone! ')" th:if="${session.user}">delete</a>
<! --<a class="delete" href="#" th:href="@{/comment/{id}/delete(id=${reply.id})}" onclick="return confirm(' Do you want to delete this comment? Think again! If you delete it, it's gone! ')" th:if="${session. User}"> delete </a>-->
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
Copy the code
3. Run access
Run the project, visit http://localhost:8080/, click an article, you can view the information of the article, and can make comments, after logging in, you can delete the comments
At this point, Springboot build personal blog details page shows the completion of the development, because the message function and comment function is basically the same, before also wrote a blog about comments (Springboot and Mybatis to achieve comments in the building function (a table is done)), so here is not talking about the development of message function, There are not understand the partner can ask me, can also add group discussion, the next is directly about classification, timeline, music box, friends account, photo wall about my page display, relatively simple, directly in an article finished
[Point attention, don’t get lost, welcome to continue to pay attention to this site]