이전에 했던 프로젝트에서 interface와 제네릭을 사용하여 원하는 분야별로 데이터를 추출하기 쉽게 하도록 하기 위해 리팩토링을 함
※ 방식은 이전과 비슷하므로 변경된 부분만 작성하도록 함
이전 방식 : [Java]대용량처리 프로젝트
1. interface + 제네릭 사용
public interface Parser<T> {
T parse(String str);
}
2. Mysql 테이블 설계

(3) 논리적 설계
| 컬럼명 | 설명 | Type | ex |
|---|---|---|---|
| id(Pk) | VARCHAR(8) | A1120837 | |
| address | 전체 주소 | VARCHAR(90) | |
| district | 서울특별시 00구 | VARCHAR(15) | 서울특별시 강남구 |
| category | ...나중에 추가 작성병원분류c | VARCHAR(1) | A: 종합병원 B: 병원 C: 의원 D: 요양병원 E: 한방병원 G: 한의원 I: 기타 M: 치과병원 N: 치과의원 R: 보건소 |
| emergency_room | 응급실운영여부 1 운영 2 운영안함 | INT | 1 또는 2 |
| name | 해당 병원의 이름 | VARCHAR(40) | 가로수치과의원 |
| subdivision | 세부 분과 피부과, 성형외과, 외과, 내과, 소아과, 가정의학과, 치과, 등 | VARCHAR(10) | 피부과 흉부외과 영상의학과 |
CREATE TABLE `likelion-db`.`seoul_hospital` (
`id` VARCHAR(8) NOT NULL,
`address` VARCHAR(90) NOT NULL COMMENT '전체 주소',
`district` VARCHAR(15) NOT NULL COMMENT '서울시 00구',
`category` VARCHAR(1) NOT NULL COMMENT '병원분류\nC의원\nE한방병원\nN치과의원\n\n',
`emergency_room` INT NOT NULL COMMENT '응급실 운영여부\n운영 1\n안함 2\n',
`name` VARCHAR(40) NOT NULL COMMENT '해당 병원명',
`subdivision` VARCHAR(10) NULL COMMENT '세부 분과\n피부과, 성형외과, 외과, 내과, 소아과, 가정의학과, 치과 등\n',
PRIMARY KEY (`id`));
3. Mysql 스키마, 테이블 생성
스키마 생성
Mysql을 실행하고 위쪽 메뉴바에 원기둥모양을 눌러 스키마 이름을 작성하고 Apply 버튼을 눌러 스키마를 생성한다.
생성하고 나면 왼쪽 Navigator바에 해당하는 이름을 가진 스키마가 생성된 것을 알 수 있다.
테이블 생성
생성된 스키마를 누르고 Table 메뉴에서 마우스 오른쪽 클릭하여 Create Table 버튼을 누른다.
테이블 이름을 작성하고 테이블에 해당하는 Column Name과 DataType, 내용등을 입력해주고 Apply를 눌러 추가해 준다.
테이블이 추가된 것을 확인 할 수 있다.
4. Mysql에 파일 데이터 insert
위쪽 파일버튼을 눌러 넣고 싶은 데이터를 저장한 파일을 불러온다. 이때 파일을 .sql 형식의 파일을 호출해야 한다.
파일을 넣고 sql문 구문을 통해 데이터를 입력하여 번개모양을 눌러주면 테이블에 데이터가 추가가 된다.
1. DTO(변수 값 저장, 맵핑)
public class Hospital {
private String id; // [0]
private String address; //주소 [1]
private String district; //구 [1]수정
private String category; //카테고리 [2]
private String name; //병원명 [10]
private String subDivision=""; //세부분과 [10] 수정
private int emergencyRoom; //응급 운영 현황 [6]
public Hospital(String id, String address, String category, int emergencyRoom,
String name){
this.id = id;
this.address = address;
this.category = category;
this.name = name;
this.emergencyRoom = emergencyRoom;
this.setDistrict();
this.setCategory();
this.setSubdivision();
}
public String getId() {
return id.replace("\"", "");
}
public String getAddress() {
return address;
}
public void setDistrict() {
String[] address = this.address.split(" ");
this.district = address[0] + " " + address[1];
}
public String getDistrict() {
return district;
}
public void setCategory() { // 맵핑 A가 들어오면 종합병원 출력
Map<String,String> categorytmap = new HashMap<>();
categorytmap.put("A","종합병원");
categorytmap.put("B","병원");
categorytmap.put("C","의원");
categorytmap.put("D","요양병원");
categorytmap.put("E","한방병원");
categorytmap.put("G","한의원");
categorytmap.put("I","기타");
categorytmap.put("M","치과병원");
categorytmap.put("N","치과의원");
categorytmap.put("R","보건소");
categorytmap.put("W","기타(구급차)");
this.category = categorytmap.get(category);
}
public String getCategory() {
return category;
}
public String setEmergencyRoom() { // 1일때 운영중, 그 외 운영안함 출력
if(emergencyRoom == 1){
return "운영중";
}else
return "운영안함";
}
public String getEmergencyRoom() {
return setEmergencyRoom();
}
public String getName() {
return name;
}
private void setSubdivision(){
String[] subdivisionList = new String[]{
"치과", "성형외과", "한방병원", "한의원", "영상의학과", "이비인후과", "소아청소년과", "내과", "정형외과", "외과",
"가정의학과","피부과", "안과", "소아과", "요양병원", "비뇨기과", "정신건강의학과", "산부인과", "재활의학과",
"정신과", "마취통증의학과"};
for(String subdivision : subdivisionList){ // subdivisionList 배열 값만큼 반복
if(name.contains(subdivision)){ // 입력받은 name과 subdivision 값을 비교하여 해당값이 존재하면 그 값을 저장
subDivision=subdivision;
break;
}else
this.subDivision = "없음";
}
}
public String getSubDivision() {
return subDivision;
}
public String getSqlInsertQuery(){ // DB에 데이터 저장을 위해 쿼리문 작성
String sql = String.format("INSERT INTO `likelion-db`.`seoul_hospital`\n" +
"(`id`,`address`,`district`,`category`,`emergency_room`,`name`,`subdivision`)\n" +
"VALUES\n" +
"(\"%s\",\n" +
"\"%s\",\n" +
"\"%s\",\n" +
"\"%s\",\n" +
"%d,\n" +
"\"%s\",\n" +
"\"%s\");",this.id,this.address,this.district,this.category,this.emergencyRoom,this.name,this.subDivision);
return sql;
}
@Override
public String toString() { // 오버라이딩
return "\"" + this.id + "\"" + "," + "\"" + this.address + "\"" + "," + "\""
+ this.district + "\"" + "," + "\"" + this.category + "\"" + "," + this.emergencyRoom + "," + "\"" +
this.name + "\"" + "," + "\""+this.subDivision+ "\"";
}
}
2. 코드의 재사용성을 높이기 위해 Interface + 제네릭 사용
public interface Parser<T> { // 인터페이스, 제네릭을 통해 여러 클래스에서 접근이 가능함
T parse(String str);
}
3. 파싱, 파일생성,작성 메서드를 가진 클래스
public class HospitalParser implements Parser<Hospital>{
static String fileaddress = "C:\\Users\\qowhx\\AppData\\Roaming\\SPB_Data\\git\\Java-Study\\lion\\test.txt";
static String DBfileaddress = "C:\\DB file\\seoul_hospital_infomation_parsingdata.txt";
@Override
public Hospital parse(String str) {
str = str.replaceAll("\"",""); // "" 제거
String[] splitted = str.split(",");
return new Hospital(splitted[0],splitted[1],splitted[2],Integer.parseInt(splitted[6]),splitted[10]);
}
public void CreateFile(){ // 파일 생성
File file = new File(fileaddress); // 파일 생성 위치및 파일 이름
try{
System.out.println("파일 생성");
file.createNewFile();
}catch (IOException e){
System.out.println("파일 생성 못함");
throw new RuntimeException();
}
}
public void Filewrite(List<Hospital> hospitals){ // 파일 작성
File file = new File(fileaddress);
try{
BufferedWriter writer = new BufferedWriter(new FileWriter(file));
for(Hospital hospital:hospitals){ // 참조변수로 받은 리스트만큼 반복
writer.write(String.valueOf(hospital)+"\n"); // 참조변수로 받은 리스트의 값+"\n" 으로 파일에 작성
}
writer.close();
}catch (IOException e){
e.printStackTrace();
}
}
public void DBFilewrite(List<Hospital> hospitals){ // 파일 작성
File file = new File(DBfileaddress);
try{
BufferedWriter writer = new BufferedWriter(new FileWriter(file));
for(Hospital hospital:hospitals){ // 참조변수로 받은 리스트만큼 반복
writer.write(hospital+"\n"); // 참조변수로 받은 리스트의 값+"\n" 으로 파일에 작성
}
writer.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
4. Controller(대용량 파일과 파싱 파일 연결)
public class FileController<T> {
String filename = "C:\\DB file\\seoul_hospital_information.txt";
Parser<T> parser;
boolean isRemoveColumnName = true;
public FileController(Parser<T> parser) {
this.parser = parser;
}
public FileController(Parser<T> parser, boolean isRemoveColumnName) {
this.parser = parser;
this.isRemoveColumnName = isRemoveColumnName;
}
List<T> readLines() throws IOException {
List<T> result = new ArrayList<>();
BufferedReader br = new BufferedReader(new FileReader(filename));
String str;
if (isRemoveColumnName) {
br.readLine();
}
while ((str = br.readLine()) != null) {
result.add(parser.parse(str));
}
return result;
}
}
5. Main
public class Main {
public static void main(String[] args) throws IOException {
FileController<Hospital> hospitalLineReader = new FileController<>(new HospitalParser());
List<Hospital> hospitals = hospitalLineReader.readLines(); // 파일에서 값을 1줄씩 전체 읽어 list에 저장
HospitalParser hospitalParser = new HospitalParser();
hospitalParser.CreateFile(); // 파일 생성
hospitalParser.Filewrite(hospitals);
hospitalParser.DBFilewrite(hospitals);
}
}
6. TDD(Test case)
class HospitalParserTest {
String str = "\"A1120837\",\"서울특별시 송파구 동남로 208 (가락동)\",\"A\",\"의원\",\"G099\",\"응급의료기관 이외\",\"1\",\"토요일 첫째주 셋째주 휴진\",\"2005년 부터 진료 재활의학과전문의 전문물리치료 통증클리닉 척추교정치료 체외충격파 휜다리교정 목허리어깨무릎발 통증 디스크 퇴행성관절염\",\"극동아파트상가204호\",\"가로수치과의원\",\"02-448-6436\",\"02-2227-7777\",\"1900\",\"1900\",\"1900\",\"1900\",\"1900\",\"1500\",\"1400\",\"1600\",\"0900\",\"0900\",\"0900\",\"0900\",\"0900\",\"0900\",\"1000\",\"0900\",\"057\",\"83\",\"127.13147131787721\",\"37.49579508152157\",\"2022-09-07 14:55:30.0\"";
@Test
@DisplayName("ID가 파싱이 잘 되는지")
void idParsing() {
HospitalParser hospitalParser = new HospitalParser();
Hospital hospital = hospitalParser.parse(str);
String address = "서울특별시 송파구 동남로 208 (가락동)";
Assertions.assertEquals("A1120837", hospital.getId());
Assertions.assertEquals(address, hospital.getAddress());
String district = "서울특별시 송파구";
Assertions.assertEquals(district, hospital.getDistrict());
String category = "종합병원";
Assertions.assertEquals(category, hospital.getCategory());
String emergency = "운영중";
Assertions.assertEquals(emergency, hospital.getEmergencyRoom());
String name = "가로수치과의원";
Assertions.assertEquals(name, hospital.getName());
String subdivision = "치과";
Assertions.assertEquals(subdivision, hospital.getSubDivision());
}
@Test
@DisplayName("insert쿼리를 잘 만드는지 test")
void makeSqlQueryTest() {
HospitalParser hospitalParser = new HospitalParser();
Hospital hospital = hospitalParser.parse(this.str);
String sql ="INSERT INTO `likelion-db`.`seoul_hospital`\n" +
"(`id`,`address`,`district`,`category`,`emergency_room`,`name`,`subdivision`)\n" +
"VALUES\n" +
"(\"A1120837\",\n" +
"\"서울특별시 송파구 동남로 208 (가락동)\",\n" +
"\"서울특별시 송파구\",\n" +
"\"종합병원\",\n" +
"1,\n" +
"\"가로수치과의원\",\n" +
"\"치과\");";
Assertions.assertEquals(sql, hospital.getSqlInsertQuery());
}
}
