十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

基于JSP+MSSQL的进销存管理系统设计与实现

基于JSP+MSSQL的进销存管理系统设计与实现 简介一份基于JSPMSSQL的Java进销存管理系统毕业设计资源包面向需要完成Java Web课程设计或毕业设计的本专科学生以及希望快速上手传统三层架构的初学者。项目覆盖商品管理、供应商管理、进货管理、销售管理、库存管理和报表分析等核心业务从需求分析到部署上线均有完整代码支撑可在此基础上扩展二次开发。压缩包共163个文件主要包括31个java源码、105个class编译文件、4个jar依赖库以及数据库mdf/ldf文件、doc设计文档、xls数据表和png界面截图整体仅1.7MB结构精简便于直接导入运行和研究。源码演示了JSP页面、Servlet/JavaBean与JDBC操作MSSQL的协作方式配套设计文档则阐述系统架构与开发流程能帮助读者理解Web系统从设计到落地的全过程。已有246人学习适合作为毕业设计参考或Java Web入门实践。1. 项目概述与核心价值做毕设或者课程设计选题目最容易踩的坑就是选一个自己hold不住的大方向或者选一个根本没技术亮点的老掉牙课题。而“进销存管理系统”这个题目放在Java技术栈里属于“经典但不过时”的典型代表——它覆盖面够广能展示数据库设计、后端逻辑、前端交互的基本功又没有复杂到让你在答辩时被问穿更重要的是它非常贴近真实业务场景。我见过很多人一上来就选电商系统、秒杀系统结果做了一半发现Redis缓存、消息队列、分布式事务这些自己根本没掌握最终只能仓促拼凑。相比之下基于JSPMSSQL的进销存管理系统核心技术栈是Java Servlet/JSPFriyond数据库设计难度适中特别适合Java基础扎实但没有大型项目经验的学生党。你不需要掌握Spring全家桶也能把整个系统的边界理清楚。这篇博文我会把这套系统的完整设计与实现思路拆开来讲——从数据库表怎么设计、三层架构怎么分层、库存预警怎么触发到权限控制怎么实现、MSSQL连接池怎么配再到答辩时必须能回答上来的几个高频问题一次讲透。无论你是打算直接基于这套源码改造还是想完全自己写一套这篇文章都能帮你省下大量踩坑时间。2. 系统需求分析与功能模块拆解2.1 核心业务场景梳理进销存拆开来看就是三个字进、销、存。但如果你只理解到这个层面做出来的系统很容易沦为“增删改查demo展览会”。真实的进销存系统核心在于“单据流转”和“库存联动”。拿一个典型的中小超市或商贸公司来说业务流程是这样的采购员录入采购入库单仓库管理员核对商品并确认入库库存表自动增加销售员开销售出库单或者小票确认出库后库存自动减少老板随时查看库存余量、商品滞销情况、毛利统计。整个流程环环相扣任何一个环节的数据不准确都会导致库存账实不符。所以你在设计功能模块时绝对不能把“进货录入”“销售录入”“库存查询”做成三个孤立的CRUD页面。它们之间必须有状态流转和数据联动。这也是面试官或者答辩老师最喜欢深挖的地方——“你的进货单审核后库存是怎么变化的销售退货时库存怎么处理”2.2 功能模块全景图整套系统的核心功能模块可以拆成五个大块基础资料管理商品信息、供应商信息、客户信息。这些是所有业务单据的基础数据来源一般做成下拉选择不允许手输一长串文本。采购管理采购订单/采购入库单的录入、审核、查询。核心要点是——单据审核通过后自动增加库存并且联动更新商品的平均进货成本。销售管理销售出库单/销售小票的录入、审核、退货处理。核心要点是——出库扣减库存、退货回补库存销售价格和成本价分离便于算毛利。库存管理实时库存查询、库存预警低于安全库存量时醒目提示、库存盘点调整账面库存。进阶一点可以加库存流水表做到每一件商品的出入库都留痕。系统管理用户管理、角色管理、密码修改、日志管理。这是体现系统完整性的加分项也是答辩时比较能聊的一块。值得提醒的是很多毕设源码里的“库存预警”只是做一个简单查询——库存数小于阈值的商品列出来。但你如果能把预警做成“在商品列表里用颜色高亮标识”“在首页dashboard展示预警数量”效果会明显好很多。技术难度不大但展示效果直接拉满因为老师一眼就能看到你做的东西有真实使用价值。3. 核心技术栈与数据库设计3.1 为什么选JSPMSSQL这套组合近几年Spring Boot太火了很多人一看到JSP就嫌弃觉得老土。但作为毕设选型的第一原则不一定是“最新最潮”而是“你能否驾驭、能否讲清楚”。JSPServlet这套技术组合是Java Web最底层的形态——你亲手写了Servlet处理请求、手动封装JDBC操作数据库、在JSP里用JSTL遍历结果集你对HTTP请求生命周期、数据库连接关闭、异常处理这些底层机制的理解会是直接上手Spring Boot的人很难达到的。面试被问“Spring MVC的DispatcherServlet原理”时你有Servlet基础是加分的不是减分的。MSSQLSQL Server数据库在企业级应用里的市场占有率一直很稳且SQL Server Management Studio工具非常成熟可视化建表、调试存储过程都很方便。相比MySQLMSSQL在事务处理、索引优化上对人更友好图形化界面更适合不常敲命令行的人。当然如果你想换MySQL代码层面只需要改JDBC驱动和少量SQL语法差异比如分页写法、自增主键定义其余几乎不用动。3.2 数据库表结构设计实战数据库是整个系统的地基。我见到的毕设里最常见的低级错误是只建了商品表、供应商表、客户表、入库表、出库表这五张表然后所有业务全靠这五张表硬撑。实际上规范的进销存系统至少要包含以下核心表t_user用户表用户ID、用户名、密码MD5加密存储、真实姓名、角色ID、创建时间。t_role角色表角色ID、角色名称、权限描述。为后续菜单权限控制留后路。t_supplier供应商表供应商ID、名称、联系人、电话、地址、备注。t_customer客户表客户ID、名称、联系人、电话、地址、欠款额度。t_category商品分类表分类ID、父级分类ID、分类名称。做树形分类时必备。t_product商品表商品ID、商品编码、品名、规格、单位、分类ID、进货价、销售价、安全库存量、当前库存、备注。t_purchase_order采购入库单主表单号、供应商ID、采购日期、经手人、总金额、审核状态、备注。t_purchase_order_detail采购入库单明细表明细ID、主表单号、商品ID、数量、单价、小计金额。t_sale_order销售出库单主表单号、客户ID、销售日期、经手人、总金额、审核状态、备注。t_sale_order_detail销售出库单明细表明细ID、主表单号、商品ID、数量、单价、小计金额。t_inventory_log库存流水表流水ID、商品ID、变动类型入库/出库/退货/盘点、关联单号、变动数量、变动前库存、变动后库存、操作时间、操作人。主表和明细表分离是这套设计的精髓。主表存一次单据的公共信息谁、什么时间、总金额多少明细表存这次单据涉及的商品行项目哪个商品、多少个、单价多少。这种方式既避免了数据冗余也方便日后做单据明细追溯。答辦的时候如果被问到“为什么拆成两张表”你就可以从数据一致性和查询效率两个角度回答。3.3 库存联动设计的关键SQL库存流水表是整个系统的“账本”。每次入库或出库除了更新商品表里的当前库存还必须在t_inventory_log里插入一条流水记录。这样做的好处是以后任何时刻你想追溯“某件商品某个时间点为什么库存变成了这个数”都有据可查。这里贴一段核心的库存变动逻辑伪代码实际在Service层处理// 1. 查询商品当前库存 int currentStock productDao.getStockById(productId); // 2. 计算变动后的库存入库为正出库为负 int newStock currentStock changeQuantity; // 3. 更新商品表的当前库存 productDao.updateStock(productId, newStock); // 4. 插入库存流水 inventoryLogDao.insert(new InventoryLog(productId, type, currentStock, newStock, relatedOrderNo, new Date(), operator));这里有个非常隐蔽但极其重要的细节计算newStock必须在数据库层面做行锁或事务控制否则并发情况下会出现超卖或负库存。你可以用“SELECT ... WITH (UPDLOCK)”或者在Service层方法上加synchronized单机环境下够用或者干脆用一条UPDATE语句的原子操作——“UPDATE t_product SET current_stock current_stock ? WHERE product_id ?”。如果你能做到这一步评委老师会觉得你不仅有代码能力还有并发安全意识。3.4 多条件组合查询与分页SQL查询和分页是这类管理系统里写得最多、也最容易出bug的地方。MSSQL的分页写法有三种OFFSET-FETCH、ROW_NUMBER()、老版本的TOPN子查询。你要根据SQL Server版本来选择——2012及以上可以直接用OFFSET-FETCH写法最简洁SELECT * FROM t_product WHERE product_name LIKE % keyword % ORDER BY product_id OFFSET (pageIndex - 1) * pageSize ROWS FETCH NEXT pageSize ROWS ONLY;多条件组合查询建议用动态SQL拼接的方式在Service层根据前端传参拼出WHERE条件而不是写死三个单独查询方法。这样代码可维护性高很多。顺便提醒不要用字符串拼接SQL时直接把用户输入怼进去要使用PreparedStatement的参数占位符这是防SQL注入的底线。4. 系统整体架构与代码分层4.1 三层架构设计思路这套系统的代码组织我强烈建议采用经典的三层架构表现层JSP→ 业务逻辑层Service→ 数据访问层DAO再加上一个实体层entity/model存放JavaBean。entity包对应数据库表的Java对象字段和表的列一一对应实现Serializable接口。dao包纯JDBC操作只管数据的增删改查不包含任何业务判断。service包业务逻辑处理比如“审核入库单时要校验供应商是否存在、计算总金额、批量插入明细、更新库存、插入流水”——这些流程控制必须在service层完成而不能散落在Servlet里。web包servlet接收请求、解析参数、调用service、转发或重定向到JSP页面。util包放数据库连接工具类DBUtil、字符串处理工具、日期工具等。分层的价值用一个例子说明如果某个日期的数据统计逻辑从“按入库日期统计”改成“按审核日期统计”你只需要修改service层对应的方法JSP页面和DAO层完全不用动。没有分层的话你可能要在十几个Servlet和JSP里同时改动改一处漏一处bug就会不断冒出来。4.2 Servlet与JSP的协作机制很多新手搞不清楚Servlet和JSP到底什么关系。简单粗暴地讲JSP本质上就是一个Servlet——一个经过容器编译后变成Servlet类的文件。只是在开发角色上做了分工JSP主要负责“显示”Servlet主要负责“控制”。结合这套系统流程是这样的浏览器发起请求比如/productList.do?page1web.xml或注解把URL映射到ProductServletProductServlet的doGet方法里调用ProductService的listProducts(page)方法拿到数据把结果存到request域里request.setAttribute(productList, list)转发到productList.jspJSP里用JSTL的c:forEach循环渲染表格浏览器看到最终的HTML表格页面有个细节值得注意转发forward和重定向redirect的选择。查询完列表用转发因为要携带数据到JSP而登录成功后跳转到主页、操作成功后返回列表页建议用重定向避免用户刷新页面时重复提交表单。4.3 数据库连接池配置用JDBC最忌讳的写法是每次操作数据库都getConnection()用完就close()。在高并发场景下频繁创建销毁连接对性能的损耗非常大而且SQL Server的连接数本身也有限。正确的做法是使用数据库连接池。虽然手写一个连接池也不难但没必要重复造轮子。推荐用阿里的Druid连接池配置非常简单# druid.properties driverClassNamecom.microsoft.sqlserver.jdbc.SQLServerDriver urljdbc:sqlserver://localhost:1433;DatabaseNameshop_db usernamesa password123456 initialSize5 maxActive20 maxWait30000然后在DBUtil里通过静态代码块加载这个配置并初始化DruidDataSource。这样一来你的应用启动时预创建5个连接用完归还而不是关闭性能提升非常明显。更妙的是Druid自带监控页面你可以接一个StatViewServlet把SQL执行频次、慢查询统计展示出来——答辩演示时随手打开监控页面立刻就能展示你的系统有“体检报告”非常加分。4.4 用户登录与权限拦截器登录模块是毕设的“门面”。最基本的逻辑是——用户提交用户名密码Servlet调用Service查询比对密码用MD5加密存储注意加盐更安全通过后把User对象放进Session跳转到主页面。但只做登录还不够还缺少关键一步——权限拦截。如果在未登录状态下任何人都能直接在浏览器地址栏输入“/productList.do”访问商品列表那登录就等于摆设。一个标准的实现是用Filter过滤器统一拦截public class LoginFilter implements Filter { public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) { HttpServletRequest request (HttpServletRequest) req; HttpSession session request.getSession(false); if (session null || session.getAttribute(loginUser) null) { ((HttpServletResponse) resp).sendRedirect(login.jsp); return; } chain.doFilter(req, resp); } }然后在web.xml里配置把除了login.jsp、loginServlet、css/js/image之外的URL全部拦截。这个小点几乎必然被答辩老师关注做出来既是安全意识的体现也是系统完整性的加分项。5. 核心模块的实现细节与踩坑记录5.1 采购入库与销售出库的联动物流很多人写入库单的逻辑是页面上选中商品放购物车点结算然后往t_purchase_order和t_purchase_order_detail各插一条数据就完事。大错特错。真实的业务里入库和出库必须像真正的仓库流程一样分步处理第一步录入单据草稿状态为“未审核”数据只存主表和明细表不触发库存变化。第二步库管员审核状态改为“已审核”这时才触发库存增加逻辑。第三步财务或管理员可得已审核单据做后续处理。这样设计的好处是——如果录入员录错了单据还没审核可以直接删除修改库存完全不受影响。只有审核后的单据才影响库存。这个“先单后审”的设计思路是区分“课堂作业”和“真实项目”的分水岭。审核接口的核心代码逻辑public synchronized boolean auditPurchase(Integer orderId) { // 1. 校验订单状态必须是未审核 PurchaseOrder order purchaseOrderDao.findById(orderId); if (order null || !待审核.equals(order.getStatus())) { return false; } // 2. 查出明细列表 ListPurchaseOrderDetail details detailDao.findByOrderId(orderId); // 3. 遍历明细逐条增加库存并写流水 for (PurchaseOrderDetail detail : details) { productDao.increaseStock(detail.getProductId(), detail.getQuantity()); inventoryLogDao.insert(...); // 建议在事务里 } // 4. 更新主表状态为“已审核” purchaseOrderDao.updateStatus(orderId, 已审核); }这里务必要加事务。如果第3步执行到一半抛异常而第4步没执行就会造成库存变了但单据还是“待审核”数据完全对不上。建议使用ThreadLocal绑定Connection在Service层开启事务DAO层统一从ThreadLocal获取连接全部执行成功后commit任何一步失败就rollback。5.2 库存预警逻辑的两种实现方案库存预警常见方案有两种方案一代码判断推荐每次查询商品列表时在Service层拿到商品的安全库存量和当前库存做比较。当前库存小于安全库存设置一个isLowStock标记JSP页面渲染时该行使用红色字体或红色背景。方案二SQL视图或计算列在数据库里创建视图直接算出一个预警状态列代码侧直接用但每次查询多一次计算。数据量大时不推荐。方案一的好处是灵活——你可以在列表、首页看板、库存查询等多个地方复用逻辑而且不用改动数据库结构。另外建议做一个独立“库存预警”页面列出所有低于安全库存的商品并按缺货严重程度排序。这类页面在系统演示时非常“显眼”老师想不注意到都难。5.3 写这套系统时遇到的经典坑既然是一路踩坑过来的我把自己折腾这系统时最崩溃的几个问题整理了一下这类问题大多不只是我会遇到很多过来人都问过。第一坑SQL Server驱动连不上。常见的报错是“com.microsoft.sqlserver.jdbc.SQLServerDriver”找不到类原因基本就两个——驱动jar包没放进WEB-INF/lib目录或者JDK版本和驱动版本不兼容。sqljdbc4.jar适合较旧的驱动较新的驱动已经把包名改成了com.microsoft.sqlserver.jdbc且兼容JDK8及以上。建议下载最新版的Microsoft JDBC Driver省心很多。第二坑JSP页面里写Java脚本片段% %导致页面特别乱。因为业务逻辑在JSP里直接混排一是代码复用差二是页面响应慢。正确的做法是JSP里只用JSTL和EL表达式所有数据都由Servlet在转发前准备好。如果你看一套源码发现JSP里到处是%这类代码的质量通常不太高建议重写而不要去整体维护。第三坑MSSQL默认隔离级别下查询库存时读到的是“已提交”的数据。如果在UPDATE库存之前先SELECT了库存在并发环境下会算出错误结果。解决之道就是前面的“一条原子UPDATE直接改库存”不要先查后改。第四坑字符集问题。MSSQL的默认排序规则在某些环境下处理中文会出现乱码。解决方法是数据库创建时选择Chinese_PRC_CI_AS排序规则连接URL里加上characterEncodingutf-8MSSQL驱动也许不支持这个参数但要注意页面编码统一为UTF-8JSP顶部写% page contentTypetext/html;charsetUTF-8 languagejava %过滤器里统一设置请求和响应的编码。第五坑不建索引导致查询奇慢。如果商品表几万条数据每次只在商品编码上查询却没有索引速度会很感人。建议在t_product.product_code、t_purchase_order.order_no、t_inventory_log.product_id这些高频查询字段上建普通索引查询性能有数量级提升。5.4 一个实用的权限控制扩展思路如果你想让系统更有亮点可以把用户表直接绑定角色表做到“不同角色登录左侧菜单显示项不同”。实现起来并不复杂——在t_role表里加一个menu_permission字段存可访问菜单的URL集合用逗号分隔登录成功后把当前角色允许访问的菜单列表写入Session。JSP页面渲染菜单时通过c:if test${fn:contains(sessionScope.menus, /purchase)}控制显示隐藏。更进一步你可以把权限控制直接做到Filter层面在LoginFilter里再校验当前用户请求的URL是否在权限列表中不在就提示无权限。这个“URL级别权限控制”的颗粒度已经比较接近真实企业项目的做法了比单纯做个登录功能高级得多。6. 系统部署与运行环境搭建用MSSQL做数据库最常见的情况是自己电脑上装了一个SQL Server然后带到答辩现场才发现连不上。所以部署环节一定要提前理顺。本地环境推荐这三件套JDK 8及以上、Apache Tomcat 8.5或9.0、SQL Server 2008 R2及以上建议2012。JDK安装后要配置JAVA_HOME、PATH变量Tomcat解压即可用关键在于MSSQL的“允许远程连接”和“启用TCP/IP协议”必须打开。SQL Server默认实例端口是1433但很多人装的是命名实例连接字符串要写成jdbc:sqlserver://localhost\实例名:1433;DatabaseNamexxx注意是反斜杠。另外MSSQL登录方式强烈建议不要去碰Windows身份验证折腾权限。直接使用“混合模式身份验证”给sa设置一个强密码在数据库里单独创建一个应用账号并只授予当前业务库的db_owner权限这样连接串、权限隔离都干净。部署到别的电脑时只需要把SQL脚本在目标库上一跑然后修改druid.properties里的数据库账号密码即可。Tomcat部署有两种方式开发时用Eclipse/IDEA内置Tomcat进行调试答辩前务必打一个WAR包放到Tomcat的webapps目录下独立部署。因为很多学校的答辩电脑不会装IDE却有可能装了Tomcat即使没有也可以现场装一个比现场调试代码稳妥得多。打包前注意确认lib目录里包含了JDBC驱动和Druid的jar包否则部署到新环境后启动直接报ClassNotFoundException。7. 常见问题排查与答辩准备7.1 高频报错自查清单HTTP Status 500后台报NullPointerException多半是request.getParameter拿到的是null常见原因是表单里的name和Servlet里取的名字不一致。挨个核对不要上来就怀疑框架。SQLServerException: 用户登录失败数据库账号密码错误、或者SQL Server没启用混合登录模式。用SSMS先手动用这个账号连接一遍排除网络和权限问题。页面上的中文全是???数据库排序规则编码问题或者JSP页面编码没统一。把数据库、连接URL、JSP页面三处的编码都统一成UTF-8或GBK别混用。Tomcat启动后访问项目404WAR包解压后的路径不对或者web.xml里配置的欢迎页不存在。确认访问路径是“http://localhost:8080/项目名/登录页面.jsp”。商品列表分页数据错乱最常见的原因是LIMIT/OFFSET参数传的类型不对或者pageIndex从1开始但SQL里写入的是0。7.2 答辩高频提问与应答思路答辦被问得最频繁的几个问题提前准备好概念和理解回答时别背用自己的话讲清楚即可为什么选用JSPServlet而不是Spring Boot抓住“底层原理”和“学习价值”。你已经把Web开发最核心的流程手写了一遍以后上框架会更明白它帮你省了什么。库存数据如何保证一致性回答数据库事务、原子UPDATE、连接池、以及“先单后审”的设计保证库存变动有据可查。数据库表为什么拆主表和明细表数据冗余小、维护容易、订单和明细的解耦、支持未来的订单状态流转。密码为什么不能明文存至少要说MD5加盐扩展可以说再加一次SHA或使用BCrypt。如果数据量从万级涨到百万级哪里是瓶颈怎么优化对关键字段加索引、分页查询不能用一次性全量加载、可以考虑在SQL Server里做分区表或只查询必要字段。7.3 演示效果的一些细节优化建议最后再分享几个让系统演示“加分”的小细节都不难但效果好得出奇商品列表页的“库存预警”行加个醒目的背景色并且截图放进论文的效果图里视觉冲击力很强。首页加一个简单的统计看板——今日销售金额、今日入库单数、库存预警数、供应商总数。用纯SQL的COUNT和SUM就够不需要引入图表库。每个表单提交后都跳转回列表页并且在列表页顶部显示“操作成功”的提示条这个细节证明你考虑了用户体验。导出一个Excel报表功能。网上有开源的JXL或EasyPOI库只需几十行代码就能把商品列表或销售明细导成Excel答辩现场演示效果极佳而且搜索热词里也有“jsp实现数据导出为excel”——需求确实存在。根据我自己的经验进销存管理系统做到“能跑通、能讲清、有点睛小亮点”这三个层次在本科毕设里就是妥妥的优秀水平。这套源码的完整代码结构、SQL建库脚本和部署说明你拿到后建议一定要从头捋一遍——不是读懂而是能默写。这样答辩时被问到的任何角落你都能从容接住。毕竟系统是你自己“做”出来的而不是“下载”出来的这句话才是答辩最好的底气。本文还有配套的精品资源点击获取
返回列表