(九)完成新增及编辑文章功能
说明
经过前面几节课的学习及实战,我们已经完善了文章编辑页面,这节课我们就可以完成新增文章的功能了
新增
前端部分
补充表单的
name
属性与文章的实体对应<form id="data-form" class="form-horizontal"> <div class="col-md-9"> <div class="form-group"> <label class="col-sm-1 control-label">标题</label> <div class="col-sm-11"> <input type="text" name="title" required class="form-control" placeholder="请输入标题..."> </div> </div> <div class="form-group"> <label class="col-sm-1 control-label">内容</label> <div class="col-sm-11"> <div id="lw-markdown-content"> <textarea name="content" style="display: none"></textarea> </div> </div> </div> <div class="form-group"> <label class="col-sm-1 control-label"></label> <a class="btn btn-info" href="javascript:void(0)">返回列表</a> <button type="submit" class="btn btn-success">保存文章</button> </div> </div> <div class="col-md-3" style="background-color:#eeeeee;padding: 20px;"> <div class="form-group" style="margin: 0;"> <label>缩略图</label> <img id="lw-upload-show" style="width: 100%;border: 1px solid #cccccc;" src="/static/admin/image/default.png" alt=""> <div style="text-align: right;margin-top: 10px;"> <button class="btn btn-warning" type="button" id="lw-upload-btn"><i class="fa fa-image"></i> 上传图片 </button> </div> <input type="hidden" name="cover" class="form-control"> <input type="file" accept="image/jpg,image/jpeg,image/png,image/gif,image/bmp" id="lw-upload-file" style="display: none" class="form-control"> </div> <div class="form-group" style="margin: 0;"> <label>分类</label> <div class="radio" th:each="category:${categories}"> <label> <input required name="cid" type="radio" th:value="${category.id}"> <th:block th:text="${category.name}"></th:block> </label> </div> </div> <div class="form-group" style="margin: 10px 0 0;position:relative;"> <label>标签</label> <ul id="lw-select-tags"></ul> <input type="text" id="lw-tag-input" class="form-control"> <ul id="lw-unselect-tags"></ul> </div> <div class="form-group" style="margin: 10px 0 0;"> <label>其它设置</label> <div class="has-error"> <div class="checkbox"> <label> <input type="checkbox" name="allowComment" checked value="1"> 允许评论 </label> </div> </div> <div class="has-error"> <div class="checkbox"> <label> <input type="checkbox" name="status" value="2"> 保存草稿 </label> </div> </div> <div class="has-error"> <div class="checkbox"> <label> <input name="type" type="checkbox" value="2"> 保存为页面 </label> </div> </div> </div> </div> </form>
标签搜索的遗留问题
selectTags.add = function (key) { if (key) { if (!selectTags[key]) { if (unSelectTags[key]) { selectTags[key] = unSelectTags[key] delete unSelectTags[key] } else { selectTags[key] = {name: key} } console.log(key); $('#lw-select-tags').append(`<li data-value="${key}">${key} <a href="javascript:void(0)">x</a></li>`) } $('#lw-tag-input').val("") $('#lw-unselect-tags').html('') } } $('#lw-tag-input').on('keydown', function (e) { if (e.keyCode === 13) { selectTags.add($(this).val()) } }) $('#lw-unselect-tags').on('click', 'li', function () { selectTags.add($(this).text()) })
- 拦截表单提交事件,构建我欲提交的数据
发送
ajax
到后端进行表单的提交$('#data-form').on('submit', function () { // a=1&b=2 表单 //a=1&b=2&category.id=1&tags[]=a&tags[]=2 // {a:1,b:2} json let data = $(this).serializeJson() data['category'] = {id: data['cid']} data['tags'] = selectTags.toList() console.log(data); $.ajax({ url: '/admin/article/', method: 'post', data: JSON.stringify(data), contentType: 'application/json', dataType: 'json', success: res => { if (res.code === 200) { layer.msg('保存成功', {icon: 1, time: 500}, function () { location.href = '/admin/article.html' }) } else { layer.msg(res.message, {icon: 2}) } } }) return false; })
后端部分
- 补充前端没有传过来的属性
- 将数据库中没有的标签进行新增操作
- 执行保存操作
@Transactional
public void save(Article article) {
article.setUpdated(new Date());
if (Objects.isNull(article.getType())) {
article.setType(Article.TYPE_ARTICLE);
}
if (Objects.isNull(article.getStatus())) {
article.setStatus(Article.STATUS_PUBLISH);
}
if (Objects.isNull(article.getAllowComment())) {
article.setAllowComment(Article.COMMENT_DISABLE);
}
if (Objects.isNull(article.getId())) {
article.setCreated(new Date());
article.setViews(0);
}
// 将数据库中不存在的标签先执行插入操作
article.setTags(article.getTags().stream().peek(x -> {
if (Objects.isNull(x.getId())) {
x.setId(tagMapper.save(x).getId());
}
}).collect(Collectors.toList()));
mapper.save(article);
}
编辑
修改列表页面的为点击标题跳转到文章的编辑页面
columns: [ { title: '序号', width: 50, align: 'center', formatter: function (value, row, index) { return index + 1 } }, { title: '标题', field: 'title', formatter: function (value, row) { return `<a href="/admin/write.html?id=${row.id}">${value}</a>` } }, { title: '状态', field: 'status' }, { title: '分类', field: 'category', formatter:function (value) { return value.name } }, { title: '浏览量', field: 'views' }, { title: '创建时间', field: 'created' }, { field: 'id', title: '操作', width: 100, formatter: function (value) { return `<button type="button" data-id="${value}" class="btn btn-danger btn-sm lw-del-btn"><i class="fa fa-trash"></i> 删除</button>` } }, ]
修改
wirte
路由,当参数id不为空时查询文章详情private final ArticleService articleService; public AdminController(CategoryService categoryService, ArticleService articleService) { this.categoryService = categoryService; this.articleService = articleService; } @GetMapping("/write.html") public String write(@RequestParam(required = false) Integer id, Model model) { List<Category> categories = categoryService.list(); Article article = Objects.isNull(id) ? Article.builder().allowComment(1).build() : articleService.detail(id); model.addAttribute("categories", categories); model.addAttribute("article", article); return "admin/write"; }
为write页面设置初始值
<form class="form-inline" style="float:right;"> <div class="form-group"> <label>分类</label> <select class="form-control" style="width: 100px;"> <option value="">全部</option> <option th:each="category:${categories}" th:value="${category.id}" th:text="${category.name}"></option> </select> </div> <div class="form-group"> <label>状态</label> <select class="form-control" style="width: 100px;"> <option value="">全部</option> <option value="1">发布</option> <option value="2">草稿</option> </select> </div> <div class="form-group"> <label>类型</label> <select class="form-control" style="width: 100px;"> <option value="">全部</option> <option value="1">文章</option> <option value="2">页面</option> </select> </div> <div class="form-group"> <label>关键字</label> <input type="text" class="form-control" placeholder="请输入关键字..."> </div> <button type="submit" class="btn btn-primary"><i class="fa fa-search"></i> 搜索</button> </form>
$.ajax({ url: '/admin/tag/', dataType: 'json', success: res => { res.data.forEach(x => unSelectTags[x.name] = x) $('#lw-select-tags li').each((index, ele) => { let key = $(ele).data('value') console.log(key); selectTags[key] = unSelectTags[key] delete unSelectTags[key] }) console.log(unSelectTags); } })
- 修改service层的save方法,当id不为空时执行非空拷贝操作且更新文章的更新时间
public void save(Article article) {
article.setUpdated(new Date());
if (Objects.isNull(article.getType())) {
article.setType(Article.TYPE_ARTICLE);
}
if (Objects.isNull(article.getStatus())) {
article.setStatus(Article.STATUS_PUBLISH);
}
if (Objects.isNull(article.getAllowComment())) {
article.setAllowComment(Article.COMMENT_DISABLE);
}
// 将数据库中不存在的标签先执行插入操作
article.setTags(article.getTags().stream().peek(x -> {
if (Objects.isNull(x.getId())) {
x.setId(tagMapper.save(x).getId());
}
}).collect(Collectors.toList()));
if (Objects.isNull(article.getId())) {
article.setCreated(new Date());
article.setViews(0);
mapper.save(article);
} else {
Article one = mapper.getOne(article.getId());
UpdateUtil.copyNullProperties(article, one);
mapper.save(one);
}
}
工具类
package cn.kevinlu98.utils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import java.beans.PropertyDescriptor;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
/**
* 更新工具类(忽略为null的字段)
*/
public class UpdateUtil {
/**
* 所有为空值的属性都不copy
* @param source
* @param target
*/
public static void copyNullProperties(Object source, Object target) {
BeanUtils.copyProperties(source, target, getNullField(source));
}
/**
* 获取属性中为空的字段
*
* @param target
* @return
*/
private static String[] getNullField(Object target) {
BeanWrapper beanWrapper = new BeanWrapperImpl(target);
PropertyDescriptor[] propertyDescriptors = beanWrapper.getPropertyDescriptors();
Set<String> notNullFieldSet = new HashSet<>();
if (propertyDescriptors.length > 0) {
for (PropertyDescriptor p : propertyDescriptors) {
String name = p.getName();
Object value = beanWrapper.getPropertyValue(name);
if (Objects.isNull(value)) {
notNullFieldSet.add(name);
}
}
}
String[] notNullField = new String[notNullFieldSet.size()];
return notNullFieldSet.toArray(notNullField);
}
}
看看
多谢大佬分享
强强强
感谢作者!
感谢!