Spring Boot 이미지 스케쥴링

송지윤·2024년 5월 2일
0

Spring Framework

목록 보기
59/65

@Scheduled

  • Spring에서 제공하는 스케줄러 - 스케줄러 : 시간에 따른 특정 작업(Job)의 순서를 지정하는 방법.

  • 설정 방법
    1) XXXSSAPPlication.java 파일에 @EnableScheduling 어노테이션 추가
    2) 스케쥴링 동작을 위한 클래스 작성

@Scheduled 속성

  • fixedDelay : 이전 작업이 끝난 시점으로 부터 고정된 시간(ms)을 설정.
    @Scheduled(fixedDelay = 10000) 이전 작업이 끝난 후 10초 뒤에 실행

수행시간이 다 끝난 후 시작함

  • fixedRate : 이전 작업이 수행되기 시작한 시점으로 부터 고정된 시간(ms)을 설정.
    @Scheduled(fixedRate = 10000) // 이전 작업이 시작된 후 10초 뒤에 실행

이전 작업이 끝났든 안 끝났든(수행 시간이 있으니까) 시작한지 10초 뒤면 또 시작함
(작업이 겹칠 수 있음)

위에 두개는 일정한 스케쥴을 가지고 돌아갈 수 없음

  • cron 속성(크론) : UNIX계열 잡 스케쥴러 표현식으로 작성 - cron="초 분 시 일 월 요일 [년도]" - 요일 : 1(SUN) ~ 7(SAT)
    ex) 2019년 9월 16일 월요일 10시 30분 20초 cron="20 30 10 16 9 2 " // 연도 생략 가능

명확한 날짜를 작성하는 속성

특수문자

* : 모든 수.
- : 두 수 사이의 값. ex) 10-15 -> 10이상 15이하
, : 특정 값 지정. ex) 3,4,7 -> 3,4,7 지정
/ : 값의 증가. ex) 0/5 -> 0부터 시작하여 5마다
? : 특별한 값이 없음. (월, 요일만 해당)
L : 마지막. (월, 요일만 해당)
@Scheduled(cron="0 * * * * *") // 모든 0초 마다 -> 매 분마다 실행

주의사항

  • @Scheduled 어노테이션은 매개변수가 없는 메소드에만 적용 가능.

1. @EnableScheduling 어노테이션 추가

BoardProjectBootApplication.java

@EnableScheduling // 스프링 스케줄러를 이용하기 위한 활성화 어노테이션
@SpringBootApplication(exclude= {SecurityAutoConfiguration.class})
public class BoardProjectBootApplication {

	public static void main(String[] args) {
		SpringApplication.run(BoardProjectBootApplication.class, args);
	}

}

2. 스케쥴링 동작을 위한 클래스 작성

@Component : 역할 명시하는 건 아님, 단순히 Bean 으로 등록할 때 사용

ImageDeleteScheduling

@Component
public class ImageDeleteScheduling {

//	@Scheduled(fixedDelay = 5000) // 이전 작업이 시작된 후 5초 후에 수행
//	@Scheduled(fixedRate = 5000) // 이전 작업 끝난 후 5초 뒤에 수행
//	@Scheduled(cron = "0,15,30,45 * * * * *") // 시계 초 단위가 0,15,30,45 경우 수행
//	@Scheduled(cron = "0 0 * * * *") // 정시 마다 수행
//	@Scheduled(cron = "0 0 0 * * *") // 자정
//	@Scheduled(cron = "0 0 12 * * *") // 정오
	@Scheduled(cron = "0 0 0 1 * *") // 매달 1일	
	public void scheduling() {
		
	}
	
}

3. DB랑 서버 파일 목록 비교해서 DB에 없는 서버 이미지 파일 삭제

scheduling 메서드 안에 작성

  1. config.properties 에 적어둔 folder-path 적어둔 걸 얻어와야함(경로)
    이 경로 안에 있는 파일 목록을 가져와야함

@PropertySource , @Value 이용해서 가져오기

@PropertySource("classpath:/config.properties")
public class ImageDeleteScheduling {

	// 회원 프로필 이미지 파일 저장 경로
	@Value("${my.profile.folder-path}")
	private String profileFolderPath;
	
	// 게시판 이미지 파일 저장 경로
	@Value("${my.board.folder-path}")
	private String boardFolderPath;
  1. 서버 파일 목록 조회하기
		File boardFolder = new File(boardFolderPath);
		File memberFolder = new File(profileFolderPath);

		File[] boardArr = boardFolder.listFiles();
		File[] memberArr = memberFolder.listFiles();
		
		// 두 배열을 하나로 합침 (for 문 한번만 돌기 위해서)
		// imageArr 이라는 빈 배열을 boardArr 과 memberArr 길이 만큼의 크기로 만든다.
		File[] imageArr = new File[boardArr.length + memberArr.length];
		
		// 배열 내용 복사 (깊은 복사)
		// System.arraycopy(복사할 배열, 몇 번 인덱스부터 복사할지, 새로운 배열, 새로운 배열의 몇 번 인덱스부터 넣을지, 복사를 어디까지 할건지)
		System.arraycopy(boardArr, 0, imageArr, 0, boardArr.length);
		System.arraycopy(memberArr, 0, imageArr, boardArr.length, memberArr.length);
		
		// 배열 -> List 변환 (다루기 쉽도록)
		List<File> serverImageList = Arrays.asList(imageArr);
  1. DB 이미지 파일 이름만 모두 조회

어노테이션, 필드 추가

@RequiredArgsConstructor
public class ImageDeleteScheduling {

	private final BoardService service;

서비스 호출

		List<String> dbImageList = service.selectDbImageList();

SQL 먼저 조회

SELECT CAST(IMG_RENAME AS VARCHAR2(300)) "rename"
FROM BOARD_IMG
UNION
SELECT SUBSTR(PROFILE_IMG, INSTR(PROFILE_IMG, '/', -1) + 1) "rename"
FROM "MEMBER"
WHERE PROFILE_IMG IS NOT NULL;

SELECT * FROM BOARD_IMG; --> NVARCHAR2(50)
SELECT * FROM "MEMBER"; --> VARCHAR2(300)
둘이 타입이 안 맞아서 UNION 안되는 걸 캐스팅으로 해결

board-mapper.xml

	<!-- DB 이미지 파일명 목록 조회 -->
	<select id="selectDbImageList">
		SELECT CAST(IMG_RENAME AS VARCHAR2(300)) "rename"
		FROM BOARD_IMG
		UNION
		SELECT SUBSTR(PROFILE_IMG, INSTR(PROFILE_IMG, '/', -1) + 1) "rename"
		FROM "MEMBER"
		WHERE PROFILE_IMG IS NOT NULL
	</select>
  1. 서버, DB 이미지 파일명을 비교해서 서버에만 있고, DB에 없는 파일을 서버에서 삭제
		if(!serverImageList.isEmpty()) { // 서버에 이미지가 있을 경우
			
			for(File serverImage : serverImageList) {
				// File.getName() : 서버 파일 이름
				
				// List.indexOf(객체) :
				// List 에 객체가 존재하면 존재하는 index 반환
				// 존재하지 않으면 -1 반환하는 메서드
				if(dbImageList.indexOf(serverImage.getName()) == -1) {
					log.info(serverImage.getName() + "삭제");
					serverImage.delete(); // 파일 삭제
				}
			}
		}

0개의 댓글