【学习笔记】手写Tomcat 四

目录

一、Read 方法返回 -1 的问题

二、JDBC 优化

1. 创建配置文件

2. 创建工具类

3. 简化 JDBC 的步骤

三、修改密码

优化返回数据

创建修改密码的页面

注意

测试

四、优化响应动态资源

1. 创建 LoginServlet 类

2. 把登录功能的代码放到 LoginServlet 类

3. 创建LoginServlet 对象,调用service方法

五、作业

1. 每个 servlet 的 service 方法都是一样的,如何优化?

2. 如何再进一步优化 Servlet 


一、Read 方法返回 -1 的问题

在 上次的基础上,我们需要解决一下  read 读取到 -1 导致报错的问题

我们需要知道,为什么会读取到 -1?什么情况下会读取到 -1

read 方法返回 -1 有以下几种情况

1. 客户端 Socket 关闭(Socket.close)

2. 客户端关闭输出流,客户端在关流的时候,还多了一个往服务器写结束标记的动作,结束标记 -1 

3. 读取超时抛出异常,java 中的 Socket 默认没有超时限制

4. 读取文件时,到了文件的末尾,表示没有数据可读,也会返回 -1

那么如何解决呢?

很简单,判断读取到的是不是 -1 ,如果是 -1 直接 return 不用往下执行了

二、JDBC 优化

当前数据库连接信息都写在了代码里面,相对于硬编码,如果以后连接信息更改了,比如数据库连接地址,数据库密码等,那么所有关于JDBC 获取数据库连接的代码都需要修改

解决方案:

生成配置文件
通过Properties类去解析配置文件
创建一个DBPropUtils工具类来获取配置文件的信息

1. 创建配置文件

配置数据库连接信息

2. 创建工具类

获取配置文件的数据库连接信息

package com.shao.Utils;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Properties;
import java.util.Set;

public class DBPropUtil {
    private static HashMap<String, String> propMap = new HashMap<String, String>();

    static {
        Properties prop = new Properties();
        try {

            // 读取数据库配置文件
            // config 包名
            // DBConnection.properties 配置文件名
            prop.load(new FileInputStream("config" + File.separator + "DBConnection.properties"));

            // 获取所有的键
            Set<Object> keySet = prop.keySet();
            Iterator<Object> it = keySet.iterator();
            // 遍历 键的 Set 集合
            while (it.hasNext()) {
                // 把键转成字符串类型
                String key = (String) it.next();

                // 获取键对应的值
                String value = prop.getProperty(key);

                // 把键值对 添加到 map集合中
                propMap.put(key, value);
            }

        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    // 对外提供一个接口,通过key 获取对应的值
    public static String getProp(String key) {
        return propMap.get(key);
    }
}

3. 简化 JDBC 的步骤

创建 数据库连接类 获取连接,释放资源的方法也可以放到这个类里,这样可以简化响应类的代码

package com.shao.Utils;

import java.sql.*;

public class DBConnectUtil {

    /**
     *  静态代码块,当类被加载时,就会执行代码块,且只执行一次
     * */
    static {
        try {
            // 加载驱动
            Class.forName("com.mysql.cj.jdbc.Driver");

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    /**
     * 对外提供的方法,获取数据库连接
     */
    public static Connection getConnection() {
        Connection connection = null;
        try {
            connection = DriverManager.getConnection(
                    DBPropUtil.getProp("url"),
                    DBPropUtil.getProp("user"),
                    DBPropUtil.getProp("password"));

        } catch (SQLException e) {
            e.printStackTrace();
        }
        return connection;
    }


    /**
     * 释放资源
     */
    public static void releaseSource(Connection connection, PreparedStatement pstmt, ResultSet resultSet) {

        // 释放连接
        try {
            if (connection != null) {
                connection.close();
            }

        } catch (SQLException e) {
            e.printStackTrace();
        }

        //关闭预编译对象
        try {
            if (pstmt != null) {
                pstmt.close();
            }

        } catch (SQLException e) {
            e.printStackTrace();
        }

        //关闭结果集
        try {
            if (resultSet != null) {
                resultSet.close();
            }

        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

在响应类中调用方法获取数据库连接

测试

三、修改密码

登录功能有了,我们再练习一个修改密码的功能

和登录功能类似,因为我们封装了 JDBC 的获取数据库连接的操作,简化了JDBC,所以获取连接只需要调用工具类的方法就可以了

                Connection connection = null;
                PreparedStatement pstmt = null;
                int result = 0;

                try {
                    // 3. 获取数据库连接
                    connection = DBConnectUtil.getConnection();

                    // 4. 获取可执行对象
                    // 定义 SQL 语句
                    String SQL = "UPDATE train.users SET password = ? WHERE account = ?";
                    pstmt = connection.prepareStatement(SQL);

                    // 设置占位符的值
                    String account = httpRequest.getRequestBodyParams().get("account");
                    String password = httpRequest.getRequestBodyParams().get("password");

                    pstmt.setString(1, password);
                    pstmt.setString(2, account);

                    // 5. 执行sql语句,获取结果
                    result = pstmt.executeUpdate();

                    // 6. 结果处理
                    responseDTO responseDTO = null;

                    if (result > 0) {
                        responseDTO = new responseDTO(200, null, "修改成功");
                    } else {
                        responseDTO = new responseDTO(201, null, "修改失败");
                    }

                    // 调用方法返回数据
                    send(JSON.toJSONBytes(responseDTO));

                } catch (SQLException e) {
                    e.printStackTrace();
                } finally {
                    // 7. 释放资源
                    // 因为 更新,添加,删除 不需要结果集,所以不需要 resultSet,不用释放资源

                    DBConnectUtil.releaseSource(connection, pstmt, null);
                }

优化返回数据

我们现在返回的数据是字符串类型的,然后转成字节数组,这样的话,数据响应到客户端还是字符串格式,不方便解析数据,所以需要把要响应的数据转成 JSON 格式

如何转成 JSON 格式呢?

1. 添加第三方 jar 包

百度网盘 fastjson2

2. 使用

转成 JSON 格式,然后转成字节数组,因为可以直接转成字节数组,为了方便,我们把响应方法里接收数据的参数也改成字节数组类型

创建修改密码的页面

百度网盘 jquery 文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>修改密码</title>
    <script src="../static/js/jquery-3.5.1.min.js"></script>
</head>
<body>
<div>
    <div class="content">
        <input type="text" class="text-input" name="account" placeholder="请输入账号">
        <input type="text" class="text-input" name="password" placeholder="请输入新密码">
        <button type="button" class="submit-button">修改密码</button>
    </div>
    <div class="msg">
        <span class="success-msg"></span>
    </div>

</div>
</body>
<style>
    .content {
        margin: 0 auto;
        width: 300px;
    }

    .msg {
        margin: 0 auto;
        width: 300px;
    }

    .text-input {
        width: 200px;
        height: 30px;
        margin: 10px;
        padding: 5px;
        border: 1px solid #ccc;
    }

    .submit-button {
        width: 100px;
        height: 30px;
        margin: 10px;
        padding: 5px;
        border: 1px solid #ccc;
        cursor: pointer;
        border-radius: 5px;
        box-shadow: 0 0 1px #ccc;
    }
</style>
<script>
    document.querySelector('.submit-button').onclick = function () {
        console.log("点击了修改按钮")
        let username = document.querySelector('input[name="account"]').value;
        let password = document.querySelector('input[name="password"]').value;
        let data = {
            account: username,
            password: password,
        }
        $.ajax({
            url: 'http://127.0.0.1:8080/ChangePassword',
            type: 'POST',
            data: data,
            success: function (data) {
                console.log(data)
                data = JSON.parse(data)
                if (data.statusCode === 200) {
                    document.querySelector('.success-msg').innerHTML = data.msg;
                } else {
                    document.querySelector('.success-msg').innerHTML = data.msg;
                }
            }
        })
    }

</script>
</html>

注意

因为修改密码的页面有引用到 static 文件夹下的 js 文件夹的 jquery 文件,当页面在游览器打开后,会自动请求 jquery 文件,当请求到达后端时,我们给请求资源的路径加了  webs/pages 的前缀,这样的话,就会在 webs/pages/static/js 文件夹下找 jquery 文件,路径不对,所以获取不到

解决方案是,只保留 webs/ 前缀即可,这样资源的路径就正确了

测试

在游览器的地址栏中输入 http://127.0.0.1:8080/pages/changePassword.html

因为删除了 pages 前缀,所以请求 pages 文件夹下的资源文件都需要加上 pages

四、优化响应动态资源

现在的结构是响应动态资源的代码都写在了响应类里,这样的话,当后面加了很多功能,响应类的代码就会很多,一是不好维护,二是不利于协同开发

那怎么解决呢?

解决方案是一个功能做成一个 servlet 

1. 创建 LoginServlet 类

2. 把登录功能的代码放到 LoginServlet 类

package com.shao.Servlet;

import com.alibaba.fastjson2.JSON;
import com.shao.Utils.DBConnectUtil;
import com.shao.Utils.responseDTO;
import com.shao.net.HttpRequest;
import com.shao.net.HttpResponse;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

public class LoginServlet {

    Connection connection = null;
    PreparedStatement pstmt = null;
    ResultSet resultSet = null;
    responseDTO responseDTO = null;

    public void service(HttpRequest request, HttpResponse response) {
        if (request.getRequestMethod().equals("GET")) {
            doGet(request, response);
        } else if (request.getRequestMethod().equals("POST")) {
            doPost(request, response);
        }
    }

    public void doGet(HttpRequest request, HttpResponse response) {

        try {

            // 3. 获取数据库连接
            connection = DBConnectUtil.getConnection();

            // 4. 获取可执行对象
            String SQL = "select count(*) from train.users where account = ? and password = ?";
            pstmt = connection.prepareStatement(SQL);

            // 设置占位符的值
            String account = request.getRequestBodyParams().get("account");
            String pwd = request.getRequestBodyParams().get("password");

            pstmt.setString(1, account);
            pstmt.setString(2, pwd);

            // 5. 执行sql语句,获取结果集
            resultSet = pstmt.executeQuery();

            // 6. 结果处理
            if (resultSet.next() && resultSet.getInt(1) > 0) {
                responseDTO = new responseDTO(200, null, "登录成功");
            } else {
                responseDTO = new responseDTO(201, null, "登录失败,请检查账号和密码");
            }

            //调用方法返回数据
            response.send(JSON.toJSONBytes(responseDTO));

        } catch (Exception e) {
            e.printStackTrace();
        } finally {

            // 7. 释放资源
            DBConnectUtil.releaseSource(connection, pstmt, resultSet);
        }
    }

    public void doPost(HttpRequest request, HttpResponse response) {
        responseDTO = new responseDTO(400, null, "不支持POST提交方法");
        response.send(JSON.toJSONBytes(responseDTO));
    }
}

3. 创建LoginServlet 对象,调用service方法

五、作业

1. 每个 servlet 的 service 方法都是一样的,如何优化?

2. 如何再进一步优化 Servlet 

把Servlet 进一步划分为 Servlet 层,Service 业务逻辑层和 Dao 数据访问层

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【工具变量】科技金融试点城市DID数据集(2000-2023年)

时间跨度&#xff1a;2000-2023年数据范围&#xff1a;286个地级市包含指标&#xff1a; year city treat post DID&#xff08;treat*post&#xff09; 样例数据&#xff1a; 包含内容&#xff1a; 全部内容下载链接&#xff1a; 参考文献-pdf格式&#xff1a;https://…

Rust GUI框架 tauri V2 项目创建

文章目录 Tauri 2.0创建应用文档移动应用开发 Android 前置要求移动应用开发 iOS 前置要求参考资料 Tauri 2.0 Tauri 是一个构建适用于所有主流桌面和移动平台的轻快二进制文件的框架。开发者们可以集成任何用于创建用户界面的可以被编译成 HTML、JavaScript 和 CSS 的前端框架…

使用madExcept检测内存泄漏

代码异常堆栈跟踪&#xff1a;Mad Except 一、安装 官网 运行&#xff0c;选择madExcept5然后安装。 输入yes继续 二、使用 新建一个VCL项目 在project中多了一项设置 选择OK后会发现项目多了几个引用单元。 此时运行程序&#xff0c;再退出&#xff0c;会显示没有任何内存…

嵌入式入门小工程

此代码基于s3c2440 1.点灯 //led.c void init_led(void) {unsigned int t;t GPBCON;t & ~((3 << 10) | (3 << 12) | (3 << 14) | (3 << 16));t | (1 << 10) | (1 << 12) | (1 << 14) | (1 << 16);GPBCON t; }void le…

道路裂缝,坑洼,病害数据集-包括无人机视角,摩托车视角,车辆视角覆盖道路

道路裂缝&#xff0c;坑洼&#xff0c;病害数据集 包括无人机视角&#xff0c;摩托车视角&#xff0c;车辆视角 覆盖道路所有问题 一共有八类16000张 1到7依次为: [横向裂缝, 纵向裂缝, 块状裂缝, 龟裂, 坑槽, 修补网状裂缝, 修补裂缝, 修补坑槽] 道路病害&#xff08;如裂缝、…

CTC loss 博客转载

论文地址&#xff1a; https://www.cs.toronto.edu/~graves/icml_2006.pdf 为了对应这个图&#xff0c;我们假设一种符合的模型情况&#xff1a; 英文OCR&#xff0c;37个类别&#xff08;26个小写字母10个汉字空格&#xff09;&#xff0c;最大输出长度8个字符 模型预测结果…

使用 nvm 管理 node 版本:如何在 macOS 和 Windows 上安装使用nvm

&#x1f525; 个人主页&#xff1a;空白诗 文章目录 一、引言二、nvm的安装与基本使用2.1 macOS安装nvm2.1.1 使用 curl 安装2.1.2 使用 Homebrew 安装 2.2 Windows安装nvm2.2.1 下载 nvm-windows2.2.2 安装 nvm-windows 2.3 安装node2.4 切换node版本 三、常见问题及解决方案…

前端JavaScript导出excel,并用excel分析数据,使用SheetJS导出excel

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享今天给大家分享一篇文章&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f…

【C高级】有关shell脚本的一些练习

目录 1、写一个shell脚本&#xff0c;将以下内容放到脚本中&#xff1a; 2、写一个脚本&#xff0c;包含以下内容&#xff1a; 1、写一个shell脚本&#xff0c;将以下内容放到脚本中&#xff1a; 1、在家目录下创建目录文件&#xff0c;dir 2、dir下创建dir1和dir2 …

电商ISV 电商SaaS 是什么

Independent Software Vendors的英文缩写&#xff0c;意为“独立软件开发商” 软件即服务(SaaS) 指一种基于云技术的软件交付模式 订阅收费 这些公司叫做ISV软件供应商&#xff0c;通过SaaS服务交付收费 为什么会有电商ISV 从商家角度划分&#xff1a;有独立品牌商家、大商…

【2025】儿童疫苗接种预约小程序(源码+文档+解答)

博主介绍&#xff1a; ✌我是阿龙&#xff0c;一名专注于Java技术领域的程序员&#xff0c;全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师&#xff0c;我在计算机毕业设计开发方面积累了丰富的经验。同时&#xff0c;我也是掘金、华为云、阿里云、InfoQ等平台…

猫咪检测系统源码分享

猫咪检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer Vision …

R语言机器学习算法实战系列(二) SVM算法(Support Vector Machine)

文章目录 介绍原理应用方向下载数据加载R包导入数据数据预处理数据描述数据切割标准化数据设置参数训练模型预测测试数据评估模型模型准确性混淆矩阵模型评估指标ROC CurvePRC Curve特征的重要性保存模型总结系统信息介绍 支持向量机(Support Vector Machine,简称SVM)是一种…

跨站请求伪造(CSRF)漏洞详解

免责申明 本文仅是用于学习检测自己搭建的DVWA靶场环境有关CSRF的原理和攻击实验,请勿用在非法途径上,若将其用于非法目的,所造成的一切后果由您自行承担,产生的一切风险和后果与笔者无关;本文开始前请认真详细学习《‌中华人民共和国网络安全法》‌及其所在国家地区相关法…

java项目之在线考试与学习交流网页平台源码(springboot)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的在线考试与学习交流网页平台。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 项目简介&#xff1a; 基于JAVA语言…

ChatGPT搭上langchain的知识库RAG应用,效果超预期

最近利用LangchainChatGPT实现了上传文档实现个人知识库应用的能力&#xff0c;效果比想象得要好。文末大家可以体验一下效果~~ 给大家大致介绍下实现方式&#xff0c;参考了Langchain chatchat。 一、LangchainChatGPT 1、概述 LangChain 是一个强大的框架&#xff0c;可以…

飞驰云联FTP替代方案:安全高效文件传输的新选择

FTP协议广泛应用各行业的文件传输场景中&#xff0c;由于FTP应用获取门槛低、使用普遍&#xff0c;因此大部分企业都习惯使用FTP进行文件传输。然而面临激增的数据量和网络安全威胁的不断演变&#xff0c;FTP在传输安全性与传输性能上有所欠缺&#xff0c;无法满足企业现在的高…

光伏板缺陷红外检测数据集

光伏板缺陷红外检测数据集 包含以下4个数据文件&#xff1a; /train&#xff1a;训练集 /valid&#xff1a;验证集 /test&#xff1a;测试集 README.txt&#xff1a;数据说明 【数据说明】检测目标以Pascal VOC格式进行标注&#xff0c;对每个图像进行以下预处理&#xff0c;统…

Codeforces Round 974 (Div. 3) A-F

封面原图 画师礼島れいあ 下午的ICPC网络赛的难受一晚上全都给我打没了 手速拉满再加上秒杀线段树 这场简直了啊 唯一可惜的是最后还是掉出了1000名 一把上蓝应该没啥希望了吧 A - Robin Helps 题意 侠盗罗宾因劫富济贫而闻名于世 罗宾遇到的 n n n 人&#xff0c;从 1 s …

中泰免签,准备去泰国旅游了吗?《泰语翻译通》app支持文本翻译和语音识别翻译,解放双手对着说话就能翻译。

泰国是很多中国游客的热门选择&#xff0c;现在去泰国旅游更方便了&#xff0c;因为泰国对中国免签了。如果你打算去泰国&#xff0c;那么下载一个好用的泰语翻译软件是很有必要的。 简单好用的翻译工具 《泰语翻译通》App就是为泰国旅游设计的&#xff0c;它翻译准确&#x…