在学Servlet API 之前,一定要先学好 HTTP 协议 和 Servlet 的基本使用
HTTP 协议
Servlet 基本使用
我们在写 Servlet 代码的时候,首先第一步就是先创建类,继承自 HttpServlet,并重写其中的某些方法
我们想要构造GET请求还是容易的,直接在地址栏输入就行,可是我们POST请求就不行了,他是隐藏的,我们需要用到 ajax或form表单
我这里就用 ajax 举个例子:
Servlet代码
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;
@WebServlet("/method")
public class MethodServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html; charset=utf8");
resp.getWriter().write("POST 响应");
}
}
ajax代码
(记得导入jqurey),且这个html文件要放在webapp下
<body>
<script src="jquery.js">script>
<script>
$.ajax({
type: 'post',
url: 'method',
success: function(body){
console.log(body);
}
});
script>
body>
还有需要注意一点的是:
写上这串代码就是为了防止页面出现乱码,因为我们浏览器是 GBK,而这里都是utf8,用这串代码告诉浏览器用utf8来读,统一编码格式,防止出现乱码
如果我们没有这串代码:
我们发现构造POST请求还挺麻烦的,有没有更快更方便的方式,当然是有的,有Postman这样一个工具:
方法名称 | 调用时机 |
---|---|
init | 在 HttpServlet 实例化之后被调用一次 |
destory | 在 HttpServlet 实例不再使用的时候调用一次 |
service | 收到 HTTP 请求的时候调用 |
doGet | 收到 GET 请求的时候调用(由 service 方法调用) |
doPost | 收到 POST 请求的时候调用(由 service 方法调用) |
doPut/doDelete/doOptions/… | 收到其他请求的时候调用(由 service 方法调用) |
我们很少会用到 init / destory / service,这里就需要说说Servlet的"生命周期"了:
Servlet"生命周期"主要分为三个阶段:
1,初始化阶段
//调用init()方法
2,响应客户请求阶段
//调用service()方法
3,终止阶段
//调用destroy()方法
1:init:
初始化阶段,对象创建好之后,就会执行到,用户可以重写这个方法,来执行一些初始化逻辑
2:service:
在处理请求阶段来调用,每一次来个请求都要调用一次service
3:destroy:
退出主循环,tomcat结束之前会调用,用来释放资源
HttpServletRequest 对应到一个 HTTP 请求,他请求里面有啥,这里就有啥,所以要想学好这个,学好 HTTP请求就轻松了
方法 | 描述 |
---|---|
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(Stringname) | 以字符串形式返回指定的请求头的值。 |
String getCharacterEncoding() | 返回请求主体中使用的字符编码的名称。 |
String getContentType() | 返回请求主体的 MIME 类型,如果不知道类型则返回 null。 |
int getContentLength() | 以字节为单位返回请求主体的长度,并提供输入流,或者如果长度未知则返回 -1。 |
InputStream getInputStream() | 用于读取请求的 body 内容. 返回一个 InputStream 对象 |
通过这些方法可以获取到一个请求中的各个方面的信息.
注意:
请求对象是服务器收到的内容, 不应该修改. 因此上面的方法也都只是 “读” 方法, 而不是 “写” 方法
我这里就打印 GET 请求了:
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.Enumeration;
@WebServlet("/showRequest")
public class ShowRequestServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("首行部分
");
stringBuilder.append(req.getProtocol());
stringBuilder.append("
"); //换行
stringBuilder.append(req.getMethod());
stringBuilder.append("
");
stringBuilder.append(req.getRequestURI());
stringBuilder.append("
");
stringBuilder.append(req.getContextPath());
stringBuilder.append("
");
stringBuilder.append(req.getQueryString());
stringBuilder.append("
");
stringBuilder.append("header 部分
");
//枚举类
Enumeration<String> headerNames = req.getHeaderNames();
while(headerNames.hasMoreElements()){
String headerName = headerNames.nextElement();
String headerValue = req.getHeader(headerName);
stringBuilder.append(headerName+": "+headerValue+"
");
}
//注意统一格式
resp.setContentType("text/html; charset=utf8");
resp.getWriter().write(stringBuilder.toString());
}
}
上述方法都不常用,真正常用的还是getParameter 这个方法(是获取到query string 中的详细内容)
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;
@WebServlet("/getParameter")
public class GetParameterServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//预期这样一个请求: /getParameter?userId=123&classId=456
String userId = req.getParameter("userId");
String classId = req.getParameter("classId");
resp.getWriter().write("userId=" + userId + ", classId=" + classId);
}
}
我们发现,没有 query string的时候,getParameter 获取的值是null
POST 请求的参数一般都是通过 body 传递给服务器的,但是我们知道前面学 HTTP请求的时候,POST中 body中的数据格式有很多种,我这里举几个例子:
Servlet代码:
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;
@WebServlet("/postGetParameter")
public class PostGetParameterServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String userId = req.getParameter("userId");
String classId = req.getParameter("classId");
resp.getWriter().write("userId="+userId+",classId="+classId);
}
}
前端代码:
<form action="postGetParameter" method="POST">
<input type="text" name="userId">
<input type="text" name="classId">
<input type="submit" value="提交">
form>
如果是 json 格式,如果我们手动来解析,是非常困难的,因为我们知道 json 是可以嵌套的,由于他们是以键值对的形式出现,就是说键对应的值也可以是一个 json 格式的
Jackson导入
所以,这里我们需要导入第三方库来解决,有很多,我这里使用的是 Jackson(因为他是 Spring 官方推荐的,后续我们学Spring 也会用到),还是一样去 中央仓库上下
官网:https://mvnrepository.com/
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.0</version>
</dependency>
Servlet代码:
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;
class User{
//当前这俩属性都设置成 public, 如果设为了private,就要提供 getter and setter 效果也一样
public int userId;
public int classId;
}
@WebServlet("/postJson")
public class PostJsonServlet extends HttpServlet {
//1.创建一个 jackson 核心对象
private ObjectMapper objectMapper = new ObjectMapper();
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//2.读取 body 中的请求,然后使用 ObjectMapper 来解析成需要的对象.
//readValue 就是把 JSON 格式的字符串,转成 java 的对象
//第一个参数,表示那个字符串进行转换,这个参数可以填写成一个 String, 也可以填一个 InputStream 对象,还可以填一个 File
// 第二个参数,表示要把这个 JSON 格式的字符串,转成哪个 Java 对象
User user = objectMapper.readValue(req.getInputStream(),User.class);
resp.getWriter().write("userId: "+user.userId+", classId: "+user.classId);
}
}
前端代码:
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>Documenttitle>
head>
<body>
<input type="text" id="userId">
<input type="text" id="classId">
<input type="button" value="提交" id="submit">
<script src="jquery.js">script>
<script>
let userIdInput = document.querySelector('#userId');
let classIdInput = document.querySelector('#classId');
let button = document.querySelector('#submit');
button.onclick = function() {
$.ajax({
type: 'post',
url: 'postJson',
contentType: 'application/json',
data: JSON.stringify({
userId: userIdInput.value,
classId: classIdInput.value
}),
success: function(body) {
console.log(body);
}
});
}
script>
body>
html>
解析代码:
Postman构造 POST 请求,JSON格式什么的是比上面更加方便的
官网下载链接:https://www.postman.com/
可能出现的问题:
变量: POSTMAN_DISABLE_GPU
值: true
最后重启Postman即可
我先在 IDEA 编写好 Servlet 代码,使用 POST 请求
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;
@WebServlet("/method")
public class MethodServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html; charset=utf8");
resp.getWriter().write("POST 响应");
}
}
启动 服务器:
选择想要的格式,我这里用的 POST 请求,就选POST方式,输入你要访问的地址,最后点击send,
这样就不用再去编写代码来实现 POST 请求了,非常方便
例如我还可以编写 JSON 格式
首先写好 Servlet 代码
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;
class User{
//当前这俩属性都设置成 public, 如果设为了private,就要提供 getter and setter 效果也一样
public int userId;
public int classId;
}
@WebServlet("/postJson")
public class PostJsonServlet extends HttpServlet {
//1.创建一个 jackson 核心对象
private ObjectMapper objectMapper = new ObjectMapper();
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//2.读取 body 中的请求,然后使用 ObjectMapper 来解析成需要的对象.
//readValue 就是把 JSON 格式的字符串,转成 java 的对象
//第一个参数,表示那个字符串进行转换,这个参数可以填写成一个 String, 也可以填一个 InputStream 对象,还可以填一个 File
// 第二个参数,表示要把这个 JSON 格式的字符串,转成哪个 Java 对象
User user = objectMapper.readValue(req.getInputStream(),User.class);
resp.getWriter().write("userId: "+user.userId+", classId: "+user.classId);
}
}
非常方便!!!
Servlet 中的 doXXX 方法的目的就是根据请求计算得到相应, 然后把响应的数据设置到HttpServletResponse 对象中.
然后 Tomcat 就会把这个 HttpServletResponse 对象按照 HTTP 协议的格式, 转成一个字符串, 并通过Socket 写回给浏览器.
方法 | 描述 |
---|---|
void setStatus(int sc) | 为该响应设置状态码。 |
void setHeader(String name,String value) | 设置一个带有给定的名称和值的 header. 如果 name 已经存在,则覆盖旧的值. |
void addHeader(Stringname, 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: 对于状态码/响应头的设置要放到 getWriter / getOutputStream 之前. 否则可能设置失效.
实现一个程序, 用户在浏览器通过参数指定要返回响应的状态码.
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;
@WebServlet("/status")
public class StatusServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setStatus(404);
resp.getWriter().write("hello");
}
}
可能有的人就会疑问了,这个404页面好像不是这样的?
那是因为服务器返回的状态码,只是在告诉浏览器,当前是个啥状态,他是不会影响显示在 body 中的内容的,就像我以哔哩哔哩
为例子:
他是可以自己设置的
实现一个程序,让浏览器每秒钟自动刷新,并显示时间戳
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;
@WebServlet("/autoRefresh")
public class AutoRefreshServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setHeader("Refresh","1");
resp.getWriter().write("timeStamp: "+System.currentTimeMillis());
}
}
实现一个程序, 返回一个重定向 HTTP 响应, 自动跳转到另外一个页面.
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;
@WebServlet("/redirect")
public class RedirectServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//我们在这里返回一个 302 重定向响应,就会自动跳转到火狐
resp.setStatus(302);
resp.setHeader("Location","https://home.firefoxchina.cn/");
}
}
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;
@WebServlet("/redirect")
public class RedirectServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.sendRedirect("https://home.firefoxchina.cn/");
}
}
我们要实现的这个案例,他不同于`我们之前写前端的时候数据不能保存,这个表白墙就需要实现数据做到"持久化"存储,我这里用数据库来存储信息
1: 创建Maven项目
2: 创建必要的 目录,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>
3:调整 pom.xml
引入依赖:
<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.12.6.1</version>
</dependency>
<!-- 引入 mysql 驱动包 -->
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.49</version>
</dependency>
</dependencies>
4: 将之前表白墙拷贝到 webapp目录中,同时也要引入 jquery
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>Documenttitle>
head>
<body>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.container {
width: 100%;
}
h3 {
text-align: center;
padding: 30px 0;
font-size: 24px;
}
p {
text-align: center;
color: rgb(62, 54, 54);
padding: 10px 0;
}
.row {
width: 400px;
height: 50px;
margin: 0 auto;
display: flex;
justify-content: center;
align-items: center;
}
.row span {
width: 60px;
font-size: 20px;
}
.row input {
width: 300px;
height: 40px;
line-height: 40px;
font-size: 20px;
text-indent: 0.5em;
/* 去掉输入框的轮廓线 */
outline: none;
}
.row #submit {
width: 300px;
height: 40px;
font-size: 20px;
line-height: 40px;
margin: 0 auto;
color: white;
background-color: rgb(203, 66, 157);
/* 去掉边框 */
border: none;
border-radius: 10px;
}
.row #submit:active {
background-color: gray;
}
style>
<div class="container">
<h3>表白墙h3>
<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 id="submit">提交button>
div>
div>
<script>
// 当用户点击 submit, 就会获取到 input 中的内容, 从而把内容构造成一个 div, 插入到页面末尾.
let submitBtn = document.querySelector('#submit');
submitBtn.onclick = function() {
// 1. 获取到 3 个 input 中的内容.
let inputs = document.querySelectorAll('input');
let from = inputs[0].value;
let to = inputs[1].value;
let msg = inputs[2].value;
if (from == '' || to == '' || msg == '') {
// 用户还没填写完, 暂时先不提交数据.
return;
}
// 2. 生成一个新的 div, 内容就是 input 里的内容. 把这个新的 div 加到页面中.
let div = document.createElement('div');
div.innerHTML = from + ' 对 ' + to + ' 说: ' + msg;
div.className = 'row';
let container = document.querySelector('.container');
container.appendChild(div);
// 3. 清空之前输入框的内容.
for (let i = 0; i < inputs.length; i++) {
inputs[i].value = '';
}
}
script>
body>
html>
所谓 “前后端交互接口” 是进行 Web 开发中的关键环节.
具体来说, 就是允许页面给服务器发送哪些 HTTP 请求, 并且每种请求预期获取什么样的 HTTP 响 应.
我们期望浏览器给服务器发送一个 GET /message 这样的请求, 就能返回当前一共有哪些留言记
录. 结果以 json 的格式返回过来.
我们用数据库来存放信息
创建 messages 表;
drop table if exists messages;
create table messages (`from` varchar(1000), `to` varchar(1000), `message` varchar(3000));
用来和数据库交互的,我用的是之前讲过的 JDBC
Mysql 的JDBC 编程
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;
public class DBUtil {
private static final String URL = "jdbc:mysql://127.0.0.1:3306/java102?characterEncoding=utf8&useSSL=false";
private static final String USERNAME = "root";
private static final String PASSWORD = "";//自己的密码
private volatile 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() throws SQLException {
return getDataSource().getConnection();
}
public static void close(Connection connection, PreparedStatement statement, ResultSet resultSet) {
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();
}
}
}
}
创建 Message 类
class Message {
public String from;
public String to;
public String message;
}
创建 MessageServlet 类
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("/message")
public class MessageServlet extends HttpServlet {
//用于转换 JSON 字符串
private ObjectMapper objectMapper = new ObjectMapper();
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 处理提交消息请求
Message message = objectMapper.readValue(req.getInputStream(), Message.class);
// 通过 ContentType 来告知页面, 返回的数据是 json 格式.
// 有了这样的声明, 此时 jquery ajax 就会自动的帮我们把字符串转成 js 对象.
// 如果没有, jquery ajax 就只是当成字符串来处理的~~
save(message);
resp.setContentType("application/json; charset=utf8");
resp.getWriter().write("{ \"ok\": true }");
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取到消息列表. 只要把消息列表中的内容整个的都返回给客户端即可
// 此处需要使用 ObjectMapper 把 Java 对象, 转成 JSON 格式字符串~
List<Message> messages = load();
String jsonString = objectMapper.writeValueAsString(messages);
System.out.println("jsonString: " + jsonString);
resp.setContentType("application/json; charset=utf8");
resp.getWriter().write(jsonString);
}
private void save(Message message) {
// 把一条消息保存到数据库中
Connection connection = null;
PreparedStatement statement = null;
try {
// 1. 和数据库建立连接
connection = DBUtil.getConnection();
// 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 {
DBUtil.close(connection, statement, null);
}
}
private List<Message> load() {
// 从数据库中获取到所有的消息
List<Message> messages = new ArrayList<>();
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
connection = DBUtil.getConnection();
String sql = "select * from messages";
statement = connection.prepareStatement(sql);
resultSet = statement.executeQuery();
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 throwables) {
throwables.printStackTrace();
} finally {
DBUtil.close(connection, statement, resultSet);
}
return messages;
}
}
<script src="jquery.js">script>
<script>
//加入 ajax 的代码,此处要加入的逻辑有两个部分
//点击提交按钮的时候,ajax 要构造数据发送给服务器
//页面加载的时候,从服务器获取消息列表,并在界面上显示
function getMessages(){
$.ajax({
type: "get",
url: "message",
success: function (body){
//当前 body 已经是一个 js 对象数组了,ajax 会根据响应的 content type 来自动进行解析.
//如果服务器返回的 content type 已经是 application/json 了,ajax 就会把 body 自动转成 js 的对象
//如果客户端没有自动转,也可以通过 JSON.parse() 这个函数来手动转换
//依次来取数组中的每个元素
let container = document.querySelector('.container');
for(let message of body){
let div = document.createElement('div');
div.innerHTML = message.from + ' 对 ' + message.to + ' 说: ' + message.message;
div.className = 'row';
container.appendChild(div);
}
}
});
}
//加上函数调用
getMessages();
// 当用户点击 submit, 就会获取到 input 中的内容, 从而把内容构造成一个 div, 插入到页面末尾.
let submitBtn = document.querySelector('#submit');
submitBtn.onclick = function() {
// 1. 获取到 3 个 input 中的内容.
let inputs = document.querySelectorAll('input');
let from = inputs[0].value;
let to = inputs[1].value;
let msg = inputs[2].value;
if (from == '' || to == '' || msg == '') {
// 用户还没填写完, 暂时先不提交数据.
return;
}
// 2. 生成一个新的 div, 内容就是 input 里的内容. 把这个新的 div 加到页面中.
let div = document.createElement('div');
div.innerHTML = from + ' 对 ' + to + ' 说: ' + msg;
div.className = 'row';
let container = document.querySelector('.container');
container.appendChild(div);
// 3. 清空之前输入框的内容.
for (let i = 0; i < inputs.length; i++) {
inputs[i].value = '';
}
//4. 把当前获取到的输入框的内容,构造成一个 HTTP POST 请求,通过 ajax 发给服务器body
let body = {
from: from,
to: to,
message: msg
};
$.ajax({
type: "post",
url: "message",
contentType: "application/json;charset=utf8",
data: JSON.stringify(body),
success: function (body){
alert("消息发送成功!");
},
error: function (){
alert("消息发送失败!");
}
})
}
script>
body>
html>
这样就算我们刷新,他的数据就不会消失了,做到了"持久保存"
核心方法:
HttpServletRequest 类方法
方法 | 描述 |
---|---|
Part getPart(String name) | 获取请求中给定 name 的文件 |
Collection getParts() | 获取所有的文件 |
Part类方法
方法 | 描述 |
---|---|
String getSubmittedFileName() | 获取提交的文件名 |
String getContentType() | 获取提交的文件类型 |
long getSize() | 获取文件的大小 |
void write(String path) | 把提交的文件数据写入磁盘文件 |
实现程序,通过网页提交一个图片到服务器上
1. 创建 upload.html, 放到 webapp 目录中.
<form action="upload" enctype="multipart/form-data" method="POST">
<input type="file" name="MyImage">
<input type="submit" value="提交图片">
form>
上传文件一般通过 POST 请求的表单实现.
在 form 中要加上 multipart/form-data 字段.
2. 创建 UploadServlet 类
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
import java.io.IOException;
@MultipartConfig
@WebServlet("/upload")
public class UploadServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Part part = req.getPart("MyImage");
System.out.println(part.getSubmittedFileName());
System.out.println(part.getContentType());
System.out.println(part.getSize());
part.write("d:/hahaha.jpg");
resp.setContentType("text/html; charset=utf8");
resp.getWriter().write("上传成功!");
}
}
注意:
1:需要给 UploadServlet 加上 @MultipartConfig 注解. 否则服务器代码无法使用 getPart 方法
2: getPart 的 参数 需要和 form 中 input 标签的 name 属性对应.
3: 客户端一次可以提交多个文件. (使用多个 input 标签). 此时服务器可以通过 getParts 获取所有的Part 对象.