我们将使用 Maven 来管理项目依赖,这是目前 Java 项目的标准做法。

(图片来源网络,侵删)
项目结构
一个标准的 Maven Java Web 项目结构如下:
registration-webapp/
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── example/
│ │ │ └── controller/
│ │ │ └── RegisterServlet.java // 处理注册请求的Servlet
│ │ │ └── model/
│ │ │ └── User.java // 用户实体类
│ │ │ └── util/
│ │ │ └── DBUtil.java // 数据库连接工具类
│ │ ├── resources/
│ │ │ └── db.properties // 数据库配置文件
│ │ └── webapp/
│ │ ├── WEB-INF/
│ │ │ └── web.xml // 部署描述符
│ │ ├── register.html // 注册页面
│ │ └── welcome.jsp // 注册成功后的欢迎页面
│ └── test/
│ └── java/
├── pom.xml // Maven 项目配置文件
第1步:准备数据库
你需要一个 MySQL 数据库,如果没有,请先安装并启动 MySQL 服务。
-
创建一个数据库:
CREATE DATABASE javaweb_demo;
-
在
javaweb_demo数据库中创建一个users表:
(图片来源网络,侵删)USE javaweb_demo; CREATE TABLE users ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL UNIQUE, password VARCHAR(100) NOT NULL, email VARCHAR(100) NOT NULL UNIQUE, registration_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP );id:主键,自增。username:用户名,必须唯一。password:密码,我们将在后端进行加密存储。email:邮箱,也必须唯一。
第2步:创建 Maven Web 项目
在你的 IDE(如 IntelliJ IDEA 或 Eclipse)中,创建一个新的 Maven 项目,并选择 maven-archetype-webapp 模板。
第3步:配置 pom.xml
在 pom.xml 文件中,添加项目所需的依赖:
- Servlet API: 用于编写后端控制器。
- JSP API: 用于支持 JSP 页面。
- JSTL (JSP Standard Tag Library): 用于在 JSP 中简化逻辑判断和循环。
- MySQL Connector/J: 用于 Java 连接 MySQL 数据库。
- BCrypt: 一个安全的密码哈希库,用于加密用户密码。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>registration-webapp</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- Servlet API -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<!-- JSP API -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.3</version>
<scope>provided</scope>
</dependency>
<!-- JSTL -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- MySQL Connector -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
<!-- BCrypt for password hashing -->
<dependency>
<groupId>org.mindrot</groupId>
<artifactId>jbcrypt</artifactId>
<version>0.4</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.3.2</version>
</plugin>
</plugins>
</build>
</project>
第4步:编写后端代码
数据库配置 (src/main/resources/db.properties)
创建一个文件来存储数据库连接信息,方便日后修改。
# Database Connection Properties db.driver=com.mysql.cj.jdbc.Driver db.url=jdbc:mysql://localhost:3306/javaweb_demo?useSSL=false&serverTimezone=UTC db.username=root db.password=your_password # 替换成你的MySQL root密码
数据库工具类 (src/main/java/com/example/util/DBUtil.java)
这个类负责从配置文件中读取信息并创建数据库连接。

(图片来源网络,侵删)
package com.example.util;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;
public class DBUtil {
private static Properties props = new Properties();
private static String DRIVER;
private static String URL;
private static String USERNAME;
private static String PASSWORD;
static {
try (InputStream is = DBUtil.class.getClassLoader().getResourceAsStream("db.properties")) {
if (is == null) {
throw new RuntimeException("db.properties not found!");
}
props.load(is);
DRIVER = props.getProperty("db.driver");
URL = props.getProperty("db.url");
USERNAME = props.getProperty("db.username");
PASSWORD = props.getProperty("db.password");
Class.forName(DRIVER);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
throw new RuntimeException("Failed to load database properties or driver.", e);
}
}
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(URL, USERNAME, PASSWORD);
}
}
用户实体类 (src/main/java/com/example/model/User.java)
这是一个简单的 Java Bean,用于封装用户数据。
package com.example.model;
public class User {
private int id;
private String username;
private String password; // 存储的是哈希后的密码
private String email;
// Getters and Setters
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
}
注册控制器 (src/main/java/com/example/controller/RegisterServlet.java)
这是整个应用的核心,它接收前端的注册请求,处理数据,并与数据库交互。
package com.example.controller;
import com.example.model.User;
import com.example.util.DBUtil;
import org.mindrot.jbcrypt.BCrypt;
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.SQLException;
@WebServlet("/register") // URL 映射
public class RegisterServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 1. 获取前端表单数据
String username = req.getParameter("username");
String plainPassword = req.getParameter("password");
String email = req.getParameter("email");
// 2. 数据验证 (简单示例,实际应用中需要更复杂的验证)
if (username == null || username.isEmpty() || plainPassword == null || plainPassword.isEmpty() || email == null || email.isEmpty()) {
req.setAttribute("error", "所有字段都必须填写!");
req.getRequestDispatcher("register.html").forward(req, resp);
return;
}
// 3. 使用 BCrypt 加密密码
String hashedPassword = BCrypt.hashpw(plainPassword, BCrypt.gensalt());
// 4. 创建 User 对象
User user = new User();
user.setUsername(username);
user.setPassword(hashedPassword);
user.setEmail(email);
// 5. 保存到数据库
Connection conn = null;
PreparedStatement pstmt = null;
try {
conn = DBUtil.getConnection();
String sql = "INSERT INTO users (username, password, email) VALUES (?, ?, ?)";
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, user.getUsername());
pstmt.setString(2, user.getPassword());
pstmt.setString(3, user.getEmail());
int rowsAffected = pstmt.executeUpdate();
if (rowsAffected > 0) {
// 注册成功,重定向到欢迎页面
resp.sendRedirect(req.getContextPath() + "/welcome.jsp?username=" + user.getUsername());
} else {
// 注册失败
req.setAttribute("error", "注册失败,请稍后重试。");
req.getRequestDispatcher("register.html").forward(req, resp);
}
} catch (SQLException e) {
e.printStackTrace();
// 处理用户名或邮箱已存在的情况
if (e.getErrorCode() == 1062) { // MySQL 唯一约束冲突的错误码
req.setAttribute("error", "用户名或邮箱已被注册!");
} else {
req.setAttribute("error", "数据库错误,请联系管理员。");
}
req.getRequestDispatcher("register.html").forward(req, resp);
} finally {
// 6. 关闭资源
try {
if (pstmt != null) pstmt.close();
if (conn != null) conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
第5步:编写前端页面
注册页面 (src/main/webapp/register.html)
这是一个简单的 HTML 表单,action 指向我们的 RegisterServlet。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">用户注册</title>
<style>
body { font-family: Arial, sans-serif; background-color: #f4f4f4; margin: 0; padding: 20px; }
.container { max-width: 400px; margin: auto; background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
h2 { text-align: center; color: #333; }
label { display: block; margin-bottom: 8px; }
input[type="text"], input[type="password"], input[type="email"] {
width: 100%;
padding: 10px;
margin-bottom: 20px;
border: 1px solid #ddd;
border-radius: 4px;
box-sizing: border-box; /* Important for padding and width */
}
button {
width: 100%;
padding: 10px;
background-color: #5cb85c;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
}
button:hover { background-color: #4cae4c; }
.error-message { color: #d9534f; margin-bottom: 15px; text-align: center; }
</style>
</head>
<body>
<div class="container">
<h2>创建新账户</h2>
<%-- 使用 JSTL 显示错误信息 --%>
<%-- @ 表示这是一个 JSP 指令,用于引入 JSTL 核心标签库 --%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<c:if test="${not empty error}">
<div class="error-message">
${error}
</div>
</c:if>
<form action="${pageContext.request.contextPath}/register" method="post">
<label for="username">用户名:</label>
<input type="text" id="username" name="username" required>
<label for="email">电子邮箱:</label>
<input type="email" id="email" name="email" required>
<label for="password">密码:</label>
<input type="password" id="password" name="password" required>
<button type="submit">注册</button>
</form>
</div>
</body>
</html>
欢迎页面 (src/main/webapp/welcome.jsp)
注册成功后,用户会被重定向到这个页面。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<head>注册成功</title>
<style>
body { font-family: Arial, sans-serif; background-color: #f4f4f4; margin: 0; padding: 20px; text-align: center; }
.container { max-width: 400px; margin: auto; background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
h2 { color: #5cb85c; }
</style>
</head>
<body>
<div class="container">
<h2>注册成功!</h2>
<p>欢迎您,<strong>${param.username}</strong>!</p>
<p>您已成功创建账户。</p>
</div>
</body>
</html>
第6步:配置 web.xml
虽然我们使用了 @WebServlet 注解,但为了完整性,也可以在 web.xml 中进行配置,对于现代项目,注解方式更常用。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<display-name>Registration WebApp</display-name>
<!-- 如果不使用 @WebServlet 注解,可以在这里配置 Servlet -->
<!--
<servlet>
<servlet-name>RegisterServlet</servlet-name>
<servlet-class>com.example.controller.RegisterServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>RegisterServlet</servlet-name>
<url-pattern>/register</url-pattern>
</servlet-mapping>
-->
<welcome-file-list>
<welcome-file>register.html</welcome-file>
</welcome-file-list>
</web-app>
第7步:部署和运行
- 配置数据库:确保
db.properties文件中的数据库连接信息(尤其是密码)是正确的。 - 打包项目:在项目根目录下运行
mvn clean package命令,这会在target目录下生成一个.war文件(registration-webapp-1.0-SNAPSHOT.war)。 - 部署到服务器:
- Tomcat: 将生成的
.war文件复制到你的 Tomcat 服务器的webapps目录下。 - 启动 Tomcat 服务器。
- Tomcat: 将生成的
- 访问:在浏览器中访问
http://localhost:8080/registration-webapp/register.html(端口号和路径可能根据你的 Tomcat 配置和项目名有所不同)。
你应该能看到一个注册页面,填写信息并提交,如果一切正常,数据将被存入数据库,并且页面会跳转到欢迎页面。
总结与扩展
这个例子涵盖了 Java Web 开发的基础流程:
- MVC 模式:
User.java是 Model (模型),register.html是 View (视图),RegisterServlet是 Controller (控制器)。 - 请求-响应:浏览器发送请求,Servlet 处理并返回响应。
- 数据持久化:通过 JDBC 将数据保存到 MySQL 数据库。
- 安全性:使用 BCrypt 对密码进行哈希处理,而不是明文存储。
可以进一步扩展的功能:
- 登录功能:创建一个
LoginServlet,验证用户提交的用户名和密码(与数据库中的哈希值比对)。 - 会话管理:使用
HttpSession来跟踪已登录的用户。 - 输入验证:在前端(JavaScript)和后端(Java)都进行更严格的输入验证(如密码强度、邮箱格式等)。
- 分页和查询:在用户表中添加更多功能,如分页显示所有用户。
- 使用框架:对于更复杂的项目,可以考虑使用 Spring Boot 或 Jakarta EE (Jakarta EE) 等现代框架,它们能大大简化开发流程。
