Spring Validation(day10)

1. Spring Validation(续)

默认情况下,Spring Validation框架会在检查所有的请求参数后再提示可能的失败,即“检查到某个错误时并不会直接中止,而是继续检查”,如果需要实现“快速失败”(即:检查到某个错误时直接视为失败,不会继续后续的检查),需要在配置类中使用@Bean方法创建并配置Validator对象!

则在项目的根包下创建config.ValidationConfiguration类,在此配置类中创建并配置Validator

package cn.tedu.csmall.product.config;

import lombok.extern.slf4j.Slf4j;
import org.hibernate.validator.HibernateValidator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.validation.Validation;

/**
 * Validation的配置类
 *
 * @author java@tedu.cn
 * @version 0.0.1
 */
@Slf4j
@Configuration
public class ValidationConfiguration {

    public ValidationConfiguration() {
        log.info("加载配置类:ValidationConfiguration");
    }

    @Bean
    public javax.validation.Validator validator() {
        return Validation
                .byProvider(HibernateValidator.class)
                .configure() // 开始配置Validator
                .failFast(true) // 快速失败,即检查到错误就直接视为失败
                .buildValidatorFactory()
                .getValidator();
    }

}

Spring Validation是通过不同的注解,实现不同的检查功能,常用的检查注解有:

  • @NotNull:不允许为null
  • @NotEmpty:不允许为空(长度为0的字符串)
    • 仅适用于字符串类型的请求参数
    • 可以与@NotNull同时使用,且当通过@NotNull后再执行检查
  • @NotBlank:不允许为空白
    • 仅适用于字符串类型的请求参数
    • 可以与@NotNull同时使用,且当通过@NotNull后再执行检查
  • @Pattern:使用正则表达式检查,需要通过此注解的regexp属性来配置正则表达式
    • 仅适用于字符串类型的请求参数
    • 可以与@NotNull同时使用,且当通过@NotNull后再执行检查
  • @Min:值不得小于多少
    • 仅适用于数值类型的请求参数
    • 可以与@NotNull同时使用,且当通过@NotNull后再执行检查
  • @Max:值不得大于多少
    • 仅适用于数值类型的请求参数
    • 可以与@NotNull同时使用,且当通过@NotNull后再执行检查
  • @Range:值必须在指定的区间范围内
    • 仅适用于数值类型的请求参数
    • 可以与@NotNull同时使用,且当通过@NotNull后再执行检查

如果处理请求的方法的参数不是封装的数据类型,需要进行检查时,需要先在当前类上添加@Validated注解,然后,再在参数上添加相关的检查注解,例如:

@Slf4j
@RestController
@RequestMapping("/brands")
@Api(tags = "02. 品牌管理模块")
@Validated // 【新增】
public class BrandController {

    @Autowired
    private IBrandService brandService;

    public BrandController() {
        log.info("创建控制器:BrandController");
    }

    // http://localhost:9080/brands/test/delete
    @Deprecated
    @ApiOperation("测试:删除品牌")
    @ApiOperationSupport(order = 901)
    @ApiImplicitParam(name = "enable", dataType = "int", paramType = "query") // 【新增】
    @GetMapping("/test/delete")
    // 【新增】以下方法的参数上添加了检查注解
    public String delete(@Range(max = 1) Integer enable) {
        log.debug("接收到【删除品牌(测试)】的请求");
        log.debug("enable = {}", enable);
        throw new RuntimeException("此接口仅用于测试,并未实现任何功能!");
    }

}

使用这种方式检查请求参数时,如果检查不通过,将抛出ConstraintViolationException异常,所以,还需要在**全局异常处理器(GlobalExceptionHandler)**中添加:

@ExceptionHandler
public JsonResult<Void> handleConstraintViolationException(ConstraintViolationException e) {
    log.debug("处理ConstraintViolationException");

    Integer serviceCode = ServiceCode.ERR_BAD_REQUEST.getValue();

    StringBuilder messageBuilder = new StringBuilder();
    Set<ConstraintViolation<?>> constraintViolations = e.getConstraintViolations();
    for (ConstraintViolation<?> constraintViolation : constraintViolations) {
        messageBuilder.append(constraintViolation.getMessage());
    }

    String message = messageBuilder.toString();
    return JsonResult.fail(serviceCode, message);
}

1. 创建Passport项目

此项目主要用于处理“管理员”相关的数据,将实现:添加管理员、管理员登录、显示管理员列表、删除管理员、启用或禁用管理员,并且,在执行相关操作前检查当前登录的账号是否具有相关权限。

项目参数:

  • GITEE仓库地址:https://gitee.com/chengheng2022/jsd2205-csmall-passport-teacher.git
  • 项目名称:jsd2205-csmall-passport-teacher
  • Group:cn.tedu
  • Artifacecsmall-passport
  • Packagecn.tedu.csmall.passport
  • Java版本:8
  • 创建过程中勾选依赖项:无

当项目创建出来后,通过前序项目,调整新项目的pom.xml,原则上,除了当前项目的信息以外,其它内容全部从前序项目中复制过来即可!

然后,创建出mall_ams数据库,并配置IntelliJ IDEA窗口中右侧的Database面板,执行mall_ams.sql中的代码,以创建出相关的数据表。

从前序项目中复制application.properties的配置到新项目中,并且,需要修改:

  • 服务端口,不得与其它服务冲突
  • 连接数据库的URL中的数据库名称,需要改为mall_ams
# 服务端口
server.port=9081

# 连接数据库的相关配置
spring.datasource.url=jdbc:mysql://localhost:3306/mall_ams?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=root

# 配置SQL的XML文件的位置
mybatis.mapper-locations=classpath:mapper/*.xml

# 开启Knife4j的增强模式
knife4j.enable=true

# 日志的显示级别
logging.level.cn.tedu.csmall=trace

然后,将前序项目的config包复制到新项目中(包括包中的各配置类),需要调整:

  • Knife4jConfiguration
    • 修改basePackage属性的值为:"cn.tedu.csmall.passport.controller"
  • MybatisConfiguration
    • 修改@MapperScan注解中的参数为:"cn.tedu.csmall.passport.mapper"

2. 添加管理员–Mapper

关于Mapper层(数据访问层 / 持久层),应该实现:

  • 插入管理员数据

    • insert into ams_admin (除了id和2个时间以外的字段列表) values (匹配的值列表)
      
  • 根据用户名统计管理员账号的数量

    • 保证用户名唯一

    • select count(*) from ams_admin where username=?
      
  • 根据手机号码统计管理员账号的数量

    • 保证手机号码唯一

    • select count(*) from ams_admin where phone=?
      
  • 根据电子邮箱统计管理员账号的数量

    • 保证电子邮箱唯一

    • select count(*) from ams_admin where email=?
      

在项目的根包下创建pojo.entity.Admin实体类,并在类中声明与数据表保持一致的属性(各属性名需遵循驼峰命名法):

@Data
public class Admin implements Serializable {
    
}

在项目的根包下创建mapper.AdminMapper接口:

public interface AdminMapper {
    int insert(Admin admin);
    int countByUsername(String username);
    int countByPhone(String phone);
    int countByEmail(String email);
}

src/main/resources下创建mapper文件夹,并在此文件夹中粘贴得到AdminMapper.xml文件:

<!-- 省略顶部固定代码 -->

<mapper namespace="cn.tedu.csmall.passport.mapper.AdminMapper">
    
    <!-- int insert(Admin admin); -->
    <insert id="insert" useGeneratedKeys="true" keyProperty="id">
        ...
    </insert>
    
    <!-- int countByUsername(String username); -->
    <select id="countByUsername" resultType="int">
        SELECT count(*) FROM ams_admin WHERE username=#{username}
    </select>
    
    <!-- int countByPhone(String phone); -->
    <select id="countByPhone" resultType="int">
        SELECT count(*) FROM ams_admin WHERE phone=#{phone}
    </select>
    
    <!-- int countByEmail(String email); -->
    <select id="countByEmail" resultType="int">
        SELECT count(*) FROM ams_admin WHERE email=#{email}
    </select>
    
</mapper>

src/test/java的根包下创建mapper.AdminMapperTests测试类,编写并执行以上各方法的测试:


3. 添加管理员–Service

在项目的根包下创建pojo.dto.AdminAddNewDTO类:

@Data
public class AdminAddNewDTO implements Serializable {
    // 用户名,密码,昵称,头像,手机号码,电子邮箱,简介,是否启用
}

在项目的根包下创建service.IAdminService接口,并在接口中添加抽象方法:

@Transactional
public interface IAdminService {
    void addNew(AdminAddNewDTO adminAddNewDTO);
}

从前序项目中复制ServiceCodeServiceException到此项目。

在项目的根包下创建service.impl.AdminServiceImpl类,实现以上接口,添加@Service注解:

@Service
public class AdminServiceImpl implements IAdminService {
    
    // 自动装配AdminMapper
    
    @Override
    public void addNew(AdminAddNewDTO adminAddNewDTO) {
        // 从参数中取出用户名
        // 调用Mapper对象的countByUsername()根据用户名统计管理员账号的数量
        // 判断统计结果是否大于0
        // 是:抛出ServiceException(ERR_CONFLICT)
        
        // 从参数中取出手机号码
        // 调用Mapper对象的countByPhone()根据手机号码统计管理员账号的数量
        // 判断统计结果是否大于0
        // 是:抛出ServiceException(ERR_CONFLICT)
        
        // 从参数中取出电子邮箱
        // 调用Mapper对象的countByEmail()根据电子邮箱统计管理员账号的数量
        // 判断统计结果是否大于0
        // 是:抛出ServiceException(ERR_CONFLICT)
        
        // 创建Admin对象,将作为插入时的参数
        // 将参数的各属性复制到Admin对象中:BeanUtils.copyProperties()
        // 补全Admin对象的属性:loginCount,值为0
        // TODO 取出Admin对象中的密码,将其加密,再存入到Admin对象中
        // 调用Mapper对象的insert()插入管理员数据,并获取返回值
        // 判断返回值是否不等于1
        // 是:抛出ServiceException(ERR_INSERT)
    }
}

提示:在实现以上业务时,请在关键点输出日志!

src/test/java下的根包下创建service.AdminServiceTests测试类,编写并执行测试:


4. 添加管理员–Controller

从前序项目中复制JsonResultGlobalExceptionHandler类到当前项目。

在项目的根包下创建controller.AdminController类,并添加注解:

  • @Slf4j

  • @RestController

  • @RequestMapping("/admins")

  • @Api(tags = "01. 管理员管理模块")

然后,在控制器类中添加处理请求的方法:

@Autowired
private IAdminService adminService;

// http://localhost:9081/admins/add-new
@ApiOperation("添加管理员")
@ApiOperationSupport(order = 100)
@PostMapping("/add-new")
public JsonResult<Void> addNew(AdminAddNewDTO adminAddNewDTO) {
    log.debug("开始处理【添加管理员】的请求,参数:{}", adminAddNewDTO);
    adminService.addNew(adminAddNewDTO);
    return JsonResult.ok();
}

完成后,启动项目,通过 http://localhost:9081/doc.html 打开在线API文档,并通过此文档进行调试。

5. 添加管理员–页面

作业

【作业】保证项目完成以下功能,要求Mapper层、Service层、Controller层的代码开发,其中,Mapper层、Service层需要有对应的测试类,Controller层配置好在线API文档,关于Spring Validation的使用是可选的

  1. 添加品牌(addNew),业务规则:品牌名必须唯一
  2. 根据id删除品牌(delete),业务规则:数据必须存在,不存在关联的类别(见pms_brand_category表),不存在关联的SPU(见pms_spu表)
  3. 根据id启用品牌(setEnable),业务规则:数据必须存在,必须处于禁用状态
  4. 根据id禁用品牌(setDisable),业务规则:数据必须存在,必须处于启用状态
  5. 根据id修改品牌基本资料(update),基本资料对应的属性:自行设计,业务规则:数据必须存在
  6. 添加类别(addNew),业务规则:父级类别id不为0时必须保证父级类别存在,类别名必须唯一,如果添加的是子级类别,需保证父级类别的isParent为1
  7. 根据id删除类别(delete),业务规则:数据必须存在,不存在关联的品牌(见pms_brand_category表),不存在关联的属性模板(见pms_category_attribute_template表),不存在关联的SPU(见pms_spu表)
  8. 根据id启用类别(setEnable),业务规则:数据必须存在,必须处于禁用状态
  9. 根据id禁用类别(setDisable),业务规则:数据必须存在,必须处于启用状态
  10. 根据id显示类别(setDisplay),业务规则:数据必须存在,必须处于隐藏状态
  11. 根据id隐藏类别(setHidden),业务规则:数据必须存在,必须处于显示状态
  12. 根据id修改类别基本资料(update),基本资料对应的属性:自行设计,业务规则:数据必须存在
  13. 绑定(插入)品牌与类别的关联(bind)(见pms_brand_category表),业务规则:品牌必须存在,类别必须存在,绑定关联必须不存在
  14. 解绑(删除)品牌与类别的关联(unbind)(见pms_brand_category表),业务规则:数据必须存在
  15. 添加相册(addNew),业务规则:相册名必须唯一
  16. 根据id删除相册(delete),业务规则:数据必须存在,不存在关联的图片(见pms_picture表),不存在关联的SPU(见pms_spu表)
  17. 根据id修改相册基本资料(update),基本资料对应的属性:自行设计,业务规则:数据必须存在
  18. 添加图片(addNew)(见pms_picture表),业务规则:相册必须存在
  19. 根据id删除图片(delete)(见pms_picture表),业务规则:数据必须存在
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值