☰
Spring Boot幼儿园管理系统实战:从需求设计到部署上线全解析
2026/10/9 4:03:21 网站建设 项目流程

做“Spring Boot幼儿园管理系统”这个题目,很多人的第一反应是“学生管理系统换个皮,把学生表改成儿童表,把成绩单改成食谱表就行了”。但真正把这个项目做完,我才发现幼儿园场景比想象中复杂不少:晨检、体温、接送、请假审批、每日考勤、班级通知、家长绑定、缴费记录,这些业务不是一张表能塞下的,而是围绕一个孩子从入园到离园的全生命周期在流转。这篇总结我根据自己的实际开发经验,把整个系统的需求拆解、数据库设计、后端实现、前端联调、部署上线的完整链路梳理一遍,同时把Spring Boot版本选择、项目结构、数据访问、自动配置这些高频踩坑点一并讲清楚。如果你正在做课程设计、毕业设计,或者想拿一个完整的Spring Boot项目练手,这篇内容可以直接参考复现。

1. 项目整体需求梳理与设计思路

1.1 幼儿园业务的核心闭环是什么

开始写代码之前,我先花了两天时间调研幼儿园的日常运营流程,最后发现系统的核心不是“管理某个实体”,而是“跟踪一个孩子的入园状态”。一个孩子从家长提交入园申请、园方审核建档、分配到班级、绑定家长账号,到每天入园时晨检、考勤、请假、离园接送,再到老师记录成长档案、发布班级通知,这是一条完整的业务链。

如果直接把需求简化成“班级管理 + 幼儿管理 + 家长管理”,后期一定会返工。比如家长要看自己孩子的出勤记录,那就需要有“家长-孩子”的关系表;老师要记录孩子的体温,那就不能只在一个“体检表”里存一个字段,而要落到“保健记录表”里,记录检查日期、体温、精神状态、处理结果。再比如请假审批,需要区分“家长替孩子请假”和“老师给孩子补录缺勤”,这两种操作最终影响的是考勤统计表。

所以我在设计阶段先画了业务状态图,这里不用工具画复杂度,就直接列清楚流转关系:入园建档和审核、分班和绑定、每日考勤和晨检、请假和消假、通知和成长记录。后面的数据库表和接口都是围绕这个闭环来做的。我建议所有做同类项目的同学,动手前先把这个业务闭环整理成文字,哪怕只是几十行的需求说明,也比直接建表强得多。

1.2 技术选型:为什么是Spring Boot而不是SSM或Spring Cloud

这个项目用Spring Boot几乎是必然选择。SSM时代需要手动整合Spring、Spring MVC、MyBatis,配置文件又多又碎,光是一个事务管理器就能折腾半天。Spring Boot通过起步依赖和自动配置把这些都封装好了,引入一个spring-boot-starter-web就能把Web容器、MVC、JSON序列化全部准备好,开发效率和可读性对于课程设计级别完全够用。

Spring Cloud对幼儿园管理系统来说明显过重。单体项目用不着服务注册发现、网关、配置中心这一套,引入之后不仅启动链路变长,部署也复杂。除非要做成微服务架构的演示项目,否则真的没必要。

还有一个很现实的问题是Spring Boot版本。我看到不少热门词里都在问“springboot版本太高”,确实,Spring Boot 3.x发布之后,很多老教程直接失效了。之前用的是javax.servlet包,3.x之后变成了jakarta.servlet,有些第三方库的兼容版本也跟得很慢。如果是第一次做这个项目,或者参考资料大量使用旧教程,我建议直接从Spring Boot 2.7.x开始,这是2.x的最终维护版本,稳定性和生态兼容性都很好。等把项目逻辑跑通,再尝试升级3.x也不迟。

2. 系统架构与数据库设计细节

2.1 项目分层结构与目录组织

Spring Boot项目看起来没有强制分层,但工程上还是要遵循“单一职责、接口分离”的原则。我最终采用的是常规的controller-service-mapper-entity四层结构,再配上config、common、security、dto这些辅助包。

src/main/java/com/example/kindergarten ├── controller │ ├── admin │ ├── teacher │ └── parent ├── service │ ├── impl │ └── 各业务接口 ├── mapper ├── entity ├── dto ├── config ├── common │ ├── Result.java │ └── GlobalExceptionHandler.java ├── security │ └── JwtAuthFilter.java └── util

controller按角色分包是很有用的习惯。管理员端接口、教师端接口、家长端接口天然权限不同,分包之后在Security配置里可以直接按路径前缀放行或拦截,比如/api/admin/**需要ROLE_ADMIN,/api/teacher/**需要ROLE_TEACHER,/api/parent/**需要ROLE_PARENT,比所有接口堆在一个controller里清晰很多。

dto包用来放请求和响应对象,不直接暴露数据库实体。刚开始图省事直接用entity接收前端参数,结果有一次字段名和前端不一致,排查老半天。把参数校验、字段映射放到dto以后,问题明显少很多,这也是项目后期最值得保持的规范。

2.2 核心数据表设计与关系拆解

幼儿园系统的表没有特别复杂的关联,但表之间的引用关系必须清晰。我的核心表是这样设计的:

  • account:登录账号表,包含用户名、密码、角色、状态。角色用字符串存储,取值是ADMIN、TEACHER、PARENT。
  • class_info:班级表,包含班级名称、年级、容量、当前人数。
  • teacher:教师表,关联到账号ID和班级ID。
  • child:幼儿表,包含姓名、性别、出生日期、入园日期、班级ID、状态。
  • parent_child:家长和孩子的关系表,一个孩子可以绑定多个家长,一个家长也可以绑定多个孩子。
  • attendance_record:考勤表,包含儿童ID、班级ID、日期、入园时间、离园时间、状态。
  • health_record:晨检和保健记录表,包含儿童ID、检查日期、体温、精神状态、备注。
  • leave_request:请假表,包含儿童ID、开始时间、结束时间、请假原因、审批状态。
  • notice:通知表,包含标题、内容、发布范围、发布时间。
  • growth_record:成长档案表,包含标题、内容、图片地址、记录人、儿童ID。

以考勤表为例,为什么没有把“入园”和“离园”分到两张表?因为考勤记录关注的是“某一天某个孩子是否到场”,早晚打卡本质上是同一条记录的两个时间字段。前端展示月度考勤统计时,一次查询就能拿到整个列表,不需要再做关联匹配。

建表时我统一使用了create_time和update_time字段,大部分表还加了deleted逻辑删除标记。原因是删除幼儿档案时,如果物理删除,考勤记录、成长记录全部会变成孤儿数据;改成逻辑删除,所有历史记录还可以正常查询,这对幼儿园这个业务场景很重要,毕竟考勤数据是要留给家长看的。

2.3 权限模型:角色与数据范围的双重控制

做过管理系统的人都知道,光有“能登进去”的权限还不够,还得有数据权限。幼儿园里很典型:一个老师登录后,不该看到全园所有孩子的数据;一个家长登录后,更不能看到别人家的孩子。所以我不仅做了角色控制,还做了数据范围控制。

具体实现上,登录后把当前用户信息放到SecurityContextHolder里,查询接口获取当前用户的角色和ID。管理员直接放行,教师根据账号关联的班级ID过滤,家长根据parent_child关系表查出绑定的儿童ID集合。前端传“孩子ID”来查成绩单,后端不会无条件信任,而是先判断这个孩子是否属于当前用户的数据范围,不符合就抛出“无权限访问”异常。

这里有一个新手很容易踩的坑:只在前端隐藏按钮,后端不做校验。前端的隐藏只是体验优化,如果直接访问接口URL,还是没有保护。我在系统里用一个@RequireRole注解配合AOP切面做统一校验,比每个controller里反复写if判断要优雅,也能在答辩时讲出点东西来。

3. 后端核心功能实现与踩坑记录

3.1 基础工程搭建与依赖配置

搭建项目时我选择了Maven,虽然网上也有Gradle教程,但国内大多数参考资料和IDE默认支持还是Maven更省心。基础pom.xml核心依赖是这样的:

<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.7.18</version> <relativePath/> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.2</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.9.1</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> </dependencies>

这个组合的好处是版本兼容已经由Spring Boot统一管理,mybatis-plus-boot-starter在Spring Boot 2.7下不用额外调整。如果用Spring Boot 3.x,需要换用mybatis-plus-spring-boot3-starter,而且MyBatis-Plus版本也要升到3.5.3以上,这就是“版本太高”最常见的翻车点。

application.yml里我主要配了数据源、MyBatis-Plus、日志和文件上传大小:

spring: datasource: url: jdbc:mysql://localhost:3306/kindergarten?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver servlet: multipart: max-file-size: 10MB max-request-size: 10MB mybatis-plus: mapper-locations: classpath:mapper/*.xml configuration: map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.stdout.StdOutImpl server: port: 8080

数据库连接串里一定要加serverTimezone=Asia/Shanghai,否则MySQL 8的时区问题会导致日期字段查询差8小时,我在项目早期被这个问题浪费了不少时间。

3.2 统一返回结构、全局异常与参数校验

接口返回结构如果不统一,前端联调时就得一个接口一个接口地适配。我先定义了一个Result<T>:

@Data public class Result<T> { private Integer code; private String message; private T data; public static <T> Result<T> success(T data) { Result<T> result = new Result<>(); result.setCode(200); result.setMessage("操作成功"); result.setData(data); return result; } public static <T> Result<T> error(int code, String message) { Result<T> result = new Result<>(); result.setCode(code); result.setMessage(message); return result; } }

配合@RestControllerAdvice做全局异常处理,业务异常、参数校验异常、权限异常都集中在同一个类里返回统一格式。这样做的好处非常明显:前端不用分情况判断返回结构,后端也不会动不动就把500堆栈抛出去。

参数校验我用了spring-boot-starter-validation里的注解,比如@NotBlank、@Email、@Past,在controller的入参上用@Valid开启校验。这样可以在进入service之前就拦截大部分不合法数据,减少service层的防御性代码。

实际开发中遇到过一个问题:使用@Valid校验失败时,默认异常信息是英文,而且格式不是前端想要的。我在全局异常处理器里单独捕获了MethodArgumentNotValidException,把FieldError.getDefaultMessage()循环取出,拼成可读的中文提示,前端直接弹窗展示。

3.3 登录认证与JWT方案落地

安全管理是整个系统的重中之重。我选择Spring Security配合JWT实现无状态认证,这样后端不需要依赖Session,接口可以被小程序、App、Web同时调用。

登录接口在SecurityConfig里配置为permitAll,其余接口全部拦截。登录成功后生成JWT,其中包含用户ID和角色,然后放在响应头Authorization里返回前端。前端之后每次请求都在请求头里带上这个Token。

JwtAuthFilter的核心逻辑是:

public class JwtAuthFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String token = request.getHeader("Authorization"); if (StringUtils.hasText(token) && token.startsWith("Bearer ")) { token = token.substring(7); String username = JwtUtil.parseToken(token); if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) { UserDetails userDetails = userDetailsService.loadUserByUsername(username); UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( userDetails, null, userDetails.getAuthorities()); authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); SecurityContextHolder.getContext().setAuthentication(authentication); } } filterChain.doFilter(request, response); } }

在配置类里注入这个Filter:

http.csrf().disable() .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .authorizeRequests() .antMatchers("/api/auth/login", "/api/auth/register").permitAll() .antMatchers("/api/admin/**").hasRole("ADMIN") .antMatchers("/api/teacher/**").hasRole("TEACHER") .antMatchers("/api/parent/**").hasRole("PARENT") .anyRequest().authenticated();

这里要注意加密方式。数据库中密码不能存明文,使用BCryptPasswordEncoder加密。这个加密算法每次生成的密文都不一样,但是校验结果是一致的,所以不需要担心“为什么两次加密结果不同”。

如果后续要扩展成多个Spring Boot项目间共享登录态,思路是把JWT密钥统一、用户信息存放到Redis中,所有项目共同校验同一份Token和用户会话。但这是微服务架构的范畴,单体项目不要提前做,免得复杂度失控。

3.4 考勤、晨检和成长档案的实现细节

考勤模块是我认为整个系统里最值得写的一个模块。老师每天早上选择一个班级,系统会列出当天未出勤和已出勤的儿童列表。批量提交出勤记录时,我用的是批量插入:

public void batchInsertAttendance(List<AttendanceRecord> records) { attendanceMapper.batchInsert(records); }

对应的Mapper XML使用foreach实现批量插入:

<insert id="batchInsert" parameterType="list"> insert into attendance_record(child_id, class_id, record_date, status) values <foreach collection="list" item="item" separator=","> (#{item.childId}, #{item.classId}, #{item.recordDate}, #{item.status}) </foreach> </insert>

注意批量插入的SQL长度限制。如果班级人数很多,一次插入几百条没问题,但超过1000条时部分MySQL配置会报max_allowed_packet错误,所以实际项目中我会按100条一批分批执行。

晨检记录和考勤可以放在一起处理:入园时老师同时记录体温和状态,出勤状态自动变为“在园”,如果体温超过37.3℃则标记为“需观察”,并自动给家长发送一条站内通知。通知这块我用了Spring Boot自带的@Async注解开异步线程去处理,不阻塞考勤接口返回。

成长档案则是简单的文本加图片上传。图片上传用MultipartFile接收,存储到服务器本地目录,然后返回可访问的URL。这里有个常见细节:文件上传目录不要放在项目根目录下,更不要放在src/main/resources下,否则打包成jar后没有可写目录。我习惯配置一个外部路径,比如/data/kindergarten/upload/,并在WebMvcConfig里把这个路径映射成静态资源访问:

@Configuration public class WebMvcConfig implements WebMvcConfigurer { @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/upload/**") .addResourceLocations("file:/data/kindergarten/upload/"); } }

3.5 自定义自动配置的进阶玩法

很多人在简历里写“熟悉Spring Boot自动配置”,但一到项目里就只会用现成的Starter。实际上在这个项目里可以做一个小亮点:自己封装一个校园消息推送的自动配置模块。

思路是这样:把“给家长发送站内通知”这个能力独立成一个notice-spring-boot-starter,里面包含配置属性类、核心服务类和一个自动配置类。

配置属性类:

@ConfigurationProperties(prefix = "kindergarten.notice") @Data public class NoticeProperties { private boolean enabled = true; private String defaultSender = "系统通知"; }

自动配置类:

@Configuration @EnableConfigurationProperties(NoticeProperties.class) public class NoticeAutoConfiguration { @Bean @ConditionalOnMissingBean public NoticeService noticeService(NoticeProperties properties) { return new NoticeService(properties); } }

在这个项目里,我把它作为一个@Configuration类直接放进主项目的config包中测试,搞清楚了原理后又抽取成独立模块。需要注意的是Spring Boot 2.7之前自动配置注册文件是META-INF/spring.factories,Spring Boot 3.0之后改成了META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports。这个差异就是网上很多人“照着教程写却不生效”的原因。

4. 前端页面与接口联调过程

4.1 模板渲染还是前后端分离:Thymeleaf与Vue3的取舍

前端方案取决于你对项目的定位。如果是典型的毕业设计,老师通常更看重后端逻辑和技术栈完整度,使用Thymeleaf配合Bootstrap搭建后台页面,服务端渲染,把Java业务逻辑和页面绑定在一起,整体实现快、不容易出跨域问题,而且代码量相对少。

如果想让项目看起来更有工程化感觉,可以选择Vue3 + Element Plus + Spring Boot的前后端分离架构。前端单独用Vite构建,后端只提供JSON接口。这样简历上可以写“基于Vue3和Spring Boot的前后端分离开发”,也是一个常见的加分方向。代价是要多配置跨域、Token拦截器、路由守卫这些内容,对初学者来说坑会多一些。

我做这个项目时最终选了Thymeleaf方案,因为要优先保证答辩时能快速演示和讲解业务逻辑。页面用Bootstrap搭建,后台布局是经典的顶部导航加左侧菜单,右侧内容区使用th:replace引入公共片段,复用性还不错。

4.2 关键页面与接口联调细节

管理后台的首页放统计看板,展示幼儿总数、今日出勤、未出勤人数、待审批请假。统计接口用聚合查询实现:

@GetMapping("/api/admin/dashboard") public Result<DashboardVO> dashboard() { DashboardVO vo = new DashboardVO(); vo.setChildCount(childService.count()); vo.setTodayAttendance(attendanceService.countToday()); vo.setPendingLeave(leaveService.countPending()); return Result.success(vo); }

接口联调时最烦的是前后端字段命名不一致。数据库字段是child_name,Java实体是childName,这没问题,因为MyBatis-Plus开了map-underscore-to-camel-case。但前端传参如果用的是childName,后端DTO里的字段又是childName,一旦前端传成childname就会收到null。我的经验是:所有接口参数统一用DTO接收,并且尽量保持命名一致,前端代码里也约定好childName的写法,不要一会儿驼峰一会儿下划线。

还有一个反复出现的问题是日期格式。Java后端返回LocalDateTime默认格式是2024-01-15T10:30:00,前端展示时不够友好。我直接在application.yml里统一配置了格式:

spring: jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT+8

这样接口返回的日期就是2024-01-15 10:30:00,前端直接展示即可。如果是前后端分离项目,前端也可以自己格式化,但后端统一配置更省心。

4.3 文件上传与富文本内容的踩坑

通知公告模块如果要做成富文本,可以考虑引入一个简单的Markdown编辑器,或者用现成的富文本组件。如果是原生textarea,就只能存纯文本,展示时样式比较单一。

上传图片的接口我单独实现了一个/api/upload/image,接收MultipartFile文件,返回图片URL。上传时要限制文件类型和后缀,不能只依赖前端判断,因为接口可以被直接调用。我后端会检查文件扩展名和Content-Type,如果不符合白名单直接返回错误。

5. 部署上线与常见问题排查

5.1 使用宝塔面板和Docker部署Spring Boot项目

项目做完后,我把它部署到了自己的一台云服务器上,环境用的是宝塔面板。部署方式有两种,一种是直接在宝塔的Java项目管理器里配置jar包运行,另一种是使用Docker。

我这次用的是Docker。先打一个Spring Boot的jar包,然后写一个Dockerfile:

FROM openjdk:8-jdk-alpine WORKDIR /app COPY target/kindergarten.jar app.jar EXPOSE 8080 ENTRYPOINT ["java", "-jar", "app.jar"]

随后用docker build -t kindergarten:v1 .构建镜像,再用docker run -d --name kindergarten -p 8080:8080 kindergarten:v1启动容器。

在这里要特别注意数据库的连接。容器内访问宿主机MySQL时,localhost是容器自身,不是宿主机。正确做法是在application.yml中使用宿主机内网IP或容器网络别名。我用的是docker-compose统一管理MySQL和Spring Boot服务,服务名可以直接作为主机名互相访问:

version: '3' services: mysql: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: 123456 MYSQL_DATABASE: kindergarten ports: - "3306:3306" app: build: . depends_on: - mysql environment: SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/kindergarten?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai ports: - "8080:8080"

Nginx反向代理也建议配一下,把80端口指向8080,同时处理静态资源缓存和HTTPS证书。使用宝塔面板可以直接在网站设置里添加反向代理,目标URL填http://127.0.0.1:8080,保存就能生效。

5.2 高频问题排查速查表

我整理了实际开发中遇到的高频问题,做成排查表,遇到对应场景可以直接对号入座。

现象可能原因解决办法
启动失败,提示端口被占用8080端口被其他进程占用使用`netstat -ano
数据库连接失败,Access denied用户名密码错误或账号无权限确认MySQL账号权限,使用GRANT ALL ON kindergarten.* TO 'root'@'%'授权
日期差8小时MySQL连接串未配置时区在url中加serverTimezone=Asia/Shanghai
Mapper方法报“Invalid bound statement”Mapper接口找不到XML检查mapper-locations路径是否和实际XML位置一致
接口返回401,但请求头带了TokenJWT过滤器未放行该路径或Token过期检查SecurityConfig放行规则,查看Token有效期
Spring Boot 3.x下javax.*包不存在版本迁移问题将javax.servlet改为jakarta.servlet,相关starter升级
上传文件报超过大小限制默认限制1MB配置spring.servlet.multipart.max-file-size
前后端联调跨域报错未配置CORS在后端添加跨域配置,或通过Nginx代理转发
定时任务不生效未启用@EnableScheduling在启动类或配置类上添加该注解
列表查询速度慢没有索引对child_id、record_date、class_id等常用查询字段加索引

5.3 MyBatis-Plus分页与条件查询的细节

做列表页的时候,分页是绕不开的。MyBatis-Plus内置了分页插件,但必须先注册一个MybatisPlusInterceptor:

@Configuration public class MybatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } }

忘记注册分页插件是新手常见问题,结果就是分页参数不生效或查询全部数据。我之前有一次就是忘记加这个配置,列表页越翻越慢,排查了半天才发现并不是SQL问题。

条件查询我习惯使用LambdaQueryWrapper,避免硬编码数据库字段名:

LambdaQueryWrapper<Child> wrapper = new LambdaQueryWrapper<>(); wrapper.eq(Child::getClassId, classId) .like(StringUtils.hasText(keyword), Child::getName, keyword) .orderByDesc(Child::getCreateTime);

拼上MyBatis-Plus的分页插件,一个带搜索功能的列表接口就很轻松了。

5.4 事务与多表操作的正确姿势

班级调班、请假审批这类操作会同时更新多张表,必须加事务。比如请假审批通过后,不仅要更新请假状态,还要在考勤表里把当天的状态改成“请假中”。如果只更新请假表,考勤统计就会出现空缺。

我是这样实现的:

@Transactional(rollbackFor = Exception.class) public void approveLeave(Long leaveId) { LeaveRequest leave = leaveMapper.selectById(leaveId); leave.setStatus("APPROVED"); leaveMapper.updateById(leave); attendanceService.updateStatusByChildAndDate( leave.getChildId(), leave.getStartDate(), leave.getEndDate(), "LEAVE"); }

事务必须加在public方法上,而且要通过Spring代理调用才生效。如果是在同一个类内部调用,比如this.approveLeave(),事务不会生效,这是一个很隐蔽的坑。建议事务方法单独放到service中,让controller调用。

6. 踩过几次坑之后的经验总结

整个项目做下来,我个人体会最深的一点是:幼儿园管理系统的难点不在框架使用,而在业务状态的流转与权限边界。考勤记录的状态、请假审批的前后衔接、家长与孩子的绑定关系,这些才是系统真正容易出错的地方。框架只是工具,需求分析和数据模型才是地基。

我也越来越觉得技术选型是第一道分水岭。Spring Boot版本、JDK版本、MyBatis-Plus版本、Security的配置方式,任何一个环节出现版本不匹配,都可能让一堆代码报错。建议初学者直接照着一个稳定版本组合走,先把项目跑通,再研究升级。

最后分享一个小技巧:把公共查询条件、当前用户信息、分页返回结构提取到一个公共层,能省掉大量重复代码。比如在BaseService里封装一个getCurrentUser()方法,所有service只需要调用它就能拿到当前登录账号的角色和ID,不需要每个方法都从SecurityContextHolder手动取值。

答辩的时候如果被问到项目亮点,可以直接从自动配置、数据权限控制、JWT无状态认证、数据库逻辑删除设计这几个点展开,这些都比“我用了Spring Boot”要扎实得多。希望这个项目的完整拆解能给你一些参考,也祝你的系统早日跑通上线。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询