2018년 4월 27일 금요일

패스트 캠퍼스 JAVA 웹 프로그래밍 마스터 23일차(Spring Boot, HTTP, 배포 설정, Message Converter)

  • 로컬과 배포시 설정
    • 로컬에서는 메모리 DB를 사용하다가 배포시에는 DB설정을 변경 하여야한다.
    • Spring Profile(스프링 자체 기능)
      • 로컬, 개발, 운영 설정을 jar로 다 가지고 다닌다. 어디서든 한번에 환경에 맞게 배포를 할 수 있다.
      • 스프링 말고 다른언어가 있으면 에서는 배포에 대한 설정을 더 해야한다. 
    • 빌드도구 툴
      • 디렉토리별로 설정파일을 만든다. 로컬, 개발, 운영에 한번에 배포하려면 3번에 걸쳐 각각 해야한다.
    • VM option
      • 자바로 실행할때 옵션
      • java VM옵션 Helloworld 프로그램옵션
  • HTTP 데이터 통신
    • 브라우저에서 post로 값을 보낼때 header에 담아서 보낸다.
    • 브라우저에서 body에 JSON,xml등 다양한 형식으로 값을 담아서 보낼수 있다.
    • WEB API에서 DTO같은 객체에 담고 싶을때 Spring mvc 에서 spring message converter를 통해 처리할 수 있다. 요청이 올때와 응답할때 처리 해준다.
    • @RestController를 선언하면 body에 담아서 응답한다.
    • Form에서 submit하면 FormData형태로 값을 보낸다.
  • Spring Boot에서 배포관련 설정
    • Profile설정에 따라 다른 객체를 주입할 수 있다.
    • application.yml 파일에 다음과 같이 기본으로 사용할 profile을 설정할 수 있다.
    • spring:
        profiles:
          active: local
      
      
      my:
        address: 192.168.1.100  <----- 공통설정
      ---
      spring:
        profiles: local
      my:
        address: 127.0.0.1       <---- local
      ---
      spring:
        profiles: real
      my:
        address: 192.168.1.120   <---- real
      
    • 아래와 같이 @Value애노테이션을 이용하여 설정을 읽어왔다.
    • 
      @Controller
      @RequestMapping("/boards")
      public class BoardController {
      
          @Value("${my.address}")
          private String address;
      }
      
    • 실행시에 프로그램 아규먼트를 줌으로써 원하는 profile로 실행할 수 있다.
    • 
      java -jar 스프링부트애플리케이션.jar --spring.profiles.active=real
      
    • Profile설정에 따라 다른 객체를 주입할 수 있다.
    • 
      package examples.boot.simpleboard.service;
      
      public interface MyService {
          public String getName();
      }
      
      
      ckage examples.boot.simpleboard.service.impl;
      
      import examples.boot.simpleboard.service.MyService;
      import org.springframework.context.annotation.Profile;
      import org.springframework.stereotype.Service;
      
      @Service
      @Profile("real")
      public class RealServiceImpl implements MyService {
          @Override
          public String getName() {
              return "real";
          }
      }
      
      
      package examples.boot.simpleboard.service.impl;
      
      import examples.boot.simpleboard.service.MyService;
      import org.springframework.context.annotation.Profile;
      import org.springframework.stereotype.Service;
      
      @Service
      @Profile("local")
      public class MyServiceImpl implements MyService {
          @Override
          public String getName() {
              return "local";
          }
      }
      
      
      @Autowired
      MyService myService;
      
  • Spring boot 2.0
    • @EnableWebMvc 을 선언 안해줘도 된다. 선언 안해주면 기본으로 사용하는 메시지 컨버터를 사용한다.
    • @EnableWebMvc 을 선언하면 메시지 컨버터를 설정 해줘야한다.
    • spring boot는 의존성을 추가하면 자동으로 설정이 된다. 웹 프로그래밍과 관련된 내용들이 자동으로 설정된다. 기본적인 메시지 컨버터들도 자동으로 등록된다.
  • Hibernate
    • 엔티티를 선언하면 Hibernate가 해당 엔티티를 상속하여 프록시 객체를 만들어 오버라이딩 하여 사용한다.
  • Message Converter
    • spring 을 이용해서 메시지 컨버터를 등록하는 방법
      http://www.baeldung.com/spring-httpmessageconverter-rest
    • spring boot에서의 메시지 컨버터 설정
      • java config파일 중 WebMvcConfigurer를 구현하는 클래스에서 다음의 메소드를 오버라이딩한다.
      • converters 에 메시지를 컨버터를 등록하면 됩니다.
      • 
        public void configureMessageConverters(List<HttpMessageConverter<?>> converters)
    • Spring Boot 2.0에서 hibernate 5를 사용하고 엔티티를 반환하면 Exception이 발생한다. 기존의 컨버터가 변환을 못한다.
      • 아래와 같이 컨버터를 생성한다
      • 변환하기 위해 jackson이 제공하는 하이버네이트 모듈을 추가한다. 
      • 이렇게 했을 경우 LocalDateTime이 jsr310형식으로 출력되지 않는다. 
      • jackson이 제공하는 jsr310모듈을 추가한다.
      • 
        // https://stackoverflow.com/questions/28862483/spring-and-jackson-how-to-disable-fail-on-empty-beans-through-responsebody
        // https://github.com/FasterXML/jackson-datatype-hibernate/issues/87
        // https://stackoverflow.com/questions/33727017/configure-jackson-to-omit-lazy-loading-attributes-in-spring-boot
        @Override
        public void configureMessageConverters(List> converters) {
        
         // http://jsonobject.tistory.com/235 iso8601 형식으로 날짜 정보 출력하기
         ObjectMapper mapper = Jackson2ObjectMapperBuilder.json().featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS).modules(new JavaTimeModule()).build();
         mapper.registerModule(new Hibernate5Module());
        
         mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
         MappingJackson2HttpMessageConverter converter =
           new MappingJackson2HttpMessageConverter(mapper);
         converter.setPrettyPrint(true);
        
         converters.add(converter);
        }
        
  • ResponseEntity
    • HttpStatus 상태값 알맞게 사용하기
  • spring boot로 spring mvc 웹 프로그래밍을 하려면 다음의 라이브러리 의존성을 추가하면 됩니다.
  • <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
  • Spring boot JPA 구성
    • Spring boot에서는 자동으로 필터가 추가되어있다.
    • 필터 - Controller - service -Repository
  • 크롬에서 네트워크 이력 남기기
    • 개발자 도구에서 Preserve log를 체크한다
  • 공부해보기
    • error handling
    • spring validation
    • osvi(JPA관련)
    • Scouter(성능 모니터링 툴)
    • Gatling 툴(네트워크 트래픽 공격)
    • OpenEntityManagerInViewFilter(OSIV)
Share:

패스트 캠퍼스 JAVA 웹 프로그래밍 마스터 22일차(Jpa, Thymeleaf)

  • JPA
    • JPQL
      • Criteria Query, Query Dsl 이 있다.
      • @Query 어노테이션을 통해 JPQL을 이용해서 사용할 수 있다.
      • @Param 어노테이션은 org.springframework.data에 포함되어있다.
      • @Query("SELECT COUNT(b) FROM Board b WHERE b.user.name = :name")
        public Long countAllByUserName(@Param("name") String name);
        
    • 페이징 처리
      • 페이지 처리를 위해서는 Pageble 객체를 사용해야 한다. Pageble은 0이 시작이다.
      • 페이징 처리를 위한 메소드는 Page<도메인객체> 반환하도록 한다. Page에는 검색된 결과, 검색된 결과의 견수, 전체 페이지수
      • 페이지 처리를 위한 메소드는 Pageble 타입을 파라미터로 받아야 한다. 사용자가 해당 인터페이스를 구현한 객체를 파라미터로 전달해서 사용해야한다.
      • Pageable pageable = PageRequest.of(....);
        
      •  PageRequest.of 안에는 파라미터(page값(시작이 0이다), 1page에 보여줄 수, 정렬규칙(sort객체))가 들어간다.
  • JAVA API
    • API를 볼때 생성자가 Deprecated 처리 되어있으면 extends 되어있는 목록을 보고 static한 것이 있는지 봐야한다.
  • Thymeleaf 사용법
    • th:if="${not #list.isEmpty(객체명)}" : 제공 하는 메소드를 이용해서 비어있지 않을 경우 tr태그를 사용
    • th:each="board : ${list}" : list에 있는 내용을 하나씩 꺼내서 board에 대입하여 반복한다.
    • <td th:text="${board.id}"></td> : board가 가지고 있는 id프로퍼티의 값을 td태그 안의 text값으로 출력한다. 만약 이름이 kim이 라면 <td>kim</td> 와 같은 결과가 출력된다.
    • <td th:text="${#temporals.format(board.regdate, 'yyyy-MM-dd HH:mm')}"></td> ; regdate는 LocalDatetTime일때 타임 리프가 제공하는 #temporals.format()을 이용해서 적절한 포맷으로 변환할 수 있다.
    • th:classappend : 조건에 따라서 클래스를 추가하 사용한다. 여러 조건을 넣을 경우 th:classappend="(조건) + (조건)" 으로 사용한다.
    • <li th:each=" i : ${numbers.sequence( {pager.startPage}, {pager.endPage)}"></li> :
      (시작번호, 끝번호)를 이용하면 위의 for문처럼 반복할 수 있다.
    • <a th:href="@{/boards(page=${i}, searchStr=${pager.searchStr}, searchType=${pager.searchType})"> : URL주소에서 파라미터를 사용하는 방법
      @{/boards(파라미터명=값, 파라미터명=값, 파라미터명=값)} 형태로 보낸다.
  • 프로그래밍을 잘한다는건?
    • 요구사항 정의(파악,분석?)
      • UI 프로타이핑
        • 기획자
      • 업무전문가
        • 기술에 대한 내용은 적지 않는다.
        • 유스케이스(기능)다이어그램
        • 기능단위로 정리한다.
    • 기능 분배
      • 트렐로 프로그램
        • Comment 에는 깃허브 브런치를 적는다.
        • 기능을 분리하여 적는다.
        • 기간을 지정한다.
        • 라벨을 사용하여 표시한다.
      • 기능을 뽑을때는 크기가 비슷해야한다.
      • 기능단위로 정리하고 0~7, ∞ 카드를 만든다.
        • 몇명의 사람이 모여서 각자 카드를 가진다.
        • 0이 나오면 토의를 해야한다.0은 이미 오픈소스가 있거나 구현되어 있는 기능에 대해 말한다. 
        • ∞를 꺼내면 다른 회사와 협력해야하거나 구현하기 어려운 기능이다.
      • 기능에 대한 개발의 일정을 정하고 분배한다. 일수를 정리한 Todo _> doing -> done 일정목록을 정리한다. 투명하게 관리가 가능하다. (제품 백로그)
        • 일찍 작업을 끝내도 버그가 많을수가 있고 일정보다 늦게 끝나도 꼼꼼하게 하는 사람이 있을 수 있다.
        • 애자일 방법론
    • 설계
      • 설계--(순공학)--> 구현
      • 업무와 아키텍처를 정의해야한다.
      • 클래스 이름은 업무를 알아야 정할수 있다.
      • 설계를 못한다는건 업무에 대해 알지 못한다는 뜻이다
      • Interface, Class, pacakge, method, package 를 정한다.
  • 컨트롤러는 어떻게 구성해야 할까?
    • 댓글만 요청안할 수도 있지만 ajax로 댓글만 요청할수도 있다.(WEB API)
    • 컨트롤러는 관련 URL처리를 하는것이다.
    • URL중심과 REST API를 나눠서 정리한다.
      • URL 중심
        • 게시물 상세보기
        • 게시물 목록보기
        • 회원가입
      • WEB API 중심
        • 댓글 등록
        • 댓글 삭제
    • 메소드 이름을 나열해보고 관련것들을 묶는다.
    • 개발은 설계를 완성해 나가는 과정이다.
  • @OneToMany 에서 fetch 옵션
    • 1: N  관계일때 사용한다.
    • FetchType.EAGER : 엔티티를 조회할때 주 테이블과 관계맺은 테이블을 조회한다.
    • FetchType.LAZY : 실제 엔티티를 사용할때 관계맺은 테이블을 조회한다.
    • FetchType.EAGER 로 다 선언했다면 하나의 테이블을 불렀을때 관련된 테이블을 다 조회하므로 좋지않다.
    • SQL이 어떻게 조회되는지 확인하자.
    • 리스트 형태에서는 FetchType.LAZY을 사용하면 안된다.
Share:

2018년 4월 26일 목요일

Thymeleaf 사용법

1. th:if="${not #list.isEmpty(객체명)}" 

제공 하는 메소드를 이용해서 비어있지 않을 경우 tr태그를 사용

2. th:each="board : ${list}"

list에 있는 내용을 하나씩 꺼내서 board에 대입하여 반복한다.

3. <td th:text="${board.id}"></td> 

board가 가지고 있는 id프로퍼티의 값을 td태그 안의 text값으로 출력한다. 만약 이름이 kim이 라면 <td>kim</td> 와 같은 결과가 출력된다.

4. <td th:text="${#temporals.format(board.regdate, 'yyyy-MM-dd HH:mm')}"></td>

regdate는 LocalDatetTime일때 타임 리프가 제공하는 #temporals.format()을 이용해서 적절한 포맷으로 변환할 수 있다.

5. th:classappend 

조건에 따라서 클래스를 추가하 사용한다. 여러 조건을 넣을 경우 th:classappend="(조건) + (조건)" 으로 사용한다.

6. <li th:each=" i : ${numbers.sequence( {pager.startPage}, {pager.endPage)}"></li> 

(시작번호, 끝번호)를 이용하면 위의 for문처럼 반복할 수 있다.

7. <a th:href="@{/boards(page=${i}, searchStr=${pager.searchStr}, searchType=${pager.searchType})">

 URL주소에서 파라미터를 사용하는 방법
@{/boards(파라미터명=값, 파라미터명=값, 파라미터명=값)} 형태로 보낸다.
Share:

2018년 4월 25일 수요일

[Baekjoon]11052번 붕어빵 판매하기

1. 문제

https://www.acmicpc.net/problem/11052

2. Source

https://github.com/lalwr/algorithm/blob/master/src/Baekjoon/algorihtm_11052.java

3. 풀이

N이 4라고 가정하면
1마리까지 팔렸을때 최대이익에 한번에 3마리를 파는 이익과
2마리까지 팔렸을때 최대이익에 한번에 2마리를 파는 이익과
3마리까지 팔렸을때 최대이익에 한번에 1마리를 파는 이익과
한번에 4마리를 파는 이익을 비교해 저장하면 된다.
dp[i] = dp[i] > dp[i-j]+set[j] ? dp[i] : dp[i-j]+set[j] ( j <= i)
Share:

2018년 4월 24일 화요일

패스트 캠퍼스 JAVA 웹 프로그래밍 마스터 21일차(JPA, Resource, Thymeleaf)

  • Spring Boot Resource
    • Gradle에서 dependencies에 추가한 webjars 파일은 META-INF에 있다.
    • 해당 폴더의 파일을 사용하려면 WebMvcconfigurer 를 구현하고 addResourceHandlers를 구현한다.
  • JPA
    • oneToMany
      • 양방향관계
        • 1 : N -> N을 가진 테이블에 FK가 있다고 생각하면 편하다
        • Many쪽이 주인공이다.
        • 단방향일때는 oneToMany일때 one관계쪽다가 Many쪽의 Join컬럼을 적어준다. 키를 먼저 알지 못하기 때문에 insert, insert, update가 일어난다.
        • 양방향 맵핑일때는 one관계쪽에는 @OneToMany 애노테이션에 mappedBy 옵션(Many쪽에 선언한 필드를 적는다)을 ,Many쪽에 @JoinColumn을 적는다. 키를 알기 때문에 insert, insert가 일어난다. 양방향으로 참조할 수 있도록 헬퍼 메소드를 만들어줘야한다. 성능적으로 단방향으로 구현하는 것보다 나을 수 있다. 서로 참조하지 않으면 무한 루프나 이상한 값이 들어갈 수 있다.
        • @OneToMany에 mappedBy 옵션을 주고 @JoinColumn 컬럼을 주면 @JoinColumn 을 선언한 곳에 FK가 생긴다.
        • 이 방법으로 모든 관계를 구현할 수 있다.
      • 단방향 관계
        • one관계를 가진 엔티티에 @JoinColumn을 선언한다.
    • OneToOne
      • 양방향 관계
        • 객체지향 관점으로는 어느쪽이 주인공(@JoinColumn)이 되든 상관이없다.  @JoinColumn을 추가한곳에 N 관계를 맺게 나중에 변경할 수 있다.
    • ManyToMany(양방향 관계)
      • 테이블 관점에서는 N:N는 존재하지 않는다. N : N은 1:N, N :1 관계로 변경해야한다.
      • @ManyToMany, @JoinTable을 사용한다. 엔티티는 2개이지만 3개의 테이블을 만들어 준다.(이방법은 비추천)
      • 1:N, N:1로 구현하자
  • Thymeleaf layout 
    • ThymeleafAutoConfiguration 클래스의 내용을 보면 해당 라이브러리가 있을 경우에만 Layout을 지정할수 있다. gradle을 예로들면 다음과 같이 추가해야한다. 
    • 
      compile group: 'nz.net.ultraq.thymeleaf', name: 'thymeleaf-layout-dialect', version: '2.3.0' 
      
      @Configuration
      @ConditionalOnClass(name = "nz.net.ultraq.thymeleaf.LayoutDialect")
      protected static class ThymeleafWebLayoutConfiguration {
      
       @Bean
       @ConditionalOnMissingBean
       public LayoutDialect layoutDialect() {
        return new LayoutDialect();
       }
      
      } 
Share:

2018년 4월 23일 월요일

2018년 4월 20일 금요일

Spring Boot 2.0에서 Gradle,Spring Security, JPA, thymeleaf, Hibernate, spring data, Message Converter

Spring Boot 2.0

  • JDk 1.8이상만 지원 
  • Tomcat 8.5 
  • Flyway 5 
  • Hibernate 5.2 
  • Thymeleaf 3

알아야 할 내용

  • 기본적으로 jsp는 지원하지 않는다.
  • Tomcat을 설치할 필요가 없다.
  • tomcat을 설치하고, Spring Boot애플리케이션을 배포할 수도 있다. 이때는 jsp가 사용가능하다.(추천하지않는다.)
  • 실행가능한 jar파일이 만들어진다.(java -jar 파일명.jar) JVM만 있으면 구동된다.
  • 어떤 라이브러리가 있으면 라이브러리에 대한 설정을 자동으로 해준다.
  • H2 dbms에 대한 의존성을 추가하면, Spring boot는 in memory형태로 자동으로 Datasource를 설정한다.
  • @SpringBootApplication 가 있으면 base package 이하로 component를 찾는다. 많을 설정을 자동으로 해주고 있다.
  • Spring Boot는 application.properties 이나 application.yml 파일을 어플리케이션에서 자동으로 읽어서 매핑시켜준다.(Snake YAML 라이브러리를 내장)
  • Spring Boot는 schema.sql, data.sql 파일이 있으면 자동으로 실행시켜준다.
  • Spring Security가 의존성에 추가되어있으면, 자동으로 인증관련 설정이 된다.( 기본 사용자 id : user, Using generated security password: 콘솔에서 확인)
  • Spring Data JPA의 JpaRepository는 인터페이스를 준비하기만 하면, 자동으로 클래스를 만들고 Bean을 생성한다.
  • jar의 표준이 없다. Spring에서 실행가능한 jar를 만들기 위한 새로운 방법을 만들었다.
  • 스프링 부트 플러그인(maven, gradle)을 이용하여 jar로 만들어야 한다.
  • Spring boot에서는 webapp폴더아래에 파일을 작성하지 않는다.
  • 정적인 리소스는 src/main/resources/static 폴더에 넣는다.
  • 타임리프 관련된 템플릿은 src/main/resources/templates 폴더에 넣는다.
  • 관련 라이브러리
    • Spring Data JPA + QueryDSL
    • Spring Security
    • Gradle
    • SPRING INITIALIZR(web, devtools, jpa, mysql, security, Thymeleaf(비동기))
    • H2 Database

Spring boot 2.0

  • @EnableWebMvc 을 선언 안해줘도 된다. 선언 안해주면 기본으로 사용하는 메시지 컨버터를 사용한다.
  • @EnableWebMvc 을 선언하면 메시지 컨버터를 설정 해줘야한다.
  • spring boot는 의존성을 추가하면 자동으로 설정이 된다. 웹 프로그래밍과 관련된 내용들이 자동으로 설정된다. 기본적인 메시지 컨버터들도 자동으로 등록된다.

spring boot에서 spring mvc

  • spring boot로 spring mvc 웹 프로그래밍을 하려면 다음의 라이브러리 의존성을 추가하면 됩니다.
  • <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

Spring boot 에서 암호화

  • 암호화의 종류는 많다. 기본으로는 bcrypt알고리즘을 사용한다.
  • PasswordEncoder가 '{암호화종류}암호화한내용' 으로 저장한다.
  • 
    PasswordEncoder passwordEncoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
    passwordEncoder.encode(user.getPassword());
    

Spring Boot Resource

  • Gradle에서 dependencies에 추가한 webjars 파일은 META-INF에 있다.
  • 해당 폴더의 파일을 사용하려면 WebMvcconfigurer 를 구현하고 addResourceHandlers를 구현한다.

Spring Boot에서 배포관련 설정

  • Profile설정에 따라 다른 객체를 주입할 수 있다.
  • application.yml 파일에 다음과 같이 기본으로 사용할 profile을 설정할 수 있다.
  • spring:
      profiles:
        active: local
    
    
    my:
      address: 192.168.1.100  <----- 공통설정
    ---
    spring:
      profiles: local
    my:
      address: 127.0.0.1       <---- local
    ---
    spring:
      profiles: real
    my:
      address: 192.168.1.120   <---- real
    
  • 아래와 같이 @Value애노테이션을 이용하여 설정을 읽어왔다.
  • 
    @Controller
    @RequestMapping("/boards")
    public class BoardController {
    
        @Value("${my.address}")
        private String address;
    }
    
  • 실행시에 프로그램 아규먼트를 줌으로써 원하는 profile로 실행할 수 있다.
  • 
    java -jar 스프링부트애플리케이션.jar --spring.profiles.active=real
    
  • Profile설정에 따라 다른 객체를 주입할 수 있다.
  • 
    package examples.boot.simpleboard.service;
    
    public interface MyService {
        public String getName();
    }
    
    
    ckage examples.boot.simpleboard.service.impl;
    
    import examples.boot.simpleboard.service.MyService;
    import org.springframework.context.annotation.Profile;
    import org.springframework.stereotype.Service;
    
    @Service
    @Profile("real")
    public class RealServiceImpl implements MyService {
        @Override
        public String getName() {
            return "real";
        }
    }
    
    
    package examples.boot.simpleboard.service.impl;
    
    import examples.boot.simpleboard.service.MyService;
    import org.springframework.context.annotation.Profile;
    import org.springframework.stereotype.Service;
    
    @Service
    @Profile("local")
    public class MyServiceImpl implements MyService {
        @Override
        public String getName() {
            return "local";
        }
    }
    
    
    @Autowired
    MyService myService;

테이블 관련 설정

  • 스프링 부트 애플리케이션이 테이블을 자동으로 생성 삭제 한다.
  • chema.sql에는 테이블 삭제, 생성관련된 sql을 넣는다.
  • data.sql도 애플리케이션이 실행될때마다 자동으로 실행한다.sample data를 넣는다.
  • properties로 설정하면 spring.java.hibernate.ddl-auto=create-drop과 같다.
    • ddl-auto : 테이블 생성 및 삭제여부
    • 
      spring:
        jpa:
          hibernate:
            ddl-auto: create-drop

재구동 없이 실행

  • runtime('org.springframework.boot:spring-boot-devtools')가 있으면 build만 해도 된다. 
  • WAS를 재구동 안해도 된다.

Gradle 명령어로 작업 파일 만들기

  • 실행가능한 jar파일 만들기
    gradle jar
    ---> Build/libs/simpleboard-0.0.1.SNAPSHOT.jar
  • 해당 jar 파일을 실행하기
    cd build/libs/
    jar -jar simpleboard-0.0.1.SNAPSHOT.jar
    종료 : ctrl + c

Spring Security

  • WebSecurityConfigurerAdapter 를 상속받아서 기능을 확장할 수 있다.
  • compile('org.springframework.boot:spring-boot-starter-security')를 추가한다.
  • 모든 경로를 로그인해야만 접근할 수 있다.
  • 기본 사용자가 추가된다. 사용자 id : user, 암호는 부트 애플리케이션이 실행될 때 출력된다.
  • 서블릿 필터는 빈이 아니다. WAS에서 생성해 준다. 
  • 스프링 컨테이너에는 10개이상의 시큐리티 관련 객체를 가지고 있는데 Spring을 개발한사람은 bean으로 관리되기를 원했다. 그래서 스프링 시큐리티가 제공해주는 필터를 넣어 준다. 이 필터는 스프링 관련 필터이기 때문에 시큐리티 관련 객체를 사용할 수 있다.
  • 빈은 컨테이너가 관리하는 것을 말한다.
  • 스프링이 빈으로 관리하는 필터가 있다.
  • FilterChainProxy를 통해 스프링 빈에서 관리하는 필터를 사용한다.
  • Spring Security Filter Chain을 추가 및 교체할 수 있다.
  • Spring에서는 설정해야 할 부분이 많다. boot에서는 간단해진다.
  • org.springframework.boot.autoconfigure.security.StaticResourceLocation 에 css, javascript, images, webjars, FAVICON 의 path가 정해져있다.
  • 로그인을 검사하는 필터가 있다. 
    • 컨트롤러를 만드는게 아니다. 
    • path도 정해줘야한다. 
    • db정보와 검사해주는 객체가 있다.
    • 권한(ROLE)을 부여해준다. 사용자아 권한은 1:N 관계
    • 사용자가 가려고 했던 path로 이동해준다. 
    • 정보가 맞으면 세션을 저장해준다.]
    • 필터에서 로그인 인증후 브라우저에게 path를 리다이렉트 한다.
  • 로그아웃을 검사하는 필터가 있다. 
    • 컨트롤러를 만드는게 아니다
    • 로그아웃후에 이동할 경로가 설정에 있다.
    • 필터에서 로그아웃 처리후 브라우저에게 path를 리다이렉트 한다.

Spring Security 옵션

  • 설정한 순서대로 옵션이 적용된다.
  • AntPathRequestMatcher : Ant관련 path 설정
  • permitAll() : 인증을 안하고 아무나 볼 수 있다.
  • PathRequest.toStaticResources().atCommonLocations()).permitAll() : static 폴더 안에 폴더 기준에 맞게 파일을 넣고 그 폴더들은 인증을 안한다.(Spring boot에서 제공한다.) 
  • .anyRequest().fullyAuthenticated() : 등록한 url 인증이 있어야 접근 가능
  • hasRole : 해당 롤 권한만 접근 할 수 있다.
  • ..antMatchers("/h2-console/**").permitAll().and() .csrf().ignoringAntMatchers("/**") // .ignoringAntMatchers("/h2-console/**") .and().headers().frameOptions().disable() :  H2 DB를 사용할때 설정
  • .and().logout().permitAll() : 로그아웃은 누구나 접근 가능
  • .and().formLogin() : 시큐리티가 제공하는 로그인 폼 사용
  • .and().formLogin().loginPage("/uers/login").usernameParameter("id").passwordParameter("password") : 로그인 페이지를 변경하려고 할때 post방식으로 '/uers/login' 으로 input name을 id, password 로 설정하고 보내야한다.  (get 방식은으로 요청하면 UI페이지로 가고 post방식으로 요청하면 스프링 시큐리티에게 요청된다.)

Spring Security 인증관련 로직 변경

  • Spring boot는 UserDetailsService를 Implement 객체를 이미 가지고 있다.
  • 인증관련 로직을 변경 하려면 UserDetailsService를 Implement 하는 클래스를 만들고.
    @Componet로 등록한다.
  • Principal를 통해 로그인 정보를 출력할 수 있다.
    SecurityContextHolder.getContext().getAuthentication() 를 통해서도 출력할수 있다(Thread local로 구현되어 있고 시큐리티가 SecurityContextHolder에 넣어준다.)
  • JdbcTokenRepositoryImpl 는 remember me 를 해주는 기능이다.

JPA 에서 1:N 관계 설정

  • 패러다임 문제 해결 : OOP(객체 모델l)와 관계형 데이터베이스(관계 모델)는 같은 데이터를 표현하고 다루는 방법이 차이가 나는 문제를 해결
  • users - user_role 테이블 (1 : N)
  • users 테이블에서
  • 
    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER) 
    @JoinColumn(name = "user_id")
    private List UserRole roles;
    
  • JSON으로 반환할때 제거하고 보여준다.
  • 
    @JsonIgnore
    private String password;
    
  • pk로 지정하고 자동으로 값을 증가한다. 자동증가를 사용하지 않으면 key가 있는지 select문을 실행하기 때문에 성능이 느리다.
  • 
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)

JPA 테이블 관계

  • @OneToMany
    • 양방향관계
      • 1 : N -> N을 가진 테이블에 FK가 있다고 생각하면 편하다
      • Many쪽이 주인공이다.
      • 단방향일때는 oneToMany일때 one관계쪽다가 Many쪽의 Join컬럼을 적어준다. 키를 먼저 알지 못하기 때문에 insert, insert, update가 일어난다.
      • 양방향 맵핑일때는 one관계쪽에는 @OneToMany 애노테이션에 mappedBy 옵션(Many쪽에 선언한 필드를 적는다)을 ,Many쪽에 @JoinColumn을 적는다. 키를 알기 때문에 insert, insert가 일어난다. 양방향으로 참조할 수 있도록 헬퍼 메소드를 만들어줘야한다. 성능적으로 단방향으로 구현하는 것보다 나을 수 있다. 서로 참조하지 않으면 무한 루프나 이상한 값이 들어갈 수 있다.
      • @OneToMany에 mappedBy 옵션을 주고 @JoinColumn 컬럼을 주면 @JoinColumn 을 선언한 곳에 FK가 생긴다.
      • 이 방법으로 모든 관계를 구현할 수 있다.
    • 단방향 관계
      • one관계를 가진 엔티티에 @JoinColumn을 선언한다.
  • @OneToOne
    • 양방향 관계
      • 객체지향 관점으로는 어느쪽이 주인공(@JoinColumn)이 되든 상관이없다.  @JoinColumn을 추가한곳에 N 관계를 맺게 나중에 변경할 수 있다.
  • @ManyToMany(양방향 관계)
    • 테이블 관점에서는 N:N는 존재하지 않는다. N : N은 1:N, N :1 관계로 변경해야한다.
    • @ManyToMany, @JoinTable을 사용한다. 엔티티는 2개이지만 3개의 테이블을 만들어 준다.(이방법은 비추천)
    • 1:N, N:1로 구현하자

JPA 사용하기

  • JPQL
    • Criteria Query, Query Dsl이 있다.
    • @Query 어노테이션을 통해 JPQL을 이용해서 사용할 수 있다.
    • @Param 어노테이션은 org.springframework.data에 포함되어있다.
    • @Query("SELECT COUNT(b) FROM Board b WHERE b.user.name = :name")
    • public Long countAllByUserName(@Param("name") String name);
  • 페이징 처리
    • 페이지 처리를 위해서는 Pageble 객체를 사용해야 한다. Pageble은 0이 시작이다.
    • 페이징 처리를 위한 메소드는 Page<도메인객체> 반환하도록 한다. Page에는 검색된 결과, 검색된 결과의 견수, 전체 페이지수
    • 페이지 처리를 위한 메소드는 Pageble 타입을 파라미터로 받아야 한다. 사용자가 해당 인터페이스를 구현한 객체를 파라미터로 전달해서 사용해야한다.
    • Pageable pageable = PageRequest.of(....);
    •  PageRequest.of 안에는 파라미터(page값(시작이 0이다), 1page에 보여줄 수, 정렬규칙(sort객체))가 들어간다.

JPA @OneToMany fetch

  • 1: N  관계일때 사용한다.
  • FetchType.EAGER : 엔티티를 조회할때 주 테이블과 관계맺은 테이블을 조회한다.
  • FetchType.LAZY : 실제 엔티티를 사용할때 관계맺은 테이블을 조회한다.
  • FetchType.EAGER 로 다 선언했다면 하나의 테이블을 불렀을때 관련된 테이블을 다 조회하므로 좋지않다.
  • SQL이 어떻게 조회되는지 확인하자.
  • FetchType.LAZY을 리스트를 가지고 올때는 사용하지 말자

Gradle 명령어로 작업하기

  • 실행가능한 jar파일 만들기
    터미널에서 gradle jar 입력
    ---> Build/libs/simpleboard-0.0.1.SNAPSHOT.jar
  • 해당 jar 파일을 실행하기
    cd build/libs/
    터미널에서 jar -jar simpleboard-0.0.1.SNAPSHOT.jar 입력
    종료 : ctrl + c

Thymeleaf 

  • th:object= "${객체}" : 객체를 셋팅한다
  • th:field= "*{객체의필드명}" : 가져온 객체의 필드를의 값을 가져온다.
  • th:action ="@{path} " : contextpath를 path 앞에 붙여준다.

Thymeleaf layout 

  • ThymeleafAutoConfiguration 클래스의 내용을 보면 해당 라이브러리가 있을 경우에만 Layout을 지정할수 있다. gradle을 예로들면 다음과 같이 추가해야한다. 
  • 
    compile group: 'nz.net.ultraq.thymeleaf', name: 'thymeleaf-layout-dialect', version: '2.3.0' 
    
    @Configuration
    @ConditionalOnClass(name = "nz.net.ultraq.thymeleaf.LayoutDialect")
    protected static class ThymeleafWebLayoutConfiguration {
    
     @Bean
     @ConditionalOnMissingBean
     public LayoutDialect layoutDialect() {
      return new LayoutDialect();
     }
    
    } 

Thymeleaf 사용법

  • th:if="${not #list.isEmpty(객체명)}" : 제공 하는 메소드를 이용해서 비어있지 않을 경우 tr태그를 사용
  • th:each="board : ${list}" : list에 있는 내용을 하나씩 꺼내서 board에 대입하여 반복한다.
  • <td th:text="${board.id}"></td> : board가 가지고 있는 id프로퍼티의 값을 td태그 안의 text값으로 출력한다. 만약 이름이 kim이 라면 <td>kim</td> 와 같은 결과가 출력된다.
  • <td th:text="${#temporals.format(board.regdate, 'yyyy-MM-dd HH:mm')}"></td> ; regdate는 LocalDatetTime일때 타임 리프가 제공하는 #temporals.format()을 이용해서 적절한 포맷으로 변환할 수 있다.
  • th:classappend : 조건에 따라서 클래스를 추가하 사용한다. 여러 조건을 넣을 경우 th:classappend="(조건) + (조건)" 으로 사용한다.
  • <li th:each=" i : ${numbers.sequence( {pager.startPage}, {pager.endPage)}"></li> :
    (시작번호, 끝번호)를 이용하면 위의 for문처럼 반복할 수 있다.
  • <a th:href="@{/boards(page=${i}, searchStr=${pager.searchStr}, searchType=${pager.searchType})"> : URL주소에서 파라미터를 사용하는 방법
    @{/boards(파라미터명=값, 파라미터명=값, 파라미터명=값)} 형태로 보낸다.

Hibernate

  • 엔티티를 선언하면 Hibernate가 해당 엔티티를 상속하여 프록시 객체를 만들어 오버라이딩 하여 사용한다.
  • 두개의 테이블이 관계를 맺고있을때 insert할떄 FK를 제외하고 insert한다음에 FK의 정보를 업데이트한다.
  • 
    Hibernate: insert into users (id, email, name, password, regdate) values (null, ?, ?, ?, ?)
    Hibernate: insert into user_roles (id, role_name) values (null, ?)
    Hibernate: update user_roles set user_id=? where id=?
    

spring data method query

  • 메소드 이름은 find로 시작한다.
    public User findUserByEmail(String email)
    user테이블에서 입력한 이메일에 맞는 조건을 찾는다.( where email = :email)

Message Converter

  • spring 을 이용해서 메시지 컨버터를 등록하는 방법
    http://www.baeldung.com/spring-httpmessageconverter-rest
  • spring boot에서의 메시지 컨버터 설정
    • java config파일 중 WebMvcConfigurer를 구현하는 클래스에서 다음의 메소드를 오버라이딩한다.
    • converters 에 메시지를 컨버터를 등록하면 됩니다.
    • 
      public void configureMessageConverters(List<HttpMessageConverter<?>> converters)
  • Spring Boot 2.0에서 hibernate 5를 사용하고 엔티티를 반환하면 Exception이 발생한다. 기존의 컨버터가 변환을 못한다.
    • 아래와 같이 컨버터를 생성한다
    • 변환하기 위해 jackson이 제공하는 하이버네이트 모듈을 추가한다. 
    • 이렇게 했을 경우 LocalDateTime이 jsr310형식으로 출력되지 않는다. 
    • jackson이 제공하는 jsr310모듈을 추가한다.
    • 
      // https://stackoverflow.com/questions/28862483/spring-and-jackson-how-to-disable-fail-on-empty-beans-through-responsebody
      // https://github.com/FasterXML/jackson-datatype-hibernate/issues/87
      // https://stackoverflow.com/questions/33727017/configure-jackson-to-omit-lazy-loading-attributes-in-spring-boot
      @Override
      public void configureMessageConverters(List> converters) {
      
       // http://jsonobject.tistory.com/235 iso8601 형식으로 날짜 정보 출력하기
       ObjectMapper mapper = Jackson2ObjectMapperBuilder.json().featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS).modules(new JavaTimeModule()).build();
       mapper.registerModule(new Hibernate5Module());
      
       mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
       MappingJackson2HttpMessageConverter converter =
         new MappingJackson2HttpMessageConverter(mapper);
       converter.setPrettyPrint(true);
      
       converters.add(converter);
      }
    Share:

    패스트 캠퍼스 JAVA 웹 프로그래밍 마스터 20일차(Spring Boot, Spring Security)

    • 재구동 없이 실행
      • runtime('org.springframework.boot:spring-boot-devtools')가 있으면 build만 해도 된다. WAS를 재구동 안해도 된다.
    • Gradle 명령어로 작업하기
      • 실행가능한 jar파일 만들기
        gradle jar
        ---> Build/libs/simpleboard-0.0.1.SNAPSHOT.jar
      • 해당 jar 파일을 실행하기
        cd build/libs/
        jar -jar simpleboard-0.0.1.SNAPSHOT.jar
        종료 : ctrl + c
    • Spring boot 설정
      • jar의 표준이 없다. Spring에서 실행가능한 jar를 만들기 위한 새로운 방법을 만들었다.
        스프링 부트 플러그인(maven, gradle)을 이용하여 jar로 만들어야 한다.
      • Spring boot에서는 webapp폴더아래에 파일을 작성하지 않는다.
      • 정적인 리소스는 src/main/resources/static 폴더에 넣는다.
        타임리프 관련된 템플릿은 src/main/resources/templates 폴더에 넣는다.
      • Spring Security를 추가한다. 
        • WebSecurityConfigurerAdapter 를 상속받아서 기능을 확장할 수 있다.
        • compile('org.springframework.boot:spring-boot-starter-security')
        • 모든 경로를 로그인해야만 접근할 수 있다.
        • 기본 사용자가 추가된다. 사용자 id : user, 암호는 부트 애플리케이션이 실행될 때 출력된다.
    • Spring Security
      • 서블릿 필터는 빈이 아니다. WAS에서 생성해 준다. 
      • 스프링 컨테이너에는 10개이상의 시큐리티 관련 객체를 가지고 있는데 Spring을 개발한사람은 bean으로 관리되기를 원했다. 그래서 스프링 시큐리티가 제공해주는 필터를 넣어 준다. 이 필터는 스프링 관련 필터이기 때문에 시큐리티 관련 객체를 사용할 수 있다.
      • 빈은 컨테이너가 관리하는 것을 말한다.
      • 스프링이 빈으로 관리하는 필터가 있다.
      • FilterChainProxy를 통해 스프링 빈에서 관리하는 필터를 사용한다.
      • Spring Security Filter Chain을 추가 및 교체할 수 있다.
      • Spring에서는 설정해야 할 부분이 많다. boot에서는 간단해진다.
      • org.springframework.boot.autoconfigure.security.StaticResourceLocation 에 css, javascript, images, webjars, FAVICON 의 path가 정해져있다.
      • 로그인을 검사하는 필터가 있다. 
        • 컨트롤러를 만드는게 아니다. 
        • path도 정해줘야한다. 
        • db정보와 검사해주는 객체가 있다.
        • 권한(ROLE)을 부여해준다. 사용자아 권한은 1:N 관계
        • 사용자가 가려고 했던 path로 이동해준다. 
        • 정보가 맞으면 세션을 저장해준다.]
        • 필터에서 로그인 인증후 브라우저에게 path를 리다이렉트 한다.
      • 로그아웃을 검사하는 필터가 있다. 
        • 컨트롤러를 만드는게 아니다
        • 로그아웃후에 이동할 경로가 설정에 있다.
        • 필터에서 로그아웃 처리후브라우저에게 path를 리다이렉트 한다.
    • Spring Security 옵션
      • 설정한 순서대로 옵션이 적용된다.
      • AntPathRequestMatcher : Ant관련 path 설정
      • permitAll() : 인증을 안하고 아무나 볼 수 있다.
      • PathRequest.toStaticResources().atCommonLocations()).permitAll() : static 폴더 안에 폴더 기준에 맞게 파일을 넣고 그 폴더들은 인증을 안한다.(Spring boot에서 제공한다.) 
      • .anyRequest().fullyAuthenticated() : 등록한 url 인증이 있어야 접근 가능
      • hasRole : 해당 롤 권한만 접근 할 수 있다.
      • ..antMatchers("/h2-console/**").permitAll().and() .csrf().ignoringAntMatchers("/**") // .ignoringAntMatchers("/h2-console/**") .and().headers().frameOptions().disable() :  H2 DB를 사용할때 설정
      • .and().logout().permitAll() : 로그아웃은 누구나 접근 가능
      • .and().formLogin() : 시큐리티가 제공하는 로그인 폼 사용
      • .and().formLogin().loginPage("/uers/login").usernameParameter("id").passwordParameter("password") : 로그인 페이지를 변경하려고 할때 post방식으로 '/uers/login' 으로 input name을 id, password 로 설정하고 보내야한다.  (get 방식은으로 요청하면 UI페이지로 가고 post방식으로 요청하면 스프링 시큐리티에게 요청된다.)
    • JPA 에서 1:N 관계 설정
      • 패러다임 문제 해결 : OOP(객체 모델l)와 관계형 데이터베이스(관계 모델)는 같은 데이터를 표현하고 다루는 방법이 차이가 나는 문제를 해결
      • users - user_role 테이블 (1 : N)
      • users 테이블에서
        @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER) @JoinColumn(name = "user_id")
        private List<UserRole> roles;
      • JSON으로 반환할때 제거하고 보여준다.
        @JsonIgnore
        private String password;
      • pk로 지정하고 자동으로 값을 증가한다. 자동증가를 사용하지 않으면 key가 있는지 select문을 실행하기 때문에 성능이 느리다.
        @Id
        @GeneratedValue(strategy=GenerationType.IDENTITY)
    • Spring boot 에서 암호화
      • 암호화의 종류는 많다. 기본으로는 bcrypt알고리즘을 사용한다.
      • PasswordEncoder가 '{암호화종류}암호화한내용' 으로 저장한다.
        PasswordEncoder passwordEncoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
        passwordEncoder.encode(user.getPassword());
    • thymeleaf
      • th:object= "${객체}" : 객체를 셋팅한다
      • th:field= "*{객체의필드명}" : 가져온 객체의 필드를의 값을 가져온다.
      • th:action ="@{path} " : contextpath를 path 앞에 붙여준다.
    • Hibernate
      • 두개의 테이블이 관계를 맺고있을때 insert할떄 FK를 제외하고 insert한다음에 FK의 정보를 업데이트한다.
      • Hibernate: insert into users (id, email, name, password, regdate) values (null, ?, ?, ?, ?)
        Hibernate: insert into user_roles (id, role_name) values (null, ?)
        Hibernate: update user_roles set user_id=? where id=?
    • spring data method query
      • 메소드 이름은 find로 시작한다.
        public User findUserByEmail(String email)
        user테이블에서 입력한 이메일에 맞는 조건을 찾는다.( where email = :email)
    • Spring Security 인증관련 로직 변경
      • Spring boot는 UserDetailsService를 Implement 객체를 이미 가지고 있다.
      • 인증관련 로직을 변경 하려면 UserDetailsService를 Implement 하는 클래스를 만들고.
        @Componet로 등록한다.
      • Principal를 통해 로그인 정보를 출력할 수 있다.
        SecurityContextHolder.getContext().getAuthentication() 를 통해서도 출력할수 있다(Thread local로 구현되어 있고 시큐리티가 SecurityContextHolder에 넣어준다.)
      • JdbcTokenRepositoryImpl 는 remember me 를 해주는 기능이다.
    Share:

    패스트 캠퍼스 JAVA 웹 프로그래밍 마스터 19일차(Spring Boot, gradle, jpa, QueryDSL)

    • URL, URI
      • URI는 URL을 포함하고 있다. 
      • URI는 유니크 하다.
    • Web API 디자인 가이드
      • URI는 정보의 자원을 표현해야 한다.
      • 자원에 대한 행위는 HTTP Method로 표현해야 한다.
      • 단어는 단수보다는 복수로표현한다.
      • URI 마지막 문자로 슬래시 구분자(/)를 포함하지 않는다.
      • 하이픈(-)은 URI가독성을 높일때 사용
      • 언더바(_)는 사용하지 않는다.
      • URI경로는 소문자만 사용한다. RFC 3986(URI문법형식)은 URI스키마와 호스트를 제외하고는 대소 문자를 구별한다.
      • 파일 확장자는 URI에 포함시키지 않는다. Accept Header를 사용한다.
      • REST API에서 HATEOAS를 사용하지 않으면 Web API 부른다.
      • 스타일 : 제약조건의 집합을 의미
    • Spring Boot 2.0(JDk 1.8이상만 지원, Hibernate 5.0)
      • 기본적으로 jsp는 지원하지 않는다.
      • Tomcat을 설치할 필요가 없다.
      • tomcat을 설치하고, Spring Boot애플리케이션을 배포할 수도 있다. 이때는 jsp가 사용가능하다.(추천하지않는다.)
      • 실행가능한 jar파일이 만들어진다.(java -jar 파일명.jar) JVM만 있으면 구동된다.
      • 어떤 라이브러리가 있으면 라이브러리에 대한 설정을 자동으로 해준다.
      • H2 dbms에 대한 의존성을 추가하면, Spring boot는 in memory형태로 자동으로 Datasource를 설정한다.
      • @SpringBootApplication 가 있으면 base package 이하로 component를 찾는다. 많을 설정을 자동으로 해주고 있다.
      • Spring Boot는 application.properties 이나 application.yml 파일을 어플리케이션에서 자동으로 읽어서 매핑시켜준다.(Snake YAML 라이브러리를 내장)
      • Spring Boot는 schema.sql, data.sql 파일이 있으면 자동으로 실행시켜준다.
      • Spring Security가 의존성에 추가되어있으면, 자동으로 인증관련 설정이 된다.( 기본 사용자 id : user, Using generated security password: 콘솔에서 확인)
      • Spring Data JPA의 JpaRepository는 인터페이스를 준비하기만 하면, 자동으로 클래스를 만들고 Bean을 생성한다.
      • 프로젝트
        • Spring Data JPA + QueryDSL
        • Spring Security
        • Gradle
        • SPRING INITIALIZR(web, devtools, jpa, mysql, security, Thymeleaf(비동기))
        • H2 Database
    •  ORM JPA
      • ORM이란 객체와 관계형 데이터베이스를 매핑하는 것이다.
      • JPA는 표준 명세이다.
      • 하이버네이트가 먼저 나왔다. 내부적으로는 Hibernate를 구현하고 있다.
      • (객체) - (Table 컬럼 <-> DMBS) 의 관계를 연결해 주는것
      • 영속성을 가진다.
      • 내부적으로 sql을 만든다.
      • JDBC API를 활용한다
      • DMBS에 에 맞춰서 구동된다.
      • JPQL은 SQL과 유사하지만 객체지향 언어이다.
      • JPQL의 오타문제를 해결하기위해 QueryDSL가 나왔다.
      • QueryDSL
        • 정적 타입을 이용해서 SQL과 같은 쿼리를 생성할 수 있도록 해 주는 프레임워크
        • 타입에 안전한 방식으로 HQL 쿼리를 실행하기 위한 목적으로 만들어졌다.
        • Fluent API를 이용하여 쿼리를 생성할 수 있다.
          • IDE의 코드 자동 완성 기능 사용
          • 문법적으로 잘못된 쿼리를 허용하지 않음
          • 도메인 타입과 프로퍼티를 안전하게 참조할 수 있음
          • 도메인 타입의 리팩토링을 더 잘 할 수 있음
        • Maven과 gradle에 QueryDSL 설정이 있으면 Book 엔티티가 있으면 컴파일할때 QBOOK 파일을 만들어 준다. QBOOK클래스 파일을 이용해서 QueryDSL을 사용한다.
      • SQL입력할때 오타문제를 해결하기 위해 JOOQ가 나왔다.
      • 사용하는 이유.
        • 패러다임 불일치 해결
        • SQL 중심적인 개발에서 객체 중심으로 개발
        • 생산성
        • 유지보수
        • 성능
        • 데이터 접근 추상호와 벤더 독립성
        • 표준
    • JPA 실습
      • 클래스는 Serializable를 구현해야 한다.
      • 다음과 같은 애노테이션이 설정되어 있어야 한다.
        • javax.persistence.Entity 애노테이션
        • javax.persistence.Table 애노테이션
          • 엔티티와 연관을 맺는 테이블 정보를 설정한다.
        • javax.persistence.Id
          • table이 라면 primary key로 생각하면 된다.
        • javax.persistence.GenerationType
          • 자동으로 id를 생성하겠다.
          • DBMS마다 id를 생성하는 방법이 다르다.(DMBS따라서 자동으로 지원)
          • ex) Oracle : sequence객체를 사용
        • javax.persistence.GeneratedValue
          • jpa를 사용할 경우 자동으로 생성되는 id를 주는 것이 효율적
      • JpaRepository 인터페이스가 제일 중요하다
      • JpaRepository를 상속
    • Gradle
      • gradle clean
      • gradle build 
      • gradle build -x test
        • build는 수행하는데 test 빼고
      • gradle compileQuerydsl
        • target / java소스폴더 / QUser 클래스 생성
    • Spring boot 테이블 관련 설정
      • 스프링 부트 애플리케이션이 테이블을 자동으로 생성 삭제 한다.
      • chema.sql에는 테이블 삭제, 생성관련된 sql을 넣는다.
      • data.sql도 애플리케이션이 실행될때마다 자동으로 실행한다.sample data를 넣는다.
      • properties로 설정하면 spring.java.hibernate.ddl-auto=create-drop과 같다.
        • ddl-auto : 테이블 생성 및 삭제여부
        
        spring:
          jpa:
            hibernate:
              ddl-auto: create-drop
        
    • @RestController
      • spring 4.0 이전에는 다음의 애노테이션을 붙였다.
        @Controller, @ResponseBody
      • 그냥 @Controller가 붙은 클래스의 메소드가 리턴하는 것은 view 이름이었다. @Controller, @ResponseBody가 붙어있을 경우에는 리턴하는 값이 출력값이다. 
      • 객체를 브라우저에게 알맞게 출력하기 위해서 사용하는 것이 MessageConverter다. 빈으로 여러개가 등록되어있다. Spring boot에서는 기본으로 설정되어 있다. 하지만 맘에안들때가 있으면 사용자가 바꿔야 한다.
    • vaadin 공부해보기
    Share:

    IT관련 약어 정리

    • IOC : Inversion of Control (제어의 역전)
      개발자가 만든 어떤 클래스나 메소드를 다른 프로그램이 대신 실행해주는 것을 제어의 역전
    • DI : Dependency Injection(의존성 주입)
      클래스 사이의 의존 관계를 빈(Bean) 설정 정보를 바탕으로 컨테이너가 자동으로 연결해주는 것
    Share:

    2018년 4월 18일 수요일

    [Baekjoon]9095번 1,2,3더하기

    1. 문제

    https://www.acmicpc.net/problem/9095

    2. Source

    https://github.com/lalwr/algorithm/blob/master/src/Baekjoon/algorihtm_9095.java
    
    
    

    3. 풀이

    값이 1일때 경우의 수 : 1 -> 1개
    값이 2일때 경우의 수 : 1+1, 2 -> 2개
    값이 3일때 경우의 수 : 1+1+1, 2+1, 1+2, 3 -> 4개
    값이 4일때 경우의 수  : 1+1+1+1, 1+1+2, 1+2+1, 2+1+1, 2+2, 1+3, 3+1 -> 7개
    값이 5일때 경우의 수  : 1+1+1+1+1, 1+1+1+2, 1+1+2+1, 1+2+1+1, 2+1+1+1, 2+2+1, 1+2+2, 2+1+2, 3+1+1, 1+3+1, 1+1+3, 3+2, 2+3 -> 13개

    5의 경우의 수를 보면
    5-1 = 4일때 1을 더하는 경우의수
    5-2 = 3일때 2을 더하는 경우의수
    5-3 = 2일때 3을 더하는 경우의수
    를 더한 값인걸 알 수있다.
    값이 N일때 경우의 수는 N = (N-1) + (N-2) + (N-3) 이라는 수식이 나온다.
    Share:

    jekyll 블로그 로컬에서 구동하기


    자킬 블로그 구동

    jekyll serve 

    접속

    프로세스 보기

    ps aux | grep jekyll

    프로세스 종료

    kill -9 PID

    Share:

    docker에서 mysql 설치

    docker 설치

    OS에 맞는 버전을 다운받고 설치한다.
    mac : https://store.docker.com/editions/community/docker-ce-desktop-mac
    윈도우7,10 홈 버전 이하 : https://docs.docker.com/toolbox/toolbox_install_windows/
    윈도우 10 프로 이상 : https://docs.docker.com/docker-for-windows/install/#download-docker-for-windows

    yml파일을 통한 설치

    docker-compose.yml 파일을 만들고 아래와 같이 작성한다.
    version: '3.1'
    services:
      db:
        image: mysql:5.5
        container_name: mysql5.5
        ports:
          - "3306:3306"
        restart: always
        environment:
          - MYSQL_ROOT_PASSWORD=root비밀번호
          - MYSQL_USER=유저아이디
          - MYSQL_PASSWORD=유저패스워드
          - MYSQL_DATABASE=데이터베이스이름
    • image : 설치할데이터베이스:버전
    • container_name : 컨테이너 이름
    • ports : localhost포트:docker container포트 매핑 설정
    • restart : always(어떤 이유로 든 종료 될 경우 서비스 를 항상 다시 시작)
    • environment : 환경 변수

    설정파일 기반으로 설치 

    백그라운드로 설정파일 실행( -d : 백그라운드 옵션)
    
    docker-compose up -d
    

    docker 태그 설정

    docker tag <image>[:tag] <docker hub 사용자명]/<image명>[:tag명]
    
    docker tag mysql:5.5 lalwrj/mysql5.5
    
    두개의 이미지가 이름은 다르나 동일 이미지를 사용하는것을 볼 수 있다.

    docker Hub에 이미지 업로드

    docker login 후 아이디 비밀번호 입력
    
    docker login
    
    docker push <docker hub 사용자명]/<image명>[:tag명]
    
    docker push lalwrj/mysql5.5

    docker Hub에서 이미지 다운로드

    docker login 후 아이디 비밀번호 입력
    
    docker login
    
    docker pull <docker hub 사용자명]/<image명>[:tag명]
    
    docker pull lalwrj/mysql5.5

    도커 이미지 확인

    docker images
    

    mysql bash에 접속하기

    docker exec -i -t mysql5.5 bash

    Window환경에서 docker 이미지에 연결

    docker실행시 보이는 ip로 연결한다.


    Share:

    2018년 4월 17일 화요일

    패스트 캠퍼스 JAVA 웹 프로그래밍 마스터 18일차(Docker, ViewResolver, profile, CTIP, ThreadLocal)

    • 운영
      • 로컬서버
        • 개발자 컴퓨터 - 로컬 DB
      • 개발서버
        • 개발 서버 - 개발 DB
      • 운영서버
        • 운영 서버 - 운영 DB
      • maven profile, spring profile
    • profile 설정
      • Spring, Maven, Gradle 
      • 차이점은??
    • CTIP
      • 지속적인 통합, 지속적인 TEST, 지속적인 Build
      • jenkins를 통해 GitHub에서 소스의 변경여부를 파악하고 테스트,빌드, report생성, error를 파악하고 사용자에게 mail, slack을 통해 통보할수 있으며 개발서버에 결과물(war, jar)파일을 deploy(배치)하며 서버를 재시작을 자동으로 해준다.
    • Docker
      • 개발환경 운영환경 같은 방법으로 관리할 수 있다.
      • 운영체제의 자원을 사용한다.
      • 설정파일만 있으면 어디서든 똑같은 환경으로 구성할 수 있다.
      • 설치 (Docker compose도 포함되어 있다.)
      • docker ps (목록)
      • https://store.docker.com/editions/community/docker-ce-desktop-mac
    • Reference architecture
      • 로드밸런싱
      • 이중화, 확장유연
      • 대용량 서비스면 관계맺어야 할 테이블이 DB가 서로 다른곳에 있을 수 있다. 개발자가 버그에 대해 생각하고 롤백처리 해야한다.
      • 분산 트랜잭션, 2단계 커밋등으로 처리할 수 있다.(서버를 사야한다. 비싸다.)
      • DB와 많은 Connection을 맺고 있으면 문제가 생길수 있다. 그래서 이중화 NUIX(웹서버) ,WAS(REST API SERVER)를 DB와 연결하고 REST API 서버와 통신하게 만든 후  REST API SERVER와 통신을 통해 DB정보를 얻어온다.
    • Connection pool
      • DB와 연결을 미리 연결을 한 상태를 말한다. Datasource를 통해 연결한다.
    • 샤딩(Sharding) 전략
      • 나누기 전략 : DB가 늘어나면 마이그레이션 해야한다.
      • 하나의 DB에서 특정한 카페의 데이터가 많을시에는 다른 카페의 속도가 느려질수 있으니 특정 카페만의 DB를 따로 구성하여 마이그레이션한다.
    • Srping Boot 2.0
    • redis
    • rabbitmq
    • JPA
    • 언어 설정
      • Locale
      • I18N
      • 지역화
      • 하드코딩으로 적지말고 properties를 통해 사용해야 한다. 
    • ThreadLocal
      • static한 객체 한테 thread별로 같은 쓰레드 안에서는 값을 유지해 준다.
      • 파라미터로 넘기지않아도 값을 꺼낼 수 있다. 같은 쓰레드라면
      • static이 아니면 매번 필드가 메모리에 만들어 진다.
      • ThreadLocal을 사용하려면 static으로 사용한다.
    • DispatcherServlet 내부 동작흐름 상세 -요청 선처리 작업
      • 요청 -> Locale 결정(언어설정) -> RequestContextHolder에 요청 저장(ThreadLocal로 구성되어있음) -> FlashMap복원(Redirect) -> 멀티파트 요청(파일관련) -> 아니요 : 핸들러 결과와 실행 / 예 : MultipartResolver가 멀티파트 결졍 -> 핸들러 결과와 실행 
      • RequestContextHolder에는 HttpServletRequest등을 포함하고 있다.
      • MultipartResolver가 작동할 떄 확장된 HttpServletRequest를 사용한다. 기존 HttpServletRequest 는 파일관련 작업을 지원하지 않는다.
    • Redirect FlashMap
      • FlashMap을 통해 값을 읽을 수 있다. 
      • 1번만 사용가능하다. 
      • 새로고침하면 사라진다.
    • ViewResolver
      • View객체에서 제일 중요한것은 render 메소드다.
      • ViewResolver객체에서 제일 중요 한 것은 resolveViewName 메소드다.
      • InternalResourceViewResolver는 내부적으로 JstlView 를 사용하고 forward 해준다.
      • 사용자가 요청한 타입에 따라서 다른 결과를 보여주고 싶을때는 ContentNegotiationManager 를 사용한다.(pdf, json등)
      • @Bean
            public ViewResolver contentNegotiatingViewResolver(ContentNegotiationManager contentNegotiationManager) {
                ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
                resolver.setContentNegotiationManager(contentNegotiationManager);
        
                // Define all possible view resolvers
                List resolvers = new ArrayList();
        
                resolvers.add(new HtmlViewResolver());
                resolvers.add(new JsonViewResolver()); // http://localhost:8080/guestbooks.json
        
                resolver.setViewResolvers(resolvers);
        
                return resolver;
            }
        
            @Bean
            public ContentNegotiationManager contentNegotiationManager(){
                ContentNegotiationManagerFactoryBean contentNegotiationManager = new ContentNegotiationManagerFactoryBean();
                contentNegotiationManager.setFavorPathExtension(true);
                contentNegotiationManager.setIgnoreAcceptHeader(true);
                contentNegotiationManager.setUseJaf(false);
                contentNegotiationManager.setDefaultContentType(MediaType.TEXT_HTML);
                contentNegotiationManager.addMediaType("html", MediaType.TEXT_HTML);
                contentNegotiationManager.addMediaType("json", MediaType.APPLICATION_JSON);
                return contentNegotiationManager.getObject();
            }
        
        
        import org.springframework.web.servlet.View;
        import org.springframework.web.servlet.ViewResolver;
        
        import java.util.Locale;
        
        
        public class JsonViewResolver implements ViewResolver {
            @Override
            public View resolveViewName(String s, Locale locale) throws Exception {
                return new JsonView();
            }
        }
        
        
        import org.springframework.web.servlet.View;
        
        import javax.servlet.http.HttpServletRequest;
        import javax.servlet.http.HttpServletResponse;
        import java.io.PrintWriter;
        import java.util.Map;
        
        public class JsonView implements View{
            @Override
            public String getContentType() {
                return "application/json";
            }
        
            @Override
            public void render(Map map, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
                httpServletResponse.setContentType("application/json");
                PrintWriter out = httpServletResponse.getWriter();
                out.println("{\"name\":\"urstory\"}");
            }
        }
        
        
        import org.springframework.web.servlet.View;
        import org.springframework.web.servlet.ViewResolver;
        
        import java.util.Locale;
        
        
        public class HtmlViewResolver implements ViewResolver {
            @Override
            public View resolveViewName(String s, Locale locale) throws Exception {
                return new HtmlView();
            }
        }
        
        
        import org.springframework.web.servlet.View;
        
        import javax.servlet.http.HttpServletRequest;
        import javax.servlet.http.HttpServletResponse;
        import java.io.PrintWriter;
        import java.util.Map;
        
        public class HtmlView implements View{
            @Override
            public String getContentType() {
                return "text/html";
            }
        
            @Override
            public void render(Map map, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
                httpServletResponse.setContentType("text/html");
                PrintWriter out = httpServletResponse.getWriter();
                out.println("hello!!!");
            }
        }
        
    Share:

    ThreadLocal 개념

    ThreadLocal

    • static한 객체한테 thread별로 같은 쓰레드 안에서는 값을 유지해 준다.
    • 동일한 쓰레드라면 파라미터로 넘기지않아도 값을 꺼낼 수 있다. 
    • ThreadLocal을 사용하려면 static으로 사용한다. static이 아니면 매번 필드가 메모리에 만들어 진다.
    • RequestContextHolder는 내부적으로 ThreadLocal이 구현되어 있다.
    
    public class MyContext{
        public static ThreadLocal threadLocalValue = new ThreadLocal<>();
        public static int value;
    }
    
    
    package examples;
    
    import examples.util.MyContext;
    
    public class Test {
        public static void main(String[] args){
            MyThread myThread1 = new MyThread(100);
            MyThread myThread2 = new MyThread(200);
            myThread1.start();
            myThread2.start();
        }
    }
    
    class MyThread extends Thread{
        int i ;
        public MyThread(int i){
            this.i = i;
        }
        public void run(){
            while(true) {
                MyContext.threadLocalValue.set(i);
    //            MyContext.value = i;
                MyService service = new MyService();
                service.print(i);
                try {
                    Thread.sleep((int)(Math.random() * 1000));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    class MyService{
        public void print(int i){
            int k = MyContext.threadLocalValue.get();
    //        int k = MyContext.value;
            System.out.println(i + " : " + k);
        }
    }
    
    
    Share:

    [Baekjoon]1436번 1로 만들기

    1. 문제

    https://www.acmicpc.net/problem/1463

    2. Source

    https://github.com/lalwr/algorithm/blob/master/src/Baekjoon/algorihtm_1436.java
    
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    
    public class Algorigtm_make1 {
        public static void main(String[] args) throws IOException {
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    
            int N = Integer.parseInt(br.readLine());
            int dp[] = new int[N+1];
            dp[1] = 0;
    
            for(int i=2;i<=N;i++) {
                dp[i] = dp[i-1]+1;
                if(i%2==0) dp[i] = dp[i/2]+1 > dp[i] ? dp[i] : dp[i/2]+1;
                if(i%3==0) dp[i] = dp[i/3]+1 > dp[i] ? dp[i] : dp[i/3]+1;
            }
            System.out.println(dp[N]);
    
        }
    }
    

    3. 풀이

    dp[i] 의 최소 횟수는 dp[i-1] + 1 , dp[i/2] + 1 , dp[i/3] + 1 값을 비교해서 최소 값을 저장하면 된다.
    Share:

    Spring Interceptor

    Interceptor

    • HandlerInterceptorAdapter에서 preHandle을 구현한 메소드가 false를 반환하면 컨트롤러가 실행되지 않는다.
    • 브라우저와 DispatcherServlet와 사이에 처리할 것이 있다면 서블릿 필터를 통해 처리할 수 있다.
    • DispatcherServlet와 Controller 사이에서 처리할것  있다면 handlerinterceptor를 통해 할 수있다.
    • WebMvcConfigurerAdapter를 구현한 곳에 addInterceptors를 오버라이딩 하고 인터셉터 처리를 한 객체를 넣는다.
      
      @EnableWebMvc
      @Configuration
      public class WebConfig extends WebMvcConfigurerAdapter {
      
          @Bean
          LocaleInterceptor localInterceptor() {
               return new LocalInterceptor();
          }
      
          @Override
          public void addInterceptors(InterceptorRegistry registry) {
              registry.addInterceptor(localeInterceptor());
          }
      
      }
    Share:

    패스트 캠퍼스 JAVA 웹 프로그래밍 마스터 17일차(파일업로드, Interceptor)

    • 파일업로드
      • try -with -resource 구문은 close 함수를 자동으로 호출해준다.
      • 고려사항
        • 중복된 파일을 올리면 안된다.
        • 하나의 폴더에 너무 많은 파일이 저장되면 관리하기 어렵다. 년/월/일 폴더를 만들고 uuid 파일이름으로 생성한다.
        • 윈도우는 디렉토리 구분자가 '\' 이고 unix계열은 디렉토리 구분자가 '/' 이다. File.separtor을 통해 이용하여 디렉토리를 구분해야한다.
        • 파일은 한번에 업로드처리 하는것이 아니다. Stream을 통해 올려야 한다. file.getbyets()는 사용금지
      • 초창기에는 http, mail도 txt로 주고받았다.
      • 외부에서는 직접 접근하면 안된다. ex) jsp를 업로드
      • Multipart 를 이용한다.
      • 서블릿
        • HttpServletRequest는 파일업로드를 지원하지 않는다.
        • 사용자가 파싱을 해야한다.
        • 별로의 라이브러리를 사용해야한다.
      • HTML Multipart
        • <form action="/upload" method="post" enctype="multipart/form-data"> 설정을 추가해야한다.
      • 라이브러리
        • commons-io , commons-fileupload 라이브러리를 통해 업로드 할수 있다.(다른 라이브러리도 가능)
      • Spring
        • multipartresolver Bean을 등록 해야한다.
        • @requestparam, multipartfile 을 통해 파일정보를 얻을수 있다.
          ex ) @requestparam("file) multipartfile file
      • Download
        • 읽어들인 파일정보를 브라우저에게 출력한다.
        • 파일정보를 reponse를 이용하여 직접 출력하겠다.
        • header에 Content-Disposition, Content-Transfer-Encoding 속성이 있으면 파일이 다운로드된다. 2개의 속성이 없으면 브라우저에서 파일 및 이미지를 보여준다.
        • @ResponseBody를 붙여주고 HttpServletResponse response를 파라미터로 주입받는다.
    • Interceptor
      • 브라우저와 DispatcherServlet와 사이에 처리할 것이 있다면 서블릿 필터를 통해 처리할 수 있다.
      • DispatcherServlet와 Controller 사이에서 처리할것  있다면 handlerinterceptor통해 할 수있다.
      • WebMvcConfigurerAdapter를 구현한 곳에 addInterceptors를 오버라이딩 하고 인터셉터 처리를 한 객체를 넣는다.
      
      @EnableWebMvc
      @Configuration
      public class WebConfig extends WebMvcConfigurerAdapter {
      
          @Bean
          LocaleInterceptor localInterceptor() {
               return new LocalInterceptor();
          }
      
          @Override
          public void addInterceptors(InterceptorRegistry registry) {
              registry.addInterceptor(localeInterceptor());
          }
      
      }
    Share:

    Spring Fileupload 관련 내용

    파일업로드

    • try -with -resource 구문은 close 함수를 자동으로 호출해준다.
    • 고려사항
      • 중복된 파일을 올리면 안된다.
      • 하나의 폴더에 너무 많은 파일이 저장되면 관리하기 어렵다. 년/월/일 폴더를 만들고 uuid 파일이름으로 생성한다.
      • 윈도우는 디렉토리 구분자가 '\' 이고 unix계열은 디렉토리 구분자가 '/' 이다. File.separtor을 통해 이용하여 디렉토리를 구분해야한다.
      • 파일은 한번에 업로드처리 하는것이 아니다. Stream을 통해 올려야 한다. file.getbyets() 파일을 한번에 읽어서 처리하므로 사용하지 않는다.
    • 초창기에는 http, mail도 txt로 주고받았다.
    • 외부에서는 직접 접근하면 안된다. ex) jsp를 업로드
    • Multipart 를 이용한다.
    • 서블릿
      • HttpServletRequest는 파일업로드를 지원하지 않는다.
      • 사용자가 파싱을 해야한다.
      • 별로의 라이브러리를 사용해야한다.
    • HTML Multipart
      • <form action="/upload" method="post" enctype="multipart/form-data"> 설정을 추가해야한다.
    • 라이브러리
      • commons-io , commons-fileupload 라이브러리를 통해 업로드 할수 있다.(다른 라이브러리도 가능)
    • Spring
      • multipartresolver Bean을 등록 해야한다.
      • @Bean
        public MultipartResolver multipartResolver() {
            CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
            multipartResolver.setMaxUploadSize(10485760); // 1024 * 1024 * 10
            return multipartResolver;
        }

    • @requestparam, multipartfile 을 통해 파일정보를 얻을수 있다.
    • ex ) @requestparam("file) multipartfile file
    • Download읽어들인 파일정보를 브라우저에게 출력한다.
      • 파일정보를 reponse를 이용하여 직접 출력하겠다.
      • header에 Content-Disposition, Content-Transfer-Encoding 속성이 있으면 파일이 다운로드된다. 2개의 속성이 없으면 브라우저에서 파일 및 이미지를 보여준다.
      • @ResponseBody를 붙여주고 HttpServletResponse response를 파라미터로 주입받는다.
    Share:

    2018년 4월 14일 토요일

    JAVA에서 String

    String 관련 개념

    • String 변수명 = 문자 : 형식으로 구현하면 상수풀에서 관리되서 같은 문자면 주소값이 같다.
    • new String(문자) 형식으로 같은 문자를 넣고 구현하면 힙객체에서 관리되서 선언할때마다 주소값이 다르다.
    • 문자열 끼리 더하면 append 함수를 많이 사용하므로 성능에 좋지 않아 StringBuffer 버퍼를 사용해서 구현한다.
    • StringBuffer 동기화를 지원하고 StringBuilder는 동기화를 지원 하지 않는다. 제공하는 메소드는 같다.
    • 문자를열을 더할때 매번 String 인스턴스를 생성하는 방식에서 Jdk 1.5버전 부터는 컴파일단계에서 내부적으로 new StringBuilder()의 append함수를 통해 더한다.
    public class stringTest {
    
        public static void main(String[] args) {
            String str1 = "hello"; //상수풀 영역에 저장
    
            String str2 = "he";
            String str3 = "llo";
    
            String str4 = str2 + str3;
    
            String str5 = "he" + "llo";
    
            String str6 = "he" + "llo" + "hi";
    
            if(str1 == str4){ //변수를 통해 더하면 힙에 생성된다
                System.out.println("str1 == str4");
            }else{
                System.out.println("str1 != str4");
            }
    
            if(str1 == str5){ //문자열로 더하는 방식은 상수풀에서 관리해서 존재하는 것을 사용한다
                System.out.println("str1 == str5");
            }else{
                System.out.println("str1 != str5");
            }
    
            if(str1 == str6){
                System.out.println("str1 == str6");
            }else{
                System.out.println("str1 != str6");
            }
    
            // '+' 연산자를 많이 사용할때는 아래와 같이 StringBuffer를 사용해서 처리한다
            StringBuffer sb = new StringBuffer();
            sb.append("select id from test ");
            sb.append("where name like '%kim%'");
            String sql = sb.toString();
            
        }
    
    }
    
    Share:

    Intellij 에서 개발소스 테스트하는 방법

    Junit Test

    • Service단계 클래스들을 Test할때 DAO 를 호출할면 단위테스트가 아니다. Mock객체를 통해서 Service 클래스만 테스트 해야한다. 
    • 파일을 여러개 선택하고 Run ... with Coverage 를 통해 한번에 Junit 테스트를 할 수 있다.
    • Coverage를 볼수 있고 리포트를 출력할수 있다(리포트 출력파일은 프로젝트 경로에 하지말것)
      Share:

      패스트 캠퍼스 JAVA 웹 프로그래밍 마스터 16일차(String, git flow, Test)

      String 관련 개념

      • String 변수명 = 문자 : 형식으로 구현하면 상수풀에서 관리되서 같은 문자면 주소값이 같다.
      • new String(문자) 형식으로 같은 문자를 넣고 구현하면 힙객체에서 관리되서 선언할때마다 주소값이 다르다.
      • 문자열 끼리 더하면 append 함수를 많이 사용하므로 성능에 좋지 않아 StringBuffer 버퍼를 사용해서 구현한다.
      • StringBuffer 동기화를 지원하고 StringBuilder는 동기화를 지원 하지 않는다. 제공하는 메소드는 같다.
      • 문자를열을 더할때 매번 String 인스턴스를 생성하는 방식에서 Jdk 1.5버전 부터는 컴파일단계에서 내부적으로 new StringBuilder()의 append함수를 통해 더한다.
      public class stringTest {
      
          public static void main(String[] args) {
              String str1 = "hello"; //상수풀 영역에 저장
      
              String str2 = "he";
              String str3 = "llo";
      
              String str4 = str2 + str3;
      
              String str5 = "he" + "llo";
      
              String str6 = "he" + "llo" + "hi";
      
              if(str1 == str4){ //변수를 통해 더하면 힙에 생성된다
                  System.out.println("str1 == str4");
              }else{
                  System.out.println("str1 != str4");
              }
      
              if(str1 == str5){ //문자열로 더하는 방식은 상수풀에서 관리해서 존재하는 것을 사용한다
                  System.out.println("str1 == str5");
              }else{
                  System.out.println("str1 != str5");
              }
      
              if(str1 == str6){
                  System.out.println("str1 == str6");
              }else{
                  System.out.println("str1 != str6");
              }
      
              // '+' 연산자를 많이 사용할때는 아래와 같이 StringBuffer를 사용해서 처리한다
              StringBuffer sb = new StringBuffer();
              sb.append("select id from test ");
              sb.append("where name like '%kim%'");
              String sql = sb.toString();
              
          }
      
      }
      

      Junit Test

      • Service -> DAO 구조일때는 단위테스트가 아니다. Mock객체를 통해 
      • 파일을 여러개 선택하고 Run ... with Coverage 를 클릭한다.
      • Coverage를 볼수 있고 리포트를 출력할수 있다(리포트 출력파일은 프로젝트 경로에 하지말것)

      Git Flow 사용중 최신 소스로 로컬에서 개발하기

      • develop 브랜치에서 자주 fetch를 받자
      • 작업중인 파일이 있으면 git stash에 넣어 놓는다.
      • feature 브랜치를 선택하고 stash에 넣어둔 파일을 가지고온다.
      • 최신소스를 유지하기 위해 feature 브랜치를 선택하고 develop 브랜치에서 오른쪽 버튼을 누르고 merge한다.

      Share:

      2018년 4월 13일 금요일

      GitHub 코드리뷰 방법

      Git Flow

        Git Flow 사용중 최신 소스로 로컬에서 개발하기

        • develop 브랜치에서 자주 fetch를 받자
        • 작업중인 파일이 있으면 git stash에 넣어 놓는다.
        • feature 브랜치를 선택하고 stash에 넣어둔 파일을 가지고온다.
        • 최신소스를 유지하기 위해 feature 브랜치를 선택하고 develop 브랜치에서 오른쪽 버튼을 누르고 merge한다.

        GitHub 코드리뷰 방법

        • Git flow를 사용한다.
        • Feature 브랜치로 로컬에서 Commit를 실행하다가 Push한다. (Merge를 하지 않는다!!!)
        • Pull Request를 눌러서 기본 브랜치를 develop로 선언하고 pull request를 만든다.
        • 댓글 및 의견 수렴후 close pull request를 한다.
        • 코드 Merge 가능한 상태면 Merge pull request 버튼을 누르고 Confirm Merge 를 한다.
        • 깃허브에서 작성한 Feature 브랜치를 제거한다.
        • 로컬에서도 Feature 브랜치를 제거한다.
        • 오픈소스를 Fork를 하면 내 저장소로 복사가 된다.
          • Clone을 받고 수정후 push하고
          • 오픈소스 저장소에 Pull request를 작성하며 내용을 적는다.
        Share:

        패스트 캠퍼스 JAVA 웹 프로그래밍 마스터 15일차(web.xml , HTTP, Junit, Trancation, jdbc, GitHub)

        • Tomcat
          • conf - Web.xml 설정
            • path 가 '/' 이면 모든 요청을 처리한다는 뜻이다.
            • / -> DefaultServlet이 처리 (모든 요청이 이미 예약되어있다. 정적인 파일을 처리하는 로직이 있다.) 
            • x.jsp, x.jspx -> JSPSerlvet이 처리
        • 프로젝트
          • Web.xml 설정
            • path를 '/' 으로 설정하면 설정이 오버라이딩 되어 DispatcherServlet가 모든요청을 처리한다.
              • @Controller, @RestController(@RequestMapping)을 처리
            • 요청이 오면 DispatcherServlet이 요청받은 path를 찾고나서 없으면 Tomcat의 DefaultServlet한테 넘기고 없으면 404에러가 나온다.
            • 동적인 파일은 DispatcherServlet 에서 처리하고 정적인 파일은 DefaultServlet에서 처리한다.
            • DispatcherServlet에서 요청온 path를 찾고 없으면 DefaultServlet을 사용한다는 설정
            • 
              @Configuration
              @EnableWebMvc
              @ComponentScan(basePackages = { "com.test.controller" })
              public class WebMvcContextConfiguration extends WebMvcConfigurerAdapter {
              
                  // default servlet handler를 사용하게 합니다. 
                  @Override
                  public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
                      configurer.enable();
                  }
              }
        • Spring 과 HTTP Protocol
          • 브라우저에서는 get, post만 사용할 수 있다.(@GetMapping, @PostMapping)
            하지만 hidden 태그와 Spring HiddenHttpMethodFilter를 통해 @PutMapping, @DeleteMapping 을 사용할수 있다.
          • GET(@GetMapping)
            • GET 방식은 HTTP 헤더에 값을 담아서 보낸다. 그래서 용량이 제한이 있다.
          • POST(@PostMapping)
            • POST방식은 HTTP body에 담아서 보낸다.
            • 등록할때 사용한다.
          • PUT(@PutMapping)
            • 수정할때 사용한다. HTTP body에 담아서 보낸다.
            • post방식으로 input hidden을 만들고 put 값을 넣은후 요청한다.
            • 
              <form method="post" action="update">
                  name : <input type="text" name="name">
                  <input type="hidden" name="_method" value="put">
                  <input type="submit">
              </form>
              
              
              <filter>
                  <filter-name>httpMethodFilter</filter-name>
                  <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
                </filter>
                <filter-mapping>
                  <filter-name>httpMethodFilter</filter-name>
                  <url-pattern>/*</url-pattern>
                </filter-mapping>
              
          • DELTE(@DeleteMapping)
            • 삭제할때 사용한다. HTTP body에 담아서 보낸다.
            • post방식으로 input hidden을 만들고  delete 값을 넣은후 요청한다.
            • 
              <form method="post" action="delete">
                  name : <input type="text" name="name">
                  <input type="hidden" name="_method" value="put">
                  <input type="submit">
              </form>
              
              
              <filter>
                  <filter-name>httpMethodFilter</filter-name>
                  <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
                </filter>
                <filter-mapping>
                  <filter-name>httpMethodFilter</filter-name>
                  <url-pattern>/*</url-pattern>
                </filter-mapping>

        • GitHub 코드리뷰 방법
          • Feature로 로컬에서 Commit를 실행하다가 Push한다. (Merge를 하지 않는다!!!)
          • Pull Request를 눌러서 기본 브랜치를 develop로 선언하고 pull request를 만든다.
          • 댓글 및 의견 수렴후 close pull request를 한다.
          • 코드 Merge 가능한 상태면 Merge pull request 버튼을 누르고 Confirm Merge 를 한다.
          • 깃허브에서 작성한 Feature 브랜치를 제거한다.
          • 로컬에서도 Feature 브랜치를 제거한다.
          • 오픈소스를 Fork를 하면 내 저장소로 복사가 된다.
            • Clone을 받고 수정후 push하고
            • 오픈소스 저장소에 Pull request를 작성하며 내용을 적는다.
        • Spring Jdbc
          • 아래와 같은 반복적이고 바뀌는 코드로 인하여 Spring Jdbc가 등장하였다.
          • java datasoure방식으로 0건 or 1건 Select 할때
            1. 접속
            2. SQL문 문자열 준비( select ......... where id = ? )
            3. DB에 준비(Prepared Statement)
            4. ?에 값을 설정(바인딩)
            5. SQL실행(ResultSet)
            6. ResultSet의 next() : 1건의 Recod(다수의 컬럼으로 구성)
            7. 1개의 Record에서 컬럼별로 값을 읽는다. getInt(1), getString(2)
        • Junit
          • system out println는 테스트코드에서 쓰지 않는다.
          • @Junit을 선언하고 @Transactional을 선언하면 Rollback이 된다.
          • 테스트 코드는 Given - When - Then 형식으로 작성한다.
        • Trancation
          • @Trancational
          • 트랜잭션 레벨을 알아두자.
          • 읽기만 할때는 @Transactional(readOnly = true) 을 사용
          • 어노테이션이 적용된 메소드 안에서는 트랜잭션 처리된다.
          • transactionManger
            • DataSource에 의존적이다.
            • transactionManger가 AOP를 통해 트랜잭션을 제어한다.
            • AutoCommit이 fasle상태다.
            • transactionManger의 Bean이 등록되어 있고 @Trancational어노테이션이 되어있으면 메소드가 실행될때 트랜잭션이 실행되고 완료후 Commit을 해준다.
            • runtimeException이 발생되면 rollBack 된다.
        • Test
          • Service 단계에서 Mockito을 통해 테스트하자.
          • Service 단계에서 Mockito를 사용하지 않고 테스트 하는 경우는 dao가 완벽한 경우이다.(db도연결해야한다.)
        Share:

        Spring 에서 HTTP Protocol(GET,POST,PUT,DELETE) 사용하기

        Spring 에서 HTTP Protocol 설정

        • 브라우저에서는 get, post만 사용할 수 있다.(@GetMapping, @PostMapping)
          하지만 hidden 태그와 Spring HiddenHttpMethodFilter를 통해 @PutMapping, @DeleteMapping 을 사용할수 있다.
          • GET(@GetMapping)
            • GET 방식은 HTTP 헤더에 값을 담아서 보낸다. 그래서 용량이 제한이 있다.
          • POST(@PostMapping)
            • POST방식은 HTTP body에 담아서 보낸다.
            • 등록할때 사용한다.
          • PUT(@PutMapping)
            • 수정할때 사용한다. HTTP body에 담아서 보낸다.
            • post방식으로 설정에 필터를 추가하고 input hidden을 만들고 put 값을 넣은후 요청한다.
            • 
              <form method="post" action="update">
                  name : <input type="text" name="name">
                  <input type="hidden" name="_method" value="put">
                  <input type="submit">
              </form>
              
              
              <filter>
                  <filter-name>httpMethodFilter</filter-name>
                  <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
                </filter>
                <filter-mapping>
                  <filter-name>httpMethodFilter</filter-name>
                  <url-pattern>/*</url-pattern>
                </filter-mapping>
              
          • DELTE(@DeleteMapping)
            • 삭제할때 사용한다. HTTP body에 담아서 보낸다.
            • post방식으로 설정에 필터를 추가하고 input hidden을 만들고 delete 값을 넣은후 요청한다.
            • 
              <form method="post" action="delete">
                  name : <input type="text" name="name">
                  <input type="hidden" name="_method" value="put">
                  <input type="submit">
              </form>
              
              
              <filter>
                  <filter-name>httpMethodFilter</filter-name>
                  <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
                </filter>
                <filter-mapping>
                  <filter-name>httpMethodFilter</filter-name>
                  <url-pattern>/*</url-pattern>
                </filter-mapping>
        Share:

        2018년 4월 12일 목요일

        Intellij 자주쓰는 단축키 정리

        Editing

        Ctrl + Space : Basic code completion (the name of any class,method or variable)
        Ctrl + Shift + Space : Smart code completion (filters the list of methodsand variables by expected type)
        Ctrl + Shift + Enter:  Complete statement
        Ctrl + P  : 함수호출시 인수 정보 확인 (within method call arguments)
        Ctrl + Q  : 코드에 대한 문서창 팝업
        Shift + F1 : 코드에 대한 문서 인터넷 브라우저로 팝업
        Ctrl + mouse  : 코드를 링크처럼 타고 들어감
        Ctrl + F1 : Show descriptions of error or warning at caret
        Alt + Insert  : 코드 생성 (Getters, Setters, Constructors,hashCode/equals, toString)
        Ctrl + O  : 메서드 오버라이드 구현
        Ctrl + I    : 인터페이스 메서드 구현
        Ctrl + Alt + T  : 다음으로 코드 감싸기… (if..else, try..catch, for,synchronized, etc.)
        Ctrl + / : 줄 단위 주석 토글
        Ctrl + Shift + /  : 블럭 단위 주석 토글
        Ctrl + W : 가장 안쪽의 괄호부터 선택(점점 확장 된다.)
        Ctrl + Shift + W : Decrease current selection to previous state
        Alt + Q : Context info
        Alt + Enter : Show intention actions and quick-fixes
        Ctrl + Alt + L  : 파일 단위 재정렬 (이클립스의 ctrl + shift + f)
        Ctrl + Alt + O : import 문 최적화
        Ctrl + Alt + I  : 줄단위 재정렬
        Tab / Shift + Tab  : 들여쓰기/내어쓰기
        Ctrl + X or Shift + Delete : 잘라내기 (블럭 선택이 안되어 있으면 라인을 잘라냄)
        Ctrl + C or Ctrl + Insert : 복사하기(블럭 선택이 안되어 있으면 라인을 복사함)
        Ctrl + V or Shift + Insert : 붙여넣기
        Ctrl + Shift + V : 복사하기 (목록에서 선택하여)
        Ctrl + D : 선택된 블럭을 복제
        Ctrl + Y : 캐럿을 있는 곳의 라인 삭제
        Ctrl + Shift + J : 스마트하게 코드를 한 줄로 합친다.
        Ctrl + Enter : 스마트하게 코드를 여러줄로 나눈다.
        Shift + Enter : 커서가 어디에 있건 다음 라인을 생성하고 첫줄로 이동
        Ctrl + Shift + U : 커서가 있는 곳이나 블럭이 있는 곳을 대문자 및 소문자로 치화
        Ctrl + Shift + ] / [  : 가장 가까운 괄호 시작/종료로 이동
        Ctrl + Delete : 단어 삭제 (커서 시작부터)
        Ctrl + Backspace : Delete to word start
        Ctrl + NumPad+/- : Expand/collapse code block
        Ctrl + Shift + NumPad+ : Expand all
        Ctrl + Shift + NumPad- : Collapse all
        Ctrl + F4 : Close active editor tab

        Double Shift Search everywhere

        Ctrl + F : Find
        F3 : Find next
        Shift + F3 : Find previous
        Ctrl + R : Replace
        Ctrl + Shift + F : Find in path
        Ctrl + Shift + R : Replace in path
        Ctrl + Shift + S : Search structurally (Ultimate Edition only)
        Ctrl + Shift + M : Replace structurally (Ultimate Edition only)

        Usage Search

        Alt + F7 / Ctrl + F7 : Find usages , Find usages in file
        Ctrl + Shift + F7 : Highlight usages in file
        Ctrl + Alt + F7 : Show usages

        Compile and Run

        Ctrl + F9 : Make project (compile modifed and dependent)
        Ctrl + Shift + F9 : Compile selected file, package or module
        Alt + Shift + F10 : Select configuration and run
        Alt + Shift + F9 : Select configuration and debug
        Shift + F10 : Run
        Shift + F9 : Debug
        Ctrl + Shift + F10 : Run context configuration from editor

        Debugging

        F8 : Step over
        F7 : Step into
        Shift + F7 : Smart step into
        Shift + F8 : Step out
        Alt + F9 : Run to cursor
        Alt + F8 : Evaluate expression
        F9 : Resume program
        Ctrl + F8 : Toggle breakpoint
        Ctrl + Shift + F8 : View breakpoints

        Navigation

        Ctrl + N : Go to class
        Ctrl + Shift + N : Go to file
        Ctrl + Alt + Shift + N : Go to symbol
        Alt + Right/Left : Go to next/previous editor tab
        F12 : Go back to previous tool window
        Esc : Go to editor (from tool window)
        Shift + Esc : Hide active or last active window
        Ctrl + Shift + F4 : Close active run/messages/find/... tab
        Ctrl + G : Go to line
        Ctrl + E : Recent files popup
        Ctrl + Alt + Left/Right : Navigate back/forward
        Ctrl + Shift + Backspace : Navigate to last edit location
        Alt + F1 : Select current file or symbol in any view
        Ctrl + B or Ctrl + Click : Go to declaration
        Ctrl + Alt + B : Go to implementation(s)
        Ctrl + Shift + I : Open quick definition lookup
        Ctrl + Shift + B : Go to type declaration
        Ctrl + U : Go to super-method/super-class
        Alt + Up/Down : Go to previous/next method
        Ctrl + ] / [ : Move to code block end/start
        Ctrl + F12 File : structure popup
        Ctrl + H Type : hierarchy
        Ctrl + Shift + H : Method hierarchy
        Ctrl + Alt + H : Call hierarchy
        F2 / Shift + F2 : Next/previous highlighted error
        F4 / Ctrl + Enter : Edit source / View source
        Alt + Home : Show navigation bar
        F11 : Toggle bookmark
        Ctrl + F11 : Toggle bookmark with mnemonic
        Ctrl + #[0-9] : Go to numbered bookmark
        Shift + F11 : Show bookmarks

        Refactoring

        F5 : Copy
        F6 : Move
        Alt + Delete : Safe Delete
        Shift + F6 : Rename
        Ctrl + F6 : Change Signature
        Ctrl + Alt + N : Inline
        Ctrl + Alt + M : Extract Method
        Ctrl + Alt + V : Extract Variable
        Ctrl + Alt + F : Extract Field
        Ctrl + Alt + C:  Extract Constant
        Ctrl + Alt + P : Extract Parameter

        VCS/Local History

        Ctrl + K : Commit project to VCS
        Ctrl + T : Update project from VCS
        Alt + Shift + C : View recent changes
        Alt + BackQuote (`) : ‘VCS’ quick popup

        Live Templates

        Ctrl + Alt + J : Surround with Live Template
        Ctrl + J : Insert Live Template
        iter : Iteration according to Java SDK 1.5 style
        inst : Check object type with instanceof and downcast it
        itco : Iterate elements of java.util.Collection
        itit : Iterate elements of java.util.Iterator
        itli : Iterate elements of java.util.List
        psf : public static final
        thr : throw new

        General

        Alt + #[0-9] : Open corresponding tool window
        Ctrl + S : Save all
        Ctrl + Alt + Y : Synchronize
        Ctrl + Shift + F12 : Toggle maximizing editor
        Alt + Shift + F : Add to Favorites
        Alt + Shift + I : Inspect current file with curre?nt profile
        Ctrl + BackQuote (`) : Quick switch current scheme
        Ctrl + Alt + S : Open Settings dialog
        Ctrl + Alt + Shift + S : Open Project Structure dialog
        Ctrl + Shift + A : Find Action
        Ctrl + Tab : Switch between tabs and tool window

        메인메소드 생성 및 실행

        - 디렉토리, 패키지, 클래스 등 생성 목록 보기
        맥 : Command + n
        윈도우 : Alt + Insert

        - 코드 템플릿
        메인 메소드 : psm
        System.out.println() : sout
        if Null 구문 : ifn

        실행환경 실행
        - 현재포커스
        맥 : Command + Shift + R
        윈도우, 리눅스 : Shift + Ctrl + F10
        - 이전실행
        맥 : Ctrl + R
        윈도우 : Shift + F10

        라인 수정하기

        -라인 복사
        맥 : Command + D
        윈도우 : Ctrl + D

        -라인 삭제
        맥 : Command + 백스페이스
        윈도우 : Ctrl + Y

        -라인 합치기(라인단위)
        맥 : Command + Shift + J
        윈도우 : Ctrl + Shift + J

        라인 단위로 옮기기
        - 구문 이동
        맥 : Command + Shift + 위,아래
        윈도우 : Ctrl + Shift + 위,아래
        - 라인 이동
        맥 : Option + Shift + 위,아래
        윈도우 : Alt + Shift + 위,아래

        - Element 단위로 옮기기
        맥 : Option + Shift + Command+ 왼쪽,오른쪽
        윈도우 : Alt + Ctrl + Shift + 왼쪽,오른쪽

        코드 즉시보기

        - 인자값 즉시 보기
        맥 : Command + P
        윈도우 : Ctrl + P

        - 코드 구현부 즉시 보기
        맥 : Option + Space
        윈도우 : Shift + Ctrl + I

        - Doc 즉시 보기
        맥 : F1
        윈도우 : Ctrl + Q

        포커스 에디터

        - 단어별 이동
        맥 : Alt + <, >
        윈도우, 리눅스 : Ctrl + <, >

        - 단어별 선택
        맥 : Shift + Alt + <, >
        윈도우, 리눅스 : Shift + Ctrl + <, >

        - 라인 첫/끝 이동
        맥 : Fn + <, >
        윈도우 : Home, End

        - 라인 전체 선택
        맥 : Shift + Command + <, >
        윈도우, 리눅스 : Shift + Home, End

        - Page Up/Down
        맥 : Fn + 위/아래
        윈도우 : Page Up / Down

        포커스 특수키

        - 포커스 범위 한 단계씩 늘리기
        맥 : Alt + 위/아래 화살표
        윈도우, 리눅스 : Ctrl + W(위) / Shift + Ctrl + W(아래) 

        - 포커스 뒤로/앞으로 가기
        맥 : Command + [ , ]
        윈도우, 리눅스 : Ctrl + Alt + 좌,우

        - 멀티 포커스
        맥 : Alt + Alt + 아래
        윈도우, 리눅스 : Ctrl + Ctrl + 아래

        - 오류 라인 자동 포커스
        맥 : F2
        윈도우, 리눅스 : F2

        검색 텍스트

        - 현재 파일에서 검색
        맥 : Command + F
        윈도우 : Ctrl + F

        - 현재 파일에서 교체
        맥 : Command + R
        윈도우 : Ctrl + R

        - 전체 검색
        맥 : Command + Shift + F
        윈도우 : Ctrl + Shift + F

        - 정규표현식으로 검색, 교체
        맥, 윈도우 : Regex 체크

        검색기타

        - 파일 검색
        맥 : Shift + Command + O
        윈도우 : Shift + Ctrl +  N

        - 메소드 검색
        맥 : Alt + Command + O
        윈도우 : Shift + Ctrl + Alt + N

        - Action 검색
        맥 : Shift + Command + A
        윈도우 : Shift + Ctrl + A

        - 최근 열었던 파일 목록 보기
        맥 : Command + E
        윈도우 : Ctrl + E

        - 최근 수정했던 파일 목록 보기
        맥 : Command + Shift+ E
        윈도우 : Ctrl + Shift + E

        - 변수/필드의 데이터 변경 지점 찾기
        변경되는 포인트 : 변수나 필드에 커서를 놓고 action 에서 "dataflow" 입력 후 "Analyze Dataflow to Here" 선택
        영향주는 포인트 : 변수나 필드에 커서를 놓고 action 에서 "dataflow" 입력 후 "Analyze Dataflow from Here" 선택

        - 중복된 코드 찾기
        action에서 " Locate Duplicate" 입력

        자동완성

        - 스마트 자동완성
        맥 : control + Shift + Space
        윈도우 : control + Shift + Space

        - 스태틱 메소드 자동완성
        맥 : control + Shift * 2
        윈도우 : control + Shift * 2

        - Getter/Setter/생성자 자동완성
        맥 : Command + N
        윈도우 : Alt + Insert

        - 자동완성
        맥 : control + I
        윈도우 : Ctrl + I

        Live Template

        - Live Template 목록 보기
        맥 : Command + J
        윈도우, 리눅스 : Ctrl + J

        - Live Template 메뉴에서 나만의 템플릿 추가 가능

        리팩토링 Extract

        - 변수 추출하기
        맥 : Command + Option + V
        윈도우, 리눅스 :  Ctrl + Alt + V

        - 파라미터 추출하기
        맥 : Command + Option + P
        윈도우, 리눅스 : Ctrl + Alt + P

        - 메소드 추출하기
        맥 : Command + Option + M
        윈도우, 리눅스 : Ctrl + Alt + M

        - 이너클래스 추출하기
        맥 : F6
        윈도우, 리눅스 : F6

        리팩토링 기타

        - 이름 일괄 변경 하기
        맥 : Shift + F6
        윈도우, 리눅스 : Shift + F6

        - 메소드 일괄 변경하기
        맥 : Shift + Command + F6
        윈도우, 리눅스 : Shift + Ctrl + F6

        - Import 정리하기
        맥 : control + Option + O
        윈도우, 리눅스 : Ctrl + Alt + O

        - Import 자동 정리하기
        Settings | Editor | General | Auto Import에서 Optimize imports on the fly 선택

        - 코드 자동 정렬하기
        맥 : Command + Option + L
        윈도우, 리눅스 : Ctrl + Alt + L

        디버깅

        - Debug 모드로 실행하기(현재 위치의 메소드)
        맥 : control + Shift + D
        윈도우, 리눅스 : 없음

        - Debug 모드로 실행하기(이전에 실행한 메소드)
        맥 : control + D
        윈도우, 리눅스 : Shift + F9

        - Resume(다음 브레이크 포인트로 이동하기)
        맥 : Command + Option + R
        윈도우, 리눅스 : F9

        - Step Over(현재 브레이크에서 다음 한줄로 이동하기)
        맥 : F8
        윈도우, 리눅스 : F8

        - Step Into(현재 브레이크의 다음 메소드로 이동)
        맥 : F7
        윈도우, 리눅스 : F7

        - Step Out(현재 메소드의 밖으로 이동)
        맥 : Shift + F8
        윈도우, 리눅스 : Shift + F8

        - Evaluate Expression(브레이크된 상태에서 코드 사용하기)
        맥 : Option+ F8
        윈도우, 리눅스 : Alt + F8

        - Watch(브레이크 이후의 코드 변경 확인하기)
        맥 : 없음
        윈도우, 리눅스 : 없음

        Git 기본 기능 사용하기

        - Git View On
        맥 : Command + 9
        윈도우, 리눅스 : Alt + 9

        - Git Option Popup
        맥 : control + V
        윈도우, 리눅스 : Alt + '(Tab 위 버튼)

        - Git History
        맥 : control + V --> 4
        윈도우, 리눅스 : Alt + '(Tab 위 버튼) --> 4

        - Branch
        맥 : control + V --> 7
        윈도우, 리눅스 : Alt + '(Tab 위 버튼) --> 7

        - Commit
        맥 : Command + k
        윈도우, 리눅스 : Ctrl + k

        - Push
        맥 : Command + Shift + k
        윈도우, 리눅스 : Ctrl + Shift + k

        - Pull
        맥 : Command + Shift + A --> git pull
        윈도우, 리눅스 : Ctrl + Shift + A --> git pull

        GitHub 연동하기

        - GitHub 연동하기
        맥 : Command + Shift + A --> Share github
        윈도우, 리눅스 : Command + Shift + A --> Share github

        - GitHub Clone
        메인 화면에서 Check out from Version Control 선택 후 Git 선택

        클래스

        - 클래스 구조 확인
        맥 : command+7
        윈동, : Alt + 7

        플러그인

        - 플러그인 설치
        맥 : Command + Shift + A --> Plugins(Preferences)
        윈도우, 리눅스 : Command + Shift + A --> Plugins(Preferences)

        - Terminal
        맥 : Option+ F12
        윈도우, 리눅스 : Alt + F12

        추천 플러그인
        - .ignore
        - Presentation Assistant : 단축키 노출(윈도우, 맥)
        - BashSupport : .sh 확장자를 가진 Bash Script 작성 기능을 제공
        https://plugins.jetbrains.com/plugin/4230-bashsupport
        - Material Theme UI
        https://plugins.jetbrains.com/plugin/8006-material-theme-ui
        - Free MyBatis plugin : 마이바티스 플러그인
        https://plugins.jetbrains.com/plugin/8321-free-mybatis-plugin
        CodeGlance : 코드 미니맵을 에티터창에 표시
        https://plugins.jetbrains.com/plugin/7275-codeglance
        - Rainbow Brackets : 각종 괄호를 짝에 맞게 무지개색으로 표시
        https://plugins.jetbrains.com/plugin/10080-rainbow-brackets
        - JetBrain 서버에 Intellij 셋팅을 연동
        https://www.jetbrains.com/help/idea/sharing-your-ide-settings.html
        Share: