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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158

@PersistenceContext
private EntityManager entityManager;


@Override
public List<Map<String, Object>> findAllByProperties(String... properties) {
return findAllByProperties(null, properties);
}


@Override
public List<Map<String, Object>> findAllByProperties(Specification<T> specification, String... properties) {
return findAllByProperties(specification, null, properties).getContent();
}


@Override
public Page<Map<String, Object>> findAllByProperties(Specification<T> specification, Pageable pageable, String... properties) {
List<GroupAggregateProperty> groupAggregateProperties = Lists.newArrayList();
for (String property : properties) {
GroupAggregateProperty groupAggregateProperty = new GroupAggregateProperty();
groupAggregateProperty.setAlias(property);
groupAggregateProperty.setLabel(property);
groupAggregateProperty.setName(property);
groupAggregateProperties.add(groupAggregateProperty);
}
Expression<?>[] expressions = buildExpressions(groupAggregateProperties);
CriteriaQuery<Tuple> select = getTupleQuery().multiselect(expressions);

if (specification != null) {
Predicate where = specification.toPredicate(getRoot(), getTupleQuery(), getCriteriaBuilder());
select.where(where);
}

// 排序处理
if (pageable != null && pageable.getSort() != null) {
Iterator<Sort.Order> orders = pageable.getSort().iterator();
List<javax.persistence.criteria.Order> jpaOrders = Lists.newArrayList();
while (orders.hasNext()) {
Sort.Order order = orders.next();
String alias = order.getProperty();
//目前发现JPA不支持传入alias作为排序属性,因此只能基于alias找到匹配的Expression表达式作为排序参数
List<Selection<?>> selections = select.getSelection().getCompoundSelectionItems();
for (Selection<?> selection : selections) {
if (selection.getAlias().equals(alias)) {
if (order.isAscending()) {
jpaOrders.add(getCriteriaBuilder().asc((Expression<?>) selection));
} else {
jpaOrders.add(getCriteriaBuilder().desc((Expression<?>) selection));
}
break;
}
}
}
select.orderBy(jpaOrders);
}

TypedQuery<Tuple> typedQuery = getEntityManager().createQuery(select);
//动态追加分页参数
if (pageable != null) {
typedQuery.setFirstResult(pageable.getOffset());
typedQuery.setMaxResults(pageable.getPageSize());
}
List<Tuple> tuples = typedQuery.getResultList();
List<Map<String, Object>> datas = Lists.newArrayList();
for (Tuple tuple : tuples) {
Map<String, Object> map = Maps.newHashMap();
groupAggregateProperties.forEach(groupAggregateProperty -> {
map.put(groupAggregateProperty.getLabel(), tuple.get(groupAggregateProperty.getAlias()));
});
datas.add(map);
}

if (pageable != null) {
// 加上过滤条件后的总数量
Long count = count(specification);
return new PageImpl<>(datas, pageable, count);
} else {
return new PageImpl<>(datas);
}
}

private Expression<?> buildExpression(String name, String alias) {
Root<T> root = getRoot();
Path<?> item;
if (name.contains(".")) {
String[] props = StringUtils.split(name, ".");
item = root.get(props[0]);
for (int j = 1; j < props.length; j++) {
item = item.get(props[j]);
}
} else {
item = root.get(name);
}
Expression<?> expr = item;
if (alias != null) {
expr.alias(alias);
}
return expr;
}

private Expression<?>[] buildExpressions(List<GroupAggregateProperty> groupAggregateProperties) {
Expression<?>[] parsed = new Expression<?>[groupAggregateProperties.size()];
int i = 0;
for (GroupAggregateProperty groupAggregateProperty : groupAggregateProperties) {
parsed[i++] = buildExpression(groupAggregateProperty.getName(), groupAggregateProperty.getAlias());
}
return parsed;
}

private class GroupAggregateProperty {
@MetaData(value = "字面属性", comments = "最后用于前端JSON输出的key")
private String label;
@MetaData(value = "JPA表达式", comments = "传入JPA CriteriaBuilder组装的内容")
private String name;
@MetaData(value = "JPA表达式alias", comments = "用于获取聚合值的别名")
private String alias;

public String getLabel() {
return label;
}

public void setLabel(String label) {
this.label = label;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getAlias() {
return alias;
}

public void setAlias(String alias) {
this.alias = alias;
}
}