ARTICLE DETAIL

资讯详情

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

基于B/S架构的工艺品展示与交流平台设计与实现

基于B/S架构的工艺品展示与交流平台设计与实现 最近刚把一个基于Java Web的工艺品展示系统做完从需求梳理到数据库设计再到最后的部署上线前后改了三版。这个题目乍一看就是个普通的信息管理系统但真正动手才发现手工艺品展示跟普通商品展示完全是两码事——它既要展示工艺细节又要有创作者与参观者之间的交流讨论还得有一套作品评价机制。这篇文章就把整个基于B/S架构的手工艺品在线展示与交流平台的设计思路、核心代码逻辑、部署细节和踩坑记录完整拆一遍不管是正在做毕业设计的学生还是想快速搭建一个作品展示类网站的同学都能直接照着参考。1. 项目定位与核心需求拆解1.1 这个系统到底在解决什么问题先明确一点这个系统不是电商系统不涉及到交易、库存、支付它的核心就是“展示”和“交流”。手工艺品行业有个很特殊的地方作品的视觉呈现方式很重要同一个陶瓷杯不同角度拍出来质感完全不同而且购买或收藏之前用户往往希望看到创作者本人对工艺过程的讲述甚至和其他爱好者聊一聊这件作品好在哪、瑕疵在哪。所以这个基于B/S架构的工艺品展示系统本质上要做三件事作品展示、在线交流、评价管理。展示是指把作品图片、工艺说明、创作者信息组织成一个清晰好看的信息流交流是指用户可以对作品发表评论、提问或回复创作者可以回答评价管理则是一套规则让用户给作品打分系统根据分数形成口碑数据。从毕业设计的角度来说这个题目属于典型的“Java Web 传统管理信息系统”范畴但因为它加入了用户互动、权限控制、图片上传、数据统计这些元素比普通CRUD系统更有层次也比较容易在答辩时讲出亮点。1.2 需求拆解展示、交流、评价三条主线我习惯把需求按角色来拆。系统里主要有四类角色游客、注册用户、创作者、管理员。不同角色看到的功能完全不一样这也是系统设计里最核心的点。游客浏览首页、按分类查看作品、查看作品详情和评论但不能点赞、不能评价、不能发评论。这里要留意游客也是目标用户不能把所有页面都锁上否则搜索引擎和初次访问的人什么都看不到项目演示时也显得很单薄。注册用户游客注册登录后可以评论作品、给作品评分、收藏作品也可以修改个人资料。这里有一个重要设计决定注册用户不等于创作者普通用户想要发布作品需要额外申请成为创作者或者由管理员在后台把角色改成创作者。这样做的好处是权限边界清楚系统不会出现“人人都能上传作品”的混乱状态。创作者在注册用户能力的基础上可以发布新作品、编辑自己的作品、下架作品还可以回复别人对自己作品的评论。创作者只能管理自己的作品不能动别人的这一点在后端校验时一定要写清楚。管理员负责用户管理、分类管理、作品审核、评论审核、数据统计。因为作品一经发布就对外开放必须有审核环节否则有人上传违规图片或者垃圾信息整场答辩演示就尴尬了。这三条主线相互交叉就构成了系统的完整功能网游客逛展、用户交流、创作者发布、管理员审核。整个数据库设计和模块开发都围绕这个功能网展开。1.3 为什么选B/S架构而不是C/S架构先给结论对于这种“以浏览浏览为主、没有任何高实时性要求”的系统B/S架构是最合理的选择。浏览器做客户端用户不用装任何软件打开网址就能用这对展示类项目来说体验最优。从技术层面看C/S架构通常需要专门开发客户端比如C# WinForm或者Java Swing程序部署时每台电脑都要装客户端升级版本还得逐个更新。而B/S架构把业务逻辑和数据处理都集中在服务器端客户端只负责渲染和交互所有的升级只需要在服务器上改一次用户刷新页面就能看到新效果。再考虑到毕业设计的演示场景答辩现场往往只有一台电脑老师可能还会让你在另一台电脑上打开网址测试。如果是B/S架构只要启动Tomcat或者其他容器局域网内任何一台电脑的浏览器都能访问。而C/S架构你需要考虑客户端依赖、环境变量、JDK版本匹配等等非常折腾。用Java来实现B/S架构还有一个隐含优势Java的Servlet规范天然就是为了Web服务设计的Spring Boot这种框架更是把部署简化到“打一个包、跑一条命令”。从项目复杂度来看一个工艺品展示系统属于中小型Web应用用B/S架构不会遇到明显的性能瓶颈反而是最稳妥的选择。2. 技术选型与方案设计2.1 Java技术栈Servlet/JSP还是Spring Boot这是很多毕业设计同学第一道坎。如果你的课程还在讲JSP、Servlet老师也明确要求写ServletJSPTomcat那你就按传统方式做。但说实话现在企业里写Java Web再用纯粹的JSP已经很少了Spring Boot已经是绝对的主流。如果你不想在答辩时被问“为什么不用Spring Boot”建议直接用Spring Boot。选型理由很简单开发效率高。Spring Boot内置Tomcat不用单独配置一堆XML一个可执行的jar包就能跑起来。生态成熟。接入MyBatis/JPA、Spring MVC、Spring Security都很方便社区资料多报错基本都能搜到。分层清晰。Controller、Service、Mapper分得明明白白评委一看代码结构就知道你懂分层架构。方便扩展。如果之后想加REST API给手机端用Spring Boot稍微改造就能做到。数据库选型上用MySQL这是最经典的搭配。如果你所在学校的环境是Oracle或者SQLServer也没问题但MySQL的开源特性和常用性更适合学生项目而且云服务器上装MySQL也容易。前端的做法我推荐两种取决于你的边界能力如果精力有限就用Thymeleaf模板引擎做服务端渲染页面里写HTML加模板语法后端把数据填充到Model里前端直接渲染如果你愿意多花点时间也可以做前后端分离后端提供JSON接口前端用Vue框架这样技术含量更高项目文件夹里前后端分开看起来更专业。我在这个项目里选的是Spring Boot MyBatis MySQL Thymeleaf。原因很简单毕业设计周期有限Thymeleaf开发速度比Vue更快而且不需要在答辩现场解释跨域和代理问题。2.2 后端层次架构设计思路后端不要图省事把所有业务逻辑都堆在Controller里一定要分层。标准的分层是Controller层负责接口接收和响应Service层负责业务逻辑处理Mapper层负责数据库操作。另外再补两个包pojo/entity放实体类vo/dto放接收前端参数和返回数据的对象。以一个具体场景为例用户给作品打5分并写了一条评论后端要做几件事校验用户是否登录校验作品是否存在判断该用户是否已经评论过这个作品如果同一个用户对同一作品多次评价会造成恶意刷分插入评论记录4. 更新作品的平均分5. 把作品热度加一。这五步如果全写在Controller里代码会膨胀得很难看而且事务不好控制。放到Service层用一个方法把所有数据层操作包在一个事务里任何一步出错都能整体回滚数据不会出现“评论加了但评分没更新”的情况。再比如权限校验系统里有游客、注册用户、创作者、管理员四种角色。最简单的方式是写一个登录拦截器在Controller之前判断Session中是否有用户再针对创作者后台单独加一个角色判断。如果接口用Spring Security做整体权限控制初学的复杂度会上升。我建议用HandlerInterceptor或者AOP来拦截代码少也容易理解。2.3 前端页面与数据交互方案页面组织上我按“首页、分类列表、作品详情、创作者后台、用户中心、管理后台”这几块来做。首页放轮播图推荐位、热门作品和最新作品分类页支持侧边栏筛选作品详情页则把图片、简介、评分、创作者信息、评论区全部放在一个页面上。因为用的是Thymeleaf数据交互很简单Controller返回视图名和Model数据模板里用th:each遍历作品列表用th:href拼接详情URL分页时把页码和分类id作为查询参数。像这样div th:eachwork : ${page.list} a th:href{/work/detail(id${work.id})} img th:src${work.coverImage} alt封面 /a h3 th:text${work.title}作品标题/h3 span th:text${work.avgScore}综合评分/span /div要注意的几个点图片链接不要存绝对路径要存相对路径这样项目挪到别的机器上也不受影响评论区的提交和回复可以用表单POST提交局部刷新用JS请求后端接口但不必引入太重的前端框架。如果你选择前后端分离后端只需要返回JSON前端用axios调用页面渲染交给Vue。那就要额外处理跨域一般用CrossOrigin注解或者在配置类里加CORS配置。我这次不用跨域反而省了很多排查时间。3. 数据库设计核心表结构与字段解析3.1 用户、作品、评价三大核心表表结构设计是整个项目的地基。我一开始设计得比较粗只有用户表和作品表后来越开发越发现缺表、缺字段返工了好几次。正确的做法是先画ER图把每个角色的操作路径走一遍再落表。用户表t_user核心字段id主键自增username登录账号唯一索引password加密后的密码nickname昵称页面显示使用role角色0游客/1用户/2创作者/3管理员avatar头像路径phone/email联系方式create_time注册时间作品表t_work核心字段id主键title作品名称description作品描述用TEXT类型记录工艺说明、创作故事cover_image封面图路径images多图列表存JSON数组字符串例如[/upload/1.jpg,/upload/2.jpg]category_id分类iduser_id创作者idstatus审核状态0待审核/1已通过/2已下架/3审核驳回view_count浏览量点赞/收藏量可以单独表或字段avg_score综合评分冗余字段create_time发布时间评论表t_comment核心字段id主键work_id对应作品iduser_id评论用户idparent_id父评论id用于回复0表示顶级评论content评论内容score评分1-5整数create_time评论时间除这三张表之外还需要分类表、收藏表、通知表。收藏表主要是用户id加作品id唯一约束通知表是给创作者发“有人评论了你的作品”的站内信如果不想要可以省掉。管理员日志表建议也建一个记录关键操作答辩时能展示系统规范性。3.2 分类与图片存储的设计细节手工艺品的分类不能太粗也不能太细。太粗像“陶瓷、雕刻、编织”这种大类首页展示还行但搜索结果会很扎堆太细像“青花瓷”“紫砂壶”“竹根雕”管理起来又太麻烦。我采用的是二级分类设计一级分类保持大类二级分类细分品种。分类表结构id主键name分类名称parent_id父分类id0表示一级分类sort排序号icon分类图标路径例如“陶瓷”是一级分类下面关联“日用陶瓷”“艺术陶瓷”“紫砂”等二级分类。前端分类导航只显示一级分类点进去后左侧栏显示该分类下的所有二级分类用户点击二级分类再筛选对应作品。这样层级清楚也不会造成页面过深。图片存储其实是个很容易踩坑的点。很多人喜欢把图片转成Base64字符串存在数据库里简单是简单但数据库会变得巨臃肿查询速度直线下降。正确做法是图片文件上传到服务器本地目录比如项目根目录下的/upload文件夹数据库里只存相对路径。MultipartFile接收上传文件后用UUID重命名文件防止中文文件名乱码和重复。String originalName file.getOriginalFilename(); String ext originalName.substring(originalName.lastIndexOf(.)); String fileName UUID.randomUUID().toString().replace(-, ) ext; File dest new File(uploadDir, fileName); file.transferTo(dest); // 数据库里存/upload/文件名这里有个细节uploadDir一定要配置成绝对路径并且要提前创建好目录否则transferTo会报目录不存在。同时也要对文件大小和类型做校验一般限制单张5MB以内只允许jpg、png、gif这些常见格式。3.3 表结构设计时容易忽略的几个坑第一密码不要用明文。有些人做课程设计图省事密码随便存。但毕业设计评委经常会问“密码怎么存储”如果回答明文印象分直接掉一大截。用BCrypt或者至少用加盐的SHA-256做哈希Spring Security里自带BCryptPasswordEncoder单独引进来也很简单。第二作品的评分不要实时去评论表里count再加avg。评论量大了以后这条查询会成为性能瓶颈。正确做法是在t_work表里加一个avg_score字段每次用户提交评论时在同一个事务里重新计算平均分并更新这个字段。读的时候就不用查评论表了。第三状态字段要用int类型尽量不用字符串。比如作品状态0、1、2、3在代码里可以定义常量来对应避免字符串比对不准确。状态变化的地方比如审核通过、用户下架要写清业务逻辑尤其是“管理员把作品驳回后创作者需要能重新编辑再提交审核”这个闭环。第四所有时间字段建议用datetime不要用timestamp还好主要区别在于时区处理MySQL里datetime更直观。读取时在实体类里用LocalDateTime对应避免java.util.Date带来的时区麻烦。4. 核心功能模块的实现细节4.1 作品展示模块从列表到详情的完整链路作品展示是整个系统的门面也是用户访问量最大的部分。列表页要支持分类筛选、关键词搜索、分页和排序。我用的方案是MyBatis动态SQL在Mapper里用if标签拼接查询条件select idpageWorks resultTypecom.example.vo.WorkVO SELECT w.*, u.nickname, c.name AS categoryName FROM t_work w LEFT JOIN t_user u ON w.user_id u.id LEFT JOIN t_category c ON w.category_id c.id WHERE w.status 1 if testcategoryId ! null AND w.category_id #{categoryId} /if if testkeyword ! null and keyword ! AND (w.title LIKE CONCAT(%, #{keyword}, %) OR w.description LIKE CONCAT(%, #{keyword}, %)) /if ORDER BY w.create_time DESC LIMIT #{offset}, #{pageSize} /select这里的LIKE查询在用户搜索时会触发全表扫描数据不多时没关系但如果作品量大了可以再加一个全文索引或者改用Elasticsearch不过对毕业设计来说这一步已经足够了。分页我建议自己用LIMIT实现不要引入PageHelper插件。PageHelper确实方便但有些版本和Spring Boot配合会碰到分页失效的奇怪问题不如老老实实传offset和pageSize逻辑透明答辩时也更好解释。作品详情页要做的一件事是浏览量自增。每访问一次view_count加一。这个操作不建议同步到数据库请求里可以用Redis缓存自增再定时落库。但如果项目里没用Redis直接在Service加一条update语句也完全能接受因为毕业设计不需要对抗高并发。关键是更新浏览量时不要影响详情查询的速度。详情页还应该显示创作者信息。这里我踩了一个坑如果直接用作品表的user_id关联用户表查询时用left join那创作者昵称和头像在列表页和详情页都能拿到。但如果你做了VO实体类记得把用户表的字段单独封装别把整张用户表所有字段全带出来尤其是密码字段绝对不能漏到前端JSON里。4.2 评论与评分模块事务和防刷是关键这个模块是系统里业务逻辑最复杂的部分。普通用户登录后可以针对作品评论、评分也可以回复别人的评论。设计上要注意几点首先是一个用户对同一作品只能评分一次。我最初没有做限制测试时自己给自己刷了五六条评分导致作品平均分跑到4.9看起来假得离谱。后来在评论表加了唯一约束UNIQUE KEY uk_work_user (work_id, user_id)并且把评分和评论放在同一条记录里也就是“评分必须附带评论内容”防止用户只打分不写文字。其次是嵌套回复的层级限制。用户A评论作品用户B可以回复A但B不能回复C对A的回复。因为一旦允许无限套娃前端展示评论区就非常复杂数据库递归查询也很头疼。做法是新建评论时判断parent_id如果parent_id不为0则查一下父评论的parent_id如果父评论的parent_id还是0允许回复否则拒绝。这样评论最多两层页面展示清晰逻辑也简单。再就是平均分更新事务。用户提交评论后Service里做三步Transactional public void addComment(CommentDTO dto, Long userId) { // 1. 校验作品存在且状态为已通过 Work work workMapper.findById(dto.getWorkId()); if (work null || work.getStatus() ! 1) { throw new BusinessException(作品不存在或未上架); } // 2. 插入评论 Comment comment new Comment(); comment.setWorkId(dto.getWorkId()); comment.setUserId(userId); comment.setScore(dto.getScore()); comment.setContent(dto.getContent()); comment.setParentId(dto.getParentId() null ? 0 : dto.getParentId()); commentMapper.insert(comment); // 3. 更新作品的平均分和评论数 MapString, Object scoreInfo commentMapper.getAvgScoreByWorkId(dto.getWorkId()); Double avgScore (Double) scoreInfo.get(avgScore); Long count (Long) scoreInfo.get(cnt); workMapper.updateScore(dto.getWorkId(), avgScore, count); }getAvgScoreByWorkId这个SQL是用来在插入评论后查询该作品所有评论的平均分和评论数再写回作品表。注意事务范围内先insert再select avgMySQL默认隔离级别下这个查询能拿到刚提交的数据所以在同一个事务里没问题。评论内容必须先过滤再入库。最简单的办法是引入一个HtmlUtils.htmlEscape()把尖括号、引号转义掉防止XSS脚本注入。如果你想更彻底可以在前端展示时再转义一次双保险。4.3 创作者后台发布、审核、状态管理创作者登录后进入专属后台可以发布作品、管理已有的作品列表、编辑作品、下架或重新上架作品。这个后台本质上是一个小型内容管理系统。发布作品的表单字段包括作品名称、分类、描述、封面图、附加图片。分类需要做成级联选择先选一级分类再选二级分类。由于分类在系统里是固定的可以提前把分类树查出来放到Redis里缓存没有Redis就每次查询也没关系因为分类表数据量很小。有一个容易忽略的点创作者提交作品后作品状态默认是0待审核状态。在这个状态下游客和普通用户在浏览页面是看不到这件作品的只有创作者自己在前台通过“我的作品”列表才能看到。管理员在后台看到待审作品后可以审核通过、驳回。驳回时最好要求管理员填写驳回理由创作者编辑后重新提交状态回到待审核。这里的权限校验要贯彻。作品的管理操作编辑、删除、上下架必须校验当前登录用户是不是作品的user_id否则一个创作者可以把别人的作品改成自己的数据就全乱了。我用一个简单的checkOwner方法在进入编辑页之前先判断。public Work getOwnedWork(Long workId, Long userId) { Work work workMapper.findById(workId); if (work null || !work.getUserId().equals(userId)) { throw new BusinessException(无权操作); } return work; }另外创作者可以在作品详情页回复用户评论。回复本质上也是插入一条评论记录parent_id指向目标评论的id。这里不需要再判断目标评论的层级吗需要。我上面说的二级评论限制在创作者后台回复时也要走同一套校验所以我把“检查评论是否可被回复”的逻辑抽成了公共方法创作者回复和普通用户回复共用一套代码避免逻辑分叉。4.4 后台管理模块审核和统计管理员后台要做的操作是查看作品列表包括待审、已发布、已下架等状态、审核作品、管理用户、管理分类、查看访问统计数据。我经验里最实用的是做一个简单数据看板展示总作品数、总用户数、今日新增作品数、待审核数、评论总数。这些数据用几个count查询拼起来就好不需要引入ECharts之类的图表库哪怕只是表格也足够。如果项目时间充足可以再加一个按分类的作品数量饼图用ECharts画起来不难效果也好看。审核操作本身要记录操作日志。比如管理员“审核通过作品ID为10”这一操作写入admin_log表附上操作人、操作时间、操作内容。答辩时展示日志表能体现系统完整性和规范性这种细节很加分。5. 实操过程与全流程部署记录5.1 开发环境准备与版本匹配我先列一下我实际使用的环境清单JDK 1.8稳定和Spring Boot 2.7.x配合良好Maven 3.6.xIDEA 2023MySQL 8.0Navicat用于数据库管理Spring Boot 2.7.8MyBatis 2.3.0ThymeleafLombok简化实体类代码有一点必须提醒Spring Boot 3.x已经发布了但3.x要求JDK17起步MyBatis和很多老版本依赖的兼容适配又不太一样。如果跟着网上的教程走很多教程用的是2.x版本你把项目建到3.x上反而容易报错。稳妥起见毕业设计直接用Spring Boot 2.7.x JDK 8这套组合最成熟、踩坑最少。MySQL连接时要注意驱动版本MySQL 8对应依赖是com.mysql.cj.jdbc.DriverURL里要加上serverTimezoneAsia/Shanghai和useSSLfalse否则启动时会有时区报错和SSL警告。5.2 项目目录结构与核心配置我用标准的Maven目录结构包名一般写成com.example.craft或者com.demo.artwork这里我建议别用全拼音用一个规范的英文包名就好。核心包结构如下src/main/java/com/example/craft ├── controller // 接口层 ├── service // 业务逻辑层 ├── mapper // MyBatis数据访问层 ├── entity // 数据库实体 ├── vo // 视图对象 ├── dto // 数据传输对象 ├── config // 配置类拦截器、静态资源映射等 ├── interceptor // 登录拦截器 └── common // 通用返回结果、异常处理application.yml核心配置server: port: 8080 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/craft_db?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/ShanghaiuseSSLfalse username: root password: 123456 servlet: multipart: max-file-size: 5MB max-request-size: 20MB thymeleaf: cache: false mybatis: mapper-locations: classpath:mapper/*.xml type-aliases-package: com.example.craft.entity configuration: map-underscore-to-camel-case: truemap-underscore-to-camel-case一定要开这样数据库字段user_id可以自动映射到实体类的userId省掉一大堆手动映射。静态资源映射也要单独配一下因为上传的图片在项目运行目录之外默认访问不到。用WebMvcConfigurer或者配置类里把/upload/**映射到本地磁盘目录Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler(/upload/**) .addResourceHandler(file: uploadDir /); }5.3 从打包到部署两种方式都要会开发阶段直接在IDEA里启动Spring Boot主类就行。但作为毕业设计建议你学会打成jar包然后用命令行运行。这样答辩时换一台电脑演示不用装IDEA只要有JDK就行。打包命令mvn clean package -DskipTests打出来的jar在target目录下名称类似craft-0.0.1-SNAPSHOT.jar。运行java -jar target/craft-0.0.1-SNAPSHOT.jar如果想部署到云服务器还得把数据库导过去上传jar包。上传后建立目录结构把application.yml里的数据库地址改成云数据库地址或服务器本机MySQL地址重新打一次包再启动。如果老师的验收环境必须用Tomcat那也可以打成war包。先把pom.xml的packaging改成war然后在启动类上继承SpringBootServletInitializer并重写configure方法。用Maven打war包后放到Tomcat的webapps目录下启动Tomcat后访问http://localhost:8080/war包名/注意多了个应用上下文路径所有页面的URL都要带上这个路径前缀。为了避免这种麻烦你可以在application.yml里设置server.servlet.context-path: /但war包方式我建议直接放弃jar方式已经能满足绝大多数场景。5.4 初始化测试数据系统里不能没有数据尤其手工类项目没有几张精美的手工艺作品图页面效果直接就塌了。我在开发阶段准备了一套测试数据大概二十件作品分布到陶瓷、木雕、编织、刺绣、金属工艺五个分类里。图片我是在开源图库网站找的免费授权图片用图片压缩工具压到100KB以内保证页面加载快。生成测试数据的SQL脚本要单独建一个data.sql文件每次重置数据库后执行一遍。数据里可以模拟几个用户一个是普通用户一个是创作者一个是管理员。管理员账号密码可以直接在SQL里插入BCrypt加密后的值。INSERT INTO t_user (username, password, nickname, role) VALUES (admin, $2a$10$...BCryptHash..., 管理员, 3);这个BCrypt哈希值怎么生成写一个最简单的main方法调用BCryptPasswordEncoder的encode方法就行。6. 常见问题与排查技巧实录6.1 典型问题速查表做这类项目翻来覆去遇到的就那么几个问题。我把高频问题和排查思路整理成了一张表遇到问题先查表比一个个搜报错快得多。问题现象可能原因解决办法启动时报数据库时区异常URL缺少serverTimezone参数加上serverTimezoneAsia/Shanghai中文乱码页面编码、响应头或数据库编码不一致数据库建库用utf8mb4页面设置charsetutf-8过滤器设置请求和响应编码图片上传后访问404静态资源映射没配配置类里把/upload/**映射到本地upload目录图片上传报exceeds maximum size上传大小超限在application.yml的multipart配置里调大max-file-size评论提交后平均分没变事务没生效或更新语句没执行检查Service方法有没有加Transactional检查作品表updateScore语句登录状态一会有一会无Session域设置或拦截器顺序问题统一用Session存用户对象拦截器排除登录、首页、详情页等公开路径列表分页页码越界前端传参没校验后端统一封装pageNum和pageSize非法时设置默认值部署到服务器后访问不到防火墙或安全策略未放行端口检查服务器安全组和本机防火墙确保8080端口开放中文文件名图片上传报错文件名里带中文和特殊字符用UUID重命名文件避免使用原始文件名6.2 排查思路与避坑经验排查问题先看日志这是我一直强调的。Spring Boot的报错日志会打印出具体异常栈根据异常类型基本能判断问题范围。比如NullPointerException通常在Service层SQLSyntaxErrorException多半是SQL语句写错FileNotFoundException基本是路径拼错。一个很典型的坑是MyBatis查询结果映射成实体类时返回null。出现这种问题第一怀疑map-underscore-to-camel-case配置没生效第二怀疑实体类字段名和数据库字段不一致第三怀疑MyBatis的resultType写错了。自己排查时可以先在Mapper接口上加一个Select注解的简单查询打印出来看看字段是否正常再定位是映射问题还是SQL问题。还有就是前后端传参时时间格式格式化问题。比如详情页显示“2024-05-12 15:30:00”如果你在实体类里直接用了LocalDateTime在Thymeleaf模板上显示会默认带个T比如“2024-05-12T15:30:00”。这时候用模板引擎自带的时间格式化函数或者在后端ToString格式化成字符串都是可以的。我一般是在VO里直接加一个格式化好的createTimeStr字段前端显示这个字符串省事且直观。另外测试功能时一定要用边界数据。比如分类下拉框什么都不选参数是空值能不能正常查全部分类搜索框输入特殊字符比如单引号会不会SQL报错评论字数超过2000字页面会不会卡死这些边界问题在答辩前自己都测一遍老师提问时你的系统表现会好很多。6.3 完善项目的小技巧加分项其实这个项目做完整以后还有很多可以低成本的加分项。一个是让页面响应式适配用Bootstrap或者纯CSS保证手机和电脑都能看手工艺品的用户很多是用手机浏览的页面在手机上不能变形。另一个是给主要模块加操作日志比如管理员审核、创作者下架作品都能记录在日志表。还有一个是我前面提到的数据看板哪怕只是几个数字卡片也说明你有数据可视化意识。再有就是善用Git。整个过程用Git管理版本每次功能做完提交一次commit即使改出问题也能回滚。有些老师答辩时还会问“开发流程”你完全可以把GitLog展示出来证明你有良好的工程习惯。这个习惯放在简历上也是能写的点。最后聊点个人体会这个项目做完我最深的感受是毕业设计做管理系统功能多不是关键关键是每个功能链路要闭环。像作品上传、管理员审核、用户评价、评分更新、创作者回复这条链路每一步的权限和数据状态变化都理清楚系统自然就稳了。很多同学做这类题做不动往往不是不会写代码而是需求自己没捋明白数据库表一下缺一个字段一下少一张表最后只能一边写一边改。所以我建议动手之前至少花两天时间做设计画ER图、画页面原型图、画角色流程图。设计稿越细后面写代码越快。技术本身没有多玄妙Spring Boot也好、MyBatis也好都是一些成熟工具的堆叠真正值钱的其实是“你清楚自己在做什么、为什么这么做”。这套思路不仅适用于这个工艺品展示系统换成任何Java Web管理类题目的毕业设计都完全通用。
返回列表