ARTICLE DETAIL

资讯详情

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

基于Spring Boot+Vue的数码产品对比平台:全栈开发与数据建模实战

基于Spring Boot+Vue的数码产品对比平台:全栈开发与数据建模实战 二手手机怎么选才不会踩坑笔记本标压和低压处理器到底差多少这些问题的答案本质上都指向同一个东西可靠的参数数据与直观的横向对比。我最近用 Java、Spring Boot 和 Vue 落地了一个数码产品对比平台正好把全栈开发里那些绕不开的坑和决策过程都走了一遍。这篇文章就从项目拆解、数据建模、核心接口设计到前端动态渲染把整个平台的实现思路完整梳理一遍附带实测数据和排错记录给正在做类似课程设计、毕业设计或者想练手全栈项目的同学一份能直接参考的实操手册。我自己在做这个项目之前一直觉得“对比平台”不就是两张表格放一起吗真正动手才发现数码产品的参数有一个非常棘手的特点异构性。手机有电池容量、相机像素笔记本有显卡功耗、屏幕刷新率电视有HDMI接口版本、色域覆盖率。如果把所有参数都塞进一张固定字段的数据库表要么列多到失控要么每种产品类型都要单独建表。对比平台的核心难点根本不在前端展示而是在数据模型和对比逻辑上。1. 项目整体设计与思路拆解1.1 核心需求解析一个数码产品对比平台用户最关心的动作无非三个选产品、看参数、做判断。往细了拆平台至少要完成这些事产品库管理支持手机、笔记本、平板、耳机、相机、显示器等多品类产品的录入与维护参数规格管理不同品类拥有不同的参数集合且参数项需要动态扩展多维筛选按价格区间、品牌、品类、核心配置如芯片、内存、屏幕尺寸快速圈定候选产品对比功能支持2到4款产品的参数并排展示差异化高亮必要时生成雷达图等可视化图表评价辅助聚合基础的用户评分与关键口碑标签辅助用户做决策这套需求放在一起技术选型并不难定后端用 Java Spring Boot前端用 Vue数据库用 MySQLORM 用 MyBatis-Plus。这套组合在中小型系统里几乎是“标准答案”生态成熟、资料多、招人容易更重要的是踩坑成本低。但这套组合里真正的设计重点不在“用没用对框架”而在两条主线上参数怎么存以及对比结果怎么算。这两条主线决定了数据模型长什么样、接口怎么设计、前端表格怎么渲染。1.2 技术选型背后的考量为什么用 Spring Boot 而不是 SSM 或者别的说实话SSM 的配置繁琐程度做过的人都懂大量 XML 配置、包扫描、事务声明挤在一起项目还没写几行业务逻辑先被配置折腾半天。Spring Boot 的自动配置和约定优于配置风格能把开发重心拉回业务本身。这一点在校招面试里也是高频考点——八股文背得再熟都不如自己在一个真实项目里体会过自动配置、starter 机制、条件装配这些概念来得扎实。Vue 这边我用的是 Vue 2 Element UI。虽然 Vue 3 已经普及但考虑到不少学校的课程设计和存量项目还是 Vue 2 生态加上 Element UI 的表格组件对动态列渲染支持比较成熟二选一我选了稳妥方案。如果你现在从零开始学直接上 Vue 3 Element Plus 也没问题核心思路完全一致。数据库为什么选 MySQL因为数据量级摆在那里个人项目或者中小型对比平台一天撑死几十万次查询MySQL 配上合适的索引和缓存完全够用没必要为了“高大上”引入分布式数据库增加部署复杂度。Redis 倒是必须的后面聊接口性能时会细说热门产品参数、筛选结果的缓存命中率直接关系到接口响应时间。1.3 功能模块划分整个平台按业务边界拆成六个模块用户模块注册、登录、JWT 鉴权、个人信息维护产品模块产品基本信息 CRUD、图片管理、上下架状态参数模块品类参数模板定义、产品参数录入与校验筛选模块多维条件组合筛选、排序、分页对比模块对比列表维护、参数对比计算、差异标记评价模块评分录入、标签聚合、评论列表六个模块里参数模块和对比模块是重头戏产品模块和筛选模块相对常规但产品模块里的数据冗余设计会直接影响筛选性能。后面一个个说。2. 核心细节解析与实操要点2.1 数码产品参数建模的方案取舍这是整个项目里最值得展开讲的部分。数码产品的参数天然异构一台手机和一台上网本完全重合的参数可能只有品牌、价格、重量、发布时间这几个。如果按照传统关系型思维做表结构有两条路第一条路一张产品表字段铺开。分 8G 内存、128G 存储、5000 毫安电池、后置一亿像素这种设计对手机没问题但加一个品类比如智能手表就得改表加字段改一次迁移一次维护成本爆炸。第二条路每个品类一张参数表。手机表、笔记本表、相机表各建各的查询是方便了但跨品类对比比如手机和手表比续航就成了灾难关联查询复杂到怀疑人生。两条路都不合适。最终我采用了「产品主表 品类模板表 通用参数字典」的组合方案产品主表存所有品类共有的信息产品名称、品牌、品类、价格、图片、发布日期、上下架状态等品类模板表定义每个品类有哪些参数项手机有“电池容量”“屏幕尺寸”“处理器”笔记本还要多出“显卡”“散热规格”产品参数表以 EAV 模型实体-属性-值存储每条记录就是一个产品的某个参数项的值EAV 模型在面试里经常被问“有什么缺点”批评者会说它查询慢、没法用数据库约束数据类型、JOIN 多。这些批评都对但在这个场景下它有一个不可替代的优势新品类上线时只需要在模板表里配一套参数不用动表结构。而“查询慢”的问题在实践中可以通过合理缓存和批量查询很好地缓解。最终表结构大概是这个样子核心字段简化版CREATE TABLE product ( id bigint(20) NOT NULL AUTO_INCREMENT, name varchar(128) NOT NULL COMMENT 产品名称, brand varchar(64) DEFAULT NULL COMMENT 品牌, category_id bigint(20) NOT NULL COMMENT 品类ID, price decimal(10,2) DEFAULT NULL COMMENT 参考价, cover_image varchar(255) DEFAULT NULL COMMENT 封面图, description text COMMENT 产品卖点描述, status tinyint(4) DEFAULT 1 COMMENT 1上架 0下架, release_date date DEFAULT NULL COMMENT 发布日期, create_time datetime DEFAULT CURRENT_TIMESTAMP, update_time datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_category_price (category_id, price) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT产品主表;CREATE TABLE category_param_template ( id bigint(20) NOT NULL AUTO_INCREMENT, category_id bigint(20) NOT NULL COMMENT 品类ID, param_key varchar(64) NOT NULL COMMENT 参数键如 battery_capacity, param_name varchar(64) NOT NULL COMMENT 参数显示名如电池容量, unit varchar(16) DEFAULT NULL COMMENT 单位如mAh, sort_order int(11) DEFAULT 0 COMMENT 展示顺序, is_core tinyint(4) DEFAULT 0 COMMENT 是否核心对比参数, PRIMARY KEY (id), UNIQUE KEY uk_category_param (category_id, param_key) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT品类参数模板;CREATE TABLE product_param_value ( id bigint(20) NOT NULL AUTO_INCREMENT, product_id bigint(20) NOT NULL COMMENT 产品ID, param_key varchar(64) NOT NULL COMMENT 参数键, param_value varchar(255) DEFAULT NULL COMMENT 参数值统一存字符串, sort_order int(11) DEFAULT 0 COMMENT 排序, PRIMARY KEY (id), KEY idx_product (product_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT产品参数值表;这里说一个关键取舍param_value 为什么统一存字符串而不是按参数类型分开存数值列、字符串列统一存字符串意味着后端拿到“5000mAh”时要做一次类型识别和单位归一化但从对比功能的实现角度模板表里增加一个value_type字段标记“数值型/字符串型/枚举型”就能在代码里按类型分别处理数值比较和文本匹配。这样设计的好处是产品参数录入接口可以写得很统一对比引擎也能基于模板元数据做差异化判断。坏处也很明显聚合查询比如“筛选电池容量大于4500mAh的手机”需要先做类型转换所以这种高并发筛选需求我在设计上直接绕开放到筛选模块用主表冗余字段解决后面会讲。2.2 对比计算的逻辑实现对比引擎的核心是“按模板对齐参数”。不同产品的参数项顺序可能不一致比如 A 产品的第 3 条参数是“屏幕刷新率”B 产品的第 5 条才是刷新率。对比模块要做的事情是把两个产品的参数按模板表里的param_key对齐到同一行然后逐个单元格比较。对齐之后是差异识别。差异识别规则我分两类数值型参数相差超过阈值就高亮阈值在模板表里配了diff_threshold比如电池容量相差 500mAh 以上标红文本型参数不等于就高亮比如处理器型号不同直接标记差异这里有个实践中的小坑单位不一致导致误判。比如 A 产品屏幕尺寸写“6.7英寸”B 产品写“17.02厘米”数值比较前必须做单位归一化否则明明一样的尺寸会被标成差异。我在模板表里给每个参数配了unit_convertible标记和标准单位值入库前先做一次转换。这个细节直接影响用户体验对比结果里全是错误差异标注用户分分钟弃用。差异标记的结果需要同时返回到前端高亮展示。接口返回结构上我设计成按“行”组织{ code: 0, data: { products: [ {id: 1, name: 某品牌手机Pro}, {id: 2, name: 某品牌手机标准版} ], rows: [ { paramKey: battery_capacity, paramName: 电池容量, unit: mAh, isDiff: true, values: [ {value: 5000, remark: 优势项}, {value: 4500, remark: } ] } ], summary: { totalDiff: 13, advantageCount: 3 } } }这个结构对前端非常友好直接v-for遍历 rows 就能生成对比表格isDiff控制是否高亮values按产品顺序排列和顶部产品列表一一对应。2.3 筛选模块的数据冗余策略前面 EAV 模型割了“按参数聚合查询”一刀筛选模块就得用另一套方案补回来。我的做法是在产品主表上冗余 4 个高频筛选字段价格、品牌、品类、发布日期。用户筛“5000元以下、某品牌、手机”时直接走主表的联合索引一次查询搞定。如果需要按“电池容量大于4500mAh”这种参数筛选就走 EAV 表先查出符合条件的 product_id 集合再回表查主表。实测下来EAV 查询“参数筛选分页”在几千条产品数据时性能完全可接受单次查询 200ms 以内。数据量到十万级以上时建议引入 Elasticsearch 或把高频参数冗余成 JSON 字段。个人项目不用提前上搜索引擎容易过度设计。关于 JSON 字段方案我可以多说一句。如果你不想用 EAV 三张表其实还有个中间方案产品表加一个param_json字段用 MySQL 的 JSON 类型存储该产品的所有参数。查询用 JSON_EXTRACT 函数能力弱于 EAV但胜在实现快。我用 EAV 的原因主要是课程设计需要体现“可扩展性”答辩时这是一个加分点。2.4 接口设计上的实践后端接口我按 RESTful 风格组织核心接口如下GET /api/product/{id}产品详情含完整参数GET /api/product/list产品列表支持关键字、品类、品牌、价格区间筛选与分页POST /api/product/compare对比接口入参是产品 ID 列表2到4个返回对齐后的对比数据GET /api/category/template/{categoryId}获取品类参数模板用于详情页渲染和对比页表头生成POST /api/product/param参数录入/更新POST /api/auth/register、POST /api/auth/login用户认证对比接口为什么用 POST 而不是 GET因为对比列表可能很长产品 ID 列表塞在 URL 里既丑又有长度限制POST body 传 JSON 干净得多。为了兼容浏览器缓存场景也可以支持GET /api/product/compare?ids1,2,3两个都留内部共用一个 service 方法。接口性能方面我主要做了三件事第一产品参数查询批量处理。避免 N1 问题产品列表查询后批量收集 product_id一次性查出所有参数再按产品分组内存里完成聚组。产品有 50 个参数查询就 2 次 SQL而不是 51 次。第二Redis 缓存。产品详情和对比结果设置 30 分钟过期热门产品浏览排行前20设置 1 小时。筛选列表按“条件 hash”做缓存 key。测试环境中对比接口缓存命中率大约在 40% 左右平均响应从 180ms 降到 60ms 左右。第三页面静态化兜底。产品详情页是访问量最大的页面考虑到 SEO 和首屏渲染速度我在 Nginx 层做了产品详情页的静态化缓存首屏秒开。3. 实操过程与核心环节实现3.1 后端工程搭建与关键依赖Spring Boot 我选的 2.7.x对应 JDK 1.8。选 2.7 而不是 3.x 的原因很现实很多学校机房、企业存量环境还是 JDK 8Spring Boot 3 最低要求 JDK 17兼容成本高。个人学习的话也建议先用 2.7把核心链路跑通再说升级的事。pom.xml核心依赖dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-validation/artifactId /dependency dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version3.5.3.1/version /dependency dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId scoperuntime/scope /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-data-redis/artifactId /dependency dependency groupIdio.jsonwebtoken/groupId artifactIdjjwt/artifactId version0.9.1/version /dependency dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId /dependency这里有个细节MyBatis-Plus 的 ID 生成策略默认是雪花算法如果表结构里主键设的是 AUTO_INCREMENT需要配置一下application.yml关键配置spring: datasource: url: jdbc:mysql://localhost:3306/digital_compare?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver redis: host: localhost port: 6379 database: 0 jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT8 mybatis-plus: configuration: map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.stdout.StdOutImpl global-config: db-config: id-type: autoid-type: auto这行千万别漏否则你 insert 之后发现主键是雪花ID和数据库自增主键对不上。我早期没配这个调试了很久才发现问题。3.2 对比引擎 Service 实现思路对比核心逻辑在CompareService里流程分四步第一步校验入参。产品 ID 数量 2 到 4 个超出直接报参数异常。所有产品必须属于同一个品类跨品类对比信息量太大表格难以组织初版不做。这一步看起来不起眼但能挡住大量异常数据。第二步批量查产品与参数。productService.listByIds(ids)查出产品基本信息再收集所有 product_id 查询product_param_value按 productId 分组。第三步按品类模板对齐参数。查category_param_template拿到参数项列表和排序规则遍历模板项分别把每个产品的对应参数值填进去。这一步在内存里完成注意处理参数缺失的情况。第四步差异化比较与优势识别。对每个参数项按值类型做比较标记差异和优势。数值型参数比较前做单位归一化和类型转换。优势项的判定规则是“同品类参数下数值更大视为优势”比如电池容量、屏幕刷新率、充电功率是越大越好部分参数需要反向配置higher_better标记比如重量、厚度是越小越好。核心伪代码我简化一下public CompareResult compare(ListLong productIds) { // 1. 校验品类一致 ListProduct products productMapper.selectBatchIds(productIds); Assert.isTrue(products.size() 2 products.size() 4, 对比产品数量需在2到4之间); Long categoryId products.get(0).getCategoryId(); products.forEach(p - Assert.isTrue(categoryId.equals(p.getCategoryId()), 跨品类暂不支持对比)); // 2. 批量查参数 MapLong, ListProductParamValue paramMap loadParamsGroupByProduct(productIds); // 3. 模板对齐 ListCategoryParamTemplate templates templateMapper.selectByCategoryId(categoryId); // 4. 逐行比较 ListCompareRow rows new ArrayList(); for (CategoryParamTemplate tpl : templates) { CompareRow row new CompareRow(tpl.getParamKey(), tpl.getParamName(), tpl.getUnit()); ListCompareValue lineValues new ArrayList(); for (Product p : products) { String rawValue findValue(paramMap.get(p.getId()), tpl.getParamKey()); CompareValue cv new CompareValue(rawValue); // 按类型归一化比较时用 lineValues.add(cv); } // 标记差异 boolean isDiff calcDiff(lineValues, tpl); // 标记优势项 markAdvantage(lineValues, tpl); row.setDiff(isDiff); row.setValues(lineValues); rows.add(row); } return buildResult(products, rows); }对比结果算完之后还要顺手做一件事给每个产品生成一个“优势项数量”统计。这个数字在对比页头部展示用户扫一眼就知道哪个产品总体参数更靠前。这个统计不是简单参数总和所以模板表里的higher_better配置在这里是核心依据。3.3 前端页面架构与核心组件前端用 Vue 2 Vue Router Vuex Element UI ECharts构建工具用 Vue CLI。目录结构如下src/ api/ # 接口封装 assets/ # 静态资源 components/ product/ # 产品卡片、参数表格等 compare/ # 对比表格、雷达图组件 router/ # 路由配置 store/ # Vuex 状态管理 views/ Home.vue # 首页品类导航 推荐产品 ProductList.vue # 产品列表筛选 分页 ProductDetail.vue# 产品详情参数展示 Compare.vue # 对比页核心对比表格 Login.vue / Register.vue路由配置里对比页的设计值得说一下对比页通过 Vuex 维护一个compareList数组用户在产品卡片上点击“加入对比”产品 ID 就进到 Vuex顶栏的对比图标上会显示数量。点击对比图标进入/compare路由从 Vuex 取出 ID 列表调用对比接口。考虑刷新丢失问题我把compareList同步到sessionStorage刷新后重新拉取体验比较顺畅。对比页的核心组件是CompareTable.vue。它接收对比接口返回的数据动态渲染表格。用 Element UI 的el-table实现时最关键的一步是动态列配置computed: { columns() { const cols [{ prop: paramName, label: 参数, width: 140, fixed: true }]; this.compareData.products.forEach((p, index) { cols.push({ prop: value_${index}, label: p.name, width: 200 }); }); return cols; } }表格数据在渲染前要把接口返回的 rows 结构转换成el-table需要的行结构——每个参数项是一行列是“参数名 各产品值”。转换逻辑放compareService.js里function buildTableRows(data) { return data.rows.map(row { const item { paramName: row.paramName, unit: row.unit, isDiff: row.isDiff }; row.values.forEach((v, i) { item[value_${i}] v.value; item[remark_${i}] v.remark; item[isAdvantage_${i}] v.isAdvantage; }); return item; }); }渲染时针对差异单元格和优势项单元格做 class 绑定el-table-column v-forcol in columns :keycol.prop :propcol.prop :labelcol.label :widthcol.width :fixedcol.fixed template slot-scopescope span v-ifscope.row.isDiff col.prop.startsWith(value_) :class{ diff-highlight: scope.row.isDiff, advantage-highlight: scope.row[isAdvantage_${col.prop.split(_)[1]}] } {{ scope.row[col.prop] }} {{ scope.row.unit }} /span span v-else{{ scope.row[col.prop] }} {{ scope.row.unit }}/span /template /el-table-column这里踩过一个坑el-table-column默认会吃scope.row上所有字段的渲染如果动态列的值里没有做脱敏DOM 上会暴露多余字段。处理方式是在buildTableRows里只返回需要的字段别图省事把原始数据一整个塞进去。雷达图我用 ECharts 实现展示产品在核心参数上的对比。雷达图的心智负担比大表格低很多用户对“哪个产品更均衡”一眼就能判断。数据准备时需要注意单位差异——电池容量按 mAh价格按元CPU 跑分按分数直接拉进同一个雷达图没有意义。我的做法是每个参数做归一化取对比产品中的最大值作为 100%其余按比例映射。这个图在答辩演示时效果很好。3.4 参数录入与管理端实现管理端用同一套 Vue 技术栈单独一套路由和视图。参数模板管理的核心是一个“配置表”式的编辑页面每个品类维护一份参数模板支持新增参数项、设置展示顺序、标记是否核心参数、配置类型和单位。产品录入时选择品类后前端会请求GET /api/category/template/{categoryId}拿到的模板动态生成表单。这里用到了 Vue 的动态表单渲染核心是遍历模板数组生成表单项el-form-item v-fortpl in templateList :keytpl.paramKey :labeltpl.paramName el-input v-modelparamForm[tpl.paramKey] :placeholder请输入${tpl.paramName} / /el-form-item提交时统一拼成{paramKey: value}的 Map 传给后端后端 foreach 写入product_param_value。这个流程是 EAV 模型最舒服的部分无论品类模板怎么变录入接口不需要改一行代码。3.5 数据填充与系统效果实测平台跑起来之后我实际录入了 4 个品类、36 款产品。手机品类录了 12 款主流机型笔记本录了 10 款平板 8 款耳机 6 款。每个品类模板配置了 18 到 30 个参数项单产品平均录入耗时大约 3 分钟。参数数据主要来自官网公开规格少量通过垂直媒体补全。实测对比一次三类核心场景同品类 3 款手机对比接口响应 150ms 左右前端表格渲染 30ms 左右整体流畅筛选条件“5000元以下、某品牌、手机”响应 80ms对比结果缓存命中响应 60ms性能数据凑合能用但 36 款产品的量级说明不了太多问题。我额外用 JMeter 做了个简单压测100 线程×10 次循环对比接口无缓存时平均响应 112msQPS 约 820错误率 0%。这个数据对于课程设计级别的项目完全达标。4. 常见问题与排查技巧实录4.1 分组对比参数错位怎么排查开发中遇到最多的问题就是对比表格里参数行错位。A 产品第 7 行是“电池容量”B 产品第 8 行才是电池容量表格一拉就乱了。这个问题的根因通常是对比数据没有按模板对齐而是直接按“各产品参数列表顺序”拼接。解决方案只有一个对比行必须由品类模板驱动而不是由产品参数驱动。模板是“标尺”产品参数是“测量值”先定标尺再填数据天然对齐。另外如果某些产品缺失某个参数值一定要在渲染时保留空行不能直接跳过否则后续所有行都会错位。4.2 对比的产品参数总数对不上检查 JSON 转义还有一个隐蔽问题参数中包含引号或特殊符号时前端传参到后端 JSON 解析失败或者数据库存储乱码。排查时先看后端日志里是否报JSON parse error再看数据库字段是否有转义问题。统一解决方案数据库连接串加characterEncodingutf8接口层对所有入参做全面校验参数值写入前用 MyBatis-Plus 的TableField配合 String 类型存储天然不会出现二进制转义问题。4.3 动态表头固定列引发的样式问题el-table动态列渲染时固定左侧参数列会让横向滚动时参数列保持可见体验很好。但有个坑固定列和普通列的边框线可能对不齐不同列宽设置导致滚动时抖动。解决办法是在动态列渲染完成后调用this.$refs.compareTable.doLayout()。Element UI 的表格在动态渲染后需要手动触发布局重算这个 API 是官方提供的但很多教程不会提。我在初始化完成后延迟调用了一次this.$nextTick(() { if (this.$refs.compareTable) { this.$refs.compareTable.doLayout(); } });4.4 接口偶发超时的排查方向问题现象对比接口偶尔超过 2 秒但刷新后又能恢复。排查步骤先看是否 Redis 缓存击穿热点 key 失效瞬间大量请求同时打到数据库。解决加互斥锁重建缓存或者给热点数据用逻辑过期时间。再看数据库连接池是否不够Spring Boot 默认 HikariCP 最大连接数 10压测时超出就排队我把maximum-pool-size调到了 20问题缓解。4.5 前端大对象渲染卡顿的处理对比表格在同时展示 4 款产品、30 行参数时如果每个单元格绑定过多计算逻辑页面会明显卡顿。我用了两个手段优化一是计算属性缓存buildTableRows只在compareData变化时执行避免每次渲染都重新计算二是对参数值这类不会变化的静态数据用Object.freeze冻结让 Vue 跳过响应式劫持减少渲染开销。实测对比页在 4 产品×30 参数场景下FPS 从 30 提升到 55 以上。冻结操作要谨慎只冻结确实不需要响应式的数据否则后续更新会失效const rows buildTableRows(data); Object.freeze(rows); this.tableRows rows;4.6 部署后的跨域与会话问题前端开发服务器8080 端口调用后端8081 端口必然遇到跨域。开发环境我在 Vue CLI 里配置了 proxy// vue.config.js module.exports { devServer: { proxy: { /api: { target: http://localhost:8081, changeOrigin: true } } } };生产环境我直接用 Nginx 做反向代理前后端同域部署连 CORS 配置都省了。JWT 认证放在拦截器里放行注册登录接口其余接口校验 token。4.7 数据录入规范的重要性最后提醒一个很多人忽略的问题数据录入质量直接决定对比平台好不好用。如果录入时把“5000mAh”写成“5000 毫安”或者“6.7英寸”写“6.7 inch”对比引擎的单位归一化做得再好也无济于事。我在管理端做了一层约束参数模板里配置了可选项的参数用下拉框数值型参数做格式校验提交前统一转成规范格式。录入规范守在源头比后端清洗数据省力十倍。说到底数码产品对比平台这个项目表面上是全栈 CRUD真正的含金量全在“参数数据模型”和“对比计算引擎”这两个点上。EAV 模型解决品类扩展模板驱动解决参数对齐单位归一化解决比较合理性这三件事想清楚整个系统的骨架就立住了。我个人做完这个项目的最大体会是不要把“对比平台”理解成两张表格拼在一起它背后是一个数据结构设计和领域逻辑梳理的完整过程把这些想透比背多少面试题都管用。
返回列表