在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 問答/Java  HTML/ Springboot如何優(yōu)雅地實現(xiàn)更新Model

Springboot如何優(yōu)雅地實現(xiàn)更新Model

更新Model目前我有兩種方式,但是感覺都不是很好:

方式一:

現(xiàn)有一個SpringBoot的WebApi項目,通過前端發(fā)起http請求來進行Model更新。
比如,要更新一個id為1的User{id,name,age,nickName}實體,我從前端只傳了這樣一個User實體json來更新nickName:{id:1,nickName:'young'},在后端接收到這樣一個實體后我是這樣更新的:

var user=userService.getById(model.id);
if(model.name!=null){
    user.name=model.name;
}
if(model.age!=null){
    user.age=model.age;
}
if(model.nickName!=null){
    user.nickName=model.nickName;
}
userService.update(user);
  • 缺點:從上面的例子中,顯而易見,這種編碼方式太糟糕了。如果User類有100個屬性,我就要if判斷100次!

方式二:

Mybatis中通過Generator工具可以生成一個updateBySelective()的方法,可以自動根據(jù)傳入的模型的值來自行完成這樣一個操作。
比如,如果你傳入的實體中含有nickName屬性,則自動幫你更新,否則不更新。這一切的操作都只需要你優(yōu)雅地調(diào)用方法就行了:

userService.update(model);

但是這樣的方法也會存在一個問題:
如果我的業(yè)務(wù)邏輯不允許修改age,但是當前端傳入了age后就肯定會自動更新這個age,如果我要限制更新age,就只能這么寫:

if(model.age!=null){
    model.age=null;
}
userService.update(model);

這樣的代碼也會顯得丑陋無比……

  • 缺點:如果某些屬性不允許更細的話,也需要不停加入if語句。

問題:

有沒有更好的方式,可以解決上面兩種方法的缺點,實現(xiàn)優(yōu)雅地更新Model?

回答
編輯回答
維他命

像1樓一樣,前后端傳值一般是定義一個Dto對象。使用hibernate-validation對Dto參數(shù)進行校驗,BeanUtils.copyProperties()方法進行屬性值替換。

2017年12月31日 18:43
編輯回答
吢丕

前端接收參數(shù)使用 Payload 而不是實體:

@Data
class UserPaylaod {
    private String id;
    private String nickName;
    
    public User toUser() {
        // 將 Payload 轉(zhuǎn)換為所需實體。
        // 這里進行一系列檢查,包括但不限于:
        // id 對應(yīng)實體是否存在
        // 參數(shù)是否符合要求
    }
}

好處是能強制忽略掉那些可能被惡意攜帶的額外參數(shù)。

至于對數(shù)據(jù)的校驗問題,要么使用 Spring Boot 集成的 hibernate-validation,要么手寫判斷代碼(也可以配合自定義注解完成一些常見的非空判斷)。

我的流程一般是:

Payload 包含一個實體在多個場景(包括但不限于增刪查改)下所需的字段,接收參數(shù)后調(diào)用 toModel 方法進行校驗并轉(zhuǎn)換為所需實體。

// CommonFields 是一些共有的字段,比如 id 啦之類的
@Data
public class UserPayload extends CommonFields implements ModelTransfer<User, Scene> {

   public enum Scene {
       Register, Login;
   }

   @NotBlank
   @Size(min = 5, max = 10)
   @Scene({Register, Login})
   // 標記這個字段在指定的場景中被要求存在(不存在則拋異常),否則忽略其值(從 JSON 反序列化后置字段空)
   private String nickName;

   @Override
   public User toModel(Scene scene) {
     // getBean 是我注入了 ApplicationContext 以方便校驗時需要用到外部 service 之類的東西
     UserService userService = getBean(UserService.class);
     User user;
     switch (scene) {
         case Register:
             // TODO ...
             break;
         case Login:
             user = userService.findById(this.id);
             // 由于我搞了異常監(jiān)聽器,下面的情況我會直接拋異常截斷流程
             Assert.notNull(user, "用戶不存在!");
             // TODO ...
             // 此時不需要更新 nickName 則不 user.setNickName(nickName);
             // 其他場景需要時則調(diào)用,且由于工具的處理,不用擔心此時 nickName 為空
             break;
         default:
             throw new IllegalSceneException("未知場景!");        
     }
     return user;
   }
}

@PostMapping("/user")
public ResponseData<User> register(@RequestBody userPayload) {
    User user = userPaylaod.toModel(Scene.Register);
    // TODO...
}

對于能用反射檢查的就在 toModel 之前檢查了(我寫了個自定義參數(shù)處理器,因為有時要注入一些 session 屬性值,同時會產(chǎn)生 payload 代理實例以方便我做其他處理),剩下的那些不同場景要求不一樣的則手寫校驗規(guī)則了。

下一步打算支持特定場景的校驗,比如: @Validate(scenes = { @SceneValidate( scene = Register, type = Validator.NotBlank, message = "不能為空!")}) 一類的寫法。 (懶癌患者小聲 bb)

上面的例子里,通過 hibernate-validation 和一些自己寫的小工具解決你的第一個方法的問題,通過 payload 概念解決你的第二個方法的問題。

總的來說,這個事情框架能做到的有限,畢竟要考慮通用性,那么只好你自己定制一些小工具來做這些事了。

2018年4月21日 08:22
編輯回答
薄荷綠

實體類有注解的,了解一下?比如@NotNull(message = "收貨人地址id不能為空")

2018年5月30日 13:42