[우리FISA] 클라우드 서비스 개발 9주차 회고 📑
1. 이번 주 학습 내용 📖
데이터 모델링, 정규화
현실에 존재하는 데이터를 데이터베이스에 적용하는 데이터 모델링을 배웠다.
ER모델을 통한 개념 모델링과 각 테이블 간의 관계 구분 및 정규화를 통한 논리 모델링 실습을 하면서 데이터베이스를 구축할 때는 고려할 사항들이 생각보다 많음을 느꼈다.
정보처리기사 공부할 때 열심히 외웠던 정규화가 왜 필요한 지에 대해 알 수 있었다.
실습한 것을 기반으로 신용등급에 따라 대출 상품 추천 목록을 조회하는 프로젝트를 수행했다.
실제 서비스라 생각하고 ERD 구축 실습을 해보면서 각 테이블에 필요한 컬럼들을 생각해보고 관계를 정의해보는 과정이 재밌었다.

JDBC API
데이터베이스에 저장된 데이터를 Java에서 활용하기 위한 java api인 JDBC에 대해 배웠다.
동작 흐름은 대략 다음과 같았다.
1. JDBC 드라이버 로딩 : 사용하고자 하는 JDBC 드라이버를 DriverManager 클래스를 통해 로딩한다.
2. Connection 객체 생성 : JDBC 드라이버가 로딩되면 DriverManager를 통해 데이터베이스와 연결되는 세션인 Connection 객체를 생성한다.
3. Statement 객체 생성 : Statement 객체는 작성된 SQL 쿼리문을 실행하기 위한 객체로 SQL 쿼리 문자열을 입력값으로 가진다.
4. Query 실행 : 생성된 Statement 객체에 들어간 SQL 쿼리를 실행한다.
5. ResultSet 데이터 조회 : 실행된 SQL 쿼리문에 대한 결과 데이터 셋을 조회한다.
6. 객체 Close : JDBC API를 통해 사용된 ResultSet, Statement, Connection 객체들을 사용한 순서의 역순으로 Close 한다.
그런데 java7 이후에 등장한 try-with-resources 문법에서는 자동으로 자원 해제를 처리해주는 기능을 제공했기에 굳이 close를 해줄 필요가 없었다.
// Java 7 이후 - try-with-resources 문법
public List<Todo> findAll() throws SQLException {
List<Todo> todos = new ArrayList<Todo>();
String selectQuery = "SELECT * FROM todo";
Connection connection = DBUtil.getConnection();
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(selectQuery);
// DBMS에게 쿼리(SQL)를 전달할 객체 생성
try (connection; statement; resultSet) {
while(resultSet.next()) {
int id = resultSet.getInt("id");
String title = resultSet.getString("title");
String description = resultSet.getString("description");
//java.sql.Date
Date date = resultSet.getDate("due_date");
LocalDate dueDate = date.toLocalDate();
boolean isCompleted = resultSet.getBoolean("is_completed");
todos.add(new Todo(id, title, description, dueDate, isCompleted));
}
} catch (SQLException e) {
e.printStackTrace();
}
return todos;
}
실습 프로젝트에서 직접 db를 구축하고 jdbc로 연결해 java로 sql 쿼리를 실행하며 데이터 CRUD를 수행했다.
이론으로만 알고 있던 JDBC를 직접 사용해볼 수 있어 좋았다.
Servlet
웹페이지를 동적으로 생성하는 서버 사이드 프로그램인 Servlet에 대해 배웠다.
servlet을 구동하기 위한 컨테이너 역할을 수행하는 tomcat도 같이 사용했다.
다음과 같은 코드로 servlet의 라이프 사이클을 알아보았다.
package dev.syntax.step02servletprocess;
import java.io.IOException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/LifeCycleServlet")
public class LifeCycleServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public LifeCycleServlet() {
super();
System.out.println("LifeCycleServlet() called");
}
public void init(ServletConfig config) throws ServletException {
System.out.println("init() called");
}
public void destroy() {
super.destroy();
System.out.println("destroy() called");
}
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("service() called");
super.service(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("doGet() called");
response.getWriter().append("Served at: ").append(request.getContextPath());
}
}
서블릿의 생명 주기는 init(), service(), destroy() 메서드 호출 순서로 진행된다.
서블릿이 처음 로드될 때, 즉 웹 애플리케이션 시작 또는 첫 요청이 있을 때 LifeCycleServlet() 생성자가 호출되고 이후 init() 메서드가 호출된다.
클라이언트로부터 HTTP 요청이 오면 service() 메서드가 호출되고 이 메서드 내에서는 HTTP 요청 방식(GET, POST, PUT, DELETE 등)에 따라 적절한 메서드(doGet(), doPost() 등)를 호출한다.
이후 웹 애플리케이션을 종료하면 destroy() 메서드가 호출되는 것이다.
따라서 다음과 같은 순서로 출력됨을 알 수 있었다.
LifeCycleServlet() called
init() called
service() called
doGet() called
destroy() called
쿠키와 세션
쿠키와 세션에 직접 데이터를 저장하고 불러와보는 실습도 했다.
쿠키는 클라이언트, 즉 웹 브라우저에 저장되어 개발자 도구에서 확인이 가능하다.
반면 세션은 서버 측에 저장되며 서버가 가진 특정 객체에 저장이 된다.
이 쿠키와 세션을 사용하는 이유는 HTTP 프로토콜이 가진 비연결성과 비상태성이라는 특징 때문이었다.
모든 사용자의 요청마다 연결과 해제를 하기 때문에 연결 상태가 유지되지 않고 상태 정보가 저장되지 않기에 웹 사이트 재방문 시 효율적으로 서비스를 제공하기 위해 사용한다는 것이다.
세션에 아이디와 비밀번호를 저장하고 로그인, 로그아웃을 하는 간단한 기능 구현을 실습했다.
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=UTF-8");
PrintWriter out = resp.getWriter();
String id = req.getParameter("id");
String pwd = req.getParameter("pwd");
if (id.isEmpty() || pwd.isEmpty()) {
out.print("아이디 및 비밀번호를 입력해주세요");
return;
}
HttpSession session = req.getSession();
if (session.isNew() || session.getAttribute("id") == null) {
session.setAttribute("id", id); // id라는 이름의 키값에 사용자의 id값을 value로 설정
out.print("로그인 완료");
} else {
out.print("이미 로그인 중입니다.");
}
out.close();
}
}
@WebServlet("/logout")
public class LogoutServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
HttpSession session = request.getSession();
if (session != null && session.getAttribute("id") != null) {
session.invalidate();
out.print("로그아웃 완료");
} else {
out.print("로그인 상태가 아닙니다");
}
out.close();
}
}
cs스터디에서 이론상으로만 공부했던 쿠키와 세션을 직접 실습해보며 왜 쿠키와 세션을 사용하는지에 대해 이해할 수 있었다.
2. CS 스터디 📔
화요일 저녁, 네트워크라는 큰 주제 안에서 각자 맡은 키워드에 대해 조사한 내용을 공유했다.
각 키워드에서 궁금한 점들을 질문하고 토론하며 부족했던 지식들을 채워가는 과정이 재밌었다.
몰랐던 부분에 대해 새로 알게되고 헷갈렸던 개념을 다시 정리하며 cs 지식을 쌓아가니 정말 개발자로서의 뇌(?)를 갖춰가는 기분이 들었다.🧠
특히 쿠키와 세션, TCP가 연결을 수립하고 해제하는 3-way handshaking과 4-way handshaking에 대해 깊게 이해할 수 있었다.
열심히 얘기하다보니 예상보다 시간이 꽤 많이 소요되었고 오히려 시간이 부족했다. 😮
내가 맡았던 부분은 http, https, http 메소드, 로드밸런싱이었는데 시간이 부족해 결국 나는 다음 주에 발표하게 되었다.
cs스터디가 끝나고 나니 정말 피곤했지만 스터디 시간은 재밌었다.😀
다음 주는 데이터베이스를 주제로 스터디할 예정인데 벌써부터 또 어떤 새로운 것을 배울 지 기대된다.😆
3. 알고리즘 스터디 💻
목요일 저녁, 알고리즘 스터디를 진행했다.
이번 주는 BFS가 주제였다.
사실 영화 웡카 시사회에 당첨되어 스터디를 빠지고 영화보러 가고싶었지만 BFS에 자신이 없었기에 영화보단 스터디를 택했다. 😥
DFS는 재귀식이라면 BFS는 queue를 사용해 푸는 방식이다.
기본 틀을 외우고 문제마다 응용하는 것이 필요한데 응용이 왜이렇게 어렵게 느껴지는지 모르겠다.. 😂
아직 연습이 많이 필요한 것 같다.
원래 주말에 주로 알고리즘 문제를 푸는 편인데 2주 연속 필기 시험 준비에 신경쓰다보니 우선순위에서 밀려 지난 주부터 알고리즘 문제 풀이에 다소 소홀했다.
다음 주부터는 다시 열심히!!!💪
4. 이번 주 음식 🍚🥘🥣🍲



