Todo 프로그램 만들기
TodoService
modelMapper통해서 vo로 만들고 todoDAO에 insert 요청
public enum TodoService { //TodoService 는 DTO, VO 사용하는 구조이므로, ModelMapper와 TodoDAO 를 이용하도록 구성한다.
INSTANCE;
private TodoDAO todoDAO;
private ModelMapper modelMapper;
//
TodoService(){
todoDAO = new TodoDAO();
modelMapper = MapperUtil.INSTANCE.get();
}
//register() 는 TodoDTO 를 파라미터로 받아서 TodoVO변환 기능
public void register(TodoDTO todoDTO) throws Exception {
TodoVO vo = modelMapper.map(todoDTO, TodoVO.class); // 클래스 변환
System.out.println("todoVO" + vo);
todoDAO.insert(vo);
}
todoDao의 insert 에서 받는다.
public void insert(TodoVO todoVO) throws Exception {
String sql = "insert into tbl_todo (title,dueDate,finished) values (?,?,?)";
@Cleanup Connection connection = ConnectionUtil.INSTANCE.getConnection();
@Cleanup PreparedStatement psmt = connection.prepareStatement(sql);
psmt.setString(1, todoVO.getTitle());
psmt.setDate(2, Date.valueOf(todoVO.getDueDate()));
psmt.setBoolean(3, todoVO.isFinished());
psmt.executeUpdate();
}
테스트 insert
public class TodoServiceTests {
//1. TodoService 객체 선언
private TodoService todoService;
//2. @BeforeEach 통해서 ready를 메소드를 이용하여 TodoService 객체 생성
@BeforeEach
public void ready(){
todoService = TodoService.INSTANCE;
}
//3. @Test : testRegister 메소드에 TodoDTO를 하나를 빌더를 통해서 (TITLE, Duedate)를 생성한 후 서비스 등록을 수행한다.
@Test
public void testRegister() throws Exception {
TodoDTO dto = TodoDTO.builder().tno(8l).title("테테스스트트").dueDate(LocalDate.of(2023,02,23)).finished(true).build();
todoService.register(dto);
}
//4. testRegister() 실행한 후 정상적으로 TodoVO의 내용이 출력되는 지 확인
//5. tbl_todo테이블에 insert가 정상적으로 입력되었는지 확인
}
(service)dto 객체를 만들어서 -> vo로 변환하고 -> (dao)vo를 받아서 db에 insert해줌
"ModelMapper"는 Java에서 사용되는 객체 매핑 라이브러리. 이 라이브러리는 객체 간의 매핑을 자동화한다. 주로 DTO(Data Transfer Object)와 Entity(데이터베이스에서 가져온 객체) 간의 변환을 담당
ModelMapper
public enum { // 싱글톤
INSTANCE;
private ModelMapper modelMapper;
//object mapping 서로 다른 클래스의 값을 한번에 복사하게 도와주는 라이브러리1
MapperUtil(){
this.modelMapper = new ModelMapper();
this.modelMapper.getConfiguration()
.setFieldMatchingEnabled(true)
.setFieldAccessLevel(Configuration.AccessLevel.PRIVATE)
.setMatchingStrategy(MatchingStrategies.STRICT);
}
public ModelMapper get(){
return modelMapper;
}
}
// setFieldMatchingEnabled(true): 이 설정은 ModelMapper가 객체 간 매핑을 할 때 필드
// 이름이 같은 필드들끼리 매핑을 수행하도록 합니다. 즉, 게터(getter)와 세터(setter) 메소드를 사용하지 않고
// 직접 필드에 접근하여 값을 할당합니다.
//
// setFieldAccessLevel(Configuration.AccessLevel.PRIVATE): 이 설정은 ModelMapper가
// private 접근 제한자를 가진 필드에도 접근할 수 있도록 허용합니다.기본적으로 ModelMapper는
// public 또는 protected 필드만 접근할 수 있지만, 이 설정을 통해 private 필드에도
// 접근이 가능해집니다.
//
// setMatchingStrategy(MatchingStrategies.STRICT): 매핑 전략을 설정하는 부분으로,
// STRICT 전략을 사용하면 매핑 과정에서 소스와 목적지 객체 간의 필드 이름이 정확히 일치해야 합니다.
// 이는 느슨한 매핑(LOOSE 전략)과 대조되는데, 느슨한 매핑은 이름이 유사하기만 해도 매핑을 수행합니다.
// STRICT 전략을 사용하면 데이터의 정확한 매핑이 보장됩니다.
//
// 예를 들어, Source 객체에 firstName이라는 필드가 있고, Destination 객체에도 firstName이라는
// 필드가 있을 때, STRICT 매칭 전략을 사용하면 ModelMapper는 이 두 필드를 매핑합니다.
// 만약 필드 이름이 약간 다르면 (예: first_name과 firstName), STRICT 전략에서는 매핑하지 않을 것입니다.
하나의 서비스객체에 연동해서 , 여러 컨트롤러로, 등록, 수정, 삭제 .. 묶어서 하나의 서비스 구현
TodoRegisterController
localhost/todo/register 로 들어가면 TodoRegisterController의 doGet메소드가 실행된다. register.jsp페이지로 이동한다.
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.getRequestDispatcher("/WEB-INF/todo/register.jsp").forward(request, response);
}
register.jsp
입력하는 title, 날짜선택하는 input이 존재하고 submit 버튼을 누르면 action="/todo/register" register 컨트롤러가 요청을 받는다.
<%@ 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>
<form action="/todo/register" method="post" accept-charset="UTF-8">
<input type="text" id="title" name="title">
<input type="date" id="dueDate" name="dueDate">
<button type="submit" name="RGISTER">등록</button>
</form>
</form>
</body>
</html>
TodoRegisterController
register 컨트롤의 doPost가 실행된다. 요청받은 title, dueDate를 사용하여 todoDTO 객체를 만들어 todoService.register 메소드로 디비에 추가한다.
그 후 sendRedirect로 list 컨트롤러로 이동한다.
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
String title = request.getParameter("title");
String dueDate = request.getParameter("dueDate");
System.out.println(title);
System.out.println(dueDate);
TodoDTO todoDTO = TodoDTO.builder()
.title(title)
.dueDate(LocalDate.parse(dueDate))
.finished(true)
.build();
try {
todoService.register(todoDTO);
} catch (Exception e) {
throw new RuntimeException(e);
}
response.sendRedirect("/todo/list");
}
todoService , 모든 리스트 가져오기 기능
dao에서 근데 vo 니까 변환 과정 필요함
dao에 있는 selectAll한테 보냄
public List<TodoDTO> listAll() throws Exception{
List<TodoVO> voList = todoDAO.selectAll();
// 반환이 VO니까 일단 VO로 받음
List<TodoDTO> dtoList = voList.stream().map(vo->modelMapper.map(vo,TodoDTO.class)).collect(Collectors.toList());
//한개씩 dto로 바꿈
return dtoList;
}
controller
/todo/list로 접속해서 doGet메소드가 실행된다.
List<TodoDTO>리스트를 만들고 request에 setAttribute한다. 그리고 dispather 로 보낸다.
@WebServlet(name="todoListController",urlPatterns = "/todo/list")
public class TodoListController extends HttpServlet {
//1. todoService 객체
private TodoService todoService = TodoService.INSTANCE; // enum 클래스의 싱글톤 패턴을 만들었기 때문에
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
System.out.println("todo list ... called");
try {
List<TodoDTO> dtoList = todoService.listAll();
request.setAttribute("dtoList",dtoList); // request 뭔가 담을 수 있는 저장공간
request.getRequestDispatcher("/WEB-INF/todo/list.jsp").forward(request,response);
} catch (Exception e) {
throw new RuntimeException("list error");
}
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
}
}
todo/list.jsp
내용 출력됨
setAttribute "dtoList"이름으로 보냈다. 리스트를 가리킨다.
하나씩 돌면서 출력됨
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
//--컨테이너가 해석하는 서버스크립트 태그
<html>
<head>
<title>TodoList</title>
</head>
<%--el사용하면 getter setter 같은 복잡한 과정 필요없음--%>
<body>
<form>
<c:forEach items="${dtoList}" var="dto">
<a href="/todo/read?param=${dto.tno}">${dto}</a><br>
</c:forEach>
</form>
</body>
</html>
리스트에 a태그를 달아 놓았다. 하나 선택해준다.
요구사항이 get방식으로 read 페이지에 전달해야하므로 href="/todo/read?param=${dto.tno} 하여 선택한 게시물 번호를 전달한다.
TodoReadController
list.jpg 에서 get방식으로 url에 선택한 todo 번호를 전달했다.
String tno = request.getParameter("param"); 에서 param 이라는 키 값으로 번호를 받아 tno에 담는다.
todoService.selectOne(Long.parseLong(tno))로 tno를 보내주어 TodoDTO객체 하나를 전달 받는다.
선택한 todo를 보여주기 위해 request.setAttribute 에다 Tno, Title, DueDate값들을 붙여주고 read.jsp로 보낸다.
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String tno = request.getParameter("param");
try {
TodoDTO dto = todoService.selectOne(Long.parseLong(tno));
System.out.println(dto);
request.setAttribute("dto",dto.getTno());
request.setAttribute("title",dto.getTitle());
request.setAttribute("dueDate",dto.getDueDate());
request.getRequestDispatcher("/WEB-INF/todo/read.jsp").forward(request, response);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
read.jsp
컨트롤러에서 보낸 값들을 <label>을 통해 출력해 주었다.
수정,삭제 하기위한 <a>을 놨뒀다. 수정이나 삭제를 할때 사용하기 위해 누르면 modify 컨트롤러에게 param=%{dto} 를 넘겨 준다.
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
<title>Read</title>
</head>
<body>
<label>READ</label>
<form action="todo/read" method="post">
<label>${dto}</label><hr>
<label>${title}</label><hr>
<label>${dueDate}</label><hr>
<a href="/todo/modify?param=${dto}">Modify/Remove</a><br>
</form>
</body>
</html>
TodoModifyController
get 방식으로 보냈으므로 modify 컨트롤러의 doGet이 실행된다.
param 키값을 가지는 파라미터를 tno에 저장했다.
그 후 tno 값을 가진채로 modify.jsp로 이동한다.
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String tno = request.getParameter("param");
System.out.println("update tno : "+tno);
request.setAttribute("tno",tno);
request.getRequestDispatcher("/WEB-INF/todo/modify.jsp").forward(request, response);
}
TodoModify.jsp
컨트롤러에서 보낸 tno 를 hidden <input>태그에 놨뒀다.
그래서 submit 할 때 사용자는 눈에 안보이지만 tno값을 전달할 수 있다.
Modify 버튼과, remove 버튼을 두어 tno가 선택된채로 수정 또는 삭제를 할 수 있다.
${tno} 는 내가 선택한 todo 이므로 따로 변경없이 그냥 박아 놨다.
예시는 4번을 선택해서 4번이 나온다.
삭제하고 싶으면 remove 버튼을 누르는데 input에 value속성으로 ${tno}를 넣어줘서 뭘 선택했는지 알 수 있다.
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>TodoModify</title>
</head>
<body>
<h1>modify</h1>
<form action="/todo/modify" method="post">
<input type="hidden" name=tno value="${tno}"><br>
${tno}<br>
<input type="text" name="title"><br>
<input type="date" name="dueDate"><br>
<button type="submit">Modify</button>
</form>
<form action="/todo/remove" method="post">
<input type="hidden" name=tno value="${tno}"><br>
<button type="submit">remove</button>
</form>
</body>
</html>
TodoModifyController
modify 버튼을 누르게 되면 TodoModify컨트롤러의 doPost가 실행된다.
tno, titl, dueDate를 받는다.
받은 데이터를 통해서 dto 를 새로 만들고 todoService.updateOne 으로 보낸다. 해당 내용으로 변경을 한 이후에 sendRedirect("/todo/list")로 이동
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("post page access");
String tno = request.getParameter("tno");
String title = request.getParameter("title");
String dueDate = request.getParameter("dueDate");
System.out.println(tno);
System.out.println(title);
System.out.println(dueDate);
TodoDTO dto = TodoDTO.builder()
.tno(Long.parseLong(tno))
.title(title)
.dueDate(LocalDate.parse(dueDate))
.build();
try {
todoService.updateOne(dto);
} catch (Exception e) {
throw new RuntimeException(e);
}
response.sendRedirect("/todo/list");
}
TodoModify.jsp 에서 remove를 누르면 TodoRemoveController 의 doPost가 실행된다.
<input type="hidden" name=tno value="${tno}"> 를 통해 tno를 받았기 때문에 request.getParameter로 받을 수 있다.
해당 tno로 todoService.deleteOne를 진행하여 삭제한다.
그 후 /todo/lis 페이지로 sendRedirect한다.
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String tno = request.getParameter("tno");
System.out.println("remove page "+Long.parseLong(tno));
try {
todoService.deleteOne(Long.parseLong(tno));
} catch (Exception e) {
throw new RuntimeException(e);
}
response.sendRedirect("/todo/list");
}
로그 기능: log4j2 라이브러리
level(레벨) 설정
Lombok의 경우 @Log4j2 를 이용하여 소스 코드 내에 로그를 적용할 수 있다.
- level (INFO를 많이함)
로그의 레벨이 높아질 수록
내가 지정한 레벨이상의 로그들만 나옴 , 개발할 때는 낮춰놓음 다 볼 수 있게 - Appender
FATAL: 가장 심각한 오류를 나타내며, 애플리케이션이 계속 실행될 수 없는 상태입니다.
ERROR: 예상치 못한 상황에서 발생한 오류로, 애플리케이션의 일부 기능이 제대로 작동하지 않을 때 사용됩니다.
WARN: 잠재적으로 해로운 상황을 경고할 때 사용됩니다. 오류는 아니지만, 주의가 필요한 상황입니다.
INFO: 애플리케이션의 일반적인 이벤트를 기록할 때 사용됩니다. 사용자에게 유용한 정보나 상태 업데이트 등에 사용됩니다.
DEBUG: 개발 과정에서 상세한 실행 정보를 기록할 때 사용됩니다. 문제 해결 및 애플리케이션의 흐름을 추적하는 데 도움이 됩니다.
TRACE: DEBUG보다 더 상세한 정보를 기록할 때 사용됩니다. 애플리케이션의 거의 모든 실행 경로를 추적할 수 있으며, 문제 해결에 매우 유용합니다.
build.gradle 추가
implementation group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.17.2'
implementation group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.17.2'
implementation group: 'org.apache.logging.log4j', name: 'log4j-slf4j-impl', version: '2.17.2'
log4j2.xml 작성
<?xml version="1.0" encoding="utf-8" ?>
<Configuration status="WARN" xmlns="http://logging.apache.org/log4j/2.0/config">
<!-- info 3단계 warn이 4단계-->
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
</Appenders>
<!-- 이 로그가 어디에 보여질 것인지 지정-->
<Loggers>
<Root level="info">
<AppenderRef ref="Console"/>
</Root>
</Loggers>
</Configuration>
TodoService 위에 어노테이션 추가, 메서드에 log.info(vo)
@Log4j2 // 어노테이션
public enum TodoService { //TodoService 는 DTO, VO 사용하는 구조이므로, ModelMapper와 TodoDAO 를 이용하도록 구성한다.
INSTANCE;
private TodoDAO todoDAO;
private ModelMapper modelMapper;
TodoService(){
todoDAO = new TodoDAO();
modelMapper = MapperUtil.INSTANCE.get();
}
//register() 는 TodoDTO 를 파라미터로 받아서 TodoVO변환 기능
public void register(TodoDTO todoDTO) throws Exception {
TodoVO vo = modelMapper.map(todoDTO, TodoVO.class); // 클래스 변환
// System.out.println("todoVO" + vo);
log.info(vo); // 보고싶은곳 메서드 추가
todoDAO.insert(vo);
}
좀 다른 에러 나옴
Test에서도 사용가능
@Log4j2
public class TodoServiceTests {
'신세계 - Spring 공부' 카테고리의 다른 글
15주차 배운점 - 퍼사드 패턴, 컨트롤러, Formatter, 예외처리, Mapper (0) | 2024.09.24 |
---|---|
15주차 배운점 - 스프링, MyBatis, 스프링 Web MVC (2) | 2024.09.23 |
14주차 배운점 - Session, 쿠키, 필터 (1) | 2024.09.23 |
14주차 배운점 - DTO, DAO, JDBC, Mapper (1) | 2024.09.23 |
14주차 배운점 - 톰캣, 서블릿, JSP (2) | 2024.09.23 |