코드로 배우는 스프링 웹 프로젝트 보면서 따라해봄!!!!!!!
4.5 MyBatis 연결
DataSource의 연결은 mybatis의 설정과는 관계있으므로 먼저 설정하고 테스트해야 합니다. 데이터 소스가 정상적으로 설정된 이후의 작업은 mybatis와 mysql을 연동시키는 작업입니다.
4.5.1 Sqlsessionfactory 객체 생성
Mybatis와 스프링 연동 작업에서의 핵심은 connection을 생성하고, 처리하는 sqlsessionfactory의 존재입니다. Sqlsessionfactory는 데이터베이스와의 연결과 sql 실행에 대한 모든 것을 가진 가장 중요한 객체입니다.
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property> </bean>
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:mybatis-spring="http://mybatis.org/schema/mybatis-spring" xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.3.xsd http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring-1.2.xsd http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
<!-- Root Context: defines shared resources visible to all other web components -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/book_ex?userSSL=false"></property>
<property name="username" value="zerock"></property> <property name="password" value="zerock"></property>
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"></property> </bean>
</beans> |
스프링을 이용할 때는 sqlsessionfactory를 생성해 주는 특별한 객체를 설정해 주는데 sqlsessionfactorybean이라는 클래스를 사용합니다. Sqlsessionfactorybean은 프로젝트의 ‘root-context.xml’을 이용해서 다음과 같이 등록합니다.
4.5.2 mybatis-config.xml 파일의 추가
나중을 위해서라도 MyBatis의 설정 파일을 하나 추가해 주는 것이 편리하다.
4.5.2.1 mybatis-config.xml 파일의 작성
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> <environments default="development"> <environment id="development"> <transactionManager type="JDBC" /> <dataSource type="POOLED"> <property name="driver" value="${driver}" /> <property name="url" value="${url}" /> <property name="username" value="${username}" /> <property name="password" value="${password}" /> </dataSource> </environment> </environments> </configuration> |
4.5.3 mybatis의 연결 테스트
5 package org.zerock.web; 6 7 import javax.inject.Inject; 8 9 import org.apache.ibatis.session.SqlSession; 10 import org.apache.ibatis.session.SqlSessionFactory; 11 import org.junit.Test; 12 import org.junit.runner.RunWith; 13 import org.springframework.test.context.ContextConfiguration; 14 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 15 16 @RunWith(SpringJUnit4ClassRunner.class) 17 @ContextConfiguration(locations = { "file:src/main/webapp/WEB-INF/spring/**/root-context.xml" }) 18 19 public class MyBatisTest { 20 21 @Inject 22 private SqlSessionFactory sqlFactory; 23 24 @Test 25 public void testFactory() { 26 System.out.println(sqlFactory); 27 28 } 29 30 @Test 31 public void testSession() throws Exception { 32 try (SqlSession session = sqlFactory.openSession()) { 33 System.out.println(session); 34 } catch (Exception e) { 35 e.printStackTrace(); 36 } 37 } 38 39 } 40 |
만들어진 파일을 편하게 사용하기 위해서는 XML 파일의 DTD나 XML 스키마라는 것이 필요합니다.
클래스 선언 아래 인스턴스 변수 sqlFactory에는 스프링이 정상적으로 동작할 경우 sqlsessionfactory를 주입시켜줄 것을 요구합니다. testSession()에서는 try – with 구문을 활용해서 실제 데이터베이스와의 연결을 담당하는 객체인 sqlsession을 생성하는 부분입니다. 위 코드의 실행 결과는 아래와 유사한 형태로 ‘org.apache/ibatis.defaults.DefaultSqlSession….’과 같은 메시지가 보여지면 정상적으로 동작하는 것 입니다.
지금 까지 한게?
- 필요한 라이브러리 추가
- Mybatis, mybatis-spring, spring-jdbc, spring-test 모듈 추가
- Datasource 객체의 설정과 테스트
- Mybatis의 sqlsessionfactorybean의 설정
- Mybatis의 설정 파일인 mybatis-config.xml 파일의 설정
- 스프링+mybatis+mysql의 최종 연결 테스트
05 모델 2 방식과 스프링 MVC
스프링으로 웹 프로젝트를 진행하면 스프링 MVC를 사용해서 진행하게 됩니다. 스프링 MVC는 모델 2방식 구조를 이용하기 때문에 이해가 필요합니다.
모델2 방식은 ‘화면과 데이터 처리를 분리해서 재사용이 가능하도록 하는 구조’라고 할 수 있습니다.
모델2 구조에서는 다음과 같은 용어들이 사용됩니다.
- 모델(Model): 데이터 혹은 데이터를 처리하는 영역을 의미합니다.
- 뷰(view): 결과 화면을 만들어 내는데 사용하는 자원을 의미합니다.
- 컨트롤러(controller): 웹의 요청(request)을 처리하는 존재로 뷰와 모델 사이의 중간 통신역할을 합니다.
C:controller, m:model, v:view
컨트롤러는 모델 계층과 연동해서 필요한 데이터를 처리하고 결과를 뷰로 전송하게 됩니다.
모델 2에서 모든 요청은 기본적으로 컨트롤러를 호출합니다. 각 컨트롤러는 자신의 호출하는 특정한 URI 경로를 가지고 있습니다. 과거에는 주로 호출 시에 마지막 확장자를 ‘*.do’등을 이용하는 방식을 많이 사용했습니다.
모델 2 방식은 1) 개발자와 웹 퍼블리셔의 영역을 분리할 수 있으며, 2) 컨트롤러의 URI를 통해서 뷰를 제어하기 때문에, 뷰의 교체나 변경과 같은 유지보수에 유용하게 사용될 수 있습니다.
5.1.1 모델 2에서 Front Cotrooler 패턴으로
모델2 방식이 개발자와 웹 퍼블리셔 간의 분업을 이루는 데는 성공했지만, 각 컨트롤러 사이의 중복적인 코드의 문제와 개발자의 개발 패턴의 차이 등의 문제로 인해 모델 2 방식은 좀 더 강제적인 형태인 Front Controller 방식을 적용하게 됩니다.
Front controller 패턴의 가장 중요한 변화는 전체 로직의 일부만을 컨트롤러가 처리하도록 변경되었다는 점입니다. 흔히 ‘위임’이라고 하는데, 전체로직의 일부를 컨트롤러에게 위임하고 모든 흐름의 제어는 앞쪽의 front controller가 담당하게 됩니다.
위와 같은 구조를 사용하게 될 경우 개발자가 작성하는 컨트롤러는 전체 로직의 일부분만을 처리하는 형태가 되기 때문에 개발자가 작성해야 하는 전체 코드는 줄어들게 됩니다. 또한 모든 컨트롤러는 front controller의 일부분을 구현하는 형태이므로, 좀 더 규격화된 코드를 작성하게 됩니다.
1) Front controller controller 2)service 3)dao 4) mapper mybatis mysql
7) view template
스프링 MVC가 처리해 주는 작업 |
개발자가 직접 해야 하는 작업 |
URI를 분석해서 적절한 컨트롤러를 찾는 작업 컨트롤러에 필요한 메소드를 호출하는 작업 컨트롤러의 결과 데이터를 뷰로 전달하는 작업 적절한 뷰를 찾는 작업 |
특정 URI에 동작하는 컨트롤러를 설계하는 작업 서비스 객체의 생성 DAO 객체의 생성 컨트롤러 내에 원하는 결과를 메소드로 설계 뷰에서 전달받은 데이터의 출력 |
스프링 MVC를 사용하면 개발의 전체 흐름은 개발자가 제어하지 않고 개발자는 필요한 부품을 끼워 넣는 형태의 작업을 하게 됩니다. 스프링 MVC의 경우에는 이 부품이 컨트롤러가 됩니다.
5.2 스프링 mvc의 컨트롤러
- 스프링 mvc 컨트롤러는 상속이나 인터페이스를 구현하지 않아도 됩니다. 기존의 프레임워크들과는 달리 스프링 mvc에서는 컨트롤러 작성시 아무런 제약이 없습니다. 그대신 해야 하는 작업은 @Controller라는 애노테이션에 대한 추가 작업입니다.
5.2.1 spring project의 servlet-context.xml 파일
스프링 mvc 컨토롤러가 어떤 설정을 통해서 동작하는지에 대한 이해
mybatis와의 연동을 위해서 작성해 본 프로젝트의 servlet-context.xml을 보면 스프링 mvc 컨트롤러 실행에 있어서 가장 중요한 정보 몇 가지를 볼 수 있습니다.
Appservlet 폴더 내에 존재하는 servlet-context.xml을 스프링 mvc 관련 설정만을 분리하기 위해서 만들어진 파일입니다.
<annotation-driven>의 설정은 클래스 선언에 애노테이션을 이용해서 컨트롤러를 작성할 수 있다는 선언입니다.
Internalresourceviewresolver 부분은 뷰를 어떻게 처리하는가에 대한 설정입니다. 이때 주목해야 하는 경로가 ‘/WEB-INF/views/’라는 경로입니다. ‘WEB-INF’는 절대로 브라우저에 직접 접근할 수 없는 경로이기 때문에 컨트롤러의 호출이 우선되는 모델 2 방식에 맞는 구조가 됩니다.
<resources>는 웹에서 이미지나 css, javascript 파일과 같이 고정된 자원들의 위치를 의미합니다.
<component-scan> 의미도 상당히 중요한 의미를 가지는데 component-scan은 base-package 속성값에 해당하는 패키지 내부의 클래스들을 조사한다는 뜻입니다. 이는 <annotation-driven>과 같이 결합해서 해당 패키지에 애노테이션 처리가 된 컨트롤러를 작성만 해주면 자동으로 인식하게 합니다.
5.2.2 스프링 mvc에서 주로 사용하는 애노테이션의 종류
스프링 mvc에서는 컨트롤러가 상속 등의 전통적인 기법을 사용하지 않는 대신에 애노테이션으로 많은 일을 처리합니다. 주로 많이 사용하는 애노테이션은 다음과 같습니다.
애노테이션 |
설명 |
사용 |
@Controller |
스프링 mvc의 컨트롤러 객체임을 명시하는 애노테이션 |
클래스 |
@requestmapping |
특정 uri에 매칭되는 클래스나 메소드임을 명시하는 애노테이션 |
클래스, 메소드 |
@requestparam |
요청에서 특정한 파라미터의 값을 찾아낼 때 사용하는 애노테이션 |
파라미터 |
@requestheader |
요청에 특정 http 헤더 정보를 추출할 때 사용 |
파라미터 |
@pathvariable |
현재의 uri에서 원하는 정보를 추출할 때 사용하는 애노테이션 |
파라미터 |
@cookievalue |
현재 사용자의 쿠키가 존재하는 경우 쿠키의 이름을 이용해서 쿠키의 값을 추출 |
파라미터 |
@modelattribute |
자동으로 해당 객체를 뷰까지 전달하도록 만드는 애노테이션 |
메소드, 파라미터 |
@sessionattribute |
세션상에서 모델의 정보를 유지하고 싶은 경우에 사용 |
클래스 |
@initbinder |
파라미터를 수집해서 객체로 만들 경우에 커스터마이징 |
메소드 |
@responsebody |
리턴 타입이 http의 응답 메시지로 전송 |
메소드, 리턴타입 |
@requestbody |
요청 문자열이 그대로 파라미터로 전달 |
파라미터 |
@repository |
Dao 객체 |
클래스 |
@service |
서비스 객체 |
클래스 |
5.2.3 기초적인 컨트롤러 생성 실습
5.2.3.1 void 리턴 타입의 경우
package org.zerock.web;
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping;
@Controller //이 클래스를 컨트롤러로 설정하게 하는 애노테이션 입니다. public class SampleController {
private static final Logger logger = LoggerFactory.getLogger(SampleController.class);
@RequestMapping("doA") //특정한 uri 경로에 해당하면 메소드가 실행됩니다. public void doA() { logger.info("doA called......"); }
@RequestMapping("doB") public void doB() { logger.info("doB called......"); }
} |
현재 메소드의 리턴 타입이 void인 경우에는 스프링 mvc는 현재 경로에 해당하는 jsp 파일을 실행하게 됩니다.
5.2.3.2 string이 리턴 타입인 경우
만일 컨트롤러에서 메소드의 리턴 타입이 문자열인 경우라면 결과는 ‘문자열+.jsp’ 파일을 찾아서 실행하게 됩니다.
package org.zerock.web;
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping;
@Controller public class SampleController2 {
private static final Logger logger = LoggerFactory.getLogger(SampleController2.class);
@RequestMapping("doC") public String doC(@ModelAttribute("msg") String msg) { logger.info("doC called......");
return "result"; }
}
|
메소드의 선언에 사용된 @RequestMappingdms URI가 /doC인 경우에 동작함을 의미합니다.
doC() 메소드 내의 파라미터에 사용된 @ModelAttribute(“msg”)는 요청(request) 시 ‘msg’ 이름의 파라미터를 문자열로 처리해 주고, 뷰에 전달되도록 합니다.
doC() 메소드의 리턴 값으로 사용된 ‘result’는 결과적으로 /WEB-INF/views/result.jsp 파일을 찾아서 실행하게 됩니다.
Result.sjp 파일의 경우 아래와 같이 작성할 수 있습니다.
**.jsp 폴더
Webapp 마우스 오른쪽 -> jsp file
<span> 태그를 보면 jsp의 EL을 사용해서 ${msg}를 출력하는 부분이 보입니다. 스프링의 mvc의 @modelattribute는 자동으로 해당 객체를 뷰까지 전달합니다.
브라우저에서 실행할 때 아래와 같이 ‘msg’ 파라미터를 같이 전달해 주면 결과 화면에 출력되는 것을 볼 수 있습니다.
<%@ page language="java" contentType="text/html; charset=EUC-KR" pageEncoding="EUC-KR"%> <!DOCTYPE html> <html> <head> <meta charset="EUC-KR"> <title>Insert title here</title> </head> <body>
<span>Hello Billy${msg}</span>
</body> </html> |
5.2.3.3 만들어진 결과 데이터를 전달해야 하는 경우
컨트롤러 제작하면서 가장 많이 하는 작업은 다른 객체의 도움을 받아 만들어진 데이터를 뷰로 전달하는 일을 하는 것입니다. 이때는 스프링 mvc의 model 객체를 사용해서 간편하게 처리할 수 있습니다.
package org.zerock.domain;
public class ProductVO {
private String name; private double price;
public ProductVO(String name, int price) { // TODO Auto-generated constructor stub super(); this.name = name; this.price = price; }
public String getName() { return name; }
public double getPrice() { return price; }
@Override public String toString() { // TODO Auto-generated method stub return "ProductVO [name=" + name + ", price=" + price + "]"; }
}
|
package org.zerock.web;
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.zerock.domain.ProductVO;
public class SampleController3 {
private static final Logger logger = LoggerFactory.getLogger(SampleController3.class);
@RequestMapping("/doD") public String doD(Model model) {
//make sample data ProductVO product = new ProductVO("Sample Product", 10000);
logger.info("doD");
model.addAttribute(product);
return "productDetail";
}
}
|
doD() 메소드의 선언에 특이하게도 Model이라는 클래스를 파라미터로 사용하는 것을 볼 수 있습니다.
ProductVO 클래스의 객체 생성 이후에 addAttribute()라는 메소드를 이용해서 ProductVO 객체를 보관시키는 것을 볼 수 있습니다.
AddAttribute()는 크게 두 가지의 형태로 사용합니다.
n addAttribute(“이름”, 객체): 객체에 특별한 이름을 부여해 뷰에서 이름값을 이용하여 객체 처리
n addAttribute(객체): 이름을 지정하지 않는 경우에는 자동으로 저장되는 객체의 클래스명 앞 글자를 소문자로 처리한 클래스명을 이름으로 간주
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" context="text/html; charset="UTF-8"> <title>Insert title here</title> </head> <body> <span>${productVO.name }</span> <span>${productVO.price }</span>
</body> </html> |
<span> 태그의 내용을 보면 productVO.name과 productVO.price를 이용하는데 이때 productVO라는 변수의 이름이 어떻게 만들어진 것인지를 알고 있어야 합니다.
5.2.3.4 리다이렉트를 해야하는 경우
가끔은 특정한 컨트롤러의 로직을 처리할 때 다른 경로를 호출해야 하는 경우가 있습니다. 이 경우에는 스프링 mvc의 특별한 문자열인 ‘redirect:’를 이용합니다.
리다이렉트를 하는 경우 RedirectAttributes라는 클래스를 파라미터로 같이 사용하게 되면 리다이렉트 시점에 원하는 데이터를 임시로 추가해서 넘기는 작업이 가능합니다.
package org.zerock.web;
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.mvc.support.RedirectAttributes;
@Controller public class SampleController4 {
private static final Logger logger = LoggerFactory.getLogger(SampleController4.class);
@RequestMapping("/doE") public String doE(RedirectAttributes rttr) { logger.info("doE called but redirect to /doF......");
rttr.addFlashAttribute("msg", "This is the Message!! with redirected"); return "redriect:/doF";
}
@RequestMapping("doF") public void doF(@ModelAttribute String msg) { logger.info("doF called......" + msg); } }
|
5.2.3.5 JSON 데이터를 생성하는 경우
이를 위해서는 pom.xml을 사용해서 Jackson-databind 라이브러리를 추가해야 합니다.
5.3 was 없이 컨트롤러를 테스트하기
Spring boot는 별도의 was 없이도 내장된 서버를 이용해서 프로그램을 실행할 수 있는 환경을 제공
Spring-test를 사용해서 실행할 때 가능하면 was의 servlet 스펙 버전을 일치시켜서 테스트하는 것이 좋습니다. 예를 들어 tomcat을 이용하면서 servlet 스펙 3.1을 이용한다면 테스트 환경에서도 맞춰주는 것이 좋습니다. 스프링 mvc를 테스트학 위해서는 pom.xml의 javax.servlet 라이브러리의 버전을 변경해야만 올바르게 실행할 수 있습니다.
컨트롤러의 테스트 코드 작성은 test 폴더를 이용해서 작성합니다. Was를 실행하지 않고 컨트롤러를 테스트 하려면 pom.xml의 servlet 버전을 높여줘야만 가능합니다.
<!-- Servlet before --> <!-- Servlet --> <!-- <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> <scope>provided</scope> </dependency> -->
<!-- Servlet after --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> </dependency>
|
package org.zerock.web;
import javax.inject.Inject;
import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.web.WebAppConfiguration; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext;
@RunWith(SpringJUnit4ClassRunner.class) @WebAppConfiguration @ContextConfiguration(locations = { "file:src/main/webapp/WEB-INF/spring/**/*.xml" })
public class SampleControllerTest {
private static final Logger logger = LoggerFactory.getLogger(SampleControllerTest.class);
@Inject private WebApplicationContext wac;
private MockMvc mockMvc;
@Before public void setup() { this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); logger.info("setup..........."); }
@Test public void testDoa() throws Exception { mockMvc.perform(MockMvcRequestBuilders.get("doA")); }
}
|
테스트 코드의 작성 시 스프링에서 제공하는 애노테이션을 사용할 필요가 있습니다.
테스트의 경로는 src/test/java 밑에 samplecontrollertest로 작성합니다.
테스트 클래스의 선언부에서는 @WebAppConfiguration 애노테이션을 사용하는데 이것이 기존의 스프링과 스프링 MVC를 테스트하는 데 있어서의 가장 큰 차이입니다.
MockMvc는 브라우저에서 요청과 응답을 의미하는 객체로 간주하면 됩니다. 매번 테스트를 진행할 때마다 가상의 요청과 응답을 처리하기 위해서 setup() 메서드에서는 @Before 애노테이션으로 처리되어 매번 테스트 메소드의 실행 전에 MockMvc 객체를 만들어내게 됩니다.
코드로 배우는 스프링 웹 프로젝트 보면서 따라해봄!!!!!!!
'JAVA > spring' 카테고리의 다른 글
Spring Connection(DataSource) (0) | 2019.06.11 |
---|---|
Spring+mybatis (0) | 2019.06.05 |
spring + MyBatis + MySQL - 1 (0) | 2019.06.03 |
spring DB connect (0) | 2019.05.28 |
spring Start (1) | 2019.05.07 |
댓글