【Java】表白墙终章-飞流直下的“甜言蜜语”-瀑布流式布局

news2025/4/9 11:06:46

飞流直下三千尺!

在这里插入图片描述

文章目录

  • 【Java】表白墙终章-飞流直下的“甜言蜜语”-瀑布流式布局
    • 1. 效果前后对比
    • 2. 瀑布流式布局原理思想
    • 3. 约定前后端接口
    • 4. 后端代码
      • 4.1 修改Love类的定义
      • 4.2 修改doPost方法
      • 4.3 修改save方法
      • 4.4 修改doGet方法
      • 4.5 修改load方法
    • 5. 前端瀑布流实现
      • 5.1 规定“甜言蜜语”的层级结构
      • 5.2 css修饰
        • 5.2.1 底板div:a
        • 5.2.2 div:box
        • 5.2.3 div:pic
        • 5.2.4 div:T
        • 5.2.5 div:Tleft
        • 5.2.6 div:Tright
        • 5.2.7 div:B
      • 5.3 JS实现瀑布流式布局
        • 5.3.1 修改getLoves函数
        • 5.3.2 waterFall函数-瀑布流排列
      • 5.4 定时刷新
    • 6. 测试

【Java】表白墙终章-飞流直下的“甜言蜜语”-瀑布流式布局

1. 效果前后对比

改进之前:

  1. 用户之间无差别
  2. 消息先来先到

在这里插入图片描述

改进后:

  1. 添加导航栏左上角的身份显示(头像 + 用户名)
  2. 采用瀑布流的方式去排列消息
  3. 消息以卡片的形式显示(头像 + 用户名 + 日期 + 甜言蜜语)
  4. 先来后到
    • 最新发布的排在最前

在这里插入图片描述

2. 瀑布流式布局原理思想

  • 瀑布流布局的前提就是,待排序的div元素都是等宽不限高的~

在这里插入图片描述

流程:

  1. 获取一个div元素盒子的宽
  2. 获取底板(父元素)的宽
  3. 计算底板最多排列的列数:n
  4. 将前四个div元素排在首行
  5. 从已排列的每一列中找到最矮的一列,将接下来的元素安插上去(通过绝对定位,即通过提供的坐标,安插到底板的固定位置)
  6. 重复5操作,直到全部排序好

动图演示:

在这里插入图片描述

越界了怎么办?

  • 加滚动条就行了~

细节:

  • 滚动条不能加在底板上,应该加在底板的至少上一级元素

原因:

  • 刚才在计算列数的时候,是没有减掉滚动条的宽度的,也就是说列数可能是多了1列,导致出现了“水平滚动条”,也就是说“竖直滚动条”挤压了原有元素,会导致一些排版重叠问题!

3. 约定前后端接口

之前的“甜言蜜语”只有简单的正文部分,而现在,它需要有更多的属性:
在这里插入图片描述

再原有基础上,应该增加三个属性

  1. image,头像(与用户名绑定)
  2. date,日期(可按时间逆排序)
  3. username,用户名(确认用户信息)

所以,我们需要数据库的一张新的表:

在这里插入图片描述

因此,我们需要更改后端代码关于json构造的部分!

4. 后端代码

在这里插入图片描述

查询的表

  • message => vindicate
  • 注意修改!

4.1 修改Love类的定义

class Love {
    public String from;
    public String to;
    public String love;
    public String username;
    public String image;
    public String date;

    public Love() {
        //没有这个一定不行!!!
        //因为后续json构建Love对象需要用到无参的构造方法
    }

    public Love(String from, String to, String love, String username, String image, Timestamp date) {
        this.from = from;
        this.to = to;
        this.love = love;
        this.username = username;
        this.image = image;
        String strn = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date);
        this.date = strn;
    }

}

注意:

  1. jdbc操作数据库,既可以将满足格式的 String类或者 Timestamp类载入数据库datetime类型字段中
  2. jdbc操作数据库,将 datetime类型的字段提取出来的时候,只能提取为 Date或者 Timestamp类(本文选择后者)

在这里插入图片描述

  • 这样子,我们在表白墙里看到的就是日期格式了~
    • 当然,日期还有格式还有很多种,这个类还能满足“yyyy/MM/dd HH-mm-ss”、“HH/mm/ss yyyy.MM.dd”等等等…
    • 但是这里,由于后续我将数据载入数据库是用的严格符合格式的字符串的方式,所以选择“yyyy-MM-dd HH:mm:ss”的格式~
    • 还有更多的类表达日期的格式,感兴趣的可以去了解了解,但是我建议,用的时候查就行了

4.2 修改doPost方法

  • 客户端发来的post请求,将客户端json格式的body转化为Love类,载入数据库

当然,客户端那里发过来的post正文是不包含,image、username和date的,所以构造的Love类对象的这三个属性的值为null~

@WebServlet("/love")
public class ShowLove extends HttpServlet {
    
    private ObjectMapper objectMapper = new ObjectMapper();
    
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Love love = objectMapper.readValue(req.getInputStream(), Love.class);
        HttpSession session = req.getSession();
        Timestamp time = new Timestamp(System.currentTimeMillis());
        String strn = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(time);
        love.date = strn;
        love.username = (String)session.getAttribute("username");
        love.image = Save.getImage(love.username);
        save(love);
        //默认返回的就是200的空报文
    }
}

在这里插入图片描述

然后就是调用save方法,将love对象载入数据库

4.3 修改save方法

private void save(Love love){
    DataSource dataSource = new MysqlDataSource();
    ((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/Loves?characterEncoding=utf8&useSSL=false");
    ((MysqlDataSource)dataSource).setUser("root");
    ((MysqlDataSource)dataSource).setPassword("mmsszsd666");//这是俺的微信号,欢迎添加,相互学习!
    try {
        Connection connection = dataSource.getConnection();
        String sql = "insert into vindicate values(?, ?, ?, ?, ?, ?);";
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        preparedStatement.setString(1, love.from);
        preparedStatement.setString(2, love.to);
        preparedStatement.setString(3, love.love);
        preparedStatement.setString(4, love.image);
        preparedStatement.setString(5, love.date);
        preparedStatement.setString(6, love.username);
        preparedStatement.executeUpdate();

        preparedStatement.close();
        connection.close();
    } catch (SQLException e) {
        e.printStackTrace();
    }

}

在这里插入图片描述

4.4 修改doGet方法

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    //如果有输入操作互动的操作,在这里refresh是不合理的,因为写着写着就刷新了,体验不好
    // 所以在这里设置refresh没用!

    //转换为json字符串!
    List<Love> list =  load();
    String result = objectMapper.writeValueAsString(list);
    resp.setContentType("application/json; charset=utf8");
    resp.getWriter().write(result);

}

这段方法没有更改,主要是load方法更改了

4.5 修改load方法

private List<Love> load(){

    DataSource dataSource = new MysqlDataSource();
    ((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/Loves?characterEncoding=utf8&useSSL=false");
    ((MysqlDataSource)dataSource).setUser("root");
    ((MysqlDataSource)dataSource).setPassword("mmsszsd666");//这是俺的微信号,欢迎添加,相互学习!
    List<Love> list = new ArrayList<>();
    try {
        Connection connection = dataSource.getConnection();
        String sql = "select * from vindicate order by date desc;";
        PreparedStatement preparedStatement = connection.prepareStatement(sql);

        //这里的Set并不是,对象为Love的Set集合,而是一个迭代器!
        ResultSet set = preparedStatement.executeQuery();
        //迭代他(是next方法而不是hasnext)

        while(set.next()) {
            String from = set.getString("from");
            String to = set.getString("to");
            String love = set.getString("love");
            String username = set.getString("username");
            if(username.length() > 9) {
                username = username.substring(0, 9) + "...";
            }
            String image = set.getString("image");
            Timestamp date = set.getTimestamp("date");
            list.add(new Love(from, to, love, username, image, date));
        }

        set.close();
        preparedStatement.close();
        connection.close();
    } catch (SQLException e) {
        e.printStackTrace();
    }
    return list;
}

在这里插入图片描述

接下来就是本文重点的前端的瀑布流布局实现了

5. 前端瀑布流实现

在这里插入图片描述

5.1 规定“甜言蜜语”的层级结构

在这里插入图片描述

在这里插入图片描述

pic的div块,就是我们的后端数据载入的对象了~
在这里插入图片描述

在这里插入图片描述

T为信息头,头像显示、用户名显示以及日期显示

B为正文,“甜言蜜语”显示

在这里插入图片描述

在这里插入图片描述

T的左侧显示头像,右侧显示用户名和日期

5.2 css修饰

在pursue.css里增加

5.2.1 底板div:a

#a {
    height: calc(100% - 66.67px);
    width: 100%;

    /* overflow: auto; */
    position: relative;
}
  • 将滚动条注释掉,交给其上一级:article

在这里插入图片描述

  • 设置属性position为:relative,相对定位 => 与绝对定位对应,如果没有这个属性,我们提供的坐标,其是按照整个页面来定位的
    • 而设置这个属性后,是以此div来定位的(坐标系平移,原点改变)

5.2.2 div:box

  • 这个盒子代表了一条信息的占位空间,主要作用是设立内边距,与其他信息块分离
  • 这个div极为主要
.box {
    /* 用padding,而不是margin,因为我们计算的时候,我们不希望算上外边距(盒子大小,js获得高度的时候还得加上margin,复杂多了) */
    padding: 15px 0 0 15px;
    height: auto;

    /* 浮动属性 */
    float: left;
}
  • 只设置上,与左的内边距为15px

    • padding:top right bottom left(顺时针)
  • 设置浮动属性:float

    • 子元素div是块级元素,独占一行,设置这个属性后,取消块级性质,并且左排列,越界换行,但是这并不能起到瀑布流的效果
      1. 如果接下来的元素可以安插到其中一列,且总长度超过其原最长高,则会补充到对应列
      2. 若1不满足,则重起一行

5.2.3 div:pic

.pic {
    background-color: rgb(255, 255, 255);
    width: 150px;
    height: auto;
    /* 边距 */
    padding: 10px;
    border: 1px solid #ccc;
    border-radius: 5px;

    /* 阴影 */
    box-shadow: 0 0 5px rgb(0, 0, 0);
}
  1. 底色为白
  2. 宽度固定为150px
  3. 高不限制,根据子元素决定
  4. 设置内边距为10px,不会导致子元素紧贴边界
  5. 设置灰色边框和黑色阴影~

5.2.4 div:T

.pic .T {
    width: 150px;
    height: 30px;
    display: flex;
    justify-content: space-between;
}

消息头的width撑破了限制无所谓~

  • 高度固定为30px => 头像为30px × 30px

设置为弹性布局,并使子元素space-between(根据实际留出间隙)

  • 并且T的左和右是不换行的~

5.2.5 div:Tleft

.Tleft {
    width: 30px;
    height: 30px;
    background-image: url(https://img1.baidu.com/it/u=4205447136,2730860147&fm=253&fmt=auto&app=138&f=JPEG?w=300&h=300);
    border: 1px solid rgb(0, 0, 0);
    border-radius: 15px;
    background-repeat: no-repeat;
    background-position: center center;
    background-size: cover;
}
  1. 设置半径为15px的圆形
  2. 图片为默认头像
  3. 黑色边框
  4. 设置属性是的图片充满圆

5.2.6 div:Tright

.Tright {
    width: 110px;
    height: 30px;
}
.Tright h4 {
    line-height: 15px;
    font-size: 15px;
    color: rgb(128, 128, 128);
}
  1. 宽度设置为110px,不会导致文字和图片太紧凑
  2. 高度设置为30px~
  3. h4标签设置为15px(因为有两个),刚好与div:T等高(字为灰色)
    • 日期可能会超出限制,不过无所谓,在正文的一开始加个换行错开就行了~

5.2.7 div:B

.B {
    width: 150px;
    height: auto;
    word-wrap: break-word;
    padding-right: 10px;
    padding-top: 5px;
}
  1. 宽度为150px
  2. 高度由正文决定
  3. 根据单词超出限制换行
    • 没有这个设置会导致B的高度始终为一个文字的高度
  4. 微调文字布局

5.3 JS实现瀑布流式布局

5.3.1 修改getLoves函数

  • 由于前后端交互接口的改变,这里也需要做一些调整~
function getLoves() {
    jQuery.ajax({
        type: "GET",
        url: "love",
        success: function (body) {
            var boxArray = [];
            //body就是数组
            for (var word of body) {
                var result =
                    "<br/><h2>" +
                    word.from +
                    "想对" +
                    word.to +
                    "说“" +
                    word.love +
                    "”</h2>";
                var aB = jQuery("<div></div>");
                aB.attr("class", "B");
                aB.append(result);

                var aTleft = jQuery("<div></div>");
                aTleft.attr("class", "Tleft");
                console.log(word.image);
                aTleft.css("background-image", "url(" + word.image + ")");

                var aTright = jQuery("<div></div>");
                aTright.attr("class", "Tright");
                aTright.append(
                    "<h4>" + word.username + ":</h4> <h4>" + word.date + "</h4>"
                );
                var aT = jQuery("<div></div>");
                aT.attr("class", "T");
                aT.append(aTleft);
                aT.append(aTright);
                var aPic = jQuery("<div></div>");
                aPic.attr("class", "pic");
                aPic.append(aT);
                aPic.append(aB);
                var aBox = jQuery("<div></div>");
                aBox.attr("class", "box");
                aPic.appendTo(aBox);
                aBox.appendTo(jQuery("#a"));
                boxArray.push(aBox);
            }
            waterFall(boxArray);
        },
    });
}

在这里插入图片描述

构造box的时候要细心哦,要契合我们的层级结构!

5.3.2 waterFall函数-瀑布流排列

function waterFall(boxes) {
    // 将a下的全部box取出来
    var oParent = jQuery("#a");
    
    // 计算显示的列数(页面的宽/box的宽)
    var oBoxWeight = boxes[0].outerWidth(); // console.log(oBoxWeight);
    var cols = Math.floor(jQuery("#a").width() / oBoxWeight);
    // 设置a的宽度
    oParent.css("width", cols * oBoxWeight + "px");
    oParent.css("margin", "0 auto");

    // 存放第该列(位置正确摆放的多个div高度)的高度的数组
    // 第一次,则是第一行每个div的高度
    var hArr = [];
    for (var i = 0; i < boxes.length; i++) {
        if (i < cols) {
            hArr.push(boxes[i].outerHeight());
        } else {
            var minH = Math.min.apply(null, hArr); //top
            var index = getMinhIndex(hArr, minH);
            boxes[i].attr(
                "style",
                "position: absolute; top: " +
                minH +
                "px; left: " +
                oBoxWeight * index +
                "px;"
            );
            //处理盒子重叠
            hArr[index] += boxes[i].outerHeight();
        }
    }
    // left -> 左边三个div的宽,top-> 最小高
}
function getMinhIndex(arr, val) {
    for (var i = 0; i < arr.length; i++) {
        if (arr[i] == val) {
            return i;
        }
    }
}

在这里插入图片描述
在这里插入图片描述

瀑布流布局完成!

5.4 定时刷新

  • 我们可以通过setInterval函数,设置一个函数多久定时调用一次
function refresh() {
    jQuery("#a").empty();
    getLoves();
}
setInterval(refresh, 5000);//5000ms

现在我们自动刷新的时机为:

  1. 点击发送
  2. 定时刷新

6. 测试

手机端:
在这里插入图片描述

电脑端:

在这里插入图片描述


文章到此结束!谢谢观看
可以叫我 小马,我可能写的不好或者有错误,但是一起加油鸭🦆

表白墙完结啦啦啦啦啦✿✿ヽ(°▽°)ノ✿

可能以后会追加一系列的功能,敬请期待

不久后将上线!

本文代码位置:六月代码/showLove/src/main · 游离态/马拉圈2023年6月 - 码云 - 开源中国 (gitee.com)


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/631869.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

面试总结个人版

一、面试题 java 集合 &#xff0c; spring springmvc springboot springcloud 数据库相关的&#xff0c; redis 相关 &#xff0c;mq 相关 &#xff0c;结合业务的场景题 1、part one 集合 HashMap底层原理 HashMap是基于哈希表的Map接口的非同步实现。元素以键值对的形式存…

asp.net教师调课系统VS开发sqlserver数据库web结构c#编程Microsoft Visual Studio

一、源码特点 asp.net教师调课管理系统 是一套完善的web设计管理系统&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为vs2010&#xff0c;数据库为sqlserver2008&#xff0c;使用c#语言开发 asp.net教师调课系统VS开发sqlser…

deadline用WebService提交Job

官方文档 网站链接 进入rest API&#xff0c;点击jobs&#xff0c;找到submit job 这里可以看到消息体需要用到JobInfo和PluginInfo这两个关键的字典&#xff08;json object&#xff09; 拿到对应的键值对 为了填写url请求的消息体 我们需要拿到必须参数的键值对 点击双击…

如何延长电脑硬盘的使用寿命?

在日常使用电脑过程中&#xff0c;一定要做好硬盘的保养和维护&#xff0c;一旦硬盘损坏&#xff0c;保存在硬盘上的数据就会丢失&#xff0c;而且找回数据也是一件很费功夫的事情&#xff0c;甚至有可能永远也找不回来。所以日常工作中定期对资料进行备份&#xff0c;做好电脑…

【算法与数据结构】24、LeetCode两两交换链表中的节点

文章目录 一、题目二、解法三、完整代码 所有的LeetCode题解索引&#xff0c;可以看这篇文章——【算法和数据结构】LeetCode题解。 一、题目 二、解法 思路分析&#xff1a;题目要求两两交换节点。在链表当中非常重要就是下一个节点&#xff0c;一旦丢失&#xff0c;这个节点后…

IDL基础语法

1 创建变量 命名规则&#xff1a;变量名必须以字母开头。它们可以包括其它字母&#xff0c;数字&#xff0c;下划线&#xff0c;美元符号。 以下是创建不同数据类型的方法&#xff0c;我们只需了解即可&#xff0c;知道如何创建整型【16位有符号长整型】和浮点型 PRO learn;创…

RedisGraph的整体架构

The architecture of RedisGraph 本文关注RedisGraph的整体架构&#xff0c;分别从图存储模型、索引、并发控制、和执行计划四个方面简要阐述。下图为RedisGraph的整体架构图。 1 图存储模型 了解一个图数据库的架构&#xff0c;最重要的就是其图存储模型&#xff0c;即其中的…

freeswitch 使用 silero-vad 静音拆分使用 fastasr 识别

silero-vad 在git 的评分挺高的测试好像比webrtc vad好下面测试下 silero-vad 支持c 和py 由于识别c的框架少下面使用py 以下基于python3.8torch1.12.0torchaudio 1.12.0 1.由于fastasr 需要16k 所以 将freeswitch的实时音频mediabug 8k转成16k 用socket传到py 模块代码…

二十三种设计模式(待更)

二十三种设计模式 二十三种设计模式结构型1.适配器 相关资料 二十三种设计模式 资料来源于老师讲解以及大佬的设计模式仓库 zhengqingya 结构型 将对象和类按某种布局组成更大的结构&#xff0c;并同时保持结构的灵活和⾼效。 1.适配器 将一个类的接口转换成客户希望的另外…

【小沐学Python】Python实现在线电子书(MkDocs + readthedocs + github + Markdown)

文章目录 1、简介2、安装3、创建新项目4、添加页面5、编辑导航页6、设置主题7、更改图标图标8、构建网站9、部署9.1 准备github项目9.2 注册登录Read the Docs9.3 导入github项目到 Read the Docs 10、Markdown语法10.1 横线10.2 标题10.3 段落10.4 文字高亮10.5 换行10.6 斜体…

你不可不知的八大全新顶级开源项目

导读九年来&#xff0c;Black Duck开源年度奖一直致力于发现过去一年中出现的最具创新性与影响力的开源项目。尽管开源项目阵营一直在快速变化&#xff0c;但年度新人奖一直在为行业趋势提供重要参考。下面&#xff0c;我们将了解这一年中的各位获奖新人! 九年来&#xff0c;B…

adb详细教程(一)-下载安装与环境变量配置

对于Android开发来说&#xff0c;adb是再熟悉不过的调试工具 但其实对于移动端的测试来说&#xff0c;adb也是一个十分重要的、能够提高测试工作效率的工具。 文章目录 一、介绍二、下载地址三、安装四、配置环境变量 一、介绍 全称 adb全称全称为Android Debug Bridge&#x…

【Python】在同一图形中的绘制多个子图

1. 引言 有时我们需要并排绘制两个图形&#xff0c;这不仅是为了更好地利用空间&#xff0c;而且主要是因为为了更加直观地对比分析数据。其实在python中可以利用subplot来实现上述功能。 闲话少说&#xff0c;我们直接开始吧&#xff01; 2. 准备工作 这里&#xff0c;我们…

JavaScript 教程---互联网文档计划

学习目标&#xff1a; 每天记录一章笔记 学习内容&#xff1a; JavaScript 教程---互联网文档计划 笔记时间&#xff1a; 2023-6-5 --- 2023-6-11 学习产出&#xff1a; 1.入门篇 1、JavaScript 的核心语法包含部分 基本语法标准库宿主API 基本语法&#xff1a;比如操作符…

代码随想录第57天

1.回文子串 暴力解法 两层for循环&#xff0c;遍历区间起始位置和终止位置&#xff0c;然后还需要一层遍历判断这个区间是不是回文 动态规划 动规五部曲&#xff1a; 确定dp数组&#xff08;dp table&#xff09;以及下标的含义 如果大家做了很多这种子序列相关的题目&…

基于html+css的图展示118

准备项目 项目开发工具 Visual Studio Code 1.44.2 版本: 1.44.2 提交: ff915844119ce9485abfe8aa9076ec76b5300ddd 日期: 2020-04-16T16:36:23.138Z Electron: 7.1.11 Chrome: 78.0.3904.130 Node.js: 12.8.1 V8: 7.8.279.23-electron.0 OS: Windows_NT x64 10.0.19044 项目…

ChatGPT对未来编程语言发展的影响与展望

目录 一、引言1.ChatGPT的介绍与背景介绍背景 2.编程语言发展的重要性和挑战重要性挑战 二、ChatGPT在编程领域的应用1.自然语言处理技术在编程中的应用现状2. ChatGPT作为编程辅助工具的潜力与优势 三、ChatGPT对编程语言发展的影响1. 创新编程模式的涌现2. 语言设计与交互方式…

【高危】GitLab CE/EE 16.0.0存在路径遍历漏洞(存在POC)

漏洞描述 GitLab 是一款基于Git的代码托管、版本控制、协作开发平台。 在 GitLab CE/EE 16.0.0版本中 &#xff0c;在文件上传时未对filename参数进行安全过滤&#xff0c;导致存在路径遍历漏洞&#xff0c;若嵌套在五个组及以上的公共项目中存在附件时&#xff0c;未经身份验…

以ChatGPT辅助软件架构工作

以ChatGPT辅助软件架构工作 在目前技术瞬息万变的背景下&#xff0c;软件建构师需要持续探索并采纳新颖的工具和方式&#xff0c;以提升开发流程&#xff0c;增强效率&#xff0c;同时保障最后成品的品质。在此之中&#xff0c;人工智能&#xff08;AI&#xff09;已经演变为一…

大数据Doris(三十八):Spark Load 导入Hive数据

文章目录 Spark Load 导入Hive数据 一、Spark Load导入Hive非分区表数据 1、在node3hive客户端&#xff0c;准备向Hive表加载的数据 2、启动Hive&#xff0c;在Hive客户端创建Hive表并加载数据 3、在Doris中创建Hive外部表 4、创建Doris表 5、创建Spark Load导入任务 6…