尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

基于JSP+Servlet+MySQL的医药垃圾分类管理系统设计与实现

基于JSP+Servlet+MySQL的医药垃圾分类管理系统设计与实现 简介这是一份基于Java的医药垃圾分类管理系统毕业设计文档面向计算机专业学生以及需要完成JSP和MySQL课程设计或毕业设计的开发者适合用于快速搭建医疗垃圾管理类系统或撰写对应论文。文档采用B/S架构围绕管理员与用户两类角色展开涵盖个人中心、用户管理、医院垃圾分类管理、医院垃圾信息管理、留言反馈管理、管理员管理等核心模块并给出了完整的功能设计与后台数据库思路。包体为docx格式共1个文件压缩包大小2.4MB文档内包含中英文摘要、目录、第1章概述、研究背景、研究现状、需求分析等完整章节层次清晰便于直接参考论文结构和系统设计内容。文档还重点介绍了JSP动态网页技术、Tomcat中间件、MySQL数据库以及Eclipse开发环境的配合方式同时梳理了医药垃圾分类管理系统的业务流程、系统结构和数据需求并体现了便捷检索与安全防护方面的设计考虑。目前已有35人学习对准备搭建类似管理系统、完成毕业设计或系统学习JSP开发流程的读者都具有较高的参考价值。1. 医药垃圾分类管理系统为什么JSPMySQL这个组合仍值得拆一遍医院后勤在Excel里维护医疗垃圾信息科室负责人查不到历史记录留言反馈靠纸质单子流转这是这套系统要解决的典型场景。基于Java的医药垃圾分类管理系统用B/S架构把角色拆成管理员和用户管理员维护医院垃圾的分类、信息和用户账号用户查信息、留言反馈。技术栈是JSPServletMySQLTomcat开发环境用Eclipse放在Spring Boot普及的今天显得朴素但它的薄分层、无框架依赖反而把请求生命周期、session管理、JDBC操作这些底层机制暴露得很清楚对课程设计和中小型内部系统来说可维护性和可复现性都更好。这个项目适合两类人一是准备Java Web课程设计或者毕设的同学想看功能模块怎么切、表怎么建二是想快速搭一个信息管理类后台的从业者看看不引入重型框架时登录鉴权、分类管理、留言审核这些通用功能代码量到底有多少。2. 从E-R图到物理表医药垃圾分类系统的五张核心表怎么设计实体关系图划定的边界是用户、医院垃圾信息、留言反馈三条主线落实到MySQL里一共五张表allusers管理员账号、yonghu用户、yiyuanlajifenlei医院垃圾分类、yiyuanlajixinxi医院垃圾信息、liuyanfankui留言反馈。这套表结构是典型的毕设风格字段名用拼音缩写好处是和各页面上的标签用户名、医院名称一一对应减少前后端翻译成本代价是英文阅读性差。实际工程里我会用英文命名但在这种交付场景里拼音字段名反而更容易和代码、页面保持一致接手的人不容易对错列。2.1 五张表的职责划分与字段含义角色上allusers和yonghu做了硬隔离。allusers只有id、username、pwd、cx四个字段cx存“管理员”或具体权限级别yonghu是前台注册用户包含手机号码、头像、性别、医院名称。两表分开之后管理端和用户端的数据互不污染登录时先判断入口再查对应表这也是后台和前台账号体系分离的常见做法。表名职责关键字段allusers管理员账号username、pwd、cxyonghu前台用户资料yonghuming、mima、touxiang、shoujihaoma、yiyuanmingchengyiyuanlajifenlei医院垃圾分类字典fenleiyiyuanlajixinxi医院垃圾信息主表lajimingcheng、tupian、fenlei、xiangxijieshao、xiangqingliuyanfankui留言反馈yonghuming、liuyanneirong、sfsh、shhfyiyuanlajixinxi里的fenlei存的是分类名称而不是分类id这算一个设计妥协。正常关系型数据库应该用外键关联yiyuanlajifenlei的id但很多毕设版本直接存字符串查询省一次join代价是分类改名时历史数据要批量update。取舍逻辑是如果分类表几乎不变存名称更直观如果分类频繁调整就存id。这套系统里分类是管理员手动维护的字典变动频率低存名称问题不大。liuyanfankui里的sfsh是否审核和shhf审核回复两个字段是留言模块的状态机核心。sfsh用varchar而不是tinyint存“是/否”这种可见值是为了在JSP页面上直接输出到表格里省一层转换shhf在审核通过后写入用户端再查留言时就能看到。2.2 建库建表SQL字段类型与约束怎么定这套系统的表结构文档里只给了字段名字段类型按这类系统的落地习惯补全。建表顺序有讲究先建分类字典表再建业务表避免插入数据时出现引用不存在的分类CREATE DATABASE IF NOT EXISTS medical_waste DEFAULT CHARSET utf8; USE medical_waste; CREATE TABLE yiyuanlajifenlei ( id INT(11) NOT NULL AUTO_INCREMENT, addtime VARCHAR(50) DEFAULT NULL, fenlei VARCHAR(50) DEFAULT NULL, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8; CREATE TABLE yiyuanlajixinxi ( id INT(11) NOT NULL AUTO_INCREMENT, addtime VARCHAR(50) DEFAULT NULL, lajimingcheng VARCHAR(50) DEFAULT NULL, tupian VARCHAR(200) DEFAULT NULL, fenlei VARCHAR(50) DEFAULT NULL, xiangxijieshao TEXT, xiangqing TEXT, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8;这里有四个参数需要注意。id用INT(11)加AUTO_INCREMENT主键自增就够了系统数据量在十万级以内不会触顶。addtime统一用VARCHAR(50)存字符串时间不建DATETIME索引排序依赖字符串比较这类项目为了简化前端展示往往会这么做但代价是无法直接使用date_format这类时间函数统计某月发布量时要先STR_TO_DATE转换。tupian字段给到VARCHAR(200)因为图片在系统里存的是upload目录下的相对路径而不是完整URL路径加文件名一般不会超过200字符。xiangxijieshao和xiangqing改成TEXT垃圾的具体介绍可能超过50字按varchar(50)定义的话在真实录入时大概率被截断管理员填写的详细说明会莫名丢失。2.3 关键词检索与联表查询的SQL写法用户端最常用的操作是按关键词查医院垃圾信息关键词匹配lajimingcheng垃圾名称实现方式是LIKE模糊查询SELECT id, lajimingcheng, tupian, fenlei, xiangxijieshao FROM yiyuanlajixinxi WHERE CONCAT(lajimingcheng, fenlei) LIKE CONCAT(%, ?, %) ORDER BY id DESC;CONCAT把名称和分类拼成一个字段再匹配这样用户输入“过期药品”时即使名称里写的是“药品过期”分类是“药物性废物”也能命中。参数用占位符?传给PreparedStatement避免直接拼SQL字符串防止单引号把查询条件截断。ORDER BY id DESC让新发布的排在前面配合后台的添加时间列列表展示顺序和录入顺序一致这是没有时间索引时的兜底排序方案。如果你的项目改了分类名出现过期数据对不上的情况需要同步执行一条批量更新UPDATE yiyuanlajixinxi SET fenlei 感染性医疗废物 WHERE fenlei 感染性废物;这就是前面说的“存名称不存id”的代价业务表里的分类值要靠UPDATE同步而不是外键关联自动生效。批量更新前先SELECT COUNT(*)确认影响行数再执行UPDATE这是SQL上线的基本操作习惯。3. JSPServlet实现登录鉴权用户表与管理员表的双重校验登录是整个系统唯一的前置入口。管理员和用户虽然是两套表但共用同一个登录页面区分方式是在提交时带一个角色参数。JSP页面负责渲染表单LoginServlet接收请求、调用JDBC查表、比对密码、写session最后用redirect或forward跳转。这个流程能完整覆盖从浏览器发起到会话建立的过程没有框架可抄正好把请求到响应的生命周期走一遍。3.1 登录表单与LoginServlet的请求处理流程login.jsp的表单部分只需要四个节点用户名输入框、密码输入框、角色下拉框、提交按钮。角色下拉框是关键管理员登录时选“管理员”用户登录时选“用户”后端据此决定查allusers还是yonghuform actionloginServlet methodpost input typetext nameusername placeholder用户名 / input typepassword namepassword placeholder密码 / select namerole option valueadmin管理员/option option valueuser用户/option /select button typesubmit登 录/button /formLoginServlet的doPost方法里先取参数再分流查表protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String username request.getParameter(username); String password request.getParameter(password); String role request.getParameter(role); String sql admin.equals(role) ? SELECT * FROM allusers WHERE username? AND pwd? : SELECT * FROM yonghu WHERE yonghuming? AND mima?; try (Connection conn DBUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql)) { ps.setString(1, username); ps.setString(2, password); ResultSet rs ps.executeQuery(); if (rs.next()) { HttpSession session request.getSession(); session.setAttribute(loginUser, username); session.setAttribute(role, role); response.sendRedirect(index.jsp); } else { request.setAttribute(errorMsg, 用户名或密码错误); request.getRequestDispatcher(login.jsp).forward(request, response); } } catch (Exception e) { e.printStackTrace(); } }这段代码的核心逻辑是role参数决定查询哪张表和哪些字段所以allusers和yonghu的密码字段名不同pwd和mima不影响登录逻辑。DBUtil.getConnection()是封装好的JDBC工具类内部维护Class.forName(com.mysql.jdbc.Driver)和DriverManager.getConnection(url, user, password)。PreparedStatement的两层意义在于参数化查询防止SQL注入同时让MySQL复用执行计划重复登录时少一次SQL解析。登录成功把username和role写进session后续所有页面的权限判断都依赖这两个值。redirect比forward更合适因为刷新页面时不会再次提交表单导致重复登录。3.2 session会话与权限控制Filter拦截与路径隔离登录之后要防止未登录用户绕过登录页直接访问后台地址。教科书里讲的是在每个页面检查session但代码会非常冗余。更规范的做法是写一个LoginFilter拦截所有受保护路径public class LoginFilter implements Filter { public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request (HttpServletRequest) req; HttpSession session request.getSession(false); String uri request.getRequestURI(); if (uri.endsWith(login.jsp) || uri.contains(/static/)) { chain.doFilter(req, resp); return; } if (session null || session.getAttribute(loginUser) null) { ((HttpServletResponse) resp).sendRedirect(login.jsp); return; } String role (String) session.getAttribute(role); if (uri.contains(/admin/) !admin.equals(role)) { ((HttpServletResponse) resp).sendRedirect(login.jsp); return; } chain.doFilter(req, resp); } }web.xml里给/admin/*和/user/*配置filter-mapping权限规则就收敛到一个类里了。getSession(false)和getSession()的区别在于前者在无会话时不新建session避免未登录访问也产生无效会话。uri.contains(/admin/)判断访问路径归属管理员模块只允许role为admin的会话通过。chain.doFilter必须在所有条件通过后调用否则请求被拦截但没有任何输出页面表现为一直白屏。filter里要先放行login.jsp和静态资源否则登录页本身也会被拦截形成死循环。这个放行列表要随项目结构调整新增静态资源目录时容易漏。3.3 密码存储的边界明文与加密的取舍这套系统的表结构里密码是明文存储的管理员表里的pwd直接就是123456这种可读字符串。局域网内部系统这么做还说得过去但系统一旦暴露到公网就属于高风险。我一般会至少做一层MD5加盐不改表结构只在写入和校验时做转换String salt medical2024; String hashed DigestUtils.md5Hex(salt password);MD5本身有彩虹表问题但加固定salt之后对这类毕业设计和内部系统已经够用不需要上BCrypt。注意allusers表里pwd字段只有VARCHAR(50)MD5后的32位字符串刚好放下如果用SHA-256就得把字段改成VARCHAR(64)。改登录校验时把参数里的password先hash再拼SQLyonghu表注册时也要用同一套hash逻辑否则老数据全部无法登录。4. 医院垃圾信息与留言反馈模块CRUD与审核状态机的落地系统里最重的两个业务模块是医院垃圾信息管理和留言反馈管理。前者是用户查询的主要信息源后者承担用户与管理员之间的沟通闭环。两个模块都是标准CRUD但各有细节垃圾信息查询要带分类筛选和关键词检索留言反馈要处理“提交→审核→回复→展示”的状态流转。4.1 医院垃圾信息的列表、筛选与新增垃圾信息表yiyuanlajixinxi的核心操作是列表展示分类筛选和关键词查询是用户最常用的两个入口form actionlistServlet methodget 分类 select namefenlei option value全部/option option感染性废物/option option损伤性废物/option option药物性废物/option /select 关键词input typetext namekeyword / button typesubmit查 询/button /form对应的listServlet在构造SQL时根据参数动态拼接条件StringBuilder sql new StringBuilder(SELECT * FROM yiyuanlajixinxi WHERE 11); ListObject params new ArrayList(); if (fenlei ! null !fenlei.isEmpty()) { sql.append( AND fenlei ?); params.add(fenlei); } if (keyword ! null !keyword.isEmpty()) { sql.append( AND CONCAT(lajimingcheng, xiangxijieshao) LIKE CONCAT(%, ?, %)); params.add(keyword); } sql.append( ORDER BY id DESC);WHERE 11在JDBC动态拼接里很实用后续每个AND条件都可以无脑追加不用判断是不是第一个条件。参数绑定用List收集循环setObject避免条件增多时索引错位。新增垃圾信息时分类通过下拉框选择管理员输入名称、上传图片、填写介绍。INSERT语句的字段要和页面表单name一一对应尤其tupian不能直接存上传文件名要先通过上传组件把文件写到服务器upload目录再把相对路径存进数据库。4.2 留言反馈的审核流转sfsh与shhf两个字段的配合留言反馈表的审核逻辑是这套系统里最值得拆的状态设计。用户提交留言时sfsh默认“否”shhf为空管理员在后台看到待审核列表审核通过时把sfsh改成“是”同时写入审核回复。用户端再次查询留言时只显示sfsh为“是”的记录UPDATE liuyanfankui SET sfsh 是, shhf ? WHERE id ?;审核操作就执行上面这条SQL管理员再在textarea里填写回复内容。用户端查询留言用的则是SELECT yonghuming, liuyanneirong, riqi, shhf FROM liuyanfankui WHERE yonghuming ? AND sfsh 是 ORDER BY id DESC;这个设计本质上是把审核状态扁平化处理不建审核记录表不做多级审核所有信息都冗余在留言表本行。优点在于用户和管理员各自只需要一次查询就能拿到全部数据缺点是无法追踪审核历史——管理员改了两次审核结论只有最后一版留存。对这套系统来说够用但如果要留审计记录就得再拆一张audit_log表记录操作人、操作时间、操作前后值。注意sfsh字段的值是中文“是/否”SQL里写sfsh是不能写sfshtrue这是拼音字段加中文值带来的易错点排查问题时第一反应要想到字段类型和取值都是varchar。4.3 图片上传与分页两个容易被忽略的边界图片上传在表单里要求enctypemultipart/form-data提交后不能直接getParameter拿文件要用上传组件解析。常见做法是给上传文件加时间戳前缀防止重名覆盖String fileName System.currentTimeMillis() _ filename; File savedFile new File(uploadDir, fileName); item.write(savedFile);分页是列表页数据量上来之后必须处理的问题。原生JDBC的分页SQL是LIMIT ?, ?第一个参数是起始偏移量第二个是每页条数SELECT * FROM yiyuanlajixinxi WHERE fenlei ? ORDER BY id DESC LIMIT ?, 10;偏移量计算方式pageSize固定10currentPage从request.getParameter(page)解析默认1offset (currentPage - 1) * pageSize。LIMIT的两个参数必须用int类型传入PreparedStatement先setInt(offset)再setInt(pageSize)不能拼字符串否则MySQL 5.7以上直接报语法错误。总页数要单独执行SELECT COUNT(*)查询一次列表底部渲染上一页、下一页链接时要用到。5. 医药垃圾分类系统的部署排错Tomcat与MySQL的五个关键配置系统交付阶段最常出问题的不在业务代码而在环境配置。按经验排序这五个坑占了至少一半的部署时间。第一是JDBC驱动类名和连接串。com.mysql.jdbc.Driver是MySQL 5.x时代的驱动类名MySQL 8.x要写com.mysql.cj.jdbc.Driver否则Class.forName直接报ClassNotFoundException。连接串也有对应要求jdbc:mysql://localhost:3306/medical_waste?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/ShanghaiserverTimezone参数不配MySQL 8.x下会报时区错误useUnicode和characterEncoding不配写入中文变问号。第二是Tomcat乱码。JSP页面顶部page指令里写pageEncodingUTF-8表单提交的POST请求还要在Servlet开头调request.setCharacterEncoding(UTF-8)注意要放在getParameter之前才生效。server.xml里Connector标签加URIEncodingUTF-8处理GET请求的参数编码。第三是驱动包位置。mysql-connector-java.jar只放在项目WEB-INF/lib下在IDE里跑没问题部署到独立Tomcat后JDBC连不上。把jar丢到Tomcat的lib目录重启即可。第四是端口占用。Tomcat默认8080被占时改conf/server.xml里的Connector port同时检查MySQL的3306端口是否被防火墙拦截部署在云服务器上尤其要注意安全组规则。第五是数据库时区不一致导致的时间错乱。Linux服务器默认UTC时区写入MySQL的CURRENT_TIMESTAMP和本地时间差8小时连接串里已经配置了serverTimezone还要检查my.cnf里的default-time-zone。验证以上配置是否生效先用MySQL自带的客户端命令确认数据库服务在跑mysqladmin -u root -p ping返回mysqld is alive说明数据库服务正常接下来再启动Tomcat打开日志文件catalina.out看启动过程有没有异常堆栈。这套检查顺序把问题边界从操作系统、数据库、中间件到应用代码一层层缩小比来回刷新页面定位问题快得多。本文还有配套的精品资源点击获取
返回列表