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

Spring Boot MVC如何编程生成实体对应的eTag值?

实现方案

核心原理

ShallowEtagHeaderFilter生成eTag的逻辑非常简单:将响应体的字节数组计算MD5值,最终拼接为W/"[32位MD5十六进制字符串]"格式的弱eTag返回。你只需要在控制器中复现相同的计算逻辑,就能得到和过滤器生成的完全一致的eTag值做校验。

实现步骤

1. 编写eTag生成工具类

直接复用ShallowEtagHeaderFilter的原生计算逻辑,编写工具类:

import org.springframework.util.DigestUtils;

public class ETagGenerator {
    public static String generateShallowETag(byte[] contentBytes) {
        String md5 = DigestUtils.md5DigestAsHex(contentBytes);
        return "W/\"" + md5 + "\"";
    }
}

2. 改造控制器方法

按如下逻辑修改你的控制器,完成eTag校验:

// 注入Spring容器自带的ObjectMapper,保证序列化规则和接口返回一致
@Autowired
private ObjectMapper objectMapper;

@RequestMapping(method = POST, value = "/assignments/{id}/edit")
public @ResponseBody
ResponseEntity<?> editStaffAssignment(@RequestBody Resource<AssignmentDTO> dtoResource,
                                      @PathVariable Long id,
                                      PersistentEntityResourceAssembler resourceAssembler, 
                                      Pageable pageable,
                                      // 新增WebRequest参数,也可以直接从HttpServletRequest拿请求头
                                      WebRequest webRequest) throws JsonProcessingException {
    // 第一步:先查询数据库中当前最新的实体
    Assignment currentAssignment = assignHandler.findById(id);
    if (currentAssignment == null) {
        return new ResponseEntity<>(HttpStatus.NOT_FOUND);
    }
    // 第二步:生成当前实体对应的eTag
    Resource<?> currentResource = resourceAssembler.toResource(currentAssignment);
    byte[] contentBytes = objectMapper.writeValueAsBytes(currentResource);
    String currentETag = ETagGenerator.generateShallowETag(contentBytes);
    // 第三步:校验eTag是否匹配,Spring自带方法会自动处理If-Match请求头对比
    if (webRequest.checkNotModified(currentETag)) {
        // 不匹配直接返回412前置条件失败
        return new ResponseEntity<>(HttpStatus.PRECONDITION_FAILED);
    }
    // 第四步:校验通过才执行更新操作
    Assignment assignment = assignHandler.updateAssignment(dtoResource.getContent(), id);
    return new ResponseEntity<>(resourceAssembler.toResource(assignment), HttpStatus.OK);
}

注意事项

  • 必须使用Spring容器中配置的ObjectMapper做序列化,不能自己new新的实例,否则序列化规则(比如日期格式、空字段处理、字段顺序)不一致会导致eTag匹配失败
  • 客户端请求时需要将eTag放到If-Match请求头中,不要放到其他自定义头里,webRequest.checkNotModified会自动读取该头
  • 条件更新更推荐使用PUT HTTP方法,更符合REST规范,不影响现有逻辑可以直接替换

内容的提问来源于stack exchange,提问作者Charlie

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 19:27:02