前面我们学习了 Java 中知名的 HTTP 服务器 tomcat 的安装和使用,还学习了 servlet 相关 API 的学习,今天,这篇文章我们将运用前面学习的 HTTP 知识、tomcat和servlet来实现一个简单的表白墙网站。
我先为大家展示一下这个表白墙网站完成之后的最终效果。
首先当我们访问表白墙网站的 HTML 页面的时候,得到的是这个结果。
当我们输入信息并且提交的时候,会将输入的信息进行处理,然后显示在这个页面的下面。
然后我们就可以根据上面的效果来逐步实现代码。
在这里我给大家说明一下:要想实现网站,不仅需要后端的知识,还需要一些像什么 HTML、CSS、JavaScript这样的前端知识,而很多人可能还没接触过前端,大家不用慌,我也是刚接触前端,本篇文章我将为大家简单的介绍一下关于前端的时候,让大家大概知道我前段的每一段代码都是干啥的就行了。并且,我也是一个前端小白,如果我的分享有错误的话,欢迎大家在评论区或者私信我指出来,我在这里谢谢大家了。
首先我们需要创建出一个 Maven 项目,然后根据 tomcat 的要求创建出符合要求的目录结构,以及配置一些文件中的内容。
创建出符合 tomcat 标准的目录结构。
在 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 Applicationdisplay-name>
web-app>
创建出一个 MessageServlet.java 文件用来写我们的后端主要的代码。
HTML、CSS 和 JavaScript 是构建网页的三种主要技术,它们分别负责网页的结构、样式和行为。
HTML (HyperText Markup Language):HTML 是网页的基础,它负责创建和组织网页的内容。HTML 是一种标记语言,它使用各种标签来定义网页中的不同元素,例如标题、段落、链接、图片等。
CSS (Cascading Style Sheets):CSS 负责网页的样式和布局。它可以改变文本的颜色、字体和大小,也可以调整元素的位置、大小和边距等。
JavaScript:JavaScript 负责网页的行为和交互。它可以动态地更改网页的内容、响应用户的点击和输入,甚至加载新的内容。
简单的讲,HTML的作用就是决定你这个网页有哪些基本的结构,就是一个人有一个嘴巴、两个眼睛、一个鼻子;CSS则是决定你某一结构的具体样式和布局,就是一个人是双眼皮、高鼻梁、小嘴巴;而JavaScript则决定你网页的行为和交互,你怎么吃饭的、怎么呼吸的。
当做好前面的准备之后,我们就需要实现表白墙网站的第一步:显示出基本页面。这个显示出页面主要用到了 HTML和CSS的知识。我们的这个 html 文件需要放在 webapp 目录下。
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>表白墙title>
<style>
/* * 通配符选择器, 是选中页面所有元素 */
* {
/* 消除浏览器的默认样式. */
margin: 0;
padding: 0;
box-sizing: border-box;
}
.container {
width: 600px;
margin: 20px auto;
}
h1 {
text-align: center;
}
p {
text-align: center;
color: #666;
margin: 20px 0;
}
.row {
/* 开启弹性布局 */
display: flex;
height: 40px;
/* 水平方向居中 */
justify-content: center;
/* 垂直方向居中 */
align-items: center;
}
.row span {
width: 80px;
}
.row input {
width: 200px;
height: 30px;
}
.row button {
width: 280px;
height: 30px;
color: white;
background-color: orange;
/* 去掉边框 */
border: none;
border-radius: 5px;
}
/* 点击的时候有个反馈 */
.row button:active {
background-color: grey;
}
style>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.min.js">script>
head>
<body>
body>
html>
CSS中的通配符选择器(*),它选中了页面上的所有元素,然后将所有元素的margin(外边距)、padding(内边距)设置为0,并将box-sizing属性设置为border-box。
这段代码的目的主要是重置网页上所有元素的默认样式。在很多情况下,浏览器会对HTML元素应用默认样式,这些默认样式可能会影响到网页的布局和元素的尺寸。通过将margin和padding设置为0,可以消除元素之间的间距(margin)和内部填充(padding),而将box-sizing设置为border-box可以使元素的宽度和高度包括其边框和内边距。
它定义了一个名为".container"的类。这个类设置了一个元素的宽度为600像素,并将外边距(margin)设置为20像素,且上下外边距为自动(auto),使得这个元素在页面上居中。
用于设置HTML文档中的h1和p元素的样式。也就是h1标签和p标签。
用于设置一个名为".row"的类的样式。这段代码使用Flexbox模型来定义行内元素的布局和对齐方式。
所有属于.row类的元素的span子元素,其宽度将被设置为80px。
所有属于.row类的元素的input子元素,其宽度将被设置为200px,高度将被设置为30px。这个就是我们输入框的相关属性。
所有属于.row类的元素的button子元素,其宽度将被设置为280px,高度将被设置为30px,文本颜色将被设置为白色,背景颜色将被设置为橙色,边框将被移除,并且边框半径(用于创建圆角)将被设置为5px。这个就是点击按钮的相关属性。
上面主要用到了我们的 HTML 和 CSS 相关的知识,基本构建出了页面的基本结构和样式,而接下来,我们将使用 JavaScript 来完成提交信息这个动作。
首先需要构建出container类中的各个输入框的行为。
<div class="container">
<h1>表白墙</h1>
<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 class="row">
xxx 对 xx 说 xxxx
</div> -->
</div>
输入内容后点击提交, 信息会显示到下方表格中:创建一个段落,用于向用户说明他们可以输入表白信息,然后点击提交按钮,信息会显示在下方的表格中。
以上的JavaScript完成了输入框和提交按钮的行为,而JavaScript还需要完成点击提交按钮之后将数据经过处理然后显示在页面上。
<script>
let containerDiv = document.querySelector('.container');]
let inputs = document.querySelector('.input');
let button = document.querySelector('#submit');
button.onclick = function() {
//获取到三个输入框的内容
let from = inputs[0];
let to = inputs[1];
let message = input[2];
//判断是否未输入
if (from == '' || to == '' || message == '') {
return;
}
//创建出一个新的元素
let rowDiv = document.createElement('div');
//定义出rowDiv的类名
rowDiv.className = 'row message';
//为rowDiv中插入元素
rowDiv.innerHtml = from + ' 对 ' + to + ' 说: ' + msg;
//将这个新创建的元素添加到containerDiv类的末尾
containerDiv.appendChild(rowDiv);
//将输入框中的内容置为空
for (let input of inputs) {
input.value = '';
}
//构造出一个对象用来存储刚才输入框输入的内容,并且这个内容是以json的格式存在的
let requestBody = {
"from": from,
"to": to,
"message": message
}
//通过我们前面引入的Jackson依赖,使用JSON中的stringify方法将对象转换为json
let jsonString = JSON.stringify(requestBody);
//$是我们前面引入的jQuery依赖中的全局变量,通过这个$可以调用jQuery中的很多方法
//通过这个ajax方法构造请求,并且发送给服务器
$.ajax({
type: 'post',
url: 'message',
contentType: 'application/json; charset=utf8';
data: jsonString,
success: function(responseBody) {
console.log(responseBody);
}
});
}
</script>
Ajax属于第三方库,所以我们要想使用的话,就需要引入相关依赖。引入jQuery库。https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.min.js
当前端构造出 post 请求发送给服务器,服务器接收到这个请求之后就需要根据这个发送来的请求做出业务处理。因为我们使用的是 Servlet 实现的,所以就需要先引入 Servlet 依赖。
因为前端构造请求的数据格式是 json 的数据格式,所以要想在 Java 中使用 json,也就需要引入 json 库,或者包装了 json 库的其他库。
当引入 Servlet 和 Jackson 依赖之后,我们服务端就可以通过 Servlet 的相关 API 做出相应的业务处理了。
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 Message {
public String from;
public String to;
public String message;
@Override
public String toString() {
return "Message{" +
"from='" + from + '\'' +
", to='" + to + '\'' +
", message='" + message + '\'' +
'}';
}
}
@WebServlet("/message")
public class MessageServlet extends HttpServlet {
private ObjectMapper objectMapper = new ObjectMapper();
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置相应的状态码
resp.setStatus(200);
//通过ObjectMapper中的readValue方法将json数据转换为Java对象
Message message = objectMapper.readValue(req.getInputStream(), Message.class);
//将客户端输入的信息进行存储
save(message);
System.out.println(message);
resp.getWriter().write("ok");
}
}
当客户端进行提交请求之后,前端会将输入的信息传给服务器,那么当服务器接收到这个请求之后,应该将输入存储在哪个地方呢?如果只是拿一个简单的 List 容器存储数据话,那么这个数据就是存储在内存中的,当服务器重启之后,之前存储的数据就会消失,那么该如何存储才能保证数据的持久性呢?这里想到的肯定就是数据库了,数据库天然支持数据存储的持久性,所以我们这里选择使用 MySQL 数据库来实现数据的存储。
-- 创建数据库
create database if not exists message_wall;
-- 选中数据库
use message_wall;
-- 为了防止这个表存在对我们的数据库造成影响,我们先删除数据库
drop table if exists message;
-- 创建表
create table message(`from` varchar(1024), `to` varchar(1024), message varchar(1024));
当创建完成数据库和表之后,我们继续要引入 MySQL 依赖,然后实现 JDBC 编程了。
这里因为我的 MySQL 版本是 MySQL8,所以依赖选择的也是 MySQL8 版本,大家需要根据自己的 MySQL 版本来导入对应的依赖。
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mysql.cj.jdbc.MysqlDataSource;
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 javax.sql.DataSource;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
class Message {
public String from;
public String to;
public String message;
@Override
public String toString() {
return "Message{" +
"from='" + from + '\'' +
", to='" + to + '\'' +
", message='" + message + '\'' +
'}';
}
}
@WebServlet("/message")
public class MessageServlet extends HttpServlet {
private ObjectMapper objectMapper = new ObjectMapper();
private DataSource dataSource = new MysqlDataSource();
@Override
public void init() throws ServletException {
((MysqlDataSource)dataSource).setURL("jdbc:mysql://127.0.0.1:3306/message_wall?characterEncoding=utf8&useSSl=false");
((MysqlDataSource)dataSource).setUser("root");
((MysqlDataSource)dataSource).setPassword("*******"); //这里是我们的MySQL密码
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置相应的状态码
resp.setStatus(200);
//通过ObjectMapper中的readValue方法将json数据转换为Java对象
Message message = objectMapper.readValue(req.getInputStream(), Message.class);
//将客户端输入的信息进行存储
try {
save(message);
} catch (SQLException e) {
throw new RuntimeException(e);
}
System.out.println(message);
resp.getWriter().write("ok");
}
private void save(Message message) throws SQLException {
Connection connection = dataSource.getConnection();
String sql = "insert into message values(?, ?, ?)";
PreparedStatement statement = connection.prepareStatement(sql);
statement.setString(1, message.from);
statement.setString(2, message.to);
statement.setString(3, message.message);
statement.executeUpdate();
statement.close();
connection.close();
}
}
当实现完成将客户端输入的数据存储进MySQL数据库之后,当我们进入这个网站的时候,还需要将数据库已经存在的信息给读取到页面上,所以,当我们访问这个网站的时候,浏览器会向服务器发送一个 Ajax 请求,当服务器接收到这个 Ajax 请求的时候就会将数据库中的数据给返回给客户端。
$.ajax({
type: 'get',
url: 'message',
success: function(body) {
let containerDiv = document.querySelector('.container');
for (let i = 0; i < body.length; i++) {
let message = body[i];
let div = document.createElement('div');
div.className = 'row';
div.innerHTML = message.from + "对" + message.to + "说" + message.message;
containerDiv.appendChild(div);
}
}
});
我们这个标签放在