`
inkcar
  • 浏览: 8184 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论
阅读更多
需求说明:
  • 进销存销售产品时,需要系统按规则生成一个销售订单号
  • 订单号需要生成如"XS-日期-序号"的格式。其中“日期”为当天日期、“序号”为当天当前的销售单量并且不足四位时,以“0”填充在数量之前。如“XS-20100501-0050”
  • 可以系统中维护订单号生成规则,并且不影响之前生成的订单号

解决办法:
一、分析需求,可确认销售订单序号的规则为“XS-日期-序号”,其中“序号”要以“日期”为因子进行归零递归。抽象出生成序号的规则“XS-{DATE}-{S4[DATE]}”。
其他可能应用到规则如下:
1. {Y} | {Y4} | {YYYY} / {Y2} | {YY} 表示获取年份值,四位数年份及二位数年份 
2. {MM} | {M} 表示月份值 
3. {DD} | {D}表示当前日期值 
4. {HH} 表示日期时间的小时值 
5. {MN} 表示日期时间的分钟值 
6. {SS} 表示日期时间的秒值 
7. {DATE} 表示当前日期同等于{YYYY}{MM}{DD}相连 
8. {NOW} 表示当前日期时间{YYYY}{MM}{DD}{HH}{MN}{SS} 
9. {@表单字段} 表示获取表单上某一控件的值为规则的一部分,如{@ORG}:获取表单上字段叫为"ORG"控件的值为规则一部分 
10. {@表单字段:replace(a,b)}/{@表单字段:replace(a)} 表示获取表单上某一控件的值,并替换值中的"a"为"b"字符,如{@createTime:replace(-)}:获取表单上字段叫为"createTime"控件的值并替换"-"为空字符。注意(支持函数):替换[replace(a,b)],截取字符[substring(开始位置,结束位置)],转小写(toLowerCase),转大写(toUpperCase),去除前后空格(trim) 
11.{W#*} 表示随机字符或数字,*号为长度,#为"D"时为随机数字(0-9);为"S"时为随机字符(A-Za-z);为空时为(0-9A-Za-z) 
12.{D*} 表示随机*位数字,*号为长度,如{D5}为随机5位数字,等同与{WD5} 
13.{C*} 表示随机*位字符,*号为长度,如{S5}为随机5位数字,等同与{WS5} 
14.{S*[#_#]}表示序号中流水号长度及增长因子(必须以S开始),其中*表示序号中流水号长度;[]之间的设置为增长因子设置,可使用上面(1-9项)的任意一种及组合,如多个组合需要使用"_"相隔。如:S5[Y_M_D]表示序号中的流水号长度为5,并且每天都会自动归1,然后重新递增 

二、创建相关数据库表,规则定义表RuleDef,规则实例表RuleInst。定义表与实例表为一对多关系。
规则定义表RuleDef
字段描述  字段名称  字段类型
id  definitionId  bigint
规则序号名称  definitionName  varchar(50)
规则序号描述  definitionCommentvarchar(50)
规则序号定义  definitionRulevarchar(100)

规则实例表RuleInst
字段描述  字段名称  字段类型
id  definitionId  bigint
规则序号名称  definitionName  varchar(50)
序号增长因子  iterateGenevarchar(50)
当前最大值  maxValueint

三、编写实现类(以正则表达式方式实现)
1、正则表达式properties配置设置
##################################################
# custom Sequence pattern -- use SequenceRender
##################################################
sequence.utils.growthFactorPattern=\\{S{1}(\\d){1,2}(?\:\\[([\\w\\@]*)\\])*\\}
sequence.utils.commonRulePattern=\\{([\\w-\\@\\[\\]]+)(?\:\\\:([^\\{]*))*\\}
sequence.utils.commonRuleFnPattern=([\\w-\\[\\]]*)(?\:\\((.*?)?\\))*
sequence.utils.randomPattern=^W?(W|D|C){1}(\\d){1,2}
#值为yyyyMMddHHmmss格式的当前日期时间值
sequence.utils.oraDatePattern=(((\\d{2}(\\d{2}))(\\d{2}))(\\d{2}))(\\d{2})(\\d{2})(\\d{2})

##################################################
# custom Sequence date Rule values -- use SequenceRender
# 以下键值为sequence.utils.oraDatePattern正则值的索引号
##################################################
#yyyyMMddHHmmss=20110630115830
sequence.utils.YYYYMMDDHHMMSS=0
sequence.utils.NOW=${sequence.utils.YYYYMMDDHHMMSS}
sequence.utils.YYYYMMDD=1
sequence.utils.DATE=${sequence.utils.YYYYMMDD}
sequence.utils.YYYYMM=2
sequence.utils.YYYY=3
sequence.utils.Y4=${sequence.utils.YYYY}
sequence.utils.Y=${sequence.utils.YYYY}
sequence.utils.YY=4
sequence.utils.Y2=${sequence.utils.YY}
sequence.utils.MM=5
sequence.utils.M=${sequence.utils.MM}
sequence.utils.DD=6
sequence.utils.D=${sequence.utils.DD}
sequence.utils.HH=7
sequence.utils.MN=8
sequence.utils.SS=9

sequence.define.xiaoShouNo=XS-{DATE}-{S4[DATE]}


2、现实类SequenceUtils.java
package test.inkcar.sequence.utils;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.beanutils.BeanUtils;

import test.inkcar.sequence.preferences.SystemGlobal;

public class SequenceUtils {
	// private static PtSequenceDefinitionBIZ ptSequenceDefinitionBIZ =
	// (PtSequenceDefinitionBIZ) BizFactory
	// .getBean("ptsequencedefinitionbiz");
	// private static PtSequenceInstanceBIZ ptSequenceInstanceBIZ =
	// (PtSequenceInstanceBIZ) BizFactory
	// .getBean("ptsequenceinstancebiz");
	/**
	 * 配置属性前缀名称
	 */
	private static final String PROPERTY_NAME = "sequence.utils.";
	/**
	 * 带时分秒的ORA标准时间格式 yyyyMMddHHmmss
	 */
	private static final SimpleDateFormat ORA_DATE_TIME_EXTENDED_FORMAT = new SimpleDateFormat(
			"yyyyMMddHHmmss");
	/**
	 * 带时分秒的ORA标准时间正则解析表达式
	 */
	private static final Pattern ORA_DATE_PATTERN = Pattern.compile(
			getPropertyName("oraDatePattern"), Pattern.CASE_INSENSITIVE);
	/**
	 * 增长因子正则解析表达式
	 */
	private static final Pattern GROWTH_FACTOR_PATTERN = Pattern.compile(
			getPropertyName("growthFactorPattern"), Pattern.CASE_INSENSITIVE);
	/**
	 * 随机字符正则解析表达式
	 */
	private static final Pattern RANDOM_PATTERN = Pattern.compile(
			getPropertyName("randomPattern"), Pattern.CASE_INSENSITIVE);
	/**
	 * 规则正则解析表达式 -- 表单值
	 */
	private static final Pattern COMMON_RULE_PATTERN = Pattern.compile(
			getPropertyName("commonRulePattern"), Pattern.CASE_INSENSITIVE);
	/**
	 * 规则正则解析表达式--表单值函数
	 */
	private static final Pattern COMMON_RULE_FN_PATTERN = Pattern.compile(
			getPropertyName("commonRuleFnPattern"), Pattern.CASE_INSENSITIVE);

	/**
	 * 带时分秒的ORA标准时间格式匹配
	 */
	private static Matcher ORA_DATE_MATCHER;

	/**
	 * 客户请求数据
	 */
	@SuppressWarnings("unchecked")
	private static ThreadLocal<Map> USERDATA = new ThreadLocal<Map>();

	/**
	 * 构造
	 */
	private SequenceUtils() {
	}

	/**
	 * 获取配置属性
	 * 
	 * @param name
	 *            属性名称
	 * @return 配置值
	 */
	private static final String getPropertyName(String name) {
		return SystemGlobal.get(PROPERTY_NAME + name);
	}

	/**
	 * 初始化当前日期时间字符串及客户端请求数据
	 */
	@SuppressWarnings("unchecked")
	private static final void reloadData(Object bean) {
		Map map = new HashMap();
		if (bean != null) {
			if ("HashMap".equals(bean.getClass().getSimpleName())) {
				map = (Map) bean;
			} else {
				try {
					map = BeanUtils.describe(bean);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
		USERDATA.set(map);
		String dte = ORA_DATE_TIME_EXTENDED_FORMAT.format(Calendar
				.getInstance().getTime());
		ORA_DATE_MATCHER = ORA_DATE_PATTERN.matcher(dte);
		ORA_DATE_MATCHER.find();
	}

	/**
	 * 渲染序号
	 * 
	 * @param ruleDef
	 *            序号规则定义字符串
	 * @return 渲染后的序号值
	 */
	public static final String render(String defName) {
		return render(defName, null);
	}

	/**
	 * 渲染序号
	 * 
	 * @param ruleDef
	 *            序号规则定义字符串
	 * @param request
	 *            客户端请求数据
	 * @return 渲染后的序号值
	 */
	public static final String render(String defName, Object bean) {

		reloadData(bean);

		String ruleDef = getGrowthFactor(defName, true);
		if (StringUtils.isEmpty(ruleDef))
			return "";

		Matcher m = COMMON_RULE_PATTERN.matcher(ruleDef);
		StringBuffer sb = new StringBuffer("");
		String paramValue = null;
		while (m.find()) {
			String r = m.group(1);
			if (StringUtils.isEmpty(r))
				continue;
			// 检查是否需要进行字串变换操作
			paramValue = getFnParam(m.group(2), getMatcherValue(r));
			
			m.appendReplacement(sb, paramValue);
		}
		m.appendTail(sb);
		return sb.toString();
	}

	/**
	 * 根据规则序号定义获取预览序号值(表单没有进行保存前显示)
	 * 
	 * @param def
	 *            规则定义实体对象
	 * @return
	 * 
	 * @author Inkcar Nov 5, 2010 3:44:10 PM
	 */
	public static final String getPreviewSequence(String defName) {
		reloadData(null);

		// 获取已设置增长因子值的规则序号及定义
		String ruleDef = getGrowthFactor(defName, false);
		if (StringUtils.isEmpty(ruleDef)) {
			return "";
		}

		Matcher m = COMMON_RULE_PATTERN.matcher(ruleDef);
		StringBuffer sb = new StringBuffer("");
		while (m.find()) {
			String r = m.group(1);
			if (StringUtils.isEmpty(r) || r.charAt(0) == '@')
				continue;
			m.appendReplacement(sb, getMatcherValue(r));
		}
		m.appendTail(sb);
		return sb.toString();
	}

	/**
	 * 获取增长因子匹配
	 * 
	 * @param gene
	 *            规则定义字符
	 * @return 匹配增长因子之后的字符
	 */
	private static final String getGrowthFactor(String defName, boolean save) {
		if (StringUtils.isEmpty(defName)) {
			return "";
		}
		/*
		 * 从数据库获取规则序号定义
		 */
		// PtSequenceDefinition def = ptSequenceDefinitionBIZ
		// .getPtSequenceDefinitionByName(defName);
		// if (def == null) {
		// return "";
		// }
		// String ruleDef = def.getDefinitionRule();
		/*
		 * 从properties配置文件读取序号规则定义
		 */
		String defineName = "sequence.define." + defName;
		String ruleDef = SystemGlobal.get(defineName);
		if (StringUtils.isEmpty(ruleDef)) {
			return "";
		}

		Matcher g = GROWTH_FACTOR_PATTERN.matcher(ruleDef);
		StringBuffer sb = new StringBuffer("");
		Integer leng = 0, value = 0;
		String cacheFieldName;
		while (g.find()) {
			StringBuffer sbGene = new StringBuffer("");
			String strGene = g.group(2);
			if (!StringUtils.isEmpty(strGene)) {
				String[] arr = strGene.split("_");
				for (int i = 0; i < arr.length; i++) {
					String ch = arr[i];
					if (StringUtils.isEmpty(ch))
						continue;
					sbGene.append(getMatcherValue(ch));
				}

			}
			// 增长因子值最小位数
			leng = Integer.valueOf(g.group(1));

			// 从properties配置文件获取当前增长因子最大值
			cacheFieldName = defineName + "." + sbGene.toString();
			value = SystemGlobal.getInteger(cacheFieldName) + 1;

			// 从数据库获取增长因子最大值
			// value =
			// ptSequenceInstanceBIZ.getGrowthFactor(def,sbGene.toString());

			// 获取并更新当前因子最大值,对数据库进行操作
			if (save) {
				// 保存到properties配置文件
				SystemGlobal.set(cacheFieldName, value.toString());
				// 保存到数据库
				// ptSequenceInstanceBIZ.updateGrowthFactor(def,
				// value);
			}
			g.appendReplacement(sb, StringUtils.getFillDigits(value.toString(),
					leng));
		}
		g.appendTail(sb);
		return sb.toString();
	}

	/**
	 * 匹配随机字符
	 * 
	 * @param gene
	 *            随机匹配字符
	 * @return 匹配值
	 */
	private static final String getRandomCharacter(String gene) {
		Matcher m = RANDOM_PATTERN.matcher(gene);
		StringBuffer sb = new StringBuffer("");
		if (m.find()) {
			// 将随机值添加到序号值中
			m.appendReplacement(sb, StringUtils.getRands(Integer.valueOf(m
					.group(2)), m.group(1)));
			return sb.toString();
		}
		return gene;
	}

	/**
	 * 获取规则序号匹配值
	 * 
	 * @param val
	 *            匹配字符串
	 * @return 匹配值
	 */
	@SuppressWarnings("unchecked")
	private static final String getMatcherValue(String val) {
		// 获取传入参数值
		if (val.charAt(0) == '@') {
			String field = val.replace("@", "");
			// 获取参数键值对象
			Map bean = getRequestThread();
			if (!StringUtils.isEmpty(field)) {
				Object value = bean.get(field);
				if (value == null)
					return "";
				return value.toString();
			}
			return "";
		}
		Integer index = -1;
		// 从properties配置文件获取规则定义
		String value = getPropertyName(val);
		try {
			index = Integer.valueOf(value);
		} catch (Exception e) {
		}

		if (index != -1) {
			// 获取当前操作时间指定位置值
			return ORA_DATE_MATCHER.group(index);
		}
		return getRandomCharacter(val);
	}

	/**
	 * 对指定值进行预定义的变换操作
	 * 
	 * @param fnName
	 *            操作类型,如replace、substring、toLowerCase、toUpperCase、trim
	 * @param paramValue
	 *            操作字符值
	 * @return
	 */
	private static String getFnParam(String fnName, String paramValue) {
		if (!StringUtils.isEmpty(fnName)) {
			Matcher fnMatcher = COMMON_RULE_FN_PATTERN.matcher(fnName);
			String fn, fnParams, reValue;
			String[] arrParams;
			while (fnMatcher.find()) {
				if (!StringUtils.isEmpty(fnMatcher.group())) {
					try {
						fn = fnMatcher.group(1);
						fnParams = fnMatcher.group(2);
						arrParams = fnParams != null ? fnParams.split(",")
								: new String[] {};
						reValue = arrParams.length > 1 ? arrParams[1] : "";
						if ("replace".equals(fn)) {
							paramValue = paramValue.replaceAll(arrParams[0],
									reValue);
						} else if ("substring".equals(fn)) {
							Integer start = arrParams.length > 0 ? Integer
									.valueOf(arrParams[0]) : 0;
							Integer end = arrParams.length > 1 ? Integer
									.valueOf(arrParams[1]) : 0;
							if (end > 0) {
								paramValue = paramValue.substring(start, end);
							} else {
								paramValue = paramValue.substring(start);
							}
						} else if ("toLowerCase".equals(fn)) {
							paramValue = paramValue.toLowerCase();
						} else if ("toUpperCase".equals(fn)) {
							paramValue = paramValue.toUpperCase();
						} else if ("trim".equals(fn)) {
							paramValue = paramValue.trim();
						}
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			}
		}
		return paramValue;
	}

	/**
	 * 获取当前请求线程
	 * 
	 * @return
	 */
	@SuppressWarnings("unchecked")
	private static final Map getRequestThread() {
		return USERDATA.get();
	}
}

3、测试类
package test.inkcar.sequence;

import test.inkcar.sequence.preferences.SystemGlobal;
import test.inkcar.sequence.utils.SequenceUtils;
import junit.framework.TestCase;

public class SequenceTest extends TestCase {

	public void testSystemGlobal() {
		System.out.println("读取配置:");
		System.out
				.println(SystemGlobal.get("sequence.define.xiaoShouNo.20110701"));
	}

	public void testSequence() {
		System.out.println("生成序号");
		System.out.println(SequenceUtils.render("xiaoShouNo"));
	}
}

分享到:
评论

相关推荐

    c# 自动序号生成

    针对硬件绑定 软件序列号生成 , 序列号检测, 相当的好用,都加了注释

    序号自动生成器.zip

    在这个“序号自动生成器.zip”压缩包中,包含了一个基于C#的源码项目,用户可以根据自己的需求进行定制,以满足特定的序号生成规则。 序号自动生成器的核心功能通常包括以下几点: 1. **序列生成策略**:序号可以...

    [FSG软件系统]密码/序号生成器 - Char Generate

    可自动生成各类序号、密码 可设置生成规则 可定长,定位,定内容生成 可设置排除或包含字串

    索尼全系列序号生成工具

    包括最新的sony vegas pro 11 crack

    c# 按日期+序号进行自动编号

    在网上搜了半天,都没有看到满意的程序。只好参照别人写的例子,自己写了。编号是按照年份和月份+三位序号自动生成的,用的是SQL server数据库,用VS2010编写的。调试已通过。希望给同为新手的各位一个参考。

    sql server 中如何增加递增的序号列【实用】

    递增的序号列是一种自动增长的序号,可以根据某个特定的规则或条件进行增长。例如,在管理客户信息时,可以根据客户的编号或注册时间来自动增长序号。这种序号列可以帮助我们更好地管理和分析数据。 现在,让我们来...

    利用SQL语句自动生成序号的两种方式.pdf

    自动生成序号的两种方式 利用 SQL 语句自动生成序号是数据库管理系统中的一种常用技术,本文将介绍两种利用 SQL 语句自动生成序号的方式,并详细解释每种方式的实现原理和应用场景。 第一种方式:使用 row_number...

    用来批量或按照某中规则命名的文件夹自动生成程序

    规则命名则是指用户可以设置一套命名规则,如序号、日期、特定字符串等,软件将自动按照这些规则为每个新生成的文件夹命名,确保了文件夹命名的统一性和可读性。 标签“文件夹生成”明确了该程序的主要应用场景,即...

    昊华智能二维码生成规则

    ### 昊华智能二维码生成规则详解 #### 一、引言 随着智能家居市场的快速发展,越来越多的家庭开始使用智能家居产品。为了确保这些智能设备能够被轻松识别和管理,昊华智能制定了一套详细的二维码生成规则及地址映射...

    SQLserver中按年月日生成日期型自增编码.pdf

    SQL Server 中按年月日生成日期型自增编码 本文档介绍了在 SQL Server 中生成日期型自增编码的方法,通过创建两个函数 `GenCustomCode` 和 `GenCustomID`,可以生成按年月日的日期型自增编码。该方法可以应用于各种...

    自动生成编号【sql】

    标题“自动生成编号【sql】”所指的是一种技术,用于在数据库表中创建自动递增或基于特定规则的唯一编号。在SQL Server 2005中,我们可以使用`IDENTITY`属性来创建自动递增的整数序列,适用于主键或序列号字段。例如...

    Oracle/MySQL以当前日期加顺番 生成编号

    //生成最大编号 规则为当前日期+6位顺番, //没有记录时,当前日期+000001 //当前日期比从数据库取得的最大日期大时, 当前日期+000001 //当前日期等于从数据库取得最大日期,顺番+1

    el-table树形表格表单验证(列表生成序号)

    在本文中,我们将深入探讨如何在使用Element Plus的`el-table`组件实现树形表格时进行表单验证以及如何生成序号。`el-table`是一个强大的数据展示组件,支持多种复杂的表格布局和功能,包括树形结构。在处理树形表格...

    .net实现新增数据时编号自动加一

    在存储过程中,我们可以根据业务规则来生成和返回自定义格式的编号。 3. **.NET代码控制**:在.NET应用程序中,我们也可以在插入数据前计算编号,然后将生成的编号和其它数据一起插入数据库。这通常适用于复杂或...

    springboot 导出excel 导入excel 生成excel 内容有点多

    在Spring Boot应用中,处理Excel文件的导出、导入和生成是常见...在实际开发中,可能需要根据业务需求进行更复杂的定制,如处理复杂格式、校验规则等。理解这些基础操作,可以灵活地构建满足各种需求的Excel处理功能。

    WPS表格序号应用技巧

    - **操作步骤**:选中需要设置条件格式的序号区域,点击“开始”选项卡下的“样式”组中的“条件格式”,根据需要选择合适的规则进行设置。 - **应用场景**:例如,对于超出一定范围的序号采用不同颜色高亮显示,...

    JAVA版本的生成唯一编号

    /** * 获得序列号,同时更新持久化存储中的序列 * @param current 当前的日期 * @param start 初始化的序号 * @return 所获得新的序列号 */ protected abstract int getOrUpdateNumber(Date current, int start);

Global site tag (gtag.js) - Google Analytics