반응형
내가 프로젝트를 시작한지 일주일 되었는데 글을 이제서야 쓰는 이유는...?
이 작업만 거의 일주일이 걸렸기 때문이다...ㅎㅎㅎ
Open API를 가져다 써본 경험이 없어서 처음이었고 + 보통 JSON 형식이던데
KOPIS API는 XML형식이라 파싱하는 것부터 애를 먹었다ㅠㅠ
그리고 DB 넣는 거!!! 이게 너무너무 어려웠다...
하고 나니 간단한데...
암튼 구글링을 했을 때 정보가 부족하다는 생각이 들어서 이것부터 정리를 해보려고 한다.
🤍XML 형식의 Open API 데이터 JSON 형식으로 파싱하기
1. 가장 먼저 Open API를 사용하기 위해 필요한 서비스키를 신청한다.
이 과정은 간단하기 때문에 생략.
2. 그다음으로 사이트에 개발에 필요한 가이드라인이 올라와 있다. 나는 뮤지컬 목록을 불러올 것이므로 [공연 목록 조회 서비스] 가이드를 보고 따라하면 된다.
가이드대로 그대로 따라하기만 하면 되는데! 항목 구분에서 필수라고 적혀있는 항목은 URL에 꼭 포함시켜서 조회를 해주어야 한다. URL 형식은 요청 URL 예제대로 따라하면 된다.
테스트를 해보면 이렇게 xml로 나온다.
3. 이제 이걸 JSON 형식으로 바꾸어야 한다. 이것을 '파싱'이라고 한다.
JSON 파싱은 두 가지 라이브러리를 사용했다.
implementation group: 'com.googlecode.json-simple', name: 'json-simple', version: '1.1'
implementation group: 'org.json', name: 'json', version: '20090211'
4.MusicalApi.java
//보안을 위해 application.properties에 설정을 해두고
#API 인증키
api.serviceKey='자신의 서비스키'
//@Value 어노테이션으로 가져오기
@Value("${api.serviceKey}")
private String apiKey;
위에서 테스트 조회했던 것처럼 작성해준다. 조회 기간은 3개월로 잡았다.
@Component
@RequiredArgsConstructor
public class MusicalApi {
@Value("${api.serviceKey}")
private String apiKey;
private final MusicalRepository musicalRepository;
public void callMusicalApiJson(){
StringBuffer result = new StringBuffer();
String jsonPrintStr = null;
try {
//3개월 기간 설정
SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd");
Date currentDate = new Date();
Calendar cal = Calendar.getInstance();
cal.setTime(currentDate);
cal.add(Calendar.MONTH,3);
String stdate = formatter.format(currentDate);
String eddate = formatter.format(cal.getTime());
String urlStr = "http://www.kopis.or.kr/openApi/restful/pblprfr?service="+
apiKey+
"&stdate="+stdate+
"&eddate="+eddate+
"shcate=AAAB"+ /* 장르 : 뮤지컬 */
"&signgucode=11"+ /* 지역 : 서울 */
"&rows=10"+
"&cpage=1";
URL url = new URL(urlStr);
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.connect();
5. 대망(?)의 파싱 코드...
XML에서 JSON으로 파싱하는 XML.toJSONObject()는 org.json에서만 제공해서
두 가지 라이브러리를 사용했다.. 이게 맞는 방법인지 모르겠지만? 삽질끝에 찾아낸 해결책...
맨 마지막줄에는 insert하기 위해 JPA의 save를 사용해주었다.
/* XML to JSON 파싱 */
BufferedInputStream bis = new BufferedInputStream(urlConnection.getInputStream());
BufferedReader br = new BufferedReader(new InputStreamReader(bis,"UTF-8"));
String returnLine;
while ((returnLine=br.readLine())!=null){
result.append(returnLine);
}
JSONObject jsonObject = XML.toJSONObject(result.toString());
jsonPrintStr = jsonObject.toString();
System.out.println(jsonPrintStr);
/* DB 저장 */
JSONParser jsonParser = new JSONParser(); //JSON Parser 객체 생성
Object obj = jsonParser.parse(jsonPrintStr); //Parser로 문자열 데이터를 객체로 변환
org.json.simple.JSONObject _jsonObject = (org.json.simple.JSONObject) obj; //파싱한 obj를 JSONObject 객체로 변환
//차근차근 파싱하기
org.json.simple.JSONObject parseResult = (org.json.simple.JSONObject) _jsonObject.get("dbs");
ObjectMapper objectMapper = new ObjectMapper();
//ObjectMapper objectMapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,false);
JSONArray parseMusicalList = (JSONArray) parseResult.get("db");
for(int i=0;i<parseMusicalList.size();i++){
org.json.simple.JSONObject dailyMusical = (org.json.simple.JSONObject) parseMusicalList.get(i);
//JSON object -> Java Object(Entity) 변환
Musical musical = objectMapper.readValue(dailyMusical.toString(),Musical.class);
//insert
musicalRepository.save(musical);
여기까지 작업하면 XML 형식으로 받아온 Open API를 JSON 형식으로 파싱하는 작업은 끝이다!!
이제 대망의 INSERT....
🤍조회해온 Open API 데이터 DB에 저장하기
6.Entity에 해당하는 Musical.java
@Entity
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Getter
@ToString
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class Musical {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "mcode")
private Long mcode;
private String mt20id; //뮤지컬코드
private String prfnm; //공연명
private String fcltynm; //공연장명
private String poster; //포스터 경로
private String prfstate; //공연 중 상태
}
XML의 각 태그 명칭과 일치하게 작성해 주었다.
7. Spring JPA 관련 MusicalRepository 작성
public interface MusicalRepository extends JpaRepository<Musical,Long> {
}
8. 서비스단 작성
/*MusicalService*/
public interface MusicalService {
public void insertMusical();
}
/*MusicalServiceImpl*/
@Service
@RequiredArgsConstructor
@Log4j2
public class MusicalServiceImpl implements MusicalService{
private final MusicalApi musicalApi;
private final MusicalRepository musicalRepository;
public void insertMusical(){
musicalApi.callMusicalApiJson();
}
}
다량의 데이터를 insert하기 위해 스프링 배치를 사용해 주었다.
💡 스프링 배치(Spring Batch)란?
- 로깅/추적, 트랜잭션 관리, 작업 재시작, 건너뛰기 등 대용량 데이터 처리에 필요한 기능들을 제공함.
- 배치가 실패하여 작업 재시작 시에도 처음부터가 아닌, 실패한 지점부터 실행을 하게됨.
- 중복 실행을 방지하기 위해 성공 이력이 있는 Batch는 동일한 Parameters로 실행 시 Exception이 발생함.
9. Spring Batch 관련 build.gradle 의존성 작성
implementation 'org.springframework.boot:spring-boot-starter-batch'
testImplementation 'org.springframework.batch:spring-batch-test'
10. BatchConfig.java 작성
@Slf4j
@RequiredArgsConstructor
@Configuration
public class BatchConfig {
private final JobBuilderFactory jobBuilderFactory;
private final StepBuilderFactory stepBuilderFactory;
private final MusicalService musicalService;
@Bean
public Job testJob(){
return jobBuilderFactory.get("testJob")
.start(testStep(null))
.build();
}
@Bean
@JobScope
public Step testStep(@Value("#{jobParameters[testParameter]}") String testParameter){
return stepBuilderFactory.get("testStep")
.tasklet((contribution, chunkContext) -> {
musicalService.insertMusical();
return RepeatStatus.FINISHED;
}).build();
}
}
여기까지 코드를 작성하고 실행했을 때 json 형식으로 파싱은 잘 되었는데 에러가 발생했다.
💡에러 원인은 json 형식 데이터 중 Entity에 미포함시킨 데이터가 있기 때문이었다.
해결 방법은 엔티티에 아래 코드를 추가해 준다.(선언한 필드 이외 모든 요소 제외)
@JsonIgnoreProperties(ignoreUnknown = true)
배치 관련 testParameter에 날짜를 추가하고 다시 실행을 해보면!!
💡최종 결과
INSERT 성공!
배치 관련 테이블도 잘 생성되었다.
반응형
'💻 my code archive > 🌈Project' 카테고리의 다른 글
[RN 프로젝트] #1 개발 환경 구축, 프로젝트 디렉토리 구조 잡기 (0) | 2022.10.05 |
---|---|
[개인 프로젝트] 스프링 시큐리티(Spring Security), OAuth2 네이버 카카오 로그인 API 사용하기 (0) | 2022.06.28 |
[개인 프로젝트] OpenAPI 조회해온 뮤지컬 정보 화면 목록 뿌리기+Bootswatch 부트스트랩 (0) | 2022.06.24 |
[개인 프로젝트] 뮤지컬 커뮤니티 만들기 - 준비 (0) | 2022.06.23 |
프로젝트 기록 - 마켓컬리 클론코딩, 레시피 게시판을 추가한 온라인 쇼핑몰 RecipeToYou 구축하기 (0) | 2022.03.10 |