Elasticsearch๋ฅผ ์คํ๋ง์ ์ฌ์ฉํ๋๋ก
๊ธฐ์ด ์์ ๊น์ง ์๋ฃํ๋ค.
์ด์ ์ฝ๋์ ์ง์ ์์ฑํด๋ณด์!
1. ๋์ ํ๋ฉด
- GIF

- ์ด๋ฏธ์ง


2. ๋ฐ์ดํฐ ์ถ๊ฐ ๊ณผ์
- ํ๋ก์ ํธ ์ค๋ช
๊ณ ๊ฐ ์ ๋ณด๋ฅผ ๊ด๋ฆฌํ๋ ํ์ด์ง๋ก ๊ณ ๊ฐ ์ ๋ณด๋ฅผ ์ถ๊ฐํ ๋ ์ด๋ฆ, ๋ฑ๊ธ, ์ฐ๋ฝ์ฒ, ์ด๋์ฝ๋, ๋ฉ๋ชจ๋ฅผ ์ ์ ์ ์๋ค.
- (์์) ์ฌ์ฉ์๊ฐ ๋ณด๋ธ JSON ๋ฐ์ดํฐ
{
"name": "ํ๊ธธ๋",
"phone": "010-1234-5678",
"code": "VIP777"
}
- CustomerSearchEntity
// MySQL์ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ ๋ ์ด๋ค ํ
์ด๋ธ์ ๋ฃ์์ง ๊ฒฐ์ ํ๋ค.
// Elasticsearch์์๋ ๋ฐ์ดํฐ๋ฅผ ์ธ๋ฑ์ค ๋จ์๋ก ๊ด๋ฆฌํ๋ค.
@Document(indexName = "customers")
@Getter
@Setter
public class CustomerSearchEntity {
@Id
private Long id;
// FieldType.Text๋ ๋ฌธ์ฅ์ด๋ ๊ธด ํ
์คํธ๋ฅผ ์ ์ฅํ ๋ ์ด๋ค.
// analyzer = "nori"๋ ๊ณต์ ํ๊ธ ํํ์ ๋ถ์๊ธฐ์ด๋ค.
// ํ๊ธธ๋ ์ด๋ฆ์ ์ ์ฅํ๋ฉด [ํ,๊ธธ,๋] ํน์ [ํ๊ธธ๋] ์ด๋ฐ์์ผ๋ก ์ ์ฅ๋๋๋ก ํ๋ค.
@Field(type = FieldType.Text, analyzer = "nori")
private String name;
// FieldType.Keywords๋ ์ ํํ ์ผ์นํด์ผํ๋ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๋ค.
// ์ ํ๋ฒํธ๋ ๊ณ ๊ฐ ์ฝ๋์ฒ๋ผ ์ซ์๋ก ์ด๋ค์ง ๊ฒฝ์ฐ Keyword๋ฅผ ์ด๋ค.
// ์์ด๋ keyword๋ฅผ ์ฌ์ฉํ๋ค.
@Field(type = FieldType.Keyword)
private String grade;
@Field(type = FieldType.Keyword)
private String phone;
@Field(type = FieldType.Keyword)
private String code;
@Field(type = FieldType.Text, analyzer = "nori")
private String note;
@Field(type = FieldType.Text)
private String nameChosung;
}
ํ๋ก์ ํธ์ CustomerEntity์ CustomerSearchEntity๋ฅผ ๋ง๋ค์๋ค. CustomerSearchEntity๋ Elasticsearch ๊ฒ์ ์์ง ์ ์ฉ ์ ์ฅ์์ ๋ฐ์ดํฐ๋ฅผ ๋ฃ์ ๋ ์ฌ์ฉํ๋ ์ํฐํฐ์ด๋ค. ๋๊ฐ์ง ์ํฐํฐ๋ฅผ ๋ง๋ ์ด์ ๋ CustomerEntity์ ์ง์ง ์๋ณธ์ธ MySQL์ฉ ์ํฐํฐ๋ก ์๋ณธ์ ์์ ํ๊ฒ ๋ณด๊ดํ๋ ์ญํ ์ ํ๋ค.
- CustomerSearchRepository
// Spring Data๊ฐ ์ ๊ณตํ๋ ํน์ ์ธํฐํ์ด์ค์ธ ElasticsearchRepository
// ์ด๊ฑธ ์์ํ๋ฉด save, delete, findById ๊ฐ์ ๊ธฐ๋ฅ์ ๋ฐ๋ก ์ธ ์ ์๋ค.
// CustomerSearchEntity๋ ๊ฒ์ ๋์์ด ๋๋ ๋ฐ์ดํฐ ํ์
์ด๊ณ ๊ทธ ๋ฐ์ดํฐ์ ID(Long)์ ์ง์ ํ๋ค.
public interface CustomerSearchRepository extends ElasticsearchRepository<CustomerSearchEntity, Long> {
// @Query๋ Elasticsearch์ ๋ณด๋ด๋ ์ง๋ฌธ์ง์ด๋ค.
// ์กฐ๊ฑด์ ์กฐํฉํ๊ธฐ ์ํด bool์ ์ฌ์ฉํ๋ค. shold๋ or ์ฐ์ฐ์์ ๋น์ทํ๋ค.
// ๋์ด๋ ์กฐ๊ฑด๋ค ์ค ํ๋๋ผ๋ ๋ง์กฑํ๋ฉด ๊ฒฐ๊ณผ์ ํฌํจํด๋ฌ๋ผ๋ ๋ง์ด๋ค.
// ๊ฒ์ ๋ฐฉ๋ฒ์ match์ wildcard๊ฐ ์๋ค.
// match๋ ํ
์คํธ ๊ฒ์(์ด๋ฆ, ๋ฉ๋ชจ)์ ๋ ์ ํฉํ๋ค. ํํ์ ๋ถ์๊ธฐ๋ก ํ๊ธธ๋์ด ์์ผ๋ฉด ๊ทธ๊ฑธ ์ฐพ์๋ธ๋ค.
// wildcard๋ ๋ถ๋ถ ์ผ์น ๊ฒ์์ ํ๋ค. ๊ทธ๋์ ๋ฑ๊ธ ์ ํ๋ฒํธ ์ฝ๋ ์ด์ฑ์ ๋ ์ ํฉํ๋ค.
// *?0*์ ์๋ค์ ์ด๋ค ๊ธ์๊ฐ ์๋ ์๊ด์์ผ๋ ํค์๋๊ฐ ํฌํจ๋์ด ์์ผ๋ฉด ์ฐพ์ผ๋ผ๋ ๊ฒ์ด๋ค.
// ๊ทธ๋ฌ๋๊น ์ซ์์ ์ผ๋ถ๋ถ, ์ ํ๋ฒํธ์ด๋ฉด ๋ท์๋ฆฌ๋ง ๊ฒ์ํด๋ ๊ฒฐ๊ณผ๊ฐ ๋ํ๋๋ค.
// should๋ ๊ฐํน ๊ฒ์ ๊ฒฐ๊ณผ๋ฅผ ๋๊ฒ ํ๋ค.
// ๊ทธ๊ฑธ ๋ฐฉ์งํ๊ธฐ ์ํด ์ต์ํ์ ์ ํ๋๋ฅผ ํ๋ณดํ๊ธฐ ์ํด์ minimum_should_match:1์ ์ ์๋ค.
// ๋์ด๋ ์กฐ๊ฑด๋ค ์ค์์ ์ ์ด๋ 1๊ฐ ์ด์ ๋ง์กฑํด์ผํ๋ค๋ ์๋ฏธ์ด๋ค.
@Query("""
{
"bool": {
"should": [
{ "match": { "name": { "query": "?0" } } },
{ "match": { "note": { "query": "?0" } } },
{ "wildcard": { "grade": { "value": "*?0*" } } },
{ "wildcard": { "phone": { "value": "*?0*" } } },
{ "wildcard": { "code": { "value": "*?0*" } } },
{ "wildcard": { "nameChosung": { "value": "*?0*" } } }
],
"minimum_should_match": 1
}
}
""")
// String keyword๋ ์ฌ์ฉ์๊ฐ ๊ฒ์์ฐฝ์ ์
๋ ฅํ ๋จ์ด์ด๋ค.
List<CustomerSearchEntity> searchAll(String keyword);
// ์ด ์ฝ๋์ ๋ํด์ ์งง๊ฒ ๋ค์ ์ ๋ฆฌํ์๋ฉด
// ์ฌ์ฉ์๊ฐ ๊ณต์ฃผ๋ฅผ ๊ฒ์ํ์ผ๋ฉด '๊ณต์ฃผ'๊ธฐ ํฌํจ๋ ๋ชจ๋ ๋ฆฌ์คํธ๋ฅผ ๋ค ๋ค๊ณ ์ค๋๋ก ํ๋ ๊ฒ์ด๋ค.
}
- CustomerController
@PostMapping
@PreAuthorize("hasAnyAuthority('ROLE_SUPER_ADMIN', 'CUSTOMER_ADD')")
public Customer saveCustomer(@RequestBody Customer customer) {
return customerService.save(customer);
}
@PostMapping ๋ฉ์๋๊ฐ ์คํ๋๋ฉฐ ์ฌ์ฉ์๊ฐ ๋ณด๋ธ JSON ๋ฐ์ดํฐ๋ฅผ Customer ๊ฐ์ฒด๋ก ๋ฐ์ต๋๋ค. ์ด ๋ถ๋ถ ์ฝ๋๊ฐ (@RequestBody Customer customer)์ด๋ค. ๊ทธ๋ฌ๋ฉด ์ปจํธ๋กค๋ฌ์์ customerService์ ์ ์ด๋ save ๋ฉ์๋๋ก customer ๊ฐ์ฒด๋ฅผ ๋ณด๋ธ๋ค. ์ฐธ๊ณ ๋ก @PreAuthorize๋ ๊ด๋ฆฌ์์ ์ญํ ์ ๋ฐ๋ผ ๊ถํ์ ๋ถ์ฌํ ์ฝ๋๋ก elasticsearch์ ๋ฌด๊ดํ๋ค.
- CustomerService
// MySQL ์ ์ฅ์๋ ์ฑ๊ณตํ๋๋ฐ Elasticsearch ์ ์ฅ์์ ์๋ฌ๊ฐ ๋๋ฉด
// MySQL ์ ์ฅ๋ ์๋ ์ผ๋ก ๋๋๋ฆฐ๋ค. (Rollback)
// ์์ชฝ ๋ฐ์ดํฐ๊ฐ ๋ถ์ผ์นํ๋ ์ํฉ์ ๋ฐฉ์งํ๊ณ ์ ์ด๋
ธํ
์ด์
์ ์ถ๊ฐํ๋ค.
@Transactional
public Customer save(Customer customer) {
// customer ๊ฐ์ฒด์ ํฌํจ๋์ด์๋ code๋ฅผ ๊บผ๋ด์ code์ ๋ฃ๋๋ค.
String code = customer.getCode();
// ๊ทธ๋ฆฌ๊ณ ์ฝ๋๊ฐ ์ค๋ณต๋์๋์ง ์ฒดํฌํ๋ค.
if (code != null && customerRepository.existsByCode(code)) {
throw new DuplicateCodeException("์ด๋์ฝ๋๊ฐ ์ค๋ณต๋์์ต๋๋ค.");
}
// customerRepository์๋ ์ ์ฅ๋๋ค.
// customerRepository์.save()๊ฐ ์คํ๋๋ฉด DB์ ์ ์ฅ๋ ์ค์ ๋ฐ์ดํฐ๊ฐ ๋ฐํ๋๋๋ฐ
// ๊ทธ๊ฑธ saved๋ผ๋ ์ด๋ฆํ๋ฅผ ๋ถ์ฌ์ ๋ณด๊ดํ๋ค.
Customer saved = customerRepository.save(customer);
// elasticsearch ๊ฒ์์ ์ํด์ ๊ฒ์ ์์ง์๋ ๋ฐ๋ก ์ ์ฅํ๋ค.
CustomerSearchEntity ela = new CustomerSearchEntity();
// ๋ณ์ saved์์ ์ ์ฅ๋ ๋ฐ์ดํฐ๋ฅผ ๊บผ๋ด์ ela์ ๋ฃ๋๋ค.
ela.setId(saved.getId());
ela.setName(saved.getName());
ela.setGrade(saved.getGrade());
ela.setPhone(saved.getPhone());
ela.setCode(saved.getCode());
ela.setNote(saved.getNote());
// ์ด์ฑ๋ ์ ์ฅํ๋ค.
// ๊ทธ๊ฑด ๋ฐ๋ก ๋ฐ์ ์ฝ๋์์ ์ค๋ช
!
ela.setNameChosung(getChosung(saved.getName()));
customerSearchRepository.save(ela);
// ๋ชจ๋ ์์
์ด ๋๋๋ฉด ์ต์ข
์ ์ผ๋ก saved๋ฅผ ์ปจํธ๋กค๋ฌ์๊ฒ ๋๋ ค์ค๋ค.
return saved;
}
// elasticsearch๋ก ์ด์ฑ ๊ฒ์์ผ๋ก๋ ์ฐพ๊ฒ ํ๊ธฐ ์ํด์
// ํ๊ธ์ ์ ๋์ฝ๋ ๊ท์น์ ์ด์ฉํด์ ์์์ ๋ถ๋ฆฌํ๋ค.
private String getChosung(String text) {
if (text == null) return "";
String[] CHO = {
"ใฑ","ใฒ","ใด","ใท","ใธ","ใน","ใ
","ใ
","ใ
","ใ
",
"ใ
","ใ
","ใ
","ใ
","ใ
","ใ
","ใ
","ใ
","ใ
"
};
StringBuilder sb = new StringBuilder();
for (int i = 0; i < text.length(); i++) {
char c = text.charAt(i);
if (c >= '๊ฐ' && c <= 'ํฃ') {
int uniVal = c - 0xAC00;
int choIdx = uniVal / 588;
sb.append(CHO[choIdx]);
} else if (c != ' ') {
sb.append(c);
}
}
return sb.toString();
}
Q. getChosung๊ณผ nori์ ์ฐจ์ด์ ์?
A. getChosung์ ๋ง ๊ทธ๋๋ก ์ด์ฑ์ ์ ์ฅํ๋ค. ํ๊ธธ๋์ด๋ ๋ฐ์ดํฐ๊ฐ ๋ค์ด์ค๋ฉด ใ ใฑใท๋ฅผ ์ ์ฅํ๋ ๊ฒ์ด๋ค. name ํ๋์์ ๋ถ์๊ธฐ nori๋ฅผ ์ฌ์ฉํ๋ค. nori๋ ํ๊ธธ๋์ ์ชผ๊ฐ ๋ค. ํ,๊ธธ,๋ ํน์ ํ๊ธธ,๊ธธ๋, ์ด๋ฐ์์ผ๋ก ๋ง์ด๋ค. ์ฌ์ฉ์๊ฐ ๊ฒ์ํ๋ฉด ์ด์ฑ ํน์ ์ผ๋ถ๋ถ๋ง ๊ฒ์ํด๋ ๊ฒฐ๊ณผ๊ฐ ๋ํ๋๋๋ก ํ๋ค.
3. ๋ฐ์ดํฐ ๊ฒ์ ๊ณผ์
- (์์) ์ฌ์ฉ์๊ฐ ๋ณด๋ธ ๊ฒ์ ์์ฒญ
GET /api/customers/search?keyword=ใ
ใฑใท
- CustomerController
@GetMapping("/search")
// ๊ถํ ๊ฒ์ฌ
@PreAuthorize("hasAnyAuthority('ROLE_SUPER_ADMIN', 'CUSTOMER_SEARCH')")
// ์ฌ๋ฌ ๊ฒ์ ๊ฒฐ๊ณผ๊ฐ ๋ฐํ๋ ์ ์์ผ๋ List๋ก ๋ฐํํ๋ค.
// @RequestParam String keyword๋ ์์ฒญ์ ๋ถ์ keyword=ใ
ใฑใท ๋ถ๋ถ์ด๋ค.
// Spring์ด ์๋์ผ๋ก keyword="ใ
ใฑใท" ์ด๋ผ๊ณ ๋ฃ๋๋ค.
public List<CustomerSearchEntity> searchCustomer(@RequestParam String keyword) {
// keyword๋ฅผ ๋ค๊ณ ๊ฐ์ ์ค์ ๊ฒ์์ด ์คํ๋๋ค.
return customerSearchRepository.searchAll(keyword);
}
- CustomerSearchRepository
{
"bool": {
"should": [
{ "match": { "name": { "query": "?0" } } },
{ "match": { "note": { "query": "?0" } } },
{ "wildcard": { "grade": { "value": "*?0*" } } },
{ "wildcard": { "phone": { "value": "*?0*" } } },
{ "wildcard": { "code": { "value": "*?0*" } } },
{ "wildcard": { "nameChosung": { "value": "*?0*" } } }
],
"minimum_should_match": 1
}
}
?0์ ใ ใฑใท์ด ๋ค์ด๊ฐ๋ค. ์ฝ๊ฒ ์ค๋ช ํ๊ธฐ ์ํด ์๋ ์ฝ๋์ฒ๋ผ ์์ฑํ๋ค.
{
"bool": {
"should": [
{ "match": { "name": { "query": "ใ
ใฑใท" } } },
{ "match": { "note": { "query": "ใ
ใฑใท" } } },
{ "wildcard": { "grade": { "value": "*ใ
ใฑใท*" } } },
{ "wildcard": { "phone": { "value": "*ใ
ใฑใท*" } } },
{ "wildcard": { "code": { "value": "*ใ
ใฑใท*" } } },
{ "wildcard": { "nameChosung": { "value": "*ใ
ใฑใท*" } } }
],
"minimum_should_match": 1
}
}
- CustomerService
ela.setNameChosung(getChosung(saved.getName()));
CustomerService์ ์์ ์ฝ๋๋ฅผ ์์ฑํ๋ค. ๊ทธ๋์ ํ๊ธธ๋์ ์ ์ฅํ์ ๋ ์๋์ ๊ฐ์ด ์ ์ฅ๋์๊ฑฐ๋ค.
{
"id": 1,
"name": "ํ๊ธธ๋",
"grade": "VIP",
"phone": "010-1234-5678",
"code": "1234",
"note": "์ค์ ๊ณ ๊ฐ",
"nameChosung": "ใ
ใฑใท"
}
์ด๋ ๊ฒ ์ด์ฑ์ ๋ฏธ๋ฆฌ ์ ์ฅํด๋ฌ์ ๊ฒ์์ ํ๋ฉด ์ฐพ์ ์ ์๋ ๊ฒ์ด๋ค.
4. MySQL์ ๊ธฐ์ค์ผ๋ก Elasticsearch ๊ฒ์ ๋ฐ์ดํฐ๋ฅผ ๋ค์ ๋ง์ถ๊ธฐ
- CustomerService
// MySQL์ ์ ์ฅ๋ ๋ชจ๋ ๊ณ ๊ฐ ๋ฆฌ์คํธ๋ฅผ ๊ธ์ด์์ ํ๋์ฉ Elasticsearch์ ๋ฃ๋๋ค.
// elasticsearch๋ฅผ ์ฌ์ฉํ๊ธฐ ์ ์ DB์ ์ ์ฅ๋์ด ์๋๊ฑธ ๊ฐ์ ธ์ค๋๋ผ ์ ์๋ ์ฝ๋์ธ๋ฐ,
// ๋๊ธฐํ ์ค๋ฅ ๋ฑ์ผ๋ก DB์ ๊ฒ์์์ง์ด ์๋ง๋ ๊ฑธ ๋๋นํด์ ํด๋น ์ฝ๋๋ฅผ ๋๋๋ค.
@Transactional
public void syncAllToElasticsearch() {
//customerRepository์ ์๋ ๋ชจ๋ ๋ฐ์ดํฐ๋ฅผ ๋ค์ด์์ list์ ๋ฃ๋๋ค.
List<Customer> list = customerRepository.findAll();
// list์ ์๋ ํญ๋ชฉ์ ๋๋ฉด์ customerSearchRepository์ ์ ์ฅํ๋ค.
// ์ฌ๊ธฐ์ customerSearchRepository๋ elasticsearch๋ฅผ ์ํด ๋ง๋ ๊ฒ์์์ง์ด๋ค.
for (Customer c : list) {
CustomerSearchEntity e = new CustomerSearchEntity();
e.setId(c.getId());
e.setName(c.getName());
e.setGrade(c.getGrade());
e.setPhone(c.getPhone());
e.setCode(c.getCode());
e.setNote(c.getNote());
e.setNameChosung(getChosung(c.getName()));
customerSearchRepository.save(e);
}
}
5. ์ ์ฒด ์ฝ๋
- CustomerSearchEntity
@Document(indexName = "customers")
@Getter
@Setter
public class CustomerSearchEntity {
@Id
private Long id;
@Field(type = FieldType.Text, analyzer = "nori")
private String name;
@Field(type = FieldType.Keyword)
private String grade;
@Field(type = FieldType.Keyword)
private String phone;
@Field(type = FieldType.Keyword)
private String code;
@Field(type = FieldType.Text, analyzer = "nori")
private String note;
@Field(type = FieldType.Text)
private String nameChosung;
}
- CustomerSearchRepository
public interface CustomerSearchRepository extends ElasticsearchRepository<CustomerSearchEntity, Long> {
@Query("""
{
"bool": {
"should": [
{ "match": { "name": { "query": "?0" } } },
{ "match": { "note": { "query": "?0" } } },
{ "wildcard": { "grade": { "value": "*?0*" } } },
{ "wildcard": { "phone": { "value": "*?0*" } } },
{ "wildcard": { "code": { "value": "*?0*" } } },
{ "wildcard": { "nameChosung": { "value": "*?0*" } } }
],
"minimum_should_match": 1
}
}
""")
List<CustomerSearchEntity> searchAll(String keyword);
}
- CustomerController
@RestController
@RequestMapping("/api/customers")
@RequiredArgsConstructor
public class CustomerController {
private final CustomerService customerService;
private final CustomerSearchRepository customerSearchRepository;
@GetMapping
@PreAuthorize("hasAnyAuthority('ROLE_SUPER_ADMIN', 'CUSTOMER_READ')")
public List<Customer> effectCustomers() {
return customerService.findAllCustomers();
}
@PostMapping
@PreAuthorize("hasAnyAuthority('ROLE_SUPER_ADMIN', 'CUSTOMER_ADD')")
public Customer saveCustomer(@RequestBody Customer customer) {
return customerService.save(customer);
}
@PutMapping("/{id}")
@PreAuthorize("hasAnyAuthority('ROLE_SUPER_ADMIN', 'CUSTOMER_EDIT')")
public ResponseEntity<Customer> updateCustomer(@PathVariable Long id, @RequestBody Customer data) {
if (!customerService.exists(id)) {
return ResponseEntity.notFound().build();
}
Customer updated = customerService.update(id, data);
return ResponseEntity.ok(updated);
}
@DeleteMapping("/{id}")
@PreAuthorize("hasAnyAuthority('ROLE_SUPER_ADMIN', 'CUSTOMER_DELETE')")
public ResponseEntity<Void> deleteCustomer(@PathVariable Long id) {
if (!customerService.exists(id)) {
return ResponseEntity.notFound().build();
}
customerService.delete(id);
return ResponseEntity.ok().build();
}
@GetMapping("/search")
@PreAuthorize("hasAnyAuthority('ROLE_SUPER_ADMIN', 'CUSTOMER_SEARCH')")
public List<CustomerSearchEntity> searchCustomer(@RequestParam String keyword) {
return customerSearchRepository.searchAll(keyword);
}
@PostMapping("/sync")
@PreAuthorize("hasRole('SUPER_ADMIN')")
public ResponseEntity<String> sync() {
customerService.syncAllToElasticsearch();
return ResponseEntity.ok("sync ok");
}
}
- CustomerService
@Service
public class CustomerService {
private CustomerRepository customerRepository;
private final CustomerSearchRepository customerSearchRepository;
@Autowired
public CustomerService(CustomerRepository customerRepository, CustomerSearchRepository customerSearchRepository) {
this.customerRepository = customerRepository;
this.customerSearchRepository = customerSearchRepository;
}
public List<Customer> findAllCustomers() {
return customerRepository.findAll();
}
public boolean exists(Long id) {
return customerRepository.existsById(id);
}
public boolean isCodeDuplicatedForCreate(String code) {
if (code == null || code.isBlank())
return false;
return customerRepository.existsByCode(code);
}
@Transactional
public Customer save(Customer customer) {
String code = customer.getCode();
if (code != null && customerRepository.existsByCode(code)) {
throw new DuplicateCodeException("์ด๋์ฝ๋๊ฐ ์ค๋ณต๋์์ต๋๋ค.");
}
Customer saved = customerRepository.save(customer);
CustomerSearchEntity ela = new CustomerSearchEntity();
ela.setId(saved.getId());
ela.setName(saved.getName());
ela.setGrade(saved.getGrade());
ela.setPhone(saved.getPhone());
ela.setCode(saved.getCode());
ela.setNote(saved.getNote());
ela.setNameChosung(getChosung(saved.getName()));
customerSearchRepository.save(ela);
return saved;
}
@Transactional
public Customer update(Long id, Customer updateData) {
Customer customer = customerRepository.findById(id)
.orElseThrow(() -> new IllegalArgumentException("๊ณ ๊ฐ์ ์ฐพ์ ์ ์์ต๋๋ค."));
String newCode = updateData.getCode();
if (newCode != null) {
customerRepository.findByCode(newCode).ifPresent(found -> {
if (!found.getId().equals(id)) {
throw new DuplicateCodeException("์ด๋์ฝ๋๊ฐ ์ค๋ณต๋์์ต๋๋ค.");
}
});
}
customer.setName(updateData.getName());
customer.setGrade(updateData.getGrade());
customer.setPhone(updateData.getPhone());
customer.setCode(updateData.getCode());
customer.setNote(updateData.getNote());
CustomerSearchEntity ela = new CustomerSearchEntity();
ela.setId(customer.getId());
ela.setName(customer.getName());
ela.setGrade(customer.getGrade());
ela.setPhone(customer.getPhone());
ela.setCode(customer.getCode());
ela.setNote(customer.getNote());
ela.setNameChosung(getChosung(customer.getName()));
customerSearchRepository.save(ela);
return customer;
}
@Transactional
public void delete(Long id) {
customerRepository.deleteById(id);
customerSearchRepository.deleteById(id);
}
@Transactional
public void syncAllToElasticsearch() {
List<Customer> list = customerRepository.findAll();
for (Customer c : list) {
CustomerSearchEntity e = new CustomerSearchEntity();
e.setId(c.getId());
e.setName(c.getName());
e.setGrade(c.getGrade());
e.setPhone(c.getPhone());
e.setCode(c.getCode());
e.setNote(c.getNote());
e.setNameChosung(getChosung(c.getName()));
customerSearchRepository.save(e);
}
}
private String getChosung(String text) {
if (text == null) return "";
String[] CHO = {
"ใฑ","ใฒ","ใด","ใท","ใธ","ใน","ใ
","ใ
","ใ
","ใ
",
"ใ
","ใ
","ใ
","ใ
","ใ
","ใ
","ใ
","ใ
","ใ
"
};
StringBuilder sb = new StringBuilder();
for (int i = 0; i < text.length(); i++) {
char c = text.charAt(i);
if (c >= '๊ฐ' && c <= 'ํฃ') {
int uniVal = c - 0xAC00;
int choIdx = uniVal / 588;
sb.append(CHO[choIdx]);
} else if (c != ' ') {
sb.append(c);
}
}
return sb.toString();
}
}