文章目录
- 1. Tomcat
- 2. 下载安装
- 3. 启动 Tomcat
- 4. 运行 Tomcat
- 5. Servlet
- 5.1 创建项目
- 5.2 引入依赖
- 5.3 创建目录
- 5.4 编写代码
- 5.5 打包程序
- 5.6 部署程序
- 5.7 验证程序
- 6. 安装 Smart Tomcat 插件
- 7. 使用 SmartTomcat 插件
- 8. 常见错误
- 8.1 出现 404
- 8.2 出现 405
- 8.3 出现 500
- 8.4 出现空白页面
- 8.5 出现 无法访问此网站
- 9. 常用 Servlet API
- 9.1 HttpServlet
- 9.2 HttpServletRequest
- 9.2.1 简单的前后端交互
- 9.3 HttpServletResponse
- 10 代码案例
- 10.1 留言板基本功能实现 (后端)
- 10.2 补充 : jackson API 使用
- 10.3 留言板前端部分
- 10.4 修改为数据库版本
- 10.5 修改为文件版本
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 即可
这里 tomcat
给 java
提供的原生进行 web
的 api
就称为 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 .
这里稍微说一下 : 动态页面
关于我们的 网页分为两类 :
- 静态页面 : 页面内容始终是固定不变的
- 动态页面 : 页面内容睡着输入参数的不同而改变
下面就来 写一个第一个 Servlet 程序 , 还是老规矩 写一个 Hello World .
这里需要 7 个步骤
- 创建项目
- 引入依赖
- 创建目录结构
- 编写代码
- 打包程序
- 部署程序
- 验证
看起来很繁琐 ,实际上 ,出来编写代码之外 ,剩下的步骤 都是固定的 (固定的意味着 , 我们多练习几遍就会了) , 正因为这里太麻烦了,后面要学习的 spring MVC 就是简化 这个开发过程的.
5.1 创建项目
这里我们需要创建一个 Maven 项目
Maven 是 个 “工具管理” 工具
- 规范目录结构
- 管理依赖 (使用了啥第三方库 , 都给处理好)
- 构建
- 打包
- 测试
- …
本文就涉及到 管理依赖 , 和 打包 ,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 主要 有两个方面
- 路径写错了
- 你的 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 当前主要掌握 三个 类即可
- HttpServlet
- HttpServletRequest
- HttpServletResponse
9.1 HttpServlet
HttpServlet 核心方法
方法名称 | 调用时机 |
---|---|
init | 在 HttpServlet 实例化之后被调用一次 |
destory | 在 HttpServlet 实例不再使用的时候调用一次 |
service | 收到 HTTP 请求的时候调用 |
doGet | 收到 GET 请求的时候调用(由 service 方法调用) |
doPost | 收到 POST 请求的时候调用(由 service 方法调用) |
doPut/doDelete/doOptions/… | 收到其他请求的时候调用(由 service 方法调用) |
- init :
tomcat
首次收到了和该类相关联的请求
的时候HttpServlet
才会实例化, 而不是tomcat
一启动就立即实例化 . (类似于之前说过的懒汉模式) ,HttpServlet
实例化后才会调用init
方法
- destory : 在 HttpServlet 实例不在使用的时候调用 一次 (服务器终止的时候,调用) ,这个方法 就可以 做一些清理之类的工作
- service : 收到 http 请求就会触发 (路径匹配的请求) , 其实 我们的 doGet 就在 service 里调用 .
init , destroy , service 这三个方法 就是 HttpServlet 最关键的 三个方法 (虽然不太会直接用这几个,不会影响他们的重要性)
谈到上面这个 ,就可以引出一个典型的 面试题 : Servlet 的生命周期 是咋回事 ??
生命周期 : 粗浅的说法 ,一个东西啥时候来的, 啥时候没的就是 生命走起 , 进一步的理解 这个东西 什么 阶段,做啥事 , 这就是更加具体的生命走起 .
举个例子 : 一个人的生命周期
-
小的时候 , 要做的就是善学
-
长大了之后, 参加工作
-
再大点 ,要结婚 生娃
-
年纪再大 , 娃要上学了
-
年纪再大 ,让 娃结婚生娃
-
年纪再大 , 帮娃带娃
-
年纪再大 驾鹤西去 …
对应的到 Servlet 生命周期
- 开始的时候, 执行 init
- 每次收到请求执行 service
- 销毁之前 ,执行 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 简单的前后端交互
前端给后端传参 有两种典型做法 :
- 通过 GET 里面的 query string 传给后端
- 通过 POST , 借助 form 表单传给后端
- 通过 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 留言板前端部分
图一 :
图二 :
图三 :
图四 :
图五 :
图六 :
到此就完成了 这个代码案例,但是 存在一个非常严重的问题 , 数据是存储在服务器的内容中 , 如果服务器重启了,那么数据仍然会丢失 。
这里有两种解决办法 :
- 将数据存储在数据库中
- 将数据存入文件 (通过文件操作 , 将数据 写入到一个文件中).
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 修改为文件版本
图一 :
图二 :
这里就不继续写了, 剩余内容放到下一篇文章中 ,防止篇幅过长