일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 누적합
- Generics
- SpringBoot
- 완전탐색
- 브루트포스
- 프로그래머스
- ES
- til
- programmers
- 객체지향
- querydsl
- Spring
- 구현
- binary search
- BFS
- Baekjoon
- 내일배움캠프
- 코딩테스트
- 알고리즘
- Java
- 계산기 만들기
- OOP
- 일정 관리
- Algorithm
- Elasticsearch
- 이분 탐색
- 이분탐색
- parametric search
- 백준
- 리팩토링
- Today
- Total
개발하는 햄팡이
[ES, SpringBoot] 공지사항 게시판 검색 기능 구현하기 (2) : 데이터 저장 및 삭제 본문
[ES, SpringBoot] 공지사항 게시판 검색 기능 구현하기 (2) : 데이터 저장 및 삭제
hampangee 2024. 11. 12. 13:16
저번에 이어 인덱스를 설계했으니 이제 CRUD차례.
우리 프로젝트는 U가 없기 때문에 CRD만 하면 되는데
일단 테스트용으로 필요한 api인 CD를 간단하게 사용하고 다음에 R을 구현할 것이다.
구현 전에 연결이 잘 되는지 확인하기 위해 서버 돌려보기는 필수
삽입, 삭제 서비스 테스트를 위해 만드는 컨트롤러라서
필요한 값들을 다른 서비스에서 받아온다고 생각하고 만든 컨트롤러이다.
(1) Controller
package com.jetty.ssafficebe.search.esnotice.controller;
import com.jetty.ssafficebe.common.payload.ApiResponse;
import com.jetty.ssafficebe.search.esnotice.payload.ESNoticeRequest;
import com.jetty.ssafficebe.search.esnotice.service.ESNoticeService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/search/notice")
@RequiredArgsConstructor
public class ESNoticeController {
private final ESNoticeService esNoticeService;
@PostMapping
public ResponseEntity<ApiResponse> saveNotice(@RequestBody ESNoticeRequest request) {
return ResponseEntity.ok(esNoticeService.saveNotice(request));
}
@DeleteMapping("/{noticeId}")
public ResponseEntity<ApiResponse> deleteNotice(@PathVariable Long noticeId) {
return ResponseEntity.ok(esNoticeService.deleteNotice(noticeId));
}
}
우리 프로젝트는 딱히 결과를 보낼 필요가 없는 컨트롤러는 ApiResponse라는 payload 객체를 만들어 리턴하고 있다.
ESNoticeRequest형태는 아래와 같다.
package com.jetty.ssafficebe.search.esnotice.payload;
import java.time.LocalDateTime;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class ESNoticeRequest {
private Long noticeId;
private String title;
private String content;
private LocalDateTime createdAt;
private LocalDateTime startDateTime;
private LocalDateTime endDateTime;
private String isEssentialYn;
private String noticeTypeCd;
private Long createUserId;
private String createUserEmail;
private String createUserName;
private String createUserProfileImgUrl;
}
서비스에서 넘겨주는 정보들을 다 필드에서 넣었다.
createUser와 관련된 부분은 따로 객체로 감쌀까 생각도 해봤는데,
현재 index에는 객체로 감싸지 않은 형태로 구성했다.
이유는 객체로 감싸면 nested 형태로 타입을 지정하는데 그렇게 되면
조회나 수정이 있을 때 text가 저장되듯이 nested 객체 또한 필드 하나하나 분해하여 저장하기 때문에 저장 삭제 수정 부분에서 비용이 좀 더 많이 들게 된다.
+ 조회시 noticeId, nested객체 아이디 총 두번 거쳐 조회를 시도하기 때문에 보다 비효율적이다.
(2) Repository
package com.jetty.ssafficebe.search.esnotice.repository;
import com.jetty.ssafficebe.search.esnotice.document.ESNotice;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
public interface ESNoticeRepository extends ElasticsearchRepository<ESNotice, Long> {
}
Repository를 만드는 방법은 JPA와 유사하다.
그냥 ElasticsearchRepository<인덱스명, 인덱스의 Id 타입>를 상속하면 된다.
ElasticsearchRepository가 CRUDRepository를 상속하기 때문에 메소드이름이나 규칙같은 게 JPA와 똑같다.
현재는 저장, 삭제만 하기 때문에 세세하게 건들 필요가 없어서 딱 저정도만 작성하고 넘어갈거다
(3) Service
package com.jetty.ssafficebe.search.esnotice.service;
import com.jetty.ssafficebe.common.payload.ApiResponse;
import com.jetty.ssafficebe.search.esnotice.payload.ESNoticeRequest;
public interface ESNoticeService {
ApiResponse saveNotice(ESNoticeRequest request);
ApiResponse deleteNotice(Long noticeId);
}
package com.jetty.ssafficebe.search.esnotice.service;
import com.jetty.ssafficebe.common.payload.ApiResponse;
import com.jetty.ssafficebe.search.esnotice.converter.ESNoticeConverter;
import com.jetty.ssafficebe.search.esnotice.document.ESNotice;
import com.jetty.ssafficebe.search.esnotice.payload.ESNoticeRequest;
import com.jetty.ssafficebe.search.esnotice.repository.ESNoticeRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@Transactional
@RequiredArgsConstructor
public class ESNoticeServiceImpl implements ESNoticeService {
private final ESNoticeRepository esNoticeRepository;
private final ESNoticeConverter esNoticeConverter;
@Override
public ApiResponse saveNotice(ESNoticeRequest request) {
ESNotice esNotice = esNoticeConverter.toESNotice(request);
ESNotice saved = esNoticeRepository.save(esNotice);
return new ApiResponse(true, "ES에 추가 성공", saved.getNoticeId());
}
@Override
public ApiResponse deleteNotice(Long noticeId) {
esNoticeRepository.deleteById(noticeId);
return new ApiResponse(true, "삭제 성공", noticeId);
}
}
Service쪽은 뭐 딱히 설명할게 없고...
MapStruct 라이브러리를 사용하여 형변환을 해주는 Converter 코드를 자동으로 작성해주는 인터페이스를 사용중이다.
참고. ESNotice Converter
package com.jetty.ssafficebe.search.esnotice.converter;
import com.jetty.ssafficebe.search.esnotice.document.ESNotice;
import com.jetty.ssafficebe.search.esnotice.payload.ESNoticeRequest;
import org.mapstruct.Mapper;
import org.mapstruct.ReportingPolicy;
@Mapper(componentModel = "spring", unmappedSourcePolicy = ReportingPolicy.IGNORE, unmappedTargetPolicy = ReportingPolicy.WARN)
public interface ESNoticeConverter {
ESNotice toESNotice(ESNoticeRequest request);
}
메소드 명명 규칙에 따라 자동으로 ConverterImpl class가 만들어지는데
이건 나중에 해당 라이브러리를 설명할 때 관련 블로그 글을 작성할 예정이다.
이제 다음부터는 본격 검색 시작...
그래도 예전에 막 이것저것 필터에 점수넣고 할 때보다 훨씬 쉬워서 검색도 바로 끝날 것 같다.
elasticsearch의 쿼리 중 각 항목별 점수를 주고,
그 점수를 계산하고,
단어 유사도 체크도 하고,
그 결과로 다른 필드에서 집계도 한 결과를 리턴하는 쿼리를 작성한 적도 있었는데
그거에 비하면 그냥 검색 구현은 너무 쉬워서 부담이 적다
얼른 끝내버려야지...
'Back-End > Spring' 카테고리의 다른 글
[Spring][일정 관리 앱 만들기] CRUD 생성 - QueryDsl 쿼리문 코드 작성 (1) | 2025.05.24 |
---|---|
[Spring][일정 관리 앱 만들기] CRUD 생성 - QueryDsl 시작하기 (2) | 2025.05.24 |
[Springboot, Mysql, Mybatis] PasswordEncoder구현 - 검색 효율 높인 게시판 구현 (0) | 2024.10.23 |