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

2024-03-12 15:10

本文主要是介绍【JavaEE】表白墙终章-飞流直下的“甜言蜜语”-瀑布流式布局,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

飞流直下三千尺!

在这里插入图片描述

文章目录

  • 【JavaEE】表白墙终章-飞流直下的“甜言蜜语”-瀑布流式布局
    • 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. 测试

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

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();@Overrideprotected 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); //topvar 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)


这篇关于【JavaEE】表白墙终章-飞流直下的“甜言蜜语”-瀑布流式布局的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/801677

相关文章

C++对象布局及多态实现探索之内存布局(整理的很多链接)

本文通过观察对象的内存布局,跟踪函数调用的汇编代码。分析了C++对象内存的布局情况,虚函数的执行方式,以及虚继承,等等 文章链接:http://dev.yesky.com/254/2191254.shtml      论C/C++函数间动态内存的传递 (2005-07-30)   当你涉及到C/C++的核心编程的时候,你会无止境地与内存管理打交道。 文章链接:http://dev.yesky

Java五子棋之坐标校正

上篇针对了Java项目中的解构思维,在这篇内容中我们不妨从整体项目中拆解拿出一个非常重要的五子棋逻辑实现:坐标校正,我们如何使漫无目的鼠标点击变得有序化和可控化呢? 目录 一、从鼠标监听到获取坐标 1.MouseListener和MouseAdapter 2.mousePressed方法 二、坐标校正的具体实现方法 1.关于fillOval方法 2.坐标获取 3.坐标转换 4.坐

Spring Cloud:构建分布式系统的利器

引言 在当今的云计算和微服务架构时代,构建高效、可靠的分布式系统成为软件开发的重要任务。Spring Cloud 提供了一套完整的解决方案,帮助开发者快速构建分布式系统中的一些常见模式(例如配置管理、服务发现、断路器等)。本文将探讨 Spring Cloud 的定义、核心组件、应用场景以及未来的发展趋势。 什么是 Spring Cloud Spring Cloud 是一个基于 Spring

Javascript高级程序设计(第四版)--学习记录之变量、内存

原始值与引用值 原始值:简单的数据即基础数据类型,按值访问。 引用值:由多个值构成的对象即复杂数据类型,按引用访问。 动态属性 对于引用值而言,可以随时添加、修改和删除其属性和方法。 let person = new Object();person.name = 'Jason';person.age = 42;console.log(person.name,person.age);//'J

java8的新特性之一(Java Lambda表达式)

1:Java8的新特性 Lambda 表达式: 允许以更简洁的方式表示匿名函数(或称为闭包)。可以将Lambda表达式作为参数传递给方法或赋值给函数式接口类型的变量。 Stream API: 提供了一种处理集合数据的流式处理方式,支持函数式编程风格。 允许以声明性方式处理数据集合(如List、Set等)。提供了一系列操作,如map、filter、reduce等,以支持复杂的查询和转

Java面试八股之怎么通过Java程序判断JVM是32位还是64位

怎么通过Java程序判断JVM是32位还是64位 可以通过Java程序内部检查系统属性来判断当前运行的JVM是32位还是64位。以下是一个简单的方法: public class JvmBitCheck {public static void main(String[] args) {String arch = System.getProperty("os.arch");String dataM

详细分析Springmvc中的@ModelAttribute基本知识(附Demo)

目录 前言1. 注解用法1.1 方法参数1.2 方法1.3 类 2. 注解场景2.1 表单参数2.2 AJAX请求2.3 文件上传 3. 实战4. 总结 前言 将请求参数绑定到模型对象上,或者在请求处理之前添加模型属性 可以在方法参数、方法或者类上使用 一般适用这几种场景: 表单处理:通过 @ModelAttribute 将表单数据绑定到模型对象上预处理逻辑:在请求处理之前

eclipse运行springboot项目,找不到主类

解决办法尝试了很多种,下载sts压缩包行不通。最后解决办法如图: help--->Eclipse Marketplace--->Popular--->找到Spring Tools 3---->Installed。

JAVA读取MongoDB中的二进制图片并显示在页面上

1:Jsp页面: <td><img src="${ctx}/mongoImg/show"></td> 2:xml配置: <?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001

Java面试题:通过实例说明内连接、左外连接和右外连接的区别

在 SQL 中,连接(JOIN)用于在多个表之间组合行。最常用的连接类型是内连接(INNER JOIN)、左外连接(LEFT OUTER JOIN)和右外连接(RIGHT OUTER JOIN)。它们的主要区别在于它们如何处理表之间的匹配和不匹配行。下面是每种连接的详细说明和示例。 表示例 假设有两个表:Customers 和 Orders。 Customers CustomerIDCus