From 31fbf6a79520a39b86afe49a341d6203333a31d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=84=EC=83=81=ED=98=84?= Date: Thu, 27 Feb 2025 10:47:50 +0900 Subject: [PATCH 1/7] Feat: add API server for company info --- .DS_Store | Bin 6148 -> 6148 bytes Task | 0 build.gradle | 12 ++ src/.DS_Store | Bin 0 -> 6148 bytes .../backend/Controller/CompanyController.java | 33 ++++++ .../backend/dto/CompanyPartialDto.java | 37 +++++++ .../backend/service/CompanyApiService.java | 104 ++++++++++++++++++ .../backend/service/CompanyApiTestRunner.java | 82 ++++++++++++++ 8 files changed, 268 insertions(+) create mode 100644 Task create mode 100644 src/.DS_Store create mode 100644 src/main/java/com/leafvillage/backend/Controller/CompanyController.java create mode 100644 src/main/java/com/leafvillage/backend/dto/CompanyPartialDto.java create mode 100644 src/main/java/com/leafvillage/backend/service/CompanyApiService.java create mode 100644 src/main/java/com/leafvillage/backend/service/CompanyApiTestRunner.java diff --git a/.DS_Store b/.DS_Store index d8d62204074cd716e2c71214db23db69c532f393..3c1701e366b69572305b58063770e70b227fb63a 100644 GIT binary patch literal 6148 zcmeHKL2uJA6n^H=OJ)OmPNcQ zKBksMnNH{!wHcX4_+imu%=nj!B+V|se@uhyzY?s}3a?aqmJe9$~v6XSRI=dded%ri4{&PBIKr-)BXqnsAJ?9*Cs_bbgTE2pxu z)mB;stOEbD0=z%CNQ^Cm3yo^)K&Gw$z#^)Zp{zdsfi717TLu>zQ3Dg23e;3#t{B4H z9fYQ%y=D9t8a17S8X5hVk%hUT2y^uiu5u^Q(r9z5fK?!?KtVrN`TRe=`u?9K*(a-j zRp6geKomROP8(A)XY11B_^fr2ULmou-$J9JAT!6YD)3Rfi=+%~E*F3;gA0wQf!PlM MC4vwg3PC diff --git a/Task b/Task new file mode 100644 index 0000000..e69de29 diff --git a/build.gradle b/build.gradle index c64a101..9a79b7d 100644 --- a/build.gradle +++ b/build.gradle @@ -41,6 +41,18 @@ dependencies { // testImplementation 'org.springframework.security:spring-security-test' } + +dependencies { + implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'org.springframework.boot:spring-boot-starter-data-jpa' + implementation 'org.jsoup:jsoup:1.15.3' + runtimeOnly 'com.h2database:h2' // 예제에서는 H2 in-memory DB 사용 + testImplementation 'org.springframework.boot:spring-boot-starter-test' +} + + + + tasks.named('test') { useJUnitPlatform() } diff --git a/src/.DS_Store b/src/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..ccac58678c50d79fba397b0764d99bc38e60116f GIT binary patch literal 6148 zcmeHK!A`Z-IyI!kW%|>f7DVjUG`$y;9$EY9kXGuN7|5C`7!YRC9 z$AA=ikU+YS_bb}w^HzSpop=4P`5k#rInbyX&bZc{wc8{eQZ;{+|!hBh7$j;9oJojE>uJFeP=j zE+t2It%Z7rN)^g}? getCompanyInfo(@RequestParam String corpNm) { + try { + // 1) 주소/전화번호 콘솔 출력 + 전체 JSON 반환 + String json = companyApiService.getCompanyDataByName(corpNm); + return ResponseEntity.ok(json); + } catch (Exception e) { + e.printStackTrace(); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) + .body("오류 발생: " + e.getMessage()); + } + } +} diff --git a/src/main/java/com/leafvillage/backend/dto/CompanyPartialDto.java b/src/main/java/com/leafvillage/backend/dto/CompanyPartialDto.java new file mode 100644 index 0000000..ea672c4 --- /dev/null +++ b/src/main/java/com/leafvillage/backend/dto/CompanyPartialDto.java @@ -0,0 +1,37 @@ +package com.leafvillage.backend.dto; + +public class CompanyPartialDto { + private String corpNm; // 회사명 + private String englishName; // 영문명 + private String address; // 주소 + + public CompanyPartialDto() { + } + + public CompanyPartialDto(String corpNm, String englishName, String address) { + this.corpNm = corpNm; + this.englishName = englishName; + this.address = address; + } + + public String getCorpNm() { + return corpNm; + } + public void setCorpNm(String corpNm) { + this.corpNm = corpNm; + } + + public String getEnglishName() { + return englishName; + } + public void setEnglishName(String englishName) { + this.englishName = englishName; + } + + public String getAddress() { + return address; + } + public void setAddress(String address) { + this.address = address; + } +} diff --git a/src/main/java/com/leafvillage/backend/service/CompanyApiService.java b/src/main/java/com/leafvillage/backend/service/CompanyApiService.java new file mode 100644 index 0000000..d836732 --- /dev/null +++ b/src/main/java/com/leafvillage/backend/service/CompanyApiService.java @@ -0,0 +1,104 @@ +package com.leafvillage.backend.service; + +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.UriComponentsBuilder; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.JsonNode; +import java.util.*; +@Service +public class CompanyApiService { + + // 이미 인코딩된 서비스키를 사용 (브라우저에서 테스트한 URL과 동일) + private static final String SERVICE_KEY = "YugI7KFgMPZzeCgNekIYquyzw8WQVtkPJfccnooevCyF5Rh5ZXaL92U26v6PxVdapMNXtf5XfzvajTKbGkfuew=="; + private static final String BASE_URL = "https://apis.data.go.kr/1160100/service/GetCorpBasicInfoService_V2/getCorpOutline_V2"; + + private final RestTemplate restTemplate; + private final ObjectMapper objectMapper; + + public CompanyApiService() { + this.restTemplate = new RestTemplate(); + this.objectMapper = new ObjectMapper(); + } + + /** + * 프론트엔드에서 한글 회사명을 전달받아, 공공데이터포털 API를 호출한 후 JSON 응답을 반환합니다. + */ + public String getCompanyDataByName(String corpNm) { + UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(BASE_URL) + .queryParam("serviceKey", SERVICE_KEY) // 대소문자도 브라우저와 동일하게 + .queryParam("pageNo", 1) + .queryParam("numOfRows", 5) + .queryParam("resultType", "json") + .queryParam("corpNm", corpNm); + + // build(false)를 사용하여 이미 인코딩된 파라미터가 재인코딩되지 않도록 합니다. + String url = builder.build(false).toUriString(); + System.out.println("요청 URL: " + url); // 디버그용 로그 + + ResponseEntity response = restTemplate.getForEntity(url, String.class); + if (response.getStatusCode().is2xxSuccessful() && response.getBody() != null) { + // JSON 파싱 + String json = response.getBody(); + try{ + JsonNode root = objectMapper.readTree(json); + JsonNode itemsNode = root.path("response") + .path("body") + .path("items") + .path("item"); + + // 정확한 매칭을 위한 리스트 + String normalizedInput = corpNm.replaceAll("\\s+", ""); + String variant1 = normalizedInput; + String variant2 = "(주)" + normalizedInput; + String variant3 = normalizedInput + "(주)"; + + List exactMatches = new ArrayList<>(); + if (itemsNode.isArray()) { + for (JsonNode item : itemsNode) { + String name = item.path("corpNm").asText("").replaceAll("\\s+", ""); + if (name.equals(variant1) || name.equals(variant2) || name.equals(variant3)) { + exactMatches.add(item); + } + } + }else if (!itemsNode.isMissingNode()) { + // 단일 객체인 경우에도 일치 여부 확인 + String name = itemsNode.path("corpNm").asText("").replaceAll("\\s+", ""); + if (name.equals(variant1) || name.equals(variant2) || name.equals(variant3)) { + exactMatches.add(itemsNode); + } + } + + if (exactMatches.isEmpty()) { + System.out.println("정확한 일치 항목이 없습니다."); + } else { + System.out.println("=== 정확하게 일치하는 항목 (" + exactMatches.size() + "건) ==="); + for (JsonNode item : exactMatches) { + String address = item.path("enpBsadr").asText("주소 없음"); + String phone = item.path("enpTlno").asText("전화번호 없음"); + String domain = item.path("enpDmn").asText("도메인 없음"); + + //System.out.println("-----"); + //System.out.println("회사명: " + item.path("corpNm").asText("회사명 없음")); + //System.out.println("주소: " + address); + //System.out.println("전화번호: " + phone); + //System.out.println("도메인: " + domain); + //if (!domain.equals("도메인 없음")) { + // String logoUrl = "https://logo.clearbit.com/" + domain; + // System.out.println("Clearbit 로고 URL: " + logoUrl); + //} else { + // System.out.println("Clearbit 로고 URL: 도메인 정보가 없어 생성할 수 없습니다."); + //} + } + } + + }catch(Exception e){ + throw new RuntimeException("JSON 파싱 오류: " + e.getMessage()); + } + return json; + } else { + throw new RuntimeException("API 호출 실패: " + response.getStatusCodeValue()); + } + } +} diff --git a/src/main/java/com/leafvillage/backend/service/CompanyApiTestRunner.java b/src/main/java/com/leafvillage/backend/service/CompanyApiTestRunner.java new file mode 100644 index 0000000..b7db22a --- /dev/null +++ b/src/main/java/com/leafvillage/backend/service/CompanyApiTestRunner.java @@ -0,0 +1,82 @@ +package com.leafvillage.backend.service; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.leafvillage.backend.service.CompanyApiService; + +import java.util.ArrayList; +import java.util.List; + +public class CompanyApiTestRunner { + public static void main(String[] args) { + CompanyApiService service = new CompanyApiService(); + try { + // 원하는 회사명 입력 (예: "네이버") + String corpNm = "삼성전자"; + // API 호출: 전체 JSON 응답을 반환 + String fullJson = service.getCompanyDataByName(corpNm); + + // 전체 API 응답 출력 + //System.out.println("=== 전체 API 응답 ==="); + //System.out.println(fullJson); + + // ObjectMapper를 사용하여 JSON 파싱 + ObjectMapper mapper = new ObjectMapper(); + JsonNode root = mapper.readTree(fullJson); + JsonNode itemsNode = root.path("response") + .path("body") + .path("items") + .path("item"); + + // 입력한 회사명을 정규화 (공백 제거) + String normalizedInput = corpNm.replaceAll("\\s+", ""); + // 다양한 "(주)" 변형 생성 + String variant1 = normalizedInput; + String variant2 = "(주)" + normalizedInput; + String variant3 = normalizedInput + "(주)"; + + // 정확히 일치하는 항목을 저장할 리스트 + List exactMatches = new ArrayList<>(); + if (itemsNode.isArray()) { + for (JsonNode item : itemsNode) { + String name = item.path("corpNm").asText("").replaceAll("\\s+", ""); + if (name.equals(variant1) || name.equals(variant2) || name.equals(variant3)) { + exactMatches.add(item); + } + } + } else if (!itemsNode.isMissingNode()) { + String name = itemsNode.path("corpNm").asText("").replaceAll("\\s+", ""); + if (name.equals(variant1) || name.equals(variant2) || name.equals(variant3) ) { + exactMatches.add(itemsNode); + } + } + + // 결과 출력 + if (exactMatches.isEmpty()) { + System.out.println("정확한 일치 항목이 없습니다."); + } else { + System.out.println("=== 정확하게 일치하는 항목 (" + exactMatches.size() + "건) ==="); + for (JsonNode item : exactMatches) { + String companyName = item.path("corpNm").asText("회사명 없음"); + String address = item.path("enpBsadr").asText("주소 없음"); + String phone = item.path("enpTlno").asText("전화번호 없음"); + String domain = item.path("enpHmpgUrl").asText("도메인 없음"); + + System.out.println("-----"); + System.out.println("회사명: " + companyName); + System.out.println("주소: " + address); + System.out.println("전화번호: " + phone); + System.out.println("도메인: " + domain); + if (!domain.equals("도메인 없음")) { + String logoUrl = "https://logo.clearbit.com/" + domain; + System.out.println("Clearbit 로고 URL: " + logoUrl); + } else { + System.out.println("Clearbit 로고 URL: 도메인 정보가 없어 생성할 수 없습니다."); + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } +} From 13ada30ab4c8a6e87aab63749a963971d03b8626 Mon Sep 17 00:00:00 2001 From: Hyunje1128 Date: Thu, 27 Feb 2025 11:38:13 +0900 Subject: [PATCH 2/7] =?UTF-8?q?Merge=20conflict=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 6 +++ .../leafvillage/backend/Config/S3Config.java | 31 +++++++++++++++ .../backend/Controller/FileController.java | 21 ++++++++++ .../Test/DatabaseTestController.java | 28 -------------- .../Controller/Test/StatusController.java | 16 -------- .../backend/Service/S3Service.java | 38 +++++++++++++++++++ 6 files changed, 96 insertions(+), 44 deletions(-) create mode 100644 src/main/java/com/leafvillage/backend/Config/S3Config.java create mode 100644 src/main/java/com/leafvillage/backend/Controller/FileController.java delete mode 100644 src/main/java/com/leafvillage/backend/Controller/Test/DatabaseTestController.java delete mode 100644 src/main/java/com/leafvillage/backend/Controller/Test/StatusController.java create mode 100644 src/main/java/com/leafvillage/backend/Service/S3Service.java diff --git a/build.gradle b/build.gradle index 9a79b7d..dbd656b 100644 --- a/build.gradle +++ b/build.gradle @@ -56,3 +56,9 @@ dependencies { tasks.named('test') { useJUnitPlatform() } + +dependencies { + implementation 'com.amazonaws:aws-java-sdk-s3:1.12.133' + implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'org.springframework.boot:spring-boot-starter-data-jpa' +} \ No newline at end of file diff --git a/src/main/java/com/leafvillage/backend/Config/S3Config.java b/src/main/java/com/leafvillage/backend/Config/S3Config.java new file mode 100644 index 0000000..67afe8b --- /dev/null +++ b/src/main/java/com/leafvillage/backend/Config/S3Config.java @@ -0,0 +1,31 @@ +package com.leafvillage.backend.Config; + +import com.amazonaws.auth.AWSStaticCredentialsProvider; +import com.amazonaws.auth.BasicAWSCredentials; +import com.amazonaws.services.s3.AmazonS3; +import com.amazonaws.services.s3.AmazonS3ClientBuilder; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class S3Config { + + @Value("${aws.s3.accessKey}") + private String accessKey; + + @Value("${aws.s3.secretKey}") + private String secretKey; + + @Value("${aws.s3.region}") + private String region; + + @Bean + public AmazonS3 amazonS3() { + BasicAWSCredentials awsCredentials = new BasicAWSCredentials(accessKey, secretKey); + return AmazonS3ClientBuilder.standard() + .withRegion(region) + .withCredentials(new AWSStaticCredentialsProvider(awsCredentials)) + .build(); + } +} \ No newline at end of file diff --git a/src/main/java/com/leafvillage/backend/Controller/FileController.java b/src/main/java/com/leafvillage/backend/Controller/FileController.java new file mode 100644 index 0000000..54c50c5 --- /dev/null +++ b/src/main/java/com/leafvillage/backend/Controller/FileController.java @@ -0,0 +1,21 @@ +package com.leafvillage.backend.Controller; + +import com.leafvillage.backend.Service.S3Service; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; + +@RestController +@RequestMapping("/api/files") +public class FileController { + + @Autowired + private S3Service s3Service; + + @PostMapping("/upload") + public String uploadFile(@RequestParam("file") MultipartFile file) throws IOException { + return s3Service.uploadFile(file); + } +} \ No newline at end of file diff --git a/src/main/java/com/leafvillage/backend/Controller/Test/DatabaseTestController.java b/src/main/java/com/leafvillage/backend/Controller/Test/DatabaseTestController.java deleted file mode 100644 index 153d538..0000000 --- a/src/main/java/com/leafvillage/backend/Controller/Test/DatabaseTestController.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.leafvillage.backend.Controller.Test; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequestMapping("/api/db") -public class DatabaseTestController { - - @Autowired - private JdbcTemplate jdbcTemplate; - - @GetMapping("/test") - public ResponseEntity testDatabaseConnection() { - try { - jdbcTemplate.queryForObject("SELECT 1", Integer.class); - return ResponseEntity.ok("RDS 연결 성공 (Spring Boot)"); - } catch (Exception e) { - return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) - .body("RDS 연결 실패: " + e.getMessage()); - } - } -} \ No newline at end of file diff --git a/src/main/java/com/leafvillage/backend/Controller/Test/StatusController.java b/src/main/java/com/leafvillage/backend/Controller/Test/StatusController.java deleted file mode 100644 index 58dcb68..0000000 --- a/src/main/java/com/leafvillage/backend/Controller/Test/StatusController.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.leafvillage.backend.Controller.Test; - -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequestMapping("/api/status") -public class StatusController { - - @GetMapping - public ResponseEntity checkStatus() { - return ResponseEntity.ok("백엔드 서버 정상 작동 중!"); - } -} \ No newline at end of file diff --git a/src/main/java/com/leafvillage/backend/Service/S3Service.java b/src/main/java/com/leafvillage/backend/Service/S3Service.java new file mode 100644 index 0000000..5ef7c23 --- /dev/null +++ b/src/main/java/com/leafvillage/backend/Service/S3Service.java @@ -0,0 +1,38 @@ +package com.leafvillage.backend.Service; + +import com.amazonaws.services.s3.AmazonS3; +import com.amazonaws.services.s3.model.ObjectMetadata; +import com.amazonaws.services.s3.model.PutObjectRequest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.io.InputStream; +import java.util.UUID; + +@Service +public class S3Service { + + @Autowired + private AmazonS3 amazonS3; + + @Value("${aws.s3.bucketName}") + private String bucketName; + + public String uploadFile(MultipartFile file) throws IOException { + String fileName = UUID.randomUUID() + "_" + file.getOriginalFilename(); // 파일명 중복 방지 + InputStream inputStream = file.getInputStream(); + + ObjectMetadata metadata = new ObjectMetadata(); + metadata.setContentLength(file.getSize()); + metadata.setContentType(file.getContentType()); + + // S3에 업로드 + amazonS3.putObject(new PutObjectRequest(bucketName, fileName, inputStream, metadata)); + + // 업로드된 파일의 URL 반환 + return amazonS3.getUrl(bucketName, fileName).toString(); + } +} \ No newline at end of file From c1bcc0a2a0ec574fc54592a7afaa24296a273f76 Mon Sep 17 00:00:00 2001 From: Hyunje1128 Date: Thu, 27 Feb 2025 11:38:33 +0900 Subject: [PATCH 3/7] Ignore .DS_Store files --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 0a253a8..b5fb2fc 100644 --- a/.gitignore +++ b/.gitignore @@ -54,3 +54,4 @@ out/ ### VS Code ### .vscode/ +.DS_Store From cbcc7922d0a61c9a862315f3f52b63f8fa3ddc0d Mon Sep 17 00:00:00 2001 From: Hyunje1128 Date: Thu, 27 Feb 2025 16:00:59 +0900 Subject: [PATCH 4/7] =?UTF-8?q?=EA=B8=B0=EC=97=85=20=EC=A0=95=EB=B3=B4=20?= =?UTF-8?q?=EC=8B=A4=ED=8C=A8=20=EA=B0=9C=EC=88=98=20=EC=B6=9C=EB=A0=A5=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .DS_Store | Bin 6148 -> 6148 bytes .../leafvillage/backend/Config/S3Config.java | 31 --- .../backend/Controller/FileController.java | 21 -- .../backend/Service/S3Service.java | 38 ---- .../backend/service/CompanyApiService.java | 2 +- .../backend/service/CompanyApiTestRunner.java | 189 ++++++++++++------ 6 files changed, 127 insertions(+), 154 deletions(-) delete mode 100644 src/main/java/com/leafvillage/backend/Config/S3Config.java delete mode 100644 src/main/java/com/leafvillage/backend/Controller/FileController.java delete mode 100644 src/main/java/com/leafvillage/backend/Service/S3Service.java diff --git a/.DS_Store b/.DS_Store index 3c1701e366b69572305b58063770e70b227fb63a..80a3cfd05f4f2061d732081fb5d38a8efe9dcbe7 100644 GIT binary patch delta 46 zcmZoMXfc@JFU-flz`)4BAi%(o;+d15oRpKFv{{g2B{L)6W+RrX%o7{bHnVg597UWpTtPYZ3W=LYlWXSW(K}Z5c9f4Ty TKNv7DZ02FP%DkDK<1aq|(18^0 diff --git a/src/main/java/com/leafvillage/backend/Config/S3Config.java b/src/main/java/com/leafvillage/backend/Config/S3Config.java deleted file mode 100644 index 67afe8b..0000000 --- a/src/main/java/com/leafvillage/backend/Config/S3Config.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.leafvillage.backend.Config; - -import com.amazonaws.auth.AWSStaticCredentialsProvider; -import com.amazonaws.auth.BasicAWSCredentials; -import com.amazonaws.services.s3.AmazonS3; -import com.amazonaws.services.s3.AmazonS3ClientBuilder; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -@Configuration -public class S3Config { - - @Value("${aws.s3.accessKey}") - private String accessKey; - - @Value("${aws.s3.secretKey}") - private String secretKey; - - @Value("${aws.s3.region}") - private String region; - - @Bean - public AmazonS3 amazonS3() { - BasicAWSCredentials awsCredentials = new BasicAWSCredentials(accessKey, secretKey); - return AmazonS3ClientBuilder.standard() - .withRegion(region) - .withCredentials(new AWSStaticCredentialsProvider(awsCredentials)) - .build(); - } -} \ No newline at end of file diff --git a/src/main/java/com/leafvillage/backend/Controller/FileController.java b/src/main/java/com/leafvillage/backend/Controller/FileController.java deleted file mode 100644 index 54c50c5..0000000 --- a/src/main/java/com/leafvillage/backend/Controller/FileController.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.leafvillage.backend.Controller; - -import com.leafvillage.backend.Service.S3Service; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.*; -import org.springframework.web.multipart.MultipartFile; - -import java.io.IOException; - -@RestController -@RequestMapping("/api/files") -public class FileController { - - @Autowired - private S3Service s3Service; - - @PostMapping("/upload") - public String uploadFile(@RequestParam("file") MultipartFile file) throws IOException { - return s3Service.uploadFile(file); - } -} \ No newline at end of file diff --git a/src/main/java/com/leafvillage/backend/Service/S3Service.java b/src/main/java/com/leafvillage/backend/Service/S3Service.java deleted file mode 100644 index 5ef7c23..0000000 --- a/src/main/java/com/leafvillage/backend/Service/S3Service.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.leafvillage.backend.Service; - -import com.amazonaws.services.s3.AmazonS3; -import com.amazonaws.services.s3.model.ObjectMetadata; -import com.amazonaws.services.s3.model.PutObjectRequest; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Service; -import org.springframework.web.multipart.MultipartFile; - -import java.io.IOException; -import java.io.InputStream; -import java.util.UUID; - -@Service -public class S3Service { - - @Autowired - private AmazonS3 amazonS3; - - @Value("${aws.s3.bucketName}") - private String bucketName; - - public String uploadFile(MultipartFile file) throws IOException { - String fileName = UUID.randomUUID() + "_" + file.getOriginalFilename(); // 파일명 중복 방지 - InputStream inputStream = file.getInputStream(); - - ObjectMetadata metadata = new ObjectMetadata(); - metadata.setContentLength(file.getSize()); - metadata.setContentType(file.getContentType()); - - // S3에 업로드 - amazonS3.putObject(new PutObjectRequest(bucketName, fileName, inputStream, metadata)); - - // 업로드된 파일의 URL 반환 - return amazonS3.getUrl(bucketName, fileName).toString(); - } -} \ No newline at end of file diff --git a/src/main/java/com/leafvillage/backend/service/CompanyApiService.java b/src/main/java/com/leafvillage/backend/service/CompanyApiService.java index d836732..c43e55d 100644 --- a/src/main/java/com/leafvillage/backend/service/CompanyApiService.java +++ b/src/main/java/com/leafvillage/backend/service/CompanyApiService.java @@ -29,7 +29,7 @@ public String getCompanyDataByName(String corpNm) { UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(BASE_URL) .queryParam("serviceKey", SERVICE_KEY) // 대소문자도 브라우저와 동일하게 .queryParam("pageNo", 1) - .queryParam("numOfRows", 5) + .queryParam("numOfRows", 5) // 아마 이 부분에서 "=== 정확하게 일치하는 항목 (5건) ===" 문구가 반복적 출력되는 듯 .queryParam("resultType", "json") .queryParam("corpNm", corpNm); diff --git a/src/main/java/com/leafvillage/backend/service/CompanyApiTestRunner.java b/src/main/java/com/leafvillage/backend/service/CompanyApiTestRunner.java index b7db22a..324344b 100644 --- a/src/main/java/com/leafvillage/backend/service/CompanyApiTestRunner.java +++ b/src/main/java/com/leafvillage/backend/service/CompanyApiTestRunner.java @@ -4,79 +4,142 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.leafvillage.backend.service.CompanyApiService; -import java.util.ArrayList; -import java.util.List; +import java.util.*; public class CompanyApiTestRunner { public static void main(String[] args) { CompanyApiService service = new CompanyApiService(); - try { - // 원하는 회사명 입력 (예: "네이버") - String corpNm = "삼성전자"; - // API 호출: 전체 JSON 응답을 반환 - String fullJson = service.getCompanyDataByName(corpNm); - - // 전체 API 응답 출력 - //System.out.println("=== 전체 API 응답 ==="); - //System.out.println(fullJson); - - // ObjectMapper를 사용하여 JSON 파싱 - ObjectMapper mapper = new ObjectMapper(); - JsonNode root = mapper.readTree(fullJson); - JsonNode itemsNode = root.path("response") - .path("body") - .path("items") - .path("item"); - - // 입력한 회사명을 정규화 (공백 제거) - String normalizedInput = corpNm.replaceAll("\\s+", ""); - // 다양한 "(주)" 변형 생성 - String variant1 = normalizedInput; - String variant2 = "(주)" + normalizedInput; - String variant3 = normalizedInput + "(주)"; - - // 정확히 일치하는 항목을 저장할 리스트 - List exactMatches = new ArrayList<>(); - if (itemsNode.isArray()) { - for (JsonNode item : itemsNode) { - String name = item.path("corpNm").asText("").replaceAll("\\s+", ""); + List corpNames = Arrays.asList( + "삼성전자", + "현대자동차", + "기아", + "LG전자", + "SK하이닉스", + "네이버", + "카카오", + "삼성생명", + "삼성물산", + "현대모비스", + "SK이노베이션", + "LG화학", + "포스코홀딩스", + "한화솔루션", + "대한항공", + "아시아나항공", + "CJ제일제당", + "롯데쇼핑", + "삼성SDI", + "셀트리온", + "삼성바이오로직스", + "엔씨소프트", + "넷마블", + "하이브", + "현대건설", + "두산에너빌리티", + "에코프로", + "한국전력공사", + "LG에너지솔루션", + "KB금융" + + ); + + ObjectMapper mapper = new ObjectMapper(); + Set printedCompanies = new HashSet<>(); // 중복 제거를 위한 Set + int failCount = 0; // 실패한 기업 수를 셀 변수 + + for (String corpNm : corpNames) { + try { + // 요청 URL 직접 출력 (한 번만 출력) + String requestUrl = "https://apis.data.go.kr/1160100/service/GetCorpBasicInfoService_V2/getCorpOutline_V2?serviceKey=YugI7KFgMPZzeCgNekIYquyzw8WQVtkPJfccnooevCyF5Rh5ZXaL92U26v6PxVdapMNXtf5XfzvajTKbGkfuew==&pageNo=1&numOfRows=5&resultType=json&corpNm=" + corpNm; + System.out.println("-----"); + //System.out.println("요청 URL: " + requestUrl); // 요청 URL 출력 + + // API 호출 + String fullJson = service.getCompanyDataByName(corpNm); +// System.out.println("-----"); + // API 호출 성공 여부 체크 + if (fullJson == null || fullJson.isEmpty()) { + System.out.println(corpNm + " : 기업 정보를 가져오는 데 실패했습니다."); + System.out.println("-----"); // 실패 시에도 구분선 추가 + failCount++; // 실패 시 카운트 증가 + continue; // 실패 시 다음 기업으로 넘어가기 + } + + JsonNode root = mapper.readTree(fullJson); + JsonNode itemsNode = root.path("response") + .path("body") + .path("items") + .path("item"); + + // 기업명 정규화 (공백 제거) + String normalizedInput = corpNm.replaceAll("\\s+", ""); + String variant1 = normalizedInput; + String variant2 = "(주)" + normalizedInput; + String variant3 = normalizedInput + "(주)"; + + List exactMatches = new ArrayList<>(); + if (itemsNode.isArray()) { + for (JsonNode item : itemsNode) { + String name = item.path("corpNm").asText("").replaceAll("\\s+", ""); + if (name.equals(variant1) || name.equals(variant2) || name.equals(variant3)) { + exactMatches.add(item); + } + } + } else if (!itemsNode.isMissingNode()) { + String name = itemsNode.path("corpNm").asText("").replaceAll("\\s+", ""); if (name.equals(variant1) || name.equals(variant2) || name.equals(variant3)) { - exactMatches.add(item); + exactMatches.add(itemsNode); } } - } else if (!itemsNode.isMissingNode()) { - String name = itemsNode.path("corpNm").asText("").replaceAll("\\s+", ""); - if (name.equals(variant1) || name.equals(variant2) || name.equals(variant3) ) { - exactMatches.add(itemsNode); - } - } - - // 결과 출력 - if (exactMatches.isEmpty()) { - System.out.println("정확한 일치 항목이 없습니다."); - } else { - System.out.println("=== 정확하게 일치하는 항목 (" + exactMatches.size() + "건) ==="); - for (JsonNode item : exactMatches) { - String companyName = item.path("corpNm").asText("회사명 없음"); - String address = item.path("enpBsadr").asText("주소 없음"); - String phone = item.path("enpTlno").asText("전화번호 없음"); - String domain = item.path("enpHmpgUrl").asText("도메인 없음"); - - System.out.println("-----"); - System.out.println("회사명: " + companyName); - System.out.println("주소: " + address); - System.out.println("전화번호: " + phone); - System.out.println("도메인: " + domain); - if (!domain.equals("도메인 없음")) { - String logoUrl = "https://logo.clearbit.com/" + domain; - System.out.println("Clearbit 로고 URL: " + logoUrl); - } else { - System.out.println("Clearbit 로고 URL: 도메인 정보가 없어 생성할 수 없습니다."); + + // 결과 출력 (중복 제거) + if (exactMatches.isEmpty()) { + System.out.println(corpNm + " : 정확한 일치 항목 없음"); + failCount++; +// System.out.println("-----"); // 실패 시에도 구분선 추가 + } else { + //System.out.println("=== 정확하게 일치하는 항목 (" + exactMatches.size() + "건) ==="); + + for (JsonNode item : exactMatches) { + String companyName = item.path("corpNm").asText("회사명 없음"); + + // 중복 체크: 이미 출력한 기업이면 건너뛰기 + if (printedCompanies.contains(companyName)) { + continue; + } + printedCompanies.add(companyName); // 출력한 기업 추가 + + String address = item.path("enpBsadr").asText("주소 없음"); + String phone = item.path("enpTlno").asText("전화번호 없음"); + String domain = item.path("enpHmpgUrl").asText("도메인 없음"); + +// System.out.println("-----"); + System.out.println("회사명: " + companyName); + System.out.println("주소: " + address); + System.out.println("전화번호: " + phone); + System.out.println("도메인: " + domain); + if (!domain.equals("도메인 없음")) { + String logoUrl = "https://logo.clearbit.com/" + domain; + System.out.println("Clearbit 로고 URL: " + logoUrl); +// System.out.println("-----"); + } else { + System.out.println("Clearbit 로고 URL: 도메인 정보 없음"); + failCount++; +// System.out.println("-----"); + } } } + } catch (Exception e) { + // 실패 시에도 구분선과 함께 메시지 출력 + System.out.println("-----"); + System.out.println("[" + corpNm + "] 데이터 조회 중 오류 발생: " + e.getMessage()); +// System.out.println("-----"); // 실패 시에도 구분선 추가 + failCount++; // 실패 시 카운트 증가 } - } catch (Exception e) { - e.printStackTrace(); } + + // 실패한 기업 개수 출력 + System.out.println("-----"); + System.out.println("총 정보 가져오기 실패한 기업 개수: " + failCount); } } From 61883477b5dad70c220509448d524f73a131fb29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=84=EC=83=81=ED=98=84?= Date: Thu, 27 Feb 2025 18:52:01 +0900 Subject: [PATCH 5/7] Pushing in DB --- .DS_Store | Bin 6148 -> 6148 bytes src/.DS_Store | Bin 6148 -> 6148 bytes .../leafvillage/backend/entity/Company.java | 66 ++++++++ .../backend/repository/CompanyRepository.java | 8 + .../backend/runner/CompanyApiRunner.java | 107 +++++++++++++ .../backend/service/CompanyApiService.java | 2 +- .../backend/service/CompanyApiTestRunner.java | 145 ------------------ .../CompanyApiStandaloneRunner.java | 79 ++++++++++ 8 files changed, 261 insertions(+), 146 deletions(-) create mode 100644 src/main/java/com/leafvillage/backend/entity/Company.java create mode 100644 src/main/java/com/leafvillage/backend/repository/CompanyRepository.java create mode 100644 src/main/java/com/leafvillage/backend/runner/CompanyApiRunner.java delete mode 100644 src/main/java/com/leafvillage/backend/service/CompanyApiTestRunner.java create mode 100644 src/main/java/com/leafvillage/backend/standalone/CompanyApiStandaloneRunner.java diff --git a/.DS_Store b/.DS_Store index 80a3cfd05f4f2061d732081fb5d38a8efe9dcbe7..7cf982eedaf6e1d3cc980a72d14db50280b5f853 100644 GIT binary patch delta 61 zcmZoMXfc@JFUrfnz`)4BAi%(o!l1{H&QQdV$dIyGkYhPBBkyK27G7o!V{;=N1w%uN R$=>XHCN^koX6N|J4*+J+4PXEO delta 98 zcmZoMXfc@JFU-flz`)4BAi%(o;+d15oRpKFv{{g2C9^h2f|VhOp_Cz$AqOD|6a}hf lSP#T{|G|KPVKWa4FEfXcsfmt)v5DnmMfN?L**X650|0-r8GZl& diff --git a/src/.DS_Store b/src/.DS_Store index ccac58678c50d79fba397b0764d99bc38e60116f..846e5e5d71a03e87052e5f335481873a4f266605 100644 GIT binary patch delta 21 ccmZoMXffEZgPFtF+(<{k(9mM@0cIBw07)JOEC2ui delta 21 ccmZoMXffEZgPFs~)I>+Y*u--40cIBw07*IqF#rGn diff --git a/src/main/java/com/leafvillage/backend/entity/Company.java b/src/main/java/com/leafvillage/backend/entity/Company.java new file mode 100644 index 0000000..9572fd3 --- /dev/null +++ b/src/main/java/com/leafvillage/backend/entity/Company.java @@ -0,0 +1,66 @@ +package com.leafvillage.backend.entity; + +import jakarta.persistence.*; + +@Entity +@Table(name = "company") +public class Company { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "corp_nm") + private String corpNm; + private String address; + private String phone; + private String domain; + + @Column(name = "logo_url") + private String logoUrl; + + // 기본 생성자 및 getter/setter + public Company() {} + + public Company(String corpNm, String address, String phone, String domain, String logoUrl) { + this.corpNm = corpNm; + this.address = address; + this.phone = phone; + this.domain = domain; + this.logoUrl = logoUrl; + } + + public Long getId() { + return id; + } + public String getCorpNm() { + return corpNm; + } + public void setCorpNm(String corpNm) { + this.corpNm = corpNm; + } + public String getAddress() { + return address; + } + public void setAddress(String address) { + this.address = address; + } + public String getPhone() { + return phone; + } + public void setPhone(String phone) { + this.phone = phone; + } + public String getDomain() { + return domain; + } + public void setDomain(String domain) { + this.domain = domain; + } + public String getLogoUrl() { + return logoUrl; + } + public void setLogoUrl(String logoUrl) { + this.logoUrl = logoUrl; + } +} diff --git a/src/main/java/com/leafvillage/backend/repository/CompanyRepository.java b/src/main/java/com/leafvillage/backend/repository/CompanyRepository.java new file mode 100644 index 0000000..eb16b03 --- /dev/null +++ b/src/main/java/com/leafvillage/backend/repository/CompanyRepository.java @@ -0,0 +1,8 @@ +package com.leafvillage.backend.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import com.leafvillage.backend.entity.Company; + +public interface CompanyRepository extends JpaRepository { + // 필요에 따라 추가 쿼리 메서드를 정의할 수 있습니다. +} diff --git a/src/main/java/com/leafvillage/backend/runner/CompanyApiRunner.java b/src/main/java/com/leafvillage/backend/runner/CompanyApiRunner.java new file mode 100644 index 0000000..8066790 --- /dev/null +++ b/src/main/java/com/leafvillage/backend/runner/CompanyApiRunner.java @@ -0,0 +1,107 @@ +package com.leafvillage.backend.runner; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.leafvillage.backend.entity.Company; +import com.leafvillage.backend.repository.CompanyRepository; +import com.leafvillage.backend.service.CompanyApiService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.CommandLineRunner; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; +import java.util.Scanner; + +@Component +public class CompanyApiRunner implements CommandLineRunner { + + @Autowired + private CompanyApiService service; + + @Autowired + private CompanyRepository companyRepository; + + @Override + public void run(String... args) throws Exception { + ObjectMapper mapper = new ObjectMapper(); + Scanner scanner = new Scanner(System.in); + while(true){ + System.out.println("조회할 기업명을 입력하세요:"); + String corpNm = scanner.hasNextLine() ? scanner.nextLine() : "기본기업명"; + if ("exit".equalsIgnoreCase(corpNm.trim())) { + break; + } + try { + // API 호출 후 전체 JSON 응답 받기 + String fullJson = service.getCompanyDataByName(corpNm); + JsonNode root = mapper.readTree(fullJson); + JsonNode itemsNode = root.path("response") + .path("body") + .path("items") + .path("item"); + + // 기업명 정규화 및 (주) 관련 케이스 구분 + String normalizedInput = corpNm.replaceAll("\\s+", ""); + String variant1 = normalizedInput; + String variant2 = "(주)" + normalizedInput; + String variant3 = normalizedInput + "(주)"; + + List exactMatches = new ArrayList<>(); + if (itemsNode.isArray()) { + for (JsonNode item : itemsNode) { + String name = item.path("corpNm").asText("").replaceAll("\\s+", ""); + if (name.equals(variant1) || name.equals(variant2) || name.equals(variant3)) { + exactMatches.add(item); + } + } + } else if (!itemsNode.isMissingNode()) { + String name = itemsNode.path("corpNm").asText("").replaceAll("\\s+", ""); + if (name.equals(variant1) || name.equals(variant2) || name.equals(variant3)) { + exactMatches.add(itemsNode); + } + } + + // 결과 출력 및 DB 저장 + if (exactMatches.isEmpty()) { + System.out.println(corpNm + " : 정확한 일치 항목 없음"); + } else { + System.out.println("=== 정확하게 일치하는 항목 (" + exactMatches.size() + "건) ==="); + for (JsonNode item : exactMatches) { + String companyName = item.path("corpNm").asText("회사명 없음"); + String address = item.path("enpBsadr").asText("주소 없음"); + String phone = item.path("enpTlno").asText("전화번호 없음"); + String domain = item.path("enpHmpgUrl").asText("도메인 없음"); + + System.out.println("회사명: " + companyName); + System.out.println("주소: " + address); + System.out.println("전화번호: " + phone); + System.out.println("도메인: " + domain); + + String logoUrl = "도메인 정보 없음"; + if (!domain.equals("도메인 없음")) { + logoUrl = "https://logo.clearbit.com/" + domain; + System.out.println("Clearbit 로고 URL: " + logoUrl); + } else { + System.out.println("Clearbit 로고 URL: " + logoUrl); + } + System.out.println("-----"); + + // Company 엔티티 생성 후 DB에 저장 + Company company = new Company(); + company.setCorpNm(companyName); + company.setAddress(address); + company.setPhone(phone); + company.setDomain(domain); + company.setLogoUrl(logoUrl); + + companyRepository.save(company); + } + } + } catch (Exception e) { + System.out.println("API 조회 중 오류 발생: " + e.getMessage()); + } + } + scanner.close(); + } +} diff --git a/src/main/java/com/leafvillage/backend/service/CompanyApiService.java b/src/main/java/com/leafvillage/backend/service/CompanyApiService.java index c43e55d..d8d4f70 100644 --- a/src/main/java/com/leafvillage/backend/service/CompanyApiService.java +++ b/src/main/java/com/leafvillage/backend/service/CompanyApiService.java @@ -29,7 +29,7 @@ public String getCompanyDataByName(String corpNm) { UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(BASE_URL) .queryParam("serviceKey", SERVICE_KEY) // 대소문자도 브라우저와 동일하게 .queryParam("pageNo", 1) - .queryParam("numOfRows", 5) // 아마 이 부분에서 "=== 정확하게 일치하는 항목 (5건) ===" 문구가 반복적 출력되는 듯 + .queryParam("numOfRows", 1) // 아마 이 부분에서 "=== 정확하게 일치하는 항목 (5건) ===" 문구가 반복적 출력되는 듯 .queryParam("resultType", "json") .queryParam("corpNm", corpNm); diff --git a/src/main/java/com/leafvillage/backend/service/CompanyApiTestRunner.java b/src/main/java/com/leafvillage/backend/service/CompanyApiTestRunner.java deleted file mode 100644 index 324344b..0000000 --- a/src/main/java/com/leafvillage/backend/service/CompanyApiTestRunner.java +++ /dev/null @@ -1,145 +0,0 @@ -package com.leafvillage.backend.service; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.leafvillage.backend.service.CompanyApiService; - -import java.util.*; - -public class CompanyApiTestRunner { - public static void main(String[] args) { - CompanyApiService service = new CompanyApiService(); - List corpNames = Arrays.asList( - "삼성전자", - "현대자동차", - "기아", - "LG전자", - "SK하이닉스", - "네이버", - "카카오", - "삼성생명", - "삼성물산", - "현대모비스", - "SK이노베이션", - "LG화학", - "포스코홀딩스", - "한화솔루션", - "대한항공", - "아시아나항공", - "CJ제일제당", - "롯데쇼핑", - "삼성SDI", - "셀트리온", - "삼성바이오로직스", - "엔씨소프트", - "넷마블", - "하이브", - "현대건설", - "두산에너빌리티", - "에코프로", - "한국전력공사", - "LG에너지솔루션", - "KB금융" - - ); - - ObjectMapper mapper = new ObjectMapper(); - Set printedCompanies = new HashSet<>(); // 중복 제거를 위한 Set - int failCount = 0; // 실패한 기업 수를 셀 변수 - - for (String corpNm : corpNames) { - try { - // 요청 URL 직접 출력 (한 번만 출력) - String requestUrl = "https://apis.data.go.kr/1160100/service/GetCorpBasicInfoService_V2/getCorpOutline_V2?serviceKey=YugI7KFgMPZzeCgNekIYquyzw8WQVtkPJfccnooevCyF5Rh5ZXaL92U26v6PxVdapMNXtf5XfzvajTKbGkfuew==&pageNo=1&numOfRows=5&resultType=json&corpNm=" + corpNm; - System.out.println("-----"); - //System.out.println("요청 URL: " + requestUrl); // 요청 URL 출력 - - // API 호출 - String fullJson = service.getCompanyDataByName(corpNm); -// System.out.println("-----"); - // API 호출 성공 여부 체크 - if (fullJson == null || fullJson.isEmpty()) { - System.out.println(corpNm + " : 기업 정보를 가져오는 데 실패했습니다."); - System.out.println("-----"); // 실패 시에도 구분선 추가 - failCount++; // 실패 시 카운트 증가 - continue; // 실패 시 다음 기업으로 넘어가기 - } - - JsonNode root = mapper.readTree(fullJson); - JsonNode itemsNode = root.path("response") - .path("body") - .path("items") - .path("item"); - - // 기업명 정규화 (공백 제거) - String normalizedInput = corpNm.replaceAll("\\s+", ""); - String variant1 = normalizedInput; - String variant2 = "(주)" + normalizedInput; - String variant3 = normalizedInput + "(주)"; - - List exactMatches = new ArrayList<>(); - if (itemsNode.isArray()) { - for (JsonNode item : itemsNode) { - String name = item.path("corpNm").asText("").replaceAll("\\s+", ""); - if (name.equals(variant1) || name.equals(variant2) || name.equals(variant3)) { - exactMatches.add(item); - } - } - } else if (!itemsNode.isMissingNode()) { - String name = itemsNode.path("corpNm").asText("").replaceAll("\\s+", ""); - if (name.equals(variant1) || name.equals(variant2) || name.equals(variant3)) { - exactMatches.add(itemsNode); - } - } - - // 결과 출력 (중복 제거) - if (exactMatches.isEmpty()) { - System.out.println(corpNm + " : 정확한 일치 항목 없음"); - failCount++; -// System.out.println("-----"); // 실패 시에도 구분선 추가 - } else { - //System.out.println("=== 정확하게 일치하는 항목 (" + exactMatches.size() + "건) ==="); - - for (JsonNode item : exactMatches) { - String companyName = item.path("corpNm").asText("회사명 없음"); - - // 중복 체크: 이미 출력한 기업이면 건너뛰기 - if (printedCompanies.contains(companyName)) { - continue; - } - printedCompanies.add(companyName); // 출력한 기업 추가 - - String address = item.path("enpBsadr").asText("주소 없음"); - String phone = item.path("enpTlno").asText("전화번호 없음"); - String domain = item.path("enpHmpgUrl").asText("도메인 없음"); - -// System.out.println("-----"); - System.out.println("회사명: " + companyName); - System.out.println("주소: " + address); - System.out.println("전화번호: " + phone); - System.out.println("도메인: " + domain); - if (!domain.equals("도메인 없음")) { - String logoUrl = "https://logo.clearbit.com/" + domain; - System.out.println("Clearbit 로고 URL: " + logoUrl); -// System.out.println("-----"); - } else { - System.out.println("Clearbit 로고 URL: 도메인 정보 없음"); - failCount++; -// System.out.println("-----"); - } - } - } - } catch (Exception e) { - // 실패 시에도 구분선과 함께 메시지 출력 - System.out.println("-----"); - System.out.println("[" + corpNm + "] 데이터 조회 중 오류 발생: " + e.getMessage()); -// System.out.println("-----"); // 실패 시에도 구분선 추가 - failCount++; // 실패 시 카운트 증가 - } - } - - // 실패한 기업 개수 출력 - System.out.println("-----"); - System.out.println("총 정보 가져오기 실패한 기업 개수: " + failCount); - } -} diff --git a/src/main/java/com/leafvillage/backend/standalone/CompanyApiStandaloneRunner.java b/src/main/java/com/leafvillage/backend/standalone/CompanyApiStandaloneRunner.java new file mode 100644 index 0000000..1ca3879 --- /dev/null +++ b/src/main/java/com/leafvillage/backend/standalone/CompanyApiStandaloneRunner.java @@ -0,0 +1,79 @@ +package com.leafvillage.backend.standalone; + +import com.leafvillage.backend.service.CompanyApiService; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.ArrayList; +import java.util.List; +import java.util.Scanner; + +public class CompanyApiStandaloneRunner { + public static void main(String[] args) { + CompanyApiService service = new CompanyApiService(); + ObjectMapper mapper = new ObjectMapper(); + Scanner scanner = new Scanner(System.in); + + System.out.println("조회할 기업명을 입력하세요:"); + String corpNm = scanner.hasNextLine() ? scanner.nextLine() : "기본기업명"; + + try { + // API 호출 후 전체 JSON 응답 받기 + String fullJson = service.getCompanyDataByName(corpNm); + JsonNode root = mapper.readTree(fullJson); + JsonNode itemsNode = root.path("response") + .path("body") + .path("items") + .path("item"); + + // 기업명 정규화 및 (주) 관련 케이스 구분 + String normalizedInput = corpNm.replaceAll("\\s+", ""); + String variant1 = normalizedInput; + String variant2 = "(주)" + normalizedInput; + String variant3 = normalizedInput + "(주)"; + + List exactMatches = new ArrayList<>(); + if (itemsNode.isArray()) { + for (JsonNode item : itemsNode) { + String name = item.path("corpNm").asText("").replaceAll("\\s+", ""); + if (name.equals(variant1) || name.equals(variant2) || name.equals(variant3)) { + exactMatches.add(item); + } + } + } else if (!itemsNode.isMissingNode()) { + String name = itemsNode.path("corpNm").asText("").replaceAll("\\s+", ""); + if (name.equals(variant1) || name.equals(variant2) || name.equals(variant3)) { + exactMatches.add(itemsNode); + } + } + + // 결과 출력 + if (exactMatches.isEmpty()) { + System.out.println(corpNm + " : 정확한 일치 항목 없음"); + } else { + System.out.println("=== 정확하게 일치하는 항목 (" + exactMatches.size() + "건) ==="); + for (JsonNode item : exactMatches) { + String companyName = item.path("corpNm").asText("회사명 없음"); + String address = item.path("enpBsadr").asText("주소 없음"); + String phone = item.path("enpTlno").asText("전화번호 없음"); + String domain = item.path("enpHmpgUrl").asText("도메인 없음"); + + System.out.println("회사명: " + companyName); + System.out.println("주소: " + address); + System.out.println("전화번호: " + phone); + System.out.println("도메인: " + domain); + if (!domain.equals("도메인 없음")) { + String logoUrl = "https://logo.clearbit.com/" + domain; + System.out.println("Clearbit 로고 URL: " + logoUrl); + } else { + System.out.println("Clearbit 로고 URL: 도메인 정보 없음"); + } + System.out.println("-----"); + } + } + } catch (Exception e) { + System.out.println("API 조회 중 오류 발생: " + e.getMessage()); + } finally { + scanner.close(); + } + } +} From 5218c345dddcf76ee6f6733303d0f2a025642549 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=84=EC=83=81=ED=98=84?= Date: Thu, 27 Feb 2025 19:50:29 +0900 Subject: [PATCH 6/7] Success on pushing on my local DB --- .../leafvillage/backend/entity/Company.java | 169 ++++++++++++++---- .../backend/repository/CompanyRepository.java | 10 +- .../backend/runner/CompanyApiRunner.java | 142 ++++++++------- .../CompanyApiStandaloneRunner.java | 17 ++ 4 files changed, 233 insertions(+), 105 deletions(-) diff --git a/src/main/java/com/leafvillage/backend/entity/Company.java b/src/main/java/com/leafvillage/backend/entity/Company.java index 9572fd3..0d9b580 100644 --- a/src/main/java/com/leafvillage/backend/entity/Company.java +++ b/src/main/java/com/leafvillage/backend/entity/Company.java @@ -1,66 +1,167 @@ package com.leafvillage.backend.entity; import jakarta.persistence.*; +import java.util.Date; @Entity @Table(name = "company") public class Company { @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; + @Column(name = "company_id", length = 36, nullable = false) + private String companyId; // 예: "c000001" - @Column(name = "corp_nm") - private String corpNm; - private String address; - private String phone; - private String domain; + @Column(name = "company", length = 255, nullable = false) + private String company; // 회사 고유 식별자 - @Column(name = "logo_url") - private String logoUrl; + @Column(name = "company_name_kr", length = 255) + private String companyNameKr; // 회사명(국문) - // 기본 생성자 및 getter/setter + @Column(name = "representative_name", length = 100) + private String representativeName; // 대표자명 + + @Column(name = "business_registration_number", length = 100) + private String businessRegistrationNumber; // 사업자등록번호 + + @Column(name = "address", length = 255) + private String address; // 주소 + + @Column(name = "phone_number", length = 255) + private String phoneNumber; // 전화번호 + + @Column(name = "fax_number", length = 255) + private String faxNumber; // 팩스번호 + + @Column(name = "homepage_url", length = 255) + private String homepageUrl; // 홈페이지 URL + + @Column(name = "standard_industry_classification", length = 255) + private String standardIndustryClassification; // 표준산업분류 + + @Column(name = "main_business", length = 255) + private String mainBusiness; // 주요사업 + + @Column(name = "establishment_date") + @Temporal(TemporalType.DATE) + private Date establishmentDate; // 설립일 + + @Column(name = "kosdaq_listed_date") + @Temporal(TemporalType.DATE) + private Date kosdaqListedDate; // 코스닥 상장일 + + @Column(name = "ticker", length = 20) + private String ticker; // 티커 + + @Column(name = "logo_image", length = 255) + private String logoImage; // 이미지 링크 + + // 기본 생성자 public Company() {} - public Company(String corpNm, String address, String phone, String domain, String logoUrl) { - this.corpNm = corpNm; - this.address = address; - this.phone = phone; - this.domain = domain; - this.logoUrl = logoUrl; + // Getter/Setter + + public String getCompanyId() { + return companyId; + } + public void setCompanyId(String companyId) { + this.companyId = companyId; + } + + public String getCompany() { + return company; + } + public void setCompany(String company) { + this.company = company; } - public Long getId() { - return id; + public String getCompanyNameKr() { + return companyNameKr; } - public String getCorpNm() { - return corpNm; + public void setCompanyNameKr(String companyNameKr) { + this.companyNameKr = companyNameKr; + } + + public String getRepresentativeName() { + return representativeName; + } + public void setRepresentativeName(String representativeName) { + this.representativeName = representativeName; + } + + public String getBusinessRegistrationNumber() { + return businessRegistrationNumber; } - public void setCorpNm(String corpNm) { - this.corpNm = corpNm; + public void setBusinessRegistrationNumber(String businessRegistrationNumber) { + this.businessRegistrationNumber = businessRegistrationNumber; } + public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } - public String getPhone() { - return phone; + + public String getPhoneNumber() { + return phoneNumber; + } + public void setPhoneNumber(String phoneNumber) { + this.phoneNumber = phoneNumber; + } + + public String getFaxNumber() { + return faxNumber; + } + public void setFaxNumber(String faxNumber) { + this.faxNumber = faxNumber; + } + + public String getHomepageUrl() { + return homepageUrl; + } + public void setHomepageUrl(String homepageUrl) { + this.homepageUrl = homepageUrl; + } + + public String getStandardIndustryClassification() { + return standardIndustryClassification; + } + public void setStandardIndustryClassification(String standardIndustryClassification) { + this.standardIndustryClassification = standardIndustryClassification; + } + + public String getMainBusiness() { + return mainBusiness; + } + public void setMainBusiness(String mainBusiness) { + this.mainBusiness = mainBusiness; } - public void setPhone(String phone) { - this.phone = phone; + + public Date getEstablishmentDate() { + return establishmentDate; } - public String getDomain() { - return domain; + public void setEstablishmentDate(Date establishmentDate) { + this.establishmentDate = establishmentDate; } - public void setDomain(String domain) { - this.domain = domain; + + public Date getKosdaqListedDate() { + return kosdaqListedDate; } - public String getLogoUrl() { - return logoUrl; + public void setKosdaqListedDate(Date kosdaqListedDate) { + this.kosdaqListedDate = kosdaqListedDate; + } + + public String getTicker() { + return ticker; + } + public void setTicker(String ticker) { + this.ticker = ticker; + } + + public String getLogoImage() { + return logoImage; } - public void setLogoUrl(String logoUrl) { - this.logoUrl = logoUrl; + public void setLogoImage(String logoImage) { + this.logoImage = logoImage; } } diff --git a/src/main/java/com/leafvillage/backend/repository/CompanyRepository.java b/src/main/java/com/leafvillage/backend/repository/CompanyRepository.java index eb16b03..4d211c6 100644 --- a/src/main/java/com/leafvillage/backend/repository/CompanyRepository.java +++ b/src/main/java/com/leafvillage/backend/repository/CompanyRepository.java @@ -1,8 +1,12 @@ package com.leafvillage.backend.repository; -import org.springframework.data.jpa.repository.JpaRepository; import com.leafvillage.backend.entity.Company; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.Optional; + +public interface CompanyRepository extends JpaRepository { -public interface CompanyRepository extends JpaRepository { - // 필요에 따라 추가 쿼리 메서드를 정의할 수 있습니다. + // 이미 있는 'company'(회사명)으로 레코드를 찾는 메서드 + Optional findByCompany(String company); } diff --git a/src/main/java/com/leafvillage/backend/runner/CompanyApiRunner.java b/src/main/java/com/leafvillage/backend/runner/CompanyApiRunner.java index 8066790..2f0d1e4 100644 --- a/src/main/java/com/leafvillage/backend/runner/CompanyApiRunner.java +++ b/src/main/java/com/leafvillage/backend/runner/CompanyApiRunner.java @@ -9,99 +9,105 @@ import org.springframework.boot.CommandLineRunner; import org.springframework.stereotype.Component; -import java.util.ArrayList; -import java.util.List; +import java.util.Optional; import java.util.Scanner; @Component public class CompanyApiRunner implements CommandLineRunner { @Autowired - private CompanyApiService service; + private CompanyApiService companyApiService; @Autowired private CompanyRepository companyRepository; @Override public void run(String... args) throws Exception { - ObjectMapper mapper = new ObjectMapper(); Scanner scanner = new Scanner(System.in); - while(true){ - System.out.println("조회할 기업명을 입력하세요:"); - String corpNm = scanner.hasNextLine() ? scanner.nextLine() : "기본기업명"; - if ("exit".equalsIgnoreCase(corpNm.trim())) { - break; - } - try { - // API 호출 후 전체 JSON 응답 받기 - String fullJson = service.getCompanyDataByName(corpNm); - JsonNode root = mapper.readTree(fullJson); - JsonNode itemsNode = root.path("response") - .path("body") - .path("items") - .path("item"); - - // 기업명 정규화 및 (주) 관련 케이스 구분 - String normalizedInput = corpNm.replaceAll("\\s+", ""); - String variant1 = normalizedInput; - String variant2 = "(주)" + normalizedInput; - String variant3 = normalizedInput + "(주)"; - - List exactMatches = new ArrayList<>(); - if (itemsNode.isArray()) { - for (JsonNode item : itemsNode) { - String name = item.path("corpNm").asText("").replaceAll("\\s+", ""); - if (name.equals(variant1) || name.equals(variant2) || name.equals(variant3)) { - exactMatches.add(item); - } + ObjectMapper mapper = new ObjectMapper(); + + while (true) { + System.out.println("조회할 기업명을 입력하세요 (종료하려면 'exit' 입력):"); + String input = scanner.nextLine().trim(); + if ("exit".equalsIgnoreCase(input)) { + break; + } + + try { + // 1) API 호출 + String fullJson = companyApiService.getCompanyDataByName(input); + JsonNode root = mapper.readTree(fullJson); + JsonNode itemsNode = root.path("response") + .path("body") + .path("items") + .path("item"); + + // 2) 일치 항목이 있는지 확인 + if (itemsNode.isMissingNode() || (itemsNode.isArray() && itemsNode.size() == 0)) { + System.out.println("[API] 일치하는 항목이 없습니다. 건너뜁니다."); + continue; } - } else if (!itemsNode.isMissingNode()) { - String name = itemsNode.path("corpNm").asText("").replaceAll("\\s+", ""); - if (name.equals(variant1) || name.equals(variant2) || name.equals(variant3)) { - exactMatches.add(itemsNode); + + // 단일 / 배열 구분 (예: 첫 번째만 사용) + JsonNode firstItem = itemsNode.isArray() ? itemsNode.get(0) : itemsNode; + + // 3) API에서 가져온 회사명 + String apiCompanyName = firstItem.path("corpNm").asText("").trim(); + apiCompanyName = apiCompanyName.replace("(주)", "") + .replace("[주]", "") + .trim(); + + if (apiCompanyName.isEmpty()) { + // 회사명이 없다면 업데이트 불가 + System.out.println("[API] 회사명이 없습니다. 건너뜁니다."); + continue; } - } - // 결과 출력 및 DB 저장 - if (exactMatches.isEmpty()) { - System.out.println(corpNm + " : 정확한 일치 항목 없음"); - } else { - System.out.println("=== 정확하게 일치하는 항목 (" + exactMatches.size() + "건) ==="); - for (JsonNode item : exactMatches) { - String companyName = item.path("corpNm").asText("회사명 없음"); - String address = item.path("enpBsadr").asText("주소 없음"); - String phone = item.path("enpTlno").asText("전화번호 없음"); - String domain = item.path("enpHmpgUrl").asText("도메인 없음"); - - System.out.println("회사명: " + companyName); - System.out.println("주소: " + address); - System.out.println("전화번호: " + phone); - System.out.println("도메인: " + domain); + // 4) DB에서 레코드 찾기 (company 컬럼 기준) + Optional optCompany = companyRepository.findByCompany(apiCompanyName); + if (optCompany.isPresent()) { + // === 이미 존재하는 레코드 => 업데이트 === + Company existing = optCompany.get(); + + // 필요한 컬럼만 업데이트 + String address = firstItem.path("enpBsadr").asText("").trim(); + String phone = firstItem.path("enpTlno").asText("").trim(); + String domain = firstItem.path("enpHmpgUrl").asText("").trim(); + // 예시로 Null이거나 빈 값일 때만 업데이트 + if (existing.getAddress() == null || existing.getAddress().isEmpty()) { + existing.setAddress(address); + } + if (existing.getPhoneNumber() == null || existing.getPhoneNumber().isEmpty()) { + existing.setPhoneNumber(phone); + } + if (existing.getHomepageUrl() == null || existing.getHomepageUrl().isEmpty()) { + existing.setHomepageUrl(domain); + } + + // 로고 URL String logoUrl = "도메인 정보 없음"; - if (!domain.equals("도메인 없음")) { + if (!domain.isBlank()) { logoUrl = "https://logo.clearbit.com/" + domain; - System.out.println("Clearbit 로고 URL: " + logoUrl); - } else { - System.out.println("Clearbit 로고 URL: " + logoUrl); } - System.out.println("-----"); + if (existing.getLogoImage() == null || existing.getLogoImage().isEmpty()) { + existing.setLogoImage(logoUrl); + } - // Company 엔티티 생성 후 DB에 저장 - Company company = new Company(); - company.setCorpNm(companyName); - company.setAddress(address); - company.setPhone(phone); - company.setDomain(domain); - company.setLogoUrl(logoUrl); + // 실제 DB 업데이트 + companyRepository.save(existing); + System.out.println("[업데이트 완료] 회사명 " + apiCompanyName + " 컬럼이 갱신되었습니다."); - companyRepository.save(company); + } else { + // === 존재하지 않는 레코드 => 새로 삽입하지 않고 스킵 === + System.out.println("[스킵] DB에 존재하지 않는 회사(" + apiCompanyName + ")입니다."); } + + } catch (Exception e) { + e.printStackTrace(); } - } catch (Exception e) { - System.out.println("API 조회 중 오류 발생: " + e.getMessage()); - } } + scanner.close(); } } diff --git a/src/main/java/com/leafvillage/backend/standalone/CompanyApiStandaloneRunner.java b/src/main/java/com/leafvillage/backend/standalone/CompanyApiStandaloneRunner.java index 1ca3879..224d8c5 100644 --- a/src/main/java/com/leafvillage/backend/standalone/CompanyApiStandaloneRunner.java +++ b/src/main/java/com/leafvillage/backend/standalone/CompanyApiStandaloneRunner.java @@ -19,6 +19,13 @@ public static void main(String[] args) { try { // API 호출 후 전체 JSON 응답 받기 String fullJson = service.getCompanyDataByName(corpNm); + + // 1) 전체 JSON을 콘솔에 출력 (디버그/확인용) + System.out.println("----- 전체 JSON 응답 -----"); + System.out.println(fullJson); + System.out.println("----- 끝 -----"); + + // 2) JSON 파싱 JsonNode root = mapper.readTree(fullJson); JsonNode itemsNode = root.path("response") .path("body") @@ -52,15 +59,25 @@ public static void main(String[] args) { } else { System.out.println("=== 정확하게 일치하는 항목 (" + exactMatches.size() + "건) ==="); for (JsonNode item : exactMatches) { + // 주요 필드 추출 String companyName = item.path("corpNm").asText("회사명 없음"); String address = item.path("enpBsadr").asText("주소 없음"); String phone = item.path("enpTlno").asText("전화번호 없음"); String domain = item.path("enpHmpgUrl").asText("도메인 없음"); + // 추가로 대표자명, 사업자등록번호, 주요사업 등 더 파싱 (필드명은 API 문서 확인 필요) + String representative = item.path("enpRprFnm").asText("N/A"); // 대표자명 + String bsnNo = item.path("enpBsnNo").asText("N/A"); // 사업자등록번호 + String mainBiz = item.path("enpMainbizNm").asText("N/A"); // 주요사업 + System.out.println("회사명: " + companyName); + System.out.println("대표자명: " + representative); + System.out.println("사업자등록번호: " + bsnNo); + System.out.println("주요사업: " + mainBiz); System.out.println("주소: " + address); System.out.println("전화번호: " + phone); System.out.println("도메인: " + domain); + if (!domain.equals("도메인 없음")) { String logoUrl = "https://logo.clearbit.com/" + domain; System.out.println("Clearbit 로고 URL: " + logoUrl); From 3235a142cd1e10181a3aeb4f1102eb6665529c5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=84=EC=83=81=ED=98=84?= Date: Thu, 27 Feb 2025 20:44:54 +0900 Subject: [PATCH 7/7] Feat: add Frontend api for companies list --- .../backend/Controller/CompanyController.java | 55 ++++--- .../backend/repository/CompanyRepository.java | 7 +- .../backend/runner/CompanyApiRunner.java | 138 +++++++----------- .../backend/service/CompanyApiService.java | 8 +- 4 files changed, 96 insertions(+), 112 deletions(-) diff --git a/src/main/java/com/leafvillage/backend/Controller/CompanyController.java b/src/main/java/com/leafvillage/backend/Controller/CompanyController.java index bc13b2c..a12c80b 100644 --- a/src/main/java/com/leafvillage/backend/Controller/CompanyController.java +++ b/src/main/java/com/leafvillage/backend/Controller/CompanyController.java @@ -1,33 +1,44 @@ package com.leafvillage.backend.Controller; -import com.leafvillage.backend.service.CompanyApiService; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; +import com.leafvillage.backend.entity.Company; +import com.leafvillage.backend.repository.CompanyRepository; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; + +import java.util.List; +import java.util.stream.Collectors; @RestController -@RequestMapping("/api") public class CompanyController { - private final CompanyApiService companyApiService; - public CompanyController(CompanyApiService companyApiService) { - this.companyApiService = companyApiService; + + private final CompanyRepository companyRepository; + + public CompanyController(CompanyRepository companyRepository) { + this.companyRepository = companyRepository; } /** - * 예: GET /api/company?corpNm=넥슨 - * - API 응답 JSON 전체를 반환 - * - 터미널에는 주소/전화번호만 출력 + * 기업 리스트 조회 (1~20개 반환) */ - @GetMapping("/company") - public ResponseEntity getCompanyInfo(@RequestParam String corpNm) { - try { - // 1) 주소/전화번호 콘솔 출력 + 전체 JSON 반환 - String json = companyApiService.getCompanyDataByName(corpNm); - return ResponseEntity.ok(json); - } catch (Exception e) { - e.printStackTrace(); - return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) - .body("오류 발생: " + e.getMessage()); - } + @GetMapping("/companies") + public List getCompanies( + @RequestParam(defaultValue = "0") int page, + @RequestParam(defaultValue = "20") int size) { + + // 페이징 적용: 최신 등록 순으로 20개만 가져오기 + Pageable pageable = PageRequest.of(page, size, Sort.by(Sort.Direction.ASC, "companyId")); + List companies = companyRepository.findAll(pageable).getContent(); + + // 필요한 데이터만 DTO로 변환하여 반환 + return companies.stream() + .map(company -> new CompanyDto(company.getCompanyId(), company.getCompany())) + .collect(Collectors.toList()); } + + // DTO 클래스 정의 + public record CompanyDto(String company_id, String company) {} } diff --git a/src/main/java/com/leafvillage/backend/repository/CompanyRepository.java b/src/main/java/com/leafvillage/backend/repository/CompanyRepository.java index 4d211c6..65c46d5 100644 --- a/src/main/java/com/leafvillage/backend/repository/CompanyRepository.java +++ b/src/main/java/com/leafvillage/backend/repository/CompanyRepository.java @@ -1,12 +1,9 @@ package com.leafvillage.backend.repository; - +import java.util.Optional; import com.leafvillage.backend.entity.Company; import org.springframework.data.jpa.repository.JpaRepository; -import java.util.Optional; - public interface CompanyRepository extends JpaRepository { - - // 이미 있는 'company'(회사명)으로 레코드를 찾는 메서드 + // 기본 제공되는 findById(companyId) 사용 (JPA에서 자동 제공) Optional findByCompany(String company); } diff --git a/src/main/java/com/leafvillage/backend/runner/CompanyApiRunner.java b/src/main/java/com/leafvillage/backend/runner/CompanyApiRunner.java index 2f0d1e4..4506c39 100644 --- a/src/main/java/com/leafvillage/backend/runner/CompanyApiRunner.java +++ b/src/main/java/com/leafvillage/backend/runner/CompanyApiRunner.java @@ -1,16 +1,14 @@ package com.leafvillage.backend.runner; +import com.leafvillage.backend.service.CompanyApiService; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import com.leafvillage.backend.entity.Company; -import com.leafvillage.backend.repository.CompanyRepository; -import com.leafvillage.backend.service.CompanyApiService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.CommandLineRunner; import org.springframework.stereotype.Component; -import java.util.Optional; -import java.util.Scanner; +import java.util.ArrayList; +import java.util.List; @Component public class CompanyApiRunner implements CommandLineRunner { @@ -18,96 +16,70 @@ public class CompanyApiRunner implements CommandLineRunner { @Autowired private CompanyApiService companyApiService; - @Autowired - private CompanyRepository companyRepository; + private final ObjectMapper objectMapper = new ObjectMapper(); @Override - public void run(String... args) throws Exception { - Scanner scanner = new Scanner(System.in); - ObjectMapper mapper = new ObjectMapper(); + public void run(String... args) { + // ✅ 하드코딩된 회사명 (테스트할 기업 리스트) + List corpNames = List.of("삼성전자", "현대자동차", "카카오"); - while (true) { - System.out.println("조회할 기업명을 입력하세요 (종료하려면 'exit' 입력):"); - String input = scanner.nextLine().trim(); - if ("exit".equalsIgnoreCase(input)) { - break; - } + for (String corpNm : corpNames) { + System.out.println("조회할 기업명: " + corpNm); try { - // 1) API 호출 - String fullJson = companyApiService.getCompanyDataByName(input); - JsonNode root = mapper.readTree(fullJson); - JsonNode itemsNode = root.path("response") - .path("body") - .path("items") - .path("item"); - - // 2) 일치 항목이 있는지 확인 - if (itemsNode.isMissingNode() || (itemsNode.isArray() && itemsNode.size() == 0)) { - System.out.println("[API] 일치하는 항목이 없습니다. 건너뜁니다."); - continue; - } - - // 단일 / 배열 구분 (예: 첫 번째만 사용) - JsonNode firstItem = itemsNode.isArray() ? itemsNode.get(0) : itemsNode; - - // 3) API에서 가져온 회사명 - String apiCompanyName = firstItem.path("corpNm").asText("").trim(); - apiCompanyName = apiCompanyName.replace("(주)", "") - .replace("[주]", "") - .trim(); - - if (apiCompanyName.isEmpty()) { - // 회사명이 없다면 업데이트 불가 - System.out.println("[API] 회사명이 없습니다. 건너뜁니다."); - continue; - } - - // 4) DB에서 레코드 찾기 (company 컬럼 기준) - Optional optCompany = companyRepository.findByCompany(apiCompanyName); - if (optCompany.isPresent()) { - // === 이미 존재하는 레코드 => 업데이트 === - Company existing = optCompany.get(); - - // 필요한 컬럼만 업데이트 - String address = firstItem.path("enpBsadr").asText("").trim(); - String phone = firstItem.path("enpTlno").asText("").trim(); - String domain = firstItem.path("enpHmpgUrl").asText("").trim(); - - // 예시로 Null이거나 빈 값일 때만 업데이트 - if (existing.getAddress() == null || existing.getAddress().isEmpty()) { - existing.setAddress(address); - } - if (existing.getPhoneNumber() == null || existing.getPhoneNumber().isEmpty()) { - existing.setPhoneNumber(phone); - } - if (existing.getHomepageUrl() == null || existing.getHomepageUrl().isEmpty()) { - existing.setHomepageUrl(domain); - } - - // 로고 URL - String logoUrl = "도메인 정보 없음"; - if (!domain.isBlank()) { - logoUrl = "https://logo.clearbit.com/" + domain; + // API 호출 후 JSON 응답 받기 + String fullJson = companyApiService.getCompanyDataByName(corpNm); + JsonNode root = objectMapper.readTree(fullJson); + JsonNode itemsNode = root.path("response").path("body").path("items").path("item"); + + // 기업명 정규화 및 (주) 관련 케이스 구분 + String normalizedInput = corpNm.replaceAll("\\s+", ""); + String variant1 = normalizedInput; + String variant2 = "(주)" + normalizedInput; + String variant3 = normalizedInput + "(주)"; + + List exactMatches = new ArrayList<>(); + if (itemsNode.isArray()) { + for (JsonNode item : itemsNode) { + String name = item.path("corpNm").asText("").replaceAll("\\s+", ""); + if (name.equals(variant1) || name.equals(variant2) || name.equals(variant3)) { + exactMatches.add(item); + } } - if (existing.getLogoImage() == null || existing.getLogoImage().isEmpty()) { - existing.setLogoImage(logoUrl); + } else if (!itemsNode.isMissingNode()) { + String name = itemsNode.path("corpNm").asText("").replaceAll("\\s+", ""); + if (name.equals(variant1) || name.equals(variant2) || name.equals(variant3)) { + exactMatches.add(itemsNode); } + } - // 실제 DB 업데이트 - companyRepository.save(existing); - System.out.println("[업데이트 완료] 회사명 " + apiCompanyName + " 컬럼이 갱신되었습니다."); - + // 결과 출력 + if (exactMatches.isEmpty()) { + System.out.println(corpNm + " : 정확한 일치 항목 없음"); } else { - // === 존재하지 않는 레코드 => 새로 삽입하지 않고 스킵 === - System.out.println("[스킵] DB에 존재하지 않는 회사(" + apiCompanyName + ")입니다."); + System.out.println("=== 정확하게 일치하는 항목 (" + exactMatches.size() + "건) ==="); + for (JsonNode item : exactMatches) { + String companyName = item.path("corpNm").asText("회사명 없음"); + String address = item.path("enpBsadr").asText("주소 없음"); + String phone = item.path("enpTlno").asText("전화번호 없음"); + String domain = item.path("enpHmpgUrl").asText("도메인 없음"); + + System.out.println("회사명: " + companyName); + System.out.println("주소: " + address); + System.out.println("전화번호: " + phone); + System.out.println("도메인: " + domain); + if (!domain.equals("도메인 없음")) { + String logoUrl = "https://logo.clearbit.com/" + domain; + System.out.println("Clearbit 로고 URL: " + logoUrl); + } else { + System.out.println("Clearbit 로고 URL: 도메인 정보 없음"); + } + System.out.println("-----"); + } } - } catch (Exception e) { - e.printStackTrace(); + System.out.println("API 조회 중 오류 발생: " + e.getMessage()); } } - - scanner.close(); } } diff --git a/src/main/java/com/leafvillage/backend/service/CompanyApiService.java b/src/main/java/com/leafvillage/backend/service/CompanyApiService.java index d8d4f70..a832101 100644 --- a/src/main/java/com/leafvillage/backend/service/CompanyApiService.java +++ b/src/main/java/com/leafvillage/backend/service/CompanyApiService.java @@ -41,6 +41,9 @@ public String getCompanyDataByName(String corpNm) { if (response.getStatusCode().is2xxSuccessful() && response.getBody() != null) { // JSON 파싱 String json = response.getBody(); + System.out.println("==============================================================="); + System.out.println(json); + System.out.println("==============================================================="); try{ JsonNode root = objectMapper.readTree(json); JsonNode itemsNode = root.path("response") @@ -49,7 +52,7 @@ public String getCompanyDataByName(String corpNm) { .path("item"); // 정확한 매칭을 위한 리스트 - String normalizedInput = corpNm.replaceAll("\\s+", ""); + String normalizedInput = corpNm.replaceAll("\\s+", "").trim(); String variant1 = normalizedInput; String variant2 = "(주)" + normalizedInput; String variant3 = normalizedInput + "(주)"; @@ -64,7 +67,7 @@ public String getCompanyDataByName(String corpNm) { } }else if (!itemsNode.isMissingNode()) { // 단일 객체인 경우에도 일치 여부 확인 - String name = itemsNode.path("corpNm").asText("").replaceAll("\\s+", ""); + String name = itemsNode.path("corpNm").asText("").replaceAll("\\s+", "").trim(); if (name.equals(variant1) || name.equals(variant2) || name.equals(variant3)) { exactMatches.add(itemsNode); } @@ -72,6 +75,7 @@ public String getCompanyDataByName(String corpNm) { if (exactMatches.isEmpty()) { System.out.println("정확한 일치 항목이 없습니다."); + return "{}"; } else { System.out.println("=== 정확하게 일치하는 항목 (" + exactMatches.size() + "건) ==="); for (JsonNode item : exactMatches) {