commit
This commit is contained in:
@@ -0,0 +1,63 @@
|
|||||||
|
package com.spring.common.util;
|
||||||
|
|
||||||
|
import org.springframework.web.context.ContextLoader;
|
||||||
|
import org.springframework.web.context.request.RequestAttributes;
|
||||||
|
import org.springframework.web.context.request.RequestContextHolder;
|
||||||
|
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||||
|
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import jakarta.servlet.http.HttpSession;
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
|
public class ApplicationUtil {
|
||||||
|
|
||||||
|
public static ServletRequestAttributes getServletRequestAttributes(){
|
||||||
|
return (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
|
||||||
|
}
|
||||||
|
//Request 객체 얻기
|
||||||
|
public static HttpServletRequest getRequest(){
|
||||||
|
return getServletRequestAttributes().getRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Set Request Attribute
|
||||||
|
public static void setRequestAttributes(String key, Object obj){
|
||||||
|
getServletRequestAttributes().setAttribute(key, obj, RequestAttributes.SCOPE_REQUEST);
|
||||||
|
}
|
||||||
|
//Get Request Attribute
|
||||||
|
public static Object getRequestAttributes(String key){
|
||||||
|
return getServletRequestAttributes().getAttribute(key, RequestAttributes.SCOPE_REQUEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Session 객체 얻기
|
||||||
|
public static HttpSession getSession(){
|
||||||
|
return getRequest().getSession();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Set Session Attributes
|
||||||
|
public static void setSessionAttributes(String key, Object obj){
|
||||||
|
getServletRequestAttributes().setAttribute(key, obj, RequestAttributes.SCOPE_SESSION);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Get Session Attributes
|
||||||
|
public static Object getSessionAttributes(String key){
|
||||||
|
return getServletRequestAttributes().getAttribute(key, RequestAttributes.SCOPE_SESSION);
|
||||||
|
}
|
||||||
|
|
||||||
|
//HttpServletResponse 객체 얻기
|
||||||
|
public static HttpServletResponse getResponse(){
|
||||||
|
return getServletRequestAttributes().getResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
//beanName을 통해서 Bean을 얻을 수 있다.
|
||||||
|
public static Object getBean(String beanName){
|
||||||
|
var context = ContextLoader.getCurrentWebApplicationContext();
|
||||||
|
if (context == null) {
|
||||||
|
throw new IllegalStateException("WebApplicationContext를 찾을 수 없습니다.");
|
||||||
|
}
|
||||||
|
return context.getBean(beanName);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -13,8 +13,8 @@ import jakarta.persistence.ManyToOne;
|
|||||||
import jakarta.persistence.Table;
|
import jakarta.persistence.Table;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
@Entity
|
// @Entity
|
||||||
@Table(name = "BATCH_JOB_EXECUTION")
|
// @Table(name = "BATCH_JOB_EXECUTION")
|
||||||
@Getter
|
@Getter
|
||||||
public class BatchJobExecution {
|
public class BatchJobExecution {
|
||||||
|
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ import jakarta.persistence.OneToOne;
|
|||||||
import jakarta.persistence.Table;
|
import jakarta.persistence.Table;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
@Entity
|
// @Entity
|
||||||
@Table(name = "BATCH_JOB_EXECUTION_CONTEXT")
|
// @Table(name = "BATCH_JOB_EXECUTION_CONTEXT")
|
||||||
@Getter
|
@Getter
|
||||||
public class BatchJobExecutionContext {
|
public class BatchJobExecutionContext {
|
||||||
|
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ import jakarta.persistence.Table;
|
|||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
@Entity
|
// @Entity
|
||||||
@Table(name = "BATCH_JOB_EXECUTION_PARAMS")
|
// @Table(name = "BATCH_JOB_EXECUTION_PARAMS")
|
||||||
@Getter
|
@Getter
|
||||||
public class BatchJobExecutionParams {
|
public class BatchJobExecutionParams {
|
||||||
|
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ import jakarta.persistence.Table;
|
|||||||
import jakarta.persistence.UniqueConstraint;
|
import jakarta.persistence.UniqueConstraint;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
@Entity
|
// @Entity
|
||||||
@Table(name = "BATCH_JOB_INSTANCE",
|
// @Table(name = "BATCH_JOB_INSTANCE",
|
||||||
uniqueConstraints = @UniqueConstraint(name = "JOB_INST_UN", columnNames = {"JOB_NAME", "JOB_KEY"}))
|
// uniqueConstraints = @UniqueConstraint(name = "JOB_INST_UN", columnNames = {"JOB_NAME", "JOB_KEY"}))
|
||||||
@Getter
|
@Getter
|
||||||
public class BatchJobInstance {
|
public class BatchJobInstance {
|
||||||
|
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ import jakarta.persistence.ManyToOne;
|
|||||||
import jakarta.persistence.Table;
|
import jakarta.persistence.Table;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
@Entity
|
// @Entity
|
||||||
@Table(name = "BATCH_STEP_EXECUTION")
|
// @Table(name = "BATCH_STEP_EXECUTION")
|
||||||
@Getter
|
@Getter
|
||||||
public class BatchStepExecution {
|
public class BatchStepExecution {
|
||||||
|
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ import jakarta.persistence.OneToOne;
|
|||||||
import jakarta.persistence.Table;
|
import jakarta.persistence.Table;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
@Entity
|
// @Entity
|
||||||
@Table(name = "BATCH_STEP_EXECUTION_CONTEXT")
|
// @Table(name = "BATCH_STEP_EXECUTION_CONTEXT")
|
||||||
@Getter
|
@Getter
|
||||||
public class BatchStepExecutionContext {
|
public class BatchStepExecutionContext {
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package com.spring.domain.email.batch;
|
||||||
|
|
||||||
|
import org.springframework.batch.core.Job;
|
||||||
|
import org.springframework.batch.core.Step;
|
||||||
|
import org.springframework.batch.core.job.builder.JobBuilder;
|
||||||
|
import org.springframework.batch.core.repository.JobRepository;
|
||||||
|
import org.springframework.batch.core.step.builder.StepBuilder;
|
||||||
|
import org.springframework.batch.core.step.tasklet.Tasklet;
|
||||||
|
import org.springframework.batch.repeat.RepeatStatus;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.transaction.PlatformTransactionManager;
|
||||||
|
|
||||||
|
import com.spring.infra.quartz.QuartzJob;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Configuration
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class EmailSendBatch {
|
||||||
|
|
||||||
|
private final JobRepository jobRepository;
|
||||||
|
private final PlatformTransactionManager transactionManager;
|
||||||
|
|
||||||
|
@QuartzJob(name = "emailSendJob", cronExpression = "*/3 * * * * ?")
|
||||||
|
@Bean(name = "emailSendJob")
|
||||||
|
Job emailSendJob(Step emailSendStep) {
|
||||||
|
log.info(">>> emailSendJob");
|
||||||
|
return new JobBuilder("emailSendJob", jobRepository)
|
||||||
|
.start(emailSendStep)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean("emailSendStep")
|
||||||
|
Step emailSendStep(Tasklet emailSendTasklet) {
|
||||||
|
log.info(">>> emailSendStep");
|
||||||
|
return new StepBuilder("emailSendStep", jobRepository)
|
||||||
|
.tasklet(emailSendTasklet, transactionManager).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
Tasklet emailSendTasklet(){
|
||||||
|
return ((contribution, chunkContext) -> {
|
||||||
|
log.info(">>>>> emailSendTasklet");
|
||||||
|
return RepeatStatus.FINISHED;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -12,8 +12,8 @@ import jakarta.persistence.Table;
|
|||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
@Entity
|
// @Entity
|
||||||
@Table(name = "QRTZ_BLOB_TRIGGERS")
|
// @Table(name = "QRTZ_BLOB_TRIGGERS")
|
||||||
@Getter
|
@Getter
|
||||||
public class QrtzBlobTriggers {
|
public class QrtzBlobTriggers {
|
||||||
|
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ import jakarta.persistence.Table;
|
|||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
@Entity
|
// @Entity
|
||||||
@Table(name = "QRTZ_CALENDARS")
|
// @Table(name = "QRTZ_CALENDARS")
|
||||||
@Getter
|
@Getter
|
||||||
public class QrtzCalendars {
|
public class QrtzCalendars {
|
||||||
|
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ import jakarta.persistence.Table;
|
|||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
@Entity
|
// @Entity
|
||||||
@Table(name = "QRTZ_CRON_TRIGGERS")
|
// @Table(name = "QRTZ_CRON_TRIGGERS")
|
||||||
@Getter
|
@Getter
|
||||||
public class QrtzCronTriggers {
|
public class QrtzCronTriggers {
|
||||||
|
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ import jakarta.persistence.Table;
|
|||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
@Entity
|
// @Entity
|
||||||
@Table(name = "QRTZ_FIRED_TRIGGERS")
|
// @Table(name = "QRTZ_FIRED_TRIGGERS")
|
||||||
@Getter
|
@Getter
|
||||||
public class QrtzFiredTriggers {
|
public class QrtzFiredTriggers {
|
||||||
|
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ import jakarta.persistence.Table;
|
|||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
@Entity
|
// @Entity
|
||||||
@Table(name = "QRTZ_JOB_DETAILS")
|
// @Table(name = "QRTZ_JOB_DETAILS")
|
||||||
@Getter
|
@Getter
|
||||||
public class QrtzJobDetails {
|
public class QrtzJobDetails {
|
||||||
|
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ import jakarta.persistence.Table;
|
|||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
@Entity
|
// @Entity
|
||||||
@Table(name = "QRTZ_LOCKS")
|
// @Table(name = "QRTZ_LOCKS")
|
||||||
@Getter
|
@Getter
|
||||||
public class QrtzLocks {
|
public class QrtzLocks {
|
||||||
|
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ import jakarta.persistence.Table;
|
|||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
@Entity
|
// @Entity
|
||||||
@Table(name = "QRTZ_PAUSED_TRIGGER_GRPS")
|
// @Table(name = "QRTZ_PAUSED_TRIGGER_GRPS")
|
||||||
@Getter
|
@Getter
|
||||||
public class QrtzPausedTriggerGrps {
|
public class QrtzPausedTriggerGrps {
|
||||||
|
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ import jakarta.persistence.Table;
|
|||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
@Entity
|
// @Entity
|
||||||
@Table(name = "QRTZ_SCHEDULER_STATE")
|
// @Table(name = "QRTZ_SCHEDULER_STATE")
|
||||||
@Getter
|
@Getter
|
||||||
public class QrtzSchedulerState {
|
public class QrtzSchedulerState {
|
||||||
|
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ import jakarta.persistence.Table;
|
|||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
@Entity
|
// @Entity
|
||||||
@Table(name = "QRTZ_SIMPLE_TRIGGERS")
|
// @Table(name = "QRTZ_SIMPLE_TRIGGERS")
|
||||||
@Getter
|
@Getter
|
||||||
public class QrtzSimpleTriggers {
|
public class QrtzSimpleTriggers {
|
||||||
|
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ import jakarta.persistence.Table;
|
|||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
@Entity
|
// @Entity
|
||||||
@Table(name = "QRTZ_SIMPROP_TRIGGERS")
|
// @Table(name = "QRTZ_SIMPROP_TRIGGERS")
|
||||||
@Getter
|
@Getter
|
||||||
public class QrtzSimpropTriggers {
|
public class QrtzSimpropTriggers {
|
||||||
|
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ import jakarta.persistence.Table;
|
|||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
@Entity
|
// @Entity
|
||||||
@Table(name = "QRTZ_TRIGGERS")
|
// @Table(name = "QRTZ_TRIGGERS")
|
||||||
@Getter
|
@Getter
|
||||||
public class QrtzTriggers {
|
public class QrtzTriggers {
|
||||||
|
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
package com.spring.infra.batch;
|
|
||||||
|
|
||||||
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
|
|
||||||
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
|
|
||||||
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
@EnableBatchProcessing
|
|
||||||
public abstract class AbstractBatchConfig {
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
protected JobBuilderFactory jobBuilderFactory;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
protected StepBuilderFactory stepBuilderFactory;
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -6,8 +6,6 @@ import org.quartz.Job;
|
|||||||
import org.quartz.Scheduler;
|
import org.quartz.Scheduler;
|
||||||
import org.quartz.spi.JobFactory;
|
import org.quartz.spi.JobFactory;
|
||||||
import org.quartz.spi.TriggerFiredBundle;
|
import org.quartz.spi.TriggerFiredBundle;
|
||||||
import org.springframework.batch.core.configuration.JobRegistry;
|
|
||||||
import org.springframework.batch.core.configuration.support.JobRegistryBeanPostProcessor;
|
|
||||||
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
|
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
@@ -24,19 +22,6 @@ public class QuartzConfig {
|
|||||||
private final DataSource dataSource;
|
private final DataSource dataSource;
|
||||||
private final PlatformTransactionManager transactionManager;
|
private final PlatformTransactionManager transactionManager;
|
||||||
|
|
||||||
/**
|
|
||||||
* JobRegistry 에 Job 을 자동으로 등록하기 위한 설정.
|
|
||||||
*
|
|
||||||
* @param jobRegistry ths Spring Batch Job Registry
|
|
||||||
* @return JobRegistry BeanPostProcessor
|
|
||||||
*/
|
|
||||||
@Bean
|
|
||||||
JobRegistryBeanPostProcessor jobRegistryBeanPostProcessor(JobRegistry jobRegistry) {
|
|
||||||
var jobRegistryBeanPostProcessor = new JobRegistryBeanPostProcessor();
|
|
||||||
jobRegistryBeanPostProcessor.setJobRegistry(jobRegistry);
|
|
||||||
return jobRegistryBeanPostProcessor;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Quartz Schedule Job 에 의존성 주입
|
* Quartz Schedule Job 에 의존성 주입
|
||||||
*
|
*
|
||||||
@@ -55,10 +40,8 @@ public class QuartzConfig {
|
|||||||
/**
|
/**
|
||||||
* Scheduler 전체를 관리하는 Manager.
|
* Scheduler 전체를 관리하는 Manager.
|
||||||
*
|
*
|
||||||
* @param datasource Spring datasource
|
* @param jobFactory job factory
|
||||||
* @param quartzProperties quartz config
|
|
||||||
* @return the scheduler factory bean
|
* @return the scheduler factory bean
|
||||||
* @throws Exception the exception
|
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
SchedulerFactoryBean schedulerFactoryBean(JobFactory jobFactory) {
|
SchedulerFactoryBean schedulerFactoryBean(JobFactory jobFactory) {
|
||||||
|
|||||||
@@ -5,36 +5,34 @@ import org.quartz.JobExecutionException;
|
|||||||
import org.springframework.batch.core.Job;
|
import org.springframework.batch.core.Job;
|
||||||
import org.springframework.batch.core.JobParameters;
|
import org.springframework.batch.core.JobParameters;
|
||||||
import org.springframework.batch.core.JobParametersBuilder;
|
import org.springframework.batch.core.JobParametersBuilder;
|
||||||
import org.springframework.batch.core.configuration.JobLocator;
|
import org.springframework.batch.core.configuration.JobRegistry;
|
||||||
import org.springframework.batch.core.launch.JobLauncher;
|
import org.springframework.batch.core.launch.JobLauncher;
|
||||||
import org.springframework.lang.NonNull;
|
import org.springframework.lang.NonNull;
|
||||||
import org.springframework.scheduling.quartz.QuartzJobBean;
|
import org.springframework.scheduling.quartz.QuartzJobBean;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
public class QuartzJobLauncher extends QuartzJobBean {
|
public class QuartzJobLauncher extends QuartzJobBean {
|
||||||
|
|
||||||
|
private final JobLauncher jobLauncher;
|
||||||
|
private final JobRegistry jobRegistry;
|
||||||
|
|
||||||
private String jobName;
|
private String jobName;
|
||||||
private JobLauncher jobLauncher;
|
|
||||||
private JobLocator jobLocator;
|
|
||||||
|
|
||||||
public void setJobName(String jobName) {
|
public void setJobName(String jobName) {
|
||||||
this.jobName = jobName;
|
this.jobName = jobName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setJobLauncher(JobLauncher jobLauncher) {
|
|
||||||
this.jobLauncher = jobLauncher;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setJobLocator(JobLocator jobLocator) {
|
|
||||||
this.jobLocator = jobLocator;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void executeInternal(@NonNull JobExecutionContext context) throws JobExecutionException {
|
protected void executeInternal(@NonNull JobExecutionContext context) throws JobExecutionException {
|
||||||
try {
|
try {
|
||||||
Job job = jobLocator.getJob(jobName);
|
Job job = jobRegistry.getJob(jobName);
|
||||||
JobParameters params = new JobParametersBuilder()
|
JobParameters params = new JobParametersBuilder()
|
||||||
.addString("JobID", String.valueOf(System.currentTimeMillis()))
|
.addString("JobID", String.valueOf(System.currentTimeMillis()))
|
||||||
.toJobParameters();
|
.toJobParameters();
|
||||||
jobLauncher.run(job, params);
|
jobLauncher.run(job, params);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new JobExecutionException(e);
|
throw new JobExecutionException(e);
|
||||||
|
|||||||
@@ -10,43 +10,34 @@ import org.quartz.Scheduler;
|
|||||||
import org.quartz.SchedulerException;
|
import org.quartz.SchedulerException;
|
||||||
import org.quartz.Trigger;
|
import org.quartz.Trigger;
|
||||||
import org.quartz.TriggerBuilder;
|
import org.quartz.TriggerBuilder;
|
||||||
import org.springframework.beans.BeansException;
|
|
||||||
import org.springframework.beans.factory.InitializingBean;
|
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.context.ApplicationContextAware;
|
import org.springframework.context.ApplicationListener;
|
||||||
|
import org.springframework.context.event.ContextRefreshedEvent;
|
||||||
|
import org.springframework.core.annotation.AnnotationUtils;
|
||||||
import org.springframework.lang.NonNull;
|
import org.springframework.lang.NonNull;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
public class QuartzJobRegistrar implements ApplicationContextAware, InitializingBean {
|
@RequiredArgsConstructor
|
||||||
|
public class QuartzJobRegistrar implements ApplicationListener<ContextRefreshedEvent> {
|
||||||
|
|
||||||
private ApplicationContext applicationContext;
|
private final Scheduler scheduler;
|
||||||
private Scheduler scheduler;
|
private final ApplicationContext applicationContext;
|
||||||
|
|
||||||
public QuartzJobRegistrar(Scheduler scheduler) {
|
|
||||||
this.scheduler = scheduler;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setApplicationContext(@NonNull ApplicationContext applicationContext) throws BeansException {
|
public void onApplicationEvent(@NonNull ContextRefreshedEvent event) {
|
||||||
this.applicationContext = applicationContext;
|
for (String beanName : applicationContext.getBeanDefinitionNames()) {
|
||||||
}
|
Object bean = applicationContext.getBean(beanName);
|
||||||
|
|
||||||
@Override
|
|
||||||
public void afterPropertiesSet() {
|
|
||||||
registerQuartzJobs();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void registerQuartzJobs() {
|
|
||||||
applicationContext.getBeansWithAnnotation(QuartzJob.class).forEach((beanName, bean) -> {
|
|
||||||
Class<?> beanClass = bean.getClass();
|
Class<?> beanClass = bean.getClass();
|
||||||
for (Method method : beanClass.getMethods()) {
|
for (Method method : beanClass.getDeclaredMethods()) {
|
||||||
QuartzJob quartzJobAnnotation = method.getAnnotation(QuartzJob.class);
|
QuartzJob quartzJobAnnotation = AnnotationUtils.findAnnotation(method, QuartzJob.class);
|
||||||
if (quartzJobAnnotation != null) {
|
if (quartzJobAnnotation != null) {
|
||||||
registerQuartzJob(quartzJobAnnotation, method.getName());
|
registerQuartzJob(quartzJobAnnotation, method.getName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void registerQuartzJob(QuartzJob quartzJobAnnotation, String jobName) {
|
private void registerQuartzJob(QuartzJob quartzJobAnnotation, String jobName) {
|
||||||
@@ -55,6 +46,7 @@ public class QuartzJobRegistrar implements ApplicationContextAware, Initializing
|
|||||||
Trigger trigger = createTrigger(quartzJobAnnotation, jobDetail);
|
Trigger trigger = createTrigger(quartzJobAnnotation, jobDetail);
|
||||||
scheduler.scheduleJob(jobDetail, trigger);
|
scheduler.scheduleJob(jobDetail, trigger);
|
||||||
} catch (SchedulerException e) {
|
} catch (SchedulerException e) {
|
||||||
|
e.printStackTrace();
|
||||||
throw new IllegalStateException("Error scheduling Quartz job", e);
|
throw new IllegalStateException("Error scheduling Quartz job", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -62,8 +54,6 @@ public class QuartzJobRegistrar implements ApplicationContextAware, Initializing
|
|||||||
private JobDetail createJobDetail(QuartzJob quartzJobAnnotation, String jobName) {
|
private JobDetail createJobDetail(QuartzJob quartzJobAnnotation, String jobName) {
|
||||||
JobDataMap jobDataMap = new JobDataMap();
|
JobDataMap jobDataMap = new JobDataMap();
|
||||||
jobDataMap.put("jobName", jobName);
|
jobDataMap.put("jobName", jobName);
|
||||||
jobDataMap.put("jobLauncher", applicationContext.getBean("jobLauncher"));
|
|
||||||
jobDataMap.put("jobLocator", applicationContext.getBean("jobLocator"));
|
|
||||||
return JobBuilder.newJob(QuartzJobLauncher.class)
|
return JobBuilder.newJob(QuartzJobLauncher.class)
|
||||||
.withIdentity(quartzJobAnnotation.name())
|
.withIdentity(quartzJobAnnotation.name())
|
||||||
.setJobData(jobDataMap)
|
.setJobData(jobDataMap)
|
||||||
|
|||||||
@@ -54,9 +54,7 @@ public class QuartzProperties {
|
|||||||
private void addProperties(String prefix, Object object, Properties properties) {
|
private void addProperties(String prefix, Object object, Properties properties) {
|
||||||
Arrays.stream(object.getClass().getDeclaredFields())
|
Arrays.stream(object.getClass().getDeclaredFields())
|
||||||
.filter(field -> !Modifier.isStatic(field.getModifiers()))
|
.filter(field -> !Modifier.isStatic(field.getModifiers()))
|
||||||
.forEach(field -> {
|
.forEach(field -> setProperties(prefix, object, properties, field));
|
||||||
setProperties(prefix, object, properties, field);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setProperties(String prefix, Object object, Properties properties, Field field) {
|
private void setProperties(String prefix, Object object, Properties properties, Field field) {
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package com.spring.infra.security.config;
|
package com.spring.infra.security.config;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
|
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
|
||||||
@@ -29,7 +31,7 @@ import lombok.RequiredArgsConstructor;
|
|||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class SecurityConfig {
|
public class SecurityConfig {
|
||||||
|
|
||||||
public static final String PERMITTED_URI[] = {"/api/auth/**", "/signIn"};
|
private static final String[] PERMITTED_URI = {"/favicon.ico", "/api/auth/**", "/signIn", "/h2-console/**"};
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
SecurityFilterChain securityFilterChain(
|
SecurityFilterChain securityFilterChain(
|
||||||
@@ -47,20 +49,23 @@ public class SecurityConfig {
|
|||||||
.requestMatchers(PERMITTED_URI).permitAll()
|
.requestMatchers(PERMITTED_URI).permitAll()
|
||||||
.anyRequest().authenticated()
|
.anyRequest().authenticated()
|
||||||
)
|
)
|
||||||
.logout((logout) -> logout
|
.logout(logout -> logout
|
||||||
.logoutSuccessUrl("/signIn")
|
.logoutSuccessUrl("/signIn")
|
||||||
.invalidateHttpSession(true))
|
.invalidateHttpSession(true))
|
||||||
.sessionManagement(session -> session
|
.sessionManagement(session -> session
|
||||||
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
|
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
|
||||||
)
|
)
|
||||||
.addFilterBefore(new JwtAuthenticationFilter(tokenService), UsernamePasswordAuthenticationFilter.class)
|
.addFilterBefore(new JwtAuthenticationFilter(tokenService, List.of(PERMITTED_URI)), UsernamePasswordAuthenticationFilter.class)
|
||||||
.exceptionHandling(ex -> ex.authenticationEntryPoint(authenticationEntryPoint).accessDeniedHandler(accessDeniedHandler));
|
.exceptionHandling(ex -> ex
|
||||||
|
.authenticationEntryPoint(authenticationEntryPoint)
|
||||||
|
.accessDeniedHandler(accessDeniedHandler)
|
||||||
|
);
|
||||||
return http.build();
|
return http.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
WebSecurityCustomizer ignoringCustomizer() {
|
WebSecurityCustomizer ignoringCustomizer() {
|
||||||
return (web) -> web.ignoring().requestMatchers("/h2-console/**");
|
return web -> web.ignoring().requestMatchers("/h2-console/**");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.spring.infra.security.filter;
|
package com.spring.infra.security.filter;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.springframework.lang.NonNull;
|
import org.springframework.lang.NonNull;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
@@ -20,11 +21,18 @@ import lombok.RequiredArgsConstructor;
|
|||||||
public final class JwtAuthenticationFilter extends OncePerRequestFilter {
|
public final class JwtAuthenticationFilter extends OncePerRequestFilter {
|
||||||
|
|
||||||
private final JwtTokenService jwtTokenService;
|
private final JwtTokenService jwtTokenService;
|
||||||
|
private final List<String> permitAllUrls;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doFilterInternal(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull FilterChain filterChain)
|
protected void doFilterInternal(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull FilterChain filterChain)
|
||||||
throws ServletException, IOException {
|
throws ServletException, IOException {
|
||||||
|
|
||||||
|
String requestURI = request.getRequestURI();
|
||||||
|
if (permitAllUrls.stream().anyMatch(requestURI::startsWith)) {
|
||||||
|
filterChain.doFilter(request, response);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
String accessToken = jwtTokenService.resolveTokenFromCookie(request, JwtTokenRule.ACCESS_PREFIX);
|
String accessToken = jwtTokenService.resolveTokenFromCookie(request, JwtTokenRule.ACCESS_PREFIX);
|
||||||
if (jwtTokenService.validateAccessToken(accessToken)) {
|
if (jwtTokenService.validateAccessToken(accessToken)) {
|
||||||
setAuthenticationToContext(accessToken);
|
setAuthenticationToContext(accessToken);
|
||||||
|
|||||||
@@ -21,11 +21,10 @@ public class JwtTokenService {
|
|||||||
private final JwtTokenUtil jwtTokenUtil;
|
private final JwtTokenUtil jwtTokenUtil;
|
||||||
private final JwtTokenGenerator jwtTokenGenerator;
|
private final JwtTokenGenerator jwtTokenGenerator;
|
||||||
private final UserPrincipalService userPrincipalService;
|
private final UserPrincipalService userPrincipalService;
|
||||||
|
private final Key accessSecretKey;
|
||||||
private final Key ACCESS_SECRET_KEY;
|
private final Key refreshSecretKey;
|
||||||
private final Key REFRESH_SECRET_KEY;
|
private final long accessExpiration;
|
||||||
private final long ACCESS_EXPIRATION;
|
private final long refreshExpiration;
|
||||||
private final long REFRESH_EXPIRATION;
|
|
||||||
|
|
||||||
public JwtTokenService(
|
public JwtTokenService(
|
||||||
JwtTokenUtil jwtTokenUtil,
|
JwtTokenUtil jwtTokenUtil,
|
||||||
@@ -36,22 +35,22 @@ public class JwtTokenService {
|
|||||||
this.jwtTokenUtil = jwtTokenUtil;
|
this.jwtTokenUtil = jwtTokenUtil;
|
||||||
this.jwtTokenGenerator = jwtTokenGenerator;
|
this.jwtTokenGenerator = jwtTokenGenerator;
|
||||||
this.userPrincipalService = userPrincipalService;
|
this.userPrincipalService = userPrincipalService;
|
||||||
this.ACCESS_SECRET_KEY = jwtTokenUtil.getSigningKey(jwtProperties.getAccessToken().getSecret());
|
this.accessSecretKey = jwtTokenUtil.getSigningKey(jwtProperties.getAccessToken().getSecret());
|
||||||
this.REFRESH_SECRET_KEY = jwtTokenUtil.getSigningKey(jwtProperties.getRefreshToken().getSecret());
|
this.refreshSecretKey = jwtTokenUtil.getSigningKey(jwtProperties.getRefreshToken().getSecret());
|
||||||
this.ACCESS_EXPIRATION = jwtProperties.getAccessToken().getExpiration();
|
this.accessExpiration = jwtProperties.getAccessToken().getExpiration();
|
||||||
this.REFRESH_EXPIRATION = jwtProperties.getRefreshToken().getExpiration();
|
this.refreshExpiration = jwtProperties.getRefreshToken().getExpiration();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String generateAccessToken(HttpServletResponse response, Authentication authentication) {
|
public String generateAccessToken(HttpServletResponse response, Authentication authentication) {
|
||||||
String accessToken = jwtTokenGenerator.generateAccessToken(authentication);
|
String accessToken = jwtTokenGenerator.generateAccessToken(authentication);
|
||||||
ResponseCookie cookie = setTokenToCookie(JwtTokenRule.ACCESS_PREFIX.getValue(), accessToken, ACCESS_EXPIRATION / 1000);
|
ResponseCookie cookie = setTokenToCookie(JwtTokenRule.ACCESS_PREFIX.getValue(), accessToken, accessExpiration / 1000);
|
||||||
response.addHeader(JwtTokenRule.JWT_ISSUE_HEADER.getValue(), cookie.toString());
|
response.addHeader(JwtTokenRule.JWT_ISSUE_HEADER.getValue(), cookie.toString());
|
||||||
return accessToken;
|
return accessToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String generateRefreshToken(HttpServletResponse response, Authentication authentication) {
|
public String generateRefreshToken(HttpServletResponse response, Authentication authentication) {
|
||||||
String refreshToken = jwtTokenGenerator.generateRefreshToken(authentication);
|
String refreshToken = jwtTokenGenerator.generateRefreshToken(authentication);
|
||||||
ResponseCookie cookie = setTokenToCookie(JwtTokenRule.REFRESH_PREFIX.getValue(), refreshToken, REFRESH_EXPIRATION / 1000);
|
ResponseCookie cookie = setTokenToCookie(JwtTokenRule.REFRESH_PREFIX.getValue(), refreshToken, refreshExpiration / 1000);
|
||||||
response.addHeader(JwtTokenRule.JWT_ISSUE_HEADER.getValue(), cookie.toString());
|
response.addHeader(JwtTokenRule.JWT_ISSUE_HEADER.getValue(), cookie.toString());
|
||||||
return refreshToken;
|
return refreshToken;
|
||||||
}
|
}
|
||||||
@@ -67,23 +66,23 @@ public class JwtTokenService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean validateAccessToken(String token) {
|
public boolean validateAccessToken(String token) {
|
||||||
return jwtTokenUtil.getTokenStatus(token, ACCESS_SECRET_KEY) == JwtTokenStatus.AUTHENTICATED;
|
return jwtTokenUtil.getTokenStatus(token, accessSecretKey) == JwtTokenStatus.AUTHENTICATED;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean validateRefreshToken(String token) {
|
public boolean validateRefreshToken(String token) {
|
||||||
return jwtTokenUtil.getTokenStatus(token, REFRESH_SECRET_KEY) == JwtTokenStatus.AUTHENTICATED;
|
return jwtTokenUtil.getTokenStatus(token, refreshSecretKey) == JwtTokenStatus.AUTHENTICATED;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String resolveTokenFromCookie(HttpServletRequest request, JwtTokenRule tokenPrefix) {
|
public String resolveTokenFromCookie(HttpServletRequest request, JwtTokenRule tokenPrefix) {
|
||||||
Cookie[] cookies = request.getCookies();
|
Cookie[] cookies = request.getCookies();
|
||||||
if (cookies == null) {
|
if (cookies == null) {
|
||||||
throw new RuntimeException("JWT_TOKEN_NOT_FOUND");
|
throw new IllegalStateException("JWT_TOKEN_NOT_FOUND");
|
||||||
}
|
}
|
||||||
return jwtTokenUtil.resolveTokenFromCookie(cookies, tokenPrefix);
|
return jwtTokenUtil.resolveTokenFromCookie(cookies, tokenPrefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Authentication getAuthentication(String token) {
|
public Authentication getAuthentication(String token) {
|
||||||
UserDetails principal = userPrincipalService.loadUserByUsername(getUserPk(token, ACCESS_SECRET_KEY));
|
UserDetails principal = userPrincipalService.loadUserByUsername(getUserPk(token, accessSecretKey));
|
||||||
return new UsernamePasswordAuthenticationToken(principal, "", principal.getAuthorities());
|
return new UsernamePasswordAuthenticationToken(principal, "", principal.getAuthorities());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -45,11 +45,11 @@ spring:
|
|||||||
|
|
||||||
batch:
|
batch:
|
||||||
jdbc:
|
jdbc:
|
||||||
initialize-schema: never
|
initialize-schema: always
|
||||||
|
|
||||||
quartz:
|
quartz:
|
||||||
jdbc:
|
jdbc:
|
||||||
initialize-schema: never
|
initialize-schema: always
|
||||||
wait-for-jobs-to-complete-on-shutdown: true
|
wait-for-jobs-to-complete-on-shutdown: true
|
||||||
job-store-type: jdbc
|
job-store-type: jdbc
|
||||||
properties:
|
properties:
|
||||||
|
|||||||
Reference in New Issue
Block a user