[英]Spring MVC: Complex object as GET @RequestParam
假设我有一个页面列出了表格上的对象,我需要放置一个表格来过滤表格。 过滤器作为 Ajax GET 发送到这样的 URL: http : //foo.com/system/controller/action?page=1&prop1= x& prop2=y&prop3=z
而不是在我的控制器上有很多参数,比如:
@RequestMapping(value = "/action")
public @ResponseBody List<MyObject> myAction(
@RequestParam(value = "page", required = false) int page,
@RequestParam(value = "prop1", required = false) String prop1,
@RequestParam(value = "prop2", required = false) String prop2,
@RequestParam(value = "prop3", required = false) String prop3) { ... }
假设我有 MyObject 为:
public class MyObject {
private String prop1;
private String prop2;
private String prop3;
//Getters and setters
...
}
我想做这样的事情:
@RequestMapping(value = "/action")
public @ResponseBody List<MyObject> myAction(
@RequestParam(value = "page", required = false) int page,
@RequestParam(value = "myObject", required = false) MyObject myObject,) { ... }
是否有可能? 我怎样才能做到这一点?
您绝对可以这样做,只需删除@RequestParam
注释,Spring 会将您的请求参数干净地绑定到您的类实例:
public @ResponseBody List<MyObject> myAction(
@RequestParam(value = "page", required = false) int page,
MyObject myObject)
我将添加一些来自我的简短示例。
DTO 类:
public class SearchDTO {
private Long id[];
public Long[] getId() {
return id;
}
public void setId(Long[] id) {
this.id = id;
}
// reflection toString from apache commons
@Override
public String toString() {
return ReflectionToStringBuilder.toString(this, ToStringStyle.SHORT_PREFIX_STYLE);
}
}
在控制器类中请求映射:
@RequestMapping(value="/handle", method=RequestMethod.GET)
@ResponseBody
public String handleRequest(SearchDTO search) {
LOG.info("criteria: {}", search);
return "OK";
}
询问:
http://localhost:8080/app/handle?id=353,234
结果:
[http-apr-8080-exec-7] INFO c.g.g.r.f.w.ExampleController.handleRequest:59 - criteria: SearchDTO[id={353,234}]
我希望它有帮助:)
更新/科特林
因为目前我正在使用 Kotlin 进行很多工作,如果有人想定义类似的 DTO,那么 Kotlin 中的类应该具有以下形式:
class SearchDTO {
var id: Array<Long>? = arrayOf()
override fun toString(): String {
// to string implementation
}
}
使用这样的data
类:
data class SearchDTO(var id: Array<Long> = arrayOf())
Spring(在 Boot 中测试)为回答中提到的请求返回以下错误:
“无法将类型 'java.lang.String[]' 的值转换为所需的类型 'java.lang.Long[]';嵌套异常为 java.lang.NumberFormatException:对于输入字符串:\\"353,234\\""
数据类仅适用于以下请求参数表单:
http://localhost:8080/handle?id=353&id=234
请注意这一点!
由于每个帖子下都会弹出如何设置必填字段的问题,我写了一个关于如何设置必填字段的小例子:
public class ExampleDTO {
@NotNull
private String mandatoryParam;
private String optionalParam;
@DateTimeFormat(iso = ISO.DATE) //accept Dates only in YYYY-MM-DD
@NotNull
private LocalDate testDate;
public String getMandatoryParam() {
return mandatoryParam;
}
public void setMandatoryParam(String mandatoryParam) {
this.mandatoryParam = mandatoryParam;
}
public String getOptionalParam() {
return optionalParam;
}
public void setOptionalParam(String optionalParam) {
this.optionalParam = optionalParam;
}
public LocalDate getTestDate() {
return testDate;
}
public void setTestDate(LocalDate testDate) {
this.testDate = testDate;
}
}
//Add this to your rest controller class
@RequestMapping(value = "/test", method = RequestMethod.GET)
public String testComplexObject (@Valid ExampleDTO e){
System.out.println(e.getMandatoryParam() + " " + e.getTestDate());
return "Does this work?";
}
我有一个非常相似的问题。 其实问题比我想象的更深。 我正在使用 jquery $.post
它使用Content-Type:application/x-www-form-urlencoded; charset=UTF-8
默认Content-Type:application/x-www-form-urlencoded; charset=UTF-8
。 不幸的是,我的系统基于此,当我需要一个复杂的对象作为@RequestParam
我不能让它发生。
在我的情况下,我试图用类似的东西发送用户偏好;
$.post("/updatePreferences",
{id: 'pr', preferences: p},
function (response) {
...
在客户端,发送到服务器的实际原始数据是;
...
id=pr&preferences%5BuserId%5D=1005012365&preferences%5Baudio%5D=false&preferences%5Btooltip%5D=true&preferences%5Blanguage%5D=en
...
解析为;
id:pr
preferences[userId]:1005012365
preferences[audio]:false
preferences[tooltip]:true
preferences[language]:en
服务器端是;
@RequestMapping(value = "/updatePreferences")
public
@ResponseBody
Object updatePreferences(@RequestParam("id") String id, @RequestParam("preferences") UserPreferences preferences) {
...
return someService.call(preferences);
...
}
我尝试了@ModelAttribute
,向UserPreferences
添加了具有所有可能性的 setter/getter、构造函数,但没有机会,因为它将发送的数据识别为 5 个参数,但实际上映射的方法只有 2 个参数。 我也尝试了 Biju 的解决方案,但是发生的情况是,spring 创建了一个带有默认构造函数的 UserPreferences 对象,并且不填充数据。
我通过从客户端发送首选项的 JSon 字符串并在服务器端将其作为字符串处理来解决该问题;
客户:
$.post("/updatePreferences",
{id: 'pr', preferences: JSON.stringify(p)},
function (response) {
...
服务器:
@RequestMapping(value = "/updatePreferences")
public
@ResponseBody
Object updatePreferences(@RequestParam("id") String id, @RequestParam("preferences") String preferencesJSon) {
String ret = null;
ObjectMapper mapper = new ObjectMapper();
try {
UserPreferences userPreferences = mapper.readValue(preferencesJSon, UserPreferences.class);
return someService.call(userPreferences);
} catch (IOException e) {
e.printStackTrace();
}
}
简而言之,我在 REST 方法中手动进行了转换。 在我看来,spring 无法识别发送的数据的原因是内容类型。
虽然引用@ModelAttribute
、 @RequestParam
、 @PathParam
等的答案是有效的,但我遇到了一个小问题。 生成的方法参数是 Spring 包裹在 DTO 周围的代理。 因此,如果您尝试在需要您自己的自定义类型的上下文中使用它,您可能会得到一些意想不到的结果。
以下将不起作用:
@GetMapping(produces = APPLICATION_JSON_VALUE)
public ResponseEntity<CustomDto> request(@ModelAttribute CustomDto dto) {
return ResponseEntity.ok(dto);
}
就我而言,尝试在 Jackson 绑定中使用它会导致com.fasterxml.jackson.databind.exc.InvalidDefinitionException
。
您将需要从 dto 创建一个新对象。
是的,您可以通过一种简单的方式做到这一点。 请参阅下面的行代码。
URL - http://localhost:8080/get/request/multiple/param/by/map?name= 'abc' & id='123'
@GetMapping(path = "/get/request/header/by/map")
public ResponseEntity<String> getRequestParamInMap(@RequestParam Map<String,String> map){
// Do your business here
return new ResponseEntity<String>(map.toString(),HttpStatus.OK);
}
接受的答案就像一个魅力,但如果对象有一个对象列表,它就不会按预期工作,所以这是我经过一些挖掘后的解决方案。
按照这个线程建议,这是我的做法。
它不是用邮递员调试 API 的最佳选择,但它按我的预期工作。
原始对象: {页面:1,大小:5,过滤器:[{字段:“id”,值:1,比较:“EQ”}
编码对象: eyJwYWdlIjoxLCJzaXplIjo1LCJmaWx0ZXJzIjpbeyJmaWVsZCI6ImlkUGFyZW50IiwiY29tcGFyaXNvbiI6Ik5VTEwifV19
@GetMapping
fun list(@RequestParam search: String?): ResponseEntity<ListDTO> {
val filter: SearchFilterDTO = decodeSearchFieldDTO(search)
...
}
private fun decodeSearchFieldDTO(search: String?): SearchFilterDTO {
if (search.isNullOrEmpty()) return SearchFilterDTO()
return Gson().fromJson(String(Base64.getDecoder().decode(search)), SearchFilterDTO::class.java)
}
这里是 SearchFilterDTO 和 FilterDTO
class SearchFilterDTO(
var currentPage: Int = 1,
var pageSize: Int = 10,
var sort: Sort? = null,
var column: String? = null,
var filters: List<FilterDTO> = ArrayList<FilterDTO>(),
var paged: Boolean = true
)
class FilterDTO(
var field: String,
var value: Any,
var comparison: Comparison
)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.