做淘宝联盟网站做淘宝类网站的步骤
做淘宝联盟网站,做淘宝类网站的步骤,太仓做网站,网站建设及推广文案基于JavaWeb的毕业设计实战#xff1a;从零构建高内聚低耦合的教务管理系统 摘要#xff1a;许多毕业生在完成基于JavaWeb的毕业设计时#xff0c;常陷入技术堆砌、架构混乱或功能冗余的困境。本文以教务管理系统为实战案例#xff0c;采用ServletJSPMySQL基础栈#xff0…基于JavaWeb的毕业设计实战从零构建高内聚低耦合的教务管理系统摘要许多毕业生在完成基于JavaWeb的毕业设计时常陷入技术堆砌、架构混乱或功能冗余的困境。本文以教务管理系统为实战案例采用ServletJSPMySQL基础栈结合MVC分层思想详解如何实现模块解耦、事务控制与用户权限校验。读者将掌握可复用的工程结构、防SQL注入的安全编码实践并获得一套可直接部署的轻量级项目模板显著提升开发效率与答辩竞争力。一、毕业生常见开发痛点代码耦合把业务逻辑、SQL、页面跳转全写进一个JSP后期改一行全站报错。无异常处理遇到主键冲突、空指针直接500浏览器堆栈信息把表结构暴露无遗。安全漏洞登录SQL拼接、${param.xxx}直接回显答辩现场被老师一句“你试过SQL注入吗”问倒。重复造轮子每个Servlet都写一遍获取Connection、关闭ResultSet代码量比业务逻辑还多。中文乱码Windows下写死new String(request.getParameter(name).getBytes(ISO-8859-1),UTF-8)部署到Linux当场翻车。二、技术选型为什么回到“原生”Servlet方案优点缺点毕业设计场景Spring Boot零配置、生态丰富起步即Parent、注解黑箱答辩易被问“Starter做了什么”老师怀疑你直接抄脚手架Spring MVC分层清晰需要理解IoC、AOP配置一堆时间紧容易调不通ServletJSP语法直观、无黑箱、服务器随处可见样板代码多正好练手机会把样板抽象成工具类体现“造轮子”能力结论用原生Servlet能把HTTP生命周期、字符编码、事务边界亲手摸一遍答辩时底气足。三、工程骨架先搭“高内聚低耦合”的目录edu-manage ├─src │ ├─main │ │ ├─java │ │ │ ├─controller // 仅收参、跳转 │ │ │ ├─service // 事务脚本 │ │ │ ├─dao // 纯SQL不含业务 │ │ │ ├─util // 连接池、字符过滤 │ │ │ └─entity // POJO │ │ └─webapp │ │ ├─WEBNAME │ │ ├─view // JSP │ │ └─static // css/js └─sql └─edu.sql // 建表样本数据约定controller层禁止出现conn.createStatement()service层做事务开关dao层只做CRUD所有外部参数先进XssFilter再进controller四、核心实现细节4.1 用户登录鉴权含防SQL注入表结构CREATE TABLE user( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(20) UNIQUE NOT NULL, password CHAR(64) NOT NULL, -- 存SHA-256 role ENUM(ADMIN,TEACHER,STUDENT) );DAO层使用PreparedStatement杜绝拼接public class UserDao { private DataSource ds DataSourceUtil.getInstance(); public OptionalUser findByUsername(String username) fro SQLException{ String sql SELECT id,username,password,role FROM user WHERE username?; try (Connection conn ds.getConnection(); PreparedStatement ps conn.prepareStatement(sql)){ ps.setString(1, username); try (ResultSet rs ps.executeQuery()) { if (rs.next()) { User u new User(); u.setId(rs.getInt(id)); u.setUsername(rs.getString(username)); u.setPassword(rs.getString(password)); u.setRole(Role.valueOf(rs.getString(role))); return Optional.of(u); } } } return Optional.empty(); } }Service层统一事务边界public class UserService { private UserDao userDao new UserDao(); public User login(String username, String rawPwd) MicException { OptionalUser op userDao.findByUsername(username); if (!op.isPresent()) { throw new MicException(用户不存在); } User u op.get(); String sha HashUtil.sha256(rawPwd); if (!sha.equals(u.getPassword())) { throw new MicException(密码错误); } return u; } }Controller层收参跳转WebServlet(/login) public class LoginServlet extends HttpServlet { private UserService userService new UserService(); Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding(UTF-8); String username req.getParameter(username); String password req.getParameter(password); try { User user userService.login(username, password); req.getSession().setAttribute(loginUser, user); resp.sendRedirect(req.getContextPath() /index.jsp); } catch (MicException e) { req.setAttribute(msg, e.getMessage()); req.getRequestDispatcher(/login.jsp).forward(req, resp); } } }注意密码在浏览器→服务器→数据库全程密文登录失败不提示“用户名或密码错误”而是统一“用户不存在或密码错误”防用户名枚举。4.2 课程CRUD与事务管理新增课程需要同时写入course表、teacher_course中间表两步必须在同一事务。public class CourseService { private CourseDao courseDao new CourseDao(); private TeacherCourseDao tcDao new TeacherCourseDao(); public void addCourseWithTeacher(Course c, int teacherId) SQLException { Connection conn DataSourceUtil.getConnection(); try { conn.setAutoCommit(false); int courseId courseDao.insert(c, conn); // 第1步 tcDao.insert(teacherId, courseId, conn); // 第2步 conn.commit(); } catch (Exception e) { conn.rollback(); throw e; } finally { conn.close(); } } }dao层重载带Connection的签名保证同链接public int insert(Course c, Connection conn) SQLException { String sql INSERT INTO course(name,credit) VALUES(?,?); try (PreparedStatement ps conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) { ps.setString(1, c.getName()); ps.setInt(2, c.getCredit()); ps.executeUpdate(); try (ResultSet keys ps.getGeneratedKeys()) { keys.next(); return keys.getInt(1); } } }4.3 统一字符编码与Clean Code小套路在web.xml里声明CharacterEncodingFilter优先于其他Filter所有常量集中public static final String SESSION_USER loginUser拒绝魔法数if (user.getRole() Role.ADMIN)而不是1异常链保留throw new MicException(xxx, e)方便日志定位五、安全性与性能5.1 XSS防护自定义EL函数库fn:escapeHtml回显用户输入或采用JSTLc:out value${param.name} /默认转义5.2 SQL注入100%使用PreparedStatement禁止“WHERE id IN (拼接)”场景用FIND_IN_SET或临时表5.3 连接池与性能选用HikariCPSpring官方也在用轻量核心配置jdbcUrljdbc:mysql://127.0.0.1:3306/edu?useSSLfalseserverTimezoneUTC maximumPoolSize20 minimumIdle5 connectionTimeout30000避免N1课程列表一次性LEFT JOIN teacher结果集用MapInteger,ListTeacher分组减少循环查库六、生产环境避坑指南Tomcat路径空格Windows把项目放Program Files路径含空格导致getRealPath()返回%20文件上传报404。统一用C:\opt\tomcat\webapps。MySQL8时区未写serverTimezoneUTC会抛The server time zone value Öйú±ê׼ʱ¼ä在jdbcUrl显式声明。中文乱码数据库utf8mb4页面meta charsetutf-8response.setContentType(text/html;charsetutf-8)统一Filter在最前链热部署与生产IDEA热部署插件改class不重启演示很爽生产务必关reloadabletrue否则Full GC狂飙。七、完整可运行代码获取仓库地址Giteehttps://gitee.com/yourname/edu-manageclone后执行导入sql/edu.sql改src/main/resources/db.propertiesmvn clean package把target/edu-manage.war丢进Tomcat webapps启动即访问http://localhost:8080/edu-manage八、下一步把项目演进成微服务拆分边界user-service注册、鉴权、JWT颁发course-service课程CRUDscore-service成绩计算、统计共享数据用MyBatis-Plus shardingsphere做分库分表避免“一个库扛全校”。网关与前端Spring Cloud Gateway统一路由前端Vue3AntV成绩统计直接出雷达图答辩秒变亮点。写在最后整套教务系统没有黑科技却能把HTTP、字符编码、事务、安全这些基本功串成线。把代码跑通后不妨先给“成绩”模块加个柱状图体会一把前端调接口的爽点再把服务拆开用Docker Compose起三个容器你就拥有了微服务雏形。毕业设计不是终点而是把“写代码”变成“做系统”的第一站——动手吧下一位拿优秀论文的就是你。