0
点赞
收藏
分享

微信扫一扫

【MyBatis】| 在WEB中应⽤MyBatis(使⽤MVC架构模式)

夏天的枫_ 2023-01-19 阅读 25

目录

一:在WEB中应⽤MyBatis(使⽤MVC架构模式)

1. 前期准备

2. 核心代码实现

3. 事务控制

4. 三大对象的作用域


一:在WEB中应⽤MyBatis(使⽤MVC架构模式)

1. 前期准备

设计表结构

 插入数据

①在pom.xml文件中引入依赖

<?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/maven-v4_0_0.xsd">

  <modelVersion>4.0.0</modelVersion>
  
  <name>mybatis-004-web</name>
  <groupId>com.bjpowernode</groupId>
  <artifactId>mybatis-004-web</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>war</packaging>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
  </properties>

  <dependencies>
    <!--mybatis依赖-->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.10</version>
    </dependency>
    <!--mysql依赖-->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.23</version>
    </dependency>
    <!--logback依赖-->
    <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-classic</artifactId>
      <version>1.2.11</version>
    </dependency>
    <!--servlet依赖-->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.1.0</version>
    </dependency>
  </dependencies>

</project>

②一些配置文件的引入

③编写前端转账页面index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>银行账户转账</title>
</head>
<body>
    <form action="/bank/transfer" method="post">
        转出账号:<input type="text" name="fromActno"><br>
        转入账号:<input type="text" name="toActno"><br>
        转账余额:<input type="text" name="money"><br>
        <input type="submit" value="转账">
    </form>
</body>
</html>

④使用MVC架构模式创建包

pojo类,封装账户信息

package com.bjpowernode.bank.pojo;

/**
 * @Author:朗朗乾坤
 * @Package:com.bjpowernode.bank.pojo
 * @Project:mybatis
 * @name:Account
 * @Date:2023/1/1 17:53
 */
public class Account {
    private Long id;
    private String actno;
    private Double balance;
    // 构造方法
    public Account() {
    }
    public Account(Long id, String actno, Double balance) {
        this.id = id;
        this.actno = actno;
        this.balance = balance;
    }
    // setter and getter
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getActno() {
        return actno;
    }

    public void setActno(String actno) {
        this.actno = actno;
    }

    public Double getBalance() {
        return balance;
    }

    public void setBalance(Double balance) {
        this.balance = balance;
    }
    // 重写toString
    @Override
    public String toString() {
        return "Account{" +
                "id=" + id +
                ", actno='" + actno + '\'' +
                ", balance=" + balance +
                '}';
    }
}

 工具类,连接数据库的类

package com.bjpowernode.bank.utils;

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;

public class SqlSessionUtils {
    public SqlSessionUtils() {
    }
    private static SqlSessionFactory sqlSessionFactory;
    static {
        try {
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader("mybatis-config.xml"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public static SqlSession openSession(){
        return sqlSessionFactory.openSession();
    }

}

2. 核心代码实现

主要框架形式和所需要的展示页面

package com.bjpowernode.bank.web;

import com.bjpowernode.bank.exception.MoenyNotEnoughException;
import com.bjpowernode.bank.exception.TransferException;
import com.bjpowernode.bank.service.AccountService;
import com.bjpowernode.bank.service.impl.AccountServiceImpl;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * @Author:朗朗乾坤
 * @Package:com.bjpowernode.bank.web
 * @Project:mybatis
 * @name:AccountServlet
 * @Date:2023/1/1 19:23
 */
@WebServlet("/transfer")
public class AccountServlet extends HttpServlet {
    // 编写业务逻辑的类,声明为成员变量,其它方法也能调用
    private AccountService accountService = new AccountServiceImpl();

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 获取表单数据
        String fromActno = request.getParameter("fromActno");
        String toActno = request.getParameter("toActno");
        double money = Double.parseDouble(request.getParameter("money"));
        // AccountService accountService = new AccountServiceImpl(); // 面向接口编程
        try {
            // 调用service的转账方法完成转账(调度业务层-M)
            accountService.transfer(fromActno,toActno,money);
            // 调用View完成展示结果
            // 转账成功,跳转页面
            response.sendRedirect(request.getContextPath()+"/success.html");
        } catch (MoenyNotEnoughException e) {
            // 钱不够,跳转页面
            response.sendRedirect(request.getContextPath()+"/money-not-enough.html");
        } catch (TransferException e) {
            // 转账失败,跳转页面
            response.sendRedirect(request.getContextPath()+"/transfer-error.html");
        }

    }
}

 余额不足money-not-enough.html页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>余额不足</title>
</head>
<body>
    <h1>余额不足</h1>
</body>
</html>

 转账成功success.html页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>转账成功</title>
</head>
<body>
    <h1>转账成功</h1>
</body>
</html>

转账失败transfer-error.html页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>转账失败</title>
</head>
<body>
    <h1>转账失败</h1>
</body>
</html>

AccountService接口

package com.bjpowernode.bank.service;

import com.bjpowernode.bank.exception.MoenyNotEnoughException;
import com.bjpowernode.bank.exception.TransferException;

public interface AccountService {
    /**
     * 账户转账
     * @param fromActno 转账账号
     * @param toActno 转入账号
     * @param money 转账金额
     */
    void transfer(String fromActno,String toActno,double money) throws MoenyNotEnoughException, TransferException;
}

AccountServiceImpl实现类

package com.bjpowernode.bank.service.impl;

import com.bjpowernode.bank.bao.AccountDao;
import com.bjpowernode.bank.bao.impl.AccountDaoImpl;
import com.bjpowernode.bank.exception.MoenyNotEnoughException;
import com.bjpowernode.bank.exception.TransferException;
import com.bjpowernode.bank.pojo.Account;
import com.bjpowernode.bank.service.AccountService;

/** 编写业务逻辑代码
 * @Author:朗朗乾坤
 * @Package:com.bjpowernode.bank.service.impl
 * @Project:mybatis
 * @name:AccountServiceImpl
 * @Date:2023/1/1 19:40
 */
public class AccountServiceImpl implements AccountService {---
   // 修改数据的类
   private AccountDao accountDao = new AccountDaoImpl();
    @Override
    public void transfer(String fromActno, String toActno, double money) throws MoenyNotEnoughException, TransferException {
        // 判断转出账户的余额是否充足
        Account fromAct = accountDao.selectByActno(fromActno);
        if (fromAct.getBalance() < money) {
            // 如果转出账户余额不足,抛出异常提示用户
            throw new MoenyNotEnoughException("对不起,余额不足");
        }
        // 如果余额充足,更新转出和转入账户余额
        Account toAct = accountDao.selectByActno(toActno);
        // 修改内存中的余额
        fromAct.setBalance(fromAct.getBalance()-money);
        toAct.setBalance(toAct.getBalance()+money);
        // 修改数据库当中余额
        int count = accountDao.updateByActno(fromAct);
        count += accountDao.updateByActno(toAct);
        if (count != 2) {
            // 转账异常
            throw new TransferException("转账异常");
        }
    }
}

 余额不足抛出异常MoenyNotEnoughException

package com.bjpowernode.bank.exception;

public class MoenyNotEnoughException extends Exception{
    // 两个构造方法
    public MoenyNotEnoughException() {
    }
    public MoenyNotEnoughException(String message) {
        super(message);
    }
}

 转账失败抛出异常TransferException

package com.bjpowernode.bank.exception;

public class TransferException extends Exception{
    public TransferException() {
    }
    public TransferException(String message) {
        super(message);
    }
}

AccountDao接口

package com.bjpowernode.bank.bao;

import com.bjpowernode.bank.pojo.Account;

/**
 * 负责对表中数据进行CRUD
 * @Author:朗朗乾坤
 * @Package:com.bjpowernode.bank.bao
 * @Project:mybatis
 * @name:AccountDao
 * @Date:2023/1/1 19:48
 */
public interface AccountDao {
    /**
     * 根据账号查询账户信息
     * @param actno
     * @return 返回的是账户信息
     */
   Account selectByActno(String actno);

    /**
     * 更新账户信息
     * @param act
     * @return 1表示更新成功
     */
   int updateByActno(Account act);
}

AccountDaoImpl类

package com.bjpowernode.bank.bao.impl;

import com.bjpowernode.bank.bao.AccountDao;
import com.bjpowernode.bank.pojo.Account;
import com.bjpowernode.bank.utils.SqlSessionUtils;
import org.apache.ibatis.session.SqlSession;

/**
 * @Author:朗朗乾坤
 * @Package:com.bjpowernode.bank.bao.impl
 * @Project:mybatis
 * @name:AccountDaoImpl
 * @Date:2023/1/1 19:57
 */
public class AccountDaoImpl implements AccountDao {
    @Override
    public Account selectByActno(String actno) {
        SqlSession sqlSession = SqlSessionUtils.openSession();
        Account account = (Account) sqlSession.selectOne("account.selectByActno", actno);
        sqlSession.close();
        return account;
    }

    @Override
    public int updateByActno(Account act) {
        SqlSession sqlSession = SqlSessionUtils.openSession();
        int count = sqlSession.update("account.updateByActno", act);
        sqlSession.commit();
        sqlSession.close();
        return count;
    }
}

编写sql语句的AccountMapper.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="account">
    <select id="selectByActno" resultType="com.bjpowernode.bank.pojo.Account">
        select * from t_act where actno=#{actno}
    </select>

    <update id="updateByActno">
        update t_act set balance = #{balance} where actno = #{actno};
    </update>
</mapper>

连接数据库的配置文件jdbc.properties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis
jdbc.username=root
jdbc.password=123

核心配置文件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>
    <!--读取配置文件-->
    <properties resource="jdbc.properties" />
    <!--引入日志-->
    <settings>
        <setting name="logImpl" value="SLF4J"/>
    </settings>
    <environments default="mybatisDB">
        <!--连接的是mybatis数据库-->
        <environment id="mybatisDB">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}" />
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <!--关联AccountMapper.xml配置文件-->
        <mapper resource="AccountMapper.xml"/>
    </mappers>

</configuration>

3. 事务控制

package com.bjpowernode.bank.service.impl;

import com.bjpowernode.bank.bao.AccountDao;
import com.bjpowernode.bank.bao.impl.AccountDaoImpl;
import com.bjpowernode.bank.exception.MoenyNotEnoughException;
import com.bjpowernode.bank.exception.TransferException;
import com.bjpowernode.bank.pojo.Account;
import com.bjpowernode.bank.service.AccountService;
import com.bjpowernode.bank.utils.SqlSessionUtils;
import org.apache.ibatis.session.SqlSession;

/**
 * @Author:朗朗乾坤
 * @Package:com.bjpowernode.bank.service.impl
 * @Project:mybatis
 * @name:AccountServiceImpl
 * @Date:2023/1/1 19:40
 */
public class AccountServiceImpl implements AccountService {
   private AccountDao accountDao = new AccountDaoImpl();
    @Override
    public void transfer(String fromActno, String toActno, double money) throws MoenyNotEnoughException, TransferException {

        // 添加事务控制代码
        SqlSession sqlSession = SqlSessionUtils.openSession();

        // 判断转出账户的余额是否充足
        Account fromAct = accountDao.selectByActno(fromActno);
        if (fromAct.getBalance() < money) {
            // 如果转出账户余额不足,抛出异常提示用户
            throw new MoenyNotEnoughException("对不起,余额不足");
        }
        // 如果余额充足,更新转出和转入账户余额
        Account toAct = accountDao.selectByActno(toActno);
        // 修改内存中的余额
        fromAct.setBalance(fromAct.getBalance()-money);
        toAct.setBalance(toAct.getBalance()+money);
        // 修改数据库当中余额
        int count = accountDao.updateByActno(fromAct);
        count += accountDao.updateByActno(toAct);
        if (count != 2) {
            // 转账异常
            throw new TransferException("转账异常");
        }

        // 提交事务
        sqlSession.commit();
        sqlSession.close();
    }
}

在工具类SqlSessionUtils中引入ThreadLocal

package com.bjpowernode.bank.utils;

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;

/**
 * @Author:朗朗乾坤
 * @Package:com.bjpowernode.mybatis.utils
 * @Project:mybatis
 * @name:SqlSessionUtils
 * @Date:2022/12/29 14:11
 */

public class SqlSessionUtils {
    public SqlSessionUtils() {
    }
    private static SqlSessionFactory sqlSessionFactory;
    static {
        try {
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader("mybatis-config.xml"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // 全局的,服务器级别的,一个服务器当中定义一个
    private static ThreadLocal<SqlSession> local = new ThreadLocal<>();

    // 获取会话对象
    public static SqlSession openSession(){
        // 先从ThreadLocal当中获取
        SqlSession sqlSession = local.get();
        // 第一次获取肯定是空的
        if (sqlSession == null) {
            // 是空的,在去工厂中获取
            sqlSession = sqlSessionFactory.openSession();
            // 将sqlSession对象绑定到当前线程上
            local.set(sqlSession);
        }
        return sqlSession;
    }

    // 关闭sqlSession对象
    public static void close(SqlSession sqlSession){
        if (sqlSession != null) {
            sqlSession.close();
            // 移除sqlSession对象与当前线程的绑定关系
            // 因为Tomcat服务器是支持多线程的,被当前用户用到的t1线程,有可能继续被其他用户使用
            local.remove();
        }
    }
}

修改数据库AccountDaoImpl类,不应该在这里面commit和close

package com.bjpowernode.bank.bao.impl;

import com.bjpowernode.bank.bao.AccountDao;
import com.bjpowernode.bank.pojo.Account;
import com.bjpowernode.bank.utils.SqlSessionUtils;
import org.apache.ibatis.session.SqlSession;

/**
 * @Author:朗朗乾坤
 * @Package:com.bjpowernode.bank.bao.impl
 * @Project:mybatis
 * @name:AccountDaoImpl
 * @Date:2023/1/1 19:57
 */
public class AccountDaoImpl implements AccountDao {
    @Override
    public Account selectByActno(String actno) {
        SqlSession sqlSession = SqlSessionUtils.openSession();
        Account account = (Account) sqlSession.selectOne("account.selectByActno", actno);
        return account;
    }

    @Override
    public int updateByActno(Account act) {
        SqlSession sqlSession = SqlSessionUtils.openSession();
        int count = sqlSession.update("account.updateByActno", act);
        return count;
    }
}

在Service层AccountServiceImpl类中增加事务的控制

package com.bjpowernode.bank.service.impl;

import com.bjpowernode.bank.bao.AccountDao;
import com.bjpowernode.bank.bao.impl.AccountDaoImpl;
import com.bjpowernode.bank.exception.MoenyNotEnoughException;
import com.bjpowernode.bank.exception.TransferException;
import com.bjpowernode.bank.pojo.Account;
import com.bjpowernode.bank.service.AccountService;
import com.bjpowernode.bank.utils.SqlSessionUtils;
import org.apache.ibatis.session.SqlSession;

/**
 * @Author:朗朗乾坤
 * @Package:com.bjpowernode.bank.service.impl
 * @Project:mybatis
 * @name:AccountServiceImpl
 * @Date:2023/1/1 19:40
 */
public class AccountServiceImpl implements AccountService {
   private AccountDao accountDao = new AccountDaoImpl();
    @Override
    public void transfer(String fromActno, String toActno, double money) throws MoenyNotEnoughException, TransferException {

        // 添加事务控制代码
        SqlSession sqlSession = SqlSessionUtils.openSession();

        // 判断转出账户的余额是否充足
        Account fromAct = accountDao.selectByActno(fromActno);
        if (fromAct.getBalance() < money) {
            // 如果转出账户余额不足,抛出异常提示用户
            throw new MoenyNotEnoughException("对不起,余额不足");
        }
        // 如果余额充足,更新转出和转入账户余额
        Account toAct = accountDao.selectByActno(toActno);
        // 修改内存中的余额
        fromAct.setBalance(fromAct.getBalance()-money);
        toAct.setBalance(toAct.getBalance()+money);
        // 修改数据库当中余额
        int count = accountDao.updateByActno(fromAct);
        count += accountDao.updateByActno(toAct);
        if (count != 2) {
            // 转账异常
            throw new TransferException("转账异常");
        }

        // 提交事务
        sqlSession.commit();
        // 调用方法关闭
        SqlSessionUtils.close(sqlSession);
    }
}

4. 三大对象的作用域

补充:我们发现Dao实现类AccountDaoImp的每个方法代码就两行,而且还有一行是重复的;那么这个类能不能不写了,在内存中生成这个接口的实现类?使用javassist技术,可以只给接口,根据这个接口在内存中自动生成这个实现类,这就是接下来要学的技术!

package com.bjpowernode.bank.bao.impl;

import com.bjpowernode.bank.bao.AccountDao;
import com.bjpowernode.bank.pojo.Account;
import com.bjpowernode.bank.utils.SqlSessionUtils;
import org.apache.ibatis.session.SqlSession;

/**
 * @Author:朗朗乾坤
 * @Package:com.bjpowernode.bank.bao.impl
 * @Project:mybatis
 * @name:AccountDaoImpl
 * @Date:2023/1/1 19:57
 */
public class AccountDaoImpl implements AccountDao {
    @Override
    public Account selectByActno(String actno) {
        SqlSession sqlSession = SqlSessionUtils.openSession();
        Account account = (Account) sqlSession.selectOne("account.selectByActno", actno);
        return account;
    }

    @Override
    public int updateByActno(Account act) {
        SqlSession sqlSession = SqlSessionUtils.openSession();
        int count = sqlSession.update("account.updateByActno", act);
        return count;
    }
}
举报

相关推荐

0 条评论