고래씌

[Spring] 12-1. 스케쥴러, Quartz를 이용한 회원 비밀번호 변경 알람(ex. 변경한지 3개월 지난경우 알람) 본문

Server/Spring

[Spring] 12-1. 스케쥴러, Quartz를 이용한 회원 비밀번호 변경 알람(ex. 변경한지 3개월 지난경우 알람)

고래씌 2024. 1. 31. 10:25

1.  Spring Scheduler

: 매일, 매분, 매초, 매주, 매달, ... 반복적으로 실행시켜야하는 작업(프로세스)가 있는 경우 스프링 스케쥴러를 사용하면
간편하게 셋팅 가능하다.

<스프링 스케쥴러 작업순서>
1. xml 파일만들고, task, context 스키마를 등록(하단 namespce탭을 이용)
2. 스케쥴링 관련 annotation 활성화
3. 스케쥴러로 사용할 클래스들을 bean 객체로 등록
4. web.xml에 프로그램 구동시 현재 xml에 읽혀지도록 등록 → *-context.xml로 등록했음
5. 스케쥴링을 원하는 메소드에 가서 schedule 어노테이션 추가 → ScheduleController에 추가함

 

 

  ref : bean 클래스의 변수명
  method : 해당 bean클래스의 스케쥴링할 메소드명
  cron : 
  * * * * * * *
  초 분 시 일 월 요일 년도(생략가능)
  * : 모든 값(매시 매분 매주 매초)
  ? : 어떤 값이든 상관없다.
  - : 범위지정(1-2) 1에서 2초
  , : 여러값을 지정. (1,5) 1초랑 5초
  / : 증분값. 0/2 → 0초부터 매 2초마다.(증가치 설정가능)
  L : 지정할 수 있는 범위의 마지막 값 (매달 말일)
  W : 가장 가까운 "평일"을 설정할 때
  # : N번째 특정 요일을 설정할때
 
  매일 30분마다 특정작업을 실행시키고 싶다.
  0 30 * * * *
 
  매일 오전 1시에 실행하게 하고 싶다?
  0 0 1 * * * *

 

 

 

 

▶ scheduler-context.xml

 

=> context, task 추가

 

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:task="http://www.springframework.org/schema/task"
	xsi:schemaLocation="http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.3.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">

	 <!-- #2 -->
	 <task:annotation-driven scheduler="khScheduler"/>
	 
	 
	 <!-- #3 -->
	 <context:component-scan base-package="com.kh.spring.common.scheduling"></context:component-scan>
	 
	 <task:scheduler id="khScheduler" pool-size="10" />
	 <!-- 
	 	pool-size : 쓰레드풀 개수 지정(기본값1)
	  -->
	  
	<task:scheduled-tasks scheduler="khScheduler">  <!-- 관리해야할 작업목록 -->
		<task:scheduled ref="scheduleController" method="testCron" cron="1 * * * * *" /> <!-- 1초 간격 -->
	</task:scheduled-tasks>



</beans>

 

 

 

 

 

 

▶ ScheduleController.java

package com.kh.spring.common.scheduling;

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Controller;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Controller
public class ScheduleController {
	
	// @Scheduled(fixedDelay = 1000) // 고정시간방식    고정된 시간마다 이 어노테이션이 실행된다.
	public void test() {
		log.info("1초마다 출력");
	}
	
	public void testCron() {
		log.info("크론탭 방식 테스트");
	}

}

 

 

크론메이커에서 cron을 상세하게 편하게 설정할 수 있다!

http://www.cronmaker.com/;jsessionid=node01pgk32hs9k7nq16qzbd9cpa2f81466910.node0?0

 

CronMaker

 

www.cronmaker.com

 

 

 


2. Quartz 스케쥴러 - ①

 

▶ Spring Quartz 설정방법
1. context:coompontentscan 추가 => bean 객체 등록시 필요
2. pom.xml에 Quartz관련된 의존성 3개 추가

Spring quartz에는 작업단위가 크게 3가지 컴포넌트로 나눠져 있음
- Job : 실제로 작업할 작업단위(기능)
- Trigger : Job을 어떤방식으로 실행시킬지 정의
- Scheuler : 내가만든 Trigger들을 등록해서, 내가 원하는 시간에 작업이 이루어지도록 스케쥴링하는 컴포넌트

 

 

 

 

 

 

=> Spring Context Support는 복사후, 해당 스프링 버전으로 재설정

${org.springframework-version}

 

▶ pom.xml에 붙여놓기

		<!-- Spring Quartz 스케쥴러 -->
		<!-- https://mvnrepository.com/artifact/org.quartz-scheduler/quartz -->
		<dependency>
		    <groupId>org.quartz-scheduler</groupId>
		    <artifactId>quartz</artifactId>
		    <version>2.3.2</version>
		</dependency>
		
		<!-- Spring Quartz Job -->
		<!-- https://mvnrepository.com/artifact/org.quartz-scheduler/quartz-jobs -->
		<dependency>
		    <groupId>org.quartz-scheduler</groupId>
		    <artifactId>quartz-jobs</artifactId>
		    <version>2.3.2</version>
		</dependency>
		
		<!-- Spring Context Support -->
		<!-- https://mvnrepository.com/artifact/org.springframework/spring-context-support -->
		<dependency>
		    <groupId>org.springframework</groupId>
		    <artifactId>spring-context-support</artifactId>
		    <version>${org.springframework-version}</version>
		</dependency>

 

 

 

 

▶ quartz-context.xml

 

=> context 추가

 

 

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">



	 <!-- job 객체 생성(bean 객체 형태)
	 	  메소드 단위로 실행되는 스케쥴러(MethodInvokingJobDetailFactoryBean)를 이용해서 객체생서예정
	  -->
	  <context:component-scan base-package="com.kh.spring.common.scheduling"></context:component-scan>
	  <bean id="job1" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
	  	<property name="targetObject" ref="scheduleController"></property>
	  	<property name="targetMethod" value="testQuartz"></property>
	  	
	  	<!-- 작업 동시 실행방지 여부 지정 -->
	  	<property name="concurrent" value="false"></property>
	  </bean>
	  
	  <!-- Trigger
	  	   내가 만든 Job을 통해 동작의 실행방법을 정의
	   -->
	   <bean id="jobTrigger1" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean" >
	   	<property name="jobDetail" ref='job1'></property>
	   	<property name="cronExpression" value="0/5 * * 1/1 * ? *"></property>
	   </bean> 
	   
	   <!-- 
	   		Scheduler
	   		위에서 정의한 trigger를 관리하고, 정의해둔 트리거를 실행시키는 역할을 하는 객체
	    -->
	    
	    <bean id="jobScheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
	    	
	    	<!-- 현재 생성된 스케쥴러를 통해 작동시킬 트리거 목록 -->
	    	<property name="triggers">
	    		
	    		<!-- list태그로 트리거들 추가 -->
	    		<list>
	    			<ref bean='jobTrigger1' />
	 
	    		</list>
	    	</property>
	    </bean>

</beans>

 

 

 

▶ ScheduleController.java에 메소드 추가

 

 

▶ 결과

 

 


3. Quartz 방식 - ② (비밀번호 변경한지 3개월 지났을 때 설정할 예정)

 

매일 오전 1시에 회원정보를 확인하여, 사용자가 비밀번호를 변경한지 3개월이 지났다면 비밀번호를 변경할 수 있도록 db상태값을 변경해줄 예정

1) db에 changePwd라는 칼럼을 추가
2) 사용자가 비밀번호변경을 안한지 3개월이 넘었다면, changePwd의 상태값을 변경
3) 사용자가 로그인 시도를 할 때 changePwd값이 바꿔져 있다면, 비밀번호 변경페이지로 이동
4) 비밀번호 변경을 하면 changePwd값은 원래 상태값으로 돌아간다.

 

 

 

▶ ChangePwdScheduler.java

package com.kh.spring.common.scheduling;

import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.scheduling.quartz.QuartzJobBean;
import org.springframework.stereotype.Component;

import com.kh.spring.member.model.service.MemberService;

@Component
public class ChangePwdScheduler extends QuartzJobBean{

	@Override
	protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
		
		// jobdataasmap에서 등록한 빈객체 가져오기
		MemberService mService = (MemberService)context.getMergedJobDataMap().get("mService");
		
		mService.updateMemberChangePwd();
	}

	

}

 

 

▶ quartz-context.xml

 

=> job2 추가

 

 

=> jobTrigger2 추가

 

=> jobTrigger2 로 변경

 

 

▶ quartz-context.xml 전체코드

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">

	 
	 <!-- job 객체 생성(bean 객체 형태)
	 	  메소드 단위로 실행되는 스케쥴러(MethodInvokingJobDetailFactoryBean)를 이용해서 객체생서예정
	  -->
	  <context:component-scan base-package="com.kh.spring"></context:component-scan>
	  
	  <bean id="job1" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
	  	<property name="targetObject" ref="scheduleController"></property>
	  	<property name="targetMethod" value="testQuartz"></property>
	  	
	  	<!-- 작업 동시 실행방지 여부 지정 -->
	  	<property name="concurrent" value="false"></property>
	  </bean>
	  
	  <!-- 비밀번호 변경주기(3개월) 지난경우 알람 -->
	  <bean id="job2" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
	  	<property name="jobClass" value="com.kh.spring.common.scheduling.ChangePwdScheduler"></property>
	  	<property name="jobDataAsMap">
	  		<map>
	  		<!-- class를 가져올 때 첫글자는 소문자로 등록 -->
	  			<entry key="mService" value-ref="memberServiceImpl" />
	  		</map>
	  	</property>
	  </bean>
	  
	  
	  
	  <!-- Trigger
	  	   내가 만든 Job을 통해 동작의 실행방법을 정의
	   -->
	   <bean id="jobTrigger1" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean" >
	   	<property name="jobDetail" ref='job1'></property>
	   	<property name="cronExpression" value="0/5 * * 1/1 * ? *"></property>
	   </bean> 
	   
	   
	   <!-- 비밀번호 변경주기(3개월) 지난경우 알람 -->
	   <bean id="jobTrigger2" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean" >
	   	<property name="jobDetail" ref='job2'></property>
	   	<property name="cronExpression" value="0/5 * * 1/1 * ? *"></property>
<!-- 	   	<property name="cronExpression" value="0/5 * 1 1/1 * ? *"></property> -->
	   </bean> 
	   
	   <!-- 
	   		Scheduler
	   		위에서 정의한 trigger를 관리하고, 정의해둔 트리거를 실행시키는 역할을 하는 객체
	    -->
	    
	    <bean id="jobScheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
	    	
	    	<!-- 현재 생성된 스케쥴러를 통해 작동시킬 트리거 목록 -->
	    	<property name="triggers">
	    		
	    		<!-- list태그로 트리거들 추가 -->
	    		<list>
	    			<!-- 비밀번호 변경주기(3개월) 지난경우 알람 -->
	    			<ref bean='jobTrigger2' />
	 				
	    		</list>
	    	</property>
	    </bean>

</beans>

 

 

① SqlDeveloper를 키고 MEMBER테이블에서 CHANGE_PWD 컬럼 추가

 

 

② 비밀번호 변경이 3개월이 지났다면 CHANGE_PWD 가 'Y'로 변경되도록 설정

 

=> 한 회원의 MODIFY_DATE를 비밀변경 변경한지 3개월이 지나도록 위와 같이 변경

 

▶ MemberService.java

void updateMemberChangePwd();

 

 

▶ MemberServiceImpl.java

	@Override
	public void updateMemberChangePwd() {
		memberDao.updateMemberChangePwd();
	}

 

 

▶ MemberDao.java

void updateMemberChangePwd();

 

 

▶ MemberDaoImpl.java

	@Override
	public void updateMemberChangePwd() {
		sqlSession.update("memberMapper.updateMemberChangePwd");
	}

 

 

▶ member-mapper.xml

	<!-- 비밀번호 변경(3개월) 지났다면 'Y'로 변경 -->
	<update id="updateMemberChangePwd">
		UPDATE MEMBER
		   SET CHANGE_PWD = 'Y'
		 WHERE SYSDATE > ADD_MONTHS(MODIFY_DATE, 3)
	</update>

 

 

=> DB에 CHANGE_PWD가 자동으로 'Y'로 바뀌는 것을 확인할 수 있다!

 

 

 

▶ 회원가입 쪽 member-mapper.xml 수정

 

=> 새로운 칼럼 추가되었으므로 DEFAULT 추가 (CHANGE_PWD = 'N' 기본값이 들어가도록)

 

 

=> CHANGE_PWD = 'N' 추가

 

 

▶ Member.java 칼럼에도 changePwd 추가

 

 

▶ MemberController.java

=> 사용자의 비밀번호 변경여부 확인을 위해 아래 코드 추가

 

 

▶ 결과

해당 아이디로 로그인한 결과, 이와 같은 알람창이 정상적으로 뜨는 것을 확인할 수 있다.