Skip to content

Commit b5a2cc0

Browse files
authored
Merge pull request #89 from prgrms-web-devcourse-final-project/feat/88-law-word
feat[law-word]:법령 검색 기능 추가
2 parents 80f201b + 17021d2 commit b5a2cc0

File tree

13 files changed

+150805
-37
lines changed

13 files changed

+150805
-37
lines changed

backend/sql/drop.sql

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
drop table ho;
2+
drop table hang;
3+
drop table jo;
4+
drop table jang;
5+
drop table law;
6+
drop table precedent;
7+
8+
ALTER TABLE ho AUTO_INCREMENT = 1;
9+
ALTER TABLE hang AUTO_INCREMENT = 1;
10+
ALTER TABLE jo AUTO_INCREMENT = 1;
11+
ALTER TABLE jang AUTO_INCREMENT = 1;
12+
ALTER TABLE law AUTO_INCREMENT = 1;
13+
ALTER TABLE precedent AUTO_INCREMENT = 1;

backend/sql/lawData.sql

Lines changed: 150586 additions & 0 deletions
Large diffs are not rendered by default.

backend/src/main/java/com/ai/lawyer/domain/law/controller/LawController.java

Lines changed: 13 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,30 +5,22 @@
55
import com.ai.lawyer.domain.law.entity.Law;
66
import com.ai.lawyer.domain.law.service.LawService;
77
import com.ai.lawyer.global.dto.PageResponseDto;
8+
import io.swagger.v3.oas.annotations.Operation;
89
import lombok.RequiredArgsConstructor;
910
import org.springframework.data.domain.Page;
1011
import org.springframework.http.ResponseEntity;
1112
import org.springframework.web.bind.annotation.*;
1213

1314
@RestController
1415
@RequiredArgsConstructor
15-
@RequestMapping("/law")
16+
@RequestMapping("/api/law")
1617
public class LawController {
1718

1819
private final LawService lawService;
1920

20-
// 법령 리스트 출력
21-
@GetMapping(value = "/list")
22-
public ResponseEntity<?> list(
23-
@RequestParam String query,
24-
@RequestParam int page
25-
) throws Exception {
26-
String lawList = lawService.getLawList(query, page);
27-
return ResponseEntity.ok().body(lawList);
28-
}
29-
3021

3122
@GetMapping(value = "/list/save")
23+
@Operation(summary = "키워드 관련 법령 데이터 저장(벡엔드 전용 API)", description = "벡엔드 데이터 저장용 API입니다")
3224
public ResponseEntity<?> getStatisticsCard(
3325
@RequestParam String query,
3426
@RequestParam int page
@@ -44,15 +36,8 @@ public ResponseEntity<?> getStatisticsCard(
4436
return ResponseEntity.ok().body("Success");
4537
}
4638

47-
@GetMapping("/{id}")
48-
public ResponseEntity<Law> getFullLaw(@PathVariable Long id) {
49-
Law law = lawService.getLawWithAllChildren(id);
50-
51-
return ResponseEntity.ok(law);
52-
}
53-
54-
5539
@PostMapping("/search")
40+
@Operation(summary = "볍령 목록 검색 기능", description = "조건에 맞는 법령 목록을 가져옵니다")
5641
public ResponseEntity<PageResponseDto> searchLaws(@RequestBody LawSearchRequestDto searchRequest) {
5742
Page<LawsDto> laws = lawService.searchLaws(searchRequest);
5843
PageResponseDto response = PageResponseDto.builder()
@@ -64,4 +49,13 @@ public ResponseEntity<PageResponseDto> searchLaws(@RequestBody LawSearchRequestD
6449
.build();
6550
return ResponseEntity.ok(response);
6651
}
52+
53+
@GetMapping("/{id}")
54+
@Operation(summary = "볍령 상세 조회 기능", description = "법령 상세 데이터를 조회합니다 \n" +
55+
"예시: /api/law/1")
56+
public ResponseEntity<Law> getFullLaw(@PathVariable Long id) {
57+
Law law = lawService.getLawWithAllChildren(id);
58+
59+
return ResponseEntity.ok(law);
60+
}
6761
}

backend/src/main/java/com/ai/lawyer/domain/law/dto/LawSearchRequestDto.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.ai.lawyer.domain.law.dto;
22

3+
import io.swagger.v3.oas.annotations.media.Schema;
34
import lombok.Builder;
45
import lombok.Data;
56

@@ -8,13 +9,31 @@
89
@Data
910
@Builder
1011
public class LawSearchRequestDto {
12+
13+
@Schema(description = "법령명", example = "노동")
1114
private String lawName; // 법령명
15+
16+
@Schema(description = "법령분야", example = "법률")
1217
private String lawField; // 법령분야
18+
19+
@Schema(description = "소관부처", example = "고용노동부")
1320
private String ministry; // 소관부처
21+
22+
@Schema(description = "공포일자 시작", example = "2000-03-25")
1423
private LocalDate promulgationDateStart; // 공포일자 시작
24+
25+
@Schema(description = "공포일자 종료", example = "2025-03-25")
1526
private LocalDate promulgationDateEnd; // 공포일자 종료
27+
28+
@Schema(description = "시행일자 시작", example = "2000-03-25")
1629
private LocalDate enforcementDateStart; // 시행일자 시작
30+
31+
@Schema(description = "시행일자 종료", example = "2025-03-25")
1732
private LocalDate enforcementDateEnd; // 시행일자 종료
33+
34+
@Schema(description = "페이지 번호 (0부터 시작)", example = "0")
1835
private int pageNumber; // 페이지 번호
36+
37+
@Schema(description = "페이지 크기", example = "10")
1938
private int pageSize; // 페이지 크기
2039
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package com.ai.lawyer.domain.lawWord.controller;
2+
3+
import com.ai.lawyer.domain.lawWord.service.LawWordService;
4+
import com.ai.lawyer.domain.precedent.entity.Precedent;
5+
import io.swagger.v3.oas.annotations.Operation;
6+
import lombok.RequiredArgsConstructor;
7+
import org.springframework.http.ResponseEntity;
8+
import org.springframework.web.bind.annotation.GetMapping;
9+
import org.springframework.web.bind.annotation.PathVariable;
10+
import org.springframework.web.bind.annotation.RequestMapping;
11+
import org.springframework.web.bind.annotation.RestController;
12+
13+
@RestController
14+
@RequiredArgsConstructor
15+
@RequestMapping("/api/law-word")
16+
public class LawWordController {
17+
18+
private final LawWordService lawWordService;
19+
20+
@GetMapping("/{word}")
21+
@Operation(summary = "법령 용어 검색", description = "법령 용어에 대한 정의를 반환합니다. \n" +
22+
"예시: /api/law-word/선박")
23+
public ResponseEntity<?> getPrecedent(@PathVariable String word) {
24+
return ResponseEntity.ok(lawWordService.findDefinition(word));
25+
}
26+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.ai.lawyer.domain.lawWord.entity;
2+
3+
import com.fasterxml.jackson.annotation.JsonIgnore;
4+
import jakarta.persistence.*;
5+
import lombok.AllArgsConstructor;
6+
import lombok.Builder;
7+
import lombok.Data;
8+
import lombok.NoArgsConstructor;
9+
10+
@Entity
11+
@Data
12+
@Builder
13+
@NoArgsConstructor
14+
@AllArgsConstructor
15+
public class LawWord {
16+
17+
@Id
18+
@GeneratedValue(strategy = GenerationType.IDENTITY)
19+
@JsonIgnore
20+
private Long id;
21+
22+
private String word; // 법률 용어
23+
24+
@Lob
25+
@Column(columnDefinition = "LONGTEXT")
26+
private String definition; // 정의
27+
28+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.ai.lawyer.domain.lawWord.repository;
2+
3+
import com.ai.lawyer.domain.lawWord.entity.LawWord;
4+
import org.springframework.data.jpa.repository.JpaRepository;
5+
import org.springframework.stereotype.Repository;
6+
7+
import java.util.Optional;
8+
9+
@Repository
10+
public interface LawWordRepository extends JpaRepository<LawWord, Long> {
11+
Optional<LawWord> findByWord(String word);
12+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package com.ai.lawyer.domain.lawWord.service;
2+
3+
import com.ai.lawyer.domain.lawWord.entity.LawWord;
4+
import com.ai.lawyer.domain.lawWord.repository.LawWordRepository;
5+
import com.fasterxml.jackson.core.JsonProcessingException;
6+
import com.fasterxml.jackson.databind.JsonNode;
7+
import com.fasterxml.jackson.databind.ObjectMapper;
8+
import lombok.AllArgsConstructor;
9+
import org.springframework.stereotype.Service;
10+
import org.springframework.web.client.RestTemplate;
11+
12+
@Service
13+
@AllArgsConstructor
14+
public class LawWordService {
15+
16+
private final LawWordRepository lawWordRepository;
17+
18+
private final RestTemplate restTemplate = new RestTemplate();
19+
private final ObjectMapper objectMapper = new ObjectMapper();
20+
21+
public String findDefinition(String word) {
22+
// 1) DB 확인
23+
return lawWordRepository.findByWord(word)
24+
.map(LawWord::getDefinition)
25+
.orElseGet(() -> {
26+
try {
27+
String url = "https://www.law.go.kr/DRF/lawService.do?OC=noheechul"
28+
+ "&target=lstrm&type=JSON&query=" + word;
29+
String json = restTemplate.getForObject(url, String.class);
30+
JsonNode rootNode = objectMapper.readTree(json);
31+
// 오류 응답 처리
32+
if (rootNode.has("Law")) {
33+
return rootNode.get("Law").asText();
34+
}
35+
JsonNode serviceNode = rootNode.path("LsTrmService");
36+
JsonNode defNode = serviceNode.path("법령용어정의");
37+
String definition;
38+
if (defNode.isArray() && defNode.size() > 0) {
39+
// definition = defNode.get(0).asText().split("\\.",2)[0].trim();
40+
definition = defNode.get(0).asText().trim();
41+
} else {
42+
// definition = defNode.asText().split("\\.",2)[0].trim();
43+
definition = defNode.asText().trim();
44+
}
45+
LawWord entity = LawWord.builder()
46+
.word(word)
47+
.definition(definition)
48+
.build();
49+
lawWordRepository.save(entity);
50+
return definition;
51+
} catch (Exception e) {
52+
throw new RuntimeException("Failed to fetch definition", e);
53+
}
54+
});
55+
}
56+
}

backend/src/main/java/com/ai/lawyer/domain/precedent/controller/PrecedentController.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,26 +5,36 @@
55
import com.ai.lawyer.domain.precedent.entity.Precedent;
66
import com.ai.lawyer.domain.precedent.service.PrecedentService;
77
import com.ai.lawyer.global.dto.PageResponseDto;
8+
import io.swagger.v3.oas.annotations.Operation;
89
import lombok.RequiredArgsConstructor;
910
import org.springframework.data.domain.Page;
1011
import org.springframework.http.ResponseEntity;
1112
import org.springframework.web.bind.annotation.*;
1213

1314
@RestController
1415
@RequiredArgsConstructor
15-
@RequestMapping("/precedent")
16+
@RequestMapping("/api/precedent")
1617
public class PrecedentController {
1718

1819
private final PrecedentService precedentService;
1920

2021
@GetMapping(value = "/list/save")
22+
@Operation(summary = "키워드 관련 판례 데이터 저장(벡엔드 전용 API)", description = "벡엔드 데이터 저장용 API입니다")
2123
public ResponseEntity<?> list(
2224
@RequestParam String query
2325
) throws Exception {
2426
return ResponseEntity.ok().body(precedentService.searchAndSaveAll(query));
2527
}
2628

29+
/**
30+
* POST /api/precedent/search
31+
* 키워드로 판례 검색 (판시사항, 판결요지, 판례내용, 사건명에서 검색)
32+
* @param requestDto
33+
* @return id, 사건명, 사건번호, 선고일자 리스트
34+
*/
35+
2736
@PostMapping("/search")
37+
@Operation(summary = "판례 목록 검색 기능", description = "조건에 맞는 판례 목록을 가져옵니다")
2838
public ResponseEntity<PageResponseDto> searchPrecedents(
2939
@RequestBody PrecedentSearchRequestDto requestDto) {
3040

@@ -44,8 +54,11 @@ public ResponseEntity<PageResponseDto> searchPrecedents(
4454
* 주어진 id로 Precedent 조회
4555
*
4656
* @param id Precedent PK
57+
* @return Precedent 엔티티
4758
*/
4859
@GetMapping("/{id}")
60+
@Operation(summary = "판례 상세 조회 기능", description = "판례 상세 데이터를 조회합니다 \n" +
61+
"예시: /api/precedent/1")
4962
public ResponseEntity<Precedent> getPrecedent(@PathVariable Long id) {
5063
Precedent precedent = precedentService.getPrecedentById(id);
5164
return ResponseEntity.ok(precedent);
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,17 @@
11
package com.ai.lawyer.domain.precedent.dto;
22

3+
import io.swagger.v3.oas.annotations.media.Schema;
34
import lombok.Data;
45

56
@Data
67
public class PrecedentSearchRequestDto {
8+
9+
@Schema(description = "검색 키워드", example = "노동")
710
private String keyword; // 검색 키워드
11+
12+
@Schema(description = "페이지 번호 (0부터 시작)", example = "0")
813
private int pageNumber; // 페이지 번호
14+
15+
@Schema(description = "페이지 크기", example = "10")
916
private int pageSize; // 페이지 크기
1017
}

0 commit comments

Comments
 (0)