Spring MVC使用Model接收帶有【特殊字符】的請求值最佳實踐

前言

單純爲了解決問題,請直接下跳轉【最佳實踐->第三種方案】。

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);
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章