2010-02-23 55 views
19

HttpServletRequest.getParameterValues() trả về một String[] chứa tất cả các giá trị của một tham số yêu cầu HTTP đã cho. Có ai biết nếu thứ tự của các giá trị trong mảng này được đảm bảo bởi đặc tả theo cùng thứ tự mà các giá trị đó được chuyển qua trong yêu cầu không?Sắp xếp các giá trị trong HttpServletRequest.getParameterValues ​​()

Ví dụ, nếu tôi có chuỗi truy vấn GET x=1&x=2&x=3, tôi đảm bảo nhận String[] {"1", "2", "3"} khi tôi gọi getParameterValues()? Nó dường như hoạt động trong thực tế, nhưng tôi không thể tìm thấy bất cứ điều gì mà chỉ ra rằng đây phải là trường hợp, vì vậy tôi miễn cưỡng dựa vào nó.

+1

Vì HttpServletRequest là một giao diện, nó phụ thuộc vào việc thực hiện nó. Mặc dù tôi sẽ ngạc nhiên nếu có một triển khai không trả lại các giá trị theo thứ tự nhận được. – Fortega

+0

Tài liệu giao diện * có thể * dictate hành vi nếu nhà thiết kế để lựa chọn, nhưng trong trường hợp này họ đã không. – skaffman

Trả lời

13

javadoc cho ServletRequest (v2.5 javadoc) không đề cập đến bất kỳ thứ gì về thứ tự các giá trị cho phương thức đó. Như vậy, tôi sẽ không dựa vào thứ tự được bảo tồn.


Cập nhật: cũng đã kiểm tra tài liệu spec cho 2.5, chứa thông tin sau liên quan đến getParameterValues ​​(). Nó không đề cập đến bất cứ điều gì về thứ tự liên quan đến chuỗi truy vấn, vì vậy tôi nghĩ rằng hành vi mà bạn đang xem là chi tiết triển khai, không được định nghĩa là một phần của giao diện.

Các thông số được lưu trữ dưới dạng tập hợp các cặp tên-giá trị . Nhiều tham số giá trị có thể tồn tại cho bất kỳ tên thông số cụ thể nào. Các phương pháp sau của giao diện ServletRequest là sẵn các thông số truy cập:

  • getParameter
  • getParameterNames
  • getParameterValues ​​
  • getParameterMap

các getParameterVa phương thức lues trả về một mảng của các đối tượng String chứa tất cả các giá trị tham số được kết hợp với tên tham số . Giá trị trả về từ phương thức getParameter phải là giá trị đầu tiên trong mảng của chuỗi đối tượng được trả về bởi getParameterValues. Phương thức getParameterMap trả về một java.util.Map của tham số của yêu cầu , có chứa tên là khóa và giá trị tham số làm giá trị bản đồ.

Để tham khảo trong tương lai, các thông số kỹ thuật Java Servlet có thể được tải về từ Sun, I mean Oracle's website. Bạn có thể kiểm tra kỹ phiên bản servlet cụ thể mà bạn quan tâm ở đó.

7

Nó thực sự không rõ ràng trong definied spec Servlet, nhưng ít nhất các hình thức HTML spec definies nó một cách rõ ràng trong phần application/x-www-form-urlencoded:

2.The tên kiểm soát/giá trị được liệt kê theo thứ tự chúng xuất hiện trong tài liệu.

Vì vậy, phần đó an toàn.Bây giờ servletcontainer, một cách hợp lý, việc thực hiện tốt và hiệu quả sẽ xử lý luồng đầu vào HTTP ngay lập tức khi nó đi vào, vì vậy các tham số sẽ được xử lý theo thứ tự như chúng xuất hiện trong URI yêu cầu (GET) hoặc cơ thể yêu cầu (POST). Thu thập chúng trong một String[] là sự lựa chọn đơn giản nhất vì nó cũng được sử dụng như trong API Servlet, vì vậy tôi thực sự không thấy bất kỳ lý do nào để thu thập nó theo cấu trúc HashSet trước, hoặc thực hiện Collections#shuffle() hoặc bất kỳ thứ gì chuyển đổi nó thành String[] sau đó. Tôi có thể ít nhất là từ kinh nghiệm, Tomcat làm đúng cách, vì vậy tất cả các thùng chứa/ứng dụng chính được xây dựng trên đỉnh của Tomcat/Catalina (Websphere của IBM, JBoss AS, Sun Glassfish, v.v.) cũng sẽ hành xử như vậy . Tôi chỉ không có kinh nghiệm với Weblogic, nhưng tôi sẽ ngạc nhiên nếu nó xử lý nó một cách khác nhau (đọc: kém hiệu quả hơn).

Chỉ có thứ tự của tham số tên không được đảm bảo, hợp lý bởi vì nó được hỗ trợ bởi HashMap.


Tóm tắt: tham số được thu thập trong HashMap<String, String[]>. Tên được kiểm dịch không được đặt hàng do bản chất của HashMap. Các giá trị (một tên thông số có thể có nhiều giá trị, ví dụ: foo=bar1&foo=bar2&foo=bar3) lần lượt được đặt hàng do bản chất của String[], mặc dù điều này không được chỉ định rõ ràng trong API Servlet.

Để an toàn, bạn muốn sử dụng một cách tiếp cận khác, ví dụ:

foos=3&foo[0]=bar1&foo[1]=bar2&foo[2]=bar3 

với

int foos = Integer.valueOf(request.getParameter("foos")); 
for (int i = 0; i < foos; i++) { 
    int foo = Integer.valueOf(request.getParameter("foo[" + i + "]")); 
} 
+2

Dựa vào điều gì đó không được ủy quyền bởi đặc tả Servlet là lỗi của IMHO. Nếu bạn làm thế, bạn chỉ cần mạo hiểm để làm cho ứng dụng của bạn không thể di chuyển được. Chắc chắn, người ta có thể tranh luận về việc triển khai container không hiệu quả nhưng điều đó không thay đổi bất cứ điều gì, đó là kỳ vọng sai ở cuối (bất kể có bao nhiêu triển khai sử dụng Tomcat). –

+0

Đó là một trường hợp góc. – BalusC

+2

Servlet Spec thực sự nên thực thi một lệnh. Điều này sẽ làm cho các tham số có nhiều giá trị hữu ích hơn nhiều vì bạn có thể tương quan các tham số liên quan từ một hàng trong bảng ví dụ. – Ryan

0

Nó phụ thuộc vào HttpServletRequest thực hiện giao diện.

+8

Tại sao bạn lặp lại nhận xét/câu trả lời đã cho? Vui lòng thêm một cái gì đó mới hoặc chỉ upvote câu trả lời bạn đồng ý và di chuyển dọc theo :) – BalusC

10

Vâng, thứ tự của các giá trị được trả về bởi getParamterValues(String) và các mục trong getParameterMap() đảm bảo bởi các Servlet Specification. Đây là đoạn văn:

Dữ liệu từ chuỗi truy vấn và nội dung bài được tổng hợp thành thông số yêu cầu được đặt. Chuỗi truy vấn dữ liệu được hiển thị trước dữ liệu bài đăng . Ví dụ, nếu một yêu cầu là thực hiện với một chuỗi truy vấn của một = hello và một cơ thể bài của a = tạm biệt & a = thế giới, kết quả tham số thiết lập sẽ ra lệnh a = (xin chào, tạm biệt, thế giới).

(Đây là từ phần "HTTP Nghị định thư thông số" trong "Yêu cầu" chương của Servlet Thông số kỹ thuật (SRV.4.1 trong phiên bản 2.4, SRV.3.1 trong phiên bản 2.5).)

không dường như là cách sạch sẽ để nhận tên theo thứ tự (getParameterNames() không không trả lại tên theo thứ tự mà trình duyệt đã cung cấp). Tôi có thể giả sử, phân tích chuỗi GET thô từ getQueryString() hoặc phân tích chuỗi POST thô từ getInputStream(), nhưng thay vào đó tôi nghĩ tôi sẽ thêm thông số ẩn khác và sau đó sử dụng getParameterValues(String) để nhận đơn đặt hàng.

Nếu bạn tò mò tại sao tôi muốn các thông số theo thứ tự, đó là bởi vì tôi có điều khiển mà người dùng có thể sắp xếp lại sử dụng jQuery, và tôi muốn biết thứ tự mà người dùng đã chọn:

<form> 
    <ul id=variables> 
    <li> 
     <input name=hello>hello 
     <input type=hidden name=variableOrder value=hello> 
    <li> 
     <input name=world>world 
     <input type=hidden name=variableOrder value=world> 
    </ul> 
</form> 
<script src="jquery.js"></script> 
<script src="jquery-ui.js"></script> 
<script> 
    jQuery('#variables').sortable().disableSelection(); 
</script> 
+5

Điều này không (rõ ràng) nói bất cứ điều gì về việc đặt hàng trong dữ liệu chuỗi truy vấn hoặc dữ liệu bài đăng, chỉ có 'dữ liệu bài đăng' sẽ xuất hiện sau' dữ liệu chuỗi truy vấn'. Đảm bảo đầy đủ được ngụ ý trong ví dụ này và việc triển khai tham chiếu tuân theo thứ tự ban đầu, nhưng ... – beetstra

2

Tôi đã có một vấn đề để trích xuất bản đồ giá trị param từ HttpServletRequest theo thứ tự phù hợp với các yếu tố trên JSP. Tôi đã viết một OrderedRequestMap phân tích cú pháp một thân yêu cầu POST/x-www-form-urlencoded POST.

import java.io.IOException; 
import java.io.InputStream; 
import java.io.InputStreamReader; 
import java.io.UnsupportedEncodingException; 
import java.net.URLDecoder; 
import java.util.Arrays; 
import java.util.LinkedHashMap; 
import java.util.Map; 


public class OrderedRequestMap extends LinkedHashMap<String,String[]> { 

private final String encoding; 

public OrderedRequestMap(InputStream httpBody, String encoding) throws IOException { 
    this.encoding = encoding; 
    fill(httpBody); 
} 

private void fill(InputStream is) throws IOException { 
    final InputStreamReader reader = new InputStreamReader(is, "ASCII"); 
    int c; 
    StringBuilder sb = new StringBuilder(1000); 
    while ((c = reader.read()) != -1) { 
     char ch = (char)c; 
     if (ch == '&') { 
      put(sb.toString()); 
      sb = new StringBuilder(1000); 
     } else { 
      sb.append(ch); 
     } 
    } 
    put(sb.toString()); 
} 

private void put(String parameter) throws UnsupportedEncodingException { 
    String[] pair = parameter.split("="); 
    if (pair.length == 0) 
     return; 
    String key = URLDecoder.decode(pair[0], encoding); 
    String val = EMPTY_STR; 
    if (pair.length > 1) 
     val = URLDecoder.decode(pair[1], encoding); 
    String[] values = get(key); 
    if (values == null) 
     values = new String[]{val}; 
    else { 
     values = Arrays.copyOf(values, values.length+1); 
     values[values.length - 1] = val; 
    } 
    put(key, values); 
} 


private static final String EMPTY_STR = ""; 
} 

Và gọi nó như thế này

new OrderedRequestMap(request.getInputStream(), request.getCharacterEncoding()); 

Hope, nó giúp.

Các vấn đề liên quan