MyBatis(六) 与Web工程的整合
前面的内容都是介绍MyBatis基本的语法,那么接下来我们在web工程中看一下稍微实际一点的例子,不过至少我们需要和web工程整合,我们之前创建的Maven工程都还不是一个web工程.所以,接下来首先第一步,我们需要在IDEA中先将之前的简单Maven工程转换成Web工程
一.在IDEA中将简单Maven工程转换成Web工程
首先来说,实际工作最重要,如果你觉得下面转换过程过于麻烦,最简单的方式就是重新创建一个带Web的Maven工程,将之前的内容包括配置文件这些,全部复制粘贴过去就行了
重现创建一个支持Maven的web工程:
重新创建一个Web项目很简单,我们这里主要讲解一下将之前的简单Maven工程转换为Web工程的过程
1. 配置Tomcat
无论怎么样,我们需要先在全局设置中配置一个本地的Tomcat,打开Preference
2. 工程结构配置
选中工程,进入工程结构配置,后面很多工程相关配置都需要进入这里进行配置
也可以在IDEA工具的右上角,直接点击图标,进入工程配置
3. 添加工程的Tomcat jar包依赖
4. 添加Web框架
5. 设置web资源文件路径
6. 设置Web工程部署描述文件 web.xml
设置部署描述文件,其实也就是我们熟悉的web.xml文件
7. 设置Tomcat部署运行
之前都是在console窗口中进行运行测试,有了web工程之后,我们需要启动Tomcat运行测试,所以需要配置Tomcat部署运行
8. 将工程部署进Tomcat中
9.Tomcat服务器基本设置
这样,我们的基本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文件中的namespace与mapper接口的类路径相同。
(2)、 Mapper接口方法名和Mapper.xml中定义的每个statement的id相同 。
(3)、 Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同。
(4)、 Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同。
总结一句就是: 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.xml
的namespace
必须指向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方法。
下面是这一步的工程结构截图:
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中配置一下就可以了
再来看一下现在工程的完整结构:
最后,点击运行Tomcat
由于我们这里的代码是从Servlet得到数据跳转到JSP页面显示,所以在浏览器中输入Servlet地址
Comments