вівторок, 1 вересня 2015 р.

Spring MVC: Доступ до статичних ресурсів

     Статичні ресурси - це елементи веб-програми, які є статичними. Ось так просто. Тобто, це файли, які не змінюються протягом виконання програми, такі як CSS-стилі,  HTML-сторінки, скрипти JavaScript, зображення і т.п. Все б нічого, але, виявляється, Spring MVC не вміє їх обробляти, якщо йому в цьому не допомогти.

     Справа в тому, що по-замовчуванню, статичні запити обробляє так званий DefaultServlet, який створюється самим сервером і який привязаний до адреси /, тобто до кореневої папки веб-програми (web application root). Якщо програма отримала запит (request) і для нього зареєстровано відповідний сервлет в файлі web.xml, то цей сервлет буде викликано для обробки запиту. А коли відповідного сервлету не зареєстровано, запит буде оброблено згаданим "сервлетом по-замовчуванню" (java-allandsundry.com). Це він знає, як обробляти запити до статичних ресурсів.

     Але згідно концепції  Spring MVC феймворку, коренева папка веб-програми закріплена за так званим фронт-контролером, який називається DispatcherServlet (див. метод getServletMappings()):


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class MusicBoxDispatcherServlet 
       extends AbstractAnnotationConfigDispatcherServletInitializer {

 @Override
 protected String[] getServletMappings() {
  return new String[] { "/" };
 }
 
 @Override
 protected Class<?>[] getRootConfigClasses() {
  return new Class<?>[] { RootConfig.class };
 }
 
 /*
  * DispatcherServlet loads beans containing web components
     * such as controllers, view resolvers, and handler mappings
     * that are defined in the SpringAppConfig configuration 
     * class (using Java configuration).
  */
 @Override
 protected Class<?>[] getServletConfigClasses() {
  return new Class<?>[] { SpringAppConfig.class };
 }

}



      Таким чином, DispatcherServlet від Spring MVC перехоплює всі запити і дезактивує роботу серверного default-сервлету. Але обробляти статичні запити він не вміє. Щоб налаштувати таку обробку є два шляхи:
- підключити заново default-сервлет (docs.spring.io);
- налаштувати ResourceHandlerRegistry (docs.spring.io).

     Перший метод в мене не запрацював, проте реалізація його виглядає доволі простою (метод має знаходитись в класі, що створить Spring-контекст, його ім'я задане в методі getServletConfigClasses() ):


1
2
3
4
 @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }

     Для другого методу потрібно всі статичні ресурси покласти в одну кореневу папку, яку можна назвати, наприклад resources. Всередині цієї папки для зручності можна створити дерево каталогів, яке буде відображати ресурси, які там знаходяться:

--- resources
     --- images
     --- style
     --- html
     --- js

     Потім в методі addResourceHandlers(ResourceHandlerRegistry registry) підвязуємо цю директорію до шаблону веб-адреси:



 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
package com.musicbox.springmvcproject.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;

@Configuration
// Class is expected to contain details on beans
// that are to be created in the spring application context.

@EnableWebMvc
// in web.xml:  <mvc:annotation-driven>

@ComponentScan(basePackages="com.musicbox")
// Enable automatic component scanning

public class SpringAppConfig extends WebMvcConfigurerAdapter {

 @Bean
 public ViewResolver viewResolver() {
  InternalResourceViewResolver resolver =
    new InternalResourceViewResolver();
  resolver.setPrefix("/WEB-INF/views/");
  resolver.setSuffix(".jsp");
  resolver.setExposeContextBeansAsAttributes(true);
  return resolver;
 }
 
 
 // Handle static requests
 @Override
        public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/resources/**")
                 .addResourceLocations("/resources/")
                 .setCachePeriod(31556926);
    }



}

      Тоді звертатися, наприклад, до зображення, можна буде наступним чином (див. малюнок - файл index.jsp):


1
2
3
4
5
6
7
8
<!DOCTYPE html>

<html>
  <body background="resources/images/background-gramophone.jpg">
 <h1>Hello world!</h1>

  </body>
</html>  


     Останнім прикладом я аж ніяк не закликаю вас використовувати css інтегровані в html код. Ні.

     В даному випадку, дерево каталогів має такий вигляд:


     Зверніть увагу, що на відміну від випадку, коли програмуєте без використання фреймворку Spring, то шлях в:

<body background="resources/images/background-gramophone.jpg">


вказується відносний - відносно файлу, з якого проводиться виклик, тобто відносно index.jsp. І цей фрагмент мав би вигляд:
 
<body background="../../resources/images/background-gramophone.jpg">

     Також зверніть увагу на наявність та відсутність слешів на початку шляху (в методі
addResourceHandlers(ResourceHandlerRegistry registry) та в файлі index.jsp
) - це може бути джерелом помилок.

     Також наостанок зауважу, що для додавання до поточного jsp іншого jsp/html в мене запрацював варіант з директивою include (include directive):

1
<%@ include file="/resources/html/header_menu.html" %>

     І не запрацював варіант із подією include (include action):

1
<jsp:include page="/resources/html/header_menu.html" flush="true" />

     Можна почитати:
fruzenshtein.com
docs.spring.io
docs.spring.io
mkyong.com
 mytechnotes.biz
baeldung.com
kielczewski.eu
spring.io/blog
java-tips.org

Немає коментарів:

Дописати коментар