JAVA/Spring

[Spring] CronExpression 유효성 검사

하농이 2023. 1. 25. 21:55

현재 진행하는 프로젝트에서 제일 신경써야 할 부분은 스케줄러 서버가 다운되지 않도록 하는 것이다.

서버가 구동중에 있을 때 어떠한 이유든지 오류가 생기지 않게 하기 위해서 예외처리 및 오류 방지를 해줘야 한다고 생각했다. 우선 사용자가 입력한 크론식이 유효한지에 대한 검사가 필요했다. 왜냐하면 스케줄러 프로그램이기 때문에 유효하지 않은 크론식을 던져줬을 때, 서버가 다운될 위험이 있다고 생각했기 때문이다. 

 

첫번째 방법으로 생각했던 건, 직접 정규식을 만들어서 적용하는 것이었다. 그리고 아래 사이트 처럼 하나 하나 바뀔 시에 해당 크론식에 대한 해석이 보이게끔 만들고 싶었다. 

https://crontab.guru/#5_0_15-20_apr_tue

 

Crontab.guru - The cron schedule expression editor

 

crontab.guru

 

하지만 정규식을 작성 하는 것과 크론식으로 나올 수 있는 경우의 수가 꽤 많기 때문에 위의 사이트처럼의 구현은 조금 힘들었다. ( 프로젝트를 기한안에 끝내야 하는 시간적인 압박도 있었다. )

그래서 두번째 방법으로 생각했던 것이 Quartz 라이브러리의 CronExpression 클래스를 사용하는 것이었다.

아래의 두 사이트를 참고해 공부하였고, 첫번째 방법으로 생각했던 것 보다 훨씬 간단하고 코드 구성이 좋았다.

https://www.quartz-scheduler.org/api/2.1.7/org/quartz/CronExpression.html#validateExpression(java.lang.String) 

 

CronExpression (Quartz Parent POM 2.1.7 API)

protected  void addToSet(int val, int end, int incr, int type)            

www.quartz-scheduler.org

https://povia.tistory.com/9

 

2020.06.02 오늘의 일지

Quartz Job을 생성할 때 Cron 식이 유효한지 확인하는 코드를 추가했다. 사용한 클래스는 "org.quartz.CronExpression"이다. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 boolean isValidExpression(String expression){ boolean result = false; if(Cr

povia.tistory.com

 

우선 내가 하고자 했던 것은 AJAX를 사용하여 회원가입 아이디 중복여부 체크 같은 비동기 방식이다.

$("#Cron-expression").keyup(function () {
            var cron = $(this).val();
            if ($(this).val() === '') {
                $('#cron-result').html('<b class="CronIsVaildText" id="fail" style="font-size: 14px; color: orange">크론식을 입력해주세요</b>');
            } else {
                $.ajax({
                        url: "/cronExpression.do",
                        type: "GET",
                        data: {
                            "expression": cron
                        },
                        contentType: "application/json; charset=UTF-8",
                        success: function (result) {
                            if (result === true) {
                                $('#cron-result').html('<b style="font-size: 14px; color: #39D452">올바른 크론식입니다.</b>');
                            } else
                                $('#cron-result').html('<b class="CronIsVaildText" id="fail" style="font-size: 14px; color: #D42449">잘못된 크론식입니다.</b>');
                        },
                        error: function (request, error) {
                            alert("code: " + request.status + "message: " + request.responseText + "error: " + error);
                        }
                    });
            }
        });

jQuery의 keyup메소드안에 Ajax를 사용해 입력이 발생할때마다 계속 컨트롤러와 통신이 되게끔 하였다. 

텍스트 박스가 비어있을 때는 '크론식을 입력해주세요', 크론식이 유효하지 않을 때는 '잘못된 크론식입니다.' , 유효할 때는 '올바른 크론식입니다' 라는 텍스트를 띄웠다.

 

아래는 컨트롤러 코드이다.

	@ResponseBody
	@RequestMapping(value = "/cronExpression.do", method = RequestMethod.GET)
	public boolean isValidExpression(@RequestParam(value="expression")String expression){
		//System.out.println(expression);
	    boolean result = false;
	    if(CronExpression.isValidExpression(expression)){
	        try {
	            //CronExpression targetExpression = new CronExpression(cron);
	            //if(targetExpression.getNextValidTimeAfter(new Date(System.currentTimeMillis())) != null){
	                //System.out.println("트루");
	            	result = true;
	                
	            //}
	        } catch (Exception e) {
	        	//System.out.println("펄스");
	            e.printStackTrace();
	        }
	    }
	    return result;
	}

CronExpression 클래스의 isValidExpression(expression) 메소드를 사용하였고 리턴 타입은 boolean 타입이다.

View에서 입력된 크론식이 유효하면 true, 유효하지 않으면 false를 반환한다.

 

isValidExpression의 내부를 보면

CronExpression을 생성하면서 파라메터의 String을 생성자로 주는데, 이 때 Exception이 발생하면 false, 제대로 생성되면 true를 반환하게 된다. 결국 5번째 줄 CronExpression 생성자를 내부에서 한번 해보고 결과를 넘겨주는 것이다.

 

두번째 조건은 getNextValidTimeAfter이다.

CronExpression이 생성됐다면, getNextValidTimeAfter를 통해 다음 수행 예정 Date가 있는지를 체크하는 것이다. 없으면 null이 반환되기 때문에 null일 경우 다음 수행 예정이 없는 무의미한 Cron 식이라는 것이고, 있다면 사용할 수 있는 식으로 간주한다.

 

결과는 다음과 같다.

아무것도 입력하지 않았을 때
크론식이 유효하지 않을 때
유효한 크론식일 때

 

Cron식이 생소한 사용자의 편의를 위해서 Cron Menual로 만들어 주었다!

부트스트랩의 콜랩스를 사용하였다. ( 메뉴얼을 굳이 안봐도 되는 사용자도 있기에..? )

Cron 메뉴얼

 

 

이상 끝-