11.15 实现写文章模块
我们在列表页上面添加一个“写文章”的入口:
<a href="addArticleView" target="_blank" class="btn btn-primary pull-right add-article">写文章</a>
其中,btn btn-primary pull-right 这三个css样式类是Flat UI组件的。add-article是我们自定义的样式类:
.add-article {
margin: 20px;
}
下面我们来写新建文章的页面。我们写文章的跳转页面路径是 <a href="addArticleView">
, 我们先来新建一个写文章页面addArticleView.ftl:
<!DOCTYPE html>
<html>
<#include "head.ftl">
<body>
<div class="container">
<h2>写文章</h2>
<form id="addArticleForm" class="form-horizontal">
<div class="form-group">
<input type="text" name="title" class="form-control" placeholder="文章标题">
</div>
<div class="form-group">
<textarea id="articleContentEditor" type="text" name="content" class="form-control" rows="20"
placeholder=""></textarea>
</div>
<div class="form-group save-article">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-primary" id="addArticleBtn">保存并发表</button>
</div>
</div>
</form>
</div>
</body>
</html>
然后,再添加控制器请求转发。这里我们使用集成WebMvcConfigurerAdapter类,重写实现addViewControllers方法的方式来添加一个不带数据传输的,单纯的请求转发的跳转View的RequestMapping Controller:
@Configuration
class WebMvcConfig : WebMvcConfigurerAdapter() {
// 注册简单请求转发跳转View的RequestMapping Controller
override fun addViewControllers(registry: ViewControllerRegistry?) {
//写文章的RequestMapping
registry?.addViewController("addArticleView")?.setViewName("addArticleView")
}
}
这样前端浏览器来的请求addArticle会直接映射转发到视图addArticle.ftl文件渲染解析。
重启应用,进入到我们的写文章的页面,如下图:
11.15.1 加上导航栏
为了方便页面之间的跳转,我们给我们的博客站点加上导航栏,我们新建一个navbar.ftl文件,内容如下:
<nav class="navbar navbar-default" role="navigation">
<div class="container-fluid">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse"
data-target="#example-navbar-collapse">
<span class="sr-only">切换导航</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">我的博客</a>
</div>
<div class="collapse navbar-collapse" id="example-navbar-collapse">
<ul class="nav navbar-nav">
<li class=""><a href="listAllArticleView">文章列表</a></li>
<li class="active"><a href="addArticleView">写文章</a></li>
<li><a href="#">关于</a></li>
<li class="dropdown">
<a href="http://www.jianshu.com/nb/12976878" class="dropdown-toggle" data-toggle="dropdown">
Kotlin <b class="caret"></b>
</a>
<ul class="dropdown-menu">
<li><a href="http://www.jianshu.com/nb/12976878" target="_blank">Kotlin极简教程</a></li>
<li class="divider"></li>
<li><a href="#">Java</a></li>
<li><a href="#">Scala</a></li>
<li><a href="#">Groovy</a></li>
<li class="divider"></li>
<li><a href="http://www.jianshu.com/nb/12066555" target="_blank">SpringBoot极简教程</a></li>
</ul>
</li>
</ul>
</div>
</div>
</nav>
11.15.2 抽取公共模板文件
考虑到head.ftl、navbar.ftl都是公共的文件,我们把他们单独放到一个common目录下。
然后,我们分别在addArticleView.ftl、listAllArticleView.ftl引用如下:
<!DOCTYPE html>
<html>
<#include "common/head.ftl">
<body>
<#include "common/navbar.ftl">
加入了导航栏之后,我们的页面现在更加美观了:
11.15.3 写文章的控制器层接口
控制器层保存接口:
@PostMapping("saveArticle")
@ResponseBody
fun saveArticle(article: Article): Article? {
article.gmtCreated = Date()
article.gmtModified = Date()
article.version = 0
return articleRepository?.save(article)
}
另外,为了支持较多内容的文章,我们把文章内容字段设置成LONGTEXT:
ALTER TABLE `blog`.`article`
CHANGE COLUMN `content` `content` LONGTEXT NULL DEFAULT NULL ;
11.15.4 前端 ajax 请求
我们在blog.js中加上ajax POST请求后端接口的逻辑:
$(function () {
$('#addArticleBtn').on('click', function () {
saveArticle()
})
function saveArticle() {
$.ajax({
url: "saveArticle",
data: $('#addArticleForm').serialize(),
type: "POST",
async: false,
success: function (resp) {
if (resp) {
saveArticleSuccess(resp)
} else {
saveArticleFail()
}
},
error: function () {
saveArticleFail()
}
})
}
function saveArticleSuccess(resp) {
alert('保存成功: ' + JSON.stringify(resp))
window.open('detailArticleView?id=' + resp.id)
}
function saveArticleFail() {
alert("保存失败!")
}
})
11.15.5 文章详情页
保存成功后,我们默认跳转该文章详情页。
后端控制器代码:
@GetMapping("detailArticleView")
fun detailArticleView(id: Long, model: Model): ModelAndView {
model.addAttribute("article", articleRepository?.findById(id)?.get())
return ModelAndView("detailArticleView")
}
注意,这里的articleRepository?.findById(id) 方法返回的是Optional
前端视图detailArticleView.ftl代码:
<!DOCTYPE html>
<html>
<#include "common/head.ftl">
<body>
<#include "common/navbar.ftl">
<div class="container">
<h3>${article.title}</h3>
<h6>${article.author}</h6>
<h6>${article.gmtModified}</h6>
<div>${article.content}</div>
</div>
</body>
</html>
我们在文章列表页中,给每篇文章标题加上跳转文章详情的超链接:
<td><a target="_blank" href="detailArticleView?id=${article.id}">${article.title}</a></td>
现在我们的文章列表页面如下:
点击一篇文章标题,即可进入详情页: