성능 최적화 요소까지 완벽한 고려는 아니지만 코드는 많이 정리된 거 같아서 적어둔다.
React 에서는 pk 값이 직접 노출되지 않도록 암호화처리하고, 대신에 no 를 넣어서 처리했다.
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
|
@Repository
@Transactional
@RequiredArgsConstructor
@Log4j2
public class ProductSearchImpl implements ProductSearch {
private final JPAQueryFactory queryFactory;
private final CryptoUtil cryptoUtil;
@Override
public Page<ProductDTO> searchList(PageRequestDTO pageRequestDTO) {
QProduct product = QProduct.product;
QProductImage productImage = QProductImage.productImage;
SearchConditionBuilder<Product> scb = new SearchConditionBuilder<>(Product.class, "product");
String where = pageRequestDTO.getFilter().getWhere();
String keyword = pageRequestDTO.getFilter().getKeyword();
OrderSpecifier<?> orderSpecifier = product.pno.desc(); // 기본값: pno 내림차순
if (keyword != null && !keyword.isBlank()) {
switch (where) {
case "pname" -> scb.addLike("pname", keyword);
case "desc" -> scb.addLike("pdesc", keyword);
case "price" -> {
try {
int minPrice = Integer.parseInt(keyword);
scb.addGreaterThanEqual("price", minPrice);
orderSpecifier = product.price.asc(); // 가격 오름차순 정렬
} catch (NumberFormatException e) {
log.warn("가격 필터 숫자 변환 실패: {}", keyword);
}
}
}
}
BooleanBuilder builder = scb.build();
Pageable pageable = PageRequest.of(
pageRequestDTO.getPage() - 1,
pageRequestDTO.getSize()
);
List<Product> productList = queryFactory
.selectFrom(product)
.leftJoin(product.imageList, productImage).fetchJoin()
.where(product.delFlag.eq(false)
.and(productImage.ord.eq(0))
.and(builder))
.offset(pageable.getOffset())
.limit(pageable.getPageSize())
.orderBy(orderSpecifier)
.fetch();
long totalCount = queryFactory
.select(product.count())
.from(product)
.leftJoin(product.imageList, productImage)
.where(product.delFlag.eq(false)
.and(productImage.ord.eq(0))
.and(builder))
.fetchOne();
List<ProductDTO> dtoList = IntStream.range(0, productList.size())
.mapToObj(i -> {
Product entity = productList.get(i);
int no = (int) (totalCount - (pageable.getPageNumber() * pageable.getPageSize()) - i);
return toDTO(entity, no);
}).toList();
return new PageImpl<>(dtoList, pageable, totalCount);
}
private ProductDTO toDTO(Product product, int no) {
String encryptedPno = cryptoUtil.encryptAES(String.valueOf(product.getPno()));
List<String> fileNames = product.getImageList().stream()
.map(ProductImage::getFileName)
.toList();
return ProductDTO.builder()
.no(no)
.pno(encryptedPno)
.pname(product.getPname())
.price(product.getPrice())
.pdesc(product.getPdesc())
.uploadFileNames(fileNames)
.build();
}
}
|
'Spring Boot > Basic' 카테고리의 다른 글
Spring Boot 3.4.5 QueryDSL 예제 개선 (0) | 2025.05.04 |
---|---|
Spring Boot 3.4.5 QueryDSL 예제 (0) | 2025.05.04 |
Spring Boot 3.4.5 JOOQ TodoSearch 예제 (0) | 2025.05.03 |
Spring Boot 3.4.5 QueryDSL TodoSearch 예제 (0) | 2025.05.01 |
Spring Boot 3.4.5 QueryDSL 설정 오류 방지 (1) | 2025.04.28 |