【Java EE】-Servlet(三) MessageWall

news2025/1/15 6:40:46

作者:学Java的冬瓜
博客主页:☀冬瓜的主页🌙
专栏:【JavaEE】
分享: 寂寞会发慌,孤独是饱满的。——史铁生《命若琴弦》

主要内容:前后端交互接口协商,约定好,使用什么数据格式传输,什么时候发送请求,发送什么请求。使用数据库对浏览器提交到服务器的信息进行长期的保存。前端html作为主体,CSS修饰html,使用js来操作dom树,并且在js中使用ajax来构造各种请求,使用ajax构造body为 json格式的post请求。后端内容将数据库连接过程使用DBUtil封装,使用MessageServlet.java来处理 前端发来的各种http请求。服务器根据请求对数据进行在数据库 存档,读档,删档的操作。

在这里插入图片描述

文章目录

  • 一、准备工作
  • 二、前端内容
  • 三、后端内容
  • 四、成果展示

一、准备工作

重点:协商前后端交互接口
写web程序前,需要约定好,前后端如何进行交互,约定好交互的数据格式。比如请求的格式,响应的格式,浏览器什么时候发送请求,服务器按照什么格式来解析浏览器的请求,以及写回到浏览器使用什么格式数据。如下图,就使用post请求提交表白信息到服务器,再用get请求从服务器取表白信息,全过程中http报文交互的body格式全部使用json格式。

需求:点击提交时,浏览器使用post请求提交一份表白信息发送到浏览器存档;页面加载时,浏览器使用get请求发送给浏览器,从服务器读取全部表白信息;点击重置时,浏览器发送delete请求给服务器,删除服务器存档的最后一份表白信息。在这里插入图片描述
在这里插入图片描述


理解:为什么使用数据库存储数据?
1> 如果不使用后端代码,只使用前端代码,可以展示表白墙的效果,但是message数据只是保存在浏览器中,当刷新一下页面,表白的信息就不在了。
2> 加入后端代码后,如果是使用一个集合来保存message信息,那么提交数据给服务器可以使用post提交,获取数据可以在加载页面时,使用get请求从服务器获取,刷新页面是给浏览器发送一个get请求,从集合中取出全部message信息显示到浏览器上,因此刷新页面数据还在。但是因为数据是存储在集合中,也就是内存中,当服务器一关闭,数据就不存在了。
3> 为了防止上述问题,最后可以使用数据库,存储在本地硬盘中,这样的话,即使服务器关闭,数据仍然存在。

二、前端内容

下面为 message.html:代码,html作为页面的主体部分,并在html中引入css。在使用js中的ajax构造body为json格式的post请求前,先引入jQuery,然后在html的body标签中引入js文件。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>表白墙</title>

    <!--引入css-->
    <link rel="stylesheet" href="./messageWall.css">

</head>
<body>
    <div class="all">
        <div class="container">
            <h2>表白墙</h2>
            <p>输入后点击提交,信息会显示在表格下方</p>
            <div class="row">
                <span>谁:</span>
                <input type="text" class="from">
            </div>
            <div class="row">
                <span>对谁:</span>
                <input type="text" class="to">
            </div>
            <div class="row">
                <span>说:</span>
                <input type="text" class="message">
            </div>
            <div class="row">
                <button id="submit">提交</button>
                <button id="reset">重置</button>
            </div>
        </div>
        <div class="Conversation"></div>
    </div>
    


    <!-- 使用ajax前先引入jquery -->
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
    <!--引入js-->
    <script src="./messageWall.js"></script>
</body>
</html>

下面为 message.css:代码,使用css修饰html页面

/* 通配符选择器,选中所有标签 */
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

.all{
    margin: 0 auto;
    padding: 0;
    background-color: pink;
    height: 650px;
}
.container{
    width: 600px;
    height: 280px;
    margin: 0px auto;
    padding: 20px;
}
/* 设置h2,p居中 */
h2 {
    text-align: center;
}
p {
    text-align: center;
    color: #666;
    /* 先竖直,再水平 */
    margin: 20px 0;
}


/* 设置弹性布局 */
.row {
    /* 开启弹性布局 */
    display: flex;
    height: 40px;
    /* 水平方向居中 */
    justify-content: center;
}
/* 设置提示框的长度 */
.row span {
    width: 80px;
}

/* 设置输入框的长度和高度 */
.row input {
    width: 200px;
    height: 30px;
}

.row button {
    color: white;
    background-color: orange;
    width: 120px;
    height: 35px;
    border: none;
    /* margin-left: 20px;
    margin-right: 20px; */
    margin: 20px;
}
/* 设置点击提交时变灰色 */
button:active {
    background-color: #666;
}

/* 设置结果的div样式 */
.result {
    text-align: center;
    margin: 5px;
    line-height: 40px;
}
.Conversation{
    width: 280px;
    height: 280px;
    margin-top: 40px;
    margin-left: auto;
    margin-right: auto;

    padding: 20px;
    background-color: rgba(0,128,0,0.6);
}

下面为message.js代码,用于操作dom树,以及使用ajax构造请求的body格式为json的post请求。

  • 按下提交时,使用ajax(得先引入jquery)给服务器发送一条post请求,提交表白信息到服务器
  • 加载页面时,使用ajax给服务器发送一条get请求,从服务器获得所有表白信息
  • 点击重置时,使用ajax给服务器发送一条delete请求,服务器将数据库的最后一条表白信息删除,然后将剩下的全部表白信息响应到ajax中,这里就需要用 js先把原来页面中的所有表白信息div删除,使用响应结果(删除最后一条表白信息后的数据) 构造表白信息div,再展示到浏览器上。
// 一.实现表白墙展示
let ConversationDiv = document.querySelector('.Conversation');
let inputs = document.querySelectorAll('input');
let submit = document.querySelector('#submit');

submit.onclick = function(){
    // 1.获取到三个input的值
    let from = inputs[0].value;
    let to = inputs[1].value;
    let mesg = inputs[2].value;
    if(from == '' || to == '' || mesg == ''){
        return;
    }
    // 2.构造新的展示div
    let resultDiv = document.createElement('div');
    resultDiv.className = 'row message result';
    resultDiv.innerHTML = from + ' 对: ' + to + ' 说: ' + mesg;
    ConversationDiv.appendChild(resultDiv);
    // 3.清空表格中的内容
    for(let input of inputs){
        input.value = '';
    }

    // 【新增一】 按下提交时,使用ajax(得先引入jquery)给服务器发送一条post请求
    // 注意:body内的数据的名称(左边)必须和后端的使用jackson解析成的 Message的字段类型一致;右边的则是上面定义获取的变量
    let body = {
        "from":from,
        "to":to,
        "message":mesg
    }
    let jsonBody = JSON.stringify(body);
    $.ajax({
        type: 'post',
        url: './message',
        contentType: 'application/json; charset=utf-8',
        data: jsonBody,
        success: function(){
            // 这里的body是响应报文json格式的字符串 转换成的js对象
            console.log("请求发送成功!");
        }
    })
}
// 【新增二】 页面加载时,从服务器获取 所有信息并显示在浏览器上
$.ajax({
    type: 'get',
    url: './message',
    success: function(body){
        console.log("响应接收成功!");
        let ConversationDiv = document.querySelector('.Conversation');
        for(let message of body){
            // 对每一个message元素构造一个div
            let resultDiv = document.createElement('div');
            resultDiv.className = 'row message result';
            resultDiv.innerHTML = message.from + ' 对: ' + message.to + ' 说: ' + message.message;
            ConversationDiv.appendChild(resultDiv);
        }
    }
})


// 二.重置时把表格下的最后一条内容清除
let reset = document.querySelector('#reset');
reset.onclick = function(){
    //【新增三】 点击重置时,不是直接删除最后一个节点,而是发送delete请求,服务器处理delete请求,然后显示剩下的所有信息
    $.ajax({
        type: 'delete',
        url: './message',
        success: function(body){
            // 1.先选中父元素ConversationDiv,然后删除所有子元素
            let ConversationDiv = document.querySelector('.Conversation');
            while(ConversationDiv.firstChild){
                ConversationDiv.removeChild(ConversationDiv.firstChild)
            }

            for(let message of body){
                // 2.对响应数据内容进行页面显示,对每一个message元素构造一个div
                let resultDiv = document.createElement('div');
                resultDiv.className = 'row message result';
                resultDiv.innerHTML = message.from + ' 对: ' + message.to + ' 说: ' + message.message;
                ConversationDiv.appendChild(resultDiv);
            }
        }
    })
}

三、后端内容

  • 使用MessageServlet处理前端发来的各种请求,注意这里需要针对前端发来的body类型为json格式的内容进行解析,可以使用jackson来解析。
  • doPost方法处理前端提交 表白信息的post请求,会在执行doPost方法中 调用save方法 将表白信息保存在数据库中。
  • doGet方法处理前端加载页面时 发来的get请求,会在执行doGet方法中 调用load方法将数据库中所有表白信息查出来,写回到浏览器。
  • doDelete方法处理前端重置,发来的删除最后一条表白信息的delete请求,会在执行doDelete方法中 调用delete方法将数据库中的最后一条信息删除,然后将剩下的内容写回浏览器。
  • 使用 MessageServlet.java类解决浏览器发来的各种请求,使用 DBUtil.java类作为工具类,用来封装数据库连接的过程。

使用 MessageServlet.java类解决浏览器发来的各种请求。

package servlet;

import com.fasterxml.jackson.databind.ObjectMapper;
import util.DBUtil;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

// 使用Message来装填jackson解析的前端发来的json格式的字符串。
class Message {
    public String from;
    public String to;
    public String message;
}

@WebServlet("/message")
public class MessageServlet extends HttpServlet {
    // 使用jackson解析浏览器发来的json格式的数据
    private ObjectMapper objectMapper = new ObjectMapper();

    // 客户端(浏览器)按提交按钮时,向服务器提交数据
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 将req里的键值对读出,并和Message比对属性名给value,返回Message对象
        Message message = objectMapper.readValue(req.getInputStream(),Message.class);
        // 把这一份表白信息保存到数据库
        int count =  save(message);
        if(count == 1){
            System.out.println("表白信息成功写入数据库");
        }else {
            System.out.println("表白信息写入数据库失败");
        }
    }

    // 浏览器加载时,从服务器获取数据
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 把messageList这个Java集合对象转成json格式的字符串,再把字符串写入resp的body中

        //注意:一定要记得设置响应报文的格式,否则前端代码会认为是其它格式,可能会按照其它格式解析
        resp.setContentType("application/json; charset=utf-8");
        // 从数据库获取所有表白信息
        List<Message> messageList = load();
        objectMapper.writeValue(resp.getOutputStream(), messageList);
    }

    @Override
    protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("application/json; charset=utf-8");
        // 从数据库获取所有表白信息
        // 1.获取最后一份表白信息,并从数据库删除
        List<Message> messageList = load();
        if(messageList.size() == 0){
            return;
        }
        Message messageEnd = messageList.get(messageList.size()-1);
        int count = delete(messageEnd);
        if(count == 1){
            System.out.println("表白信息删除成功");
        }else {
            System.out.println("表白信息删除失败");
        }
        // 2.获取删除最后一条信息后的 全部表白信息,并写回到浏览器
        messageList = load();
        objectMapper.writeValue(resp.getOutputStream(), messageList);
    }


    private int save(Message message){
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        int count = 0;

        try {
            // 1.获取连接
            connection = DBUtil.getConnection();
            // 2.编写sql
            String sql = "insert into message values(?,?,?)";
            // 3.获取预编译对象,进行预编译
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setString(1,message.from);
            preparedStatement.setString(2,message.to);
            preparedStatement.setString(3,message.message);
            // 4.执行sql语句
            count = preparedStatement.executeUpdate();
            // 5.处理结果
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            DBUtil.close(connection, preparedStatement, null);
        }
        return count;
    }
    private List<Message> load(){
        // 从数据库查询表白信息,把每条信息都放进这个集合里
        List<Message> messageList = new ArrayList<>();

        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        try {
            // 1.获取连接
            connection = DBUtil.getConnection();
            // 2.编写sql
            String sql = "select * from message";
            // 3.获取预编译对象,进行预编译
            preparedStatement = connection.prepareStatement(sql);
            // 4.执行sql语句
            resultSet = preparedStatement.executeQuery();
            // 5.处理结果集
            while (resultSet.next()){
                Message message = new Message();
                message.from = resultSet.getString("from");
                message.to = resultSet.getString("to");
                message.message = resultSet.getString("message");

                messageList.add(message);
            }

        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            DBUtil.close(connection, preparedStatement, resultSet);
        }
        return messageList;
    }
    private int delete(Message message){
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        int count = 0;
        try {
            // 1.获取连接
            connection = DBUtil.getConnection();
            // 2.编写sql
            String sql = "delete from message where `from` = ? and `to` = ? and message = ?";
            // 3.获取预编译对象,进行预编译
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setString(1, message.from);
            preparedStatement.setString(2, message.to);
            preparedStatement.setString(3, message.message);
            // 4.执行sql语句
            count = preparedStatement.executeUpdate();
            // 5.处理结果

        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            DBUtil.close(connection, preparedStatement, null);
        }
        return count;
    }
}

使用 DBUtil.java类作为工具类,用来封装数据库连接的过程

package util;

import com.mysql.cj.jdbc.MysqlDataSource;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

// DBUtil作为一个工具类,通过这个类,把数据库连接过程封装一下
public class DBUtil {
    // 数据源是单例,饿汉模式创建mysql数据源
    private static DataSource dataSource = new MysqlDataSource();

    static {
        // 使用静态代码块, 对 dataSource初始化
        // 理解:这里的Url中的 jdbc:mysql是协议名称,其后跟ip和端口,然后是数据库 + query string
        ((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/myProject?characterEncoding=utf8&useSSL=false");
        ((MysqlDataSource)dataSource).setUser("root");
        ((MysqlDataSource)dataSource).setPassword("xxx");//写你自己的数据库密码哦
    }

    // 获取数据库连接对象
    public static Connection getConnection() throws SQLException {
        return dataSource.getConnection();
    }

    // 关闭资源封装
    public static void close(Connection connection, PreparedStatement preparedStatement, ResultSet resultSet){
        if(resultSet != null){
            try {
                resultSet.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if (preparedStatement != null){
            try {
                preparedStatement.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if (connection != null){
            try {
                connection.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }
}

四、成果展示

1、输入:
输入表白信息(提交两份表白信息):
在这里插入图片描述
点击提交:
在这里插入图片描述
在这里插入图片描述

数据库中:
在这里插入图片描述

2、查询
提交表白信息后,重启服务器,输入地址,可以查询到之前提交的表白信息
在这里插入图片描述
会先展示出页面,过一小段时间后,就从数据库中查询出来,展示在页面上了
在这里插入图片描述

3、重置
点击重置后,页面中可以看到删除了最后一条表白信息:
在这里插入图片描述

数据库中:
在这里插入图片描述

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

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

相关文章

变现 起航篇! 手把手交你用chatgpt快速生成视频!

Chatgpt 很多同学都用的非常熟练了&#xff0c;但是都停留在文字阶段&#xff0c;有没有更好玩的用法&#xff0c;可以深度的利用chatgpt做一些事情呢&#xff1f; 今天菜哥就找一个方法可以快速利用chatgpt制作视频&#xff0c;整个过程大概3分钟&#xff0c;非常有趣&#xf…

浪涌保护器的工作类型及其应用

所有电路系统中的电气设备都需要浪涌保护器的保护支持。这主要取决于器件的内部电路如何能够处理电压波动。如果器件出现输入电压波动&#xff0c;则会导致器件损坏&#xff0c;因为电源电压的波动可能对器件有害。在本文中&#xff0c;我们将了解什么是浪涌保护器&#xff0c;…

【源码+个人总结】Spring 的 三级缓存 解决 循环依赖

Spring可以通过以下方法来避免循环依赖&#xff1a; 构造函数注入&#xff1a;使用构造函数注入来注入依赖项&#xff0c;这是一种比较安全的方式&#xff0c;因为在对象创建时就会注入依赖项&#xff0c;可以避免循环依赖。 Setter方法注入&#xff1a;使用Setter方法注入依赖…

云开发谁是卧底线下小游戏发牌助手微信小程序源码

源码下载&#xff1a;https://download.csdn.net/download/m0_66047725/87614365 云开发谁是卧底线下小游戏源码&#xff0c;发牌助手微信小程序源码。 “谁是卧底OL”是一个非常有趣&#xff0c;风靡全国的比拼语言表述能力、知识面与想象力的游戏。 谁是卧底OL是一款由开发…

Notepad++下载安装NppFTP插件

文章目录 一、Notepad内下载安装NppFTP插件1.打开Notepad——插件——插件管理2.找到NppFTP插件——点击安装3.安装完成 二、直接下载安装NppFTP插件1.网盘下载2.将下载好的NppFTP插件放入到Notepad\plugins的插件目录下3.重启Notepad 三、Notepad下载总结 一、Notepad内下载安…

【刷题】142. 环形链表 II

142. 环形链表 II 一、题目描述二、示例三、实现3.1 方法13.2 方法2 142. 环形链表 II 一、题目描述 给定一个链表的头节点 head &#xff0c;返回链表开始入环的第一个节点。 如果链表无环&#xff0c;则返回 null。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 nex…

前端学习 - 淼哥学Vue

如何判断数据是否受Vue管理&#xff0c;数据&#xff08;对象&#xff0c;数组&#xff0c;字符串等&#xff09;能否响应式更新&#xff1f; 即查看数据是否有对应get/set方法&#xff0c;数组没有对应get/set方法&#xff0c;故操作数组要通过其封装好的变更方法 变更方法 …

js高级知识汇总一

目录 1.怎么理解闭包&#xff1f; 2.闭包的作用&#xff1f; 3.闭包可能引起的问题&#xff1f; 4.变量提升 5.函数动态参数 6.剩余参数 ...&#xff08;实际开发中提倡使用&#xff09; 7.展开运算符 8.箭头函数 9.解构赋值&#xff08;数组、对象&#xff09; 10 创…

一文总结动态规划

动态规划 一、背包问题1 问题定义2 问题分类3 解题模板01背包最值问题剩余背包问题 4 例题分析LeetCode1049.最后一块石头的重量II 二、区间动态规划1 解题模板2 例题分析牛客.石子合并 总结与分析 一、背包问题 1 问题定义 如何确定一个题目是否可以用背包问题解决 背包问题…

给儿童使用护眼台灯怎么样选择更好?专家建议孩子买台灯

随着娃越长越大&#xff0c;虽然还在读幼儿园&#xff0c;但平时免不了要写写画画&#xff0c;之前一直在这个桌子上&#xff0c;台灯是一个赠送的LED货色&#xff0c;那个频闪啊&#xff0c;于是趁着当地商场活动先入了张学习桌椅&#xff0c;至于台灯嘛当然要选个好的了&…

21财经专访徐亚波博士:AI恒纪元时代,数说故事踏浪新征途

21世纪经济报道【创业投资】栏目&#xff0c;一直致力于寻找中国最有生命力和创造力的快速成长公司&#xff0c;探秘其背后的新兴资本推动力。为此&#xff0c;数说故事创始人兼CEO徐亚波博士接受了21世纪经济报道的专访。 近年来&#xff0c;大数据产业已经成为推动数字经济发…

【C语言】都玩过三子棋游戏把,但你知道怎么用C语言实现三子棋游戏吗?让我来手把手教你。

三子棋游戏 1.前言2.功能分析2.1主函数设计及菜单设计2.2打印棋盘与棋盘初始化2.3玩家下棋2.4电脑下棋2.5判断输赢 3.game.h头文件展示4.text.c源文件文件展示5.game.c源文件文件展示 所属专栏&#xff1a;C语言 博主首页&#xff1a;初阳785 代码托管&#xff1a;chuyang785 感…

Android 开发中高阶函数的 10 个实例

Android 开发中高阶函数的 10 个实例 Kotlin 是一种现代编程语言&#xff0c;由于其表现力、简洁性和多功能性而变得越来越流行。它的关键特性之一是支持高阶函数&#xff0c;这使您可以编写更简洁、更灵活的代码。高阶函数是一种将一个或多个函数作为参数或返回一个函数作为结…

python+java+nodejs基于vue的企业人事工资管理系统

根据系统功能需求分析&#xff0c;对系统功能的进行设计和分解。功能分解的过程就是一个由抽象到具体的过程。 作为人事数据库系统&#xff0c;其主要实现的功能应包括以下几个模块&#xff1a; 1.登录模块 登录模块是由管理员、员工2种不同身份进行登录。 2.系统管理模块 用户…

工具抓包Charles配置HTTPS步骤

charles抓取HTTPS设置&#xff0c;详细踩坑版 写这篇文章的背景就是&#xff0c;每次我在一台新电脑上用charles抓包时&#xff0c;总是因为各种原因无法抓到https请求&#xff0c;每个百度出来的回答又不是那么详细&#xff0c;需要通过几篇回答才能解决过程中的各种问题&…

C++程序员的职业前景怎么样?来谈谈我自己的想法

我之前提到了程序员在二线城市的大概待遇。今天&#xff0c;我要说一下普通程序员的职业前景。因为最初阶段的工资可能比较高&#xff0c;但如果没有可持续性&#xff0c;这就不是一个特别好的工作。 从我自身的经验来看&#xff0c;我们公司的程序员主要有两条路线。一条是纯…

【存储数据恢复】NetApp存储WAFL文件系统数据恢复案例

存储数据恢复环境&#xff1a; NetApp存储设备&#xff0c;WAFL文件系统&#xff0c;底层是由多块硬盘组建的raid磁盘阵列。 存储故障&#xff1a; 工作人员误操作导致NetApp存储内部分重要数据被删除。 存储数据恢复过程&#xff1a; 1、将存储设备的所有磁盘编号后取出&…

软考A计划-常用公式复习

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例 &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff0c;以及各种资源分享&am…

使用Nginx做反向代理

使用Nginx做反向代理 文章目录 使用Nginx做反向代理代理HTTP请求代理HTTPS请求举个大栗子 代理HTTP请求 按照以下步骤使用Nginx做反向代理&#xff1a; 编辑 Nginx 的配置文件。默认情况下&#xff0c;Nginx 的配置文件位于 /etc/nginx/nginx.conf。 sudo nano /etc/nginx/ngi…

1703_LibreOffice常用功能使用体验

全部学习汇总&#xff1a; GreyZhang/windows_skills: some skills when using windows system. (github.com) 首先需要说明的是我不是一个重度Office用户&#xff0c;甚至算不上一个重度的Office用户。我使用的Office软件最多的功能就是文档编辑&#xff0c;绝大多数时候还是文…