【项目-前后端交互-项目】表白墙【servlet实践】

news2024/11/25 19:46:23

【项目—前后端交互 案例】表白墙

    • 代码示例: 服务器版表白墙
        • 1. 准备工作
        • 2. 约定前后端交互接口
        • 3. 实现服务器端代码
            • 创建 Message 类
            • 创建 MessageServlet 类
        • 4. 调整前端页面代码
        • 5. 数据存入文件.
        • 6. 数据存入数据库
          • 1) 在 pom.xml 中引入 mysql 的依赖
          • 2) 创建数据库, 创建 messages 表
          • 3) 创建 DBUtil 类
          • 4) 修改 load 和 save 方法, 改成操作数据库
        • 代码总结
            • 1. pom.xml
            • 2. web.xml
            • 3. 表白墙.html
            • 4. DBUtil
            • 5. Message
            • 6. MessageServlet

先学习servlet

代码示例: 服务器版表白墙

结合上述 API, 我们可以把之前实现的表白墙程序修改成服务器版本. 这样即使页面关闭, 表白墙的内容也不会丢失.

1. 准备工作

  1. 创建 maven 项目.
  2. 创建必要的目录 webapp, WEB-INF, web.xml
<!DOCTYPE web-app PUBLIC
        "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
        "http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
    <display-name>Archetype Created Web Application</display-name>
</web-app>
  1. 调整 pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.example</groupId>
    <artifactId>表白墙服务器版</artifactId>
    <version>1.0-SNAPSHOT</version>
    <dependencies>
        <!-- 加入 servlet 依赖 -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <!-- servlet 版本和 tomcat 版本有对应关系,切记 -->
            <version>3.1.0</version>
            <!-- 这个意思是我们只在开发阶段需要这个依赖,部署到 tomcat 上时就不需要了 -->
            <scope>provided</scope>
        </dependency>
        <!-- 
https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -
->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.12.3</version>
        </dependency>
    </dependencies>
    <packaging>war</packaging>
    <build>
        <finalName>MessageWall</finalName>
    </build>
</project>
  1. 把之前实现的表白墙前端页面拷贝到 webapp 目录中.

2. 约定前后端交互接口

所谓 “前后端交互接口” 是进行 Web 开发中的关键环节.
具体来说, 就是允许页面给服务器发送哪些 HTTP 请求, 并且每种请求预期获取什么样的 HTTP 响应

  1. 获取全部留言
    在这里插入图片描述
    我们期望浏览器给服务器发送一个 GET /message 这样的请求, 就能返回当前一共有哪些留言记录. 结果以 json 的格式返回过来.

  2. 发表新留言

请求: body 也为 JSON 格式.

在这里插入图片描述
我们期望浏览器给服务器发送一个 POST /message 这样的请求, 就能把当前的留言提交给服务

3. 实现服务器端代码

创建 Message 类
public class Message {
    public String from;
    public String to;
    public String message;
}
创建 MessageServlet 类
@WebServlet("/message")
public class MessageServlet extends HttpServlet {
    // 用于保存所有的留言
    private List<Message> messages = new ArrayList<Message>();
    // 用于转换 JSON 字符串
    private ObjectMapper objectMapper = new ObjectMapper();
    // 获取所有留言
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
throws ServletException, IOException {
        resp.setContentType("application/json;charset=utf-8");
        String respString = objectMapper.writeValueAsString(messages);
        resp.getWriter().write(respString);
   }
    // 新增留言
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) 
throws ServletException, IOException {
        resp.setContentType("application/json;charset=utf-8");
        Message message = objectMapper.readValue(req.getInputStream(), 
Message.class);
        messages.add(message);
        resp.getWriter().write("{ \"ok\": 1 }");
   }
}
  • ObjectMapper 的 readValue 方法也能直接从一个 InputStream 对象读取数据.
  • ObjectMapper 的 writeValueAsString 方法也能把一个对象数组直接转成 JSON 格式的字符串

4. 调整前端页面代码

修改 “表白墙.html”

  1. 拷贝之前封装好的 ajax 函数
// 把之前封装的 ajax 函数拷贝过来
function ajax(args) {
 // ...... 代码内容参考 HTTP 协议章节
}
  1. 新加 load 函数, 用于在页面加载的时候获取数据
// 从服务器加载数据, 显示在界面上
function load() {
    ajax({
        url: 'message',
        method: 'GET',
        callback: function (data, status) {
            // 先把字符串格式的 body 转成 对象数组
            let messages = JSON.parse(data);
            // 把每个消息都构造一个 HTML 标签
            for (let message of messages) {
                var row = document.createElement('div');
                row.className = 'row';
                row.innerHTML = message.from + '对' + message.to + '说: ' +
message.message;
                // 3. 把构造好的元素添加进去
                var container = document.querySelector('.container');
                container.appendChild(row);
           }
       }
   });
}
// 调动 load 执行数据加载
load();
  1. 修改原来的点击事件回调函数. 在点击按钮的时候同时给服务器发送消息.
// 给点击按钮注册点击事件
var submit = document.querySelector('.submit');
submit.onclick = function () {
 // ...... 前面的代码略, 参考 JavaScript(WebAPI) 章节.
    // 给服务器发送消息
    ajax({
        method: "POST",
        url: "message",
        contentType: "application/json; charset=utf-8",
        body: JSON.stringify({ from: from, to: to, message: message }),
        callback: function (data, status) {
            if (status == 200) {
                console.log("提交消息成功!");
           } else {
                console.log("提交消息失败! " + status);
           }
       }
   });
}

此时在浏览器通过 URL http://127.0.0.1:8080/MessageServlet/表白墙.html 访问服务器, 即可看到

此时我们每次提交的数据都会发送给服务器. 每次打开页面的时候页面都会从服务器加载数据. 因此及时关闭页面, 数据也不会丢失.

但是数据此时是存储在服务器的内存中 ( private List messages = new ArrayList(); ), 一旦服务器重启, 数据仍然会丢失

5. 数据存入文件.

针对上面的问题, 如果把数据保存在文件中, 那么重启服务器也不会丢失数据了…

修改 MessageServlet 代码.

  • 删掉之前的 messages 成员.
  • 创建新的成员 String filePath, 表示要存储的文件的路径.
  • 新增 load 方法, 用来从文件中读取内容. (会在页面加载的时候调用 load)
  • 新增 save 方法, 用来往文件中写入内容. (会在提交留言的时候调用 save)
  • 文件格式按照 行文本 的方式存储. 每个记录占用一行, 每个记录的字段之间(from, to, message) 使用 \t 分隔.

文件格式形如:
在这里插入图片描述

@WebServlet("/message")
public class MessageServlet extends HttpServlet {
    // 用于保存所有的留言
    // private List<Message> messages = new ArrayList<Message>();
    // 用于转换 JSON 字符串
    private ObjectMapper objectMapper = new ObjectMapper();
    // 数据文件的路径
    private String filePath = "d:/messages.txt";
    public List<Message> load() {
        List<Message> messages = new ArrayList<>();
        System.out.println("从文件读取数据");
        try (BufferedReader bufferedReader = new BufferedReader(new
FileReader(filePath))) {
            while (true) {
                String line = bufferedReader.readLine();
                if (line == null) {
                    break;
               }
                String[] tokens = line.split("\t");
                Message message = new Message();
                message.from = tokens[0];
                message.to = tokens[1];
                message.message = tokens[2];
                messages.add(message);
           }
       } catch (IOException e) {
            // 首次运行的时候文件不存在, 可能会在这里触发异常.
            e.printStackTrace();
       }
        System.out.println("共读取数据 " + messages.size() + " 条!");
        return messages;
   }
    public void save(Message message) {
        System.out.println("向文件写入数据");
        // 使用追加写的方式打开文件
        try (FileWriter fileWriter = new FileWriter(filePath, true)) {
            fileWriter.write(message.from + "\t" + message.to + "\t" +
message.message + "\n");
       } catch (IOException e) {
            e.printStackTrace();
       }
   }
    // 获取所有留言
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
throws ServletException, IOException {
        List<Message> messages = load();
        resp.setContentType("application/json;charset=utf-8");
        String respString = objectMapper.writeValueAsString(messages);
        resp.getWriter().write(respString);
   }
    // 新增留言
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) 
throws ServletException, IOException {
        resp.setContentType("application/json;charset=utf-8");
        Message message = objectMapper.readValue(req.getInputStream(), 
Message.class);
        save(message);
        resp.getWriter().write("{ \"ok\": 1 }");
   }
}

此时即使重启服务器, 留言数据也不会丢失了.

6. 数据存入数据库

使用文件的方式存储留言固然可行, 但是并不优雅.
我们还可以借助数据库完成存储工作.

1) 在 pom.xml 中引入 mysql 的依赖
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.45</version>
</dependency>
2) 创建数据库, 创建 messages 表
set character_set_database=utf8;
set character_set_server=utf8;
create database if not exists MessageWall;
use MessageWall;
drop table if exists messages;
create table messages (`from` varchar(255), `to` varchar(255), `message` 
varchar(2048));
3) 创建 DBUtil 类

DBUtil 类主要实现以下功能:

  • 创建 MysqlDataSource 实例, 设置 URL, username, password 等属性.
  • 提供 getConnection 方法, 和 MySQL 服务器建立连接.
  • 提供 close 方法, 用来释放必要的资源.
// 负责和数据库建立连接
public class DBUtil {
    private static final String URL = "jdbc:mysql://127.0.0.1:3306/MessageWall?
characterEncoding=utf8&useSSL=false";
    private static final String USERNAME = "root";
    private static final String PASSWORD = "";
    private static DataSource dataSource = null;
    private static DataSource getDataSource() {
        if (dataSource == null) {
            synchronized (DBUtil.class) {
                if (dataSource == null) {
                    dataSource = new MysqlDataSource();
                   ((MysqlDataSource)dataSource).setUrl(URL);
                   ((MysqlDataSource)dataSource).setUser(USERNAME);
                   ((MysqlDataSource)dataSource).setPassword(PASSWORD);
               }
           }
       }
        return dataSource;
   }
    public static Connection getConnection() {
        try {
            return getDataSource().getConnection();
       } catch (SQLException e) {
            e.printStackTrace();
       }
        return null;
   }
    public static void close(Connection connection,
                             PreparedStatement statement,
                             ResultSet resultSet) {
        try {
            if (resultSet != null) {
                resultSet.close();
           }
            if (statement != null) {
                statement.close();
           }
            if (connection != null) {
                connection.close();
           }
       } catch (SQLException e) {
            e.printStackTrace();
       }
   }
}
4) 修改 load 和 save 方法, 改成操作数据库
private List<Message> load() {
    List<Message> messages = new ArrayList<>();
    // 1. 和数据库建立连接
    Connection connection = DBUtil.getConnection();
    PreparedStatement statement = null;
    ResultSet resultSet = null;
    try {
        // 2. 拼装 SQL
        String sql = "select * from messages";
        statement= connection.prepareStatement(sql);
        // 3. 执行 SQL
        resultSet = statement.executeQuery();
        // 4. 遍历结果集合
        while (resultSet.next()) {
            Message message = new Message();
            message.from = resultSet.getString("from");
            message.to = resultSet.getString("to");
            message.message = resultSet.getString("message");
            messages.add(message);
       }
   } catch (SQLException e) {
        e.printStackTrace();
   } finally {
        // 5. 释放必要的资源
        DBUtil.close(connection, statement, resultSet);
   }
    return messages;
}
private void save(Message message) {
    // 1. 和数据库建立连接
    Connection connection = DBUtil.getConnection();
    PreparedStatement statement = null;
    try {
        // 2. 拼装 SQL
        String sql = "insert into messages values(?, ?, ?)";
        statement = connection.prepareStatement(sql);
        statement.setString(1, message.from);
        statement.setString(2, message.to);
        statement.setString(3, message.message);
        // 3. 执行 SQL
        statement.executeUpdate();
   } catch (SQLException e) {
        e.printStackTrace();
   } finally {
        // 4. 释放必要的资源
        DBUtil.close(connection, statement, null);
   }
}

重新部署程序, 此时使用数据库之后也可以保证即使服务器重启, 数据也不丢失.

在这里插入图片描述

代码总结

1. pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>MessageWall</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.13.4.1</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.49</version>
        </dependency>

    </dependencies>

</project>
2. web.xml
<!DOCTYPE web-app PUBLIC
        "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
        "http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
    <display-name>Archetype Created Web Application</display-name>
</web-app>
3. 表白墙.html
<!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>
</head>
<body>
<style>
        .container {
            width: 400px;
            /* margin 外边距. 第一个数字上下外边距, 第二个数字表示水平外边距. 如果水平设置成 auto 表示元素就水平居中~~ */
            margin: 0 auto;
        }

        h1 {
            text-align: center;
        }

        p {
            text-align: center;
            color: #666;
        }

        .row {
            height: 40px;
            display: flex;
            /* 水平居中 */
            justify-content: center;
            /* 垂直居中 */
            align-items: center;
        }

        .row span {
            width: 100px;
        }

        .row input {
            width: 200px;
            height: 30px;
        }

        .row button {
            width: 306px;
            height: 40px;
            color: white;
            background: orange;
            border: none;
        }

        .row button:active {
            background-color: #666;
        }
    </style>

<div class="container">
    <h1>表白墙</h1>
    <p>输入后点击提交, 就会把信息显示在表格中</p>
    <div class="row">
        <span>谁: </span><input type="text">
    </div>
    <div class="row">
        <span>对谁: </span><input type="text">
    </div>
    <div class="row">
        <span>说: </span><input type="text">
    </div>
    <div class="row">
        <button>提交</button>
    </div>

    <!-- 需要构造出一个形如 -->
    <!-- <div class="row">
        黑猫 对 白猫 说: 喵
    </div> -->
</div>

<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>

<script>
        let container = document.querySelector('.container');
        let button = document.querySelector('button');
        button.onclick = function() {
            // 1. 获取到输入框的内容
            let inputs = document.querySelectorAll('input');
            let from = inputs[0].value;
            let to = inputs[1].value;
            let message = inputs[2].value;
            if (from == '' || to == '' || message == '') {
                alert('当前输入框内容为空!');
                return;
            }
            console.log(from + ", " + to + ", " + message);
            // 2. 能够构造出新的 div, 用来保存用户提交的内容
            let rowDiv = document.createElement('div');
            rowDiv.className = 'row';
            rowDiv.innerHTML = from + " 对 " + to + " 说: " + message;
            container.appendChild(rowDiv);
            // 3. 提交完之后, 清空输入框的内容
            for (let i = 0; i < inputs.length; i++) {
                inputs[i].value = '';
            }

            let data = {
                from: from,
                to: to,
                message: message
            };
            // 4. 点击发送按钮, 给服务器发个 post 请求.
            $.ajax({
                type: 'post',
                url: 'message',
                // url: '/java105/message',
                // 这里放的是 body 的内容
                data: JSON.stringify(data),
                contentType: "application/json; charset=utf8",
                success: function(body) {
                    console.log("提交数据成功");
                }
            });
        }

        // 直接写在 script 标签里的代码, 都是在页面加载的时候执行的.
        // 来获取服务器的数据
        function getMessages() {
            $.ajax({
                type: 'get' ,
                url: 'message',
                success: function(body) {
                    // body 就是响应的 body 内容, json 数组.
                    // jquery 非常智能的帮我们把 json 数组给解析成了 js 对象数组
                    // 但是有个前提条件, 就是响应的 Content-Type 得是 application/json
                    let container = document.querySelector('.container');
                    for (let i = 0; i < body.length; i++) {
                        let message = body[i];
                        // 根据这个元素构造一个 div.row, 来容纳数据
                        // <div class="row">
                        //     黑猫 对 白猫 说: 喵
                        // </div>
                        let row = document.createElement('div');
                        row.className = 'row';
                        row.innerHTML = message.from + " 对 " + message.to + " 说: " + message.message;
                        container.appendChild(row);
                    }
                }
            });
        }

        getMessages();
    </script>
</body>
</html>
4. DBUtil
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;

import javax.sql.DataSource;

// 使用这个类来封装 DataSource 的单例
public class DBUtil {
    private static volatile DataSource dataSource = null;

    public static DataSource getDataSource() {
        if (dataSource == null) {
            synchronized (DBUtil.class) {
                if (dataSource == null) {
                    dataSource = new MysqlDataSource();
                    ((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/java105?characterEncoding=utf8&useSSL=false");
                    ((MysqlDataSource)dataSource).setUser("root");
                    // 我这里的数据库是没密码的.
                    ((MysqlDataSource)dataSource).setPassword("");
                }
            }
        }
        return dataSource;
    }

    private DBUtil() {}
}
5. Message
public class Message {
    private String from;
    private String to;
    private String message;

    public String getFrom() {
        return from;
    }

    public void setFrom(String from) {
        this.from = from;
    }

    public String getTo() {
        return to;
    }

    public void setTo(String to) {
        this.to = to;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}
6. MessageServlet
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;

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 javax.sql.DataSource;
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;

@WebServlet("/message")
public class MessageServlet extends HttpServlet {
    // 这个对象在多个方法中都需要使用
    private ObjectMapper objectMapper = new ObjectMapper();

    // 负责让页面获取到数据
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 显式声明当前的响应数据格式 不要让客户端去猜!!!
        resp.setContentType("application/json; charset=utf8");
        // 把 messageList 转成 json 字符串, 并且返回给页面就行了.
        List<Message> messageList = null;
        try {
            messageList = load();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        resp.getWriter().write(objectMapper.writeValueAsString(messageList));
    }

    // 提交数据
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 获取到 body 中的数据并解析
        Message message = objectMapper.readValue(req.getInputStream(), Message.class);
        // 把这个 message 保存一下. 简单的办法就是保存在内存中.
        // messageList.add(message);
        try {
            save(message);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        resp.setStatus(200);

        System.out.println("提交数据成功: from=" + message.getFrom()
                + ", to=" + message.getTo() + ", message=" + message.getMessage());
    }

    private List<Message> load() throws SQLException {
        // 从数据库查询数据

        // 1. 先有一个数据源
        DataSource dataSource = DBUtil.getDataSource();

        // 2. 建立连接
        Connection connection = dataSource.getConnection();

        // 3. 构造 SQL
        String sql = "select * from message";
        PreparedStatement statement = connection.prepareStatement(sql);

        // 4. 执行 SQL
        ResultSet resultSet = statement.executeQuery();

        // 5. 遍历结果集合
        List<Message> messageList = new ArrayList<>();
        while (resultSet.next()) {
            Message message = new Message();
            message.setFrom(resultSet.getString("from"));
            message.setTo(resultSet.getString("to"));
            message.setMessage(resultSet.getString("message"));
            messageList.add(message);
        }

        // 6. 关闭连接
        statement.close();
        connection.close();
        return messageList;
    }

    private void save(Message message) throws SQLException {
        // 把数据保存到数据库中

        // 1. 先有一个数据源
        DataSource dataSource = DBUtil.getDataSource();

        // 2. 建立连接
        Connection connection = dataSource.getConnection();

        // 3. 构造 SQL
        String sql = "insert into message values(?, ?, ?)";
        PreparedStatement statement = connection.prepareStatement(sql);
        statement.setString(1, message.getFrom());
        statement.setString(2, message.getTo());
        statement.setString(3, message.getMessage());

        // 4. 执行 SQL
        int ret = statement.executeUpdate();
        System.out.println("ret = " + ret);

        // 5. 关闭连接
        statement.close();
        connection.close();
    }
}

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

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

相关文章

ModuleNotFoundError: No module named ‘Multiscaledeformableattention‘

在实现DINO Detection方法时&#xff0c;我们可能会遇到以上问题。因为在DeformableAttention模块&#xff0c;为了加速&#xff0c;需要自己去编译这个模块。 如果你的环境变量中能够找到cuda路径&#xff0c;使用正确的torch版本和cuda版本的话&#xff0c;这个问题很容易解…

代码随想录算法训练营第三十九天 | 不同路径(挺简单的)

62.不同路径 文档讲解&#xff1a;代码随想录 (programmercarl.com) 视频讲解&#xff1a;动态规划中如何初始化很重要&#xff01;| LeetCode&#xff1a;62.不同路径_哔哩哔哩_bilibili 状态&#xff1a;能直接做出来。 思路 机器人从(1 , 1) 位置出发&#xff0c;到(m, n)终…

对抗训练方法:保卫人工智能的盾牌

❤️觉得内容不错的话&#xff0c;欢迎点赞收藏加关注&#x1f60a;&#x1f60a;&#x1f60a;&#xff0c;后续会继续输入更多优质内容❤️ &#x1f449;有问题欢迎大家加关注私戳或者评论&#xff08;包括但不限于NLP算法相关&#xff0c;linux学习相关&#xff0c;读研读博…

【纳什博弈、ADMM】基于纳什博弈和交替方向乘子法的多微网主体能源共享研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

ch07-Pytorch的训练技巧

ch07-Pytorch的训练技巧 0.引言1.模型保存与加载1.1.序列化与反序列化1.2.PyTorch 中的模型保存与加载1.3.模型的断点续训练 2.模型 Finetune2.1.Transfer Learning & Model Finetune2.2.PyTorch中的Finetune 3.使用 GPU 训练模型3.1.CPU与GPU3.2.数据迁移至GPU3.3. 多 GPU…

mac下安装cnpm淘宝镜像

在mac安装cnpm时&#xff0c;输入npm install -g cnpm -registryhttps://registry.npm.taobao.org 报错&#xff1a; npm ERR! code EACCES npm ERR! syscall mkdir npm ERR! path /usr/local/lib/node_modules/cnpm npm ERR! errno -13 npm ERR! Error: EACCES: permission de…

单细胞 | label transfer with Seurat4(未知细胞映射到注释好的细胞图谱)

场景&#xff1a;把新的细胞比对到已经注释过的细胞集合上&#xff0c;获取映射后的细胞标签&#xff0c;UMP坐标。 准备&#xff1a; 一个分析好的单细胞图谱数据集&#xff0c;作为reference数据集。一个新的单细胞counts矩阵&#xff0c;记为 query数据集。 主要分为两个步…

在浏览器从输入URL到页面加载完成都经历了什么/一个完整的URL解析过程详细介绍

一、简述在浏览器从输入URL到页面加载完成都经历了什么 浏览器地址栏输入url地址&#xff0c;首先要在客户端上进行url解析 浏览器会首先查看自身的缓存&#xff0c;如果浏览器缓存中有对应的解析记录&#xff0c;直接返回结果 如果浏览器没有缓存&#xff0c;电脑会查看本地操…

Selenium+Unittest自动化测试框架实战(框架源码都给你)

目录 前言 项目框架 首先管理时间 !/usr/bin/env python3 -- coding:utf-8 -- 配置文件 conf.py config.ini# 读取配置文件 记录操作日志 简单理解POM模型 管理页面元素 封装Selenium基类 创建页面对象 熟悉unittest测试框架 编写测试用例 执行用例 生成测试报…

qemu-ARM篇——ARM 栈帧(一)

ARM 栈帧 本系列均已 corter-A7(armv7-a) 为例 在 ARM 中&#xff0c;通常为满减栈&#xff08;Full Descending FD&#xff09;, 也就是说&#xff0c;堆栈指针指向堆栈内存中最后一个填充的位置&#xff0c;并且随着每个新数据项被压入堆栈而递减。 栈的本质 要理解栈的本…

前端CSS学习(三)

1、盒子模型 盒子的概念1、页面中的每一个标签&#xff0c;都可看做是一 个“盒子” &#xff0c;通过盒子的视角更方便的进行布局2、浏览器在渲染 (显示)网页时&#xff0c;会将网页中的元素看做是一个个的矩形区域&#xff0c;我们也形象的称之为盒子CSS中规定每个盒子分别由…

BESV博世蔚发布2023全新款折叠e-bike —— F3,在中国自行车展会上大放异彩

BESV博世蔚身为跨界智慧出行的专家&#xff0c;今年在国内最大规模的中国国际自行车展上发布了其最新的e-bike折叠车款---VOTANI F3。拥有纯正荷兰血统的VOTANI系列车款&#xff0c;在设计外观上沿袭了欧风的极简主义和时尚设计&#xff0c;并搭配上折叠系统更易于携带和收纳。…

AnyStock JS Crack,AnyStock JS功能

AnyStock JS Crack,AnyStock JS功能 添加了新的技术指标-除了已经支持的几十个指标外&#xff0c;股票图表现在还提供了三个新的开箱即用技术指标&#xff1a; Aroon振荡器-通过从Aroon Up中减去Aroon Down&#xff0c;可以很容易地测量趋势的强度。 加权移动平均线(WMA)-通过更…

D-遗迹探险

牛客小白月赛 72 D 题目链接 链接&#xff1a;https://ac.nowcoder.com/acm/contest/56825/D 来源&#xff1a;牛客网 示例1 输入 3 3 1 2 3 4 5 6 7 8 9 2 2 1 1 3 3 3 1 1 1 3 3 1输出 58 41题解&#xff1a; 如果先不考虑传送门&#xff0c;这题就是一道简单dp 设状态 …

【后端随笔】mysql操作语句记录

sql语句不区分大小写 show bases&#xff1b; --号注释 /**/多行注释 DDL定义 DML删改 DQL查询 DCL权限控制语言 1、DDL操作数据库 &#xff08;1&#xff09;查询 SHOW DATABASES; (2)创建 CREATE DATABASES;//创建数据库 CREATE DATABASES IF NOT EXISTS 数据库名称&#xff…

stata学习笔记①stata基础介绍

文章目录 一、为什么要学stata二、软件基本解释1.软件界面2.导入示例数据3.认识几个重要的功能符号 三、数据的基本观测四、统计性描述1.codebook 数据字典使用2.summarize 五、图像初步探索1.histogram 直方图2.graph box /hbox 箱线图3.vioplot小提琴图 一、为什么要学stata …

JavaWeb:过滤器 Filter、监听器 Listener

文章目录 JavaWeb - 04一、Filter1. 概述2. 实现步骤3. 运行结果 二、Filter 应用&#xff1a;实现权限拦截1. 登录步骤2. 添加的过滤器部分3. 运行结果4. 总结 三、监听器注意&#xff1a; JavaWeb - 04 一、Filter 1. 概述 Filter&#xff1a;过滤器&#xff0c;可以用来过…

有用的知识又增加了:为何无法编译某些  WWDC 官方视频中的代码?

概览 作为 Apple 开发者而言&#xff0c;每期 WWDC 官方视频无疑是我们日常必看的内容。 不过&#xff0c;小伙伴们是否发现视频中有些示例代码在我们自己测试时却无法编译这一尴尬的情况呢&#xff1f; 在本篇博文中&#xff0c;我们将通过一则非常简单的示例来向大家展示为…

【Matlab】基于遗传算法的列车发车时刻(发车间隔)优化

【Matlab】基于遗传算法的列车发车时刻&#xff08;发车间隔&#xff09;优化 一、模型介绍&#xff08;一&#xff09;引言&#xff08;二&#xff09;符号定义&#xff08;三&#xff09;目标函数(四&#xff09;约束条件4.1到达乘客数量4.2乘客进站限制4.3乘客总数量&#x…