├── .gitignore
├── README.md
├── deploy.sh
├── images
├── fastcampus-java-1.jpg
├── mappedsuperclass.png
├── messageSource.png
└── resttemplate.png
├── out
└── production
│ └── fastcampus-java
│ ├── main
│ ├── Calculator.class
│ └── StringCalculator.class
│ └── test
│ └── main
│ ├── CalculatorTest.class
│ └── StringCalculatorTest.class
├── review
└── README.md
└── src
├── main
└── week1
│ ├── Calculator.java
│ └── StringCalculator.java
└── test
└── main
└── week1
├── CalculatorTest.java
└── StringCalculatorTest.java
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by .ignore support plugin (hsz.mobi)
2 | *.iml
3 | .idea
4 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 패스트캠퍼스 자바 웹 프로그래밍 CAMP
2 |
3 | * 자바지기(박재성)님의 [패스트캠퍼스 자바 웹 프로그래밍 CAMP](http://www.fastcampus.co.kr/dev_camp_jwp/) 강의 내용 정리
4 | * 광고 아니라 진심으로 150만원 상당의 수강료가 아깝지 않은 명품 강의였다.
5 |
6 | ## 1일차 - TDD 시작
7 | * 일반적인 main()을 이용한 테스트 방식의 문제점
8 | * 이클립스에서 Junit 사용법 (난 중간중간 인텔리제이로 검색해서 적용함)
9 | * @Before 사용하는 이유 : 각 테스트들간의 고유한 객체를 생성해주기 위해
10 | * 선 테스트코드 작성후 실제 코드 개발
11 | * 구현 -> 테스트 -> 리펙토링 과정으로 진행
12 | * 테스트 메소드는 production 코드에서 exception을 던질수 있기 때문에 웬만하면 throws Exception을 추가하는게 좋다
13 | * private 메소드의 테스트는 private를 지우고 테스트 or 해당 메소드를 class로 뽑아서(Refactor 사용) 진행도 가능
14 | * Refactor 사용을 활성화 하자! (Method, Class 등)
15 |
16 | ## 2일차 - HTTP 웹서버 실습
17 | * 순수 Java로 웹 서버 구축 - [프로젝트 코드] (https://github.com/jojoldu/web-application-server)
18 | * 문자열 덧셈 게시판 못다한 이야기
19 | * sum(toInts(split(text))) 을 람다식으로 표현
20 | ```
21 | Arrays.stream(split(text))
22 | .map(t -> Integer.parseInt(t))
23 | .reduce(0, (number, sum) -> number + sum);
24 | ```
25 | * RequestHandler는 Thread를 상속 받는다
26 | * connection은 대기하다가, 사용자가 접속하면 Thread 객체를 생성한다. (즉, 사용자 1명당 Thread 객체 1개가 할당된다)
27 | * 그럼 동접이 1만명 10만명인 경우 Thread가 1만개, 10만개가 생성되는가?
28 |
29 | ## 3일차 - HTTP 웹서버 리팩토링 실습
30 | * 좋은개발자란?
31 | - 20대~ 30대초반 : 기술적으로 뛰어난 개발자
32 | - 30대 중,후반 : 협업과 소통이 잘되어 같이 일하고 싶은 개발자
33 | - 현재 : 사람을 중심에 두면서 기술을 사용할줄 아는 개발자
34 | * Exception
35 | - exception은 컴파일 exception
36 | - 잘모르겠으면 throw new RuntimeException을 보낸다.
37 | - 통장에서 돈을 인출하려는데 잔액 부족할 경우 - checked exception
38 | - DB연결이 끊길 경우 - unchecked exception
39 | - 확실히 시스템 문제라면 unchecked exception, 그외에는 checked exception
40 | - appender를 이용하면 별도의 코드 추가없이 모니터링 서비스로 에러로그를 보낼수가 있다.
41 | * 복잡해진 웹 서버의 코드를 리팩토링 하자 - [프로젝트 코드] (https://github.com/jojoldu/web-application-server/tree/was-step1-bad-version)
42 | * 소켓이 생성되려면 서버의 IP/Port 와 클라이언트의 IP/Port가 필요하다
43 | * TCP three-way handshake
44 | - 3번에 걸쳐 서버와 클라이언트간 교환작업
45 | - DB와 웹서버의 경우 이 작업이 너무 크므로 웹서버와 DB간의 three-way handshake를 미리 완료하여 이를 connection pool에 담아서 이 작업을 최소화 한다.
46 | - 이게 가능한 이유는 클라이언트(즉, 여기선 DB)의 IP와 포트를 고정시킬수 있기 때문이다. 브라우저는 IP가 고정되어있지 않으므로 불가능하다.
47 | * HTTP Status
48 | - 302를 만나면 브라우저는 location 헤더 값이 있겠구나고 생각하고, location에 있는 값으로 다시 서버에 요청한다. 모든 리다이렉트 API는 이러한 방식이다.
49 | - 200은 index.html을 body에 담아서 보내는거라 리다이렉트 되지 않는다.
50 | * HTTP 상태 vs 무상태
51 | - 상태 protocol: 서버가 클라이언트의 상태값을 계속 갖고 있는 것(connection을 계속 이어간다.)
52 | - 무상태 protocol: 서버가 클라이언트에 결과를 보내면 connection을 끊어버린다.
53 | - 세션은 정보를 서버에 저장하고, 세션 ID를 쿠키로 전달한다.
54 | * CSRF 토큰: 주요 요청 직전에 발급하는 토큰으로, 이와 맞지 않으면 요청을 무효화시킨다.
55 |
56 | ## 4일차 - HTTP 웹서버 코드리뷰
57 | * Github를 통해 관리해야하는 코드는?
58 | - build를 통해 생성되는 파일 (.settings, target 등)
59 | - 의존성 관리 툴(maven, gradle, npm, bower)을 통해 다운받는 라이브러리
60 | - IDE를 통해 생성되는 파일 (.project, .iml, .springbeans 등)
61 | - 모르겠으면 [gitignore.io](https://www.gitignore.io/)에서 java로 검색해서 제외해야할것 찾아서 .gitignore에 추가하자
62 | - Gradle 과 Maven 둘다 하기보다는 1개라도 잘하자
63 |
64 | * 객체지향의 다형성에 익숙해지려면 어떻게 해야하나?
65 | - DB연동이 없고, UI를 고려하지 않는 프로젝트를 진행할것 (웹은 좋은 예제는 아니다)
66 | - ex) HTTP웹서버, 프레임워크 or 라이브러리, 체스게임, 지뢰찾기, 볼링게임점수판 등
67 | - [객체지향 생활 체조 총정리](https://developerfarm.wordpress.com/2012/02/03/object_calisthenics_summary/)의 내용을 참고
68 | - 하나의 프로젝트(주제)를 주기적으로 다시 만들어보자 여러 프로젝트를 하지 말자.
69 | - 예를 들어 전사케릭을 50까지 키웠는데 재미없어서, 마법사케릭을 다시 키워서 50까지 키우니 재미없어서 궁수케릭을 다시 키우는 식이 될수있다.
70 | - 하나의 케릭을 쭈욱 키우는게 더 높은 곳까지 갈 수 있다.
71 |
72 | * HTTP 웹서버 코드리뷰 진행
73 | - 기존에 짠 코드를 테스트하는게 아니다
74 | - 테스트를 위해 기존 코드를 고치는 것이다. 즉, 테스트를 원하는 코드를 계속 method로 빼고, 세분화하자
75 | - 테스트하기 쉬운 코드 혹은 method는 input이 있고 return이 있어야 한다. (스칼라가 지향하는 방향과 동일하네?)
76 | - private method의 경우 method보다는 class가 오히려 더 잘어울릴수 있다. (힌트가 될수 있다)
77 | - logger같은 경우 IDE에 템플릿 등록해서 사용하면 반복작업을 최소화할수 있다.
78 | - 상태값을 가지는 객체의 경우 쓰레드마다 매번 객체 생성 해야하지만, 상태값이 없는 객체의 경우 재사용해야 한다.
79 | - 서블릿컨테이너 : 서블릿을 실행시켜주는 역할
80 | - 서블릿 컨테이너에서 서블릿 인스턴스는 1개만 생성되고 이를 재사용하는 방식이다.
81 | - 서블릿 컨테이너는 모든 사용자 요청에 대해 Thread를 생성해야하나? 1000명이 요청하면 1000개의 Thread가 필요한가?
82 | - 서블릿 컨테이너는 서버가 생성할 수 있는 Thread수를 제한한다.
83 | - Thread Pool을 사용해 제한된 **Thread를 재사용**한다.
84 | - Thread수를 초과한 사용자들은 큐에서 대기하여 처리될때마다 Thread를 할당한다.
85 | - 그래서 Tomcat 설정에 maxThreads는 최대 Threads수, acceptCount는 큐의 최대 대기자수를 말한다.
86 |
87 | * Servlet과 JSP 시작 - 1
88 | - @WebServlet과 extends HttpServlet 되어 있는 class를 등록한다.
89 |
90 | ## 5일차 - MVC 프레임워크 1단계 구현 실습
91 | * 배움 관련 이야기
92 | - 주변사람과의 비교는 결국 나를 초라하게 만든다.
93 | * Servlet을 사용하여 MVC 프레임워크 구축하기
94 | - doGet, doPost를 사용하는 많은 Servlet Controller들을 Controller Interface 구현체로 만들어 리팩토링하기
95 |
96 | ## 6일차 - MVC 프레임워크 및 JDBC
97 | * MVC 프레임워크 Flow
98 | - 모든 요청은 중앙집중형 DispatcherServlet이 받는다. 요청에 대한 url을 RequestMapping에게 준다
99 | - RequestMapping은 url에 해당하는 Controller를 DispatcherServlet에게 전달해준다.
100 | - DispatcherServlet은 RequestMapping에게 받은 Controller를 실행시킨다.
101 | - J2EE 패턴중 Front Controller패턴이라고 보면 된다. (DispatcherServlet가 Front Controller라고 보면 된다.)
102 | - Controller은 사용자가 입력한 값에 대한 유효성 처리를 담당한다.
103 | - Controller은 Model과 View 사이를 연결하는 연결자 역할을 한다.
104 | - 비지니스 로직은 Model에서 구현해야 한다.
105 | - View는 Controller에게 받은 데이터를 출력시키기만 한다.
106 |
107 | * 서블릿 Life Cycle
108 | - init() : 서블릿 생성시 처리할 내용을 담고 있는 메소드
109 | - service() : 실제 수행될 로직을 담당
110 | - destroy() : 후처리
111 | - 컨테이너 : 해당하는 것(서블릿, 빈)들의 라이프사이클을 관리하는 역할
112 |
113 | * loadOnStartup
114 | - 서블릿컨테이너가 시작될때 해당 설정값을 가지고 있는 서블릿 인스턴스를 생성하고 init() 를 호출해준다.
115 |
116 | * JDBC
117 | - 문제점3 : 서버를 재시작하면 데이터가 사라진다. 영구보존 할수있는 방법을 도입해보자.
118 | - DAO는 DB, 외부API등 데이터 접근과 관련한 모든 처리를 담당한다.
119 | - JDBC는 인터페이스이다. 각 DBMS의 드라이버를 구현체로 사용하기때문에 DBMS 교체가 용이하다.
120 |
121 | ## 7일차 - Ajax
122 | * JDBC 코드리뷰
123 | - Object... parameters : 가변인자 (배열처럼 쓸수있으며 없어도 컴파일 에러가 없음. 단, 인자의 마지막에만 위치할 수 있음)
124 | - try-with-resources는 AutoCloseable을 구현한 객체일 경우에만 가능하다
125 | - web.xml의 welcome-file-list는 root path로 접근시 무조건 먼저 읽게 하는 설정이다. 이를 수정해야 원하는 페이지로 이동가능
126 |
127 | ## 8일차 - 중간점검
128 |
129 |
130 | ## 9일차 - AWS 배포
131 | * 프로그래밍을 잘한다의 정의
132 | - 현재 처해있는 상황에서 가장 적합한 기술을 찾아 적용할 수 있는 사람
133 |
134 | * Baas를 통해 백엔드 개발자의 자리가 점점 사라지는것 아닌가
135 | - 프론트엔드, QA, DBA, 시스템 등 다른 영역과 백엔드를 연결하는 접점에 대한 수요가 점점 생기고 있다.
136 | - 좋은 서비스를 개발하기 위해서는 결국 타 영역으로 넘어가야하는 순간이 온다.
137 | - 백엔드에 일정수준에 도달하면 타 영역에 도전해보자.
138 |
139 | * 신기술 공부?
140 | - 나만의 색깔 찾기 -> 일정시간 투자해 역량 쌓기 -> 다른 분야로 관심사 넓히기
141 | - 위 사이클을 반복하자
142 | - 가장 중요한건 내가 어떤것에 장점이 있고 나의 강점이 무엇인지 파악하기
143 | - 다른 사람이 뭐라해도 흔들리지 않는 자신만의 철학을 갖기
144 |
145 | * 중간 점검 피드백
146 | - 필터의 chain.doFilter()를 기준으로 전처리/후처리를 할수가 있음
147 | - MVC 프레임워크란 MVC를 제외한 나머지는 개발자가 개발하지 않아도 되는 프레임워크를 말한다.
148 | - stack vs heap (7번 문제)
149 | - 쓰레드마다 고유의 stack영역을 가지지만 Heap은 모든 쓰레드가 공유한다.
150 | - ShowController가 Heap영역에 있어, Question/answers 역시 Heap에 있고 이로인해 쓰레드가 요청시마다 필드인 Question/answers 가 유지가 안되서 문제가 발생한다.
151 | - Layered 아키텍처 : 여러개의 클래스 사이에 중복코드가 발생하면 Composition 패턴을 사용하는것이 좋다. 우리가 controller에서 service를 호출해 service에서 비즈니스로직을 위임하듯이
152 |
153 | * 실습 - AWS 배포
154 |
155 | ## 10일차 - Spring MVC
156 | * AWS 배포 리뷰
157 | - Symbolic link로 설정들을 잡아놓으면 이후 버전 업데이트시 변경양이 최소화됨
158 | - 웹서버들의 virtual host를 통해 동일 IP에서도 호스트에 따라 할당되는 프로젝트 다르게 처리가능
159 |
160 | * 스프링 MVC
161 | - 자세한 내용을 [Blog](http://jojoldu.tistory.com/28) 에 정리하였으니 참고하자.
162 | - POJO가 특정 클래스를 상속받지 않았는데도 Spring에서 관리되도록 할수 있는데 이는 해당 class를 Bean으로 관리되도록 설정할수있기 때문이다.
163 | - DispatcherServlet는 서블릿 컨테이너가 관리하지만, 확장포인트가 있어 Spring에서 설정 수정이 가능하다.
164 | - BeanFactory를 applicationContext가 상속하고 있다. 그래서 Bean에 관련한 기능들은 BeanFactory가 하고 있고 그외에 추가적인 기능들은 ApplicationContext에 추가되어있다.
165 | - 테스트 코드 작성을 예로 들면
166 | ```
167 | ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); 로 선언하면 Bean들을 다 사용할 수 있게 된다.
168 | ```
169 |
170 | * @Bean의 @Component 차이는? [Blog](http://jojoldu.tistory.com/27) 참고!
171 |
172 | * web.xml없이 개발하기
173 | - 서블릿 3.0부터 지원하는 ServletContainerInitializer(WebApplicationInitializer)를 통해 가능하다.
174 |
175 | * MVC 프레임워크 만들기
176 | - 새로운 Request 요청은 new MockHttpServletRequest("POST", "/users") 식으로 만들수 있다.
177 |
178 | ## 11일차 - Spring MVC 실습
179 | * spring-web의 META-INF/services를 보면 ServletContainerInitializer에 풀네임의 initializer가 지정되어 있다.
180 | * 열어보면 WebApplicationInitializer 인터페이스를 구현한 모든 클래스들을 초기화 시키는 코드가 있음을 알수 있다.
181 | * MyWebInitializer에는 GET/POST 외에 다른 HTTP Method를 받을수 있도록 꼼수로 ``` ```로 지정하면 HiddenHttpMethodFilter 클래스가 처리해준다.
182 | * maven plugin에 downloadSources를 추가하면 이클립스에서 자동으로 jar를 attachment 해준다 (인텔리J는 자동으로 해줘서 신경안썼는데 유용할것같다!)
183 | * form의 input name은 model 객체의 field 이름과 매칭되는게 아니라 field의 set 메소드의 이름을 보고 자동으로 매칭을 시킨다.
184 | * Java Bean의 규약은
185 | - Default 생성자를 명시 (Controller에서 자동 매칭되는것은 디폴트 생성자를 통해서 하기 때문에)
186 | - getter/setter 메소드가 필수로 존재
187 |
188 | * 2가지 경우 중 하나는 꼭 해당되어야하는 if문을 작성할 경우 보통은 if/else로 잡지만 좀 더 안전하게 가려면 if/else if로 정상path를 잡고 else로 throw new Exception 한다. exception에는 404나 500 같은 status를 추가한다.
189 |
190 | ## 13일차 - Mockito를 활용한 테스트
191 | * class에서 상태를 가진다는게 무슨 뜻인지?
192 | - 상태 == 데이터
193 | - 메소드/함수 == 데이터(상태)를 변경
194 | - 상태 (데이터)를 관리하는 방법
195 | - 메소드의 인자를 활용
196 | - 클래스의 필드 상태값을 변경 가능하도록 구현
197 | - 클래스의 필드 상태값을 변경 불가능하도록 구현
198 |
199 | * static import : static 메소드들을 로컬 메소드처럼 메소드앞에 namespace 없이 바로 사용 가능하게 하는것
200 | * mockito
201 | - when : 어떤 메소드를 호출하면
202 | - thenReturn : 여기에 포함된 값을 리턴시킨다.
203 | - thenThrow : exception을 발생시킨다.
204 | - verify : 특정 객체가 몇번 호출 되면 등을 지정
205 | - @RunWith(MockitoJUnitRunner.class) TestClass : mockito 사용환경 구축
206 | - @Mock private UserDao userDao : userDao의 가짜 구현체를 생성
207 | - @InjectMocks private UserService userService : 내가 지정한(@Mock) 을 해당 Bean의 @Autowired 객체에 대신하고 싶다.
208 |
209 | * Junit
210 | - @Test(expected = 원하는 Exception.class) : 해당 메소드는 실행시 지정한 Exception.class가 무조건 발생한다로 비교
211 |
212 | * 객체지향적 코딩
213 | - 객체지향적인 코딩이란 상태를 가지고 있는 객체가 상태를 변경하도록 코딩을 해야한다.
214 | - 코드가 객체지향적이라면 mockito와 같은 테스트 프레임워크가 없더라도 테스트코드를 작성할수가 있다.
215 | - service가 비지니스로직의 모든것을 처리하진 않는다. 상태를 가지는 객체가 로직을 처리하는것이 맞다.
216 | - service는 도메인 객체들간의 관계를 정리하고, 캐시/트랜잭션들에 대한 처리를 할뿐이다.
217 |
218 | * 빈 컨테이너 설정 관리
219 | - 모든 Layer의 설정을 하나에서 관리 vs Layer별로 설정을 분리
220 | - excludeFilters에 Controller.class를 지정해서 @ComponentScan에서 제외시키겠다.
221 | - includeFilters에 Controller.class를 지정해서 해당 어노테이션만 스캔하겠다.
222 | - 부모/자식 구조 : 프레젠테이션 Layer(Controller)만 다르고 Service/Dao설정을 재사용
223 |
224 | * 인스턴스 추가/삭제
225 | - @PostConstruct : Bean이 생성되고 DI후, 바로 실행할 메소드 지정
226 | - @PreDestroy : Bean이 삭제되기 바로 직전에 실행할 메소드 지정
227 |
228 | * Property와 환경변수
229 | - reload resource bundle을 통해 주기적으로 properties를 체크해서 적용하도록 할수는 있다.
230 | - 변경이 있으면 안되는 DB설정 같은 경우는 제외하고, 자주 변경이 필요한 properties만 reload 설정에 포함시킨다. (설정간 분리가능)
231 |
232 | ## 14일차 - AOP
233 | * [AOP정리 참고](http://jojoldu.tistory.com/69)
234 | * properties는 한글을 유니코드로 관리하는게 디폴트다.
235 | * messageSource로 properties의 값을 몇초 주기로 리로딩할수 있다.
236 | 
237 |
238 | * AOP가 필요한 요구사항
239 | - 모든 Controller와 Dao에서 처리시간이 500ms 이상인 경우는 로그를 남겨라
240 | - Dao 클래스의 모든 method에 인자로 전달되는 인자를 debug 레벨로 로그를 남겨라
241 |
242 | * AOP가 해결하고자 하는것은 비지니스로직의 중복제거가 아닌 시스템 전반적인 중복을 제거하기 위함
243 | - 비지니스 로직 코드의 중복 제거 : OOP
244 | - 인프라 코드의 중복 제거 : AOP
245 |
246 | * FactoryBean : new 키워드를 통해 생성될수 없는 Bean들을 생성하기 위해 필요
247 | - 예를 들어, 기존 Bean에 몇가지 기능이 추가된 ProxyBean이 필요할때 FactoryBean을 implement하여 빈을 등록한다
248 | - 예전 xml로 Bean을 관리하던 시절에는 FactoryBean의 구현이 필요했지만 현재는 java code로 Bean등록이 가능하므로 현재는 잘쓰이지 않는다.
249 |
250 | * 용어
251 | - target : 부가기능을 부여할 대상
252 | - advice : target에 제공할 부가 기능을 담은 클래스
253 | - joinpoint : sadvice가 적용될 수 있는 위치, 예를 들어 method의 실행단계
254 | - pointcut : joinpoint를 선별하는 작업 또는 그 기능을 정의한 모듈
255 |
256 | ## 15일차 - Transactional & Cache & SpringBoot
257 | #### Transactional
258 | * readOnly = true : select성 메소드에서는 성능이 더 좋아서 추천
259 | * isolation level : 하나의 데이터를 반영하는데 동시에 2명이상이 접근했을때 데이터를 어떻게 관리하는지에 대한 개념
260 | - tx1에선 select, tx2에선 update를 동시에 요청하면? isolation level마다 다르다. update후 select할지, select하고 update할지
261 | * isolation level의 레벨이 낮을수록 성능은 좋고 데이터 무결성 보장성을 낮춘다.
262 |
263 | * propagation : tx 생성 rule
264 | * propagation_required : default이며, 상위계층(service)에서 하위 계층(dao)요청시 하위계층에 tx가 없으면 **상위계층의 tx를 사용**한다
265 | * propagation_new : 상위계층(service)에서 하위 계층(dao)요청시 하위계층에 tx가 없으면 **새로운 tx를 만든다**
266 | * Spring transactional은 runtime exception일 경우에만 rollback되고 checked exception에서는 rollback되지 않는다
267 | - rollbackFor = checked Exception을 지정하여 사용할 수 있다.
268 | * 테스트 코드 작성시 Dao일 경우에는 테스트 후 DB를 원복시키고 싶을경우가 많으니 class 혹은 method에 @Transactional을 지정하면 된다.
269 |
270 | #### Cache
271 | * @Cacheable(key="키값") : 해당하는 키값을 캐시하도록 지정
272 | * @CacheEvict(key="키값") : 해당하는 키값이 변경되면 캐시데이터를 변경하도록 한다
273 | * 직접 만든 캐시를 해당 어노테이션으로 관리하고자 한다면 CacheManager 구현체를 만들고 지정하면 된다
274 |
275 | ## 16일차 - JPA 소개
276 | * 설계 패러다임의 변경: Table -> Object
277 | * 대세는 쿼리매퍼에서 ORM으로 넘어가고 있다. (C#, 루비등 타언어에선 이미 ORM이 대세)
278 | * 하이버네이트와 달리 SpringDataJpa는 interface의 메소드 네이밍으로 조건절 생성
279 | * @Transient : DB 컬럼과 맵핑되는것에서 제외시킨다.
280 | * @ManyToOne을 지정했다고해서 반대편 Entity에 꼭 OneToMany를 할필요는 없다.
281 |
282 | ## 17일차 - JPA + Profile
283 | * @MappedSuperclass :
284 | 
285 |
286 | * @JpaTest (SpringBoot 1.4부터 지원)
287 | * 객체지향적인 코딩이란 객체들끼리 서로 협력해서 일을 처리하도록 하는것
288 | - 만약 서비스 메소드에서 직접 필요한 객체를 가져오는 일을 다 하고 있다면 절차지향적인 방법일 확률이 높다
289 |
290 | * API 서버 구축 도구
291 | - [Swaggger2](http://www.baeldung.com/swagger-2-documentation-for-spring-rest-api) : API를 문서화할수 있는 도구 [상세 내용](http://jojoldu.tistory.com/31)
292 | - restTemplate & @SpringBootTest
293 |
294 | 
295 |
296 | * Flyway DB
297 | - 테이블 스키마의 버전관리 (DB계의 Git이라 보면 됨)
298 | - 네이밍 규칙: V숫자__설명
299 | - ex) V1__init_db_schema.sql
300 | - Spring Boot 설정 파일에 spring.jpa.show-sql=true로 설정되어 있으면 서버가 시작할 때 생성되는 테이블 스키마, foreign key 생성 쿼리를 확인할 수 있다.
301 |
302 |
--------------------------------------------------------------------------------
/deploy.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | REPOSITORY_DIR=/home/git/jwp-basic
3 | PID="ps -ef|grep tomcat|grep java| awk ' { print $2 } '"
4 | cd $REPOSITORY_DIR
5 | sudo git pull
6 | sudo mvn clean package -Dmaven.test.skip=true
7 | kill -9 $PID
8 | mv $REPOSITORY_DIR/target/jwp-basic /usr/local/tomcat8/webapps/ROOT
9 | startup
10 |
--------------------------------------------------------------------------------
/images/fastcampus-java-1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jojoldu/fastcampus-java/33653fc622d9c61c2398a90dbd9e5e44dbb9a7b1/images/fastcampus-java-1.jpg
--------------------------------------------------------------------------------
/images/mappedsuperclass.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jojoldu/fastcampus-java/33653fc622d9c61c2398a90dbd9e5e44dbb9a7b1/images/mappedsuperclass.png
--------------------------------------------------------------------------------
/images/messageSource.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jojoldu/fastcampus-java/33653fc622d9c61c2398a90dbd9e5e44dbb9a7b1/images/messageSource.png
--------------------------------------------------------------------------------
/images/resttemplate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jojoldu/fastcampus-java/33653fc622d9c61c2398a90dbd9e5e44dbb9a7b1/images/resttemplate.png
--------------------------------------------------------------------------------
/out/production/fastcampus-java/main/Calculator.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jojoldu/fastcampus-java/33653fc622d9c61c2398a90dbd9e5e44dbb9a7b1/out/production/fastcampus-java/main/Calculator.class
--------------------------------------------------------------------------------
/out/production/fastcampus-java/main/StringCalculator.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jojoldu/fastcampus-java/33653fc622d9c61c2398a90dbd9e5e44dbb9a7b1/out/production/fastcampus-java/main/StringCalculator.class
--------------------------------------------------------------------------------
/out/production/fastcampus-java/test/main/CalculatorTest.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jojoldu/fastcampus-java/33653fc622d9c61c2398a90dbd9e5e44dbb9a7b1/out/production/fastcampus-java/test/main/CalculatorTest.class
--------------------------------------------------------------------------------
/out/production/fastcampus-java/test/main/StringCalculatorTest.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jojoldu/fastcampus-java/33653fc622d9c61c2398a90dbd9e5e44dbb9a7b1/out/production/fastcampus-java/test/main/StringCalculatorTest.class
--------------------------------------------------------------------------------
/review/README.md:
--------------------------------------------------------------------------------
1 | # 패스트캠퍼스 자바지기님의 강의 수강을 마치며
2 |
3 | 2016.06.27 ~ 2016.08.25 총 8.5주라는 시간동안 [자바지기님의 강의](http://www.fastcampus.co.kr/dev_camp_jwp/)를 수강하였다.
4 | * 강의는 얼마나 좋았는가?
5 | - 얼리버드라서 할인을 받았지만 120만원(기본은 145만원)이란 금액을 지불하였다. (내돈으로.. 회사돈 아님)
6 | - 근데 이번 강의의 다음 스탭에 해당하는 강의가 개설되면 또 들을 생각이다. 내돈으로
7 | - 8주에 120~150만원 이란 금액이 작은 금액은 아니다. 근데 **또 들어야겠다고 생각이 들정도로 좋은 강의**였다.
8 |
9 | 강의 내용에 대해선 [Github](https://github.com/jojoldu/fastcampus-java)에 정리 하였으니 참고하면 좋을것 같다.
10 | (아직도 작성중이다. 수업내용을 복기하는 마음으로 다시 보면서 내용을 추가/수정중이다.)
11 | * 다른 회사의 개발방식을 알수 있었다.
12 | - 우리회사도 SpringBoot와 ORM을 사용중이다 (SpringDataJpa가 아닌 네이티브 하이버네이트이지만...)
13 | - 하지만 TDD를 진행하지 않고 있으며,
14 | - 개인적으로 **가장 좋았던 부분**이다.
15 |
16 | * 맞춤형 강의였다.
17 | - 2주정도 지난 시점에서 수강생들의 실력이 비슷하지 않다는것을 인지하시고, 강의 내용을 2가지 타입으로 나누셨다.
18 | - A : SpringMVC 이미 사용해본 수강생들에겐 직접 MVC/DI 프레임워크를 구축하는 과정을 진행
19 | - B : SpringMVC 혹은 웹개발을 처음 접한 수강생들에겐 SpringMVC를 사용한 웹개발 과정을 진행
20 | - 각자 실력에 맞게 A/B를 나눠서 동시 진행하다보니 너무 어려워하거나 쉬워하는 수강생들이 줄어 끝까지 텐션을 유지할 수 있었다.
21 |
22 | * 우리가 사용중인 프레임워크를 직접 구현해보았다.
23 | - 톰캣도 없고, Spring도 없는 상황에서 순수 Servlet 만으로 게시판을 구현해보는 경험은 절대 이 시간외에는 경험해보지 못했을 것이다.
24 | - HttpRequest가 쓰레드를 상속 받는것을 이제야 알았다.
25 | - JDBC Template를 직접 구현해보았다. (난 시간이 되서 ORM도 도전해보았다.)
26 | -
27 |
28 | * TDD를 시작할수 있게 되었다.
29 | - 사내 우리팀에서 TDD가 활성화 되어 있지 않아(타팀은 하는지 잘모르겠어서..), 온라인상에서 아무리 TDD의 중요성을 외쳐도 실감하지 못하고 있었다.
30 | - 책이나 동영상 강의로 혼자 공부하기는 어려웠다. 뜬구름잡는 이야기도 많았고, 웹 프로젝트보다는 Java 어플리케이션을 예제코드로 보여줘서 Bean Injection, DB연동, HttpRequest 등에 대한 테스트를 알수없었다.
31 | - 강의에서 Junit & Mockito같은 테스트 프레임워크 없이 테스트 코드
32 | - 블로그에 기술관련 포스팅을 할 경우 항상 테스트 코드를 통해 코드를 공개하게 되었다.
33 | - 회사에서 웬만큼 일정이 급하지 않은 경우에 테스트 코드를 작성하면서 개발을 진행하게 되었다.
34 |
35 | * 객체지향적 코딩에 대해
36 | -
37 |
--------------------------------------------------------------------------------
/src/main/week1/Calculator.java:
--------------------------------------------------------------------------------
1 | package main.week1;
2 |
3 | /**
4 | * Created by jojoldu@gmail.com on 2016-06-27.
5 | */
6 | public class Calculator {
7 | public int add(int a, int b){
8 | return a+b;
9 | }
10 |
11 | public int minus(int a, int b){
12 | return a-b;
13 | }
14 |
15 | public int divide(int a, int b) {
16 | return a/b;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/week1/StringCalculator.java:
--------------------------------------------------------------------------------
1 | package main.week1;
2 |
3 | import java.util.regex.Matcher;
4 | import java.util.regex.Pattern;
5 |
6 | /**
7 | * Created by jojoldu@gmail.com on 2016-06-27.
8 | */
9 | public class StringCalculator {
10 | public int add(String str){
11 | if (isBlank(str)) return 0;
12 |
13 | return sum(getStrArray(str, getSplitChar(str)));
14 | }
15 |
16 | private boolean isBlank(String str) {
17 | return str == null || str.isEmpty();
18 | }
19 |
20 | private int sum(String[] strs) {
21 | int result = 0;
22 | for(String s : strs){
23 | result += str2int(s);
24 | }
25 | return result;
26 | }
27 |
28 | public String getSplitChar(String str){
29 | String defaultSplit = ",|:";
30 | String regex = "\\/\\/(.*?)\\\n";
31 | Pattern p = Pattern.compile(regex);
32 | Matcher m = p.matcher(str);
33 | if(!m.find()){
34 | return defaultSplit;
35 | }
36 | return m.group(1);
37 | }
38 |
39 | public String[] getStrArray(String str, String split){
40 | String[] arr = str.split(split);
41 | if(isNotNumber(arr[0]) && isNotNumber(arr[1])){
42 | arr[0] = "0";
43 | arr[1] = arr[1].replaceAll("\\\n", "");
44 | }
45 | return arr;
46 | }
47 |
48 | private boolean isNotNumber(String str){
49 | try {
50 | Integer.parseInt(str);
51 | return false;
52 | } catch (NumberFormatException e) {
53 | return true;
54 | }
55 | }
56 |
57 | private int str2int(String str){
58 | try {
59 | int result = Integer.parseInt(str);
60 | if(result < 0){
61 | throw new RuntimeException();
62 | }
63 | return result;
64 | } catch (NumberFormatException e) {
65 | return 0;
66 | }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/test/main/week1/CalculatorTest.java:
--------------------------------------------------------------------------------
1 | package test.main.week1;
2 |
3 | import main.week1.Calculator;
4 | import org.junit.Test;
5 | import org.junit.Before;
6 | import org.junit.After;
7 | import static org.junit.Assert.*;
8 |
9 | /**
10 | * Calculator Tester.
11 | *
12 | * @author
13 | * @since