从HttpHeader中获取范围值

时间:2012-01-12 19:54:29

标签: java spring-mvc solr pagination range

出于分页目的,我们的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标头中解析这样的范围信息吗?

3 个答案:

答案 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) {
        //...
    }

如果它通常出现在控制器中,这将非常有用。或者如果它只是一个在控制器方法内部进行解析的地方就足够了。