【Java】Sping Boot中使用Javax Bean Validation

目录

  • Javax Bean Validation
  • 在Spring Boot中集成Javax Bean Validation
  • 使用案例
  • 功能测试
  • 配置全局异常处理器
  • 重新测试
  • 返回特定形式的信息
    • 方式一
    • 方式二
  • 附:常用的注解

Javax Bean Validation

Javax Bean Validation是Java平台的一项规范,旨在提供一种简单且可扩展的方式来验证Java对象的数据。它提供了一组注解,可以应用于Java Bean的属性上,以定义验证规则,并提供了一组验证器来执行这些规则。

在Spring Boot中集成Javax Bean Validation

本文基于SSM框架(可参考博客:【Java】使用IntelliJ IDEA搭建SSM(MyBatis-Plus)框架并连接MySQL数据库)

Spring Boot对Javax Bean Validation提供了内置支持。

在pom.xml文件中添加依赖(包含在标签dependencies中):

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
    <groupId>javax.validation</groupId>
    <artifactId>validation-api</artifactId>
    <version>2.0.1.Final</version>
</dependency>
<dependency>
    <groupId>org.apache.tomcat.embed</groupId>
    <artifactId>tomcat-embed-el</artifactId>
    <version>9.0.83</version>
</dependency>

这些依赖会自动包含Javax Bean Validation API以及Hibernate Validator作为实现。
其中spring-boot-starter-validation的版本由其parent确定:

<!-- 定义父项目,使用Spring Boot 的版本管理 -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.17</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

使用案例

以用户注册功能为例,验证用户输入的用户名和密码。

  1. 创建一个名为User的Java实体类:
import lombok.Data;
import javax.validation.constraints.Size;
import javax.validation.constraints.NotBlank;

@Data
public class User {

    @NotBlank(message = "用户名不能为空")
    private String username;

    @Size(min = 6, message = "密码长度不能少于6位")
    private String password;
}

在User类中,使用了@NotBlank@Size注解来定义了对用户名和密码的验证规则。

  1. 创建UserMapper,UserMapperxml,UserService,UserServiceImpl
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.z.entity.User;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface UserMapper extends BaseMapper<User> {
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.z.mapper.UserMapper">
</mapper>
import com.baomidou.mybatisplus.extension.service.IService;
import com.z.entity.User;

public interface UserService extends IService<User> {
}
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.z.entity.User;
import com.z.mapper.UserMapper;
import com.z.service.UserService;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
}
  1. 创建一个REST控制器来处理用户注册请求:
import com.z.entity.User;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;

@RestController
public class UserController {

    @PostMapping("/register")
    public ResponseEntity<String> registerUser(@RequestBody @Valid User user) {
        // 处理用户注册逻辑
        return ResponseEntity.ok("用户注册成功");
    }
}

在UserController中,使用了@Valid注解来告诉Spring Boot验证User对象,并通过@RequestBody注解将请求体映射到User对象上。

  1. 新建一个数据库及与实体类对应的数据表,并配置数据库:

在resources下添加application.yml文件:

server:
  # 端口
  port: 8080

spring:
  # 数据源配置
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/yourdatabase?characterEncoding=utf-8
    username: yourusername
    password: yourpassword
  jackson:
    time-zone: GMT+8
    date-format: yyyy-MM-dd HH:mm:ss


mybatis-plus:
  # mapper文件映射路径
  mapper-locations: classpath*:mapper/*.xml
  configuration:
    # 打印SQL语句
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

其中,yourusername,yourpassword,yourdatabase注意换成自己的。

  1. 编写Main.java运行项目,并通过IDEA的启动按钮启动项目:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Main {
    public static void main(String[] args) {
        SpringApplication.run(Main.class, args);
    }
}

功能测试

使用Postman发送以下JSON请求体:
在这里插入图片描述

点击send,接收到一个400 Bad Request响应:

在这里插入图片描述
可以观察到,之前写在注解中的message并没有展示,需配置全局异常处理器处理异常。

配置全局异常处理器

创建一个@ControllerAdvice类,并在其中定义一个方法来处理MethodArgumentNotValidException异常:

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<String> handleValidationExceptions(MethodArgumentNotValidException ex) {
        StringBuilder errors = new StringBuilder();
        ex.getBindingResult().getFieldErrors().forEach(error -> errors.append(error.getDefaultMessage()).append("\n"));
        return ResponseEntity.badRequest().body(errors.toString());
    }
}

重新测试

重新运行程序测试,并发送请求,得到如下结果:
在这里插入图片描述
可以观察到,这里仅仅是将错误信息以文本形式展示,并没有返回状态码等信息。

返回特定形式的信息

方式一

重写全局异常处理器:

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<Object> handleValidationExceptions(MethodArgumentNotValidException ex) {
        Map<String, Object> body = new HashMap<>();
        body.put("timestamp", LocalDateTime.now());
        body.put("status", 400);
        body.put("error", "Bad Request");

        StringBuilder errors = new StringBuilder();
        ex.getBindingResult().getFieldErrors().forEach(error -> errors.append(error.getDefaultMessage()).append(System.lineSeparator()));
        body.put("message", errors.toString());

        return ResponseEntity.badRequest().body(body);
    }
}

测试结果:
在这里插入图片描述

方式二

  1. 定义一个返回结果类型ApiResult
import lombok.Data;
import java.util.List;

@Data

public class ApiResult {
    // 定义状态码
    public static final int OK = 200;
    public static final int ERROR = 500;
    public static final int Invalid = 400;

    // 定义返回结果的字段
    private int code;
    private String message;
    private Object data;

    // 构造器
    public ApiResult(int code, String message, Object data) {
        this.code = code;
        this.message = message;
        this.data = data;
    }

    // 静态方法创建成功的响应
    public static ApiResult ok(String message, Object data) {
        return new ApiResult(OK, message, data);
    }

    // 静态方法创建错误的响应
    public static ApiResult error(String message) {
        return new ApiResult(ERROR, message, null);
    }

    public static ApiResult violateConstraint(List<String> violation) {
        return new ApiResult(Invalid, "参数校验未通过", violation);
    }
}
  1. 修改全局异常处理器:
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.List;
import java.util.stream.Collectors;

@ResponseBody
@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ApiResult handleValidationExceptions(MethodArgumentNotValidException ex) {
        List<String> violations = ex.getBindingResult().getFieldErrors().stream().map(FieldError::getDefaultMessage).
                collect(Collectors.toList());
        return ApiResult.violateConstraint(violations);
    }
}
  1. 修改UserController中注册接口的返回类型:
@RestController
@RequestMapping("/test")
public class UserController {

    @Autowired
    private UserService userService;

    @PostMapping("/register")
    public ApiResult registerUser(@RequestBody @Valid User user) {
        userService.save(user);
        return ApiResult.ok("用户注册成功",user);
    }
}

测试结果:
在这里插入图片描述

附:常用的注解

注解适用类型说明使用案例
@Null任意类型被注释的元素必须为null@Null(message = "必须为null")
@NotNull任意类型被注释的元素不能为null@NotNull(message = "不能为null")
@NotEmpty字符串、集合、数组被注释的元素不能为 null 也不能为空@NotEmpty(message = "不能为null或者为空")
@NotBlank字符串被注释的字符串不能为 null ,且去除空格后的长度不为 0@NotBlank(message = "name为必传参数")
@Size字符串、集合、数组被注解的元素的大小必须在指定的范围内@Size(min = 5,max = 20,message = "字符长度在 5 -20 之间")
@Min数字被注解的元素必须是一个数字,其值必须大于等于指定的最小值@Min(value = 0,message = "最小金额不能小于 0")
@Max数字被注解的元素必须是一个数字,其值必须小于等于指定的最大值@Max(value = 200,message = "最大金额不能超过 200")
@DecimalMin数字被注解的元素必须是一个数字,其值必须大于等于指定的最小值,可用于浮点数比较@DecimalMin(value = "0.1",message = "该参数不能小于 0.1")
@DecimalMax数字被注解的元素必须是一个数字,其值必须小于等于指定的最大值,可用于浮点数比较@DecimalMax(value = "100.4",message = "该参数不能大于 100.4")
@Digits数字被注解的元素必须是一个数字,且其值必须在指定的范围内@Digits(integer = 3,fraction = 2,message = "该参数整数位数不能超出3位,小数位数不能超过2位")
@Negative数字被注释的元素必须是负数@Negative(message = "必须是负数")
@NegativeOrZero数字被注释的元素必须是负数或 0@NegativeOrZero(message = "必须是负数或者为0")
@Positive数字被注释的元素必须是正数@Positive(message = "必须是正数")
@PositiveOrZero数字被注释的元素必须是正数或0@PositiveOrZero(message = "必须是正数或者为0")
@Pattern字符串被注解的字符串必须符合指定的正则表达式@Pattern(regexp = "^1[3456789]\d{9}$",message = "手机号格式不正确")
@Email字符串被注解的元素必须是一个电子邮件地址@Email(message = "email格式错误")
@Future日期、时间被注解的元素必须是一个将来的日期@Future(message = "预约日期要大于当前日期")
@FutureOrPresent日期、时间被注释的元素必须是现在或者未来的日期@FutureOrPresent(message = "预约日要大于当前日期")
@AssertTrue布尔被注解的元素必须是true@AssertTrue(message = "该参数必须为 true")
@AssertFalse布尔被注解的元素必须是false@AssertFalse(message = "该参数必须为 false")

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/645022.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

如何处理时间序列的缺失数据

您是否应该删除、插入或估算&#xff1f; 世界上没有完美的数据集。每个数据科学家在数据探索过程中都会有这样的感觉&#xff1a; df.info()看到类似这样的内容&#xff1a; 大多数 ML 模型无法处理 NaN 或空值&#xff0c;因此如果您的特征或目标包含这些值&#xff0c;则在…

Java开发大厂面试第22讲:Redis 是如何保证系统高可用的?它的实现方式有哪些?

高可用是通过设计&#xff0c;减少系统不能提供服务的时间&#xff0c;是分布式系统的基础也是保障系统可靠性的重要手段。而 Redis 作为一款普及率最高的内存型中间件&#xff0c;它的高可用技术也非常的成熟。 我们今天分享的面试题是&#xff0c;Redis 是如何保证系统高可用…

mysql - 索引原理

mysql索引原理 文中的查询, 以该表结构为例 CREATE TABLE user (id int NOT NULL COMMENT id,name varchar(255) COLLATE utf8mb4_bin NOT NULL COMMENT 姓名,age int NOT NULL COMMENT 年龄,sex tinyint(1) NOT NULL COMMENT 性别,phone varchar(255) CHARACTER SET utf8mb4…

源码编译安装LAMP

1.LAMP介绍 LAMP架构是目前成熟的企业网站应用模式之一&#xff0c;指的是协同工作的一整套系统和相关软件&#xff0c;能够提供动态Web站点服务及其应用开发环境。LAMP是一个缩写词&#xff0c;具体包括Linux操作系统、Apache网站服务器、MySQL数据库服务器、PHP&#xff08;…

公安知识学习与题目练习系统

一、系统概述 系统采用C用户小程序端、管理员Web端架构。通过UniappVueSpringboot主流技术实现。具体功能分为&#xff0c;管理侧&#xff1a;可以维护学习知识点、更新知识点详情&#xff1b;C端用户&#xff1a;可以学习知识点、在线刷题练习的功能。次系统在公安专业知识学习…

ChatGLM2-6B 模型基于 [P-Tuning v2]的微调

ChatGLM2-6B-PT 一、介绍 1、本文实现对于 ChatGLM2-6B 模型基于 [P-Tuning v2](https://github.com/THUDM/P-tuning-v2) 的微调 2、运行至少需要 7GB 显存 3、以 [ADGEN](https://aclanthology.org/D19-1321.pdf) (广告生成) 数据集为例介绍代码的使用方法。 模型部署参考…

安装termux遇到的问题-逍遥模拟器

问题一 做一次更新即可解决问题&#xff0c;pkg update 问题二 sshd&#xff1a;no hostkeys available -- exiting. 尝试了网上提供的方法 ssh-keygen -t rsa -f /data/data/com.termux/files/usr/etc/ssh/ssh_host_rsa_key ssh-keygen -t dsa -f /data/data/com.termux/…

OTA在线旅行社系统架构:连接世界的科技纽带

随着互联网的快速发展和人们对旅行需求的不断增长&#xff0c;OTA&#xff08;Online Travel Agency&#xff09;在线旅行社成为了现代旅行业中的重要一环。OTA系统架构的设计和实现将对旅行行业产生深远影响。本文将探讨OTA在线旅行社系统架构的重要性和关键组成部分&#xff…

【论文阅读|cryoET】ICE-TIDE

简介 三维cryoET重建的保真度进一步受到采集过程中物理扰动的影响。这些扰动以各种形式表现出来&#xff0c;例如连续采集之间的样本漂移&#xff0c;导致连续投影未对准&#xff0c;或者由于未散射的电子而导致二维投影中的局部变形。 传统的冷冻电子断层扫描工作流程需要对…

论文阅读--ActionCLIP

原来的动作识别问题在于标注太难太贵&#xff0c;将动作表示为短语的latent space太大 本文的贡献&#xff1a;&#xff08;1&#xff09;将CLIP的image encoder换成video encoder&#xff0c;方法与CLIP4Clip几乎一样 &#xff08;2&#xff09;CLIP的ground truth来自于文本…

销量翻倍不是梦!亚马逊速卖通自养号测评实战技巧分享!

在亚马逊、速卖通这些跨境电商平台上&#xff0c;卖家们都在想各种办法让自己的产品卖得更好。现在&#xff0c;有一种叫做“自养号测评”的方法特别火。简单来说&#xff0c;就是自己养一些买家账号&#xff0c;然后让这些账号来给你的产品写好评。这样&#xff0c;你的产品就…

绘制t-SNE图

什么是t-SNE图&#xff1f; 如下图&#xff0c;下图来源于论文Contrastive Clustering 一般用于分类问题/对比学习。 作用&#xff1f; 体现出经过层层训练&#xff0c;类内越来越紧密&#xff0c;类间差异越来越大&#xff1b;或者也可以做消融可视化。 怎么画&#xff1f…

【spring】@PathVariable注解学习

PathVariable介绍 PathVariable是Spring框架中的一个注解&#xff0c;主要用于处理RESTful风格URL中的路径变量。在RESTful接口设计中&#xff0c;我们经常将资源的ID或者其他标识信息直接放在URL路径中&#xff0c;而不是作为查询参数。PathVariable注解使得控制器方法能够轻…

【Linux】如何优雅的检查Linux上的用户登录、关机和重启日志

在诸如Ubuntu、Debian、Linux Mint、Fedora和Red Hat等广受欢迎的Linux发行版中&#xff0c;系统会忠实记录用户的登录、关机、重启以及运行时长信息。这些信息对管理员调查事件、排查故障或汇总用户活动报告极为宝贵。 Linux系统及应用程序日志通常保存在/var/log/目录下&…

RuoYI框架集成Sqlite与Mybatis-plus

一、RuoYi 中集成 SQLite 、MyBatis-Plus RuoYi 是一个基于 Spring Boot 的权限管理系统,它默认使用 MySQL 作为数据库。如果你想在 RuoYi 中集成 SQLite 数据库,并使用 MyBatis-Plus 作为 ORM 框架,你需要进行一些配置和代码更改。以下是集成的基本步骤: 添加依赖:在项目…

Java进阶学习笔记19——内部类

1、 内部类&#xff1a; 是类中五大成分之一&#xff08;成员变量、方法、构造函数、内部类、代码块&#xff09;&#xff0c;如果一个类定义在另一个 类的内部&#xff0c;这个类就是内部类。 场景&#xff1a;当一个类的内部&#xff0c;包含了一个完整的事物&#xff0c;且…

Linux服务升级:Predixy 升级代理 Redis-cluster 集群

目录 一、实验 1.环境 2. 启动Redis服务 3.Predixy 升级代理 Redis-cluster 集群 二、问题 1. Predixy进行set操作报错 2.如何创建脚本启动predixy 3.Redis代理对比 一、实验 1.环境 &#xff08;1&#xff09;主机 表1 主机 系统版本节点软件IP备注CentOS7.9Redis…

JavaFX学习教程二

一、JavaFX 体系结构 JavaFX 场景图(Scene Graph)是构建 JavaFX 应用程序的起点&#xff0c;一种树状数据结构&#xff0c;用于排列&#xff08;和分组&#xff09;图形对象&#xff0c;以便于逻辑表示。 stage:舞台&#xff0c;操作系统窗口的 JavaFX 表示&#xff0c;是所有…

网络编程的基础知识(适合新手)

网络编程 在Java中&#xff0c;网络编程是指使用Java语言进行网络通信的编程技术。这种技术使得位于不同地理位置的计算机能够通过网络进行通信&#xff0c;实现资源共享和信息传递。 一、定义 Java网络编程是Java语言在网络通信方面的应用&#xff0c;它利用Java提供的网络…

恢复Android数据的综合指南:适用于Android的数据恢复工具

随着存储空间的快速增长&#xff0c;智能手机已成为我们最可靠的个人数据库。我们的 Android 手机不亚于我们自己的延伸&#xff0c;包含各种重要文件、照片、文档、视频、联系人、通话记录等等。由于这些智能 Android 设备上存储了如此多有价值的信息&#xff0c;意外删除或丢…