korean english
Last Modified 5.3.2025

Simple Spring MyBatis Example

sqlplus scott/tiger
create table music (
no number,
content varchar2(4000),
constraint PK_MTV PRIMARY KEY(no)
);

create sequence SEQ_MUSIC
increment by 1
start with 1;
mybatismusic
├── pom.xml
└── src
    └── main
        ├── java
        │   └── net
        │       └── java_school
        │           ├── mybatis
        │           │   └── MusicVideoMapper.java
        │           └── mybatismusic
        │               ├── HomeController.java
        │               ├── MusicVideo.java
        │               ├── MusicVideoService.java
        │               └── MusicVideoServiceImpl.java
        ├── resources
        │   ├── commons-logging.properties
        │   ├── log4j2.xml
        │   └── net
        │       └── java_school
        │           └── mybatis
        │               ├── Configuration.xml
        │               └── MusicVideoMapper.xml
        └── webapp
            ├── WEB-INF
            │   ├── applicationContext.xml
            │   ├── mybatismusic-servlet.xml
            │   ├── views
            │   │   └── index.jsp
            │   └── web.xml
            └── resources
                └── js
                    └── jquery.js
<?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 
    http://maven.apache.org/xsd/maven-4.0.0.xsd">
    
<modelVersion>4.0.0</modelVersion>
<groupId>net.java_school</groupId>
<artifactId>mybatismusic</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>mybatismusic Maven Webapp</name>
<url>http://localhost:8080</url>

<properties>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  <maven.compiler.source>21</maven.compiler.source>
  <maven.compiler.target>21</maven.compiler.target>
  <spring.version>6.2.6</spring.version>
</properties>

<dependencies>
  <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.11</version>
    <scope>test</scope>
  </dependency>
  <!-- https://mvnrepository.com/artifact/jakarta.servlet/jakarta.servlet-api -->
  <dependency>
    <groupId>jakarta.servlet</groupId>
    <artifactId>jakarta.servlet-api</artifactId>
    <version>6.1.0</version>
    <scope>provided</scope>
  </dependency>       
  <!-- https://mvnrepository.com/artifact/jakarta.servlet.jsp.jstl/jakarta.servlet.jsp.jstl-api -->
  <dependency>
    <groupId>jakarta.servlet.jsp.jstl</groupId>
    <artifactId>jakarta.servlet.jsp.jstl-api</artifactId>
    <version>3.0.2</version>
  </dependency>
  <!-- https://mvnrepository.com/artifact/org.glassfish.web/jakarta.servlet.jsp.jstl -->
  <dependency>
    <groupId>org.glassfish.web</groupId>
    <artifactId>jakarta.servlet.jsp.jstl</artifactId>
    <version>3.0.1</version>
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>${spring.version}</version>
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>${spring.version}</version>
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>${spring.version}</version>
  </dependency>
  <!-- https://mvnrepository.com/artifact/com.oracle.database.jdbc/ojdbc11 -->
  <dependency>
    <groupId>com.oracle.database.jdbc</groupId>
    <artifactId>ojdbc11</artifactId>
    <version>23.7.0.25.01</version>
  </dependency>
  <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
  <dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.19</version>
  </dependency>
  <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
  <dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>3.0.4</version>
  </dependency>
  <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-dbcp2 -->
  <dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-dbcp2</artifactId>
    <version>2.13.0</version>
  </dependency>
  <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-api -->
  <dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-api</artifactId>
    <version>2.24.3</version>
  </dependency>
  <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
  <dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.24.3</version>
  </dependency>
  <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-jcl -->
  <dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-jcl</artifactId>
    <version>2.24.3</version>
  </dependency>
</dependencies>

<build>
  <finalName>mybatismusic</finalName>
  <pluginManagement>
    <plugins>
      <plugin>
        <artifactId>maven-clean-plugin</artifactId>
        <version>3.1.0</version>
        <configuration>
          <filesets>
             <fileset>
                <directory>src/main/webapp/WEB-INF/classes</directory>
             </fileset>
             <fileset>
                <directory>src/main/webapp/WEB-INF/lib</directory>
             </fileset>
          </filesets>
        </configuration>
      </plugin>
      <plugin>
        <artifactId>maven-resources-plugin</artifactId>
        <version>3.0.2</version>
      </plugin>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.8.0</version>
      </plugin>
      <plugin>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>2.22.1</version>
      </plugin>
      <plugin>
        <artifactId>maven-war-plugin</artifactId>
        <version>3.2.2</version>
      </plugin>
      <plugin>
        <artifactId>maven-install-plugin</artifactId>
        <version>2.5.2</version>
      </plugin>
      <plugin>
        <artifactId>maven-deploy-plugin</artifactId>
        <version>2.8.2</version>
      </plugin>
      <!-- https://mvnrepository.com/artifact/org.eclipse.jetty/jetty-maven-plugin -->
      <plugin>
        <groupId>org.eclipse.jetty</groupId>
        <artifactId>jetty-maven-plugin</artifactId>
        <version>11.0.25</version>
      </plugin>
    </plugins>
  </pluginManagement>
</build>

</project>

src/main/resources

commons-logging.properties
org.apache.commons.logging.Log = org.apache.commons.logging.impl.Log4JLogger
log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration>
<Configuration>
    <Appenders>
        <File name="MyBatisMusic" fileName="/var/log/tomcat9/MyBatisMusic.log" append="false">
            <PatternLayout pattern="%t %-5p %c{2} - %m%n" />
        </File>
        <Console name="STDOUT" target="SYSTEM_OUT">
            <PatternLayout pattern="%d %-5p [%t] %C{2} (%F:%L) - %m%n" />
        </Console>
    </Appenders>
    <Loggers>
        <Logger name="net.java_school" level="DEBUG">
            <AppenderRef ref="MyBatisMusic" />
        </Logger>
        <Root level="INFO">
            <AppenderRef ref="STDOUT" />
        </Root>
    </Loggers>
</Configuration>

src/main/resources/net/java_school/mybatis

Configuration.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>
    <settings>
        <setting name="logImpl" value="LOG4J2"/>
    </settings>

    <typeAliases>
        <typeAlias type="net.java_school.mybatismusic.MusicVideo" alias="MusicVideo" />
    </typeAliases>

</configuration>
MusicVideoMapper.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="net.java_school.mybatis.MusicVideoMapper">

    <select id="selectCountOfVideos" resultType="int">
        SELECT count(*) FROM music 
    </select>

    <select id="selectVideos" parameterType="hashmap" resultType="MusicVideo">
        SELECT content 
        FROM (
            SELECT rownum R,A.* 
            FROM (
                SELECT 
                    content
                FROM 
                    music
                ORDER BY no DESC
                 ) A
             )
        WHERE R BETWEEN #{start} AND #{end}
    </select>    

    <insert id="insert">
        insert into music values (seq_music.nextval, #{content})
    </insert>
    
</mapper>

src/main/java/net/java_school/mybatis

MusicVideoMapper.java
package net.java_school.mybatis;

import java.util.HashMap;
import java.util.List;
import net.java_school.mybatismusic.MusicVideo;
import org.apache.ibatis.annotations.Param;

public interface MusicVideoMapper {
    public int selectCountOfVideos();

    public List<MusicVideo> selectVideos(HashMap<String, String> hashmap);

    public void insert(@Param("content") String content);
}

src/main/java/net/java_school/mybatismusic

MusicVideo.java
package net.java_school.mybatismusic;

public class MusicVideo {
    private int no;
    private String content;

    public MusicVideo() {}

    public MusicVideo(int no, String content) {
        this.no = no;
        this.content = content;
    }

    public int getNo() {
           return no;
    }

    public void setNo(int no) {
        this.no = no;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }
}    
MusicVideoService.java
package net.java_school.mybatismusic;

import java.util.List;

public interface MusicVideoService {
    
    public int getTotalRecords();

    public List<MusicVideo> getVideos(Integer startRecord, Integer endRecord);

    public void add(String content);
}
MusicVideoServiceImpl.java
package net.java_school.mybatismusic;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.HashMap;
import net.java_school.mybatis.MusicVideoMapper;

@Service
public class MusicVideoServiceImpl implements MusicVideoService {

    @Autowired
    private MusicVideoMapper musicVideoMapper;

    @Override
    public int getTotalRecords() {
        return musicVideoMapper.selectCountOfVideos();
    }

    @Override
    public List<MusicVideo> getVideos(Integer startRecord, Integer endRecord) {
        HashMap<String, String> hashmap = new HashMap<String, String>();
        hashmap.put("start", startRecord.toString());
        hashmap.put("end", endRecord.toString());

        return musicVideoMapper.selectVideos(hashmap);
    }

    @Override
    public void add(String content) {
        musicVideoMapper.insert(content);
    }
}
HomeController.java
package net.java_school.mybatismusic;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.List;
import java.util.Map;
import java.util.HashMap;

@Controller
public class HomeController {
    @Autowired
    private MusicVideoService musicVideoService;

    private Map<String, Integer> getNumbersForPaging(int totalRecord, 
            int page, int numPerPage, int pagePerBlock) {

        Map<String, Integer> map = new HashMap<String, Integer>();

        int totalPage = totalRecord / numPerPage;
        if (totalRecord % numPerPage != 0) totalPage++;

        int totalBlock = totalPage / pagePerBlock;
        if (totalPage % pagePerBlock != 0) totalBlock++;

        int block = page / pagePerBlock;
        if (page % pagePerBlock != 0) block++;

        int firstPage = (block - 1) * pagePerBlock + 1;
        int lastPage = block * pagePerBlock;

        int prevPage = 0;
        if (block > 1) prevPage = firstPage - 1;

        int nextPage = 0;
        if (block < totalBlock) nextPage = lastPage + 1;
        if (block >= totalBlock) lastPage = totalPage;
        
        int listItemNo = totalRecord - (page - 1) * numPerPage;
        int startRecord = (page - 1) * numPerPage + 1;
        int endRecord = page * numPerPage;

        map.put("totalPage", totalPage);
        map.put("firstPage", firstPage);
        map.put("lastPage", lastPage);
        map.put("prevPage", prevPage);
        map.put("nextPage", nextPage);
        map.put("startRecord", startRecord);
        map.put("endRecord", endRecord);

        return map;
    }

    @GetMapping("/")
    public String index(@RequestParam(name="page", required=false) Integer page, Model model) {
        if (page == null) return "redirect:/?page=1";

        int numPerPage = 4;
        int pagePerBlock = 50;

        int totalRecord = musicVideoService.getTotalRecords();

        Map<String, Integer> map = getNumbersForPaging(totalRecord, page, numPerPage, pagePerBlock);
        Integer startRecord = map.get("startRecord");
        Integer endRecord = map.get("endRecord");

        List<MusicVideo> list = musicVideoService.getVideos(startRecord, endRecord);

        Integer prevPage = map.get("prevPage");
        Integer nextPage = map.get("nextPage");
        Integer firstPage = map.get("firstPage");
        Integer lastPage = map.get("lastPage");
        Integer totalPage = map.get("totalPage");

        model.addAttribute("list", list);
        model.addAttribute("prevPage", prevPage);
        model.addAttribute("nextPage", nextPage);
        model.addAttribute("firstPage", firstPage);
        model.addAttribute("lastPage", lastPage);
        model.addAttribute("totalPage", totalPage);

        return "index";
    }

    @PostMapping("/")
    @ResponseBody
    public void add(@RequestParam(name="content") String content) {
        musicVideoService.add(content);    
    }
}
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee
                      https://jakarta.ee/xml/ns/jakartaee/web-app_6_1.xsd"
  version="6.1"
  metadata-complete="true">

<display-name>MyBatis Music</display-name>

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>

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

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

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

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

</web-app>
mybatismusic-servlet.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"
    xmlns:mybatis="http://mybatis.org/schema/mybatis-spring"
    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://mybatis.org/schema/mybatis-spring 
    http://mybatis.org/schema/mybatis-spring.xsd">

<mvc:resources location="/resources/" mapping="/resources/**" />

<mvc:annotation-driven />

<context:component-scan base-package="net.java_school.mybatismusic" />

<mybatis:scan base-package="net.java_school.mybatis" />

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

</beans>
applicationContext.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:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans.xsd">

<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
    <property name="url" value="jdbc:oracle:thin:@localhost:1521:XE" />
    <property name="username" value="scott" />
    <property name="password" value="tiger" />
    <property name="maxTotal" value="100" />
    <property name="maxWaitMillis" value="1000" />
    <property name="poolPreparedStatements" value="true" />
    <property name="defaultAutoCommit" value="true" />
    <property name="validationQuery" value=" SELECT 1 FROM DUAL" />
</bean>

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="configLocation" value="classpath:net/java_school/mybatis/Configuration.xml" />
</bean>

</beans>

src/main/webapp/WEB-INF/views

index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
         pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>MyBatis Music</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="Keywords" content="MyBatis Music App Test" />
<meta name="Description" content="This is test web app for MyBatis Music Video" />
<style>
html, body {
    margin: 0;
    padding: 0;
    background-color: #FFF;
    font-family: "Liberation Sans", Helvetica, sans-serif;
}
#videos .iframe {
    float: left;
}
#paging {
    width: 640px;
    float: left;
    font-size: 1em;
}
form {
    display: flex;
}
textarea {
    display: inline-block;
    width: 85%;
    resize: none;
}
#submit {
    display: inline-block;
    width: 10%;
    margin-bottom: -10px;
}
</style>
<script src="resources/js/jquery.js"></script>
<script>
$(document).ready(function() {
    $("#addForm").submit(function (event) {
        event.preventDefault();
        var $form = $(this);
        var content = $('#addForm-ta').val();
        content = $.trim(content);
        if (content.length === 0) {
            $('#addForm-ta').val('');
            return false;
        }
        var dataToBeSent = $form.serialize();
        var url = $form.attr("action");
        var posting = $.post(url, dataToBeSent);
        posting.done(function () {
            $('#addForm-ta').val('');
        });
    });    

    var originWidth = $('#videos > iframe').width();
    var originHeight = $('#videos > iframe').height();

    var width = $('#paging').width();
    var height = originHeight * width / originWidth;

    $('#videos > iframe').attr('width', width);
    $('#videos > iframe').attr('height', height);

    $('#videos > iframe').attr('allowFullScreen', '');

});
</script>
</head>
<body>
    <div id="videos">
        <c:forEach var="video" items="${list }" varStatus="status">
        ${video.content }
        </c:forEach>
    </div>

    <div id="paging">
        <c:if test="${prevPage > 0}">
        <a href="?page=1" title="1">[First]</a>
        <a href="?page=${prevPage }" title="${prevPage }">[Prev]</a>
        </c:if>

        <c:forEach var="i" begin="${firstPage }" end="${lastPage }" varStatus="status">
        <c:choose>
            <c:when test="${param.page == i}">
            <strong>${i }</strong>
            </c:when>
            <c:otherwise>
            <a href="?page=${i }" title="${i }">${i }</a>
            </c:otherwise>
        </c:choose>
        </c:forEach>

        <c:if test="${nextPage > 0 }">
        <a href="?page=${nextPage }" title="${nextPage }">[Next]</a>
        <a href="?page=${totalPage }" title="${totalPage }">[Last]</a>
        </c:if>
        <form id="addForm" action="./">
            <textarea id="addForm-ta" name="content" cols="30" rows="1"></textarea>
            <input id="submit" type="submit" value="Send" /> 
        </form>
    </div>
</body>
</html>

https://jquery.com/download/
src/main/webapp/resources/js/jquery.js

Run

mvn jetty:run

https://github.com/kimjonghoon/mybatismusic

Related Articles