我在Spring中为项目创建REST API。春季地图可选查询参数到SQL准备语句
我面临的问题是如何优雅地创建一个带有可变数量参数的PreparedStatement。
例如,我有一个产品的收集和我有很多的查询参数
/账户?的categoryId =不便&为了= ASC &价格= 上限= 10 &偏移= 300
问题是,这些参数可能会或可能不会设置。
目前,我有一些看起来像这样,但我还没有开始消毒用户输入
控制器
@RequestMapping(method = RequestMethod.GET)
public List<Address> getAll(@RequestParam Map<String, String> parameters) {
return addressRepository.getAll(parameters);
}
库
@Override
public List<Address> getAll(Map<String, String> parameters) {
StringBuilder conditions = new StringBuilder();
List<Object> parameterValues = new ArrayList<Object>();
for(String key : parameters.keySet()) {
if(allowedParameters.containsKey(key) && !key.equals("limit") && !key.equals("offset")) {
conditions.append(allowedParameters.get(key));
parameterValues.add(parameters.get(key));
}
}
int limit = Pagination.DEFAULT_LIMIT_INT;
int offset = Pagination.DEFAULT_OFFSET_INT;
if(parameters.containsKey("limit"))
limit = Pagination.sanitizeLimit(Integer.parseInt(parameters.get("limit")));
if(parameters.containsKey("offset"))
offset = Pagination.sanitizeOffset(Integer.parseInt(parameters.get("offset")));
if(conditions.length() != 0) {
conditions.insert(0, "WHERE ");
int index = conditions.indexOf("? ");
int lastIndex = conditions.lastIndexOf("? ");
while(index != lastIndex) {
conditions.insert(index + 2, "AND ");
index = conditions.indexOf("? ", index + 1);
lastIndex = conditions.lastIndexOf("? ");
}
}
parameterValues.add(limit);
parameterValues.add(offset);
String base = "SELECT * FROM ADDRESSES INNER JOIN (SELECT ID FROM ADDRESSES " + conditions.toString() + "LIMIT ? OFFSET ?) AS RESULTS USING (ID)";
System.out.println(base);
return jdbc.query(base, parameterValues.toArray(), new AddressRowMapper());
}
我能提高吗?或者,还有更好的方法?
这种方法的另一个问题是,我失去的参数类型安全。作为收集资源,我必须分页。每次查询参数映射时,我都必须检查它是否为LIMIT或OFFSET,并将参数值转换为long。我必须为每个允许的参数附加一组规则。我是否让这个过于复杂? – 2014-12-06 07:57:35
是的,我认为你让它变得复杂:)。您原来的方法中也丢失了类型安全性,主要是因为您收到一个Map作为参数。为此,您可以尝试@QueryParam,但namedParameters贴图仍然必须是Map 。如果你想使地图类型安全,那么在编写适用于所有参数的通用代码时就会失败。 –
2014-12-06 10:39:37