Spring - ToDoList 만들기

HI_DO·2024년 6월 7일
post-thumbnail
package org.zerock.w1.todo;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(name = "todoListController", urlPatterns = "/todo/list")
public class TodoListController extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {       System.out.println(("/todo/list"));
        req.getRequestDispatcher("/WEB-INF/todo/list.jsp").forward(req, resp);
    }
}
  • 실행 및 결과
  • list.jsp 생성
  • TodoRegisterController.java 생성
package org.zerock.w1.todo;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(name="todoRegisterController",urlPatterns = "/todo/register")
public  class  TodoRegisterController extends HttpServlet{
    @Override
    protected void  doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
        System.out.println("입력화면을 볼 수 있도록 설정");
        RequestDispatcher dispatcher = req.getRequestDispatcher("/WEB-INF/todo/register.jsp");
        dispatcher.forward(req,resp);
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
        System.out.println("입력을 처리하고 목록 페이지로 이동");
    }
}
  • 참고
  • register.jsp 생성
<%--
  Created by IntelliJ IDEA.
  User: EZEN
  Date: 2024-06-07
  Time: 오전 9:54
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<form action="/todo/register" method="post">
    <button type="submit">등록처리</button>
</form>
</body>
</html>
  • 실행 및 결과
  • 실행 오류 및 수정


    (Ctrl+Alt+s)

Redirect

  • '새로고침'을 하는 경우에 계속해서 post방식의 호출이 된다.
    서버에서 동일한 호출이 여러번 이루어질때 "양식을 다시 제출하시겠습니까?"라는 메시지가 보여진다.
    이를 막기 위해서 PRG패턴을 적용하도록 sendRedirect()가 필요하다
  • TodoRegisterController 수정
package org.zerock.w1.todo;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(name="todoRegisterController",urlPatterns = "/todo/register")
public  class  TodoRegisterController extends HttpServlet{
    @Override
    protected void  doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
     System.out.println("doGet*******");
        RequestDispatcher dispatcher = req.getRequestDispatcher("/WEB-INF/todo/register.jsp");
        dispatcher.forward(req,resp);
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
   System.out.println("doPost*******");
        // 브라우저가 호출해야 하는 주소
        resp.sendRedirect("/todo/list");
    }
}
  • 실행 및 결과



  • 수정 후 실행 및 결과
package org.zerock.w1.todo;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(name="todoRegisterController",urlPatterns = "/todo/register")
public  class  TodoRegisterController extends HttpServlet{
    @Override
    protected void  doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
        System.out.println("겟");
        RequestDispatcher dispatcher = req.getRequestDispatcher("/WEB-INF/todo/register.jsp");
        dispatcher.forward(req,resp);
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
        System.out.println("포스트");
        // 브라우저가 호출해야 하는 주소
        resp.sendRedirect("/todo/list");
    }
}

Model(모델)

  • 서비스(로직)계층과 영속(데이터)계층

DTO(Data Transfer Object)

  • 데이터 교환을 위한 객체
    여러개를 하나의 객체로 묶어서 전달하는것을 DTO라고 한다.
    DTO는 여러개의 데이터를 묶어서 필요한 곳에 전달하거나 호출을 결과로 바꾸는 방식으로 사용하기 때문에 특별한 규격이나 제약이 있는 것은 아니지만, 대부분은 Java Beans 형태로 구성하는 경우가 많다.
  • Java Beans의 구성
  1. 생성자가 없거나 반드시 파라미터가 없는 생성자 함수를 가진 형태
  2. 속성(멤버 변수)은 private로 작성
  3. getter/setter를 제공할 것
  • dto 패키지 및 TodoDTO.java 생성

  • (Alt+Insert) - 하나로 묶어서 만드는 객체 -> 이것이 DTO 작업





    -> 함수로 처리하는 것은 불변성과 보안 때문이다.

서비스 객체

  • '기능(로직)들의 묶음' 기능들의 실제 처리를 담당.
  • CRUD(등록/조회/수정/삭제) 기능들을 모두 서비스 객체에 모아서 구현
  • TodoService -> TodoListController, TodoRegisterController, TodoModifyController, Todo RemoveController
  • service 패키지 및 TodoSerive 생성
  • TodoService.INSTANCE는 하나의 객체만을 가리키게 되는데 이처럼 객체를 하나만 생성해서 사용하는 패턴을 싱글톤 패턴(singleton pattern)이라고 한다.
    여러 컨트롤러들이 TodoService객체를 통해서 원하는 데이터를 주고 받는 구조로 구성하기 때문에 TodoService객체를 하나만 생성하도록 한것
package org.zerock.w1.todo.service;
import org.zerock.w1.todo.dto.TodoDTO;
import java.time.LocalDate;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public enum TodoService {
    INSTANCE;
    public void  register(TodoDTO todoDTO){       System.out.println("DEBUG.............." + todoDTO);
    }
    public List<TodoDTO> getList(){
   										 //0-9번까지만 순회
        List<TodoDTO> todoDTOS = IntStream.range(0,10).mapToObj(i->{
            TodoDTO dto = new TodoDTO();
            dto.setTno((long)i);
            dto.setTitle("Todo.."+i);       dto.setDueDate(LocalDate.now());
            return dto;    
            // mapToObj에서 생성된 TodoDTO객체들을 리스트로 만들고 리스트로 반환.           }).collect(Collectors.toList());
        return todoDTOS;
    }
}
  • TodoListController 수정
package org.zerock.w1.todo;
import org.zerock.w1.todo.dto.TodoDTO;
import org.zerock.w1.todo.service.TodoService;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
@WebServlet(name = "todoListController", urlPatterns = "/todo/list")
public class TodoListController extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {      System.out.println(("/todo/list"));
        List<TodoDTO> dtoList = TodoService.INSTANCE.getList();
        //list라는 이름으로 dtoList객체를 보관해서 넘기는 메서드
        req.setAttribute("list", dtoList);
       req.getRequestDispatcher("/WEB-INF/todo/list.jsp").forward(req, resp);
    }
}
  • list.jsp 수정
<%--
  Created by IntelliJ IDEA.
  User: EZEN
  Date: 2024-06-07
  Time: 오전 9:41
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<h1>List Page</h1>
${list}
</body>
</html>
  • 실행 및 결과

JSTL(JavaServer Pages Standard Tag Library)

  • JSP에서 동작하는 새로운 태그들의 묶음.
    자바 문법보다 더 간결하게 제어문이나, 반복문 선언문 등을 처리할 수 있고 확장이 가능하도록 설계되어있다.
  • build.gradle에서 library 설치

    -> 보통은 https://mvnrepository.com/artifact/jakarta.servlet.jsp.jstl 여기서 다운 받음
  • list.jsp 수정
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<h1>List Page</h1>
<ul>
    <c:forEach var="dto" items="${list}">
        <li>${dto}</li>
    </c:forEach>
</ul>
</body>
</html>
  • 실행 및 결과
  • TodoService 수정
package org.zerock.w1.todo.service;
import org.zerock.w1.todo.dto.TodoDTO;
import java.time.LocalDate;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public enum TodoService {
    INSTANCE;
    public void  register(TodoDTO todoDTO){
        System.out.println("DEBUG.............." + todoDTO);
    }
    public List<TodoDTO> getList(){                                               //0-9번까지만 순회
        List<TodoDTO> todoDTOS = IntStream.range(0,10).mapToObj(i->{
            TodoDTO dto = new TodoDTO();
            dto.setTno((long)i);
            dto.setTitle("Todo.."+i);
            dto.setDueDate(LocalDate.now());
            return dto;
            // mapToObj에서 생성된 TodoDTO객체들을 리스트로 만들고 리스트로 반환.        }).collect(Collectors.toList());
        return todoDTOS;
    }
    public TodoDTO get(Long tno){
        TodoDTO dto = new TodoDTO();
        dto.setTno(tno);
        dto.setTitle("Sample Todo");        dto.setDueDate(LocalDate.now());
        dto.setFinished(true);
        return dto;
    }
}

  • TodoReadController.java 생성
package org.zerock.w1.todo;
import org.zerock.w1.todo.dto.TodoDTO;
import org.zerock.w1.todo.service.TodoService;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(name = "todoReadController", urlPatterns = "/todo/read")
public class TodoReadController extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{       System.out.println("/todo/read");
        //      /todo/read?tno=123
        Long tno = Long.parseLong(req.getParameter("tno"));
        TodoDTO dto = TodoService.INSTANCE.get(tno);
        req.setAttribute("dto",dto);
       req.getRequestDispatcher("/WEB-INF/todo/read.jsp").forward(req,resp);
    }
}
  • read.jsp 생성
<%--
  Created by IntelliJ IDEA.
  User: EZEN
  Date: 2024-06-07
  Time: 오후 12:35
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<div>${dto.tno}</div>
<div>${dto.title}</div>
<div>${dto.dueDate}</div>
<div>${dto.finished}</div>
</body>
</html>
  • 실행 및 결과

웹과 데이터베이스

  • 데이터베이스(데이터를 보관하고 관리하는 )에서 가장 많이 사용하는 관계형 데이터베이스를 구축. Maria DB를 통해 자바프로그램과 연동하는 JDBC프로그래밍을 확인한다.
    https://mariadb.org/download/



    _''는 서버 충동날 수도 있어서 쓰는거임



    -----------여기까지 테스트-------------













    (3.1.4 다운)

JDBC

  • Java Database connectivity의 약자
  • 자바 프로그램과 데이터베이스를 네트워크 상에서 연결하며 데이터를 교환하는 프로그램
  • JDBC 프로그램을 작성하려면 데이터베이스와 자바 사잉에서 네트워크 데이터를 처리하는 코드가 필요한데 JDBC드라이버가 이런 역할을 수행한다.
  • 매우작은 정수 1bytr(-128~127)
    finished TINYINT DEFAULT 0.
  • dao 패키지와 ConnectTests.java 생성
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import java.sql.Connection;
import java.sql.DriverManager;
public class ConnectTests {
    @Test
    public void testConnection() throws Exception{        
        // jdbc 드라이버 클래스를 메모리상으로 로딩하는 역할.        Class.forName("org.mariadb.jdbc.Driver");
        // 데이터베이스 내에 있는 여러 정보들을 통해서 특정한 데이터베이스(webdb)에 연결을 시도
        Connection connection = DriverManager.getConnection(                "jdbc:mariadb://localhost:3307/webdb",
                "webuser",
                "webuser"
        );
        //데이터베이스와 정상적으로 연결이 된다면 true        Assertions.assertNotNull(connection);
        // 데이터베이스 연결 종료
        connection.close();
    }
}
  • console 수정
CREATE TABLE webdb.tbl_todo (
                                tno INT AUTO_INCREMENT PRIMARY KEY,
                                title VARCHAR(100) NOT NULL,
                                dueDate DATE NOT NULL,
                                finished TINYINT DEFAULT 0,
                                writer VARCHAR(100)
);
insert into tbl_todo (title, dueDate, finished) values ('Test...', '2024-12-31', 1);
select * from tbl_todo;
select * from tbl_todo where tno >= 3;
update tbl_todo set finished =0, title ='Not Yet...' where tno = 3;
delete  from tbl_todo where tno>3;

JDBC 프로그래밍을 위한 API용어들

  • 자바를 이용해서 데이터베이스를 연동하는 프로그램을 작성하기 위해서 필수적인 API
  1. java.sql.Connection
    스와 네트워크상의 연결을 의미합니다. 데이터베이스에 SQL을 실행하기 위해서는 반드시 정상적인 Connection 타입의 객체를 생성해야 합니다. 개발자들은 Connection이라는 인터페이스를 활용하고 실제 구현 클래스는 JDBC 드라이버 파일 내부의 클래스를 이용합니다.
    JDBC 프로그래밍에서 가장 중요한 사실은 ‘Connection은 반드시 close()해야 한다’입니다.
    데이터베이스는 많은 연결을 처리해야 하는데 연결이 종료가 되지 않으면 새로운 연결을 받을 수 없는 상황이 발생합니다. Connection의 close()는 데이터베이스쪽에 연결을 끊어도 좋다는 신호를 주고 네트워크 연결을 종료하는 역할을 합니다.
Connection connection = ...
PreparedStatement preparedStatement = connection.preparedStatement("select * from tbl_todo");

-> java.sql.Statement/PreparedStatement
JDBC에서 SQL을 데이터베이스로 보내기 위해서는 Statement/PreparedStatement 타입을 이용합니다.(이 외에도 데이터베이스 내 프로시저 등을 호출하기 위한 CallableStatement라는 것이 존재하긴 합니다만, 순수한 SQL은 Statement/PreparedStatement를 이용합니다).
Statement와 PreparedStatement는 SQL을 전달한다는 점에서 같지만 SQL문을 미리 전달하고 나중에 데이터를 보내는 방식(PreparedStatement)과 SQL문 내부에 모든 데이터를 같이 전송하는 방식(Statement)이라는 차이가 있습니다. 실제 개발에서는 PreparedStatement만을 이용하는 것이 관례입니다(SQL 내부에 고의적으로 다른 처리가 가능한 SQL문자열을 심어서 보내는 SQL injection 공격을 막기 위함).
-PreparedStatement의 메서드

  • setXXX(): setInt(), setString(), setDate() 와 같이 다양한 타입에 맞게 데이터를 세팅할 수 있음.
  • executeUpdate(): DML(insert/update/delete)을 실행하고 결과를 int타입으로 반환합니다. 결과는 ‘몇 개의 행(row)이 영향을 받았는가’입니다. 예를 들어 1개의 데이터가 insert되었는지와 같은 결과를 알 수 있습니다.
  • executeQuery(): 말그대로 쿼리(select)를 실행할 때 사용합니다. executeQuery() 경우에는 ResultSet이라는 리턴 타입을 이용합니다.
    Statement 역시 마지막에는 Connection과 마찬가지로 close()를 통해서 종료해 주어야만 데이터베이스 내부에서도 메모리와 같이 사용했던 자원들이 즉각적으로 정리됩니다.
  • java.sql.ResultSet
    PreparedStatement를 이용해서 insert/update/delete를 처리하는 DML의 경우에는 int로 반환되는 것과 달리 쿼리(select)를 실행했을 때 데이터베이스에서 반환하는 데이터를 읽어 들이기 위해서는 특별하게 ResultSet이라는 인터페이스를 이용합니다. ResultSet 은 자바 코드에서 데이터를 읽어 들이기 때문에 getInt(), getString() 등의 메소드를 이용해서 필요한 타입으로 데이터를 읽어 들입니다. ResultSet에는 next() 메서드가 존재하는데 데이터를 순차적으로 읽는 방식으로 구성되기 때문에 next()를 이용해서 다음 행(row)의 데이터를 읽을 수 있도록 이동하는 작업을 진행할 수 있다.
  • Connection Pool과 DataSource
    JDBC 프로그램은 기본적으로 필요한 순간에 잠깐 데이터베이스와 네트워크로 연결하고 데이터를 보내고 받는 방식으로 구성됩니다. 이 과정에서 데이터베이스와의 연결(Connection)을 맺는 작업은 많은 시간과 자원을 쓰기 때문에 여러번 SQL을 실행할수록 성능 저하는 피할 수 없습니다. JDBC에서는 보통 Connection Pool(커넥션 풀)이라는 것을 이용해서 이 문제를 해결합니다. Connection pool: Connection들을 생성해서 보관하고, 필요할 때마다 꺼내서 쓰는 방식.
    Connection pool을 HikariCP(히카리씨피)라이브러리를 사용하도록 한다.
  • DAO(Data Access Object)
    데이터를 전문적으로 처리하느 객체.
    일반적으로 데이터베이스의 접근과 처리를 전담하는 객체를 의미하는데 dao는 주로 vo를 단위로 처리한다. DAO를 호출하는 객체는 DAO가 내부에 어떤식으로 데이터를 처리하는지 알 수 없도록 구성한다.
  • DTO는 택배상자와 비슷하다고 보면되고 getter/setter를 이용해서 자유롭게 데이터를 가공할 수 있다.
  • VO 데이터베이스의 엔티티를 자바 객체를 표현한 것이고 데이터 자체를 의미하기 때문에 getter만을 이용하는 경우가 대부분이다.
    https://projectlombok.org

DAO

  • ConnectTests 수정
    package dao;
    import com.zaxxer.hikari.HikariConfig;
    import com.zaxxer.hikari.HikariDataSource;
    import org.junit.jupiter.api.Assertions;
    import org.junit.jupiter.api.Test;
    import java.sql.Connection;
    import java.sql.DriverManager;
    public class ConnectTests {
       @Test
       public void testConnection() throws Exception{
           // jdbc 드라이버 클래스를 메모리상으로 로딩하는 역할.
           Class.forName("org.mariadb.jdbc.Driver");
           // 데이터베이스 내에 있는 여러 정보들을 통해서 특정한 데이터베이스(webdb)에 연결을 시도.
           Connection connection = DriverManager.getConnection(
                   "jdbc:mariadb://localhost:3306/webdb",
                   "webuser",
                   "webuser"
           );
           // 데이터베이스와 정상적으로 연결이 된다면 true
           Assertions.assertNotNull(connection);
           // 데이터베이스연결 종료
           connection.close();
       }
       @Test
       public void testHikariCP() throws Exception{
           HikariConfig config = new HikariConfig();
           config.setDriverClassName("org.mariadb.jdbc.Driver");
           config.setJdbcUrl("jdbc:mariadb://localhost:3306/webdb");
           config.setUsername("webuser");
           config.setPassword("webuser");
           config.addDataSourceProperty("cachePrepStmts", "true");
           config.addDataSourceProperty("prepStmtCacheSize", "250");
           config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
           HikariDataSource ds = new HikariDataSource(config);
           Connection connection = ds.getConnection();
           System.out.println(connection);
           connection.close();
       }
    }
- ConnectionUtil.java 생성
```java
package org.zerock.jdbcex.dao;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import java.sql.Connection;
public enum ConnectionUtil {
    INSTANCE;
    private HikariDataSource ds;
    ConnectionUtil() {
        HikariConfig config = new HikariConfig();
        config.setDriverClassName("org.mariadb.jdbc.Driver");
        config.setJdbcUrl("jdbc:mariadb://localhost:3306/webdb");
        config.setUsername("webuser");
        config.setPassword("webuser");
        config.addDataSourceProperty("cachePrepStmts", "true");
        config.addDataSourceProperty("prepStmtCacheSize", "250");
        config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
        ds = new HikariDataSource(config);
    }
    public Connection getConnection()throws Exception{
        return ds.getConnection();
    }
}
  • TodoDAO.java 생성
package org.zerock.jdbcex.dao;
import org.zerock.jdbcex.dao.ConnectionUtil;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
public class TodoDAO {
    public  String getTime(){
        String now = null;
    // Connection: 데이터베이스와 네트워크상의 연결을 도와주는 인터페이스
        try(Connection connection = ConnectionUtil.INSTANCE.getConnection();
            //PreparedStatement는 SQL을 전달한다는 점에서 같지만 SQL문을 미리 전달하고 나중에 데이터를 보내는 방식
            PreparedStatement preparedStatement = connection.prepareStatement("select now()");
                //쿼리를 실행하기 위한 메서드, 결과는 ResultSet으로 반환받아야 한다.
            ResultSet resultSet = preparedStatement.executeQuery();
        ){
                // 데이털르 순차적으로 읽는 방식
            resultSet.next();
            now = resultSet.getString(1);
        }catch (Exception e){
            e.printStackTrace();
        }
        return now;
    }
}
  • dao 패키지 안에 TodoDAOTests.java 생성
package dao;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.zerock.jdbcex.dao.TodoDAO;
public class TodoDAOTests {
    private TodoDAO todoDAO;
    @BeforeEach // ready()를 통해서 테스트 하기전에 TodoDAO 를 생성하도록.
    public void ready(){
        todoDAO = new TodoDAO();
    }
    @Test
    public void testTime() throws Exception{
        System.out.println(todoDAO.getTime());
    }
}

lombok의 @Cleanup

  • try-catch문안에 다시 try-catch문을 해야 하는 경우가 있다.
    중첩 try-catch를 이용하는 경우 가독성이 상당히 나빠지게 된다. 이런 경우에는 @Cleanup 적용을 고려해볼수 있는데 @Cleanup이 추가된 변수는 해당 메서드가 끝날때 close()가 호출되는 것을 보장한다.
  • TodoDAO.java 수정
package org.zerock.jdbcex.dao;
import lombok.Cleanup;
import org.zerock.jdbcex.domain.TodoVO;
import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
public class TodoDAO {
    public  String getTime(){
        String now = null;
        //  Connection: 데이터베이스와 네트워크상의 연결을 도와주는 인터페이스
        try(Connection connection = ConnectionUtil.INSTANCE.getConnection();
            //PreparedStatement는 SQL을 전달한다는 점에서 같지만 SQL문을 미리 전달하고 나중에    데이터를 보내는 방식
            PreparedStatement preparedStatement = connection.prepareStatement("select now()");
            //쿼리를 실행하기 위한 메서드, 결과는 ResultSet으로 반환받아야 한다.
            ResultSet resultSet = preparedStatement.executeQuery();
        ){
            //데이터를 순차적으로 읽는 방식
            resultSet.next();
            now = resultSet.getString(1);
        }catch (Exception e){
            e.printStackTrace();
        }
        return now;
    }
    public String getTime2() throws Exception{
        @Cleanup Connection connection = ConnectionUtil.INSTANCE.getConnection();
        @Cleanup PreparedStatement preparedStatement = connection.prepareStatement("select now()");
        @Cleanup ResultSet resultSet = preparedStatement.executeQuery();
        resultSet.next();
        String now = resultSet.getString(1);
        return now;
    }
    public void insert(TodoVO vo) throws Exception{
        String sql = "insert into tbl_todo (title, dueDate, finished) values (?, ?, ?)";
        @Cleanup Connection connection = ConnectionUtil.INSTANCE.getConnection();
        @Cleanup PreparedStatement preparedStatement = connection.prepareStatement(sql);
        preparedStatement.setString(1, vo.getTitle());
        preparedStatement.setDate(2, Date.valueOf(vo.getDueDate()));
        preparedStatement.setBoolean(3, vo.isFinished());
        preparedStatement.executeUpdate();
    }
    public List<TodoVO> selectAll()throws Exception{
        String sql = "select * from tbl_todo";
        @Cleanup Connection connection = ConnectionUtil.INSTANCE.getConnection();
        @Cleanup PreparedStatement preparedStatement = connection.prepareStatement(sql);
        @Cleanup ResultSet resultSet = preparedStatement.executeQuery();
        List<TodoVO> list = new ArrayList<>();
        while ((resultSet.next())){
            TodoVO vo = TodoVO.builder()
                    .tno(resultSet.getLong("tno"))
                    .title(resultSet.getString("title"))
                    .dueDate(resultSet.getDate("dueDate").toLocalDate())
                    .finished(resultSet.getBoolean("finished"))
                    .build();
            list.add(vo);
        }
        return list;
    }
    public TodoVO selectOne(Long tno) throws Exception{
        String sql = "select * from tbl_todo where tno = ?";
        @Cleanup Connection connection = ConnectionUtil.INSTANCE.getConnection();
        @Cleanup PreparedStatement preparedStatement = connection.prepareStatement(sql);
        preparedStatement.setLong(1, tno);
        @Cleanup ResultSet resultSet = preparedStatement.executeQuery();
        resultSet.next();
        TodoVO vo = TodoVO.builder()
                .tno(resultSet.getLong("tno"))
                .title(resultSet.getString("title"))
                .dueDate(resultSet.getDate("dueDate").toLocalDate())
                .finished(resultSet.getBoolean("finished"))
                .build();
        return vo;
    }
}
}
  • TodoDAOTests.java 수정
package dao;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.zerock.jdbcex.dao.TodoDAO;
import org.zerock.jdbcex.domain.TodoVO;
import java.time.LocalDate;
import java.util.List;
public class TodoDAOTests {
    private TodoDAO todoDAO;
    @BeforeEach // ready()를 통해서 테스트 하기전에 TodoDAO 를 생성하도록.
    public void ready(){
        todoDAO = new TodoDAO();
    }
    @Test
    public void testTime() throws Exception{
        System.out.println(todoDAO.getTime());
    }
    @Test
    public  void testInsert() throws Exception{
        TodoVO todoVO = TodoVO.builder()
                .title("Sample Title..")
                .dueDate(LocalDate.of(2023,12,31))
                .build();
        todoDAO.insert(todoVO);
    }
    @Test
    public void  testList() throws Exception{
        List<TodoVO> list = todoDAO.selectAll();
        list.forEach(vo -> System.out.println(vo));
    }
}
profile
하이도의 BackEnd 입문

0개의 댓글