规则序号生成

需求说明:
[list]
[*]进销存销售产品时,需要系统按规则生成一个销售订单号
[*]订单号需要生成如"XS-日期-序号"的格式。其中“日期”为当天日期、“序号”为当天当前的销售单量并且不足四位时,以“0”填充在数量之前。如“XS-20100501-0050”
[*]可以系统中维护订单号生成规则,并且不影响之前生成的订单号
[/list]
解决办法:
一、分析需求,可确认销售订单序号的规则为“XS-日期-序号”,其中“序号”要以“日期”为因子进行归零递归。抽象出生成序号的规则“[b]XS-{DATE}-{S4[DATE]}[/b]”。
其他可能应用到规则如下:
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[table]
|字段描述 |字段名称 |字段类型
|id |definitionId |bigint
|规则序号名称 |definitionName |varchar(50)
|规则序号描述 |definitionComment|varchar(50)
|规则序号定义 |definitionRule|varchar(100)
[/table]
规则实例表RuleInst
[table]
|字段描述 |字段名称 |字段类型
|id |definitionId |bigint
|规则序号名称 |definitionName |varchar(50)
|序号增长因子 |iterateGene|varchar(50)
|当前最大值 |maxValue|int
[/table]
三、编写实现类(以正则表达式方式实现)
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"));
}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值