Hướng dẫn tích hợp SSM (Spring + Spring MVC + MyBatis) từ đầu

Dù Spring Boot đã giúp việc cấu hình SSM trở nên nhanh chóng, nhưng hiểu cách tích hợp thủ công vẫn rất quan trọng. Nó giúp bạn nắm vững bản chất các cấu hình và dễ dàng bảo trì các dự án cũ không dùng Spring Boot. Bài viết này sẽ hướng dẫn chi tiết từng bước tích hợp ba framework này, kèm giải thích ý nghĩa từng cấu hình.

1. Tạo và cấu hình dự án

1.1. Tạo project với Maven

Sử dụng IntelliJ IDEA, tạo một Maven project với web archetype. Đặt GroupId và ArtifactId phù hợp.

1.2. Nâng cấp web.xml lên Servlet 3.1

Sau khi tạo, web.xml mặc định là phiên bản 2.3. Vào Project Structure → Modules → Web, xóa cấu hình web cũ, thêm mới và chọn phiên bản 3.1.

1.3. Thiết lập cấu trúc thư mục

Tạo các thư mục sau và gán nhãn tương ứng:

  • src/main/javaSources Root (mã nguồn chính)
  • src/main/resourcesResources Root (tài nguyên, cấu hình)
  • src/testTest Sources Root (mã kiểm thử)

Trong src/main/java, tạo các package: controller, service, mapper, entity.

2. Thêm dependencies vào pom.xml

Khai báo các thư viện cần thiết. Lưu ý quản lý phiên bản tập trung trong thẻ <properties>.

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    <mysql.version>5.1.48</mysql.version>
    <spring.version>5.2.0.RELEASE</spring.version>
    <jackson.version>2.10.0</jackson.version>
</properties>

<dependencies>
    <!-- JUnit -->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>

    <!-- Logback -->
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>1.2.3</version>
    </dependency>

    <!-- Lombok (tùy chọn) -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.10</version>
        <scope>provided</scope>
    </dependency>

    <!-- MySQL Driver -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>${mysql.version}</version>
    </dependency>

    <!-- Druid DataSource -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.1.12</version>
    </dependency>

    <!-- MyBatis -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.4.6</version>
    </dependency>

    <!-- Java EE API -->
    <dependency>
        <groupId>javax</groupId>
        <artifactId>javaee-api</artifactId>
        <version>8.0</version>
        <scope>provided</scope>
    </dependency>

    <!-- JSTL -->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>jstl</artifactId>
        <version>1.2</version>
    </dependency>

    <!-- Jackson -->
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-core</artifactId>
        <version>${jackson.version}</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>${jackson.version}</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-annotations</artifactId>
        <version>${jackson.version}</version>
    </dependency>

    <!-- Spring Context -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>${spring.version}</version>
    </dependency>

    <!-- Spring JDBC -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>${spring.version}</version>
    </dependency>

    <!-- Spring Web MVC -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>${spring.version}</version>
    </dependency>

    <!-- AspectJ -->
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.9.4</version>
    </dependency>

    <!-- Spring Test -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>${spring.version}</version>
        <scope>test</scope>
    </dependency>

    <!-- MyBatis-Spring -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>1.3.2</version>
    </dependency>
</dependencies>

3. Tích hợp Spring với MyBatis

3.1. Chuẩn bị Database và Entity

Tạo database ssm_demo và bảng user:

CREATE TABLE `user` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'Primary key',
  `name` varchar(255) COLLATE utf8mb4_bin NOT NULL COMMENT 'Username',
  `password` varchar(255) COLLATE utf8mb4_bin NOT NULL COMMENT 'Password',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;

INSERT INTO `user` VALUES (1, 'admin', '123456');
INSERT INTO `user` VALUES (2, 'rudecrab', '654321');

Entity class User.java trong package entity:

@Data // Lombok: tự động sinh getter, setter, toString
public class User implements Serializable {
    private Long id;
    private String name;
    private String password;
}

3.2. Cấu hình database.properties

Trong src/main/resources, tạo file database.properties:

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/ssm_demo?characterEncoding=utf-8&useSSL=false&autoReconnect=true&serverTimezone=UTC
jdbc.username=root
jdbc.password=root

3.3. Cấu hình logback.xml

Tạo file logback.xml trong resources:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <property name="LOG_ERROR_HOME" value="error"/>
    <property name="LOG_INFO_HOME" value="info"/>

    <appender name="CONSOLE_LOG" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>%red(%d{yyyy-MM-dd HH:mm:ss.SSS}) %yellow([%-5p]) %highlight([%t]) %boldMagenta([%C]) %green([%L]) %m%n</pattern>
        </encoder>
    </appender>

    <appender name="INFO_LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>DENY</onMatch>
            <onMismatch>ACCEPT</onMismatch>
        </filter>
        <encoder>
            <pattern>[%d{yyyy-MM-dd' 'HH:mm:ss.SSS}] [%C] [%t] [%L] [%-5p] %m%n</pattern>
        </encoder>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_INFO_HOME}//%d.log</fileNamePattern>
            <maxHistory>30</maxHistory>
        </rollingPolicy>
    </appender>

    <appender name="ERROR_LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>ERROR</level>
        </filter>
        <encoder>
            <pattern>[%d{yyyy-MM-dd' 'HH:mm:ss.SSS}] [%C] [%t] [%L] [%-5p] %m%n</pattern>
        </encoder>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_ERROR_HOME}//%d.log</fileNamePattern>
            <maxHistory>30</maxHistory>
        </rollingPolicy>
    </appender>

    <logger name="com.rudecrab.ssm.mapper" level="DEBUG"/>

    <root level="info">
        <appender-ref ref="CONSOLE_LOG"/>
        <appender-ref ref="INFO_LOG"/>
        <appender-ref ref="ERROR_LOG"/>
    </root>
</configuration>

3.4. Cấu hình mybatis-config.xml

File này chứa các cài đặt toàn cục cho MyBatis:

<?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>
    <settings>
        <setting name="logImpl" value="SLF4J"/>
        <setting name="useGeneratedKeys" value="true"/>
        <setting name="mapUnderscoreToCamelCase" value="true"/>
        <setting name="cacheEnabled" value="true"/>
    </settings>
</configuration>

3.5. Cấu hình spring-mybatis.xml

File tích hợp chính giữa Spring và 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:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       https://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/tx
       http://www.springframework.org/schema/tx/spring-tx.xsd">

    <context:property-placeholder location="classpath:database.properties" file-encoding="UTF-8"/>

    <context:component-scan base-package="com.rudecrab.ssm" use-default-filters="true">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
        <property name="initialSize" value="10"/>
        <property name="maxActive" value="100"/>
    </bean>

    <bean class="org.mybatis.spring.SqlSessionFactoryBean" id="sqlSessionFactory">
        <property name="dataSource" ref="dataSource"/>
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
        <property name="mapperLocations" value="classpath:mapper/*.xml"/>
    </bean>

    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
        <property name="basePackage" value="com.rudecrab.ssm.mapper"/>
    </bean>

    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <tx:annotation-driven/>
</beans>

3.6. Kiểm thử tích hợp Spring + MyBatis

Tạo các file cần thiết:

  • Mapper interface (UserMapper.java):
@Repository
public interface UserMapper {
    List<User> selectAll();
}
  • Mapper XML (UserMapper.xml trong resources/mapper/):
<?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="com.rudecrab.ssm.mapper.UserMapper">
    <cache/>
    <select id="selectAll" resultType="com.rudecrab.ssm.entity.User">
        select * from user
    </select>
</mapper>
  • Service interface (UserService.java):
public interface UserService {
    List<User> getAll();
}
  • Service implementation (UserServiceImpl.java):
@Service
@Transactional(rollbackFor = Exception.class)
public class UserServiceImpl implements UserService {
    @Autowired
    private UserMapper userMapper;

    @Override
    public List<User> getAll() {
        return userMapper.selectAll();
    }
}
  • Test class (UserServiceTest.java trong src/test):
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:spring-mybatis.xml"})
public class UserServiceTest {
    @Autowired
    private UserService userService;

    @Test
    public void getAll() {
        System.out.println(userService.getAll());
    }
}

Chạy test, nếu console in ra danh sách user là thành công.

4. Tích hợp Spring MVC

4.1. Cấu hình spring-mvc.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: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
       https://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/mvc
       https://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/views/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

    <mvc:default-servlet-handler/>

    <context:component-scan base-package="com.rudecrab.ssm.controller" use-default-filters="false">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

    <mvc:annotation-driven/>
</beans>

4.2. Cấu hình web.xml

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

    <!-- ContextLoaderListener cho Spring IoC -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring-mybatis.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <!-- DispatcherServlet cho Spring MVC -->
    <servlet>
        <servlet-name>SpringMVC</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring-mvc.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>SpringMVC</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <!-- CharacterEncodingFilter -->
    <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>

4.3. Tạo Controller và View

  • JSP (/WEB-INF/views/index.jsp):
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Home</title>
</head>
<body>
<c:forEach var="user" items="${userList}">
    <ul>
        <li>${user}</li>
    </ul>
</c:forEach>
</body>
</html>
  • Controller (UserController.java):
@Controller
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserService userService;

    @GetMapping("/getList")
    public String getList(Model model) {
        model.addAttribute("userList", userService.getAll());
        return "index";
    }

    @GetMapping("/getJson")
    @ResponseBody
    public List<User> getJson() {
        return userService.getAll();
    }
}

4.4. Chạy ứng dụng

Deploy lên Tomcat, truy cập http://localhost:8080/<context-path>/user/getList để thấy dữ liệu dạng HTML, hoặc /user/getJson để nhận JSON. Như vậy SSM đã được tích hợp hoàn chỉnh.

Thẻ: Spring Spring MVC mybatis SSM Java

Đăng vào ngày 14 tháng 6 lúc 02:01