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

如何通过Ajax POST请求从Spring ResponseEntity获取渲染后的Thymeleaf片段

如何通过Ajax POST请求从Spring ResponseEntity获取渲染后的Thymeleaf片段

我明白你现在的困扰——你想返回不同的HTTP状态码,同时让Thymeleaf渲染指定的提示片段作为响应体,但现在拿到的只是片段的表达式字符串,完全没被渲染。这是@ResponseBody的工作机制导致的,我来帮你一步步解决这个问题。

问题根源

你之前直接返回"fragments/components :: ajaxResponse"这类字符串,加上@ResponseBody注解后,Spring会把它原封不动地作为响应体返回,不会触发Thymeleaf的渲染流程。只有当你返回视图名称或者ModelAndView时,Spring才会自动调用模板引擎处理内容。所以核心解决方案是:手动调用Thymeleaf模板引擎渲染片段,再把渲染后的HTML作为响应体返回。


具体解决步骤

第一步:注入Thymeleaf的TemplateEngine

首先在你的Controller里注入TemplateEngine,它是Thymeleaf渲染模板的核心类:

@Autowired
private TemplateEngine templateEngine;

第二步:编写片段渲染工具方法

写一个辅助方法,把Controller的Model属性传递给Thymeleaf上下文,然后渲染指定的片段,返回最终的HTML字符串:

private String renderAjaxResponseFragment(Model model) {
    // 创建Thymeleaf上下文,用于传递模板变量
    Context thymeleafContext = new Context();
    // 把Controller Model中的所有属性复制到上下文
    model.asMap().forEach(thymeleafContext::setVariable);
    // 渲染指定的Thymeleaf片段,返回HTML字符串
    return templateEngine.process("fragments/components :: ajaxResponse", thymeleafContext);
}

第三步:修改Controller的返回逻辑

现在调整你的deleteMultipleMyObjects方法,不再返回片段表达式,而是返回渲染后的HTML。对于需要同时返回数据(比如已删除ID列表)的场景,我们可以创建一个简单的DTO来封装数据和HTML:

先创建DTO类(放在合适的包下)

public class DeleteMultipleResponse {
    private List<Long> deletedIds;
    private String htmlFragment;

    // 构造器
    public DeleteMultipleResponse(List<Long> deletedIds, String htmlFragment) {
        this.deletedIds = deletedIds;
        this.htmlFragment = htmlFragment;
    }

    // Getter方法(必须,否则JSON序列化会失败)
    public List<Long> getDeletedIds() {
        return deletedIds;
    }

    public String getHtmlFragment() {
        return htmlFragment;
    }
}

修改Controller方法

@PostMapping("/deleteMultipleMyObjects")
@ResponseBody
public ResponseEntity<Object> deleteMultipleMyObjects(Model model, @ModelAttribute("myObjectIds") String myObjectIds) {

    if (myObjectIds.length() == 0) {
        MessageHelper.addInfoAttribute(model, "objects.delete.none");
        // 渲染片段得到最终HTML
        String renderedHtml = renderAjaxResponseFragment(model);
        return ResponseEntity.badRequest().body(renderedHtml);
    }

    Pair<List<Long>, List<Long>> res = myObjectService.deleteMultipleMyObjects(myObjectIds);

    if (!res.getValue1().isEmpty()) {
        MessageHelper.addWarningAttribute(model, "objects.delete.warn", res.getValue1());
        String renderedHtml = renderAjaxResponseFragment(model);
        // 封装已删除ID和渲染后的HTML
        DeleteMultipleResponse response = new DeleteMultipleResponse(res.getValue0(), renderedHtml);
        return ResponseEntity.status(HttpStatus.PRECONDITION_FAILED).body(response);
    }

    MessageHelper.addSuccessAttribute(model, "objects.delete.ok");
    String renderedHtml = renderAjaxResponseFragment(model);
    return ResponseEntity.accepted().body(renderedHtml);
}

第四步:调整前端JavaScript逻辑

现在前端收到的要么是直接的HTML字符串,要么是包含deletedIds和htmlFragment的JSON对象,所以需要调整JS代码:

function deleteMultipleMyObjects() {
  let myObjectIds = getAllCheckedObjects();

  let fragment;
  $.post("deleteMultipleMyObjects", {myObjectIds: myObjectIds})
  .done(function (data, status, xhr){
    hideAllCheckedObjects();
    fragment = data; // 这里data已经是渲染好的HTML
  })
  .fail(function(xhr, status, error){
    if (xhr.responseJSON) {
      // 处理已删除的ID列表
      hideLinesWithId(xhr.responseJSON.deletedIds);
      // 拿到渲染好的HTML片段
      fragment = xhr.responseJSON.htmlFragment;
    } else {
      fragment = xhr.responseText;
    }
  })
  .always(function() {
    $("#alertDiv").empty(); // 清空容器,比text("")更干净
    $("#alertDiv").append(fragment); // 直接插入渲染好的HTML
  });
}

补充说明

这样调整后,无论是成功、空ID还是部分删除的场景,前端都会收到已经渲染好的Thymeleaf片段HTML,而不是片段表达式字符串。同时你也能保持不同的HTTP状态码,满足业务对响应状态的要求。

另外要确保你的Thymeleaf配置正确,TemplateEngine能正确找到fragments/components.html模板文件(通常放在src/main/resources/templates目录下)。

备注:内容来源于stack exchange,提问作者Orangeade

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 09:43:04