2009-08-05 22 views
55

Nếu tôi ánh xạ ứng dụng mùa xuân của mình để xử lý tất cả các yêu cầu gửi đến ('/ *'), thì các yêu cầu cho nội dung tĩnh trả về 404. Ví dụ: yêu cầu "myhost.com/css/global.css" sẽ trả về 404, mặc dù tài nguyên tồn tại khi Spring chặn yêu cầu.SpringMVC có thể được cấu hình để xử lý tất cả các yêu cầu, nhưng không bao gồm các thư mục nội dung tĩnh?

Cách khác là ánh xạ SpringMVC vào thư mục con (ví dụ '/ home/'), nhưng trong trường hợp này, bạn phải vượt qua thư mục này trong tất cả các liên kết trong ứng dụng. Có cách nào để ánh xạ SpringMVC đến '/' và loại trừ một tập hợp các thư mục để xử lý không?

cấu hình web.xml hiện tại của tôi là:

<servlet> 
    <servlet-name>springApp</servlet-name> 
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 
    <load-on-startup>2</load-on-startup> 
</servlet> 

<servlet-mapping> 
    <servlet-name>springApp</servlet-name> 
    <url-pattern>/home/*</url-pattern> 
</servlet-mapping> 

Idealy Tôi muốn có các bản đồ có một cái gì đó như sau:

<servlet-mapping> 
    <servlet-name>springApp</servlet-name> 
    <url-pattern>/*</url-pattern> 
    <exclude>/css/*,/js/*</exclude> 
</servlet-mapping> 

là loại điều có thể?

Trả lời

7

Nếu bạn muốn làm điều này với mùa xuân duy nhất, đó là có thể, nhưng một chút lộn xộn:

  1. Bạn có thể sẽ cần phải sử dụng một SimpleUrlHandlerMapping mà bạn có thể xác định rõ ràng các mẫu URL cần được ánh xạ tới bộ điều khiển HOẶC mở rộng nó để hỗ trợ các URL "bỏ qua" như "css/**".
  2. Bạn sẽ cần phải viết thực hiện HttpRequestHandler của riêng mình về cơ bản sẽ bao gồm "getServletContext(). GetRequestDsipatcher(). Include()" gọi để trả về tài nguyên được yêu cầu.
  3. Bạn sẽ phải đăng ký trình xử lý đó làm mặc địnhHandler cho SimpleUrlHandlerMapping ở trên.

Sau khi tất cả được thực hiện, tất cả các yêu cầu không thể ánh xạ tới bộ điều khiển của bạn sẽ được chuyển tiếp đến số HttpRequestHandler và được phân phối "nguyên trạng".

+1

Tôi hiện đang sử dụng DefaultAnnotationHandlerMapping để thực hiện ánh xạ dựa trên chú thích của bộ điều khiển. Dựa trên đề xuất của bạn, tôi sẽ mở rộng nó và thêm hỗ trợ cho các loại trừ dựa trên đường dẫn. Cám ơn đã chỉ tôi hướng đi đúng. –

+0

Câu trả lời thú vị! –

+0

Trong trường hợp bất cứ ai bỏ lỡ nó, lưu ý rằng một giải pháp tốt hơn nhiều tồn tại cho mùa xuân 3.x. Hãy xem câu trả lời dưới đây! –

2

Bạn đang sử dụng gì để phục vụ hình ảnh tĩnh của mình? Nếu đó là Apache thì bạn có thể định cấu hình Apache để không chuyển yêu cầu css/js tới máy chủ ứng dụng của bạn.

Nếu bạn đang sử dụng Tomcat bạn muốn đặt một cái gì đó như thế này trong httpd.conf của bạn:

JkUnMount /*.css webapp 

đâu webapp 'là sự xâm nhập từ workers.properties của bạn.

Rất tiếc, tôi không thể cung cấp cho bạn giải pháp Spring nguyên chất, nhưng đây là cách tôi làm.

+1

Đây là một mẹo tuyệt vời, nhưng tôi đang tìm thứ gì đó cầm tay; Vì vậy, khi WAR được lắp ráp được đặt vào một thùng chứa servlet, nó sẽ hoạt động mà không cần cấu hình bên ngoài. –

3

Một cách để thực hiện điều đó là với Bộ lọc. Bạn sẽ phải viết một chút mã tùy chỉnh nhưng nó không phải là xấu. Dưới đây là một ví dụ nếu bạn không muốn để vượt qua * .css hoặc * .js file servlet mùa xuân của bạn:

web.xml:

<filter-mapping> 
    <filter-name>fileTypeFilter</filter-name> 
    <filter-class>foo.FileTypeFilter</filter-class> 
    <url-pattern>/*</url-pattern> 
</filter-mapping> 

Java lớp:

public class FileTypeFilter implements Filter { 
    public void init(FilterConfig conf) { 
     // init logic here 
    } 

    public void destroy() { 
     // release resources here 
    } 

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws ServletException, IOException { 
      if(shouldExclude(req)) { 
       chain.doFilter(req, res); 
       //some logic so the request doesnt go to the servlet 

       //maybe you could just forward 
       //the request directly to the file getting accessed. not sure if that would work 
      } 

      //file should be passed to the servlet; you can do some logic here 
      //if you want   
    } 
    private boolean shouldExclude(ServletRequest req) { 
     if(req instanceof HttpServletRequest) { 
      HttpServletRequest hreq = (HttpServletRequest) req; 
      return (hreq.getRequestURI().endsWith(".css") || 
        hreq.getRequestURI().endsWith(".js")); 
     } 
     return false; 
    } 
} 

tôi chưa thử nghiệm điều này, nhưng tôi nghĩ nó sẽ hoạt động.

EDIT: Không có chức năng loại trừ nào trong thông số kỹ thuật servlet. Tôi không nghĩ rằng có một cách tốt để làm điều này trong mùa xuân, nhưng về cơ bản nó đạt được điều tương tự trong bài viết của bạn.

EDIT 2: Nếu bạn muốn có thể dễ dàng thay đổi nội dung được lọc, bạn có thể sử dụng Spring để chèn thứ gì đó vào Bộ lọc lúc chạy.

CHỈNH SỬA 3: Tôi vừa nhận ra nếu bạn chuyển tiếp trực tiếp đến tệp, nó sẽ thực hiện lại bộ lọc và bạn sẽ bị phát hiện trong vòng lặp vô hạn. Có thể có một cách khác để làm điều này với các bộ lọc, nhưng tôi thành thật không chắc chắn nó là gì.

+0

giống như giải pháp +1 – Gurnard

0

Bạn có một (các) tiện ích nhất quán cho các yêu cầu bạn muốn xử lý bởi điều phối viên Spring (Tôi tin rằng hầu hết các ví dụ mùa xuân sử dụng * .htm)? Trong trường hợp đó, bạn có thể ánh xạ tới các phần mở rộng mà bạn muốn xử lý sẽ bỏ qua các tệp css và js của bạn.

Nếu không, tôi đồng ý với Nalandial, cách tiếp cận Bộ lọc có lẽ là công việc tốt nhất vào thời điểm này.

+0

Tôi đang sử dụng url an toàn, do đó không có phần mở rộng cho bất kỳ thứ gì trong ứng dụng, do đó ánh xạ hậu tố sẽ không hoạt động đối với tôi. –

27

Tôi đã giải quyết bằng cách phân phối nội dung tĩnh thông qua servlet 'mặc định', chỉ phục vụ nội dung cho khách hàng. Vì vậy, web.xml của tôi trông giống như sau:

<servlet> 
    <servlet-name>MyApp</servlet-name> 
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 
</servlet> 
<servlet-mapping> 
    <servlet-name>MyApp</servlet-name> 
    <url-pattern>/</url-pattern> 
</servlet-mapping> <!-- The 'dynamic' content --> 

<servlet-mapping> 
    <servlet-name>default</servlet-name> 
    <url-pattern>*.css</url-pattern> 
</servlet-mapping> 
<servlet-mapping> 
    <servlet-name>default</servlet-name> 
    <url-pattern>*.js</url-pattern> 
</servlet-mapping> 
<servlet-mapping> 
    <servlet-name>default</servlet-name> 
    <url-pattern>*.jpg</url-pattern> 
</servlet-mapping> <!-- The 'static' content --> 

Hy vọng điều này sẽ hữu ích.

+0

Tôi cũng đã xem xét giải pháp này - vấn đề duy nhất của tôi với nó là: Tôi không tin nó là di động và b: Tôi gặp khó khăn khi ánh xạ đường dẫn "/" qua chú thích. Nếu hai điều này có thể được giải quyết, đây sẽ là giải pháp hoàn hảo cho tôi. –

+0

Xin lỗi nếu tôi trả lời trễ, tôi đã ra khỏi thị trấn. Có thể là you'r đúng về vấn đề di chuyển. Tôi không có vấn đề này bởi vì tôi bị mắc kẹt trên tomcat. Có lẽ bạn có thể bao gồm trong cuộc chiến DefaultServlet. Về đường dẫn "/" thông qua chú thích, trong cấu hình của tôi (IndexController chú thích mức phương thức) nó hoạt động với @RequestMapping (value = "/"). Với bộ điều khiển chú thích cấp lớp đôi khi tôi cần chú thích cách này @RequestMapping (value = "") –

+0

Giải pháp tuyệt vời nếu bạn chạy một cá thể phát triển và không muốn bị làm phiền khi thiết lập máy chủ Web cho phương tiện tĩnh. –

-1

Đó là sạch để sử dụng UrlRewriteFilter để chuyển hướng yêu cầu để servlet của bạn, đây là một ví dụ về urlrewrite.xml

<urlrewrite> 
    <rule> 
     <from>^/img/(.*)$</from> 
     <to>/img/$1</to> 
    </rule> 
    <rule> 
     <from>^/js/(.*)$</from> 
     <to>/js/$1</to> 
    </rule> 
    <rule> 
     <from>^/css/(.*)$</from> 
     <to>/css/$1</to> 
    </rule> 
    <rule> 
     <from>^/(.*)$</from> 
     <to>/app/$1</to> 
    </rule> 
    <outbound-rule> 
     <from>/app/(.*)$</from> 
     <to>/$1</to> 
    </outbound-rule> 
</urlrewrite> 

GHI CHÚ:

  • Điều quan trọng là người cuối cùng <rule> là ở phía dưới cái img, js , css sẽ bị bắt trước tiên
  • <outbound-rule> là tùy chọn và chỉ để làm cho số hiện tại
    <c:url value="/app/some" /> hiển thị /some thay vì /app/some
56

Chú ý: câu trả lời này áp dụng cho mùa xuân 3.0.4+ CHỈ

(BTW, câu hỏi này cũng đã được xử lý ở đây: Spring serving static content with mvc:resources, invalid xsd)

Check-out mùa xuân dự án mvc-showcase vào mùa xuân subversion samples repository. Nó cho thấy chính xác những gì bạn muốn làm, cụ thể là bạn có thể phân định các tài nguyên tĩnh mà sẽ không được xử lý bởi DisapatcherServlet. Xem tập tin /mvc-showcase/src/main/webapp/WEB-INF/spring/appServlet/servlet-context.xml. Dưới đây là một đoạn làm thế nào tôi xử lý các ngoại lệ, nơi JS, CSS, và hình ảnh là trong thư mục gốc bối cảnh ứng dụng (với không gian tên MVC ánh xạ tới mvc:

<!-- resources exclusions from servlet mapping --> 
<mvc:resources mapping="/css/**" location="/css/" /> 
<mvc:resources mapping="/images/**" location="/images/" /> 
<mvc:resources mapping="/js/**" location="/js/" /> 
+6

Lưu ý: Dự án giới thiệu Spring MVC đã chuyển sang github. Truy cập tại đây: https://github.com/SpringSource/spring-mvc-showcase – WarFox

+0

Bạn sẽ làm điều tương tự như thế nào trong cấu hình bằng chú thích? – Jackie

+0

nm http://stackoverflow.com/questions/14299149/how-to-use-spring-mvcs-mvcresources-tag-in-a-java-application-context – Jackie

0

Thông thường, các trang web lớn thích sử dụng máy chủ khác chỉ để Xử lý nội dung tĩnh Yêu cầu nội dung tĩnh đi tới một máy chủ và động sẽ chuyển sang một máy chủ khác và động sẽ chuyển sang một máy chủ khác (với lò xo, trong trường hợp này). và máy chủ rất nhanh

Nhưng điều này không phải là tầm thường để thực hiện. Rất nhiều cấu hình.

4

đơn giản nhất cách cho tôi (nếu sử dụng một phiên bản cuối đủ của Spring) là

<mvc:resources mapping="/**/*.js" location="/"/> 
<mvc:resources mapping="/**/*.css" location="/"/> 
... 
+1

Tôi thích giải pháp này vì tôi đang thêm mùa xuân vào trang web cũ có nội dung tĩnh trên toàn bộ địa điểm. Tất cả các ví dụ khác mà tôi gặp phải không tính đến điều đó. Cảm ơn bạn! – Jason

0

tôi sử dụng đường dẫn URL ảo để lấy tài nguyên tôi cần. Thông thường tôi sử dụng Spring MVC, vì vậy tôi không thể có javascripts và css trong thư mục/WEB-INF/views. Tôi đã đưa ra servlet tùy chỉnh này để CHỈ cho phép truy cập vào các tệp .js & .css trong thư mục/WEB-INF/views. Trong trường hợp của bạn, nếu bạn di chuyển thư mục/css và thư mục/js vào thư mục mẹ như/resource thì giải pháp của tôi sẽ được áp dụng cho bạn.

Bạn có thể thay đổi url String = "YOUR_RESOURCE_FOLDER"

Vì vậy, ví dụ, đường dẫn ảo có thể được cái gì đó như http://www.mysite.com/resources/path/path/app.js

Điều đó sẽ ánh xạ của tôi/WEB-INF/views/path/path/app .js

web.xml

<servlet> 
    <servlet-name>ResourceDispatcherServlet</servlet-name> 
    <servlet-class>mywebapp.web.ResourceDispatcherServlet</servlet-class> 
</servlet> 

<servlet-mapping> 
    <servlet-name>ResourceDispatcherServlet</servlet-name> 
    <url-pattern>/resource/*</url-pattern> 
</servlet-mapping> 

servlet

public class ResourceDispatcherServlet extends HttpServlet { 

    public void init() throws ServletException { 

    } 

    public void doGet(HttpServletRequest req, HttpServletResponse rsp) throws ServletException, IOException { 


     String servletPath = req.getServletPath(); // /resource 
     String pathInfo = req.getPathInfo();   // /path/path/app.js 

     String url = "/WEB-INF/views" + pathInfo; 

     String lastPath = StringUtil.substringAfterLast(pathInfo, "/"); 
     String extension = StringUtil.substringAfterLast(lastPath, "."); 

     try { 
      RequestDispatcher dispatcher = null; 
      if (!StringUtil.isEmpty(extension) && ("js".equals(extension) || "css".equals(extension))) { 
       dispatcher = req.getRequestDispatcher(url); 
      } 

      if (dispatcher != null) { 
       dispatcher.include(req, rsp); 
      } 
      else { 
       rsp.sendError(404); 
      } 
     } 
     catch (Exception e) { 
      if (!rsp.isCommitted()) { 
       rsp.sendError(500); 
      } 
     } 
    } 
} 
0

Nếu bạn đang sử dụng Spring 3.0.4 trở lên bạn nên sử dụng solution provided by atrain

Nếu không, bạn có thể làm điều này đơn giản điều:

có lẽ bạn đã sau cấu trúc thư mục tĩnh bạn muốn phục vụ:

WebContent 
    | 
    WEB-INF 
    | 
    public 
     | 
     css 
     | 
     js 
     | 
     img 

Eclipse Dự án web động theo mặc định tạo cấu trúc sau: WebContent/WEB-INF. Di chuyển thư mục public ra khỏi thư mục WEB-INF của bạn vào thư mục WebContent.

Về phía khách hàng

tham khảo các tập tin tĩnh của bạn theo cách sau:

<link rel="stylesheet" type="text/css" href="public/css/mystyles.css"> 

Đây là reference.

2

Tôi có cùng một vấn đề của tôi và đây là cách tôi giải quyết nó:

Sau đây đã được thêm vào tệp web.xml:

<servlet-mapping> 
    <servlet-name>default</servlet-name> 
    <url-pattern>*.js</url-pattern> 
    <url-pattern>*.css</url-pattern> 
    <url-pattern>*.ico</url-pattern> 
    <url-pattern>*.png</url-pattern> 
    <url-pattern>*.jpg</url-pattern> 
    <url-pattern>*.htc</url-pattern> 
    <url-pattern>*.gif</url-pattern> 
    <url-pattern>*.html</url-pattern> 
    <url-pattern>*.htm</url-pattern> 
</servlet-mapping> 

Sau đây đã được thêm vào spring3 MVC servlet tập tin định nghĩa bean (như applicationContext.xml, các tập tin đã được cấu hình trong web.xml như contextConfigLocation.):

<mvc:annotation-driven /> 
<mvc:default-servlet-handler /> 
-1

Trong trường hợp của tôi tất cả mọi thứ đều ổn. Nhưng tôi gặp sự cố trong Bộ điều khiển

đó là vấn đề của tôi @RequestMapping (method = RequestMethod.GET)

y thay đổi cho việc này:

@RequestMapping(value = "/usuario", method = RequestMethod.GET) 

và nó hoạt động

nhìn cho một bộ điều khiển có @RequestMappgin xấu và thay đổi.

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