This commit is contained in:
2025-09-20 17:46:33 +08:00
parent 353c57c98b
commit 2685df85c3
4 changed files with 499 additions and 3 deletions

View File

@@ -89,6 +89,10 @@ func RegisterCustomValidators(validate *validator.Validate) {
// 回调地址验证器
validate.RegisterValidation("validReturnURL", validateReturnURL)
// 企业名称验证器
validate.RegisterValidation("enterprise_name", validateEnterpriseName)
validate.RegisterValidation("validEnterpriseName", validateEnterpriseName)
}
// validatePhone 手机号验证
@@ -490,6 +494,76 @@ func validateReturnURL(fl validator.FieldLevel) bool {
return true
}
// validateEnterpriseName 企业名称验证器
func validateEnterpriseName(fl validator.FieldLevel) bool {
enterpriseName := fl.Field().String()
// 去除首尾空格
trimmedName := strings.TrimSpace(enterpriseName)
if trimmedName == "" {
return false
}
// 长度验证2-100个字符
if len(trimmedName) < 2 || len(trimmedName) > 100 {
return false
}
// 检查是否包含非法字符(允许中英文括号)
invalidChars := []string{
"`", "~", "!", "@", "#", "$", "%", "^", "&", "*",
"+", "=", "{", "}", "[", "]", "\\", "|", ";", ":", "'", "\"", "<", ">", ",", ".", "?", "/",
}
for _, char := range invalidChars {
if strings.Contains(trimmedName, char) {
return false
}
}
// 必须包含至少一个中文字符或英文字母
hasValidChar := regexp.MustCompile(`[\p{Han}a-zA-Z]`).MatchString(trimmedName)
if !hasValidChar {
return false
}
// 验证企业名称的基本格式(支持各种类型的企业)
// 支持:有限公司、股份有限公司、工作室、个体工商户、合伙企业等
validSuffixes := []string{
"有限公司", "有限责任公司", "股份有限公司", "股份公司",
"工作室", "个体工商户", "个人独资企业", "合伙企业",
"集团有限公司", "集团股份有限公司",
"Co.,Ltd", "Co., Ltd", "Ltd", "LLC", "Inc", "Corp",
"Company", "Studio", "Workshop", "Enterprise",
}
// 检查是否以合法的企业类型结尾(不强制要求,因为有些企业名称可能没有标准后缀)
// 但如果有后缀,必须是合法的
hasValidSuffix := false
for _, suffix := range validSuffixes {
if strings.HasSuffix(trimmedName, suffix) {
hasValidSuffix = true
break
}
}
// 如果名称中包含常见的企业类型关键词,则必须是合法的后缀
enterpriseKeywords := []string{"公司", "工作室", "企业", "集团", "Co", "Ltd", "LLC", "Inc", "Corp", "Company", "Studio", "Workshop", "Enterprise"}
containsKeyword := false
for _, keyword := range enterpriseKeywords {
if strings.Contains(trimmedName, keyword) {
containsKeyword = true
break
}
}
// 如果包含企业关键词但没有合法后缀,则验证失败
if containsKeyword && !hasValidSuffix {
return false
}
return true
}
// ================ 统一的业务校验方法 ================
// ValidatePhone 验证手机号
@@ -694,6 +768,80 @@ func ValidateSliceNotEmpty(slice interface{}, fieldName string) error {
return nil
}
// ValidateEnterpriseName 验证企业名称
func ValidateEnterpriseName(enterpriseName string) error {
if enterpriseName == "" {
return fmt.Errorf("企业名称不能为空")
}
// 去除首尾空格
trimmedName := strings.TrimSpace(enterpriseName)
if trimmedName == "" {
return fmt.Errorf("企业名称不能为空")
}
// 长度验证2-100个字符
if len(trimmedName) < 2 {
return fmt.Errorf("企业名称长度不能少于2个字符")
}
if len(trimmedName) > 100 {
return fmt.Errorf("企业名称长度不能超过100个字符")
}
// 检查是否包含非法字符(允许中英文括号)
invalidChars := []string{
"`", "~", "!", "@", "#", "$", "%", "^", "&", "*",
"+", "=", "{", "}", "[", "]", "\\", "|", ";", ":", "'", "\"", "<", ">", ",", ".", "?", "/",
}
for _, char := range invalidChars {
if strings.Contains(trimmedName, char) {
return fmt.Errorf("企业名称不能包含特殊字符: %s", char)
}
}
// 必须包含至少一个中文字符或英文字母
hasValidChar := regexp.MustCompile(`[\p{Han}a-zA-Z]`).MatchString(trimmedName)
if !hasValidChar {
return fmt.Errorf("企业名称必须包含中文字符或英文字母")
}
// 验证企业名称的基本格式(支持各种类型的企业)
// 支持:有限公司、股份有限公司、工作室、个体工商户、合伙企业等
validSuffixes := []string{
"有限公司", "有限责任公司", "股份有限公司", "股份公司",
"工作室", "个体工商户", "个人独资企业", "合伙企业",
"集团有限公司", "集团股份有限公司",
"Co.,Ltd", "Co., Ltd", "Ltd", "LLC", "Inc", "Corp",
"Company", "Studio", "Workshop", "Enterprise",
}
// 检查是否以合法的企业类型结尾
hasValidSuffix := false
for _, suffix := range validSuffixes {
if strings.HasSuffix(trimmedName, suffix) {
hasValidSuffix = true
break
}
}
// 如果名称中包含常见的企业类型关键词,则必须是合法的后缀
enterpriseKeywords := []string{"公司", "工作室", "企业", "集团", "Co", "Ltd", "LLC", "Inc", "Corp", "Company", "Studio", "Workshop", "Enterprise"}
containsKeyword := false
for _, keyword := range enterpriseKeywords {
if strings.Contains(trimmedName, keyword) {
containsKeyword = true
break
}
}
// 如果包含企业关键词但没有合法后缀,则验证失败
if containsKeyword && !hasValidSuffix {
return fmt.Errorf("企业名称格式不正确,请使用标准的企业类型后缀(如:有限公司、工作室等)")
}
return nil
}
// ================ 便捷的校验器创建函数 ================
// NewBusinessValidator 创建业务验证器(保持向后兼容)

View File

@@ -0,0 +1,135 @@
package validator
import (
"testing"
)
func TestValidateEnterpriseName(t *testing.T) {
tests := []struct {
name string
input string
expectError bool
errorMsg string
}{
{
name: "有效的有限公司名称",
input: "北京天远数据科技有限公司",
expectError: false,
},
{
name: "有效的工作室名称",
input: "张三设计工作室",
expectError: false,
},
{
name: "有效的英文公司名称",
input: "Apple Inc",
expectError: false,
},
{
name: "有效的英文有限公司",
input: "Google LLC",
expectError: false,
},
{
name: "有效的股份有限公司",
input: "中国移动股份有限公司",
expectError: false,
},
{
name: "有效的个体工商户",
input: "李四个体工商户",
expectError: false,
},
{
name: "空字符串",
input: "",
expectError: true,
errorMsg: "企业名称不能为空",
},
{
name: "只有空格",
input: " ",
expectError: true,
errorMsg: "企业名称不能为空",
},
{
name: "长度过短",
input: "A",
expectError: true,
errorMsg: "企业名称长度不能少于2个字符",
},
{
name: "包含非法字符",
input: "测试公司@#$",
expectError: true,
errorMsg: "企业名称不能包含特殊字符",
},
{
name: "包含公司关键词但后缀不合法",
input: "测试公司123",
expectError: true,
errorMsg: "企业名称格式不正确,请使用标准的企业类型后缀",
},
{
name: "包含工作室关键词但后缀不合法",
input: "设计工作室ABC",
expectError: true,
errorMsg: "企业名称格式不正确,请使用标准的企业类型后缀",
},
{
name: "只包含数字和特殊字符",
input: "12345-67890",
expectError: true,
errorMsg: "企业名称必须包含中文字符或英文字母",
},
{
name: "没有企业类型关键词的个人名称",
input: "张三理发店",
expectError: false, // 没有企业关键词,所以不强制要求后缀
},
{
name: "包含括号的企业名称",
input: "北京天远数据科技有限公司(分公司)",
expectError: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := ValidateEnterpriseName(tt.input)
if tt.expectError {
if err == nil {
t.Errorf("期望有错误,但没有返回错误")
} else if tt.errorMsg != "" && !containsString(err.Error(), tt.errorMsg) {
t.Errorf("期望错误消息包含 '%s',但得到 '%s'", tt.errorMsg, err.Error())
}
} else {
if err != nil {
t.Errorf("期望没有错误,但得到错误: %v", err)
}
}
})
}
}
// containsString 检查字符串是否包含子字符串
func containsString(s, substr string) bool {
return len(s) >= len(substr) &&
(s == substr ||
len(s) > len(substr) &&
(s[:len(substr)] == substr ||
s[len(s)-len(substr):] == substr ||
containsSubstring(s, substr)))
}
// containsSubstring 辅助函数检查子字符串
func containsSubstring(s, substr string) bool {
for i := 0; i <= len(s)-len(substr); i++ {
if s[i:i+len(substr)] == substr {
return true
}
}
return false
}