(五)在WEB中应用MyBatis(使用MVC架构模式)

Mybatis学习目录

上一篇:(四)手写简单版MyBatis框架
下一篇:(六)Mybatis中接口代理机制及使用

环境搭建

实现功能:银行账户转账
使用技术:HTML + Servlet + MyBatis + Tomcat10
数据库准备:

id  BIGINT  主键,自增  账户的id
actno VARCHAR(255) 账户名
balance DECIMAL(10,2)  账户金额

数据:
请添加图片描述
IDEA中创建Maven WEB应用,使用以下模板
请添加图片描述
配置Tomcat 10服务器,把项目部署进去

默认创建的maven web应⽤没有java和resources目录
需要自己手动加上
或者修改本地Maven仓库maven-archetype-webapp-1.4.jar中的配置文件
请添加图片描述
web.xml⽂件的版本较低,可以从tomcat10的样例
请添加图片描述
删除index.jsp文件,因为我们这个项⽬不使⽤JSP。只使⽤html。
确定pom.xml⽂件中的打方式是war包。
引⼊相关依赖和编译器配置:

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

  <dependencies>
    <dependency>
      <groupId>jakarta.servlet</groupId>
      <artifactId>jakarta.servlet-api</artifactId>
      <version>5.0.0</version>
    </dependency>

    <dependency>
      <groupId>jakarta.servlet.jsp</groupId>
      <artifactId>jakarta.servlet.jsp-api</artifactId>
      <version>3.0.0</version>
    </dependency>

    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>8.0.26</version>
    </dependency>

    <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-classic</artifactId>
      <version>1.2.11</version>
    </dependency>

    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.10</version>
    </dependency>

  </dependencies>

引⼊相关配置文件,放到resources目录下
mybatis-config.xml Mybatis核心配置文件
ActMapper.xml 账户映射文件
logback.xml 日志配置文件
jdbc.properties 数据库配置文件

jdbc.properties:

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/mvc?serverTimezone=Asia/Shanghai
username=root
password=root

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"/>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <!--mysql数据库连接信息-->
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <!--指定Mapper.xml文件的路径,resource是在类的根资源路径下查找-->
        <mapper resource="ActMapper.xml"/>
    </mappers>
</configuration>

logback.xml:

<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
    <!--定义⽇志⽂件的存储地址-->
    <property name="LOG_HOME" value="/home"/>
    <!-- 控制台输出 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化输出:%d表示⽇期,%thread表示线程名,%-5level:级别从左显示5
           个字符宽度%msg:⽇志消息,%n是换⾏符-->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
        </encoder>
    </appender>
    <!--mybatis log configure-->
    <logger name="com.apache.ibatis" level="TRACE"/>
    <logger name="java.sql.Connection" level="DEBUG"/>
    <logger name="java.sql.Statement" level="DEBUG"/>
    <logger name="java.sql.PreparedStatement" level="DEBUG"/>
    <!-- ⽇志输出级别,logback⽇志级别包括五个:TRACE < DEBUG < INFO < WARN < ERROR -->
    <root level="DEBUG">
        <appender-ref ref="STDOUT"/>
        <appender-ref ref="FILE"/>
    </root>
</configuration>

ActMapper.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">
    
</mapper>

前端index页面

在webapp下新建一个index.html页面用于用户账户转账,提供form形式进行数据提交

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>银行账户转账</title>
</head>
<body>
<form action="/mybatis_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>

三层架构包创建

创建dao层(持久化层/数据访问层)
创建service层 (业务逻辑层)
创建web层 (控制层/表示层/表现层)

utils包:将之前编写的SqlSessionUtil工具类拷贝到该包下。
exceptions包:自定义异常
pojo包:普通java类
请添加图片描述

定义pojo类:Account

/**
 * 简单的账户类
 */
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;
    }

    @Override
    public String toString() {
        return "Account{" +
                "id=" + id +
                ", actno='" + actno + '\'' +
                ", balance=" + balance +
                '}';
    }

    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;
    }
}

编写Dao层接口,以及Dao层Impl实现类

分析dao中⾄少要提供几个方法,才能完成转账:
转账前需要查询余额是否充足:selectByActno
转账时要更新账户:update

AccountDao接口:

/**
 * 账户的DAO对象,负责t_act表数据的CRUD
 */
public interface AccountDao {
    /**
     * 根据账号查询账户信息
     * @param actno 账号
     * @return 账户信息
     */
    Account selectByActno(String actno);

    /**
     * 更新账户信息
     * @param act 被更新的账户对象
     * @return 1表示成功,其他表示失败
     */
    int updateByActno(Account act);
}

AccountDaoImpl实现类:

public class AccountDaoImpl implements AccountDao{
    @Override
    public Account selectByActno(String actno) {
        SqlSession session = SqlSessionUtil.getSession();
        Account account = session.selectOne("selectByActno", actno);
        return account;
    }

    @Override
    public int updateByActno(Account act) {
        SqlSession session = SqlSessionUtil.getSession();
        int count = session.update("updateByActno",act);
        return count;
    }
}

Dao层编写的mybatis需要SQL映射文件配置

ActMapper.xml:

	<select id="selectByActno" resultType="com.bank.pojo.Account">
        select * from t_act where actno=#{actno}
    </select>
    <update id="updateByActno">
        update t_act set balance = #{balance} where actno=#{actno}
    </update>

编写业务逻辑

在service编写业务,创建接口

/**
 * 账户业务类,负责处理账户
 */
public interface AccountService {
    /**
     * 转账业务
     * @param fromact 转出账户
     * @param toact 转入账户
     * @param meney 转账金额
     */
    void transfer(String fromact,String toact,double meney) throws MoneyNotEnoughException, TransferException;
}

转账前需要查询余额是否充足,不充足需要抛出异常
exceptions编写自定义账户金额不足异常类

/**
 * 账户金额不足异常
 */
public class MoneyNotEnoughException extends Exception{
    public MoneyNotEnoughException() {
    }

    public MoneyNotEnoughException(String message) {
        super(message);
    }
}

转账时要更新账户,两个账户更新不成功需要抛出异常
exceptions编写自定义转账异常类

/**
 * 转账异常
 */
public class TransferException extends Exception{
    public TransferException() {
    }

    public TransferException(String message) {
        super(message);
    }
}

编写业务逻辑层实现类

public class AccountServiceImpl implements AccountService {
    private AccountDao accountDao = new AccountDaoImpl();
    @Override
    public void transfer(String fromact, String toact, double meney) throws MoneyNotEnoughException, TransferException {

        //处理事务
        SqlSession sqlSession = SqlSessionUtil.getSession();

        //1.判断转出账户余额是否充足,不充足提示
        Account fromAccount = accountDao.selectByActno(fromact);
        if (fromAccount.getBalance() < meney) {
            //提示用户
            throw new MoneyNotEnoughException("不好意思,账户余额不足");
        }

        //2.转出账户余额充足,更新转出账户余额
        Account toactAccount = accountDao.selectByActno(toact);
        fromAccount.setBalance(fromAccount.getBalance() - meney);

        /*String s = null;//这里模拟异常,测试事务处理是否成功
        s.toString();*/

        toactAccount.setBalance(toactAccount.getBalance() + meney);

        int count = accountDao.updateByActno(fromAccount);
        count += accountDao.updateByActno(toactAccount);
        if (count != 2) {
            sqlSession.rollback();//事务回滚
            throw new TransferException("转账异常,未知原因");
        }
        
        sqlSession.commit();//事务提交
        SqlSessionUtil.close(sqlSession);
    }
}

编写web层代码

创建一个类继承HttpServlet,前端是doPost提交,需要覆盖doPost方法

@WebServlet("/transfer")
public class AccountServlet extends HttpServlet {
    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"));
        //调用service的转账方法完成转账(调业务层)
        try {
            accountService.transfer(fromactno,toactno,money);
            response.sendRedirect(request.getContextPath() + "/success.html");
        } catch (MoneyNotEnoughException e) {
            response.sendRedirect(request.getContextPath() + "/error1.html");
        } catch (TransferException e) {
            response.sendRedirect(request.getContextPath() + "/error2.html");
        }catch (Exception e){
            response.sendRedirect(request.getContextPath() + "/error2.html");
        }
    }
}

前端错误页面和成功页面

success.html:

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

error1.html:

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

error2.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>转账报告</title>
</head>
<body>
<h1>转账失败,未知原因!!!</h1>
</body>
</html>

测试

启动Tomcat,浏览器输入http://localhost:8080/mybatis_bank/ (mybatis_bank项目名)
输入数据,点击转账测试
请添加图片描述
请添加图片描述
数据库数据改变
请添加图片描述

输入超过金额数据,点击转账测试
请添加图片描述
请添加图片描述
数据库数据没有变化
请添加图片描述
测试事务是否正常处理,在更新账户之间模拟空指针异常
AccountServiceImpl:

String s = null;
s.toString();

输入数据,点击转账测试
请添加图片描述
请添加图片描述
数据库数据,没有改变,总体测试成功
请添加图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

忆亦何为

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值