Spring
Spring 05 - 도서CRUD(4) - update, JSTL (fmt)
inderrom
2023. 1. 20. 17:35
먼저 <detail.jsp> 에서
수정폼을 추가하자!
<p><a href="/update?bookId=${bookId}">수정폼</a></p>
<%@ page language="java" contentType="text/html;charset=UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="/resources/js/jquery.3.6.0.js"></script>
<title>도서관리시스템</title>
<script type="text/javascript" src="/resources/ckeditor/ckeditor.js"></script>
</head>
<body>
<!-- mav.addObject("data", data); => bookVO 데이터 -->
<%-- ${data} --%>
<!-- <hr /> -->
<!-- mav.addObject("bookId", data.getBookId());기본키 값(int 타입) -->
<%-- ${bookId} --%>
<!--
JSTL(JSP Standard Tag Library) : 개발자가 자주 사용하는 패턴을 모아놓은 집합
=> BookController에서 보내준 데이터를 뷰에 표현하도록 도와줌
JSTL은 maven에서 설정되어 있음 => pom.xml => jstl
-->
<h1>책 상세</h1>
<p>제목 : ${data.title} </p>
<p>카테고리 : ${data.category}</p>
<p>가격 : ${data.price}</p>
<p>입력일 : ${data.insertDate}</p>
<p>내용 :
<textarea name="content" rows="5" cols="30" readonly>${data.content}</textarea>
</p>
<p><a href="/update?bookId=${bookId}">수정폼</a></p>
<script type="text/javascript">
CKEDITOR.replace("content");
// CKEDITOR.instances['content'].setReadOnly(false);
</script>
</body>
</html>
<BookController.java>
update 메소드 추가
// 요청URI : /updata?bookId=2
// 요청URL : /update
// 요청파라미터 : bookId=2
// @ModelAttribute VO가 있는 곳에 붙힌다. 생략 가능
@RequestMapping(value="/update", method=RequestMethod.GET)
public ModelAndView update(@ModelAttribute BookVO bookVO,
ModelAndView mav) {
log.info("bookVO : " + bookVO);
// 책 수정 화면 = 책 입력 화면 + 책 상세 데이터
// 책 입력 화면 양식을 그대로 따라가고, 빈 칸을 데이터로 채워주면 됨
BookVO data = bookService.detail(bookVO);
log.info("data : " + data);
// ModelAndView mav = new ModelAndView(); 를 해줘도 되고
// 파라미터에 넣어서 변수를 호출해도 된다. (mav.addObject)
// model : 데이터를 jsp로 넘겨줌
mav.addObject("data", data);
// View : jsp의 경로
// WEB-INF/views/ + book/update + .jsp
// forwarding
mav.setViewName("book/update");
return mav;
}
package kr.or.ddit.controller;
import java.util.Date;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import kr.or.ddit.service.BookService;
import kr.or.ddit.vo.BookVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.dbcp2.BasicDataSource;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
/* Controller 어노테이션
스프링 프레임워크에게 "이 클래스는 웹 브라우저(클라이언트)의 요청(request)을
받아들이는 컨트롤러야" 라고 알려주는 것임.
스프링은 servlet-context.xml의 context:component-scan의 설정에 의해
이 클래스를 자바빈 캑체로 미리 등록 (메모리에 바인딩)
*/
// slf4j를 쓰면 lombok을 쓸 수 있다.
@Slf4j
@Controller
public class BookController {
// 서비스를 호출하기 위해 의존성 주입 (Dependency Injection -DI)
@Autowired
BookService bookService;
// 요청 URI : /create
// 방법 : get
// 요청 - (매핑) - 메소드
@RequestMapping(value="/create", method=RequestMethod.GET)
public ModelAndView create() {
/* ModelAndView
1) Model : Controller가 반환할 데이터(String, int ,List, Map, VO ..)를 담당.
2) View : 화면을 담당(뷰(View : jsp)의 경로).jsp파일의 위치
*/
ModelAndView mav = new ModelAndView();
/*
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
prefix + 뷰경로 +.jsp가 조립
servlet-context에서 중복 되는 주소를 지운다.
/WEB-INF/views/book/create.jsp
*/
// forwarding
mav.setViewName("book/create");
return mav;
}
/*
요청URI : /cretae?title=롬이야기&category=소설&price=10000
요청URL : /create
요청파라미터 : {title=롬이야기&category=소설&price=10000}
요청방식 : post
bookVO{bookId:null,title:롬이야기,category:소설price:10000,insertDate:null
content:null}
private int bookId;
private String title;
private String category;
private int price;
private Date insertDate;
private String content;
*/
@RequestMapping(value="/create", method=RequestMethod.POST)
public ModelAndView createPost(BookVO bookVO, ModelAndView mav) {
log.info("bookBO : " + bookVO.toString());
//<selectKey resultType="int" order="BEFORE" keyProperty="bookId">
//1 증가된 기본키 값을 받음
int bookId = bookService.createPost(bookVO);
log.info("bookId :" + bookId);
if(bookId <1) { // 등록 실패
// /create로 요청을 다시 함 => uri주소가 바뀜
mav.setViewName("redirect:/create");
}else {// 등록 성공 : 상세보기 페이지로 이동
mav.setViewName("redirect:/detail?bookId=" + bookId);
}
return mav;
}
// 책 상세보기
// 요청URI : /detail?bookId=2
// 요청URI : /detail
// 요청파라미터 : (HTTP파라미터=QueryString)bookId=2
//bookVO{bookId:2,title:null,category:nullprice:0,insertDate:null
//content:null}
@RequestMapping(value="/detail",method=RequestMethod.GET)
public ModelAndView detail(BookVO bookVO, ModelAndView mav) {
log.info("bookVO : " + bookVO );
BookVO data = bookService.detail(bookVO);
log.info("data : " + data);
// ModelAndView mav = new ModelAndView(); 를 해줘도 되고
// 파라미터에 넣어서 변수를 호출해도 된다. (mav.addObject)
// model : 데이터를 jsp로 넘겨줌
mav.addObject("data", data);
mav.addObject("bookId", data.getBookId()); // 기본키 값
/* servlet-context.xml에서 매핑 되어서 주소를 book/detail로 생략해서 쓰기 가능
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
prefix + 뷰경로 +.jsp가 조립
servlet-context에서 중복 되는 주소를 지운다.
/WEB-INF/views/book/create.jsp
*/
//forwarding => detail.jsp를 해석/컴파일 => html로 크롬에게 리턴. 데이터 전달 기능
mav.setViewName("book/detail");
return mav;
}
// 요청URI : /updata?bookId=2
// 요청URL : /update
// 요청파라미터 : bookId=2
// @ModelAttribute VO가 있는 곳에 붙힌다. 생략 가능
@RequestMapping(value="/update", method=RequestMethod.GET)
public ModelAndView update(@ModelAttribute BookVO bookVO,
ModelAndView mav) {
log.info("bookVO : " + bookVO);
// 책 수정 화면 = 책 입력 화면 + 책 상세 데이터
// 책 입력 화면 양식을 그대로 따라가고, 빈 칸을 데이터로 채워주면 됨
BookVO data = bookService.detail(bookVO);
log.info("data : " + data);
// ModelAndView mav = new ModelAndView(); 를 해줘도 되고
// 파라미터에 넣어서 변수를 호출해도 된다. (mav.addObject)
// model : 데이터를 jsp로 넘겨줌
mav.addObject("data", data);
// View : jsp의 경로
// WEB-INF/views/ + book/update + .jsp
// forwarding
mav.setViewName("book/update");
return mav;
}
}
<update.jsp>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="/resources/ckeditor/ckeditor.js">
</script>
<meta charset="UTF-8">
<title>책 수정하기</title>
</head>
<body>
<h1>책 수정</h1>
<!-- 폼페이지
mav.addObject("data",data); // data: bookVO
-->
<!--
요청URI : /update
요청파라미터 : {bookId:2 tilte=롬이야기,category=소설,price=10000}
요청방식 : post
-->
<form action="/update" method="post">
<!-- 폼데이터 -->
<!-- bookId는 기본키 .. 있어야한다. -->
<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="number" name="price" value="${data.price}" required /></p>
<p>내용: <textarea name="content" rows="5" cols="30"">${data.content}</textarea></p>
<p>
<input type="submit" value="저장" />
<input type="button" value="목록" />
</p>
</form>
<script type="text/javascript">
CKEDITOR.replace('content');
</script>
</body>
</html>
detail.jsp 날짜 , 가격 출력 방식 변경하기
<%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> 사용하자
<detail.jsp>
<%@ page language="java" contentType="text/html;charset=UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="/resources/js/jquery.3.6.0.js"></script>
<title>도서관리시스템</title>
<script type="text/javascript" src="/resources/ckeditor/ckeditor.js"></script>
</head>
<body>
<!-- mav.addObject("data", data); => bookVO 데이터 -->
<%-- ${data} --%>
<!-- <hr /> -->
<!-- mav.addObject("bookId", data.getBookId());기본키 값(int 타입) -->
<%-- ${bookId} --%>
<!--
JSTL(JSP Standard Tag Library) : 개발자가 자주 사용하는 패턴을 모아놓은 집합
=> BookController에서 보내준 데이터를 뷰에 표현하도록 도와줌
JSTL은 maven에서 설정되어 있음 => pom.xml => jstl
-->
<h1>책 상세</h1>
<p>제목 : ${data.title} </p>
<p>카테고리 : ${data.category}</p>
<p>가격 : <fmt:formatNumber type="number" pattern="###,###" maxFractionDigits="0"
value="${data.price}"/></p>
<p>입력일 : <fmt:formatDate pattern="yyyy.MM.dd HH:mm:ss"
value="${data.insertDate}" /></p>
<p>내용 :
<textarea name="content" rows="5" cols="30" readonly>${data.content}</textarea>
</p>
<p><a href="/update?bookId=${bookId}">수정폼</a></p>
<script type="text/javascript">
CKEDITOR.replace("content");
// CKEDITOR.instances['content'].setReadOnly(false);
</script>
</body>
</html>
<BookController.java>
/*
요청URI : /update
요청파라미터 : {bookId:2 tilte=롬이야기2,category=소설2,price=11000}
요청방식 : post
*/
@RequestMapping(value="/update", method=RequestMethod.POST)
public ModelAndView updatePost(BookVO bookVO
, ModelAndView mav) {
log.info("bookVO(updatePost) : " + bookVO);
return mav;
}
UPDATE 쿼리문 추가
<book_SQL.xml> 추가
<!-- 책 수정하기. update 태그는 update 쿼리를 실행하기 위한 mybatis 태그 -->
<!-- insert/update/delete의 경우 resultType 생략 가능(당연히 int) -->
<update id="updatePost" parameterType="bookVO">
UPDATE BOOK
SET TITLE=#{title}, CATEGORY=#{category}
,PRICE=#{price},INSERT_DATE=SYSDATE,CONTENT=#{content}
WHERE BOOK_ID =#{bookId}
</update>
< BookDao.java> 추가
// 책 수정하기
public int updatePost(BookVO bookVO) {
//.update("namespace.id",파라미터)
// 반환타입 int : update구문이 반영된 행의 수
return this.sqlSessionTemplate.update("book.updatePost",bookVO);
}
<BookServiceImple.java> 추가
// 책 수정하기
@Override
public int updatePost(BookVO bookVO) {
return this.bookDao.updatePost(bookVO);
}
<BookService.java> 추가
// 도서 변경하기
public int updatePost(BookVO bookVO);
<BookController.java> 수정
/*
요청URI : /update
요청파라미터 : {bookId:2 tilte=롬이야기2,category=소설2,price=11000}
요청방식 : post
*/
@RequestMapping(value="/update", method=RequestMethod.POST)
public ModelAndView updatePost(BookVO bookVO
, ModelAndView mav) {
log.info("bookVO(updatePost) : " + bookVO);
//result는 update문에 반영된 행의 수
int result = this.bookService.updatePost(bookVO);
if(result > 0) { // 업데이트 성공 -> 책 상세페이지(/detail)로 이동
mav.setViewName("redirect:/detail?bookId="+bookVO.getBookId());
}else { // 업데이트 실패 -> 업데이트 뷰페이지(/update)로 이동
mav.setViewName("redirect:/update?bookId="+bookVO.getBookId());
}
return mav;
}