格式化提供者,用于对字符串进行转换:
1
2
3
4
5
6
7
8
9
10
11
12
|
public
interface
FormatProvider {
/**
* 把指定的值进行处理后返回
*
* @param string
* 要进行格式化的值
* @return 格式化好的值
* @throws FormatException
*/
String format(Context context, String string)
throws
FormatException;
}
|
接口方法只有一个,输入有两个参数,一个是上下文,一个是要进行格式的串,返回的值是格式化处理好的串。
当然,我也担心,一些串可能会与我们的点位符有冲突,因此期望能由用户自行指定点位符,因此设定了下面的接口:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
|
/**
* 模式匹配处理接口
*
* @author luoguo
*
*/
public
interface
PatternDefine {
/**
* 返回正则匹配
*
* @return
*/
Pattern getPattern();
/**
* 设置前缀
*
* @param prefixPatternString
*/
void
setPrefixPatternString(String prefixPatternString);
/**
* 设置后缀
*
* @param postfixPatternString
*/
void
setPostfixPatternString(String postfixPatternString);
/**
* 设置正则表达式中间部分
*
* @param patternString
*/
void
setPatternString(String patternString);
/**
* 返回正文部分
*
* @param string
* @return
*/
String getPureMatchText(String string);
/**
* 根据正文返回完整部分
*
* @param string
* @return
*/
String getFullMatchText(String string);
/**
* 设置域分隔符
*
* @return
*/
void
setSplitChar(
char
splitChar);
/**
* 返回分隔符
*
* @return
*/
char
getSplitChar();
}
|
当然上面的接口如果是固定一个的话,框架内部已经提供,不必另行进行扩展。
格式化接口如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
/**
* 格式化的接口
*
* @author luoguo
*
*/
public
interface
Formater
extends
FormatProvider {
/**
* 设置正则表达式,如果不想用默认正则表达式,可以通过此方法自行定义
*
* @param patternHandle
*/
void
setPatternHandle(PatternDefine patternHandle);
/**
* 设置格式化提供者
*
* @param formatProviders
* Key为匹配范围符
*/
void
setFormatProviders(Map<String, FormatProvider> formatProviders);
/**
* 添加格式化提供者
* @param prefix 前缀
* @param formatProvider
*/
void
addFormatProvider(String prefix, FormatProvider formatProvider);
}
|
三个方法, setPatternHandle用于设定格式话模式,setFormatProviders用于设定格式化提供者,由于是一个map,key值是前缀,value是对应的格式化处理器。当然也可以通过addFormatProvider一个一个的增加出来。
好的,接口的事情就搞定了,我们来看看具体的实现类:
默认的格式化实现类:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
public
class
DefaultPatternDefine
implements
PatternDefine {
private
static
final
String DEFAULT_PATTERN_STRING =
"([$]+[{]+[a-zA-Z0-9[.[_[:[/[#]]]]]]+[}])"
;
private
static
final
String DEFAULT_POSTFIX_PATTERN_STRING =
"}"
;
private
static
final
String DEFAULT_PREFIX_PATTERN_STRING =
"${"
;
private
static
final
char
DEFAULT_SPLIT_CHAR =
':'
;
private
String prefixPatternString = DEFAULT_PREFIX_PATTERN_STRING;
// 前缀
private
String postfixPatternString = DEFAULT_POSTFIX_PATTERN_STRING;
// 后缀
private
String patternString = DEFAULT_PATTERN_STRING;
// 中间部分
private
Pattern pattern;
private
char
splitChar = DEFAULT_SPLIT_CHAR;
// 域分隔符
public
Pattern getPattern() {
if
(pattern ==
null
) {
pattern = Pattern.compile(patternString);
}
return
pattern;
}
public
void
setPrefixPatternString(String prefixPatternString) {
this
.prefixPatternString = prefixPatternString;
}
public
void
setPostfixPatternString(String postfixPatternString) {
this
.postfixPatternString = postfixPatternString;
}
public
void
setPatternString(String patternString) {
this
.patternString = patternString;
}
public
String getPureMatchText(String string) {
int
startPos = prefixPatternString.length();
int
endPos = string.length() - postfixPatternString.length();
return
string.substring(startPos, endPos);
}
public
String getFullMatchText(String string) {
return
String.format(
"%s%s%s"
, prefixPatternString, string,
postfixPatternString);
}
public
void
setSplitChar(
char
splitChar) {
this
.splitChar = splitChar;
}
public
char
getSplitChar() {
return
splitChar;
}
}
|
下面是一个针对Context的格式串:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
public
class
ContextFormater
implements
FormatProvider {
public
String format(Context context, String string)
throws
FormatException {
Object obj = context.get(string);
if
(obj !=
null
) {
return
obj.toString();
}
int
index = string.indexOf(
'.'
);
if
(index >
0
) {
String name = string.substring(
0
, index);
obj = context.get(name);
if
(obj !=
null
) {
String property = string.substring(index +
1
);
try
{
return
BeanUtils.getProperty(obj, property).toString();
}
catch
(Exception e) {
throw
new
FormatException(e);
}
}
}
return
null
;
}
}
|
下面是核心的格式化算法了:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
|
public
class
FormaterImpl
implements
Formater {
private
Map<String, FormatProvider> formatProviders;
private
PatternDefine patternDefine =
new
DefaultPatternDefine();
/**
* 构造函数 使用默认的配置加载器
*/
public
FormaterImpl() {
}
/**
* 格式化找到的内容,其余内容不变,如果找不到内容,则原样保留
*
* @throws FormatException
*/
public
String format(Context context, String source)
throws
FormatException {
Matcher matcher = patternDefine.getPattern().matcher(source);
StringBuffer buf =
new
StringBuffer();
int
curpos =
0
;
while
(matcher.find()) {
String replaceStr = patternDefine.getPureMatchText(matcher.group());
buf.append(source.substring(curpos, matcher.start()));
curpos = matcher.end();
String str = formatSingle(context, replaceStr);
if
(str !=
null
) {
buf.append(str);
}
continue
;
}
buf.append(source.substring(curpos));
return
buf.toString();
}
/**
* 格式化字符串
*
* @param string
* String
* @return String
* @throws FormatException
* @throws Exception
*/
private
String formatSingle(Context context, String string)
throws
FormatException {
String s[] = string.split(patternDefine.getSplitChar() +
""
);
if
(s.length >=
2
) {
FormatProvider o = (FormatProvider) formatProviders.get(s[
0
]);
if
(o !=
null
) {
return
o.format(context, s[
1
]);
}
}
else
{
FormatProvider o = (FormatProvider) formatProviders.get(
""
);
if
(o !=
null
) {
return
o.format(context, string);
}
}
return
patternDefine.getFullMatchText(string);
}
public
void
setFormatProviders(Map<String, FormatProvider> formatProviders) {
this
.formatProviders = formatProviders;
}
public
void
setPatternHandle(PatternDefine patternHandle) {
this
.patternDefine = patternHandle;
}
public
void
addFormatProvider(String prefix, FormatProvider formatProvider) {
if
(formatProviders ==
null
) {
formatProviders =
new
HashMap<String, FormatProvider>();
}
formatProviders.put(prefix, formatProvider);
}
}
|
好吧,还有一些配置相关的类,由于不是关键性的,就不在这里讲了,那么接下来看示例:
增加一个常量格式化提供者:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
public
class
ConstFormatProvider
implements
FormatProvider {
Map<String, String> constMap =
new
HashMap<String, String>();
public
String format(Context context, String key) {
return
constMap.get(key);
}
public
Map<String, String> getConstMap() {
return
constMap;
}
public
void
setConstMap(Map<String, String> constMap) {
this
.constMap = constMap;
}
}
|
再增加一个日期格式化提供者:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
public
class
DateFormatProvider
implements
FormatProvider {
Map<String, String> constMap =
new
HashMap<String, String>();
public
String format(Context context, String key) {
return
constMap.get(key);
}
public
Map<String, String> getConstMap() {
return
constMap;
}
public
void
setConstMap(Map<String, String> constMap) {
this
.constMap = constMap;
}
}
|
再增加一个用于测试的POJO类:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
public
class
User {
String name;
int
age;
public
String getName() {
return
name;
}
public
void
setName(String name) {
this
.name = name;
}
public
int
getAge() {
return
age;
}
public
void
setAge(
int
age) {
this
.age = age;
}
public
User() {
}
public
User(String name,
int
age) {
this
.name = name;
this
.age = age;
}
}
|
好吧,我承认,前面都是做铺垫,跑龙套的,真正的秀场下面开始:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
/**
* 测试不存在任何标记情况
*
* @throws FormatException
*/
public
void
testFormatNotPlaceholder()
throws
FormatException {
assertEquals(
"this is test"
, formater.format(context,
"this is test"
));
}
/**
* 测试存在标记,且有处理提供者处理的情况
*
* @throws FormatException
*/
public
void
testFormatExistPlaceholderProvider()
throws
FormatException {
Context context =
new
ContextImpl();
assertEquals(
"this is v1 test"
,
formater.format(context,
"this is ${const:1} test"
));
}
/**
* 测试存在标记,且没有处理提供者处理的情况
*
* @throws FormatException
*/
public
void
testFormatExistPlaceholderNoProvider()
throws
FormatException {
assertEquals(
"this is ${abc:2} test"
,
formater.format(context,
"this is ${abc:2} test"
));
}
/**
* 测试存在标记,且是bean的情况
*
* @throws FormatException
*/
public
void
testFormatBean()
throws
FormatException {
User user =
new
User(
"aa"
,
123
);
context.put(
"user"
, user);
assertEquals(
"this is aa test 123"
,
formater.format(context,
"this is ${context:user.name} test ${context:user.age}"
));
}
|
下面总结一下:
上面的格式化占位符方式是${...}方式的,中间的...可以是aa:bb的方式,或者直接是bb的方式,冒号前面实际是一个区域的概念,表示由对应的区域处理器进行处理。这样就可以由开发人员不断的扩展格式化处理器的处理能力。由于占位匹配器也是可以进行扩展的,因此,可以自行定义自己的格式化占位方式。
对于对象的属性可以无限向下“.”下去,当然也可以添加其它的处理方式,比如:数组之类的。
所以从功能及定位来说,与@Brin想写程序 是一样的。
剧透一下:当时我本来是想写模板语言的,后来直接选择复用Velocity了,所以,就只到此为止了。
虽然放弃了,但是其中在设计及基础构架方面的一些思想及模式,还是值得同学们参考与借鉴的。