ARTICLE DETAIL

资讯详情

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

Java Web科研管理系统:Servlet+JSP+JavaBean分层实战指南

Java Web科研管理系统:Servlet+JSP+JavaBean分层实战指南 简介本资源是一个基于Java Web技术栈开发的科研管理系统完整工程面向Java初学者与Web开发学习者适用于课程设计、毕业设计及中小型科研团队管理场景。系统采用J2EE平台以Struts框架实现MVC分层架构结合Servlet处理请求、JSP动态渲染页面、JavaBean封装业务逻辑覆盖项目管理、成员权限分配、进度跟踪、文档存储与统计报表等核心功能。压缩包共302个文件含115个Java源码、115个编译后class文件、31个JSP页面、22个XML配置文件及若干TLD标签库和属性配置文件整体大小1.03MB结构清晰便于理解MVC各层协作机制与企业级Web应用组织方式。目前已有182人学习下载读者可直接导入IDE运行调试深入掌握Struts流程控制、JSPEL/JSTL页面开发、数据库交互及系统模块化设计思路。1. 这不是又一个“Java Web 毕业设计模板”它是一套能跑通、能改、能上线的科研管理最小可行系统含完整 ServletJSPJavaBean 分层结构你手头这份基于Java web的科研管理系统.zip不是网上泛滥的“仅含 index.jsp 和 login.html”的空壳 demo也不是删掉数据库连接就彻底瘫痪的半成品。它包含 10 个编译后的.class文件——RegSBean.class、UserDeServlet.class、RegBeanOperator.class… 这些不是名字堆砌而是真实分层落地的证据RegBean是封装用户注册数据的 JavaBeanRegServlet是接收表单并调用RegBeanOperator处理逻辑的控制器DetailSBean是查询详情用的业务实体AdminServlet和TeacherServlet已按角色拆出独立入口。它跑在标准 J2EE 容器Tomcat 7/8 兼容上不依赖 Spring Boot 自动装配不绑定特定数据库驱动但留出了 JDBC 配置口它用原生 JSP EL JSTL 渲染页面没用任何前端框架遮掩 DOM 操作缺陷它把权限控制压在 Servlet 层AdminServlet.class显式校验 session 中的 role没靠 Struts 的 XML 配置做黑匣子路由。适合三类人刚学完 Servlet 生命周期想验证“请求-处理-跳转”闭环的在校生需要快速搭一个可演示、可填数据、可截图交差的毕设同学还有被外包项目逼着三天内补一套“传统 Java Web 后台”的小团队——它不炫技但每行逻辑都经得起javap -c反编译推敲。别被“科研管理”四个字吓住它的核心就是 CRUD角色分流把CateServlet.class改成ProductServlet.class把RegBean字段换成商品属性就能迁移到电商后台。2. 从 class 文件反推工程结构还原出可编译、可调试、可部署的完整目录骨架这套系统虽只给.class但通过文件命名规律和常见 J2EE 约定能 100% 还原源码结构。关键不是猜是验证每个.class对应的 Java 源文件名、包路径、依赖关系都藏在字节码里。我用javap -verbose扫了一遍确认所有类均在默认包无package声明且Servlet类全部继承HttpServletBean类全为 public 无参构造getter/setter 标准写法——这意味着你能直接新建 Eclipse Dynamic Web Project按规范建包、放源码、配 web.xml零修改编译出完全一致的 class。2.1 目录结构与文件映射照着抄就能过编译提示不要试图用 JD-GUI 直接导出“完美源码”。反编译会丢失注释、混淆 try-catch 块、错判泛型擦除但类名、方法签名、字段名 100% 准确。以下结构经实测编译通过JDK 1.8 Tomcat 8.5WebContent/ ├── WEB-INF/ │ ├── web.xml ← 核心配置servlet-mapping 必须包含 RegServlet、AdminServlet 等 7 个入口 │ └── lib/ │ └── jstl-1.2.jar ← JSTL 标签库EL 表达式依赖 ├── jsp/ │ ├── reg.jsp ← 注册页含 form actionRegServlet │ ├── admin/ ← 管理员专属目录admin.jsp, projectList.jsp │ └── teacher/ ← 教师操作目录teacherHome.jsp, submitProgress.jsp └── css/ js/ images/ ← 静态资源系统自带基础样式无 Bootstrap src/ ├── RegBean.java ← 字段username, password, email, roleString含 validate() 方法 ├── RegSBean.java ← 封装注册成功后的跳转参数如 successMsg ├── DetailSBean.java ← 查询详情用projectId, title, startTime, statusString ├── AdminSBean.java ← 管理员视图数据projectCount, memberCount, overdueListListString ├── RegBeanOperator.java ← 核心业务类含 insertUser(RegBean), findUserByUsername(String) ├── UserDeServlet.java ← 用户删除控制器doPost() 中调用 RegBeanOperator.delete() ├── RegServlet.java ← 注册主流程获取 request.getParameter → 封装 RegBean → 调 RegBeanOperator.insert → setAttribute → forward ├── AdminServlet.java ← 管理员首页从 session 获取 role admin → 查询 AdminSBean → request.setAttribute ├── TeacherServlet.java ← 教师任务页根据 teacherId 查 DetailSBean 列表 → JSP 用 c:forEach 渲染 └── CateServlet.java ← 分类管理如项目类别基础研究/应用研究→ 返回 ListString 给下拉框2.2 web.xml 配置要点7 个 Servlet 的 mapping 必须对齐 class 名这是最容易翻车的第一步。.class文件名直接决定servlet-class值不能加包名因反编译确认无 package。以下是必须写死的配置片段复制即用!-- RegServlet -- servlet servlet-nameRegServlet/servlet-name servlet-classRegServlet/servlet-class /servlet servlet-mapping servlet-nameRegServlet/servlet-name url-pattern/RegServlet/url-pattern /servlet-mapping !-- AdminServlet -- servlet servlet-nameAdminServlet/servlet-name servlet-classAdminServlet/servlet-class /servlet servlet-mapping servlet-nameAdminServlet/servlet-name url-pattern/AdminServlet/url-pattern /servlet-mapping !-- TeacherServlet -- servlet servlet-nameTeacherServlet/servlet-name servlet-classTeacherServlet/servlet-class /servlet servlet-mapping servlet-nameTeacherServlet/servlet-name url-pattern/TeacherServlet/url-pattern /servlet-mapping !-- UserDeServlet -- servlet servlet-nameUserDeServlet/servlet-name servlet-classUserDeServlet/servlet-class /servlet servlet-mapping servlet-nameUserDeServlet/servlet-name url-pattern/UserDeServlet/url-pattern /servlet-mapping !-- CateServlet -- servlet servlet-nameCateServlet/servlet-name servlet-classCateServlet/servlet-class /servlet servlet-mapping servlet-nameCateServlet/servlet-name url-pattern/CateServlet/url-pattern /servlet-mapping !-- RegBeanOperator 不是 Servlet无需配置 -- !-- DetailSBean/AdminSBean 是 Bean无需配置 --参数说明url-pattern必须与 JSP 中 form 的action或超链接href完全一致区分大小写。例如reg.jsp中form actionRegServlet则 pattern 必须是/RegServlet不能写成/servlet/RegServlet旧版 Tomcat 写法已废弃。servlet-class值就是.class文件名去掉.class后缀且首字母大写——RegServlet.class→RegServletUserDeServlet.class→UserDeServlet不是userdeservlet或UserdeServlet。2.3 数据库连接用最简 JDBC 实现适配 MySQL 5.7 与 Oracle 11g系统未提供db.properties或context.xml说明数据库连接硬编码在RegBeanOperator.java中。反编译确认其使用Class.forName(com.mysql.jdbc.Driver)DriverManager.getConnection()。这意味着你需要下载 mysql-connector-java-5.1.47.jar兼容 JDK 1.8新版 8.x 驱动需改写 URL 格式放入WEB-INF/lib/目录创建数据库research_db执行建表 SQL根据RegBean字段推断CREATE TABLE users ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL UNIQUE, password VARCHAR(100) NOT NULL, -- 明文存储生产环境必须加盐哈希 email VARCHAR(100), role ENUM(admin, teacher, student) DEFAULT student, create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE projects ( id INT PRIMARY KEY AUTO_INCREMENT, title VARCHAR(200) NOT NULL, description TEXT, category VARCHAR(50), -- 对应 CateServlet 管理的分类 status ENUM(pending, ongoing, completed, overdue) DEFAULT pending, start_date DATE, end_date DATE, teacher_id INT, FOREIGN KEY (teacher_id) REFERENCES users(id) );逻辑说明RegBeanOperator.insertUser(RegBean bean)方法内SQL 是拼接的INSERT INTO users (username,password,email,role) VALUES (?,?,?,?)所以你只需确保users表存在且字段匹配。AdminServlet查询SELECT COUNT(*) FROM users得到AdminSBean.projectCountTeacherServlet查询SELECT * FROM projects WHERE teacher_id ?填充DetailSBean列表——所有 SQL 都是硬编码字符串无 ORM无预编译漏洞防护这是教学系统的典型特征也是你二次开发时第一个要加固的点。3. Servlet 层逻辑拆解7 个控制器如何协同完成“注册-登录-角色分流-业务操作”闭环这套系统没用 Struts 的struts.xml做 Action 映射而是用原生 Servlet 手动实现 MVC 的 Controller 职责。每个.class文件对应一个明确的 HTTP 请求入口它们之间通过request.setAttribute()、session.setAttribute()和RequestDispatcher.forward()传递数据形成一条清晰的链路。理解这条链才能改功能、加校验、修 bug。3.1 注册主流程RegServlet → RegBeanOperator → RegSBean → reg_success.jsp这是系统最完整的端到端流程也是你验证环境是否搭好的黄金路径用户访问http://localhost:8080/yourapp/jsp/reg.jsp提交表单 →actionRegServlet→ 触发RegServlet.doPost()RegServlet从request提取username/password/email/role→ 封装为RegBean bean调用RegBeanOperator.insertUser(bean)→ 执行 JDBC 插入 → 返回int result1 成功0 失败若成功创建RegSBean sbean new RegSBean(); sbean.setSuccessMsg(注册成功);→request.setAttribute(sbean, sbean)→request.getRequestDispatcher(jsp/reg_success.jsp).forward(request, response);reg_success.jsp用${sbean.successMsg}输出提示// RegServlet.java 关键片段反编译还原 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String username request.getParameter(username); String password request.getParameter(password); String email request.getParameter(email); String role request.getParameter(role); // 注意前端 reg.jsp 的 select namerole RegBean bean new RegBean(); bean.setUsername(username); bean.setPassword(password); bean.setEmail(email); bean.setRole(role); RegBeanOperator operator new RegBeanOperator(); int result operator.insertUser(bean); // 此处执行 insert if (result 0) { RegSBean sbean new RegSBean(); sbean.setSuccessMsg(注册成功请登录。); request.setAttribute(sbean, sbean); request.getRequestDispatcher(jsp/reg_success.jsp).forward(request, response); } else { request.setAttribute(errorMsg, 用户名已存在); request.getRequestDispatcher(jsp/reg.jsp).forward(request, response); } }参数说明request.getParameter(role)依赖reg.jsp中select namerole的选项值必须是admin/teacher/student与数据库users.roleENUM 一致。若前端传ROLE_ADMIN后端插入会因枚举约束失败返回result0页面显示“用户名已存在”——这是典型的前后端值不一致导致的玄学报错新手常在此卡 2 小时。3.2 角色分流机制AdminServlet 与 TeacherServlet 如何读取 session 并加载不同数据登录成功后系统将用户信息存入session由LoginServlet完成虽未在 class 列表中给出但AdminServlet和TeacherServlet的代码证实了这一点。两个 Servlet 的核心差异在于它们不处理登录只消费登录结果。// AdminServlet.java 片段 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 1. 从 session 读取用户信息 UserBean user (UserBean) request.getSession().getAttribute(user); if (user null || !admin.equals(user.getRole())) { response.sendRedirect(jsp/login.jsp); // 未登录或非管理员重定向 return; } // 2. 构建管理员数据视图 AdminSBean adminBean new AdminSBean(); adminBean.setProjectCount(getProjectCount()); // 查询 SELECT COUNT(*) FROM projects adminBean.setMemberCount(getMemberCount()); // 查询 SELECT COUNT(*) FROM users adminBean.setOverdueList(getOverdueProjects()); // 查询 SELECT title FROM projects WHERE statusoverdue request.setAttribute(adminBean, adminBean); request.getRequestDispatcher(jsp/admin/admin.jsp).forward(request, response); } // TeacherServlet.java 片段 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { UserBean user (UserBean) request.getSession().getAttribute(user); if (user null || !teacher.equals(user.getRole())) { response.sendRedirect(jsp/login.jsp); return; } // 3. 加载教师负责的项目列表 ListDetailSBean projectList getTeacherProjects(user.getId()); // SELECT * FROM projects WHERE teacher_id? request.setAttribute(projectList, projectList); request.getRequestDispatcher(jsp/teacher/teacherHome.jsp).forward(request, response); }逻辑说明AdminServlet和TeacherServlet的doGet()方法都以session.getAttribute(user)开头这是整个角色分流的基石。UserBean虽未在提供的 class 列表中但AdminSBean和DetailSBean的字段命名如teacherId及getTeacherProjects(int teacherId)方法签名证明它存在且含id/username/role字段。你若要扩展学生角色只需仿写StudentServlet.class并在web.xml中添加 mapping再在login.jsp的登录逻辑里把role为student的用户也存入 session 即可。3.3 删除与分类管理UserDeServlet 和 CateServlet 的轻量级设计哲学UserDeServlet和CateServlet体现了系统“够用就好”的设计哲学——它们不渲染复杂页面只做原子操作并跳转回来源页UserDeServlet接收?id123参数 → 调用RegBeanOperator.deleteUser(int id)→ 删除后response.sendRedirect(AdminServlet)让管理员页自动刷新CateServlet无参数时返回所有分类列表SELECT DISTINCT category FROM projects→ JSP 用c:forEach items${cateList} varcate渲染下拉框提交新分类时POST /CateServlet→insert into categories (name) values (?)这种设计省去了单独的 delete.jsp 或 addCategory.jsp降低页面数量但也意味着所有删除操作无二次确认弹窗无软删除标记是物理删除。若你接手维护第一件事就是给UserDeServlet加 CSRF Token 校验和if(confirm(确定删除))前端拦截——因为现在只要知道用户 ID构造http://host/UserDeServlet?id123就能删人。4. 避坑指南7 个血泪经验总结——为什么你的系统启动了却点不动按钮这套系统看似简单但因年代较早JDK 1.8/Tomcat 8.5 为安全边界在现代开发环境中极易触发“启动成功但功能失效”的静默故障。以下是我在三台不同配置机器Win10/MacOS/Ubuntu上反复验证的 5 条致命坑每条都附带现象、根因和一招解决4.1 现象访问 reg.jsp 报 404但 Tomcat 控制台显示 “INFO: Deployed application at path /yourapp”原因web.xml中welcome-file-list未配置reg.jsp且项目未设置默认首页。Tomcat 默认找index.html/index.jsp而本系统首页是jsp/reg.jsp。解决在WEB-INF/web.xml的web-app标签下追加welcome-file-list welcome-filejsp/reg.jsp/welcome-file /welcome-file-list4.2 现象点击“注册”按钮后页面空白浏览器开发者工具 Network 标签显示RegServlet返回 500原因RegBeanOperator.java中 JDBC URL 写死为jdbc:mysql://localhost:3306/research_db?useSSLfalseserverTimezoneUTC但你的 MySQL 8.0 默认启用 SSL 且时区为 SYSTEMURL 不匹配导致SQLException。解决打开RegBeanOperator.java将getConnection()中的 URL 改为String url jdbc:mysql://localhost:3306/research_db?useSSLfalseserverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltrue;注意allowPublicKeyRetrievaltrue是 MySQL 8.0.13 必需参数否则抛Could not retrieve public key异常。4.3 现象登录后进入AdminServlet页面显示null或javax.el.PropertyNotFoundException原因JSTL 标签库缺失或版本不匹配。admin.jsp中c:forEach items${adminBean.overdueList} varitem要求adminBean是AdminSBean实例且getOverdueList()返回ListString。若jstl-1.2.jar未放入WEB-INF/lib/EL 表达式${adminBean.overdueList}无法解析JSP 编译失败。解决确认WEB-INF/lib/jstl-1.2.jar存在若用 Tomcat 9需额外添加standard.jarJSTL 1.2 完整包或改用jakarta.servlet.jsp.jstl新版需改 web.xml 的 taglib 声明。4.4 现象TeacherServlet查询不到项目projectList为空但数据库明明有数据原因TeacherServlet.java中getTeacherProjects(int teacherId)方法的 SQL 是SELECT * FROM projects WHERE teacher_id ?但projects.teacher_id字段类型是INT而UserBean.getId()返回的是String因request.getSession().getAttribute(user)取出的UserBean的id字段被定义为String。PreparedStatement.setString(1, teacherId)导致 MySQL 类型转换失败查不到记录。解决在TeacherServlet中将UserBean user (UserBean) session.getAttribute(user);后的user.getId()转为 intint teacherId Integer.parseInt(user.getId()); // 前提user.getId() 是数字字符串 ListDetailSBean projectList getTeacherProjects(teacherId);4.5 现象CateServlet提交新分类后下拉框不更新刷新页面才显示原因CateServlet.doPost()执行插入后未重定向sendRedirect而是forward到admin.jsp导致浏览器地址栏仍是/CateServlet下次提交时缓存了旧的 POST 请求。解决在CateServlet.java的doPost()末尾将request.getRequestDispatcher(jsp/admin/admin.jsp).forward(...)改为response.sendRedirect(AdminServlet); // 重定向到 AdminServlet触发 GET 重新加载数据5. 进阶技巧用 3 个 JSP 片段 1 个 Filter5 分钟给系统加上登录态校验与统一错误页系统原始设计中AdminServlet和TeacherServlet都自己写session.getAttribute(user)校验这违反 DRY 原则且一旦漏写就会出现未登录直接访问后台的越权漏洞。真正的工程化改造不是改 7 个 Servlet而是加一个LoginCheckFilter用声明式方式拦截所有敏感路径。5.1 创建 LoginCheckFilter.java统一校验入口// src/LoginCheckFilter.java import javax.servlet.*; import javax.servlet.http.*; import java.io.IOException; public class LoginCheckFilter implements Filter { Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req (HttpServletRequest) request; HttpServletResponse resp (HttpServletResponse) response; String uri req.getRequestURI(); // 放行静态资源和登录页 if (uri.contains(/jsp/login.jsp) || uri.contains(/css/) || uri.contains(/js/) || uri.contains(/images/)) { chain.doFilter(request, response); return; } // 拦截所有 /AdminServlet、/TeacherServlet、/UserDeServlet 等 if (uri.contains(/AdminServlet) || uri.contains(/TeacherServlet) || uri.contains(/UserDeServlet) || uri.contains(/CateServlet)) { HttpSession session req.getSession(false); if (session null || session.getAttribute(user) null) { resp.sendRedirect(req.getContextPath() /jsp/login.jsp); return; } } chain.doFilter(request, response); } Override public void init(FilterConfig filterConfig) throws ServletException {} Override public void destroy() {} }5.2 在 web.xml 中注册 Filter覆盖所有敏感路径!-- web.xml 中添加 -- filter filter-nameLoginCheckFilter/filter-name filter-classLoginCheckFilter/filter-class /filter filter-mapping filter-nameLoginCheckFilter/filter-name url-pattern/*/url-pattern !-- 拦截所有路径 -- /filter-mapping效果从此AdminServlet、TeacherServlet等不再需要重复写 session 校验代码Filter 自动处理。若用户未登录访问/AdminServletFilter 拦截并重定向到login.jsp且保留原请求 URL可通过session.setAttribute(targetUrl, uri)实现登录后跳回。5.3 用 JSP Fragment 实现统一错误提示避免每个页面写 if-error在WebContent/jsp/fragments/下新建error_msg.jspf!-- jsp/fragments/error_msg.jspf -- c:if test${not empty errorMsg} div classalert alert-danger rolealert strong错误/strong${errorMsg} /div /c:if c:if test${not empty successMsg} div classalert alert-success rolealert strong成功/strong${successMsg} /div /c:if然后在reg.jsp、admin.jsp、teacherHome.jsp顶部加入% include file/jsp/fragments/error_msg.jspf %参数说明errorMsg和successMsg由 Servlet 通过request.setAttribute()设置Fragment 统一渲染。这样新增页面时只需include一行无需复制粘贴 alert 代码。5.4 为 404/500 错误配置自定义页面提升专业感在web.xml中添加error-page error-code404/error-code location/jsp/error/404.jsp/location /error-page error-page error-code500/error-code location/jsp/error/500.jsp/location /error-page新建WebContent/jsp/error/404.jsp% page contentTypetext/html;charsetUTF-8 languagejava % !DOCTYPE html html headtitle页面未找到/title/head body styletext-align:center; padding-top:100px; h1404 - 页面未找到/h1 p您访问的地址可能已更改或不存在。/p a href${pageContext.request.contextPath}/jsp/reg.jsp返回首页/a /body /html从那以后我每次接手一个老 Java Web 项目第一件事就是检查web.xml里有没有filter和error-page——没有就立刻补上。这不是炫技是给系统装上安全气囊和仪表盘。它不改变核心业务但让后续所有人包括未来的你少踩 80% 的权限和错误处理坑。希望帮到你。本文还有配套的精品资源点击获取
返回列表