Spring

Spring 02 - 도서 CRUD (1) - create

inderrom 2023. 1. 19. 17:49

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 검색

 

https://mvnrepository.com/

 

복사 후 

 

<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 설치

 

maven build를 하면 자동으로 생성되는데 .. 그 폴더에서 cmd를 실행시킨다.

cmd에 명령어 입력

java -jar lombok-1.18.24.jar

install 한다.

 

 


<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 라이브러리 설치

  1. mybatis 3.5.10
  2. mybatis-spring 2.0.4 
  3. spring-jdbc 5.2.5
  4. commons-dbcp2 2.7.0
  5. log4jdbc-log4j2-jdbc4 1.16
  6. ojdbc6  11.2.0.4

 maven 소스 copy

 

2.0.4 버진
5.2.5 버전
2.7.0 버전

<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여서 전송을 보내고난 후

다시 돌아온다 ..!