SpringBoot开源项目个人博客——(12)留言/其余页面显示

一、留言页面

留言和评论的实现几乎一模一样,还不需要传blogid,设计思路也一样,这里就直接给出代码。(或者直接参照评论代码,直接复制来改)

1. 持久层接口

dao包下创建MessageDao接口,添加如下接口:(不需要传博客id)

@Mapper
@Repository
public interface MessageDao {

    //新增一个留言
    int savaMessage(Message message);

    //删除一个留言
    void deleteMessage(Long id);

    /*查询父级留言 查询一级回复 查询二级回复*/

    //查询父级留言 : 它的评论类的父留言的-1
    List<Message> findMessageParentIdNull(Long messageParentId);

    //查询一级回复 : 根据父留言id
    List<Message> findMessageParentNotNull(Long parentId);

    //查询二级回复 : 根据子回复 id
    List<Message> findMessageReplyId(Long childId);

    //单独查询一条回复,查出父评论,用于发送回复邮件
    Message findByParentId(Long id);
}

2.mapper

mapper目录下创建MessageDao.xml文件,添加如下

<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.hxj.dao.MessageDao">

    <!--新增一个留言-->
    <insert id="savaMessage" parameterType="Message">
        insert into t_message (nickname, email, content, avatar, create_time, parent_message_id, admin_message)
        values (#{nickname},#{email},#{content},#{avatar},#{createTime},#{parentMessageId},#{adminMessage});
    </insert>


    <!--删除一个留言-->
    <delete id="deleteMessage">
        delete
        from t_message
        where id=#{id};
    </delete>

    <!--查询父级留言 : 它的评论类的父留言的-1-->
    <select id="findMessageParentIdNull" resultType="Message">
        select *
        from t_message
        where parent_message_id = #{messageParentId}
        order by create_time desc;
    </select>

    <!--查询一级回复 : 根据父留言id-->
    <select id="findMessageParentNotNull" resultType="Message">
        select *
        from t_message
        where parent_message_id = #{parentId}
        order by create_time desc;
    </select>

    <!--查询二级回复 : 根据子回复 id-->
    <select id="findMessageReplyId" resultType="Message">
        select *
        from t_message
        where parent_message_id = #{childId}
        order by create_time desc;
    </select>

    <select id="findByParentId" resultType="Message">
        select *
        from t_message where  id = #{id};
    </select>

</mapper>

3. 业务层

service包下创建MessageService接口

public interface MessageService {

    //新增一个留言
    int savaMessage(Message message);

    //删除一个留言 Message message
    void deleteMessage(Long id);

    /*查询留言信息*/
    List<Message> listMessage();

    Message findByParentId(Long id);//为了发邮件
}

Impl包下创建接口实现类:MessageServiceImpl接口实现类

@Service
public class MessageServiceImpl implements MessageService {

    @Autowired
    private MessageDao messageDao;

    //存放迭代子评论的集合
    private List<Message> tempReplys = new ArrayList<>();

    @Override
    public int savaMessage(Message message) {
        message.setCreateTime(new Date());
        return messageDao.savaMessage(message);
    }

    @Override
    public void deleteMessage(Long id) {
        messageDao.deleteMessage(id);
    }

    @Override
    public List<Message> listMessage() {
        //查出父节点, pid =-1
        List<Message> messages = messageDao.findMessageParentIdNull((long) -1);

        //为每个父评论 找到 它的子代评论
        for (Message message : messages) {
            Long id = message.getId(); //作为 子代的  pid
            String Nickname = message.getNickname();

            List<Message> childMessages = messageDao.findMessageParentNotNull(id);
            //查出这个父评论的  所有子评论
            combineChildren(childMessages, Nickname); //查询完后,所有子代 都添加到 tempReplys中

            message.setReplyMessages(tempReplys);
            //System.out.println(tempReplys);
            tempReplys = new ArrayList<>();//给下一个用,不可以单纯清空内容
        }
        return messages;
    }

    private void combineChildren(List<Message> childMessages,String Nickname){

        //判读是否有 一级子评论
        if(childMessages.size() > 0){

            //循环找出 子评论
            for (Message childMessage : childMessages) {
                String parentNickname1 = childMessage.getNickname(); //作为 二级评论 的 父name
                Long childId = childMessage.getId();

                childMessage.setParentNickname(Nickname); //在这里才设置 回复的 parentNickname
                tempReplys.add(childMessage); //存入 子代评论中

                //循环 查出所有子二级评论
                recursively(childId,parentNickname1);
            }
        }

    }

    private void recursively(Long childId,String parentNickname){
        //根据一级评论 id  找到所有二级评论
        List<Message> replyMessages = messageDao.findMessageReplyId(childId);

        if(replyMessages.size()>0){
            for (Message replyMessage : replyMessages) {
                String parentNickname2 = replyMessage.getNickname();
                Long replyId = replyMessage.getId();

                replyMessage.setParentNickname(parentNickname);

                tempReplys.add(replyMessage);
                //评论可能还有 子代评论,接着找(直到空为止)
                recursively(replyId,parentNickname2);
            }
        }
    }


    //为了发邮件
    @Override
    public Message findByParentId(Long id) {
        return messageDao.findByParentId(id);
    }
}

4. 控制器

为了实现局部刷新,前端改动:

在这里插入图片描述

删除操作也改成局部刷新

<a class="reply" data-messageid="1" data-messagenickname="Matt"
   th:attr="data-messageid=${message.id},data-messagenickname=${message.nickname}" onclick="reply(this)">回复</a>
<a class="delete"  href="#"
   th:attr="data-messageid=${message.id}"  onclick="shanchu(this)"
   th:if="${session.user}">删除</a>

...
...
...
<a class="reply" data-messageid="1" data-messagenickname="Matt"
   th:attr="data-messageid=${reply.id},data-messagenickname=${reply.nickname}"
   onclick="reply(this)">回复</a>
<a class="delete" href="#"
   th:attr="data-messageid=${reply.id}"
   onclick="shanchu(this)"
   th:if="${session.user}">删除</a>

JS部分:

// 校验信息
$('#messagepost-btn').click(function () {
    var boo = $('.ui.form').form('validate form');
    if (boo) {
        console.log('校验成功');
        postData();
    } else {
        console.log('校验失败');
    }
});

//发送请求给后端
function postData() {
    $('#message-container').load(/*[[@{/message}]]*/"/message", {
        "parentMessage.id": $("[name='parentMessage.id']").val(),
        "nickname": $("[name='nickname']").val(),
        "email": $("[name='email']").val(),
        "content": $("[name='content']").val()
    }, function (responseTxt, statusTxt, xhr) {
        clearContent();
    });
}

// 清除表单
function clearContent() {
    $("[name='nickname']").val('');
    $("[name='email']").val('');

    var user = /*[[${session.user}]]*/ null;
    /*因为我们在 admin的logincontroller 把user 传进 session*/
    console.log(user);
    if( user ){
        $("[name='nickname']").val(user.nickname);
        $("[name='email']").val(user.email);
    }

    $("[name='content']").val('');
    $("[name='parentMessage.id']").val(-1);
    $("[name='content']").attr("placeholder", "请输入评论信息...");
}

function reply(obj) {
    //alert("回复");
    var messageId = $(obj).data('messageid');
    var messageNickname = $(obj).data('messagenickname');
    $("[name='content']").attr("placeholder", "@" + messageNickname).focus();
    $("[name='parentMessage.id']").val(messageId);
    $(window).scrollTo($('message-form'), 500);
}

/*改造成,删除了只改动评论区. 不然模板包太大,评论区又会问题..目前只能这样*/
function shanchu(obj){
    var flag =  confirm('确定要删除该评论吗?三思啊! 删了可就没了!');
    if(flag == true){
        var messageId = $(obj).data('messageid');

        $("#message-container").load(/*[[@{/messages/delete}]]*/"/messages/delete",{
            "messageId" : messageId
        });
    }
    $(window).scrollTo($('#message-container'),500);
}

controller包下创建MessageController类,编写如下代码:(敏感词和邮件发送功能与评论一样,这里不再细说

@Controller
public class MessageController {
    @Autowired
    private MessageService messageService;
    @Autowired
    private MailUtil mailUtil;
    @Autowired
    private SensitiveFilterUtil sensitiveFilterUtil;
    @Value("${message.avatar}")
    private String avatar;

    private String subject="HXJ的博客留言回复";

    @GetMapping("/message")
    public String message(Model model){
        List<Message> messages = messageService.listMessage();
        System.out.println(messages);
        model.addAttribute("messages",messages);
        return "message";
    }

    //新增留言
    @PostMapping("/message")
    public String post(Message message,Model model, HttpSession session){
        User user =(User)session.getAttribute("user");
        if(user!=null){
            message.setAvatar(user.getAvatar());
            message.setAdminMessage(true);
        }else {
            message.setAvatar(avatar);
        }

        message.setContent(sensitiveFilterUtil.filter(message.getContent()));

        //前端传的是 parentMessage.id
        if(message.getParentMessage().getId()!=null){
            //是评论
            message.setParentMessageId(message.getParentMessage().getId());//到impl中 的展示才设置parentNickname

            //是子评论
            if(message.getParentMessageId()!=-1){
                Message parentMessage = messageService.findByParentId(message.getParentMessageId());//获得父评论
                //发邮件给父评论
                String rpl="亲爱的【"+parentMessage.getNickname()+"】,你在【HXJ的博客】的评论:"+parentMessage.getContent()+".收到了来自【"+
                        message.getNickname()+"】的回复! 内容如下:\n\n";
                mailUtil.sendSimpleMail(parentMessage.getEmail(), subject, rpl+message.getContent());
            }
        }
        messageService.savaMessage(message);
        List<Message> messages = messageService.listMessage();
        System.out.println(messages);
        model.addAttribute("messages",messages);
        return "message :: messageList";
    }

    //删除
    @PostMapping("/messages/delete")
    public String delete(Model model, @RequestParam("messageId")Long messageId){
        messageService.deleteMessage(messageId);

        List<Message> messages = messageService.listMessage();
        System.out.println(messages);
        model.addAttribute("messages",messages);
        return "message :: messageList";
    }

}

效果示例图如下:

在这里插入图片描述


二、归档页(时间轴)

前端直接拿来用,前端所需要的字段较少(但不想再多建一个VO,拿已经有的vo中找一个属性最少的),于是用后台的这个BlogQuery

这样dao接口Service接口和mapper都用已经存在的getAllBlogQuery接口。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-r1VNMra7-1653976189192)(其余页面显示.assets/image-20220531132830021.png)]

在这里插入图片描述

  • 只需要编写控制器代码:

controller包下创建ArchiveShowController类:

@Controller
public class ArchiveShowController {

    @Autowired
    private BlogService blogService;

    @GetMapping("/archives")
    public String archives(Model model){
        List<BlogQuery> list = blogService.getAllBlogQuery();
        model.addAttribute("blogs",list);
        return "archives";
    }

}
  • 效果示例图如下:

在这里插入图片描述

三、友链页

根据前端页面显示,可以直接调用持久层的listFriendLink接口,只需编写控制层代码就可以了。

在这里插入图片描述

  • 编写控制器代码:

controller包下创建FriendsShowController类:

@Controller
public class FriendsShowController {

    @Autowired
    private FriendLinkService friendLinkService;

    @GetMapping("/friends")
    public String friend(Model model){
        List<FriendLink> friendLinks = friendLinkService.listFriendLink();
        model.addAttribute("friendlinks",friendLinks);
        return "friends";
    }
}
  • 效果示例图如下:

在这里插入图片描述

四、照片墙页面显示

根据前端页面显示,可以直接调用持久层的listPicture接口,只需编写控制层代码就可以了。

在这里插入图片描述

照片墙使用了(lightbox插件)jkresponsivegallery.js

官方使用例:

在这里插入图片描述

  • 编写控制器代码:

controller包下创建PictureShowController类:

@Controller
public class PictureShowController {

    @Autowired
    private PictureService pictureService;

    @GetMapping("/picture")
    public String picture(Model model){
        List<Picture> pictures = pictureService.listPicture();
        model.addAttribute("pictures",pictures);
        return "picture";
    }
}
  • 效果示例图如下:

在这里插入图片描述

在这里插入图片描述

五、关于我页面显示

关于我页面显示是一个静态页面,直接在控制器中返回页面就可以了

  • 编写控制器代码:

controller包下创建AboutShowController类:

@Controller
public class AboutShowController {

    @GetMapping("/about")
    public String about(){

        return "about";
    }
}

六、音乐盒

音乐盒显示是一个静态页面,直接在控制器中返回页面就可以了

原本oneStar使用了一个轻量的音乐js插件,结果我发现不如直接拉一个网易云外链方便。

  • 编写控制器代码:

controller包下创建MusicShowController类:

@Controller
public class MusicShowController {

    //就一个静态页面
    @GetMapping("/music")
    public String music(){
        return "music";
    }
}

小结

至此所有功能开发已经完成。


如果想更换图片资源使用图床,可以看oneStar的Typora+PicGo+七牛云实现图片上传存储(配置不难,但是用PicGo配置的时候要知道自己的存储区域 官方手册有提到


线上部署方面,没有买服务器(没精力管),就做了一个穷人体验版。

使用了VMware Workstation 装个centos7,在虚拟机配置好后,本机也可以实现访问(下一篇文章将讲解我的操作。)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值