Tomcat And Servlet (1)

1. Tomcat

谈到 “汤姆猫”, 大家可能更多想到的是大名鼎鼎的这个:

在这里插入图片描述


事实上, Java 世界中的 “汤姆猫” 完全不是一回事, 但是同样大名鼎鼎

在这里插入图片描述


Tomcat 是一个 HTTP 服务器 , HTTP 协议就是 HTTP 客户端 和 HTTP 服务器之间通信使用的协议 , HTTP 客户端就是 浏览器 (当然也有别的) 。

HTTP 服务器 则有很多种实现 ,Tomcat 是 java 圈子中 , 最知名 ,最广泛使用的 http 服务器


下面就来 了解一下 Tomcat ,这里我们先来 安装他

2. 下载安装

图一 :

在这里插入图片描述


图二 :

在这里插入图片描述

3. 启动 Tomcat

在这里插入图片描述

4. 运行 Tomcat


我们使用 tomcat 最大的用途就是把我们写好的网站,给部署上去 , 一个网站 = 前端 + 后端 , 这里 先部署点前端的代码 , 来体验一下.


图一 :

在这里插入图片描述


图二 :

在这里插入图片描述


到此我们已经 看完了 Tomcat 安装 , Tomcat 启动 …


但是这只是开胃菜 ,我们学习 Tomcat 的最核心的目标是基于 tomcat 编程 ,做出一个网站来 .


下面就来学习 通过 tomcat 进行 网站 后端开发 , 网站后端 , http 服务器 肯定是需要针对 http 协议进行一系列操作的 , 幸运的是 tomcat

已经把 这些 http 协议相关的底层操作 封装好了 ,我们只需要调用 tomcat 给 提供的 api 即可

这里 tomcatjava 提供的原生进行 webapi 就称为 Servlet , 未来我们 可能还要接触一些框架 (spring 全家桶) Spring MVC 等

也是 进行 web 开发的 api (这组 api 也是基于 servlet 的 ,相当于 对 servlet 的封装)


题外话 :

关于 Servlet ,在企业中已经 几乎不会使用了, 就和 企业中 会不会使用 jdbc 是一样的 .

因为 spring 会比 Servlet 更好用 ,更简单 ,就好比 汽车 自动挡 和 手动挡的区别 ,那么 为啥还要学 Servlet 呢 ,

因为 Servlet 是未来学习框架的基础 , 我们将 基础打扎实了 那么 学习 框架 就会事半功倍 ,

另外 技术是在不停的进步的 ,新的技术体系是层出不穷的 ,这两年流行 spring ,

再过几年 是否有更好的框架代替 spring 是说不定的 。 但是 不管框架 咋样变化 ,

我们想要 使用 java 进行 web 开发 , Servlet 都是恒定不变的。

下面就来学习 Servlet

5. Servlet


Servlet 是 一种实现 动态页面的技术 , 是一组 Tomcat 提供给 程序猿的 API , 帮助程序猿 简单高效开发 一个 web app .


这里稍微说一下 : 动态页面


关于我们的 网页分为两类 :

  1. 静态页面 : 页面内容始终是固定不变的
  2. 动态页面 : 页面内容睡着输入参数的不同而改变

在这里插入图片描述


下面就来 写一个第一个 Servlet 程序 , 还是老规矩 写一个 Hello World .


这里需要 7 个步骤

  1. 创建项目
  2. 引入依赖
  3. 创建目录结构
  4. 编写代码
  5. 打包程序
  6. 部署程序
  7. 验证


看起来很繁琐 ,实际上 ,出来编写代码之外 ,剩下的步骤 都是固定的 (固定的意味着 , 我们多练习几遍就会了) , 正因为这里太麻烦了,后面要学习的 spring MVC 就是简化 这个开发过程的.

5.1 创建项目

这里我们需要创建一个 Maven 项目


Maven 是 个 “工具管理” 工具

  1. 规范目录结构
  2. 管理依赖 (使用了啥第三方库 , 都给处理好)
  3. 构建
  4. 打包
  5. 测试


本文就涉及到 管理依赖 , 和 打包 ,Maven 其他的功能 可以自己 去 了解一下 .


图一 :

在这里插入图片描述


图二 :

在这里插入图片描述


项目创建后,来完成第二个步骤 引入依赖

5.2 引入依赖


这里我们需要引入的 依赖 就是 Servlet 对应的 jar 包 .


这里我们可以在 中央仓库 去找 Servlet 对应的 jar 包 , 附上中央仓库 : Maven Repository: Search/Browse/Explore (mvnrepository.com)

在这里插入图片描述


到此第二步就完成了,下面来完成第三步 创建目录

5.3 创建目录


虽然 Maven 已经帮我们自动的创建了一些目录,但是还不够 ,此处是需要使用 Maven 开发一个 web 程序 , 还需要别的 目录 .

在这里插入图片描述

<!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>


提问 : 这里个 web.xml 有啥用 ?


答 :


当前 写的 servlet 程序 和以往写的 代码相比 有一个非常大的 区别, 没有 main 方法

main 方法 可以视为 是 汽车的发送机 ,有发送机才能跑 , r如果现在有辆车 ,没有发送机 ,能不能有办法跑 ?

是有办法的 , 比如 挂一个车头 ,拽着它跑就行了 , 比如 火车 , 有很多车厢 , 只有一个车头 ,当车头开起来的时候就可以拖着 车厢跑了 .

我们写的 servlet 程序 就是车厢 ,tomact 就是车头 , 我们把写好的 servlet 程序 放到 webapps 目录下 ,就相当于 把车厢给挂到车头后面了.

tomcat 如何识别 ,webapps 目录下 ,那些是需要拉着跑的车厢 ? 那些是普通的不需要拉着跑的目录呢 ?


就是靠 目录下的 WEB-INF 里面的 web.xml , 这个文件 就相当于 投名状 . Tomcat 大哥 ,小弟我以后跟着你混了. 此时 tomcat 就把我们写的代码加载并运行起来了 。

在这里插入图片描述

到此 目录就创建好, 下面来完成最核心的一步 编写代码

5.4 编写代码


图一 :

在这里插入图片描述


图二 :

在这里插入图片描述


代码编写完,下面来 完成第五步 打包程序

5.5 打包程序


打包程序 : 把程序编译好 (得到一些 .class 文件) , 再把这些 .class 达成 压缩包 .


jar 就是 一种 .class 构成的压缩包 , 但是这里我们需要打的是 war 包 .

jar 只是一个普通的 java 程序 ,war 则是 tomcat 专属的用来描述 webapp 的程序 ,一个 war 就是一个 webapp !!!


这里如何 打 war 包呢 ?

很简单直接通过 Mavne 就可以 打包了

在这里插入图片描述


到此我们的 第五步 打包操作就完成了 , 下面来完成第六步部署程序

5.6 部署程序


部署 : 把刚才打包号的 war 拷贝到 tomcat 的 webapps 目录 中即可 !!!

无论 tomcat 是 在 你的电脑上 还是不同电脑上,都是这样拷贝

在这里插入图片描述


到此 第六步就完成了, 下面来完成最后一步 启动 Tomcat ,验证我们的程序

5.7 验证程序


如果 tomcat 正在运行 ,直接拷贝 ,tomcat 也能识别 (这个识别操作可能存在 bug ,windows , 在 Linux 并不会) ,

实际工作中 ,tomcat 基本都是在 Linux 上运行的 , 所以这个小问题 ,不要太在意 ,如果你的没有识别,那么请重启 Tomcat

在这里插入图片描述


到此我们已经完成了 七步操作 , 别看 步骤很多 ,其实是很简单的, 多操作几遍 很快就熟悉了, 另外 大家有没有一种感觉, 上面的步骤是不是非常繁琐与麻烦 , 下面就来 简化 流程 .

6. 安装 Smart Tomcat 插件


图一 :

在这里插入图片描述


图二 :

在这里插入图片描述


安装完 SmartTomcat 后 ,我们就来使用他

7. 使用 SmartTomcat 插件


图一 :

在这里插入图片描述


图二 :

在这里插入图片描述


Smart Tomcat 工作原理

不是说自动把 war 包拷贝了 (webapps 里是不变的) , 是通过 另一种方式来启动 Tomcat 的 , Tomcat 支持启动的时候 显示指定一个 特定的 webapp 目录 , 相当于 让 Tomcat 加载 单个 webapp 运行 。

在这里插入图片描述


如果 觉得这一套有一点麻烦 , 没关系,等我们学习了 Spring , Spring Boot , Spring MVC , 后面在实现类似的功能就方便了.


到此 我们已经 基本入门了,下面来看看常见的错误 .

8. 常见错误

8.1 出现 404


404: 标识你要访问的资源在服务上 不存在 / 找不到


这里出现 404 主要 有两个方面

  1. 路径写错了
  2. 你的 webapp 没有被部署


路径写错了

在这里插入图片描述


webapp 没有被部署

在这里插入图片描述

8.2 出现 405


405 : Method Not Allowed 表示 对应的 HTTP 请求方法没有实现

在这里插入图片描述

8.3 出现 500


出现 500 是最好解决的 , 上面的 404 , 405 需要我们的经验 去猜哪里错了,而 500 会直接告诉你哪里错了. 500 本质上是代码抛出了异常 , 出现500 的时候 日志 中会明确的告诉你 异常调用栈,告诉你 哪一行代码出的问题

在这里插入图片描述

8.4 出现空白页面

在这里插入图片描述

8.5 出现 无法访问此网站

在这里插入图片描述


常见错误看完,下面我们来 看看 Servlet 中 常用的 API

9. 常用 Servlet API


关于 Servlet API 当前主要掌握 三个 类即可

  1. HttpServlet
  2. HttpServletRequest
  3. HttpServletResponse

9.1 HttpServlet

HttpServlet 核心方法

方法名称 调用时机
init 在 HttpServlet 实例化之后被调用一次
destory 在 HttpServlet 实例不再使用的时候调用一次
service 收到 HTTP 请求的时候调用
doGet 收到 GET 请求的时候调用(由 service 方法调用)
doPost 收到 POST 请求的时候调用(由 service 方法调用)
doPut/doDelete/doOptions/… 收到其他请求的时候调用(由 service 方法调用)

  1. init : tomcat 首次收到了和该类相关联的 请求 的时候 HttpServlet 才会实例化, 而不是 tomcat 一启动就立即实例化 . (类似于之前说过的懒汉模式) , HttpServlet 实例化后才会调用 init 方法

在这里插入图片描述

  1. destory : 在 HttpServlet 实例不在使用的时候调用 一次 (服务器终止的时候,调用) ,这个方法 就可以 做一些清理之类的工作

在这里插入图片描述

  1. service : 收到 http 请求就会触发 (路径匹配的请求) , 其实 我们的 doGet 就在 service 里调用 .

在这里插入图片描述


init , destroy , service 这三个方法 就是 HttpServlet 最关键的 三个方法 (虽然不太会直接用这几个,不会影响他们的重要性)


谈到上面这个 ,就可以引出一个典型的 面试题 : Servlet 的生命周期 是咋回事 ??


生命周期 : 粗浅的说法 ,一个东西啥时候来的, 啥时候没的就是 生命周期 , 进一步的理解 这个东西 什么 阶段,做啥事 , 这就是更加具体的生命周期 .

举个例子 : 一个人的生命周期

  1. 小的时候 , 要做的就是善学

  2. 长大了之后, 参加工作

  3. 再大点 ,要结婚 生娃

  4. 年纪再大 , 娃要上学了

  5. 年纪再大 ,让 娃结婚生娃

  6. 年纪再大 , 帮娃带娃

  7. 年纪再大 驾鹤西去 …


对应的到 Servlet 生命周期

  1. 开始的时候, 执行 init
  2. 每次收到请求执行 service
  3. 销毁之前 ,执行 destroy


如果后面 问到 xxx 的生命周期 , 其实就问你 , 这个东西在 每个 阶段 都在干啥 .


注意 : 一个 Servlet 程序 里面可以包含很多 Servlet ,某个 Servlet 的生死 ,不影响 整个 Servlet 程序

接下来的 几个 ,其实我们已经会用了, 之前使用的 是 doGet 方法来处理请求 , doPost 等方法都是差不多的 。


这里为了省心 ,下面就在来写一些代码看看 :


图一 :

在这里插入图片描述


图二 :

在这里插入图片描述


图三 :

在这里插入图片描述


再唠一句 :如果你通过上面的 ajax 发送请求 ,结果 访问 浏览器并没有发送,那么 有可能 是你修改了 type 后,并没有重写启动服务器, 此时服务器运行的还是旧的代码 .


如果你觉得 每次都重启 太麻烦 了 , 也是有办法的 ,只不过我现在不说 , 如果你就是不想那么麻烦, 那么你可以自己去搜索一下 如何开

启 热部署 , 关于 如何开启热部署 ,会在 spring 系列文章中提到 .


到此 HttpServlet 类我们就搞定了, 下面来看看 第二个类 HttpServletRequest

9.2 HttpServletRequest


HttpServletRequest 表示的是 HTTP 请求

在这里插入图片描述


HttpServletRequest 的核心方法

方法 描述
String getProtocol() 返回请求协议的名称和版本。
String getMethod() 返回请求的 HTTP 方法的名称,例如,GET、POST 或 PUT。
String getRequestURI() 从协议名称直到 HTTP 请求的第一行的查询字符串中,返回该请求的 URL 的一部分。
String getContextPath() 返回指示请求上下文的请求 URI 部分。
String getQueryString() 返回包含在路径后的请求 URL 中的查询字符串。
Enumeration getParameterNames() 返回一个 String 对象的枚举,包含在该请求中包含的参数的名称。
String getParameter(String name) 以字符串形式返回请求参数的值,或者如果参数不存在则返回 null。
String[] getParameterValues(String name) 返回一个字符串对象的数组,包含所有给定的请求参数的值,如果参数不存在则返回 null。
Enumeration getHeaderNames() 返回一个枚举,包含在该请求中包含的所有的头名。
String getHeader(String name) 以字符串形式返回指定的请求头的值。
String getCharacterEncoding() 返回请求主体中使用的字符编码的名称。
String getContentType() 返回请求主体的 MIME 类型,如果不知道类型则返回 null。
int getContentLength() 以字节为单位返回请求主体的长度,并提供输入流,或者如果长度未知则返回 -1。
InputStream getInputStream() 用于读取请求的 body 内容. 返回一个 InputStream 对象.


注意: 请求对象是服务器收到的内容, 不应该修改. 因此上面的方法也都只是 “读” 方法, 而不是 “写” 方法.


图一 :

在这里插入图片描述


图二 :

在这里插入图片描述


这里的 API 使用 其实都比较简单 ,下面来看一个重要的知识点 , 前端给后端传参

9.2.1 简单的前后端交互

前端给后端传参 有两种典型做法 :

  1. 通过 GET 里面的 query string 传给后端
  2. 通过 POST , 借助 form 表单传给后端
  3. 通过 POST , 借助 json 格式表示 body 传给后端

GET , query string


在前端给后端传两个数字 ,一个是同学的 studentId , 一个是 classId 。


比如 : ?studentId=10&classId=20


下面来写一个代码来处理这个请求 :

在这里插入图片描述


2. POST , from


对于前端是 form 表单这样的格式的数据 ,后端还是使用 getParameter 来获取 .


form 表单 也是键值对,和 query string的格式一样,知识这部分内容在 body 中 .


通过 form 表单构造的请求 大致如下 :

首行
POST http://localhost:8080/hello_servlet/postParameter HTTP/1.1

header 部分 :
[
	若干 header
]

body 部分 :
studentId = 10 & classId = 20


下面就来通过 html 的 form 标签来构造 上述的请求

在这里插入图片描述


这里其实就涉及到了前后端交互,如果觉得 有点乱的 话 ,这里可以画个图来帮助大家理解

在这里插入图片描述


POST , json


json 是一种非常主流的数据格式 ,也是键值对结构 .

大概长下面这样子 :

{
    
    
	classId:20,
	studentId:10
}


我们请求中的 body 就可以按照 json 的格式来组织.


前端可以通过 ajax 的方式来构造出这个内容 (body 为 json 形式) , 更简单的方式 使用第三方工具 postman 直接构造。


图一 :

在这里插入图片描述


图二 :

在这里插入图片描述


图三 :

在这里插入图片描述


图四 :

在这里插入图片描述

9.3 HttpServletResponse

HttpServletResponse : 对应到 HTTP 响应 ,我们 可以通过 这个对象来构造出 HTTP 响应 返回给前端.


HttpServletResponse 核心方法

方法 描述
void setStatus(int sc) 为该响应设置状态码.
void setHeader(String name, String value) 设置一个带有给定的名称和值的 header. 如果 name 已经存在, 则覆盖旧的值.
void addHeader(String name, String value) 添加一个带有给定的名称和值的 header. 如果 name 已经存在, 不覆盖旧的值, 并列添加新的键值对
void setContentType(String type) 设置被发送到客户端的响应的内容类型。
void setCharacterEncoding(String charset) 设置被发送到客户端的响应的字符编码(MIME 字符集)例如,UTF-8。
void sendRedirect(String location) 使用指定的重定向位置 URL 发送临时重定向响应到客户端。
PrintWriter getWriter() 用于往 body 中写入文本格式数据.
OutputStream getOutputStream() 用于往 body 中写入二进制格式数据.


响应对象是服务器要返回给浏览器的内容, 这里的重要信息都是程序猿设置的. 因此上面的方
法都是 “写” 方法.


演示几个方法


1. 设置状态码

图一 :

在这里插入图片描述


图二 :

在这里插入图片描述

2. 重定向 : sendRedirect 方法

图一 :

在这里插入图片描述


3. 补充一个字段 : Refresh

再 header 里面 添加一个 Refresh 可以实现 浏览器 “自动刷新” 即 让浏览器每隔几秒自动刷新一次.

在这里插入图片描述


到此 我们的 Servlet 常用 API 就看完了 ,下面我们来写两个代码案例 来熟悉他们 .

10 代码案例


还记得在 学习前端三剑客 (HTML, CSS , javaScript) 的时候 写过一个静态页面 留言版 , 下面就根据它来完成一个前后端交互的小案例.

javaScript-扫盲

10.1 留言板基本功能实现 (后端)


图一 : 约定前后端交互数据格式

在这里插入图片描述


下面就来写代码


图一 :

在这里插入图片描述


图二 :

在这里插入图片描述


注意 : 这里多敲了一个变量 from ,可以自己 删改一下 .


图三 :

在这里插入图片描述


图四 :

在这里插入图片描述

附上代码 : MessageServlet

import com.fasterxml.jackson.databind.ObjectMapper;

import javax.jws.WebService;
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.util.ArrayList;
import java.util.List;


class Message {
    
    


    private String to;

    private String message;

    private String form;



    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;
    }

    public String getForm() {
    
    
        return form;
    }

    public void setForm(String form) {
    
    
        this.form = form;
    }
}

@WebServlet("/message")
public class MessageServlet extends HttpServlet {
    
    

    @Override
    public void init() throws ServletException {
    
    
        deleteServlet.messageList = messageList;
    }

    // 使用这个 List 变量保存所有消息
    private List<Message> messageList = new ArrayList<>();

    // 向服务器提交数据
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    

        // jackson 库中的核心类
        ObjectMapper objectMapper = new ObjectMapper();

        //  将 body 中的内容读取出来 , 解析成 一个 Message 对象
        Message message = objectMapper.readValue(req.getInputStream(), Message.class);

        // 这里先通过简单除暴的方式来完成保存
        messageList.add(message);

        // 此处的设定状态码可以省略 , 不设定默认也是 200
        resp.setStatus(200);

    }


    // 从服务器获取数据
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    

        ObjectMapper objectMapper = new ObjectMapper();

        resp.setContentType("application/json; charset=utf8");

        // 第一个参数 往那个里面写 , 第二参数 需要转为 json 的数据
        objectMapper.writeValue(resp.getWriter(), messageList);
    }
}

deleteServlet

import com.fasterxml.jackson.databind.ObjectMapper;

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.util.ArrayList;
import java.util.List;

@WebServlet("/delete")
public class deleteServlet extends HttpServlet {
    
    


    public static List<Message> messageList = new ArrayList<>();


    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    

        ObjectMapper objectMapper = new ObjectMapper();

        int size = messageList.size();

        messageList.remove(size - 1);

        resp.setContentType("text/json; charset=utf8");
        // 将数据返回 :
        objectMapper.writeValue(resp.getWriter(), messageList);

    }
}

这里留言板的 基本功能就完成了 , 如果 对 jackson 这库有点陌生的话, 这里就带着大家 , 写一个代码来认识一下.

10.2 补充 : jackson API 使用


在这里插入图片描述

关于 jackson 的API 后面会经常使用 , 这里 不熟悉没关系 ,后面 用多了 , 就熟悉了, 下面完成 前端部分 .

10.3 留言板前端部分


图一 :

在这里插入图片描述


图二 :

在这里插入图片描述


图三 :

在这里插入图片描述

图四 :

在这里插入图片描述


图五 :

在这里插入图片描述


图六 :

在这里插入图片描述


到此就完成了 这个代码案例,但是 存在一个非常严重的问题 , 数据是存储在服务器的内容中 , 如果服务器重启了,那么数据仍然会丢失 。


这里有两种解决办法 :

  1. 将数据存储在数据库中
  2. 将数据存入文件 (通过文件操作 , 将数据 写入到一个文件中).

10.4 修改为数据库版本


这先来完成 通过 数据库 存储数据的版本


图一 :

在这里插入图片描述


DBUtil


// 通过 这个类 ,把数据库连接过程封装一下

// 此处把这个 DBUtil 作为一个 工具类, 提供 static 方法供其他代码来调用

import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;

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

// DBUtil 本质上是 管理了 单例的 DataSource 的类
public class DBUtil {
    
    

    // 这里URL 后面的 只需要改数据名即可
    private static final String URL = "jdbc:mysql://127.0.0.1:3306/lx?characterEncoding=utf8&useSSL=false";

    private static final String USERNAME = "root";

    private static final String PASSWORD = "1234"; // 我们部署到 服务器 , 服务器没有密码所以不填

    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(URL);
                    ((MysqlDataSource) dataSource).setUser(USERNAME);
                    ((MysqlDataSource) dataSource).setPassword(PASSWORD);
                }
            }
        }
        return dataSource;
    }


    public static Connection getConnection() {
    
    
        // 通过 getDataSource 来 建立数据库连接
        try {
    
    
            return getDataSource().getConnection();
        } catch (SQLException e) {
    
    
            e.printStackTrace();
        }
        System.out.println("数据库连接失败,请检查数据库是否启动正确, url是否正确");
        return null;
    }

    public static void close(Connection connection, PreparedStatement statement, ResultSet resultSet) {
    
    
        // 用来关闭

        // 此处的 三个 try catch 分开写更好 , 避免前面的异常导致后面的代码不执行
        if (resultSet != null) {
    
    
            try {
    
    
                resultSet.close();
            } catch (SQLException e) {
    
    
                e.printStackTrace();
            }
        }
        if (statement != null) {
    
    
            try {
    
    
                statement.close();
            } catch (SQLException e) {
    
    
                e.printStackTrace();
            }
        }

        if (connection != null) {
    
    
            try {
    
    
                connection.close();
            } catch (SQLException e) {
    
    
                e.printStackTrace();
            }
        }
    }
}

图二 :

在这里插入图片描述


图三 :

在这里插入图片描述

附上代码 :

deleteServlet

import com.fasterxml.jackson.databind.ObjectMapper;

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;

@WebServlet("/delete")
public class deleteServlet extends HttpServlet {
    
    


//    public static List<Message> messageList = new ArrayList<>();


    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    

        ObjectMapper objectMapper = new ObjectMapper();


        List<Message> messageList = load();
        int size = messageList.size();


        Message message = messageList.get(size - 1);
        delete(message);


        resp.setContentType("text/json; charset=utf8");
        // 将数据返回 :
//        objectMapper.writeValue(resp.getWriter(), messageList);

    }


    private void delete(Message message) {
    
    

        Connection connection = null;

        PreparedStatement statement = null;

        try {
    
    
            // 1. 建立连接
            connection = DBUtil.getConnection();

            // 2. 构造 SQL
            String sql = "delete from message where `from` = ? and `to` = ? and message = ?";

            statement = connection.prepareStatement(sql);

            statement.setString(1, message.getForm());

            statement.setString(2, message.getTo());

            statement.setString(3, message.getMessage());

            // 3.  执行 SQL

            statement.executeUpdate();


        } catch (SQLException e) {
    
    
            e.printStackTrace();
        }finally {
    
    
            // 4. 释放资源
            DBUtil.close(connection,statement,null);
        }


    }


    // 从数据库获取数据
    private List<Message> load() {
    
    

        Connection connection = null;

        PreparedStatement statement = null;

        List<Message> messageList = new ArrayList<>();

        ResultSet resultSet = null;
        try {
    
    
            // 1. 建立连接
            connection = DBUtil.getConnection();

            // 2. 构造SQL
            String sql = "select * from message";

            statement = connection.prepareStatement(sql);

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


            // 4. 遍历 结果集合
            while (resultSet.next()) {
    
    

                Message message = new Message();

                message.setForm(resultSet.getString("from"));

                message.setTo(resultSet.getString("to"));

                message.setMessage(resultSet.getString("message"));

                messageList.add(message);
            }


        } catch (SQLException e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            // 5. 释放资源 ,断开连接
            DBUtil.close(connection, statement, resultSet);
        }

        return messageList;
    }

}


messageServlet

import com.fasterxml.jackson.databind.ObjectMapper;

import javax.jws.WebService;
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;


class Message {
    
    


    private String to;

    private String message;

    private String form;


    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;
    }

    public String getForm() {
    
    
        return form;
    }

    public void setForm(String form) {
    
    
        this.form = form;
    }
}

@WebServlet("/message")
public class MessageServlet extends HttpServlet {
    
    

//    @Override
//    public void init() throws ServletException {
    
    
//        deleteServlet.messageList = messageList;
//    }

    // 使用这个 List 变量保存所有消息
//    private List<Message> messageList = new ArrayList<>();

    // 向服务器提交数据
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    

        // jackson 库中的核心类
        ObjectMapper objectMapper = new ObjectMapper();

        //  将 body 中的内容读取出来 , 解析成 一个 Message 对象
        Message message = objectMapper.readValue(req.getInputStream(), Message.class);

        // 这里先通过简单除暴的方式来完成保存
//        messageList.add(message);

        save(message);
        // 此处的设定状态码可以省略 , 不设定默认也是 200
        resp.setStatus(200);

    }


    // 从服务器获取数据
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    

        ObjectMapper objectMapper = new ObjectMapper();

        resp.setContentType("application/json; charset=utf8");

        List<Message> messageList = load();
        // 第一个参数 往那个里面写 , 第二参数 需要转为 json 的数据
        objectMapper.writeValue(resp.getWriter(), messageList);
    }


    // JDBC 操作 :

    // 提供一对方法

    // 往数据库中存 一条数据
    private void save(Message message) {
    
    

        Connection connection = null;

        PreparedStatement statement = null;

        try {
    
    

            // 1. 建立连接 :
            connection = DBUtil.getConnection();

            // 2. 构造 SQL 语句 , ? 表示占位符
            String sql = "insert into message values(?,?,?)";

            statement = connection.prepareStatement(sql);
            statement.setString(1, message.getForm());
            statement.setString(2, message.getTo());
            statement.setString(3, message.getMessage());

            // 3. 执行 sql
            statement.executeUpdate();

        } catch (SQLException e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            // 4. 关闭连接
            DBUtil.close(connection, statement, null);
        }
    }

    // 从数据库获取数据
    private List<Message> load() {
    
    

        Connection connection = null;

        PreparedStatement statement = null;

        List<Message> messageList = new ArrayList<>();

        ResultSet resultSet = null;
        try {
    
    
            // 1. 建立连接
            connection = DBUtil.getConnection();

            // 2. 构造SQL
            String sql = "select * from message";

            statement = connection.prepareStatement(sql);

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


            // 4. 遍历 结果集合
            while (resultSet.next()) {
    
    

                Message message = new Message();

                message.setForm(resultSet.getString("from"));

                message.setTo(resultSet.getString("to"));

                message.setMessage(resultSet.getString("message"));

                messageList.add(message);
            }


        } catch (SQLException e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            // 5. 释放资源 ,断开连接
            DBUtil.close(connection, statement, resultSet);
        }

        return messageList;
    }

}


到此 数据库版本就完成了,下面再来写一个 文件版本 ,将数据存入文件中.

10.5 修改为文件版本


图一 :

在这里插入图片描述


图二 :

在这里插入图片描述


这里就不继续写了, 剩余内容放到下一篇文章中 ,防止篇幅过长

猜你喜欢

转载自blog.csdn.net/mu_tong_/article/details/129730715