2.3.太极平台:使用自定义表单的action来独立处理增删改操作

it2022-05-05  131

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的触发器、外键、索引等特性,辅助实现功能。


最新回复(0)