ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Java Web CRM系统实战:Servlet+JSP+JDBC全链路解析

Java Web CRM系统实战:Servlet+JSP+JDBC全链路解析 简介这是一套基于Java技术栈开发的客户关系与进销存一体化管理系统面向Java初学者及中小型企业管理软件学习者适用于课程设计、毕业项目或企业轻量级OA系统原型开发。系统覆盖客户全生命周期管理含VIP、签约、潜在、放弃等客户分类、日常办公流程OA模块以及核心进销存功能入库、出库、库存查询具备完整业务闭环能力。资源包共114个文件含36个Java源码文件构成主体逻辑47个JAR包提供Spring 4.0、MyBatis 3.2、Jackson、EhCache、MySQL驱动等关键依赖22个XML配置文件支撑框架整合与SQL映射辅以JSP页面和Properties属性配置整体压缩包大小为14.71MB。目前已有60人学习下载读者可直接导入IDE运行调试获得结构清晰的MVC分层代码、典型企业级框架集成实践、数据库表设计参考及完整的客户库存双主线业务实现方案。1. 一个能跑起来的 Java 客户关系管理系统不是 Demo是能填客户、查跟进、导数据的真实业务入口你下载到一个叫java客户关系管理系统.rar的压缩包双击解压后看到src/、WebContent/、lib/和一堆.class文件——这不是教学用的“Hello CRM”小练习而是典型基于 Servlet JSP JDBC 构建的轻量级企业级 CRM 骨架。它不依赖 Spring Boot 自动装配也不用 Maven 一键拉包但正因如此它成了 Java 初中级开发者理解「请求怎么从浏览器进到数据库、页面如何动态拼接、权限怎么靠 session 控制」最扎实的沙盒。适合刚学完 JDBC 和 JSP 的人在本地 Tomcat 上部署、改字段、加按钮、连真实 MySQL也适合面试前一周想快速串起「Java Web 全链路」的人从web.xml的 servlet-mapping到CustomerDao.java里的 PreparedStatement 防 SQL 注入再到list.jsp里用 JSTLc:forEach渲染客户列表——所有环节都裸露可调试。它不炫技但每行代码都在回答「Java Web 应用到底长什么样」。2. 用标准 Java Web 技术栈在本地跑通 CRM 的最小命令与结构验证2.1 确认 JDK 与 Tomcat 版本兼容性JDK 8 是当前最稳的基线这个系统大概率编译于 JDK 1.8即 JDK 8因为其web.xml中version2.5或3.0、lib/下常见servlet-api-2.5.jar或jsp-api-2.1.jar且无module-info.java。若你本地已装 JDK 17 或 21不要直接运行——Tomcat 9 可兼容 JDK 17但该系统若含javax.*包如javax.servlet.http.HttpServlet而非jakarta.*则必须降级或启用 Jakarta 迁移工具。最稳妥做法是单独安装 JDK 8u202官网归档版并配置环境变量# Linux/macOS 示例~/.bashrc 或 ~/.zshrc export JAVA_HOME/opt/jdk1.8.0_202 export PATH$JAVA_HOME/bin:$PATH提示执行java -version输出必须为1.8.0_202且javac -version一致。若java -version显示 17 但javac -version显示 8说明 PATH 混乱需彻底清理旧 JDK 路径。2.2 解压后直读web.xml定位核心 Servlet 与 URL 映射路径进入解压目录打开WebContent/WEB-INF/web.xml。重点看servlet和servlet-mapping块。典型结构如下servlet servlet-nameCustomerServlet/servlet-name servlet-classcom.crm.servlet.CustomerServlet/servlet-class /servlet servlet-mapping servlet-nameCustomerServlet/servlet-name url-pattern/customer/url-pattern /servlet-mapping这意味着访问http://localhost:8080/your-app-name/customer将触发com.crm.servlet.CustomerServlet类的doGet()或doPost()方法。注意url-pattern值——它决定了你在浏览器输入的路径也是后续测试接口的基础。若url-pattern是/cust那你就不能访问/customer否则 404。2.3 部署到 Tomcat 并验证基础服务是否启动成功将整个解压后的文件夹如crm-system/直接复制到 Tomcat 的webapps/目录下不要嵌套子文件夹。启动 Tomcat# Linux/macOS $CATALINA_HOME/bin/startup.sh # Windows %CATALINA_HOME%\bin\startup.bat等待日志输出Server startup in [xxx] ms后访问http://localhost:8080/crm-system/crm-system为文件夹名。若看到登录页常见login.jsp或 404说明部署成功若报HTTP Status 500则进入下一步排查。注意Tomcat 默认端口为 8080。若被占用修改conf/server.xml中Connector port8080 .../为8081重启后访问http://localhost:8081/crm-system/。2.4 快速验证数据库连接用CustomerDao.java中的 JDBC URL 手动连库打开src/com/crm/dao/CustomerDao.java路径可能略有差异如dao.impl.CustomerDaoImpl查找类似以下代码private static final String URL jdbc:mysql://localhost:3306/crm_db?useUnicodetruecharacterEncodingUTF-8; private static final String USER root; private static final String PASSWORD 123456;用命令行 MySQL 客户端验证mysql -h localhost -P 3306 -u root -p123456 -e USE crm_db; SHOW TABLES;若返回客户表名如t_customer说明库存在且账号密码正确若报Unknown database crm_db需手动创建库并导入 SQL 文件通常在sql/或db/目录下文件名如crm_init.sqlmysql -u root -p -e CREATE DATABASE IF NOT EXISTS crm_db DEFAULT CHARSET utf8mb4; mysql -u root -p crm_db sql/crm_init.sql提示SQL 文件中若含DROP TABLE IF EXISTS请确保目标库无重要数据若执行报错Incorrect string value说明 SQL 文件编码非 UTF-8用 VS Code 以 UTF-8 无 BOM 重新保存后再导入。3. 修改登录逻辑与客户列表展示从硬编码校验到真实数据库查询3.1 登录功能改造把LoginServlet中的用户名密码比对改为 JDBC 查询原始LoginServlet.java常见写法是硬编码校验// ❌ 危险不可用于生产 if (admin.equals(username) 123.equals(password)) { request.getSession().setAttribute(user, username); response.sendRedirect(main.jsp); }应替换为调用UserDao查询数据库// ✅ 安全做法查库验证 UserDao userDao new UserDao(); // 假设已实现 User user userDao.findByUsernameAndPassword(username, password); if (user ! null) { request.getSession().setAttribute(user, user); // 存完整 User 对象含 id、role 等 response.sendRedirect(main.jsp); } else { request.setAttribute(error, 用户名或密码错误); request.getRequestDispatcher(login.jsp).forward(request, response); }对应UserDao.java需实现public User findByUsernameAndPassword(String username, String password) { String sql SELECT id, username, password, role FROM t_user WHERE username ? AND password ?; // 注意实际项目应加密存储密码此处为演示用明文仅限学习环境 return query(sql, User.class, username, password); // query() 为通用 JDBC 查询方法 }3.2 客户列表页list.jsp的 JSTL 动态渲染与分页参数传递打开WebContent/list.jsp确认是否使用 JSTL 标签库。顶部应有% taglib prefixc urihttp://java.sun.com/jsp/jstl/core % % taglib prefixfmt urihttp://java.sun.com/jsp/jstl/fmt %客户表格主体应为table border1 tr th客户ID/thth姓名/thth电话/thth邮箱/thth操作/th /tr c:forEach items${customerList} varcust tr td${cust.id}/td td${cust.name}/td td${cust.phone}/td td${cust.email}/td td a hrefcustomer?actioneditid${cust.id}编辑/a | a hrefcustomer?actiondeleteid${cust.id} onclickreturn confirm(确定删除)删除/a /td /tr /c:forEach /table关键点${customerList}必须由CustomerServlet的listaction 放入 request// CustomerServlet.java 中 list 方法 ListCustomer list customerDao.findAll(); request.setAttribute(customerList, list); request.getRequestDispatcher(list.jsp).forward(request, response);3.3 添加新客户add.jsp表单提交到CustomerServlet的addactionadd.jsp应包含标准 HTML 表单form actioncustomer methodpost input typehidden nameaction valueadd/ 姓名input typetext namename required/br/ 电话input typetext namephone/br/ 邮箱input typeemail nameemail/br/ input typesubmit value添加客户/ /formCustomerServlet.java中需新增add分支} else if (add.equals(action)) { String name request.getParameter(name); String phone request.getParameter(phone); String email request.getParameter(email); Customer cust new Customer(); cust.setName(name); cust.setPhone(phone); cust.setEmail(email); int result customerDao.add(cust); // 返回影响行数 if (result 0) { request.setAttribute(msg, 添加成功); } else { request.setAttribute(msg, 添加失败请重试); } request.getRequestDispatcher(add.jsp).forward(request, response); }注意add.jsp中form actioncustomer的action值必须与web.xml中url-pattern一致如/customer否则请求无法路由到该 Servlet。4. 数据库字段扩展与中文乱码修复让客户信息支持地址、备注等业务字段4.1 在t_customer表中安全添加address和remark字段先备份原表CREATE TABLE t_customer_backup AS SELECT * FROM t_customer;再执行添加字段语句MySQL 5.6ALTER TABLE t_customer ADD COLUMN address VARCHAR(255) DEFAULT COMMENT 客户地址, ADD COLUMN remark TEXT COMMENT 备注信息;验证字段是否添加成功DESCRIBE t_customer; -- 应看到 address 和 remark 列4.2 同步更新 Java 实体类Customer.java与 DAO 层映射打开src/com/crm/entity/Customer.java添加属性及 getter/setterprivate String address; private String remark; // getter/setter 省略IDE 可自动生成 public String getAddress() { return address; } public void setAddress(String address) { this.address address; } public String getRemark() { return remark; } public void setRemark(String remark) { this.remark remark; }在CustomerDao.java的add()方法中更新 SQL 与参数绑定// 原 add() 方法中 String sql INSERT INTO t_customer (name, phone, email, address, remark) VALUES (?, ?, ?, ?, ?); return update(sql, customer.getName(), customer.getPhone(), customer.getEmail(), customer.getAddress(), customer.getRemark());同理update()和findById()方法也需同步增加address和remark字段的读写逻辑。4.3 彻底解决中文乱码从数据库、连接 URL 到 JSP 页面三重设置乱码根源常在三层脱节。按顺序检查MySQL 库与表字符集SHOW CREATE DATABASE crm_db; -- 应为 DEFAULT CHARACTER SET utf8mb4 SHOW CREATE TABLE t_customer; -- 应为 ENGINEInnoDB DEFAULT CHARSETutf8mb4若非utf8mb4执行ALTER DATABASE crm_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; ALTER TABLE t_customer CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;JDBC 连接 URL 强制指定编码CustomerDao.java中 URL 必须含characterEncodingUTF-8private static final String URL jdbc:mysql://localhost:3306/crm_db?useUnicodetruecharacterEncodingUTF-8serverTimezoneAsia/Shanghai;JSP 页面声明 UTF-8 编码所有.jsp文件顶部第一行必须为% page languagejava contentTypetext/html; charsetUTF-8 pageEncodingUTF-8%且head中含meta http-equivContent-Type contenttext/html; charsetUTF-8提示若 Tomcat 日志中出现?替代中文优先检查第 2 步 JDBC URL若浏览器页面显示方块优先检查第 3 步 JSP 编码声明。5. 面试高频考点落地用这个 CRM 理解 Java Web 核心机制与八股文答案5.1 Servlet 生命周期与web.xml配置的对应关系从load-on-startup到destroy()这个 CRM 的CustomerServlet未配置load-on-startup因此首次访问/customer时才实例化init()被调用。若你想让 Servlet 启动时就加载如初始化缓存可在web.xml中添加servlet servlet-nameCustomerServlet/servlet-name servlet-classcom.crm.servlet.CustomerServlet/servlet-class load-on-startup1/load-on-startup !-- 数字越小优先级越高 -- /servlet此时 Tomcat 启动时即调用init()。而destroy()在 Tomcat 关闭或应用卸载时调用常用于释放数据库连接池资源。在CustomerServlet.java中可重写Override public void destroy() { System.out.println(CustomerServlet 已销毁释放资源...); // 如关闭静态连接池若使用了 if (connectionPool ! null) { connectionPool.close(); } }这直接对应 Java 面试题“Servlet 的生命周期是怎样的”——答案必须包含init()一次、service()多次、destroy()一次且明确init()和destroy()由容器调用非程序员主动触发。5.2 Session 与 Cookie 在 CRM 登录中的协作为什么关浏览器就退出CRM 登录后request.getSession().setAttribute(user, user)将用户对象存入 Session。Session ID 默认通过 Cookie 传递名为JSESSIONID。当浏览器关闭该 Cookie 被清除下次请求无有效 Session ID服务器生成新 Session原user属性丢失导致“退出”。验证方式登录后浏览器开发者工具 → Application → Cookies查看JSESSIONID值关闭浏览器再打开该值已变。若需“记住我”功能需额外实现前端勾选“记住我”后端生成长期 Token 存入数据库设置 CookiemaxAge为 7 天非会话 Cookie每次请求优先校验 Token再 fallback 到 Session。这正是 Java 面试中“Session 和 Cookie 区别”的实操注脚Cookie 是客户端存储Session 是服务端存储二者通过 Cookie 中的 Session ID 关联。5.3 JDBC 中PreparedStatement防 SQL 注入的代码级证明打开UserDao.java的findByUsernameAndPassword方法对比两种写法// ❌ Statement 拼接字符串 —— 危险 String sql SELECT * FROM t_user WHERE username username AND password password ; Statement stmt conn.createStatement(); ResultSet rs stmt.executeQuery(sql); // 若 usernameadmin --则绕过密码校验 // ✅ PreparedStatement 占位符 —— 安全 String sql SELECT * FROM t_user WHERE username ? AND password ?; PreparedStatement pstmt conn.prepareStatement(sql); pstmt.setString(1, username); // 参数 1 绑定 username pstmt.setString(2, password); // 参数 2 绑定 password ResultSet rs pstmt.executeQuery(); // username 中的 不会被解析为 SQL 语法在 CRM 中搜索所有executeQuery(或executeUpdate(确认均使用PreparedStatement而非Statement。这是 Java 基础和 Java 面试八股文中“如何防止 SQL 注入”的标准答案——必须写出?占位符和setXxx()方法调用。5.4 JSP 四大作用域与 EL 表达式${}的实际作用范围对照表CRM 中不同位置使用的 EL 表达式对应不同作用域EL 表达式示例作用域设置位置Java 侧生效范围面试考点${user.name}sessionrequest.getSession().setAttribute(user, user)当前会话所有请求Session 作用域最大跨请求${msg}requestrequest.setAttribute(msg, 添加成功)仅本次请求转发如forwardRequest 作用域最小仅一次跳转${param.id}paramURL 参数?id123任何 JSP 可读取Param 是只读作用域对应 GET/POST 参数${initParam.appName}applicationweb.xml中context-param整个 Web 应用Application 作用域最大全局共享在list.jsp中${customerList}来自request.setAttribute()故属于 request 作用域而login.jsp中${error}同理。理解此表就能清晰回答“JSP 四大作用域的区别与使用场景”。注意若 EL 表达式不解析显示为原文${user.name}检查web.xml是否为version2.5以上且 JSP 顶部有% page isELIgnoredfalse %默认为 false通常无需显式写。本文还有配套的精品资源点击获取
返回列表