33import com .codingapi .springboot .framework .dto .request .Filter ;
44import com .codingapi .springboot .framework .dto .request .PageRequest ;
55import com .codingapi .springboot .framework .dto .request .RequestFilter ;
6- import jakarta .persistence .criteria .CriteriaBuilder ;
7- import jakarta .persistence .criteria .Order ;
8- import jakarta .persistence .criteria .Predicate ;
9- import jakarta .persistence .criteria .Root ;
106import org .springframework .beans .BeanUtils ;
117import org .springframework .data .domain .Example ;
128
9+ import jakarta .persistence .ManyToMany ;
10+ import jakarta .persistence .ManyToOne ;
11+ import jakarta .persistence .OneToMany ;
12+ import jakarta .persistence .OneToOne ;
13+ import jakarta .persistence .criteria .*;
1314import java .beans .PropertyDescriptor ;
15+ import java .lang .reflect .Field ;
1416import java .util .ArrayList ;
1517import java .util .Date ;
1618import java .util .List ;
19+ import java .util .Set ;
1720
1821public class QueryRequest {
1922
@@ -52,10 +55,22 @@ public <T> Example<T> getExample() {
5255
5356
5457 private List <String > getClazzProperties () {
58+ return getClazzProperties (clazz );
59+ }
60+
61+ private List <String > getClazzProperties (Class <?> clazz ) {
5562 List <String > properties = new ArrayList <>();
5663 PropertyDescriptor [] descriptors = BeanUtils .getPropertyDescriptors (clazz );
5764 for (PropertyDescriptor descriptor : descriptors ) {
58- properties .add (descriptor .getName ());
65+ Class <?> propertyType = descriptor .getPropertyType ();
66+ String name = descriptor .getName ();
67+ if (propertyType .getPackage () != null && !propertyType .getPackage ().getName ().startsWith ("java" )) {
68+ List <String > childProperties = getClazzProperties (propertyType );
69+ for (String child : childProperties ) {
70+ properties .add (name + "." + child );
71+ }
72+ }
73+ properties .add (name );
5974 }
6075 return properties ;
6176 }
@@ -73,91 +88,113 @@ public <T> List<Order> getOrder(Root<T> root, CriteriaBuilder criteriaBuilder) {
7388 return orderList ;
7489 }
7590
91+ private Path getPathByKey (Root root , String key ) {
92+ String [] keys = key .split ("\\ ." );
93+ if (keys .length > 1 ) {
94+ String lastKey = keys [keys .length -1 ];
95+ From current = root ;
96+ for (int i =0 ;i < keys .length -1 ;i ++) {
97+ String item = keys [i ];
98+ Set <Join > joins = current .getJoins ();
99+ for (Join <?, ?> join : joins ) {
100+ if (join .getModel ().getBindableJavaType ().getSimpleName ().equalsIgnoreCase (item )) {
101+ current = join ;
102+ }
103+ }
104+ }
105+ return current .get (lastKey );
106+ } else {
107+ return root .get (key );
108+ }
109+ }
110+
76111
77112 private <T > Predicate toPredicate (Filter filter , CriteriaBuilder criteriaBuilder , Root <T > root , List <String > properties ) {
78113 String key = filter .getKey ();
79114 if (filter .isAndFilters () || filter .isOrFilters () || properties .contains (key )) {
80115
116+ Path path = getPathByKey (root , key );
117+
81118 if (filter .isEqual ()) {
82- return criteriaBuilder .equal (root . get ( key ) , filter .getValue ()[0 ]);
119+ return criteriaBuilder .equal (path , filter .getValue ()[0 ]);
83120 }
84121
85122 if (filter .isLike ()) {
86123 String matchValue = (String ) filter .getValue ()[0 ];
87- return criteriaBuilder .like (root . get ( key ) , "%" + matchValue + "%" );
124+ return criteriaBuilder .like (path , "%" + matchValue + "%" );
88125 }
89126
90127 if (filter .isBetween ()) {
91128 Object value1 = filter .getValue ()[0 ];
92129 Object value2 = filter .getValue ()[2 ];
93130 if (value1 instanceof Integer && value2 instanceof Integer ) {
94- return criteriaBuilder .between (root . get ( key ) , (Integer ) value1 , (Integer ) value2 );
131+ return criteriaBuilder .between (path , (Integer ) value1 , (Integer ) value2 );
95132 }
96133
97134 if (value1 instanceof Long && value2 instanceof Long ) {
98- return criteriaBuilder .between (root . get ( key ) , (Long ) value1 , (Long ) value2 );
135+ return criteriaBuilder .between (path , (Long ) value1 , (Long ) value2 );
99136 }
100137
101138 if (value1 instanceof Date && value2 instanceof Date ) {
102- return criteriaBuilder .between (root . get ( key ) , (Date ) value1 , (Date ) value2 );
139+ return criteriaBuilder .between (path , (Date ) value1 , (Date ) value2 );
103140 }
104141 }
105142
106143 if (filter .isGreaterThan ()) {
107144 Object value = filter .getValue ()[0 ];
108145 if (value instanceof Integer ) {
109- return criteriaBuilder .greaterThan (root . get ( key ) , (Integer ) value );
146+ return criteriaBuilder .greaterThan (path , (Integer ) value );
110147 }
111148 if (value instanceof Long ) {
112- return criteriaBuilder .greaterThan (root . get ( key ) , (Long ) value );
149+ return criteriaBuilder .greaterThan (path , (Long ) value );
113150 }
114151 if (value instanceof Date ) {
115- return criteriaBuilder .greaterThan (root . get ( key ) , (Date ) value );
152+ return criteriaBuilder .greaterThan (path , (Date ) value );
116153 }
117154 }
118155
119156 if (filter .isGreaterThanEqual ()) {
120157 Object value = filter .getValue ()[0 ];
121158 if (value instanceof Integer ) {
122- return criteriaBuilder .greaterThanOrEqualTo (root . get ( key ) , (Integer ) value );
159+ return criteriaBuilder .greaterThanOrEqualTo (path , (Integer ) value );
123160 }
124161 if (value instanceof Long ) {
125- return criteriaBuilder .greaterThanOrEqualTo (root . get ( key ) , (Long ) value );
162+ return criteriaBuilder .greaterThanOrEqualTo (path , (Long ) value );
126163 }
127164 if (value instanceof Date ) {
128- return criteriaBuilder .greaterThanOrEqualTo (root . get ( key ) , (Date ) value );
165+ return criteriaBuilder .greaterThanOrEqualTo (path , (Date ) value );
129166 }
130167 }
131168
132169 if (filter .isLessThan ()) {
133170 Object value = filter .getValue ()[0 ];
134171 if (value instanceof Integer ) {
135- return criteriaBuilder .lessThan (root . get ( key ) , (Integer ) value );
172+ return criteriaBuilder .lessThan (path , (Integer ) value );
136173 }
137174 if (value instanceof Long ) {
138- return criteriaBuilder .lessThan (root . get ( key ) , (Long ) value );
175+ return criteriaBuilder .lessThan (path , (Long ) value );
139176 }
140177 if (value instanceof Date ) {
141- return criteriaBuilder .lessThan (root . get ( key ) , (Date ) value );
178+ return criteriaBuilder .lessThan (path , (Date ) value );
142179 }
143180 }
144181
145182 if (filter .isLessThanEqual ()) {
146183 Object value = filter .getValue ()[0 ];
147184 if (value instanceof Integer ) {
148- return criteriaBuilder .lessThanOrEqualTo (root . get ( key ) , (Integer ) value );
185+ return criteriaBuilder .lessThanOrEqualTo (path , (Integer ) value );
149186 }
150187 if (value instanceof Long ) {
151- return criteriaBuilder .lessThanOrEqualTo (root . get ( key ) , (Long ) value );
188+ return criteriaBuilder .lessThanOrEqualTo (path , (Long ) value );
152189 }
153190 if (value instanceof Date ) {
154- return criteriaBuilder .lessThanOrEqualTo (root . get ( key ) , (Date ) value );
191+ return criteriaBuilder .lessThanOrEqualTo (path , (Date ) value );
155192 }
156193 }
157194
158195 if (filter .isIn ()) {
159196 Object [] value = filter .getValue ();
160- CriteriaBuilder .In <Object > in = criteriaBuilder .in (root . get ( key ) );
197+ CriteriaBuilder .In <Object > in = criteriaBuilder .in (path );
161198 for (Object item : value ) {
162199 in .value (item );
163200 }
@@ -192,10 +229,33 @@ private <T> Predicate toPredicate(Filter filter, CriteriaBuilder criteriaBuilder
192229 }
193230
194231
232+ private void fetchJoins (From root , Class <?> clazz ) {
233+ Field [] fields = clazz .getDeclaredFields ();
234+ for (Field field : fields ) {
235+ if (field .getAnnotation (OneToOne .class ) != null ) {
236+ Join <?, ?> join = root .join (field .getName (), JoinType .INNER );
237+ this .fetchJoins (join , field .getType ());
238+ }
239+ if (field .getAnnotation (ManyToOne .class ) != null ) {
240+ Join <?, ?> join = root .join (field .getName (), JoinType .INNER );
241+ this .fetchJoins (join , field .getType ());
242+ }
243+ if (field .getAnnotation (OneToMany .class ) != null ) {
244+ Join <?, ?> join = root .join (field .getName (), JoinType .INNER );
245+ this .fetchJoins (join , field .getType ());
246+ }
247+ if (field .getAnnotation (ManyToMany .class ) != null ) {
248+ Join <?, ?> join = root .join (field .getName (), JoinType .INNER );
249+ this .fetchJoins (join , field .getType ());
250+ }
251+ }
252+ }
253+
195254 public <T > List <Predicate > getPredicate (Root <T > root , CriteriaBuilder criteriaBuilder ) {
196255 List <Predicate > predicates = new ArrayList <>();
197256 List <String > properties = getClazzProperties ();
198257 RequestFilter requestFilter = request .getRequestFilter ();
258+ this .fetchJoins (root , clazz );
199259 for (Filter filter : requestFilter .getFilters ()) {
200260 Predicate predicate = toPredicate (filter , criteriaBuilder , root , properties );
201261 if (predicate != null ) {
0 commit comments