SpringBoot加Lambda进行参数校验的一个通用方案

简介: SpringBoot加Lambda进行参数校验的一个通用方案

 一、背景

有这样一个业务场景,用户要申请一个功能,但是这个功能需要有校验多种资格。如果有些资格不满足需要给用户提示。

下面给出一个简单的通用方案。

这个方案的优势是,加新的校验非常容易,只需要写一个新的校验函数,添加校验条件即可,不至于把所有校验写在一大串代码里,导致可读性,可维护性都不好。

其实还可以更强大一些,可以在应用启动后获取某个注解或者继承自某个类或接口的所有校验类,然后校验时自动调用。

参见另外一篇博客:https://blog.csdn.net/w605283073/article/details/95688171

二、方法

2.1 项目结构

image.png

2.2 pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.chujianyun</groupId>
    <artifactId>lambdacheck</artifactId>
    <version>1.0-SNAPSHOT</version>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.6.RELEASE</version>
    </parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.8</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.9</version>
        </dependency>
    </dependencies>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

image.gif

2.3 实体

import lombok.Data;
@Data
public class UserParam {
    /**
     * 用户ID
     */
    private Long userId;
}

image.gif

结果

package com.chujianyun.entity.dto;
import lombok.Data;
import java.util.List;
@Data
public class UserCheckResultDTO {
    /**
     * 是否有效
     */
    private Boolean isValidUser;
    /**
     * 是否白名单
     */
    private Boolean isInWhiteList;
    /**
     * 是否等级高
     */
    private Boolean isHighLevel;
    /**
     * 失败原因
     */
    private List<String> failedMessages;
}

image.gif

上下文

import com.chujianyun.entity.dto.UserCheckResultDTO;
import lombok.Data;
@Data
public class UserCheckContext {
    private UserCheckResultDTO userCheckResultDTO = new UserCheckResultDTO();
    // 可以携带其他结果
}

image.gif

2.4 核心封装

package com.chujianyun.component;
import com.chujianyun.entity.context.UserCheckContext;
import com.chujianyun.entity.dto.UserCheckResultDTO;
import com.chujianyun.entity.param.UserParam;
import com.chujianyun.util.CheckUtil;
import org.apache.commons.lang3.RandomUtils;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
@Component
public class UserCheckFuntions {
    // 注入校验所需的各种Bean
    public Function<UserCheckContext, UserCheckContext> checkIsValid(UserParam userParam) {
        return CheckUtil.buildCheck(userCheckContext -> {
            UserCheckResultDTO userCheckResultDTO = userCheckContext.getUserCheckResultDTO();
            // 模拟调用服务A,检查有效性
            boolean result = (userParam.getUserId() > 50);
            if (result) {
                userCheckResultDTO.setIsValidUser(true);
            } else {
                userCheckResultDTO.setIsValidUser(false);
                addFailedMessage(userCheckResultDTO, "无效");
            }
        });
    }
    public Function<UserCheckContext, UserCheckContext> checkIsInWhiteList(UserParam userParam) {
        return CheckUtil.buildCheck(userCheckContext -> {
            UserCheckResultDTO userCheckResultDTO = userCheckContext.getUserCheckResultDTO();
            // 模拟调用服务B,检查是否在白名单
            boolean result = (userParam.getUserId() > 500);
            if (result) {
                userCheckResultDTO.setIsInWhiteList(true);
            } else {
                userCheckResultDTO.setIsInWhiteList(false);
                addFailedMessage(userCheckResultDTO, "不在白名单");
            }
        });
    }
    public Function<UserCheckContext, UserCheckContext> checkIsHighLevel(UserParam userParam) {
        return CheckUtil.buildCheck(userCheckContext -> {
            UserCheckResultDTO userCheckResultDTO = userCheckContext.getUserCheckResultDTO();
            // 模拟调用服务C,检查是否高级用户
            boolean result = (userParam.getUserId() > 30);
            if (result) {
                userCheckResultDTO.setIsHighLevel(true);
            } else {
                userCheckResultDTO.setIsHighLevel(false);
                addFailedMessage(userCheckResultDTO, "等级不够");
            }
        });
    }
    /**
     * 添加失败的信息
     */
    public void addFailedMessage(UserCheckResultDTO userCheckResultDTO, String message) {
        List<String> failMessages = userCheckResultDTO.getFailedMessages();
        if (failMessages == null) {
            failMessages = new ArrayList<>();
            userCheckResultDTO.setFailedMessages(failMessages);
        }
        failMessages.add(message);
    }
}

image.gif

2.5 服务类

import com.chujianyun.entity.dto.UserCheckResultDTO;
import com.chujianyun.entity.param.UserParam;
public interface UserService {
    UserCheckResultDTO checkUser(UserParam userParam);
}

image.gif

实现

import com.chujianyun.component.UserCheckFuntions;
import com.chujianyun.entity.context.UserCheckContext;
import com.chujianyun.entity.dto.UserCheckResultDTO;
import com.chujianyun.entity.param.UserParam;
import com.chujianyun.service.UserService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service
public class UserServiceImpl implements UserService {
    @Resource
    private UserCheckFuntions userCheckFuntions;
    @Override
    public UserCheckResultDTO checkUser(UserParam userParam) {
        UserCheckContext userCheckContext = new UserCheckContext();
        return userCheckFuntions.checkIsValid(userParam)
                .andThen(userCheckFuntions.checkIsInWhiteList(userParam))
                .andThen(userCheckFuntions.checkIsHighLevel(userParam))
                .apply(userCheckContext)
                .getUserCheckResultDTO();
    }
}

image.gif

如果需要新增一个校验,则结果对象里加一个boolean属性,在Function里加一个校验函数,然后再实现类里加一个andThen的校验即可。

2.6 控制器

import com.chujianyun.entity.dto.UserCheckResultDTO;
import com.chujianyun.entity.param.UserParam;
import com.chujianyun.service.UserService;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.annotation.Resource;
@Controller
@RequestMapping("/user")
public class HelloController {
    @Resource
    private UserService userService;
    @PostMapping("/check")
    public ResponseEntity<UserCheckResultDTO> checkUser(UserParam userParam) {
        return new ResponseEntity<>(userService.checkUser(userParam), HttpStatus.OK);
    }
}

image.gif

2.7 校验工具类

package com.chujianyun.util;
import java.util.function.Consumer;
import java.util.function.Function;
public class CheckUtil {
    public static <T> Function<T, T> buildCheck(Consumer<T> checkConsumer) {
        return (checkContext) -> {
            checkConsumer.accept(checkContext);
            return checkContext;
        };
    }
}

image.gif

2.8 测试

image.png

image.png

三、总结

本文主要演示Lambda表达式在参数校验的特殊场景下的一个很有趣的应用,可读性,可拓展性更强。

给我们的启发是要灵活运用Java8提供的新的函数式类。

本文源码:https://github.com/chujianyun/lambdacheck

创作不易,如果觉得本文对你有帮助,欢迎点赞,欢迎关注我,如果有补充欢迎评论交流,我将努力创作更多更好的文章。


相关文章
|
1月前
|
JSON 前端开发 Java
Spring MVC——获取参数和响应
本文介绍了如何在Spring框架中通过不同的注解和方法获取URL参数、上传文件、处理cookie和session、以及响应不同类型的数据。具体内容包括使用`@PathVariable`获取URL中的参数,使用`MultipartFile`上传文件,通过`HttpServletRequest`和`@CookieValue`获取cookie,通过`HttpSession`和`@SessionAttribute`获取session,以及如何返回静态页面、HTML代码片段、JSON数据,并设置HTTP状态码和响应头。
49 1
Spring MVC——获取参数和响应
|
1月前
|
easyexcel Java UED
SpringBoot中大量数据导出方案:使用EasyExcel并行导出多个excel文件并压缩zip后下载
在SpringBoot环境中,为了优化大量数据的Excel导出体验,可采用异步方式处理。具体做法是将数据拆分后利用`CompletableFuture`与`ThreadPoolTaskExecutor`并行导出,并使用EasyExcel生成多个Excel文件,最终将其压缩成ZIP文件供下载。此方案提升了导出效率,改善了用户体验。代码示例展示了如何实现这一过程,包括多线程处理、模板导出及资源清理等关键步骤。
|
1月前
|
JSON NoSQL Java
springBoot:jwt&redis&文件操作&常见请求错误代码&参数注解 (九)
该文档涵盖JWT(JSON Web Token)的组成、依赖、工具类创建及拦截器配置,并介绍了Redis的依赖配置与文件操作相关功能,包括文件上传、下载、删除及批量删除的方法。同时,文档还列举了常见的HTTP请求错误代码及其含义,并详细解释了@RequestParam与@PathVariable等参数注解的区别与用法。
|
2月前
|
缓存 前端开发 Java
springboot 的单体服务 字典参数转译
本文介绍了如何在Spring Boot项目中使用缓存来管理字典参数,并确保前后端数据一致性。首先,通过`@EnableCaching`启用缓存功能,接着创建一个自定义的字典缓存类`DicCache`。然后,通过配置类将`DicCache`添加到`cacheManager`中。此外,对字典服务进行改造,使用`@CachePut`和`@CacheEvict`注解保证数据一致性。最后,实现自定义注解`@DicSerializer`和序列化处理类`DictSerializerHandel`,用于在序列化过程中自动转换字典值。通过这种方式,可最小化代码改动并提高系统性能。
springboot 的单体服务 字典参数转译
|
1月前
|
前端开发 Java Spring
【Spring】“请求“ 之传递单个参数、传递多个参数和传递对象
【Spring】“请求“ 之传递单个参数、传递多个参数和传递对象
110 2
|
2月前
|
JSON Java 数据格式
springboot 参数统一处理
springboot 参数统一处理
|
1月前
|
监控 Java Maven
springboot学习二:springboot 初创建 web 项目、修改banner、热部署插件、切换运行环境、springboot参数配置,打包项目并测试成功
这篇文章介绍了如何快速创建Spring Boot项目,包括项目的初始化、结构、打包部署、修改启动Banner、热部署、环境切换和参数配置等基础操作。
125 0
|
1月前
|
存储 NoSQL Java
Spring Boot项目中使用Redis实现接口幂等性的方案
通过上述方法,可以有效地在Spring Boot项目中利用Redis实现接口幂等性,既保证了接口操作的安全性,又提高了系统的可靠性。
37 0
|
2月前
|
Java Spring
spring boot 启动项目参数的设定
spring boot 启动项目参数的设定