Spring 02 - 도서 CRUD (1) - create
CRUD
Create Real Update Delete
Insert Select Update Delete
스프링 웹(view) 설정 파일
<servlet-context>
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
<!-- 스프링 웹(view) 설정 파일 -->
<!-- Enables the Spring MVC @Controller programming model -->
<annotation-driven />
<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
<resources mapping="/resources/**" location="/resources/" />
<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>
<context:component-scan base-package="kr.or.ddit" />
</beans:beans>
scan => 스프링이 클래스를 객체로 만들어준다. (인스턴스화)
<context:component-scan base-package="kr.or.ddit" />
create
<BookController.java>
package kr.or.ddit;
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;
/* Controller 어노테이션
스프링 프레임워크에게 "이 클래스는 웹 브라우저(클라이언트)의 요청(request)을
받아들이는 컨트롤러야" 라고 알려주는 것임.
스프링은 servlet-context.xml의 context:component-scan의 설정에 의해
이 클래스를 자바빈 캑체로 미리 등록 (메모리에 바인딩)
*/
@Controller
public class BookController {
// 요청 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;
}
}
<create.jsp>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>책 등록하기</title>
</head>
<body>
<h1>책 등록</h1>
<!-- 폼페이지 -->
<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>
<input type="submit" value="저장" />
<input type="button" value="목록" />
</p>
</form>
</body>
</html>
** 전송을 하면 405 에러가 난다. controller에서 GET으로 받기 때문이다
--- > 그러므로 controller에서 POST로 받는 메소드를 만들어주자.
BOOK 테이블 만들기
SQL developer 계정 생성
- cmd 명령어 입력
sqlplus sys/java@localhost:1521 as sysdba
create user spring identified by java;
grant connect, resource to spring;
book 테이블 생성
create table book (
book_id number not null,
title varchar2(600) not null,
category varchar2(600) not null,
price number,
insert_date date,
content clob,
CONSTRAINT pk_book_id PRIMARY KEY(book_id)
);
설명 달기
COMMENT ON TABLE BOOK IS '도서정보';
COMMENT ON COLUMN BOOK.BOOK_ID IS '책 아이디';
COMMENT ON COLUMN BOOK.TITLE IS '제목';
COMMENT ON COLUMN BOOK.CATEGORY IS '카테고리';
COMMENT ON COLUMN BOOK.PRICE IS '가격';
COMMENT ON COLUMN BOOK.INSERT_DATE IS '입력일자';
COMMENT ON COLUMN BOOK.CONTENT IS '책 내용';
컬럼명 ( 카멜표기 변환)
/
create or replace FUNCTION FN_GETCAMEL(COLUMN_NAME IN VARCHAR2)
RETURN VARCHAR2
IS
RSLT VARCHAR2(30);
BEGIN
--카멜표기로 변환(SITE_NUM -> siteNum)
SELECT LOWER(SUBSTR(REPLACE(INITCAP(COLUMN_NAME),'_'),1,1))
|| SUBSTR(REPLACE(INITCAP(COLUMN_NAME),'_'),2) INTO RSLT
FROM DUAL;
--리턴
RETURN RSLT;
END;
/
--구글 카멜변환(https://heavenly-appear.tistory.com/270)
SELECT COLUMN_NAME
, DATA_TYPE
, CASE WHEN DATA_TYPE='NUMBER' THEN 'private int ' || FN_GETCAMEL(COLUMN_NAME) || ';'
WHEN DATA_TYPE IN('VARCHAR2','CHAR') THEN 'private String ' || FN_GETCAMEL(COLUMN_NAME) || ';'
WHEN DATA_TYPE='DATE' THEN 'private Date ' || FN_GETCAMEL(COLUMN_NAME) || ';'
ELSE 'private String ' || FN_GETCAMEL(COLUMN_NAME) || ';'
END AS CAMEL_CASE
, '' RESULTMAP
FROM ALL_TAB_COLUMNS
WHERE TABLE_NAME = 'BOOK';
camel_case 를 vo로 만들자!
<BookVO.java>
package kr.or.ddit.vo;
import java.util.Date;
// 자바빈 클래스
// 1) 멤버변수 2) 기본생성자 3) getter/setter메소드
public class BookVO {
private int bookId;
private String title;
private String category;
private int price;
private Date insertDate;
private String content;
// 기본생성자. 생략가능
public BookVO() {}
// getter/setter 메서드
public int getBookId() {
return bookId;
}
public void setBookId(int bookId) {
this.bookId = bookId;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getCategory() {
return category;
}
public void setCategory(String category) {
this.category = category;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public Date getInsertDate() {
return insertDate;
}
public void setInsertDate(Date insertDate) {
this.insertDate = insertDate;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
@Override
public String toString() {
return "BookVO [bookId=" + bookId + ", title=" + title + ", category=" + category + ", price=" + price
+ ", insertDate=" + insertDate + ", content=" + content + "]";
}
}
- jsp에서 input의 name값은 vo의 멤버변수와 똑같이 써준다.
다시 controller로 돌아가서 POST 메소드를 작성해보자.
우선 mvn에서 lombok 검색
복사 후
<pom.xml>에 복사 해준다.
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<!--
1) 자바빈 클래스(VO)의 getter/setter 메소드, toString 자동 처리
2) log.info() 메소드로 sysout 대신 로그를 console에 출력
-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
<scope>provided</scope>
</dependency>
pom.xml을 수정했으면 다시 프로젝트 우클릭 - Run as - maven build를 꼭 해줘야한다.
lombok 설치
cmd에 명령어 입력
java -jar lombok-1.18.24.jar
<BookController.java>
@Slf4j
lombok을 쓸 수 있는 어노테이션
package kr.or.ddit;
import java.util.Date;
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.vo.BookVO;
import lombok.extern.slf4j.Slf4j;
/* Controller 어노테이션
스프링 프레임워크에게 "이 클래스는 웹 브라우저(클라이언트)의 요청(request)을
받아들이는 컨트롤러야" 라고 알려주는 것임.
스프링은 servlet-context.xml의 context:component-scan의 설정에 의해
이 클래스를 자바빈 캑체로 미리 등록 (메모리에 바인딩)
*/
// slf4j를 쓰면 lombok을 쓸 수 있다.
@Slf4j
@Controller
public class BookController {
// 요청 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());
// /create로 요청을 다시 함 => uri주소가 바뀜
mav.setViewName("redirect:/create");
return mav;
}
}
다시 실행 시키면 (localhost/create)
input에 입력한대로 콘솔에 log 가 찍힌다.
INFO : kr.or.ddit.BookController - bookBO : BookVO [bookId=0, title=롬이야기, category=소설, price=10000, insertDate=null, content=null]
DB 라이브러리 설치
- mybatis 3.5.10
- mybatis-spring 2.0.4
- spring-jdbc 5.2.5
- commons-dbcp2 2.7.0
- log4jdbc-log4j2-jdbc4 1.16
- ojdbc6 11.2.0.4
maven 소스 copy
<pom.xml> (110번대부터 보자)
매핑해준다.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>kr.or</groupId>
<artifactId>ddit</artifactId>
<name>springProj</name>
<packaging>war</packaging>
<version>1.0.0-BUILD-SNAPSHOT</version>
<properties>
<java-version>1.8</java-version>
<org.springframework-version>5.2.5.RELEASE</org.springframework-version>
<org.aspectj-version>1.6.10</org.aspectj-version>
<org.slf4j-version>1.6.6</org.slf4j-version>
</properties>
<dependencies>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${org.springframework-version}</version>
<exclusions>
<!-- Exclude Commons Logging in favor of SLF4j -->
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${org.springframework-version}</version>
</dependency>
<!-- AspectJ -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${org.aspectj-version}</version>
</dependency>
<!-- Logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${org.slf4j-version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>${org.slf4j-version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${org.slf4j-version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.15</version>
<exclusions>
<exclusion>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
</exclusion>
<exclusion>
<groupId>javax.jms</groupId>
<artifactId>jms</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jdmk</groupId>
<artifactId>jmxtools</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jmx</groupId>
<artifactId>jmxri</artifactId>
</exclusion>
</exclusions>
<scope>runtime</scope>
</dependency>
<!-- @Inject -->
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
<!-- Servlet -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- Test -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.7</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<!--
1) 자바빈 클래스(VO)의 getter/setter 메소드, toString 자동 처리
2) log.info() 메소드로 sysout 대신 로그를 console에 출력
-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
<scope>provided</scope>
</dependency>
<!-- Datebase 라이브러리 시작 -->
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<!-- XML로 쿼리를 작성하게 해주는 라이브러리 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.10</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
<!-- 스프링과 mybatis를 연동하게 해주는 라이브러리 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<!-- 스프링에스 JDBC(Java Database Connectivity)를 사용하도록 해주는 라이브러리 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<!-- <version>5.2.5.RELEASE</version> -->
<!-- 이 방식으로 쓰면 버전이 바껴도 매핑이 된다. -->
<version>${org.springframework-version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-dbcp2 -->
<!-- dbcp : database connection pool => 커넥션객체를 미리 만들어놓고 쓰고/반납
최근에는 hikaricp를 사용하는 경우도 있음 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
<version>2.7.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.bgee.log4jdbc-log4j2/log4jdbc-log4j2-jdbc4 -->
<!-- 로깅을 위한 라이브러리. 쿼리를 console이나 파일 로그로 볼 수 있음 -->
<dependency>
<groupId>org.bgee.log4jdbc-log4j2</groupId>
<artifactId>log4jdbc-log4j2-jdbc4</artifactId>
<version>1.16</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.oracle.database.jdbc/ojdbc6 -->
<!-- ojdbc6: oracle java database connectivity 드라이버 -->
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc6</artifactId>
<version>11.2.0.4</version>
</dependency>
<!-- Datebase 라이브러리 끝 -->
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-eclipse-plugin</artifactId>
<version>2.9</version>
<configuration>
<additionalProjectnatures>
<projectnature>org.springframework.ide.eclipse.core.springnature</projectnature>
</additionalProjectnatures>
<additionalBuildcommands>
<buildcommand>org.springframework.ide.eclipse.core.springbuilder</buildcommand>
</additionalBuildcommands>
<downloadSources>true</downloadSources>
<downloadJavadocs>true</downloadJavadocs>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.5.1</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
<compilerArgument>-Xlint:all</compilerArgument>
<showWarnings>true</showWarnings>
<showDeprecation>true</showDeprecation>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.2.1</version>
<configuration>
<mainClass>org.test.int1.Main</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
수정 후 Run as - maven build 해준다.
<BookController.java>에 import 해준다.
import org.apache.commons.dbcp2.BasicDataSource;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
<root-context.xml>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- Root Context: defines shared resources visible to all other web components -->
<!-- root-context.xml : 스프링 설정 파일
스프링 설정? view와 관련되지 않은 객체들을 정의
Service(기능), DAO(Repository : 저장소), DB등 비즈니스 로직과 관련된 설정
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName("oracle.jdbc.driver.OracleDriver")
bean : 객체 생성
property : 멤버변수
<property name="mapperLocations" value="classpath:/sqlmap/**/*_SQL.xml" />
classpath : sqlmap ==> src/main/resources에 생성될 패키지명
-->
<!-- dataSource : 데이터베이스와 관련된 정보를 설정 -->
<bean id="dataSource"
class="org.apache.commons.dbcp2.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:@localhost:1521:xe" />
<property name="username" value="spring" />
<property name="password" value="java" />
</bean>
<!-- 데이터베이스와 연결을 맺고 끊어질 때까지의 라이프 사이클을 관리해주는
sqlSession 객체를 생성
1) satasource
2) 매퍼 xml의 위치 지정 : src/main/resources
-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="mapperLocations" value="classpath:/sqlmap/**/*_SQL.xml" />
<property name="configLocation" value="/WEB-INF/mybatisAlias/mybatisAlias.xml" />
</bean>
<!-- 데이터베이스에 개별적으로 쿼리를 실행시키는 객체
이 객체를 통해 query를 실행함
-->
<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory" />
</bean>
</beans>
다시 서버를 돌리고
localhost/create 를 실행시키면
redirect여서 전송을 보내고난 후
다시 돌아온다 ..!