出于分页目的,我们的UI人员在Http标头中指定项目范围,如下所示:
Range: items=0-15
在后续请求中,来自网络的范围可以是
Range: items=16-31
Range: items=32-45
...等...等
在我的控制器SearchRequestController.java中,我试图提取这些范围,以便我可以通过设置开始和偏移量将其发送到Solr服务器以返回请求的卡盘中的值。
我正在做的如下(在SearchRequestController.java中):
@RequestMapping("/billsSearch")
@ResponseBody
public SearchResult searchBills(HttpServletRequest request,@RequestBody SearchRequest searchRequest){
String rangeRequest = request.getHeader("Range");
//(1)Parse the rangeRequest using some mechanism
//(2)Set the start using the first value of the range
//(3) Add the second value to the start to get the offset
searchRequest.setStart(startValue);
searchRequest.setOffset(offsetValue);
return searchHelper(request,searchRequest);
}
我有几个问题: 这是从服务器以分块方式请求数据的最佳方式吗?
如何从请求标题中提取范围?
我假设request.getHeader("Range")
将返回“items=16-31
”。
正则表达式是从此字符串中抓取16和31的最佳方法吗?
如果我决定使用正则表达式,如果我将范围标题更改为billItems = 16-31,表达式是否会中断?
我是一个正则表达式n00b,所以我很可能以错误的方式思考这个问题。
还有正则表达式的替代方法可以从SpringMVC中的http标头中解析这样的范围信息吗?
答案 0 :(得分:2)
这是从服务器以分块方式请求数据的最佳方式吗?
另一种方法是使用请求参数:
/billsSearch?from=15&to=31
顺便说一句,你可以使用@RequestHeader
注释:
public SearchResult searchBills(
@RequestBody SearchRequest searchRequest,
@RequestHeader("Range") String range) {
//...
}
如何从请求标头中提取范围? [...]正则表达式是从这个字符串中获取16和31的最佳方法吗?
我会剪切尾随的"items="
字符串,在-
字符上拆分并解析两个结果数字:
String[] ranges = range.substring("items=".length()).split("-");
int from = Integer.valueOf(ranges[0]);
int to = Integer.valueOf(ranges[1]);
答案 1 :(得分:2)
符合http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35
的简单范围标头解析器class Range {
Integer start;
Integer end;
Integer suffixLength;
}
public class Main {
public static void main(String[] args) {
String input = "bytes=33-22,-333,20-,-55,43-0002";
for (Range range : decodeRange(input)) {
if (range.suffixLength == null) {
System.out.printf("Range: %d->%s\n", range.start, range.end == null ? "enf of file" : range.end);
} else {
System.out.printf("Last %d bytes\n", range.suffixLength);
}
}
}
public static List<Range> decodeRange(String rangeHeader) {
List<Range> ranges = new ArrayList<>();
String byteRangeSetRegex = "(((?<byteRangeSpec>(?<firstBytePos>\\d+)-(?<lastBytePos>\\d+)?)|(?<suffixByteRangeSpec>-(?<suffixLength>\\d+)))(,|$))";
String byteRangesSpecifierRegex = "bytes=(?<byteRangeSet>" + byteRangeSetRegex + "{1,})";
Pattern byteRangeSetPattern = Pattern.compile(byteRangeSetRegex);
Pattern byteRangesSpecifierPattern = Pattern.compile(byteRangesSpecifierRegex);
Matcher byteRangesSpecifierMatcher = byteRangesSpecifierPattern.matcher(rangeHeader);
if (byteRangesSpecifierMatcher.matches()) {
String byteRangeSet = byteRangesSpecifierMatcher.group("byteRangeSet");
Matcher byteRangeSetMatcher = byteRangeSetPattern.matcher(byteRangeSet);
while (byteRangeSetMatcher.find()) {
Range range = new Range();
if (byteRangeSetMatcher.group("byteRangeSpec") != null) {
String start = byteRangeSetMatcher.group("firstBytePos");
String end = byteRangeSetMatcher.group("lastBytePos");
range.start = Integer.valueOf(start);
range.end = end == null ? null : Integer.valueOf(end);
} else if (byteRangeSetMatcher.group("suffixByteRangeSpec") != null) {
range.suffixLength = Integer.valueOf(byteRangeSetMatcher.group("suffixLength"));
} else {
throw new RuntimeException("Invalid range header");
}
ranges.add(range);
}
} else {
throw new RuntimeException("Invalid range header");
}
return ranges;
}
};
或查看here
答案 2 :(得分:1)
如果目标类型不是字符串,则@RequestParameter和@RequestHeader参数都要进行类型转换。如果你有一个Range类型,你可以创建一个转换器&lt; String,Range&gt;并将其注册到conversionService。然后你的控制器看起来会更清洁:
public SearchResult searchBills(
@RequestBody SearchRequest searchRequest,
@RequestHeader Range range) {
//...
}
如果它通常出现在控制器中,这将非常有用。或者如果它只是一个在控制器方法内部进行解析的地方就足够了。