You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Spring+Thymeleaf实现可动态新增多行的配药表单批量提交功能

Spring + Thymeleaf 动态配药明细一次性提交实现方案

1 后端核心代码实现

1.1 实体类设计

// 配药明细实体类,对应dispense表
public class Dispense {
    private Long id;
    private Long consultationId; // 关联问诊单ID
    private String drugName; // 药品名称
    private String specification; // 药品规格
    private Integer dosage; // 用量
    private String usage; // 使用方法
    // 省略Getter、Setter、无参构造方法
}

// 问诊单主表单实体,用于接收前端提交的全量数据
public class ConsultationForm {
    private Long patientId;
    private String symptom;
    private String diagnosis;
    // 核心字段:存储所有动态新增的配药明细
    private List<Dispense> dispenseList = new ArrayList<>();
    // 省略Getter、Setter
}

1.2 控制器层逻辑

@Controller
@RequestMapping("/consultation")
public class ConsultationController {
    @Resource
    private ConsultationService consultationService;
    @Resource
    private DispenseService dispenseService;

    // 跳转问诊单录入页面
    @GetMapping("/form")
    public String showForm(Model model) {
        ConsultationForm form = new ConsultationForm();
        // 默认初始化一条空配药行,满足Thymeleaf集合绑定要求
        form.getDispenseList().add(new Dispense());
        model.addAttribute("consultationForm", form);
        return "consultation-form";
    }

    // 表单提交接口,实现批量插入配药数据
    @PostMapping("/submit")
    public String submitForm(@ModelAttribute ConsultationForm form, RedirectAttributes attr) {
        // 第一步:保存问诊单主数据,获取生成的问诊单ID
        Long consultationId = consultationService.saveMainInfo(form);
        // 第二步:为所有配药明细绑定关联的问诊单ID,过滤空行
        List<Dispense> validDispenseList = form.getDispenseList().stream()
                .filter(item -> StrUtil.isNotBlank(item.getDrugName()))
                .peek(item -> item.setConsultationId(consultationId))
                .collect(Collectors.toList());
        // 第三步:批量插入所有有效配药明细到dispense表
        dispenseService.batchInsert(validDispenseList);
        attr.addFlashAttribute("msg", "提交成功,共录入" + validDispenseList.size() + "条配药明细");
        return "redirect:/consultation/list";
    }
}

1.3 批量入库MyBatis实现

<!-- DispenseMapper.xml 批量插入语句 -->
<insert id="batchInsert" parameterType="java.util.List">
    INSERT INTO dispense (consultation_id, drug_name, specification, dosage, `usage`)
    VALUES
    <foreach collection="list" item="item" separator=",">
        (#{item.consultationId}, #{item.drugName}, #{item.specification}, #{item.dosage}, #{item.usage})
    </foreach>
</insert>

2 前端Thymeleaf页面实现

2.1 配药明细网格表单代码

<form th:action="@{/consultation/submit}" th:object="${consultationForm}" method="post" id="consultationForm">
    <!-- 省略问诊单其他字段:患者信息、主诉、诊断等 -->
    
    <h3>配药明细</h3>
    <table id="dispenseTable" class="table table-bordered">
        <thead>
            <tr>
                <th>药品名称</th>
                <th>规格</th>
                <th>剂量</th>
                <th>用法</th>
                <th>操作</th>
            </tr>
        </thead>
        <tbody>
            <!-- Thymeleaf索引绑定集合元素 -->
            <tr th:each="item, stat : *{dispenseList}">
                <td><input type="text" th:field="*{dispenseList[__${stat.index}__].drugName}" class="form-control"></td>
                <td><input type="text" th:field="*{dispenseList[__${stat.index}__].specification}" class="form-control"></td>
                <td><input type="number" th:field="*{dispenseList[__${stat.index}__].dosage}" class="form-control"></td>
                <td><input type="text" th:field="*{dispenseList[__${stat.index}__].usage}" class="form-control"></td>
                <td><button type="button" class="btn btn-danger delRowBtn">删除</button></td>
            </tr>
        </tbody>
    </table>
    <button type="button" id="addRowBtn" class="btn btn-primary mt-2">新增配药条目</button>
    <button type="submit" class="btn btn-success mt-2 ms-2">提交全部数据</button>
</form>

2.2 动态新增/删除行JS逻辑

// 新增配药行逻辑
document.getElementById('addRowBtn').addEventListener('click', () => {
    const tableBody = document.querySelector('#dispenseTable tbody');
    const rowCount = tableBody.querySelectorAll('tr').length;
    // 新行的name属性索引与当前行数保持一致,保证后端集合绑定正确
    const newRow = `
        <tr>
            <td><input type="text" name="dispenseList[${rowCount}].drugName" class="form-control"></td>
            <td><input type="text" name="dispenseList[${rowCount}].specification" class="form-control"></td>
            <td><input type="number" name="dispenseList[${rowCount}].dosage" class="form-control"></td>
            <td><input type="text" name="dispenseList[${rowCount}].usage" class="form-control"></td>
            <td><button type="button" class="btn btn-danger delRowBtn">删除</button></td>
        </tr>
    `;
    tableBody.insertAdjacentHTML('beforeend', newRow);
});

// 删除配药行逻辑,事件委托适配动态新增的行
document.querySelector('#dispenseTable tbody').addEventListener('click', (e) => {
    if (!e.target.classList.contains('delRowBtn')) return;
    // 删除当前行
    e.target.closest('tr').remove();
    // 重新计算所有行的索引,避免提交时集合绑定错位
    const allRows = document.querySelectorAll('#dispenseTable tbody tr');
    allRows.forEach((row, index) => {
        row.querySelectorAll('input').forEach(input => {
            const originName = input.getAttribute('name');
            if (originName) {
                const newName = originName.replace(/dispenseList\[\d+\]/, `dispenseList[${index}]`);
                input.setAttribute('name', newName);
            }
        });
    });
});

3 注意事项

  • 可在提交前增加表单校验,过滤未填写核心字段的空行,避免无效数据入库
  • 配药条目数量较多时,建议增加懒加载或分页逻辑,避免页面卡顿
  • 如需草稿保存能力,可增加临时存储接口定期缓存表单内容,无需提前写入正式配药表

内容的提问来源于stack exchange,提问作者hoosain.madhi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 05:51:00