Spring 실습

Spring 2024-04-23 실습(2일차)

choco2706 2024. 4. 23. 10:44

어제 하던 데이터 등록을 이어서 해보자

<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<title>Insert title here</title>
</head>
<body>
<!-- mav.addObject("title","상품 분류 생성") -->
<h1>${title}</h1>
<!--
   요청URI : /lprod/create
   요청파라미터 : {lprodId=14, lprodGu=P501, lprodNm=분식류}
   요청방식 : post
-->
<form action="/lprod/create" method="post">
	<p><input type="number" name="lprodId" placeholder="상품분류ID(ex. 14)"></p>
	<p><input type="text" name="lprodGu" placeholder="상품분류코드(ex. P501)"></p>
	<p><input type="text" name="lprodNm" placeholder="상품분류명(ex. 분식류)"></p>
	<p><input type="submit" value="전송"></p>
</form>
</body>
</html>

위 코드 실행 화면

 

lprod라는 테이블에 상품을 추가하기 위해 form안에 input에 데이터를 입력하고 submit 버튼을 누르면 각 name명으로 데이터들이 form의 action에 들어있는 경로로 데이터가 전달된다.

 

Controller로 받아주기 전에 LprodVO를 만들자

package kr.or.ddit.vo;

import lombok.Data;

@Data
public class LprodVO {
	private int lprodId;
	private String lprodGu;
	private String lprodNm;
}

 

@Data : 어제 롬복을 깔아놨기 때문에 getter/setter나 생성자를 굳이 만들어주지 않아도 된다.

단. POJO를 위반하기 때문에 의존성이 높아진다는 단점은 있다.

 

package kr.or.ddit.controller;

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.LprodVO;
import lombok.extern.slf4j.Slf4j;

// 스프링 프레임워크에게 "이 클래스는 컨트롤러야"라고 알려주기
@Slf4j
@RequestMapping("/lprod")
@Controller
public class LprodController {
	/*
		    요청URI : /lprod/create
		    요청파라미터 : 
		    요청방식 : get
	 */
	@RequestMapping(value="/create",method=RequestMethod.GET)
	public ModelAndView create() {
		ModelAndView model = new ModelAndView();
		// 데이터
		model.addObject("title","상품 분류 등록");
		// jsp
		// /WEB-INF/Views/ + lprod/create + .jsp
		model.setViewName("lprod/create");
		
		return model;
	}
	
	@RequestMapping(value="/create", method=RequestMethod.POST)
	public ModelAndView createPost(LprodVO lprodVO) {
		ModelAndView model = new ModelAndView();
		
		log.info("lprodVO : " + lprodVO);
		
		model.setViewName("redirect:/lprod/create");
		
		return model;
	}
}

 

post 방식으로 /create로 보내기 때문에 위로는 가지 않고 아래 있는 createPost로 데이터가 넘어오게 되고

log.info()를 통해 이클립스 콘솔창에 데이터 정보가 뜨게 된다.

(log.info()가 오류가 뜰 시 클래스 최상단에 @Slf4j를 추가해보자. lombok의 기능 중 하나)

 

이제 jsp에 데이터를 넣고 실행을 하면

데이터를 받아오는 모습

 

이클립스 콘솔창으로 데이터가 넘어오는 것을 볼 수 있다.

 

--> 데이터베이스(오라클 SQL 기준)에서 VO명처럼 긁어오는 방법

더보기
--구글 카멜변환(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
, '<result property="'||FN_GETCAMEL(COLUMN_NAME)||'" column="'||COLUMN_NAME||'"/>' RESULTMAP
FROM ALL_TAB_COLUMNS
WHERE TABLE_NAME = '테이블이름(대문자)'
AND       USER = '사용자이름(대문자)';

 

root-context.xml, pom.xml, web.xml 설정

데이터베이스와 연동하기 위해 위 3개의 파일을 설정해줘야한다.

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 : 스프링 설정 파일
   서블릿과 필터가 공유할 수 있는 루트 스프링 컨테이너 설정으로, 공통 빈(Service, Repository(DAO), DB, Log 등)을 설정함.
   공통빈을 설정하는 곳으로 주로 View 지원을 제외한 bean을 설정함
   
   스프링 설정?
   view와 관련되지 않은 객체를 정의
   Service(기능), DAO(Repository : 저장소), DB등 비즈니스 로직과 관련된 설정
   BasicDataSource dataSource = new BasicDataSource();
   dataSource.setDriverClassName() = "oracle.jdbc.driver.OracleDriver";
    -->
    <!-- dataSource : 데이터베이스와 관련된 정보를 설정 -->
   <!-- 
   db : database(개념. 공유/저장/통합/운영). RDB(Relational DB.관계형DB)
   dbms : database management system(DB관리시스템.오라클)
   localhost=127.0.0.1=내ip주소
   xe : express(OracleXE11g.r2) => SID(sequence ID)
    -->
   <!-- 
   BasicDataSource dataSource = new BasicDataSource();
   dataSource.setDriverClassName("oracle.jdbc.driver.OracleDriver");
   dataSource.setUrl("jdbc:oracle:thin:@localhost:1521:xe");
    -->
   <bean id="uploadFolder" class="java.lang.String">
      <constructor-arg value="C:\\eGovFrameDev-3.10.0-64bit\\workspace\\springProj\\src\\main\\webapp\\resources"></constructor-arg>
   </bean>
   
   <bean id="uploadFolderDirect" class="java.lang.String">
      <constructor-arg value="C:\\eGovFrameDev-3.10.0-64bit\\workspace\\.metadata\\.plugins\\org.eclipse.wst.server.core\\tmp0\\wtpwebapps\\springProj\\resources\\upload"></constructor-arg>
   </bean>
    
   
   <bean id="dataSource" 
      class="org.apache.commons.dbcp2.BasicDataSource" 
      destroy-method="close">
      <property name="driverClassName" 
      value="oracle.jdbc.driver.OracleDriver" />
      <!-- url부분에는 본인 오라클 ip와 
   		오라클에 접속할때 사용되는 사용자 이름, 비밀번호를 작성해야 한다 -->
      <property name="url" 
      value="jdbc:oracle:thin:@localhost:1521:xe" />
      <property name="username" value="pc11_2" />
      <property name="password" value="java" />
   </bean>
   <!-- 데이터베이스와 연결을 맺고 끊어질 때까지의 
   라이프 사이클을 관리해주는 sqlSession 객체를 생성
   1) dataSource
   2) 매퍼 xml의 위치 지정. / : src/main/resources/
   SqlSessionFactoryBean sqlSessionFactory = new SqlSessionFactoryBean();
   sqlSessionFactory.setDataSource(dataSource);
    -->
   <bean id="sqlSessionFactory"
   class="org.mybatis.spring.SqlSessionFactoryBean">
      <property name="dataSource" ref="dataSource"></property>
      <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>

web.xml

더보기
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1" xmlns="http://java.sun.com/xml/ns/javaee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_3_1.xsd">
	
	<!-- 
	web.xml : tomcat서버의 설정
	웹 프로젝트의 배포 설명자/배치 기술서(deployment description)이며, 웹 프로젝트가 배포되는 데 이용되는 XML 형식의
	자바 웹 애플리케이션 환경 설정 부분을 담당함
	스프링 웹 프로젝트가 실행되면 가장 먼저 web.xml 파일을 읽어들이고 위부터 차례로 태그를 해석함
	
	1) 네임 스페이스 : 코드에서 이름은 같지만 내용이 전혀 다른 요소와 충돌하지 않도록, 즉 이런 요소를 구별하는 데 사용함
	2) 스키마 : 코드의 구조와 요소, 속성의 관계를 정의하여 다양한 자료형을 사용할 수 있도록 정의된 문서 구조, 즉 틀을 의미함
	   xsi:schemaLocation 속성은 참조하고자 하는 인스턴스 문서의 URI를 지정함
	                    두 개의 속성 값은 공백으로 구분. 첫 번째는 사용할 네임 스페이스(보통 기본 네임 스페이스와 동일)고,
	                                        두 번째는 참조할 스키마 파일 이름.
	-->

	<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/spring/root-context.xml</param-value>
	</context-param>
	
	<!-- Creates the Spring Container shared by all Servlets and Filters -->
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>

	<!-- Processes application requests -->
	<servlet>
		<servlet-name>appServlet</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
		
	<servlet-mapping>
		<servlet-name>appServlet</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>
	
	<!-- 한글 처리 -->
   <filter>
      <filter-name>encodingFilter</filter-name>
      <filter-class>
         org.springframework.web.filter.CharacterEncodingFilter
      </filter-class>
      <init-param>
         <param-name>encoding</param-name>
         <param-value>UTF-8</param-value>
      </init-param>
      <init-param>
         <param-name>forceEncoding</param-name>
         <param-value>true</param-value>
      </init-param>
   </filter>
   <filter-mapping>
      <filter-name>encodingFilter</filter-name>
      <!-- 모든 요청에서 -->
      <url-pattern>/*</url-pattern>
   </filter-mapping>

</web-app>

pom.xml

맨 위 properties에 있는 java-version은 본인 자바 버전을 적어준다.

더보기
<?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>   
		
		<!-- Database 라이브러리 시작 -->
      <!-- 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 Connectivitiy) -->
      <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-jdbc</artifactId>
          <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>
      <!-- Database 라이브러리 시작 -->   
      
      <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
	      <!-- 
	         1) 자바빈 클래스(VO)의 getter/setter메소드, toString 자동처리
	         2) log.info() 메소드로 sysout대신 로그를 console에 출력
	         1. 개요
	         	메이븐을 사용하게 되면 POM 파일을 다뤄야 합니다. 
	        	POM은 Project Object Model의 약자인데... 
	        	pom.xml이라는 파일이 바로 POM 파일이고 이 파일을 통해 dependency라고 부르는 의존성 설정을 하게 됩니다...
	        	 그리고 각 dependency는 scope을 가지고 있어요...
	         	종류는 compile, runtime, provided 등의 종류가 있지요...
	         2. compile
	         compile은 컴파일때 필요한 것입니다... 기본값이기 때문에 만일 scope 설정을 안하면 compile이 기본입니다...
	         
	         3. runtime
	         runtime은 런타임때 필요한 것입니다. 컴파일할 때는 필요가 없지만 실행할 때는 필요한 것이지요.
	         JDBC 드라이버 같은게 되겠습니다.
	         
	         4. provided
	         provided는 컴파일때 필요하긴 하지만 런타임때는 JDK 혹은 컨테이너가 제공하는 것입니다.
		         마지막 패키징 시 포함되지 않음
		         서블릿이나 JSP 관련 API 같은거죠. 
		         즉 WAS에서 제공하는 servlet-api.jar를 사용하는 경우 (대부분이겠죠) 입니다.
		         만약 운영환경에서 servlet-api.jar 중복으로 인한 문제가 발생한다면 꼭 provided로 바꿔주셔야 합니다.
	         
	         5. test
	         test는 조금 특별한데 테스트 코드를 컴파일할때 필요하지만 배포때는 제외가 됩니다. (따라서 굳이 운영 환경에 JUnit 의존성을 삭제할 필요가 없어요)
	         easymock, JUnit 같은거죠.
	         
	         6. system
	         system은 provided와 유사하지만 JAR 파일을 직접 사용합니다...
	                  이 때는 JAR 파일의 위치를 지정하는 systemPath 엘리먼트가 따라와야 해요...
      		-->
      <dependency>
          <groupId>org.projectlombok</groupId>
          <artifactId>lombok</artifactId>
          <version>1.18.22</version>
          <scope>provided</scope>
      </dependency>  
	</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>

 

 

 

Service, Dao 만들기

기본 틀

kr.or.ddit 패키지 안에 service 패키지를 만든다.

ctrl + n을 누르고 BookService라는 interface를 만들어 두고 class를 하나 만든 뒤 

오른쪽 중간에 Add를 누른 후 만들어 둔 interface를 선택한 뒤 finish

같은 방식으로 Dao 패키지도 만들어 준다

아래 사진에는 BookDao가 Interface로 만들어져있는데 그냥 Class로 만들어주어야한다.

완성본( Dao는 위 글 참고 )

 

ServiceImpl은 Service패키지 안에 Impl패키지를 하나 더 만든 다음 그 안에 넣어둔다.

 

이제 xml 파일을 만들어주어야 하는데 아래 사진을 참고하여 경로대로 만들어 준다

xml 파일 경로
MVC 패턴의 진행 방식 (중요)

 

Controller->Service->Impl(Service)->Dao->Sql.xml->DB(쿼리문 작동) 후 역행하여 jsp화면으로 출력

Controller, jsp : 프리젠테이션 계층

Service, ServiceImpl : 서비스(비즈니스 계층)

Dao : 퍼시스턴스 계층

 

데이터베이스에 insert 하기

package kr.or.ddit.controller;

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;

/*
	Controller 어노테이션
	스프링 프레임워크에게 "이 클래스는 웹 브라우저의 요청(request)를 받아들이는 컨트롤러야" 라고 알려주는 것.
	스프링은 servlet-context.xml의 context:component-scan의 설정에 의해
	이 클래스를 자바빈 객체로 등록(메모리에 바인딩).
*/
@Slf4j
@Controller
public class BookController {
	// 서비스를 호출하기 위해 의존성 주입(Dependency Injection-DI)
	// IoC(Inversion of Control) - 제어의 역전.(개발자가 객체생성하지 않고 스프링이 객체를 미리 생성해놓은 것을 개발자가 요청)
	// 의존성 주입
	@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);
		
		// 도서 등록
		int result = this.bookService.createPost(bookVO);
		log.info("result : " + result);
		
		ModelAndView mav = new ModelAndView();
		
		// data
		mav.addObject("bookVO", bookVO);
		// jsp / redirect : 새로운 URL 요청
		mav.setViewName("redirect:/create");
		
		return mav;
	}
	
}

 

만들어 놓은 컨트롤러에 BookService bookService를 만들어주고

createPost에  int result = this.bookService.createPost(bookVO);로 선언해주면 createPost쪽이 빨간 줄이 나면서 에러가 난다

 

Service 인터페이스에 createPost라는 메소드가 없기 때문이니까 빨간줄에 f2를 눌러준 뒤 Create method...를 눌러준다

위에껄 눌러야 한다

 

BookService InterFace

그럼 BookService Interface에 자동으로 메소드가 하나 만들어지고, 

BookServiceImpl

더보기
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
public class BookServiceImpl implements BookService {
	
	@Autowired
	BookDao bookDao;

	@Override
	public int createPost(BookVO bookVO) {
		
		return this.bookDao.createPost(bookVO);
	}
	
}

BookServiceImpl에도 같은 이름으로 오버라이딩 된다.(@Service 어노테이션은 스프링이 자바빈으로 등록하기 위한 역할이기때문에 필수적이다.)

 

마찬가지로 return에 있는 createPost는 Dao에 메소드가 없기 때문에 연동이 안된다는 오류이기 때문에 f2를 눌러 메소드를 만들어주자

 

package kr.or.ddit.dao;

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
	SqlSessionTemplate sqlSessionTemplate;

	public int createPost(BookVO bookVO) {
		//book_SQL.xml 파일의 namespace가 book이고, id가 insert인
        //태그를 찾아 그 안에 들어있는 sql을 실행함
        //bookVO=>{"bookId":"","title":"총알탄 개똥이","category":"소설","price":10000,"insertDate":""}
        //insert,update,delete는 반영된 건수가 return됨
        //insert성공 : 1이상, 실패면 0
		return this.sqlSessionTemplate.insert("book.createPost", bookVO);
	}

}

 

serviceImpl과 마찬가지로 @Repository를 반드시 넣어주어야 한다.

 

SqlSessionTemplate의 변수명은 root-context.xml의 맨 아래 있는 bean의 id값과 일치해야 한다.

root-context.xml

 

return this.sqlSessionTemplate.insert("book.createPost", bookVO);

의 부분에서도 앞 "book"은 만들어놓은 book_SQL.xml에 있는 namespace값을 넣어주고 insert태그의 id를 붙혀주어야 한다.(뒤 코드 참고) 

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의 멤버변수(결과를 담을)
      -->
      <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>
</mapper>

 

완성된 book_SQL.xml코드이다. 파라미터값으로 bookVO를 받아오며, 그 안에 있는 bookId, title 등을 꺼내와서

#{}안에 매핑된다.

 

bookId의 경우 따로 적지 않고 데이터베이스 안에 담겨있는 bookId의 마지막 번호가 자동으로 입력되게 작성했다. 

이전 게시물에서 우린 title, categort, price 셋만 담아왔기 때문.

 

위 코드에서는 insert문이 실행 되기 "전에"  selectKey에 담겨있는 코드가 먼저 실행이 된 후 bookId라는 키값으로 값이 나오게 된다. 그 다음 insert문을 실행하며 bookId값이 위에 실행된 코드로 인해 생성이 된 상태로 쿼리가 실행된다.

 

이제 다시 컨트롤러로 넘어와서

 

데이터를 입력하고 저장을 누르면

이클립스 콘솔창

 

테이터베이스

데이터베이스에 잘 들어가있는 모습을 볼 수 있다.

 

※주의

어노테이션(@...)이 제대로 적혀있지 않으면 500에러를 띄울 수 있다.

나의 경우 @Autowired를 제대로 적어주지 않아 java.lang.NullPointerException 에러가 떴었다.

 

(@...)어노테이션(Annotation)이란?

사전적 의미로는 주석이라는 뜻이지만, 자바에서는 코드 사이에 특별한 의미, 기능을 수행하도록 하는 기술이라고 한다.

어노테이션을 사용하면 코드가 깔끔해지고 재사용이 가능하다.

  • 컴파일러에게 코드 작성 문법 에러를 체크하도록 정보를 제공
  • 소프트웨어 개발 툴이 빌드나 배치시 코드를 자동으로 생성할수 있도록 제공
  • 실행시(런타임 시) 특정 기능을 실행하도록 정보를 제공

오늘 사용한 어노테이션만 정리해보겠다.

 

@Autowired

필드, setter 메소드, 생성자에 사용하며, Type에 따라 알아서 Bean을 주입해주는 역할

객체애 대한 의존성을 주입하며, 스프링이 자동적으로 값을 할당한다.

Controller 클래스에서 DAO나 Service에 관한 객체를 주입 시킬 때 자주 사용된다.

 

@Controller

Spring MVC의 Controller로 사용되는, 클래스 선언을 단순화 시켜주는 어노테이션이다.

 

@Repository

DAO class에서 쓰이는 어노테이션이다.

데이터베이스에 접근하는 메소드를 가지고있는 class에서 사용된다.

 

@Service

Service class에서 쓰이는 어노테이션으로 비즈니스 로직을 수행하는 class라는 것을 나타내는 용도로 사용된다.

 

@RequestMapping

어떤 URL을 어떤 method가 처리할 지 매핑해주는 어노테이션이다. Controller나 Controller의 메소드에 적용한다.

요청을 받는 형식인 GET / POST / PUT / PATCH / DELETE 를 정의하기도 한다.(생략시 GET으로 설정됀다.)

 

@Slf4j (Simple Logging Facade for Java)

java.util.logging, logback, log4j와 같은 다양한 로깅 프레임 워크에 대한 추상화(인터페이스) 역할을 하는 라이브러리 

인터페이스이기 때문에 단독으로 사용이 불가능하다.

 

 

 

2일차 종료!