从零开始实现放置游戏(七)——实现后台管理系统(5)参数校验

简介: 前面几章实现了在RMS系统中进行数据的增删查改以及通过Excel批量导入。但仍有遗留的问题,比如在新增或编辑时,怪物的生命值、护甲等数据我们可以输入负值,这种数据是不合理且没有意义的。本章我们就实现服务端对参数的校验。

 前面几章实现了在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();
        }
    }
}


四、运行效果


微信图片_20220423204023.gif


小结


  本章实现了对请求参数的后台校验,当然也可以在前端提前进行校验,但后端的校验一般必不可少。


相关文章
|
2月前
|
搜索推荐
7、自定义工作界面
这篇文章是关于如何自定义Photoshop工作界面的,但具体内容没有在摘要中提供,因此无法给出详细摘要。如果需要了解Photoshop工作界面的自定义方法,包括面板、菜单、快捷键等的个性化设置,建议直接访问博客以获取完整信息。
7、自定义工作界面
|
3月前
|
前端开发 JavaScript Java
文本----简单编写文章的方法(中),后端接口的编写,自己编写好页面就上传到自己的服务器上,使用富文本编辑器进行编辑,想写好一个项目,先分析一下需求,再理一下实现思路,再搞几层,配好参数校验,lomb
文本----简单编写文章的方法(中),后端接口的编写,自己编写好页面就上传到自己的服务器上,使用富文本编辑器进行编辑,想写好一个项目,先分析一下需求,再理一下实现思路,再搞几层,配好参数校验,lomb
|
5月前
游戏开发实战教程(15):形状放置预提示
游戏开发实战教程(15):形状放置预提示
58 0
|
前端开发
前端学习笔记202304学习笔记第七天-了解自定义验证函数
前端学习笔记202304学习笔记第七天-了解自定义验证函数
56 0
|
前端开发
前端学习笔记202304学习笔记第七天-自定义验证函数
前端学习笔记202304学习笔记第七天-自定义验证函数
62 0
|
前端开发 Java 数据库
给角色分配菜单的功能后台代码的编写 | 学习笔记
快速学习给角色分配菜单的功能后台代码的编写
给角色分配菜单的功能后台代码的编写 | 学习笔记
|
SQL XML JSON
从零开始实现放置游戏(四)——实现后台管理系统(2)数值配置的增删查改
 上一章我们将RMS后台管理系统搭建完毕,本章我们就在这个系统上实现录入游戏配置的功能。目前我们需要配置四项,每个等级的人物属性,每个等级的升级经验,游戏地图,地图中的怪物。下面我们以游戏地图配置为例子,实现对它的增删查改功能。
从零开始实现放置游戏(四)——实现后台管理系统(2)数值配置的增删查改
|
IDE Java 应用服务中间件
从零开始实现放置游戏(五)——实现后台管理系统(3)实现切面日志
 上一章,我们初步实现了后台管理系统的增删查改功能。然而还有很多功能不完善。这一章,我们先把系统日志搭建起来,不管是生产问题排查,还是方便开发调试,日志都是必不可少的核心功能。所谓切面日志,比如说,我们想把每个方法的入参都记录日志,那需要在每个方法里都写一行记录参数的语句,非常繁琐。所以需要提取出切面“方法执行前”,“方法执行后”等等,然后在这个切面里进行编程,记录入参的语句只需要写一次。
从零开始实现放置游戏(五)——实现后台管理系统(3)实现切面日志
|
SQL 缓存 前端开发
从零开始实现放置游戏(十一)——实现战斗挂机(2)注册登陆和游戏主界面
 本章主要实现注册登陆功能和游戏的主界面。有了游戏的界面,大家能有更直观的认识。   本章我们主要开发的是idlewow-game模块,其实就是游戏的客户端展示层。因为是放置游戏,为了方便,主要使用spring-mvc来开发,整个游戏形式是类似web端的文字mud游戏,会稍带一些图形图片。当然,游戏的客户端可以是多种多样的,也可以使用U3D开发成移动端或者C++/flash/silver light,开发成PC端、网页端、微端等等形式,但需要更多的美术资源。
从零开始实现放置游戏(十一)——实现战斗挂机(2)注册登陆和游戏主界面
|
JavaScript 前端开发 Java
从零开始实现放置游戏(九)——实现后台管理系统(7)地图选择控件
前面做了地图怪物的添加,删除,查询等功能。但添加怪物的时候,需要选择怪物所在地图。前几张的源代码中,我忘了把这部分改回去,所以如果想要成功添加,需要自己改一下html界面,手动填写怪物所在地图的ID。然而,我们配置的时候,地图ID并不是固定的,而是数据库自增的。所以这里最好做成一个弹窗,点击后弹出一个地图列表,让我们手动选择怪物所在地图。   本章我们就实现这样一个弹窗控件,实现对地图的选择。后面如果有选择怪物,选择装备等需求,都可照猫画虎。
从零开始实现放置游戏(九)——实现后台管理系统(7)地图选择控件