【学习笔记】手写 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.mzph.cn/news/880572.shtml

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

相关文章

Python 算法交易实验89 QTV200日常推进-模式思考

说明 过去几天大A的表现还是比较戏剧化的。 让我想到了&#xff1a; 1 价稳量缩模式。之前很长一段时间都是这种状态&#xff0c;最终还是大爆发了&#xff0c;这个可取。2 周期模式。假设价格是一个周期为T(T可变)的正弦波&#xff0c;所以最终还是回到了几个月前的位置&…

UE学习篇ContentExample解读------Blueprints Advanced-下

文章目录 总览描述批次阅览2.1 Timeline animation2.2 Actor tracking2.3 Button Trigger using a blueprint interface2.4 Opening door with trigger2.5 Child Blueprints 概念总结致谢&#xff1a; 总览描述 打开关卡后&#xff0c;引入眼帘的就是针对关卡的总体性文字描述&…

物联网系统中基于IIC通信的数字温度传感器测温方案

01 物联网系统中为什么要使用数字式温度传感器芯片 物联网系统中使用数字式温度传感器芯片的原因主要有以下几点&#xff1a; 高精度与稳定性 高精度测量&#xff1a;数字式温度传感器芯片&#xff0c;如DS18B20&#xff0c;采用芯片集成技术&#xff0c;能够有效抑制外界不…

算法宝典——二分查找算法

1.认识二分查找 二分查找的时间复杂度:O(logN) 二分查找属于算法中耳熟能详的一类&#xff0c;通常的我们会说只有数组有序才可以使用二分查找&#xff0c;不过这种说法并不完全正确&#xff0c;只要数据具有"二段性"就可以使用二分查找&#xff0c;即我们可以找出一…

【零散技术】Odoo PDF 打印问题问题合集

序言:时间是我们最宝贵的财富,珍惜手上的每个时分 Odoo PDF打印 是一个必备功能&#xff0c;但是总会遇到一些奇奇怪怪的问题&#xff0c;此帖仅做记录&#xff0c;方便查阅。 目录 1、样式丢失 2、部分结构丢失 3、没有中文字体 1、样式丢失 这种情况一般是由于 …

ppt压缩有什么简单方法?压缩PPT文件的几种方法

ppt压缩有什么简单方法&#xff1f;许多用户常常面临文件过大的问题&#xff0c;尤其在需要通过电子邮件发送或上传至网络平台时&#xff0c;大文件会带来诸多麻烦。此外&#xff0c;较大的文件可能导致软件响应缓慢&#xff0c;从而影响整体的演示体验。因此&#xff0c;寻找有…

C++ 基础入门-命名空间、c++的输入输出、缺省参数、函数重载、引用、内联函数超详细讲解

这篇文章主要对c的学习做一个基础铺垫&#xff0c;方便后续学习。主要通过示例讲解命名空间、c的输入输出cout\cin&#xff0c;缺省参数、函数重载、引用、内联函数&#xff0c;auto关键字&#xff0c;for循环&#xff0c;nullptr以及涉及到的周边知识&#xff0c;面试题等。为…

机械键盘驱动调光DIY--【DAREU】

1 下载键盘对应的驱动&#xff0c;不要装到C盘 达尔优驱动下载中心 2 驱动更改教程 标准模式 键盘功能 鼠标功能 切换灯光 切换配置文件 多媒体 windows快捷键 禁用 Fn 启动程序 文本功能 光标定位 FN模式 灯光效果设置 注意 宏--自定义功能

面试扩展知识点

1.C语言中分为下面几个存储区 栈(stack): 由编译器自动分配释放堆(heap): 一般由程序员分配释放&#xff0c;若程序员不释放&#xff0c;程序结束时可能由OS回收全局区(静态区): 全局变量和静态变量的存储是放在一块的&#xff0c;初始化的全局变量和静态变量在一块区域&#…

用于探索和测试API的开源IDE工具-Bruno

1、前言 在进行软件开发与测试过程中&#xff0c;无论是开发人员还是测试人员&#xff0c;都会或多或少地进行接口调试与接口测试。尤其针对那种测试流程规范性很高的项目&#xff0c;测试人员进行接口测试是不可或缺的一部分。而这其中&#xff0c;大多数都会使用 Postman 作…

9.26 Buu俩题解

[CISCN2019 华东北赛区]Web2 看wp写完之后写的 知识点 存储型XSS与过滤绕过sql注入 题解 好几个页面&#xff0c;存在登录框可以注册&#xff0c;存在管理员页面(admin.php) ->既然存在管理员页面&#xff0c;且直接访问admin.php提示我们 说明存在身份验证&#xff0…

crypto-js解密报错malformed utf-8 data

在进行加解密处理时出现这个问题。 但是当在一个完整程序运行环境内加密字符串&#xff0c;解密字符串是没问题的。 当把加密的字符存储到txt文件&#xff0c;在读取解密时出现错误无法解密。 最后&#xff0c;使用res.replace(/\s/g,‘’)正则过滤掉txt文件内的空格就成功了。…

若依生成主子表

一、准备工作 确保你已经部署了若依框架&#xff0c;并且熟悉基本的开发环境配置。同时&#xff0c;理解数据库表结构对于生成代码至关重要。 主子表代码结构如下&#xff08;字表中要有一个对应主表ID的字段作为外键&#xff0c;如下图的customer_id&#xff09; -- ------…

SOCKS5代理和HTTP代理哪个快?深度解析两者的速度差异

在现代互联网环境中&#xff0c;使用代理IP已经成为了许多人日常生活和工作的必备工具。无论是为了保护隐私&#xff0c;还是为了访问某些特定资源&#xff0c;代理IP都扮演着重要的角色。今天&#xff0c;我们就来聊聊SOCKS5代理和HTTP代理&#xff0c;看看这两者到底哪个更快…

【赵渝强老师】K8s中的Deployment控制器

K8s的Deployment将Pod部署成无状态的应用程序&#xff0c;它只关心Pod的数量、Pod更新方式、使用的镜像和资源限制等。由于是无状态的管理方式&#xff0c;因此Deployment中没有角色和顺序的概念&#xff0c;换句话说&#xff1a;Deployment中没有状态。   通过使用Deploymen…

UART 如何实现波特率自动检测原理介绍

为什么需要波特率自动检测机制 我们都知道&#xff0c;串口通讯是需要约定波特率才能够进行准确的通讯。此时假设&#xff0c;你们公司开发了一个板子&#xff0c;有一个串口与外接设备进行通讯。因为你们公司开发的产品要提供给多个客户&#xff0c;而有些客户可能之前就有一…

MacOS Catalina 从源码构建Qt6.2开发库之02: 配置QtCreator

安装Qt-creator-5.0.2 在option命令中配置Qt Versions指向 /usr/local/bin/qmake6 Kits选入CLang

SSM+Vue社区物业管理系统

目录 1 项目介绍2 项目截图3 核心代码3.1 Controller3.2 Service3.3 Dao3.4 spring-mybatis.xml3.5 spring-mvc.xml3.5 Vue 4 数据库表设计5 文档参考6 计算机毕设选题推荐7 源码获取 1 项目介绍 博主个人介绍&#xff1a;CSDN认证博客专家&#xff0c;CSDN平台Java领域优质创作…

【cache】浅析四种常用的缓存淘汰算法 FIFO/LRU/LFU/W-TinyLFU

本文浅析淘汰策略与工作中结合使用、选取&#xff0c;并非针对算法本身如何实现的 文章目录 FIFOLFULRUW-TinyLFU实践与优化监控与调整 FIFO first input first output &#xff0c; 先进先出&#xff0c;即最早存入的元素最先取出&#xff0c; 典型数据结构代表&#xff1a;…

Elasticsearch使用Easy-Es + RestHighLevelClient实现深度分页跳页

注意&#xff01;&#xff01;&#xff01;博主只在测试环境试了一下&#xff0c;没有发到生产环境跑。因为代码还没写完客户说不用弄了( •̩̩̩̩&#xff3f;•̩̩̩̩ ) 也好&#xff0c;少个功能少点BUG 使用from size的时候发现存在max_result_window10000的限制&…