이전 게시글까지 청년 정책 Open API를 연동하고, 데이터베이스에 저장하는 과정에서 스케줄러를 사용해 월요일 자정에 데이터가 리프레시 되도록 설정했다.
스케줄러 이외에도 관리자가 직접 데이터를 리프레시 하는 기능을 추가하여, 임의로 리프레시가 필요하다고 판단될 때 수행할 수 있도록 했다.
1. 프로젝트 구조
src/main/java/com/example/withpeace/
│
├── config/ # 설정 관련 클래스
│ ├── SecurityConfig.java # Spring Security 설정
│ └── WebMvcConfig.java # Web MVC 설정
│
├── domain/ # 도메인 모델 (엔티티)
│ └── YouthPolicy.java # 청년 정책 엔티티
│
├── repository/ # 데이터 접근 계층
│ └── YouthPolicyRepository.java # 게시글 레포지토리
│
├── dto/ # 데이터 전송 객체
│ └── response/
│ ├── YouthPolicyListResponseDto.java # 응답 DTO
│ └── YouthPolicyResponseDto.java # 응답 DTO
│
├── controller/ # 컨트롤러 계층
│ └── PolicyController.java # 정책 관련 API 엔드포인트
│
└── service/ # 비즈니스 로직 계층
└── PolicyService.java # 정책 관련 비즈니스 로직
2. Spring Security 설정
SecurityConfig
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {
// ... (기존 설정 생략)
@Bean
protected SecurityFilterChain securityFilterChain(final HttpSecurity httpSecurity) throws Exception {
return httpSecurity
// ... (기존 설정 생략)
.authorizeHttpRequests(requestMatcherRegistry -> requestMatcherRegistry
// ... (다른 경로 생략)
.requestMatchers("/api/v1/policies/refresh").hasRole(ERole.ADMIN.toString())
.anyRequest().authenticated())
// ... (기존 설정 생략)
}
}
.requestMatchers("/api/v1/policies/refresh").hasRole(ERole.ADMIN.toString())
Spring Security 설정 파일에서 "/api/v1/policies/refresh" 경로에 `.hasRole(ERole.ADMIN.toString())` 을 통해 관리자(ADMIN)만 리프레시 기능을 사용할 수 있도록 설정했다.
3. Web MVC 설정
WebMvcConfig
@Configuration
@EnableWebMvc
@RequiredArgsConstructor
public class WebMvcConfig implements WebMvcConfigurer {
// ... (기존 코드 생략)
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer
.defaultContentType(MediaType.APPLICATION_JSON)
.ignoreAcceptHeader(true)
.useRegisteredExtensionsOnly(true); // 불필요하므로 제거 예정
}
}
Spring MVC의 Content Negotiation(컨텐츠 협상)을 구현했다.
응답의 출력 헝식이 XML로 나오는 경우가 있었다. 정확한 이유를 파악하지 못했지만 Open API의 응답 형식이 XML이라서 이것에 영향을 받는 것 같다.
API 응답 형식을 JSON으로 통일하기 위해 `configureContentNegotiation`를 추가했다.
configureContentNegotiation 메서드
- `.defaultContentType(MediaType.APPLICATION_JSON)`
- 기본 응답 형식을 JSON으로 설정한다.
- 클라이언트가 특정 형식을 요청하지 않았을 때 JSON 형식으로 응답한다.
- `.ignoreAcceptHeader(true)`
- 클라이언트의 Accept 헤더를 무시한다.
- 클라이언트가 요청한 형식에 관계없이 서버에서 지정한 형식으로 응답한다.
- `.useRegisteredExtensionsOnly(true)` (제거 예정)
- 등록된 확장자만 사용하도록 설정한다.
- URL의 확장자를 통한 컨텐츠 협상을 제한한다.
4. 컨트롤러 구현
YouthPolicyController
@RestController
@RequiredArgsConstructor
@RequestMapping("api/v1/policies")
@Slf4j
public class YouthPolicyController {
private final YouthPolicyService youthPolicyService;
// 정책 데이터 리프레시 (관리자)
@PostMapping("/refresh")
public ResponseDto<?> refreshPolicy(@UserId Long userId) {
youthPolicyService.scheduledFetchAndSaveYouthPolicy();
return ResponseDto.ok(true);
}
}
기존의 스케줄러 메서드(`scheduledFetchAndSaveYouthPolicy`)를 재사용해 리프레시 기능을 구현했다.
5. 기존 서비스
YouthPolicyService
@Scheduled(cron = "0 0 0 * * MON") // 매주 월요일 00:00에 실행되도록 설정
@Transactional
public void scheduledFetchAndSaveYouthPolicy() {
try {
// 데이터 삭제
deleteAllYouthPolicies();
saveCount = 0;
// 데이터 가져오기 및 저장
fetchAndSaveYouthPolicy();
log.info("Youth Policy data update job completed. Total {} policies saved.", saveCount);
} catch (CommonException e) {
if (e.getErrorCode() == ErrorCode.YOUTH_POLICY_FETCH_AND_SAVE_ERROR
|| e.getErrorCode() == ErrorCode.YOUTH_POLICY_DELETE_ERROR)
throw e;
} catch (Exception e) {
throw new CommonException(ErrorCode.YOUTH_POLICY_SCHEDULED_ERROR);
}
}
@Transactional
private void deleteAllYouthPolicies() {
try {
youthPolicyRepository.deleteAll();
log.info("All existing youth policies deleted.");
} catch (Exception e) {
throw new CommonException(ErrorCode.YOUTH_POLICY_DELETE_ERROR);
}
}
`scheduledFetchAndSaveYouthPolicy` 메서드는 기존 정책 데이터를 모두 삭제하고 API를 호출하여 최신 데이터로 갱신하는 작업을 수행한다.
6. API 응답 예시
요청 URL
[POST] http://cheongha.site/api/v1/policies/refresh
Response Body
{
"data": true,
"error": null
}
'Projects > 청하-청년을 위한 커뮤니티 서비스' 카테고리의 다른 글
[청하] 27. 정책 상세 조회 기능 구현 (3) | 2024.10.18 |
---|---|
[청하] 26. 정책 리스트 조회 기능 구현 (0) | 2024.10.18 |
[청하] 24. 청년 정책 Open API 연동 및 데이터베이스 저장 (feat. XML 데이터 매핑, 스케줄러 적용) (5) | 2024.10.17 |
[청하] 23. 게시글 삭제 기능 - 외래키 제약 조건 수정 (2) | 2024.10.16 |
[청하] 22. Android 강제 업데이트 검사 기능 - JWT 인증 필터에서 제외 (2) | 2024.10.16 |
댓글