news 2026/10/2 3:06:32

SpringBoot+Vue3+MyBatis电影评论网站全栈开发实战指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
SpringBoot+Vue3+MyBatis电影评论网站全栈开发实战指南

说实话,看到"Java SpringBoot+Vue3+MyBatis 电影评论网站系统源码"这个标题,我就知道十有八九是冲着毕业设计或简历项目来的。这个组合现在几乎成了全栈入门项目的标配——后端用SpringBoot撑起业务逻辑,前端用Vue3做交互界面,ORM层交给MyBatis操作MySQL,最后配一个前后端分离的架构,面子上过得去,里子上也基本把主流技术栈的常见问题都踩了一遍。

我去年帮人从头到尾捋过一套类似的项目,从数据库建表到功能实现再一直到部署上线,前前后后改了六七版,踩了不少坑。这篇文章就按实际动手的顺序,把这个电影评论网站系统从设计到落地的全过程拆开揉碎讲清楚。适合正在做毕设、想写在简历上的Java后端开发者,也适合刚学完SpringBoot和Vue3、想做个完整项目练手的朋友,看完基本能照着把项目搭起来。

1. 项目整体设计与技术选型思路

1.1 前后端分离到底在分离什么

先说架构。很多人以为前后端分离就是把代码分成两个文件夹,前端一个、后端一个,这就是天大的误会。前后端分离的核心是职责边界和交互协议的分离,代码文件放哪只是表象。

在这个电影评论系统里,后端只负责两件事:处理业务逻辑、提供JSON接口。前端也只负责两件事:渲染页面、调用接口。整个系统通过HTTP接口通信,前端不碰数据库,后端不碰页面渲染。

具体到项目目录,后端是一个标准的SpringBoot工程,包结构按controller、service、mapper、entity四个层级划分;前端是一个Vue3工程,按views、components、api、router四个目录组织。前后端通过统一的前缀约定(比如后端所有接口都以/api开头)配合跨域配置进行通信。

之所以坚持前后端分离而不是用Thymeleaf那套服务端渲染,原因有两个。第一,前后端可以并行开发,后端定义好接口文档后,前端直接用Mock数据推进,不用等后端写完才启动,项目周期能压缩不少。第二,部署时可以前端静态资源放Nginx、后端打jar包独立跑,只要接口不跨域或者反向代理配好,后期扩展和运维都灵活得多。

1.2 技术栈选型的取舍逻辑

这套技术栈单拆开看每个都不算新,但组合在一起恰好覆盖了Java生态最常见的开发链路:

  • SpringBoot: 2.7.x版本是当前兼容性最稳的,自带Tomcat、自动配置、starter机制,把过去SpringMVC那种繁琐的XML配置全部干掉,几分钟就能跑起一个Web服务。
  • Vue3: 用Composition API配合script setup语法,组件逻辑复用比Vue2的Options API舒服太多。电影列表、评论区、用户中心这些页面拆成组件后,状态管理清晰,数据响应式处理也顺手。
  • MyBatis: 比JPA更贴近SQL本身,尤其是电影评论这种需要多表联查、动态条件筛选(按类型筛选、按评分排序、分页)的业务场景,手写SQL的可控性远高于自动生成的SQL。
  • MySQL: 8.0以上版本在事务、性能、JSON支持上都够用,而且也是大多数公司的生产环境数据库,学这个不亏。

这套组合最舒服的地方在于踩坑资料多。不管是MyBatis的#{}和${}区别、Vue3的响应式陷阱,还是MySQL的连接配置问题,网上随便一搜就有大量现成解决方案,对于新手项目来说,能快速找到答案比什么都重要。

1.3 功能模块拆解与需求梳理

一个能拿得出手的电影评论网站,光有增删改查是不够的。我在设计功能清单时,会刻意覆盖一些常见业务场景,这样写起简历来也更有话可说。最终敲定的核心功能模块如下:

  • 用户模块:注册、登录、个人信息查看与修改。登录使用JWT实现无状态认证,用户密码经过BCrypt加密存储,不保存明文。
  • 电影模块:电影列表展示、按类型/关键字搜索、电影详情页。列表分页,支持按上映时间、评分高低排序。
  • 评论模块:用户对电影发表评论、查看评论列表、删除自己发布的评论。评论支持分页加载。
  • 评分模块:用户给电影打1到5分,系统自动计算并更新电影的平均评分和评分人数。

除此之外,还有几个容易被忽略但实际必做的环节:异常统一处理、参数合法性校验、跨域配置、数据库连接池配置。这些杂活看着不起眼,但恰恰是项目能不能稳定跑起来的关键。

2. 数据库设计与核心表结构搭建

2.1 表结构设计:三张表解决问题

电影评论系统的数据模型不复杂,三张核心表就能覆盖全部业务:用户表、电影表、评论表。但真正的细节都在字段设计上,这是新手最容易忽略的地方。

用户表(t_user)的大致结构:

CREATE TABLE `t_user` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID', `username` varchar(50) NOT NULL COMMENT '用户名', `password` varchar(100) NOT NULL COMMENT '密码(BCrypt加密)', `nickname` varchar(50) DEFAULT NULL COMMENT '昵称', `avatar` varchar(255) DEFAULT NULL COMMENT '头像URL', `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', PRIMARY KEY (`id`), UNIQUE KEY `uk_username` (`username`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';

电影表(t_movie)的字段要稍微多几个:

CREATE TABLE `t_movie` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID', `title` varchar(100) NOT NULL COMMENT '电影标题', `poster` varchar(255) DEFAULT NULL COMMENT '海报URL', `director` varchar(50) DEFAULT NULL COMMENT '导演', `actors` varchar(255) DEFAULT NULL COMMENT '主演', `genre` varchar(50) DEFAULT NULL COMMENT '类型(动作/科幻/喜剧等)', `release_date` date DEFAULT NULL COMMENT '上映日期', `duration` int(11) DEFAULT NULL COMMENT '片长(分钟)', `rating` decimal(3,1) DEFAULT '0.0' COMMENT '平均评分', `rating_count` int(11) DEFAULT '0' COMMENT '评分人数', `description` text COMMENT '剧情简介', `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='电影表';

评论表(t_comment)是业务逻辑的核心,先看定义:

CREATE TABLE `t_comment` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID', `movie_id` int(11) NOT NULL COMMENT '电影ID', `user_id` int(11) NOT NULL COMMENT '用户ID', `content` text NOT NULL COMMENT '评论内容', `score` int(11) DEFAULT NULL COMMENT '评分(1-5分)', `like_count` int(11) DEFAULT '0' COMMENT '点赞数', `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '发布时间', PRIMARY KEY (`id`), KEY `idx_movie_id` (`movie_id`), KEY `idx_user_id` (`user_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='评论表';

在设计评论表时有个容易纠结的点:把评分字段放在评论表里,还是单独建一张评分表?我的方案是把评分直接放在评论表里,用户每发一条带评分的评论就算做一次打分。这样做的逻辑很简单:一个用户对一部电影只会有一个有效评分,想改评分就更新自己的评论,不需要再单独维护评分关系。这样查询某个电影的评分,直接对评论表的score字段做聚合就行,一步到位。

2.2 字符集与存储引擎的坑

这个坑我踩过不止一次,必须单独拿出来讲。

MySQL建表时如果你不指定字符集,会继承数据库级别的默认字符集。很多低版本MySQL默认的latin1不支持中文,到时候插入数据直接报错或者乱码。所以建表语句里务必显式写上CHARSET=utf8mb4。

utf8mb4不是utf8,它多支持了emoji和生僻字。电影简介里万一有特殊符号,用utf8就会插入失败。我这个项目所有表统一用utf8mb4,字段类型能选text就选text而不是varchar(评论内容这种不限制长度的字段用text更合适),能省掉很多不必要的commons。

存储引擎选择InnoDB基本没有悬念。它支持事务、行级锁、外键约束和崩溃恢复,对于需要保证用户评论不丢失的场景,这是唯一靠谱的选择。

2.3 初始化数据从哪里来

做毕设或演示项目,没有电影数据就是空壳子。我有两个建议渠道:

第一,从豆瓣或其他电影网站抓取一批经典电影数据,整理成SQL脚本直接导入。注意别一次性导入太多,50到100部足够撑起页面展示效果。数据字段至少要覆盖标题、海报、导演、主演、类型、上映日期、简介,不然电影详情页会很寒酸。

第二,如果不想手动整理,写一个简单的DataInitializer,在SpringBoot启动时自动向数据库植入种子数据。这种方式的好处是项目拉下来一跑就有数据,不用手动执行SQL脚本。

我实际项目中两种方式都用了:开发环境跑种子数据,生产环境用固定SQL脚本。种子数据类在项目里要加@Profile("dev")限制,防止每次启动都重复插入。

3. 后端核心模块实现与接口设计

3.1 SpringBoot分层结构与启动类

后端工程我习惯按这种包结构组织:

com.example.movie ├── MovieApplication.java # 启动类 ├── common # 通用返回结果、异常处理 │ ├── Result.java │ └── GlobalExceptionHandler.java ├── config # 跨域、拦截器、JWT配置 │ ├── CorsConfig.java │ └── JwtInterceptor.java ├── controller # 接口层 │ ├── UserController.java │ ├── MovieController.java │ └── CommentController.java ├── entity # 数据库实体 │ ├── User.java │ ├── Movie.java │ └── Comment.java ├── mapper # MyBatis数据访问层 │ ├── UserMapper.java │ ├── MovieMapper.java │ └── CommentMapper.java ├── service # 业务逻辑层 │ ├── UserService.java │ ├── MovieService.java │ └── CommentService.java └── vo # 前端展示对象 └── CommentVO.java

MovieApplication.java就是标准的三件套:@SpringBootApplication注解、main方法、SpringApplication.run()。很多教程会在启动类上扫描@MapperScan,我习惯把@MapperScan("com.example.movie.mapper")直接写在启动类上,比在每个Mapper接口上加@Mapper注解省事,也更整洁。

一个好的实践是Controller只做参数接收和结果返回,把业务逻辑全部下沉到Service层。这样Controller代码行数会缩到很短,真正的逻辑都在Service里,方便测试和复用。

3.2 MyBatis实战配置与SQL映射

集成MyBatis最省力的方式是引入mybatis-spring-boot-starter,版本一定要选对。SpringBoot 2.7.x对应2.3.x版本的starter,版本跨代太大会出现各种奇怪的兼容性问题。

在application.yml里,MyBatis相关的核心配置有四项:

mybatis: # mapper XML文件位置 mapper-locations: classpath:mapper/*.xml # 实体类别名包路径,省去每次写全限定类名 type-aliases-package: com.example.movie.entity configuration: # 下划线转驼峰:数据库字段create_time自动映射为createTime map-underscore-to-camel-case: true # 控制台打印SQL日志,开发排错神器 log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

其中map-underscore-to-camel-case务必设为true,否则你的实体类要么字段名全改成下划线风格(丑和别扭),要么在XML里每个字段写resultMap映射(累赘)。开启后,数据库的create_time自动映射到实体的createTime字段,省了一大半工作量。

再说SQL映射文件。评论列表是这项目最复杂的查询,因为要联表拿用户名和用户头像。对应的Mapper接口方法定义是:

public interface CommentMapper { List<CommentVO> selectCommentsByMovieId(@Param("movieId") Integer movieId, @Param("offset") Integer offset, @Param("limit") Integer limit); int insertComment(Comment comment); int deleteComment(@Param("id") Integer id, @Param("userId") Integer userId); }

CommentVO对象里可以直接多定义两个字段:username、userAvatar,它们不在评论表但SQL能查出来。XML映射:

<select id="selectCommentsByMovieId" resultType="com.example.movie.vo.CommentVO"> SELECT c.id, c.content, c.score, c.create_time, c.like_count, u.username, u.avatar AS userAvatar FROM t_comment c LEFT JOIN t_user u ON c.user_id = u.id WHERE c.movie_id = #{movieId} ORDER BY c.create_time DESC LIMIT #{offset}, #{limit} </select>

这个SQL有几个细节值得说。第一,LEFT JOIN比INNER JOIN稳妥,因为理论上评论的用户一定存在,但数据库FK如果没建,可能出现孤儿数据,LEFT JOIN至少能保证评论不丢。第二,用#{offset}, #{limit}做物理分页,虽然数据量大时性能不算最优,但这个项目是学习用,足够实用和直观。

特别注意:MyBatis里#{}和${}完全是两回事。#{}走的是预编译,会生成?占位符,能防SQL注入;${}是纯字符串拼接,能实现动态表名、动态排序字段,但有注入风险。除非万不得已,一律用#{}。

3.3 JWT登录认证与拦截器设计

登录认证是全栈项目避不开的模块。这个项目选JWT而不是Session,核心原因是前后端分离下,后端服务可能是多实例部署的,Session复制方案太复杂。JWT把用户信息加密放在token本身,服务端无状态,后端拿着密钥验签就行。

依赖方面,我用jjwt库,版本选0.9.1,这是目前资料最多、用法最稳定的版本。生成token的核心逻辑:

public String generateToken(User user) { Date now = new Date(); Date expireDate = new Date(now.getTime() + 24 * 60 * 60 * 1000); // 24小时过期 return Jwts.builder() .setSubject(user.getUsername()) .claim("userId", user.getId()) .claim("nickname", user.getNickname()) .setIssuedAt(now) .setExpiration(expireDate) .signWith(SignatureAlgorithm.HS256, secretKey) .compact(); }

注意secretKey不能太短,至少要32个字符,不然HS256会报弱密钥异常。这是jjwt 0.9.1版本的硬性规定,不少人都栽在这。

前端拿到token后一般存localStorage,然后每次请求在Authorization头带上。后端拦截器从请求头取token并解析,解析失败则返回401。拦截器注册时要配置放行路径,注册、登录、电影列表查询这些接口不需要携带token就能访问,要是拦错了前端会一直报401死循环。

顺带的密码安全问题:用户注册时密码用BCryptPasswordEncoder加密后存库,登录时用matches方法比对。这是SpringSecurity自带的实用工具类,不用引入整个SpringSecurity就能用。绝不允许存明文密码,这种项目将来即使只是作为简历展示,也要体现安全意识。

3.4 统一返回格式与全局异常处理

很多新手项目接口返回格式五花八门,有的返回String,有的直接裸返回Map,前端对接时全靠猜。我强烈建议统一用一个Result<T>包装所有接口返回。

public class Result<T> { private Integer code; // 200成功 400业务错误 401未登录 500系统异常 private String message; private T data; // 静态方法:success(data)、error(message)... }

配合一个GlobalExceptionHandler,让所有业务的RuntimeException自动转换成Result.error()返回。这样Controller里的逻辑就干净了,不用到处写try-catch。

这个模块看起来简单,但能让代码整洁度上一个档次,也让前端拿到所有响应时都能用一个统一的解析逻辑处理。

4. 前端Vue3页面实现与数据交互

4.1 Vue3工程搭建与目录规划

前端工程用Vite搭建,命令就三行:

npm create vite@latest movie-web -- --template vue cd movie-web npm install

前端目录规划,我清理掉脚手架自带的杂乱结构后,最终是这样的:

movie-web ├── src │ ├── api # 接口请求封装 │ │ ├── request.js │ │ ├── auth.js │ │ ├── movie.js │ │ └── comment.js │ ├── assets │ ├── components # 公共组件 │ │ ├── MovieCard.vue │ │ └── CommentList.vue │ ├── router # 路由配置 │ │ └── index.js │ ├── stores # Pinia状态管理 │ │ └── userStore.js │ ├── views # 页面组件 │ │ ├── Home.vue │ │ ├── MovieDetail.vue │ │ ├── Login.vue │ │ └── Profile.vue │ ├── App.vue │ └── main.js

4.2 Axios封装与认证拦截

Axios请求封装是前端能顺畅开发的基础。我的做法是创建一个request.js,统一配置baseURL并加请求拦截器和响应拦截器。

import axios from 'axios' import { ElMessage } from 'element-plus' const request = axios.create({ baseURL: '/api', timeout: 10000 }) // 请求拦截器:自动携带token request.interceptors.request.use(config => { const token = localStorage.getItem('token') if (token) { config.headers.Authorization = token } return config }) // 响应拦截器:统一处理后端返回 request.interceptors.response.use( response => { const res = response.data if (res.code === 200) { return res.data } else if (res.code === 401) { // 登录过期,跳回登录页 localStorage.removeItem('token') window.location.href = '/login' return Promise.reject(new Error('未登录')) } else { ElMessage.error(res.message) return Promise.reject(new Error(res.message)) } }, error => { ElMessage.error('网络异常,请稍后重试') return Promise.reject(error) } ) export default request

这里有个值得注意的细节:baseURL设为/api,如果前端是Vite开发环境,需要在vite.config.js里配置代理,把请求转发到后端的http://localhost:8080。如果前端最终部署到Nginx,也要用location /api反向代理到后端服务。这个跨域问题不解决,前端会一直报CORS错误。

4.3 电影详情页和评论提交交互

电影详情页是整个系统交互最丰富的页面,包含电影信息展示、平均评分展示、历史评论列表、当前用户评分评论框四个核心区块。

评论提交的表单我用的Element Plus组件,评分组件el-rate绑定评论分数,评论内容用el-input多行输入。提交前做两层校验:前端Button的disabled属性控制用户没登录或分数为空时不能提交;后端Controller再用@NotBlank等注解兜底校验。双保险在前后端分离项目里几乎是必须的——前端校验只为了用户体验,后端校验才真正保护数据安全。

评论列表用CommentList.vue组件抽出来,接收movieId属性,负责分页加载评论数据。这里我用了Vue3的Composition API的ref和onMounted来管理加载逻辑。对于第一次写这种交互的人来说,可能会遇到一个Vue3特有的坑:reactive对象深拷贝时响应式丢失。用ref包数组基本能绕开这个坑,简单数据一律ref没毛病。

4.4 路由守卫与用户状态管理

前端路由分为公开页面和需要登录才能访问的页面。我的处理方式是:

router.beforeEach((to, from, next) => { const token = localStorage.getItem('token') if (to.meta.requiresAuth && !token) { next({ path: '/login', query: { redirect: to.fullPath } }) } else { next() } })

/movie/:id详情页是所有用户都能访问的,/profile个人中心需要登录。requiresAuth直接写在路由meta里即可,清晰直观。

用户状态管理我用Pinia,计数器式的store就够:维护一个userInfo对象,初始从localStorage恢复,登录成功时更新并持久化。Vue3的官方推荐状态库就是Pinia,相比Vuex写起来少了一半样板代码。

4.5 后端单元测试怎么让接口验证更顺手

接口开发完,验证逻辑对不对。我通常会做两种验证:

第一,用浏览器的Network面板手动调接口确认返回。这在开发阶段最常用,配合后端控制台打印SQL,能快速定位是SQL问题还是参数问题。

第二,为Service层写单元测试,用spring-boot-starter-test加上H2内存数据库跑用例。测试覆盖评论发布、评分更新这类核心业务。这个动作虽然会多花点时间,但能在简历上大方写"项目包含单元测试",这在同龄候选人里算加分项。

5. 完整部署与上线操作流程

5.1 从零到一的全流程演示

下面是最省心的操作顺序,建议按这个步骤一步步来:

  1. 在MySQL里执行建库建表脚本,确认表结构和字段正确。
  2. 修改后端application.yml的数据库账号密码,确认能连上库。
  3. 启动后端MovieApplication,观察控制台日志没有报错。
  4. 用curl http://localhost:8080/api/movie/list?page=1验证接口通不通。
  5. 启动前端npm run dev,浏览器打开http://localhost:5173。
  6. 注册一个新用户,登录后尝试发表评论。
  7. 检查数据库t_comment表是否新增了记录,评分是否更新到t_movie表。
  8. 本地验证通过后,构建部署包:mvn clean package -DskipTests打包后端jar,npm run build打包前端静态文件。
  9. 部署到服务器:jar用java -jar启动,前端静态文件传Nginx的html目录并配置反向代理。

5.2 部署过程中必备的Nginx配置参考

如果你的服务器上装了Nginx,下面这个配置片段可以直接参考:

server { listen 80; server_name your-domain.com; root /var/www/movie-web/dist; index index.html; # 前端路由history模式回退 location / { try_files $uri $uri/ /index.html; } # 后端接口反向代理 location /api/ { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }

两个关键点:try_files是前端history路由的标配,刷新页面时不会404;proxy_pass结尾的/务必保留,它表示把/api前缀掰掉后再转发给后端。如果漏了/,后端接口路径就会变成/api/list而不是/list,直接404。

5.3 Maven与前端构建的常见坑

后端打包,强烈建议加-DskipTests跳过测试阶段,否则本地如果有不确定的测试用例会直接卡住构建。

前端构建最大的坑是Node版本和依赖版本不匹配,Vite 5要求Node 18以上,老版本Node会直接报错。构建产物在dist目录,里面是纯静态文件,扔给任意Web服务器就能跑。

6. 项目扩展与性能优化进阶建议

6.1 部署一台Nginx的缓存配置参考

基础版本跑通后,有几个低成本高收益的优化思路很值得做。

缓存优化:电影列表和详情这类读多写少的数据,后端可以用Spring Cache配合Redis做缓存,设置合理的过期时间。请求到达时先查缓存,缓存没有才走数据库。评论新增时主动淘汰对应电影的缓存,保证数据一致性。

索引优化:评论表已经建了movie_id索引,但如果用户量多大后经常按用户查他的评论记录,user_id的索引也建议建上。对于大表的排序分页查询,可以用覆盖索引减少回表。

全文搜索:当前的LIKE '%关键字%'写法在数据量大时必定慢,MySQL的全文索引或引入Elasticsearch都可以解决。前者实现简单,后者更专业。这个优化点写到简历的"项目亮点"是很扎实的一条。

6.2 从单机到微服务不必过度设计

诚实说,这个体量的项目上微服务纯属炫技。业务边界只有一个聚合根,服务拆了反而增加通信成本和运维复杂度。但如果是为了面试聊架构演进,你可以把潜在拆分点列出来:用户认证服务、电影信息服务、评论服务。说明清楚什么规模该拆、拆之后面临的分布式事务问题怎么处理,这比真拆一个微服务工程能聊的东西更多。

6.3 给毕业设计交作业的加分细节

最后补充几个能让你在答辩或面试时多聊几句的细节:

  • 在README里写清楚环境要求、启动步骤、接口文档和项目结构说明,这是负责任的项目该有的样子。
  • 后端写几个关键接口的单元测试,面试官问"你这项目怎么保证质量"的时候,你就有具体内容可以讲。
  • 统一定义Result全局返回格式,这比Map<String, Object>看起来专业很多。
  • 密码加密存储 + 统一鉴权 + 接口参数校验,这三点能直接体现工程素养,答辩或面试的时候有得聊。

我个人的实际体会是:这类项目做出来不难,难的是每个细节都能说出"为什么这么做"以及"换一种方案的差别是什么"。照着本文把项目搭起来只是第一步,真正有价值的是在调试过程中把SpringBoot的启动流程、MyBatis的代理机制、Vue3的响应式原理这些底层概念弄明白。这样面试官深挖技术栈的时候,你才不会只停留在"会用"的层面。

最后再分享一个小技巧:所有代码写完后,把项目丢到GitHub上,并开启GitHub Actions自动构建,每次push都能自动跑测试和打包。这一个小小的习惯,会让你的项目完整度直接上一个台阶,面试官看到你懂CI/CD,兴致会明显不一样。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/2 3:06:13

Linux tail命令详解:从查看日志末尾到实时追踪的工程实践

凌晨两点半&#xff0c;告警短信把我从被窝里拽出来&#xff0c;连上跳板机后的第一件事就是敲下tail -n 100 app.log。我得在最短时间内知道服务崩溃前到底发生了什么。这个场景我猜不少人都经历过。tail大概是 Linux 下除了ls、cd之外最容易上手的命令之一&#xff0c;但从&q…

作者头像 李华
网站建设 2026/10/2 3:05:58

前端接口模拟与 Mock 实践:Apifox 打通前后端联调

上周三下午&#xff0c;产品经理在群里甩过来一张原型图&#xff0c;说这个页面下周一要给客户演示。我看了眼接口文档&#xff0c;后端同事那边表结构还在改&#xff0c;接口最快也得下周三才能出第一版。这种场景做前端的应该都不陌生——布局、交互、样式、动画全都能自己搞…

作者头像 李华
网站建设 2026/10/2 3:05:17

SpringBoot+Vue+MyBatis+MySQL:从0到1搭建网站管理系统

SpringBootVue这套前后端分离的组合&#xff0c;到今天依然是中小型网站管理系统的主流选择。不是因为它最时髦&#xff0c;而是因为它省钱、省心、能落地——SpringBoot把后端服务的配置复杂度降下来了&#xff0c;Vue把页面的交互响应速度提上去了&#xff0c;再配上MyBatis的…

作者头像 李华
网站建设 2026/10/2 3:05:16

SpringBoot+Vue前后端分离旅游平台实战:从架构设计到部署上线全解析

先说个背景。去年我帮桂林本地一家做地接业务的旅游公司搭了套“旅游景点导游平台”&#xff0c;技术栈选了 SpringBoot Vue MyBatis MySQL&#xff0c;前后端完全分离&#xff0c;从数据库设计、接口联调到最终部署上线&#xff0c;整套流程走了一遍。这个系统功能上没有特…

作者头像 李华
网站建设 2026/10/2 3:04:57

DehazeNet 去雾实战:PyTorch 实现、训练与部署全流程

简介&#xff1a;这份资源是面向具备深度学习基础的研究者与图像处理方向学习者的PyTorch版DehazeNet图像去雾实现&#xff0c;提供从网络结构定义、训练流程到推理演示的完整代码链路&#xff0c;并附带已训练好的室内与室外场景预训练权重&#xff0c;可直接加载使用&#xf…

作者头像 李华
网站建设 2026/10/2 3:04:57

云服务器成本优化实战:从选型到架构的降本指南

上个月整理自己的云资源账单时&#xff0c;我发现一台2核4G的云服务器实例已经连续运行了47天&#xff0c;而它承载的只是一个几乎没人访问的内部演示环境。月底看到那笔并没有创造实际价值的支出时&#xff0c;我第一次真正意识到&#xff1a;云服务器这种东西&#xff0c;开起…

作者头像 李华