Jsonview4 Framework

Fourth-generation Jsonview.

License

License

Categories

Categories

JSON Data
GroupId

GroupId

com.github.developframework
ArtifactId

ArtifactId

jsonview4
Last Version

Last Version

4.0.2
Release Date

Release Date

Type

Type

pom
Description

Description

Jsonview4 Framework
Fourth-generation Jsonview.
Project URL

Project URL

https://github.com/developframework/jsonview4
Source Code Management

Source Code Management

https://github.com/developframework/jsonview4

Download jsonview4

Filename Size
jsonview4-4.0.2.pom 6 KB
Browse

How to add to project

<!-- https://jarcasting.com/artifacts/com.github.developframework/jsonview4/ -->
<dependency>
    <groupId>com.github.developframework</groupId>
    <artifactId>jsonview4</artifactId>
    <version>4.0.2</version>
    <type>pom</type>
</dependency>
// https://jarcasting.com/artifacts/com.github.developframework/jsonview4/
implementation 'com.github.developframework:jsonview4:4.0.2'
// https://jarcasting.com/artifacts/com.github.developframework/jsonview4/
implementation ("com.github.developframework:jsonview4:4.0.2")
'com.github.developframework:jsonview4:pom:4.0.2'
<dependency org="com.github.developframework" name="jsonview4" rev="4.0.2">
  <artifact name="jsonview4" type="pom" />
</dependency>
@Grapes(
@Grab(group='com.github.developframework', module='jsonview4', version='4.0.2')
)
libraryDependencies += "com.github.developframework" % "jsonview4" % "4.0.2"
[com.github.developframework/jsonview4 "4.0.2"]

Dependencies

There are no dependencies for this project. It is a standalone project that does not depend on any other jars.

Project Modules

  • jsonview4-core
  • jsonview4-spring

Jsonview4

0. 文档传送

1. 简介

Jsonview框架构建于jackson框架之上,实现通过XML文件配置来自定义json格式,大大提升了java生成json字符串的自由性,让开发模块化更加便捷快速。

1.1. 运行环境

JDK8及以上

1.2. 使用方式

maven

<dependency>
	<groupId>com.github.developframework</groupId>
	<artifactId>jsonview4-core</artifactId>
	<version>4.0.2</version>
</dependency>

1.3. 依赖项

  • commons-lang3.jar
  • slf4j-api.jar
  • jackson-core.jar
  • jackson-databind.jar
  • jackson-annotations.jar
  • lombok.jar
  • expression.jar

2. HelloWorld

一个最简单的jsonview使用示例:

public class Application {

    public static void main(String[] args) {
        JsonviewFactory factory = new JsonviewFactory("/jsonview/jsonview-demo.xml");
        JsonProducer jsonProducer = factory.getJsonProducer();
        DataModel dataModel = new HashDataModel();
        dataModel.putData("sayHello", "Hello Jsonview4!");
        String json = jsonProducer.createJson(dataModel, "jsonview-demo", "first-view");
        System.out.println(json);
    }
}

你需要一份jsonview XML配置,位置在上述声明的/jsonview/jsonview-demo.xml:

<jsonview-configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                        xmlns="https://github.com/developframework/jsonview4/schema"
                        xsi:schemaLocation="
	https://github.com/developframework/jsonview4/schema
	https://github.com/developframework/jsonview4/schema/jsonview-configuration-4.0.xsd">

    <template-package namespace="jsonview-demo">

        <template id="first-view">
            <property data="sayHello"/>
        </template>
      
    </template-package>
</jsonview-configuration>

运行结果:

{"sayHello":"Hello Jsonview4!"}

3. 概览

3.1. java概览

3.1.1. DataModel

com.github.developframework.jsonview.data.DataModel接口是jsonview框架的数据模型。用于装载需要在json视图中渲染的数据或函数接口实现,数据由键值对构成。接口提供存入和取出数据的方法。 目前实现类仅有com.github.developframework.jsonview.data.HashDataModel 存取数据范例:

DataModel dataModel = new HashDataModel();
dataModel.putData("sayHello", "Hello Jsonview!");
Optional<Object> value = dataModel.getData("sayHello");
value.ifPresent(System.out::println);

3.1.2. Expression

com.github.developframework.expression.Expression类是jsonview框架从DataModel中提取数据的表达式。不论dataModel存的是java实体类还是Map对象都可以使用表达式取值。 范例:

  • student 你可以从DataModel对象内取得名为student的对象
  • #student 你可以从DataModel对象内 强制从根路径 取得名为student的对象
  • student.name 你可以从DataModel对象内取得名为student的对象的name属性值
  • students[0] 你可以从DataModel对象内取得名为students的数组内的第1个元素
  • student[0].name 你可以从DataModel对象内取得名为students的数组内的第1个元素的name属性值

Expression 的详细使用请查看独立项目expression

3.1.3. JsonviewFactory

com.github.developframework.jsonview.core.JsonviewFactory类是jsonview框架的构建工厂。使用jsonview框架的第一步就是建立该对象。 建立该对象需要提供配置文件路径的字符串,多份配置文件可以采用字符串数组。

final String[] configs = {"config1.xml", "config2.xml"};
JsonviewFactory jsonviewFactory = new JsonviewFactory(configs);

3.1.4. JsonviewConfiguration

com.github.developframework.jsonview.core.JsonviewConfiguration类为Jsonview框架的总配置文件,可以从JsonviewFactory中得到该对象。

JsonviewConfiguration jsonviewConfiguration = jsonviewFactory.getJsonviewConfiguration();

3.1.5. JsonProducer

com.github.developframework.jsonview.core.JsonProducer接口是json字符串建造类,执行一次生成json字符串的操作需要构建该对象。JsonProducer由JsonviewFactory生成。 该对象提供三个构建json字符串的方法:

public String createJson(DataModel dataModel, String namespace, String id, boolean isPretty);

返回json字符串

  • isPretty=true时可以美化json
public String createJson(DataModel dataModel, String namespace, String id);

返回json字符串,不美化

public void printJson(JsonGenerator generator, DataModel dataModel, String namespace, String id);

将json输出到ObjectMapper的generator对象

3.1.6. Template

com.github.developframework.jsonview.core.element.Template类,一个Template类的实例代表一种json的视图模板。它由namespaceid唯一确定。可以通过以下方法得到Template实例:

Template template = jsonviewConfiguration.extractTemplate("namespace", "id");

3.1.7. JsonviewTemplatePackage

com.github.developframework.jsonview.core.element.JsonviewTemplatePackage类,一个JsonviewTemplatePackage实例是一个命名空间,可以装载若干个Template实例。推荐将Template按功能有序存放于JsonviewTemplatePackage。通过以下方法得到JsonviewTemplatePackage对象:

JsonviewTemplatePackage jsonviewTemplatePackage = jsonviewConfiguration.getTemplatePackageByNamespace("namespace");

3.1.8. 异常

Jsonview框架的所有异常类。

异常 说明
JsonviewException jsonview顶级异常
ConfigurationSourceException 配置源异常
TemplateUndefinedException template未定义异常
TemplatePackageUndefinedException templatePackage未定义异常
JsonviewParseXmlException 配置文件解析错误异常
LinkSizeNotEqualException 使用link功能时数组大小不相等异常
ResourceNotUniqueException 资源定义不唯一异常
InvalidArgumentsException 无效的参数异常
DataUndefinedException data没有定义在DataModel异常

3.2. XML概览

3.2.1. 结构

Jsonview configuration 文档的结构如下:

<jsonview-configuration>
    <template-package namespace="">
    	<template id="">
    		<!-- 定义视图内容 -->
    	</template>
    	<template id="">
    		<!-- 定义视图内容 -->
    	</template>
    	<!-- 其它jsonview -->
    </template-package>
    <!-- 其它template-package -->
</jsonview-configuration>

<jsonview-configuration>节点中你可以配置任意数量的<template-package>,代表不同的模板包,在<template-package>节点上你必须声明命名空间namespace属性,并且namespace是唯一的,不然会抛出ResourceNotUniqueException

在每个<template-package>节点中你可以配置任意数量的<template>。每个<template>即代表了某一种json格式的视图,在<template>节点你必须声明id属性,并且id必须是唯一的,不然会抛出ResourceNotUniqueException

Jsonview configuration文档不是唯一的,Jsonview框架允许你拥有多份的Jsonview configuration配置文档,文档的加载顺序不分先后。

3.2.2. 标签

基本型标签

  • <template>
  • <object>
  • <array>
  • <property>
  • <prototype>

功能型标签

  • <include>
  • <link>
  • <relevance>
  • <object-virtual>
  • <property-ignore>
  • <extend-port>
  • <if><else>

拓展型标签

  • <property-date>

  • <property-unixtimestamp>

  • <property-boolean>

3.2.2.1. 基本型标签
a) template

当你需要声明一个json格式模板时,你将会使用到<template>标签。

<template id="" data="" for-class=""></jsonview>
属性 功能 是否必须
id 声明模板编号,在命名空间中唯一
data 取值表达式
for-class 声明data表达式指向的对象类型
extend 声明继承的jsonview和端口,格式为namespace.id:port(namespace不填时默认为当前namespace)
map-function 仅当data指代的数据为数组或List时有效。MapFunction的实现类全名或Expression表达式。详见5.1.2节
b) object

当你需要在json中构建一个对象结构时,你将会使用到<object>标签。详见4.1.节

<object data="" alias="" for-class="" null-hidden="true"></object>
属性 功能 是否必须
data 取值表达式
alias 别名,你可以重新定义显示名
for-class 声明data表达式指向的对象类型
null-hidden true时表示表达式取的值为null时隐藏该节点,默认为false
c) array

当你需要在json中构建一个数组结构时,你将会使用到<array>标签。详见4.6.节

<array data="" alias="" for-class="" null-hidden="true"></array>
属性 功能 是否必须
data 取值表达式
alias 别名,你可以重新定义显示名
for-class 声明data表达式指向的对象类型
null-hidden true时表示表达式取的值为null时隐藏该节点,默认为false
map-function MapFunction的实现类全名或Expression表达式。详见5.1.2节

<array>标签可以没有子标签,这时表示数组为基本类型数组。

d) property

当你需要在json中构建一个普通属性结构时, 你将会使用到<property>标签。

<property data="" alias="" converter="" null-hidden="true"/>
属性 功能 是否必须
data 取值表达式
alias 别名,你可以重新定义显示名
converter 类型转换器全限定类名或expression表达式。详见5.1.1节
null-hidden true时表示表达式取的值为null时隐藏该节点,默认为false
e) prototype

使用Jackson原型实体构建结构, 你将会使用到<prototype>标签。详见4.7.节

<prototype data="" alias="" converter="" null-hidden="true"/>
属性 功能 是否必须
data 取值表达式
alias 别名,你可以重新定义显示名
converter 类型转换器全限定类名或expression表达式。详见5.1.1节
null-hidden true时表示表达式取的值为null时隐藏该节点,默认为false
3.2.2.2. 功能型标签
a) include

Jsonview框架提供模块化设计json结构视图的功能。在一个<template>标签中你可以采用<include>标签来导入其它的<template>的结构内容,从而实现模块化单元分解。详见5.3.1.节

<include id="" namespace=""/>
属性 功能 是否必须
id 需要导入的jsonview id
namespace jsonview的命名空间,不填默认为当前命名空间
b) link

该标签用于实现一对一链接对象功能。详见5.4.1.节

<link data="" alias="" for-class="" null-hidden="true"></link>
属性 功能 是否必须
data 取值表达式,data必须指代一个List或array类型的对象
alias 别名,你可以重新定义显示名
for-class 声明data表达式指向的对象类型
null-hidden true时表示表达式取的值为null时隐藏该节点,默认为false
c) relevance

该标签用于实现一对多关联功能。详见5.4.2.节

<relevance data="" alias="" rel-function="" null-hidden="true"></relevance>
属性 功能 是否必须
data 取值表达式,data必须指代一个List或array类型的对象
alias 别名,你可以重新定义显示名
rel-function 关联判定器全限定类名或expression表达式
null-hidden true时表示表达式取的值为null时隐藏该节点,默认为false
map-function MapFunction的实现类全名或Expression表达式。详见5.1.2节
d) object-virtual

该标签用于虚拟对象结构。详见5.2.节

<object-virtual alias=""></object-virtual>
属性 功能 是否必须
alias 别名
e) property-ignore

忽略属性,需结合for-class属性使用。详见4.5.节

<property-ignore name=""/>
属性 功能 是否必须
name 类中忽略的属性名称
f) extend-port

此标签位置作为子<template>的接入位置。详见5.3.2节

<extend-port port-name=""/>
属性 功能 是否必须
port-name 端口名称
g) if else

分支结构标签。详见5.5.1节

<if condition="">

</if>
<else>

</else>
属性 功能 是否必须
condition 条件接口实现类全名或Expression表达式
3.2.2.3. 拓展型标签
a) property-date

该标签拓展于<property>,针对时间日期类型,使用pattern属性来格式化日期时间。详见4.3.1.节

拓展属性 功能 是否必须
pattern 格式化模板字符串,不填默认为"yyyy-MM-dd HH:mm:ss"

支持的时间日期类型:

  • java.util.Date
  • java.util.Calendar
  • java.sql.Date
  • java.sql.Time
  • java.sql.Timestamp
  • (JDK8) java.time.LocalDate
  • (JDK8) java.time.LocalDateTime
  • (JDK8) java.time.LocalTime
  • (JDK8) java.time.Instant
b) property-unixtimestamp

该标签拓展于<property>,针对时间日期类型,可以将时间日期类型转化为unix时间戳格式显示。可支持的时间日期类型同<property-date>。详见4.3.2.节

c) property-boolean

该标签拓展于<property>,可以将数字类型(short、int、long)变为boolean型,非0值为true,0值为false。详见4.3.3节

4. 基本使用

模型声明(以下各小节示例代码均使用这些模型实体类):

// 学生类 Student.java
@Data
public class Student {
    // 编号
    private int id;
    // 学生名称
    private String name;
    // 班级ID
    private int classId;
    // 出生日期
    private Date birthday;

    public Student(int id, String name, int classId, String birthday) {
        this.id = id;
        this.name = name;
        this.classId = classId;
        if(birthday != null) {
            DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
            try {
                this.birthday = dateFormat.parse(birthday);
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }
    }
}
// 账户类 Account.java   一个学生对应有一个账户
@Data
@AllArgsConstructor
public class Account {
    private String username;
    private String password;
}
// 班级类 SchoolClass.java   一个班级对应多个学生
@Data
@AllArgsConstructor
public class SchoolClass {

    private int id;

    private String className;
}

4.1. 简单输出模型对象Json

<!-- /jsonview/jsonview-student.xml --> 
<!-- 忽略jsonview-configuration -->
<template-package namespace="jsonview-student">
  <template id="student-detail" data="student">
    <property data="id"/>
    <property data="name"/>
    <property data="classId"/>
    <property data="birthday"/>
  </template>
</template-package>
// Application.java    main()
JsonviewFactory factory = new JsonviewFactory("/jsonview/jsonview-student.xml");
JsonProducer jsonProducer = factory.getJsonProducer();
DataModel dataModel = new HashDataModel();
Student peter = new Student(1, "Peter", 1, "1995-01-01");
dataModel.putData("student", peter);
String json = jsonProducer.createJson(dataModel, "jsonview-student", "student-detail");
System.out.println(json);

执行结果:

{"id":1,"name":"Peter","classId":1,"birthday":"Sun Jan 01 00:00:00 CST 1995"}

4.2. 使用alias修改显示名称

<!-- /jsonview/jsonview-student.xml --> 
<!-- 忽略jsonview-configuration -->
<template-package namespace="jsonview-student">
  <template id="student-detail" data="student">
    <property data="id" alias="student_id"/>
    <property data="name" alias="student_name"/>
    <property data="classId" alias="student_classId"/>
    <property data="birthday" alias="student_birthday"/>
  </template>
</template-package>
{"student_id":1,"student_name":"Peter","student_classId":1,"student_birthday":"Sun Jan 01 00:00:00 CST 1995"}

4.3. property扩展

4.3.1 使用property-date格式化日期时间

该标签可以格式化时间。 把4.1.节代码

<property data="birthday"/>

替换为

<property-date data="birthday" pattern="yyyy-MM-dd"/>

运行结果:

{"id":1,"name":"Peter","classId":1,"birthday":"1995-01-01"}

4.3.2 使用property-unixtimestamp输出时间戳

该标签可以使日期时间类型转化成时间戳形式输出。

dataModel.putData("datetime", LocalDateTime.of(2016, 1, 1, 0, 0, 0));
{"datetime" : 1451577600}

4.3.3 使用property-boolean转换

该标签可以把非0数字转换成true,0转换成false

DataModel dataModel = new HashDataModel();
dataModel.putData("number1", 1);
dataModel.putData("number2", 0);
{"number1" : true, "number2" : false}

4.4. 使用null-hidden隐藏值为null的属性

把4.1.节代码

<property data="birthday"/>

替换为

<property data="birthday" null-hidden="true"/>

student实例传入null的birthday值

Student student = new Student(1, "Peter", 1, null);

运行结果:

{"id":1,"name":"Peter","classId":1}

4.5. 使用for-class输出模型对象Json

<template id="student-detail" data="student" for-class="test.Student" />

运行结果和4.1.节相同。 使用property-ignore忽略不需要的属性:

<template id="student-detail" data="student" for-class="test.Student">
  <property-ignore name="birthday" />
</template>

运行结果:

{"id":1,"name":"Peter","classId":1}

4.6. 简单输出数组模型Json

利用array 标签构造一个数组结构:

<template id="student-list">
  <array data="students">
    <property data="name"/>
    <property data="classId"/>
    <property-date data="birthday" pattern="yyyy-MM-dd"/>
  </array>
</template>
Student peter = new Student(1, "Peter", 1, "1995-01-01");
Student john = new Student(2, "John", 1, "1996-5-20");
Student[] students = {peter, john};
dataModel.putData("students", students);
// isPretty参数设为true,开启json美化
String json = jsonProducer.createJson(dataModel, "jsonview-student", "student-list", true);
{
  "students" : [ {
    "id" : 1,
    "name" : "Peter",
    "classId" : 1,
    "birthday" : "1995-01-01"
  }, {
    "id" : 2,
    "name" : "John",
    "classId" : 1,
    "birthday" : "1996-05-20"
  } ]
}

或者直接把data设定在<template> 标签上,Jsonview框架会自动识别data对应的数据是否是数组或List。

<template id="student-list" data="students">
  <property data="id"/>
  <property data="name"/>
  <property data="classId"/>
  <property-date data="birthday" pattern="yyyy-MM-dd"/>
</template>
[ {
  "id" : 1,
  "name" : "Peter",
  "classId" : 1,
  "birthday" : "1995-01-01"
}, {
  "id" : 2,
  "name" : "John",
  "classId" : 1,
  "birthday" : "1996-05-20"
} ]

4.7. 使用Jackson原型实体

使用<prototype> 标签可以使用原生的Jackson方式转化实体成json。

<template id="student-detail">
  <prototype data="student" />
</template>
@Data
public class Student {
    // 编号
    private int id;
    // 学生名称
    @JsonProperty("student_name")	// 通过注解@JsonProperty对属性重命名
    private String name;
    // 班级ID
    @JsonIgnore		// 通过注解@JsonIgnore忽略该属性
    private int classId;
    // 出生日期
    @JsonFormat(locale="zh", timezone="GMT+8", pattern="yyyy-MM-dd")//通过@JsonFormat格式化日期
    private Date birthday;
    //构造方法略
}
{
  "student" : {
    "id" : 1,
    "birthday" : "1995-01-01",
    "student_name" : "Peter"
  }
}

更多注解使用请参考jackson-annotations文档。

5. 高级功能

5.1.处理器

5.1.1. <property> 的转换器 converter

com.github.developframework.jsonview.core.dynamic.PropertyConverter 接口可以对表达式选取的属性值进行自定义转换。

@FunctionalInterface
public interface PropertyConverter<TARGET> {

    /**
     * 转化方法
     * @param source 源对象
     * @return 目标对象
     */
    TARGET convert(Object source);
}
  • 泛型TARGET为转化后的类型。

例如将peter的name处理后输出:

<template id="student-detail" data="student">
  <property data="id" />
  <property data="name" converter="nameConverter"/>
  <property data="classId"/>
  <property-date data="birthday" pattern="yyyy-MM-dd"/>
</template>
dataModel.putData("student", peter);
// 这里采用JDK8 lambda写法
dataModel.putData("nameConverter", (PropertyConverter<String>) source -> "My name is " + source);
{
  "id" : 1,
  "name" : "My name is Peter",
  "classId" : 1,
  "birthday" : "1995-01-01"
}

<property> 系列标签的converter 属性可以填写Expression表达式,还可以填写PropertyConverter 的接口实现类全类名。

5.1.2. <array> 的元素映射器 map-function

<array>节点属性map-function用于指定对每个元素的映射函数。map-function的值可以为Expression表达式或一个实现com.github.developframework.jsonview.core.dynamic.MapFunction接口的完全类名。其中使用表达式方式,其获取的实例必须是com.github.developframework.jsonview.core.dynamic.MapFunction的实现类。具体示例:实现功能:对数组的每个元素进行映射处理,处理结果作为生成Json的数据。以下示例在字符串数组的每项元素以value_{item}_{i} 形式输出。

String[] strArray = new String[]{"aaa", "bbb", "ccc"};
dataModel.putData("strArray", strArray);
dataModel.putData("func", ((MapFunction<String, String>) (item, i) -> "value_" + item + "_" + i));
<template id="array-map-function-demo" >
  <array data="strArray" map-function="func"></array>
</template>
{"str_array":["value_aaa_0","value_bbb_1","value_ccc_2"]}

注意

使用map-function会导致<array>标签的所有子节点失效,因为映射结果将会直接作为json数据。

如果你设置了子节点将会出现以下警告:

The child element invalid, because you use "map-function" attribute.

5.2. 虚拟结构

使用<object-virtual>可以虚拟一个对象结构。 利用仅有的属性值,构造一个对象结构:

<template id="student-detail">
  <object-virtual alias="student">
    <property data="id"/>
    <property data="name"/>
    <property data="classId"/>
    <property-date data="birthday" pattern="yyyy-MM-dd"/>
  </object-virtual>
</template>
dataModel.putData("id", 1);
dataModel.putData("name", "Peter");
dataModel.putData("classId", 1);
dataModel.putData("birthday", "1995-01-01");
{
  "student" : {
    "id" : 1,
    "name" : "Peter",
    "classId" : 1,
    "birthday" : "1995-01-01"
  }
}

5.3. 模块化

5.3.1 引用

使用<include>标签引用其它<template>模板,从而可实现模块化设计,避免重复定义视图模板。

<template-package namespace="jsonview-student">
  <template id="student-list" data="students">
    <include id="student-detail" />
  </template>

  <template id="student-detail">
    <property data="id"/>
    <property data="name"/>
    <property data="classId"/>
    <property-date data="birthday" pattern="yyyy-MM-dd"/>
  </template>
</template-package>

5.3.2 继承

Jsonview框架的继承的概念,在<template>标签可以添加属性extend指定继承的template和继承的端口。继承的概念可以理解为反向include,调用子template视图,会优先从父template开始构造结构,当遇到匹配端口名的<extend-port>标签时才会构造子template视图。

**注意:**假如单独调用了有<extend-port>标签的父template视图或者端口没有与之对应的子template实现,则<extend-port>标签被忽略。

<template-package namespace="jsonview-student">
  <!-- 一个父视图模板  -->
  <template id="student-parent">
    <object-virtual alias="other">
      <property data="otherData" />
    </object-virtual>
    <!-- 子视图模板的内容将会插入到这个端口位置上 -->
    <extend-port port-name="my-port" />
  </template>

  <!-- 子视图模板  -->
  <template id="student-detail" extend="student-parent:my-port">
    <!-- 本模板内容将会插入到父视图模板的my-port端口位置上 -->
    <object data="student">
      <property data="id"/>
      <property data="name"/>
      <property data="classId"/>
      <property-date data="birthday" pattern="yyyy-MM-dd"/>
    </object>
  </template>
</template-package>
Student peter = new Student(1, "Peter", 1, "1995-01-01");
dataModel.putData("student", peter);
dataModel.putData("otherData", "I'm other data.");
// 这里调用的子视图模板
String json = jsonProducer.createJson(dataModel, "jsonview-student", "student-detail", true);
{
  "other" : {
    "otherData" : "I'm other data."
  },
  "student" : {
    "id" : 1,
    "name" : "Peter",
    "classId" : 1,
    "birthday" : "1995-01-01"
  }
}

extend 属性的写法为 namespace.templateId:portName 其中namespace可以省略,默认为当前命名空间下。

5.4. 链接与关联

5.4.1. 一对一数组链接

使用<link> 标签可以在数组间一对一链接对象。**该标签仅能在<array>下使用。**当<link> 的data属性所指的数组和父<array>数组个数不相同时将会抛出LinkSizeNotEqualException。 例子: 假如每个学生实例都有一个账户实例,并且又都一对一对应了一个成绩值。

<template-package namespace="jsonview-student">

  <template id="student-list" data="students">
    <property data="id"/>
    <property data="name"/>
    <property data="classId"/>
    <property-date data="birthday" pattern="yyyy-MM-dd"/>
    <!-- 一对一对应accounts数组每项 -->
    <link data="#accounts" alias="account">
      <!-- 引用另一个命名空间的模板 -->
      <include id="account-detail" namespace="jsonview-account"/>
    </link>
    <!-- 一对一对应scores数组每项 -->
    <link data="#scores" alias="score"/>
  </template>
</template-package>

<template-package namespace="jsonview-account">

  <template id="account-detail">
    <property data="username"/>
    <property data="password"/>
  </template>
</template-package>
 Account peterAccount = new Account("peter's username", "peter's password");
Account johnAccount = new Account("john's username", "john's password");

Student[] students = {peter, john};
Account[] accounts = {peterAccount, johnAccount};
Integer[] scores = {95, 98};

dataModel.putData("students", students);
dataModel.putData("accounts", accounts);
dataModel.putData("scores", scores);
[ {
  "id" : 1,
  "name" : "Peter",
  "classId" : 1,
  "birthday" : "1995-01-01",
  "account" : {
    "username" : "peter's username",
    "password" : "peter's password"
  },
  "score" : 95
}, {
  "id" : 2,
  "name" : "John",
  "classId" : 1,
  "birthday" : "1996-05-20",
  "account" : {
    "username" : "john's username",
    "password" : "john's password"
  },
  "score" : 98
} ]

5.4.2. 根据条件关联

假如A数组有2个元素,B数组有3个元素。其中A[0] 需要关联B[0]和B[1], A[1] 需要关联B[2]。这种需求下就可以使用<relevance>标签,实现在数组间一对多关联。属性rel-function 指定判定条件,需要实现一个接口:

public interface RelFunction<S, T> {

    boolean relevant(S sourceItem, int sourceIndex, T target, int targetIndex);
}

其中泛型S指代A数组类型,T指代B数组类型。

sourceItem是迭代了A数组的每一项,sourceIndex是它的索引。每一项的A元素都会去迭代B数组的每一项target,targetIndex是索引,relevant 方法返回true表示需要关联。

具体看示例,有如下数据结构关系:

// 1班
SchoolClass schoolClass1 = new SchoolClass(1, "1班");
// 2班
SchoolClass schoolClass2 = new SchoolClass(2, "2班");
// 1班的学生
Student peter = new Student(1, "Peter", 1, "1995-01-01");
Student john = new Student(2, "John", 1, "1996-5-20");
// 2班的学生
Student bill = new Student(3, "Bill", 2, "1993-4-16");

Student[] students = {peter, john, bill};
SchoolClass[] schoolClasses = {schoolClass1, schoolClass2};
dataModel.putData("students", students);
dataModel.putData("schoolClasses", schoolClasses);
<template-package namespace="jsonview-student">
  <template id="student-detail">
    <property data="name"/>
    <property-date data="birthday" pattern="yyyy-MM-dd"/>
  </template>
</template-package>

<template-package namespace="jsonview-class">
  <template id="class-list" data="schoolClasses">
    <property data="id" />
    <property data="className" />
    <!-- 关联学生列表 -->
    <relevance data="#students" rel-function="rel-function">
      <include id="student-detail" namespace="jsonview-student" />
    </relevance>
  </template>
</template-package>

实现RelFunction

dataModel.putData("rel-function", (RelFunction<SchoolClass, Student>) (sourceItem, sourceIndex, target, targetIndex) -> sourceItem.getId() == target.getClassId());

判定条件为当SchoolClass(sourceItem)的id与Student(target)的classId相等时,允许关联。

[ {
  "id" : 1,
  "className" : "1班",
  "students" : [ {
    "name" : "Peter",
    "birthday" : "1995-01-01"
  }, {
    "name" : "John",
    "birthday" : "1996-05-20"
  } ]
}, {
  "id" : 2,
  "className" : "2班",
  "students" : [ {
    "name" : "Bill",
    "birthday" : "1993-04-16"
  } ]
} ]

5.5. 分支结构

5.5.1. <if> <else>

可以使用<if> <else> 标签进行模块内容的取舍。<else> 标签可以不写,但必须紧跟<if> 后出现。

<if> 标签的condition 属性内容为接口com.github.developframework.jsonview.core.dynamic.Condition 的实现类或直接使用Boolean类型。

@FunctionalInterface
public interface Condition {

    /**
     * 判断条件
     * @param dataModel 数据模型
     * @param expression 当前位置的表达式
     * @return 判断结果
     */
    boolean verify(DataModel dataModel, Expression expression);
}

最简范例:

<template id="first-view">
  <if condition="myCondition">
    <property data="sayHello"/>
  </if>
  <else>
    <property data="sayBye"/>
  </else>
</template>
dataModel.putData("sayHello", "Hello");
dataModel.putData("sayBye", "Bye");
dataModel.putData("myCondition", (Condition) (dm, expression) -> true);
// 或直接使用boolean
// dataModel.putData("myCondition", true);
{"sayHello" : "Hello"}

当myCondition 接口返回false时

{"sayBye" : "Bye"}

6. 日志

Jsonview框架使用slf4j-api日志接口,提供内部日志打印功能。可以使用log4j或者logback打印日志。 以下示例使用logback

<configuration scan="true" scanPeriod="60 seconds" debug="false">
	<contextName>jsonview-log</contextName>
	<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
		<encoder>
			<pattern>%d{HH:mm:ss.SSS} %-5level - %msg%n
			</pattern>
		</encoder>
	</appender>
	<logger name="com.github.developframework.jsonview" level="INFO" additivity="false">
		<appender-ref ref="STDOUT" />
	</logger>
</configuration>

项目启动日志:

09:29:07.753 INFO  - Jsonview framework loaded the configuration source "/jsonview/jsonview-demo.xml".

Versions

Version
4.0.2
4.0.1
4.0.0