일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- 자바문제
- FastAPI
- Mac
- crud
- 대덕인재개발원
- 반복문
- python
- Oracle
- pyqt
- JDBC
- Android
- 자바
- 배열
- 이클립스
- servlet
- Java
- spring
- API
- 컬렉션프레임워크
- ibatis
- 맥
- 단축키
- nodejs
- 생활코딩
- jsp
- ddit
- html
- 객체지향
- Homebrew
- Error
Archives
- Today
- Total
romworld
Spring 03 - 도서 CRUD(2) - insert 본문
- 스프링은 인터페이스다.
INSERT 쿼리문 (ex)
INSERT BOOK(BOOK_ID, TITLE, CATEGORY, PRICE, INSERT_DATE, CONTENT) values((SELECT NVL(MAX(BOOK_ID),0)+1 FROM BOOK),'낭만닥터개똥이','드라마',12000,sysdate,'김사부');
Insert into Book(BOOK_ID, TITLE, CATEGORY, PRICE, INSERT_DATE, CONTENT)
values(1,'검은개똥이','드라마',10000,sysdate,'검은태양 후속작');
Insert into Book(BOOK_ID, TITLE, CATEGORY, PRICE, INSERT_DATE, CONTENT)
values(1,'검은개똥이','드라마',10000,sysdate,'검은태양 후속작');
Insert into Book(BOOK_ID, TITLE, CATEGORY, PRICE, INSERT_DATE, CONTENT)
values(2,'수리남','드라마',11000,sysdate,'식사는 잡쉈구');
-- 이렇게 넣으면 쭉쭉 계속 들어감
Insert into Book(BOOK_ID, TITLE, CATEGORY, PRICE, INSERT_DATE, CONTENT)
values((SELECT NVL(MAX(BOOK_ID),0)+1 FROM BOOK),'낭만닥터개똥이','드라마',12000,sysdate,'김사부');
SELECT * FROM BOOK;
--TCL(Transaction Control Language)
--트랜잭션 : 데이터베이스를 변경하기 위해 수행되어야 할 논리적 단위.
-- 여러개의 SQL로 구성되어 있음
--1) COMMIT : DB에 반영
--2) ROLLBACK : 마지막 COMMIT/ROLLBACK 시점으로 되돌림
--3) SAVEPOINT : 중간저장
ROLLBACK;
--시퀀스에는 OR REPLACE가 없음
CREATE SEQUENCE SEQ_BOOK
START WITH 3
INCREMENT BY 1;
--현재 시퀀스
SELECT SEQ_BOOK.CURRVAL FROM DUAL;
--다음 시퀀스값
SELECT SEQ_BOOK.NEXTVAL FROM DUAL;
--서브쿼리 : 메인SQL안에 사용된 또 다른 쿼리
--1) SCALAR : SELECT
--2) NESTED : WHERE
--3) INLINE VIEW : FROM
-- 괄호로 묶어야 함
-- 널이 있으면 널봐라 (NULL이 있으면 0)
SELECT NVL(MAX(BOOK_ID),0)+1 FROM BOOK;
-- 집게함수
--SUM, AVG,MAX,MIN,COUNT
쿼리문을 작성할 xml 파일 생성
- * : 모든 단어가 들어갈 수 있고 뒤에 _SQL.xml 이라는 이름을 똑같이 설정해야한다.
<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">
<!-- namespace : xml 파일이 여러개일 수 있으므로
이를 구별하기 위한 식별 용도로 사용 -->
<mapper namespace="book">
<!-- MyBatis에서 제공해주는 데이터 입력을 나타내는 태그
1) 드루와 : Dao 객체가 던진 데이터타입. parameterType만 씀
2) 가즈아 : Dao 객체의 메소드 쪽으로 리턴할 타입. insert/update/delete의 경우 생략(당연히 int)
- resultType : String, int, hashMap, VO
- resultMap : 1:N의 관계 . MyBatis의 resultMap 태그를 사용
-->
<!--
(전) bookVO{bookId:0,title:롬이야기,category:소설price:10000,insertDate:null
content:null}
(후) bookVO{bookId:1,title:롬이야기,category:소설price:10000,insertDate:null
content:null}
MyBatis 쿼리 XML에 전달되면 #{멤버변수}로 작성하여 값을 치환
-->
<insert id="createPost" parameterType="bookVO" >
<!-- 키를 높이면 락(rOK)커가 될 수 있을까? -->
<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, CONTENT)
VALUES(#{bookId},#{title},#{category},
#{price},SYSDATE,#{content})
</insert>
</mapper>
mapper.xml를 실행시키는 DAO 클래스
<BookDao.java>
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;
/*
매퍼XML(book_SQL.xml)을 실행시키는 DAO(Data Access Object) 클래스
Repository 어노테이션 : 데이터에 접근하는 클래스
=> 스프링이 데이터를 관리하는 클래스라고 인지하여 자바빈 객체로 등록하여 관리함
*/
@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를 써줘야 한다.
// 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;
}
}
Controller와 DAO를 연결하는 Service
<BookService.java> - 인터페이스
package kr.or.ddit.service;
import kr.or.ddit.vo.BookVO;
// 서비스 interface : 비즈니스 로직(비지니스 레이어)
public interface BookService {
// 메소드 시그니처
public int createPost(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);
}
}
<BookController.java>
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;
}
}
localhost/create 주소를 입력하고 전송을 누르면 부적합한 열이 있다는 오류가 나온다
create.jsp 에서 cotent를 빠트리고 작성했기 때문
그러므로 내용을 다시 추가해주고 실행 시키면
<p>내용: <input type="text" name="content" required /></p>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
</script>
<meta charset="UTF-8">
<title>책 등록하기</title>
</head>
<body>
<h1>책 등록</h1>
<!-- 폼페이지 -->
<!--
요청URI : /cretae?title=롬이야기&category=소설&price=10000
요청파라미터 : tilte=롬이야기&category=소설&price=10000
요청방식 : post
-->
<form action="/create" method="post">
<!-- 폼데이터 -->
<p>제목 : <input type="text" name="title" required /></p>
<p>카테고리 : <input type="text" name="category" required /></p>
<p>가격: <input type="number" name="price" required /></p>
<p>내용: <textarea name="content" rows="5" cols="30"></textarea></p>
<p>
<input type="submit" value="저장" />
<input type="button" value="목록" />
</p>
</form>
</body>
</html>
데이터가 정상적으로 삽입된 것을 볼 수 있다.
ckeditor 사용하기
resources 안에 ckeditor 폴더를 넣어준다.
<servlet-context.xml>
resources에 매핑한다. (**는 resources안에 있는 모든 것이 적용됨)
<!-- static folder설정(정적 폴더 설정) => css, images, upload, js
http://localhost/resources/
-->
<resources mapping="/resources/**" location="/resources/" />
<create.jsp>
- head 밑에 스크립트 삽입
<script type="text/javascript" src="/resources/ckeditor/ckeditor.js">
- body 안에 스크립트 삽입
<script type="text/javascript">
CKEDITOR.replace('content');
</script>
다시 실행 시키면 ckeditor가 적용된다.
아직 detail.jsp를 만들지 않았기 때문에 화면은 전환되지 않는다.
이제 detail을 만들어 보자 !
'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 04 - 도서CRUD(3) - select문 , detail 페이지 (0) | 2023.01.20 |
Spring 02 - 도서 CRUD (1) - create (0) | 2023.01.19 |
Spring 01 - [Eclipse] 환경 설정 (Window) , SVN , STS , Apache Tomcat 설치 (0) | 2023.01.19 |
Comments