Springboot/Angular2 - Как обрабатывать URL-адреса HTML5?

Я считаю, что это простой вопрос, но я не мог найти ответ или хотя бы использовать правильные термины в поиске.

Я настраиваю Angular2 и Springboot вместе. По умолчанию Angular будет использовать пути, такие как localhost:8080\dashboard и localhost:8080\dashboard\detail.

Я хотел бы избежать использования пути как хэш, если это возможно. Как Angular документация заявляет:

Функция router обеспечиватьRouter устанавливает свойство LocationStrategy в PathLocationStrategy, что делает его стратегией по умолчанию. Мы можем переключиться на HashLocationStrategy с переопределением во время процесса начальной загрузки, если мы предпочитаем его.

И затем...

Почти все Angular 2 проекта должны использовать стиль HTML по умолчанию. Он создает URL-адреса, которые пользователям легче понять. И он сохраняет возможность выполнения рендеринга на стороне сервера позже.

Проблема в том, что когда я пытаюсь получить доступ к localhost:8080\dashboard, Spring будет искать некоторое сопоставление контроллера этому пути, которого у него не будет.

Whitelabel Error Page
There was an unexpected error (type=Not Found, status=404).
No message available

Сначала я думал, что все мои службы будут находиться под localhost:8080\api и все мои статические под localhost:8080\app. Но как я могу сказать Spring игнорировать запросы к этому пути app?

Есть ли лучшее решение с Angular2 или Boot?

Ответ 1

У меня есть решение для вас, вы можете добавить ViewController для пересылки запросов на Angular из Spring загрузки.

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class ViewController {

@RequestMapping({ "/bikes", "/milages", "/gallery", "/tracks", "/tracks/{id:\\w+}", "/location", "/about", "/tests","/tests/new","/tests/**","/questions","/answers" })
   public String index() {
       return "forward:/index.html";
   }
}

здесь я перенаправил все мои angular2 ( "/bikes", "/milages", "/gallery", "/tracks", "/tracks/{id:\w +}", "/location", "" /about "," /tests "," /tests/new "," /tests/ ** "," /questions "," /answers ") в мой SPA Вы можете сделать то же самое для своего предлога, и вы также можете перенаправить страницу ошибки 404 на индексную страницу в качестве следующего шага. Наслаждайтесь!

Ответ 2

Вы можете перенаправить все не найденные ресурсы на свою основную страницу, предоставив пользовательский ErrorViewResolver. Все, что вам нужно сделать, это добавить это в свой класс @Configuration:

@Bean
ErrorViewResolver supportPathBasedLocationStrategyWithoutHashes() {
    return new ErrorViewResolver() {
        @Override
        public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map<String, Object> model) {
            return status == HttpStatus.NOT_FOUND
                    ? new ModelAndView("index.html", Collections.<String, Object>emptyMap(), HttpStatus.OK)
                    : null;
        }
    };
}

Ответ 3

В моих приложениях загрузки Spring (версии 1 и 2) мои статические ресурсы находятся в одном месте:

src/main/resources/static

static является папкой, распознанной Spring Boot для загрузки статических ресурсов.

Тогда идея состоит в настройке конфигурации Spring MVC.
Более простой способ - использовать конфигурацию Java Spring.

Я реализую WebMvcConfigurer для переопределения addResourceHandlers(). Я добавляю одиночный ResourceHandler к текущему ResourceHandlerRegistry.
Обработчик сопоставляется по каждому запросу, и я указываю classpath:/static/ как значение местоположения ресурса (вы можете, конечно, добавить другие, если требуется).
Я добавляю пользовательский анонимный класс PathResourceResolver для переопределения getResource(String resourcePath, Resource location).
Правило для возврата ресурса следующее: если ресурс существует и доступен для чтения (так что это файл), я возвращаю его. В противном случае по умолчанию я возвращаю страницу index.html. Каково ожидаемое поведение для обработки URL-адресов HTML 5.

Spring Загрузка 1.X-приложения:

Расширение org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter - это способ.
Класс является адаптером интерфейса WebMvcConfigurer с пустыми методами, позволяющими подклассам переопределять только те методы, которые им интересны.

Вот полный код:

import java.io.IOException;

import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.resource.PathResourceResolver;

@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {


    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {

    registry.addResourceHandler("/**/*")
        .addResourceLocations("classpath:/static/")
        .resourceChain(true)
        .addResolver(new PathResourceResolver() {
            @Override
            protected Resource getResource(String resourcePath,
                Resource location) throws IOException {
                  Resource requestedResource = location.createRelative(resourcePath);
                  return requestedResource.exists() && requestedResource.isReadable() ? requestedResource
                : new ClassPathResource("/static/index.html");
            }
        });
    }
}

Spring Загрузка 2.X-приложения:

org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter устарел.
Внедрение непосредственно WebMvcConfigurer - это теперь путь, так как он по-прежнему является интерфейсом, но теперь он имеет методы по умолчанию (что стало возможным благодаря базовой линии Java 8) и может быть реализовано непосредственно без использования адаптера.

Вот полный код:

import java.io.IOException;

import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.resource.PathResourceResolver;

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {

      registry.addResourceHandler("/**/*")
        .addResourceLocations("classpath:/static/")
        .resourceChain(true)
        .addResolver(new PathResourceResolver() {
            @Override
            protected Resource getResource(String resourcePath,
                Resource location) throws IOException {
                Resource requestedResource = location.createRelative(resourcePath);
                return requestedResource.exists() && requestedResource.isReadable() ? requestedResource
                : new ClassPathResource("/static/index.html");
            }
        });
    }
}

Ответ 4

Чтобы сделать его более простым, вы можете просто реализовать ErrorPageRegistrar напрямую.

@Component
public class ErrorPageConfig implements ErrorPageRegistrar {

    @Override
    public void registerErrorPages(ErrorPageRegistry registry) {
        registry.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/"));
    }

}

Это отправит запросы index.html.

@Controller
@RequestMapping("/")
public class MainPageController {

    @ResponseStatus(HttpStatus.OK)
    @RequestMapping({ "/" })
    public String forward() {
        return "forward:/";
    }
}

Ответ 5

Вот три шага, которые вам нужно выполнить:

  • Внесите свой собственный TomcatEmbeddedServletContainerFactory bean и настройте RewriteValve

      import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;  
      ...
      import org.apache.catalina.valves.rewrite.RewriteValve; 
      ... 
    
      @Bean TomcatEmbeddedServletContainerFactory servletContainerFactory() {
        TomcatEmbeddedServletContainerFactory factory = new TomcatEmbeddedServletContainerFactory();
        factory.setPort(8080);
        factory.addContextValves(new RewriteValve());
        return factory;
      }
    
  • Добавьте файл rewrite.conf в каталог WEB-INF вашего приложения и укажите правила перезаписи. Ниже приведен пример содержимого rewrite.conf, которое я использую в приложении angular, чтобы использовать angular PathLocationStrategy (в основном я просто перенаправляю все на index.html, поскольку мы просто используем spring boot для обслуживания статический веб-контент, иначе вам нужно отфильтровать ваши контроллеры в правиле RewriteCond):

      RewriteCond %{REQUEST_URI} !^.*\.(bmp|css|gif|htc|html?|ico|jpe?g|js|pdf|png|swf|txt|xml|svg|eot|woff|woff2|ttf|map)$
      RewriteRule ^(.*)$ /index.html [L]
    
  • Измените использование useHash (или установите его в false) из объявлений маршрутизации:

      RouterModule.forRoot(routes)
    

или

      RouterModule.forRoot(routes, {useHash: false})

Ответ 6

Вы можете перенаправить все, не привязанные к Angular, используя что-то вроде этого:

@Controller
public class ForwardController {

    @RequestMapping(value = "/**/{[path:[^\\.]*}")
    public String redirect() {
        // Forward to home page so that route is preserved.
        return "forward:/";
    }
} 

Источник: fooobar.com/questions/381700/...

My Spring Загрузочный сервер для Angular также является сервером шлюза с вызовами API на /api, чтобы не иметь страницу входа перед страницами Angular, вы можете использовать что-то вроде.

import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;

/**
 * This sets up basic authentication for the microservice, it is here to prevent
 * massive screwups, many applications will require more secuity, some will require less
 */

@EnableOAuth2Sso
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter{

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http
                .logout().logoutSuccessUrl("/").and()
                .authorizeRequests()
                .antMatchers("/api/**").authenticated()
                .anyRequest().permitAll().and()
                .csrf()
                .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
    }
}

Ответ 7

перенаправить все Angular маршрутизацию с помощью index.html. В том числе базовый href.

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class ViewController {

@RequestMapping({ "jsa/customer","jsa/customer/{id}",})
   public String index() {
       return "forward:/index.html";
   }
}

В моем случае jsa является базовым href.