1、需求场景
太极平台自身的框架,已经封装了增删改的操作。不需要修改任何配置项,每个组件就会自动完成增删改的功能。
但是如果我们的增删改操作,不仅仅只是想要完成单表单条数据的操作,而是要实现复杂的逻辑呢?
比如添加成本支出记录时,要同步修改总支出数据(也可以通过数据库的触发器实现,参见章节:使用触发器完成关联数据的更新);
删除订单数据时,要同步删除该条订单关联的支出记录(也可以通过数据库设置外键关联来自动完成,参见章节:使用外键完成关联数据的自动删除)。
上述2个需求有其他简单的解决方案(括号内的方案),仅作为抛砖引玉。如果我们在添加数据时,还需要进行多个业务逻辑的计算,还要请求第三方的服务进行验证,那这个需求仅仅通过太极平台自带的保存功能,就无法实现了。必须要单独编写业务逻辑代码去完成。
下面介绍如何实现。
2、实现过程
为简单示例,我们就去实现上面的2个需求。
先说明一下数据库表结构,2张表:订单表、订单支出表。我们直接引用触发器章节的表结构。
1)订单表(qd_order)
2)订单支出表(qd_order_cost)
3)表关系的E-R图,如下图所示。
1)添加支出记录时,更新订单表的总支出金额。
1.1、太极平台后台设置
太极平台自带的添加功能,只会插入一条支出记录。为了实现同步更新订单总支出金额,我们需要指定添加表单的action地址,指向到我们自己的业务处理地址。此时表单数据就会提交到新的action地址去。
如下图所示,在太极平台管理后台→组件管理→选择成本支出条目→编辑组件→添加表单设置→保存添加数据action,指向到:order.do?action=addcost
修改了action,变更了后端处理;前端我们还是可以借用框架生成的添加页面,不用再去独立编写添加页面。能省一点就省一点嘛。
在浏览器端,我们按F12在调试界面,可以看到添加表单数据提交的action,已经是我们自己设置的地址了。
1.2、项目编码
- 在servlet包中,新建一个OrderServlet,用于接收订单数据请求,指定urlPatterns为order.do。
- 在dao包中,建立OrderDao用于处理数据库连接和操作。
- 在entity包中,建立OrderCost实体类,映射订单支出记录。
如下图所示,是建立好文件后的项目结构图。
1.2.1、OrderServlet的业务处理
主要处理逻辑:接收数据,验证数据,保存数据,返回结果。
返回结果调用ExceptionUtil类里面的printlnSuccess和printlnFailure方法,分别返回成功和失败的json格式到前端,前端会进行相应的提示。如下图所示。
提交的数据,通过调试窗口也可以看到,如下图所示。
因此后端只需要进行相应的数据处理即可。代码如下。
package tech.qidian.servlet;
import tech.qidian.dao.OrderDao;
import tech.qidian.dev.admincommon.entity.TaiJiUser;
import tech.qidian.dev.webcommon.util.ExceptionUtil;
import tech.qidian.dev.webcommon.util.StringUtil;
import tech.qidian.entity.OrderCost;
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.sql.SQLException;
@WebServlet(name = "OrderServlet", description = "处理订单相关请求", urlPatterns = {"/order.do"})
public class OrderServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String action = request.getParameter("action");
if (action == null) {
action = "";
}
switch (action) {
//添加支出记录
case "addcost":
saveAddOrderCost(request, response);
break;
}
}
//处理添加支出记录
private void saveAddOrderCost(HttpServletRequest request, HttpServletResponse response) throws IOException {
//验证订单ID正确
int orderId = StringUtil.convertToInt(request.getParameter("OrderId"));
if (orderId <= 0) {
ExceptionUtil.printlnFailure(response, "订单id参数错误");
return;
}
//验证支出名称必填。太极框架自带的必填项选项,会自动验证。
String costName = request.getParameter("CostName");
if (StringUtil.isEmpty(costName)) {
ExceptionUtil.printlnFailure(response, "支出名称必填");
return;
}
//验证支出金额大于0
float costMoney = StringUtil.convertToFloat(request.getParameter("CostMoney"));
if (Float.compare(costMoney, 0.0f) <= 0) {
ExceptionUtil.printlnFailure(response, "支出金额必填,且大于0");
return;
}
OrderCost orderCost = new OrderCost();
orderCost.setOrderId(orderId);
orderCost.setCostName(costName);
orderCost.setCostType(request.getParameter("CostType"));
orderCost.setCostMoney(costMoney);
orderCost.setCostDate(StringUtil.convertToDate(request.getParameter("CostDate")));
//从session中获取昵称。
//定义了TaiJiUser.SESSION_NICKNAME="nickname"。getAttribute有可能为null,因此需要判断转换一下。
orderCost.setNickName(StringUtil.convertObjToString(request.getSession().getAttribute(TaiJiUser.SESSION_NICKNAME)));
OrderDao dao = new OrderDao();
try {
int rowId = dao.insertOrderCost(orderCost);
//返回id小于等于0,则添加失败。
if (rowId <= 0) {
ExceptionUtil.printlnFailure(response, "支出记录添加失败");
return;
}
} catch (SQLException e) {
e.printStackTrace();
//异常,进行异常日志记录。
ExceptionUtil.insertDB(e, "支出记录添加异常");
//返回异常给前端显示
ExceptionUtil.printlnFailure(response, "支出记录添加异常");
return;
}
ExceptionUtil.printlnSuccess(response, "支出记录添加成功");
}
}
1.2.2、订单支出实体类OrderCost,比较简单。
package tech.qidian.entity;
import java.util.Date;
public class OrderCost {
private int id;
private int orderId;
private String costName;
private String costType;
private float costMoney;
private Date costDate;
private String nickName;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getOrderId() {
return orderId;
}
public void setOrderId(int orderId) {
this.orderId = orderId;
}
public String getCostName() {
return costName;
}
public void setCostName(String costName) {
this.costName = costName;
}
public String getCostType() {
return costType;
}
public void setCostType(String costType) {
this.costType = costType;
}
public float getCostMoney() {
return costMoney;
}
public void setCostMoney(float costMoney) {
this.costMoney = costMoney;
}
public Date getCostDate() {
return costDate;
}
public void setCostDate(Date costDate) {
this.costDate = costDate;
}
public String getNickName() {
return nickName;
}
public void setNickName(String nickName) {
this.nickName = nickName;
}
}
1.2.3、OrderDao数据库处理类
这里用到了事务处理,调用DbManager类的executeTransaction方法。多条SQL语句,在二维数组中,分别指定参数。
package tech.qidian.dao;
import tech.qidian.dev.webcommon.util.DbManager;
import tech.qidian.entity.OrderCost;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
public class OrderDao {
//插入新的支出记录
public int insertOrderCost(OrderCost orderCost) throws SQLException {
if (orderCost == null) {
return 0;
}
//因为要同步处理添加和更新,所以需要使用事务进行操作
List<String> listSql = new ArrayList<>();
//添加新的支出记录
listSql.add("insert into qd_order_cost(OrderId,CostName,CostType,CostMoney,CostDate,NickName) values(?,?,?,?,?,?)");
//更新订单表的总支出金额
listSql.add("update qd_order set TotalCost=(select sum(CostMoney) from qd_order_cost where OrderId=?) where Id=?");
//各条语句对应的参数。一个二维数组参数。
Object[][] params = {
{orderCost.getOrderId(), orderCost.getCostName(), orderCost.getCostType(),
orderCost.getCostMoney(), orderCost.getCostDate(), orderCost.getNickName()},
{orderCost.getOrderId(), orderCost.getOrderId()}
};
//执行事务
int[] rows = DbManager.executeTransaction(listSql, params);
//事务批量执行影响的总行数求和
return DbManager.sumIntArray(rows);
}
}
最后执行添加,在数据库中看已经成功保存,并且同步更新了总支出金额。功能成功实现。
2)修改支出,删除支出处理
有了上面的案例,同样的思路去处理编辑和删除。在组件设置中,指定编辑和删除的action地址。之后,在servlet中处理action分支响应,主要逻辑结构如下。
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String action = request.getParameter("action");
if (action == null) {
action = "";
}
switch (action) {
//添加支出记录
case "addcost":
saveAddOrderCost(request, response);
break;
//编辑支出记录
case "editCost":
break;
//删除支出记录
case "deleteCost":
break;
}
}
3、总结
从上面的案例中可以看出,哪怕是自己单独去处理一个很简单业务逻辑,也需要编写三层业务架构。所以我们能不编码,就尽量不要去编码。这也是开发太极平台框架的初衷,减少编码量,利用配置项去实现。稳定、快速。
同时,我们也可以充分MySQL的触发器、外键、索引等特性,辅助实现功能。