前言
springMvc中提供了许多好用的参数绑定的方式办法,那枚举呢?或许参数的值是一个json字符串的时候?你是怎样处理的?下面我就给jym分享一下我的处理方式。
枚举
一般的枚举类型,比方单列值的那种:one ,two… 。这种事不需要特别处理的,咱们是可以直接接纳值并绑定数据的。
要是下面这种枚举类型呢?而且咱们的参数传递的是:0,1这种数字,办法参数是枚举类型。spring还能帮咱们自动绑定参数嘛?
public enum StatusEnum {
online(1),
offline(0);
private Integer value;
StatusEnum(Integer value) {
this.value = value;
}
public Integer getValue() {
return value;
}
}
这时候spring就无法自动帮咱们绑定参数了,报如下过错:
完成方式
- 经过定时枚举参数注解来符号参数:这是一个枚举类型的参数。
- 经过自界说参数解析器来剖析枚举参数注解,来完成参数的绑定。
界说注解
@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()
办法。
界说枚举参数解析器
中心代码:
// 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字符串参数注解,来完成参数和目标特点的绑定。
界说注解
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface JsonParam {
String value() default ""
Class<?> objectType() default JsonParam.class;
}
- value() : value用于绑定恳求参数和办法参数名共同时的对应联系。和 EnumParam中的value界说差不多。
- objectType() : 当参数是数组目标时,赋值特点。
界说Json参数解析器
中心代码:
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配置文件中如下配置:
server:
tomcat:
relaxed-path-chars: ['|','{','}','[',']']
relaxed-query-chars: ['|','{','}','[',']']