2018년 5월 31일 목요일

패스트 캠퍼스 JAVA 웹 프로그래밍 마스터 37일차(RabbitMQ, WebSocket)

RabbitMQ

Queue형식이고 FIFO다.
이벤트 프로그래밍에서 주로 사용된다.

여러가지 방식이 있다.
publis / Subscribe(발행자,구독자) 패턴: 구독하고 있는 사람들에게 모두 발송한다.
topics 패턴 : 패턴에 의해 읽어간다.(한큐에 같은 패턴의 여러 클라이언트가 붙어있을 경우는 먼저 호출한 클라이언트에게만 발송된다.)

WebSocket

어떤 브라우저에서는 WebSocket을 지원 안할수 있다. 그래서 SockJS를 사용한다.
연결 흐름은 HTTP연결후 WebSocket연결을 한다.

크롬 요소검사에서 Network - WS - Frame 메뉴에서 통신하는 메시지를 볼수 있다.
오래동안 사용하지 않으면 연결이 끊길수 있다. 백그라운드에서 특정 주기마다 통신해야한다.

Srping SockJS

afterConnectionEstablished : 현재 연결된 파라미터가 들어온다.(클라이언트 연결 개수만큼 실행)
afterConnectionClosed : 종료될때 사용된다.

로그인 사용자 채팅

웹소켓도 시큐리티가 필요하다.
HttpSessionHandsakeInterceptor()를 통해 WebSocketSession에 로그인 정보를 저장후 사용하는곳에서 session정보를 불러와 사용한다.

Share:

2018년 5월 28일 월요일

패스트 캠퍼스 JAVA 웹 프로그래밍 마스터 35일차(Test, 공부방법)

Controller 테스트

@RunWith(SpringRunner.class)
@WebMvcTest(BoardController.class)
  1. RunWith는 Runner를 구현한 객체를 이용해서 Test를 수행한다.
  2. SpringRunner는 내부적으로 ApplciationContext를 가지고 있고, 해당 Test객체도 Bean으로써 등록된다.
  3. @WebMvcTest : Spring MVC를 테스트를 사용하기 위한 애노테이션이다.
    Controller는 여러개의 Service를 사용한다. Service의 구현과 상관없이 Controller를 테스트해야한다.
    이것이 올바른 Controller의 단위테스트가 된다.
    @WebMvcTest(BoardController.class) : BoardController를 테스트하겠다.
@Autowired
private MockMvc mvc;
@WebMvcTest를 사용하면 MockMvc를 주입받을 수 있다. WAS를 실행하지 않고, Controller를 실행하도록 도와준다.

mvc.perform(get("/boards").with(new RequestPostProcessor() {
    @Override
    public MockHttpServletRequest postProcessRequest(MockHttpServletRequest mockHttpServletRequest) {
        User user = new User();
        user.setId(1L);
        user.setName("홍길동");
        mockHttpServletRequest.setAttribute("loginUser", user);
        return mockHttpServletRequest;
    }
}))
.andExpect(status().isOk()) // 200 OK면 성공
.andExpect(model().attribute("list", page)) // ModelMap에 값을 담으면, 템플릿까지 값이 전달된다. Controller에서 ModelMap에 "list"란 이름으로 값을 담았는데, 그게 page와 같은지 본다.
.andExpect(content().string(containsString("test1"))); // content()는 템플릿엔진을 통해 랜더링한 결과에 "test1"이라는 문자열이 있는지 본다.
}
mvc는 Spring MVC가 controller를 실행하는 것을 시뮬레이션 한다. perform메소드는 controller의 특정메소드를 get, post, put, delete등으로 실행하도록 한다.
@MockBean
BoardService boardService;
BoardController가 의존하고 있는 Service를 Mock으로 설정한다.
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-test</artifactId>
    <version>5.0.4.RELEASE</version>
    <scope>test</scope>
</dependency>
테스트를 할 때 Spring security와 관련된 부분을 도와주는 라이브러리를 추가한다.
Test메소드를 만든다.
@WithMockUser(username = "admin@gmail.com", authorities = {"USER"})
로그인한 사용자의 username과 권한을 지정할 수 있다.
// with()부분은 Controller가 아닌 인터셉터에서 로그인한 정보를 저장하는데,
// 이 부분이 템플릿에서 사용하기 때문에 request에 로그인한 정보를 넣어줌.
ResultActions content1 = mvc.perform(get("/boards/1")
    .with(mockHttpServletRequest -> {
        User user = new User();
        user.setId(1L);
        user.setName("홍길동");
        mockHttpServletRequest.setAttribute("loginUser", user);
        return mockHttpServletRequest;
    }))
    .andExpect(status().isOk())
    .andExpect(content().string(containsString("content1")));
인터셉터에서 정보를 넣어주는 로직이 있을때 사용한다.

공부방법

  1. 책과 문서를 보며 어려웠던 부분과 중요한 부분을 체크하며 읽는다. 흐르듯이!(메모장등에 체크)
  2. 깃허브에서 소스를 보면서 내가 그 프로젝트를 만든다고 생각하고 소스를 본다.
  3. 궁금한점은 검색하면서 좋은 소스들을 찾아서 본다.
  4. 샘플코스를 작성한다. 라이브러리 및 프로그램이 이미 정해져있다.
  5. 잘하는 프로그래머한테 리뷰를 요청한다.
  6. 다른사람에게 설명한다.
  7. 개발할때 스스로에게 설명하면서 만든다.(이해 안가는게 있으면 적어놓던지 찾아본다.)







Share:

2018년 5월 22일 화요일

패스트 캠퍼스 JAVA 웹 프로그래밍 마스터 32일차(Exception처리)

Exception 화면

  • Exception이 발생하면 사용자에게 에러화면을 보여줘야 한다.

Exception 처리

  1. 처리하는 메소드에서 try cath문을 통해 처리하면 프로그램이 죽지않지만 잘못된 값을 가질수 있다. 
  2. 메소드에서 throws Exception명을 통해 Exception을 넘겨줘서 호출한 곳에서 try - catch 처리를 한다.
  3. Controller, Service, Repository에 throws Exception명을 처리하여 Dispatcherservlet에 에러 처리를 넘긴다. ExceptionHandler를 이용해 에러 처리를 한다.(Web api와 일반 호출하는 방법에 대해 최소 2개이상 에러 처리를 해야한다.)
  4. Excpetion처리를 위한 에러 처리를 하는 전용 클래스를 만든다.RuntimeException을 상속하여 구현한다. 처리하는 메소드에서 try - catch - throw - throws 처리하여 에러전용 클래스에 throw한다. Controller, Service, Repository마다 에러전용 클래스에 throw한 내용을 바탕으로 ExceptionHandler에서 log를 남긴다. 
잘못된 값을 넘겨줘서 연산이 일어나는 것은 매우 심각하다.
Share:

2018년 5월 17일 목요일

패스트 캠퍼스 JAVA 웹 프로그래밍 마스터 30일차(Test)

1. Test

Spring Boot는 격리시켜서 테스트 한다.

1번째 방법
  • 설정파일에 설정된 모든 빈들을 읽어서 사용한다.
@RunWith(SpringRunner.class)
@SpringBootTest
@Transactional
public class UserRepositoryTest

2번째 방법
  • @Repository와 @Entity만 생성한다.
  • @SpringBootApplication에서 @Autowired가 있으면 주입이 안될수도 있다. @Autowired(required = false)로 지정해주면 된다.
@RunWith(SpringRunner.class)
@DataJpaTest
public class UserRepositoryTest

2. Jenkins(CI)

https://jenkins.io/
java와 빌드도구가 설치되어 있어야 한다.

주기적으로 변경여부를 확인할 수 있다.

2-1. 젠킨스 war파일 실행

젠킨스 war파일 설치 젠킨스 포트 변경하여 실행하고 로그 저장
java -jar /Users/mac/programing/CI/jenkins/jenkins.war --httpPort=9999 > /Users/mac/programing/CI/jenkins/app.log 2> /Users/mac/programing/CI/jenkins/error.log &
실행 확인
ps -ef | grep jenkins

2-2. 비밀번호 보기

localhost:9999 접속
접속시 보이는 경로 shell cat명령어로 확인후  비밀번호 입력

2-3. 작업 생성하고 빌드하기

깃 저장소 추가하고 저장

빌드실행하기
left menu: Build now 선택
Console Output에서 확인

빌드 실행옵션 변경하려면
left menu: 구성 선택
build항목에서
Excute Shell 선택후 gradle build -x test 입력

자동화 만들기
sftp -i 계정명@아이피
put명령어 사용하여 jar 업로드
종료

ssh 접속
jar파일 실행
종료


- 알면 좋은것들
PMD : 코드 품질 관리
linux expect : CLI 상호작용 자동화 프로그램
fabric : http://tech.whatap.io/2015/10/15/install-whatap-on-multiple-linux-simultaneously/

Share:

Spring boot에서 @SpringBootTest와 @DataJpaTest 차이점

Test

Spring Boot는 격리시켜서 테스트 한다.

1번째 방법
  • 설정파일에 설정된 모든 빈들을 읽어서 사용한다.
@RunWith(SpringRunner.class)
@SpringBootTest
@Transactional
public class UserRepositoryTest

2번째 방법
  • @Repository와 @Entity만 생성한다.
  • @SpringBootApplication에서 @Autowired가 있으면 주입이 안될수도 있다. @Autowired(required = false)로 지정해주면 된다.
@RunWith(SpringRunner.class)
@DataJpaTest
public class UserRepositoryTest

Share:

2018년 5월 15일 화요일

Docker 정리

Docker 명령어

https://docs.docker.com/get-started/

#도커 이미지 목록
docker images

#도커 컨테이너 전체 목록
docker container ls -all

#도커 실행중인 목록
docker ps

#도커 컨테이너 전체 목록
docker ps -a

#도커 죽이기
docker kill 컨테이너id

#도커 삭제하기
docker rm 컨테이너 id

#도커 이미지 삭제하기
docker rmi 컨테이너 id

#Compose 파일로 컨테이너 생성(-d : 백그라운드 실행), docker-compose.yml파일이 있는곳 실행
docker-compose up -d

#Compose 파일에 정의 된 서비스 용 컨테이너 제거
docker-compose down

#도커 이미지 생성 및 태그 부여(현재지점)
#tag명:버전 (입력하지않으면 latest로 입력되고 생성할대 마다 이미지가 계속 쌓인다)
docker build -t 태그명 .

#도커 이미지 실행
#-d : 백그라운드 실행
docker run -p 내컴퓨터포트:도커연결할포트 태그명 -d

#로그보기
docker logs 컨테이너id

#도커로그인
docker login

#도커이미지 복사하기
docker tag 내컴퓨터에있는이미지명 계정명/생성할이미지명:생성할태그명

#도커hub에 이미지 업로드
docker push 계정명/이미지명:태그명

#도커서비스 목록
docker service ls
docker service ps 서비스명

#도커 swam시작하기(라운드로빈가능)
docker swarm init

#docker swam join문을 실행하여 다른 컴퓨터와 연결할 수 있다.
docker swarm join --token 토큰키 아이피:포트

#docker yml설정 파일 기반으로 swam실행하고 이름 지정하기
docker stack deploy -c docker-compose.yml swam생성이름
#docker-compose.yml 예제
version: "3"
services:
  web:
    # replace username/repo:tag with your name and image details
    image: username/repo:tag
    deploy:
      replicas: 5
      resources:
        limits:
          cpus: "0.1"
          memory: 50M
      restart_policy:
        condition: on-failure
    ports:
      - "80:80"
    networks:
      - webnet
networks:
  webnet:

#docker swam 서비스중인 목록
docker service ls

#docker swam 이름으로 실행중인 서비스 목록 보기
docker service ps swam생성이름

#docker swam 종료
docker swarm leave --force

#docker swam 제거
docker stack rm swam생성이름
Share:

패스트 캠퍼스 JAVA 웹 프로그래밍 마스터 29일차(docker)

Docker 명령어

https://docs.docker.com/get-started/
#도커 이미지 목록
docker images

#도커 컨테이너 전체 목록
docker container ls -all

#도커 실행중인 목록
docker ps

#도커 컨테이너 전체 목록
docker ps -a

#도커 죽이기
docker kill 컨테이너id

#도커 삭제하기
docker rm 컨테이너 id

#도커 이미지 삭제하기
docker rmi 컨테이너 id

#도커 이미지 생성 및 태그 부여(현재지점)
#tag명:버전 (입력하지않으면 latest로 입력되고 생성할대 마다 이미지가 계속 쌓인다)
docker build -t 태그명 .

#도커 이미지 실행
#-d : 백그라운드 실행
docker run -p 내컴퓨터포트:도커연결할포트 태그명 -d

#로그보기
docker logs 컨테이너id

#도커로그인
docker login

#도커이미지 복사하기
docker tag 내컴퓨터에있는이미지명 계정명/생성할이미지명:생성할태그명
#도커hub에 이미지 업로드
docker push 계정명/이미지명:태그명

#도커서비스 목록
docker service ls
docker service ps 서비스명

#도커 swam시작하기
docker swarm init

#docker swam join문을 실행하여 다른 컴퓨터와 연결할 수 있다.
docker swarm join --token 토큰키 아이피:포트

#docker yml설정 파일 기반으로 swam실행하고 이름 지정하기
docker stack deploy -c docker-compose.yml swam생성이름
#docker-compose.yml 예제
version: "3"
services:
  web:
    # replace username/repo:tag with your name and image details
    image: username/repo:tag
    deploy:
      replicas: 5
      resources:
        limits:
          cpus: "0.1"
          memory: 50M
      restart_policy:
        condition: on-failure
    ports:
      - "80:80"
    networks:
      - webnet
networks:
  webnet:

#docker swam 서비스중인 목록
docker service ls

#docker swam 이름으로 실행중인 서비스 목록 보기
docker service ps swam생성이름

#docker swam 종료
docker swarm leave --force

#docker swam 제거
docker stack rm swam생성이름
Share:

패스트 캠퍼스 JAVA 웹 프로그래밍 마스터 28일차(docker)

  • Docker
    • 도커이미지 : 도커에 의해서 설치되는 것
    • 명령어
      • docker images : 도커 이미지 목록
    • 설정
      • https : 443포트사용
      • links : 도커의 아이피는 항상 변경되서 다른 도커를 연결할때 links라는 옵션을 사용한다.
      • volumes : 설정파일을 도커안에 복사해서 사용한다.
    • docker-compose.xml : 어떻게 실행할지 아는 파일
Share:

2018년 5월 14일 월요일

2018년 5월 13일 일요일

패스트캠퍼스 개발자 커리어 컨퍼런스

이직을 꿈꾸는 개발자들에게 선배 개발자들이 진솔하게 전하는 개발자 이야기
# 인사 담당자가 말하는 개발자 채용
# 개발자로서의 성장
# 한국 개발 커리어의 현실
에 대한 내용을 얘기해보는 컨퍼런스다.




Session 1. 인사담당자가 말하는 개발자 채용

1.1 개발인력의 공통특징/특성 및 채용관점에서 본 개발인력에 대하 요구역량/성장경로


  • 시간이 지날 수록 아래로 가서 역량을 펼쳐라
  • 본인이 가치창출, 희소성, 모방의 어려움, 비 대체성이 있는지 확인하라(by 제임스반)
  • 30대 중반부터 생산성이 하락
  • 요즘은 역량기반으로 채용
  • 우수 S/W
    • 프로그래밍 능력, 도메인지식, 커뮤니케이션
    • 문제가 주어지는 순간 머리속에 그려짐
    • 직무간(도메인) 전환도 빠르게 적용
    • 의사 소통이 중요(안좋으면 좋은 인사고과, 좋은 급여를 받기 힘듬)
    • 개발 업무 수행시 요구 사항 분석에 많은 시간을 투자
  • 채용 면접 평가 기준
    • 신입 : 기본기 위주 skill
    • 박사 : 지식+스킬 기반으로 프로젝트 등 새로운 문제해결 시도 및 어떤결과를 냈는지 평가
    • 경력 : 현재 사용 가능한 skill
  • 리더 역량
    • 기술+인간관계+관리능력
  • 스택을 넓히고 도메인을 깊이
  • 개발자에게 동기부여
    • 레벨 테스트
    • 주축 개발자가 20~30%정도의 시간을 투자해 교육 및 보상
  • 관련없는 분야 이직시
    • 트렌드를 보자
    • 기존에 가지고 있던 도메인에 대한 개인공부
  • 내역량을 드러내는 방법
    • 다른사람과 다른 나의 고유한 내적 특성
    • 오픈소스기여(재밌어서 하는게 좋다)
  • 기업별 보는 스킬
    • 대기업: 한개의 도메인의 깊이
    • 중견기업 : 한개를 잘하지만 다른것도
    • 회사의 성향을 보자

Session 2. 개발자, 직장인? 직업인?

개발자로서 실력을 키워 성장하는 법과, 개발팀 직원으로서 좋은 인사고과를 받고 살아남아 승진하는 법은 다릅니다.
개발 실력과 회사 생활 양쪽을 모두 신경써야하는 직장인 개발자를 위한 성장 꿀팁을 공개합니다.

2.1 개발과 업무의 환경에서 - 레이니스트 안드로이드 개발자 김범준

  • 개발에 빠진 이유?
  • 개발이 즐거운가?
  • 일이 즐겁나요? 반복적인 일, 쉬운일

2.2 어떻게 하면 추천받는 개발자가 될 수 있을까? - 카카오 이경일

  • 경력공채, 수시채용 -> 사내추천
  • 추천해준 사람을 통해 면접관의 관심사를 알 수 있다.
  • 같은조직에 한해 서류전형이 통과될 수 있다.
  • 리스크가 적다.
  • 추천받는법(2가지이상)
    • 현 동료와 좋은 고나계를 유지하라(커뮤니케이션, 협엽)
    • 본인의 업무에 최선을 다하라(전문성, 도메인)
    • 했던일을 적극적으로 표현(깃허브 세미나, 블로그)
    • 컨퍼런스 참석
    • 4가지를 충족해도 인성이 나쁘면? 별로다
    • 이사람에게 일을 맡기면 해결할 수 있는 인식이 중요

2.3 관리자와 개발자 - 리멤버 CTO 임세준

  • 시간이 지나면 관리자?
  • API 개발이 즐거웠다
    • 메소드 시그니처
    • 클래스 나누기
    • 라이브러리
    • 성능
  • 기술리더 : 코딩할 시간이 없다
  • 조직관리
  • 문화 프로세스
    • 업무프로세스 : 스크럼, pp, 코드리뷰
    • 품질관리 : 단위테스트, QA
    • Risk Taking : 신기술 도입장려
  • 채용
    • 채용기준
    • 채용프로세스
    • 다양한 리쿠르팅 활동

QnA


  • 같이 일하기 싫은사람?
    • 독단적인 사람
    • 방어적인 태도
    • 근거와 공감능력이 필요하다
    • 생각에 대한 논리적인 근거가 필요하다
  • 개발성장과 도움
    • 문제해결능력(논리적 상황에서 관련된 사항 보는 능력)
    • 내가한 행동을 동료에게 넘기고 피드백 요청
  • 다른분야로 이직
    • 토이프로젝트가 필요
    • 빠른 습득력 필요
  • 연봉과 역량 그리고 업무,
    • 서비스를 빨리 끝내면 그것은 인센티브
    • 역량은 윗분들에게 리뷰요청등 피드백 요청해서 알리자 연봉협상에 좋다
    • 나의 관심사를 적용해 개발

Session 3. 내가 보는 한국 개발 커리어의 현실

내가 개발자로서 언제까지 살아남을 수 있을까?
핫한 기술 스택 열심히 배우면 이직/승진이 쉬워질까?

3.1 17년을 돌이켜보며 - 네이버 조은

  • 언어를 잘하는 것이 아니라 프로그래밍을 잘해야 한다
  • 내가 잘하는것 못하는것, 어디에 초점을 맞출까?
  • 면접을 보면 나를 알 수 있다
  • 레퍼런스 번역을 하며 공부하는것도 방법
  • 회사도 중요하시만 팀에서 하는일도 중요

3.2 야생에서 살아남는법 프리로 사는법 하이퍼커넥트 - 최완복

  • 짧은 프로젝트 위주의 경력
  • 야생 생종법
    • 기간, 공백
    • 계약해지
    • 평판이 중요하다
    • 커뮤니티 활동
    • 일감확보(기존 거래처 오퍼 및 커뮤니티에서 검색)
    • 기술력 확보
      • 공격적인 기술셋
      • 짧게 여러 프로젝트에 적용
    • 커뮤니티로 배우기
      • 열정을 충전
      • 어려운 문제 해결
    • 오픈소스 기여
      • 가르키는것이 최고 학습법
    • 관계 맺기/유지
      • 커뮤니티 : 신기술, 행사
      • 해커톤 : 골라서 잘가자
    • 새로운 시도 지속하기

3.3 20년차 개발자로 살아남는법 - CTO 굿닥 신현묵

  • 벤처 -> SI -> 의료 -> 헬스케어 전문가
  • 27년차 개발자
  • 20년차 개발자 볼수있나?
    • 고참 테크니션이 필요한 곳
    • 고참 경력자를 인정하는 곳
  • 20년차
    • 분석, 설계
    • 기술적 로드맵 결정 참여
    • 기술적인 이슈 결정 참여
    • 비즈니스에 대한 이해도 상승
  • How?
    • 다양한 경험
      • 초기 5년이 중요
      • 대기업 별로(4~7년은 까지만)
      • 커뮤니티 오픈소스 활동
    • 리뷰 활동
    • 뛰어난 아키텍처 동료
    • 운도 중요
    • 10년이상개발자는 인건비내리자 
    • 망해보자
  • 살아남는법? 직장인? 개발자?
    • 사장님
    • 개발팀장
    • CTO
    • 솔루션 or 프레임워크 주요커미터
    • 변신
      • IT출판사 직원
      • 컨설턴트 기술 영업직
      • 직장인
    • 대화가 잘되고 조언주는 사람

QnA

  • 연 8~10억정도 솔루션이면 혼자해도 된다
  • 문제에 대한 솔루션은 없는데 고민이 있을때 이직한다
  • 이직
    • 경영자가 삽질할때
    • 내가 필요 없을때
  • 주니어/시니어, A/B급
    • 업무이외 개발을 하는가? 즐기면서 하고있는가?
    • 잘만드나? 가독성 Test, 성능, 설계
  • 개발자에게 서포트?
    • 개발자가 뭘 원하는가? 맥북..
    • 연봉
    • 자율출퇴근
    • 시간적인 자유로움
    • 철학, 비전 공감이 필요하다
    • 삽질안하고 동일한 행동 반복 안하게하고 CTO가 좋은 결정하면 된다.
Share:

2018년 5월 12일 토요일

github에서 특정 파일 삭제 하기

특정파일(yml파일) 모든곳에서 히스토리 삭제

git filter-branch -f --index-filter 'git rm --cached --ignore-unmatch *.yml' --prune-empty -- --all # 모든 히스토리에서 해당 파일 삭제
git push origin --force --all

원격 저장소와 로컬 저장소에 있는 파일을 삭제

git rm file1.txt
git commit -m "remove file1.txt"
git push

원격 저장소의 파일 삭제

git rm --cached file1.txt
git commit -m "remove file1.txt"
git push

* 참고 사이트

Share:

AWS Linux에서 JDK 1.8 , Tomcat 8.5 , Maven 설정하기 (mac기준)

1. 인스턴스 생성

Linux를 선택하고 기본으로 셋팅하고 만든다.(고정 아이피도 설정)

보안그룹에서 8080, 22, 80번 포트를 열어둔다.

2. 터미널에서 키에 대한 권한설정(ec2-user계정)

#파일권한 변경
chmod 400 키파일디렉토리/lalwrj.pem

AWS에 접속하기
ssh -i ~/키파일디렉토리/pem키파일 ec2-user@아이피주소

아이피주소 : IPv4 Public IP

3. 루트계정 만들기(ec2-user계정)

3.1. 루트관리자 계정 만들기(root)

sudo passwd
처음엔 일반사용자 패스워드 입력.
그 다음엔 루트사용자 패스워드 입력.

root 관리자로 로그인 테스트
su -

3.2. ssh 터미널에 루트관리자로 로그인하기 위한 ssh 환경설정파일 편집

vi 에디터로 파일 열기( vi 대신 nano 사용 가능)
vi /etc/ssh/sshd_config  또는 nano /etc/ssh/sshd_config

PermitRootLogin without-password 라인을 아래와 같이 수정
PermitRootLogin yes

StrictModes yes 라인을 아래와 같이 수정(주석처리로 비활성화. 앞에 #만 붙이면 됨)
#StrictModes yes

3.3. 아마존 AWS로 부터 받은 일반사용자 암호화키를 루트관리자 계정에도 복사

sudo cp /home/ec2-user/.ssh/authorized_keys /root/.ssh

* 위의 경로에서 /home/ec2-user는 윈도우 OS로 따지면 "C:\사용자\홍길동" 과 같음.
따라서, 여기서 ec2-user는 아마존에서 인스턴스 생성시 자동으로 만들어진 사용자 계정의 기본 홈 폴더임.
명칭이 다른 경우엔 당연히 /home/ 뒤에 해당 명칭을 입력해줘야 함.
.ssh/authorized_keys는 보안을 위한 개인 암호화키가 해당 디렉토리에 들어있음을 표시.
따라서, /home/ec2-user/.ssh/authorized_keys를 /root/.ssh 디렉토리에 복사하면 루트관리자 로그인시 일반사용자 로그인처럼 해당 암호화키를 사용해서 로그인할 수 있는 것

3.4. ssh 서비스 재시작

service sshd restart

4. Jdk 설치(root 계정)

4.1 wget 으로 설치

다운로드
wget --no-cookies --no-check-certificate --header "Cookie: gpw_e24=http%3A%2F%2Fwww.oracle.com%2F; oraclelicense=accept-securebackup-cookie" "http://download.oracle.com/otn-pub/java/jdk/8u171-b11/512cd62ec5174c3487ac17c61aaa89e8/jdk-8u171-linux-x64.tar.gz"
압출풀기
tar xvzf jdk-8u171-linux-x64.tar.gz 

4.2 FTP 설치

http://www.oracle.com/technetwork/pt/java/javase/downloads/jdk8-downloads-2133151.html

FTP 프로그램에서 root로 접속후 파일 업로드

압축 풀기
tar xvzf jdk-8u171-linux-x64.tar.gz

파일 이동
mv jdk1.8.0_171 /loal/java/

버전확인
java -version
javac -version
기존 설치 버전이 계속 사용되면 제거 후 다시 확인

rpm -qa | grep jdk
yum remove jdk명

5. Tomcat 설치(root 계정)

https://tomcat.apache.org/download-80.cgi
tar xvzf apache-tomcat-8.5.31.tar.gz
파일 이동
mv apache-tomcat-8.5.31.tar.gz /local/tomcat8.5

tomcat 설치후 EC2 의 Security Group 에서 inbound 에 Custom TCP Rule 을 추가해 Port Range 에 8080 을 추가

6. Maven 설치(root 계정)

다운로드
wget http://mirror.apache-kr.org/maven/maven-3/3.5.4/binaries/apache-maven-3.5.4-bin.tar.gz
압출풀기
tar xvzf apache-maven-3.5.4-bin.tar.gz
파일 이동
mv apache-maven-3.5.4 /local/apache-maven-3.5.4

7. JDK, Tomcat, Maven 환경변수 설정(ec2-user계정)

bash_profile 파일 수정
vi ~/.bash_profile
마지막에 하단에 내용 입력
export JAVA_HOME=/local/java/jdk1.8.0_171
export MAVEN_HOME=/local/maven/apache-maven-3.5.4
export CATALINA_HOME=/local/tomcat8.5
export CLASSPATH=.:$JAVA_HOME/jre/lib/ext:$JAVA_HOME/lib/tools.jar:$CATALINA_HOME/lib/jsp-api.jar:$CATALINA_HOME/lib/servlet-api.jar PATH=$PATH:$JAVA_HOME/bin:$CATALINA_HOME/bin
export PATH=$PATH:$JAVA_HOME/bin:$MAVEN_HOME/bin
환경변수 적용
source ~/.bash_profile

8. 각 계정별 UTF-8 인코딩 설정해 한글 이슈 해결(ec2-user계정)

bash_profile 파일 수정
vi ~/.bash_profile
UTF-8인코딩 설정
LANG="ko_KR.UTF-8"
LANGUAGE="ko_KR:ko:en_US:en"
설정정보 적용
source ~/.bash_profile
env명령어로 확인
env

9. 접속 

톰캣 실행
/local/tomcat8.5/bin/startup.sh

AWS주소:8080 로 접속
Share:

2018년 5월 10일 목요일

패스트 캠퍼스 JAVA 웹 프로그래밍 마스터 26일차(Web API, 소켓)

  • Web API
    • RestTemplate
    • WebClient(qlehdrl)
  • 소켓
    • HTTP통신으로는 안되고 웹소켓을 사용해야 한다.
    • websocket, stomp, sock.js
    • 웹소켓을 지원해주지 않는 브라우저를 위해 라이브러가 있다.
      자바스크립트 라이브러리 : socket.io
      스프링 라이브러리 : sock.js
    • subscribe는 서버에게 특정 주소로 구독을 요청한다. 서버는 클라이언트가 요청한 주소를 알고있다. 서버한테 특정 주소로 메시지가 오면 구독한 클라이언트에게 전송한다.
    • spring에서 /app 경로는 생략한다.
    • SimpMessagingTemplate는 메시지를 보내기위한 객체
    • 채팅방에 접속할때 연결되고 나가면 연결이 끊긴다. 페이지를 나가도 연결을 유지하려면 원페이지로 만들어야 한다.(프론트 프레임워크를 통해서)
Share:

2018년 5월 9일 수요일

Spring JPA

EntityManager

  • EntityManager는 데이터베이스 연결이 꼭 필요한 시점까지 커넥션을 얻지 않는다.
  • 트랜잭션을 시작할 때 커넥션을 획득한다.(@Transactional이 없으면 EntityManager를 관리하지 못한다.)
  • 하이버네이트를 포함한 JPA구현체들은 EntityManagerFactory를 생성할 때 커넥션 풀도 만든다.
  • 스프링 부트에서는 필터(OSIV) - DS - C - S - R - DB 순으로 처리된다.
    필터(OSIV) - DS - C 에서는 트랜잭션이 ReadOnly이다.
    S - R - DB 단계에서는 읽고 쓰기가 가능하다.
    레이지 로딩 사용하려고 필터단계에서 트랜잭션이 시작된다.

영속성 컨텍스트(Persistence context)

  • 엔티티를 영구 저장하는 환경
  • 논리적인 개념에 가깝다. 
  • 영속성 컨텍스트는 EntityManager를 생성할 때 하나 만들어진다. 그리고 엔티티 메니저는 영속성 컨텍스트에 접근할 수 있고, 영속성 컨텍스트를 관리할 수 있다.

영속성 컨텍스트 특징

  • 영속성 컨텍스트와 식별자 값. : 영속성 컨텍스트는 엔티티를 식별자 값으로 구분한다. 영속상태는 식별자 값이 반드시 있어야 한다.
  • 영속성 컨텍스트와 데이터 베이스 저장 : JPA는 보통 트랜잭션이 커밋하는 순간 영속성 컨텍스트에 새로 저장된 엔티티를 데이터베이스에 반영한다.이를 flush라고 한다.
  • 영속성 컨텍스트가 엔티티를 관리할 때의 장점 : 1차 캐시, 동일성 보장, 트랜잭션을 지원하는 쓰기 지연, 변경감지, 지연 로딩

엔티티 조회, 입력

영속성 컨텍스트는 내부에 캐시를 가지고 있는데, 이를 1차 캐시라 한다. 영속상태의 엔티티는 모두 이곳에 저장된다.
1차 캐시의 키는 식별자 값이다. 이미 1차캐시에 있을 경우 db에서 조회하지 않고 캐시에서 조회하게 된다.
ex> em.persist(member); 가 호출될 경우 1차 캐시에 저장된다.

ID를 자동생성으로 셋팅하면 DB에 insert가 먼저 일어나고 키를 얻어온다. 자동생성 하지 않으면 DB에 INSET하지 않고 ID를 가지고 1차캐시에 저장된다.

엔티티 수정

엔티티가 수정된 것을 감지하여 db내용을 수정하는 것을 변경감지라한다.
jpa는 영속성 컨텍스트에 보관할 때 최초 상태를 복사해서 저장해둔다. 이를 스냅샷이라 한다. 그리고 플러시 시점에 스냅샷과 엔티티를 배고해 변경된 엔티티를 찾는다.
변경된 엔티티가 있으면 수정 쿼리를 생성해서 쓰기 지연 sql저장소에 보낸다.
쓰기 지연 저장소의 sql을 데이터베이스 보낸다.

변경관리는 영속성 컨텍스트가 관리하는 영속 상태의 엔티티에만 적용된다.

엔티티 생명주기

  • 비영속(new/transient) : 영속성 컨텍스트와 전혀 관계가 없는 상태
  • 영속(managed) : 영속성 컨텍스트에 저장된 상태
  • 준영속(detached) : 영속성 컨텍스트에 저장되었다가 분리된 상태
  • 삭제(removed) : 삭제된 상태




User user = new User();
위의 user객체는 비영속 상태다.

EntityManager를 통해 엔티티를 영속성 컨텍스트에 저장할 경우 영속 상태가 된다.
영속성 컨텍스트에 위해 관리되는 상태를 영속상태라 한다.
영속상태라는 것은 영속성 컨텍스트에 의해 관리된다는 것을 의미한다.

조회된 엔티티도 영속성 컨텍스트가 관리하는 영속 상태다.

EntityManager가 관리하던 엔티티를 더이상 관리하지 않으면 준영속상태가 된다.
em.detach()를 호출하면 된다. 혹은 em.close()를 호출해서 영속성 컨텍스트를 닫거나 em.clear()를
해서 영속성 컨텍스트가 초기화 해도 영속성 컨텍스가 관리하던 엔티티가 준영속 상태가 된다.

em.detach(user);
삭제는 em.remove(user); 를 이용해서 삭제할 경우이다.

준영속

영속 상태의 엔티티를 준영속 상태로 만드는 방법

  • em.detach(entity) : 특정 엔티티를 준영속 상태로 전환한다. 1차 캐시부터 쓰기 지연 sql저장소까지 해당 엔티티를 관리하기 위한 모든 정보가 제거된다.
  • em.clear() : 영속성 컨텍스트를 초기화 한다.
  • em.close() : 영속성 컨텍스트를 종료한다.

준영속 상태의 특징

- 거의 비영속 상태에 가깝다.
- 식별자 값을 가지고 있다.
- 지연 로딩을 할 수 없다.

merge()를 통해 병합할 수 있다.

준영속 상태의 엔티티를 다시 영속상태로 변경할 경우 merge()를 사용한다.

ex: User user = em.merge(user);

영속 엔티티의 동일성 보장 

같은 id의 값을 가진 엔티티를 조회하면 == 를 이용했을 경우 참이 나온다. 이를 동일성이라한다. 이는 실제 인스턴스가 같다는 것을 의미한다.

트랜잭션 지연쓰기

ex> em.persist(user1); em.persist(user2); 와 같이 여러번 영속성을 부여한 다음 트랜잭션을 커밋할 때 한꺼번에 sql이 실행된다. 이를 트랜잭션을 지원하는 쓰기 지연이라고 말한다.
이를 flush라고 한다.

모아둔 쿼리를 한번에 전달해서 성능을 최적화 할 수 있다.
Share:

스프링에서 검증 @Valid 와 BindingResult

@Valid

  • Dispatcherservlet이 메소드안에 선언된 객체를 만들어주고 값을 넣어준다.
  • @Valid선언된객체에 설정을 바탕으로 검사후 BindingResult에 담아준다.
  • 에러를 발생하려면 FieldError객체를 만들어서 BindingResult에 넣어준다.
  • 태그에서 object에 담긴 객체의 프로퍼티를 filed *{필드이름} 형식으로 사용한다
  • errors는 BindingResult에 있는 에러값을 출력해준다.
  • BindingResult.hasErrors : 에러가 있는지 검사한다.
  • lombok, thymeleaf를 사용하여 사용한 예제이다.
@Setter
@Getter
@ToString
public class UserJoinForm {

    @NotNull
    @Size(min = 2, max = 10)
    private String name;
    @NotNull
    @Size(min = 2, max = 50)
    private String email;
    @NotNull
    @Size(min = 2, max = 100)
    private String address;
    @NotNull
    @Size(min = 11, max = 11)
    private String phone;
    @NotNull
    @Size(min = 2, max = 15)
    private String password;
    @NotNull
    @Size(min = 2, max = 15)
    private String rePassword;
}
@PostMapping(path = "/join")
public String join(@Valid UserJoinForm userJoinForm, BindingResult bindingResult){
    //에러발생
    if(bindingResult.hasErrors()){
        return "/login/join";
    }
   
    if(!userJoinForm.getPassword().equals(userJoinForm.getRePassword())){
        FieldError fieldError = new FieldError("userJoinForm", "rePassword", "암호가 일치하지 않습니다");
        bindingResult.addError(fieldError);
        return "login/join";
    }

    User userByEmail = userService.getUserByEmail(userJoinForm.getEmail());
    if(userByEmail != null){
        FieldError fieldError = new FieldError("userJoinForm", "email", "이미 존재하는 email입니다.");
        bindingResult.addError(fieldError);
        return "login/join";
    }

    User user = new User();
    BeanUtils.copyProperties(userJoinForm, user);

    PasswordEncoder passwordEncoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
    user.setPassword(passwordEncoder.encode(user.getPassword()));

    UserRole userRole = new UserRole();
    userRole.setRoleName("USER");
    user.addUserRole(userRole);

    User saveUser = userService.addUser(user);

    return;
}
<form class="form" id="formJoin" role="form" autocomplete="off"  novalidate="" method="POST" th:object="${userJoinForm}" th:action="@{/users/join}" action="#">
    <div class="form-group">
        <label for="name">name</label>
        <input type="text" class="form-control form-control-lg rounded-0" name="name" id="name" required="" th:field="*{name}">
        <small class="text-danger" th:if="${#fields.hasErrors('name')}" th:errors="*{name}"></small>
    </div>
    <div class="form-group">
        <label for="email">email</label>
        <input type="text" class="form-control form-control-lg rounded-0" name="email" id="email" required="" th:field="*{email}">
        <small class="text-danger" th:if="${#fields.hasErrors('email')}" th:errors="*{email}"></small>
    </div>
    <div class="form-group">
        <label>Password</label>
        <input type="password" class="form-control form-control-lg rounded-0" id="password" name="password" required="" th:field="*{password}" >
        <small class="text-danger" th:if="${#fields.hasErrors('password')}" th:errors="*{password}"></small>
    </div>
    <div class="form-group">
        <label>Re Password</label>
        <input type="password" class="form-control form-control-lg rounded-0" id="rePassword" required="" th:field="*{rePassword}" >
        <small class="text-danger" th:if="${#fields.hasErrors('rePassword')}" th:errors="*{rePassword}"></small>
    </div>
    <div class="form-group">
        <label>phone</label>
        <input type="text" class="form-control form-control-lg rounded-0" id="phone" name="phone" required="" size="11" maxlength="11" th:field="*{phone}">
        <small class="text-danger" th:if="${#fields.hasErrors('phone')}" th:errors="*{phone}"></small>
    </div>
    <div class="form-group">
        <label>address</label>
        <button type="button" class="btn btn-info btn-sm" id="addressSearch">search</button>
        <input type="text" class="form-control form-control-lg rounded-0" id="address" name="address" required="" th:field="*{address}">
        <small class="text-danger" th:if="${#fields.hasErrors('address')}" th:errors="*{address}"></small>
    </div>
    <div>
        <label class="custom-control custom-checkbox">
            <input type="checkbox" class="">
            <span class="custom-control-indicator"></span>
            <span class="custom-control-description small text-dark">Remember me on this computer</span>
        </label>
    </div>
    <i class="fab fa-facebook"></i>
    <div class="form-group row">
        <div class="col-sm-10">
            <a th:href="@{/sign-in/facebook}">facebook 가입 및 로그인</a>
        </div>
    </div>
    <button type="submit" class="btn btn-success btn-lg float-right" id="join">Join</button>
</form>
Share:

2018년 5월 8일 화요일

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

  • 데이터베이스를 많이 사용하는 사이트는 어떤 곳일까?
    • 정적 데이터(사진사이트)
    • 비지니스 로직(은행)
    • DATA
  • 비지니스 로직이 많을때 여러개의 WAS를 사용
    • L4스위치를 통해 하나의 WAS를 통해 사용가능하게 할 수 있다.(비싸다)
    • 브라우저와 WAS사이에 nginx, 웹서버를 두어서 라운드 로빈방식으로 구현
      • 요청이 올때마다 하나의 WAS에 연결해준다.
      • 세션은 WAS남기 떄문에 문제가 있다. 그래서 세션정보를 공유하는부분을 만들어야한다.
      • Spring Session을 통해 Redis에 저장할 수 있다.
      • Nginx는 재시작을 해도 기존 사용자가 있다면 프로세스를 다 쓸때까지 종료되지 않는다. 새로 추가된 Nginx는 추가된 WAS에 연결되고 사용자가 사용하던 Nginx는 기존사용 종료후 재시작 되서 추가된 WAS와 연결된다. 무중단으로 서비스가 가능하다.
  • 값 검증
    • @Valid가 선언된객체에 설정을 바탕으로 검사후 BindingResult에 담아준다.
    • BindingResult.hasErrors : 에러가 있는지 검사한다.
    • 에러를 발생하려면 FieldError객체를 만들어서 BindingResult에 넣어준다.
    • dispatcherservlet이 메소드안에 선언된 객체를 만들어주고 값을 넣어준다.
    • 태그에서 object에 담긴 객체의 프로퍼티를 filed *{필드이름} 형식으로 사용한다
    • errors는 BindingResult에 있는 에러값을 출력해준다.
  • JPA
    • EntityManager가 제일 중요하다.
    • 영속성 상태일때만 작업이 일어난다.
    • 영속성을 부여하면 1차 캐시에 저장된다. 그리고 따로 스냅샷을(복사본) 만든다. 
    • 영속성 상태일때 @Id와 엔티티가 키가되고 엔티티가 값이된다.
    • ID를 자동생성으로 셋팅하면 DB에 insert가 먼저 일어나고 키를 얻어온다. 자동생성 하지 않으면 DB에 INSET하지 않고 ID를 가지고 1차캐시에 저장된다.
    • 1차캐시와 스냅샷이 서로 다를떄 UPDATE가 실행된다. 
    • EntityManager가 트랜잭션이 커밋될때 모아둔 SQL을 최적으로 실행한다.
    • EntityManager은 캐시에 데이터가 있으면 DB를 이용하지 않고 캐시에 있는것을 반환한다.
    • 비영속 : 객체만 생성한 단계
    • persist : 영속성 상태가 된다. insert가 작동하는것은 아니다. 조회를 할때도 영속성을 가진다.
    • detach : 비영속 상태가 된다.
    • 준영속상태 : 아이디를 가지고 있는 상태, 영속상태로 변경할 수있다.(merge)
    • @Transactional이 없으면 EntityManager를 관리하지 못한다.
    • 스프링 부트에서는 필터(OSIV) - DS - C - S - R - DB
      필터(OSIV) - DS - C 에서는 트랜잭션이 ReadOnly이다.
      S - R - DB 단계에서는 읽고 쓰기가 가능하다.
      레이지 로딩 사용하려고 필터단계에서 트랜잭션이 시작된다.
  • QueryDSL
    • JPQL을 오류나지않게 생성해주는 도구
  • JOOQ
    • natavie SQL을 사용하게 해주는 도구
  • 공부목록
    • Spring Session
Share:

2018년 5월 7일 월요일

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

  • Spring Security Filter
    • 필터에서 인증처리를 한다.
    • WebSecurity는 HttpSecurity를 통하지 않고 DispatcherServlet로 전송하고 싶을때 사용한다.
    • HttpSecurity는 인증처리를 실행한다.
    • addFilterBefore : 시큐리티 필터처리 되는 부분에서 중간에 필터를 넣는다.
    • 소셜 로그인
      • 소셜로그인 정보로 저장된 정보가 있는지 판단
        • 있다.
          • 인증정보 설정(Redirect)
        • 없다
          • 이미 이메일로 가입된 경우
            • 아이디, 패스워드로 로그인, 인증정보제거
          • 이메일이 없는 경우
            • 유저정보 저장, 유저커넥션 정보 저장, 인증정보 저장
          • 이미 로그인 상태
            • 유저커넥션정보 저장
  • Spring Boot 2.0
    • Spring Boot에서는 resources/static/ 에서 css, js디렉토리를 인식한다.
    • http://localhost:8080/css/a.css 로 접근이 가능하다
    • http://localhost:8080/static/css/a.css 로 접근가능하게 하려면 addResourceHandlers를 설정한다.
Share: