目录
PaymentRecordQueryServlet.java
一、题目要求
用户分为业主和系统管理员两种,业主可以通过注册页面添加自己的基本信息,包括姓名、楼号、单元号、房号、类型(户主/租户)、车牌号(没有车可以为空)、手机号等,可以在系统中查询水费、电费、物业费、卫生费、暖气费、停车费等收费标准及历史缴费情况。也可以在线自主缴费。自主缴费时选择对应项目并填写缴费数量(如100度电),系统会自动算出缴费总额。收费功能暂用一个二维码图片代替。系统管理员可以对物业收费项目进行增删改查等操作,也可以查询业主的缴费记录。系统采用预交费方式,如某业主电费余额为0后系统自动对其断电。物业费、卫生费等欠费后,管理员电话通知业主缴费,否则,用户无法通过系统交纳水电费。
二、系统基本功能结构
系统总体架构图
项目结构体图(主要的类、JSP页面存放目录结构等
三、数据库设计
1、综合E-R模型
2、表结构
Charge_item 表:存储缴费项目信息,包括缴费编号(item_id,自增主键)、项目名称(item_name)、单价(Charge_standard)。、Charge_item表
字段名称 | 数据类型 | 约束 | 备注 |
item_id | Int(auto increment) | primary key | 缴费编号 |
item_name | Varchar(255) | 名称 | |
Charge_standard | decimal | 单价 |
Payment_record 表:记录物费缴费情况,有物费编号(record_id,主键)、用户编号(user_id)、物费名称(item_id)、缴费金额(payment_amount)、时间(payment_time)。
字段名称 | 数据类型 | 约束 | 备注 |
record_id | Int | primary key | 物费编号 |
user_id | Int | 用户名称 | |
item_id | Int | 物费名称 | |
payment_amount | decimal | 缴费金额 | |
payment_time | Timestamp | 时间 |
user 表:涵盖用户基本信息,用户编号(User_id,主键)、姓名(name)、楼名(Building_number)、单元名(Unit_number)、房间名(Room_number)、户主类别(type)、车号(Car_number)、电话(Phone_number)、密码(password)、登录类别(role)。
字段名称 | 数据类型 | 约束 | 备注 |
User_id | int | primary key | 用户编号 |
name | char | 用户名称 | |
Building_number | char | 楼名 | |
Unit_number | char | 单元名 | |
Room_number | char | 房间名 | |
type | enum | 户主类别 | |
Car_number | char | 车号 | |
Phone_number | char | 电话 | |
password | char | 密码 | |
role | enum | 登录类别 |
3、JSP 页面设计
admin_index.jsp:
管理员首页,提供收费项目管理、缴费记录查询入口及退出按钮,页面样式简洁,通过合理的 CSS 设置增强可读性与操作便捷性。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html>
<head>
<title>管理员首页</title>
<style>
/* 全局样式设置 */
body {
font-family: Arial, sans-serif;
background-color: #f4f4f4;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
min-height: 100vh;
}
/* 页面标题样式 */
h2 {
text-align: center;
color: #333;
margin-bottom: 20px;
}
/* 功能链接通用样式 */
a {
display: block;
text-decoration: none;
color: white;
background-color: #007bff;
padding: 10px 20px;
border-radius: 5px;
margin-bottom: 10px;
width: 200px;
text-align: center;
transition: background-color 0.3s ease;
}
a:hover {
background-color: #0056b3;
}
/* 退出按钮样式 */
#logout {
background-color: #f44336;
margin-top: 20px;
}
#logout:hover {
background-color: #d32f2f;
}
</style>
</head>
<body>
<div class="card">
<h2>欢迎管理员登录</h2>
<a href="/ChargeItemManageServlet">收费项目管理</a>
<a href="/PaymentRecordQueryServlet">缴费记录查询</a>
<a href="<%=request.getContextPath()%>/LoginServlet?action=logout" id="logout">退出到登录界面</a>
</div>
</body>
</html>
Charge_item_manage.jsp
用于收费项目管理,可添加、修改、删除收费项目,并展示项目列表,借助 JavaScript 实现表单显示与隐藏以及删除确认功能,提升用户交互体验。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="java.util.List" %>
<%@ page import="com.tt.entity.ChargeItem" %>
<!DOCTYPE html>
<html>
<head>
<title>收费项目管理</title>
<style>
/* 全局样式设置 */
body {
font-family: Arial, sans-serif;
background-color: #f4f4f4;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
min-height: 100vh;
}
/* 页面容器样式 */
.page-container {
background-color: white;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
border-radius: 5px;
padding: 20px;
width: 80%;
max-width: 1000px;
}
h2 {
text-align: center;
color: #333;
margin-bottom: 20px;
}
/* 链接通用样式 */
a {
display: inline-block;
text-decoration: none;
color: white;
background-color: #007bff;
padding: 10px 20px;
border-radius: 5px;
margin-bottom: 10px;
margin-right: 10px;
text-align: center;
transition: background-color 0.3s ease;
}
a:hover {
background-color: #0056b3;
}
/* 返回按钮样式 */
.back-button {
background-color: #6c757d;
margin-top: 20px;
margin-bottom: 20px;
}
.back-button:hover {
background-color: #5a6268;
}
table {
border-collapse: collapse;
width: 100%;
margin-top: 20px;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
}
th, td {
border: 1px solid #dddddd;
text-align: left;
padding: 12px;
}
tr:nth-child(even) {
background-color: #f2f2f2;
}
/* 表头样式优化 */
th {
background-color: #007bff;
color: white;
font-weight: bold;
}
/* 鼠标悬停行样式 */
tr:hover {
background-color: #e0e0e0;
}
/* 表单样式 */
form {
background-color: white;
padding: 20px;
border-radius: 5px;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
margin-top: 20px;
}
label {
display: block;
margin-bottom: 5px;
}
input[type="text"] {
width: 100%;
padding: 10px;
margin-bottom: 15px;
border: 1px solid #ccc;
border-radius: 3px;
}
input[type="submit"] {
background-color: #007bff;
color: white;
padding: 10px 15px;
border: none;
border-radius: 3px;
cursor: pointer;
}
input[type="submit"]:hover {
background-color: #0056b3;
}
</style>
</head>
<body>
<div class="page-container">
<a href="${pageContext.request.contextPath}/admin_index.jsp" class="back-button">返回管理员首页</a>
<h2>收费项目管理</h2>
<a href="#" onclick="showAddForm()">添加收费项目</a>
<div id="addForm" style="display:none;">
<form action="/ChargeItemManageServlet" method="post">
<input type="hidden" name="action" value="add">
<label for="itemName">项目名称:</label><input type="text" id="itemName" name="itemName" required><br>
<label for="chargeStandard">收费标准:</label><input type="text" id="chargeStandard" name="chargeStandard" required><br>
<input type="submit" value="添加">
</form>
</div>
<table>
<thead>
<tr>
<th>项目编号</th>
<th>项目名称</th>
<th>收费标准</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<%
List<ChargeItem> chargeItems = (List<ChargeItem>) request.getAttribute("chargeItems");
if (chargeItems!= null) {
for (ChargeItem item : chargeItems) {
%>
<tr>
<td><%= item.getItem_id() %></td>
<td><%= item.getItem_name() %></td>
<td><%= item.getCharge_standard() %></td>
<td>
<a href="#" onclick="showUpdateForm(<%= item.getItem_id() %>, '<%= item.getItem_name() %>', <%= item.getCharge_standard() %>)">修改</a>
<a href="#" onclick="confirmDelete(<%= item.getItem_id() %>)">删除</a>
</td>
</tr>
<%
}
}
%>
</tbody>
</table>
<div id="updateForm" style="display:none;">
<form action="ChargeItemManageServlet" method="post">
<input type="hidden" name="action" value="update">
<input type="hidden" id="updateItemId" name="itemId">
<label for="updateItemName">项目名称:</label><input type="text" id="updateItemName" name="itemName" required><br>
<label for="updateChargeStandard">收费标准:</label><input type="text" id="updateChargeStandard" name="chargeStandard" required><br>
<input type="submit" value="更新">
</form>
</div>
</div>
<script>
function showAddForm() {
document.getElementById('addForm').style.display = 'block';
}
function showUpdateForm(itemId, itemName, chargeStandard) {
document.getElementById('updateForm').style.display = 'block';
document.getElementById('updateItemId').value = itemId;
document.getElementById('updateItemName').value = itemName;
document.getElementById('updateChargeStandard').value = chargeStandard;
}
function confirmDelete(itemId) {
if (confirm("确定要删除该收费项目吗?")) {
var form = document.createElement('form');
form.action = 'ChargeItemManageServlet';
form.method = 'post';
form.style.display = 'none';
var inputAction = document.createElement('input');
inputAction.type = 'hidden';
inputAction.name = 'action';
inputAction.value = 'delete';
form.appendChild(inputAction);
var inputItemId = document.createElement('input');
inputItemId.type = 'hidden';
inputItemId.name="itemId";
inputItemId.value = itemId;
form.appendChild(inputItemId);
document.body.appendChild(form);
form.submit();
}
}
</script>
</body>
</html>
index.jsp
页面重定向至 login.jsp,引导用户进入登录页面。
<%--
Created by IntelliJ IDEA.
User: *****
Date: 2024/12/15
Time: 18:04
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<meta http-equiv="refresh" content="0;url=login.jsp">
<title>$Title$</title>
</head>
<body>
$END$
</body>
</html>
login.jsp:用户登录页面,包含手机号和密码输入框,对输入错误进行提示,确保用户输入信息的准确性。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html>
<head>
<title>登录</title>
<style>
body {
font-family: Arial, sans-serif;
background-color: #f4f4f4;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
margin: 0;
padding: 0;
}
form {
background-color: white;
padding: 20px;
border-radius: 5px;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
width: 300px;
}
h2 {
text-align: center;
margin-bottom: 20px;
}
label {
display: block;
margin-bottom: 5px;
}
input[type="text"],
input[type="password"] {
width: 100%;
padding: 10px;
margin-bottom: 15px;
border: 1px solid #ccc;
border-radius: 3px;
margin-right: 10px; /* 添加这行代码,设置右侧外边距为10px */
}
input[type="submit"] {
background-color: #007bff;
color: white;
padding: 10px 15px;
border: none;
border-radius: 3px;
cursor: pointer;
}
input[type="submit"]:hover {
background-color: #0056b3;
}
p {
color: red;
margin-top: 10px;
text-align: center;
}
</style>
</head>
<body>
<form action="/LoginServlet" method="post">
<h2>用户登录</h2>
<div>
<label for="phone">手机号:</label>
<input type="text" id="phone" name="phone" required>
</div>
<div>
<label for="password">密码:</label>
<input type="password" id="password" name="password" required>
</div>
<input type="submit" value="登录">
<%
String errorMessage = (String) request.getAttribute("errorMessage");
if (errorMessage!= null) {
%>
<p><%= errorMessage %></p>
<%
}
%>
</form>
</body>
</html>
owner_index.jsp:业主首页,提供缴费记录查询和进行缴费的功能入口,方便业主操作。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html>
<head>
<title>业主首页</title>
<style>
/* 全局样式设置 */
body {
font-family: Arial, sans-serif;
background-color: #f4f4f4;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
min-height: 100vh;
}
/* 页面标题样式 */
h2 {
text-align: center;
color: #333;
margin-bottom: 20px;
}
/* 功能链接通用样式 */
a {
display: block;
text-decoration: none;
color: white;
background-color: #007bff;
padding: 10px 20px;
border-radius: 5px;
margin-bottom: 10px;
width: 200px;
text-align: center;
transition: background-color 0.3s ease;
}
a:hover {
background-color: #0056b3;
}
/* 退出按钮样式 */
#logout {
background-color: #f44336;
margin-top: 20px;
}
#logout:hover {
background-color: #d32f2f;
}
</style>
</head>
<body>
<div class="card">
<h2>欢迎业主登录</h2>
<a href="/PaymentRecordQueryServlet">缴费记录查询</a>
<a href="/PaymentServlet">进行缴费</a>
<a href="<%=request.getContextPath()%>/LoginServlet?action=logout" id="logout">退出到登录界面</a>
</div>
</body>
</html>
payment.jsp
业主缴费页面,可选择收费项目并输入缴费金额,页面设计注重用户输入流程的顺畅性。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="java.util.List" %>
<%@ page import="com.tt.entity.ChargeItem" %>
<!DOCTYPE html>
<html>
<head>
<title>进行缴费</title>
<style>
/* 全局样式设置 */
body {
font-family: Arial, sans-serif;
background-color: #f4f4f4;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
min-height: 100vh;
}
/* 页面容器样式 */
.page-container {
background-color: white;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
border-radius: 5px;
padding: 20px;
width: 80%;
max-width: 600px;
}
h2 {
text-align: center;
color: #333;
margin-bottom: 20px;
}
/* 返回按钮样式 */
.back-button {
display: inline-block;
text-decoration: none;
color: white;
background-color: #6c757d;
padding: 10px 20px;
border-radius: 5px;
margin-bottom: 20px;
text-align: center;
transition: background-color 0.3s ease;
}
.back-button:hover {
background-color: #5a6268;
}
label {
display: block;
margin-bottom: 5px;
font-weight: bold;
}
select, input[type="text"] {
width: 100%;
padding: 10px;
margin-bottom: 15px;
border: 1px solid #ccc;
border-radius: 3px;
}
input[type="submit"] {
background-color: #007bff;
color: white;
padding: 10px 15px;
border: none;
border-radius: 3px;
cursor: pointer;
}
input[type="submit"]:hover {
background-color: #0056b3;
}
</style>
</head>
<body>
<div class="page-container">
<a href="${pageContext.request.contextPath}/owner_index.jsp" class="back-button">返回业主首页</a>
<h2>进行缴费</h2>
<form action="/PaymentServlet" method="post">
<label for="itemId">选择收费项目:</label>
<select id="itemId" name="itemId" required>
<%
List<ChargeItem> chargeItems = (List<ChargeItem>) request.getAttribute("chargeItems");
if (chargeItems!= null &&!chargeItems.isEmpty()) {
for (ChargeItem item : chargeItems) {
%>
<option value="<%= item.getItem_id() %>"><%= item.getItem_name() %></option>
<%
}
} else {
%>
<option value="" disabled selected>暂无收费项目可选,请联系管理员</option>
<%
}
%>
</select><br>
<label for="paymentAmount">缴费金额:</label><input type="text" id="paymentAmount" name="paymentAmount" required><br>
<input type="submit" value="缴费">
</form>
</div>
</body>
Payment_record_query.jsp
用于查询缴费记录,以表格形式展示记录详情,提升数据展示的清晰度。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="java.util.List" %>
<%@ page import="com.tt.entity.PaymentRecord" %>
<!DOCTYPE html>
<html>
<head>
<title>缴费记录查询</title>
<style>
/* 全局样式设置 */
body {
font-family: 'Roboto', sans-serif; /* 使用更现代大气的字体 */
background-color: #f0f2f5; /* 柔和的背景色 */
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
min-height: 100vh;
}
/* 页面容器样式 */
.page-container {
background-color: white;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); /* 增加立体感的阴影 */
border-radius: 8px;
padding: 30px;
width: 80%;
max-width: 1200px; /* 限制最大宽度,适应不同屏幕 */
}
h2 {
text-align: center;
color: #333;
margin-bottom: 30px;
font-size: 28px; /* 加大标题字体 */
}
table {
border-collapse: collapse;
width: 100%;
margin-top: 20px;
}
th, td {
border: 1px solid #e0e0e0; /* 更淡的边框色 */
text-align: left;
padding: 15px 20px; /* 加大内边距 */
font-size: 16px;
}
tr:nth-child(even) {
background-color: #f8f8f8;
}
/* 表头样式优化 */
th {
background-color: #007bff;
color: white;
font-weight: bold;
}
/* 鼠标悬停行样式 */
tr:hover {
background-color: #e8e8e8;
}
/* 返回按钮样式 */
.back-button {
display: inline-block;
text-decoration: none;
color: white;
background-color: #6c757d;
padding: 12px 25px; /* 加大按钮尺寸 */
border-radius: 6px;
margin-bottom: 20px;
font-size: 16px;
transition: background-color 0.3s ease;
}
.back-button:hover {
background-color: #5a6268;
}
</style>
</head>
<body>
<div class="page-container">
<a href="${pageContext.request.contextPath}/owner_index.jsp" class="back-button">返回管理员首页</a>
<h2>缴费记录查询</h2>
<table>
<thead>
<tr>
<th>记录编号</th>
<th>用户编号</th>
<th>项目编号</th>
<th>缴费金额</th>
<th>缴费时间</th>
</tr>
</thead>
<tbody>
<%
List<PaymentRecord> paymentRecords = (List<PaymentRecord>) request.getAttribute("paymentRecords");
if (paymentRecords!= null) {
for (PaymentRecord record : paymentRecords) {
%>
<tr>
<td><%= record.getRecord_id() %></td>
<td><%= record.getUser_id() %></td>
<td><%= record.getItem_id() %></td>
<td><%= record.getPayment_amount() %></td>
<td><%= record.getPayment_time() %></td>
</tr>
<%
}
}
%>
</tbody>
</table>
</div>
</body>
</html>
qrcord.jsp
显示缴费二维码页面,提示缴费成功并展示缴费金额,虽二维码为占位,但整体页面设计符合业务流程。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html lang="en">
<head>
<title>缴费二维码</title>
<style>
/* 全局样式设置 */
body {
font-family: Arial, sans-serif;
background-color: #f8f9fa; /* 更柔和的背景色 */
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
min-height: 100vh;
}
.page-container {
background-color: white;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); /* 增强阴影效果 */
border-radius: 10px; /* 更圆润的边框 */
padding: 30px;
width: 80%;
max-width: 600px;
text-align: center;
}
h2 {
color: #007bff; /* 标题颜色改为主题色,更醒目 */
margin-bottom: 20px;
font-size: 24px; /* 增大标题字体大小 */
}
p {
color: #6c757d; /* 正文内容颜色稍作调整 */
margin-bottom: 15px;
font-size: 16px;
}
img {
max-width: 300px;
max-height: 300px;
margin-bottom: 20px;
border-radius: 5px; /* 给二维码图片添加圆角 */
box-shadow: 0 0 5px rgba(0, 0, 0, 0.1); /* 给图片添加阴影 */
}
.back-button {
display: inline-block;
padding: 10px 20px;
background-color: #007bff; /* 按钮背景色为主题色 */
color: white; /* 按钮文字颜色为白色 */
text-decoration: none; /* 去除下划线 */
border-radius: 5px; /* 按钮圆角 */
transition: background-color 0.3s ease; /* 过渡效果 */
}
.back-button:hover {
background-color: #0056b3; /* 鼠标悬停时按钮颜色加深 */
}
</style>
</head>
<body>
<div class="page-container">
<h2>缴费成功</h2>
<!-- 获取并显示缴费金额 -->
<p>缴费金额:<%= request.getParameter("paymentAmount") %> 元</p>
<!-- 这里使用img标签占位,实际需替换为生成二维码的代码 -->
<img src="img/zhifu.png" alt="缴费二维码">
<a href="owner_index.jsp" class="back-button">返回业主首页</a>
</div>
</body>
</html>
四、Servlet 设计
ChargeItemManageServlet.java
处理收费项目管理请求,支持添加、修改、删除操作,操作结果反馈给用户,并重新展示收费项目列表。
package com.tt.servlet;
import com.tt.dao.ChargeItemDAO;
import com.tt.dao.ChargeItemDAOImpl;
import com.tt.entity.ChargeItem;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
@WebServlet("/ChargeItemManageServlet")
public class ChargeItemManageServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ChargeItemDAO chargeItemDAO = new ChargeItemDAOImpl();
List<ChargeItem> chargeItems = chargeItemDAO.getAllChargeItems();
request.setAttribute("chargeItems", chargeItems);
request.getRequestDispatcher(request.getContextPath() + "charge_item_manage.jsp").forward(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String action = request.getParameter("action");
ChargeItemDAO chargeItemDAO = new ChargeItemDAOImpl();
try {
if ("add".equals(action)) {
String itemName = request.getParameter("itemName");
double chargeStandard = Double.parseDouble(request.getParameter("chargeStandard"));
ChargeItem chargeItem = new ChargeItem();
chargeItem.setItem_name(itemName);
chargeItem.setCharge_standard(chargeStandard);
int result = chargeItemDAO.addChargeItem(chargeItem);
if (result > 0) {
request.setAttribute("successMessage", "收费项目添加成功!");
} else {
request.setAttribute("errorMessage", "收费项目添加失败,请稍后再试!");
}
} else if ("update".equals(action)) {
int itemId = Integer.parseInt(request.getParameter("itemId"));
String itemName = request.getParameter("itemName");
double chargeStandard = Double.parseDouble(request.getParameter("chargeStandard"));
ChargeItem chargeItem = new ChargeItem();
chargeItem.setItem_id(itemId);
chargeItem.setItem_name(itemName);
chargeItem.setCharge_standard(chargeStandard);
int result = chargeItemDAO.updateChargeItem(chargeItem);
if (result > 0) {
request.setAttribute("successMessage", "收费项目更新成功!");
} else {
request.setAttribute("errorMessage", "收费项目更新失败,请稍后再试!");
}
} else if ("delete".equals(action)) {
int itemId = Integer.parseInt(request.getParameter("itemId"));
int result = chargeItemDAO.deleteChargeItem(itemId);
if (result > 0) {
request.setAttribute("successMessage", "收费项目删除成功!");
} else {
request.setAttribute("errorMessage", "收费项目删除失败,请稍后再试!");
}
}
doGet(request, response);
} catch (NumberFormatException e) {
request.setAttribute("errorMessage", "参数格式错误,请检查输入的数字格式是否正确!");
doGet(request, response);
}
}
}
LoginServlet.java
处理用户登录请求,验证手机号和密码,根据用户角色(admin 或 owner)重定向到相应首页,同时支持退出登录功能。
package com.tt.servlet;
import jakarta.servlet.annotation.WebServlet;
import com.tt.dao.UserDAO;
import com.tt.dao.UserDAOImpl;
import com.tt.entity.User;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import java.io.IOException;
import java.util.logging.Logger;
@WebServlet("/LoginServlet")
public class LoginServlet extends HttpServlet {
private static final Logger logger = Logger.getLogger(LoginServlet.class.getName());
private static final long serialVersionUID = 1L;
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String phone = request.getParameter("phone");
String password = request.getParameter("password");
System.out.println(phone+" " +password);
logger.info("用户尝试登录,手机号:" + phone);
UserDAO userDAO = new UserDAOImpl();
User user = userDAO.getUserByPhoneAndPassword(phone, password);
if (user!= null) {
logger.info("用户登录成功,用户信息:" + user);
HttpSession session = request.getSession(true);
session.setAttribute("user", user);
if ("admin".equals(user.getRole())) {
response.sendRedirect(request.getContextPath() + "admin_index.jsp");
} else {
response.sendRedirect(request.getContextPath() + "owner_index.jsp");
}
} else {
logger.warning("用户登录失败,手机号或密码错误,手机号:" + phone);
request.setAttribute("errorMessage", "手机号或密码错误,请重新登录!");
request.getRequestDispatcher(request.getContextPath() + "/login.jsp").forward(request, response);
}
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 处理退出登录逻辑,获取当前会话
HttpSession session = request.getSession(false);
if (session!= null) {
// 移除用户相关信息(这里以移除名为 "user" 的属性为例)
session.removeAttribute("user");
// 使会话失效
session.invalidate();
}
// 重定向到登录页面,假设登录页面路径为 /login.jsp,根据实际情况修改
response.sendRedirect(request.getContextPath() + "/login.jsp");
}
}
PaymentRecordQueryServlet.java
查询缴费记录,管理员可查看所有记录,业主只能查看自己的记录,确保数据访问的安全性与合理性。
package com.tt.servlet;
import com.tt.dao.PaymentRecordDAO;
import com.tt.dao.PaymentRecordDAOImpl;
import com.tt.entity.PaymentRecord;
import com.tt.entity.User;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import java.io.IOException;
import java.util.List;
@WebServlet("/PaymentRecordQueryServlet")
public class PaymentRecordQueryServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpSession session = request.getSession(false);
if (session!= null) {
try {
User user = (User) session.getAttribute("user");
PaymentRecordDAO paymentRecordDAO = new PaymentRecordDAOImpl();
List<PaymentRecord> paymentRecords;
if ("admin".equals(user.getRole())) {
paymentRecords = paymentRecordDAO.getAllPaymentRecords();
} else {
paymentRecords = paymentRecordDAO.getPaymentRecordsByUserId(user.getUser_id());
}
request.setAttribute("paymentRecords", paymentRecords);
request.getRequestDispatcher(request.getContextPath() + "payment_record_query.jsp").forward(request, response);
} catch (ClassCastException e) {
request.setAttribute("errorMessage", "用户信息获取出现异常,请重新登录!");
response.sendRedirect(request.getContextPath() + "/login.jsp");
}
} else {
response.sendRedirect(request.getContextPath() + "/login.jsp");
}
}
}
PaymentServlet.java
处理缴费请求,获取收费项目和缴费金额,校验参数后添加缴费记录,成功则跳转到缴费二维码页面,失败给出错误提示。
package com.tt.servlet;
import com.tt.dao.ChargeItemDAOImpl;
import com.tt.dao.PaymentRecordDAO;
import com.tt.dao.PaymentRecordDAOImpl;
import com.tt.entity.ChargeItem;
import com.tt.entity.PaymentRecord;
import com.tt.entity.User;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
@WebServlet("/PaymentServlet")
public class PaymentServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 设置请求字符编码为 UTF-8
request.setCharacterEncoding("UTF-8");
// 设置响应字符编码为 UTF-8
response.setContentType("text/html; charset=UTF-8");
try {
// 获取收费项目列表(此处可添加日志记录查看查询操作是否执行)
System.out.println("开始查询收费项目列表...");
ChargeItemDAOImpl chargeItemDAO = new ChargeItemDAOImpl();
List<ChargeItem> chargeItems = chargeItemDAO.getAllChargeItems();
request.setAttribute("chargeItems", chargeItems);
System.out.println("成功获取收费项目列表,数量:" + chargeItems.size());
// 获取缴费相关参数,进行格式校验(增加更详细的异常处理)
String itemIdStr = request.getParameter("itemId");
String paymentAmountStr = request.getParameter("paymentAmount");
if (itemIdStr == null || paymentAmountStr == null || itemIdStr.isEmpty() || paymentAmountStr.isEmpty()) {
throw new IllegalArgumentException("缴费参数不能为空,请检查输入!");
}
int itemId;
double paymentAmount;
try {
itemId = Integer.parseInt(itemIdStr);
paymentAmount = Double.parseDouble(paymentAmountStr);
} catch (NumberFormatException e) {
throw new IllegalArgumentException("缴费参数格式错误,请检查输入的参数格式是否正确!", e);
}
HttpSession session = request.getSession(false);
if (session!= null) {
User user = (User) session.getAttribute("user");
if (user == null) {
// 用户信息不存在,可能是会话异常等情况,重定向到登录页
System.out.println("用户信息在会话中不存在,重定向到登录页");
response.sendRedirect(request.getContextPath() + "/login.jsp");
return;
}
PaymentRecord paymentRecord = new PaymentRecord();
paymentRecord.setUser_id(user.getUser_id());
paymentRecord.setItem_id(itemId);
paymentRecord.setPayment_amount(paymentAmount);
paymentRecord.setPayment_time(new Date());
PaymentRecordDAO paymentRecordDAO = new PaymentRecordDAOImpl();
int result = paymentRecordDAO.addPaymentRecord(paymentRecord);
if (result > 0) {
// 缴费成功后,将缴费金额作为参数添加到重定向的URL中,同时格式化日期时间方便展示(可根据需求调整日期格式)
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String formattedPaymentTime = sdf.format(paymentRecord.getPayment_time());
System.out.println("缴费成功,用户:" + user.getUser_id() + ",缴费项目:" + itemId + ",金额:" + paymentAmount + ",时间:" + formattedPaymentTime);
response.sendRedirect(request.getContextPath() + "/qrcode.jsp?paymentAmount=" + paymentAmount);
} else {
request.setAttribute("errorMessage", "缴费失败,请稍后再试!");
request.getRequestDispatcher(request.getContextPath() + "/payment.jsp").forward(request, response);
System.out.println("缴费记录插入数据库失败,可能是数据库操作异常等原因");
}
} else {
System.out.println("未获取到有效的会话,重定向到登录页");
response.sendRedirect(request.getContextPath() + "/login.jsp");
}
} catch (IllegalArgumentException e) {
// 捕获参数相关异常,记录错误信息并转发到缴费页面提示用户
System.out.println("参数异常:" + e.getMessage());
request.setAttribute("errorMessage", e.getMessage());
request.getRequestDispatcher(request.getContextPath() + "/payment.jsp").forward(request, response);
} catch (ServletException | IOException e) {
// 捕获其他Servlet相关异常,记录详细错误信息(可考虑更完善的错误页面展示给用户)
System.out.println("Servlet执行出现严重错误:" + e.getMessage());
e.printStackTrace();
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "服务器内部出现错误,请联系管理员!");
} catch (Exception e) {
// 捕获其他未预期的异常,记录并返回通用错误信息给用户(可根据实际完善错误处理逻辑)
System.out.println("出现未知异常:" + e.getMessage());
e.printStackTrace();
request.setAttribute("errorMessage", "系统出现未知错误,请联系管理员!");
request.getRequestDispatcher(request.getContextPath() + "/payment.jsp").forward(request, response);
}
}
}
RegisterServlet.java
处理业主注册请求,校验手机号格式,添加业主信息到数据库,注册成功跳转至登录页,失败提示错误。
package com.tt.servlet;
import com.tt.dao.UserDAO;
import com.tt.dao.UserDAOImpl;
import com.tt.entity.User;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.regex.Pattern;
@WebServlet("/RegisterServlet")
public class RegisterServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String name = request.getParameter("name");
String buildingNumber = request.getParameter("buildingNumber");
String unitNumber = request.getParameter("unitNumber");
String roomNumber = request.getParameter("roomNumber");
String houseType = request.getParameter("houseType");
String carNumber = request.getParameter("carNumber");
String phone = request.getParameter("phone");
String password = request.getParameter("password");
String role = "owner"; // 这里默认注册为普通业主角色,可根据需求调整
// 简单校验手机号格式,这里只是简单判断是否是11位数字,实际应用中可使用更严格的校验规则
if (!Pattern.matches("\\d{11}", phone)) {
request.setAttribute("errorMessage", "手机号格式不正确,请重新输入!");
request.getRequestDispatcher(request.getContextPath() + "/register.jsp").forward(request, response);
return;
}
User user = new User();
user.setName(name);
user.setBuilding_number(buildingNumber);
user.setUnit_number(unitNumber);
user.setRoom_number(roomNumber);
user.setHouse_type(houseType);
user.setCar_number(carNumber);
user.setPhone(phone);
user.setPassword(password);
user.setRole(role);
UserDAO userDAO = new UserDAOImpl();
int result = userDAO.addUser(user);
if (result > 0) {
response.sendRedirect(request.getContextPath() + "/login.jsp");
} else {
request.setAttribute("errorMessage", "注册失败,请稍后再试!");
request.getRequestDispatcher(request.getContextPath() + "/register.jsp").forward(request, response);
}
}
}
五、运行效果
1.登录
2.管理员页面
3.收费管理页面
4.缴费记录页面查询
5.用户页面
6.用户缴费页面
7.用户缴费记录查询
七、心得体会
在完成本项目的过程中,不仅对 Java Web 开发技术有了更深入的理解和掌握,包括 JSP、Servlet、JDBC 等技术的实际应用,还提高了自己对复杂系统的设计和开发能力。从需求分析、技术选型到功能模块设计和数据库设计,每一个环节都需要严谨对待,任何一个小的疏忽都可能导致后续开发的困难。同时,在解决实际工程问题时,学会了运用所学知识设计多种解决方案,并通过查阅文献等方式寻求更好的替代方案,这对于提升自己的技术素养和解决问题的能力有很大帮助。此外,在开发环境的搭建和配置以及页面设计方面,也积累了宝贵的经验,明白了良好的用户体验和系统稳定性的重要性。总之,通过这个项目的实践,收获颇丰,也认识到自己在技术领域还有很多需要学习和提高的地方,将继续努力提升自己的专业能力。