基于javaweb+mysql的jsp+servlet家政服务系统(java+jsp+jquery+servlet+mysql)
'# 基于javaweb+mysql的jsp+servlet家政服务系统(java+jsp+jquery+servlet+mysql)
一、背景与问题
在传统的Web开发中,JSP(Java Server Pages)和Servlet作为经典的Java Web技术栈,仍然在中小型项目中占据重要地位。家政服务系统作为一个典型的业务场景,需要处理用户注册、服务展示、预约管理、订单支付等核心功能。
当前技术方案面临以下几个核心问题:
- 前端页面与后端逻辑耦合度高
- 跨域请求处理不完善
- 数据库查询性能优化不足
- 安全防护机制缺失
- 异步交互体验不友好
二、基本原理
本系统采用MVC(Model-View-Controller)架构模式,通过JSP负责视图层,Servlet处理业务逻辑,数据库存储数据。关键流程如下:
- 用户在JSP页面发起请求(如点击"预约服务"按钮)
- JavaScript通过JQuery发起AJAX请求(异步交互)
- Servlet接收请求,调用业务逻辑处理
- 数据库操作通过JDBC连接MySQL
- Servlet返回JSON数据给前端
- JSP页面根据返回数据更新DOM
三、环境准备
开发环境要求:
- JDK 1.8+
- Tomcat 9.x
- MySQL 8.x
- IDE(推荐IntelliJ IDEA)
关键配置文件:
<!-- web.xml -->
<web-app>
<servlet>
<servlet-name>UserServlet</servlet-name>
<servlet-class>com.example.UserServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>UserServlet</servlet-name>
<url-pattern>/user/*</url-pattern>
</servlet-mapping>
</web-app>四、核心实现
1. 数据库设计
-- 家政服务表
CREATE TABLE service (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(255) NOT NULL,
description TEXT,
price DECIMAL(10,2),
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- 用户表
CREATE TABLE user (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) NOT NULL UNIQUE,
password VARCHAR(100) NOT NULL,
email VARCHAR(100),
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- 预约表
CREATE TABLE booking (
id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT,
service_id INT,
booking_time DATETIME,
status ENUM('pending','confirmed','cancelled') DEFAULT 'pending',
FOREIGN KEY (user_id) REFERENCES user(id),
FOREIGN KEY (service_id) REFERENCES service(id)
);2. Servlet核心处理
// UserServlet.java
@WebServlet("/user/*")
public class UserServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String action = request.getPathInfo();
switch (action) {
case "/register":
registerUser(request, response);
break;
case "/login":
loginUser(request, response);
break;
default:
response.sendError(HttpServletResponse.SC_NOT_FOUND);
}
}
private void registerUser(HttpServletRequest request, HttpServletResponse response) {
String username = request.getParameter("username");
String password = request.getParameter("password");
// 验证用户名是否存在
String sql = "SELECT id FROM user WHERE username = ?";
try (PreparedStatement stmt = connection.prepareStatement(sql)) {
stmt.setString(1, username);
ResultSet rs = stmt.executeQuery();
if (rs.next()) {
response.getWriter().write("{\"error\":\"Username exists\"}");
return;
}
// 插入新用户
String insertSql = "INSERT INTO user (username, password) VALUES (?,?)";
try (PreparedStatement insertStmt = connection.prepareStatement(insertSql)) {
insertStmt.setString(1, username);
insertStmt.setString(2, password);
insertStmt.executeUpdate();
response.getWriter().write("{\"success\":true}");
}
} catch (SQLException e) {
response.getWriter().write("{\"error\":\"Database error\"}");
}
}
}3. 前端交互实现
<!-- register.jsp -->
<%@ page contentType="text/html;charset=UTF-8" %>
<html>
<head>
<title>注册</title>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
</head>
<body>
<form id="registerForm">
用户名:<input type="text" name="username" required><br>
密码:<input type="password" name="password" required><br>
<button type="submit">注册</button>
</form>
<div id="message"></div>
<script>
$('#registerForm').on('submit', function(e) {
e.preventDefault();
$.ajax({
url: '/user/register',
type: 'POST',
data: $(this).serialize(),
success: function(result) {
$('#message').text(result.success ? '注册成功' : '注册失败');
}
});
});
</script>
</body>
</html>五、完整案例:预约服务系统
项目结构
src/
├── com.example
│ ├── controller
│ │ └── BookingServlet.java
│ ├── model
│ │ └── Booking.java
│ └── dao
│ └── BookingDAO.java
web/
├── WEB-INF
│ └── web.xml
├── booking.jsp
└── styles.css核心代码示例
预约Servlet
// BookingServlet.java @WebServlet("/booking/*") public class BookingServlet extends HttpServlet { private static final long serialVersionUID = 1L; protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String action = request.getPathInfo(); switch (action) { case "/create": createBooking(request, response); break; case "/list": listBookings(request, response); break; default: response.sendError(HttpServletResponse.SC_NOT_FOUND); } } private void createBooking(HttpServletRequest request, HttpServletResponse response) { int userId = Integer.parseInt(request.getParameter("user_id")); int serviceId = Integer.parseInt(request.getParameter("service_id")); String bookingTime = request.getParameter("booking_time"); // 验证预约时间是否有效 if (isValidBookingTime(bookingTime)) { BookingDAO dao = new BookingDAO(); try { int id = dao.createBooking(userId, serviceId, bookingTime); response.getWriter().write("{\"id\":" + id + ",\"success\":true}"); } catch (SQLException e) { response.getWriter().write("{\"error\":\"Database error\"}"); } } else { response.getWriter().write("{\"error\":\"Invalid booking time\"}"); } } private boolean isValidBookingTime(String time) { // 实现时间有效性校验逻辑 return true; } }数据库访问层
// BookingDAO.java public class BookingDAO { private Connection connection; public BookingDAO() throws SQLException { // 初始化数据库连接 connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/home_service", "root", "password"); } public int createBooking(int userId, int serviceId, String bookingTime) throws SQLException { String sql = "INSERT INTO booking (user_id, service_id, booking_time) VALUES (?, ?, ?)"; try (PreparedStatement stmt = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) { stmt.setInt(1, userId); stmt.setInt(2, serviceId); stmt.setString(3, bookingTime); stmt.executeUpdate(); ResultSet rs = stmt.getGeneratedKeys(); if (rs.next()) { return rs.getInt(1); } return -1; } } }前端展示页面
<!-- booking.jsp --> <%@ page contentType="text/html;charset=UTF-8" %> <html> <head> <title>预约服务</title> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <style> .booking-list { margin-top: 20px; } </style> </head> <body> <h2>预约服务</h2> <form id="bookingForm"> <select name="service_id" required> <option value="">请选择服务</option> <!-- 动态加载服务列表 --> </select> <input type="datetime-local" name="booking_time" required> <button type="submit">预约</button> </form> <div class="booking-list" id="bookingList"></div> <script> // 加载服务列表 $.get('/service/list', function(data) { let select = $('#bookingForm select'); data.forEach(item => { select.append(`<option value="${item.id}">${item.name}</option>`); }); }); $('#bookingForm').on('submit', function(e) { e.preventDefault(); $.ajax({ url: '/booking/create', type: 'POST', data: $(this).serialize(), success: function(result) { if (result.success) { $('#bookingList').append( `<div>预约ID: ${result.id} 成功</div>` ); } else { alert(result.error); } } }); }); </script> </body> </html>
六、源码解析
1. Servlet处理流程
Servlet通过doPost方法处理请求,根据路径信息决定执行哪个业务逻辑。在createBooking方法中,首先进行预约时间有效性校验,然后调用DAO层完成数据库操作。
2. 数据库连接管理
DAO类在初始化时建立数据库连接,使用DriverManager.getConnection方法获取连接。注意在实际生产环境中应使用连接池(如HikariCP)来管理数据库连接。
3. 前端交互机制
使用JQuery实现AJAX请求,通过$.ajax方法发送POST请求。前端页面通过动态加载服务列表,实现与后端的异步交互。
七、进阶使用
1. 增强安全防护
- 使用Spring Security进行身份验证
- 对用户输入进行严格的校验(正则表达式)
- 使用PreparedStatement防止SQL注入
- 添加CSRF保护机制
2. 性能优化方案
- 使用数据库连接池(如HikariCP)
- 为频繁查询的字段添加索引
- 对高并发接口进行缓存(如使用Redis)
- 优化SQL查询语句(使用EXPLAIN分析执行计划)
3. 异步处理机制
- 对预约成功后发送通知等操作,使用消息队列(如RabbitMQ)
- 对耗时操作进行异步处理(使用CompletableFuture)
- 对大量数据查询进行分页处理
八、性能与工程实践
1. 性能优化策略
对频繁访问的数据库表添加索引:
CREATE INDEX idx_user_username ON user(username);配置数据库连接池参数:
HikariConfig config = new HikariConfig(); config.setJdbcUrl("jdbc:mysql://localhost:3306/home_service"); config.setUsername("root"); config.setPassword("password"); config.setMaximumPoolSize(10); config.setIdleTimeout(30000);
2. 异常处理机制
在Servlet中统一处理异常:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { // 业务逻辑 } catch (Exception e) { response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage()); } }
3. 安全防护措施
使用Spring Security配置:
@Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .anyRequest().authenticated() .and() .formLogin() .and() .logout().logoutSuccessUrl("/"); } }
九、常见问题与踩坑
1. 常见错误及解决方案
错误:Servlet配置未生效
- 原因:
web.xml配置错误或未正确部署 - 解决方案:检查
web.xml中servlet和servlet-mapping的配置,确保路径匹配
错误:数据库连接失败
- 原因:数据库URL、用户名或密码错误
- 解决方案:检查
DriverManager.getConnection的参数,确保数据库服务正在运行
错误:AJAX请求跨域问题
- 原因:前端页面和后端接口不在同一域
解决方案:在Servlet中添加CORS支持:
response.setHeader("Access-Control-Allow-Origin", "*"); response.setHeader("Access-Control-Allow-Methods", "GET, POST");
2. 安全风险分析
SQL注入风险
- 原因:未使用预编译语句
改进方案:使用PreparedStatement替代Statement
String sql = "SELECT * FROM user WHERE username = ?"; try (PreparedStatement stmt = connection.prepareStatement(sql)) { stmt.setString(1, username); ResultSet rs = stmt.executeQuery(); }
XSS攻击防护
- 原因:未对用户输入进行过滤
改进方案:使用HTML转义处理
String safeHtml = Jsoup.clean(userInput, Whitelist.basic());
十、最佳实践
1. 项目结构推荐
src/
├── main
│ ├── java
│ │ └── com.example
│ │ ├── controller
│ │ ├── model
│ │ └── dao
│ └── webapp
│ ├── WEB-INF
│ └── static
└── test
└── java
└── com.example2. 接口设计规范
- 使用RESTful风格设计URL路径
- 所有接口返回JSON格式数据
错误信息包含错误代码和描述
{ "code": 200, "message": "成功", "data": {} }
3. 代码规范建议
- 使用日志框架(如SLF4J)记录日志
- 对核心业务逻辑进行单元测试
- 使用代码规范工具(如Checkstyle)进行代码检查
十一、总结
基于JSP+Servlet+MySQL的家政服务系统是一个典型的Java Web项目案例,其核心在于理解MVC架构模式和前后端分离的实现方式。通过本篇文章的深入探讨,我们了解到:
- 如何构建完整的Web应用架构
- 不同技术组件的协作机制
- 常见的开发陷阱及解决方案
- 安全防护和性能优化的策略
- 实际项目中的最佳实践
这种技术方案适用于中小型项目,尤其适合需要快速开发、功能较为明确的业务场景。但在处理高并发、复杂业务逻辑或需要微服务架构时,建议考虑使用Spring Boot、Spring Cloud等现代框架进行重构。对于新手开发者,建议从简单的项目开始实践,逐步掌握各技术组件的使用和协作方式。
评论已关闭