728x90

QueryDSL 이전 게시글의 최적화 버전을 chatGPT 도움으로 변경한 것이다.

 

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
import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.types.dsl.PathBuilder;
import com.querydsl.jpa.impl.JPAQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.data.domain.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
 
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
 
@Service
@Transactional
@Log4j2
@RequiredArgsConstructor // 생성자 자동 주입
public class AccessLogSearchImpl implements AccessLogSearch {
    private final JPAQueryFactory queryFactory;
    private final ErrorCodeRepository errorCodeRepository;
 
    @Override
    public Page<AccessLogDTO> search1(PageRequestDTO pageRequestDTO) {
        QAccessLog accessLog = QAccessLog.accessLog;
        BooleanBuilder builder = new BooleanBuilder();
 
        String where = pageRequestDTO.getFilter().getWhere();
        String keyword = pageRequestDTO.getFilter().getKeyword();
 
        log.info("검색 필터 where = {}, keyword = {}", where, keyword);
 
        if (keyword != null && !keyword.trim().isEmpty()) {
            buildSearchCondition(builder, accessLog, where.trim(), keyword.trim());
        }
 
        Pageable pageable = PageRequest.of(
                pageRequestDTO.getPage() - 1,
                pageRequestDTO.getSize(),
                Sort.by("uid").descending()
        );
 
        JPAQuery<AccessLog> query = queryFactory
                .selectFrom(accessLog)
                .where(builder)
                .offset(pageable.getOffset())
                .limit(pageable.getPageSize())
                .orderBy(accessLog.uid.desc());
 
        List<AccessLog> resultList = query.fetch();
 
        long totalCount = queryFactory
                .select(accessLog.count())
                .from(accessLog)
                .where(builder)
                .fetchOne();
 
        // errorCode 메시지 전체 Map으로 미리 조회 (N+1 제거)
        Map<Integer, String> errorMap = errorCodeRepository.findAll().stream()
                .collect(Collectors.toMap(ErrorCode::getCodeId, ErrorCode::getCodeNm));
 
        List<AccessLogDTO> dtoList = IntStream.range(0, resultList.size())
                .mapToObj(i -> {
                    AccessLog entity = resultList.get(i);
                    int no = (int) (totalCount - (pageable.getPageNumber() * pageable.getPageSize()) - i);
                    return toDTO(entity, no, errorMap);
                })
                .collect(Collectors.toList());
 
        return new PageImpl<>(dtoList, pageable, totalCount);
    }
 
    private void buildSearchCondition(BooleanBuilder builder, QAccessLog accessLog, String where, String keyword) {
        switch (where) {
            case "userID" -> builder.and(accessLog.userid.containsIgnoreCase(keyword));
            case "userNM" -> builder.and(accessLog.userNM.containsIgnoreCase(keyword));
            case "ipaddr" -> builder.and(accessLog.ipaddr.containsIgnoreCase(keyword));
            case "route" -> builder.and(accessLog.route.stringValue().containsIgnoreCase(keyword));
            case "errorCode" -> {
                List<Integer> codeIds = errorCodeRepository.findCodeIdsByCodeNmLike(keyword);
                if (!codeIds.isEmpty()) {
                    builder.and(accessLog.errCode.in(codeIds));
                } else {
                    builder.and(accessLog.errCode.eq(-9999)); // fallback
                }
            }
            case "accessDate" -> {
                String[] parts = keyword.split("/");
                if (parts.length == 2) {
                    String from = parts[0].trim();
                    String to = parts[1].trim();
                    if (from.length() == 8 && to.length() == 8) {
                        if (from.compareTo(to) > 0) {
                            String temp = from;
                            from = to;
                            to = temp;
                        }
                        builder.and(accessLog.date.between(from, to));
                    }
                } else {
                    builder.and(accessLog.date.startsWith(keyword));
                }
            }
            default -> {
                Set<String> allowedFields = Set.of("userid""userNM""ipaddr""browser""os""date");
                if (allowedFields.contains(where)) {
                    PathBuilder<AccessLog> pathBuilder = new PathBuilder<>(AccessLog.class"accessLog");
                    builder.and(pathBuilder.getString(where).containsIgnoreCase(keyword));
                } else {
                    log.warn(" 잘못된 where 필드명: '{}'. 검색 조건 무시", where);
                }
            }
        }
    }
 
    private AccessLogDTO toDTO(AccessLog entity, int no, Map<Integer, String> errorMap) {
        String errorMessage = errorCodeRepository
                .findMessageByCode(entity.getErrCode())
                .orElse(String.valueOf(entity.getErrCode()));
 
        return AccessLogDTO.builder()
                .no(no)  //  추가
                .uid(entity.getUid())
                .ipaddr(MaskingUtil.ipAddressMasking(entity.getIpaddr()))
                .date(InputSanitizer.displayDate(entity.getDate()))
                .time(entity.getTime())
                .OS(entity.getOs())
                .browser(entity.getBrowser())
                .userid(MaskingUtil.idMasking(entity.getUserid()))
                .userNM(MaskingUtil.letterMasking(entity.getUserNM()))
                .success(entity.getSuccess())
                .route(entity.getRoute())
                .errCode(entity.getErrCode())
                .errorMessage(errorMap.getOrDefault(entity.getErrCode(), String.valueOf(entity.getErrCode())))
                .build();
    }
 
}
 
 
cs

 

 

728x90
블로그 이미지

Link2Me

,