하고싶은 작업

  • 로컬에 이미지 파일을 가지고 있으며 해당 이미지 파일은 다른 곳에서 최신화가 이뤄진다.
  • 원격의 이미지 파일이 최신화가 되었는지 HTTP 응답의 Lastmodified 헤더를 체크하여 로컬 이미지 파일을 최신화 한다.

RestTemplate

  • 스프링부트 웹프로젝트이므로 이미 의존성으로 들어온 RestTemplate를 이용한다. 비동기 방식이지만 어플리케이션에 크게 영향을 주지 않으므로 사용한다.
  • RestTemplate으로 HTTP 요청을 날려 응답의 LAST_MODIFIED 헤더를 체크한다.

ZonedDateTime, LocalDateTime

  • HTTP 응답의 헤더는 타임존이 GMT로 되어있다.
  • Asia/Seoul 지역의 시간으로 변경하여 기준일자와 비교한다.

테스트코드

@RunWith(SpringRunner.class)
@SpringBootTest
public class RestTemplateTest {
    @Autowired
    RestTemplateBuilder restTemplateBuilder;

    @Test
    public void RestTemplate를_이용하여_이미지_최신화() throws URISyntaxException {
        // 체크할 이미지 파일의 URL주소
        String imgSrc = "http://steamcdn-a.akamaihd.net/steam/apps/359550/capsule_sm_120.jpg";
        
        // 스프링부트의 빌더를 이용하여 RestTemplate 생성
        RestTemplate restTemplate = restTemplateBuilder.build();

        // 헤더만을 가져오도록 제공되는 메서드 사용
        HttpHeaders httpHeaders = restTemplate.headForHeaders(new URI(imgSrc));
        String lastModified = httpHeaders.get(HttpHeaders.LAST_MODIFIED).get(0);
        
        // 응답의 헤더는 GMT 시간
        System.out.println("lastModified : " + lastModified); // Fri, 21 Feb 2020 19:40:42 GMT

        // 응답의 시간에 맞는 포맷터를 지정하여 ZonedDateTime(Asia/Seoul) 객체 생성 
        ZonedDateTime lastModifiedZDT = ZonedDateTime.parse(lastModified, DateTimeFormatter.RFC_1123_DATE_TIME)
                                                     .withZoneSameInstant(ZoneId.of("Asia/Seoul"));
        System.out.println("lastModifiedZDT : " + lastModifiedZDT); // 2020-02-22T04:40:42+09:00[Asia/Seoul]

        // ZonedDateTime -> LocalDateTime
        LocalDateTime lastModifiedLDT = lastModifiedZDT.toLocalDateTime();
        System.out.println("lastModifiedLDT : " + lastModifiedLDT); // 2020-02-22T04:40:42

        // 기준일시를 생성하여 체크!
        LocalDateTime stdLDT = LocalDateTime.now().minusDays(1); // 기준일시(하루전) 생성
        if(lastModifiedLDT.isAfter(stdLDT)){ // 기준일시 이후에 변경이 일어나면
            System.out.println("다운로드(최신화) 필요함");
        }else{
            System.out.println("기존과 같음");
        }
    }
}

 

'개발 > 기타' 카테고리의 다른 글

Quartz misfireThreshold  (2) 2020.12.06
패스워드 암호화에 대해서  (0) 2020.12.06
Maven 기본  (0) 2019.11.12
UTC, GMT, Epoch Time  (0) 2019.10.11
Ajax에 관하여  (0) 2018.12.13

오류발생

새로운 Controller를 테스트하기 위해 테스트 소스를 작성하고 WebMvc와 관련된 빈만 등록해 테스트 하고자 했다.
제공되는 SliceTest 애노테이션인 @WebMvcTest를 테스트클래스에 마킹하고 실행했으나 초기화 단계에서 Exception이 발생하였다.

 

org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'entityManagerFactory' available

 

원인

@WebMvcTest로 WebMvc와 관련된 빈만 등록된 상태에서 메인클래스에 마킹한 @EnableJpaRepositories이 JPA와 관련된 빈을 찾아 작업을 하려할 때 오류가 발생하였다.

해결

QueryLookupStrategy 설정을 위해 메인클래스에 @EnableJpaRepositories를 마킹했으나, 굳이 필요한 설정은 아니므로 지우고 테스트를 실행하였다.(그저 학습의 이유로 디폴트 전략을 명시적으로 설정하였다.)
만일 필요한 옵션이라면 @EnableJpaRepositories를 통해서 하지않고 다른 방법으로 옵션을 줬어야 했을것이다.

@SpringBootApplication
//@EnableJpaRepositories(queryLookupStrategy = QueryLookupStrategy.Key.CREATE_IF_NOT_FOUND)
public class App {
    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(App.class);
        app.setWebApplicationType(WebApplicationType.SERVLET);
        app.run(args);
    }
}

참고

링크 : github.com/spring-projects/spring-boot/issues/6844 

By using @EnableJpaRepositories you are explicitly telling Spring Boot’s auto-configuration to back off and that you’ll handle Spring Data yourself.
I think what’s happening is that @WebMvcTest is turning off JPA (i.e. not finding your @Entity classes) but @EnableJpaRepositories is still active so it complains that it can’t find any JPA models.

스프링부트의 Log 라이브러리

스프링부트는 Java Util Logging, Log4J2, Logback 이렇게 3가지에 대해 기본 설정을 제공하고 있다. spring-boot-starter-logging 의존성을 추가하면 로그관련 라이브러리들이 추가되는 것을 볼 수 있다.

이 중에서 스프링부트는 기본으로 Logback을 사용하며 자동으로 이루어지는 설정은 org.springframework.boot.logging.DefaultLogbackConfiguration 파일을 참고한다.
기본설정으로 아래와 같이 시간-로그레벨-프로세스ID-구분자-쓰레드명-로거명-로그내용 포맷이 출력된다.

디폴트 설정에서 변경을 원한다면 프로퍼티 설정파일에서 logging으로 시작하는 옵션을 지정하거나 별도의 로그설정파일(logback.xml 등)을 사용하여 디폴트 설정을 오버라이드 한다.


Log Level

스프링부트의 기본설정은 INFO 레벨 이상인 로그만 보여준다. 만일 상세한 로그가 보고 싶다면 debug모드로 어플리케이션을 기동하던지 출력되는 로그레벨을 프로퍼티에서 조정한다.

  • 디버그 모드로 기동
    • jar파일 실행시 --debug 옵션을 부여한다.
    • 프로퍼티 설정파일(application.properties)에 debug=true을 추가한다.
  • 어플리케이션의 출력로그 레벨을 조정
    • logging.level을 prefix로 하는 프로퍼티를 추가한다.
    • logging.level.<logger-name>=<level>
    • logging.level.com.yang.wind.mapper=TRACE : com.yang.wind.mapper 패키지 이하의 로그레벨을 TRACE로 한다.
    • logging.level.root=INFO : root 이하 모든 패키지의 로그레벨을 INFO로 한다.

Log Color

만약 ANSI를 지원하는 터미널을 사용한다면 프로퍼티 설정파일에 spring.output.ansi.enabled=detect 또는 always 옵션을 줘서 로그를 컬러풀하게 출력할 수 있다.


Log 파일출력

기본적으로 아무설정이 없다면 콘솔은 출력하지만 로그파일은 작성되지 않는다. 파일로 로그를 출력하고자 한다면 프로퍼티 설정파일에 logging.file.name  logging.file.path 프로퍼티를 추가한다.
name과 path 두 설정을 모두 지정할 경우에는 함께 동작하지 않는다. logback-spring.xml 과 같이 별도의 파일로 설정을 해줘야 할 듯 싶다.
프로퍼티 지정에 따른 동작방식은 아래를 참고하자.


Log Group

특정 로거들을 그룹핑하여 설정을 동일하게 변경이 가능하다. 예를들어 Tomcat에 관련된 로거들을 동시에 설정변경 하고자 한다면 각자의 패키지로 설정을 변경하기 보다는 그룹을 지정하여 간편하게 변경할 수 있다.

프로퍼티 설정파일에서 tomcat이라는 그룹을 생성하고 설정을 변경한다. 

  • logging.group.tomcat=org.apache.catalina, org.apache.coyote, org.apache.tomcat
  • logging.level.tomcat=TRACE

또한 스프링부트는 미리 설정된 그룹을 제공하기 때문에 편리하게 로그레벨 설정이 가능하다.


Custom Log 설정

설정한 로그시스템에 따라 아래의 파일이 로드되어 환경이 구성된다. 디테일한 커스텀 설정을 위해서는 로그시스템 별로 아래 xml 파일이나 properties 파일을 작성한다.

+ Recent posts