Skip to content

Commit 805212b

Browse files
committed
search feature:
improve code and bug fix
1 parent 2022290 commit 805212b

6 files changed

Lines changed: 55 additions & 22 deletions

File tree

README.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ this project, implement instance of basic feature, <br> you maybe want use for A
1919
- define your validation and use for model
2020
- decoupling layer
2121
- controller, service and repository layer for easy extend
22+
- flexible search
23+
- use CriteriaQuery and CriteriaBuilder for search base on Entity
2224

2325
## Run guide
2426
### Run for develop and debug: <br>
@@ -45,4 +47,10 @@ this project, implement instance of basic feature, <br> you maybe want use for A
4547
1 - create your own validation type <br>
4648
2 - define your own validation process for entity <br>
4749
3 - use "@validator" annotation on field of entity for validate <br>
48-
4 - log for validation and save error-message in log file <br>
50+
4 - log for validation and save error-message in log file <br>
51+
52+
### search feature
53+
1 - create your own search model <br>
54+
2 - use pagination for search <br>
55+
3 - create query dynamic base on search request <br>
56+
4 - use order and direction for sort data <br>

src/main/java/ir/bigz/springbootreal/controller/SampleController.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,10 @@ public ResponseEntity<?> getAllUser() {
6363

6464
@GetMapping(path = "/user/search", produces = MediaType.APPLICATION_JSON_VALUE)
6565
public ResponseEntity<?> getUserWithSearch(@RequestBody UserSearchDto userSearchDto,
66-
@RequestParam(name = "sortorder") String sortOrder,
67-
@RequestParam(name = "direction") String direction,
68-
@RequestParam(name = "pagenumber") Integer pageNumber,
69-
@RequestParam(name = "pagesize") Integer pageSize) {
66+
@RequestParam(name = "sortorder", defaultValue = "id") String sortOrder,
67+
@RequestParam(name = "direction", defaultValue = "desc", required = false) String direction,
68+
@RequestParam(name = "pagenumber", defaultValue = "1") Integer pageNumber,
69+
@RequestParam(name = "pagesize", defaultValue = "5") Integer pageSize) {
7070
Page<UserModel> userPageResult = userService.getUserSearchResult(userSearchDto, sortOrder, Sort.Direction.fromString(direction), pageNumber, pageSize);
7171
return ResponseEntity.ok(userPageResult);
7272
}

src/main/java/ir/bigz/springbootreal/dal/UserRepository.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,13 @@
44
import ir.bigz.springbootreal.viewmodel.search.UserSearchDto;
55
import org.springframework.data.domain.Page;
66
import org.springframework.data.domain.Pageable;
7+
import org.springframework.data.domain.Sort;
78
import org.springframework.stereotype.Repository;
89

910
@Repository
1011
public interface UserRepository extends DaoRepository<User,Long> {
1112

1213
User getUserWithNationalCode(String nationalCode);
1314

14-
Page<User> getUserSearchResult(UserSearchDto userSearchDto, Pageable pageable);
15+
Page<User> getUserSearchResult(UserSearchDto userSearchDto, Sort.Order order, Pageable pageable);
1516
}

src/main/java/ir/bigz/springbootreal/dal/UserRepositoryImpl.java

Lines changed: 37 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,13 @@
55
import ir.bigz.springbootreal.viewmodel.search.UserSearchDto;
66
import org.springframework.data.domain.Page;
77
import org.springframework.data.domain.Pageable;
8+
import org.springframework.data.domain.Sort;
89
import org.springframework.stereotype.Component;
910

10-
import javax.persistence.criteria.CriteriaQuery;
11-
import javax.persistence.criteria.Predicate;
12-
import javax.persistence.criteria.Root;
13-
import java.util.ArrayList;
14-
import java.util.List;
15-
import java.util.Map;
16-
import java.util.Objects;
11+
import javax.persistence.criteria.*;
12+
import java.lang.reflect.Field;
13+
import java.sql.Timestamp;
14+
import java.util.*;
1715
import java.util.stream.Collectors;
1816

1917
@Component
@@ -34,17 +32,41 @@ public User getUserWithNationalCode(String nationalCode) {
3432
}
3533

3634
@Override
37-
public Page<User> getUserSearchResult(UserSearchDto userSearchDto, Pageable pageable) {
35+
public Page<User> getUserSearchResult(UserSearchDto userSearchDto, Sort.Order order, Pageable pageable) {
36+
3837
CriteriaQuery<User> criteriaQuery = criteriaBuilder.createQuery(User.class);
3938
Root<User> userRoot = criteriaQuery.from(User.class);
40-
Map<String, String> map = new ObjectMapper().convertValue(userSearchDto, Map.class);
41-
List<Predicate> collect = map.keySet().stream().filter(s -> (Objects.nonNull(map.get(s)) && !(map.get(s).equals(""))))
42-
.map(s -> criteriaBuilder.like(userRoot.get(s), "%"+map.get(s)+"%"))
43-
.collect(Collectors.toList());
44-
Predicate[] predicates = collect.stream().toArray(Predicate[]::new);
45-
Predicate and = criteriaBuilder.and(predicates);
46-
criteriaQuery.where(and);
39+
List<Predicate> searchConditions = getSqlCondition(userSearchDto, criteriaBuilder, userRoot);
40+
Predicate concatConditions = criteriaBuilder.and(searchConditions.stream().toArray(Predicate[]::new));
41+
criteriaQuery.where(concatConditions);
42+
if(order.getDirection().name().equals("ASC"))
43+
criteriaQuery.orderBy(criteriaBuilder.asc(userRoot.get(order.getProperty())));
44+
else
45+
criteriaQuery.orderBy(criteriaBuilder.desc(userRoot.get(order.getProperty())));
4746
Page<User> users = genericSearch(criteriaQuery, pageable);
4847
return users;
4948
}
49+
50+
private <T,K> List<Predicate> getSqlCondition(T searchModel, CriteriaBuilder criteriaBuilder, Root<K> root){
51+
List<Field> collect = Arrays.stream(searchModel.getClass().getDeclaredFields()).collect(Collectors.toList());
52+
Map<String, String> map = new ObjectMapper().convertValue(searchModel, Map.class);
53+
54+
return map.keySet().stream()
55+
.filter(s -> (Objects.nonNull(map.get(s)) && !(map.get(s).equals(""))))
56+
.flatMap(s -> collect.stream().filter(field -> field.getName().equals(s)))
57+
.map(field -> {
58+
if (field.getType().getName().contains("String"))
59+
return criteriaBuilder.like(root.get(field.getName()), "%" + map.get(field.getName()) + "%");
60+
else if (field.getType().getName().contains("Timestamp")){
61+
if(field.getName().contains("from") || field.getName().contains("start")){
62+
return criteriaBuilder.greaterThanOrEqualTo(root.get(field.getName()), map.get(field.getName()));
63+
}
64+
else
65+
return criteriaBuilder.lessThanOrEqualTo(root.get(field.getName()), map.get(field.getName()));
66+
}
67+
else
68+
return criteriaBuilder.equal(root.get(field.getName()), map.get(field.getName()));
69+
})
70+
.collect(Collectors.toList());
71+
}
5072
}

src/main/java/ir/bigz/springbootreal/service/UserServiceImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ public Page<UserModel> getUserSearchResult(UserSearchDto userSearchDto, String s
122122
try {
123123
Sort.Order order = new Sort.Order(direction, sortOrder);
124124
Pageable pageable = PageRequest.of(pageNumber, pageSize, Sort.by(order));
125-
Page<User> users = userRepository.getUserSearchResult(userSearchDto, pageable);
125+
Page<User> users = userRepository.getUserSearchResult(userSearchDto, order, pageable);
126126
List<UserModel> collect = users.get().map(userMapper::userToUserModel).collect(Collectors.toList());
127127
return new PageImpl<>(collect, pageable, users.getTotalElements());
128128
}catch (RuntimeException exception){

src/main/java/ir/bigz/springbootreal/viewmodel/search/UserSearchDto.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package ir.bigz.springbootreal.viewmodel.search;
22

3+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
34
import lombok.Getter;
45
import lombok.NoArgsConstructor;
56
import lombok.Setter;
@@ -11,6 +12,7 @@
1112
@Getter
1213
@Setter
1314
@ToString
15+
@JsonIgnoreProperties(ignoreUnknown = true)
1416
public class UserSearchDto implements Serializable {
1517

1618
private String firstName;

0 commit comments

Comments
 (0)