JAVA采用 Luhm 校验算法来生成条码(银行卡号),防止被篡改

开发过程中,经常会生成一段条码来做为一个标识,比如生成几个商品的条码。但如果只是简单的使用几个随机数来标记,没有任何的校验过程,有时可能不太安全。这里介绍一个简单使用的条码校验方法。这样如果条码被修改过,就无法通过校验,从而达到提高安全性的目的。

这里主要使用Luhm 校验算法。Luhm 校验算法广泛用在银行卡号的生成,校验等场景上,这里不多说了。

简单介绍校验的过程:

1、从最后一位数字开始,逆向将奇数位(1、3、5等等)相加。

2、从最后一位数字开始,逆向将偶数位数字,先乘以2(如果乘积为两位数,则将其减去9),再求和。

3、将奇数位总和加上偶数位总和,结果应该可以被10整除。

例如,卡号是:5432123456788881

则奇数、偶数位(用红色标出)分布:5432123456788881

奇数位和=35

偶数位乘以2(有些要减去9)的结果:16 2 6 1 5 7 7,求和=35。

最后35+35=70可以被10整除,认定校验通过。否则则不通过。

这里提供一个工具类,方便大家使用:

/*
 * 文件名:CodeNumberUtil.java 版权:Copyright by www.poly.com 描述: 修改人:gogym 修改时间:2018年10月19日 跟踪单号: 修改单号:
 * 修改内容:
 */

package com.im.plugin.barcode;

import java.util.Random;

import org.springframework.util.StringUtils;

/**
 * 条码生成 采用 Luhm 校验算法
 * 
 * @author gogym
 * @version 2018年10月19日
 * @see CodeNumberUtil
 * @since
 */
public class CodeNumberUtil {
	private static int i = 0;
	public static final String NUMBERCHAR = "0123456789";

	/**
	 * 
	 * Description: 生成条码(卡号)
	 * 
	 * @return
	 * @see
	 */
	public static String getCodeNumber(String prefix) {
		if (!StringUtils.isEmpty(prefix)) {
			//可以修改生成随机数的长度,生成想要的长度的条码
			String num = generateNumString(5);
			String st = prefix + num + getUnixTime();
			return st + getCardCheckCode(st);
		}
		return "prefix不能为空";
	}

	/**
	 * 传入一个前缀和一个码。 【根据自己的业务定义】
	 * 
	 * @param prefix
	 * @return
	 */
	public static String getCodeNumber(String prefix, String code) {
		if (!StringUtils.isEmpty(prefix) && !StringUtils.isEmpty(code)) {
			String st = prefix + code + getUnixTime();
			return st + getCardCheckCode(st);
		}
		return "prefix和code不能为空";
	}

	/**
	 * 校验条码是否正确
	 * 
	 * @param cardId
	 * @return
	 */
	public static boolean checkCode(String code) {
		char bit = getCardCheckCode(code.substring(0, code.length() - 1));
		if (bit == 'N') {
			return false;
		}
		return code.charAt(code.length() - 1) == bit;
	}

	/**
	 * 从不含校验位的卡号采用 Luhm 校验算法获得校验位
	 * 
	 * @param nonCheckCodeCardNo
	 * @return
	 */
	private static char getCardCheckCode(String nonCheckCodeCardNo) {
		if (nonCheckCodeCardNo == null
				|| nonCheckCodeCardNo.trim().length() == 0
				|| !nonCheckCodeCardNo.matches("\\d+")) {
			// 如果传的不是数据返回N
			return 'N';
		}
		char[] chs = nonCheckCodeCardNo.trim().toCharArray();
		int luhmSum = 0;
		for (int i = chs.length - 1, j = 0; i >= 0; i--, j++) {
			int k = chs[i] - '0';
			if (j % 2 == 0) {
				k *= 2;
				k = k / 10 + k % 10;
			}
			luhmSum += k;
		}
		return (luhmSum % 10 == 0) ? '0' : (char) ((10 - luhmSum % 10) + '0');
	}

	/***
	 * 获取当前系统时间戳 并截取后8位
	 * 
	 * @return
	 */
	private static String getUnixTime() {
		try {
			Thread.sleep(10);// 快速执行时,休眠10毫秒 防止号码重复
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		i++;
		i = i > 100 ? i % 10 : i;
		return ((System.currentTimeMillis() / 100) + "").substring(5)
				+ (i % 10);
	}

	/**
	 * 生成一个定长的纯数字符串
	 * 
	 * @param length
	 *            字符串长度
	 * @return 纯0字符串
	 */
	private static String generateNumString(int length) {
		StringBuffer sb = new StringBuffer();
		Random random = new Random();
		for (int i = 0; i < length; i++) {
			sb.append(NUMBERCHAR.charAt(random.nextInt(NUMBERCHAR.length())));
		}
		return sb.toString();
	}

	
	//测试
	public static void main(String[] args) {

		try {

			for (int i = 0; i < 1; i++) {
				// 生成条码
				String code = getCodeNumber("18");
				System.out.println(code);
				// 检验条码
				System.out.println(checkCode(code));
			}

		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值