
// TodoServiceImpl.java
@Service // 비즈니스 로직(데이터 가공, 트랜잭션 처리 등)의 역할을 명시 + Bean 등록
public class TodoServiceImpl implements TodoService {
}
.
.
@Autowired // 타입이 같거나 상속관계를 DI 함
private TodoService service;
package edu.kh.todo.model.mapper;
import org.apache.ibatis.annotations.Mapper;
// Mybatis를 사용하면 Mapper가 DAO를 대신해서 사용됌
/**
* @Mapper - Mybatis에서 제공하는 어노테이션 - Mybatis에서 SQL과 Java 메서드를 연결해주는
* 인터페이스(Mapper)의 구현체를 스프링의 Bean으로 등록할 수 있게 해주는 어노테이션
*
* 이 어노테이션을 붙이면 Spring이 Mapper 인터페이스를 인식하고, 자동으로 구현체를 생성해줌 -> 이 구현체가
* Bean으로 등록됨!
*
* - ⭐⭐⭐ 해당 어노테이션이 작성된 인터페이스는 namespace에 해당 인터페이스가 작성된 xxx-mapper.xml
* 파일과 연결되어 SQL 호출/수행/결과 반환이 가능해짐 -> 현재는 todo-mapper.xml에 namespace에 작성을
* 해서 연결이 되어 있음
*
*
*/
// 전체 흐름은 현재 DAO가 있다는 가정하에 다음과 같다
// client -> service -> DAO -> Mapper -> xml
// 돌아오는 것은 반대로 돌아오면 된다.
@Mapper
public interface TodoMapper {
String testTitle();
}
.
.
<!-- 태그로 SQL 구문 지정하고 작성 -->
<!-- 여기서부터는 Mybatis -->
<!-- id는 todoMapper에 있는 메서드 명과 똑같이 해줘야 한다. -->
<select id="testTitle">
SELECT TODO_TITLE
FROM TB_TODO
WHERE TODO_NO = 1
</select>
<!-- <select> 태그 속성 - id 속성 : 태그를 식별하는 값 (연결된 Mapper의 메서드명과 동일하게 작성하면 된다) -->
.
.
<!-- resultType=""은 반환받아오는 타입을 지정해주는 것 -> 반환 타입은 모두 소문자로 적기 -->
<!-- parameterType : 전달받은 값(전달 인자)의 타입을 명시하는
속성 -> DTO, Map인 경우 필드명/key
를 입력해서 값/value을 하나씩 꺼내 사용할 수 있음 -->

⇒ 즉, TodoMapper.java에 있는 testTitle() 메서드를 id에 작성해주면 해당 메서드가 실행이 된다.
<!-- parameterType : 전달받은 값(전달 인자)의 타입을 명시하는
속성 -> DTO, Map인 경우 필드명/key
를 입력해서 값/value을 하나씩 꺼내 사용할 수 있음 -->
<!--
mapper.xml 에서 java data(파라미터)를 SQL에 삽입하는 방법!
1) #{변수명 | 필드명} : SQL에 삽입 시 양쪽에 '' 붙여서 삽입
ex) MEMBER_EMAIL = #{memberEmail}
-> 'member01@naver.com'
=============================================================
2) ${변수명 | 필드명} : SQL에 삽입 시 양쪽에 '' 붙이지 않고
삽입
${} 언제 사용할까?
1) 삽입할 값이 숫자인 경우
2) SQL문 자체가 변해야 하는 경우
ex) SELECT MEMBER_NAME, ${key} FROM "MEMBER"
-> ${key}가 ENROLL_DATE 인 경우
-> SELECT MEMBER_NAME, ENROLL_DATE FROM "MEMBER"
-> ${key}가 MEMBER_ADDRESS 인 경우
-> SELECT MEMBER_NAME, MEMBER_ADDRESS FROM "MEMBER"
-->
package edu.kh.todo.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import edu.kh.todo.model.dao.TodoDAO;
import edu.kh.todo.model.service.TodoService;
/**
* @Transactional - 트랜잭션 처리를 수행하라고 지시하는 어노테이션 -> 커밋, 롤백이 필요한 상황이 있을 때 하라고 지시하는
* 어노테이션 - 정상 코드 수행시 commit이 되고, 그 이외에는 rollback이 됨 - 기본값 :
* Service 내부 코드 수행 중에 RuntimeException이 발생하면 rollback
*/
@Transactional(rollbackFor = Exception.class) // 커밋, 롤백을 자동으로 진행
/**
* rollbackFor = Exception.class => 어떠한 예외가 발생했을 때, 롤백을 해줄지 지정해주는 속성인데
* Exception.class는 모든 예외 발생시 rollback 하겠다는 의미
*/
@Service // 비즈니스 로직(데이터 가공, 트랜잭션 처리 등)의 역할을 명시 + Bean 등록
public class TodoServiceImpl implements TodoService {
@Autowired // TodoDAO와 같은 타입/상속관계 Bean 의존성 주입(DI)
private TodoDAO dao;
@Override
public String testTitle() {
return dao.testTitle();
}
}
@GetMapping("detail") // /todo/detail로 Get 방식 요청 매핑
public String todoDetail(@RequestParam("todoNo") int todoNo, Model model, RedirectAttributes ra) {
Todo todo = service.todoDetail(todoNo);
String path = null;
if (todo != null) {
// 조회 결과가 있을 경우 detail.html로 forward
path = "todo/detail";
model.addAttribute("todo", todo);
} else {
// 조회 결과가 없을 경우 main 페이지로 redirect
path = "redirect:/";
ra.addFlashAttribute("message", "해당 할 일이 존재하지 않습니다.");
}
return path;
}
@Override
public int addTodo(String todoTitle, String todoContent) {
Todo todo = new Todo();
todo.setTodoTitle(todoTitle);
todo.setTodoContent(todoContent);
// Todo.builder().todoTitle(todoTitle).todoContent(todoContent).build();
int result = mapper.addTodo(todo);
// 마이바티스에서 SQL에 전달할 수 있는 파라미터 개수는 오직 1개
// -> TodoMapper에 생성될 추상메서드의 매개변수도 1개여야 한다는 것
// 근데 2개 전달인자 가능
// int result = mapper.addTodo(todoTitle, todoContent);
return result;
}
<button id="deleteBtn" th:data-todo-no="${todo.todoNo}">삭제</button>
⇒ 따라서, todo-no -> todoNo로 변환이 됌
const deleteBtn = document.querySelector("#deleteBtn");
deleteBtn.addEventListener("click", (e) => {
if (confirm("정말 삭제하시겠습니까?")) {
// 삭제 요청
location.href = `/todo/delete?todoNo=${e.target.dataset.todoNo}`;
// location.href는 Get 방식
}
});
⇒ 위 코드처럼 dataset.key값으로 접근할 수 있다.