这里以一个转账的例子原型开启手写IOC和AOP过程。
原型代码是按三层架构模型来写的,controller层采用的是servlet,dao层采用jdbc来实现的,此代码中只是简单的模拟了转账的过程,中间存在的问题点,在后面会去分析以及改进。
代码结构如下:
前台页面:
在页面中对账户信息给定了默认值,对应数据库中的账户信息,我们可以自定义转账的金额。
采用ajax指定发送url地址和发送的数据,返回结果采用json格式进行接收并根据返回的结果码信息以弹出框的形式给出转账结果的提示。
<script type="text/javascript">
$(function(){
$(".submitBtn").bind("click",function(){
var fromAccount = $("#fromAccount").val();
var toAccount = $("#toAccount").val();
var money = $("#money").val();
if(money == null || $.trim(money).length == 0){
alert("sorry,必须输入转账金额~");
return;
}
$.ajax({
url:'/transferServlet',
type:'POST', //GET
async:false, //或false,是否异步
data:{
fromCardId:fromAccount.split(' ')[1],
toCardId:toAccount.split(' ')[1],
money:money
},
timeout:5000, //超时时间
dataType:'json', //返回的数据格式:json/xml/html/script/jsonp/text
success:function(data){
if("200" == data.status){
alert("转账成功~~~");
}else{
alert("转账失败~~~,message:" + data.message);
}
}
})
})
})
//检查输入值是否为整数
function checkFormat(obj){
var reg = /^[0-9]+[0-9]*]*$/;
if($.trim($(obj).val()).length>0){
if(!reg.test($(obj).val())){
alert("输入格式错误!请输整数!");
$(obj).val("");
}else{
$(obj).val(parseInt($(obj).val()));
}
}
}
</script>
controller层:
在@WebServlet注解指定消息的接收url,在doPost方法中,获取请求参数,调用业务层方法,返回json数据。
@WebServlet(name="transferServlet",urlPatterns = "/transferServlet")
public class TransferServlet extends HttpServlet {
private TransferService transferService = new TransferServiceImpl();
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 设置请求体的字符编码
req.setCharacterEncoding("UTF-8");
String fromCardId = req.getParameter("fromCardId");
String toCardId = req.getParameter("toCardId");
String moneyStr = req.getParameter("money");
int money = Integer.parseInt(moneyStr);
Result result = new Result();
try {
// 调用service层方法
transferService.transfer(fromCardId,toCardId,money);
result.setStatus("200");
} catch (Exception e) {
e.printStackTrace();
result.setStatus("300");
result.setMessage(e.toString());
}
// 响应
resp.setContentType("application/json;charset=utf-8");
resp.getWriter().print(JsonUtils.object2Json(result));
}
}
json工具类:采用jackson实现
/**
* JSON工具类(使用的jackson实现)
*/
public class JsonUtils {
private static final ObjectMapper MAPPER = new ObjectMapper();
/**
* 将对象转化成json格式
*
* @param obj 被转化的对象
*/
public static String object2Json(Object obj) {
try {
String value = MAPPER.writeValueAsString(obj);
return value;
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
}
/**
* 将json数据转换成对应的对象
*
* @param jsonData json数据
* @param beanType 对象的class类型
* @param <T> 返回转换后的对象
* @return
*/
public static <T> T json2Object(String jsonData, Class<T> beanType) {
try {
return MAPPER.readValue(jsonData, beanType);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
/**
* 将json数据转换成集合
* @param jsonData json数据
* @param beanType 集合中对象的class类型
* @param <T>
* @return
*/
public static <T> List<T> json2List(String jsonData, Class<T> beanType) {
JavaType javaType = MAPPER.getTypeFactory().constructParametricType(List.class, beanType);
try {
return MAPPER.readValue(jsonData, javaType);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
service层:进行转账业务的处理
public interface TransferService {
/**
* 转账的方法
* @param fromCardId 转出账户账号
* @param toCardId 转入账户账号
* @param money 转账金额
* @throws Exception
*/
void transfer(String fromCardId, String toCardId, int money) throws Exception;
}
public class TransferServiceImpl implements TransferService {
private AccountDao accountDao = new AccountDaoImpl();
@Override
public void transfer(String fromCardId, String toCardId, int money) throws Exception {
Account fromAcctInfo = accountDao.queryAcctByCardId(fromCardId);
Account toAcctInfo = accountDao.queryAcctByCardId(toCardId);
fromAcctInfo.setMoney(fromAcctInfo.getMoney() - money);
toAcctInfo.setMoney(toAcctInfo.getMoney() + money);
accountDao.updateAcctByCardId(fromAcctInfo);
accountDao.updateAcctByCardId(toAcctInfo);
}
}
dao层:采用JDBC进行实现,数据源采用阿里的Druid(德鲁伊)
public interface AccountDao {
/**
* 通过账户id查询对应账户信息
* @param cardId 账户id
*/
Account queryAcctByCardId(String cardId) throws Exception;
/**
* 更新账户信息
* @param account 待更新的账户信息
*/
int updateAcctByCardId(Account account) throws Exception;
}
public class AccountDaoImpl implements AccountDao {
@Override
public Account queryAcctByCardId(String cardId) throws Exception {
//使用阿里druid连接池,获取连接
Connection connection = DruidUtils.getInstance().getConnection();
String sql = "select * from account where cardId = ?";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(1,cardId);
ResultSet resultSet = preparedStatement.executeQuery();
Account account = new Account();
while (resultSet.next()){
account.setName(resultSet.getString("cardId"));
account.setMoney(resultSet.getInt("money"));
account.setCardId(resultSet.getString("cardId"));
}
//关闭连接,归还连接到连接池
resultSet.close();
preparedStatement.close();
connection.close();
return account;
}
@Override
public int updateAcctByCardId(Account account) throws Exception {
//使用阿里druid连接池,获取连接
Connection connection = DruidUtils.getInstance().getConnection();
String sql = "update account set money = ? where cardId = ?";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
preparedStatement.setInt(1,account.getMoney());
preparedStatement.setString(2,account.getCardId());
int result = preparedStatement.executeUpdate();
//关闭连接,归还连接到连接池
preparedStatement.close();
connection.close();
return result;
}
}
pojo:
账户对象:
public class Account {
private String cardId;
private String name;
private int money;
public String getCardId() {
return cardId;
}
public void setCardId(String cardId) {
this.cardId = cardId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
@Override
public String toString() {
return "Account{" +
"cardId='" + cardId + '\'' +
", name='" + name + '\'' +
", money=" + money +
'}';
}
}
结果对象:用于对处理结果的封装。
public class Result {
private String status;
private String message;
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
@Override
public String toString() {
return "Result{" +
"status='" + status + '\'' +
", message='" + message + '\'' +
'}';
}
}
Druid数据源工具类:配置连接数据库的相关参数,相关参数可以写到配置文件中,然后从配置文件中进行读取,这里没做过多处理
public class DruidUtils {
private DruidUtils() {
}
private static DruidDataSource druidDataSource = new DruidDataSource();
static {
druidDataSource.setDriverClassName("com.mysql.jdbc.Driver");
druidDataSource.setUrl("jdbc:mysql://localhost:3306/bank?characterEncoding=utf8&useSSL=false&serverTimezone=UTC");
druidDataSource.setUsername("root");
druidDataSource.setPassword("root");
druidDataSource.setInitialSize(5);
druidDataSource.setMaxActive(10);
druidDataSource.setMaxWait(3000);
}
public static DruidDataSource getInstance() {
return druidDataSource;
}
}
sql建表:就三个字段,名称、账户Id、账户余额。如果真正涉及设计账户相关表的话,账户表应该只包含账户相关的一些标识以及账户的基本信息,比如账户类型、账户状态、付费类型等,账户金额应该设计一个专门的账户余额表进行存储。
CREATE TABLE `account` (
`name` varchar(30) DEFAULT NULL,
`cardId` varchar(255) DEFAULT NULL,
`money` int DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
代码SSH:
git@gitee.com:Max-cole/spring-learn.git