티스토리 뷰

728x90

-1. 예제를 위해 Customer 테이블을 생성한다.

  -1-0 사용자 springstudent를 만들고 암호도 springstudent를 생성한다.

  -1-1 web_customer_tracker라는 데이터베이스를 생성한다.

  -1-2 Customer 테이블을 생성한다.

 

0. Web과 Hibernate를 위한 Dependency를 추가한다. (Bold 부분은 WebMVC에 hibernate를 붙이기 위해 추가로 필요)

  0-1 스프링 기본적인 동작을 위한 spring core, spring context

  0-2 스프링 Web을 위한 spring WebMvc

  0-3 스프링 transaction처리를 위한 spring tx

  0-4 스프링 ORM사용을 위한 spring orm

  0-5 하이버네이트를 위한 hibernate core

  0-6 MySql을 위한 mysql connector java

  0-7 DataSource를 위한 mchange c3p0

  0-8 jsp, jstl을 위한 jsp-api, jstl, servlet-api

  0-9 선택적으로 편리한 개발을 위한 lombok

<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-core</artifactId>
	<version>5.2.6.RELEASE</version>
</dependency>
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-context</artifactId>
	<version>5.2.6.RELEASE</version>
</dependency>
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-webmvc</artifactId>
	<version>5.2.6.RELEASE</version>
</dependency>
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-tx</artifactId>
	<version>5.2.6.RELEASE</version>
</dependency>
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-orm</artifactId>
	<version>5.2.6.RELEASE</version>
</dependency>
<dependency>
	<groupId>com.mchange</groupId>
	<artifactId>c3p0</artifactId>
	<version>0.9.5.5</version>
</dependency>
<dependency>
	<groupId>junit</groupId>
	<artifactId>junit</artifactId>
	<version>4.11</version>
	<scope>test</scope>
</dependency>
<dependency>
	<groupId>org.hibernate</groupId>
	<artifactId>hibernate-core</artifactId>
	<version>5.4.15.Final</version>
</dependency>
<dependency>
	<groupId>mysql</groupId>
	<artifactId>mysql-connector-java</artifactId>
	<version>8.0.20</version>
</dependency>

<dependency>
	<groupId>org.projectlombok</groupId>
	<artifactId>lombok</artifactId>
	<version>1.18.12</version>
	<scope>provided</scope>
</dependency>

<dependency>
	<groupId>javax.servlet</groupId>
	<artifactId>jstl</artifactId>
	<version>1.2</version>
</dependency>
<dependency>
	<groupId>javax.servlet.jsp</groupId>
	<artifactId>javax.servlet.jsp-api</artifactId>
	<version>2.3.3</version>
	<scope>provided</scope>
</dependency>
<dependency>
	<groupId>javax.servlet</groupId>
	<artifactId>javax.servlet-api</artifactId>
	<version>4.0.1</version>
	<scope>provided</scope>
</dependency>

1. WebMVC와 Hibernate를 같이 사용하면 hibernate.cfg.xml 파일 대신 스프링 컨테이너 설정을 사용할 수 있다.

  1-0 컨테이너 설정에서 DataSource, SessionFactory, TransactionManager 구현 객체를 만들어 사용할 수 있다.

  1-1 DataSource는 데이터베이스와 연결을 위한 JDBC 설정으로 Connection Pool 설정 등을 포함하고 있다.

  1-2 이렇게 스프링 컨테이너의 bean으로 생성하면 필요한 경우에 @Autowired로 언제 든 사용가능하다.

  1-3 설정파일은 xml로 되어 있으므로 그냥 복사해서 사용하는 게 좋다. 다시 말하지만 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" 
  xmlns:context="http://www.springframework.org/schema/context"
  xmlns:tx="http://www.springframework.org/schema/tx"
  xmlns:mvc="http://www.springframework.org/schema/mvc"
  xsi:schemaLocation="
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/mvc
    http://www.springframework.org/schema/mvc/spring-mvc.xsd
    http://www.springframework.org/schema/tx 
    http://www.springframework.org/schema/tx/spring-tx.xsd">

  <!-- 외부 리소스를 사용하기 위한 설정 --> 
  <mvc:resources location="/resources/" mapping="/resources/**"></mvc:resources>

  <!-- Step 3: Add support for component scanning -->
  <context:component-scan base-package="pe.pilseong.hibernateweb" />

  <!-- Step 4: Add support for conversion, formatting and validation support -->
  <mvc:annotation-driven/>
  
  <!-- Step 5: Define Spring MVC view resolver -->
  <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/view/" />
    <property name="suffix" value=".jsp" />
  </bean>
  
  <bean id="myDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
    <property name="driverClass" value="com.mysql.cj.jdbc.Driver"></property>
    <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/web_customer_tracker?useSSL=true&amp;serverTimezone=Asia/Seoul"></property>
    <property name="user" value="springstudent"></property>
    <property name="password" value="springstudent"></property>
    
    <property name="minPoolSize" value="5"></property>
    <property name="maxPoolSize" value="20"></property>
    <property name="maxIdleTime" value="30000"></property>
  </bean>
  
  <bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
    <property name="dataSource" ref="myDataSource"></property>
    <property name="packagesToScan" value="pe.pilseong.hibernateweb.entity"></property>
    <property name="hibernateProperties">
      <props>
        <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
        <prop key="hibernate.show_sql">true</prop>
      </props>
    </property>
  </bean>
  
  <bean id="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory"></property>
  </bean>
  
  <tx:annotation-driven transaction-manager="transactionManager" />
</beans>

  1-4 위 스프링 컨테이너 설정을 호출하는 전형적인 web.xml파일이다.

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
  id="WebApp_ID" version="4.0">

  <display-name>spring-mvc-demo</display-name>

  <absolute-ordering />

  <!-- Spring MVC Configs -->

  <!-- Step 1: Configure Spring MVC Dispatcher Servlet -->
  <servlet>
    <servlet-name>dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>/WEB-INF/spring-hibernate-servlet.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>

  <!-- Step 2: Set up URL mapping for Spring MVC Dispatcher Servlet -->
  <servlet-mapping>
    <servlet-name>dispatcher</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
  
</web-app>

2. 테이블에 매핑되는 Customer Entity class를 만든다.

  2-1 관계하는 Entity가 없는 단순한 클래스이다.

@Entity
@Table(name = "customer")
@Data
@NoArgsConstructor
public class Customer {
  
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;
  
  @Column(name = "first_name")
  private String firstName;
  
  @Column(name = "last_name")
  private String lastName;
  
  @Column
  private String email;
}

3. 사용자를 읽어서 jsp파일에서 보여주는 Controller를 생성한다.

package pe.pilseong.hibernateweb.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import pe.pilseong.hibernateweb.dao.CustomerDAO;

@Controller
@RequestMapping("/customer")
public class CustomerController {
  
  @Autowired
  private CustomerDAO customerDAO;
  
  @GetMapping("/list")
  public String listCustomers(Model model) {
    
    model.addAttribute("customers", this.customerDAO.getCustomers());
    
    return "list-customers";
  }
}

4. hibernate로 연결된 데이터베이스에서 데이터를 가져와 돌려 주는 Data Access Object

  4-1 getCustomers 메소드에 @Transactional이 설정되어 있으므로 beginTransaction을 별도로 처리할 필요없다.

  4-2 마찬가지로 session.close() 같은 뒷처리도 할 필요가 없다.

// 인터페이스
package pe.pilseong.hibernateweb.dao;

import java.util.List;

import pe.pilseong.hibernateweb.entity.Customer;

public interface CustomerDAO {
  List<Customer> getCustomers();
}


// 구현 클래스
package pe.pilseong.hibernateweb.dao;

import java.util.List;

import javax.transaction.Transactional;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import pe.pilseong.hibernateweb.entity.Customer;

@Repository
public class CustomerDAOImpl implements CustomerDAO {

  @Autowired
  private SessionFactory sessionFactory;

  @Override
  @Transactional
  public List<Customer> getCustomers() {
    Session session = this.sessionFactory.getCurrentSession();

    return session.createQuery("from Customer", Customer.class).getResultList();
  }
}

5. 테스트용 jsp파일 - resources 폴더 아래에 있는 외부 리소스를 사용하고 있다.

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
  pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet"
  href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"
  integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh"
  crossorigin="anonymous">
<link rel="stylesheet" href="${pageContext.request.contextPath}/resources/css/sytle.css"/>
<title>List of Customers</title>
</head>
<body>
  <div class="container">
    <h2 class="mb-5 mt-5">CRM - Customer Relationship Manager</h2>
    <table class="table">
      <thead>
        <tr>
          <th>First Name</th>
          <th>Last Name</th>
          <th>Email</th>
        </tr>
      </thead>
      <tbody>
        <c:forEach var="customer" items="${ customers }">
          <tr>
            <td>${ customer.firstName }</td>
            <td>${ customer.lastName }</td>
            <td>${ customer.email }</td>
          </tr>
        </c:forEach>
      </tbody>
    </table>
  </div>
  <script src="https://code.jquery.com/jquery-3.4.1.slim.min.js"
    integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n"
    crossorigin="anonymous"></script>
  <script
    src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js"
    integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo"
    crossorigin="anonymous"></script>
  <script
    src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js"
    integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6"
    crossorigin="anonymous"></script>
</body>
</html>


// 결과
List of Customers
[Customer(id=1, firstName=Pilseong, lastName=Heo, email=heops79@gmail.com), 
Customer(id=2, firstName=Suel, lastName=Heo, email=suel@gmail.com), 
Customer(id=3, firstName=Noel, lastName=Heo, email=noel@gmail.com),
Customer(id=4, firstName=Rael, lastName=Kim, email=rael@gmail.com), 
Customer(id=5, firstName=Song, lastName=Choi, email=song@gmail.com)]

6. 선택적으로 welcome jsp파일을 생성할 수 있다.

  6-1 webapp 아래 index.jsp파일을 생성하면 root로 접근 시 이 파일을 실행하게 된다.

  6-2 아래의 소스는 간단히 위의 리스트 페이지로 넘어가게 한다.

 

<% response.sendRedirect("customer/list"); %>
728x90
댓글