Mr丶冷文

文章 分类 评论
125 10 8032

站点介绍

冷文学习者(KEVINLU98.COM),记录一个北漂小码农的日常业余生活
友链申请地址(直接评论即可): 传送门

(九)完成新增及编辑文章功能

MR丶冷文 2022-10-09 768 0条评论 个人博客项目视频教程 javaspringboot个人博客博客系统

首页 / 正文
Freewind主题v1.5版本已发布,下载请移步Freewind 1.5,同时还有主题伴生插件Freewind Markdown,下载请移步 Freewind Markdown,有问题请在留言板,交换友链请直接在友链留言,我创建了一个主题交流群,有兴趣可以加下: 点此加入
报毒我说明一下,是因为我把主题的版权信息做了加密,其中用了eval,杀毒软件认为eval函数是一个危险的操作,这点介意的话请勿下载,我也没有强迫任何人去下载,也没有向大家收取一分钱的主题费用,所以也犯不着因为这些事情来喷我,喜欢就用,不喜欢就不用,就这么简单

发布于2022-10-28

(九)完成新增及编辑文章功能

说明

经过前面几节课的学习及实战,我们已经完善了文章编辑页面,这节课我们就可以完成新增文章的功能了

新增

前端部分

  • 补充表单的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);
  }
}

评论(0)

热门文章

最新评论

  • 阳光

    学习学习

  • ThatDay

    谢谢分享

  • 学会成熟

    看看

  • gtbrfs

    学习

  • gtbrfs

    学习

日历

2024年04月

 123456
78910111213
14151617181920
21222324252627
282930    

文章目录

站点公告
Freewind主题v1.5版本已发布,下载请移步Freewind 1.5,同时还有主题伴生插件Freewind Markdown,下载请移步 Freewind Markdown,有问题请在留言板,交换友链请直接在友链留言,我创建了一个主题交流群,有兴趣可以加下: 点此加入
报毒我说明一下,是因为我把主题的版权信息做了加密,其中用了eval,杀毒软件认为eval函数是一个危险的操作,这点介意的话请勿下载,我也没有强迫任何人去下载,也没有向大家收取一分钱的主题费用,所以也犯不着因为这些事情来喷我,喜欢就用,不喜欢就不用,就这么简单
点击小铃铛关闭