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