当前位置: 首页 > news >正文

软件开发新技术课设-个人博客系统(一)

前言:

停了很久的博客,因为把心思放在高数上面了,不过涉及到课设还是考虑到把开发流程放到CSDN上作为保存。前面都是废话,请直接从标题-框架搭建开始看

一、 考核内容

(1)根据本学期所学内容,开发一个“个人博客系统”。

(2)个人博客系统需求: 系统中有两个角色,分别是管理员和用户。系统功能可以分为前台管理和后台管 理。

  前台管理:

(1)系统首页可以根据文章分类列表展示用户发布的已审核的文章。

(2)用户可以查看文章详情、文章的评论列表以及文章的点击量。

(3)用户可以对文章发表自己的评论。

后台管理:

系统中管理员和用户都需要登录并拥有管理后台。

(1)管理员: 系统中默认有一个管理员admin,可以在管理后台管理文章类别、对用户发 布的文章进行审核以及文章点击量统计。

(2)用户: 用户需要在系统中进行注册,可以在管理后台发布文章并对文章进行管理 (增删改查),发布文章时需要选择文章类别。在管理后台,用户也可以查看文章的 点击量以及评论内容。

(3)考核要求: 本项目为个人开发项目,需要结合系统需求自行设计数据库,使用本学期所学的 软件开发新技术完成项目的设计与开发。

二、评价标准

 三、技术选型

层级技术栈
后端框架Spring Boot 3.x + MyBatis-plus
数据库MySQL 5.7
前端模板

thymeleaf模板

安全框架Spring Security
构建工具Maven

 四、框架搭建

4.1构建与配置 

1、引入Spring Boot模块:

web

Thymeleaf

JPA     MyBatis-plus

MySQL

Aspects

DevTools

2、application.yml配置

使用 thymeleaf 3

pom.xml: 

<thymeleaf.version>3.0.2.RELEASE</thymeleaf.version>
<thymeleaf-layout-dialect.version>2.1.1</thymeleaf-layout-dialect.version>
application.yml: 

spring:thymeleaf:mode: HTML
 3、数据库连接配置

spring:datasource:driver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/blog?useUnicode=true&characterEncoding=utf-8username: rootpassword: root
4、日志配置 
logging:level:root: infocom.imcoding: debugfile: log/imcoding.log
5、 logback-spring.xml:

<?xml version="1.0" encoding="UTF-8" ?>
<configuration><!--包含Spring boot对logback日志的默认配置--><include resource="org/springframework/boot/logging/logback/defaults.xml" /><property name="LOG_FILE" value="${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}}/spring.log}"/><include resource="org/springframework/boot/logging/logback/console-appender.xml" /><!--重写了Spring Boot框架 org/springframework/boot/logging/logback/file-appender.xml 配置--><appender name="TIME_FILE"class="ch.qos.logback.core.rolling.RollingFileAppender"><encoder><pattern>${FILE_LOG_PATTERN}</pattern></encoder><file>${LOG_FILE}</file><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><fileNamePattern>${LOG_FILE}.%d{yyyy-MM-dd}.%i</fileNamePattern><!--保留历史日志一个月的时间--><maxHistory>30</maxHistory><!--Spring Boot默认情况下,日志文件10M时,会切分日志文件,这样设置日志文件会在100M时切分日志--><timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"><maxFileSize>10MB</maxFileSize></timeBasedFileNamingAndTriggeringPolicy></rollingPolicy></appender><root level="INFO"><appender-ref ref="CONSOLE" /><appender-ref ref="TIME_FILE" /></root></configuration><!--1、继承Spring boot logback设置(可以在appliaction.yml或者application.properties设置logging.*属性)2、重写了默认配置,设置日志文件大小在100MB时,按日期切分日志,切分后目录:blog.2017-08-01.0   80MBblog.2017-08-01.1   10MBblog.2017-08-02.0   56MBblog.2017-08-03.0   53MB......-->

6、生产环境与开发环境配置

   *  application-dev.yml()

   *  application-pro.yml

4.2 异常处理

1、定义错误界面: 

老三样:404、500、error

 2、全局异常处理:统一异常处理
package com.lrm.handler;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;@ControllerAdvice
public class ControllerExceptionHandler {private final Logger logger = LoggerFactory.getLogger(this.getClass());@ExceptionHandler(Exception.class)public ModelAndView exceptionHander(HttpServletRequest request, Exception e) throws Exception {logger.error("Requst URL : {},Exception : {}", request.getRequestURL(),e);if (AnnotationUtils.findAnnotation(e.getClass(), ResponseStatus.class) != null) {throw e;}ModelAndView mv = new ModelAndView();mv.addObject("url",request.getRequestURL());mv.addObject("exception", e);mv.setViewName("error/error");return mv;}
}
3、错误页面异常信息显示处理: 
<div><div th:utext="'&lt;!--'" th:remove="tag"></div><div th:utext="'Failed Request URL : ' + ${url}" th:remove="tag"></div><div th:utext="'Exception message : ' + ${exception.message}" th:remove="tag"></div><ul th:remove="tag"><li th:each="st : ${exception.stackTrace}" th:remove="tag"><span th:utext="${st}" th:remove="tag"></span></li></ul><div th:utext="'--&gt;'" th:remove="tag"></div>
</div>
 4、资源找不到异常:
@ResponseStatus(HttpStatus.NOT_FOUND)
public class NotFoundExcepiton extends RuntimeException {public NotFoundExcepiton() {}public NotFoundExcepiton(String message) {super(message);}public NotFoundExcepiton(String message, Throwable cause) {super(message, cause);}
}

4.3日志处理 

1、记录日志内容

*  请求 url

*  访问者 ip

*  调用方法 classMethod

*  参数 args

*  返回内容

2、记录日志类 
@Aspect
@Component
public class LogAspect {private final Logger logger = LoggerFactory.getLogger(this.getClass());/*** 定义切面*/@Pointcut("execution(* com.imcoding.web.*.*(..))")public void log() {}@Before("log()")public void doBefore(JoinPoint joinPoint) {ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();HttpServletRequest request = attributes.getRequest();String classMethod = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName();ReqeustLog reqeustLog = new ReqeustLog(request.getRequestURL().toString(),request.getRemoteAddr(),classMethod,joinPoint.getArgs());logger.info("Rquest  ----- {}",reqeustLog);}@After("log()")public void doAfter() {//logger.info("---------- doAfter 2 ----------");}@AfterReturning(returning = "result",pointcut = "log()")public void doAtfertRturning(Object result) {logger.info("Return ------ {}",result );}private class ReqeustLog {private String url;private String ip;private String classMethod;private Object[] args;public ReqeustLog(String url, String ip, String classMethod, Object[] args) {this.url = url;this.ip = ip;this.classMethod = classMethod;this.args = args;}@Overridepublic String toString() {return "ReqeustLog{" +"url='" + url + '\'' +", ip='" + ip + '\'' +", classMethod='" + classMethod + '\'' +", args=" + Arrays.toString(args) +'}';}}}

4.4页面处理:(均打算用AI)

1、静态页面导入project

2、thymeleaf布局

 定义fragment

使用fragment布局

3、错误页面美化

 五、设计与规范

 5.1实体类设计

博客 Blog

博客分类 Type

博客标签 Tag

博客评论 Comment

用户 User

 暂时先这几个,如果后面要加的时候补个分割线补充

 5.2实体关系:

建完数据库了再写这里,先空着

六、功能实现

6.1登录

1、构建登录页面和后台管理首页

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head th:replace="admin/_fragments :: head(~{::title})"><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>博客管理登录</title><link rel="stylesheet" href="https://cdn.jsdelivr.net/semantic-ui/2.2.4/semantic.min.css"><link rel="stylesheet" href="../../static/css/me.css">
</head>
<body><br>
<br>
<br>
<div class="m-container-small m-padded-tb-massive" style="max-width: 30em !important;"><div class="ur container"><div class="ui middle aligned center aligned grid"><div class="column"><h2 class="ui teal image header"><div class="content">管理后台登录</div></h2><form class="ui large form" method="post" action="#" th:action="@{/admin/login}"><div class="ui  segment"><div class="field"><div class="ui left icon input"><i class="user icon"></i><input type="text" name="username" placeholder="用户名"></div></div><div class="field"><div class="ui left icon input"><i class="lock icon"></i><input type="password" name="password" placeholder="密码"></div></div><button class="ui fluid large teal submit button">登   录</button></div><div class="ui error mini message"></div><div class="ui mini negative message" th:unless="${#strings.isEmpty(message)}" th:text="${message}">用户名和密码错误</div></form></div></div></div>
</div><!--/*/<th:block th:replace="_fragments :: script">/*/-->
<script src="https://cdn.jsdelivr.net/npm/jquery@3.2/dist/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/semantic-ui/2.2.4/semantic.min.js"></script>
<!--/*/</th:block>/*/--><script>$('.ui.form').form({fields : {username : {identifier: 'username',rules: [{type : 'empty',prompt: '请输入用户名'}]},password : {identifier: 'password',rules: [{type : 'empty',prompt: '请输入密码'}]}}});
</script></body>
</html>
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head th:replace="_fragments :: head(~{::title})"><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>博客</title><link rel="stylesheet" href="https://cdn.jsdelivr.net/semantic-ui/2.2.4/semantic.min.css" ><link rel="stylesheet" href="../static/css/me.css" >
</head>
<body><!--导航--><nav th:replace="_fragments :: menu(1)" class="ui inverted attached segment m-padded-tb-mini m-shadow-small" ><div class="ui container"><div class="ui inverted secondary stackable menu"><h2 class="ui teal header item">Blog</h2><a href="#" class=" m-item item m-mobile-hide"><i class="mini home icon"></i>首页</a><a href="#" class="m-item item m-mobile-hide"><i class="mini idea icon"></i>分类</a><a href="#" class="m-item item m-mobile-hide"><i class="mini tags icon"></i>标签</a><a href="#" class="m-item item m-mobile-hide"><i class="mini clone icon"></i>归档</a><a href="#" class="m-item item m-mobile-hide"><i class="mini info icon"></i>关于我</a><div class="right m-item item m-mobile-hide"><div class="ui icon inverted transparent input m-margin-tb-tiny"><input type="text" placeholder="Search...."><i class="search link icon"></i></div></div></div></div><a href="#" class="ui menu toggle black icon button m-right-top m-mobile-show"><i class="sidebar icon"></i></a></nav><!--中间内容--><div  class="m-container m-padded-tb-big animated fadeIn"><div class="ui container"><div class="ui stackable grid"><!--左边博客列表--><div class="eleven wide column"><!--header--><div class="ui top attached segment"><div class="ui middle aligned two column grid"><div class="column"><h3 class="ui teal header">博客</h3></div><div class="right aligned column">共 <h2 class="ui orange header m-inline-block m-text-thin" th:text="${page.total}"> 14 </h2> 篇</div></div></div><!--content--><div class="ui attached  segment"><div class="ui padded vertical segment m-padded-tb-large" th:each="blog : ${page.records}"><div class="ui middle aligned mobile reversed stackable grid" ><div class="eleven wide column"><h3 class="ui header" ><a href="#" th:href="@{/blog/{id}(id=${blog.id})}" target="_blank" class="m-black" th:text="${blog.title}">你真的理解什么是财富自由吗?</a></h3><p class="m-text" th:text="|${blog.description}......|">正确做好任何一件事情的前提是清晰、正确的理解目标。而事实是,我们很多人很多时候根本没有对目标正确的定义,甚至根本从来就没有想过,只是大家都那么做而已…...</p><div class="ui grid"><div class="eleven wide column"><div class="ui mini horizontal link list"><div class="item"><img src="https://unsplash.it/100/100?image=1005" th:src="@{${blog.user.avatar}}"  alt="" class="ui avatar image"><div class="content"><a href="#" class="header" th:text="${blog.user.nickname}" >像污秽一样</a></div></div><div class="item"><i class="calendar icon"></i><span th:text="${#dates.format(blog.updateTime,'yyyy-MM-dd')}">2017-10-01</span></div><div class="item"><i class="eye icon"></i> <span th:text="${blog.views}">2342</span></div></div></div><div class="right aligned five wide column"><a href="#" target="_blank" class="ui teal basic label m-padded-tiny m-text-thin" th:text="${blog.type.name}">认知升级</a></div></div></div><div class="five wide column"><a href="#" th:href="@{/blog/{id}(id=${blog.id})}" target="_blank"><img src="https://unsplash.it/800/450?image=1005" th:src="@{${blog.firstPicture}}"  alt="" class="ui rounded image"></a></div></div></div><!--/*--><div class="ui padded vertical segment m-padded-tb-large"><div class="ui mobile reversed stackable grid"><div class="eleven wide column"><h3 class="ui header">你真的理解什么是财富自由吗?</h3><p class="m-text">正确做好任何一件事情的前提是清晰、正确的理解目标。而事实是,我们很多人很多时候根本没有对目标正确的定义,甚至根本从来就没有想过,只是大家都那么做而已…...</p><div class="ui grid"><div class="eleven wide column"><div class="ui mini horizontal link list"><div class="item"><img src="https://unsplash.it/100/100?image=1005" alt="" class="ui avatar image"><div class="content"><a href="#" class="header">像污秽一样</a></div></div><div class="item"><i class="calendar icon"></i> 2017-10-01</div><div class="item"><i class="eye icon"></i> 2342</div></div></div><div class="right aligned five wide column"><a href="#" target="_blank" class="ui teal basic label m-padded-tiny m-text-thin">认知升级</a></div></div></div><div class="five wide column"><a href="#" target="_blank"><img src="https://unsplash.it/800/450?image=1005" alt="" class="ui rounded image"></a></div></div></div><div class="ui padded vertical segment m-padded-tb-large"><div class="ui mobile reversed stackable grid"><div class="eleven wide column"><h3 class="ui header">你真的理解什么是财富自由吗?</h3><p class="m-text">正确做好任何一件事情的前提是清晰、正确的理解目标。而事实是,我们很多人很多时候根本没有对目标正确的定义,甚至根本从来就没有想过,只是大家都那么做而已…...</p><div class="ui grid"><div class="eleven wide column"><div class="ui mini horizontal link list"><div class="item"><img src="https://unsplash.it/100/100?image=1005" alt="" class="ui avatar image"><div class="content"><a href="#" class="header">像污秽一样</a></div></div><div class="item"><i class="calendar icon"></i> 2017-10-01</div><div class="item"><i class="eye icon"></i> 2342</div></div></div><div class="right aligned five wide column"><a href="#" target="_blank" class="ui teal basic label m-padded-tiny m-text-thin">认知升级</a></div></div></div><div class="five wide column"><a href="#" target="_blank"><img src="https://unsplash.it/800/450?image=1005" alt="" class="ui rounded image"></a></div></div></div><div class="ui padded vertical segment m-padded-tb-large"><div class="ui mobile reversed stackable grid"><div class="eleven wide column"><h3 class="ui header">你真的理解什么是财富自由吗?</h3><p class="m-text">正确做好任何一件事情的前提是清晰、正确的理解目标。而事实是,我们很多人很多时候根本没有对目标正确的定义,甚至根本从来就没有想过,只是大家都那么做而已…...</p><div class="ui grid"><div class="eleven wide column"><div class="ui mini horizontal link list"><div class="item"><img src="https://unsplash.it/100/100?image=1005" alt="" class="ui avatar image"><div class="content"><a href="#" class="header">像污秽一样</a></div></div><div class="item"><i class="calendar icon"></i> 2017-10-01</div><div class="item"><i class="eye icon"></i> 2342</div></div></div><div class="right aligned five wide column"><a href="#" target="_blank" class="ui teal basic label m-padded-tiny m-text-thin">认知升级</a></div></div></div><div class="five wide column"><a href="#" target="_blank"><img src="https://unsplash.it/800/450?image=1005" alt="" class="ui rounded image"></a></div></div></div><div class="ui padded vertical segment m-padded-tb-large"><div class="ui mobile reversed stackable grid"><div class="eleven wide column"><h3 class="ui header">你真的理解什么是财富自由吗?</h3><p class="m-text">正确做好任何一件事情的前提是清晰、正确的理解目标。而事实是,我们很多人很多时候根本没有对目标正确的定义,甚至根本从来就没有想过,只是大家都那么做而已…...</p><div class="ui grid"><div class="eleven wide column"><div class="ui mini horizontal link list"><div class="item"><img src="https://unsplash.it/100/100?image=1005" alt="" class="ui avatar image"><div class="content"><a href="#" class="header">像污秽一样</a></div></div><div class="item"><i class="calendar icon"></i> 2017-10-01</div><div class="item"><i class="eye icon"></i> 2342</div></div></div><div class="right aligned five wide column"><a href="#" target="_blank" class="ui teal basic label m-padded-tiny m-text-thin">认知升级</a></div></div></div><div class="five wide column"><a href="#" target="_blank"><img src="https://unsplash.it/800/450?image=1005" alt="" class="ui rounded image"></a></div></div></div><div class="ui padded vertical segment m-padded-tb-large"><div class="ui mobile reversed stackable grid"><div class="eleven wide column"><h3 class="ui header">你真的理解什么是财富自由吗?</h3><p class="m-text">正确做好任何一件事情的前提是清晰、正确的理解目标。而事实是,我们很多人很多时候根本没有对目标正确的定义,甚至根本从来就没有想过,只是大家都那么做而已…...</p><div class="ui grid"><div class="eleven wide column"><div class="ui mini horizontal link list"><div class="item"><img src="https://unsplash.it/100/100?image=1005" alt="" class="ui avatar image"><div class="content"><a href="#" class="header">像污秽一样</a></div></div><div class="item"><i class="calendar icon"></i> 2017-10-01</div><div class="item"><i class="eye icon"></i> 2342</div></div></div><div class="right aligned five wide column"><a href="#" target="_blank" class="ui teal basic label m-padded-tiny m-text-thin">认知升级</a></div></div></div><div class="five wide column"><a href="#" target="_blank"><img src="https://unsplash.it/800/450?image=1005" alt="" class="ui rounded image"></a></div></div></div><div class="ui padded vertical segment m-padded-tb-large"><div class="ui mobile reversed stackable grid"><div class="eleven wide column"><h3 class="ui header">你真的理解什么是财富自由吗?</h3><p class="m-text">正确做好任何一件事情的前提是清晰、正确的理解目标。而事实是,我们很多人很多时候根本没有对目标正确的定义,甚至根本从来就没有想过,只是大家都那么做而已…...</p><div class="ui grid"><div class="eleven wide column"><div class="ui mini horizontal link list"><div class="item"><img src="https://unsplash.it/100/100?image=1005" alt="" class="ui avatar image"><div class="content"><a href="#" class="header">像污秽一样</a></div></div><div class="item"><i class="calendar icon"></i> 2017-10-01</div><div class="item"><i class="eye icon"></i> 2342</div></div></div><div class="right aligned five wide column"><a href="#" target="_blank" class="ui teal basic label m-padded-tiny m-text-thin">认知升级</a></div></div></div><div class="five wide column"><a href="#" target="_blank"><img src="https://unsplash.it/800/450?image=1005" alt="" class="ui rounded image"></a></div></div></div><div class="ui padded vertical segment m-padded-tb-large"><div class="ui mobile reversed stackable grid"><div class="eleven wide column"><h3 class="ui header">你真的理解什么是财富自由吗?</h3><p class="m-text">正确做好任何一件事情的前提是清晰、正确的理解目标。而事实是,我们很多人很多时候根本没有对目标正确的定义,甚至根本从来就没有想过,只是大家都那么做而已…...</p><div class="ui grid"><div class="eleven wide column"><div class="ui mini horizontal link list"><div class="item"><img src="https://unsplash.it/100/100?image=1005" alt="" class="ui avatar image"><div class="content"><a href="#" class="header">像污秽一样</a></div></div><div class="item"><i class="calendar icon"></i> 2017-10-01</div><div class="item"><i class="eye icon"></i> 2342</div></div></div><div class="right aligned five wide column"><a href="#" target="_blank" class="ui teal basic label m-padded-tiny m-text-thin">认知升级</a></div></div></div><div class="five wide column"><a href="#" target="_blank"><img src="https://unsplash.it/800/450?image=1005" alt="" class="ui rounded image"></a></div></div></div><div class="ui padded vertical segment m-padded-tb-large"><div class="ui mobile reversed stackable grid"><div class="eleven wide column"><h3 class="ui header">你真的理解什么是财富自由吗?</h3><p class="m-text">正确做好任何一件事情的前提是清晰、正确的理解目标。而事实是,我们很多人很多时候根本没有对目标正确的定义,甚至根本从来就没有想过,只是大家都那么做而已…...</p><div class="ui grid"><div class="eleven wide column"><div class="ui mini horizontal link list"><div class="item"><img src="https://unsplash.it/100/100?image=1005" alt="" class="ui avatar image"><div class="content"><a href="#" class="header">像污秽一样</a></div></div><div class="item"><i class="calendar icon"></i> 2017-10-01</div><div class="item"><i class="eye icon"></i> 2342</div></div></div><div class="right aligned five wide column"><a href="#" target="_blank" class="ui teal basic label m-padded-tiny m-text-thin">认知升级</a></div></div></div><div class="five wide column"><a href="#" target="_blank"><img src="https://unsplash.it/800/450?image=1005" alt="" class="ui rounded image"></a></div></div></div><div class="ui padded vertical segment m-padded-tb-large"><div class="ui mobile reversed stackable grid"><div class="eleven wide column"><h3 class="ui header">你真的理解什么是财富自由吗?</h3><p class="m-text">正确做好任何一件事情的前提是清晰、正确的理解目标。而事实是,我们很多人很多时候根本没有对目标正确的定义,甚至根本从来就没有想过,只是大家都那么做而已…...</p><div class="ui grid"><div class="eleven wide column"><div class="ui mini horizontal link list"><div class="item"><img src="https://unsplash.it/100/100?image=1005" alt="" class="ui avatar image"><div class="content"><a href="#" class="header">像污秽一样</a></div></div><div class="item"><i class="calendar icon"></i> 2017-10-01</div><div class="item"><i class="eye icon"></i> 2342</div></div></div><div class="right aligned five wide column"><a href="#" target="_blank" class="ui teal basic label m-padded-tiny m-text-thin">认知升级</a></div></div></div><div class="five wide column"><a href="#" target="_blank"><img src="https://unsplash.it/800/450?image=1005"  alt="" class="ui rounded image"></a></div></div></div><!--*/--></div><!--footer--><div class="ui bottom attached segment" th:if="${page.pages}>1"><div class="ui middle aligned two column grid"><div class="column"><a href="#" th:href="@{/(page=${page.number}-1)}"  th:unless="${page.first}" class="ui mini teal basic button">上一页</a></div><div class="right aligned column"><a href="#" th:href="@{/(page=${page.number}+1)}"  th:unless="${page.last}" class="ui mini teal basic button">下一页</a></div></div></div></div><!--右边的top--><div class="five wide column"><!--分类--><div class="ui segments"><div class="ui secondary segment"><div class="ui two column grid"><div class="column"><i class="idea icon"></i>分类</div><div class="right aligned column"><a href="#" th:href="@{types/-1}" target="_blank">more <i class="angle double right icon"></i></a></div></div></div><div class="ui teal segment"><div class="ui fluid vertical menu" ><a href="#" th:href="@{/types/{id}(id=${type.id})}" target="_blank" class="item"  th:each="type : ${types}"><span th:text="${type.name}">学习日志</span><div class="ui teal basic left pointing label" th:text="${#arrays.length(type.blogs)}">13</div></a><!--/*--><a href="#" class="item">思考与感悟<div class="ui teal basic left pointing label">13</div></a><a href="#" class="item">学习日志<div class="ui teal basic left pointing label">13</div></a><a href="#" class="item">学习日志<div class="ui teal basic left pointing label">13</div></a><a href="#" class="item">学习日志<div class="ui teal basic left pointing label">13</div></a><a href="#" class="item">学习日志<div class="ui teal basic left pointing label">13</div></a><!--*/--></div></div></div><!--标签--><div class="ui segments m-margin-top-large"><div class="ui secondary segment"><div class="ui two column grid"><div class="column"><i class="tags icon"></i>标签</div><div class="right aligned column"><a href="#" th:href="@{tags/-1}" target="_blank">more <i class="angle double right icon"></i></a></div></div></div><div class="ui teal segment"><a href="#" th:href="@{/tags/{id}(id=${tag.id})}" target="_blank" class="ui teal basic left pointing label m-margin-tb-tiny" th:each="tag : ${tags}"><span th:text="${tag.name}">方法论</span> <div class="detail" th:text="${#arrays.length(tag.blogs)}">23</div></a><!--/*--><a href="#" target="_blank" class="ui teal basic left pointing label m-margin-tb-tiny">论 <div class="detail">23</div></a><a href="#" target="_blank" class="ui teal basic left pointing label m-margin-tb-tiny">论 <div class="detail">23</div></a><a href="#" target="_blank" class="ui teal basic left pointing label m-margin-tb-tiny">方法论 <div class="detail">23</div></a><a href="#" target="_blank" class="ui teal basic left pointing label m-margin-tb-tiny">方法论 <div class="detail">23</div></a><a href="#" target="_blank" class="ui teal basic left pointing label m-margin-tb-tiny">方法论 <div class="detail">23</div></a><a href="#" target="_blank" class="ui teal basic left pointing label m-margin-tb-tiny">方法论 <div class="detail">23</div></a><a href="#" target="_blank" class="ui teal basic left pointing label m-margin-tb-tiny">方法论 <div class="detail">23</div></a><a href="#" target="_blank" class="ui teal basic left pointing label m-margin-tb-tiny">方法论 <div class="detail">23</div></a><a href="#" target="_blank" class="ui teal basic left pointing label m-margin-tb-tiny">方法论 <div class="detail">23</div></a><!--*/--></div></div><!--最新推荐--><div class="ui segments m-margin-top-large"><div class="ui secondary segment "><i class="bookmark icon"></i>最新推荐</div><div class="ui segment" th:each="blog : ${recommendBlogs}"><a href="#" th:href="@{/blog/{id}(id=${blog.id})}" target="_blank" class="m-black m-text-thin" th:text="${blog.title}">用户故事(User Story)</a></div><!--/*--><div class="ui segment" ><a href="#" target="_blank" class="m-black m-text-thin">用户故事(User Story)</a></div><div class="ui segment"><a href="#" target="_blank" class="m-black m-text-thin">用户故事(User Story)</a></div><div class="ui segment"><a href="#" target="_blank" class="m-black m-text-thin">用户故事(User Story)</a></div><div class="ui segment"><a href="#" target="_blank" class="m-black m-text-thin">用户故事(User Story)</a></div><div class="ui segment"><a href="#" target="_blank" class="m-black m-text-thin">用户故事(User Story)</a></div><div class="ui segment"><a href="#" target="_blank" class="m-black m-text-thin">用户故事(User Story)</a></div><div class="ui segment"><a href="#" target="_blank" class="m-black m-text-thin">用户故事(User Story)</a></div><!--*/--></div><!--二维码--><h4 class="ui horizontal divider header m-margin-top-large">扫码关注我</h4><div class="ui centered card" style="width: 11em"><img src="../static/images/wechat.jpg" th:src="@{/images/wechat.jpg}" alt="" class="ui rounded image" ></div></div></div></div></div><br><br><!--底部footer--><footer th:replace="_fragments :: footer" class="ui inverted vertical segment m-padded-tb-massive"><div class="ui center aligned container"><div class="ui inverted divided stackable grid"><div class="three wide column"><div class="ui inverted link list"><div class="item"><img src="../static/images/wechat.jpg" th:src="@{/images/wechat.jpg}"  class="ui rounded image" alt="" style="width: 110px"></div></div></div><div class="three wide column"><h4 class="ui inverted header m-text-thin m-text-spaced " >最新博客</h4><div class="ui inverted link list"><a href="#" class="item m-text-thin">用户故事(User Story)</a><a href="#" class="item m-text-thin">用户故事(User Story)</a><a href="#" class="item m-text-thin">用户故事(User Story)</a></div></div><div class="three wide column"><h4 class="ui inverted header m-text-thin m-text-spaced ">联系我</h4><div class="ui inverted link list"><a href="#" class="item m-text-thin">Email:flowerfog07@outlook.com</a><a href="#" class="item m-text-thin">QQ:2252221508</a></div></div><div class="seven wide column"><h4 class="ui inverted header m-text-thin m-text-spaced ">Blog</h4><p class="m-text-thin m-text-spaced m-opacity-mini">这是我的个人博客、会分享关于编程、写作、思考相关的任何内容,希望可以给来到这儿的人有所帮助...</p></div></div><div class="ui inverted section divider"></div><p class="m-text-thin m-text-spaced m-opacity-tiny">Copyright © 2016 - 2017 flowerfog Designed by flowerfog</p></div></footer>
<!--/*/<th:block th:replace="_fragments :: script">/*/--><script src="https://cdn.jsdelivr.net/npm/jquery@3.2/dist/jquery.min.js"></script><script src="https://cdn.jsdelivr.net/semantic-ui/2.2.4/semantic.min.js"></script>
<!--/*/</th:block>/*/--><script>$('.menu.toggle').click(function () {$('.m-item').toggleClass('m-mobile-hide');});</script>
</body>
</html>

2、UserService和UserMapper
package com.flowerfog.blog.service;import com.flowerfog.blog.pojo.User;public interface UserService {User checkUser(String username, String password);User getById(Long id);
}

package com.flowerfog.blog.service.imp;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.flowerfog.blog.mapper.UserMapper;
import com.flowerfog.blog.pojo.User;
import com.flowerfog.blog.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;@Service
public class UserServiceImp implements UserService {@Autowiredprivate UserMapper userMapper;/*** TOOD: 密码加密* @param username* @param password* @return*/
//    @Autowired
//    private PasswordEncoder passwordEncoder;@Overridepublic User checkUser(String username, String password) {// 使用 MyBatis-Plus 的 QueryWrapper 构建查询条件,仅根据用户名查询用户QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.eq("username", username);User user = userMapper.selectOne(queryWrapper);// 验证用户是否存在以及密码是否匹配
//        if (user != null && passwordEncoder.matches(password, user.getPassword())) {
//            return user;
//        }if(user != null && user.getPassword().equals(password)){return user;}return null;}@Overridepublic User getById(Long id) {return userMapper.selectById(id);}
}

package com.flowerfog.blog.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;import com.flowerfog.blog.pojo.User;
import org.springframework.stereotype.Repository;@Repository
public interface UserMapper extends BaseMapper<User> {
}
3、LoginController实现登录
package com.flowerfog.blog.controller.admin;import com.flowerfog.blog.pojo.User;
import com.flowerfog.blog.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;/*** Created by flowerfog on 2025/5/15.*/
@Controller
@RequestMapping("/admin")
public class LoginController {@Autowiredprivate UserService userService;//    @GetMapping
//    public String loginPage() {
//        return "admin/login";
//    }@GetMappingpublic String loginPage(HttpServletRequest request) {String message = (String) request.getSession().getAttribute("message");if (message != null) {request.setAttribute("message", message);request.getSession().removeAttribute("message");}return "admin/login";}@GetMapping("/index")public String index() {return "admin/index";}//    @PostMapping("/login")
//    public String login(@RequestParam String username,
//                        @RequestParam String password,
//                        RedirectAttributes attributes,
//                        HttpSession session) {
//        User user =  userService.checkUser(username,password);
//        if (user != null) {
//            user.setPassword(null);
//            session.setAttribute("user",user);
//            return "admin/index";
//        } else {
//            attributes.addFlashAttribute("message", "用户名和密码错误");
//            return "redirect:/admin";
//        }
//    }@GetMapping("/logout")public String logout(HttpSession session) {session.removeAttribute("user");return "redirect:/admin";}
}
4、security配置
package com.flowerfog.blog.config;import com.flowerfog.blog.handler.CustomAuthenticationSuccessHandler;
import com.flowerfog.blog.service.CustomUserDetailsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;@Configuration
@EnableWebSecurity
public class SecurityConfig {@Autowiredprivate CustomUserDetailsService customUserDetailsService;@Autowiredprivate CustomAuthenticationSuccessHandler customAuthenticationSuccessHandler;@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}@Beanpublic DaoAuthenticationProvider authenticationProvider() {DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();authProvider.setUserDetailsService(customUserDetailsService);authProvider.setPasswordEncoder(passwordEncoder());return authProvider;}@Beanpublic AuthenticationManager authenticationManager(AuthenticationConfiguration authConfig) throws Exception {return authConfig.getAuthenticationManager();}@Beanpublic SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {http.csrf(csrf -> csrf.disable()).authorizeHttpRequests(auth -> auth.requestMatchers("/admin", "/admin/login").permitAll().requestMatchers("/admin/**").authenticated().anyRequest().permitAll()).formLogin(form -> form.loginPage("/admin").loginProcessingUrl("/admin/login")// 设置认证成功处理器.successHandler(customAuthenticationSuccessHandler).failureHandler(authenticationFailureHandler()).permitAll()).logout(logout -> logout.logoutUrl("/admin/logout").logoutSuccessUrl("/admin").permitAll());http.authenticationProvider(authenticationProvider());return http.build();}@Beanpublic AuthenticationFailureHandler authenticationFailureHandler() {return (request, response, exception) -> {request.getSession().setAttribute("message", "用户名和密码错误");response.sendRedirect("/admin");};}
}

其中 CustomUserDetailsService和CustomAuthenticationSuccessHandler如下:

package com.flowerfog.blog.service;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.flowerfog.blog.mapper.UserMapper;
import com.flowerfog.blog.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;import java.util.ArrayList;
import java.util.Collection;
import java.util.Set;@Service
public class CustomUserDetailsService implements UserDetailsService {@Autowiredprivate UserMapper userMapper;public CustomUserDetailsService() {}@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.eq("username", username);User user = userMapper.selectOne(queryWrapper);if (user == null) {throw new UsernameNotFoundException("未找到用户名: " + username + " 对应的用户");}UserDetails userDetails = new org.springframework.security.core.userdetails.User(user.getUsername(),user.getPassword(),AuthorityUtils.NO_AUTHORITIES);return userDetails;}}
package com.flowerfog.blog.handler;import com.flowerfog.blog.pojo.User;
import com.flowerfog.blog.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;import java.io.IOException;@Component
public class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandler {@Autowiredprivate UserService userService;@Overridepublic void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,Authentication authentication) throws IOException, ServletException {// 获取认证后的用户信息UserDetails userDetails = (UserDetails) authentication.getPrincipal();String username = userDetails.getUsername();// 调用 UserService 获取用户实体User user = userService.checkUser(username,"");if (user != null) {// 清除密码信息user.setPassword(null);HttpSession session = request.getSession();// 将用户信息存入会话session.setAttribute("user", user);}// 重定向到登录成功后的页面response.sendRedirect("/admin/index");}
}

6.2分类管理

mapper这些就不放了,太多了懒得站,分页设计这些也是老生常谈了
package com.flowerfog.blog.controller.admin;import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.flowerfog.blog.pojo.Type;
import com.flowerfog.blog.service.TypeService;
import jakarta.validation.Valid;
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.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;/*** Created by flowerfog on 2024/12/16.*/@Controller
@RequestMapping("/admin")
public class TypeController {@Autowiredprivate TypeService typeService;@GetMapping("/types")public String types(@RequestParam(defaultValue = "1") Integer pageNum,        // 当前页码(从1开始)@RequestParam(defaultValue = "10") Integer pageSize,      // 每页大小@RequestParam(defaultValue = "id") String sortField,      // 排序字段@RequestParam(defaultValue = "DESC") String sortDirection,// 排序方向Model model) {// 创建MyBatis-Plus分页对象Page<Type> page = new Page<>(pageNum, pageSize);// 设置排序规则if ("ASC".equalsIgnoreCase(sortDirection)) {page.addOrder(OrderItem.asc(sortField));} else {page.addOrder(OrderItem.desc(sortField));}// 调用服务层获取分页数据Page<Type> typePage = (Page<Type>) typeService.listType(page);// 把数据传递给视图model.addAttribute("page", typePage);return "admin/types";}@GetMapping("/types/input")public String input(Model model) {model.addAttribute("type", new Type());return "admin/types-input";}@GetMapping("/types/{id}/input")public String editInput(@PathVariable Long id, Model model) {model.addAttribute("type", typeService.getType(id));return "admin/types-input";}@PostMapping("/types")public String post(@Valid Type type, BindingResult result, RedirectAttributes attributes) {Type type1 = typeService.getTypeByName(type.getName());if (type1 != null) {result.rejectValue("name","nameError","不能添加重复的分类");}if (result.hasErrors()) {return "admin/types-input";}Type t = typeService.saveType(type);if (t == null ) {attributes.addFlashAttribute("message", "新增失败");} else {attributes.addFlashAttribute("message", "新增成功");}return "redirect:/admin/types";}@PostMapping("/types/{id}")public String editPost(@Valid Type type, BindingResult result,@PathVariable Long id, RedirectAttributes attributes) {Type type1 = typeService.getTypeByName(type.getName());if (type1 != null) {result.rejectValue("name","nameError","不能添加重复的分类");}if (result.hasErrors()) {return "admin/types-input";}Type t = typeService.updateType(id,type);if (t == null ) {attributes.addFlashAttribute("message", "更新失败");} else {attributes.addFlashAttribute("message", "更新成功");}return "redirect:/admin/types";}@GetMapping("/types/{id}/delete")public String delete(@PathVariable Long id,RedirectAttributes attributes) {typeService.deleteType(id);attributes.addFlashAttribute("message", "删除成功");return "redirect:/admin/types";}}

 6.3标签管理

同上

package com.flowerfog.blog.controller.admin;import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.flowerfog.blog.pojo.Tag;
import com.flowerfog.blog.service.TagService;
import jakarta.validation.Valid;
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.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;/*** Created by flowerfog on 2024/12/16.*/@Controller
@RequestMapping("/admin")
public class TagController {@Autowiredprivate TagService tagService;@GetMapping("/tags")public String tags(@RequestParam(defaultValue = "1") Integer pageNum,        // 当前页码(从1开始)@RequestParam(defaultValue = "10") Integer pageSize,      // 每页大小@RequestParam(defaultValue = "id") String sortField,      // 排序字段@RequestParam(defaultValue = "DESC") String sortDirection,// 排序方向Model model) {// 创建 MyBatis-Plus 分页对象Page<Tag> page = new Page<>(pageNum, pageSize);// 设置排序规则if ("ASC".equalsIgnoreCase(sortDirection)) {page.addOrder(OrderItem.asc(sortField));} else {page.addOrder(OrderItem.desc(sortField));}// 调用服务层获取分页数据Page<Tag> tagPage = (Page<Tag>) tagService.listTag(page);// 传递数据到视图model.addAttribute("page", tagPage);return "admin/tags";}@GetMapping("/tags/input")public String input(Model model) {model.addAttribute("tag", new Tag());return "admin/tags-input";}@GetMapping("/tags/{id}/input")public String editInput(@PathVariable Long id, Model model) {model.addAttribute("tag", tagService.getTag(id));return "admin/tags-input";}@PostMapping("/tags")public String post(@Valid Tag tag, BindingResult result, RedirectAttributes attributes) {Tag tag1 = tagService.getTagByName(tag.getName());if (tag1 != null) {result.rejectValue("name","nameError","不能添加重复的分类");}if (result.hasErrors()) {return "admin/tags-input";}Tag t = tagService.saveTag(tag);if (t == null ) {attributes.addFlashAttribute("message", "新增失败");} else {attributes.addFlashAttribute("message", "新增成功");}return "redirect:/admin/tags";}@PostMapping("/tags/{id}")public String editPost(@Valid Tag tag, BindingResult result,@PathVariable Long id, RedirectAttributes attributes) {Tag tag1 = tagService.getTagByName(tag.getName());if (tag1 != null) {result.rejectValue("name","nameError","不能添加重复的分类");}if (result.hasErrors()) {return "admin/tags-input";}Tag t = tagService.updateTag(id,tag);if (t == null ) {attributes.addFlashAttribute("message", "更新失败");} else {attributes.addFlashAttribute("message", "更新成功");}return "redirect:/admin/tags";}@GetMapping("/tags/{id}/delete")public String delete(@PathVariable Long id,RedirectAttributes attributes) {tagService.deleteTag(id);attributes.addFlashAttribute("message", "删除成功");return "redirect:/admin/tags";}}

6.4 博客管理 

package com.flowerfog.blog.controller.admin;import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.flowerfog.blog.pojo.Blog;
import com.flowerfog.blog.pojo.User;
import com.flowerfog.blog.service.BlogService;
import com.flowerfog.blog.service.TagService;
import com.flowerfog.blog.service.TypeService;
import com.flowerfog.blog.vo.BlogQuery;
import org.apache.ibatis.javassist.NotFoundException;
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.*;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;//import javax.servlet.http.HttpSession;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;
/*** Created by flowerfog on 2025/5/15.*/
@Controller
@RequestMapping("/admin")
public class BlogController {private static final String INPUT = "admin/blogs-input";private static final String LIST = "admin/blogs";private static final String REDIRECT_LIST = "redirect:/admin/blogs";@Autowiredprivate BlogService blogService;@Autowiredprivate TypeService typeService;@Autowiredprivate TagService tagService;@GetMapping("/blogs")public String blogs(@RequestParam(defaultValue = "1") Integer pageNum,        // 当前页码(从1开始)@RequestParam(defaultValue = "8") Integer pageSize,       // 每页大小@RequestParam(defaultValue = "update_time") String sortField, // 排序字段@RequestParam(defaultValue = "DESC") String sortDirection, // 排序方向BlogQuery blog,Model model) {// 创建 MyBatis-Plus 分页对象(注意:pageNum 从1开始)Page<Blog> page = new Page<>(pageNum, pageSize);// 设置排序规则if ("ASC".equalsIgnoreCase(sortDirection)) {page.addOrder(OrderItem.asc(sortField));} else {page.addOrder(OrderItem.desc(sortField));}// 调用服务层方法获取分页数据Page<Blog> blogPage = (Page<Blog>) blogService.listBlog(page, blog);// 传递数据到视图model.addAttribute("types", typeService.listType());// 将 MyBatis-Plus 的 Page 转换为 Spring 的 Page(可选,视视图层需求)// 若视图层直接使用 MyBatis-Plus 的 Page,可直接传递 blogPagemodel.addAttribute("page", blogPage);return LIST;}@PostMapping("/blogs/search")public String search(@RequestParam(defaultValue = "1") Integer pageNum,        // 当前页码(从1开始)@RequestParam(defaultValue = "8") Integer pageSize,       // 每页大小@RequestParam(defaultValue = "update_time") String sortField, // 排序字段@RequestParam(defaultValue = "DESC") String sortDirection, // 排序方向BlogQuery blog,Model model) {// 创建 MyBatis-Plus 分页对象Page<Blog> page = new Page<>(pageNum, pageSize);// 设置排序规则page.addOrder(Sort.Direction.DESC.equals(sortDirection) ?OrderItem.desc(sortField) :OrderItem.asc(sortField));// 调用服务层执行搜索和分页Page<Blog> blogPage = blogService.searchBlog(page, blog); // 假设服务层方法名为 searchBlog// 传递分页结果到视图model.addAttribute("page", blogPage);return "admin/blogs :: blogList"; // 维持原视图路径不变}@GetMapping("/blogs/input")public String input(Model model) {setTypeAndTag(model);model.addAttribute("blog", new Blog());return INPUT;}private void setTypeAndTag(Model model) {model.addAttribute("types", typeService.listType());model.addAttribute("tags", tagService.listTag());}@GetMapping("/blogs/{id}/input")public String editInput(@PathVariable Long id, Model model) {setTypeAndTag(model);Blog blog = blogService.getBlog(id);blog.init();model.addAttribute("blog",blog);return INPUT;}@PostMapping("/blogs")public String post(Blog blog, RedirectAttributes attributes, HttpSession session) throws NotFoundException {blog.setUser((User) session.getAttribute("user"));blog.setType(typeService.getType(blog.getType().getId()));blog.setTags(tagService.listTag(blog.getTagIds()));Blog b;if (blog.getId() == null) {b =  blogService.saveBlog(blog);} else {b = blogService.updateBlog(blog.getId(), blog);}if (b == null ) {attributes.addFlashAttribute("message", "操作失败");} else {attributes.addFlashAttribute("message", "操作成功");}return REDIRECT_LIST;}@GetMapping("/blogs/{id}/delete")public String delete(@PathVariable Long id,RedirectAttributes attributes) {blogService.deleteBlog(id);attributes.addFlashAttribute("message", "删除成功");return REDIRECT_LIST;}}

七、前端展示功能实现

7.1 首页展示 

博客列表
@GetMapping("/")public String index(@RequestParam(defaultValue = "1") Integer pageNum,@RequestParam(defaultValue = "8") Integer pageSize,@RequestParam(defaultValue = "update_time") String sortField,@RequestParam(defaultValue = "DESC") String sortDirection,Model model) {// 创建 MyBatis-Plus 分页对象Page<Blog> page = new Page<>(pageNum, pageSize);// 设置排序规则if ("ASC".equalsIgnoreCase(sortDirection)) {page.addOrder(OrderItem.asc(sortField));} else {page.addOrder(OrderItem.desc(sortField));}// 获取博客分页数据(修改此处,调用带用户查询的方法)Page<Blog> blogPage = (Page<Blog>) blogService.listBlogWithUser(page);// 获取分类、标签和推荐博客List<Type> types = typeService.listTypeTop(6);List<Tag> tags = tagService.listTagTop(10);List<Blog> recommendBlogs = blogService.listRecommendBlogTop(8);// 传递数据到视图model.addAttribute("page", blogPage);model.addAttribute("types", types);model.addAttribute("tags", tags);model.addAttribute("recommendBlogs", recommendBlogs);return "index";}
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head th:replace="_fragments :: head(~{::title})"><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>博客</title><link rel="stylesheet" href="https://cdn.jsdelivr.net/semantic-ui/2.2.4/semantic.min.css" ><link rel="stylesheet" href="../static/css/me.css" >
</head>
<body><!--导航--><nav th:replace="_fragments :: menu(1)" class="ui inverted attached segment m-padded-tb-mini m-shadow-small" ><div class="ui container"><div class="ui inverted secondary stackable menu"><h2 class="ui teal header item">Blog</h2><a href="#" class=" m-item item m-mobile-hide"><i class="mini home icon"></i>首页</a><a href="#" class="m-item item m-mobile-hide"><i class="mini idea icon"></i>分类</a><a href="#" class="m-item item m-mobile-hide"><i class="mini tags icon"></i>标签</a><a href="#" class="m-item item m-mobile-hide"><i class="mini clone icon"></i>归档</a><a href="#" class="m-item item m-mobile-hide"><i class="mini info icon"></i>关于我</a><div class="right m-item item m-mobile-hide"><div class="ui icon inverted transparent input m-margin-tb-tiny"><input type="text" placeholder="Search...."><i class="search link icon"></i></div></div></div></div><a href="#" class="ui menu toggle black icon button m-right-top m-mobile-show"><i class="sidebar icon"></i></a></nav><!--中间内容--><div  class="m-container m-padded-tb-big animated fadeIn"><div class="ui container"><div class="ui stackable grid"><!--左边博客列表--><div class="eleven wide column"><!--header--><div class="ui top attached segment"><div class="ui middle aligned two column grid"><div class="column"><h3 class="ui teal header">博客</h3></div><div class="right aligned column">共 <h2 class="ui orange header m-inline-block m-text-thin" th:text="${page.total}"> 14 </h2> 篇</div></div></div><!--content--><div class="ui attached  segment"><div class="ui padded vertical segment m-padded-tb-large" th:each="blog : ${page.records}"><div class="ui middle aligned mobile reversed stackable grid" ><div class="eleven wide column"><h3 class="ui header" ><a href="#" th:href="@{/blog/{id}(id=${blog.id})}" target="_blank" class="m-black" th:text="${blog.title}">你真的理解什么是财富自由吗?</a></h3><p class="m-text" th:text="|${blog.description}......|">正确做好任何一件事情的前提是清晰、正确的理解目标。而事实是,我们很多人很多时候根本没有对目标正确的定义,甚至根本从来就没有想过,只是大家都那么做而已…...</p><div class="ui grid"><div class="eleven wide column"><div class="ui mini horizontal link list"><div class="item"><img src="https://unsplash.it/100/100?image=1005" th:src="@{${blog.user.avatar}}"  alt="" class="ui avatar image"><div class="content"><a href="#" class="header" th:text="${blog.user.nickname}" >像污秽一样</a></div></div><div class="item"><i class="calendar icon"></i><span th:text="${#dates.format(blog.updateTime,'yyyy-MM-dd')}">2017-10-01</span></div><div class="item"><i class="eye icon"></i> <span th:text="${blog.views}">2342</span></div></div></div><div class="right aligned five wide column"><a href="#" target="_blank" class="ui teal basic label m-padded-tiny m-text-thin" th:text="${blog.type.name}">认知升级</a></div></div></div><div class="five wide column"><a href="#" th:href="@{/blog/{id}(id=${blog.id})}" target="_blank"><img src="https://unsplash.it/800/450?image=1005" th:src="@{${blog.firstPicture}}"  alt="" class="ui rounded image"></a></div></div></div><!--/*--><div class="ui padded vertical segment m-padded-tb-large"><div class="ui mobile reversed stackable grid"><div class="eleven wide column"><h3 class="ui header">你真的理解什么是财富自由吗?</h3><p class="m-text">正确做好任何一件事情的前提是清晰、正确的理解目标。而事实是,我们很多人很多时候根本没有对目标正确的定义,甚至根本从来就没有想过,只是大家都那么做而已…...</p><div class="ui grid"><div class="eleven wide column"><div class="ui mini horizontal link list"><div class="item"><img src="https://unsplash.it/100/100?image=1005" alt="" class="ui avatar image"><div class="content"><a href="#" class="header">像污秽一样</a></div></div><div class="item"><i class="calendar icon"></i> 2017-10-01</div><div class="item"><i class="eye icon"></i> 2342</div></div></div><div class="right aligned five wide column"><a href="#" target="_blank" class="ui teal basic label m-padded-tiny m-text-thin">认知升级</a></div></div></div><div class="five wide column"><a href="#" target="_blank"><img src="https://unsplash.it/800/450?image=1005" alt="" class="ui rounded image"></a></div></div></div><div class="ui padded vertical segment m-padded-tb-large"><div class="ui mobile reversed stackable grid"><div class="eleven wide column"><h3 class="ui header">你真的理解什么是财富自由吗?</h3><p class="m-text">正确做好任何一件事情的前提是清晰、正确的理解目标。而事实是,我们很多人很多时候根本没有对目标正确的定义,甚至根本从来就没有想过,只是大家都那么做而已…...</p><div class="ui grid"><div class="eleven wide column"><div class="ui mini horizontal link list"><div class="item"><img src="https://unsplash.it/100/100?image=1005" alt="" class="ui avatar image"><div class="content"><a href="#" class="header">像污秽一样</a></div></div><div class="item"><i class="calendar icon"></i> 2017-10-01</div><div class="item"><i class="eye icon"></i> 2342</div></div></div><div class="right aligned five wide column"><a href="#" target="_blank" class="ui teal basic label m-padded-tiny m-text-thin">认知升级</a></div></div></div><div class="five wide column"><a href="#" target="_blank"><img src="https://unsplash.it/800/450?image=1005" alt="" class="ui rounded image"></a></div></div></div><div class="ui padded vertical segment m-padded-tb-large"><div class="ui mobile reversed stackable grid"><div class="eleven wide column"><h3 class="ui header">你真的理解什么是财富自由吗?</h3><p class="m-text">正确做好任何一件事情的前提是清晰、正确的理解目标。而事实是,我们很多人很多时候根本没有对目标正确的定义,甚至根本从来就没有想过,只是大家都那么做而已…...</p><div class="ui grid"><div class="eleven wide column"><div class="ui mini horizontal link list"><div class="item"><img src="https://unsplash.it/100/100?image=1005" alt="" class="ui avatar image"><div class="content"><a href="#" class="header">像污秽一样</a></div></div><div class="item"><i class="calendar icon"></i> 2017-10-01</div><div class="item"><i class="eye icon"></i> 2342</div></div></div><div class="right aligned five wide column"><a href="#" target="_blank" class="ui teal basic label m-padded-tiny m-text-thin">认知升级</a></div></div></div><div class="five wide column"><a href="#" target="_blank"><img src="https://unsplash.it/800/450?image=1005" alt="" class="ui rounded image"></a></div></div></div><div class="ui padded vertical segment m-padded-tb-large"><div class="ui mobile reversed stackable grid"><div class="eleven wide column"><h3 class="ui header">你真的理解什么是财富自由吗?</h3><p class="m-text">正确做好任何一件事情的前提是清晰、正确的理解目标。而事实是,我们很多人很多时候根本没有对目标正确的定义,甚至根本从来就没有想过,只是大家都那么做而已…...</p><div class="ui grid"><div class="eleven wide column"><div class="ui mini horizontal link list"><div class="item"><img src="https://unsplash.it/100/100?image=1005" alt="" class="ui avatar image"><div class="content"><a href="#" class="header">像污秽一样</a></div></div><div class="item"><i class="calendar icon"></i> 2017-10-01</div><div class="item"><i class="eye icon"></i> 2342</div></div></div><div class="right aligned five wide column"><a href="#" target="_blank" class="ui teal basic label m-padded-tiny m-text-thin">认知升级</a></div></div></div><div class="five wide column"><a href="#" target="_blank"><img src="https://unsplash.it/800/450?image=1005" alt="" class="ui rounded image"></a></div></div></div><div class="ui padded vertical segment m-padded-tb-large"><div class="ui mobile reversed stackable grid"><div class="eleven wide column"><h3 class="ui header">你真的理解什么是财富自由吗?</h3><p class="m-text">正确做好任何一件事情的前提是清晰、正确的理解目标。而事实是,我们很多人很多时候根本没有对目标正确的定义,甚至根本从来就没有想过,只是大家都那么做而已…...</p><div class="ui grid"><div class="eleven wide column"><div class="ui mini horizontal link list"><div class="item"><img src="https://unsplash.it/100/100?image=1005" alt="" class="ui avatar image"><div class="content"><a href="#" class="header">像污秽一样</a></div></div><div class="item"><i class="calendar icon"></i> 2017-10-01</div><div class="item"><i class="eye icon"></i> 2342</div></div></div><div class="right aligned five wide column"><a href="#" target="_blank" class="ui teal basic label m-padded-tiny m-text-thin">认知升级</a></div></div></div><div class="five wide column"><a href="#" target="_blank"><img src="https://unsplash.it/800/450?image=1005" alt="" class="ui rounded image"></a></div></div></div><div class="ui padded vertical segment m-padded-tb-large"><div class="ui mobile reversed stackable grid"><div class="eleven wide column"><h3 class="ui header">你真的理解什么是财富自由吗?</h3><p class="m-text">正确做好任何一件事情的前提是清晰、正确的理解目标。而事实是,我们很多人很多时候根本没有对目标正确的定义,甚至根本从来就没有想过,只是大家都那么做而已…...</p><div class="ui grid"><div class="eleven wide column"><div class="ui mini horizontal link list"><div class="item"><img src="https://unsplash.it/100/100?image=1005" alt="" class="ui avatar image"><div class="content"><a href="#" class="header">像污秽一样</a></div></div><div class="item"><i class="calendar icon"></i> 2017-10-01</div><div class="item"><i class="eye icon"></i> 2342</div></div></div><div class="right aligned five wide column"><a href="#" target="_blank" class="ui teal basic label m-padded-tiny m-text-thin">认知升级</a></div></div></div><div class="five wide column"><a href="#" target="_blank"><img src="https://unsplash.it/800/450?image=1005" alt="" class="ui rounded image"></a></div></div></div><div class="ui padded vertical segment m-padded-tb-large"><div class="ui mobile reversed stackable grid"><div class="eleven wide column"><h3 class="ui header">你真的理解什么是财富自由吗?</h3><p class="m-text">正确做好任何一件事情的前提是清晰、正确的理解目标。而事实是,我们很多人很多时候根本没有对目标正确的定义,甚至根本从来就没有想过,只是大家都那么做而已…...</p><div class="ui grid"><div class="eleven wide column"><div class="ui mini horizontal link list"><div class="item"><img src="https://unsplash.it/100/100?image=1005" alt="" class="ui avatar image"><div class="content"><a href="#" class="header">像污秽一样</a></div></div><div class="item"><i class="calendar icon"></i> 2017-10-01</div><div class="item"><i class="eye icon"></i> 2342</div></div></div><div class="right aligned five wide column"><a href="#" target="_blank" class="ui teal basic label m-padded-tiny m-text-thin">认知升级</a></div></div></div><div class="five wide column"><a href="#" target="_blank"><img src="https://unsplash.it/800/450?image=1005" alt="" class="ui rounded image"></a></div></div></div><div class="ui padded vertical segment m-padded-tb-large"><div class="ui mobile reversed stackable grid"><div class="eleven wide column"><h3 class="ui header">你真的理解什么是财富自由吗?</h3><p class="m-text">正确做好任何一件事情的前提是清晰、正确的理解目标。而事实是,我们很多人很多时候根本没有对目标正确的定义,甚至根本从来就没有想过,只是大家都那么做而已…...</p><div class="ui grid"><div class="eleven wide column"><div class="ui mini horizontal link list"><div class="item"><img src="https://unsplash.it/100/100?image=1005" alt="" class="ui avatar image"><div class="content"><a href="#" class="header">像污秽一样</a></div></div><div class="item"><i class="calendar icon"></i> 2017-10-01</div><div class="item"><i class="eye icon"></i> 2342</div></div></div><div class="right aligned five wide column"><a href="#" target="_blank" class="ui teal basic label m-padded-tiny m-text-thin">认知升级</a></div></div></div><div class="five wide column"><a href="#" target="_blank"><img src="https://unsplash.it/800/450?image=1005" alt="" class="ui rounded image"></a></div></div></div><div class="ui padded vertical segment m-padded-tb-large"><div class="ui mobile reversed stackable grid"><div class="eleven wide column"><h3 class="ui header">你真的理解什么是财富自由吗?</h3><p class="m-text">正确做好任何一件事情的前提是清晰、正确的理解目标。而事实是,我们很多人很多时候根本没有对目标正确的定义,甚至根本从来就没有想过,只是大家都那么做而已…...</p><div class="ui grid"><div class="eleven wide column"><div class="ui mini horizontal link list"><div class="item"><img src="https://unsplash.it/100/100?image=1005" alt="" class="ui avatar image"><div class="content"><a href="#" class="header">像污秽一样</a></div></div><div class="item"><i class="calendar icon"></i> 2017-10-01</div><div class="item"><i class="eye icon"></i> 2342</div></div></div><div class="right aligned five wide column"><a href="#" target="_blank" class="ui teal basic label m-padded-tiny m-text-thin">认知升级</a></div></div></div><div class="five wide column"><a href="#" target="_blank"><img src="https://unsplash.it/800/450?image=1005"  alt="" class="ui rounded image"></a></div></div></div><!--*/--></div><!--footer--><div class="ui bottom attached segment" th:if="${page.pages}>1"><div class="ui middle aligned two column grid"><div class="column"><a href="#" th:href="@{/(page=${page.number}-1)}"  th:unless="${page.first}" class="ui mini teal basic button">上一页</a></div><div class="right aligned column"><a href="#" th:href="@{/(page=${page.number}+1)}"  th:unless="${page.last}" class="ui mini teal basic button">下一页</a></div></div></div></div><!--右边的top--><div class="five wide column"><!--分类--><div class="ui segments"><div class="ui secondary segment"><div class="ui two column grid"><div class="column"><i class="idea icon"></i>分类</div><div class="right aligned column"><a href="#" th:href="@{types/-1}" target="_blank">more <i class="angle double right icon"></i></a></div></div></div><div class="ui teal segment"><div class="ui fluid vertical menu" ><a href="#" th:href="@{/types/{id}(id=${type.id})}" target="_blank" class="item"  th:each="type : ${types}"><span th:text="${type.name}">学习日志</span><div class="ui teal basic left pointing label" th:text="${#arrays.length(type.blogs)}">13</div></a><!--/*--><a href="#" class="item">思考与感悟<div class="ui teal basic left pointing label">13</div></a><a href="#" class="item">学习日志<div class="ui teal basic left pointing label">13</div></a><a href="#" class="item">学习日志<div class="ui teal basic left pointing label">13</div></a><a href="#" class="item">学习日志<div class="ui teal basic left pointing label">13</div></a><a href="#" class="item">学习日志<div class="ui teal basic left pointing label">13</div></a><!--*/--></div></div></div><!--标签--><div class="ui segments m-margin-top-large"><div class="ui secondary segment"><div class="ui two column grid"><div class="column"><i class="tags icon"></i>标签</div><div class="right aligned column"><a href="#" th:href="@{tags/-1}" target="_blank">more <i class="angle double right icon"></i></a></div></div></div><div class="ui teal segment"><a href="#" th:href="@{/tags/{id}(id=${tag.id})}" target="_blank" class="ui teal basic left pointing label m-margin-tb-tiny" th:each="tag : ${tags}"><span th:text="${tag.name}">方法论</span> <div class="detail" th:text="${#arrays.length(tag.blogs)}">23</div></a><!--/*--><a href="#" target="_blank" class="ui teal basic left pointing label m-margin-tb-tiny">论 <div class="detail">23</div></a><a href="#" target="_blank" class="ui teal basic left pointing label m-margin-tb-tiny">论 <div class="detail">23</div></a><a href="#" target="_blank" class="ui teal basic left pointing label m-margin-tb-tiny">方法论 <div class="detail">23</div></a><a href="#" target="_blank" class="ui teal basic left pointing label m-margin-tb-tiny">方法论 <div class="detail">23</div></a><a href="#" target="_blank" class="ui teal basic left pointing label m-margin-tb-tiny">方法论 <div class="detail">23</div></a><a href="#" target="_blank" class="ui teal basic left pointing label m-margin-tb-tiny">方法论 <div class="detail">23</div></a><a href="#" target="_blank" class="ui teal basic left pointing label m-margin-tb-tiny">方法论 <div class="detail">23</div></a><a href="#" target="_blank" class="ui teal basic left pointing label m-margin-tb-tiny">方法论 <div class="detail">23</div></a><a href="#" target="_blank" class="ui teal basic left pointing label m-margin-tb-tiny">方法论 <div class="detail">23</div></a><!--*/--></div></div><!--最新推荐--><div class="ui segments m-margin-top-large"><div class="ui secondary segment "><i class="bookmark icon"></i>最新推荐</div><div class="ui segment" th:each="blog : ${recommendBlogs}"><a href="#" th:href="@{/blog/{id}(id=${blog.id})}" target="_blank" class="m-black m-text-thin" th:text="${blog.title}">用户故事(User Story)</a></div><!--/*--><div class="ui segment" ><a href="#" target="_blank" class="m-black m-text-thin">用户故事(User Story)</a></div><div class="ui segment"><a href="#" target="_blank" class="m-black m-text-thin">用户故事(User Story)</a></div><div class="ui segment"><a href="#" target="_blank" class="m-black m-text-thin">用户故事(User Story)</a></div><div class="ui segment"><a href="#" target="_blank" class="m-black m-text-thin">用户故事(User Story)</a></div><div class="ui segment"><a href="#" target="_blank" class="m-black m-text-thin">用户故事(User Story)</a></div><div class="ui segment"><a href="#" target="_blank" class="m-black m-text-thin">用户故事(User Story)</a></div><div class="ui segment"><a href="#" target="_blank" class="m-black m-text-thin">用户故事(User Story)</a></div><!--*/--></div><!--二维码--><h4 class="ui horizontal divider header m-margin-top-large">扫码关注我</h4><div class="ui centered card" style="width: 11em"><img src="../static/images/wechat.jpg" th:src="@{/images/wechat.jpg}" alt="" class="ui rounded image" ></div></div></div></div></div><br><br><!--底部footer--><footer th:replace="_fragments :: footer" class="ui inverted vertical segment m-padded-tb-massive"><div class="ui center aligned container"><div class="ui inverted divided stackable grid"><div class="three wide column"><div class="ui inverted link list"><div class="item"><img src="../static/images/wechat.jpg" th:src="@{/images/wechat.jpg}"  class="ui rounded image" alt="" style="width: 110px"></div></div></div><div class="three wide column"><h4 class="ui inverted header m-text-thin m-text-spaced " >最新博客</h4><div class="ui inverted link list"><a href="#" class="item m-text-thin">用户故事(User Story)</a><a href="#" class="item m-text-thin">用户故事(User Story)</a><a href="#" class="item m-text-thin">用户故事(User Story)</a></div></div><div class="three wide column"><h4 class="ui inverted header m-text-thin m-text-spaced ">联系我</h4><div class="ui inverted link list"><a href="#" class="item m-text-thin">Email:flowerfog07@outlook.com</a><a href="#" class="item m-text-thin">QQ:2252221508</a></div></div><div class="seven wide column"><h4 class="ui inverted header m-text-thin m-text-spaced ">Blog</h4><p class="m-text-thin m-text-spaced m-opacity-mini">这是我的个人博客、会分享关于编程、写作、思考相关的任何内容,希望可以给来到这儿的人有所帮助...</p></div></div><div class="ui inverted section divider"></div><p class="m-text-thin m-text-spaced m-opacity-tiny">Copyright © 2016 - 2017 flowerfog Designed by flowerfog</p></div></footer>
<!--/*/<th:block th:replace="_fragments :: script">/*/--><script src="https://cdn.jsdelivr.net/npm/jquery@3.2/dist/jquery.min.js"></script><script src="https://cdn.jsdelivr.net/semantic-ui/2.2.4/semantic.min.js"></script>
<!--/*/</th:block>/*/--><script>$('.menu.toggle').click(function () {$('.m-item').toggleClass('m-mobile-hide');});</script>
</body>
</html>
 最新博客推荐
@GetMapping("/footer/newblog")public String newblogs(Model model) {model.addAttribute("newblogs", blogService.listRecommendBlogTop(3));return "_fragments :: newblogList";}
略 

 7.2博客详情

Markdown 转换 HTML 

*  [commonmark-java  https://github.com/atlassian/commonmark-java](https://github.com/atlassian/commonmark-java)

*  pom.xml引用commonmark和扩展插件

依赖:

<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>

控制器:

@GetMapping("/blog/{id}")public String blog(@PathVariable Long id,Model model) throws NotFoundException {Blog blog = blogService.getAndConvert(id);model.addAttribute("blog",blog );return "blog";}

界面:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head th:replace="_fragments :: head(~{::title})"><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>博客详情</title><link rel="stylesheet" href="https://cdn.jsdelivr.net/semantic-ui/2.2.4/semantic.min.css"><link rel="stylesheet" href="../static/css/typo.css"><link rel="stylesheet" href="../static/css/animate.css"><link rel="stylesheet" href="../static/lib/prism/prism.css"><link rel="stylesheet" href="../static/lib/tocbot/tocbot.css"><link rel="stylesheet" href="../static/css/me.css">
</head>
<body><!--导航--><nav th:replace="_fragments :: menu(1)"  class="ui inverted attached segment m-padded-tb-mini m-shadow-small" ><div class="ui container"><div class="ui inverted secondary stackable menu"><h2 class="ui teal header item">Blog</h2><a href="#" class="active m-item item m-mobile-hide"><i class="mini home icon"></i>首页</a><a href="#" class="m-item item m-mobile-hide"><i class="mini idea icon"></i>分类</a><a href="#" class="m-item item m-mobile-hide"><i class="mini tags icon"></i>标签</a><a href="#" class="m-item item m-mobile-hide"><i class="mini clone icon"></i>归档</a><a href="#" class="m-item item m-mobile-hide"><i class="mini info icon"></i>关于我</a><div class="right m-item item m-mobile-hide"><div class="ui icon inverted transparent input m-margin-tb-tiny"><input type="text" placeholder="Search...."><i class="search link icon"></i></div></div></div></div><a href="#" class="ui menu toggle black icon button m-right-top m-mobile-show"><i class="sidebar icon"></i></a></nav><!--中间内容--><div id="waypoint" class="m-container-small m-padded-tb-big animated fadeIn"><div class="ui container"><div class="ui top attached segment"><div class="ui horizontal link list"><div class="item"><img src="https://unsplash.it/100/100?image=1005" th:src="@{${blog.user.avatar}}"  alt="" class="ui avatar image"><div class="content"><a href="#" class="header" th:text="${blog.user.nickname}">像污秽一样</a></div></div><div class="item"><i class="calendar icon"></i> <span th:text="${#dates.format(blog.updateTime,'yyyy-MM-dd')}">2017-10-01</span></div><div class="item"><i class="eye icon"></i> <span th:text="${blog.views}">2342</span></div></div></div><div class="ui attached segment"><!--图片区域--><img src="https://unsplash.it/800/450?image=1005" th:src="@{${blog.firstPicture}}" alt="" class="ui fluid rounded image"></div><div class="ui  attached padded segment"><!--内容--><div class="ui right aligned basic segment"><div class="ui orange basic label" th:text="${blog.flag}">原创</div></div><h2 class="ui center aligned header" th:text="${blog.title}">关于刻意练习的清单</h2><br><!--中间主要内容部分--><div id="content" class="typo  typo-selection js-toc-content m-padded-lr-responsive m-padded-tb-large" th:utext="${blog.content}"><h2 id="section1">一、关于 <i class="serif">Typo.css</i></h2><pre><code class="language-css">p { color: red }</code></pre><pre><code class="language-css">p { color: red }</code></pre><p><i class="serif">Typo.css</i> 的目的是,在一致化浏览器排版效果的同时,构建最适合中文阅读的网页排版。</p><h4 >现状和如何去做:</h4><p class="typo-first">排版是一个麻烦的问题 <sup><a href="#appendix1"># 附录一</a></sup>,需要精心设计,而这个设计却是常被视觉设计师所忽略的。前端工程师更常看到这样的问题,但不便变更。因为在多个 OS 中的不同浏览器渲染不同,改动需要多的时间做回归测试,所以改变变得更困难。而像我们一般使用的Yahoo、Eric Meyer 和 Alice base.css 中采用的 Reset 都没有很好地考虑中文排版。<i class="serif">Typo.css</i> 要做的就是解决中文排版的问题。</p><p><strong><i class="serif">Typo.css</i> 测试于如下平台:</strong></p><table class="ui table" summary="Typo.css 的测试平台列表"><thead><tr><th>OS/浏览器</th><th>Firefox</th><th>Chrome</th><th>Safari</th><th>Opera</th><th>IE9</th><th>IE8</th><th>IE7</th><th>IE6</th></tr></thead><tbody><tr><td>OS X</td><td>✔</td><td>✔</td><td>✔</td><td>✔</td><td>-</td><td>-</td><td>-</td><td>-</td></tr><tr><td>Win 7</td><td>✔</td><td>✔</td><td>✔</td><td>✔</td><td>✔</td><td>✔</td><td>✔</td><td>-</td></tr><tr><td>Win XP</td><td>✔</td><td>✔</td><td>✔</td><td>✔</td><td>-</td><td>✔</td><td>✔</td><td>✔</td></tr><tr><td>Ubuntu</td><td>✔</td><td>✔</td><td>-</td><td>✔</td><td>-</td><td>-</td><td>-</td><td>-</td></tr></tbody></table><h4>中文排版的重点和难点</h4><p>在中文排版中,HTML4 的很多标准在语义在都有照顾到。但从视觉效果上,却很难利用单独的 CSS 来实现,像<abbr title="在文字下多加一个点">着重号</abbr>(例:这里<em class="typo-em">强调一下</em>)。在 HTML4 中,专名号标签(<code>&lt;u&gt;</code>)已经被放弃,而HTML5 被<a href="http://html5doctor.com/u-element/">重新提起</a>。<i class="serif">Typo.css</i> 也根据实际情况提供相应的方案。我们重要要注意的两点是:</p><ol><li>语义:语义对应的用法和样式是否与中文排版一致</li><li>表现:在各浏览器中的字体、大小和缩放是否如排版预期</li></ol><p>对于这些,<i class="serif">Typo.css</i> 排版项目的中文偏重注意点,都添加在附录中,详见:</p><blockquote><b>附录一</b>:<a href="#appendix1"><i class="serif">Typo.css</i> 排版偏重点</a></blockquote><p>目前已有像百姓网等全面使用 <i class="serif">Typo.css</i> 的项目,测试平台的覆盖,特别是在<abbr title="手机、平板电脑等移动平台">移动端</abbr>上还没有覆盖完主流平台,希望有能力的同学能加入测试行列,或者加入到 <i class="serif">Typo.css</i>的开发。加入方法:<a href="https://github.com/sofish/Typo.css">参与 <i class="serif">Typo.css</i> 开发</a>。如有批评、建议和意见,也随时欢迎给在 Github 直接提 <ahref="https://github.com/sofish/Typo.css/issues">issues</a>,或给<abbr title="Sofish Lin, author of Typo.css"role="author">我</abbr>发<ahref="mailto:sofish@icloud.com">邮件</a>。</p><h2 id="section2">二、排版实例:</h2><p>提供2个排版实例,第一个中文实例来自于来自于<cite class="typo-unique">张燕婴</cite>的《论语》,由于古文排版涉及到的元素比较多,所以采用《论语》中《学而》的第一篇作为排版实例介绍;第2个来自到经典的Lorem Ipsum,并加入了一些代码和列表等比较具有代表性的排版元素。</p><h3 id="section2-1">例1:论语学而篇第一</h3><p><small><b>作者:</b><abbr title="名丘,字仲尼">孔子</abbr>(<time>前551年9月28日-前479年4月11日</time>)</small></p><h4>本篇引语</h4><p>《学而》是《论语》第一篇的篇名。《论语》中各篇一般都是以第一章的前二三个字作为该篇的篇名。《学而》一篇包括16章,内容涉及诸多方面。其中重点是「吾日三省吾身」;「节用而爱人,使民以时」;「礼之用,和为贵」以及仁、孝、信等道德范畴。 </p><h4>原文</h4><p>子曰:「学而时习之,不亦说乎?有朋自远方来,不亦乐乎?人不知,而不愠,不亦君子乎?」 </p><h4>译文</h4><p>孔子说:「学了又时常温习和练习,不是很愉快吗?有志同道合的人从远方来,不是很令人高兴的吗?人家不了解我,我也不怨恨、恼怒,不也是一个有德的君子吗?」 </p><h4>评析</h4><p>宋代著名学者<u class="typo-u">朱熹</u>对此章评价极高,说它是「入道之门,积德之基」。本章这三句话是人们非常熟悉的。历来的解释都是:学了以后,又时常温习和练习,不也高兴吗等等。三句话,一句一个意思,前后句子也没有什么连贯性。但也有人认为这样解释不符合原义,指出这里的「学」不是指学习,而是指学说或主张;「时」不能解为时常,而是时代或社会的意思,「习」不是温习,而是使用,引申为采用。而且,这三句话不是孤立的,而是前后相互连贯的。这三句的意思是:自己的学说,要是被社会采用了,那就太高兴了;退一步说,要是没有被社会所采用,可是很多朋友赞同<abbrtitle="张燕婴">我</abbr>的学说,纷纷到我这里来讨论问题,我也感到快乐;再退一步说,即使社会不采用,人们也不理解我,我也不怨恨,这样做,不也就是君子吗?(见《齐鲁学刊》1986年第6期文)这种解释可以自圆其说,而且也有一定的道理,供读者在理解本章内容时参考。</p><p>此外,在对「人不知,而不愠」一句的解释中,也有人认为,「人不知」的后面没有宾语,人家不知道什么呢?当时因为孔子有说话的特定环境,他不需要说出知道什么,别人就可以理解了,却给后人留下一个谜。有人说,这一句是接上一句说的,从远方来的朋友向我求教,我告诉他,他还不懂,我却不怨恨。这样,「人不知」就是「人家不知道我所讲述的」了。这样的解释似乎有些牵强。</p><p>总之,本章提出以学习为乐事,做到人不知而不愠,反映出孔子学而不厌、诲人不倦、注重修养、严格要求自己的主张。这些思想主张在《论语》书中多处可见,有助于对第一章内容的深入了解。</p><h3 id="section2-2">例2:英文排版</h3><p>Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry'sstandard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make atype specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remainingessentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsumpassages, and more recently with desktop publishing software like Aldus PageMaker including versions of LoremIpsum.</p><blockquote>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magnaaliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</blockquote><h4>The standard Lorem Ipsum passage, used since the 1500s</h4><p>"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magnaaliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sintoccaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."</p><h4>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC</h4><p>"Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam,eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsamvoluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui rationevoluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipiscivelit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enimad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodiconsequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur,vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?"</p><h4>List style in action</h4><ul><li>If you wish to succeed, you should use persistence as your good friend, experience as your reference, prudence asyour brother and hope as your sentry.<p>如果你希望成功,当以恒心为良友,以经验为参谋,以谨慎为兄弟,以希望为哨兵。</p></li><li>Sometimes one pays most for the things one gets for nothing.<p>有时候一个人为不花钱得到的东西付出的代价最高。</p></li><li>Only those who have the patience to do simple things perfectly ever acquire the skill to do difficult thingseasily.<p>只有有耐心圆满完成简单工作的人,才能够轻而易举的完成困难的事。</p></li></ul><h4>You may want to create a perfect <code>&lt;hr /&gt;</code> line, despite the fact that there will never have one</h4><hr/><p><abbr title="法国作家罗切福考尔德">La Racheforcauld</abbr> said:<mark>"Few things are impossible in themselves; and it is often for want of will, rather than of means, that man failsto succeed".</mark>You just need to follow the browser's behavior, and set a right <code>margin</code> to it。it will works nice as thedemo you're watching now. The following code is the best way to render typo in Chinese:</p><pre ><code class="language-css">
/* 标题应该更贴紧内容,并与其他块区分,margin 值要相应做优化 */
h1,h2,h3,h4,h5,h6 {line-height:1;font-family:Arial,sans-serif;margin:1.4em 0 0.8em;
}
h1{font-size:1.8em;}
h2{font-size:1.6em;}
h3{font-size:1.4em;}
h4{font-size:1.2em;}
h5,h6{font-size:1em;}/* 现代排版:保证块/段落之间的空白隔行 */
.typo p, .typo pre, .typo ul, .typo ol, .typo dl, .typo form, .typo hr {margin:1em 0 0.6em;
}
</code></pre><h3 id="section3">三、附录</h3><h5 id="appendix1">1、<i class="serif">Typo.css</i> 排版偏重点</h5><table class="ui table" summary="Typo.css 排版偏重点"><thead><tr><th>类型</th><th>语义</th><th>标签</th><th>注意点</th></tr></thead><tbody><tr><th rowspan="15">基础标签</th><td>标题</td><td><code>h1</code> ~ <code>h6</code></td><td>全局不强制大小,<code>.typo</code> 中标题与其对应的内容应紧贴,并且有相应的大小设置</td></tr><tr><td>上、下标</td><td><code>sup</code>/<code>sub</code></td><td>保持与 MicroSoft Office Word 等程序的日常排版一致</td></tr><tr><td>引用</td><td><code>blockquote</code></td><td>显示/嵌套样式</td></tr><tr><td>缩写</td><td><code>abbr</code></td><td>是否都有下划线,鼠标 <code>hover</code> 是否为帮助手势</td></tr><tr><td>分割线</td><td><code>hr</code></td><td>显示的 <code>padding</code> 和 <code>margin</code>正确</td></tr><tr><td>列表</td><td><code>ul</code>/<code>ol</code>/<code>dl</code></td><td>在全局没有 <code>list-style</code>,在 .<code>typo</code> 中对齐正确</td></tr><tr><td>定义列表</td><td><code>dl</code></td><td>全局 <code>padding</code> 和 <code>margin</code>为0, .<code>typo</code> 中对齐正确</td></tr><tr><td>选项</td><td><code>input[type=radio[, checkbox]]</code></td><td>与其他 <code>form</code> 元素排版时是否居中</td></tr><tr><td>斜体</td><td><code>i</code></td><td>只设置一种斜体,让 <code>em</code> 和 <code>cite</code> 显示为正体</td></tr><tr><td>强调</td><td><code>em</code></td><td>在全局显示正体,在 <code>.typo</code> 中显示与 <code>b</code> 和 <code>strong</code> 的样式一致,为粗体</td></tr><tr><td>加强</td><td><code>strong/b</code></td><td>显示为粗体</td></tr><tr><td>标记</td><td><code>mark</code></td><td>类似荧光笔</td></tr><tr><td>印刷</td><td><code>small</code></td><td>保持为正确字体的 80% 大小,颜色设置为浅灰色</td></tr><tr><td>表格</td><td><code>table</code></td><td>全局不显示线条,在 <code>table</code> 中显示表格外框,并且表头有浅灰背景</td></tr><tr><td>代码</td><td><code>pre</code>/<code>code</code></td><td>字体使用 <code>courier</code> 系字体,保持与 <code>serif</code> 有比较一致的显示效果</td></tr><tr><th rowspan="5">特殊符号</th><td>着重号</td><td><em class="typo-em">在文字下加点</em></td><td>在支持 <code>:after</code> 和 <code>:before</code> 的浏览器可以做渐进增强实现</td></tr><tr><td>专名号</td><td><u>林建锋</u></td><td>专名号,有下划线,使用 <code>u</code> 或都 <code>.typo-u</code> 类</td></tr><tr><td>破折号</td><td>——</td><td>保持一划,而非两划</td></tr><tr><td>人民币</td><td>&yen;</td><td>使用两平等线的符号,或者 HTML 实体符号 <code>&amp;yen;</code></td></tr><tr><td>删除符</td><td><del>已删除(deleted)</del></td><td>一致化各浏览器显示,中英混排正确</td></tr><tr><th rowspan="3">加强类</th><td>专名号</td><td><code>.typo-u</code></td><td>由于 <code>u</code> 被 HTML4 放弃,在向后兼容上推荐使用 <code>.typo-u</code></td></tr><tr><td>着重符</td><td><code>.typo-em</code></td><td>利用 <code>:after</code> 和 <code>:before</code> 实现着重符</td></tr><tr><td>清除浮动</td><td><code>.clearfix</code></td><td>与一般 CSS Reset 保持一对致 API</td></tr><tr><th rowspan="5">注意点</th><td colspan="3">(1)中英文混排行高/行距</td></tr><tr><td colspan="3">(2)上下标在 IE 中显示效果</td></tr><tr><td colspan="3">(3)块/段落分割空白是否符合设计原则</td></tr><tr><td colspan="3">(4)input 多余空间问题</td></tr><tr><td colspan="3">(5)默认字体色彩,目前采用 <code>#333</code> 在各种浏览显示比较好</td></tr></tbody></table><h5 id="appendix2">2、开源许可</h5></div><!--标签--><div class="m-padded-lr-responsive"><div class="ui basic teal left pointing label" th:each="tag : ${blog.tags}" th:text="${tag.name}">方法论</div></div><!--赞赏--><div th:if="${blog.appreciation}"><div class="ui center aligned basic segment"><button id="payButton" class="ui orange basic circular button">赞赏</button></div><div class="ui payQR flowing popup transition hidden"><div class="ui orange basic label"><div class="ui images" style="font-size: inherit !important;"><div class="image"><img src="../static/images/wechat.jpg" th:src="@{/images/wechat.jpg}" alt="" class="ui rounded bordered image" style="width: 120px"><div>支付宝</div></div><div class="image"><img src="../static/images/wechat.jpg" th:src="@{/images/wechat.jpg}" alt="" class="ui rounded bordered image" style="width: 120px"><div>微信</div></div></div></div></div></div></div><div class="ui attached positive message" th:if="${blog.shareStatement}"><!--博客信息--><div class="ui middle aligned grid"><div class="eleven wide column"><ui class="list"><li>作者:<span th:text="${blog.user.nickname}">像污秽一样</span><a href="#" th:href="@{/about}" target="_blank">(联系作者)</a></li><li>发表时间:<span th:text="${#dates.format(blog.updateTime,'yyyy-MM-dd HH:mm')}">2017-10-02 09:08</span></li><li>版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)</li><li>公众号转载:请在文末添加作者公众号二维码</li></ui></div><div class="five wide column"><img src="../static/images/wechat.jpg" th:src="@{/images/wechat.jpg}" alt="" class="ui right floated rounded bordered image" style="width: 110px"></div></div></div><div  class="ui bottom attached segment" th:if="${blog.commentabled}"><!--留言区域列表--><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">评论</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}">博主</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)">回复</a></div></div><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}">小红</span><div class="ui mini basic teal left pointing label m-padded-mini" th:if="${reply.adminComment}">博主</div>&nbsp;<span th:text="|@ ${reply.parentComment.nickname}|" class="m-teal">@ 小白</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)">回复</a></div></div></div></div></div><!--/*--><div class="comment"><a class="avatar"><img src="https://unsplash.it/100/100?image=1005"></a><div class="content"><a class="author">Elliot Fu</a><div class="metadata"><span class="date">Yesterday at 12:30AM</span></div><div class="text"><p>This has been very useful for my research. Thanks as well!</p></div><div class="actions"><a class="reply">回复</a></div></div><div class="comments"><div class="comment"><a class="avatar"><img src="https://unsplash.it/100/100?image=1005"></a><div class="content"><a class="author">Jenny Hess</a><div class="metadata"><span class="date">Just now</span></div><div class="text">Elliot you are always so right :)</div><div class="actions"><a class="reply">回复</a></div></div></div></div></div><div class="comment"><a class="avatar"><img src="https://unsplash.it/100/100?image=1005"></a><div class="content"><a class="author">Joe Henderson</a><div class="metadata"><span class="date">5 days ago</span></div><div class="text">Dude, this is awesome. Thanks so much</div><div class="actions"><a class="reply">回复</a></div></div></div><!--*/--></div></div></div><div id="comment-form" class="ui form"><input type="hidden" name="blog.id" th:value="${blog.id}"><input type="hidden" name="parentComment.id" value="-1"><div class="field"><textarea name="content" placeholder="请输入评论信息..."></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="姓名" 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="邮箱" 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>发布</button></div></div></div></div></div></div><div id="toolbar" class="m-padded m-fixed m-right-bottom" style="display: none"><div class="ui vertical icon buttons "><button type="button" class="ui toc teal button" >目录</button><a href="#comment-container" class="ui teal button" >留言</a><button class="ui wechat icon button"><i class="weixin icon"></i></button><div id="toTop-button" class="ui icon button" ><i class="chevron up icon"></i></div></div></div><div class="ui toc-container flowing popup transition hidden" style="width: 250px!important;"><ol class="js-toc"></ol></div><div id="qrcode" class="ui wechat-qr flowing popup transition hidden "style="width: 130px !important;"><!--<img src="./static/images/wechat.jpg" alt="" class="ui rounded image" style="width: 120px !important;">--></div><br><br><!--底部footer--><footer th:replace="_fragments :: footer" class="ui inverted vertical segment m-padded-tb-massive"><div class="ui center aligned container"><div class="ui inverted divided stackable grid"><div class="three wide column"><div class="ui inverted link list"><div class="item"><img src="../static/images/wechat.jpg" class="ui rounded image" alt="" style="width: 110px"></div></div></div><div class="three wide column"><h4 class="ui inverted header m-text-thin m-text-spaced " >最新博客</h4><div class="ui inverted link list"><a href="#" class="item m-text-thin">用户故事(User Story)</a><a href="#" class="item m-text-thin">用户故事(User Story)</a><a href="#" class="item m-text-thin">用户故事(User Story)</a></div></div><div class="three wide column"><h4 class="ui inverted header m-text-thin m-text-spaced ">联系我</h4><div class="ui inverted link list"><a href="#" class="item m-text-thin">Email:flowerfog07@163.com</a><a href="#" class="item m-text-thin">QQ:2252221508</a></div></div><div class="seven wide column"><h4 class="ui inverted header m-text-thin m-text-spaced ">Blog</h4><p class="m-text-thin m-text-spaced m-opacity-mini">这是我的个人博客、会分享关于编程、写作、思考相关的任何内容,希望可以给来到这儿的人有所帮助...</p></div></div><div class="ui inverted section divider"></div><p class="m-text-thin m-text-spaced m-opacity-tiny">Copyright © 2016 - 2017 flowerfog07 Designed by flowerfog07</p></div></footer><!--/*/<th:block th:replace="_fragments :: script">/*/-->
<script src="https://cdn.jsdelivr.net/npm/jquery@3.2/dist/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/semantic-ui/2.2.4/semantic.min.js"></script>
<script src="//cdn.jsdelivr.net/npm/jquery.scrollto@2.1.2/jquery.scrollTo.min.js"></script><script src="../static/lib/prism/prism.js"></script>
<script src="../static/lib/tocbot/tocbot.min.js"></script>
<script src="../static/lib/qrcode/qrcode.min.js"></script>
<script src="../static/lib/waypoints/jquery.waypoints.min.js"></script><!--/*/</th:block>/*/--><script th:inline="javascript">$('.menu.toggle').click(function () {$('.m-item').toggleClass('m-mobile-hide');});$('#payButton').popup({popup : $('.payQR.popup'),on : 'click',position: 'bottom center'});tocbot.init({// Where to render the table of contents.tocSelector: '.js-toc',// Where to grab the headings to build the table of contents.contentSelector: '.js-toc-content',// Which headings to grab inside of the contentSelector element.headingSelector: 'h1, h2, h3',});$('.toc.button').popup({popup : $('.toc-container.popup'),on : 'click',position: 'left center'});$('.wechat').popup({popup : $('.wechat-qr'),position: 'left center'});var serurl = /*[[#{blog.serurl}]]*/"127.0.0.1:8080";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});$('#toTop-button').click(function () {$(window).scrollTo(0,500);});var waypoint = new Waypoint({element: document.getElementById('waypoint'),handler: function(direction) {if (direction == 'down') {$('#toolbar').show(100);} else {$('#toolbar').hide(500);}console.log('Scrolled to waypoint!  ' + direction);}})//评论表单验证$('.ui.form').form({fields: {title: {identifier: 'content',rules: [{type: 'empty',prompt: '请输入评论内容'}]},content: {identifier: 'nickname',rules: [{type: 'empty',prompt: '请输入你的大名'}]},type: {identifier: 'email',rules: [{type: 'email',prompt: '请填写正确的邮箱地址'}]}}});$(function () {$("#comment-container").load(/*[[@{/comments/{id}(id=${blog.id})}]]*/"comments/6");});$('#commentpost-btn').click(function () {var boo = $('.ui.form').form('validate form');if (boo) {console.log('校验成功');postData();} else {console.log('校验失败');}});function postData() {$("#comment-container").load(/*[[@{/comments}]]*/"",{"parentComment.id" : $("[name='parentComment.id']").val(),"blog.id" : $("[name='blog.id']").val(),"nickname": $("[name='nickname']").val(),"email"   : $("[name='email']").val(),"content" : $("[name='content']").val()},function (responseTxt, statusTxt, xhr) {
//        $(window).scrollTo($('#comment-container'),500);clearContent();});}function clearContent() {$("[name='content']").val('');$("[name='parentComment.id']").val(-1);$("[name='content']").attr("placeholder", "请输入评论信息...");}function reply(obj) {var commentId = $(obj).data('commentid');var commentNickname = $(obj).data('commentnickname');$("[name='content']").attr("placeholder", "@"+commentNickname).focus();$("[name='parentComment.id']").val(commentId);$(window).scrollTo($('#comment-form'),500);}</script>
</body>
</html>

7.3评论功能

游客评论

*  评论信息提交与回复功能

*  评论信息列表展示功能

*  管理员回复评论功能

package com.flowerfog.blog.controller;import com.flowerfog.blog.pojo.Comment;
import com.flowerfog.blog.pojo.User;
import com.flowerfog.blog.service.BlogService;
import com.flowerfog.blog.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 jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;/*** Created by flowerfog on 2025/5/22.*/
@Controller
public class CommentController {@Autowiredprivate CommentService commentService;@Autowiredprivate BlogService blogService;@Value("${comment.avatar}")private String avatar;@GetMapping("/comments/{blogId}")public String comments(@PathVariable Long blogId, Model model) {model.addAttribute("comments", commentService.listCommentByBlogId(blogId));return "blog :: commentList";}@PostMapping("/comments")public String post(Comment comment, HttpSession session) {Long blogId = comment.getBlogId();comment.setBlog(blogService.getBlog(blogId));User user = (User) session.getAttribute("user");if (user != null) {comment.setAvatar(user.getAvatar());comment.setAdminComment(true);} else {comment.setAvatar(avatar);}commentService.saveComment(comment);return "redirect:/comments/" + blogId;}}

剩下的就省略了。

写在最后

分类页 、标签页、归档、以及关于就都差不多了,我是把前年的商城实训粘来让AI改了,但是说实话AI改的很丑,redis,eureka这些也都没加上,但是应付课设肯定没问题了,后面有时间的话就拿个模板来改改再优化一下。

 放点截图

 

相关文章:

  • Python中的enumerate函数:优雅地遍历序列索引与元素
  • 大模型强化学习中的 PPO、DPO、KTO、ORPO 全解析
  • 【Linux】(1)—进程概念-③Linux进程概念与PCB
  • 2025推客系统小程序开发:独立部署源码交付,高性价比裂变增长引擎
  • 什么是系统调用
  • iVX 如何用 VL 中间语言构建程范式闭环?
  • 【速通RAG实战:进阶】16、AI生成思维导图全技术解析
  • 视频监控管理平台EasyCVR安防监控小知识:视频监控AI智能分析的常见部署方式有哪些?
  • RISC-V PMA、PMP机制深入分析
  • 基于qt5和stk10开发的互联调试
  • leetcode235.二叉搜索树的最近公共祖先:迭代法利用有序性高效寻根
  • 责任链模式:构建灵活可扩展的请求处理体系(Java 实现详解)
  • 数据结构 - 树相关计算题
  • Java中float和double的区别与用法解析
  • 通义灵码2.5——基于MCP实现我的12306火车票智能查询小助手
  • Selenium 测试框架 - Kotlin
  • RFID综合项目实训 | 基于C#的一卡通管理系统
  • 开疆智能Profinet转Profibus网关连接EC-CM-P1 PROFIBUS DP从站通讯模块配置案例
  • 计算机操作系统(十四)互斥锁,信号量机制与整型信号量
  • DTO、VO、DO、BO、PO 的概念与核心区别
  • 如何更新网站快照/重要新闻
  • 怎样在各大网站发布信息/推广策略
  • 在360上做网站多少钱/广告推广方案怎么写
  • wordpress 搜索引擎收录/重庆整站seo
  • 免费做婚礼邀请函的网站/全网模板建站系统
  • 贵阳网站建设/58百度搜索引擎