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:
2026-07-19 19:36:38 +08:00
parent 8256817ef7
commit b79cc1003c
5 changed files with 103 additions and 2 deletions

View 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+@Patterncompany/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 (新增)

View File

@@ -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/@PatternService 加 sanitizePhone 清洗
- SQL: docs/sql/2026-07-19_cms_contact_lead_phone_resize.sql (phone 扩到 VARCHAR(32))
- 前端 bug: id=NaN 传入后端,需前端判空 (Number.isNaN)

View 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';

View File

@@ -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无效")

View File

@@ -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]", "");
}
// -------------------------------------------------------- // --------------------------------------------------------
// 异步通知(企业微信 + 飞书) // 异步通知(企业微信 + 飞书)
// -------------------------------------------------------- // --------------------------------------------------------