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는 리소스의 자원을 표현해야 한다.
- 일반적으로 다음과 같은 규칙을 가짐
-
URI는 명사를 사용
-
슬래시(/)로 계층 관계를 나타낸다.
-
URI의 마지막에는 슬래시를 사용하지 않는다.
-
URI는 소문자로만 작성한다
-
가독성을 위해 하이픈(-)은 사용하나 밑줄(_)은 사용하지 않는다
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는 각 기능의 동작이 어떻게 되어야 한다는 것을 정의한 기술 명세이기 때문에 기술 명세에 따라 실제로 기능을 구현한 구현체가 필요
장점
- 개발 편리
- DB에 독립적인 개발 가능
- 유지 보수 쉬움
단점
- 학습이 어려움
- DB 기능 사용 못함
- 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이라도 알려주지;;