회사 프로젝트중에 모바일 푸시 서비스 관련 개발을 하다가 우연히 HTTP2 프로토콜에 대해 접하게 되었다.

HTTP2 프로토콜이란.. 결론적으로 HTTP/1.x 방식에 비해 빠르다는 것이다.

정확한 내용은 아래의 URL을 참고하자.

https://developers.google.com/web/fundamentals/performance/http2/?hl=ko

또한 HTTP2 프로토콜은 HTTP/1.x 을 대체하는 것이 아니라, 확장한다는 개념이기 때문에 HTTP2프로토콜로 사용한다고 해서 기존 어플리케이션을 코드를 수정할 필요는 없고 단순히 프로토콜을 사용하기 위한 설정만 해주면 된다.

먼저, HTTP2를 사용하기 위해서는 HTTPS를 설정해야 한다.

때문에, tomcat에서 SSL을 사용하기 위한 개발용 keystore 파일을 생성해보자.(pkcs12 포맷으로 생성)

sts terminal창에서 아래의 명령어를 실행한 후 아래와 같이 패스워드와 기타 정보들을 입력하면 생성이 된다.

keytool -genkey -alias javaboja -storetype PKCS12 -keyalg RSA -keysize 2048 -keystore keystore.p12 -validity 4000

생성한 후에, application.properties에서 ssl 설정과 HTTP2 설정을 하면 끝이다.

<application.properties>

server.ssl.key-store=keystore.p12
server.ssl.key-store-type=PKCS12
server.ssl.key-store-password=
server.ssl.key-alias=javaboja
server.port=443
server.http2.enabled=true

실제 HTTP2프로토콜 사용을 확인하기 위해 test용 controller와 html을 생성하자.

 

<HomeController.java>

package com.javaboja.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class HomeController {

	@GetMapping("/test")
	public String test() {
		return "test";
	}

}

<test.html>

<!DOCTYPE html>
<html>
<head>
<meta charset="EUC-KR">
<title>Insert title here</title>
</head>
<body>
	Hello!!
</body>
</html>

 

프로젝트를 실행한 후 크롬 콘솔창을 보면 Protocol에 h2라고 되어있는데 HTTP2 프로토콜을 사용하고 있다는 것을 의미한다.

- STS 4.2.0

- open jdk 1.8

 

Could not run build action using Gradle distribution 'https://services.gradle.org/distributions/gradle-5.4.1-bin.zip'. 

 

집에서 작업하던 spring boot 프로젝트를 github를 통해 회사 PC에 check out 했더니 위와 같은 에러가 발생하면서, gradle build가 제대로 되지 않았다. 회사에서 원래 사용하던 sts 3.9.3과 open jdk 9 버전을 사용하고 있던 부분 때문에 생긴 문제로 판단이 되었고, gradle 관련 설정을 수정해야 정상적으로 동작할 것 같았다.

 

프로젝트의 설정을 들어가보자.

설정을 들어가면 아래와 같이 화면이 나오는데,

기존 사용하던 툴(sts 3.9.3)로 인해 생성된 C:\Users\carrey\.gradle경로를 sts4.2.0이 동일하게 사용하려다 보니,

기존 버전 것 과의 충돌이 일어나거나, 버전 즉 싱크가 어긋나서 제대로 build되지 않았을 것이라고 판단하여, gradle user home 경로를 새로운 경로로 잡아 주었다.

또한 회사 PC에 있는 sts3.9.3은 jdk 9를 사용하였고, 집 PC에 있는 sts4.2.0은 jdk 8을 사용하였다. 이부분이 또 다르게 적용 될 수 있다고 판단이 되어, java home을 jdk8로 집 PC 환경과 동일하게 맞춰 주었다.

그리고 다시 빌드 하니 정상 적으로 되더라.

 

정말 spring은 셋팅이 너무 힘들다..

 

'spring boot' 카테고리의 다른 글

spring boot에 HTTP2 방식을 적용해보자.  (0) 2019.11.04
lombok을 활용하여 보자  (0) 2019.06.19
sts4, spring boot(jar), gradle, jpa 시작  (0) 2019.06.15

먼저, lombok을 설치하자, 공식사이트를 들어가보면 설치하는 방법에 대해 설명되어 있다. 

https://objectcomputing.com/resources/publications/sett/january-2010-reducing-boilerplate-code-with-project-lombok

 

1. getter, setter 자동 생성

 

@Getter, @Setter : 각 전역변수에 선언해 주면 자동으로 getter, setter 메서드를 생성해 주지 않아도 된다.

public class User {
    @Getter
    @Setter(AccessLevel.PROTECTED)
    private String name;
}

또한 @Setter(AccessLevel.PROTECTED) 접근권한을 제어할 수 있다.(AccessLevel.PUBLIC, AccessLevel.PRIVATE 등등..)
AccessLevel.NONE 설정을 통해 메소드 생성을 제한시킬 수 도 있다. -> 잘 쓸 것 같지는 않음

 

2. NULL 예외처리

 

@NonNull 말 그대로 NonNull이다. 멤버필드에 선언해 주면, 해당 변수 Setter에 null값이 들어 올 때 NullPointException을 발생시킨다.

public class User {

    @NonNull
    private String name;
}

 

3. 현재 객체 정보 출력

 

@ToString -> 객체.toString() 메서드를 대체하는 어노테이션으로 callSuper값을 true로 할 경우 상속받은 클래스의 정보까지 출력되며,
exclude를 통해 제외하고자 하는 변수를 선택할 수 있다. 설정하지 않을 경우 @ToString만 선언하면 된다.

@ToString(callSuper=true,exclude="phoneNumber")
public class User extends Address{

    private String name;
    private String phoneNumber;

    /*
    @override
    public toString(){
        return "Address(super = " + super.toString() +
              ", name = " + name + ")";
    }
    */
}

 

4. 객체 비교

 

@EqualsAndHashCode -> 객체 비교에 사용되는 메소드를 대체하는 어노테이션

 

5. setter+getter+toString+nunNull+equalsAndHashCode 모두 사용할 경우

 

@Data -> 위의 어노테이션을 합체시킨 어노테이션, 그러나 각 어노테이션에서 설정할 수 있는 세분성까지는 제공하지 못한다. 위에 중요 따로 설정해서 사용할 어노테이션을 설정한 후, 추가적으로 사용하는 것을 권장한다.

@Data(staticConstructor="of") 매개 변수의 값을 원하는 메소드 이름(of)으로 설정하면 생성자를 private로 만들어 주고, 주어진 이름의 static factory method (new를 사용하지 않고 객체를 만들 수 있음)를 만들어준다.

@Data(staticConstructor="of")
public class User {

    private String name;
}


public class Addredss {

    static public void main(String []args){
        User.of().getName();
    }
}

 

6. 자동 자원 close

 

@cleanup -> try finally에서 close()를 대신 호출해주는 어노테이션

public class User {

    static public void main(String [] args){
        try {
            @Cleanup ByteArrayOutputStream baos = new ByteArrayOutputStream();
                baos.write(new byte[] {'Y','e','s'});
               System.out.println(baos.toString());
           } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

 

7. 동기화

 

java의 synchronized를 사용하면 객체 레벨에서 락이 걸려 여러가지 문제가 발생할 수 있다.
@Synchronized 어노테이션을 사용하면 가상의 필드 레벨에서 보다 더 안전하게 락을 걸어 준다.

@Synchronized
public class User {
    public void ok(){
        System.out.println("ok");
    }
}

 

8. 불변 객체 클래스

class에 @Value 어노테이션을 선언하면, 불변 객체를 만들 수 있다.

@Value
public class User {
    public String name; //setter 메소드 사용 불가능
}

 

9. 로그를 편하게

 

class에 @Slf4j, @Log 등 해당 어노테이션을 선언하면, log관련 static 메소드를 클래스 별로 선언할 필요가 없다.

@Controller
@Slf4j
public class HomeController {

    @GetMapping(path="/")
    public @responseBody String hello(){
        log.info("hello!!!");
        return "hello!!";
    }
}

 

10. Builder 사용

 

class에 @Builder 어노테이션을 선언하면 생성자 대신에 빌더를 사용할 수 있다.
또한 @Singular 어노테이션을 collection 타입에 선언하게 되면 파라미터를 하나씩 추가할 수 있다.

@Builder
public class User {

      private Long id;
      private String name;
      private String password;

      @Singular
      private List<String> habby;

    @Singular
     private Map<String, String> maps;

    /* Example
        User user = User.builder().id(0)
                                  .name("javaboja")
                                  .password("java123")
                                  .habby("football")
                                  .habby("Mountain climbing")
                                  .maps("abc","abc")
                                  .maps("def","def")
                                  .build();
                                  .
    */
}

 

사실상 업무 시 사용되는 어노테이션은 @Getter, @Setter, @Slf4j 등이 사용되며, 나머지 어노테이션은 가급적이면

사용하지 않는 것을 권장한다.(필자는 @Builder까지 사용할 생각이다.)

spring framework를 계속 사용하다 보니 회의감에 느껴 기존에 미니 프로젝트로 시작하려고 했던

spring boot, security, jpa, mysql(mariadb)를 사용한 웹 개발 프로젝트를 시작하려고 한다.

프로젝트를 시작하기에 앞서, 기본 셋팅을 해보자.

먼저 tool은 sts 4.2.0

java는 open jdk1.8이다.

이번 페이지에서는 security를 제외하고 jpa까지만 진행할 것이다.

자, sts를 실행시킨 후 spring starter project로 프로젝트를 생성해보자.

spring starter project 생성 화면-1

- name : 프로젝트명

- Type : Gradle -> 필자는 3.x버전 선택

- Packaging : 프로젝트 빌드 타입 -> 필자는 jar로 선택

- Java Version : 8

나머지는 선호하는 형식으로 넣어준 후 Next>

boot 버전 및 의존 설정

- Spring Boot Version : spring boot 버전 선택 -> 필자는 2.1.5로 선택하였다.

- Frequently Used : 최근 사용했던 dependencies를 표출해준다.

- Available : 사용할 dependencies 선택

              -> SQL에서 Spring Data JPA 선택

              -> Web에서 Spring Web Starter 선택

Finish를 선택하여 프로젝트 생성을 끝낸다.

다음으로 mariadb와 연결하기 위해 gradle 의존 설정 및 application.properties 설정을 해야한다.

먼저 gradle에 의존을 추가하기 위해 build.gradle을 열어보자.

<build.gradle>

build.gradle

pom.xml에 추가하는 것과 거의 동일하다.

dependencies에 아래의 내용을 추가해주자.

compile group: 'org.mariadb.jdbc', name: 'mariadb-java-client', version: '2.4.1'  
compile group: 'mysql', name: 'mysql-connector-java', version: '8.0.16'

maridb 관련 의존 추가

<application.properties 경로 : src/main/resources/>

application.properties에 datasource 및 jpa 기본 설정 추가

(mariadb 서버 만드는 방법은 추후에 필요하면 게시하도록 하겠다.)

기존 mybatis설정하는 것 처럼 url, driverClassName, username, password를 추가해주고

jpa.hibernate.ddl-auto=create를 추가해 준다.(jpa및 datasource관련 설정은 추후에 추가적으로 설명하겠다.)

기본 설정이 끝났다.

이제 class들을 만들어 보자.

먼저, 패키지와 클래스 구성은 다음과 같이 해보았다.

패키지 및 클래스구성

패키지를 구성하는 과정에서, 한가지 문제점이 있었는데 springboot시 자동 생성되는 application.java이

배치되어 있는 패키지(com.example.demo)를 base-package로 잡고, 나머지 패키지를 생성해야 MVC관련

어노테이션들이 인식이 되었다. @componentScan을 사용하여 base package를 변경하려고 시도했으나,

인식이 되지 않았다. (혹시 방법 알고 있으신 분들으 댓글 부탁 바랍니다.)

<Application.java (BootSecurityJpa1Application.java) 소스코드>

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class BootSecurityJpa1Application {

    public static void main(String[] args) {
        SpringApplication.run(BootSecurityJpa1Application.class, args);
    }

}

-> 기본으로 생성되는 클래스로 현 페이지에서는 아무런 작업을 하지 않았다.

<MainController.java 소스코드>

package com.example.demo.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.example.demo.service.UserService;
import com.example.demo.vo.User;

@Controller    // This means that this class is a Controller
public class MainController {

    @Autowired
    private UserService userService;

    @GetMapping(path="/add") // Map ONLY GET Requests
    public @ResponseBody String addNewUser (@RequestParam String name
            , @RequestParam String email) {
        // @ResponseBody means the returned String is the response, not a view name
        // @RequestParam means it is a parameter from the GET or POST request

        User n = new User();
        n.setName(name);
        n.setEmail(email);
        userService.userInsert(n);
        return "Saved";
    }

    @GetMapping(path="/all")
    public @ResponseBody Iterable<User> getAllUsers() {
        // This returns a JSON or XML with the users
        return userService.userSelect();
    }
}

-> MainController.java의 소스코드 일부는 spring boot 공식사이트에서 발췌한 부분으로
쿼리를 수행하는 userService 객체를 주입받기 위해 @Autowired를 사용했다.
또한 /add는 사용자를 추가하기위함이고, /all은 추가한 사용자를 확인하기 위한 url이다.

<UserRepository.java 소스코드>

package com.example.demo.repository;

import org.springframework.data.repository.CrudRepository;
import com.example.demo.vo.User;


// This will be AUTO IMPLEMENTED by Spring into a Bean called userRepository
// CRUD refers Create, Read, Update, Delete

public interface UserRepository extends CrudRepository<User, Integer> {

}

->하나의 테이블이라고 생각하면 이해가 쉬울 것 같다. CrudRepository 인터페이스를 상속받으며
제네릭 타입중 첫번째는 테이블의 컬럼이 매핑되어있는 클래스(User.java)를 넣고, 두번째는 User테이블의 기본키 타입을 넣는다.

<UserService.java>

package com.example.demo.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.example.demo.repository.UserRepository;
import com.example.demo.vo.User;

@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    public void userInsert(User user) {
        userRepository.save(user);
    }

    public Iterable<User> userSelect() {
        return userRepository.findAll();
    }
}

-> UserService.java는 데이터를 컨트롤러에서 받아 받은 데이터로 쿼리를 수행하여 나온 결과를 다시
컨트롤러에 전달해주는 역할을 한다.
UserRepository 객체를 주입받으며, sava()는 Insert쿼리를 수행하고,
findAll()은 select쿼리를 수행한다.

<User.java 소스코드>

package com.example.demo.vo;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity // This tells Hibernate to make a table out of this class
public class User {
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private Integer id;

    private String name;

    private String email;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }


}

-> User.java는 하나의 테이블을 의미하며 @Entity 어노테이션을 사용하여 테이블임을 명시하고,
테이블에 해당하는 컬럼들을 변수로 지정하여 Getter, Setter를 구현한다.
또한 @Id 어노테이션을 사용하여 기본키임을 id변수에 명시를 하며, @GeneratedValue(strategy=GenerationType.AUTO)
어노테이션을 사용하여 기본키값을 자동으로 증가하도록 설정하였다.'

 

자 이제, 제대로 동작하는지 확인해보자. 

로컬환경에서 실행하기 위해서는 Run As에서 Spring Boot App를 클릭하자.

(기존 spring 프로젝트 수행시 tomcat에 추가할 필요가 없다.)

 

<수행 시 화면>

Spring Boot App 수행 화면

위와 같이 콘솔에 해당 내용들이 출력되었다면, Spring Boot App가 정상적으로 수행된 것이다.

자 이제, 웹 브라우저 또는 HTTP를 호출할 수 있는 tool을 사용하여 사용자를 추가하여 보자.

http://127.0.0.1:8080/add?name=javaboja&email=javaboja@javaboja.com -> 호출!!

사용자 추가

Saved가 출력되었다면, 쿼리가 제대로 수행된 것이다.

이제, 추가된 사용자를 출력하여 보자.

http://127.0.0.1:8080/all -> 호출!!

사용자 조회

추가된 사용자가 제대로 출력되는 것을 확인할 수 있다.

Spring Boot, JPA, Mysql 기본 셋팅이 끝났다.

+ Recent posts