又到了毕业设计扎堆的季节,每年这个时候总有学弟学妹来问“Java Web做什么题目好”。如果你正好在找SpringBoot相关的实战项目,或者打算做一个校园二手交易类的毕设,这篇内容就是冲着你来的。题目是“基于SpringBoot的校园闲置教材循环共享平台”,说白了就是一个校园二手书籍交易App,核心逻辑是让高校学生能把用过的教材挂上去卖,也能低价买到别人闲置的教材,再往深一点做,还能带上学长学姐的学习笔记和书评,形成一个轻量级的社群化阅读圈子。这个项目非常典型,技术栈主流、业务场景清晰、扩展空间大,不管是拿来当毕业设计还是写进简历,都是性价比很高的选择。
这篇内容我会从项目整体思路、数据库设计、后端核心模块、前端App实现到常见问题排查,完整拆解一套可落地方案。所有内容都基于实际开发经验,配置和代码片段也都是可以直接用的,不同基础的人都能跟着进度走下来。
1. 项目整体设计与思路拆解
1.1 核心需求解析
很多第一次做完整项目的人容易一上来就写代码,结果写到一半发现表结构不对、业务逻辑混乱、页面需求变来变去。这个项目的第一个关键步骤,就是把需求拆干净。
校园闲置教材循环共享平台,从用户视角来看其实就是三件事:发布闲置教材、浏览搜索教材、完成交易闭环。但作为毕业设计,只做这三件事是不够的,题目里明确提到了“社群化阅读系统”,这意味着你还要加上书籍评价、学习笔记、收藏关注之类的功能,让平台不只是交易工具,还能沉淀内容。
把需求整理成模块,大致是这样:
- 用户模块:注册、登录、个人信息维护、学历/专业信息绑定
- 图书模块:发布教材信息、编辑/下架、图书分类、图书详情展示
- 搜索模块:关键词搜索、分类筛选、价格区间筛选、按新旧程度排序
- 交易模块:加入购物车、生成订单、订单状态管理、交易记录
- 评价与社群模块:书籍评价、阅读笔记发布、点赞评论、收藏关注
- 管理后台:用户管理、图书审核、订单管理、数据统计
1.2 技术选型与架构考量
这个项目最适合的技术组合是 SpringBoot + MyBatis-Plus + MySQL + Redis + Vue + UniApp。简单解释一下为什么选这套。
首先,SpringBoot是目前Java Web领域绝对的主流,无论你以后找工作还是继续做项目,这套框架都是绕不开的,而且它在简化配置、内嵌容器、生态整合方面确实做得非常友好。特别是SpringBoot 2.7版本,搭配JDK 8,是现阶段最稳妥的组合。为什么不说SpringBoot 3.x?因为3.x要求JDK 17起步,很多学校的教学环境和老项目依赖还停留在JDK 8,选3.x容易给自己添麻烦。我见过不少学生因为用了SpringBoot 3.0然后发现某些依赖不兼容,回头折腾半天,非常打击信心。
持久层用MyBatis-Plus,这个工具的好处是单表CRUD基本不用写SQL,内置的Wrapper条件构造器让多条件查询变得极其简洁。如果你是手写JDBC或者MyBatis注解,开发效率会低不少。
数据库选MySQL,这是Java后端最经典的搭配。Redis用来做验证码缓存、Token存储和热门图书排行榜,属于加分项,但适合写进简历和论文里。
前端这边,既然题目里写了“APP”,你要么用Android原生,要么用跨端方案。我的建议是用UniApp,原因很简单:一套代码可以同时打包成App、小程序和H5,开发效率高,而且Vue语法和你的后端接口对接非常自然。如果你想稳一点,用Vue写一个Web商城也是可以的,但那样“APP”这个属性就弱了,答辩时容易被追问。
整体架构就是经典的前后端分离:UniApp/Vue发请求,经过nginx(本地开发直接访问后端端口)到SpringBoot网关层,进入Controller层、Service层、Mapper层,最后落到MySQL。Redis穿插在认证、缓存、排行榜场景中。要画架构图的话,这个分层模型够用了,而且每一层都有实际代码支撑,不会被问倒。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 数据库设计与核心表结构
2.1 核心表设计
项目做得好不好,数据库设计占了很大比重。我见过太多表结构混乱导致代码越写越痛苦的案例。这个项目最核心的表是用户表(user)、图书表(book)、订单表(orders),再加上 评价表(book_comment) 和收藏表(favorite) 用来支撑社群化内容。
用户表重点字段如下:
- id 主键,自增
- openid 微信登录标识(如果你做了微信登录,这个字段必须有)
- username 用户名
- password 密码(BCrypt加密存储)
- student_no 学号
- college 学院
- major 专业
- avatar 头像URL
- role 角色(0普通用户,1管理员)
- status 状态(0正常,1禁用)
- create_time / update_time
图书表是业务核心,重点字段如下:
- id 主键
- user_id 发布者ID
- title 书名
- author 原作者
- publisher 出版社
- isbn ISBN号
- category 分类(公共课/专业课/选修课等)
- original_price 原价
- selling_price 售价
- degree 新旧程度(1-10分或成色描述)
- cover 封面图URL
- description 描述和笔记说明
- status 状态(0在售,1已下单,2已售出,3下架)
- view_count 浏览数
- create_time
订单表字段:
- id 主键
- order_no 订单号(建议用时间戳+随机数生成)
- book_id 图书ID
- seller_id 卖家ID
- buyer_id 买家ID
- amount 成交金额
- status 状态(0待付款,1待发货,2已发货,3已完成,4已取消)
- create_time / pay_time / finish_time
2.2 关键表关系与冗余策略
表关系上,一个用户可以有多个图书,一个图书只能属于一个用户;一个用户可以下多个订单,一个订单对应一个图书(这个项目建议一单只包含一本书,因为二手教材交易通常是一对一的,避免购物车和订单拆分的复杂度。如果执意要做购物车,那要加一个订单明细表,复杂度会翻倍)。
关于点赞和评价,这里的表设计要注意一个问题:点赞是高频操作,如果每次点赞都去查一次评论表再插入记录,对数据库压力有点大。所以我建议加一个冗余字段like_count在评论表里,点赞时直接update book_comment set like_count = like_count + 1 where id = ?,同时插入一条点赞记录。这样读起来快,写起来也不复杂。也就是拿一点点的数据冗余换取读写性能。
收藏表favorite比较简单,就是id、user_id、book_id、create_time,加上唯一索引防止重复收藏。
数据库设计的几个注意事项:
- 所有表都要有
create_time,这是硬习惯,方便以后排查数据和做统计 - 金额字段用
decimal(10,2),不要用float/double,否则容易出精度问题 - 手机号、学号等字段不要用
int,要用varchar,以免将来有前缀0或者超过int范围 - 每张表都要加逻辑删除标记
deleted(MyBatis-Plus默认支持@TableLogic),这样删除操作可以恢复,管理后台也好做回收站功能 - 常用查询字段要加索引,比如
book.status、book.category、orders.buyer_id,否则数据量上来后接口会明显变慢
我现在的习惯是先设计完表再写代码,表设计如果变了,改起来成本极高。对于这个项目,核心表就这几张,加一个admin表就差不多了,不要画蛇添足搞一堆没用的表。
3. 后端核心模块实现与难点突破
3.1 SpringBoot基础工程搭建与配置
创建一个SpringBoot项目很简单,IDEA选Spring Initializr,或者直接去Spring官网生成。关键在依赖选择上。
对于这个项目,pom.xml里需要包含这些依赖:
- spring-boot-starter-web(Web基础)
- mybatis-plus-boot-starter(持久层增强)
- mysql-connector-java(MySQL驱动)
- lombok(减少实体类样板代码)
- spring-boot-starter-data-redis(缓存和Token)
- jjwt(JWT生成和校验)
- spring-boot-starter-validation(参数校验)
- hutool(工具类,生成验证码、时间格式化等)
配置文件application.yml里的几个关键项:
yaml复制server:
port: 8080
spring:
datasource:
url: jdbc:mysql://localhost:3306/campus_book?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: root
redis:
host: localhost
port: 6379
database: 0
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
map-underscore-to-camel-case: true
global-config:
db-config:
logic-delete-field: deleted
logic-delete-value: 1
logic-not-delete-value: 0
这里有几个容易踩的坑。第一个是serverTimezone必须设置,否则MySQL连接会报时区错误。第二个是useSSL=false,本地开发不需要SSL证书,省去麻烦。第三个是MyBatis-Plus的map-underscore-to-camel-case,开启后数据库字段的create_time才能自动映射到实体的createTime。
3.2 用户认证与权限控制
用户认证这块,毕设项目首选JWT(JSON Web Token)。为什么要用JWT而不是Session?因为前后端分离架构下,App端和Web端都通过接口访问后端,Session模式需要维护会话状态,跨域处理也麻烦。JWT是无状态的,用户登录成功后后端签发一个Token,前端每次请求把Token放在请求头里,后端拦截器校验通过就放行。
登录流程是这样的:用户输入账号密码(或手机号验证码)→ 后端校验通过 → 生成一个Token,把用户ID和角色等信息放进去 → 返回给前端 → 前端存储并随请求携带。Token过期时间可以设置成7天,用户再次访问时如果过期则跳转登录页。
具体实现上,我会有一个JwtUtil负责生成和解析Token:
java复制public class JwtUtil {
private static final String SECRET = "your-secret-key";
private static final long EXPIRE_TIME = 7 * 24 * 60 * 60 * 1000;
public static String generateToken(Long userId, String role) {
return Jwts.builder()
.setSubject(String.valueOf(userId))
.claim("role", role)
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + EXPIRE_TIME))
.signWith(SignatureAlgorithm.HS256, SECRET)
.compact();
}
public static Claims parseToken(String token) {
return Jwts.parser()
.setSigningKey(SECRET)
.parseClaimsJws(token)
.getBody();
}
}
然后是拦截器或者过滤器校验Token。我习惯用HandlerInterceptor,在preHandle方法里取请求头的Authorization字段,去掉Bearer 前缀,解析Token。解析失败直接返回401,成功就把用户ID放入request.setAttribute("userId", ...),后续业务方法从请求里取。
对于管理员接口,可以加一个@RequireRole("admin")这样的自定义注解,配合拦截器做角色校验。这样用户和管理员接口就分离清楚了,答辩的时候这也是一大亮点。
需要注意的细节:密码存储一定要用BCrypt加密,不要用MD5。MD5已经非常好破解了,随便一个网站就能查。Spring Security的BCryptPasswordEncoder单独拿来用就行,不需要整上Spring Security那一套复杂配置,毕业设计没必要给自己找那么多麻烦。
3.3 图书发布、检索与订单闭环
图书发布接口的核心逻辑是:接收前端传的图书信息,把封面图Base64或文件流交给OSS/本地存储处理成URL,然后插入book表,状态置为在售。
这里要说一下图片上传的问题。很多第一次做的人会直接把图片Base64传到数据库里,这是大忌,数据库会迅速膨胀,接口也会变慢。正确做法是:前端上传图片到后端,后端把图片保存到本地某个目录(比如/upload/),访问时通过静态资源映射来访问。SpringBoot里加一个配置类:
java复制@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/upload/**")
.addResourceHandler("file:" + System.getProperty("user.dir") + "/upload/");
}
}
如果你有云服务器,还可以接阿里云OSS或者七牛云,图片访问速度更快,也更专业。但对于毕设来说,本地存储完全够用,答辩时说明一下生产环境可以迁移到OSS就行。
图书搜索是另一个重点。我的方案是在Service层用MyBatis-Plus的LambdaQueryWrapper动态拼接条件:
java复制public Page<Book> searchBooks(String keyword, String category, BigDecimal minPrice,
BigDecimal maxPrice, Integer degree, int page, int size) {
LambdaQueryWrapper<Book> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Book::getStatus, 0) // 只查在售
.like(StringUtils.isNotBlank(keyword), Book::getTitle, keyword)
.or().like(StringUtils.isNotBlank(keyword), Book::getAuthor, keyword)
.eq(StringUtils.isNotBlank(category), Book::getCategory, category)
.ge(minPrice != null, Book::getSellingPrice, minPrice)
.le(maxPrice != null, Book::getSellingPrice, maxPrice)
.le(degree != null, Book::getDegree, degree)
.orderByDesc(Book::getCreateTime);
return bookMapper.selectPage(new Page<>(page, size), wrapper);
}
注意这里有个坑:like和or混用的时候,如果不加括号,条件会乱掉。MyBatis-Plus的Wrapper支持and(w -> w.like().or().like())这种嵌套,我建议关键词模糊匹配用一下嵌套,不要直接在wrapper上并列like和or。
订单流程是交易模块的核心。整个流程大家参考电商的订单状态机:
- 买家下单:状态设为“待付款”
- 买家支付(这里做模拟支付即可):状态变为“待发货”
- 卖家发货(线下当面交易的话可以改成“待确认”):状态变为“已发货”
- 买家确认收货:状态变为“已完成”,同时把书的
status置为“已售出” - 如果任何一方取消:状态变为“已取消”,书恢复在售状态
这里边有一个高并发的并发安全问题:两个人同时下单同一本书怎么办?最简单的方案是在下单前通过select ... for update锁住图书记录,SpringBoot里可以用@Transactional配合MyBatis-Plus的selectById加行锁。不过更简单的做法是给book表加一个乐观锁字段version,MyBatis-Plus的@Version注解可以自动处理。更新图书状态的时候带上版本号,如果版本号不对就更新失败,提示“手慢无”。这算是一个不错的加分点。
3.4 社群化阅读与系统监控
既然题目的后半段是“社群化阅读系统”,评价和笔记模块就不能随便做做。我的设计是:
- 用户购买完成并确认收货后,可以对这本书写一条评价,评分1~5星
- 用户随时可以发布一条“阅读笔记”,类似一条朋友圈,分享自己读了什么书、有什么心得,并且可以关联到某个具体的图书
- 其他用户可以点赞、评论笔记
这个模块的价值在于解决了二手交易平台“买完就走”的流量流失问题。有了内容沉淀,用户会反复打开App,浏览别人的读书心得,然后发现某本书不错,产生新的交易。内容黏住了用户,平台才能活下去。这也是答辩时“项目为什么这么设计”的一个好答案。
关于点赞功能,我前面提过,用like_count冗余字段提升性能。评论的排序方式,我建议按时间倒序,但点赞多的可以排在前面,SQL里加一个order by like_count desc, create_time desc即可。
对于系统整体监控,你可以用Spring Boot Actuator暴露健康检查接口,配合Spring Boot Admin做简单的服务状态监控,虽然不是必须的,但如果论文或答辩想突出工程化能力,这是一个不错的展示点。
4. 前端App/小程序实现要点
4.1 跨端选型与工程结构
前端我推荐用UniApp来写,因为它可以直接发布到微信小程序和App,一套代码多端复用。对于没有Android原生开发经验的同学来说,UniApp的学习成本低很多。
工程结构大致这样:
/pages页面目录/pages/index/index首页(图书推荐流)/pages/search/search搜索页/pages/book/detail图书详情页/pages/publish/publish发布闲置页/pages/order/list订单列表页/pages/user/user个人中心页
/api接口请求封装/store全局状态管理(Vuex/Pinia)/utils工具函数
页面跳转用UniApp自带的路由,uni.navigateTo、uni.switchTab、uni.redirectTo这几个API掌握好就够用了。
4.2 核心页面与接口对接
首页推荐流是用户进入App的第一个界面,直接决定了用户对产品的印象。我做的首页是横幅轮播+图书瀑布流。瀑布流用mescroll这个插件做上拉加载,配合后端的分页接口,每次下拉加载一页数据。接口返回的数据结构是{ records: [], total: 0, current: 1, size: 10 },前端拿到records追加到列表,total用来判断是否还有下一页。
图书详情页的字段比较多,重点是把“推荐理由”和“学长学姐笔记”这两个板块突出展示。因为对于二手教材来说,买家最关心的不只是价格,还包括这本书的使用价值——划重点多不多、课后题有没有做、考试范围是怎样的。这些信息恰恰是上一任使用者的笔记能提供的东西。
订单页做两个Tab:我买到的和我卖出的。点进订单详情可以看到完整的物流/交易状态,加上线下交易约定的取货地点和联系方式。
发布闲置页有一个容易忽略的细节:教材类目选择。因为二手教材的特殊性,一定要有“按课程/专业分类”的下拉选择,否则用户发布时不知道归到哪个类目。分类名称可以直接复用后端接口返回的数据,前端做一个级联选择器就可以。
网络请求封装部分,建议做一个统一的request.js,每次请求自动带上Token,收到401就跳转登录页,收到500就弹出错误提示。代码大致这样:
javascript复制import store from '@/store'
const BASE_URL = 'http://localhost:8080'
export function request(options) {
return new Promise((resolve, reject) => {
uni.request({
url: BASE_URL + options.url,
method: options.method || 'GET',
data: options.data || {},
header: {
'Authorization': 'Bearer ' + uni.getStorageSync('token'),
'Content-Type': 'application/json'
},
success: (res) => {
if (res.data.code === 200) {
resolve(res.data.data)
} else if (res.data.code === 401) {
uni.navigateTo({ url: '/pages/login/login' })
reject(res.data)
} else {
uni.showToast({ title: res.data.msg, icon: 'none' })
reject(res.data)
}
},
fail: (err) => {
console.log('request fail', err)
uni.showToast({ title: '网络异常', icon: 'none' })
reject(err)
}
})
})
}
这样封装之后,每个页面调接口只要写request({ url: '/book/list', method: 'GET', data: { page: 1 } })就行,非常干净。
4.3 图片上传与缓存处理
发布图书时图片处理是一个常常被忽视的点。直接用uni.chooseImage选图文件,然后uni.uploadFile上传到后端接口。后端接口接收文件后保存到本地目录,返回给前端一个图片URL。前端拿到URL再跟其他表单字段一起提交。如果你用uni.chooseImage时把图片压缩参数sizeType设为['compressed'],可以明显减少上传流量,用户体验也会好很多。
有一个常见错误是:上传图片接口拿到的响应是一个文件流,需要设置formData传递用户ID,后端才能知道这个图片属于谁。图片上传和发布接口建议分开,图片上传成功后返回URL,发布接口只接收URL。这样后期如果发布时用户退出了,图片也不会成为孤儿数据影响数据库。
全局缓存方面,用户信息可以放在uni.setStorageSync('userInfo', ...)里,登录状态通过Token判断。页面之间的参数传递尽量不要用全局变量,使用URL传参或者Vuex状态管理,避免页面刷新后数据丢失。
关于网络环境和真机调试,本地开发时如果你用的是电脑上的后端,在App真机上访问localhost是不通的,必须改成电脑在局域网内的IP地址,比如http://192.168.1.102:8080。这确实是个新手非常容易卡住的地方,我当年第一次调试的时候也在这个问题上花了整整一晚上,发现是手机和电脑没连同一个WiFi。
5. 常见问题与打包部署实录
5.1 版本兼容性合集
这应该是开发过程中最磨人的部分。SpringBoot版本相差一个小版本号,依赖就可能全崩。整理几个高频问题:
问题一:SpringBoot 3.x + JDK 17不兼容老依赖
症状:javax.servlet包找不到,或某些开源工具类报ClassNotFoundException。原因:SpringBoot 3在Java EE基础上把javax换成了jakarta命名空间,大量老依赖没有适配。我建议这个项目直接用SpringBoot 2.7.x + JDK 8,不要追新。
问题二:MyBatis-Plus和SpringBoot版本不匹配
MyBatis-Plus 3.5.x对SpringBoot 2.x支持得很好,但对SpringBoot 3.x需要引入mybatis-plus-spring-boot3-starter这个专门的分支。如果你已经用了SpringBoot 3,MyBatis-Plus的依赖名就完全不同,不要搞混。
问题三:Lombok报you aren't using a compiler supported by lombok
这个报错一般是Lombok版本和JDK版本不匹配。比如JDK 8的编译器比较老,而Lombok 1.18.30开始不再支持JDK 8。解决办法是Lombok版本降级到1.18.28,或者把JDK升上去。如果是IDEA自带的JDK,还要确认项目的Project Structure里选对了版本。
问题四:Redis连接不上
本地开发如果没装Redis,最简单的方案是使用Docker起容器。注意连接报错时要先确认Redis服务有没有启动,再看application.yml里配的密码是否为空(本地默认无密码,如果你设置了密码就一定要填上)。
5.2 前后端联调与部署
前后端联调有几个常见问题,提前知道能少走不少弯路:
跨域问题:浏览器访问http://localhost:8080接口,前端页面在http://localhost:5173,必然产生跨域。后端加一个全局配置即可:
java复制@Configuration
public class CorsConfig {
@Bean
public CorsFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
config.addAllowedOriginPattern("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
config.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
}
部署问题:如果只是给学校演示,直接把项目打包成jar,在服务器上java -jar xxx.jar运行就行。新装服务器的话,要先把MySQL和Redis装好,然后执行项目里的sql目录下的建库建表脚本。注意Linux服务器上MySQL默认大小写敏感,所以表名和字段名最好统一用小写,免得有些地方不一致报Table doesn't exist。
静态资源404问题:打包后的jar在服务器上跑,本地图片上传路径如果是/upload/这种绝对路径,跨机器访问会404。我建议在配置文件里把上传根目录做成一个可配置项,比如upload.path: /home/ubuntu/upload/,在服务器上部署时修改配置文件指向服务器上的绝对路径。这句虽然听着简单,但很多项目都是部署的时候才发现图片挂的。
5.3 答辩环节的高频追问
作为一个带过几届学生的老开发,我大致能猜到答辩时老师会问什么。提前把这些问题想清楚,答辩就稳了。
问题一:为什么用JWT而不用Session?
从可扩展性上回答:JWT无状态,后端不需要保存会话信息,适合分布式部署和App多端接入。Session需要服务端存储,一旦后端扩容多个节点,Session同步就成了大问题。另外JWT自带有效期和签名,天然防篡改。
问题二:MyBatis-Plus真的会写SQL吗?
很多老师会盯着这个问。你可以说:单表的CRUD用MyBatis-Plus简化代码,多表关联、复杂报表统计依然手写XML里的SQL。为了体现这件事,你可以把“热门图书排行榜”做一个自定义SQL,在Mapper XML里写一个join查询加group by统计订单数量,展示真正的SQL能力。
问题三:这个系统怎么保证交易安全?
可以从几个方面答:密码BCrypt加密存储,防止拖库泄露;JWT设置有效期,防止Token被滥用;订单状态有状态机流转,防止重复下单;用户身份需要学号认证才能发布图书,从源头上减少虚假信息。
问题四:如果数据库量很大怎么办?
这个属于拔高题。你可以说:目前用的是MySQL单库,未来可以引入读写分离、分库分表,项目里已经通过MyBatis-Plus的分页插件和索引优化做了前置准备。Redis缓存热数据和排行榜,减轻数据库压力。即使答不好,这种系统性的思考也能给老师留下好印象。
根据我的经验,答辩最忌讳的是对自己项目“知其然不知其所以然”。写完代码之后,花点时间把架构图、表关系图、业务流程图认认真真画一遍,每一行核心配置的含义搞清楚,比什么都管用。
写在最后
我在帮人做毕业设计指导的过程中,发现一个很普遍的现象:毕业生最容易“淹死”的环节不是写代码本身,而是写代码前不知道怎么拆解需求、遇到报错不知道怎么排查、系统做完了不知道怎么把亮点讲清楚。这个校园二手教材交易平台虽然不算特别庞大,但它把用户认证、商品发布、搜索筛选、订单流转、内容社区、文件上传这些典型功能串成了一整条链路,任何一个环节的经验,都能直接迁移到未来的工作项目里。
最后再分享一个小技巧:项目做到中后期,养成一天一提交Git的习惯,每次提交只改一小块功能,并且写清楚提交说明。这样做毕业设计有两个好处:一是你随时可以回退到能跑的版本,不至于改挂了整个系统却不知道怎么恢复;二是答辩时如果老师说“展示一下你的开发记录”,你能直接打开Git历史,一份完整的开发日志比嘴上说“我做了很多工作”有说服力得多。
如果做这个项目的过程中卡住了,记住先看日志,再看配置,最后看代码。数据库连不上就查端口和账号密码,接口404就查路径和访问前缀,数据显示不对就打印SQL,这些问题九成以上都能自己解决。祝你的毕设顺利过关,也祝你在这个过程中真正把SpringBoot这套东西学扎实。
