목차
// testcode 10만명 파싱하기 에러를 아직 고치지 못한 코드입니다.
→ 코드에 문제 없었고, 데이터 UTF-8 인코딩 과정에서 발생한 에러였습니다
전국 병의원 정보 검색 API 만들기
FileLineParser 실습 진행 : fulldata_01_01_02_P_의원.csv
1.
전국 병원 정보가 들어갈 table 설게
2.
create table
3.
table에 넣기위한 domain class 만들기
테이블 설계
코드
컬럼 타입을 세분화 하는 이유 db에 저장공간을 줄이고, 검색 속도를 최적화 하기 위함
•
tinyint - 작은 int 범위가 작지만 int에 비해 공간을 덜 차지 한다.
•
datetime - where 조건에 날짜 from to
•
float – 소수점 int에 넣으면 소수점이 잘리기 때문 int에 비해 공간을 더 차지 한다.
•
varchar - 한글은 한 글자당 2byte사용된다.
no | 컬럼 위치 | 컬럼명 | Java | 타입 | 설명 |
1 | 0 | id(pk) | id | Int | 번호 |
2 | 1 | open_service_name | openServiceName | VARCHAR(10) | 개방서비스명 |
3 | 3 | open_local_government_code | openLocalGovernmentCode | int | 개방자치단체코드 |
4 | 4 | management_number(unique) | managementNumber | varchar(40) | 관리번호 |
5 | 5 | license_date | license_date | datetime | 인허가일자 |
6 | 7 | business_status | businessStatus | tinyint(2) | 1: 영업/정상
2: 휴업
3: 폐업
4: 취소/말소영업상태구분 |
7 | 9 | business_status_code | businessStatusCode | tinyint(2) | 영업상태코드
2: 휴업
3: 폐업
13: 영업중 |
8 | 15 | phone | phone | varchar(20) | 소재지전화 |
9 | 18 | full_address | fullAddress | VARCHAR(200) | 소재지전체주소 |
10 | 19 | road_name_address | roadNameAddress | VARCHAR(200) | 도로명전체주소 |
11 | 21 | hospital_name | hospitalName | VARCHAR(20) | 사업장명(병원이름) |
12 | 25 | business_type_name | businessTypeName | VARCHAR(10) | 업태구분명 |
13 | 29 | healthcare_provider_count | healthcareProviderCount | tinyint(2) | 의료인수 |
14 | 30 | patient_room_count | patientRoomCount | tinyint(2) | 입원실수 |
15 | 31 | total_number_of_beds | totalNumberOfBeds | tinyint(2) | 병상수 |
16 | 32 | total_area_size | totalAreaSize | float | 총면적 |
Create Table
코드 구현
1. 도메인 hospital 생성
Lombok 이용 : 칼럼이 추가되거나 제거되어도 Constructor, Gettter, Setter을 수정하지 않고 사용할 수 있어서 편하다.
@AllArgsConstructor
@Getter
@Setter
@NoArgsConstructor // 빈
public class Hospital {
private int id;
private String openServiceName; // java는 camel case로 변수작성
private int openLocalGovernmentCode;
private String managementNumber;
private LocalDateTime licenseDate;
private int businessStatus;
private int businessStatusCode;
private String phone;
private String fullAddress;
private String roadNameAddress;
private String hospitalName;
private String businessTypeName;
private int healthcareProviderCount;
private int patientRoomCount;
private int totalNumberOfBeds;
private float totalAreaSize;
}
Java
복사
hospital.java
2. HospitalParser.java 구현
public interface Parser<T> {
T parse(String str);
}
Java
복사
Parser.java
•
String에서 따옴표 제거
public class HospitalParser implements Parser<Hospital> {
@Override
public Hospital parse(String str) {
// \"...\"를 기준으로 split
String[] row = str.split("\",\"");
// 객체 생성
Hospital hospital = new Hospital();
// row 배열을 출력
System.out.println(Arrays.toString(row));
return hospital;
}
}
Java
복사
HospitalParser.java
3. 테스트 코드 작성
•
Alt + enter
•
testCode 1
class HospitalParserTest {
String line1 = "\"1\",\"의원\",\"01_01_02_P\",\"3620000\",\"PHMA119993620020041100004\",\"19990612\",\"\",\"01\",\"영업/정상\",\"13\",\"영업중\",\"\",\"\",\"\",\"\",\"062-515-2875\",\"\",\"500881\",\"광주광역시 북구 풍향동 565번지 4호 3층\",\"광주광역시 북구 동문대로 24, 3층 (풍향동)\",\"61205\",\"효치과의원\",\"20211115113642\",\"U\",\"2021-11-17 02:40:00.0\",\"치과의원\",\"192630.735112\",\"185314.617632\",\"치과의원\",\"1\",\"0\",\"0\",\"52.29\",\"401\",\"치과\",\"\",\"\",\"\",\"0\",\"0\",\"\",\"\",\"0\",\"\",";
@Test
@DisplayName("csv 1 줄을 Hospital로 잘 만드는지 test")
void convertToHospital() {
HospitalParser hp = new HospitalParser();
Hospital hospital = hp.parse(line1);
}
}
Java
복사
•
결과 확인
4. HospitalParser에서 Setter로 값을 설정하고, HospitalParserTest에서 Getter로 값을 가져와 비교
4_1. Map Reduce : 병렬처리 후 합치기
•
맨 앞과 맨 뒤의 “ “를 제거하기 위해 replace()를 활용했다.
replace
replace함수는 자신이 바꾸고싶은 문자로 문자열을 치환시켜주는 기능을 한다.
ex) a.replace(바꾸고 싶은 부분, 바꿀 문자열)
•
DateTime
substring
년,월,일을 표시하기 위해 문자열을 substring()을 활용했다.
// LocalDatetTime 클래스 사용하여 DateTime 구하기
int year = Integer.parseInt(row[5].substring(0, 4));
int month = Integer.parseInt(row[5].substring(4, 6));
int day = Integer.parseInt(row[5].substring(6, 8));
// System.out.printf("%d %d %d \n", year, month, day);
hospital.setLicenseDate(LocalDateTime.of(year, month, day, 0, 0, 0));
Java
복사
전체 코드
4_2. Test 코드에서 실행확인
class HospitalParserTest {
String line1 = "\"1\",\"의원\",\"01_01_02_P\",\"3620000\",\"PHMA119993620020041100004\",\"19990612\",\"\",\"01\",\"영업/정상\",\"13\",\"영업중\",\"\",\"\",\"\",\"\",\"062-515-2875\",\"\",\"500881\",\"광주광역시 북구 풍향동 565번지 4호 3층\",\"광주광역시 북구 동문대로 24, 3층 (풍향동)\",\"61205\",\"효치과의원\",\"20211115113642\",\"U\",\"2021-11-17 02:40:00.0\",\"치과의원\",\"192630.735112\",\"185314.617632\",\"치과의원\",\"1\",\"0\",\"0\",\"52.29\",\"401\",\"치과\",\"\",\"\",\"\",\"0\",\"0\",\"\",\"\",\"0\",\"\",";
@Test
@DisplayName("csv 1 줄을 Hospital로 잘 만드는지 test")
void convertToHospital() {
HospitalParser hp = new HospitalParser();
Hospital hospital = hp.parse(line1);
assertEquals(1, hospital.getId());
assertEquals("의원", hospital.getOpenServiceName());
assertEquals(3620000,hospital.getOpenLocalGovernmentCode());
assertEquals("PHMA119993620020041100004",hospital.getManagementNumber());
assertEquals(LocalDateTime.of(1999,6,12,0,0,0), hospital.getLicenseDate());
assertEquals(1, hospital.getBusinessStatus());
assertEquals(13, hospital.getBusinessStatusCode());
assertEquals("062-515-2875", hospital.getPhone());
assertEquals("광주광역시 북구 풍향동 565번지 4호 3층", hospital.getFullAddress());
assertEquals("광주광역시 북구 동문대로 24, 3층 (풍향동)", hospital.getRoadNameAddress());
assertEquals("효치과의원", hospital.getHospitalName());
assertEquals("치과의원", hospital.getBusinessTypeName());
assertEquals(1, hospital.getHealthcareProviderCount());
assertEquals(0, hospital.getPatientRoomCount());
assertEquals(0, hospital.getTotalNumberOfBeds());
assertEquals(52.29f, hospital.getTotalAreaSize());
}
}
Java
복사
•
결과 확인
수동으로 IoC와 Di하기 : Factory
1.
Parser 디렉토리에 ParserFactory 생성, ReadLineContext 생성
ReadLineContext.java
ParserFactory
2.
SpringBoot 사용
a.
추가 : @SpringBootTest @Autowired
b.
Test 파일에 데이터를 가져와서 파싱하는 것까지 Test
@SpringBootTest
class HospitalParserTest {
String line1 = "\"1\",\"의원\",\"01_01_02_P\",\"3620000\",\"PHMA119993620020041100004\",\"19990612\",\"\",\"01\",\"영업/정상\",\"13\",\"영업중\",\"\",\"\",\"\",\"\",\"062-515-2875\",\"\",\"500881\",\"광주광역시 북구 풍향동 565번지 4호 3층\",\"광주광역시 북구 동문대로 24, 3층 (풍향동)\",\"61205\",\"효치과의원\",\"20211115113642\",\"U\",\"2021-11-17 02:40:00.0\",\"치과의원\",\"192630.735112\",\"185314.617632\",\"치과의원\",\"1\",\"0\",\"0\",\"52.29\",\"401\",\"치과\",\"\",\"\",\"\",\"0\",\"0\",\"\",\"\",\"0\",\"\",";
@Autowired
ReadLineContext<Hospital> hospitalReadLineContext;
@Test
@DisplayName("10만건 이상 데이터가 파싱되는지")
void name() throws IOException {
String filname = "C:\\Users\\wjdtk\\Downloads\\fulldata_의원.csv";
List<Hospital> hospitalList = hospitalReadLineContext.readByLine(filname);
assertTrue(hospitalList.size()>10000);
assertTrue(hospitalList.size()>100000);
}
@Test
@DisplayName("csv 1 줄을 Hospital로 잘 만드는지 test")
void convertToHospital() {
HospitalParser hp = new HospitalParser();
Hospital hospital = hp.parse(line1);
assertEquals(1, hospital.getId());
assertEquals("의원", hospital.getOpenServiceName());
assertEquals(3620000,hospital.getOpenLocalGovernmentCode());
assertEquals("PHMA119993620020041100004",hospital.getManagementNumber());
assertEquals(LocalDateTime.of(1999,6,12,0,0,0), hospital.getLicenseDate());
assertEquals(1, hospital.getBusinessStatus());
assertEquals(13, hospital.getBusinessStatusCode());
assertEquals("062-515-2875", hospital.getPhone());
assertEquals("광주광역시 북구 풍향동 565번지 4호 3층", hospital.getFullAddress());
assertEquals("광주광역시 북구 동문대로 24, 3층 (풍향동)", hospital.getRoadNameAddress());
assertEquals("효치과의원", hospital.getHospitalName());
assertEquals("치과의원", hospital.getBusinessTypeName());
assertEquals(1, hospital.getHealthcareProviderCount());
assertEquals(0, hospital.getPatientRoomCount());
assertEquals(0, hospital.getTotalNumberOfBeds());
assertEquals(52.29f, hospital.getTotalAreaSize());
}
}
Java
복사