Spring IP地址验证

10

我正在寻找在我的Spring Roo项目中验证IP地址的可能性。

我的实体看起来像这样

package com.ip.test.domain;

import javax.persistence.ManyToOne;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import org.springframework.roo.addon.javabean.RooJavaBean;
import org.springframework.roo.addon.jpa.activerecord.RooJpaActiveRecord;
import org.springframework.roo.addon.tostring.RooToString;

@RooJavaBean
@RooToString
@RooJpaActiveRecord
public class IP {

@NotNull
@Size(min = 7, max = 15)
private String ip;

@ManyToOne
private Hoster Hoster;
}

使用这个设置,它只会验证字符串是否包含7到15个字符,但并不真正验证它是否是IP地址。

类似于

@validIpAddress
private String ip;

能实现就太好了。

你知道这是否可能吗?


你需要构建自己的验证器。查看此页面,了解一个验证ISBN号码的示例。 - Augusto
4个回答

16

您可以使用JSR 303模式验证器,配合IP地址正则表达式:

@NotNull
@Pattern(regexp = "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$")
private String ip;

编辑:转义反斜杠


模式可以很容易地扩展... 关键是当您可以使用正则表达式时,不要编写额外的注释和验证器。 - David Rabinowitz
2
但是,如果我创建了一个额外的注释,我可以多次使用它,并且只需要在一个地方进行扩展。感谢正则表达式,我无论如何都需要它进行验证。 - mbs
正则表达式字符串字面量需要转义。 - Lonre Wang

8

完全有可能。您需要编写自定义注释和实现类。不需要太多的努力。请参见此处的背景:http://docs.jboss.org/hibernate/validator/5.0/reference/en-US/html_single/#validator-customconstraints

@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE })
@Documented
@Constraint(validatedBy = IpAddressValidator.class)
public @interface IpAddress
{
  String message() default "{ipAddress.invalid}";
  Class<?>[] groups() default {};
  Class<? extends Payload>[] payload() default {};
}

并且

public class IpAddressValidator implements ConstraintValidator<IpAddress, Object>
{
  @Override
  public void initialize(IpAddress constraintAnnotation)
  {
  }

  @Override
  public boolean isValid(Object value, ConstraintValidatorContext cvContext)
  {
    // logic here
  }
}

请问为什么初始化方法是空的? - Peters_
你需要该方法来满足ConstraintValidator接口的合约,但如果你不需要实际初始化任何内容,可以将其留空。 - sbk

0

基本上,您想要使用JSR-303注释与自定义验证器。请参见完整的工作示例此处


0
我知道我在挖掘一个旧答案,但我想在这里补充一些东西。因为出于几个原因,我对所有这些答案都不满意。
1)像那样在每个IP上面加上@Pattern有点丑陋,只需有一个快速的类就好了。
2)IPv4很简单,IPv6则不然。
如果你想要处理IPv6,请阅读这篇文章:匹配有效IPv6地址的正则表达式 3)如果你想要一个简单的IPv4验证器,可以看看我在自己的网站上编写和测试的代码。效果很好。
import jakarta.validation.Constraint;
import jakarta.validation.Payload;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Pattern;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Pattern(regexp = ValidIPv4.IPV4_REGEX)
@Constraint(validatedBy = {})
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface ValidIPv4 {
    // JSR 303 Pattern Validator for IPv4
    String IPV4_REGEX = "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$";

    String message() default "must match " + IPV4_REGEX;

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}

当然,你可以使用一个非常好的单元测试:
import jakarta.validation.ConstraintViolation;
import jakarta.validation.Validation;
import jakarta.validation.Validator;
import jakarta.validation.ValidatorFactory;
import org.springframework.validation.annotation.Validated;
import org.testng.annotations.Test;

import java.util.Set;

import static org.testng.AssertJUnit.assertEquals;

public class ValidIPv4Test {

    @Validated
    private class MyClass {
        @ValidIPv4
        private String ipv4;

        public String getIpv4() {
            return ipv4;
        }

        public void setIpv4(String ipv4) {
            this.ipv4 = ipv4;
        }
    }

    @Test
    public void testValidFormat() {
        // Create a ValidatorFactory and Validator
        ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();
        Validator validator = validatorFactory.getValidator();

        // Create an object with the field to validate
        MyClass myClass = new MyClass();
        myClass.setIpv4("127.0.0.1");

        // Perform validation
        Set<ConstraintViolation<MyClass>> violations = validator.validate(myClass);

        // Assert that there are no validation violations
        assertEquals(0, violations.size());
    }

    @Test
    public void testInvalidFormat() {
        // Create a ValidatorFactory and Validator
        ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();
        Validator validator = validatorFactory.getValidator();

        // Create an object with the field to validate
        MyClass myClass = new MyClass();
        myClass.setIpv4("827.0.0.1");

        // Perform validation
        Set<ConstraintViolation<MyClass>> violations = validator.validate(myClass);

        // Assert that there is one validation violation
        assertEquals(1, violations.size());

        // Assert that the violation is related to the field
        ConstraintViolation<MyClass> violation = violations.iterator().next();
        assertEquals("must match \"" + ValidIPv4.IPV4_REGEX + "\"", violation.getMessage());
        assertEquals("ipv4", violation.getPropertyPath().toString());
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接