Spring MVC와 MyBatis를 이용한 기본 CRUD 구현

사용자 테이블 생성

간단한 사용자 정보를 저장할 데이터베이스 테이블을 생성합니다.

CREATE TABLE `users` (
  `id` int(20) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) NOT NULL,
  `age` int(20) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8;

-- 샘플 데이터 삽입
INSERT INTO `users` VALUES ('1', '홍길동', '25');
INSERT INTO `users` VALUES ('2', '김철수', '30');
INSERT INTO `users` VALUES ('3', '이영희', '22');

웹 프로젝트 설정

Spring MVC 디스패처 서블릿 구성

ssi-servlet.xml 파일에 Spring MVC 관련 설정을 정의합니다.

<?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:mvc="http://www.springframework.org/schema/mvc"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
                           http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
                           http://www.springframework.org/schema/context 
                           http://www.springframework.org/schema/context/spring-context-4.1.xsd
                           http://www.springframework.org/schema/aop 
                           http://www.springframework.org/schema/aop/spring-aop-4.1.xsd
                           http://www.springframework.org/schema/mvc 
                           http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd">

    <context:component-scan base-package="com.example.controller"/>
    <mvc:annotation-driven/>
    <mvc:default-servlet-handler />
    <aop:aspectj-autoproxy proxy-target-class="true" /> 
    
    <!-- 뷰 리졸버 설정 -->
    <bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
        <property name="mediaTypes">
            <map>
                <entry key="atom" value="application/atom+xml"/>
                <entry key="html" value="text/html"/>
                <entry key="json" value="application/json"/>
            </map>
        </property>
        <property name="viewResolvers">
            <list>
                <bean class="org.springframework.web.servlet.view.BeanNameViewResolver"/>
                <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
                    <property name="prefix" value="/views/"/>
                    <property name="suffix" value=".jsp"/>
                </bean>
            </list>
        </property>
    </bean>
</beans>

웹 애플리케이션 구성

web.xml 파일에 필수적인 웹 컴포넌트들을 등록합니다.

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
         xmlns="http://java.sun.com/xml/ns/javaee" 
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
                             http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" 
         version="2.5">
         
    <display-name>Spring MyBatis CRUD App</display-name>
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>

    <servlet>
        <servlet-name>ssi</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>ssi</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <filter>
        <filter-name>CharacterEncodingFilter</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>
    </filter>

    <filter-mapping>
        <filter-name>CharacterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
    </context-param>

    <session-config>
        <session-timeout>30</session-timeout>
    </session-config>
</web-app>

MyBatis 설정

MyBatis 관련 타입 별칭을 conf.xml에 정의합니다.

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <typeAliases>
        <typeAlias type="com.example.model.UserInfo" alias="User"/>
    </typeAliases>
</configuration>

Spring 컨텍스트 구성

applicationContext.xml 파일에 데이터 소스 및 MyBatis 통합 설정을 추가합니다.

<?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:aop="http://www.springframework.org/schema/aop" 
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
                           http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
                           http://www.springframework.org/schema/context 
                           http://www.springframework.org/schema/context/spring-context-4.1.xsd
                           http://www.springframework.org/schema/aop 
                           http://www.springframework.org/schema/aop/spring-aop-4.1.xsd
                           http://www.springframework.org/schema/tx 
                           http://www.springframework.org/schema/tx/spring-tx-4.1.xsd">

    <!-- 데이터베이스 연결 풀 설정 -->
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/crud_app"/>
        <property name="username" value="developer"/>
        <property name="password" value="dev_password"/>
        <property name="maxActive" value="20"/>
        <property name="maxIdle" value="10"/>
        <property name="initialSize" value="5"/>
    </bean>

    <!-- MyBatis 세션 팩토리 설정 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="configLocation" value="classpath:conf.xml"/>
        <property name="dataSource" ref="dataSource"/>
        <property name="mapperLocations" value="classpath:com/example/mapper/*.xml"/>
    </bean>

    <!-- 매퍼 스캐너 설정 -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.example.repository"/>
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
    </bean>

    <!-- 트랜잭션 관리자 설정 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <tx:annotation-driven transaction-manager="transactionManager"/>
    <context:annotation-config/>
    <context:component-scan base-package="com.example.service"/>
</beans>

도메인 모델 및 데이터 접근 계층

엔티티 클래스

User.java 파일에 사용자 정보를 표현하는 POJO 클래스를 정의합니다.

package com.example.model;

public class UserInfo {
    private int userId;
    private String userName;
    private int userAge;

    public UserInfo() {}

    public UserInfo(int userId, String userName, int userAge) {
        this.userId = userId;
        this.userName = userName;
        this.userAge = userAge;
    }

    // getter 및 setter 메서드
    public int getUserId() { return userId; }
    public void setUserId(int userId) { this.userId = userId; }
    
    public String getUserName() { return userName; }
    public void setUserName(String userName) { this.userName = userName; }
    
    public int getUserAge() { return userAge; }
    public void setUserAge(int userAge) { this.userAge = userAge; }

    @Override
    public String toString() {
        return "UserInfo{userId=" + userId + ", userName='" + userName + "', userAge=" + userAge + "}";
    }
}

데이터 접근 인터페이스

UserRepository.java 파일에 데이터베이스 작업을 위한 인터페이스를 선언합니다.

package com.example.repository;

import java.util.List;
import com.example.model.UserInfo;

public interface UserRepository {
    void save(UserInfo user);
    void modify(UserInfo user);
    void remove(int id);
    UserInfo findById(int id);
    List<UserInfo> findAll();
}

매퍼 XML 설정

UserRepository.xml 파일에 SQL 쿼리를 매핑합니다.

<?xml version="1.0" encoding="UTF-8" ?>
<mapper namespace="com.example.repository.UserRepository">
    
    <select id="findById" parameterType="int" resultType="User">
        SELECT id AS userId, name AS userName, age AS userAge 
        FROM users WHERE id = #{userId}
    </select>

    <insert id="save" parameterType="User">
        INSERT INTO users(name, age) VALUES(#{userName}, #{userAge})
    </insert>

    <delete id="remove" parameterType="int">
        DELETE FROM users WHERE id = #{userId}
    </delete>

    <update id="modify" parameterType="User">
        UPDATE users SET name = #{userName}, age = #{userAge} WHERE id = #{userId}
    </update>

    <select id="findAll" resultType="User">
        SELECT id AS userId, name AS userName, age AS userAge FROM users
    </select>
</mapper>

컨트롤러 구현

UserController.java 파일에 요청 처리 로직을 작성합니다.

package com.example.controller;

import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import com.example.model.UserInfo;
import com.example.repository.UserRepository;

@Controller
@RequestMapping("/api/users")
public class UserController {

    @Autowired
    private UserRepository userRepository;

    @GetMapping
    public String listUsers(HttpServletRequest request) {
        List<UserInfo> userList = userRepository.findAll();
        request.setAttribute("users", userList);
        return "userList";
    }

    @PostMapping
    public String createUser(UserInfo user) {
        userRepository.save(user);
        return "redirect:/api/users";
    }

    @DeleteMapping("/{id}")
    public String deleteUser(@PathVariable int id) {
        userRepository.remove(id);
        return "redirect:/api/users";
    }

    @GetMapping("/{id}")
    public String getUser(@PathVariable int id, HttpServletRequest request) {
        UserInfo user = userRepository.findById(id);
        request.setAttribute("userInfo", user);
        return "userEdit";
    }

    @PutMapping("/{id}")
    public String updateUser(@PathVariable int id, UserInfo updatedUser) {
        UserInfo existingUser = userRepository.findById(id);
        existingUser.setUserName(updatedUser.getUserName());
        existingUser.setUserAge(updatedUser.getUserAge());
        userRepository.modify(existingUser);
        return "redirect:/api/users";
    }
}

뷰 템플릿

사용자 등록 폼

index.jsp 파일에 새로운 사용자를 추가하는 폼을 구성합니다.

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>사용자 등록</title>
</head>
<body>
    <h2>새 사용자 추가</h2>
    <form action="api/users" method="post">
        이름: <input type="text" name="userName"><br>
        나이: <input type="text" name="userAge"><br>
        <input type="submit" value="등록">
    </form>
</body>
</html>

사용자 수정 페이지

userEdit.jsp 파일에 기존 사용자 정보를 수정하는 폼을 만듭니다.

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>사용자 정보 수정</title>
</head>
<body>
    <h2>사용자 정보 수정</h2>
    <form action="api/users/${userInfo.userId}" method="post">
        <input type="hidden" name="_method" value="put">
        이름: <input type="text" name="userName" value="${userInfo.userName}"><br>
        나이: <input type="text" name="userAge" value="${userInfo.userAge}"><br>
        <input type="submit" value="수정">
    </form>
</body>
</html>

태그: spring-mvc MyBatis CRUD JSP Servlet

10월 9일 21:29에 게시됨