Sự khác biệt giữa / và / * trong mẫu url ánh xạ servlet


175

Mã quen thuộc:

<servlet-mapping>
    <servlet-name>main</servlet-name>
    <url-pattern>/*</url-pattern>
</servlet-mapping>

<servlet-mapping>
    <servlet-name>main</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

Hiểu biết của tôi là /*bản đồ đến http://host:port/context/*.

Thế còn /? Nó chắc chắn không ánh xạ đến http://host:port/contextroot. Trong thực tế, nó sẽ chấp nhận http://host:port/context/hello, nhưng từ chối http://host:port/context/hello.jsp.

Bất cứ ai có thể giải thích làm thế nào là http://host:port/context/hellobản đồ?

Câu trả lời:


268

<url-pattern>/*</url-pattern>

Trên /*một servlet ghi đè tất cả các servlet khác, bao gồm tất cả các servlet được cung cấp bởi servletcontainer, chẳng hạn như servlet mặc định và servlet JSP. Bất cứ yêu cầu nào bạn bắn, nó sẽ kết thúc trong servlet đó. Do đó, đây là một mẫu URL xấu cho các servlet. Thông thường, bạn chỉ muốn sử dụng /*trên một Filter. Nó có thể cho phép yêu cầu tiếp tục với bất kỳ servlet nào nghe trên một mẫu URL cụ thể hơn bằng cách gọi FilterChain#doFilter().

<url-pattern>/</url-pattern>

Các /không ghi đè lên bất kỳ servlet khác. Nó chỉ thay thế servlet mặc định của servletcontain cho tất cả các yêu cầu không khớp với bất kỳ servlet đã đăng ký nào khác. Điều này thường chỉ được gọi trên các tài nguyên tĩnh (CSS / JS / image / etc) và danh sách thư mục. Servlet mặc định của servletcontainer cũng có khả năng xử lý các yêu cầu bộ đệm HTTP, truyền phát phương tiện (âm thanh / video) và tiếp tục tải xuống tệp. Thông thường, bạn không muốn ghi đè servlet mặc định vì nếu không bạn sẽ phải lo tất cả các tác vụ của nó, điều này không chính xác (thư viện tiện ích JSF OmniFaces có một ví dụ nguồn mở ). Do đó, đây cũng là một mẫu URL xấu cho các servlet. Về lý do tại sao các trang JSP không đánh vào servlet này, đó là bởi vì servlet JSP dựng sẵn của servlet sẽ được gọi, mặc định đã được ánh xạ trên mẫu URL cụ thể hơn *.jsp.

<url-pattern></url-pattern>

Sau đó, cũng có mẫu URL chuỗi trống . Điều này sẽ được gọi khi root ngữ cảnh được yêu cầu. Điều này khác với <welcome-file>cách tiếp cận mà nó không được gọi khi bất kỳ thư mục con nào được yêu cầu. Đây rất có thể là mẫu URL mà bạn thực sự đang tìm kiếm trong trường hợp bạn muốn có một "dịch vụ trang chủ ". Tôi chỉ phải thừa nhận rằng tôi trực giác mong đợi mẫu URL chuỗi rỗng và mẫu URL gạch chéo /được xác định chính xác theo cách khác, vì vậy tôi có thể hiểu rằng rất nhiều người mới bắt đầu đã nhầm lẫn về điều này. Nhưng đó là những gì nó được.

Bộ điều khiển phía trước

Trong trường hợp bạn thực sự có ý định để có một servlet front controller, sau đó bạn muốn bản đồ tốt nhất nó trên một mẫu URL cụ thể hơn như *.html, *.do, /pages/*, /app/*, vv Bạn có thể ẩn đi phía trước mẫu URL điều khiển và bìa các tài nguyên tĩnh trên một mẫu URL chung như /resources/*, /static/*v.v với sự trợ giúp của bộ lọc servlet. Xem thêm Cách ngăn chặn tài nguyên tĩnh được xử lý bởi servlet bộ điều khiển phía trước được ánh xạ trên / * . Đáng chú ý là Spring MVC có một servlet tài nguyên tĩnh tích hợp, vì vậy đó là lý do tại sao bạn có thể ánh xạ bộ điều khiển phía trước của nó /nếu bạn định cấu hình một mẫu URL phổ biến cho tài nguyên tĩnh trong Spring. Xem thêm Cách xử lý nội dung tĩnh trong Spring MVC?


9
Cảm ơn. Sau một số nghiên cứu, tôi muốn làm rõ một điểm tinh tế. / ghi đè lên servlet mặc định mà máy chủ web cài đặt. Ví dụ: Tomcat cài đặt DefaultServlet phục vụ tài nguyên tĩnh. Sử dụng / thoát khỏi servlet mặc định như là một tác dụng phụ (rất có thể không mong muốn).
Kẹo Chiu

Chà, tôi sẽ không gọi nó là "ghi đè", mà là "thay thế". Nó có thể hữu ích để thay thế các servlet mặc định như thế.
BalusC

1
<url-mẫu> </ url-mẫu> gây ra lỗi: <url-mẫu> không hợp lệ trong ánh xạ servlet
mỏng

Thông báo lỗi là từ tomcat, không phải IDE của tôi; tuy nhiên, tôi đang sử dụng Tomcat 6, vì vậy đó có lẽ là vấn đề;)
mỏng

2
@BalusC, bạn có thể vui lòng cho tôi biết /**mô hình nào cho biết?
Sajib Acharya

45

Tôi muốn bổ sung câu trả lời của BalusC bằng các quy tắc ánh xạ và một ví dụ.

Quy tắc ánh xạ từ đặc tả Servlet 2.5:

  1. Bản đồ URL chính xác
  2. Bản đồ đường dẫn ký tự đại diện
  3. Bản đồ mở rộng
  4. Ánh xạ tới servlet mặc định

Trong ví dụ của chúng tôi, có ba servlet. / là servlet mặc định được cài đặt bởi chúng tôi. Tomcat cài đặt hai servlet để phục vụ jsp và jspx. Vì vậy, để bản đồhttp://host:port/context/hello

  1. Không có dịch vụ URL chính xác được cài đặt, tiếp theo.
  2. Không có đường dẫn ký tự đại diện được cài đặt, tiếp theo.
  3. Không phù hợp với bất kỳ tiện ích mở rộng nào, tiếp theo.
  4. Ánh xạ tới servlet mặc định, trả về.

Để lập bản đồ http://host:port/context/hello.jsp

  1. Không có dịch vụ URL chính xác được cài đặt, tiếp theo.
  2. Không có đường dẫn ký tự đại diện được cài đặt, tiếp theo.
  3. Tìm thấy mở rộng servlet, trở lại.

25

Có lẽ bạn cũng cần biết các url được lập bản đồ như thế nào, vì tôi đã chịu đựng 404hàng giờ. Có hai loại xử lý yêu cầu xử lý. BeanNameUrlHandlerMappingSimpleUrlHandlerMapping. Khi chúng tôi xác định a servlet-mapping, chúng tôi đang sử dụng SimpleUrlHandlerMapping. Một điều chúng ta cần biết là hai trình xử lý này có chung một thuộc tính được gọi là alwaysUseFullPathmặc định false.

falseở đây có nghĩa là Spring sẽ không sử dụng đường dẫn đầy đủ để ánh xạ url tới bộ điều khiển. Nó có nghĩa là gì? Nó có nghĩa là khi bạn xác định một servlet-mapping:

<servlet-mapping>
    <servlet-name>viewServlet</servlet-name>
    <url-pattern>/perfix/*</url-pattern>
</servlet-mapping>

xử lý thực sự sẽ sử dụng *một phần để tìm bộ điều khiển. Ví dụ: bộ điều khiển sau sẽ gặp 404lỗi khi bạn yêu cầu nó sử dụng/perfix/api/feature/doSomething

@Controller()
@RequestMapping("/perfix/api/feature")
public class MyController {
    @RequestMapping(value = "/doSomething", method = RequestMethod.GET) 
    @ResponseBody
    public String doSomething(HttpServletRequest request) {
        ....
    }
}

Đó là một trận đấu hoàn hảo, phải không? Nhưng tại sao 404. Như đã đề cập trước đó, giá trị mặc định alwaysUseFullPathlà sai, có nghĩa là trong yêu cầu của bạn, chỉ /api/feature/doSomethingđược sử dụng để tìm Bộ điều khiển tương ứng, nhưng không có Bộ điều khiển quan tâm đến đường dẫn đó. Bạn cần thay đổi url của mình thành /perfix/perfix/api/feature/doSomethinghoặc xóa perfixkhỏi cơ sở MyControll @RequestingMapping.


8

Tôi nghĩ câu trả lời của Candy chủ yếu là đúng. Có một phần nhỏ tôi nghĩ khác.

Để ánh xạ máy chủ: cổng / bối cảnh / hello.jsp

  1. Không có dịch vụ URL chính xác được cài đặt, tiếp theo.
  2. Tìm thấy đường dẫn ký tự đại diện , trở về.

Tôi tin rằng tại sao "/ *" không khớp với máy chủ: port / bối cảnh / xin chào vì nó coi "/ hello" là một đường dẫn thay vì một tệp (vì nó không có phần mở rộng).


2

Sự khác biệt cơ bản giữa /*/là một servlet có ánh xạ /*sẽ được chọn trước bất kỳ servlet nào có ánh xạ mở rộng (như *.html), trong khi một servlet có ánh xạ /sẽ chỉ được chọn sau khi ánh xạ mở rộng được xem xét (và sẽ được sử dụng cho mọi yêu cầu không ' t khớp với bất cứ thứ gì khác --- nó là "servlet mặc định").

Cụ thể, /*ánh xạ sẽ luôn được chọn trước khi /ánh xạ. Việc ngăn chặn bất kỳ yêu cầu nào đến được servlet mặc định của chính bộ chứa.

Hoặc sẽ chỉ được chọn sau khi ánh xạ servlet khớp chính xác (như /foo/bar) và ánh xạ đường dẫn dài hơn /*(như /foo/*). Lưu ý rằng ánh xạ chuỗi trống là khớp chính xác cho gốc ngữ cảnh ( http://host:port/context/).

Xem Chương 12 của Đặc tả Servlet Java, có sẵn trong phiên bản 3.1 tại http://doad.oracle.com/otndocs/jcp/servlet-3_1-fr-eval-spec/index.html .

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.