2013年1月10日 星期四

符合Bean Validation規格的統一編號驗證 (JSR303)

Annotation
package com.gss.gmo.cao.validator.constraints;

import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import javax.validation.Constraint;
import javax.validation.Payload;

import com.gss.gmo.cao.validator.constraints.impl.UnifiedBusinessNumberValidator;

/**
 * The annotated element has to represent a valid unified business number.
 * 
 * @author linus_chien
 * 
 */
@Documented
@Constraint(validatedBy = UnifiedBusinessNumberValidator.class)
@Target(value = { METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
@Retention(value = RUNTIME)
public @interface UnifiedBusinessNumber {

    /**
     * Default key:
     * com.gss.gmo.cao.validator.constraints.UnifiedBusinessNumber.message.
     * 
     * @return
     */
    String message() default "{com.gss.gmo.cao.validator.constraints.UnifiedBusinessNumber.message}";

    /**
     * Default {}.
     * 
     * @return
     */
    Class<?>[] groups() default {};

    /**
     * Default {}.
     * 
     * @return
     */
    Class<? extends Payload>[] payload() default {};

    /**
     * Defines several @UnifiedBusinessNumber annotations on the same element.
     * 
     * @author linus_chien
     * 
     */
    @Documented
    @Target(value = { METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
    @Retention(value = RUNTIME)
    public @interface List {
        /**
         * @return
         */
        UnifiedBusinessNumber[] values();
    }

}
ConstraintValidator Implementation
package com.gss.gmo.cao.validator.constraints.impl;

import java.util.regex.Pattern;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

import com.gss.gmo.cao.validator.constraints.UnifiedBusinessNumber;

/**
 * 營利事業統一編號檢查程式 可至 http://www.etax.nat.gov.tw/ 查詢營業登記資料
 * 
 * @author linus_chien
 * 
 */
public class UnifiedBusinessNumberValidator implements ConstraintValidator<UnifiedBusinessNumber, String> {

    /**
     * Number pattern.
     */
    public static final Pattern NUMBER_PATTERN = Pattern.compile("^[0-9]{8}$");

    /**
     * Calculate weight.
     */
    public static final char[] WEIGHT = "12121241".toCharArray();

    @Override
    public void initialize(UnifiedBusinessNumber annotation) {
    }

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        if (value == null) {
            return true;
        }

        if (!NUMBER_PATTERN.matcher(value).matches()) {
            return false;
        }

        char[] numbers = value.toCharArray();

        boolean isSeven = (numbers[6] == '7'); // 第七個數是否為七

        int sum = 0;
        for (int i = 0; i < 8; i++) {
            if (i == 6 && isSeven) {
                continue;
            }
            int singleValue = (numbers[i] - '0') * (WEIGHT[i] - '0');
            sum += (singleValue / 10) + (singleValue % 10);
        }

        if (isSeven) {
            if ((sum % 10) == 0 || ((sum + 1) % 10) == 0) {
                return true;
            }
        } else {
            if ((sum % 10) == 0) {
                return true;
            }
        }

        return false;

    }

}