news 2026/10/15 7:05:43

SpringBoot+Vue+MySQL实习生管理系统设计与部署实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
SpringBoot+Vue+MySQL实习生管理系统设计与部署实践

开箱即用的一套实习生管理系统,SpringBoot后端、Vue前端、MySQL做数据存储,三件套组合已经被无数个中小型项目验证过了。这套源码有完整的用户登录、角色权限、实习过程记录、日报周报、考勤统计、成绩评定,能直接跑起来,也适合拿来二次开发。这篇内容我不打算贴一堆官方文档,而是把整个系统的设计逻辑、核心模块的实现思路、数据库表怎么建、前后端怎么联调、部署时最容易翻车的几个点全部拆开讲一遍。无论你是打算拿这套系统做课程设计、企业内部工具,还是想学一下前后端分离项目的完整结构,后面的内容都值得认真看一遍。

1. 项目全景:一个实习管理系统到底解决了什么问题

1.1 核心需求拆解

实习生管理在很多企业里是一个“看似简单,实际人人头疼”的事情。实习生来了一波又一波,信息登记靠Excel,日报周报靠邮箱,考勤靠微信群里手动签到,最后实习结束要给个评价,又要去翻聊天记录。这套系统的出现就是把这些散落的信息收拢到一个平台上,让实习生、指导老师、企业管理员三方都在一个页面里完成自己的工作。

从角色上看,系统至少要拆成三类用户:实习生本人、指导老师(或者部门主管)、系统管理员。实习生要能维护个人资料、查看实习单位信息、打卡签到、提交日报周报、查看自己的得分;指导老师要能看到名下带的学生、审核日报周报、登记考勤异常、录入评语和分数;管理员则是综合管理,包括创建用户、分配角色、维护单位信息、查看统计报表。

从业务流程上看,实习生进入企业之后,管理员先开通账号,分配实习单位和指导老师。实习生每天登录系统签到,定期提交日报或者周报,指导老师对这些内容进行审核。实习期结束,指导老师和单位负责人打分,系统汇总成最终成绩。这个过程如果全靠线下,任何一个环节断掉都会出问题,而信息化的核心就是把流程中的每一步变成可跟踪的数据记录。

1.2 技术选型的逻辑:为什么是SpringBoot + Vue + MySQL

很多人一上来会问,为什么用SpringBoot而不是SSH或者Servlet + JSP,为什么用Vue而不是JQuery + Bootstrap。这个问题其实得结合项目交付和后续维护来看。

SpringBoot最大的优势是“配置简化 + 生态成熟”。实习生管理系统属于典型的管理信息系统,涉及用户登录、权限控制、CRUD、文件上传、报表统计,这些在Spring生态里都有非常成熟的解决方案。用SpringBoot可以迅速把项目骨架搭起来,内嵌Tomcat,打成jar包就能跑,部署成本极低。相比传统的SSH那一套,省掉了大量XML配置,对新手更友好,对老手来说写代码也更清爽。

Vue在前端的价值体现在组件化和数据驱动的页面更新。管理后台这种界面,左边菜单、顶部栏、中间内容区,加上一堆表格和表单,用Vue写起来比JQuery直接操作DOM要舒服太多。尤其是表格数据要和后端接口联动,Vue的响应式机制能自动刷新视图,不需要手动拼接HTML字符串。再加上Element UI这类组件库,表格、弹窗、表单验证开箱即用,界面能在一两天内搭出专业感。

MySQL在这个场景下完全是性价比最高的选择。实习生管理系统的数据量不大,事务要求也不高,MySQL的单机性能足够支撑几千用户的规模。而且MySQL的生态工具链非常完整,Navicat、DBeaver、mysqldump,备份、迁移、调试都方便。用PostgreSQL当然也可以,但项目要“可直接运行”,MySQL的普适性明显更强。

2. 系统设计:从数据库到接口,把业务理清楚

2.1 数据库设计:核心表结构解析

一个信息管理系统的地基在数据库。如果表建得稀烂,后面写代码全是补丁。这套系统的库名建议直接用intern_manage,字符集用utf8mb4,排序规则用utf8mb4_general_ci,因为要存中文,也可能会存表情符号,utf8mb4是最稳的。

核心表离不开这么几张:用户表、实习生信息表、实习单位表、日报/周报表、考勤表、成绩评定表。下面逐个说:

用户表sys_user是所有登录账号的根基,字段包括用户ID、用户名、密码、真实姓名、角色类型、手机号、邮箱、状态、创建时间。密码必须存加密后的密文,千万不要明文存。角色类型可以用一个字符串字段区分STUDENT、TEACHER、ADMIN,也可以用角色关联表,但小项目里直接一个字段最省事。

实习生信息表intern_info和用户表是一对一的关系,额外记录学号、学校、专业、实习单位ID、指导老师ID、实习开始日期、实习结束日期、实习状态。学校和专业用普通字符串就行,不需要单独建字典表,除非你的字典项特别多。

实习单位表company_info记录单位名称、统一社会信用代码、单位地址、联系人、联系电话、单位性质。这个表可以被实习生表和成绩评定表引用。

日报/周报表intern_report是业务流水表,字段包括ID、实习生用户ID、报告类型(日/周)、报告日期、所属周、工作内容、问题与收获、指导老师评语、审核状态、提交时间、审核时间。审核状态用数字0/1/2表示待审核、已通过、已驳回,比用字符串更有效率。

考勤表attendance_record字段包括ID、实习生用户ID、签到日期、签到时间、签到状态、备注。每天一人一条记录,当天重复签到就做更新而不是插入新记录。

成绩评定表score_assessment字段包括ID、实习生用户ID、单位评分、导师评分、自评分、综合得分、评价内容、评定时间。综合得分可以前端算,也可以后端算,建议后端算,保持逻辑统一。

这里有一个容易忽略的点:所有业务表都要带上create_time和update_time,哪怕你觉得没必要。后面排查数据问题、写统计SQL的时候,时间字段会让你省掉一大半麻烦。

2.2 后端工程结构与接口分层

后端包结构建议按模块分,不要一个包下面堆一百个类。我建议这样拆:

com.example.intern ├── common │ ├── Result.java │ ├── ResultCode.java │ └── GlobalExceptionHandler.java ├── config │ ├── CorsConfig.java │ └── WebMvcConfig.java ├── controller │ ├── AuthController.java │ ├── InternController.java │ ├── ReportController.java │ ├── AttendanceController.java │ └── ScoreController.java ├── service │ ├── AuthService.java │ ├── InternService.java │ ├── ReportService.java │ └── ScoreService.java ├── mapper │ ├── UserMapper.java │ ├── InternMapper.java │ ├── ReportMapper.java │ └── ... ├── entity │ ├── SysUser.java │ ├── InternInfo.java │ └── ... └── utils └── JwtUtils.java

Controller层只做参数接收和结果返回,Service层写业务逻辑,Mapper层通过MyBatis操作数据库。这样分层的好处是,如果前端字段变了,你只需改Controller;如果业务规则变了,你只需改Service;如果数据库表改了,你只需改Mapper。

统一返回结果类是前后端联调的基础。每个接口返回的JSON结构要一致,比如:

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.code = 200; result.message = "操作成功"; result.data = data; return result; } public static <T> Result<T> error(Integer code, String message) { Result<T> result = new Result<>(); result.code = code; result.message = message; return result; } }

前端只要判断code === 200就取data,其余情况弹message。这个约定看上去简单,但能省掉大量因返回结构不一致导致的联调时间。

全局异常处理也很重要。写代码的时候难免出现空指针、参数不合法,如果不做兜底,系统会直接返回Tomcat默认错误页,前端根本没法解析。用@RestControllerAdvice拦截所有异常,统一返回Result.error(500, e.getMessage()),这样后端崩了前端也能看到一条明确提示,而不是白白刷新页面。

2.3 前端页面与交互逻辑

Vue前端工程目录按页面模块划分,整个后台采用经典布局:左侧菜单、顶部栏、中间内容区。路由表用动态渲染,根据用户角色过滤可见菜单。

src ├── api │ ├── auth.js │ ├── intern.js │ ├── report.js │ └── score.js ├── router │ └── index.js ├── store │ └── user.js ├── views │ ├── login.vue │ ├── layout.vue │ ├── intern/info.vue │ ├── report/list.vue │ ├── attendance/calender.vue │ └── score/table.vue └── utils └── request.js

axios请求封装建议统一放在request.js,设置基础URL、超时时间、拦截器。请求拦截器里带上token,响应拦截器里统一处理401跳转登录和错误提示。

import axios from 'axios' const request = axios.create({ baseURL: '/api', timeout: 10000 }) 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) { ElMessage.error(res.message) return Promise.reject(new Error(res.message)) } return res.data }, error => { if (error.response && error.response.status === 401) { localStorage.clear() window.location.href = '/login' } else { ElMessage.error('网络异常,请稍后重试') } return Promise.reject(error) } ) export default request

这个封装几乎是所有Vue后台管理项目的通用模板,拿来直接用就行。注意baseURL要配合开发环境的代理,否则会出现跨域。

3. 核心功能实现:几个关键模块的实战拆解

3.1 权限控制:如何做到不同角色各看各的

权限控制是信息系统绕不开的环节。这套系统最简单可靠的方案是“登录认证 + 角色拦截”。

后端使用JWT做登录认证。用户登录成功后,根据用户名查询用户信息,把用户ID和角色塞进token,设置有效期,返回给前端。前端把token存在localStorage里,每次请求在请求头带上。后端通过一个拦截器验证token,解析出用户信息后存入ThreadLocal,后面的Controller和Service直接从ThreadLocal取当前用户,不用每个接口都传用户ID。

JWT工具类的核心代码大致是这样:

public class JwtUtils { private static final String SECRET = "your-secret-key-change-me"; private static final long EXPIRE = 7 * 24 * 60 * 60 * 1000L; public static String createToken(String userId, String role) { return Jwts.builder() .claim("userId", userId) .claim("role", role) .setExpiration(new Date(System.currentTimeMillis() + EXPIRE)) .signWith(SignatureAlgorithm.HS256, SECRET) .compact(); } public static Claims parseToken(String token) { return Jwts.parser() .setSigningKey(SECRET) .parseClaimsJws(token) .getBody(); } }

拦截器里对不需要认证的接口(比如登录接口、验证码接口)放行,其余接口全部校验。校验通过后,可以根据角色再做接口级控制:比如管理员可以调用GET /api/intern/list查看所有实习生,而实习生只能拿到自己的数据。最简单的做法是在Service层加一个判断:

if ("STUDENT".equals(userRole)) { query.setInternUserId(currentUserId); }

前端页面同样要做角色控制。路由表里给每个路由配置meta.roles,比如:

{ path: '/score', component: Layout, meta: { roles: ['ADMIN', 'TEACHER'] }, children: [ { path: 'list', component: ScoreList, meta: { roles: ['ADMIN', 'TEACHER'] } } ] }

在路由守卫里读取当前用户的角色,如果不在可访问列表里,就重定向到首页。不要只靠前端隐藏菜单,后端必须做校验,否则别人直接调接口就能越权。

3.2 实习过程管理:从签到到日报的流转

实习过程管理是整个系统的业务核心。实习生每天登录系统后的第一件事就是签到。签到接口的逻辑是:先判断当前用户是否是实习生角色,再查今天是否已经签到。如果已签到,直接返回“今日已签到”;如果没签到,插入一条记录。

为了避免重复插入,数据库层面可以给attendance_record表加一个唯一索引uk_intern_date(intern_user_id, sign_date),这样即使并发请求,数据库也会拒绝重复记录,而不是让代码去判断。这个做法看起来简单,但很多新手会忽略,导致并发情况下数据有两条。

日报提交的逻辑类似。实习生填写工作内容、遇到问题、明日计划,提交后状态是“待审核”。指导老师打开审核列表,看到自己名下的实习生提交的报告,可以点击通过或者驳回,驳回时必须填写原因,实习生端会看到驳回原因并重新编辑提交。这里的状态流转可以用数字字段控制:0待审核 1已通过 2已驳回。

写一个提交日报的接口示例:

@PostMapping("/report/submit") public Result<Void> submitReport(@RequestBody ReportSubmitDTO dto) { SysUser currentUser = UserContext.getCurrentUser(); if (!"STUDENT".equals(currentUser.getRole())) { return Result.error(403, "只有实习生可以提交报告"); } Report report = new Report(); report.setInternUserId(currentUser.getId()); report.setReportType(dto.getReportType()); report.setReportDate(dto.getReportDate()); report.setContent(dto.getContent()); report.setStatus(0); reportService.save(report); return Result.success(null); }

实际代码里还要校验报告日期是否在实习期内、同一日期的报告是否重复提交等细节。这些校验逻辑一旦漏掉,就会在真实使用中冒出一堆脏数据。

3.3 成绩评定与统计报表

成绩评定涉及三个维度:实习生自评、指导老师评分、实习单位评分。每个维度满分100分,最后综合得分按权重计算:自评20%,导师评价50%,单位评价30%。权重可以在系统参数表里配置,也可以写死在代码里,为了演示方便先写死,但设计时最好留一个配置项。

后端在计算综合得分时,先查出三个分数,然后加权:

double finalScore = selfScore * 0.2 + teacherScore * 0.5 + companyScore * 0.3;

成绩表和实习考核表可以通过实习记录ID关联,不过更简单的方式是直接挂在实习生ID下,一个实习生只有一个最终成绩。

统计报表部分需要写SQL做分组聚合。比如查询每个实习单位的平均分:

SELECT c.company_name, ROUND(AVG(s.final_score), 2) AS avg_score FROM score_assessment s LEFT JOIN intern_info i ON s.intern_user_id = i.user_id LEFT JOIN company_info c ON i.company_id = c.id GROUP BY c.company_name ORDER BY avg_score DESC;

后端用MyBatis写一个对应的Mapper方法,返回一个Map列表,前端用ECharts展示柱状图或者饼图。这里要注意SQL中的LEFT JOIN一定不能在连接条件上放多余过滤条件,比如想过滤实习生状态,要写在WHERE中,否则会丢数据。

4. 环境准备与直接运行:让人少踩坑的部署全过程

标题里写了“可直接运行”,这背后其实藏着不少环境坑。下面按我实测的流程走一遍。

4.1 基础环境要求

后端部分需要JDK 1.8及以上,推荐1.8,因为SpringBoot 2.x在1.8下最稳定,不会出现新版本特性带来的兼容问题。Maven 3.6+,用来拉取依赖。前端部分需要Node.js 14+,npm 6+,如果你装的是Node 18,也没关系,但是很多旧依赖的版本会冲突,所以建议用Node 14.21.3这种稳定版本。数据库用MySQL 5.7或8.0,5.7在老设备上兼容性更好,8.0功能更新但需要对应驱动版本,如果项目里mysql-connector-java是5.x,连8.0会报错,所以最好按源码的配置走。

4.2 初始化数据库

拿到源码后,在源码目录下找到一个类似sql/intern_manage.sql的文件。用Navicat或者命令行创建数据库并导入:

mysql -u root -p -e "CREATE DATABASE intern_manage DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;" mysql -u root -p intern_manage < sql/intern_manage.sql

导入成功后,打开后端的application.yml,修改数据库连接信息:

spring: datasource: url: jdbc:mysql://localhost:3306/intern_manage?useUnicode=true&characterEncoding=utf8mb4&serverTimezone=Asia/Shanghai username: root password: yourpassword driver-class-name: com.mysql.cj.jdbc.Driver

这里最需要注意的是URL里的serverTimezone=Asia/Shanghai。没有这个参数,Java连接MySQL 8.0会报时区异常,页面上的时间也会差8小时。

4.3 启动后端服务

在项目根目录下打开终端,先执行:

mvn clean install -DskipTests

然后启动:

mvn spring-boot:run

如果没有报错,日志里会看到Tomcat started on port(s): 8080。如果你想打包部署,执行mvn clean package -DskipTests,然后:

java -jar target/intern-management-1.0.0.jar

提醒一句:检测端口是否被占用时,注意有些机器的8080端口被其他服务占着。可以用netstat -ano | findstr 8080查看,如果占用就改配置。

4.4 启动前端工程

前端目录一般是frontend或vue-web。进入目录后:

npm install npm run serve

第一次npm install会很慢,因为要拉几十个依赖包。如果遇到网络问题,可以使用国内镜像源:

npm config set registry https://registry.npmmirror.com

安装成功后,运行npm run serve,默认端口是8080,但后端已经占用了8080,Vue的脚手架会检测到端口冲突,自动改用8081。所以前端访问地址通常是http://localhost:8081。

开发环境下跨域需要在根目录创建vue.config.js:

module.exports = { devServer: { port: 8081, proxy: { '/api': { target: 'http://localhost:8080', changeOrigin: true, pathRewrite: { '^/api': '' } } } } }

这个配置的含义是:前端把请求发给/api开头的地址,开发服务器转发到后端的8080,并且把路径中的/api前缀去掉。如果你的后端接口本身就带/api前缀,就不用pathRewrite。这个细节很容易搞错,一旦配置错,接口会404。

4.5 验证系统可访问

打开浏览器,输入http://localhost:8081,正常情况会跳到登录页。源码里一般预置了三个账号:admin/admin123、teacher/123456、student/123456。先用admin登录,左侧菜单应该能看到全部功能模块。点击“实习生管理”,可以新增一条实习生数据,然后给该实习生关联一个账号;切换到实习生账号登录,能看到自己的信息、签到功能和日报提交流程。如果这几个流程走通,说明系统运行正常。

5. 实际运行中常见问题与排查经验

5.1 数据库连接失败的 5 种可能

后端启动或者登录时报数据库连接错误,基本逃不出下面几种情况:

现象原因解决方式
Access denied for user用户名或密码不对检查application.yml中的账号密码和数据库实际密码是否一致
Unknown database 'intern_manage'数据库没有创建或名字写错执行CREATE DATABASE后重新导入SQL
The server time zone value ...缺少时区参数URL加上serverTimezone=Asia/Shanghai
Public Key Retrieval is not allowedMySQL 8.0的认证插件导致URL加上allowPublicKeyRetrieval=true
Communications link failure数据库服务没启动或端口不对检查MySQL服务是否运行、端口是3306还是其他

每一条都是真实踩出来的。尤其是allowPublicKeyRetrieval这个参数,MySQL 8.0默认情况下连接会直接被拒绝,很多人查半天查不到原因。

5.2 跨域问题的定位与处理

前端的请求发出去了,但浏览器控制台报No 'Access-Control-Allow-Origin' header is present,这就是跨域问题。

解决跨域有两个办法。开发环境优先使用Vue的proxy代理,前面已经写了配置。生产环境如果前端和后端不在一起,需要后端开启CORS:

@Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOriginPatterns("*") .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") .allowedHeaders("*") .maxAge(3600); } }

还有一个容易忽略的点:使用了JWT后,前端请求头带了Authorization,那allowedHeaders("*")必须写,否则浏览器会以预检请求的形式拦掉带自定义头的请求。

5.3 前端页面空白或接口404

页面空白大概率是路由问题。如果你用的是history模式,并且部署到Nginx,没有配置try_files,刷新页面就会404。开发环境很少遇到,但打包部署后很常见。Nginx配置需要加:

location / { try_files $uri $uri/ /index.html; }

如果是接口404,先看请求路径。开发环境下,前端proxy代理的target写错,或者pathRewrite把不该去掉的前缀去掉了,都会导致后端找不到接口。最简单的排查方式:打开前端控制台,看Network里的请求URL,复制出来在浏览器直接访问,看返回什么。

5.4 端口冲突与配置修改

后端端口、前端端口、数据库端口都可能撞车。最常见的场景:启动了两个无关的Java服务,8080被占用,导致SpringBoot启动失败。这时候别急着改端口,先查占用。

如果确实需要修改后端端口,在application.yml里写:

server: port: 8082

同时前端proxy的target也要改成http://localhost:8082。前端端口则通过vue.config.js的devServer.port修改。记住一个原则:端口改动一定要同时检查后端配置、前端代理、以及页面里的接口地址,漏一个就废。

6. 项目扩展方向:从可用到好用的升级建议

6.1 增加消息通知与定时任务

现在的系统都是用户主动刷新才能看到新数据。比如指导老师审核了日报,实习生要自己点进详情页才能看到结果。更好的做法是加入站内消息通知:审核状态一变,实习生登录后首页就有未读消息。

后端可以用Spring自带的Scheduled定时任务,也可以引入消息队列,但小系统没必要上重量级框架。用一个消息表记录通知,前端每隔30秒拉一次未读数量,这个方案足够简单可靠。定时任务还有一个典型用途:每天晚上自动把当天未签到的实习生生成提醒列表,第二天早上推送给指导老师。

6.2 引入Excel导入导出

管理员经常需要批量导入实习生名单,而不是一个个在网页上添加。用Apache POI或者阿里开源的EasyExcel都能实现。EasyExcel性能更好,API也清爽得多。导入时先解析Excel,逐行校验必填项、学号重复、用户是否已存在,最后批量插入。导出功能则可以把实习名单、成绩表一键生成Excel文件下载,这个功能在真实企业场景里几乎天天用到。

6.3 部署方式升级

现在直接在服务器上java -jar和npm run build拷贝静态文件,已经能应付大部分需求。但如果换机器或者多环境部署,环境差异会带来麻烦。建议用Docker Compose把MySQL、后端、前端全部编排起来:

version: '3' services: mysql: image: mysql:5.7 container_name: intern-mysql environment: MYSQL_ROOT_PASSWORD: root123 MYSQL_DATABASE: intern_manage ports: - "3306:3306" volumes: - ./sql:/docker-entrypoint-initdb.d backend: build: ./backend container_name: intern-backend ports: - "8080:8080" depends_on: - mysql frontend: build: ./frontend container_name: intern-frontend ports: - "80:80" depends_on: - backend

这样在一台新服务器上只需一条docker-compose up -d就能全部跑起来,初始化SQL也会在MySQL容器首次启动时自动执行。

6.4 安全增强与日志监控

这套系统已经有JWT认证,但距离生产标准还差几步。密码如果存的是明文,赶紧改成BCrypt加密;接口层要加上参数校验注解,比如@NotNull、@Size;对于频繁调用的登录接口、接口日志输出,建议引入Logback的按天滚动日志,并且把登录失败记录、异常堆栈单独输出到文件。线上环境还要加一个健康检查接口,配合运维监控系统定时探测,系统挂了第一时间告警。

我在实际维护这类系统时最大的体会是:功能开发只占一半精力,另一半全在环境配置、边界条件校验和数据一致性上。比如日报同日重复提交、成绩权重变更、用户被删除后历史数据保留,这些细节看起来不起眼,却决定了系统能不能从演示Demo走向真正长期使用。把这套源码跑起来只是第一步,后续的每一次需求变更都会逼着你把设计想得更完整。如果你准备在这个基础上做二次开发,建议先在数据库层把所有外键关系梳理清楚,再动手改代码,会少走很多弯路。

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

时变电磁场如何自激形成电磁波?从麦克斯韦到Wi-Fi的物理直觉

1. 项目概述&#xff1a;为什么“电磁场与电磁波”需要被重新讲清楚&#xff1f;“电磁场与电磁波”这门课&#xff0c;在很多人的学习记忆里&#xff0c;是本科电类专业一道绕不过去的坎——公式密布、矢量繁杂、物理图像模糊、数学工具陡峭。我带过几届某高校通信工程方向的本…

作者头像 李华
网站建设 2026/10/15 7:05:05

LinkedList源码拆解:双向链表如何优雅实现栈、队列与双端操作

在Java日常开发里&#xff0c;提到List大家第一反应基本都是ArrayList&#xff0c;数组加下标的随机访问实在太顺滑。但有一个类平时不怎么起眼&#xff0c;一旦遇到频繁头尾增删、需要双端操作、或者想顺手搭一个栈和队列&#xff0c;它才是真正的主角——这就是LinkedList。这…

作者头像 李华
网站建设 2026/10/15 7:05:00

EDR数据读取与事故重建:从OBD诊断到碰撞曲线解析

简介&#xff1a;围绕汽车事件数据记录系统&#xff08;EDR&#xff09;&#xff0c;这份PDF文档对GB 39732《汽车事件记录系统》国家标准进行系统拆解&#xff0c;面向汽车安全工程师、测试人员及相关法规研究人员&#xff0c;帮助厘清标准执行难点。解读覆盖目的意义、国内外…

作者头像 李华
网站建设 2026/10/15 7:04:56

C++代码重构实战:从上帝类到智能指针与依赖注入

接盘一个维护了三年多的C服务端模块时&#xff0c;我的第一反应和大多数人一样&#xff1a;先把能跑的部分看明白&#xff0c;再把明显不合理的地方一点点改掉。那段时间我第一次认真体会到&#xff0c;所谓“C代码重构”不是一个“收拾屋子”的动作&#xff0c;而是一整套以行…

作者头像 李华
网站建设 2026/10/15 7:04:54

TensorFlow实战:从零搭建可复现的图像分类训练流水线

深度学习框架实战&#xff1a;从零搭建一个可复现的图像分类训练流水线搞深度学习这行的&#xff0c;几乎没人绕得开TensorFlow这个框架。不管你是刚入门的新手&#xff0c;还是已经带过几个模型上线跑推理的老手&#xff0c;手里总会有那么一两个项目是用它写的。但说实话&…

作者头像 李华