前言
单纯为了解决问题,请直接下跳转【最佳实践->第三种方案】。
Spring MVC使用时候wield便于数据传输,都会使用Model进行接收参数,见实例:
请求:
127.0.0.1:8080/test?myName=zs&myAge=10
接收请求:
@GetMapping("/demo")
public R<String> query(Demo demo) {
// 调用具体服务
service.server(demo);
return R.ok(“业务处理完毕”);
}
接收实体:
class Demo {
private String myName;
private String myAge;
public void setMyName(String myName) {
this.myName = myName;
}
public void setMyAge(String myAge) {
this.myAge = myAge;
}
}
那如果请求的变成下列这样(带了字符),在不改变接收参数的开发习惯下(驼峰命名)该怎么解决?
127.0.0.1:8080/test?my_name=zs&my_age=10
最佳实践
对于这种的127.0.0.1:8080/test?my_name=zs&my_age=10请求,有多种解决方案:
第一种:使用@RequestParam
见实例,这种的比较笨,需要手动赋值,显然没有交给Spring MVC去处理来的轻松。
@GetMapping("/demo")
public R<String> query(@RequestParam(name = "my_name", required = false) String myName,
@RequestParam(name = "my_age", required = false) String myAge) {
final Demo demo = new Demo();
demo.setMyName(myName);
demo.setMyAge(myAge);
// 调用具体服务
service.server(demo);
return R.ok("业务处理完毕");
}
第二种:改变setter方法
见下图,接收仍然是对象,尽管能运行,但强迫症使我接收不了啊,不论是属性还是Setter方法变得太难受了,怎么办,最佳实践肯定有好的解决办法,见第三。
@GetMapping("/demo")
public R<String> query(Demo demo) {
// 调用具体服务
service.server(demo);
return R.ok(“业务处理完毕”);
}
class Demo {
private String myName;
// 直接赋值
private String my_age;
// 通过setter赋值
public void setMy_name(String myName) {
this.myName = myName;
}
}
第三种:使用@ConstructorProperties
使用@ConstructorProperties标记构造方法即可完美解决问题,强迫症终于治愈了
public R<String> query(Demo demo) {
// 调用具体服务
service.server(demo);
return R.ok(“业务处理完毕”);
}
class Demo {
private String myName;
private String myAge;
@ConstructorProperties({"my_name", "my_age"})
public Demo(String myName, String myAge) {
this.myName = myName;
this.myAge = myAge;
}
public void setMyName(String myName) {
this.myName = myName;
}
public void setMyAge(String myAge) {
this.myAge = myAge;
}
}
源码截图
Spring MVC解析参数并绑定对象的处理类:org.springframework.web.method.annotation.ModelAttributeMethodProcessor
具体方法:
constructAttribute(java.lang.reflect.Constructor<?>, java.lang.String, org.springframework.core.MethodParameter, org.springframework.web.bind.support.WebDataBinderFactory, org.springframework.web.context.request.NativeWebRequest)
// 通过构造方法构建,然而这里并没有做任何事,固定返回null
Object constructed = constructAttribute(ctor, attributeName, binderFactory, webRequest);
if (constructed != null) {
return constructed;
}
// 构造方法是个无惨构造方法
if (ctor.getParameterCount() == 0) {
// 那么只能通过setter 或 直接属性赋值了,对应改变setter 和属性值
return BeanUtils.instantiateClass(ctor);
}
// 没错,就是这里了通过有参构造器注入,同时呢,他会去看一个注解,
// 就是我们用的@ConstructorProperties,当然如果请求参数和构造参数完全一致,那就不需要该注解了。
ConstructorProperties cp = ctor.getAnnotation(ConstructorProperties.class);
String[] paramNames = (cp != null ? cp.value() : parameterNameDiscoverer.getParameterNames(ctor));
Assert.state(paramNames != null, () -> "Cannot resolve parameter names for constructor " + ctor);
Class<?>[] paramTypes = ctor.getParameterTypes();
...省略...
return BeanUtils.instantiateClass(ctor, args);