728x90

오피셜 프로젝트 : https://github.com/SpringForAll/spring-boot-starter-swagger 라고 하네

 

일단 관련 Library 부터 추가해 보자, 22년 12월 21일 기준으로 아직도 해당 버전이 제일 인기가 많은것 같다.

<!-- https://mvnrepository.com/artifact/com.spring4all/swagger-spring-boot-starter -->
<dependency>
    <groupId>com.spring4all</groupId>
    <artifactId>swagger-spring-boot-starter</artifactId>
    <version>1.9.0.RELEASE</version>
</dependency>

application.properties 작성해 보자 

swagger.title=spring-boot-starter-swagger
swagger.description=Starter for swagger 2.x
swagger.version=1.4.0.RELEASE
swagger.license=Apache License, Version 2.0
swagger.licenseUrl=https://www.apache.org/licenses/LICENSE-2.0.html
swagger.termsOfServiceUrl=https://github.com/dyc87112/spring-boot-starter-swagger
swagger.contact.name=blake
swagger.contact.url=https://rainsister.tistory.com
swagger.contact.email=dyc87112@qq.com
swagger.base-package=com.blake
swagger.base-path=/**

혹은 application.yml 사용법은 

swagger:
    base-package: com.http:rainsister
    base-path: /**
    contact:
        email: luxury515@naver.com
        name: blake
        url: https://rainsister.tistory.com
    description: Starter for swagger 2.x
    license: Apache License, Version 2.0
    licenseUrl: https://www.apache.org/licenses/LICENSE-2.0.html
    termsOfServiceUrl: 
    title: spring-boot-starter-swagger
    version: 1.4.0.RELEASE

세팅 완료!

프로젝트를 구동후  http://localhost:8080/swagger-ui.html 에 접속하면

끝!

728x90
User 에 대하여 RESTful API를 만들어본다.
아주 기본적인 User 객체부터 만들어보자.
@Data
public class User {

    private Long id;
    private String name;
    private Integer age;

}
어 ? @Data 저거는 뭐지? 하는 분들을 위해 lombok 이라는 라이브러리를 간단하게 설명드린다.
lombok 은 java에서 객체를 만들때 getter , setter 코드를 컴파일 단계에서 자동으로 만들어주는 라이브러리다. 이놈 없이도 개발 가능하지만 getter, setter 만 만들다가 중도에 포기할수도 있다.
 
사용하고자 하는 library를 추가 ,다들 dependency를 추가한다고 하지.
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>

controller 작성

@RestController
@RequestMapping(value = "/users")
public class UserController {

    static Map<Long, User> users = Collections.synchronizedMap(new HashMap<Long, User>());

    @GetMapping("/")
    public List<User> getUserList() {
    
        List<User> r = new ArrayList<User>(users.values());
        return r;
    }

    @PostMapping("/")
    public String postUser(@RequestBody User user) {
    
        users.put(user.getId(), user);
        return "success";
    }

    @GetMapping("/{id}")
    public User getUser(@PathVariable Long id) {
        
        return users.get(id);
    }


    @PutMapping("/{id}")
    public String putUser(@PathVariable Long id, @RequestBody User user) {
        User u = users.get(id);
        u.setName(user.getName());
        u.setAge(user.getAge());
        users.put(id, u);
        return "success";
    }

    
    @DeleteMapping("/{id}")
    public String deleteUser(@PathVariable Long id) {
        users.remove(id);
        return "success";
    }

}

만들었으니 테스트도 해보자

@RunWith(SpringRunner.class)
@SpringBootTest
public class Chapter21ApplicationTests {

    private MockMvc mvc;

    @Before
    public void setUp() {
        mvc = MockMvcBuilders.standaloneSetup(new UserController()).build();
    }

    @Test
    public void testUserController() throws Exception {
        RequestBuilder request;

        request = get("/users/");
        mvc.perform(request)
                .andExpect(status().isOk())
                .andExpect(content().string(equalTo("[]")));

        request = post("/users/")
                .contentType(MediaType.APPLICATION_JSON)
                .content("{\"id\":1,\"name\":\"테스트 합니다.\",\"age\":20}");
        mvc.perform(request)
                .andExpect(content().string(equalTo("success")));

        request = get("/users/");
        mvc.perform(request)
                .andExpect(status().isOk())
                .andExpect(content().string(equalTo("[{\"id\":1,\"name\":\"테스트 합니다.\",\"age\":20}]")));

        request = put("/users/1")
                .contentType(MediaType.APPLICATION_JSON)
                .content("{\"name\":\"테스트 합니다.\",\"age\":30}");
        mvc.perform(request)
                .andExpect(content().string(equalTo("success")));

        request = get("/users/1");
        mvc.perform(request)
                .andExpect(content().string(equalTo("{\"id\":1,\"name\":\"테스트 합니다.\",\"age\":30}")));

        request = delete("/users/1");
        mvc.perform(request)
                .andExpect(content().string(equalTo("success")));

        request = get("/users/");
        mvc.perform(request)
                .andExpect(status().isOk())
                .andExpect(content().string(equalTo("[]")));

    }

}
MockMvc 를 처음 사용해 보시는 분이라면 일부 함수가 존재 하지 않는다는 메시지가 있을것이다. 상단에 아래 패키지들이 잘 import 되었는지도 살피자!
import static org.hamcrest.Matchers.equalTo;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

끝!

728x90
왜 암호화를 해야 하는지는 따론 찾아보시길 바란다.
그럼 바로 코드로 시작하자.
 
https://github.com/ulisesbocchio/jasypt-spring-boot 라는 오픈소스를 이용하여 설정값들을 암호화 하도록 하자. 요즘 클라우드서버를 많이 사용하지 예를 들으 아마존 클라우드에서 공짜로 제공하는 kms라는 서비스가 있거든 그걸 사용해도 되지만 일단 오늘은 jasypt를 사용해 보도록 하자.
 
설정
datasource.password=blake.com

테스트 코드 작성

@Slf4j
@SpringBootTest
public class PropertiesTest {

    @Value("${datasource.password:}")
    private String password;

    @Test
    public void test() {
        log.info("datasource.password : {}", password);
    }

}

결과!

2022-12-21 14:28:45.506  INFO 70405 --- [           main] com.blake.encypt.PropertiesTest   : datasource.password : blake.com
띠롱 ~ 아직은 암호화가 안됐음!
일단 library 추가해야지.
<dependency>
    <groupId>com.github.ulisesbocchio</groupId>
    <artifactId>jasypt-spring-boot-starter</artifactId>
    <version>3.0.3</version>
</dependency>

application.properties

jasypt.encryptor.password=blakespace

DEC() 로 암화할 대상을 감싼다.

datasource.password=DEC(blakespace.com)

jasypt-maven-plugin 이 DEC()의 내용을 일괄처리한다.

mvn jasypt:encrypt -Djasypt.encryptor.password=blakespace

주의 : -Djasypt.encryptor.password 명령시 properties 내의 설정된 값이랑 일치하게 해야 암호화 실패 안한다.
실행후 로그는 아래와 같다!

datasource.password=ENC(/AL9nJENCYCh9Pfzdf2xLPsqOZ6HwNgQ3AnMybFAMeOM5GphZlOK6PxzozwtCm+Q)

jasypt.encryptor.password=blakespace

암화화 되었으니 이제 복호화를 해볼차례다.

mvn jasypt:decrypt -Djasypt.encryptor.password=blakespace

해당명령은 단순 화면에 출력하는 용도일뿐 실제 파일은 수정하지 않는다.

datasource.password=DEC(blakespace.com)

jasypt.encryptor.password=blakespace

끝!

'Springboot2.x 강좌' 카테고리의 다른 글

Springboot 2.x 가이드북[작성중]  (0) 2022.12.21
728x90
프로젝트 생성시 src/main/resources/application.properties 파일이 생긴다
 
현지점 기준으로 .properties 형식의 파일 보다 .yml 파일을 더 많이 쓴다.
  • properties 파일과 yml 파일을 비교해보자
environments.dev.url=http://dev.bar.com
environments.dev.name=Developer Setup
environments.prod.url=http://foo.bar.com
environments.prod.name=My Cool App
environments:
dev:
url: http://dev.bar.com
name: Developer Setup
prod:
url: http://foo.bar.com
name: My Cool App
  • .yml 의 장점은 단일 파일에 다중설정 이 가능하다
server:
port: 8881
---
spring:
profiles: dev
server:
port: 8882
---
spring:
profiles: test
server:
port: 8883
---
spring:
profiles: prod
server:
port: 8883
 
단점은 @PropertySource 사용하여 로딩할수 없다. 하지만 yml 은 메모리에 저장된다. 항상 properties 파일보다 우선순위가 높다.
사용자 지정 매개변수
book.name=SpringCloudInAction
book.author=blaketest

@Value 로 값 불러오기

@Component
public class Book {

@Value("${book.name}")
private String name;
@Value("${book.author}")
private String author;

// getter setter 생략
}
  • PlaceHolder 방식: ${...}
  • SpEL 방식 : SpEL 란 ? Spring Expression Language , #{...}
application.properties 값 참조
book.name=SpringCloud
book.author=blaketest
book.desc=${book.author} is writing《${book.name}》

Random 수를 사용가능

# 랜덤 string
com.blake.blog.value=${random.value}
# 랜덤 int
com.blake.blog.number=${random.int}
# 랜덤 long
com.blake.blog.bignumber=${random.long}
# 10 내
com.blake.blog.test1=${random.int(10)}
# 10-20 사이
com.blake.blog.test2=${random.int[10,20]}
 
Command
java -jar xxx.jar --server.port=8888
처럼 -- 기호를 사용여 application.properties 값을 불러 올수 있다.
properties 파일 멀티 환경 지원
application-{profile}.properties
application-dev.properties:개발
application-test.properties:테스트
application-prod.properties:운영
spring.profiles.active 값에 의하여 어떤 설정파일이 로딩될지 결정된다.
스크립트 작성핼때 고려하면 좋을것 같다.
java -jar xxx.jar --spring.profiles.active=test
java -jar xxx.jar --spring.profiles.active=prod
Spring Boot는 각 속성의 값을 보다 합리적으로 다시 쓸 수 있도록 다음과 같은 특별한 속성 로딩 순서를 사용합니다.

아래 내용들은 높은 우선순으로 나열 한다.

1. 명령줄에 들어오는 매개 변수입니다.
2. SPRING_APPLICATION_JSON의 속성.SPRING_APPLICATION_JSON은 시스템 환경 변수에 JSON 형식으로 구성된 콘텐츠이다.
3. java:comp/env의 JNDI 속성
4. Java의 시스템 속성은 System.getProperties( )를 통해 얻을 수 있음.
5. 운영 체제의 환경 변수
6. random.*을 통해 구성된 임의 속성
7. 현재 응용 프로그램 jar 패키지에 있는 다른 {profile} 환경에 대한 설정 파일. 예를 들어 application-{profile}.properties 또는 YAML 정의 설정 파일.
8. 현재 응용 프로그램 jar 패키지에 있는 {profile} 환경에 대한 설정 파일 내용. 예를 들어 application-{profile}.properties 또는 YAML 정의 설정 파일.
9. 현재 응용 프로그램 jar 패키지 밖에 있는 application.properties와 YAML 설정 내용.
10. 현재 응용 프로그램 jar 패키지에 있는 application.properties와 YAML 설정 내용.
11. @Configuration 주기에 의해 수정된 클래스에서 @PropertySource 주기에 의해 정의된 속성.
12. SpringApplication.setDefaultProperties를 사용하여 정의된 기본 속성 적용
항목 7과 9는 모두 애플리케이션 jar 패키지 외부에서 구성 파일을 읽는 것을 볼 수 있으므로 외부 구성을 구현하는 원리는 여기에서 잘라내어 jar 패키지 내의 구성 내용을 대체하는 외부 구성 파일의 로딩 위치를 지정하는 것.이러한 실현을 통해 우리의 프로젝트 설정들은 깔끔해지고 환경별로 개발에 필요한 설정들을 관리하면 유지하는데 더 효율있고 편리하다.

Springboot 2.x 특징

Spring Boot 2.0에서 구성 속성을 로드할 때 1.x 버전에서와 같이 특수 문자를 제거하는 것 외에도 구성을 모두 소문자로 일치시키고 로드한다.그러므로 아래의 4가지 배치 방식은 모두 동등하다고면 된다다.
application.properties
spring.jpa.databaseplatform=mysql
spring.jpa.database-platform=mysql
spring.jpa.databasePlatform=mysql
spring.JPA.database_platform=mysql
application.yml
spring:
  jpa:
    databaseplatform: mysql
    database-platform: mysql
    databasePlatform: mysql
    database_platform: mysql
- 로 문자를 분리해라! 예시:spring.jpa.database-platform=mysql
List 타입
spring.my-example.url=http://example.com,http://spring.io
spring:
  my-example:
    url:
      - http://example.com
      - http://spring.io
spring:
  my-example:
    url: http://example.com, http://spring.io

주의: Springboot2.0 이후 버전은 배열에 대한 설정은 꼭 연속된 배열이 여야 한다. 아닐시UnboundConfigurationPropertiesException 예외 발생한다.

  • Springboot 1.x 에서는 아래와 같은 방식이 가능했다.
foo[0]=a
# foo[1] 이 없이니 값은 null 이다.
foo[2]=b
  • Map 타입
properties 방식
spring.my-example.foo=bar
spring.my-example.hello=world
yaml 방식
spring:
my-example:
foo: bar
hello: world
spring.my-example.foo=bar
spring.my-example.hello=world
주의 : map key 가 자모가 아닌 또는 - 부호가 포함될때 아래와 같이 [ ] 로 감싼다.
spring:
  my-example:
    '[foo.baz]': bar
환경속성바인딩
일반유형
일반적으로 환경변수 SPRING_JPA_DATABASEPLATFORM=mysql 는 아래와 같이 변경된다.
properties 파일의 내용 spring.jpa.databaseplatform=mysql 과 동일 효과를 가진다.
List 타입 환경설정에서는 [ 와 ] 를 사용할수 없으므로 _ (어더바) 로 대체 한다.
MY_FOO_1_ = my.foo[1]
MY_FOO_1_BAR = my.foo[1].bar
MY_FOO_1_2_ = my.foo[1][2]
그리고 (언더바) 로 끝나는 부분은 _ (언더바) 는 삭제된다. 위 코드에서 1,3번 행은 아래와 같이
MY_FOO_1_ = my.foo[1]
MY_FOO_1_2_ = my.foo[1][2]
# 아래와 같이 _ 가 생략 된다.
MY_FOO_1 = my.foo[1]
MY_FOO_1_2 = my.foo[1][2]

시스템속성 바인딩

  • 일반유형
spring.jpa.databaseplatform=mysql 를 시스템속성은 아래와 같이 설정
-Dspring.jpa.database-platform=mysql
-Dspring.jpa.databasePlatform=mysql
-Dspring.JPA.database_platform=mysql
  • List 유형
 
-Dspring.my-example.url[0]=http://example.com
-Dspring.my-example.url[1]=http://spring.io
-Dspring.jpa.database-platform=mysql
-Dspring.jpa.databasePlatform=mysql
-Dspring.JPA.database_platform=mysql
혹은 , 로 분리 할수도 있다.
-Dspring.my-example.url=http://example.com,http://spring.io
  • 속성읽기
spring.jpa.database-platform 설정 값을 읽으려면
this.environment.containsProperty("spring.jpa.database-platform")
아래 방식으로는 값을 획득할수 없다!!!
this.environment.containsProperty("spring.jpa.databasePlatform")
 
주의 ! @Value 방식으로 값을 불러올때도 위와 같은 문제가 있다. - 로 단어구분을 했는지 살펴보자.
 
 
새로운 바인딩 API
Spring Boot 2.0 부터 지원하는 api는 더욱 편리하게 설정값을 불러올수 있다.
예를 들어 propertes 에 com.blake.foo=bar 값이 있다고 치자.
 

 

@Data
@ConfigurationProperties(prefix = "com.blake")
public class FooProperties {

    private String foo;

}
 
새로운 방법을 살펴보자!
@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        ApplicationContext context = SpringApplication.run(Application.class, args);

        Binder binder = Binder.get(context.getEnvironment());

        // 간단하게 설정값을 바인딩 할수 있다.
        FooProperties foo = binder.bind("com.blake", Bindable.of(FooProperties.class)).get();
        System.out.println(foo.getFoo());
    }
}

 

List 유형
 
com.blake.post[0]=Why Spring Boot
com.blake.post[1]=Why Spring Cloud

com.blake.posts[0].title=Why Spring Boot
com.blake.posts[0].content=It is perfect!
com.blake.posts[1].title=Why Spring Cloud
com.blake.posts[1].content=It is perfect too!
아래와 같이 값을 바인딩 한다.
ApplicationContext context = SpringApplication.run(Application.class, args);

Binder binder = Binder.get(context.getEnvironment());

// List 값 바인딩!
List<String> post = binder.bind("com.blake.post", Bindable.listOf(String.class)).get();
System.out.println(post);

List<PostInfo> posts = binder.bind("com.blake.posts", Bindable.listOf(PostInfo.class)).get();
System.out.println(posts);
 
끝!

+ Recent posts