TL; DR
patchy
是我想出的一个很小的库,它照顾了
PATCH在Spring中正确处理所需的主要样板代码,即:
class Request : PatchyRequest { @get:NotBlank val name:String? by { _changes } override var _changes = mapOf<String,Any?>()}@RestControllerclass PatchingCtrl { @RequestMapping("/", method = arrayOf(RequestMethod.PATCH)) fun update(@Valid request: Request){ request.applyChangesTo(entity) }}简单的解决方案
由于
PATCH请求表示要应用于资源的更改,因此我们需要对其进行显式建模。
一种方法是使用普通的旧版本
Map<String,Any?>,其中
key客户提交的每个字段都代表对资源相应属性的更改:
@RequestMapping("/entity/{id}", method = arrayOf(RequestMethod.PATCH))fun update(@RequestBody changes:Map<String,Any?>, @PathVariable id:Long) { val entity = db.find<Entity>(id) changes.forEach { entry -> when(entry.key){ "firstName" -> entity.firstName = entry.value?.toString() "lastName" -> entity.lastName = entry.value?.toString() } } db.save(entity)}上面的内容很容易遵循:
- 我们 没有验证 请求值
可以通过在域层对象上引入验证注释来缓解上述问题。尽管这在简单的场景中非常方便,但是一旦我们根据域对象的状态或执行更改的主体的角色引入条件验证,这往往是不切实际的。更重要的是,在产品使用了一段时间并引入了新的验证规则之后,很常见的是仍然允许在非用户编辑上下文中更新实体。在域层上强制不变量,但将验证保留在边缘似乎更为实用。
- 在许多地方可能非常相似
这实际上很容易解决,在80%的情况下,以下方法将起作用:
fun Map<String,Any?>.applyTo(entity:Any) { val entityEditor = BeanWrapperImpl(entity) forEach { entry -> if(entityEditor.isWritableProperty(entry.key)){ entityEditor.setPropertyValue(entry.key, entityEditor.convertForProperty(entry.value, entry.key)) } }}验证请求
感谢Kotlin中的委托属性,可以很容易地构建一个包装器
Map<String,Any?>:
class NameChangeRequest(val changes: Map<String, Any?> = mapOf()) { @get:NotBlank val firstName: String? by changes @get:NotBlank val lastName: String? by changes}使用
Validator接口,我们可以过滤出与请求中不存在的属性相关的错误,如下所示:
fun filterOutFieldErrorsNotPresentInTheRequest(target:Any, attributesFromRequest: Map<String, Any?>?, source: Errors): BeanPropertyBindingResult { val attributes = attributesFromRequest ?: emptyMap() return BeanPropertyBindingResult(target, source.objectName).apply { source.allErrors.forEach { e -> if (e is FieldError) { if (attributes.containsKey(e.field)) { addError(e) } } else { addError(e) } } }}显然,我们可以简化
HandlerMethodArgumentResolver我在下面所做的开发。
最简单的解决方案
我认为,这将是有意义搞什么名堂上述成一个简单易用的库来包装-看哪修修补补。使用 修补程序时,
可以具有强类型的请求输入模型以及声明性验证。您要做的就是导入配置
@import(PatchyConfiguration::class)并
PatchyRequest在模型中实现接口。
进一步阅读
- spring同步
- fge / json-patch



