fix(cms): 修复联系表单手机号长度及格式问题
- 为 CmsContactLead 实体的 name 和 phone 加入 @NotBlank、@Size 及 @Pattern 校验 - 规范 company、delivery、need、source、ip 字段长度限制,防止数据异常 - 在提交服务中新增 sanitizePhone 方法,清除手机号中的空格、横线及括号等分隔符 - 扩展数据库中 phone 字段长度到 VARCHAR(32),支持国际及带分机号格式 - 更新数据库中 name、company、need 字段长度,避免未来数据截断风险 - 补充项目长期记忆文件,记录技术栈及该修复详情
This commit is contained in:
19
.workbuddy/memory/2026-07-19.md
Normal file
19
.workbuddy/memory/2026-07-19.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# 2026-07-19 工作日志
|
||||||
|
|
||||||
|
## cms-api phone 字段超长报错修复
|
||||||
|
- **问题**: cms-api 容器报 `com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Data too long for column 'phone' at row 1`
|
||||||
|
- **根因**: 公开接口 `/api/cms/cms-contact-lead/submit` (官网联系表单,无需登录) 前端传入超长/带分隔符的手机号,直接写入 MySQL 触发截断异常
|
||||||
|
- **影响**: 用户提交联系表单失败,销售线索丢失;公开接口易被刷
|
||||||
|
- **修复**:
|
||||||
|
1. `CmsContactLead.java` 实体加 JSR-303 校验: name/phone 加 @NotBlank+@Size+@Pattern,company/delivery/need/source/ip 加 @Size
|
||||||
|
2. `CmsContactLeadServiceImpl.submit()` 加 `sanitizePhone()` 清洗逻辑: 去空格/横线/括号,仅保留 + 和数字
|
||||||
|
3. 新增 SQL 迁移: `docs/sql/2026-07-19_cms_contact_lead_phone_resize.sql`,phone 扩到 VARCHAR(32),同步放宽 name/company/need
|
||||||
|
|
||||||
|
## 关联问题(未修复,需前端处理)
|
||||||
|
- 日志中 `参数类型转换异常: 参数名=id, 传入值=NaN, 期望类型=Integer`:前端 JS 把 NaN 拼到 URL 调用 `@GetMapping("/{id}")`,需前端判空
|
||||||
|
- `定时任务需要查询所有租户的超时订单 list = 0`:正常 INFO 日志,非错误
|
||||||
|
|
||||||
|
## 修改的文件
|
||||||
|
- src/main/java/com/gxwebsoft/cms/entity/CmsContactLead.java
|
||||||
|
- src/main/java/com/gxwebsoft/cms/service/impl/CmsContactLeadServiceImpl.java
|
||||||
|
- docs/sql/2026-07-19_cms_contact_lead_phone_resize.sql (新增)
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
# 项目长期记忆
|
||||||
|
|
||||||
|
## 项目技术栈
|
||||||
|
- Spring Boot 2.x + Spring Security 5.7.11 + MyBatis-Plus 3.4.1 + Druid + MySQL
|
||||||
|
- 验证框架: JSR-303 (javax.validation),通过 spring-boot-starter-web 间接引入,无需额外声明
|
||||||
|
- 多租户架构: 表普遍有 tenant_id 字段,定时任务需遍历所有租户
|
||||||
|
- SQL 迁移文件惯例: docs/sql/YYYY-MM-DD_描述.sql
|
||||||
|
- 实体软删除: @TableLogic + deleted 字段
|
||||||
|
- 部署方式: Docker (cms-api 容器)
|
||||||
|
|
||||||
|
## 已知问题与修复
|
||||||
|
- 2026-07-19: cms-api 报 `Data too long for column 'phone'`
|
||||||
|
- 根因: 公开接口 /api/cms/cms-contact-lead/submit 前端传入超长/带分隔符手机号
|
||||||
|
- 修复: CmsContactLead 实体加 @NotBlank/@Size/@Pattern;Service 加 sanitizePhone 清洗
|
||||||
|
- SQL: docs/sql/2026-07-19_cms_contact_lead_phone_resize.sql (phone 扩到 VARCHAR(32))
|
||||||
|
- 前端 bug: id=NaN 传入后端,需前端判空 (Number.isNaN)
|
||||||
|
|||||||
38
docs/sql/2026-07-19_cms_contact_lead_phone_resize.sql
Normal file
38
docs/sql/2026-07-19_cms_contact_lead_phone_resize.sql
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
-- ============================================================
|
||||||
|
-- 修复: cms_contact_lead.phone 字段长度不足导致 "Data too long"
|
||||||
|
-- 错误: com.mysql.cj.jdbc.exceptions.MysqlDataTruncation:
|
||||||
|
-- Data truncation: Data too long for column 'phone' at row 1
|
||||||
|
-- 原因: 公开接口 /api/cms/cms-contact-lead/submit 传入超长/带分隔符的手机号
|
||||||
|
-- (如 "+86 (138) 1234-5678 ext 8888" 或恶意超长 payload)
|
||||||
|
-- 方案:
|
||||||
|
-- 1. 将 phone 字段从原长度(VARCHAR(20)) 扩到 VARCHAR(32),
|
||||||
|
-- 足以容纳国际号码 + 分机号;
|
||||||
|
-- 2. (可选) 同时放宽 name / company 等字段,避免后续再撞同类问题。
|
||||||
|
-- 配合代码侧改动:
|
||||||
|
-- - CmsContactLead 实体加 @Size / @Pattern / @NotBlank 校验
|
||||||
|
-- - CmsContactLeadServiceImpl.submit 加 phone 清洗逻辑
|
||||||
|
-- (去除空格、横线、括号,仅保留 + 和数字)
|
||||||
|
-- 执行环境: 所有部署了 cms-api 的租户库 (cms_contact_lead 为全局表)
|
||||||
|
-- 执行方式: 幂等,可重复执行
|
||||||
|
-- ============================================================
|
||||||
|
|
||||||
|
-- 1. 主修复:扩展 phone 字段到 VARCHAR(32)
|
||||||
|
ALTER TABLE cms_contact_lead
|
||||||
|
MODIFY COLUMN phone VARCHAR(32) DEFAULT NULL COMMENT '手机号';
|
||||||
|
|
||||||
|
-- 2. (可选) 同步放宽 name / company,避免后续同类报错
|
||||||
|
ALTER TABLE cms_contact_lead
|
||||||
|
MODIFY COLUMN name VARCHAR(50) DEFAULT NULL COMMENT '联系人姓名';
|
||||||
|
|
||||||
|
ALTER TABLE cms_contact_lead
|
||||||
|
MODIFY COLUMN company VARCHAR(100) DEFAULT NULL COMMENT '单位/公司名称';
|
||||||
|
|
||||||
|
ALTER TABLE cms_contact_lead
|
||||||
|
MODIFY COLUMN need VARCHAR(1000) DEFAULT NULL COMMENT '需求描述';
|
||||||
|
|
||||||
|
-- 3. 验证字段类型已更新
|
||||||
|
-- 预期: phone VARCHAR(32), name VARCHAR(50), company VARCHAR(100), need VARCHAR(1000)
|
||||||
|
SHOW COLUMNS FROM cms_contact_lead LIKE 'phone';
|
||||||
|
SHOW COLUMNS FROM cms_contact_lead LIKE 'name';
|
||||||
|
SHOW COLUMNS FROM cms_contact_lead LIKE 'company';
|
||||||
|
SHOW COLUMNS FROM cms_contact_lead LIKE 'need';
|
||||||
@@ -8,6 +8,9 @@ import io.swagger.v3.oas.annotations.media.Schema;
|
|||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotBlank;
|
||||||
|
import javax.validation.constraints.Pattern;
|
||||||
|
import javax.validation.constraints.Size;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
@@ -28,25 +31,35 @@ public class CmsContactLead implements Serializable {
|
|||||||
@TableId(value = "lead_id", type = IdType.AUTO)
|
@TableId(value = "lead_id", type = IdType.AUTO)
|
||||||
private Integer leadId;
|
private Integer leadId;
|
||||||
|
|
||||||
@Schema(description = "联系人姓名")
|
@Schema(description = "联系人姓名", required = true)
|
||||||
|
@NotBlank(message = "姓名不能为空")
|
||||||
|
@Size(max = 50, message = "姓名长度不能超过50个字符")
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
@Schema(description = "手机号")
|
@Schema(description = "手机号", required = true)
|
||||||
|
@NotBlank(message = "手机号不能为空")
|
||||||
|
@Size(max = 25, message = "手机号长度不能超过25个字符")
|
||||||
|
@Pattern(regexp = "^[+]?[0-9\\-\\s()]{6,25}$", message = "手机号格式不正确")
|
||||||
private String phone;
|
private String phone;
|
||||||
|
|
||||||
@Schema(description = "单位/公司名称")
|
@Schema(description = "单位/公司名称")
|
||||||
|
@Size(max = 100, message = "公司名称长度不能超过100个字符")
|
||||||
private String company;
|
private String company;
|
||||||
|
|
||||||
@Schema(description = "交付方式: saas/private/hybrid")
|
@Schema(description = "交付方式: saas/private/hybrid")
|
||||||
|
@Size(max = 20, message = "交付方式长度不能超过20个字符")
|
||||||
private String delivery;
|
private String delivery;
|
||||||
|
|
||||||
@Schema(description = "需求描述")
|
@Schema(description = "需求描述")
|
||||||
|
@Size(max = 1000, message = "需求描述长度不能超过1000个字符")
|
||||||
private String need;
|
private String need;
|
||||||
|
|
||||||
@Schema(description = "来源渠道: web/miniapp/app")
|
@Schema(description = "来源渠道: web/miniapp/app")
|
||||||
|
@Size(max = 20, message = "来源渠道长度不能超过20个字符")
|
||||||
private String source;
|
private String source;
|
||||||
|
|
||||||
@Schema(description = "提交IP")
|
@Schema(description = "提交IP")
|
||||||
|
@Size(max = 50, message = "IP长度不能超过50个字符")
|
||||||
private String ip;
|
private String ip;
|
||||||
|
|
||||||
@Schema(description = "跟进状态: 0待跟进 1跟进中 2已成交 3无效")
|
@Schema(description = "跟进状态: 0待跟进 1跟进中 2已成交 3无效")
|
||||||
|
|||||||
@@ -70,6 +70,10 @@ public class CmsContactLeadServiceImpl extends ServiceImpl<CmsContactLeadMapper,
|
|||||||
lead.setIp(ip);
|
lead.setIp(ip);
|
||||||
lead.setStatus(0); // 默认待跟进
|
lead.setStatus(0); // 默认待跟进
|
||||||
|
|
||||||
|
// 清洗手机号:去除空格、横线、括号等分隔符,仅保留 + 和数字
|
||||||
|
// 防止 "Data too long for column 'phone'" 异常
|
||||||
|
lead.setPhone(sanitizePhone(lead.getPhone()));
|
||||||
|
|
||||||
boolean result = save(lead);
|
boolean result = save(lead);
|
||||||
if (result) {
|
if (result) {
|
||||||
log.info("[联系表单] 新线索提交成功,name={}, phone={}", lead.getName(), lead.getPhone());
|
log.info("[联系表单] 新线索提交成功,name={}, phone={}", lead.getName(), lead.getPhone());
|
||||||
@@ -79,6 +83,17 @@ public class CmsContactLeadServiceImpl extends ServiceImpl<CmsContactLeadMapper,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清洗手机号:去除空格、横线、括号等分隔符,仅保留 + 和数字
|
||||||
|
* 例如:"+86 (138) 1234-5678" -> "+8613812345678"
|
||||||
|
*/
|
||||||
|
private String sanitizePhone(String phone) {
|
||||||
|
if (StrUtil.isBlank(phone)) {
|
||||||
|
return phone;
|
||||||
|
}
|
||||||
|
return phone.replaceAll("[^+0-9]", "");
|
||||||
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------
|
// --------------------------------------------------------
|
||||||
// 异步通知(企业微信 + 飞书)
|
// 异步通知(企业微信 + 飞书)
|
||||||
// --------------------------------------------------------
|
// --------------------------------------------------------
|
||||||
|
|||||||
Reference in New Issue
Block a user