setting
mybatisAlias.xml 설정
<typeAliases></typeAliases> 사이 <typeAlias type="VO경로 작성" alias="별칭이름"/> 작성
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--
[마이바티스] 스프링에서 "_"를 사용한 컬럼명을 사용 시(BOOK 테이블의 BOOK_ID)
카멜케이스로 읽어줌(bookId)
ex) 테이블 컬러명이 member_id인 경우 jsp화면단에서 이 값을 사용 시 memberId로 사용
-->
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<!-- 자주 사용하는 타입의 별칭을 세팅 -->
<typeAliases>
<typeAlias type="kr.or.ddit.vo.BookVO" alias="bookVO"/>
</typeAliases>
</configuration>
BookController.java
@Slf4j
log.info(); 사용하기 위한 어노테이션
@Controller
스프링 프레임워크에게 "이 클래스는 웹 브라우저의 요청(request)를 받아들이는 컨트롤러야" 라고 알려주는 것임.
스프링은 servlet-context.xml의 context:component-scan의 설정에 의해 이 클래스를 자바빈 객체로 등록
(메모리에 바인딩).
@Autowired
IoC(Inversion of Control) - 제어의 역전.(개발자가 객체생성하지 않고 스프링이 객체를 미리 생성해놓은 것을 개발자가 요청)
서비스를 호출하기 위해 의존성 주입(Dependency Injection-DI)
메모리 있는 객체 사용
@RequestMapping
value, method 구성
value ⇒ 요청 url
method ⇒ get방식(RequestMethod.GET) 또는 post 방식(RequestMethod.POST)으로 작성
ModelAndView
1) Model : Controller가 반환할 데이터(String, int, List, Map, VO..)를 담당
2) View : 화면을 담당(뷰(View : JSP)의 경로)
.addObject("name",value);
jsp 데이터 전송
.setViewName()
forwarding 인 경우
servlet-context.xml 에서
prefix(접두어) : /WEB-INF/views/ ,suffix(접미어) : .jsp ⇒ jsp 경로위치 앞 뒤로 붙힘
ex)/WEB-INF/views/ + book/create + .jsp
redirect 인 경우 ⇒새로운 URL 요청
.setViewName("redirect:/@RequestMapping(value값)");
단.redirect 하면 addObject();의미 사라짐
post 방식으로 파라미터 받는 경우
요청파라미터는 매개변수로 받는다
예를들어
요청URI : /crate
요청파라미터 : {title=개똥이의 모험, category=소설, price=12000}
요청방식 : post
요청 파라미터는 BookVO클래스 bookVO로 저장이 된다
요청URI : /list?keyword=알탄 or /list or /list?keyword=
요청파라미터 : keyword=알탄
요청방식 : get
required=false : 선택사항. 파라미터가 없어도 무관
defaultValue ⇒ 기본값
String keyword ⇒ jsp에서 요청파라미터 보낸 값 받음
@GetMapping
@GetMapping("value")
ex) @GetMapping("/detail")
get방식으로 데이터 받음
Model
데이터
.addAttribute("name",value) ⇒ jsp 데이터 전송
ex)
model.addAttribute("title", "도서 상세");
model.addAttribute("bookVO", bookVO);
return "jsp 경로위치";
return "book/detail"; ⇒ /WEB-INF/views/book/detail.jsp
Service
@Service
서비스 클래스 : 비즈니스 로직
스프링 MVC 구조에서 Controller와 DAO를 연결하는 역할
서비스 클래스라고 알려줌, 그래서 자바빈(객체)으로 등록해줌
Dao
@Repository
매퍼xml(book_SQL.xml)을 실행시키는 DAO(Data Access Object) 클래스
데이터에 접근하는 클래스
스프링이 데이터를 관리하는 클래스라고 인지하여 자바빈으로 등록하여 관리함
insert("namespace.id",파라미터);
public int createPost(BookVO bookVO) { return this.sqlSessionTemplate.insert("book.createPost", bookVO); }
insert성공 : 1이상, 실패면 0
selectList("namespace.id",파라미터);
public List<BookVO> list(Map<String, Object> map) { return this.sqlSessionTemplate.selectList("book.list",map); }
selectOne("namespace.id",파라미터);
public BookVO detail(BookVO bookVO) { return this.sqlSessionTemplate.selectOne("book.detail", bookVO); }
update("namespace.id",파라미터);
public int updatePost(BookVO bookVO) { return this.sqlSessionTemplate.update("book.updatePost", bookVO); }
delete("namespace.id",파라미터);
public int deletePost(BookVO bookVO) { return this.sqlSessionTemplate.delete("book.deletePost", bookVO); }
book_SQL.xml(mapper.xml)
- MyBatis에서 제공해주는 데이터 입력을 나타내는 태그
- parameterType :Dao 객체가 던진 데이터타입
- Dao 객체의 메소드 쪽으로 리턴할 타입.
- resultType : vo, hashMap, String, int
- resultMap : MyBatis의 resultMap 태그를 사용 - 마이바티스 쿼리 XML에 전달되면 #{vo변수명}을 "value"로 자동 변환함
insert + selectKey
<insert id="createPost" parameterType="bookVO"> <!-- insert문을 실행하기 전에 실행됨 --> <selectKey resultType="int" order="BEFORE" keyProperty="bookId"> 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>
<selectKey>
order : BEFORE(쿼리를 실행하기 전에 먼저 selectKey를 실행)
resultType : selectKey 쿼리를 실행 한 결과 타입
keyProperty : bookVO의 멤버변수(결과를 담을)
select
<select id="list" parameterType="hashMap" resultType="bookVO"> SELECT book_id, title, category, price, insert_date FROM book WHERE 1=1 <if test ="keyword!=null and keyword!=''" > and (title like '%'||#{keyword}||'%' or category like '%'||#{keyword}||'%' or price like '%'||#{keyword}||'%' ) </if> order by book_id desc </select> <select id="detail" parameterType="bookVO" resultType="bookVO"> SELECT BOOK_ID, TITLE, CATEGORY, PRICE, INSERT_DATE FROM BOOK WHERE BOOK_ID = #{bookId} </select>
update
<update id="updatePost" parameterType="bookVO"> UPDATE book SET TITLE=#{title} , CATEGORY=#{category} , PRICE=#{price} WHERE book_id = #{bookId} </update>
delete
<delete id="deletePost" parameterType="bookVO"> delete from book where book_id = #{bookId} </delete>
원본
BookController.java
package kr.or.ddit.controller;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
import kr.or.ddit.service.BookService;
import kr.or.ddit.vo.BookVO;
import lombok.extern.slf4j.Slf4j;
/*
Controller 어노테이션
스프링 프레임워크에게 "이 클래스는 웹 브라우저의 요청(request)를
받아들이는 컨트롤러야" 라고 알려주는 것임.
스프링은 servlet-context.xml의 context:component-scan의 설정에 의해
이 클래스를 자바빈 객체로 등록(메모리에 바인딩).
*/
@Slf4j
@Controller
public class BookController {
//서비스를 호출하기 위해 의존성 주입(Dependency Injection-DI)
//IoC(Inversion of Control) - 제어의 역전.(개발자가 객체생성하지 않고 스프링이 객체를 미리 생성해놓은 것을 개발자가 요청)
//의존성 ( Injection)
@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)의 경로)
*/
ModelAndView mav = new ModelAndView();
//데이터 -> name :title / value : "도서생성" 데이터 담기
mav.addObject("title", "도서생성");
//jsp
// <beans:property name="prefix" value="/WEB-INF/views/" />
// <beans:property name="suffix" value=".jsp" />
// prefix(접두어) : /WEB-INF/views/
// suffix(접미어) : .jsp
// /WEB-INF/views/ + book/create + .jsp
//forwarding
mav.setViewName("book/create");
return mav;
}
/*
요청URI : /crate
요청파라미터 : {title=개똥이의 모험, category=소설, price=12000}
요청방식 : post
*/
@RequestMapping(value="/create",method=RequestMethod.POST)
public ModelAndView createPost(BookVO bookVO) {
log.info("bookVO:"+bookVO);
ModelAndView mav = new ModelAndView();
//도서 등록
int result =this.bookService.createPost(bookVO);
// log.info("createPost->result : "+result);
//데이터
mav.addObject("bookVO", bookVO); //redirect 하면 의미 사라짐
//redirect : 새로운 URL 요청
mav.setViewName("redirect:/list");
return mav;
}
/*
요청URI : /list?keyword=알탄 or /list or /list?keyword=
요청파라미터 : keyword=알탄
요청방식 : get
required=false : 선택사항. 파라미터가 없어도 무관, 필수가 아니다
defaultValue => 기본값
*/
@RequestMapping(value="/list",method=RequestMethod.GET)
public ModelAndView list(ModelAndView mav,
@RequestParam(value = "keyword",required=false,defaultValue = "") String keyword) {
// log.info("list에 왔다");
log.info("list -> keyword:" +keyword);
//map{"keyword":"알탄"}
Map<String,Object> map = new HashMap<String, Object>();
map.put("keyword", keyword);
// 도서목록
List<BookVO> bookVOList = this.bookService.list(map);
// log.info("list ->bookVOList >>>"+bookVOList);
// Model: 데이터
mav.addObject("bookVOList", bookVOList);
//View : jsp
//forwarding
mav.setViewName("book/list");
return mav;
}
//책 상세보기
//요청된 URI 주소 : http://localhost/detail?bookId=3
//요청파라미터(HTTP 파라미터), 쿼리 스트링(Query String) : bookId=3
//요청방식 : get
//매개변수 : bookVO => {"bookId":"3","title":null,"category":null,"price":0,"insertDate":null}
@RequestMapping(value="/detail", method=RequestMethod.GET)
public ModelAndView detail(BookVO bookVO, ModelAndView mav) {
// log.info("detail -> bookVO: "+bookVO);
//호출 전 : {"bookId":"3","title":null,"category":null,"price":0,"insertDate":null}
//도서 상세
bookVO=this.bookService.detail(bookVO);
//호출 후 : {"bookId":"3","title":"개똥이의 모험","category":"소설","price":12000,"insertDate":"2024-04-22"}
// log.info("detail 후 -> bookVO: "+bookVO);
//Model : 데이터
mav.addObject("title", "도서 상세");
mav.addObject("bookVO", bookVO);
//view : jsp
mav.setViewName("book/detail");
return mav;
}
// @RequestMapping(value="/detail", method=RequestMethod.GET)
// value라는 속성이 하나 -> 생략 가능
@GetMapping("/detail2")
public String detail2(BookVO bookVO, Model model) {
// log.info("detail -> bookVO: "+bookVO);
//호출 전 : {"bookId":"3","title":null,"category":null,"price":0,"insertDate":null}
//도서 상세
bookVO=this.bookService.detail(bookVO);
//호출 후 : {"bookId":"3","title":"개똥이의 모험","category":"소설","price":12000,"insertDate":"2024-04-22"}
// log.info("detail 후 -> bookVO: "+bookVO);
//Model : 데이터
model.addAttribute("title", "도서 상세");
model.addAttribute("bookVO", bookVO);
//view : jsp
// mav.setViewName("book/detail"); 사라지고 지런으로 가
return "book/detail";
}
/*
요청URI : /updatePost
요청파라미터 : {bookId=127, title=개똥이의 모험2, category=소설2, price=12002}
요청방식 : post
*/
@RequestMapping(value = "/updatePost", method = RequestMethod.POST)
public ModelAndView updatePost(BookVO bookVO, ModelAndView mav) {
log.info("updatePost-> bookVO:"+bookVO);
//insert, update, delete의 return 타입 : int타입
int result =this.bookService.updatePost(bookVO);
log.info("updatePost ->result"+result);
// redirect -> 새로운 URI를 재요청 /detail?bookId=127
mav.setViewName( "redirect:/detail?bookId="+bookVO.getBookId());
return mav;
}
/*
요청URI : /deletePost
요청파라미터 : {bookId=127, title=개똥이의 모험2, category=소설2, price=12002}
요청방식 : post
*/
@RequestMapping(value="/deletePost",method = RequestMethod.POST)
public ModelAndView deletePost(BookVO bookVO, ModelAndView mav) {
// BookVO(bookId=131, title=test, category=test, price=1234, insertDate=null)
log.info("deletePost->bookVO "+bookVO);
int result =this.bookService.deletePost(bookVO);
log.info("deletePost ->result"+result);
//redirect -> list로 보냄
mav.setViewName("redirect:/list");
return mav;
}
}
BookService.java → 인터페이스
package kr.or.ddit.service;
import java.util.List;
import java.util.Map;
import kr.or.ddit.vo.BookVO;
public interface BookService {
//도서등록
public int createPost(BookVO bookVO);
//도서목록
public List<BookVO> list(Map<String, Object> map);
//도서 상세
public BookVO detail(BookVO bookVO);
//도서 수정
public int updatePost(BookVO bookVO);
//도서 삭제
public int deletePost(BookVO bookVO);
}
BookServiceImpl.java
package kr.or.ddit.service.impl;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import kr.or.ddit.dao.BookDao;
import kr.or.ddit.service.BookService;
import kr.or.ddit.vo.BookVO;
//서비스 클래스 : 비즈니스 로직
//스프링 MVC 구조에서 Controller와 DAO를 연결하는 역할
/*
스프링 프레임워크는 개발자가 직접 클래스를 생성하는 것을 지양하고,
* 프링은 인터페이스를 좋아해. 자꾸자꾸 좋아지면 Impl은 어떡해
인터페이스를 통해 접근하는 것을 권장하고 있기 때문.(확장성)
그래서 서비스 레이어는 인터페이스(BookService)와 클래스(BookServiceImpl)를 함께 사용함
Impl : implement의 약자
*/
//"프링아 이 클래스 서비스 클래야"라고 알려주자. 프링이가 자바빈으로 등록해줌.
@Service
public class BookServiceImpl implements BookService {
//데이터베이스 접근을 위해 BookDao 인스턴스를 주입받자
//DI(Dependency Injection):의존성 주입
//IoC(Inversion of Control):제어의 역전
@Autowired
BookDao bookDao;
//매서드 재정의
@Override
public int createPost(BookVO bookVO) {
return this.bookDao.createPost(bookVO);
}
@Override
public List<BookVO> list(Map<String, Object> map) {
return this.bookDao.list(map);
}
//도서 상세
@Override
public BookVO detail(BookVO bookVO) {
return this.bookDao.detail(bookVO);
}
@Override
public int updatePost(BookVO bookVO) {
return this.bookDao.updatePost(bookVO);
}
@Override
public int deletePost(BookVO bookVO) {
return this.bookDao.deletePost(bookVO);
}
}
BookDao.java
package kr.or.ddit.dao;
import java.util.List;
import java.util.Map;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import kr.or.ddit.vo.BookVO;
//매퍼xml(book_SQL.xml)을 실행시키는
//DAO(Data Access Object) 클래스
//Repository 어노테이션 : 데이터에 접근하는 클래스
//스프링이 데이터를 관리하는 클래스라고 인지하여 자바빈으로 등록하여 관리함
@Repository //자바빈으로 등록
public class BookDao {
//DI(Dependency Injection) : 의존성 주입
//개발자가 new 키워드를 통해 직접 객체를 생성하지 않고!!!
//스프링이 미리 만들어 놓은(서버 실행 시 스프링이 미리 xml을 읽어
//객체를 인스턴스화 해놓음)
//sqlSessionTemplate 타입 객체를 BookDao 객체에 주입함
@Autowired // 메모리에 있는것 사용하는것,(DI)
SqlSessionTemplate sqlSessionTemplate; //root-context.xml bean id="sqlSessionTemplate" 똑같이 써야한다
public int createPost(BookVO bookVO) {
//book_SQL.xml 파일의 namespace가 book이고, id가 createPost인
//태그를 찾아 그 안에 들어있는 sql을 실행함
//bookVO=>{"bookId":"","title":"총알탄 개똥이","category":"소설","price":10000,"insertDate":""}
//insert,update,delete는 반영된 건수가 return됨
//insert성공 : 1이상, 실패면 0
return this.sqlSessionTemplate.insert("book.createPost", bookVO);
}
public List<BookVO> list(Map<String, Object> map) {
//.selectList("namespace.id",파라미터)
return this.sqlSessionTemplate.selectList("book.list",map);
}
public BookVO detail(BookVO bookVO) {
return this.sqlSessionTemplate.selectOne("book.detail", bookVO);
}
public int updatePost(BookVO bookVO) {
return this.sqlSessionTemplate.update("book.updatePost", bookVO);
}
public int deletePost(BookVO bookVO) {
return this.sqlSessionTemplate.delete("book.deletePost", bookVO);
}
}
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">
<!-- MyBatis에서 제공해주는 데이터 입력을 나타내는 태그
1) 드루와 : Dao 객체가 던진 데이터타입.parameterType만 씀
2) 가즈아 : Dao 객체의 메소드 쪽으로 리턴할 타입.
- resultType : vo, hashMap, String, int
- resultMap : MyBatis의 resultMap 태그를 사용
-->
<!-- bookVO(전)=>{"bookId":0,"title":"총알탄 개똥이","category":"소설","price":10000,"insertDate":""} -->
<!-- bookVO(후)=>{"bookId":1,"title":"총알탄 개똥이","category":"소설","price":10000,"insertDate":""} -->
<!-- 마이바티스 쿼리 XML에 전달되면 샵{title}을 "총알탄 개똥이"로 자동 변환함 -->
<insert id="createPost" parameterType="bookVO">
<!-- 니키? 내키? 아니! 우리키!! -->
<!-- 키를 높이면 락(rok)커가 될 수 있을까?
order : BEFORE(쿼리를 실행하기 전에 먼저 selectKey를 실행)
resultType : selectKey 쿼리를 실행 한 결과 타입
keyProperty : bookVO의 멤버변수(결과를 담을)
-->
<!-- insert문을 실행하기 전에 실행됨 -->
<selectKey resultType="int" order="BEFORE" keyProperty="bookId">
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>
<!-- 도서목록
where 1 = 1은 늘 참임.
조건이 2개 이상일 때 WHERE + AND
조건이 1개일 때 WHERE이어야 함.
WHERE(생략)
AND => 오류 발생
==>
WHERE 1 = 1
AND(생략)
AND => 정상
True and True = True
True and False = False
keyword : null(/list)
keyword : "" (/list?keyword=)
-->
<!-- hashMap => map 클래스 -->
<select id="list" parameterType="hashMap" resultType="bookVO">
SELECT
book_id,
title,
category,
price,
insert_date
FROM
book
WHERE 1=1
<if test ="keyword!=null and keyword!=''" >
and (title like '%'||#{keyword}||'%'
or category like '%'||#{keyword}||'%'
or price like '%'||#{keyword}||'%' )
</if>
order by book_id desc
</select>
<!-- parameterMap 사용암함!!
resultMap은 JOIN 도는 CLOB 자료형에서 주로 사용함
-->
<select id="detail" parameterType="bookVO" resultType="bookVO">
SELECT BOOK_ID, TITLE, CATEGORY, PRICE, INSERT_DATE
FROM BOOK
WHERE BOOK_ID = #{bookId}
</select>
<update id="updatePost" parameterType="bookVO">
UPDATE book
SET
TITLE=#{title}
, CATEGORY=#{category}
, PRICE=#{price}
WHERE
book_id = #{bookId}
</update>
<delete id="deletePost" parameterType="bookVO">
delete from book
where book_id = #{bookId}
</delete>
</mapper>
mybatisAlias.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--
[마이바티스] 스프링에서 "_"를 사용한 컬럼명을 사용 시(BOOK 테이블의 BOOK_ID)
카멜케이스로 읽어줌(bookId)
ex) 테이블 컬러명이 member_id인 경우 jsp화면단에서 이 값을 사용 시 memberId로 사용
-->
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<!-- 자주 사용하는 타입의 별칭을 세팅 -->
<typeAliases>
<typeAlias type="kr.or.ddit.vo.BookVO" alias="bookVO"/>
</typeAliases>
</configuration>
BookVO.java
package kr.or.ddit.vo;
import java.util.Date;
import lombok.Data;
//자바빈 클래스
//1) 멤버변수(프로퍼티) 2) 기본생성자 3) getter/setter메소드
//@Data=> PoJo(Plain순수한 old Java object)에 위배
@Data
public class BookVO {
private int bookId;
private String title;
private String category;
private int price;
private Date insertDate;
}
list.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.min.js"></script>
<title>도서 목록</title>
<script type="text/javascript">
$(function(){
$("#btnSearch").on("click",function(){
let keyword =$("input[name='keyword']").val();
//json오브젝트
let data={
"keyword":keyword
};
console.log("data:",data)
//this => 내가 바로 클릭한것
$(this).parent().submit();
});
});
</script>
</head>
<body>
<h3>도서 목록</h3>
<p>
<!--
action속성 및 값이 생략 시, 현재 URI(/list)를 재요청.
method는 GET(form 태그의 기본 HTTP 메소드는 GET임)
param : keyword=알탄
요청URI : /list?keyword=알탄 or /list or /list?keyword=
요청파라미터 : keyword=알탄
요청방식 : get
-->
<form>
<input type="text" name="keyword" value="" placeholder="검색어 입력하세요">
<!-- submit /button/ reset -->
<button type="button" id="btnSearch">검색</button>
</form>
<a href="/create">도서등록</a>
</p>
<%-- <p>${bookVOList} </p> --%>
<table border=1>
<thead>
<tr>
<th>번호</th><th>제목</th><th>카테고리</th><th>가격</th>
</tr>
</thead>
<tbody>
<!--
forEach 태그? 배열(String[], int[][]), Collection(List, Set) 또는
Map(HashTable, HashMap, SortedMap)에 저장되어 있는 값들을
순차적으로 처리할 때 사용함. 자바의 for, do~while을 대신해서 사용함
var : 변수
items : 아이템(배열, Collection, Map)
varStatus : 루프 정보를 담은 객체 활용
- index : 루프 실행 시 현재 인덱스(0부터 시작)
- count : 실행 회수(1부터 시작. 보통 행번호 출력)
-->
<!-- data : mav.addObject("bookVOList", bookVOList); -->
<!-- bookVOList => List<BookVO> -->
<!-- row : bookVO 1행 -->
<!-- -->
<c:forEach var="bookVO" items="${bookVOList}" varStatus="stat">
<tr>
<td>${stat.count}</td>
<td><a href="/detail?bookId=${bookVO.bookId}"> ${bookVO.title}</a></td>
<td>${bookVO.category}</td>
<td><fmt:formatNumber value="${bookVO.price}" pattern="#,###"/>
</tr>
</c:forEach>
</tbody>
</table>
</body>
</html>
detail.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="/resources/js/jquery.min.js"></script>
<script type="text/javascript">
//document 내의 모든 요소들이 로딩된 후에 시랳ㅇ
//1개의 jsp에 하나 만 사용하자
let title="${bookVO.title}";
let category = "${bookVO.category}";
let price ="${bookVO.price}"
$(function(){
$("#list").on("click",function(){
location.href="list";
});
//수정버튼 클릭 -> 수정 모드 전환
$("#edit").on("click",function(){
$("#p1").css("display","none");
$("#p2").css("display","block");
//readonly 속성 제거
$(".formdata").removeAttr("readonly");
});
//취소버튼 클릭
$("#cancel").on("click",function(){
$("#p1").css("display","block");
$("#p2").css("display","none");
//readonly 속성 추가
$(".formdata").attr("readonly",true);
//입력란 초기화
//태그로 접근하면 태그만
$("input[name='title']").val(title);
$("input[name='category']").val(category);
$("input[name='price']").val(price);
console.log("title:"+title+",category:"+category+",price"+price);
});
/*
요청URI : /deletePost
요청파라미터 : {bookId=127, title=개똥이의 모험2, category=소설2, price=12002}
요청방식 : post
*/
//삭제버튼 클릭
$("#delete").on("click",function(){
//속성 변경 action="/deletePost" 변경
$("#frm").attr("action","/deletePost");
let result = confirm("삭제하시겠습니까?");
//확인:true / 취소 : false
console.log("result:"+result);
if(result > 0){ // true ==1
$("#frm").submit();
}else{
alert("삭제가 취소되었습니다.");
}
});
});
</script>
<meta charset="UTF-8">
<title>도서 상세</title>
</head>
<body>
<%-- <p>${bookVO} --%>
<h1>도서 상세</h1>
<!-- BookController.java에서 mav.addObject("title", "도서생성"); -->
<h5>${title}</h5>
<!--
요청URI : /updatePost
요청파라미터 : {bookId=127, title=개똥이의 모험2, category=소설2, price=12002}
요청방식 : post
-->
<!-- /create URL 같지만 방식이 다르다 그래서 다른 요청이다 -->
<form id="frm" name="frm" action="/updatePost" method="post">
<!-- 폼데이터 -->
<input type="hidden" name="bookId" value="${bookVO.bookId }">
제목 : <input type="text" name="title" value="${bookVO.title}"
class="formdata" readonly placeholder="제목"> <br>
카테고리 : <input type="text" name="category" value="${bookVO.category}"
class="formdata" readonly placeholder="카테고리"><br>
가격 : <input type="number" name="price" value="${bookVO.price}"
class="formdata" readonly placeholder="가격"><br>
<!-- 일반 모드 시작 -->
<p id="p1">
<input type="button" id="edit" value="수정">
<input type="button" id="delete" value="삭제">
<input type="button" id="list" value="목록">
</p>
<!-- 일반 모드 끝 -->
<!-- 수정 모드 시작 -->
<p id="p2" style ="display:none">
<input type="submit" id="confirm" value="확인">
<input type="button" id="cancel" value="취소">
</p>
<!-- 수정 모드 끝 -->
</form>
</body>
</html>
create.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>책 등록</h1>
<!-- BookController.java에서 mav.addObject("title", "도서생성"); -->
<h5>${title}</h5>
<!--
요청URI : /crate
요청파라미터 : {title=개똥이의 모험, category=소설, price=12000}
요청방식 : post
-->
<!-- /create URL 같지만 방식이 다르다 그래서 다른 요청이다 -->
<form action="/create" method="post">
<!-- 폼데이터 -->
제목 : <input type="text" name="title" placeholder="제목"> <br>
카테고리 : <input type="text" name="category"placeholder="카테고리"><br>
가격 : <input type="number" name="price" placeholder="가격"><br>
<input type="submit" value="저장">
</form>
</body>
</html>
'JAVA > spring' 카테고리의 다른 글
컨트롤러 요청 매핑 (0) | 2024.04.29 |
---|---|
Spring - 타일즈(Tiles) (1) | 2024.04.26 |
ckeditor5 사용법 (0) | 2024.04.26 |
spring 프로젝트 환경설정 (0) | 2024.04.22 |
스프링부트 전체 환경설정(자바 버전, 인코딩) (0) | 2024.04.22 |