從零開始實現放置游戲(七)——實現后台管理系統(5)參數校驗


  前面幾章實現了在RMS系統中進行數據的增刪查改以及通過Excel批量導入。但仍有遺留的問題,比如在新增或編輯時,怪物的生命值、護甲等數據我們可以輸入負值,這種數據是不合理且沒有意義的。本章我們就實現服務端對參數的校驗。

一、添加依賴項

  在rms模塊的pom.xml中,添加校驗組件的依賴項(注意:之前的組件我們都引用了最新版本。但因hibernate-validator的最新版本6.xx+中引用的el-api.jar有沖突,無法用maven插件啟動,所以這里使用5.1.1版本):

<!-- 參數校驗 -->
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>5.1.1.Final</version>
</dependency>

  這個組件本身提供了一些注解,@NotNull, @NotBlank, @Min等等,來對模型進行校驗,但錯誤提示不夠好,默認通用的錯誤提示無法明確知道是哪個字段報錯。如果為每個字段添加一個提示語,又非常繁瑣,所以我們這里稍加改動,在util模塊做一個通用的校驗工具包。

  在util模塊的pom.xml中添加依賴:

<dependency>
    <groupId>javax.validation</groupId>
    <artifactId>validation-api</artifactId>
    <version>2.0.1.Final</version>
    <scope>provided</scope>
</dependency>

二、添加自定義注解及提示信息

  以非空校驗為例,在util模塊中新建包com.idlewow.util.validation.annotaion,在此包下新建一個注解類NotBlank.java如下:

package com.idlewow.util.validation.annotation;


import com.idlewow.util.validation.validator.NotBlankValidator;

import javax.validation.Constraint;
import javax.validation.Payload;
import javax.validation.ReportAsSingleViolation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Documented
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@ReportAsSingleViolation
@Constraint(validatedBy = NotBlankValidator.class)
@NotNull
public @interface NotBlank {
    String field() default "";

    String message() default "{field.not.blank.message}";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};

    @Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @interface List {
        NotBlank[] value();
    }
}

  注解有了,還需要一個對應的檢驗器,新建包com.idlewow.util.validation.validator,並在此包下新建類NotBlankValidator如下:

package com.idlewow.util.validation.validator;

import com.idlewow.util.validation.annotation.NotBlank;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

public class NotBlankValidator implements ConstraintValidator<NotBlank, CharSequence> {
    public NotBlankValidator() {
    }

    public void initialize(NotBlank annotation) {
    }

    @Override
    public boolean isValid(CharSequence charSequence, ConstraintValidatorContext constraintValidatorContext) {
        if (charSequence == null) {
            return false;
        } else {
            return charSequence.toString().trim().length() > 0;
        }
    }
}

  另外,在對模型進行校驗時,不同場景下的需求不同。比如,在新增時,因為主鍵由數據庫自增,無需添加主鍵;編輯時,則必須指定主鍵ID,對其進行非空校驗。因此,我們在com.idlewow.util.validation包下在新建一個對校驗分組的類ValidateGroup:

package com.idlewow.util.validation;

import javax.validation.groups.Default;
import java.io.Serializable;

public class ValidateGroup implements Serializable {
    public interface Create extends Default {
    }

    public interface Update extends Default {

    }
}

  最后,我們在util模塊的resource資源目錄下添加提示信息的資源文件ValidationMessages.properties,

#common invalid message
field.not.blank.message={field}不能為空
field.not.null.message={field}不能為NULL
field.size.message={field}的長度應為{min}至{max}之間
field.min.message={field}不能小於{value}
field.max.message={field}不能大於{value}
field.range.message={field}的大小應為{min}至{max}之間
field.positive.message={field}必須是正數
field.negative.message={field}必須是負數

三、參數校驗注解的使用

  首先,我們需要在需要校驗的模型上加上注解,此處以怪物模型為例:

package com.idlewow.mob.model;

import com.idlewow.common.model.BaseModel;
import com.idlewow.util.validation.annotation.NotBlank;
import com.idlewow.util.validation.annotation.NotNull;
import com.idlewow.util.validation.annotation.Positive;
import lombok.Data;
import lombok.EqualsAndHashCode;

import java.io.Serializable;

@Data
@EqualsAndHashCode(callSuper = true)
public class MapMob extends BaseModel implements Serializable {
    @NotBlank(field = "主鍵id", groups = ValidateGroup.Update.class)
    private String id;
    @NotBlank(field = "怪物名稱")
    private String name;
    @NotBlank(field = "地圖id")
    private String mapId;
    @NotBlank(field = "地圖名稱")
    private String mapName;
    @NotNull(field = "陣營")
    private Integer faction;
    @NotNull(field = "怪物種類")
    private Integer mobClass;
    @NotNull(field = "怪物類型")
    private Integer mobType;
    @Positive(field = "等級")
    private Integer level;
    @Positive(field = "生命值")
    private Integer hp;
    @Positive(field = "傷害")
    private Integer damage;
    @Positive(field = "護甲")
    private Integer amour;
}

  模型注解添加完畢,我們在BaseController中添加一個通用的校驗方法,方便在各個Controller中調用:

public abstract class BaseController {
    ......
    ......
    @Autowired
    protected Validator validator;
    
    ......
    ......

    protected CommonResult validate(Object object, Class... classes) {
        Set<ConstraintViolation<Object>> set = validator.validate(object, classes);
        if (set != null && set.size() > 0) {
            ConstraintViolation constraintViolation = set.iterator().next();
            return CommonResult.fail(constraintViolation.getMessage());
        }

        return CommonResult.success();
    }
}

  在MapMobController的新增和編輯方法中,添加校驗邏輯,

@Controller
@RequestMapping("/manage/map_mob")
public class MapMobController extends BaseController {
    ……
    ……

    @ResponseBody
    @RequestMapping(value = "/add", method = RequestMethod.POST)
    public Object add(@RequestBody MapMob mapMob) {
        try {
            CommonResult commonResult = this.validate(mapMob, ValidateGroup.Create.class);
            if (!commonResult.isSuccess())
                return commonResult;

            mapMob.setCreateUser(this.currentUserName());
            mapMobManager.insert(mapMob);
            return CommonResult.success();
        } catch (Exception ex) {
            logger.error(ex.getMessage(), ex);
            return CommonResult.fail();
        }
    }
    
    ……
    ……

    @ResponseBody
    @RequestMapping(value = "/edit/{id}", method = RequestMethod.POST)
    public Object edit(@PathVariable String id, @RequestBody MapMob mapMob) {
        try {
            if (!id.equals(mapMob.getId())) {
                return CommonResult.fail("id不一致");
            }

            CommonResult commonResult = this.validate(mapMob, ValidateGroup.Update.class);
            if (!commonResult.isSuccess())
                return commonResult;

            mapMob.setUpdateUser(this.currentUserName());
            mapMobManager.update(mapMob);
            return CommonResult.success();
        } catch (Exception ex) {
            logger.error(ex.getMessage(), ex);
            return CommonResult.fail();
        }
    }
}

四、運行效果

  

小結

  本章實現了對請求參數的后台校驗,當然也可以在前端提前進行校驗,但后端的校驗一般必不可少。

  源碼下載地址:https://idlestudio.ctfile.com/fs/14960372-384755438

  本文原文地址:https://www.cnblogs.com/lyosaki88/p/idlewow_7.html

  項目交流群:329989095


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM