springboot 연습 02

Updated:

SpringBoot (6장 ~ 10장)

파일 업로드
  • 스프링에서 제공하는 인터페이스 : MultipartResolver
  • 구현체는 다음과 같다
    • 아파치의 Common Fileupload를 이용한 CommonMultipartResolver (실습에선 이거 사용)
    • 서블릿 3.0 이상의 API를 이용한 StandardServletMultipartResolver
@SpringBootApplication
  • @SpringBootApplication 은 세 개의 어노테이션으로 구성
어노테이션 설명
@SpringBootConfiguration spring boot 자동화 기능(spring 설정)을 활성화
@ComponentScan 패키지 내 @Configuration, @Repository, @Controller, @Service, @RestController가 붙은 클래스 찾아서 빈으로 등록.
@EnableAutoConfiguration 미리 정의되어 있는 빈들을 가져와서 등록. Spring의 META-INF 파일을 읽어들인다. 즉, 환경 설정에 필요한 자동 설정을 Bean으로 등록해준다.

Bean@ComponentScan@EnableAutoConfiguration에 의해 두 단계로 나눠서 읽힌다.

Spring @Configuration, @Component 차이점
  • @Configuration은 Bean을 생성 할 때 Single Tone으로 한번만 생성하고 @Component는 Bean을 생성 할 때 java에서 new로 생성하듯이 생성한다.

파일 형식 확인

  • 파일의 확장자를 파일 이름에서 가져오는 방식은 위험
  • 확자는 쉽게 바꿀 수 있기 때문에 실제 파일의 형식과 확장자가 다를 수 있고 위변조 확인 불가능
  • 실제 개발은 JDK 1.7 이상에서 지원하는 nio 패키지를 이용하거나 아파치 티카같은 라이브러리 이용

userGeneratedKeys, keyProPerty

<insert id="insertBoard" parameterType="board.board.dto.BoardDto" useGeneratedKeys="true" keyProperty="boardIdx">
  • useGeneratedKeys 속성은 DBMS가 자동생성키 제공할 경우 사용 가능
  • keyProperty는 useGeneratedKeys나 selectKey 하위 엘리먼트에 의해 리턴되는 키를 의미
  • 게시글의 경우 board_idx 컬럼이 PK이면서 자동 생성이 되게끔 했기 때문에 이 컬럼을 사용

  • 즉, DB에 새로운 게시글이 등록되면 파라미터인 BoardDto 클래스의 boardIdx에 새로운 게시글 번호가 저장되어 반환된다.

RESTFULL API

  • REST란 REpresentational State Transfer의 약자로 HTTP 창시자 중 한 사람인 로이 필딩이 소개
  • 기존의 웹 아키텍처가 HTTP의 우수성을 활용하지 못한다고 생각
  • 그 장점을 최대한 활용할 수 있는 아키텍처로 REST를 소개

  • 한마디로 정의하기 힘듬. 아래는 저자의 생각

잘 표현된 HTTP URI로 리소스를 정의하고 HTTP 메소드로 리소스에 대한 행위를 정의한다.

리소스는 JSON, XML과 같은 여러가지 언어로 표현 가능

리소스

  • 리소스는 서비스를 제공하는 시스템의 자원을 의미. URI로 정의
  • 즉, REST API의 URI는 리소스의 자원을 표현해야 한다.
  • 일반적으로 다음과 같은 규칙을 가짐
  1. URI는 명사를 사용

  2. 슬래시(/)로 계층 관계를 나타낸다.

  3. URI의 마지막에는 슬래시를 사용하지 않는다.

  4. URI는 소문자로만 작성한다

  5. 가독성을 위해 하이픈(-)은 사용하나 밑줄(_)은 사용하지 않는다

HTTP 메서드

HTTP 메서드에는 여러가지가 있는데 REST에서는 4개만 사용

HTTP 메서드 의미 역할
POST Create 리소스 생성
GET Read 해당 URI의 리소스 조회
PUT Update 해당 URI의 리소스 수정
DELETE Delete 해당 URI의 리소스 삭제
  • 그외 메서드
HTTP 메서드 역할
HEAD 문서 정보 요청. body 없이 http 헤더만 보냄
OPTION 웹 서버측 제공 메소드에 대한 질의
TRACE 요청 리소스가 수신되는 경로를 보여줌
CONNECT 프록시 서버와 같은 중간 서버 경유. SSL(HTTPS)를 사용하는 웹 사이트 접속하는데 사용
  • HTML에서는 GET, POST만 지원. 스프링은 웹 브라우저에서 사용되는 POST, GET 방식을 이용해서 PUT과 DELETE 방식을 사용할 수 있는 기능을 지원.
  • HiddenHttpMethodFilter가 바로 그것. 스프링부트 2.1.x부터는 자동 등록되어 있음.
<script type="text/javascript">
		$(document).ready(function(){
			/* 여기 */
			var boardIdx = $("#boardIdx").val();
			
			$("#list").on("click", function(){
				/* 여기 */
				location.href = "/board/";
			});
			
			$("#edit").on("click", function(){
				/* 여기 */
				$("#method").val("put");
				
				var frm = $("#frm")[0];
				frm.action = "/board/"+boardIdx;
				frm.submit();
			});
			
			$("#delete").on("click", function(){
				/* 여기 */
				$("#method").val("delete");
				
				var frm = $("#frm")[0];
				frm.action = "/board/"+boardIdx;
				frm.submit();
			});
		});
</script>
  • HiddenHttpMethodFilter는 _method라는 이름의 파라미터가 존재할 경우 그 값을 요청 방식으로 사용 함
  • 즉, _method 값을 PUT으로 보내면 컨트롤러에서 RequestMethod.PUT의 값을 가진 URI가 호출

  • 이건 인터넷에서 찾아보니 GET, POST 방식 이외에는 보안이 취약해서 사용을 권장하지 않는다고 한다.
@PathVariable
  • 메서드의 파라미터가 URI 변수로 사용되는 것을 의미
// 게시글 번호가 URI의 {boardIdx}에 바인드
// 예를 들어 boardIdx가 1인 경우 /board/1이 된다.
@RequestMapping(value="/board/{boardIdx}", method=RequestMethod.GET)
public ModelAndView openBoardDetail(@PathVariable("boardIdx") int boardIdx, ModelMap model) throws Exception{
    ModelAndView mv = new ModelAndView("/board/restBoardDetail");

    BoardDto board = boardService.selectBoardDetail(boardIdx);
    mv.addObject("board", board);

    return mv;
}
@RestController
  • @Controller와 @ResponseBody를 합친 것
  • 해당 API의 응답 결과를 응답 body를 이용해서 보내줌
  • 서버와 클라이언트는 일반적으로 JSON 방식 사용. 그래서 JSON을 사용
GET, POST 사용시 주의점
  • GET은 요청 주소에 파라미터를 같이 보냄
  • POST는 HTTP 패킷의 파라미터를 같이 보냄
  • @RequestBody는 메서드의 파라미터가 반드시 HTTP 패킷의 바디에 담겨있어야 한다는 것을 의미
  • GET은 @RequestParam을 사용

JPA

  • 실제 프로젝트에서는 JPA 의 한 종류인 하이버네이트를 많이 사용

  • 하이버네이트는 스프링과 연동해야하고 새로 문법을 알아야하므로 여기선 스프링 데이터 프로젝트 하위 프로젝트인 스프링 데이터 JPA로 사용
  • 스프링 데이터 JPA는 JPA를 스프링에서 쉽게 사용할 수 있도록 도와주는 프레임워크

JPA란

  • Java Persistence API
  • 자바 객체와 DB 테이블 간의 매핑을 처리하는 ORM 기술의 표준
  • ORM이란 객체와 관계를 설정하는 것
  • 객체란 OOP의 객체를 말함
  • 관계란 개발자들이 사용하는 관계형 DB를 의미
  • 정리하면 OOP의 객체와 DB의 테이블 구조가 비슷해서 이를 맵핑시킨다는 개념(ORM)
  • 이러한 ORM 개념을 구현하기 위한 표준이 JPA
  • JPA는 각 기능의 동작이 어떻게 되어야 한다는 것을 정의한 기술 명세이기 때문에 기술 명세에 따라 실제로 기능을 구현한 구현체가 필요

장점

  1. 개발 편리
  2. DB에 독립적인 개발 가능
  3. 유지 보수 쉬움

단점

  1. 학습이 어려움
  2. DB 기능 사용 못함
  3. OOP 설계가 필요

스프링 데이터 JPA란?

그전에 알아야할 스프링 데이터 구조

  • 스프링 데이터 : SQL & NoSQL 저장소 지원 프로젝트의 묶음을 의미

  • 스프링 데이터 common : 여러 저장소 지원 프로젝트의 공통 기능 제공 (Repository, Bean 등)

  • 스프링 데이터 REST : 저장소의 데이터를 하이퍼 미디어 기반 HTTP 리소스로(REST API)로 제공하는 프로젝트

  • 스프링 데이터 JPA : 스프링데이터 Common 이 제공하는 기능에 JPA 관련 기능 추가

스프링 데이터 JPA란?

  • 하이버네이트는 엔티티메니저 설정하고 장벽이 있다.
  • 하지만 spring date JPA는 repository 인터페이스를 제공
@EntityScan
  • 애플리케이션이 실행될 때 basePackages로 지정된 패키지 하위에서 JPA엔티티(@Entity 설정된 도메인 클래스)를 검색.
  • 여기에 원하는 클래스 등록

스프링 데이터 JPA 리포지터리 인터페이스

  • CrudRepository 인터페이스는 CRUD 기능을 기본적으로 제공
  • PagingAndSortingRepository는 CrudRepository에 페이징, 정렬 기능 추가
CrudRepository 제공 기본 메소드
메서드 설명
< S extends T> save(S entity) 주어진 엔티티를 저장
< S extends T> Iterable< S> saveAll (Iterable< S> entities) 주어진 엔티티 목록을 저장
Option< T> findById(Id id) 주어진 아이디로 식별된 엔티티를 반환
boolean existsById(Id id) 주어진 아이디로 식별된 엔티티가 존재하는지 반환
Iterable< T> findAll() 모든 엔티티를 반환
Iterable< T> findAllById(Iterable< ID> ids 주어진 아이디 목록에 맞는 모든 엔티티 목록을 반환
long count() 사용 가능한 엔티티의 개수를 반환
void deleteById(ID id) 주어진 아이디로 식별된 엔티티를 삭제
void delete(T entity) 주어진 엔티티를 삭제
void deleteAll(Iterable<? extends T> entities) 주어진 엔티티 목록으로 식별된 엔티티를 모두 삭제
void deleteAll 모든 엔티티를 삭제
쿼리 메서드
  • 스프링 데이터 JPA 규칙에 맞게 메서드를 추가하면 메서드 이름으로 쿼리를 생성
  • find … By, read …. By, query … By, count …. By, get …. By로 시작
  • By 뒤쪽은 컬럼이름 (즉, 검색 조건)
  • 예를 들어 BoardEntry의 제목으로 검색하려면 다음과 같이 작성 ex) findByTitle(String title);
  • 그러면 다음과 같은 JPQL문이 실행
select jpaboard0.board_idx as board_id1_0, ... 중략... 
from t_jpa_board jpaboard0_
where jpaboard0.title = ?
  • 두 개 이상의 속성을 조합하려면 And 키워드를 사용하면 된다.
findByTitleAndContents(String title, String contents);
비교연산자 아래 참조

https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.repositories

구글 클라우드 플랫폼에 배포하기

mysql 설치

  • mysql 설치 후 테이블 생성할 때 No database select가 뜬다
  • 뭐 grant하고 권한주라는데 다 꺼지고
  • select database(); 처보면 database 이름이 null란다
  • create database ‘원하는이름’ 명령어 치고 테이블 생성하면 됨

jdk, tomcat 설치

  • 책에서는 jdk, tomcat 다운받아서 GCP에 옮기라는데 이에 대한 설명이 없어서 조금(?) 방황.. ㅅㅂ
  • https://blog.naver.com/PostView.nhn?blogId=poolve&logNo=221780478060&parentCategoryNo=&categoryNo=15&viewDate=&isShowPopularPosts=true&from=search
  • 위에 블로그에서 참조한 영어 버전 유투브를 보면 파일 전송할 수 있는 방법이 잘 설명되어 있다.
  • putty key 생성 프로그램, 파일질라 client 다운 받아서 따라하면 가능
  • 파일질라 업로드시 “전송을 시작하지 못함” 이라는 오류 메시지의 경우 ssh 파일에서 파일의 권한을 주면 됨

젠킨스 설치

  • 책에서 하는대로 안된다
  • https://goddaehee.tistory.com/82 여기 따라하면 잘됨 굿
  • 포트 입력하고 브라우저로 접속 시 안될 경우 인스턴스의 방화벽 설정 잘 보시길. 분명 거부이거나 포트 번호 잘못 쓴 경우가 많음.

스웨거(Swagger)

  • 프로젝트 API 목록을 웹에서 확인 및 테스트 할 수 있게 해주는 라이브러리
@Configuration
@EnableSwagger2
public class SwaggerConfiguration {
	
	@Bean
    public Docket api() {
        return new Docket(DocumentationType.SWAGGER_2)
                .select()
                .apis(RequestHandlerSelectors.basePackage("board"))
            // board 패키지 내에 RequestMapping으로 할당된 모든 URL을 선택합니다.
                .paths(PathSelectors.any())
            // PathSelectors.any("/api/**")와 같이 사용하면 특정 URI를 가진 주소만 선택 가능
                .build();
    }
}

스프링 클라우드 Config

  • 설정파일을 서버나 개발자들에게 효율적으로 배포하고 관리하기 위해 사용
  • 설정정보를 가지는 서버
  • 설정정보를 가지는 서버에서 필요한 정보만 가져오는 클라이언트로 구성

YAML

  • 사람이 쉽게 읽을 수 있는 데이터 표현 형식
  • 계층 구조를 표한하기에 적합
  • 하나의 파일로 여러 개의 설정을 구분
# 프로퍼티스
spring.datasource.hikari.connection-test-query=SELECT 1
spring.datasource.hikari.allow-pool-suspension=true
# YAML
spring:
	datasource:
		hikari:
			connection-test-query: SELECT 1
			allow-pool-suspension=true

비트버킷

  • 책에서 깃 저장소를 위해 github 또는 비트버킷을 사용하라고 한다.
  • 비트버킷으로 책에서 설명해가는데 뜬금없이 레퍼지토리 만들라고 한다.
  • https://bitbucket.org/ 여기 들어가서 가입하고 만들면 된다;; 초보용 책이면 URL이라도 알려주지;;