01月16, 2019

MyBatis手把手跟我做(六) 与Web工程的整合

MyBatis(六) 与Web工程的整合

前面的内容都是介绍MyBatis基本的语法,那么接下来我们在web工程中看一下稍微实际一点的例子,不过至少我们需要和web工程整合,我们之前创建的Maven工程都还不是一个web工程.所以,接下来首先第一步,我们需要在IDEA中先将之前的简单Maven工程转换成Web工程

一.在IDEA中将简单Maven工程转换成Web工程

首先来说,实际工作最重要,如果你觉得下面转换过程过于麻烦,最简单的方式就是重新创建一个带Web的Maven工程,将之前的内容包括配置文件这些,全部复制粘贴过去就行了

重现创建一个支持Maven的web工程: 2019-01-15_10-26-00

重新创建一个Web项目很简单,我们这里主要讲解一下将之前的简单Maven工程转换为Web工程的过程

1. 配置Tomcat

无论怎么样,我们需要先在全局设置中配置一个本地的Tomcat,打开Preference

2019-01-15_10-36-35 2019-01-15_10-38-01

2. 工程结构配置

选中工程,进入工程结构配置,后面很多工程相关配置都需要进入这里进行配置 2019-01-15_10-46-53

也可以在IDEA工具的右上角,直接点击图标,进入工程配置

3. 添加工程的Tomcat jar包依赖

2019-01-15_09-33-20

4. 添加Web框架

2019-01-15_09-35-19

5. 设置web资源文件路径

2019-01-15_09-38-22

6. 设置Web工程部署描述文件 web.xml

设置部署描述文件,其实也就是我们熟悉的web.xml文件 2019-01-15_09-41-29

7. 设置Tomcat部署运行

之前都是在console窗口中进行运行测试,有了web工程之后,我们需要启动Tomcat运行测试,所以需要配置Tomcat部署运行 2019-01-15_11-27-02

2019-01-15_09-49-12

8. 将工程部署进Tomcat中

2019-01-15_09-51-10

2019-01-15_11-40-50

9.Tomcat服务器基本设置

2019-01-16_09-55-48

这样,我们的基本Maven工程就转换成为了一个Web工程了

二.MyBatis的Mapper动态代理

之前我们的代码全部是直接写在XML里面直接做的测试,但是真正的工程至少需要三层架构与MVC模式,也就是说至少需要Dao,Service,Controller与View这些东西.不管其他的,至少我现在先要把Dao完整的实现

Dao层,我们以前写代码的时候一般都是要先写接口,然后再根据接口方法写数据库的实现.之前的例子我们都已经使用MyBatis在XML中写了数据库的相关操作.我们还是可以像之前一样,写Dao层,然后写实现类,然后再在实现类中调用一下XXXMapper.xml中的方法.

1. 使用原始的Dao层接口-实现类方式调用Mapper方法

UserDao接口:

public interface UserDao {
    //根据ID查询用户信息
    public User findUserById(int id) throws Exception;
    //添加用户信息
    public void insertUser(User user) throws Exception;
    //删除用户信息
    public void deleteUser(int id) throws Exception;
}

UserDaoImpl实现类:

public class UserDaoImpl implements UserDao{

    // 需要向dao实现类中注入SqlSessionFactory
    // 这里通过构造方法注入
    private SqlSessionFactory sqlSessionFactory;

    public UserDaoImpl(SqlSessionFactory sqlSessionFactory) {
        this.sqlSessionFactory = sqlSessionFactory;
    }
    @Override
    public void deleteUser(int id) throws Exception {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //执行删除操作
        sqlSession.insert("deleteUserById", id);
        // 提交事务
        sqlSession.commit();
        // 释放资源
        sqlSession.close();
    }
    @Override
    public User findUserById(int id) throws Exception {
        SqlSession sqlSession = sqlSessionFactory.openSession();//获取sqlSession
        User user = sqlSession.selectOne("getUser", id);
        sqlSession.close();//关闭资源
        return user;
    }
    @Override
    public void insertUser(User user) throws Exception {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //执行插入操作
        sqlSession.insert("insertUserSelective", user);
        // 提交事务
        sqlSession.commit();
        // 释放资源
        sqlSession.close();
    }
}

测试类 Test3:

//这里测试一下根据id查找用户的方法即可,其他方法自行试验
public class Test3 {
    private SqlSessionFactory sqlSessionFactory;
    private static Logger log = Logger.getLogger(Test.class);

    @Before
    public void init(){
        //mybatis全局配置文件
        String resource = "mybatis-configuration.xml";
        //加载全局配置文件
        InputStream is = this.getClass().getClassLoader().getResourceAsStream(resource);
        //创建SqlSession工厂
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
    }

    @org.junit.Test
    public void testFindUserById() throws Exception{
        //创建UserDao对象
        UserDao userDao = new UserDaoImpl(sqlSessionFactory);
        //调用UserDao的方法,根据ID查找user
        User user = userDao.findUserById(1);
        //打印用户信息
        log.info(user);
    }
}

这种方式相信大家比较好理解,无非就是之前直接写JDBC实现,改成了用Mapper.xml写数据库实现,MyBatis封装了JDBC,其实并不推荐,我们直接使用MyBatis的动态代理就行了

2. Mapper的动态代理

JDBC实现其实已经被Mapper.xml替代了,UserDaoImpl的存在就显得很多余,所以我们其实只需要Dao层和Mapper.xml实现对应其实就可以了,这个就是Mapper动态代理的意义

要这么做的话肯定就需要按照规定来办事:

Mapper接口开发需要遵循以下规范:

(1)、 Mapper.xml文件中的namespacemapper接口的类路径相同。
(2)、 Mapper接口方法名和Mapper.xml中定义的每个statementid相同 。
(3)、 Mapper接口方法的输入参数类型和mapper.xml中定义的每个sqlparameterType的类型相同。
(4)、 Mapper接口方法的输出参数类型和mapper.xml中定义的每个sqlresultType的类型相同。

总结一句就是: Mapper接口要和Mapper.xml一一对应 重新来实现一下,写一个UserMapper.java的接口和UserMapper.xml进行一一对应

UserMapper.java接口:

//注意UserMapper接口放在com.yingside.dao包中,这个路径很重要
//UserMapper.xml中的namespace需要和这个路径对应
package com.yingside.dao;
import com.yingside.bean.User;
public interface UserMapper {
    //根据ID查询用户信息
    public User getUser(int id) throws Exception;
    //添加用户信息
    public void insertUserSelective(User user) throws Exception;
    //删除用户信息
    public void deleteUserById(int id) throws Exception;
    //获取全部用户信息
    public List<User> getAll() throws Exception;
}

UserMapper.xml之前已经写好,但是现在需要做一下修改,UserMapper.xmlnamespace必须指向Dao层的路径

UserMapper.xml:

......
<!-- 要和接口对应,这个的namespace就必须指向接口所在路径 -->
<mapper namespace="com.yingside.dao.UserMapper">
......

重新写一个测试方法,注意了之前测试方法的区别

测试类 Test3.java:

......
@org.junit.Test
public void testGetUser() throws Exception{
    //获取sqlSession对象
    SqlSession sqlSession = sqlSessionFactory.openSession();
    //创建UserMapper对象,MyBatis自动生成mapper代理
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    //调用userMapper的方法
    User user = userMapper.getUser(1);
    //关闭资源
    sqlSession.close();
    //打印用户信息
    log.info(user);
}

@org.junit.Test
public void insertUserSelective() throws Exception{
    //获取sqlSession对象
    SqlSession sqlSession = sqlSessionFactory.openSession();
    //创建UserMapper对象,MyBatis自动生成mapper代理
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    //生成一个User对象
    User user = new User();
    user.setUsername("袁承志");
    user.setPassword("abcdefg");
    user.setUserTel("13880000014");
    user.setRegistrationTime("2019-01-07");
    //调用userMapper的方法
    userMapper.insertUserSelective(user);
    //提交事务
    sqlSession.commit();
    //关闭资源
    sqlSession.close();
    //打印新增用户的主键id
    log.info(user.getId());
}

@org.junit.Test
public void testGetAll() throws Exception{
    //获取sqlSession对象
    SqlSession sqlSession = sqlSessionFactory.openSession();
    //创建UserMapper对象,MyBatis自动生成mapper代理
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    //调用userMapper的方法
    List<User> users = userMapper.getAll();
    //关闭资源
    sqlSession.close();
    //打印所有用户信息
    log.info(users);
}
......

注意这里和之前的不同,这里使用反射,直接生成了UserMaper对象,而下面就是直接通过对象调用方法了,这是因为动态代理对象调用sqlSession.selectOne()和sqlSession.selectList()是根据mapper接口方法的返回值决定,如果返回list则调用selectList方法,如果返回单个对象则调用selectOne方法。

下面是这一步的工程结构截图: 2019-01-16_13-39-03

Dao层现在已经有了,那么接下来我们需要做出完成的三层结构以及Servlet+JSP的MVC模式

三.完整的三层与MVC结构

那接下来就应该是业务层,我们这里业务层很简单,没啥业务,就直接套一下Dao层的方法就行了,当然同样需要接口与实现类

由于版面原因,这里测试一下获取全部用户信息就行了,其他的请自行试验

UserService接口:

public interface UserService {
    //获取全部用户信息
    public List<User> getAll() throws Exception;
}

UserServiceImpl实现类:

public class UserServiceImpl implements UserService {
    private UserMapper userMapper;
    SqlSessionFactory sqlSessionFactory = null;
    public UserServiceImpl(SqlSessionFactory sqlSessionFactory) {
        this.sqlSessionFactory = sqlSessionFactory;
    }
    @Override
    public List<User> getAll() throws Exception {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        List<User> users = userMapper.getAll();
        sqlSession.close();
        return users;
    }
}

接下来接续创建Servlet与JSP,实现在页面的访问

UserServlet:

public class UserServlet extends HttpServlet {
    private UserService userService;
    @Override
    public void init() throws ServletException {
        //mybatis全局配置文件
        String resource = "mybatis-configuration.xml";
        //加载全局配置文件
        InputStream is = this.getClass().getClassLoader().getResourceAsStream(resource);
        //创建SqlSession工厂
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        //创建userService
        userService = new UserServiceImpl(sqlSessionFactory);
    }
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        List<User> users = null;
        try {
            users = userService.getAll();
        } catch (Exception e) {
            e.printStackTrace();
        }
        request.setAttribute("list",users);//将查询结果保存在attribute list中,传送到前台页面
        request.getRequestDispatcher("users.jsp").forward(request, response);
    }
}

有了Servlet,那肯定需要配置一下web.xml

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_4_0.xsd"
         version="4.0">
    <servlet>
        <servlet-name>UserServlet</servlet-name>
        <servlet-class>com.yingside.servlet.UserServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>UserServlet</servlet-name>
        <url-pattern>/user</url-pattern>
    </servlet-mapping>
</web-app>

在jsp页面遍历显示所有用户信息

users.jsp:

<%@ page import="com.yingside.bean.User" %>
<%@ page import="java.util.List" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>用户信息列表</title>
</head>
<body>
<table border="1">
    <tr>
        <th>编号</th>
        <th>用户名</th>
        <th>电话</th>
        <th>注册时间</th>
    </tr>
    <%
        List<User> list = (List<User>) request.getAttribute("list");
        if(list == null || list.size() < 1){
            out.print("没有数据");
        }else{
            for (User u:list) {
    %>
        <tr>
            <td><%=u.getId() %></td>
            <td><%=u.getUsername() %></td>
            <td><%=u.getUserTel() %></td>
            <td><%=u.getRegistrationTime() %></td>
        </tr>
    <%
            }
        }
    %>
</table>
</body>
</html>

代码这些就大功告成了,但是现在执行的话会报类不能找到的错误NoClassDefFoundError,这是由于我们通过Maven导入的MyBatis,MySql,log4j等jar包在IDEA帮我们打包工程的时候,没有将这些包进入进来,导致运行Tomcat找不到这些jar包,这个我们只需要再IDEA中配置一下就可以了 2019-01-16_14-52-18

再来看一下现在工程的完整结构: 2019-01-16_16-16-15

最后,点击运行Tomcat

由于我们这里的代码是从Servlet得到数据跳转到JSP页面显示,所以在浏览器中输入Servlet地址 2019-01-16_16-28-47

本文链接:http://www.yanhongzhi.com/post/mybatis-web.html

-- EOF --

Comments