Tiny Formater

格式化提供者,用于对字符串进行转换:

?


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了,所以,就只到此为止了。

虽然放弃了,但是其中在设计及基础构架方面的一些思想及模式,还是值得同学们参考与借鉴的。

时间: 2024-09-14 18:38:17

Tiny Formater的相关文章

使用TinySpider实战抓取自己博客中的内容

因为做官网,没有内容,因此就想办法从OSChina中写的博客里弄点内容,这就要用到爬虫了. 然后就花了几分钟搞了一下,步骤如下: 第一步,写个方法抓目录: ? 1 2 3 4 5 6 7 8 9 10 11 public static void processCategory(String categoryId) {         Watcher watcher = new WatcherImpl();         Spider spider = new SpiderImpl();    

Tiny框架启动过程日志

一个系统的日志,可以看到许多东东. 下面是Tiny框架的Web应用启动与停止过程 ? 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

悠然乱弹:“最好的模板引擎”Beetl 剖析及与Tiny模板引擎对比

Beetl的环境搭建 输入命令 ? 1 git clone https://git.oschina.net/xiandafu/beetl2.0.git 不一会儿,输出了下面的内容 ? 1 2 3 4 5 6 7 Cloning into 'beetl2.0'... remote: Counting objects: 5807, done. remote: Compressing objects: 100% (2145/2145), done. remote: Total 5807 (delta

Tiny模板引擎(Velocity Plus)应用示例

把TinyTemplate当成是Velocity的升级版其实也是可以的,毕竟它的语法是基到Veloccity扩展而来的,兼容度在80%以上. 至于TinyTemplate的实例是怎样的,且看下面: 宏的可变参数 在Java中的可变参数使用起来非常方便,Tiny模板也对可变参有一定支持. ? 1 2 3 4 5 6 7 8 #macro hello() ParameterList: ${helloParameterList.size()}     #for(para:helloParameterL

Tiny快速入门之Web界面快速开发实践

本来想改改OSChina的界面,但是研究了一下,OSChina界面实在是高大上呀,不是做不出来,只是工作量比较大,因此还是做个简单的网站来展示一下用Tiny开发界面的过程,同时在展示过程的同时,会把相关的知识做一个充分的介绍 . 一.寻找网站模板 要做网站,不能没有模板,自己不会做网页设计,咋办?问谷歌找百度呗,找了一阵,看到下面这个模板不错,就它了. http://www.tooplate.com/zip_files/2042_the_block.zip 相仔细了解这篇文章的同学,建议把原板的

从应用示例来认识Tiny框架

呵呵,Tiny框架神龙见首不见尾已经许多时间了,里面只看到一些几个孤零零的子框架.今天就通过Tiny开发示例的方式来重点展示一下利用Tiny框架是如何开发的. HelloWorld 首先从这个神一样的示例写起. 服务开发: 方式1:注解方式 ? 1 2 3 4 5 6 7 8 9 10 11 12 @ServiceComponent() public class HelloWorldAnnotationService{     @ServiceMethod(serviceId = "sayHel

TINY框架FAQ汇集

问题:Tiny的贡献者有哪些? 创建及主要设计者:悠悠然然 主要参与人员:Atizose,ballackhui,nishihe,达达 其它贡献人员:dandy 问题:要学习Tiny框架要有什么前提条件? 必备条件: 首先会Java 掌握Maven 熟悉git 可选条件: 有oschina的注册帐号:可以与Tiny框架构建者沟通 有oschina的git注册帐号:便于创建Tiny框架的Fork,并提交给原作者 对悠悠然然加粉:享受果粉待遇,得到辅导及及时回复 加入Q群:可即时互动 问题:学习Tin

构建Tiny生态圈

生态圈 生态圈又称商业生态圈,指商业活动的各利益相关者通过共同建立一个价值平台.各个角色关注其所在的价值平台的整体特性,通过平台撬动其它参与者的能力,使这一系统能够创造价值,并从中分享利益. 一个好的架构,必须构建一个围绕平台的生态系统,或者流行的说法,叫生态圈.因为再好的系统,如果只是做输出,总是会有这样那样不足的地方,Spring提供了一个依赖注入,实际上就是创建了一个Bean的生态圈,所以Spring的应用推广效果就非常好:Maven构建了一个插件生态圈和资产生态圈,所以,通过插件生态圈,

Tiny开发框架PPT介绍

我有一个梦想,那就是那一个NB的开发框架,让使用它的企业成本下降,让使用它的软件工程师轻松快乐.有人问我,你觉得smart框架与Tiny相比怎么样?我的回答是:smart是一个非常棒的框架.有人把JFinal的特性贴出来问我,你觉得Tiny框架与JFinal比怎么样?我的回答是:JFinal是一个非常出色的框架.不同的框架有不同的目标定位,有不同的目标群体,只要是使有者觉得不错,那就是合适的,就是好的.也有人非让我把Tiny框架和其它开源框架比较到底差异在哪里?这个问题确实不太好回答,于是我回答