基于Spring Boot+Vue的博客系统 20——留言功能的实现

需求

博客给浏览者提供留言功能,可以是指出博主文章的错误,也可以是关于博客设计上的不足。未登录的用户可以进行匿名留言,匿名留言展示默认头像和默认昵称。

实现

后端数据库设计

与数据库中留言表对应实体类设计如下:

package com.qianyucc.blog.model.entity;

import lombok.*;
import javax.persistence.*;

/**
 * @author lijing
 * @date 2019-10-17 16:41
 * @description 留言实体类
 */
@Data
@Entity
@Table(name = "message")
public class MessageDO {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private Long creator;
    private String content;
    @Column(name = "gmt_update")
    private Long gmtCreate;
}

数据库访问层设计

package com.qianyucc.blog.repository;

import com.qianyucc.blog.model.entity.*;
import org.springframework.data.jpa.repository.*;

/**
 * @author lijing
 * @date 2019-10-17 16:45
 * @description 留言数据库访问层
 */
public interface MessageRepository  extends JpaRepository<MessageDO, Long>, JpaSpecificationExecutor<MessageDO>{
}

业务层主要实现留言插入和查询功能:

package com.qianyucc.blog.service;

import com.qianyucc.blog.model.dto.*;
import com.qianyucc.blog.model.entity.*;
import com.qianyucc.blog.model.vo.*;
import com.qianyucc.blog.repository.*;
import com.qianyucc.blog.utils.*;
import org.springframework.beans.factory.annotation.*;
import org.springframework.stereotype.*;

import java.time.*;
import java.util.*;
import java.util.stream.*;

/**
 * @author lijing
 * @date 2019-10-17 16:47
 * @description 与留言相关的业务
 */
@Service
public class MessageService {
    @Autowired
    private MessageRepository messageRepository;
    @Autowired
    private UserRepository userRepository;

    /**
     * 插入一条留言
     *
     * @param messageDTO
     */
    public void insMessage(MessageDTO messageDTO) {
        MessageDO messageDO = new MessageDO();
        messageDO.setCreator(messageDTO.getCreatorId());
        messageDO.setContent(messageDTO.getContent());
        messageDO.setGmtCreate(Instant.now().toEpochMilli());
        messageRepository.save(messageDO);
    }

    /**
     * 查询所有留言信息
     *
     * @return
     */
    public List<MessageVO> findAllMessages() {
        List<MessageDO> messageDOS = messageRepository.findAll();
        List<MessageVO> messageVOS = messageDOS.stream()
                .sorted(Comparator.comparing(MessageDO::getGmtCreate).reversed())
                .map(messageDO -> {
                    MessageVO messageVO = new MessageVO();
                    messageVO.setCreatorId(messageDO.getCreator());
                    Optional<UserDO> byId = userRepository.findById(messageDO.getCreator());
                    byId.ifPresent(m -> {
                        messageVO.setCreatorName(m.getName());
                        messageVO.setAvatarUrl(m.getAvatarUrl());
                    });
                    messageVO.setContent(messageDO.getContent());
                    messageVO.setGmtCreate(BlogUtil.formatDate(messageDO.getGmtCreate(), "yyyy年MM月dd日 HH:mm"));
                    return messageVO;
                })
                .collect(Collectors.toList());
        return messageVOS;
    }
}

此处用到MessageVO来封装发送给前端的信息

package com.qianyucc.blog.model.vo;

import lombok.*;

/**
 * @author lijing
 * @date 2019-10-17 16:42
 * @description 封装向页面返回的留言信息
 */
@Data
public class MessageVO {
    private Long creatorId;
    private String creatorName;
    private String avatarUrl;
    private String content;
    private String gmtCreate;
}

设计Controller

package com.qianyucc.blog.controller.comm;

import com.qianyucc.blog.model.dto.*;
import com.qianyucc.blog.model.vo.*;
import com.qianyucc.blog.service.*;
import org.springframework.beans.factory.annotation.*;
import org.springframework.web.bind.annotation.*;

import java.util.*;

/**
 * @author lijing
 * @date 2019-10-17 16:46
 * @description 留言信息api
 */
@RestController
@RequestMapping("/api/comm/message")
public class MessageController {
    @Autowired
    private MessageService messageService;

    @GetMapping("/getMessages")
    public List<MessageVO> getMessages() {
        List<MessageVO> messages = messageService.findAllMessages();
        return messages;
    }

    @PostMapping("/leaveAMessage")
    public RespDataVO leaveAMessage(@RequestBody MessageDTO messageDTO) {
        messageService.insMessage(messageDTO);
        return RespDataVO.ok("留言成功!");
    }
}

其中MessageDTO的设计如下:

package com.qianyucc.blog.model.dto;

import lombok.*;

/**
 * @author lijing
 * @date 2019-10-17 16:52
 * @description 前端传递的留言信息
 */
@Data
public class MessageDTO {
    private Long creatorId;
    private String content;
}

前端实现

/src/request/api/url.js中添加对应URL

// message
const getMessagesUrl = baseUrl + 'api/comm/message/getMessages'
const leaveAMessageUrl = baseUrl + 'api/comm/message/leaveAMessage'

新建/src/request/api/message.js文件,用来封装与留言相关的api

// 导入axios实例
import axios from "@/request/http"
// 导入所有url
import url from '@/request/api/url'

export default {
  getMessages(callback) {
    axios
      .get(url.getMessagesUrl)
      .then(callback)
      .catch(err => {
        console.log("getMessages Error");
      })
  },
  leaveAMessage(message, callback) {
    axios
      .post(url.leaveAMessageUrl, message)
      .then(callback)
      .catch(err => {
        console.log("leaveAMessage Error");
      })
  }
}

不要忘了在/src/request/api/index.js中导入message
导入message
新建/src/components/page/leaveMessage.vue组件,展示留言,并提供留言功能:

<template>
  <b-container class="main">
    <h5>说点什么吧......</h5>
    <hr />

    <b-media>
      <template v-slot:aside>
        <b-img
          rounded="circle"
          width="60"
          height="60"
          :src="isLogin == true ? userInfo.avatarUrl : '/static/images/no-name.png'"
        ></b-img>
      </template>
      <h6 thumbnail v-text="isLogin == true ? userInfo.name : '匿名用户'"></h6>
      <b-textarea rows="5" placeholder="请输入留言内容......" v-model="message"></b-textarea>
      <b-button class="pull-right" variant="success" @click="leaveAMessage()">提交</b-button>
    </b-media>
    <hr />
    <marquee direction="down" behaviour="scroll" height="300px">
      <b-media v-for="(m,index) in messages" :key="index" class="message">
        <template v-slot:aside>
          <b-img
            rounded="circle"
            width="60"
            height="60"
            :src="m.creatorId == 0 ? '/static/images/no-name.png' : m.avatarUrl"
          ></b-img>
        </template>
        <h6 thumbnail v-text="m.creatorId == 0 ? '匿名用户' : m.creatorName"></h6>
        <p>{{m.content}}</p>
        <small>{{m.gmtCreate}}</small>
      </b-media>
    </marquee>
  </b-container>
</template>

<script>
import { mapState } from "vuex";
export default {
  name: "leaveMessage",
  data() {
    return {
      messages: [],
      message: ""
    };
  },
  computed: {
    ...mapState({
      isLogin: state => state.app.isLogin,
      userInfo: state => state.user.userInfo
    })
  },
  methods: {
    leaveAMessage() {
      if (this.message.trim() != "") {
        let messageInfo = {
          creatorId: this.isLogin ? this.userInfo.id : 0,
          content: this.message
        };
        this.$api.message.leaveAMessage(messageInfo);
        this.message = "";
        this.getMessages();
      }
    },
    getMessages() {
      this.$api.message.getMessages(resp => {
        this.messages = resp.data;
      });
    }
  },
  created() {
    this.getMessages();
  }
};
</script>

<style scoped>
.main {
  margin-top: 10px;
  padding: 20px;
  background-color: #fff;
  min-height: 100%;
}
textarea {
  margin-bottom: 10px;
}
h6 {
  font-weight: bold;
}
.pull-right {
  float: right;
}
.message {
  border: solid rgb(239, 239, 239) 1px;
  border-radius: 10px;
  padding: 10px;
  margin-bottom: 10px;
}
</style>

上面代码用到了<marquee></marquee>标签,可实现滚动效果

扫描二维码关注公众号,回复: 8491568 查看本文章

在路由中添加leaveMessage

{
  path: "/leaveMessage",
  name: "leaveMessage",
  component: leaveMessage
},

修改导航栏,点击“留言”跳转到leaveMessage组件

<b-nav-item to="/leaveMessage">留言</b-nav-item>

页面效果

留言功能效果展示

发布了126 篇原创文章 · 获赞 12 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/li3455277925/article/details/102612897
今日推荐