用mybatis实现银行转账
要求
转账时,账户和密码不匹配跳转到错误信息页面
转账时,余额不足时跳转到错误信息页面
转账时,收款人帐号和姓名不匹配跳转到错误信息页面
如果转账成功:
修改账户余额以外还需要把操作记录到日志表中,同时还需要记录到log日志文件中.
日志文件中只需要记录哪个账户给哪个账户在什么时间转了多少钱
跳转到转账记录页面
代码实现
为了方便阅读,对于代码中的导包,以及一些没有阅读性的代码,我用语言进行描述,不再用大量的代码占用空间
1.数据库
create table account(
id int(10) primary key auto_increment comment '编号',
accon varchar(18) unique comment '转账账户',
password int(6) comment '密码',
balance double comment '金额',
name varchar(20) comment '收款人姓名'
) comment '银行转账系统';
insert into account values(default,'1','2',1000,'代红1');
insert into account values(default,'3','4',3000,'代红2');
insert into account values(default,'5','6',2000,'代红3');
2.搭建mybatis环境
- 导jar包
- 放入全局配置文件
创建两个resource=""。其中填写AccountMapper.xml,LogMapper.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">
<!-- DTD:xml的语法检查器,限制写什么 -->
<configuration>
<typeAliases>
<package name="com.youdian.pojo"/>
</typeAliases>
<!-- default 引用 environment 的 id,当前所使用的环境 -->
<environments default="default">
<!-- 声明可以使用的环境 -->
<environment id="default">
<!-- 使用原生 JDBC 事务 -->
<transactionManager type="JDBC">
</transactionManager>
<!-- 数据库连接池 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/sum"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/youdian/mapper/AccountMapper.xml"/>
<mapper resource="com/youdian/mapper/LogMapper.xml"/>
</mappers>
</configuration>
3.开始建立项目
- 新建一个包package com.youdian.pojo;建立Account.java的实体类。
public class Account {
private int id;
private String accNo;
private int password;
private String name;
private double balance;
}
生成get(),set()方法
- 数据访问层mapper,新建一个包package com.youdian.mapper,建立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="com.youdian.mapper.AccountMapper">
<!-- 根据帐号和密码查询账户信息 -->
<select id="selByAccnoPwd" resultType="account" parameterType="account">
select * from account where accno=#{accNo} and password=#{password}
</select>
<!-- 根据帐号和姓名查询账户信息 -->
<select id="selByAccnoName" resultType="account" parameterType="account">
select * from account where accno=#{accNo} and name=#{name}
</select>
<!-- 根据accNo修改账户余额 -->
<update id="updBalanceByAccno" parameterType="account">
update account set balance=balance+#{balance} where accno=#{accNo}
</update>
</mapper>
- 创建service层
首先创建接口AccountService.java
/**
* 转账
* 传入两个参数,一个收款账户,一个转账账户
*
*/
public interface AccountService {
/**
* 帐号和密码不匹配状态码
*/
int ACCOUNT_PASSWORD_NOT_MATCH=1;
/**
* 余额不足
*/
int ACCOUNT_BALANCE_NOT_ENOUGH=2;
/**
* 账户姓名不匹配
*/
int ACCOUNT_NAME_NOT_MATCH=3;
/**
* 转账失败
*/
int ERROR=4;
/**
* 转账成功
*/
int SUCCESS=5;
int transfer(Account accIn,Account accOut) throws IOException;
}
再创建实体类AccountServiceImpl.java:
记录日志,新建日志表
public class AccountServiceImpl implements AccountService {
public int transfer(Account accIn, Account accOut) throws IOException {
InputStream is = Resources.getResourceAsStream("mybatis.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
SqlSession session = factory.openSession();
//先判断帐号和密码是否匹配
Account accOutSelect = session.selectOne("com.youdian.mapper.AccountMapper.selByAccnoPwd",accOut);
if(accOutSelect!=null){
if(accOutSelect.getBalance()>=accOut.getBalance()){
Account accInSelect = session.selectOne("com.youdian.mapper.AccountMapper.selByAccnoName",accIn);
if(accInSelect!=null){
accIn.setBalance(accOut.getBalance());
accOut.setBalance(-accOut.getBalance());
int index = session.update("com.youdian.mapper.AccountMapper.updBalanceByAccno",accOut);
index += session.update("com.youdian.mapper.AccountMapper.updBalanceByAccno",accIn);
if(index==2){
//日志表记录
Log log = new Log();
log.setAccIn(accIn.getAccNo());
log.setAccOut(accOut.getAccNo());
log.setMoney(accIn.getBalance());
session.insert("com.youdian.mapper.LogMapper.insLog",log);
//日志文件记录
Logger logger = Logger.getLogger(AccountServiceImpl.class);
logger.info(log.getAccOut()+"给"+log.getAccIn()+"在"+new Date().toLocaleString()+"转了"+log.getMoney());
session.commit();
session.close();
return SUCCESS;
}else{
session.rollback();
session.close();
return ERROR;
}
}else{
return ACCOUNT_NAME_NOT_MATCH;
}
}else{
//余额不足
return ACCOUNT_BALANCE_NOT_ENOUGH;
}
}else{
//帐号和密码不匹配
return ACCOUNT_PASSWORD_NOT_MATCH;
}
}
}
- 创建servlet层
@WebServlet("/transfer")
public class TransferServlet extends HttpServlet{
private AccountService accService = new AccountServiceImpl();
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
Account accOut = new Account();
accOut.setAccNo(req.getParameter("accOutAccNo"));
accOut.setPassword(Integer.parseInt(req.getParameter("accOutPassword")));
accOut.setBalance(Double.parseDouble(req.getParameter("accOutBalance")));
Account accIn =new Account();
accIn.setAccNo(req.getParameter("accInAccNo"));
accIn.setName(req.getParameter("accInName"));
int index = accService.transfer(accIn, accOut);
if(index==AccountService.SUCCESS){
resp.sendRedirect("/bank/index.jsp");
}else{
HttpSession session = req.getSession();
session.setAttribute("code", index);
resp.sendRedirect("/bank/error.jsp");
}
}
}
跳转的页面index.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="transfer" method="post">
转账账户:<input type="text" name="accOutAccNo"/><br/>
密码:<input type="password" name="accOutPassword"/><br/>
金额:<input type="text" name="accOutBalance"/><br/>
收款帐号:<input type="text" name="accInAccNo"/><br/>
收款姓名:<input type="text" name="accInName"/><br/>
<input type="submit" value="转账"/>
</form>
</body>
</html>
跳转的页面error.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
对不起操作失败:<br/>
错误原因:
${sessionScope.code}
</body>
</html>
4.加入日志功能
- 新创建一个log表进行获取日志
create table log(
id int(10) primary key auto_increment,
account varchar(18),
accin varchar(18),
money double
);
- 再com.youdian.pojo包中新建一个类Log.java
加入set()和get()方法:
public class Log {
private int id;
private String accIn;
private String accOut;
private double money;
}
- 再主页面进行转账成功相当于新增功能:
在com.youdian.mapper包下新建LogMapper.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="com.youdian.mapper.LogMapper">
<insert id="insLog" parameterType="log">
insert into log values(default,#{accOut},#{accIn},#{money})
</insert>
<select id="selByPage" parameterType="map" resultType="log">
select * from log limit #{pageStart},#{pageSize}
</select>
<select id="selCount" resultType="long">
select count(*) from log
</select>
</mapper>
- 分页查询
在com.youdian.pojo包下建立PageInfo.java进行分页查询的对象包装
加入set()和get()方法
public class PageInfo {
private int pageSize;
private int pageNumber;
private long total;
private List<?> list;
在com.youdian.service包下建立LogService.java进行返回showPage分页显示
public interface LogService {
/**
* @param pageSize
* @param pageNumber
*/
PageInfo showPage(int pageSize,int pageNumber) throws IOException;
}
在com.youdian.service.impl包下建立实体类:
public class LogServiceImpl implements LogService {
public PageInfo showPage(int pageSize, int pageNumber) throws IOException {
InputStream is = Resources.getResourceAsStream("mybatis.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
SqlSession session = factory.openSession();
Map<String,Object> param = new HashMap<>();
param.put("pageStart",pageSize*(pageNumber-1));
param.put("pageSize", pageSize);
List<Log> list = session.selectList("com.youdian.mapper.LogMapper.selByPage",param);
long count = session.selectOne("com.youdian.mapper.LogMapper.selCount");
PageInfo pi = new PageInfo();
pi.setList(list);
pi.setPageNumber(pageNumber);
pi.setPageSize(pageSize);
pi.setTotal(count%pageSize==0?count/pageSize:count/pageSize+1);
return pi;
}
}
mapper下的LogMapper.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="com.youdian.mapper.LogMapper">
<insert id="insLog" parameterType="log">
insert into log values(default,#{accOut},#{accIn},#{money})
</insert>
<select id="selByPage" parameterType="map" resultType="log">
select * from log limit #{pageStart},#{pageSize}
</select>
<select id="selCount" resultType="long">
select count(*) from log
</select>
</mapper>
- 处理servlet中的页面跳转请求:
@WebServlet("/show")
public class ShowServlet extends HttpServlet {
private LogService logService = new LogServiceImpl();
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
int pageSize = 2;
String pageSizeStr = req.getParameter("pageSize");
if(pageSizeStr!=null&&!pageSizeStr.equals("")){
pageSize = Integer.parseInt(pageSizeStr);
}
int pageNumber = 1;
String pageNumberStr = req.getParameter("pageNumber");
if(pageNumberStr!=null&&!pageNumberStr.equals("")){
pageNumber = Integer.parseInt(pageNumberStr);
}
req.setAttribute("pageinfo", logService.showPage(pageSize, pageNumber));
req.getRequestDispatcher("/log.jsp").forward(req, resp);
}
}
- 写出跳转的页面log.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<table border="1">
<tr>
<th>转账帐号</th>
<th>收款帐号</th>
<th>转账金额</th>
</tr>
<c:forEach items="${pageinfo.list}" var="log">
<tr>
<td>${log.accOut }</td>
<td>${log.accIn }</td>
<td>${log.money }</td>
</tr>
</c:forEach>
</table>
<a href="show?pageSize=${pageinfo.pageSize }&pageNumber=${pageinfo.pageNumber-1}" <c:if test="${pageinfo.pageNumber<=1 }"> οnclick="javascript:return false;"</c:if>>上一页</a>
<a href="show?pageSize=${pageinfo.pageSize }&pageNumber=${pageinfo.pageNumber+1}" <c:if test="${pageinfo.pageNumber>=pageinfo.total }"> οnclick="javascript:return false;"</c:if>>下一页</a>
</body>
</html>
- 把TransferServlet.java中成功转账的跳转页面换成show页面