2019년 1월 28일 월요일

실용주의 프로그래머 책 메모

실용주의 프로그래머 

드디어 실용주의 프로그래머를 다 읽었다.
영어공부에 대해 이야기하다가 사수에게 한글로 책을 읽고 원서로 한번 더 읽는 방법을 추천받아 이 책까지 빌리게 되었는데 1챕터 읽고 멈췄었다...
하지만, 2019년 읽을 도서 목록으로
실용주의 프로그래머 -> 이펙티브 자바 -> 클린코드 -> ...more
으로 정하여서 2019년 1월 - 약 1달에 걸쳐서 다 읽게 되었다.
사실..1월말 까지 책을 돌려줘야해서 살짝 급하게 읽었다. 중간에 대충 읽은 부분도 많다.
이 책은 어디선가 보고 들은 개발자가 가져야할 생각이나 명심해야할 것들을 모아놓은 책 느낌이었다. 그래서 더 읽는데 속도가 붙을 수 있었던 것 같았다. 책을 사서 다시 읽어봐도 좋을 듯 하다.
그땐 또 다른 느낌점들과 깨닫는 것들이 생길 것 같다.

인상깊은 문장 메모
  • 자신의 일에 대해 생각하면서 일해라!
  • 깨진 창문(나쁜설계, 잘못된 결정, 혹은 형편없는 코드)을 고치지 않은 채로 내버려 두지 마라.
  • 큰 그림에 늘 주의를 기울여라. 개인적을 무엇을 하고 있는가에만 정신을 쏟지 말고, 주변에서 무슨일이 벌어지는지 지속적으로 살펴보라.
  • DRY - Don't Repeat Yourself
  • 관련 없는 것들 간에 서로 영향이 없도록 하라. (직교성 강조하고 있음)
  • 최종 결정이란 없다. (유연성강조)
  • 언제나 소스코드 관리 시스템을 사용하라.
  • 가장 속이기 쉬운 사람은 자기 자신이다.
  • 가정하지 마라. 증명하라.
  • 단정문을 사용해서 불가능한 상황을 예방하라.
  • 시작한 것은 끝내라.
  • 모듈간의 결합도를 최소화하라.
  • 통합하지 말고 설정하라.
  • 코드에는 추상화를, 메타데이터에는 세부 내용을.
  • <의도적으로 프로그래밍하기>
    • 정말로 제대로 돌아가는 것이 아닐지도 모른다. 우리에게만 그런 것처럼 보일 수도 있다.
    • 신뢰할 수 있는 것에만 기대라. 우연한 일이나 가정에 의존하지 말라.
    • 기존 코드가 아픙로 짤 코드를 지배하도록 놓아두지 말라. 더 이상 적절한 코드가 아니라고 생각되면, 어떤 코드라도 교체할 수 있다.
    • 어떤 것이 잘돌아가는 것처럼 보이기는 하는데 그 이유를 모를 경우, 그것이 우연은 아닌지 반드시 확인하라.
  • 일찍 리팩터링하고, 자주 리팩터링 하라.
    • 리팩터링과 새로운 기능 추가를 동시에 하지마라.
    • 리팩터링 전 테스트 집합이 있는지 먼저 확인하라.
    • 단계를 작게 나누어서 신중하게 작업하라. 단계가 끝날 때마다 테스트를 돌려라.
  • 테스트 코드를 쉽게 접근할 수 있게 해놓는 것은 앞으로 코드를 사용할지 모르는 개발자들에게 매우 귀중한 자원 2가지를 제공하는 것이다.
    • 모듈의 모든 기능을 어떻게 이용하야 하는지 보여주는 예제
    • 후일 코드 변경 시 검증하기 위한 희귀 테스트를 구축할 수 있는 수단
  • 주석에 나오지 말아야 할 것들의 목록
    • 파일 내의 코드가 export하는 함수들의 목록
    • 리비전 기록
    • 이 파일이 사용하는 파일 목록

2019년 1월 13일 일요일

스프링에서 선언식 트랜잭션 간단하게 실습해보기

트랜잭션이란??

정보처리기사에 정말 많이 나오는 개념으로 all or nothing 이라고 생각하면 된다.
'모두 처리 아니면 모두 X'
예를 들면, 트랜잭션이 적용된 어떠한 행동이 3가지의 insert , update, insert의 쿼리를 수행하는 행동일 때,
insert 성공
update 성공
insert 실패
가 되었을 때 앞의 insert와 update 쿼리가 성공이 되었을 지라도 마지막 insert가 실패되었기 때문에 모두 롤백이 되어야하는 개념이다.
스프링에서 트랜잭션은 선언식 트랜잭션과 프로그램에 의한 트랜잭션을 통해 사용할 수 있는 것 같다.
선언식 트랜잭션 중 어노테이션방법을 게시판의 예제로 간단하게 살펴보자
사용자가 게시물을 클릭한다고 생각하면 다음의 순서로 진행된다. 
1. 조회수가 오른다. (update)
2. 게시물의 데이터를 가져온다. (select)
만약 이때 2. select 과정에서 오류가 발생한다고 가정한다면, 게시물의 데이터를 못가져왔으므로 조회가 되지않는다. 그렇다면 조회수도 오르지 말아야한다.
(예시가 좀 이상하다. 적절한 예시를 찾아서 수정해야할듯...)
이 행동에 대해서 트랜잭션을 적용해보겠다.

root-context.xml
...

    <!-- transactionManager -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

...
servlet-context.xml
...

<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>

...
serviceImpl
package com.wpp.service;
...
import org.springframework.transaction.annotation.Transactional;
...

@Service
public class BoardServiceImpl implements BoardService{
...


@Transactional
public Object read(int bnum) throws Exception {
    Object object = null;

    //조회수 올리기
    boardDao.uphit(bnum);

    //게시물 내용
    object = boardDao.read(bnum);

    //트랜잭션 테스트를 위한 Exception 발생
    if( object == null) {
        throw new RuntimeException();
    }

    return object;
}


...
}
아까 만든 가정대로 테스트를 하기위해
다음과 같이 object가 null이면 RuntimeException 을 발생시켜보았다.
breakpoint를 잡고 object = freeboardDao.read(bnum); 부분에 bum의 값을 DB에 없는 값을 줘서 object를 null이 나오도록 하였다.
@Transactional 어노테이션이 없을 때는 해당 Exception이 발생하더라도 그 전의 조회수가 올라가는 것을 볼 수 있지만, 어노테이션을 추가한 후에는 조회수 부분이 rollback 된 것을 볼 수 있다.

@Transactional 에는 다양한 속성을 지정해줄 수 있다.
ex_) @Transactional(isolation=Isolation.DEFAULT, timeout=10)
- 격리레벨 : 데이터에 대한 격리
  - ex_) 커밋된 데이터 읽기 허용, 커밋되지 않는 데이터 읽기 허용 등)
- 전파 : 트랜잭션 중 다른 트랜잭션 호출할 때의 경우
  - ex_) 기존에 실행되고 있는 트랜잭션이 있으면 참여 아니면 새로 생성, 무조건 트랜잭션 새로 생성
- readonly : 트랜잭션을 읽기전용으로 적용
  - ex_) 쓰기작업 발생 시 예외발생(기본설정은 false)
- rollbackFor : 특정 예외가 발생할 경우 롤백 처리 설정
  - ex_) : 스프링의 데이터엑세스 예외는 RuntimeException 이므로, 런타임예외만 롤백대상이므로 다른예외도 추가하는 방식...인가????
- timeout : timeout발생 시 롤백 처리(초단위같음)
  - ex_) : 지정된 시간안에 수행이 되지 않으면 롤백

어노테이션 외에도 aop를 이용해 service단의 모든 메소드에 트랜잭션을 적용시킬 수 있다.

게시판에 트랜잭션을 적용하려고 다시 소스를 보았는데.....
정말 개판이다..

물론 이 때는 게시판을 만들어보는 것에 목적으로 두고 생성하였지만,
참...ㅋㅋㅋ 이 구조는 왜 이런식이며...service단은 그냥 쿼리를 호출하는 거랑 뭐가 다르게 만들어졌으며..

너무 못짰다. 이게 뭐야ㅠㅠㅠㅠㅠㅠㅠㅠ
얘를 개선할 수 있을까?
todo
aop 예제도 해보자.

2019년 1월 2일 수요일

그림과 실습으로 git branch 연습하기

개발자 커뮤니티 페이지를 돌아다니다가 git이 어렵다면 branch가 어려운 일 겁니다. 라는 제목을 보았다.
이 글에서 git branch 관련해서 연습을 하는 사이트를 추천해주셨는데

아주 직관적이고 그림으로 움직이면서 설명을 해줘서 브랜치에 대해 이해하기 쉽게 만들어져있었다.
마침 매번 사용할 때마다 찾아보고, 이클립스 안에서만 간단하게 commit, push만 하는 나에게 유익하다고 생각되었다.
commit, branch, checkout, cherry-pick, reset, revert, rebase, merge
의 명령어를 사용할 수 있고, 다음과 같은 단계별로 진행된다.

각 단계마다 명령어횟수를 측정하는데 모범답안 횟수에 도달하거나 하지 못할 때 메시지를 보여준다.

하단부에서 답안을 확인할 수 있으며, 초기화(Reset)이나 되돌리기(Undo)가 가능하다.

단계별로 되어있어 복습하기 쉽고, 답안까지 친절하게 제공해주고 있어 학습하기 좋은 것 같다. 



나도 언젠가 누군가에게 쉽고 간단하게 설명해줄 수 있는 날이 올까....?

2018년 12월 23일 일요일

리눅스 명령어 간단 정리

기본적인 리눅스 명령어 (책)

cd : 디렉토리 변경(change directory)
  cd .. : 상위 디렉토리로 이동
  cd : 홈 디렉토리로 이동
  pwd : 현재 디렉토리 위치
ls(list segments) : 디렉토리 및 파일 정보 화면에 출력
  -l : 긴 리스트 형으로 화면에 출력
history : 사용자가 입력한 명령어들의 기록을 보여줌
alias : 사용자 정의 명령어
  ex) alias ex1 = "clear"  ex1 입력하면 clear 실행됨
      alias 입력 시 설정된 내용 조회 가능
      unalias ex1 로 해제가능
rm : 파일이나 디렉토리 삭제
  -r 디렉터리 삭제, 하위 내용을 먼저 삭제
  -f / --force / 강제로 파일이나 디렉토리를 삭제하고, 삭제할 대상이 없을 경우 메시지를 출력하지 않음
  -i  매번 삭제할 때마다 사용자에게 질문함
  -v 삭제하는 내용 보여줌
mv : 파일 및 디렉토리 이동, 이름 변경
  -b 백업 파일을 생성
  -f 사용자에 묻지 않고 파일 덮어씀
  -i 덮어쓸 경우 사용자에게 물어봄
  -n 파일이 존재하면 덮어쓰지 않음
  -S 지정한 접미사로 백업생성
  -t 전체 원본파일을 대상 디렉토리로 이동
  -u 파일이 업데이트된 경우에만 이동함
  -v 진행상태 정보를 출력
| (pipe) : 어떤 명령어의 실행 결과를 다른 명령어의 입력으로 전달하는 것
  ex) ls -l | grep "tom"
crontab : 시스템에서 주기적으로 실행하는 명령어 설정
  -l 현재 로그인된 계정에 잡혀있는 작업 스케쥴 확인
  -e 현재 로그인 중인 계정에 작업을 등록  
  (0 0 * * 0 /bin/myjob.sh ---> 매월 일요일 0시 0분에 /bin/myjob.sh 실행
  분 시 일 월 요일)
  -r 현재 crontab에 등록된 작업을 삭제
gzip : 파일압축
  -n 1~9, 1이 가장 빠르고 압축률은 가장 낮음
  -c 압축결과를 출력, 원본파일은 그대로 둠
  -d 압축해제
  -f 강제압축
  -l 압축파일의 정보 출력
  -r 디렉토리에 포함된 모든 파일을 압축
  -t 압축파일 테스트
  -v 압축 혹은 해제 시 정보출력
tar : 파일을 압출하거나 해제하는 명령어
  -z gzip으로 압축하거나 해제
  -x 압축을 해제함
  -h 심볼릭 링크는 묶지 않고 심볼릭 링크가 가리키는 파일을 묶음
  -c 새 저장파일을 만듦
  -f 파일이름 지정
  -m 파일의 변경 시간정보를 유지하지 않음
  -P 모든 퍼미션 정보를 유지
  -p 파일 이름의 맨 앞, 문자를 버리지 않음
  -s 저장 파일 목록과 똑같은 순서로 압축을 해제
  -v 처리 중인 파일을 자세하게 보여줌
  -Z Compress 압축하거나 해제
which : 리눅스에서 사용하는 명령어의 경로를 찾아서 화면에 출력 (whereis는 관련파일까지 제공)
mkdir : 디렉토리 생성
  -m 디렉토리 권한 설정 (기본 755 rxwr-xr-x)
  -p 상위 경로도 함께 지정
  -v 디렉토리 생성 후에 생성된 디렉토리에 대한 메시지를 출력함
cp : 파일 혹은 디렉토리를 복사
  -f 덮어쓰기를 해서 복사
  -r 하위 디렉토리 전부를 모두 복사
  ex) cp test1 test2  ---> test1파일을 test2파일로 복사
touch : 파일을 생성하거나 파일의 시간정보 변경
  ex) touch test1.txt ---> 파일이없으면 생성
  touch -t 1801220333 ---> 18년 1월 22일 3시 33분으러 시간정보 변경
  touch -r test1 test2 --> test1파일과 test2파일의 시간정보를 같게 변경
file : 파일의 종류확인
  -b 파일의 유형만 출력
  -f 파일목록에서 지정한 파일들에 대해서만 명령을 실행
  -i MIME 타입형태로 출력
  -m 매직 파일을 지정
  -L 심볼릭 링크된 파일을 추적
  -v 버전 정보 출력
  -z 압축된 파일 확인
cat : 파일의 내용을 확인할 수 있는 명령어
head : 파일을 읽어 첫줄부터 10번째 줄까지 화면에 출력
tail: 파일을 끝부터 읽어 10번째 줄까지 화면에 출력
grep : 특정파일 내에 있는 문자열을 검색하는 역할을하는 명령어
  -c 검색 문자열이 속한 행 수를 출력
  -H 파일명과 함께 출력
  -i 대소문자를 구분하지 않음
  -n 검색한 문자가 속하는 행번호와 함께 출력
  -r 현재경로에서 하위경로까지 검색
  -v 검색하는 문자가 없는 행을 출력
  -w 패턴 표현식을 하나의 단어로 검색

grep 정규식
. 한글자
* 길이와 관계없는 문자열
^ 행의 첫 시작
$ 행의 마지막 위치
[] 한 문자길이 패턴
[^] 입력된 문자들의 여집합
wc : 특정 파일의 바이트 수나 검색하고자 하는 단어 수 및 행수를 알고자 할때 사용
  -c 바이트 크기 출력
  -m 문자 수를 출력
  -l 행수를 출력
  -L 가장 긴 문자만을 출력
sort : 파일을 내용을 정렬하는 명령어
  -k 지정한 필드를 기준으로 정렬
  -r 내림차순 정렬
  -f 모든 문자를 소문자로 식별
  -u 필드 내에서 중복된 값을 제거하여 유일한 값만 출력
cut : 텍스트 파일에서 특정 부분을 지정하여 출력할 수가 있는 명령어
  -b 특정 자리만 출력함
  -d 인자 문자열을 기준으로 해서 출력
  -f d옵션과 함께 사용되어서 구분된 필드를 출력
split : 파일을 나누고 싶을 때 사용
  -b 바이트 단위로 파일을 나눔
  -l 지정한 라인 수 만큼 파일을 나눔
  ex) split -b 1500k 파일명
diff : 두 개의 파일간의 차이점을 알 수 있음
shutdown : 리눅스 정지
  -r 재부팅
  -h shutdown 후 시스템 종료
  -c 진행중인 shutdown을 취소
  -k 경고메시지를 출력하고 실제 shutdown은 수행하지 않음
  -f fsck를 실행하지 않고 재부팅
  -t sec 지정한 시간에 재기동
  -v 상세 정보를 출력
reboot : 리눅스 다시 시작
  -n 연산은 중지하고 다시시작
  -f 강제로 다시시작
  -p 연산을 중지 시에 전원을 종료
  -q 오류가 없으면 다시시작하지 않음
  -v 상세정보 출력
netstat : 시스템과 연결된 모든 네트워크 연결을 확인
  -a 모든 소켓 정보를 확인
  -n 도메인 주소를 읽지 않고 숫자로 출력
  -p PID와 사용 중인 프로그램명을 출력
  -g 멀티캐스트 그룹 정보
ping : 네트워크 상태를 정보를 점검하기 위한 명령어(ICMP프로토콜을 사용하여 ICMP echo Request를 전송하고 ICMP echo reply가 되돌아오는 지 확인)
ping 210.220.163.82
PING 210.220.163.82 (210.220.163.82): 56 data bytes
64 bytes from 210.220.163.82: icmp_seq=0 ttl=248 time=9.240 ms
64 bytes from 210.220.163.82: icmp_seq=1 ttl=248 time=9.830 ms
nslookup : 도메인명에 대한 IP주소를 확인하기 위해 DNS에 질의를 실행함
$ nslookup www.naver.com
Server:        210.220.163.82
Address:    210.220.163.82#53

Non-authoritative answer:
www.naver.com    canonical name = www.naver.com.nheos.com.
Name:    www.naver.com.nheos.com
Address: 125.209.222.142
Name:    www.naver.com.nheos.com
Address: 125.209.222.141

halt : 리눅스 종료
  -d wtmp에 로그를 기록하지 않음
  -f 강제로 종료
  -n 종료할 때 동기화를 하지 않음
  -w 실제로 종료하지 않고 /var/log/wtmp에 로그를 기록

객체지향의 사실과 오해 - 인터페이스 부분 정리

객체지향의 사실과 오해 - 인터페이스
  • 인터페이스는 객체가 다른 객체와 협력하기 위한 접점
  • 일반적으로 인터페이스는 다음과 같은 세 가지 특징을 지님
1. 인터페이스의 사용법을 익히기만 하면 내부 구조나 동작방식을 몰라도 쉽게 대상을 조작하거나 의사를 전달할 수 있음
2. 인터페이스 자체는 변경하지 않고 단순히 내부 구성이나 작동방식만을 변경하는 것은 인터페이스 사용자에게 어떤 영향도 미치지 않는다
3. 대상이 변경되더라도 동일한 인터페이스르 제공하기만 하면 아무런 문제없이 상호작용을 할 수 있다
  • 객체가 다른 객체와 상호작용할 수 있는 유일한 방법은 '메시지 전송'
  • 책임은 객체가 메시지를 수신했을 때 수행해야 하는 객체의 행동이며, 실제로 객체의 공용 인터페이스를 구성하는 것은 객체가 외부로부터 수신할 수 있는 메시지의 목록
객체가 메시지를 수신했을 때 적절한 객체의 책임이 수행됨 -----> 메서드
  • 객체지향적인 사고방식을 이해하기 위해서는 세 가지 원칙이 중요
1. 좀 더 추상적인 인터페이스 : 지나치게 상세한 수준의 메시지를 보내는 것은 객체의 자율성을 저해함
2. 최소 인터페이스 : 외부에서 사용할 필요가 없는 인터페이스는 최대힌 노출하지 말라
(객체 내부를 수정하더라도 외부에 미치는 영향을 최소화할 수 있음)
3. 인터페이스와 구현간의 차이가 있다는 점을 인식
: 훌륭한 객체란 구현을 모른 채 인터페이스만 알면 쉽게 상호작용할 수 있는 객체
----> 객체 외부에 노출되는 인터페이스와 객체의 내부에 숨겨지는 구현을 분리해서 고려해야함
----> '인터페이스와 구현의 분리 원칙'
----> why? 객체의 모든 것이 외부에 공개돼 있다면 아무리 작은 부분을 수정하더라도 변경에 의한 파급효과가 객체 공동체의 구석구석까지 파고들 것임

'강조'
객체가 가져야 할 상태와 메서드 구현은 객체 내부에 속함. 이 부분을 수정하더라도 객체 외부에 영향을 미쳐서는 안됨
객체 외부에 영향을 미치는 변경은 객체의 공용 인터페이스를 수정할 때만
---> 캡슐화
  • 캡슐화: 객체의 자율성을 보존하기 위해 구현을 외부로부터 감추는 것
---> 객체의 상태와 행위를 캡슐화함으로써 협력적이고 자율적인 존재가 될 수 있음
  • 자율적인 객체? : 공용 인터페이스를 수정하지 않는 한 자신과 협력하는 외부 객체에 영향을 미치지 않고 내부의 구현을 '자유롭게' 수정할 수 있음
  • 결론: 객체가 자율적인 책임을 가지는 것이 중요하다
객체의 책임이 자율적일수록 협력이 이해하기 쉬워지고 유연하게 변경할 수 있게 된다

1. 자율적인 책임은 협력을 단순하게 만든다
---> 책임이 적절하게 추상화됨

2. 외부와 내부를 명확하게 분리
---> 요청하는 객체가 몰라도 되는 사적인 부분이 객체 내부로 캡슐화되면서 인터페이스와 구현이 분리됨

3. 내부적인 방법을 변경하더라도 외부에 영향을 미치지 않음
---> 책임이 자율적일 수록 변경에 의해 수정되야하는 범위가 좁아지고 명확(결홥도가 낮아짐)

4. 협력의 대상을 다양하게 선택할 수 있는 유연성을 제공
---> 설계가 유연해지고 재사용성이 높아짐

5. 객체의 역할을 이해햐기 쉬워짐
---> 객체의 응집도를 높은 상태로 유지가 쉬워짐

2018년 12월 16일 일요일

CI 실습해보기(AWS, Jenkins)

AWS의 EC2 를 이용하여 CI를 실습해보고자 한다.
단계는
1. AWS 인스턴스 신청
2. 서버 설정
3. GIT 연동하여 빌드 / 배포
로 나누어 진행했다.

1. AWS 인스턴스 신청

AWS는 1년 프리티어를 제공하고 있다. 이를 이용해서 무료서버를 체험해볼 수 있다.
프리티어를 사용하기 위해서는 마스터카드를 등록해야함.
가입 후 EC2 인스턴스를 생성한다.


나의 경우는 우분투를 선택하였다.

키페어를 생성 후 다운받아 인스턴스에 SSH 를 통해 접속할 수 있다.

잘 보관할 것
aws가 친절하게 인스턴스에 연결하는 방법을 알려준다. 키페어위치만 잘 입력하여 접속하자

yes를 누르면 다음과 같이 접속할 수 있는 것을 볼 수 있음

윈도우는 putty를 통해 접속할 수 있음

2. 서버 설정

- 자바 설치
sudo apt-get install openjdk-8-jdk
Reading package lists... Done
Building dependency tree
Reading state information... Done
E: Unable to locate package openjdk-8-jdk
해당 오류 발생(해당 패키지가 없는 듯하다..)
sudo add-apt-repository ppa:webupd8team/java
를 입력하고 다시 install 하니 설치가 되었다.
ubuntu@ip-:~$ sudo apt install openjdk-8-jdk
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following additional packages will be installed:
  adwaita-icon-theme at-spi2-core ca-certificates-java dconf-gsettings-backend
  ...
0 upgraded, 148 newly installed, 0 to remove and 112 not upgraded.
Need to get 80.2 MB of archives.
After this operation, 443 MB of additional disk space will be used.
Do you want to continue? [Y/n] y
자바설치완료!
ubuntu@ip~$ java -version
openjdk version "1.8.0_191"
OpenJDK Runtime Environment (build 1.8.0_191-8u191-b12-0ubuntu0.18.04.1-b12)
OpenJDK 64-Bit Server VM (build 25.191-b12, mixed mode)
- 톰캣 설치
톰캣과 톰캣어드민를 설치한다.
sudo apt-get install tomcat8

sudo apt-get install tomcat8-admin
어드민페이지에 접속할 수 있게 해당 xml을 수정한다.
sudo vi /etc/tomcat8/tomcat-users.xml
다음을 추가해준다
<role rolename="manager-gui"/>    
<role rolename="manager-script"/>  
<role rolename="manager-status"/>
<user username="admin" password="비번" roles="manager-gui,manager-script,manager-status"/>
manager 페이지는 
주소:8080/manager 입력하면 위에 입력한 username과 password를 입력하면 보여진다. 
해당 페이지에서 직접 war파일을 올려 배포할 수도 있다.

- DB설치
나의 경우에는 mysql을 설치하였음
설치 후 워크벤치로 서버에 설치된 DB에 접속하려하였지만, 계속 실패하였음
grant all privileges on *.* to root@'%' identified by '루트계정 비밀번호';
해당 명령어 입력 후 정상접속됨.. root 계정 권한문제?
- 젠킨스 설치
wget -q -O - https://pkg.jenkins.io/debian/jenkins-ci.org.key | sudo apt-key add -

echo deb https://pkg.jenkins.io/debian-stable binary/ | sudo tee /etc/apt/sources.list.d/jenkins.list

sudo apt-get update

sudo apt-get install jenkins
톰캣을 8080으로 써야하므로 젠킨스는 7070으로 포트 변경
sudo vim /etc/default/jenkins
HTTP_PORT 7070으로 변경
# port for HTTP connector (default 8080; disable with -1)
HTTP_PORT=7070
주소:7070 으로 접속하려하였지만, ERR_CONNECTION_TIMED_OUT 발생 7070을 못쓰나 하고 8080으로 다시 수정 후 접속하려하였지만, 또 발생
aws 방화벽 문제인 듯 하여 인스턴스 inbound 규칙 추가해줌

인바운드 아웃바운드 규칙란?
-인바운드 : 서버 내부로 들어오는 것 (클라이언트 -> 서버)
(ex 클라이언트가 업로드)
-아웃바운드 : 서버 외부로 송출 (서버 -> 클라이언트)
(ex 클라이언트가 다운로드)

- 젠킨스 설정
이제 http://주소:7070 을 들어가면 젠킨스 설정화면이 보인다.

첫 보안인증 화면은
sudo cat /var/lib/jenkins/secrets/initialAdminPassword
의 패스워드를 쓰면 됨

잘 모르니 suggested 고고 ㅎㅎ;;

계정 생성하면 다음과 같은 화면보임! Jenkins 띄우기 성공! 

3. GIT 연동 / 빌드 / 배포

새로운 JOB을 만들어서
다음과 같이 Freestyle project 선택

소스코드관리 Git을 선택하고 띄울 프로젝트의 github저장소 URL 를 입력한다.

BUILD 
나의 경우에는 maven 빌드이므로 다음과 같이 설정하였음
프로젝트의 pom.xml 경로를 입력해준다. 

Jenkins를 통해 빌드만 하여 war만 만들어놓고 원하는 경로에 놓을 수 있지만, 젠킨스를 통해 빌드 후 배포까지 가능하다. 
빌드 조치 (배포) 빌드 후 조치 메뉴의 Deploy war/ear to a container 를 선택하여 다음과 같이 입력하였다.
서버에 깔린 톰캣 버전과 URL를 입력 후 매니저 페이지 계정과 비밀번호를 입력해주었음. 

경로만 제대로 입력/설정되어 있다면 다음과같이 빌드와 배포가 SUCCESS 가 된다.


젠킨스는 테스트, 알림, 다양한 플러그인 등의 다양한 기능을 제공하고있음.
이를 응용하여 더 해봐야할 듯 함!!!

=======================================================
ㅜㅜ....삽질을 너무 많이함 
1. mysql 계정권한문제 삽질 
2. 빌드 후 생성되는 war에 classes 하위가 없거나 src/main/webapp 폴더 안의 것들이 없었음
이것때문에 게속 삽질함... 그리고 젠킨스 빌드 시 서버가 급속도로 느려지면서 아무것도 못하는 경우 발생 인스턴스 재시작하면서 퍼블릭IP가 바뀌어서 매우 귀찮아졌었음.... ㅠ퓨

--> 느려지는 원인!!!
프리티어는 1기가 메모리를 제공하고있음.
근데 이 서버에 DB, tomcat, jenkins 까지 올려놓고 쓰니 당근 서버가 뻗을 수 밖에...

classes에 없는건 pom.xml 위치인 듯하고
(pom이 이상한 곳에 생성되었었는데 그걸로 빌드하니 class들이 모두 생성이 되지 않았음) 
webapp 없는건 경로문제인듯함 그래서 pom.xml에 warSourceDirectory  src/main/webapp 로 경로를 설정해주니 생김!
이 링크 참조하여 해결
이클립스에서도 war로 export하면 동일한 war가 생성되어 내 문제임을 알았다.
링크보고 이클립스 프로젝트 Properties - Deployment Assembly 에서
Source  와 Deploy Path 를 보고 
webapp가 이상한 것으로 잡혀있어서 배포 시 생성이 안된거였음...!
/src/main/webapp 가 없어서 추가하고 다시 export 하니 war가 제대로 생성되었음.

근데 이건 이클립스 프로젝트 설정 바꾸는건데 젠킨스는 git에서  땡겨서 빌드하는데 이 속성을 가져올 수 있을까?
 pom.xml

<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.4</version>
<configuration>
        <warSourceDirectory>src/main/webapp</warSourceDirectory>
</configuration>
</plugin>


warSourceDirectory 에 원래 webapp만 있었는데 src/main 을 추가 후 git에 올리고 
다시 젠킨스로 빌드 후 배포하니 정상적으로 배포까지 완료됨... 
...와르소스디렉토리인데 왜 될까 ..? 

오! 여기 딱 나와있음...

WAR에 포함될 추가적인 파일들을 위한 디렉토리이다. 
이것은 너의 JSP파일들을 놓은 위치이다. 

메이븐 공부할 때 한번 읽어 볼 필요가 있을듯... 

https://maven.apache.org/plugins/maven-war-plugin/war-mojo.html

Required Parameters

NameTypeSinceDescription
<cacheFile>File2.1-alpha-1The file containing the webapp structure cache.
Default value is${project.build.directory}/war/work/webapp-cache.xml.
<outputDirectory>String-The directory for the generated WAR.
Default value is${project.build.directory}.
<warSourceDirectory>File-Single directory for extra files to include in the WAR. This is where you place your JSP files.
Default value is${basedir}/src/main/webapp.
<webappDirectory>File-The directory where the webapp is built.
Default value is${project.build.directory}/${project.build.finalName}.
<workDirectory>File-Directory to unpack dependent WARs into if needed.
Default value is${project.build.directory}/war/work.

todo 
1. git  push 인식하여 빌드하도록 설정하기 
2. 메이븐 공부하기 
(한번 읽어볼 것 
https://wikidocs.net/book/1910
)