前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >减少10%的代码? 自定义参数解析器真的很强大,赶紧了解一下!

减少10%的代码? 自定义参数解析器真的很强大,赶紧了解一下!

原创
作者头像
程序员蜗牛
发布2024-03-04 21:32:28
1110
发布2024-03-04 21:32:28

springMvc中提供了很多好用的参数绑定的方式方法,那枚举呢?

或者参数的值是一个json字符串的时候?

你是怎么处理的?

下面我就给大家分享一下我的处理方式。

枚举

普通的枚举类型,比如单列值的那种:one ,two... 。

这种事不需要特殊处理的,我们是可以直接接收值并绑定数据的。

要是下面这种枚举类型呢?

而且我们的参数传递的是:0,1这种数字,方法参数是枚举类型。

spring还能帮我们自动绑定参数嘛?

代码语言:javascript
复制
public?enum?StatusEnum?{
????online(1),
????offline(0);

????private?Integer?value;

????StatusEnum(Integer?value)?{
????????this.value?=?value;
????}

????public?Integer?getValue()?{
????????return?value;
????}
}

这时候spring就无法自动帮我们绑定参数了,报如下错误:

图片
图片

实现方式

  • 通过定时枚举参数注解来标记参数:这是一个枚举类型的参数。
  • 通过自定义参数解析器来分析枚举参数注解,来实现参数的绑定。
定义注解
代码语言:javascript
复制
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public?@interface?EnumParam?{
????String?value()?default?"";
????/**
?????*?赋值调用方法
?????*?如果为空,默认调用name()方法
?????*?该方法必须是一个不含参数的方法,否则将会调用失败
?????*
?????*?@return
?????*/
????String?valueMethod()?default?"";
}
  • value():?value用于绑定请求参数和方法参数名一致时的对应关系。比如user?statusNo=1?。
    • 方法的参数写法如下:getUser(@EnumParam(value="statusNo") int status)?或者?getUser(@EnumParam() int statusNo)
  • valueMethod():?赋值时调用枚举中的方法。
    • 如果该属性不传值则默认调用枚举类默认提供的 “valueOf()” 方法。
    • 如果自定义一个方法,该方法必须是一个不含参数的方法,否则将会调用失败。比如上述示例枚举?StatusEnum的getValue()方法。
定义枚举参数解析器

核心代码:

代码语言:javascript
复制
//?1
public?class?EnumParamArgumentResolver?implements?HandlerMethodArgumentResolver?{
????@Override
????public?boolean?supportsParameter(MethodParameter?parameter)?{
????????return?parameter.hasParameterAnnotation(EnumParam.class);
????}

????@Override
????public?Object?resolveArgument(MethodParameter?parameter,?ModelAndViewContainer?mavContainer,?NativeWebRequest?webRequest,?WebDataBinderFactory?binderFactory)?throws?Exception?{
????????//?2?
????????EnumParam?annotation?=?parameter.getParameterAnnotation(EnumParam.class);
????????Object?object?=?null;
????????if?(annotation?!=?null)?{
????????????String?parameterName?=?annotation.value();
????????????//?3
????????????if?(!StringUtils.hasText(parameterName))?{
????????????????parameterName?=?annotation.name();
????????????}
????????????if?(!StringUtils.hasText(parameterName))?{
????????????????parameterName?=?parameter.getParameterName();
????????????}

????????????String?value?=?webRequest.getParameter(parameterName);

????????????if?(StringUtils.hasText(value))?{
????????????????//?4?
????????????????Class<?>?objectType?=?parameter.getParameterType();
????????????????String?method?=?Objects.equals(annotation.valueMethod(),?"")???"valueOf"?:?annotation.valueMethod();
????????????????Object[]?enumConstants?=?objectType.getEnumConstants();
????????????????//?如果方法没了就?抛出异常
????????????????Method?declaredMethod?=?objectType.getDeclaredMethod(method);
????????????????try?{
????????????????????for?(Object?enumConstant?:?enumConstants)?{
????????????????????????//?5
????????????????????????Object?invoke?=?method.equals("valueOf")???declaredMethod.invoke(enumConstant,?enumConstant.toString())?:?declaredMethod.invoke(enumConstant);
????????????????????????if?(invoke?!=?null)?{
????????????????????????????if?(Convert.toStr(invoke).equals(Convert.toStr(value)))?{
????????????????????????????????object?=?enumConstant;
????????????????????????????????break;
????????????????????????????}
????????????????????????}
????????????????????}
????????????????}?catch?(Exception?e)?{
????????????????????log.error("参数enum转换失败:{}.{}[{}]",?parameter.getContainingClass().getName(),?parameter.getMethod().getName(),?parameterName);
????????????????????object?=?null;
????????????????}
????????????}
????????????mavContainer.addAttribute(parameterName,?object);
????????}
????????return?object;
????}
}
  • 枚举参数解析器(EnumParamArgumentResolver)实现 spring mvc的扩展接口HandlerMethodArgumentResolver
  • 从参数中获取是否标记了?EnumParam?注解,如果是则进行解析。
  • 处理?EnumParam.value()?的值并进行赋值给parameterName
  • 通过返回的方式拿到需要执行的方法和目标枚举类的值。
  • 通过循环枚举的值然后比较。如果匹配则立即跳出循环并mavContainer.addAttribute(parameterName, object);然后返回。

以上就是实现枚举参数解析器的全部步骤。

示例

方法示例:

图片
图片

请求示例:

图片
图片

json字符串

我们有时候可能会遇到这种请求:

localhost:8088/prt/jsonParams?user={"age":12,"id":"1","name":"凹凸曼"}?那么这种我们可能一般都是使用String接收,然后在调用转JSON的API进行处理。可是这种代码每个方法都去写的话,太不优雅了。毕竟:「温柔永不落伍, 优雅永不过时 」 。

实现方式
  • 通过定时JSON参数注解来标记参数:这是一个JSON字符串的参数。
  • 通过自定义参数解析器来分析JSON字符串参数注解,来实现参数和对象属性的绑定。
定义注解
代码语言:javascript
复制
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public?@interface?JsonParam?{
????String?value()?default?""

????Class<?>?objectType()?default?JsonParam.class;
}
  • value()?: value用于绑定请求参数和方法参数名一致时的对应关系。和 EnumParam中的value定义差不多。
  • objectType()?: 当参数是数组对象时,赋值属性。
定义Json参数解析器

核心代码:

代码语言:javascript
复制
public?class?JsonParamArgumentResolver?implements?HandlerMethodArgumentResolver?{
????@Override
????public?boolean?supportsParameter(MethodParameter?parameter)?{
????????return?parameter.hasParameterAnnotation(?JsonParam.class?);
????}

????@Override
????public?Object?resolveArgument(MethodParameter?parameter,?ModelAndViewContainer?mavContainer,?NativeWebRequest?webRequest,?WebDataBinderFactory?binderFactory)?throws?Exception?{
????????JsonParam?annotation?=?parameter.getParameterAnnotation(?JsonParam.class?);
????????Object?object?=?null;
????????if?(annotation?!=?null)?{
????????????String?parameterName?=?annotation.value();
????????????if?(StringUtils.isBlank(?parameterName?))?{
????????????????parameterName?=?annotation.name();
????????????}

????????????if?(StringUtils.isBlank(?parameterName?))?{
????????????????parameterName?=?parameter.getParameterName();
????????????}

????????????String?value?=?webRequest.getParameter(?parameterName?);
????????????if?(StringUtils.isNotBlank(?value?))?{
????????????????//?2
????????????????Class<?>?objectType?=?annotation.objectType();
????????????????try?{
????????????????????if?(objectType?!=?JsonParam.class)?{
????????????????????????object?=?JSON.parseArray(?value,?objectType?);
????????????????????}?else?{
????????????????????????object?=?JSON.parseObject(?value,?parameter.getParameterType()?);
????????????????????}
????????????????}?catch?(Exception?e)?{
????????????????????LoggerFactory.getLogger(?JsonParamArgumentResolver.class?)
????????????????????????????.error(?"参数Json转换失败:"?+?parameter.getContainingClass().getName()?+?"."?+?parameter.getMethod().getName()?+?"["?+?parameterName?+?"]"?);
????????????????????object?=?null;
????????????????}
????????????}
????????????//this.validate(?parameter,?mavContainer,?object,?parameterName?);
????????????mavContainer.addAttribute(?parameterName,?object?);
????????}
????????return?object;
????}
}
  • 上述步骤的大部分逻辑和 枚举参数解析器 大体一致。
  • 步骤2是判断objectType是否是JsonParam类型,如果是则是对象类型;如果不是JsonParam,这是数组对象类型。

以上就是实现Json参数解析器的全部步骤。

示例
  • 示例1

普通对象方法示例:

图片
图片

请求示例:

图片
图片
  • 示例2

数组对象方法示例:

图片
图片

请求示例:

图片
图片

SpringMvc自带解析器

普通参数绑定&@RequestParam

一般我们普通的参数我们无需加任何额外的注解标记,spring既可以给我们自定绑定参数。

这种,当我们的请求参数与方法参数不一致时可以使用@RequestParam

如下:

图片
图片
图片
图片

@PathVariable

在Controller方法的参数前面添加@PathVariable注解,将路径参数的值绑定到对应的参数上。

如下:

图片
图片
图片
图片

@RequestBody

在Controller方法的参数前面添加@RequestBody注解,将请求体的值绑定到对应的参数上 。

“注意这种模式不支持:Content-Type: application/x-www-form-urlencoded或?Content-Type: application/x-www-form的请求。

图片
图片
图片
图片

@ModelAttribute

在Controller方法的参数前面添加@ModelAttribute注解,将表单参数的值绑定到对应的参数上。同上这种模式不支持?Content-Type: application/json的请求。

图片
图片
图片
图片

附录

问题1

springBoot+tomcat报错:Invalid character found in the request target [...]. The valid characters are defined in RFC 7230 and RFC 3986

原因是:SpringBoot 2.0.0 以上都采用内置tomcat8.0以上版本,而tomcat8.0以上版本遵从RFC规范添加了对Url的特殊字符的限制,url中只允许包含英文字母(a-zA-Z)、数字(0-9)、-_.~四个特殊字符以及保留字符(?! * ’ ( ) ; : @ & = + $ , / ? # [ ]?) (26*2+10+4+18=84)这84个字符,请求中出现了{}大括号或者[],所以tomcat报错。

处理办法:在application.yml配置文件中如下配置:

代码语言:javascript
复制
server:
?tomcat:
????relaxed-path-chars:?['|','{','}','[',']']
????relaxed-query-chars:?['|','{','}','[',']']?

最后说一句(求关注!别白嫖!)

如果这篇文章对您有所帮助,或者有所启发的话,求一键三连:点赞、转发、在看。

关注公众号:woniuxgg,在公众号中回复:笔记??就可以获得蜗牛为你精心准备的java实战语雀笔记,回复面试、开发手册、有超赞的粉丝福利!

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 枚举
    • 实现方式
      • 实现方式
  • json字符串
  • SpringMvc自带解析器
    • 普通参数绑定&@RequestParam
      • @PathVariable
        • @RequestBody
          • @ModelAttribute
          • 附录
            • 问题1
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
            http://www.vxiaotou.com