와이프가 결혼전에 집에서 사용하던 노트북 lenovo 제품이 있어서 이걸 간단하게 사용할 서버로 쓰고 싶었다.

그래서 우분투를 설치하려고 하는데 계속 the 'grub-efi-amd64-signed' package failed to install into /target/. Without the GRUB boot loader, the installed system will not boot. 라는 오류만 발생했다.

구글링을 하면서 efl boot 영역을 설정해주고 별짓 을 다해도 안되었는데

 

오늘 아침에 이 유튜브를 보고 해결했다. 나중을 위해서 공유해논다.

https://www.youtube.com/watch?v=DWlB0_f3GAY

spring acturator를 통해서 스프링 애플리케이션의 작동여부등을 체크해보자.

 

설정


우선 gradle 라이브러리를 추가한다.

compile 'org.springframework.boot:spring-boot-starter-actuator'

그리고 기존에는 application.properties나 yml에 아래 옵션을 설정해줘야 했지만 기본적으로 설정이 되어있다.

endpoints.health.enabled=true

하지만 이는 Spring boot 2.0에서 다음으로 변경되었다. (https://stackoverflow.com/questions/48900892/how-to-enable-all-endpoints-in-actuator-spring-boot-2-0-0-rc1)

 

How to enable all endpoints in actuator (Spring Boot 2.0.0 RC1)

I moved to Spring Boot 2.0.0 RC1 from 1.5.10 and I am stuck with actuator in the latest version. How can I enable expose and enable all actuator endpoints? The only endpoints that get exposed are:...

stackoverflow.com

각 health, info등으로 적어도 되지만 귀찮으면 asterisk로 모두 포함해도 된다. 대표적인 엔드포인트에 대한 설명은 아래 기재해 놓았다.

management:
  endpoints:
    web:
      exposure:
        include: "*"

endpoint는 다음과 같이 지정해줄수 있다.

management:
  endpoints:
    web:
      base-path: /application

 

기본적인 정보를 보여주는 Endpoint 


Actuator에서 사용할 수 있는 기본적인 엔드포인트는 다음과 같고 더 자세하게 다른 정보를 볼 수 있는 api들도 제공한다.

 

/health

 앱의 대한 건강 정보를 보여준다. 


/info 

전체적인 앱에 대한 정보를 보여준다.


/metrics 

앱에 대한 통계정보를 보여준다. (카운터 등등) 

우선적으로 볼 수 있는 파라미터정보가 나오고 상세히 보고 싶은경우 다음 경로에 추가해서 조회하면 볼 수있다.


/httptrace

앱에 대한 상세 요청정보를 보여준다.

 

Spring Acturator의 데이터는 모두 휘발성으로 데이터를 저장하고 있지는 않다. 이를 저장하는 방법은 따로 있는지는 확인해보지는 않았다. 나주에 기회되면 확인해보고 정리해봐야겠다. 그리고 health endpoint를 내가 원하는대로 커스텀할 수 있다. 이 또한 당장 필요성이 없어 상세하게 알아보지는 않았지만 크게 어렵지는 않은 것 같다. 

모니터링 할 수 있는 Acturator가 생각보다 괜찮은 것 같다. 나중에 실무에서 써볼 수 있으면 써봐야겠다.

 

기존에 공부삼아서 개발중이던 wedulpos에 spring batch를 추가해보려고 했다.

그래서 공통으로 mono 프로젝트로 되어있던 wedulpos를 multi module로 수정했다.

 

그랬더니 이상하게 servlet context에서 jsp를 로드하지 못했다.

그래서 계속해서 ServletException not include... jsp 또는 ServletException not jsp found 오류가 발생했다.

 

그래서 엄청난 구글링을 2틀동안했다. 집에서 그리고 약속장소에서 기다리면서 노트북으로 그리고 퇴근하고 오늘..

정말 가지가지한 방법을 다해봤었다. 기본적으로 embed-tomcat의 경우 jasper를 가지고 있지 못해서 별도의 모듈을 추가하고 servlet jspl 추가했고, compileOnly, provieded 별 난리를 다했다 ㅋㅋㅋ

하지만 tiles, url resolver 모두 bean이 등록되어있고 잘 동작하는데 jsp를 못찾는 해결하지 못했다.

최후에 방법으로 검색해본 키워드 intellij에서 정답을 찾았다. 

 

intellij에서 module 안에 웹 모듈을 실행시킬때는 working directory를 해당 모듈로 설정해줘야 한다. 그렇지 않으면 최상의 root로 working directory가 지정되기 때문이다.

https://stackoverflow.com/questions/44794588/intellij-run-configuration-spring-boot-vs-maven-issues

그래서 이 글을 보고 바로 지정해봤다.

 

결과는 성공 ㅋㅋㅋㅋㅋㅋㅋ

 

ㅋㅋㅋㅋ

너무 행복하다.  이 맛에 구글링하고 개발하는거 같다.

 

이제 내일부터는 spring batch를 공부해서 하나하나 정리하고 간단하게 batch를 만들어보자. 휴

git 주소 : https://github.com/weduls/wedulpos_boot

  1. 김병관 2019.08.06 09:00

    이 글을 보고 암이 나았습니다.감사합니다.하마터면죽을뻔했네요

heroku에 코드를 올리지 않고 바로 jar 파일을 deploy하기 위해서 heroku cli를 이용하여 올리는데 자꾸 Web process failed to bind to $PORT within 90 seconds of launch가 발생했다.

이유를 몰라서 계속 알아보던 중 heroku에서 spring boot를 실행시키기 위해서는 Procfile을 작성하고 port를 지정해줘야 한다.

우선 application.yml 설정

server:
    port: ${port:8080}

 

Procfile 설정

- Procfile은 확장자 없이 만들어야한다. 

- 포트는 8080이나 원하는 걸로 지정해 주고 profile까지 작성해주고 나머지 depoly를 위한 내요을 작성한다.

web: java -Dspring.server.port=8080 -Dspring.profiles.active=production $JAVA_OPTS -jar wedulpos-0.0.1-SNAPSHOT.war

 

Deploy 실행

heroku deploy:jar wedulpos-0.0.1-SNAPSHOT.war --app wedulpos

 

로그를 확인해보면 정상적으로 실행되는 걸 확인할 수 있땅. 2시간을 삽질했네 짱나겡

wedul$ heroku logs --tail --app wedulpos

 

Elasticsearch를 Spring Boot에서 작업을 하는 간단한 정리를 해보자.


1. Library 추가

Elasticsearch를 사용하기 위해서는 spring-data-elasticsearch 라이브러리가 추가되어야 한다. 

gradle에 추가해보자.

1
2
3
4
5
6
7
dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-elasticsearch'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    compileOnly "org.projectlombok:lombok:1.16.16"
}
 
cs


spring-data-elasticsearch 버전별로 호환되는 elasticsearch가 상이하니 참고

spring data elasticsearchelasticsearch
3.2.x6.5.0
3.1.x6.2.2
3.0.x5.5.0
2.1.x2.4.0
2.0.x2.2.0
1.3.x1.5.2


2. Configuration

Elasticsearch에 접속하기 위한 Configuration을 정의해준다.

Elasticsearch  접속을 위해서는 host, port, cluster name이 필요하다. cluster name을 알아야 하는데 docker에 설치 한 경우 여기서 확인하면 된다.

우선 docker exec -it elastic bash로 콘솔에 접속한 후에 elasticsearch.yml에 적혀있는 cluster name을 확인한다.

그리고 application.properties에 설정 내용을 적어준다.

1
2
3
4
elasticsearch.host=127.0.0.1
elasticsearch.port=9300
elasticsearch.cluster_name=docker-cluster
spring.main.allow-bean-definition-overriding=true
cs

그리고 EnableElasticsearchRepositories 애노테이션을 설정한 Configuration 클래스를 만들어준다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
package com.elasticsearch.study.configuration;
 
import org.springframework.beans.factory.annotation.Value;
import org.elasticsearch.client.Client;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.transport.client.PreBuiltTransportClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories;
 
import java.net.InetAddress;
 
/**
 * Elasticsearch Configuration
 *
 * @author wedul
 * @since 2019-02-09
 **/
@EnableElasticsearchRepositories
@Configuration
public class ElasticConfiguration {
 
  @Value("${elasticsearch.host}")
  private String host;
 
  @Value("${elasticsearch.port}")
  private int port;
 
  @Value("${elasticsearch.cluster_name")
  private String clusterName;
 
  @Bean
  public Client client() throws Exception {
    Settings settings = Settings.builder().put("cluster.name", clusterName).build();
 
    TransportClient client = new PreBuiltTransportClient(settings);
    client.addTransportAddress(new TransportAddress(InetAddress.getByName(host), port));
    return client;
  }
 
  @Bean
  public ElasticsearchOperations elasticsearchTemplate() throws Exception {
    return new ElasticsearchTemplate(client());
  }
 
}
 
cs


3. DTO 생성

Elasticsearch에서 Document 내용을 담을 DTO를 만들어주고 @Document 애노테이션을 달고 index name과 type을 정의해준다.

@Id 어노테이션이 붙은 필드는 각 Doucument에 붙어있는 _id 값이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package com.elasticsearch.study.dto;
 
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
 
/**
 * studyFor
 *
 * @author wedul
 * @since 2019-02-09
 **/
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
@Document(indexName = "wedul_play", type = "story")
public class WedulPlay {
 
  @Id
  private String id;
  private String title;
  private String user;
  private long startAt;
  private long endAt;
 
}
 
cs


4. Repository

JPA를 사용하면 익숙할 패턴으로 Elasticsearch에서도 ElasticsearchRepository가 존재한다. 사용방법은 JPA와 동일하게 저장할 때는 save, 조회할 때는 find(), findByUser()등으로 사용할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.elasticsearch.study.repository;
 
import com.elasticsearch.study.dto.WedulPlay;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Repository;
 
/**
 * study
 *
 * @author wedul
 * @since 2019-02-09
 **/
@Repository("wedulPlayRepository")
public interface WedulPlayRepository extends ElasticsearchRepository<WedulPlay, String> {
 
  WedulPlay findByUser(String user);
  
}
 
cs


5. Service

지금 테스트 하는 부분에서는 크게 비즈니스 로직에 들어갈 소스가 없다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package com.elasticsearch.study.service;
 
import com.elasticsearch.study.dto.WedulPlay;
import com.elasticsearch.study.repository.WedulPlayRepository;
import com.google.common.collect.Lists;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import org.springframework.stereotype.Service;
 
import java.util.List;
 
/**
 * study
 *
 * @author wedul
 * @since 2019-02-09
 **/
@AllArgsConstructor
@NoArgsConstructor
@Service
public class WedulPlayService {
 
  private WedulPlayRepository wedulPlayRepository;
 
  public void save(WedulPlay play) {
    wedulPlayRepository.save(play);
  }
 
  public List<WedulPlay> findAll() {
    return Lists.newArrayList(wedulPlayRepository.findAll());
  }
 
  public WedulPlay findByUser(String user) {
    return wedulPlayRepository.findByUser(user);
  }
 
}
 
cs


6. Test 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
package com.elasticsearch.study.wedulplay;
 
import com.elasticsearch.study.dto.WedulPlay;
import com.elasticsearch.study.repository.WedulPlayRepository;
import com.elasticsearch.study.service.WedulPlayService;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
 
import java.util.List;
 
import org.hamcrest.core.IsNull;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
 
/**
 * wedul play document 조회
 *
 * @author wedul
 * @since 2019-02-09
 **/
@RunWith(SpringRunner.class)
@SpringBootTest
public class WedulPlayTest {
 
  WedulPlayService wedulPlayService;
 
  @Autowired
  @Qualifier("wedulPlayRepository")
  WedulPlayRepository wedulPlayRepository;
 
  @Before
  public void setup() {
    wedulPlayService = new WedulPlayService(wedulPlayRepository);
  }
 
  @Test
  public void whenValidParameter_thenSuccessFind() {
    List<WedulPlay> list = wedulPlayService.findAll();
 
    assertNotNull(list);
  }
 
  @Test
  public void whenValidParameter_thenSuccessSave() {
    Exception ex = null;
 
    try {
      wedulPlayService.save(WedulPlay.builder().title("안녕 이건 테스트야").user("위들").startAt(1242421424).endAt(23214124).build());
    } catch (Exception exception) {
      ex = exception;
    }
 
    assertTrue(null == ex);
  }
 
  @Test
  public void whenValidParameter_thenSuccessFindByUser() {
    Exception ex = null;
 
    try {
      WedulPlay play = wedulPlayService.findByUser("위들");
 
      assertThat(play, is(IsNull.notNullValue()));
    } catch (Exception exception) {
      ex = exception;
    }
 
    assertTrue(null == ex);
  }
 
 
}
 
cs


설정이 간단하다. 

나중에 이용해 먹어야지


자세한 소스코드는 여기 참조

https://github.com/weduls/spring_elastic

+ Recent posts