springboot整合JSR303的快速失败和国际化

版本说明

springboot 2.2.6.RELEASE
hibernate-validator 6.0.18.Final (与springboot版本对应)

解决了什么问题

org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 2 errors
{"status":10001,"desc":"must be less than or equal to 2","data":null}
  1. hibernate-validator 默认 fast-fail = false,即会验证所有属性
  2. hibernate-validator 默认 读取ValidationMessages.properties配置文件,即失败提示message为英文

本文将要实现

  1. hibernate-validator 使用 fast-fail = true,即只要有一个属性验证失败,就不再继续验证
  2. hibernate-validator 根据默认配置语言和请求参数,决定读取哪个ValidationMessages_*.properties配置文件

代码实例

pom.xml

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.2.6.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>demo1</artifactId>
	<version>1.0.0-SNAPSHOT</version>
	<name>demo1</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-validation</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<scope>runtime</scope>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-configuration-processor</artifactId>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
			<exclusions>
				<exclusion>
					<groupId>org.junit.vintage</groupId>
					<artifactId>junit-vintage-engine</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

验证实体类

package com.example.demo.rest.vo;

import javax.validation.constraints.DecimalMax;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;

public class UserVO {

	@Min(value = 6)
	private Integer id;
	
	@NotBlank
	private String username;
	
	@DecimalMax(value = "2")
	private String password;

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

}

rest接口

package com.example.demo.rest.ctrl;

import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.example.demo.rest.vo.UserVO;

@RestController
@RequestMapping("/user")
public class UserController {
	
	@PostMapping("/createUser")
	public void createUser(@Validated UserVO userVO) {
		System.out.println(userVO);
	}
}

测试接口

package com.example.demo;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import java.nio.charset.Charset;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;

@SpringBootTest
class Demo1ApplicationTests {
	
	@Autowired
	private WebApplicationContext wac;
	
	private MockMvc mvc;
	
	@BeforeEach
	public void setup() {
		mvc = MockMvcBuilders.webAppContextSetup(wac).build();
	}

	@Test
	public void test() throws Exception {
		String result = mvc.perform(post("/user/createUser")
				.param("password", "3")
	//			.param("l", "fr"))
				.andExpect(status().isOk())
				.andReturn().getResponse().getContentAsString(Charset.forName("UTF-8"));
		System.out.println(result);
	}

}

核心代码

国际化类

package com.example.demo.rest.advice;

import java.util.Locale;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.util.StringUtils;
import org.springframework.web.servlet.LocaleResolver;

public class MyLocaleResolver implements LocaleResolver {

	@Override
	public Locale resolveLocale(HttpServletRequest request) {
		//此处可以根据项目需要修改代码,比如使用session或cookie
		String l = request.getParameter("l");
		Locale locale = null;
		if (StringUtils.isEmpty(l)) {
			locale = Locale.getDefault();
		} else {
			String[] split = l.split("_");
			if (split.length == 1) {
				locale = new Locale(split[0]);
			} else {
				locale = new Locale(split[0], split[1]);
			}
		}
		return locale;
	}

	@Override
	public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
		
	}

}

配置类

package com.example.demo.rest.config;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.web.servlet.LocaleResolver;

import com.example.demo.rest.advice.MyLocaleResolver;

@Configuration
@ConfigurationProperties(prefix = "spring.validator")
public class ValidatorConfig {

	private String failFast = "true";
	
	public String getFailFast() {
		return failFast;
	}

	public void setFailFast(String failFast) {
		this.failFast = failFast;
	}
	
	@Bean
	public LocalValidatorFactoryBean validator() {
		LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean();
		factoryBean.getValidationPropertyMap().put("hibernate.validator.fail_fast", failFast);
		return factoryBean;
	}
	
	@Bean
	public LocaleResolver localeResolver() {
		return new MyLocaleResolver();
	}
}

测试1

	@Test
	public void test() throws Exception {
		String result = mvc.perform(post("/user/createUser")
				.param("password", "3")
				.param("l", "fr")) //法语
				.andExpect(status().isOk())
				.andReturn().getResponse().getContentAsString(Charset.forName("UTF-8"));
		System.out.println(result);
	}

结果

org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errors
{"status":10001,"desc":"ne peut pas être vide","data":null}

测试2

	@Test
	public void test() throws Exception {
		String result = mvc.perform(post("/user/createUser")
				.param("password", "3")
				.andExpect(status().isOk())
				.andReturn().getResponse().getContentAsString(Charset.forName("UTF-8"));
		System.out.println(result);
	}

结果

org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errors
{"status":10001,"desc":"不能为空","data":null}

备注

本文使用到了springboot返回统一数据格式

Spring Boot整合Akka,你需要进行以下几个步骤: 1. 添加Akka的依赖项。在你的项目的构建文件中,添加Akka的相关依赖项,例如akka-actor、akka-remote和akka-slf4j。你可以使用类似以下的代码来添加依赖项: ``` compile("com.typesafe.akka:akka-actor_2.12:2.5.22") compile("com.typesafe.akka:akka-remote_2.12:2.5.22") compile("com.typesafe.akka:akka-slf4j_2.12:2.5.22") ``` 还需要添加JSR 330标准注解的依赖项: ``` compile("javax.inject:javax.inject:1") ``` 2. 配置Akka。在你的配置文件中,你需要配置Akka的相关属性,例如数据库配置。你可以修改`spring.datasource.core.jdbc-url`、`spring.datasource.core.username`和`spring.datasource.core.password`来配置数据库。 3. 创建消息生产者控制器。你可以创建一个带有`@RestController`和`@RequestMapping`注解的类,例如`KafkaProducerController`。在该控制器中,你可以注入`KafkaTemplate`,并使用`@PostMapping`注解来定义一个推送消息的方法。在该方法中,你可以使用`kafkaTemplate`发送消息到指定的主题。你可以参考以下代码: ```java @RestController @RequestMapping("/kafka/producer") public class KafkaProducerController { private static final Logger LOGGER = LoggerFactory.getLogger(KafkaProducerController.class); private static final String TOPIC = "topic-test"; private KafkaTemplate kafkaTemplate; public KafkaProducerController(KafkaTemplate kafkaTemplate) { this.kafkaTemplate = kafkaTemplate; } @PostMapping("/push") public ResponseEntity<String> pushMessage(@RequestBody Message message) { Date time = new Date(); message.setSendTime(time); kafkaTemplate.send(TOPIC, JSON.toJSONString(message)).addCallback( success -> LOGGER.info("{}-生产者发送消息成功:{},时间:{}", TOPIC, success, time), failure -> LOGGER.error("{}-生产者发送消息失败:{}", failure.getMessage()) ); return new ResponseEntity<>("success", HttpStatus.OK); } } ``` 这样,你就完成了在Spring Boot整合Akka的步骤。你可以根据自己的需求进行进一步的配置和开发。 #### 引用[.reference_title] - *1* [springboot集成akka](https://blog.csdn.net/qq_35890572/article/details/117037447)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [SpringBoot整合PowerJob--使用/教程/实例](https://blog.csdn.net/feiying0canglang/article/details/120385372)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [Springboot 整合 kafka 实现消息的发布和订阅](https://blog.csdn.net/qq_34596292/article/details/120706456)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值