文章目录
前言
本文是对响应对象编程-对数据库中的文本和图片的读取的实践,本文实现了对数据库中的图片和文本的读取,以及在网页上显示。依托于博客一招学会idea
中用使用Servlet
连接mysql
,超级详解(图解)-CSDN博客,若没有相关基础可以先学习这篇博客。
1. HTTP响应的基础知识
1.1 HTTP响应的内容
客户端发送请求,Server处理请求,处理完请求,会发送响应内容给客户端(浏览器):
- 状态码 (Status Code)
- 响应头(Response Header)
- 响应体(Response Body) (如果是重定向响应,没有响应体)
1.2 状态码
Server
通知客户端请求处理的状态。 W3C组织指定一套标准的状态,使用所有浏览器都认可的整数。
1xx
:系列: 正在处理,没处理完。通常浏览器看不到1xx
信息,需要通过AJAX
编程取得服务器返回的状态。2xx
:200 OK
,处理没有错误,响应结束。3xx
:内部转移处理4xx
:请求处理发生错误404
: 地址不存在405
: 请求方式不支持400
:发送数据无法接受
5xx
:500 Java
代码处理出现错误
1.3 响应头
- 响应头指定响应体的信息。
- 响应体类型:ContentType: 文本或二进制
- 字符编码集:文本响应需要指定字符编码
- 响应体长度
- Cookie信息
- 重定向信息:没有响应体,告诉浏览器跳转一个新的地址。
- 请求JSP时常用的响应头信息
1.4 响应体
就是要浏览器显示的内容。
- 类型:
- 文本:网页HTML,XML,JSON,纯文本
- 二进制:图片,音频,视频等。
- 响应体的类型使用MIME标准
- MIME标准使用格式:主类型/子类型
- text/html, text/plain,application/json
image/jpeg, image/gif, image/pnp
video/mpeg
- text/html, text/plain,application/json
2. 创建实验所需的数据库
创建数据库名称:CITYERP
.
创建表:ERP_PRODUCT
,字段和数据类型如下表所示。
字段名 | 类型 | 说明 |
---|---|---|
PID | Varchar(20) | 产品编号 (主键) |
PNAME | Varchar(200) | 产品名称 |
PRICE | Decimal(10,2) | 产品单价 |
PDATE | datetime | 产品生产日期 |
PHOTO | longblob | 产品图片 |
PHOTOTYPE | Varchar(200) | 产品图片类型 |
3. 前端页面的书写
3.1 search.jsp的书写
在 webapp/product/search.jsp
文件中,创建产品检索表单:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>产品检索</title>
</head>
<body>
<h1>产品检索</h1>
<form action="show.do" method="post">
产品编号: <input type="text" name="pid" required>
<input type="submit" value="查询产品">
</form>
</body>
</html>
使用bootstrap
进行美化
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>产品检索</title>
<link rel="stylesheet" href="../bs/bootstrap.css">
</head>
<body>
<div class="container mt-5">
<h1 class="text-center">产品检索</h1>
<form action="show.do" method="post" class="mt-4">
<div class="form-group">
<label for="pid">产品编号:</label>
<input type="text" id="pid" name="pid" class="form-control" required>
</div>
<div class="text-center">
<button type="submit" class="btn btn-primary">查询产品</button>
</div>
</form>
</div>
</body>
</html>
3.2 show.jsp的书写
在 webapp/product/show.jsp
文件中,创建显示产品信息的页面:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>产品信息</title>
</head>
<body>
<h1>产品信息</h1>
<p>产品编号: ${pid}</p>
<p>产品名称: ${pname}</p>
<p>产品单价: ${price}</p>
<p>产品生产日期: ${pdate}</p>
<img src="showphoto.do?pid=${pid}" alt="产品图片">
</body>
</html>
使用bootstrap
进行美化
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" isELIgnored="false"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>产品信息</title>
<link rel="stylesheet" href="../bs/bootstrap.css">
</head>
<body>
<div class="container mt-5">
<h1 class="text-center">产品信息</h1>
<div class="card">
<div class="card-body">
<h5 class="card-title">产品编号: ${pid}</h5>
<p class="card-text">产品名称: ${pname}</p>
<p class="card-text">产品单价: ${price}</p>
<p class="card-text">产品生产日期: ${pdate}</p>
<img src="showphoto.do?pid=${pid}" alt="产品图片" class="img-fluid">
</div>
</div>
</div>
</body>
</html>
4 后端的书写
4.1 ProductShowServlet的书写
在 com.city.erp.servlet
包中创建 ProductShowServlet
类:
package com.city.erp.servlet;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.io.IOException;
import java.sql.*;
@WebServlet("/product/show.do") // 映射URL到这个Servlet
public class ProductShowServlet extends HttpServlet {
private Connection dbconn; // 用于存放数据库连接的变量
@Override
public void init() throws ServletException {
// 数据库连接配置
String dbUrl = "jdbc:mysql://127.0.0.1:3306/cityerp?useSSL=false&serverTimezone=UTC"; // 数据库地址
String username = "root"; // MySQL用户名
String password = "root"; // MySQL密码
try {
// 加载MySQL的JDBC驱动
Class.forName("com.mysql.cj.jdbc.Driver");
// 建立数据库连接
dbconn = DriverManager.getConnection(dbUrl, username, password);
System.out.println("Database connected successfully!"); // 连接成功的提示
} catch (ClassNotFoundException e) {
// 如果加载JDBC驱动失败,抛出异常
throw new ServletException("JDBC Driver not found", e);
} catch (SQLException e) {
// 如果连接数据库失败,抛出异常
throw new ServletException("Error connecting to the database", e);
}
}
public void destroy() {
// Servlet被销毁时关闭与数据库的连接
try {
if (dbconn != null && !dbconn.isClosed()) { // 检查连接是否非空且未关闭
dbconn.close(); // 关闭连接
System.out.println("Database connection closed."); // 连接关闭的提示
}
} catch (SQLException e) {
e.printStackTrace(); // 打印异常堆栈
}
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 处理GET请求,转发到产品搜索页面
RequestDispatcher dispatcher = request.getRequestDispatcher("/product/search.jsp");
dispatcher.forward(request, response); // 转发请求
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String pid = req.getParameter("pid"); // 获取提交的产品编号
try {
// 查询产品信息的SQL语句
String sql = "SELECT PNAME, PRICE, PDATE FROM ERP_PRODUCT WHERE PID = ?";
PreparedStatement stmt = dbconn.prepareStatement(sql); // 准备SQL语句
stmt.setString(1, pid); // 设置产品编号参数
ResultSet rs = stmt.executeQuery(); // 执行查询
if (rs.next()) { // 如果找到产品信息
// 将产品信息存入请求属性
req.setAttribute("pname", rs.getString("PNAME"));
req.setAttribute("price", rs.getBigDecimal("PRICE"));
req.setAttribute("pdate", rs.getTimestamp("PDATE"));
req.setAttribute("pid", pid); // 存储产品编号
// 转发到显示产品信息的JSP页面
req.getRequestDispatcher("/product/show.jsp").forward(req, resp);
} else {
resp.getWriter().println("产品不存在"); // 如果产品不存在,输出提示
}
} catch (SQLException e) {
e.printStackTrace(); // 打印异常堆栈
resp.getWriter().println("数据库错误"); // 输出数据库错误提示
}
}
}
4.2 ProductPhotoShowServlet的书写
在 com.city.erp.servlet
包中创建 ProductPhotoShowServlet
类:
package com.city.erp.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.io.IOException;
import java.io.OutputStream;
import java.sql.*;
@WebServlet("/product/showphoto.do")
public class ProductPhotoShowServlet extends HttpServlet {
private Connection dbconn;// 这个变量用于存放数据库连接的数据
@Override
public void init() throws ServletException {
// 下面这句话中的book要改成你的数据库的名称
String dbUrl = "jdbc:mysql://127.0.0.1:3306/cityerp?useSSL=false&serverTimezone=UTC";
String username = "root"; // 你的Mysql的用户名
String password = "root"; // 你的Mysql的密码
try {
// 加载MySQL的JDBC驱动
Class.forName("com.mysql.cj.jdbc.Driver");
// 建立数据库连接
dbconn = DriverManager.getConnection(dbUrl, username, password);
System.out.println("Database connected successfully!");
} catch (ClassNotFoundException e) {
// 如果加载JDBC驱动时发生错误,抛出 ClassNotFoundException,表示找不到JDBC驱动类。
throw new ServletException("JDBC Driver not found", e);
} catch (SQLException e) {
// 如果连接数据库时发生错误(如用户名或密码错误,数据库不可用等),抛出 SQLException
throw new ServletException("Error connecting to the database", e);
}
}
public void destroy() {
// Servlet被销毁时关闭与数据库的连接
try {
if (dbconn != null && !dbconn.isClosed()) {
dbconn.close();
System.out.println("Database connection closed.");
}
} catch (SQLException e) {
e.printStackTrace();
}
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String pid = req.getParameter("pid");
try {
String sql = "SELECT PHOTO, PHOTOTYPE FROM ERP_PRODUCT WHERE PID = ?";
PreparedStatement stmt = dbconn.prepareStatement(sql);
stmt.setString(1, pid);
ResultSet rs = stmt.executeQuery();
if (rs.next()) {
byte[] photoData = rs.getBytes("PHOTO");
String photoType = rs.getString("PHOTOTYPE");
resp.setContentType(photoType);
OutputStream out = resp.getOutputStream();
out.write(photoData);
out.flush();
} else {
resp.getWriter().println("产品图片不存在");
}
} catch (SQLException e) {
e.printStackTrace();
resp.getWriter().println("数据库错误");
}
}
}