资讯动态

Spring Boot与Web Service的教务管理系统毕业设计实战

发布时间:2026/10/13 23:58:59 来源:尧图企业网站定制
每年到了毕设选题季总有一批学生盯上“教务管理系统”这类题目业务好理解、资料多、答辩论得清。但真上手写代码之后很多人又会被“springboot web service技术”这几个字绊住——网上搜出来的教程一半是SSM老项目另一半则是纯REST风格跟题目里“web service技术”完全对不上。这篇文章我按一个可落地的毕业设计路线来聊Spring Boot做主体框架Web Service技术作为对外接口层落地把教务管理里用户、课程、选课、成绩这几条主链路串起来同时把权限、并发、部署、答辩这些容易被追问的点一并讲透。内容尽量贴近实际开发顺序适合准备做此类课题、或者已经在写代码但卡在某个环节的同学参考。1. 教务管理系统这个选题为什么值得做但没那么简单1.1 它在毕设选题中的定位教务管理系统属于典型的信息管理系统放在计算机毕业设计里看属于“安全牌”和“平庸牌”的分岔口。说它安全是因为业务需求明确学生、教师、课程、成绩这些对象大家在学校里天天接触不需要额外科普需求分析、用例图、E-R图都能顺畅画出来。说它容易平庸是因为这类系统做到最后往往就是一堆增删改查页面论文没什么可写的答辩时老师问两句就露怯。所以做这个题目的第一个原则是不要只做CRUD要在业务规则上做出差异化。比如选课时防止超选、退课后的名额回补、成绩只能由开课教师录入、一门课程不能被同一个学生重复选择这些约束在初版功能里就应该体现。它们不复杂但能证明你理解“系统”而不是“代码集合”。第二个原则是把“web service技术”这个点真正落进代码里。很多同学用Spring MVC写完后发现自己全程用的是RESTful接口和题目中的“web service”确实有关系但答辩时容易说不清。稳妥做法是主体功能用Spring Boot Spring MVC模板渲染再额外用JAX-WS发布一组SOAP服务比如成绩查询、教师课程列表查询作为对外服务接口层。1.2 业务边界哪些功能必须做哪些直接砍教务管理系统的全貌很大排课、教室调度、教材管理、学费核算、评教这些都属于教务范畴但毕设周期根本做不完。建议把功能收敛为一条主线基础档案 培养环节。具体必要功能我列一个MVP清单照着这个顺序开发不会跑偏模块核心功能涉及角色登录认证账号密码登录、退出、密码修改所有角色用户权限角色区分、页面访问拦截管理员学生管理学生信息维护、按学号/姓名查询、按班级筛选管理员教师管理教师档案维护、所属院系统计管理员班级/专业管理班级、专业、院系基础数据维护管理员课程管理课程基本信息维护包括学分、学时、任课教师管理员开课管理每学期生成课程记录设定选课容量管理员选课管理学生选课、退课、选课名单查看学生、教师成绩管理成绩录入、修改、成绩查询、加权统计教师、学生数据统计学生选课门数统计、课程选课人数统计管理员排课算法、智能推荐、复杂权限框架这些内容初版不要碰。如果后面中期检查觉得进度快再往外扩一两个功能作为加分项比如成绩单导出、按学分绩点排名。把主链路做扎实比堆砌一堆半成品功能要有效得多。我在给同学改代码时见过一个很典型的反面案例表建了十几张控制器写了一百多个方法但选课记录没有任何唯一性约束同一个学生能把同一门选修课选三次。这种系统演示时看起来很热闹答辩时一查数据就得露馅。基础约束和数据一致性才是这种项目的血和肉。2. 技术栈取舍springboot做主框架web service怎么落地2.1 为什么选Spring Boot而不是纯Spring MVC现在再让学生从零搭一个SSM架构的XML配置工程已经不太符合实际工作情况。Spring Boot的价值在于自动配置和约定优于配置内嵌Tomcat、默认依赖管理、Starter机制直接把常用组件的配置包好。对毕业设计来说选择Spring Boot至少有三个实打实的好处第一工程结构简洁不需要写一堆XML配置文件精简掉大量和业务无关的配置代码论文里也能用更短的篇幅讲清楚技术方案。第二本地开发调试直接运行主类启动服务不用安装独立的Tomcat或者Jetty部署到服务器时也可选择直接打jar包运行。第三Spring Boot对Spring生态的兼容性最好集成MyBatis、Spring Security、Apache CXF这些组件都有成熟的Starter方案。选版本的时候注意一点如果你用的是JDK8直接选Spring Boot 2.7.x系列最省心如果学校环境或者你个人装了JDK17以上再考虑Spring Boot 3.x。下面的代码示例统一按JDK8 Spring Boot 2.7.x来写这是当前毕业设计环境里兼容性最高的组合。2.2 Web Service两种实现SOAP还是REST毕设怎么选“Web Service”这个术语其实有广义和狭义两套理解。广义上凡是基于HTTP提供跨系统服务能力的都可以叫Web ServiceRESTful接口也算狭义上主要指基于SOAP协议、用XML描述消息、并通过WSDL文档对外公布接口定义的分布式服务方式。如果你的题目出现“web service技术”但没写“rESTful”很多答辩老师的第一反应是“你是不是要讲SOAP”这时候只做JSON接口是有点风险的。我的建议是两者都做但分工明确。系统内部以及浏览器页面请求走常规的Spring MVC接口对外提供教务数据服务时用JAX-WS发布SOAP Web Service例如成绩查询服务、教师课表查询服务服务通过WSDL对外暴露。这样系统本身很好用也有标准Web Service的落地证据。实现SOAP服务时主要用Apache CXF框架它是Java生态里比较主流的Web Service框架和Spring Boot有对应的Starter集成。它在服务端负责把Java接口按照JAX-WS规范发布成SOAP端点自动生成WSDL在客户端则可以用wsimport或CXF自带的客户端工厂生成调用代码。后面第4章我会把从引入依赖到测试调用的完整过程写出来。2.3 开发环境与版本组合为了避免大家照着教程做时出现版本错位我把一份经过验证的开发环境组合放在表格里供直接参考组件版本建议说明JDK8兼容性最好学校机房一般也有该环境Maven3.6.3及以上依赖管理工具Spring Boot2.7.182.7系列最后的稳定版Apache CXF3.5.x/3.6.x与Spring Boot 2.7适配良好MyBatismybatis-spring-boot-starter 2.3.x如果用Spring Boot3则换成3.x版本MySQL5.7或8.0字符集用utf8mb4IDEIntelliJ IDEA社区版即可如果你决定用JDK17 Spring Boot 3.xCXF记得换4.x版本MyBatis Starter也要换3.x版本否则运行时会报一类“ClassNotFoundException”或者依赖冲突。这个坑我帮人排查过很多次每次都差不多先看依赖版本是否匹配。3. 从数据库表到功能模块先画好一张依赖图再写代码3.1 核心表结构设计毕设级教务系统不需要做太复杂的数据建模但核心表和关联关系要想清楚。通常至少要有这些表用户表、角色表、学生信息表、教师信息表、班级表、课程表、开课记录表、选课记录表。我先说设计意图再给关键SQL。用户表存登录账号和密码但不要把学生姓名、学号、性别这些塞在用户表里而是用user_id去关联学生表或教师表。这样设计的理由是一个账号可以只存在于用户体系不一定对应学生或教师角色后续要扩展管理员等角色也方便。角色字段我习惯直接放在用户表里用一个字符串或整数表示毕设规模完全够用不用再单独做user-role关联表。开课记录表是课程表的下游表。课程表只保存课程本身静态信息比如课程代码、名称、学分开课记录表保存“这学期开了哪门课、由哪位老师上、容量是多少、已选多少人”。这样同一个课程不同学期可以有不同的开课记录也方便统计每个学期的选课情况。选课记录表则连接学生和开课记录同时直接承载成绩字段。一门学生选过的课对应一条记录成绩就记在选课记录上要不要单独建成绩表我建议不要加了反而要在逻辑上保证“每条成绩都必须对应一条选课记录”白白增加复杂度。以下是选课记录表的简化版本CREATE TABLE student_course ( id BIGINT NOT NULL AUTO_INCREMENT COMMENT 主键, student_id BIGINT NOT NULL COMMENT 学生ID关联student.id, course_open_id BIGINT NOT NULL COMMENT 开课ID关联course_open.id, semester VARCHAR(20) NOT NULL COMMENT 选课学期如2024-2025-1, score DECIMAL(5,2) DEFAULT NULL COMMENT 成绩未录入时为空, status TINYINT NOT NULL DEFAULT 0 COMMENT 0正常1退课, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_student_course_open (student_id, course_open_id, semester), KEY idx_course_open_id (course_open_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT选课记录表;这里最重要的就是uk_student_course_open这个联合唯一索引。哪怕应用层漏做了重复判断数据库也能兜底保证同一个学生同一个学期同一门开课记录只能出现一次。3.2 模块落地的推荐顺序开发顺序建议按依赖关系来排而不是按页面优先或者代码生成器优先。我推荐的顺序是先搭数据库把表结构和基础数据准备出来这是后面所有模块的地基。先做登录认证和用户上下文。登录不做好后面每个页面都没法验证“当前是谁”权限拦截也无从谈起。再做基础档案班级、学生、教师。它们是选课和成绩的“主语”。再推进课程和开课模块把课程批量导入或单条维护做通。接下来是选课退课这是系统里最关键的业务模块会涉及并发更新和唯一性约束。最后做成绩模块和统计页面因为成绩依赖选课数据统计依赖前面所有数据。这个顺序的好处是每一阶段都能独立测试。我不太建议一开始就配置好代码生成器把全部表的增删改查都生成出来那样看起来很快但到了业务逻辑集成阶段大量生成代码反而让人不知道该改哪里。3.3 容易翻车的业务约束这块是教务系统区别于玩具Demo的关键我把高频出的几个问题列一下重复选课前面那张选课表加了联合唯一索引代码里选课之前先执行一次查询校验双保险。超选名额不要先查容量再判断再更新要用原子更新来兜底。以下是一个比较稳妥的写法int updated courseOpenMapper.reduceOrOccupy( courseOpenId, 1, // 本次要占用的名额 maxCapacity); if (updated 0) { throw new BizException(课程名额不足或课程不存在); }对应的SQL大致是这样UPDATE course_open SET selected_count selected_count #{delta} WHERE id #{courseOpenId} AND selected_count #{delta} #{maxCapacity}用影响行数来判断到底有没有占上名额能避免并发选课时两个人同时读到剩余名额为1、然后都选上的问题。这里不需要复杂分布式锁一条带条件的UPDATE语句就够了。成绩录入权限教师端查询可录入成绩的开课记录时必须用当前登录教师的id去过滤不能允许教师通过篡改参数给其他老师的课录成绩。退课释放退课时把选课状态改为1同时执行selected_count selected_count - 1注意这个操作和选课一样要放在事务里。4. Spring Boot集成JAX-WS发布SOAP服务的完整过程4.1 依赖引入与配置类写法在Spring Boot工程里用CXF发布SOAP服务第一步是引入CXF的Starter依赖比手工配置CXF和Servlet要省事很多。以Spring Boot 2.7为例在pom.xml中添加dependency groupIdorg.apache.cxf/groupId artifactIdcxf-spring-boot-starter-jaxws/artifactId version3.6.4/version /dependency然后写一个配置类通过CXF的EndpointImpl把服务实现类发布到指定路径。这里一个容易踩的坑是不要用JDK自带的javax.xml.ws.Endpoint.publish那样会另起一个独立的HTTP端口和Spring Boot的主服务脱离后面处理统一端口、过滤器、全局异常都会很别扭。正确做法是用CXF的EndpointImpl。import org.apache.cxf.Bus; import org.apache.cxf.jaxws.EndpointImpl; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import javax.xml.ws.Endpoint; Configuration public class CxfWebServiceConfig { private final Bus bus; private final ScoreWebService scoreWebService; public CxfWebServiceConfig(Bus bus, ScoreWebService scoreWebService) { this.bus bus; this.scoreWebService scoreWebService; } Bean public Endpoint scoreServiceEndpoint() { EndpointImpl endpoint new EndpointImpl(bus, scoreWebService); // 发布路径http://localhost:8080/services/scoreService endpoint.publish(/services/scoreService); return endpoint; } }注意scoreWebService这里注入的是服务实现类的Bean它的类上要标注Service而不是Endpoint这一类的旧式注解。发布完之后应用启动时控制台会看到CXF自动生成了WSDL路径直接用浏览器访问/services/scoreService?wsdl就能看到XML格式的接口描述。4.2 服务端接口与实现类的分层陷阱SOAP服务的接口定义要走JAX-WS规范。接口上标注WebService方法上标注WebMethod参数和返回值上用WebParam标记名称。返回值对象需要是一个普通的POJO而且要能序列化为XML字段上可以用XmlElement控制节点名。这里有个非常容易犯的错误直接把业务实体类返回出去。实体类里如果存在嵌套关联或者其他类型的字段CXF生成WSDL时可能报错或生成一堆难以理解的复杂类型建议单独定义DTO类只暴露必要字段。我以一个成绩查询服务为例。接口定义WebService(targetNamespace http://service.course.demo/, name ScoreWebService, serviceName ScoreWebService) public interface ScoreWebService { WebMethod ScoreResult getScoreByStudentNo(WebParam(name studentNo) String studentNo, WebParam(name semester) String semester); }实现类不要一上来就写数据库操作而是继续调用内部的业务Service。这样做的目的很直接底层事务、缓存、业务校验都收敛在Spring管理的Service里Web Service层只做协议适配。实现类写法如下Service public class ScoreWebServiceImpl implements ScoreWebService { private final ScoreBusinessService scoreBusinessService; public ScoreWebServiceImpl(ScoreBusinessService scoreBusinessService) { this.scoreBusinessService scoreBusinessService; } Override public ScoreResult getScoreByStudentNo(String studentNo, String semester) { return scoreBusinessService.queryScoreByStudentNo(studentNo, semester); } }4.3 WSDL生成与调用方wsimport测试服务启动后根据实际部署地址打开WSDL地址。如果你在前面的配置里发布到了/services/scoreService那么本地开发环境的WSDL地址就是http://localhost:8080/services/scoreService?wsdl浏览器打开后是一大段XML里面包含wsdl:service、wsdl:portType和xsd:element等结构。这就是WSDL的核心作用它把服务能做什么、入参出参长什么样、用哪个HTTP地址访问全部以机器可读的方式描述出来。在论文里截一张WSDL的关键片段再配一段说明就能很直观地体现“Web Service技术”不是空话。客户端测试有两种方式。一种是用wsimport命令直接生成调用代码wsimport -keep -p com.demo.client http://localhost:8080/services/scoreService?wsdl执行后会在当前目录生成com/demo/client包下的若干类其中有一个ScoreWebService接口和一个ScoreWebServiceImpl服务实现类。接着写个简单测试代码调通public class ScoreClientTest { public static void main(String[] args) { ScoreWebService service new ScoreWebServiceService() .getScoreWebServicePort(); ScoreResult result service.getScoreByStudentNo(20240001, 2024-2025-1); System.out.println(result.getCourseName() : result.getScore()); } }另一种方式是直接在SOAP UI里导入WSDL手动构造SOAP请求报文发送。两种方式二选一即可但建议在答辩演示前用客户端代码方式跑通一次因为现场环境如果没有安装SOAP UI类工具命令行或者IDEA里的测试类更稳。4.4 事务、异常和鉴权在Web Service层的处理这里集中说三个容易让工程“能跑但经不起问”的点。第一是事务。如果ScoreWebServiceImpl直接调用了多个DAO操作务必要让被调用的业务Service方法标注Transactional并确保该Service是Spring容器管理的Bean。CXF发布SOAP端点时配置类注入的scoreWebService也是Spring Bean所以Spring事务拦截器能够生效。这要求你在设计接口时不要通过new关键字创建服务对象否则事务注解完全不生效。第二是异常。不要让SQL异常或者RuntimeException直接穿透到SOAP调用方。CXF收到未处理异常时生成的SOAP Fault内容可能异常粗糙甚至把内部堆栈信息暴露出去。建议在Web Service实现类或业务Service里捕获业务异常转换为自定义的Fault消息或者抛出带有明确错误码的Fault异常。以CXF的org.apache.cxf.interceptor.Fault为例可以用它包装统一的错误信息。第三是鉴权。SOAP服务是对外发布的如果谁都能拿学号查成绩这系统就不用答辩了。最简单的方案是给每个对外方法加一个token参数调用方在登录系统后通过内部接口获取token调SOAP服务时把token传进来服务端在交互层校验token是否有效、是否过期。想做得更正式也可以用CXF的拦截器在请求进入前统一校验SOAP Header里的凭证信息但毕设阶段在接口参数里带token的方式已经足够且讲解起来容易听得懂。5. 登录认证与权限控制这种系统避不开RBAC5.1 Session还是JWT的取舍教务管理系统天然需要角色权限学生能查课选课教师能录成绩管理员能维护基础数据。如果不区分角色前面做的所有业务约束都可以被绕过。至于用Session还是JWT要看你的页面形态方案适合场景实现难度答辩亮点Session 拦截器后端模板渲染前后端不分离低一般JWT 认证拦截器前后端分离REST接口中较高Spring Security追求完整安全框架高较高但要能讲清楚配置逻辑我的建议是优先选Session 拦截器。毕业设计的时间大头应该花在业务逻辑上而不是调安全框架的过滤器链。只要在配置类里注册一个拦截器让它处理登录状态和角色判断就能完成80%的需求。做JWT、Spring Security可以作为中期检查之后的加分扩展但不要一开始就把主架构押在复杂的权限框架上。5.2 拦截器与角色判断的实现思路登录成功后将用户对象放入Sessionkey可以叫LOGIN_USER。拦截器负责两个判断是否登录、当前角色是否允许访问某个路径。路径和角色的规则可以直接硬编码在拦截器里毕设规模完全可控没有必要设计动态权限表。public class LoginInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { Object loginUser request.getSession().getAttribute(LOGIN_USER); if (loginUser null) { response.sendRedirect(request.getContextPath() /login); return false; } // 可在此处提取角色进一步做路径级别的角色校验 return true; } }然后注册拦截器并放行登录页、静态资源、SOAP服务路径Configuration public class WebMvcConfig implements WebMvcConfigurer { Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new LoginInterceptor()) .addPathPatterns(/**) .excludePathPatterns( /login, /doLogin, /css/**, /js/**, /img/**, /services/** ); } }把/services/**排除掉是必要的因为SOAP服务不经过页面登录它的鉴权由第4.4节的token机制处理。角色判断通常在业务Service里做。比如教师录入成绩时Service方法先取出当前登录教师id再校验这个开课记录的teacher_id和当前id是否一致不一致直接抛“无权操作”。不要把这种校验全部堆在Controller里因为一个Controller方法被调用时上下文可能一致但Service作为最后防线把数据库层面的归属权校验放在它里面更安全。5.3 密码安全与越权防护密码存储必须用BCrypt加密。很多教程为了演示方便把密码明文入库答辩时老师问一句“数据库泄露了怎么办”就会很难受。Spring Security里有一个单独的BCryptPasswordEncoder组件不引入完整Spring Security也能单独使用注册成一个Bean后在注册和修改密码的地方调用。校验时用matches(原始密码, 加密密码)。越权防护还要注意URL参数。典型问题出现在学生查询成绩的接口上学生A请求接口时传入学生B的学号如果后端只看参数而不回查当前登录用户的身份就会查出别人的成绩。正确做法是查询操作优先以Session里的学生id为准传入的学号只做页面展示和日志记录。数据范围权限是信息管理系统里比角色权限更容易出问题的地方往往被忽略一旦被发现就是大部室级事故。6. 打包部署与答辩现场能跑通只是第一步6.1 从开发到演示jar包部署与外置Tomcat的差异系统开发完成后建议打可执行jar包部署这也是Spring Boot最推荐的模式。在pom.xml里确保packaging为jar执行mvn clean package然后在target目录拿到xxx.jar命令行运行java -jar xxx.jar这种部署方式对答辩演示特别方便把jar包拷到一台装了JDK8的机器一条命令就能启动。如果答辩现场用的是学校机房电脑可能没有外网下载依赖所以提前在本地把包打全再带上MySQL初始化脚本整个环境迁移能控制在十分钟内。如果老师明确要求必须部署到外置Tomcat那就需要把packaging改为war并将启动类继承SpringBootServletInitializer重写configure方法SpringBootApplication public class CourseApplication extends SpringBootServletInitializer { Override protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) { return builder.sources(CourseApplication.class); } }改了war方式之后使用内置Tomcat启动时访问路径可能会带上context-path注意统一配置否则演示时页面链接会404。6.2 答辩中最容易被追问的四个点根据过往经验这类题目答辩现场被问最多的问题集中在以下几类提前准备好答复思路就好你的系统哪里体现了Web Service技术回答要点系统内部主体功能使用Spring MVC和JSON交互对外提供基于SOAP协议的成绩查询服务通过CXF发布客户端通过WSDL发现并调用服务。尽量切到代码里展示WSDL文件和wsimport生成的客户端代码比口头描述有说服力。SOAP和REST有什么不同回答要点SOAP基于XML标准协议依赖WSDL实现服务描述适合跨语言、跨平台的企业级接口标准化REST利用HTTP现有语义通常返回JSON轻量高效。强调你既使用REST处理内部页面请求又用SOAP处理对外服务两者是互补关系。选课时并发怎么防超选回答要点用条件UPDATE实现原子操作数据库行锁加唯一索引防止同一门课并发下超选展示相关SQL和影响行数判断逻辑。如果学生退课了名额如何回到可选项里回答要点退课和释放名额在同一个事务里完成修改选课记录状态后对开课记录的已选人数减一再开放该课的选课入口。不用背答案只要这几个问题能结合自己的代码讲清楚老师基本就认可这是自己做的系统。6.3 论文里该把Web Service技术写进哪一章很多同学代码写得很顺但论文里“技术介绍”部分写得很泛。针对有“web service技术”字样的题目我建议论文按这个思路编排技术章节第三章“系统关键技术”拆成三节Spring Boot框架、Web Service技术SOAP协议、WSDL、JAX-WS规范、CXF框架、MyBatis与MySQL。注意将理论概念和自己项目的技术选型结合起来写不要大段粘贴教材。第五章“系统详细设计与实现”里单独加一个小节叫“基于Web Service的对外接口设计与实现”里面贴出核心服务接口代码、CXF配置、WSDL局部片段以及客户端调用测试截图。数据库设计部分重点描述选课表唯一索引和开课表容量字段方便答辩时直接对应到并发方案。论文里技术图不需要画得太庞大但要在系统架构图上把“浏览器→Spring MVC”和“外部系统→CXF Web Service→业务Service”两条链路区分开这样阅卷老师一眼就能看出架构层次。最后分享一个细节我在做类似项目时会把WSDL文件保存一份到resources目录下手动备份因为不同机器上CXF生成的WSDL动态生成过程偶尔会有出入万一现场网络有问题或服务没起来至少能在论文和PPT里展示同一个可靠版本。这个习惯不算什么技巧但它能在答辩这样高压的场合多给你留一条退路。整个项目做下来最有价值的部分其实不是某个炫酷的技术而是把“教务管理”这种常见业务从需求到设计再到代码完整地走了一遍这个过程比多少篇现成代码都值得写进自己的履历。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑