스프링의 핵심개념인 DI와 스프링 IoC컨테이너의 개념을 이해하기
스프링의 Controller, Service, Repository 의 필요성을 이해하기
스프링 학습 전략
- 간단한 프로젝트들을 만들어 사용법 위주의 경험을 쌓는다. (예. 웹 개발의 봄 '스프링' 과정)
- 그 프로젝트들에 원하는 기능들을 기획하고 추가해 본다.
- 필요한 부분들을 중점적으로 학습한다.
- 자주 막히는 부분 위주로!
- 어떻게 사용하는게 맞는지 아리송할때!
- 스프링 학습은 주제 별로, 이해가 가는 부분까지만 학습 반복
- 너무 완벽히 이해하려고 하지 말기
Servlet (서블릿)은 자바를 사용하여 웹페이지를 동적으로 생성하는 서버측 프로그램 혹은 그 사양을 말함
package com.sparta.springcore;
import com.fasterxml.jackson.databind.ObjectMapper;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.*;
import java.time.LocalDateTime;
import java.util.ArrayList;
@WebServlet(urlPatterns = "/api/products/*", loadOnStartup = 1)
public class AllInOneServlet extends HttpServlet {
// 신규 관심상품 등록
// POST /api/products
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
// 요청 Body 의 JSON -> 자바 객체
ProductRequestDto requestDto = null;
StringBuffer jb = new StringBuffer();
String line = null;
try {
BufferedReader reader = request.getReader();
while ((line = reader.readLine()) != null)
jb.append(line);
ObjectMapper objectMapper = new ObjectMapper();
requestDto = objectMapper.readValue(jb.toString(), ProductRequestDto.class);
} catch (Exception e) { /*report an error*/ }
// 요청받은 DTO 로 DB에 저장할 객체 만들기
Product product = new Product(requestDto);
LocalDateTime now = LocalDateTime.now();
product.setCreatedAt(now);
product.setModifiedAt(now);
// DB 연결
try {
Connection connection = DriverManager.getConnection("jdbc:h2:mem:springcoredb", "sa", "");
// DB Query 작성
PreparedStatement ps = connection.prepareStatement("select max(id) as id from product");
ResultSet rs = ps.executeQuery();
if (rs.next()) {
// product id 설정 = product 테이블의 마지막 id + 1
product.setId(rs.getLong("id") + 1);
} else {
throw new SQLException("product 테이블의 마지막 id 값을 찾아오지 못했습니다.");
}
ps = connection.prepareStatement("insert into product(id, title, image, link, lprice, myprice, created_at, modified_at) values(?, ?, ?, ?, ?, ?, ?, ?)");
ps.setLong(1, product.getId());
ps.setString(2, product.getTitle());
ps.setString(3, product.getImage());
ps.setString(4, product.getLink());
ps.setInt(5, product.getLprice());
ps.setInt(6, product.getMyprice());
ps.setString(7, product.getCreatedAt().toString());
ps.setString(8, product.getModifiedAt().toString());
// DB Query 실행
ps.executeUpdate();
// DB 연결 해제
ps.close();
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
// 자바 객체 -> JSON 으로 변환
ObjectMapper objectMapper = new ObjectMapper();
String productJson = objectMapper.writeValueAsString(product);
// 응답 보내기
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
out.print(productJson);
out.flush();
}
// 희망 최저가 변경
// PUT /api/products/{id}
@Override
protected void doPut(HttpServletRequest request, HttpServletResponse response) throws IOException {
// 요청 URL 에 입력되어 있는 'id' 파라미터 조회
String uri = request.getRequestURI();
String idStr = uri.substring(uri.lastIndexOf("/") + 1);
Long id = Long.parseLong(idStr);
// 요청 BODY 의 JSON -> 자바 객체
ProductMypriceRequestDto requestDto = null;
StringBuffer jb = new StringBuffer();
String line = null;
try {
BufferedReader reader = request.getReader();
while ((line = reader.readLine()) != null)
jb.append(line);
ObjectMapper objectMapper = new ObjectMapper();
requestDto = objectMapper.readValue(jb.toString(), ProductMypriceRequestDto.class);
} catch (Exception e) { /*report an error*/ }
Product product = new Product();
try {
// DB 연결
Connection connection = DriverManager.getConnection("jdbc:h2:mem:springcoredb", "sa", "");
// DB Query 작성
PreparedStatement ps = connection.prepareStatement("select * from product where id = ?");
ps.setLong(1, id);
// DB Query 실행
ResultSet rs = ps.executeQuery();
if (rs.next()) {
product.setId(rs.getLong("id"));
product.setCreatedAt(rs.getTimestamp("created_at").toLocalDateTime());
product.setModifiedAt(rs.getTimestamp("modified_at").toLocalDateTime());
product.setImage(rs.getString("image"));
product.setLink(rs.getString("link"));
product.setLprice(rs.getInt("lprice"));
product.setMyprice(rs.getInt("myprice"));
product.setTitle(rs.getString("title"));
} else {
throw new NullPointerException("해당 아이디가 존재하지 않습니다.");
}
// DB Query 작성
ps = connection.prepareStatement("update product set myprice = ?, modified_at = ? where id = ?");
ps.setInt(1, requestDto.getMyprice());
ps.setString(2, LocalDateTime.now().toString());
ps.setLong(3, product.getId());
// DB Query 실행
ps.executeUpdate();
// DB 연결 해제
rs.close();
ps.close();
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
// 자바 객체 -> JSON 으로 변환
ObjectMapper objectMapper = new ObjectMapper();
String productIdJson = objectMapper.writeValueAsString(product.getId());
// 응답 보내기 (업데이트된 상품 id)
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
out.print(productIdJson);
out.flush();
}
// 등록된 전체 상품 목록 조회
// GET /api/products
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
ArrayList<Product> products = new ArrayList<>();
try {
// DB 연결
Connection connection = DriverManager.getConnection("jdbc:h2:mem:springcoredb", "sa", "");
// DB Query 작성 및 실행
Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery("select * from product");
// DB Query 결과를 상품 객체 리스트로 변환
while (rs.next()) {
Product product = new Product();
product.setId(rs.getLong("id"));
product.setCreatedAt(rs.getTimestamp("created_at").toLocalDateTime());
product.setModifiedAt(rs.getTimestamp("modified_at").toLocalDateTime());
product.setImage(rs.getString("image"));
product.setLink(rs.getString("link"));
product.setLprice(rs.getInt("lprice"));
product.setMyprice(rs.getInt("myprice"));
product.setTitle(rs.getString("title"));
products.add(product);
}
// DB 연결 해제
rs.close();
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
// 자바 객체 -> JSON 으로 변환
ObjectMapper objectMapper = new ObjectMapper();
String productsJson = objectMapper.writeValueAsString(products);
// 응답 보내기
response.setHeader("Content-Type", "application/json");
response.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
out.print(productsJson);
out.flush();
}
}
코드가 복잡해지고 중복코드가 많아진다.
가독성이 떨어진다. 하나를 바꾸려면 오래걸린다.
@Controller 는 스프링 서버 개발자 입장에서는 시작점과 끝점으로 보이지만, 사실 스프링이 사용자의 요청 (Request) 과 응답 (Response) 을 처리해 주고 있습니다.
객체지향적으로 프로그래밍을 해야 한다.
스프링은 DI를 통해 객체를 대신 생성해준다. 스프링이 생성해주는 객체를 빈(Bean)이라고 한다. 이 빈을 모아둔 곳이 IoC 컨테이너. 우리는 IoC컨테이너에 등록되어있는 빈을 사용하면 된다. 기본적으로 싱글턴 형태로 되어있다.
스프링 프레임워크란?
The Spring Framework provides a comprehensive programming and configuration model for modern Java-based enterprise applications - on any kind of deployment platform.
* 출처: 스프링 공식 홈페이지
A key element of Spring is infrastructural support at the application level: Spring focuses on the "plumbing" of enterprise applications so that teams can focus on application-level business logic, without unnecessary ties to specific deployment environments.
* 출처: 스프링 공식 홈페이지
스프링 프레임워크를 통해 개발자는 비즈니스 로직만 신경쓰면 된다.