detail.jsp : 상세보기 폼을 보여주는곳
<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
<head>
<title>책 상세</title>
</head>
<body>
<h1>책 상세</h1>
<p>제목 : ${data.title}</p>
<p>카테고리 : ${data.category}</p>
<p>가격 : ${data.price}</p>
<p>입력일 : ${data.insertDate}</p>
<p><a href="/update?bookId=${data.bookId}">수정</a></p>
<p><a href="/list">목록으로</a>
</body>
</html>
update.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!--
BookVO
[bookId=3, title=해리포터, category=소설, price=15000, insertDate=2022-01-28 11:21:37.0]
BookController에서 mav 객체에 data라는 이름으로 select검색 결과를 넣었으므로..
mav.addObject("data", bookVO)
달러{data.title} 형식으로 사용하면 됨
-->
<!DOCTYPE html>
<html>
<head>
<title>책 수정하기</title>
</head>
<body>
<h1>책 수정</h1>
<!-- action이 없으면 /update를 재요청한다! 단, 메서드는 post로 바뀜 -->
<form method="post">
<input type="hidden" name="bookId" value="${data.bookId}" />
<p>제목 : <input type="text" name="title" value="${data.title}"
required /></p>
<p>카테고리 : <input type="text" name="category"
value="${data.category}" required /></p>
<p>가격 : <input type="text" name="price"
value="${data.price}" /></p>
<p>
<input type="submit" value="저장" />
<input type="button" value="취소"
onclick="javascript:location.href='/detail?bookId=${data.bookId}'" />
</p>
</form>
</body>
</html>
BookController.java : 상세보기 컨트롤러
//book 상세 보기
//파라미터목록(쿼리스트링) : bookId=1
//map = {bookId,1}
@RequestMapping(value = "/detail", method = RequestMethod.GET) //요청을 리퀴러 메핑해준다
public ModelAndView detail(@RequestParam Map<String,Object> map) {
logger.info("map:" + map);
BookVO bookVO = new BookVO();
bookVO.setBookId(Integer.parseInt((String)map.get("bookId")));
//{bookId:1, 나머지는 null}
logger.info("bookVO(before) : "+ bookVO.toString());
//상세보기 데이터 가져오기
bookVO = this.bookService.detail(bookVO);
//{bookId:1, 나머지도 있음}
logger.info("bookVO(after) : "+ bookVO.toString());
ModelAndView mav = new ModelAndView();
// book/detail : 뷰 경로
// forwarding방식임!! : 여기는 데이터를 넣을 수 있음
mav.addObject("data",bookVO); //데이터를 담음
mav.setViewName("book/detail");
return mav;
}
BookController.java : 수정하기 컨트롤러
// /update?bookId=3
//쿼리스트링 : bookId=3
//map : {bookId:3}
//책 수정 화면 = 책 입력 화면(jsp) + 책 상세 서비스 로직
@RequestMapping(value="/update", method=RequestMethod.GET)
public ModelAndView update(@RequestParam Map<String, String> map) {
logger.info("map : "+map);
//책 상세 서비스 로직 사용
BookVO bookVO = new BookVO();
bookVO.setBookId(Integer.parseInt(map.get("bookId")));
bookVO = this.bookService.detail(bookVO);
ModelAndView mav = new ModelAndView();
//request.setAttribute("data",bookVO);
mav.addObject("data",bookVO);
//forwarding
mav.setViewName("book/update");
return mav;
}
//책 수정 post
@RequestMapping(value = "/update",method = RequestMethod.POST)
public ModelAndView updatePost(@ModelAttribute BookVO bookVO,
ModelAndView mav) {//멤버면수와 네브를?같이 쓰면 이게 가능해짐
logger.info("bookVO : " + bookVO.toString());
//true : update성공, false : update실패
boolean isUpdateSuccess = this.bookService.update(bookVO);
if(isUpdateSuccess) {//성공
//상세페이지로 이동
mav.setViewName("redirect:/detail?bookId="+bookVO.getBookId());
}else {//실패
//책 수정 화면으로 돌아가기
//방법1)
// mav.setViewName("redirect:/update?bookId="+bookVO.getBookId());
//방법2)
//멥을 만들어서
Map<String,String> map = new HashMap<String, String>();
//넣어라
map.put("bookId", ""+bookVO.getBookId());
mav=this.update(map);//다이렉트로 호출
}
return mav;
}
BookService
package kr.or.ddit;
public interface BookService {
//dao에 있는메소드를 그대로 복붙한 것
//book 테이블로 insert
public int insert(BookVO bookVO);
//메소드 시그니처 처리를 하는 것
//book 상세보기
public BookVO detail(BookVO bookVO);
//book 수정하기(메서드 시그니처?)
public boolean update(BookVO bookVO);
}
BookServiceImpl
package kr.or.ddit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
//어노테이션.. 스프링에게 이 클래스는 서비스 클래스임을 알려줌
//스프링이 자바 빈(java bean)으로 등록하여 관리
@Service
public class BookServiceImpl implements BookService {//클래스 implements 인터페이스
private static final Logger logger =
LoggerFactory.getLogger(BookServiceImpl.class);
//이미 관리되어있는 객체를 가져다 쓴다
@Autowired
BookDao bookDao;
//부모 객체의 메소드를 재정의 하는 것
@Override
//메서드를 재정의 하는거라 오버라이드가 맞음 근데 어디서?
public int insert(BookVO bookVO) {
logger.info("bookVO : " + bookVO.toString());
int affectRowCount = this.bookDao.insert(bookVO);
if(affectRowCount == 1) {//입력이 성공
//xml에서 selectKey에서 세팅된 그 값(max(book_id)+1)
return bookVO.getBookId();
}
//입력 실패
return 0;
}
//책 상세보기
@Override
public BookVO detail(BookVO bookVO) {
return this.bookDao.detail(bookVO);
//컨트롤러로 리턴되는 것
}
//책 수정하기
@Override
public boolean update(BookVO bookVO) {
return this.bookDao.update(bookVO);
}
}
BookDao.java
package kr.or.ddit;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
//mapper xml을 실행해주는 클래스.
//어노테이션을 붙여서 이 클래스는 데이터에 접근하는 클래스야~
//Spring에게 알려줘!
//Spring이 데이터를 관리하는 클래스라고 인지해서 자바 빈(java bean)으로 등록해서 관리
@Repository
public class BookDao { //사람
//sqlSessionTempate 사용
/*
* new 키워드를 통해 직접 생성 안했는데 객체가 생성이 됨!! 싱기방구
* 이게 바로 의존성 주입임!!!(Dependency Injection - DI)
* DI로 주입 받는 것임
* 스프링이 이미 만들어 놓은 sqlSessionTemplate 타입 객체를 BookDao 객체에 주입
* 이 과정은 자동으로 스프링에서 실행되며, 개발자가 직접 객체를 생성하지 않음(이것이 바로 IoC: 제어의 역전)
*
*/
@Autowired//자동 주입
SqlSessionTemplate sqlSessionTemplate;//미리 만들어 놓은 백신(root컨택스트에서 온것)
public int insert(BookVO bookVO) {
//book_SQL.xml 파일에서
//namespace="book"
//id="insert"
//book.insert : 매퍼 쿼리 명
//bookVO : 두 번째 인수.. 쿼리에 전달할 데이터(String, int, VO, Map)
return this.sqlSessionTemplate.insert("book.insert", bookVO);//마이바티스가 만든 메서드
}
//책 상세보기
public BookVO detail(BookVO bookVO) {
//.selectOne 메소드 : 1행을 가져올때 사용
// 결과 행 수가 0이면 null반환
// 결과 행 수가 2이상일 때 TooManyResultsException 예외 발생
//(namespace.id, 파라미터)
return sqlSessionTemplate.selectOne("book.detail",bookVO);
}
//책 수정하기
public boolean update(BookVO bookVO) {
//(namespace.id, 파라미터)
//update 후에 영양받은 행의 수를 받음
int result = this.sqlSessionTemplate.update("book.update",bookVO);
//0보타 크다는 것은 update가 성공했다는 의미
return result > 0;
}
}
book_SQL.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="book">
<!-- 클래스이름까지 다쓰는게 파라미터 타입 -->
<!-- bookId값은 어떻게 넣을까? -->
<!-- selectKey란?
마이바티스는 쿼리 실행 시 파라미터를 치환해줌
selectKey 전 : {"title":"검은태양", "category":"드라마", "price":10000}
selectKey 후 : {"bookId":1, "title":"검은태양","category":"드라마" ,"price":10000}
-->
<insert id="insert" parameterType="kr.or.ddit.BookVO">
<!-- ******* -->
<!-- 1이 bookId안에 들어감 -->
<selectKey order="BEFORE" keyProperty="bookId" resultType="integer">
SELECT NVL(MAX(BOOK_ID),0)+1 FROM BOOK
</selectKey>
INSERT INTO BOOK(BOOK_ID,TITLE,CATEGORY,PRICE,INSERT_DATE)
VALUES(#{bookId},#{title},#{category},#{price},SYSDATE)
</insert>
<!-- 책 상세보기 -->
<select id="detail" parameterType="bookVO" resultType="bookVO">
select BOOK_ID,TITLE,CATEGORY,PRICE,INSERT_DATE
from book
where book_id=#{bookId}
</select>
<!-- 책 수정하기, update태그는 UPDATE 쿼리를 실행하기 위한 마이바티스 태그 -->
<update id="update" parameterType="bookVO">
update book
set TITLE=#{title},CATEGORY=#{category},PRICE=#{price}
where book_id=#{bookId}
</update>
</mapper>