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
相关产品推荐
相关产品推荐

