일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- API
- 이클립스
- html
- crud
- 자바
- FastAPI
- 자바문제
- Homebrew
- ibatis
- servlet
- JDBC
- 반복문
- Oracle
- 맥
- spring
- Error
- ddit
- Mac
- 생활코딩
- nodejs
- 객체지향
- pyqt
- 단축키
- Android
- python
- 컬렉션프레임워크
- Java
- 대덕인재개발원
- 배열
- jsp
- Today
- Total
romworld
Spring 04 - 도서CRUD(3) - select문 , detail 페이지 본문
SQL문 쿼리
SELECT BOOK_ID, TITLE, CATEGORY, PRICE, INSERT_DATE, CONTENT
FROM BOOK
WHERE BOOK_ID = 2;
<book_SQL.xml>
insert문 아래 select문 추가
<!-- p.71 -->
<!-- 책 상세보기
select 태그는 조회(select) 쿼리를 실행하기 위한 mybatis 태그
드루와 : parameterType(book_SQL.xml로 드루와) - bookVO 타입
가즈아 : resultType(BookDao로 가즈아) - bookVO 타입
(전) bookVO{bookId:2,title:롬이야기,category:소설price:10000,insertDate:null
content:null}
(후) bookVO{bookId:2,title:롬이야기,category:소설price:10000,insertDate:23/01/20
content:롬이의 모험 이야기}
-->
<select id="detail" parameterType="bookVO" resultType="bookVO">
SELECT BOOK_ID, TITLE, CATEGORY, PRICE, INSERT_DATE, CONTENT
FROM BOOK
WHERE BOOK_ID = #{bookId}
</select>
여기에서 왜 컬럼명 표기법이 다른데 적용이 잘 되어지냐면
mybatisAlias.xml을 보면 알 수 있다.
<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>
<BookDao.java>
상세보기 메소드 추가 해준다.
// 책 상세보기
public BookVO detail(BookVO bookVO) {
// 쿼리를 실행해주는 객체?(힌트 : root_contxt.xml)
// selectOne() 메소드 : 1행을 가져올 때 사용
// selectList() 메소드 : 결과 집합 목록 반환(다중행)
// 결과 행 수가 0이면? null을 반환
// 결과 행 수가 2 이상이면? TooManyResultException 예외 발생
// .selectOne("namespace명.id명", 파라미터)
return this.sqlSessionTemplate.selectOne("book.detail", bookVO);
}
package kr.or.ddit.dao;
import java.lang.reflect.Parameter;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import kr.or.ddit.vo.BookVO;
import lombok.extern.slf4j.Slf4j;
/*
매퍼XML(book_SQL.xml)을 실행시키는 DAO(Data Access Object) 클래스
Repository 어노테이션 : 데이터에 접근하는 클래스
=> 스프링이 데이터를 관리하는 클래스라고 인지하여 자바빈 객체로 등록하여 관리함
*/
@Slf4j
@Repository
public class BookDao {
/* DI(Dependency Injection) : 의존성 주입
new 키워드를 통해 개발자가 직접 생성하지 않고,
스프링이 미리 만들어 놓은(톰켓서버 실행 시 스프링이 미리 객체를 인스턴스화 해놓음)
sqlSessionTemplate 타입 객체를 BookDao 객체에 주입함
IoC(Inversion of Control) : 제어의 역전
*/
//sqlSessionTemplate : 모더나/ BookDao : 새롬이 -> 모더나를 새롬이 팔에 주입
/*
root-context.xml <bean id="sqlSessionTemplate"...
데이터베이스에 개별적으로 쿼리를 실행시키는 객체
이 객체를 통해 query를 실행함
*/
@Autowired
SqlSessionTemplate sqlSessionTemplate;
// 도서 테이블(Book)에 입력
//<insert id="createPost" parameterType="bookVO"> insert id와 메서드 명을 같게 설정
public int createPost(BookVO bookVO) {
// .insert("namespace값.id값",파라미터)
// book_SQL.xml 파일의 namespace가 book이고, id가 insert인
// 태그를 찾아 그 안에 들어있는 sql을 실행함
// this는 클래스를 말함 ->BookDao
// this는 생략 가능 하나 만약 BookDao에도 변수를 선언하고 createPost 파라미터에도 같은 변수가
// 선언되어 있으면 구분을 해주기 위해 this를 써줘야 한다.
log.info("bookVO :" + bookVO.toString());
// insert,update,delete는 반영된 행수가 return됨
// insert성공 : 1이상. 실패면 0
int result = this.sqlSessionTemplate.insert("book.createPost",bookVO);
int bookId = 0;
if(result >0) { // insert 성공
bookId = bookVO.getBookId(); // 0? 1(1 증가된 값이 들어있음. selectKey에 의해 생성됨)?
}else { // insert 실패
bookId = 0;
}
return bookId;
}
// 책 상세보기
public BookVO detail(BookVO bookVO) {
// 쿼리를 실행해주는 객체?(힌트 : root_contxt.xml)
// selectOne() 메소드 : 1행을 가져올 때 사용
// selectList() 메소드 : 결과 집합 목록 반환(다중행)
// 결과 행 수가 0이면? null을 반환
// 결과 행 수가 2 이상이면? TooManyResultException 예외 발생
// .selectOne("namespace명.id명", 파라미터)
return this.sqlSessionTemplate.selectOne("book.detail", bookVO);
}
}
<BookService.java>
package kr.or.ddit.service;
import kr.or.ddit.vo.BookVO;
// 서비스 interface : 비즈니스 로직(비지니스 레이어)
public interface BookService {
// 메소드 시그니처
public int createPost(BookVO bookVO);
// 상세보기
public BookVO detail(BookVO bookVO);
}
<BookServiceImpl.java>
package kr.or.ddit.service.impl;
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를 연결하는 역할
/*
스프링 프레임워크(디자인패턴 + 라이브러리)는 직접 클래스를 생성하는 것을 지양(싫음)하고,
인터페이스를 통해 접근하는 것을 권장하고 있기 때문에(확장성)
프링이는 인터페이스를 좋아해 ..
그래서 서비스 레이어는 인터페이스(BookService)와 클래스(BookServiceImpl)를 함께 사용함
Impl : implement의 약자
*/
// Service 어노테이션 : "프링아 이 클래스는 서비스 클래스야" 라고 알려줌.
// 프링이가 자바빈으로 등록해줌
@Service
public class BookServiceImpl implements BookService {
// 데이터베이스에 접근하기 위해 BookDao 인스턴스를 주입받자
@Autowired
BookDao bookDao;
// 도서 테이블(Book)에 입력
//<insert id="createPost" parameterType="bookVO"> insert id와 메서드 명을 같게 설정
@Override
public int createPost(BookVO bookVO) {
//bookId를 리턴받음
return bookDao.createPost(bookVO);
}
// 책 상세보기
@Override
public BookVO detail(BookVO bookVO) {
return bookDao.detail(bookVO);
}
}
<BookController.java>
ModelAndView는 나중에는 잘 안 쓰지만 배우기 위해 사용해본다.
상세보기로 데이터를 보내는 메서드 추가
// 책 상세보기
// 요청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;
}
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.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;
}
}
detail.jsp를 만들기 전 새로운 템플릿 적용
새로운 jsp template 적용해보자!
new template
<detail.jsp>
BookController에서 넣어놨던 data를 꺼내보자 ~ (JSTL 사용)
<%@ 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>
</head>
<body>
<!-- mav.addObject("data", data); => bookVO 데이터 -->
${data}
<hr />
<!-- mav.addObject("bookId", data.getBookId());기본키 값(int 타입) -->
${bookId}
</body>
</html>
ckeditor와 jstl를 사용해서 상세보기 출력을 해보자 ~
<%@ 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>
<script type="text/javascript">
CKEDITOR.replace("content");
// CKEDITOR.instances['content'].setReadOnly(false);
</script>
</body>
</html>
'Spring' 카테고리의 다른 글
Spring 06 - 도서 CRUD(5) - delete,select(책목록) PL/SQL문 (0) | 2023.01.25 |
---|---|
Spring 05 - 도서CRUD(4) - update, JSTL (fmt) (0) | 2023.01.20 |
Spring 03 - 도서 CRUD(2) - insert (1) | 2023.01.20 |
Spring 02 - 도서 CRUD (1) - create (0) | 2023.01.19 |
Spring 01 - [Eclipse] 환경 설정 (Window) , SVN , STS , Apache Tomcat 설치 (0) | 2023.01.19 |