Just a simple demo: SpringMVC + Mybatis

2018-08-22 by Victor Lv Filed under 技术博客

Just a simple demo: SpringMVC + Mybatis

1. web.xml

First configure web.xml which is used for Spring and SpringMVC: web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
         xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
    http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

    <servlet>
        <!-- This servlet-name links to the configuration file: app-servlet.xml -->
        <servlet-name>app</servlet-name>
        <servlet-class>
            org.springframework.web.servlet.DispatcherServlet
        </servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

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

</web-app>

Here, web.xml configure the important element DispatcherServlet and map it into / url ( website root url ). If external context configuration is needed, we can define external configuration in this way:

<!-- Specify the external context configuration file -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring/root-context.xml</param-value>
    </context-param>

    <!-- Setup Spring's context listener which will load the context configured in `contextConfigLocation` -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

2. servlet.xml

In web.xml, we define a servlet who's name is app. This will tell the program to search a xml configuration who's name is app-servlet.xml. So, we need to create app-servlet.xml: app-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"
       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-3.0.xsd">

    <!-- Enable Spring-MVC, driven by annotation -->
    <mvc:annotation-driven />

    <context:component-scan base-package="test.control" />

    <!-- Configure JSP ViewResolver -->
    <bean 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>

In this file, we enable the Spring-MVC driven by annotation. And we tell the program to search the component bean in package test.control and then load the beans into context. Also, we inject a ViewResolver bean used to render JSP views.

3. Controller and View

Ok, configure is finished. Let's begin write MVC (model - view - control) code. First, we complete the controllers. All websites need an index page, generally be index view. IndexController is showed as follow: IndexController.java

package test.control;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import static org.springframework.web.bind.annotation.RequestMethod.*;

/**
 * @ClassName: IndexController
 * @Description: TODO
 * @Author: Victor Lv (http://langlv.me)
 * @Date: 2018/8/17 16:36
 * @Version: 1.0
 */

@Controller
public class IndexController {

    @RequestMapping(value = "/", method = GET)
    public String index() {
        System.out.println("Index controller");
        return "index";
    }

}

IndexController is very simple. It just map the root path / into the index method, and then return the view name index. In app-context.xml, we specify the view's preffix as /WEB-INF/views/, suffix as .jsp. So DispatcherServlet will help us to convert the returned string ( index ) into view's real path: /WEB-INF/views/index.jsp, and invoke the ViewResolver to render it into html page which is the real page we see in web browser. Then, let's create a simple JSP view: index.jsp

<%--
  Created by IntelliJ IDEA.
  User: lvlang
  Date: 2018/8/20
  Time: 11:24
  To change this template use File | Settings | File Templates.
--%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page session="false" %>
<html>
<head>
    <title>Just a simple demo: SpringMVC + Mybatis</title>
</head>
<body>
<h1>Just a simple demo: SpringMVC + Mybatis</h1>

<form action="/selectAllUser" method="post">
    <div>
        <span>Search all user:</span>
        <input type="submit" id="selectAllUser" value="search" />
    </div>
</form>
<form action="/selectUserID" method="post">
    <div>
        <span>Search user by user ID, please enter user ID:</span>
        <input type="text" name="userID">
        <input type="submit" value="search" />
    </div>
</form>
<form action="/insertUser" method="post">
    <div>
        <span>Insert user, please enter user name:</span>
        <input type="text" name="insertUserName" />
        <span>user address:</span>
        <input type="text" name="insertUserAddress" />
        <input type="submit" id="insert" value="insert" />
    </div>
</form>
<form action="/updateUser" method="post">
    <div>
        <span>Update user, please enter user ID:</span>
        <input type="text" name="updateUserID" />
        <span>user name:</span>
        <input type="text" name="updateUserName" />
        <span>user address:</span>
        <input type="text" name="updateUserAddress" />
        <input type="submit" id="updateUser" value="update" />
    </div>
</form>
<form action="/deleteUser" method="post">
    <div>
        <span>Delete user by ID, please enter user ID:</span>
        <input type="text" name="deleteUserID"/>
        <input type="submit" id="deleteUser" value="delete" />
    </div>
</form>

</body>
</html>

In this simple page, we install the user CRUD action. Every action redirect an website relative path. So, let's create the UserController to process the user CRUD request. UserController.java

package test.control;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import test.entity.User;
import test.dao.UserTool;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;

import static org.springframework.web.bind.annotation.RequestMethod.*;

/**
 * @ClassName: UserController
 * @Description: TODO
 * @Author: Victor Lv (http://langlv.me)
 * @Date: 2018/8/20 11:06
 * @Version: 1.0
 */

@Controller
public class UserController {

    @RequestMapping(value = "/selectAllUser" , method = POST)
    public ModelAndView selectAllUser() {
        System.out.println("Selecting All User.");
        List<User> user = UserTool.selectAllUser();
        ModelAndView modelAndView = new ModelAndView("/user_list");
        modelAndView.addObject("user", user);
        return modelAndView;
    }

    @RequestMapping(value = "/selectUserID" , method = POST)
    public ModelAndView selectUserID(HttpServletRequest httpServletRequest) {
        String userID = httpServletRequest.getParameter("userID");
        System.out.println("Selecting myUser who's ID is: " + userID);
        List<User> user = new ArrayList<User>();
        User user1 = UserTool.selectUser(Integer.parseInt(userID));
        //Avoid adding "null" into List which will cause exception
        if (null != user1) {
            user.add(user1);
        }
        ModelAndView modelAndView = new ModelAndView("/user_list");
        modelAndView.addObject("user", user);
        return modelAndView;
    }

    @RequestMapping(value = "/insertUser", method = POST)
    public String insertUser(HttpServletRequest httpServletRequest) {
        String newUserName = httpServletRequest.getParameter("insertUserName");
        String newUserAddress = httpServletRequest.getParameter("insertUserAddress");
        System.out.println("Inserting user, name: " + newUserName + ", address:" + newUserAddress);
        boolean insertSuccess = UserTool.insertUser(newUserName, newUserAddress);
        if (insertSuccess){
            return "success";
        }else {
            return "fail";
        }
    }

    @RequestMapping(value = "/updateUser", method = POST)
    public String updateUser(HttpServletRequest httpServletRequest) {
        String updateUserID = httpServletRequest.getParameter("updateUserID");
        String updateUserName = httpServletRequest.getParameter("updateUserName");
        String updateUserAddress = httpServletRequest.getParameter("updateUserAddress");
        System.out.println("Updating user, ID:" + updateUserID + ", name:" + updateUserName + ", address:" + updateUserAddress);
        boolean updateSuccess = UserTool.updateUser(Integer.parseInt(updateUserID), updateUserName, updateUserAddress);
        if (updateSuccess){
            return "success";
        }else {
            return "fail";
        }
    }

    @RequestMapping(value = "/deleteUser", method = POST)
    public String deleteUser(HttpServletRequest httpServletRequest) {
        String deleteUserID = httpServletRequest.getParameter("deleteUserID");
        System.out.println("Deleting user, ID: " + deleteUserID);
        boolean deleteSuccess = UserTool.deleteUser(Integer.parseInt(deleteUserID));
        if (deleteSuccess){
            return "success";
        }else {
            return "fail";
        }
    }

}

To finish the user CRUD's action, we need DAO ( Data Access Object ) to connect the database. Here, we use the ORM framework Mybatis as the tool. By the way, we can use something else database access framework. That is, in MVC framework, each layer is separate so that we can choose the framework we like such as choosing Hibernate or Mybatis in Model layer and JSP or html in view layer. Every framework is just an plug-in component or to say: Service. We can choose and change Service as we like. Sounds greate ?

Model layer & Mybatis

First, we need the Mybatis's configuration. Here, mybatis-config.xml configures the dataSource infomation and specify the Mapper.xml file path. mybatis-config.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>

    <!-- including external configuration file -->
    <properties resource="mybatis/jdbc.properties"></properties>

    <!-- Set type alias used for Mapper.xml -->
    <typeAliases>
        <typeAlias alias="User" type="test.entity.User" />
    </typeAliases>

    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${JDBC.driverClass}"/>
                <property name="url" value="${JDBC.url}"/>
                <property name="username" value="${JDBC.userName}"/>
                <property name="password" value="${JDBC.userPassword}"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <mapper resource="mybatis/UserMapper.xml"></mapper>
    </mappers>

</configuration>

For the convenience of modification, we put the database connection information into the external file jdbc.properties: jdbc.properties

JDBC.driverClass=com.mysql.jdbc.Driver
JDBC.url=jdbc:mysql://localhost:3306/lvlang?autoReconnect=true&amp;useUnicode=true&amp;characterEncoding=UTF-8
JDBC.userName=root
JDBC.userPassword=123456

Then, we configure our SQL statement in UserMapper.xml: UserMapper.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="UserMapper">

    <sql id="userList">id, name, address</sql>

    <select id="queryAll" resultType="User">
        SELECT 
        <include refid="userList" />
        FROM User
        ORDER BY id ASC
    </select>

    <select id="selectUser" parameterType="int" resultType="User">
        SELECT
        <include refid="userList" />
        FROM User
        WHERE id = #{id}
    </select>

    <insert id="insertUser" parameterType="User" useGeneratedKeys="true" keyProperty="id">
        insert into User (name, address)
                VALUES (#{name}, #{address})
    </insert>

    <delete id="deleteUser" parameterType="int" >
        DELETE FROM User WHERE id = #{id}
    </delete>

    <update id="updateUser" parameterType="User">
        UPDATE User set
            name = #{name},
            address = #{address}
        where id = #{id}
    </update>
</mapper>

Ok, Mybatis's configuration and SQL mapper is ready. In Mybatis, SqlSession is used to execute database access. Here, we create an simple SqlSession pool to provide SqlSession: SessionFactory.java

package test.dao;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;

/**
 * @ClassName: SessionFactory.java
 * @Description: TODO
 * @Author: http://langlv.me
 * @Date: 2018/7/10 15:44
 * @Version: 1.0
 */

public class SessionFactory {

    private static SqlSessionFactory sqlSessionFactory;

    static {
        // introduce the datasource configuration file
        String resource = "mybatis/mybatis-config.xml";
        try {
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static SqlSession getSession() {
        return sqlSessionFactory.openSession();
    }

}

Then, let's use the SqlSession to access database and excute the User table's CURD: UserTool.java

package test.dao;

import org.apache.ibatis.session.SqlSession;
import test.entity.User;

import java.io.IOException;
import java.util.List;

/**
 * @ClassName: UserTool.java
 * @Description: TODO
 * @Author: http://langlv.me
 * @Date: 2018/7/10 15:44
 * @Version: 1.0
 */

public class UserTool {

    public static void main(String arg[]) throws IOException {
        User user1 = selectUser(1);
        System.out.println(user1.toString());

        System.out.println("Insert user: " + insertUser("Victor", "New York"));

        System.out.println("Update user: " + updateUser(7, "Bill Gates", "Beijing"));
        User user2 = selectUser(7);
        System.out.println(user2.toString());

        System.out.println("Delete User: " + deleteUser(12));

    }

    public static List<User> selectAllUser() {
        SqlSession session = SessionFactory.getSession();

        System.out.println("Selecting all users...");
        try {
            List<User> userList = session.selectList((String) "UserMapper.queryAll");
            if (null != userList) {
                return userList;
            } else {
                System.out.println("Not found!");
                return null;
            }
        } catch (Exception e) {
            e.printStackTrace();
            session.rollback();
            return null;
        } finally {
            session.close();
        }
    }

    public static User selectUser(int id) {
        SqlSession session = SessionFactory.getSession();

        System.out.println("Selecting user...");
        try {
            User user = (User) session.selectOne((String) "UserMapper.selectUser", id);
            if (null != user) {
                System.out.println(user.toString());
                return user;
            } else {
                System.out.println("Not found!");
                return null;
            }
        } catch (Exception e) {
            e.printStackTrace();
            session.rollback();
            return null;
        } finally {
            session.close();
        }
    }

    public static boolean insertUser(String name, String address) {
        SqlSession session = SessionFactory.getSession();

        System.out.println("Inserting user...");
        try {
            User user1 = new User();
            user1.setName(name);
            user1.setAddress(address);
            int index = session.insert("UserMapper.insertUser", user1);
            boolean result = (index > 0) ? true : false;
            session.commit();
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            session.rollback();
            return false;
        } finally {
            session.close();
        }
    }

    public static boolean updateUser(int id, String name, String address) {
        SqlSession session = SessionFactory.getSession();

        System.out.println("Updating user...");
        try {
            User user = new User(id, name, address);
            int index = session.update("UserMapper.updateUser", user);
            boolean result = (index > 0) ? true : false;
            session.commit();
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            session.rollback();
            return false;
        } finally {
            session.close();
        }
    }

    public static boolean deleteUser(int id) {
        SqlSession session = SessionFactory.getSession();

        System.out.println("Deleting user...");
        try {
            int index = session.delete("UserMapper.deleteUser", id);
            boolean result = (index > 0) ? true : false;
            session.commit();
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            session.rollback();
            return false;
        } finally {
            session.close();
        }
    }
}

Also, the User entiry is needed which mapping the User table in database: User.java

/**
 * @ClassName: User.java
 * @Description: TODO
 * @Author: http://langlv.me
 * @Date: 2018/7/10 15:44
 * @Version: 1.0
 */

package test.entity;

public class User {

    private int id;

    private String name;

    private String address;

    public User() {
    }

    public User(int id, String name, String address) {
        this.id = id;
        this.name = name;
        this.address = address;
    }

    /**
     * @return the id
     */
    public int getId() {
        return id;
    }

    /**
     * @param id the id to set
     */
    public void setId(int id) {
        this.id = id;
    }

    /**
     * @return the name
     */
    public String getName() {
        return name;
    }

    /**
     * @param name the name to set
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * @return the address
     */
    public String getAddress() {
        return address;
    }

    /**
     * @param address the address to set
     */
    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "User [id=" + id + ", name=" + name +", address= " + address + " ]";
    }
}

Ok, database access tool is finished. Now we clear the way between controller and model. Here is the work flow of Spring-MVC's DispatcherServlet :  DispatcherServlet's work flow

The DispatcherServlet gets http request from browser and then dispatchs the request to specific controller according to the request url path. The controller will invoke the model layer to execute database operation and return the view page alias string and result data to DispatcherServlet. Then DispatcherServlet / ViewResolver will combine the model data with JSP view to create the real html page and return it to browser.

Ok, all is done. Let's review the project structure: project structrure

A little bit ugly pages

Index page:

index page

Select all user:

selectAllUser

Insert a user and then redirect to success page:

insertUser


本文作者为 Victor Lv ,原出处为Victor Lv's Blog(http://langlv.me),转载请保留此句。


标签 spring mybatis springMVC Java-Web
Fork me on GitHub