SpringMVC数据校验、数据格式化处理、国际化设置

SpringMVC数据校验、数据格式化处理、国际化设置

1.数据验证

(1)使用JSR-303验证框架

JSR(Java Specification Requests),意思是Java 规范提案。JSR-303是JAVA EE 6中的一项子规范,叫做Bean Validation。JSR 303,Bean Validation规范 ,为Bean验证定义了元数据模型和API。默认的元数据模型是通过Annotations来描述的,使用规范定义的这些注解有效的替换了if-else冗长的校验代码。

引入依赖:

•validation-api

•hibernate-validator(附加了一些验证注解)

•jakarta.validation-api(Spring6以上引入此依赖)

JSR-303验证框架常用注解

在这里插入图片描述

使用案例:

@Data
public class SysUser {/*** 用户ID*/@NotNull(message = "用户id不能为空")private Long userId;/** 用户名*/@NotBlank(message = "用户名不能为空")@Length(max = 20, message = "用户名不能超过20个字符")@Pattern(regexp = "^[\\u4E00-\\u9FA5A-Za-z0-9\\*]*$", message = "用户昵称限制:最多20字符,包含文字、字母和数字")private String username;/** 手机号*/@NotBlank(message = "手机号不能为空")@Pattern(regexp = "^[1][3,4,5,6,7,8,9][0-9]{9}$", message = "手机号格式有误")private String mobile;/**性别*/private String sex;/** 邮箱*/@NotBlank(message = "联系邮箱不能为空")@Email(message = "邮箱格式不对")private String email;/** 密码*/private String password;/*** 创建时间 */@Future(message = "时间必须是将来时间")private Date startTime;
}

在controller层方法参数列表前加上@Valid或@Validated注解

@PostMapping("/save/valid")
@ResponseBody
public Result save(@RequestBody @Valid User user) {if(userService.save(user)>0)return Result.ok();elsereturn Result.fail();
}

@Valid@Validated的区别 :

区别@Valid@Validated
来源标准JSR-303规范Spring‘s JSR-303规范,是标准JSR-303的一个变种。
分组验证不支持支持(使用注解的group属性设定)
声明位置可以用在方法、构造函数、方法参数和成员属性(字段)上,支持嵌套验证。可以用在类型、方法和方法参数上,但不能用在成员属性(字段)上,从而不支持嵌套验证功能。

@Valid嵌套验证

@Data
public class Food {@Validprivate Drink drink;@NotNullprivate String type;
}@Data
public class Drink {@NotNullprivate String name;@Size(min = 1,max = 10000)private String describ;@Digits(integer = 2,fraction = 2)private Double price;
}
//controller层
@PostMapping("/food")
public String addFood(@Valid Food food){return food.getDrink().getName();
}

数据验证全局异常定义案例:

@Component  
@ResponseBody  
@ControllerAdvice
public class GlobalExceptionHandler {    /**方法参数校验(接收参数加上@RequestBody注解才会有这种异常) */@ExceptionHandler(MethodArgumentNotValidException.class)public Result handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {log.error("方法参数校验失败", e);return Result.fail(Objects.requireNonNull(e.getBindingResult().getFieldError()).getDefaultMessage());}@ExceptionHandler(BindException.class)public Result bindException(BindException ex, HttpServletRequest request) {log.error("数据绑定异常", ex);try {// 拿到@NotNull,@NotBlank和 @NotEmpty等注解上的message值String msg = Objects.requireNonNull(ex.getBindingResult().getFieldError()).getDefaultMessage();if (StringUtils.isNotEmpty(msg)) {return Result.fail(msg);}} catch (Exception e) {e.printStackTrace();}        StringBuilder msg = new StringBuilder(); // 参数类型不匹配检验List<FieldError> fieldErrors = ex.getFieldErrors();fieldErrors.forEach((oe) ->msg.append("参数:[").append(oe.getObjectName()).append(".").append(oe.getField()).append("]的传入值:[").append(oe.getRejectedValue()).append("]与预期的字段类型不匹配."));return Result.fail(msg.toString());}/**ConstraintViolationException */@ExceptionHandler(ConstraintViolationException.class)public Result handleConstraintViolationException(ConstraintViolationException e) {log.error("注解校验异常", e);Set<ConstraintViolation<?>> violations = e.getConstraintViolations();String message = violations.stream().map(ConstraintViolation::getMessage).collect(Collectors.joining(";"));return Result.fail(message);}
}

自定义验证注解的步骤案例:

•定义注解接口

@Documented
@Target({ElementType.PARAMETER, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = CardNoValidator.class)
public @interface CardNo {String message() default "{edu.cqie.ssm.cardNoErrorMessage}";Class<?>[] groups() default {};Class<? extends Payload>[] payload() default {};
}

•创建ConstraintValidator接口实现类

public class CardNoValidator implements ConstraintValidator<CardNo, Object> {@Overridepublic void initialize(CardNo constraintAnnotation) {ConstraintValidator.super.initialize(constraintAnnotation);}@Overridepublic boolean isValid(Object o, ConstraintValidatorContext constraintValidatorContext) {if (o == null) {return true;//身份证号未传递时,不做校验}return IdCardValidatorUtils.isValidate18Idcard(o.toString());}
}

•使用注解

@Data
public class User {/*** 用户ID*/@NotNull(message = "用户id不能为空")private Long userId;/** 用户名*/@NotBlank(message = "用户名不能为空")@Length(max = 20, message = "用户名不能超过20个字符")@Pattern(regexp = "^[\\u4E00-\\u9FA5A-Za-z0-9\\*]*$", message = "用户昵称限制:最多20字符,包含文字、字母和数字")private String username;@CardNoprivate String cardNo;
}

2.数据格式化

SpringMVC Formatter

•SpringMVC类型转换器提供了一个统一的ConversionService API以及一个强类型的Converter SPI,用于实现从一种类型另一种类型转换逻辑。例如,将Short强制转换为Long。

•在Spring MVC中,HTTP中的源数据都是String类型,数据绑定需要将String转换为其他类型,同时也可能需要将数据转换为具有本地格式的字符串样式进行展示,而Converter SPI不能直接满足这种格式要求。

•Spring 3 引入了一个方便的Formatter SPI,当在客户端环境(如Web应用程序)中工作并且需要解析和输出本地化字段值时,可以使用Formatter SPI。

(1)使用Converter转换
public class StringToDateConverter implements Converter<String, Date> {private String pattern;public StringToDateConverter(String pattern) {this.pattern = pattern;}@Overridepublic Date convert(String source) {try {SimpleDateFormat dateFormat = new SimpleDateFormat(pattern);dateFormat.setLenient(false);return dateFormat.parse(source);} catch (ParseException e) {throw new IllegalArgumentException("invalid date format. Please use this pattern\"" + pattern + "\"");}}
}

注册bean

<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean"><property name="converters"><set><bean class="edu.cqie.ssm.converter.StringToDateConverter"><constructor-arg name="pattern" value="yyyy-MM-dd"/></bean></set></property>
</bean><mvc:annotation-driven conversion-service="conversionService"/>
(2)使用Formatter转换
public class DateFormatter implements Formatter<Date> {private SimpleDateFormat sdf;public DateFormatter(String pattern) {this.sdf = new SimpleDateFormat(pattern);sdf.setLenient(false);}@Overridepublic Date parse(String s, Locale locale) throws IllegalArgumentException {try {return this.sdf.parse(s);} catch (ParseException e) {throw new IllegalArgumentException("invalid date format. Please use this pattern\"" + this.sdf.toPattern() + "\"");}}@Overridepublic String print(Date date, Locale locale) {return this.sdf.format(date);}
}
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"><property name="formatters"><set><bean class="edu.cqie.ssm.formatter.DateFormatter"><constructor-arg name="pattern" value="yyyy-MM-dd"/></bean></set></property>
</bean>
<mvc:annotation-driven conversion-service="conversionService"/>
(3)内置Formatter转换器
类型说明
NumberFormatter实现 Number 与 String 之间的解析与格式化
CurrencyFormatter实现 Number 与 String 之间的解析与格式化(带货币符号)
PercentFormatter实现 Number 与 String 之间的解析与格式化(带百分数符号)
DateFormatter实现 Date 与 String 之间的解析与格式化

两个格式化注解

•@NumberFormat

•@DateTimeFormat

使用注解格式化

@DateTimeFormat(pattern="yyyy/MM/dd")
private Date birthday;@NumberFormat(style = NumberFormat.Style.CURRENCY )
private Double balance;//货币金额  ¥5000@NumberFormat(pattern = "#,###.##")
private Double salary; //工资  10,000.00@NumberFormat(style = NumberFormat.Style.PERCENT) 
private Double percent;//不加%按p*100来显示,加上按提交精度来显示

3.国际化

什么是国际化?

国际化(也叫 i18n),由于国际化英文单词是 internationalization,在 i 和 n 之间有 18 个字母,因此国际化又叫做 i18n。国际化是指程序在不做任何修改的情况下,就可以在不同的国家或地区和不同的语言环境下,按照当地的语言和格式习惯的显示字符,例如MyBatis官方网站等。

国际化设置场景:

•Spring标签国际化

•接口方法国际化

LocaleResolver

•AcceptHeaderLocaleResolver:根据请求头中的 Accept-Language 字段来确定当前的区域语言。

•SessionLocaleResolver:根据请求参数来确定区域语言,确定后会保存在 Session 中,只要 Session不变,Locale 对象就一直有效。

•CookieLocaleResolver:根据请求参数来确定区域语言,确定后会保存在Cookie中,只要Cookie不变Locale对象就一直有效。

•FixedLocaleResolver:配置时直接提供一个 Locale 对象,以后不能修改。

在这里插入图片描述
在这里插入图片描述

(1)AcceptHeaderLocaleResolver

步骤一:添加多语言配置文件
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

步骤二:修改****spring-mvc.xml

<bean id="messageSource“class="org.springframework.context.support.ResourceBundleMessageSource"><property name="basename" value="i18n.message"/><property name="defaultEncoding" value="UTF-8"/>
</bean>

步骤三:在页面中引用

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<html>
<head><title><spring:message code="login.title"/></title>
</head>
<body><form action="toRegister" method="post"><div><spring:message code="login.content.title"/></div><div><span><spring:message code="login.account"/></span><input type="tel" name="phone" maxlength="11" placeholder='<spring:message code="login.account.holder"/>'/></div><div><span><spring:message code="login.password"/></span><input type="password" name="pwd" minlength="8" maxlength="20" placeholder='<spring:message code="login.password.holder"/>'/></div><div><input type="submit" value='<spring:message code="login.submit"/>'/></div></form>
</body>
</html>

步骤四:在接口中引用

@Controller
public class LoginController {@AutowiredMessageSource messageSource;@GetMapping("/login")public String login() {String username = messageSource.getMessage("login.username", null, LocaleContextHolder.getLocale());String password = messageSource.getMessage("login.password", null, LocaleContextHolder.getLocale());System.out.println("username = " + username);System.out.println("password = " + password);return "login";}
}
(2)SessionLocaleResolver

**步骤一:添加多语言配置文件(与上面一样)

步骤二:修改****spring-mvc.xml

<bean id="messageSource"class="org.springframework.context.support.ResourceBundleMessageSource"><property name="basename" value="i18n.message"/><property name="defaultEncoding" value="UTF-8"/>
</bean>
<mvc:interceptors><mvc:interceptor><mvc:mapping path="/**"/><bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"><property name="paramName" value="locale"/></bean></mvc:interceptor>
</mvc:interceptors>
<bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver">
</bean>

步骤三:在接口中使用

@Controller
public class LoginController {@AutowiredMessageSource messageSource;@GetMapping("/login")public String login(String locale,HttpSession session) {if ("zh-CN".equals(locale)) {session.setAttribute(SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME, new Locale("zh", "CN"));} else if ("en-US".equals(locale)) {session.setAttribute(SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME, new Locale("en", "US"));}String username = messageSource.getMessage("login.username", null, LocaleContextHolder.getLocale());String password = messageSource.getMessage("login.password", null, LocaleContextHolder.getLocale());System.out.println("username = " + username);System.out.println("password = " + password);return "login";}
}
(3)CookieLocaleResolver

**步骤一:添加多语言配置文件(与上面一样)

步骤二:修改****spring-mvc.xml

<bean id="messageSource"class="org.springframework.context.support.ResourceBundleMessageSource"><property name="basename" value="i18n.message"/><property name="defaultEncoding" value="UTF-8"/>
</bean>
<bean id="localeResolver" class="org.springframework.web.servlet.i18n.CookieLocaleResolver"/>

步骤三:在接口中使用

@GetMapping("/login")
public String login(String locale, HttpServletRequest req, HttpServletResponse resp) {CookieLocaleResolver resolver = new CookieLocaleResolver();if ("zh-CN".equals(locale)) {resolver.setLocale(req, resp, new Locale("zh", "CN"));} else if ("en-US".equals(locale)) {resolver.setLocale(req, resp, new Locale("en", "US"));}String username = messageSource.getMessage("login.username", null, LocaleContextHolder.getLocale());String password = messageSource.getMessage("login.password", null, LocaleContextHolder.getLocale());System.out.println("username = " + username);System.out.println("password = " + password);return "login";
}
    resolver.setLocale(req, resp, new Locale("zh", "CN"));
} else if ("en-US".equals(locale)) {resolver.setLocale(req, resp, new Locale("en", "US"));
}
String username = messageSource.getMessage("login.username", null, LocaleContextHolder.getLocale());
String password = messageSource.getMessage("login.password", null, LocaleContextHolder.getLocale());
System.out.println("username = " + username);
System.out.println("password = " + password);
return "login";

}


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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

加速 AI 创新:引入 Elastic AI 生态系统

作者&#xff1a;来自 Elastic Alyssa Fitzpatrick, Steve Kearns 生成式人工智能 (Generative AI - GenAI) 正在改变我们所熟知的商业格局。为了简化和加速开发人员构建和部署检索增强生成 (retrieval augmented generation - RAG) 应用程序的方式&#xff0c;Elastic 自豪地宣…

SpringSecurity 鉴权认证入门讲解

​ Spring Security 是 Spring 家族中的一个安全管理框架。相比与另外一个安全框架Shiro&#xff0c;它提供了更丰富的功能&#xff0c;社区资源也比Shiro丰富。 ​ 一般来说中大型的项目都是使用SpringSecurity 来做安全框架。小项目有Shiro的比较多&#xff0c;因为相比与Sp…

# ubuntu 安装的pycharm不能输入中文的解决方法

ubuntu 安装的pycharm不能输入中文的解决方法 一、问题描述&#xff1a; 当在 ubuntu 系统中&#xff0c;安装了 pycharm&#xff08;如&#xff1a;pycharm2016, 或 pycharm2018&#xff09;,打开 pycharm 输入代码时&#xff0c;发现不能正常输入中文&#xff0c;安装的搜狗…

小白进!QMK 键盘新手入门指南

经常玩键盘的伙伴应该都知道&#xff0c;现在的键盘市场可谓是百花齐放&#xff0c;已经不是之前的单一功能产品化时代。我们可以看到很多诸如&#xff1a;机械轴键盘、磁轴键盘、光轴键盘、电感轴键盘&#xff0c;以及可能会上市的光磁轴键盘&#xff0c;更有支持屏幕的、带旋…

EXCEL 或 WPS 列下划线转驼峰

使用场景&#xff1a; 需要将下划线转驼峰&#xff0c;直接在excel或wps中第一行使用公式&#xff0c;然后快速刷整个列格式即可。全列工下划线转为格式&#xff0c;使用效果如下&#xff1a; 操作步骤&#xff1a; 第一步&#xff1a;在需要显示驼峰的一列&#xff0c;复制以…

微信小程序:vant组件库安装步骤

前言&#xff1a;在微信小程序中引用vant组件报错&#xff0c;提示路径不存在&#xff0c;这很有可能是因为没有安装构建vant组件库导致。下面是我整理的安装vant组件库的步骤: 第一步&#xff1a;安装node.js(执行完第一步请重启小程序) 具体步骤请看链接&#xff1a;node.js…

vue3【实战】切换全屏【组件封装】FullScreen.vue

效果预览 原理解析 使用 vueUse 里的 useFullscreen() 实现 代码实现 技术方案 vue3 vite UnoCSS vueUse 组件封装 src/components/FullScreen.vue <template><component:is"tag"click"toggle":class"[!isFullscreen ? i-ep:full-sc…

GPIO相关的寄存器(重要)

目录 一、GPIO相关寄存器概述 二、整体介绍 三、详细介绍 1、端口配置低寄存器&#xff08;GPIOx_CRL&#xff09;&#xff08;xA...E&#xff09; 2、端口配置高寄存器&#xff08;GPIOx_CRH&#xff09;&#xff08;xA...E&#xff09; 3、端口输入数据寄存器&#xff…

【Hadoop实训】Hive 数据操作②

延续上一篇文章&#xff0c;不懂的宝子们请看以下链接&#xff1a; 【Hadoop实训】Hive 数据操作①-CSDN博客 目录 一、Group by 语句 (1)、计算emp表每个部门的平均工资 (2)、计算emp表每个部门中每个岗位的最高工资 二、Having 语句 (1)、求每个部门的平均工资 (2)、求每个…

Vulhub漏洞复现---solr---CVE-2019-17558

漏洞描述 Apache Solr 5.0.0到Apache Solr 8.3.1容易受到通过VelocityResponseWriter执行的远程代码的攻击。Velocity模板可以通过configset ’ Velocity / 目录中的Velocity模板或作为参数提供。用户定义的configset可以包含可呈现的、潜在的恶意模板。参数提供的模板在默认情…

ADS学习笔记 5. 微带天线设计

基于ADS2023 update2 参考书籍&#xff1a;卢益锋老师《ADS射频电路设计与仿真学习笔记》 更多笔记&#xff1a;ADS学习笔记 1. 功率放大器设计ADS学习笔记 2. 低噪声放大器设计ADS学习笔记 3. 功分器设计ADS学习笔记 4. 微带分支定向耦合器设计 目录 0、设计指标 1、微带…

【JAVA】使用IDEA创建maven聚合项目

【JAVA】使用IDEA创建maven聚合项目 1.效果图 2.创建父模块项目 2.1删除父模块下面的src目录以及不需要的maven依赖 3创建子模块项目 3.1右击父模块项目选择Module… 3.2创建子模块 3.3删除子模块下不需要的maven依赖 4.子模块创建完成后引入SpringBoot依赖启动项目

一文详细深入总结服务器选型

1. 题记&#xff1a; 服务器选型工作是项目规划检讨的一项非常重要的工作&#xff0c;本文详细深入总结服务器选型。 2. 服务器基础知识概览 2.1 服务器的定义与功能 2.1 .1 定义 服务器是一种高性能计算机&#xff0c;其设计目的是在网络中提供服务。它可以处理来自多个客…

如何编译 Cesium 源码

如何编译 Cesium 源码 Cesium 是一个开源的 JavaScript 库&#xff0c;用于构建 3D 地球和地图应用程序。它提供了一套强大的 API 和工具&#xff0c;使开发者能够创建丰富的地理空间应用。本文将指导您如何从 GitHub 下载 Cesium 源码&#xff0c;并在本地进行编译。 TilesB…

车载诊断架构 --- 关于DTC的开始检测条件

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 所有人的看法和评价都是暂时的,只有自己的经历是伴随一生的,几乎所有的担忧和畏惧,都是来源于自己的想象,只有你真的去做了,才会发现有多快乐。…

AI大模型(一):Prompt AI编程

一、Prompt Engineering&#xff0c;提示工程 提示工程也叫指令工程&#xff1a; Prompt是发给大模型的指令&#xff0c;比如【讲个睡前故事】、【用Python写个消消乐游戏】等&#xff1b;本质上大模型相关的工程工作&#xff0c;都是围绕prompt展开的&#xff1b;提示工程门…

如何在 Ubuntu 上安装 Jellyfin 媒体服务器

Jellyfin 是一个开源的媒体服务器软件&#xff0c;让你可以整理、管理和流式传输你的个人媒体收藏&#xff0c;比如电影、音乐、电视节目和照片&#xff0c;而且完全免费&#xff0c;没有订阅费用或数据收集的担忧。 简介 媒体管理&#xff1a;Jellyfin 整理媒体库&#xff0…

数据结构(初阶4)---循环队列详解

循环队列 1.循环队列的结构  1).逻辑模式 2.实现接口  1).初始化  2).判断空和满  3).增加  4).删除  5).找头  6).找尾 3.循环队列的特点 1.循环队列的结构 1).逻辑模式 与队列是大同小异的&#xff0c; 其中还是有一个指向队列头的head指针&#xff0c; 也有一个指向尾…

Qwen2.5-Coder-32B-Instruct Docker 部署openai接口

Qwen2.5-Coder-32B-Instruct 模型下载,国内快捷方式: conda create -n modelscope python=3.10 conda activate modelscopepip install modelscopemodelscope download --model Qwen/Qwen2.5-Coder-32B-Instruct --local_dir /ssd/xiedong/Qwen/Qwen2.5-Coder-32B-I

图形几何之美系列:二维凸包艺术赏析

“凸包是计算几何中的概念&#xff0c;凸包在多个领域中有广泛的应用&#xff0c;主要包括几何计算、图形处理、优化问题、路径规划等。” 1.前言 凸包话题包括二维凸包、三维凸包以及高维凸包。对于平面点集&#xff0c;探究如何构造可以覆盖给定点集最小的凸多边形&#xff1…