ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

基于JSP的在线家政网系统设计与实现全流程详解

基于JSP的在线家政网系统设计与实现全流程详解 简介《基于JSP的在线家政网设计与实现》是一份面向Java Web课程设计、毕业设计及家政类小型系统开发参考的完整论文文档。内容覆盖可行性分析、总体设计原则、系统分析与结构化模块设计重点展开家政预约、家教预约、在线求职及个人后台申请查看等功能并介绍JSP技术、B/S模式、MyEclipse开发平台与SQL Server 2008数据库设计过程数据库部分从概念结构、逻辑结构到表设计逐层说明同时给出功能模块图和前后台信息读取、录入的实现思路。压缩包内共1个docx文件总大小1.02MB为可直接阅读的论文正文适合需要撰写设计说明或快速梳理系统结构的读者。已有126人学习下载。文档从项目背景到发展前景梳理完整可借此了解家政网站的设计脉络、关键技术选型与模块落地方式作为方案撰写和答辩准备的实用参考。1. 基于jsp的在线家政网先想清楚这是个什么系统再动手基于jsp的在线家政网设计与实现听起来是毕业设计题目其实就是家政公司把雇主下单、阿姨接单、派单调度和售后评价从电话本、Excel表挪到Web端的一整套Java Web小系统。JSP在这里承担所有动态页面的渲染Servlet承担请求控制MySQL负责存储Tomcat负责运行整个链路没有引入Spring这种重型框架反而适合快速交付和答辩讲解。这篇笔记按我自己做过类似项目的顺序拆目录结构怎么搭、数据库怎么落表、JSP页面交互怎么处理、部署时哪里最容易翻车。适合正在写毕设的学生、需要给中小家政公司做内网系统的一线开发者。跟着章节走你能拿到一套能直接抄作业的骨架也能避开那些只听课不实操根本遇不到的坑。2. 搭JSP项目骨架目录结构、web.xml与JDBC连接池的具体选型2.1 Model2架构下JSP、Servlet、DAO三层各自的职责边界家政网这类系统最忌讳把Java代码直接塞进JSP页面里。很多教材还在教% %脚本片段但真实项目里页面一多HTML和Java混在一起改一个样式都可能碰到数据库代码属于给自己埋雷。我习惯用Model2架构也就是JSP只做视图里面用EL表达式和JSTL标签展示数据Servlet只做控制器负责接收请求、调用业务方法、决定跳转到哪个页面数据访问全部收敛到DAO层每一个表对应一个DAO类。这样分工之后有一个很实际的收益接单、派单这种订单状态变化频繁的操作可以只改Servlet和DAOJSP页面完全不动。比如雇主提交订单的流程JSP里一个表单POST到OrderServletServlet把参数封装成实体调用OrderDAO.insert()成功后sendRedirect到订单列表页。这条链路清晰答辩时讲起来也顺。2.2 建工程手动放lib还是用Maven两条路的取舍建JSP工程有两种常见做法。第一种是手动方式IDEA里新建一个普通Java Web项目在webapp/WEB-INF/lib下直接放mysql-connector-java.jar、jstl.jar、standard.jar然后右键添加到Library。这种方式对毕业设计很直观导师点开目录就能看到所有依赖不用理解Maven坐标体系。第二种是Maven方式用pom.xml声明依赖适合要长期维护、需要一键打包的场景。我一般推荐新手选Maven因为依赖版本冲突少而且clean package之后能直接拿到war包丢进Tomcat。一个典型的结构是这样的home-service/ ├── pom.xml └── src └── main ├── java │ └── com/homeservice │ ├── dao # 数据访问层 │ ├── model # 实体类 │ ├── servlet # 控制器 │ └── util # DBUtil等工具类 ├── resources │ └── db.properties # 数据库连接配置 └── webapp ├── WEB-INF │ ├── web.xml │ └── jsp # 受保护的JSP页面 ├── css ├── js ├── uploads # 图片上传目录 └── index.jsp这里有一个容易忽略的点WEB-INF/jsp目录下的页面不能通过浏览器直接URL访问必须由Servlet内部forward跳转过去。好处是权限控制更安全比如后台管理页面放在WEB-INF/jsp/admin下未登录用户直接访问只会得到404。坏处是新人第一次跑通时会以为项目坏了其实路径没写错只是访问方式变了。如果用Mavenpom.xml里的核心依赖大概是这几样dependencies dependency groupIdjavax.servlet/groupId artifactIdjavax.servlet-api/artifactId version4.0.1/version scopeprovided/scope /dependency dependency groupIdjavax.servlet/groupId artifactIdjstl/artifactId version1.2/version /dependency dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version8.0.33/version /dependency /dependenciesservlet-api的scope必须设为provided因为Tomcat自带了Servlet容器实现如果打成war包时把这依赖也打进去会和Tomcat自带的类冲突启动时直接报NoSuchMethodError或者类加载器异常。JSTL必须显式引入否则JSP里的c:forEach标签会全部报错。2.3 web.xml配置Servlet映射路径与Session超时时间web.xml是整个项目的注册中心。Servlet 3.0以上虽然支持注解方式WebServlet(/order)但很多教材和答辩模板还是用XML配置我建议两种都掌握。XML的好处是能集中看到所有请求路径的映射关系排查404时非常方便。web-app xmlnshttp://xmlns.jcp.org/xml/ns/javaee xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd version4.0 display-nameHomeService/display-name welcome-file-list welcome-fileindex.jsp/welcome-file /welcome-file-list servlet servlet-nameOrderServlet/servlet-name servlet-classcom.homeservice.servlet.OrderServlet/servlet-class /servlet servlet-mapping servlet-nameOrderServlet/servlet-name url-pattern/order/url-pattern /servlet-mapping session-config session-timeout30/session-timeout /session-config /web-appurl-pattern/order/url-pattern表示所有http://localhost:8080/home/order的POST或GET请求都进入OrderServlet。注意项目部署后如果不改Tomcat的appBase默认访问路径是http://localhost:8080/工程名/order很多404就是因为忘了带工程名。session-timeout单位是分钟家政网的雇主端一般30分钟合适后台管理端可以缩短到15分钟。2.4 JDBC连接池DBUtil与最容易报错的数据库连接参数JSP项目里最简单的数据库访问是DriverManager.getConnection()但每次请求都创建连接在高并发下很快就会把MySQL的连接数打满。我习惯在工具类里做一个轻量连接池不引第三方框架用ThreadLocal加一个静态队列模拟。当然正规做法是引Druid或C3P0但毕业设计阶段自己写一个简单的能讲清楚原理反而加分。public class DBUtil { private static String url; private static String username; private static String password; private static LinkedListConnection pool new LinkedList(); static { try { Class.forName(com.mysql.cj.jdbc.Driver); url jdbc:mysql://localhost:3306/home_service ?useSSLfalseserverTimezoneAsia/ShanghaicharacterEncodingutf8; username root; password 123456; for (int i 0; i 5; i) { pool.add(DriverManager.getConnection(url, username, password)); } } catch (Exception e) { e.printStackTrace(); } } public static Connection getConnection() { if (pool.isEmpty()) { try { return DriverManager.getConnection(url, username, password); } catch (SQLException e) { throw new RuntimeException(数据库连接失败, e); } } return pool.removeFirst(); } public static void close(Connection conn, PreparedStatement ps, ResultSet rs) { try { if (rs ! null) rs.close(); } catch (SQLException ignored) {} try { if (ps ! null) ps.close(); } catch (SQLException ignored) {} if (conn ! null) { try { pool.add(conn); } catch (Exception ignored) {} } } }这段代码里最值得注意的是JDBC URL带了三个参数。useSSLfalse是为了避免MySQL 8驱动和MySQL 5.7版本之间的SSL握手警告serverTimezoneAsia/Shanghai是必须的不加的话MySQL 8驱动会报The server time zone value йʱ is unrecognized这是从MySQL 8开始强制校验时区导致的characterEncodingutf8保证数据库读写中文不乱码。连接归还时把conn放回队列而不是真正关闭这就是最小连接池的思路。3. 家政网数据库设计与核心模块用户、订单、评价怎么落表3.1 实体关系梳理雇主、阿姨、服务分类与订单状态机家政网的业务实体其实不多核心是四张表用户表、服务分类表、订单表、评价表。用户表用role字段区分雇主和阿姨是常见做法。如果拆成两张表每次查询订单时要UNION两张表再关联SQL复杂度直接上一个台阶对一个小型系统来说得不偿失。订单表是整个系统的核心。一个订单从产生到结束状态流转必须清晰雇主下单后是WAIT_ACCEPT待接单阿姨接单后变成ACCEPTED已接单上门服务中改成SERVING服务中完成之后是FINISHED已完成。再加一个CANCELLED取消状态兜底。这些状态建议在Java代码里定义成常量类不要散落在各个Servlet里写魔法数字。评价表关联订单和用户保证一个订单只能有一条评价通过订单表主键做唯一约束来实现。这里有个实际场景完成订单后雇主需要填写评分和文字评价如果不对评价表做唯一约束用户重复提交就会产生多条记录导致统计均价出错。3.2 建表SQL与索引设计个人信息展示页面的查询前提设计表结构时我习惯把主键统一命名为id所有外键字段用xxx_id的格式这样JSP页面上用EL表达式取值时心智负担最小。下面四张表是家政网最精简的起步方案。CREATE TABLE user ( id INT NOT NULL AUTO_INCREMENT, username VARCHAR(50) NOT NULL, password VARCHAR(100) NOT NULL, role TINYINT NOT NULL DEFAULT 0 COMMENT 0雇主 1阿姨 2管理员, real_name VARCHAR(50) DEFAULT NULL, phone VARCHAR(20) DEFAULT NULL, avatar VARCHAR(255) DEFAULT NULL, address VARCHAR(255) DEFAULT NULL, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_username (username) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE service_category ( id INT NOT NULL AUTO_INCREMENT, name VARCHAR(50) NOT NULL, description VARCHAR(500) DEFAULT NULL, icon VARCHAR(255) DEFAULT NULL, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE orders ( id INT NOT NULL AUTO_INCREMENT, order_no VARCHAR(32) NOT NULL, employer_id INT NOT NULL, worker_id INT DEFAULT NULL, category_id INT NOT NULL, appointment_time DATETIME NOT NULL, address VARCHAR(255) NOT NULL, remark VARCHAR(500) DEFAULT NULL, status VARCHAR(20) NOT NULL DEFAULT WAIT_ACCEPT, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_order_no (order_no), KEY idx_employer_status (employer_id, status), KEY idx_worker_status (worker_id, status) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE review ( id INT NOT NULL AUTO_INCREMENT, order_id INT NOT NULL, employer_id INT NOT NULL, rating TINYINT NOT NULL DEFAULT 5, content VARCHAR(1000) DEFAULT NULL, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_order_id (order_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;字符集一定要用utf8mb4因为utf8在MySQL里最多存3个字节用户评价里如果出现emoji表情直接插入就会报Incorrect string value错误这是线上最容易出现的低级翻车点。订单号order_no用唯一索引不要直接用自增id当订单号暴露给用户否则别人能通过id推断出你们一天有多少单。索引设计上orders表的核心查询场景是“某个雇主查看自己待接单的订单”所以建了(employer_id, status)复合索引。查询时WHERE employer_id ? AND status WAIT_ACCEPT能直接命中索引避免全表扫描。对个人信息展示页面来说用户表的主键索引已经足够不需要额外加索引但这张表用username做登录查询UNIQUE KEY起到了索引作用登录接口不会慢。3.3 DAO层实现PreparedStatement参数化与订单并发修改的边界DAO层写法直接决定了系统能不能扛住多人同时操作订单。一定不能用字符串拼接SQL比如SELECT * FROM user WHERE username name 这就是典型的SQL注入入口。JSP项目里全部改用PreparedStatement占位符简单有效。public class OrderDAO { public ListOrder findByEmployerAndStatus(int employerId, String status) { String sql SELECT * FROM orders WHERE employer_id ? AND status ? ORDER BY create_time DESC; ListOrder list new ArrayList(); try (Connection conn DBUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql)) { ps.setInt(1, employerId); ps.setString(2, status); try (ResultSet rs ps.executeQuery()) { while (rs.next()) { Order o new Order(); o.setId(rs.getInt(id)); o.setOrderNo(rs.getString(order_no)); o.setAppointmentTime(rs.getTimestamp(appointment_time)); o.setStatus(rs.getString(status)); o.setAddress(rs.getString(address)); list.add(o); } } } catch (SQLException e) { e.printStackTrace(); } return list; } }setInt和setString这一类方法会把参数转义后再拼进SQL注入代码只会被当成普通字符串处理。这个写法在代码审查时也是最容易得分的点因为教科书上一再强调一定要用PreparedStatement真正做到的作业反而不多。订单接单操作有一个必须处理的并发边界。两个阿姨同时点击同一个待接单订单时如果各自执行UPDATE orders SET worker_id?, statusACCEPTED WHERE id?可能导致两个人同时接单成功。正确做法是SQL里带上当前状态条件public int acceptOrder(int orderId, int workerId) { String sql UPDATE orders SET worker_id?, statusACCEPTED WHERE id? AND statusWAIT_ACCEPT; try (Connection conn DBUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql)) { ps.setInt(1, workerId); ps.setInt(2, orderId); return ps.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); return 0; } }返回的executeUpdate()值等于1说明有且只有一个人抢单成功等于0说明订单状态已经变了这次更新失败。这种通过状态条件实现乐观锁的方式比先查询再更新的方式可靠得多而且代码很简单值得在答辩时专门提一句。4. JSP页面与前后端交互列表渲染、个人信息展示与图片坐标定位4.1 首页服务列表与JSTL/EL渲染让JSP页面不写Java代码JSP页面里出现% java代码 %是新手最容易犯的错。正确做法是把查询结果放到request.setAttribute()里然后JSP页面用EL表达式和JSTL标签渲染。首页展示服务分类和最新订单核心代码长这样% page contentTypetext/html;charsetUTF-8 languagejava % % taglib prefixc urihttp://java.sun.com/jsp/jstl/core % % taglib prefixfn urihttp://java.sun.com/jsp/jstl/functions % html headtitle在线家政网/title/head body h1在线家政网/h1 div classcategory-list c:forEach items${categoryList} varcat div classcategory-item img src${cat.icon} alt${cat.name} / span${cat.name}/span p${fn:substring(cat.description, 0, 30)}.../p /div /c:forEach /div /body /htmlitems${categoryList}里的数据来自Servlet端request.setAttribute(categoryList, list)EL表达式会自动调用List的迭代器。fn:substring是JSTL函数库里的字符串截断函数当服务描述过长时只在首页显示前30个字符避免页面被撑得乱七八糟。这段JSP代码里没有任何Java语法页面美工和后台开发可以完全分开这也是JSP即便老在小团队里依然有生命力的原因。4.2 个人信息展示页面的图片坐标定位用数据属性传坐标前端动态计算JSP图片坐标定位的实际需求常常出现在家政人员信息展示页给阿姨上传一张服务范围示意图图片上几个坐标点标记了雇主小区的位置。后端不要试图在服务端算像素坐标因为浏览器窗口大小、图片实际渲染尺寸都不固定算法写在Java里纯属自找麻烦。正确做法是JSP把坐标数据以百分比形式输出到标签的data属性前端用JavaScript根据图片实际宽度计算位置。div classmap-wrapper img idserviceMap src${worker.mapUrl} alt服务范围 / c:forEach items${worker.markerList} varmarker span classmarker >window.addEventListener(DOMContentLoaded, function () { var img document.getElementById(serviceMap); var markers document.querySelectorAll(.marker); img.onload function () { var naturalWidth img.naturalWidth; var naturalHeight img.naturalHeight; markers.forEach(function (m) { var x parseFloat(m.getAttribute(data-x)) / 100 * naturalWidth; var y parseFloat(m.getAttribute(data-y)) / 100 * naturalHeight; m.style.left x px; m.style.top y px; }); }; });坐标定位必须等图片加载完成后才能算所以代码写在img.onload回调里。用百分比而不是固定像素是为了适配不同分辨率的屏幕。如果上传的图片是750像素宽标注点在中间>window.onload function () { if (window.location.search.indexOf(refreshed1) -1) { window.location.href window.location.pathname ?refreshed1; } };判断refreshed1这个参数刷新后带上标记下一次onload不会再次触发跳转彻底避免死循环。不过这种整页刷新的体验一般家政网订单状态更重要页面停留在一个订单详情上雇主希望看到阿姨何时接单。我一般用Ajax轮询实现局部刷新每5秒查一次订单状态状态变化后只更新按钮和提示文字。function pollOrderStatus(orderId) { var timer setInterval(function () { $.ajax({ url: /home/order/status?id orderId, type: GET, dataType: json, success: function (res) { if (res.status ACCEPTED) { $(#statusText).text(已接单); $(#acceptBtn).hide(); clearInterval(timer); } } }); }, 5000); }轮询间隔设在5秒比较合理。设1秒的话几十个用户同时在线Tomcat线程池会被大量HTTP请求占满其他页面打开也会变卡。这个接口返回JSON时注意Content-Type要设置成application/json;charsetUTF-8否则前端拿到的字符串会被浏览器误判成HTML导致res.status永远是undefined。4.4 前端样式的取舍要不要给JSP套饿了么Element UI并排组件很多同学看到“饿了么Element UI图标”很心动想在JSP项目里也套上Vue组件库。这里要说清楚Element UI是Vue 2的组件库想在JSP页面里用完整组件必须先引入Vue.js再初始化Vue实例这意味着JSP里必须有一块区域交给Vue管理数据渲染的活就要从JSTL切换到Vue的v-for等于同一页里两套渲染引擎并存维护成本翻倍。我的建议是分需求。如果只是想要几个好看的图标比如电话图标、地址图标完全可以用Element UI的图标库独立产物element-icons.css它就是一堆字体图标不依赖Vue在JSP头部引入CSS后直接用i classel-icon-phone/i即可。如果确实需要下拉框、日期选择器这类复杂组件那就老实引入Vue并且把所有需要动态渲染的部分圈在一个div idapp里JSP标签只负责给Vue提供初始数据两者别混在一个DOM节点里。这套组合方案我在项目里验证过比纯手写CSS省时间又不会让整个页面变成Vue单页应用。5. 部署与常见问题排查Tomcat启动、中文乱码、404路径的避坑清单5.1 Tomcat启动闪退先看日志再谈别的启动Tomcat后窗口一闪而过这事看起来像玄学其实原因非常具体。常见的情况是8080端口被占用比如之前残留的Tomcat进程没杀掉或者别的服务占了端口。解决办法是切换到Tomcat的bin目录下用命令行启动让错误信息直接打在控制台上。cd /opt/tomcat/bin ./catalina.sh runcatalina.sh run会以前台模式启动所有的异常堆栈都会输出到当前终端。如果是端口占用日志里会明确写出Port 8080 required by Tomcat ... is already in use。这时候先查占用进程再决定是杀掉旧进程还是改端口。netstat -ano | grep 8080改端口的话编辑Tomcat的conf/server.xml找到Connector port8080那一行把端口改成8081同时JSP页面里的所有请求路径也要跟着改。记住端口一旦改动之前写死的http://localhost:8080地址全部失效这是排查404时最容易被忽略的一点。5.2 JSP中文乱码从请求参数到响应输出要过三层编码中文乱码在JSP项目里几乎人人遇到。现象是页面上的中文全是问号或者是POST表单提交到Servlet后数据变乱码。原因很清晰JSP页面本身的编码、HTTP请求的编码、HTTP响应的编码三层中任何一层不一致中文就会乱。JSP页面顶部必须写明编码% page contentTypetext/html;charsetUTF-8 languagejava %这行设置的是响应编码。单靠它还不够POST请求体里的参数编码由Tomcat决定Tomcat 8以上默认URIEncoding是UTF-8但GET请求的查询参数中文、POST表单的中文仍然可能出问题。最稳妥的方式是在Servlet处理任何请求之前统一设置request.setCharacterEncoding(UTF-8); response.setContentType(text/html;charsetUTF-8);第一行必须在读取任何request.getParameter()之前调用否则参数已经被Tomcat按默认编码解析过了再设置也来不及。如果表单提交后还是乱码检查一下页面form标签有没有加accept-charsetUTF-8以及数据库连接URL里有没有characterEncodingutf8乱码往往是这三个地方各漏了一个导致的。5.3 图片上传后404虚拟目录映射与路径参数一个都不能少家政网里雇主上传头像、阿姨上传服务图片图片保存后刷新页面却404。这通常不是代码逻辑问题而是文件保存的绝对路径和Web应用访问路径对不上。request.getServletContext().getRealPath(/uploads)拿到的目录在Tomcat的webapps/工程名/uploads下这个目录在开发环境能用但每次重新部署war包时会被整体清除之前上传的图片全部消失。我一般在上传图片时不往应用目录里写而是指定一个外部绝对路径比如/data/home_service/uploads然后在Tomcat的server.xml里增加虚拟目录映射Host namelocalhost appBasewebapps unpackWARstrue autoDeploytrue Context path/uploads docBase/data/home_service/uploads / /Host配置之后JSP页面里图片的src/uploads/avatar_123.jpg就能正常显示了。这个做法的好处是图片和数据分离重新部署应用不会删掉用户上传的文件。要注意docBase指向的目录必须存在否则启动时Tomcat会报错拒绝启动。上传代码里路径拼接时经常出现多一个斜杠或少一个斜杠的问题/data/home_service/uploads/加avatar_123.jpg和/data/home_service/uploads加/avatar_123.jpg拼出来的路径都对但两种写法混着用就会得到双斜杠路径。5.4 JDBC连接失败MySQL8驱动参数和连接池泄漏两个隐藏原因部署环境换成MySQL 8后原来的JDBC连接代码报错Public Key Retrieval is not allowed这个错误在MySQL 8默认的caching_sha2_password认证插件下最常见。解决方式是在JDBC URL上增加一个参数String url jdbc:mysql://localhost:3306/home_service ?useSSLfalseallowPublicKeyRetrievaltrueserverTimezoneAsia/ShanghaicharacterEncodingutf8;allowPublicKeyRetrievaltrue允许客户端向服务器请求公钥用于密码加密传输。这个参数在MySQL 5.7下没有影响加上无妨。另一个坑是连接池泄漏代码里拿了Connection但异常时没有归还连接池里的连接被慢慢消耗光现象就是系统运行几个小时后突然所有页面报数据库连接超时。排查方法很简单在DBUtil.close()里打印连接池剩余数量tail -f /opt/tomcat/logs/catalina.out | grep pool size如果日志显示剩余连接数持续下降且不回升基本可以断定哪里少写了close()。我常用的排查方式是检查所有DAO方法里有没有在finally块中关闭资源或者是否都用上了try-with-resources。连池里的连接只是借出用完之后必须归还这是JSP项目面试时高频考点也是线上事故高发点。6. 验证方法进阶用curl脚本和并发压测给家政网把关6.1 curl冒烟脚本五分钟验证核心流程是否通JSP项目写完不要只靠浏览器点点点。我习惯启动Tomcat后用curl把核心流程串一遍登录、下单、接单、评价每一步都校验HTTP状态码和返回内容。用一个bash脚本就能完成冒烟测试# 登录雇主账号并保存Cookie curl -s -c cookies.txt -X POST http://localhost:8080/home/login \ -d usernameemployer01password123456 -o /dev/null -w %{http_code}\n # 创建订单 curl -s -b cookies.txt -X POST http://localhost:8080/home/order/create \ --data-urlencode category_id1 \ --data-urlencode appointment_time2025-03-20 10:00:00 \ --data-urlencode address幸福小区2号楼 \ --data-urlencode remark需要保洁2小时 -o /dev/null -w %{http_code}\n # 查询待接单订单列表 curl -s -b cookies.txt http://localhost:8080/home/order/list?statusWAIT_ACCEPT | grep 幸福小区-c cookies.txt保存会话Cookie-b cookies.txt在后续请求中携带这模拟了浏览器登录后的状态。--data-urlencode会处理URL编码中文地址不会在传输过程中变成乱码。第三步检查返回页面里能不能搜到“幸福小区”如果搜不到说明订单创建后没有正确落到列表里问题大概率出在DAO的SQL或Servlet参数封装环节。6.2 并发下单场景的验证技巧看更新行数而不只看结果家政网的核心并发场景是多个阿姨同时抢一个订单。验证乐观锁写没写对用一段简单的并发测试脚本就够了for i in $(seq 1 20); do curl -s -b cookies.txt -X POST http://localhost:8080/home/order/accept \ -d order_id101 -o /dev/null done wait20个并发请求同时尝试接单最后去数据库查这条订单的worker_id正常情况下只会被一个阿姨抢到。如果发现worker_id变了多次说明UPDATE ... WHERE statusWAIT_ACCEPT的条件没写对或者多个请求读到了同一份旧状态。这里最关键的验证点不是看谁接单成功而是看失败请求的影响行数是否为0这才证明乐观锁真正生效。我做这类JSP项目最大的教训就是把所有逻辑都堆在JSP里到最后改一个页面要牵连三处代码。现在每写一个功能都会先问自己这个数据该在DAO里查还是该在Servlet里处理JSP只负责把结果摆上去。你接手或重写家政网时也照这个原则走后面加功能、换前端、接支付都会省力很多。希望帮到你。本文还有配套的精品资源点击获取
返回列表