복붙노트

[SPRING] Springboot / Angular2 - HTML5 URL 처리 방법

SPRING

Springboot / Angular2 - HTML5 URL 처리 방법

나는 이것이 단순한 질문이라고 믿지만, 나는 대답을 찾지 못하거나 적어도 검색에서 정확한 용어를 사용하지 못했다.

Angular2와 Springboot를 함께 설정합니다. 기본적으로 Angular는 localhost : 8080 \ dashboard 및 localhost : 8080 \ dashboard \ detail과 같은 경로를 사용합니다.

가능한 경우 해시로 경로를 사용하지 마십시오. Angular 문서에서 말한 것처럼 :

그리고...

문제는 내가 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에게이 앱 경로에 대한 요청을 무시하도록하려면 어떻게해야합니까?

Angular2 또는 Boot 중 더 나은 솔루션이 있습니까?

해결법

  1. ==============================

    1.나는 당신을 위해 해결책을 가지고있다. 당신은 Spring 부트로부터 Angular로 요청을 전달하기 위해 ViewController를 추가 할 수있다.

    나는 당신을 위해 해결책을 가지고있다. 당신은 Spring 부트로부터 Angular로 요청을 전달하기 위해 ViewController를 추가 할 수있다.

    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";
       }
    }
    

    여기에 모든 각도 2 ( "/ 자전거", "/ milages", "/ 갤러리", "/ 트랙", "/ 트랙 / {id : \ w +}", "/ location" "/ 테스트", "/ 테스트 / 새", "/ 테스트 / **", "/ 질문", "/ 대답") 내 SPA 프리젠 테이션을 위해 동일한 작업을 수행 할 수 있으며 추가 단계로 404 오류 페이지를 인덱스 페이지로 리디렉션 할 수 있습니다. 즐겨!

  2. ==============================

    2.내 스프링 부트 응용 프로그램 (버전 1 및 2)에서 정적 리소스는 단일 위치에 있습니다.

    내 스프링 부트 응용 프로그램 (버전 1 및 2)에서 정적 리소스는 단일 위치에 있습니다.

    src/main/resources/static
    

    static은 정적 자원을로드하기 위해 Spring Boot에 의해 인식되는 폴더입니다.

    그런 다음 Spring MVC 설정을 커스터마이징하는 것이다. 더 간단한 방법은 Spring Java 설정을 사용하는 것이다.

    webMvcConfigurer를 구현하여 addResourceHandlers ()를 재정의합니다. 하나의 ResourceHandler를 현재 ResourceHandlerRegistry에 추가합니다. 핸들러는 모든 요청에 ​​매핑되며 classpath : / static /을 리소스 위치 값으로 지정합니다. 물론 필요한 경우 다른 리소스를 추가 할 수도 있습니다. getResource (String resourcePath, Resource location)를 재정의하는 사용자 지정 PathResourceResolver 익명 클래스를 추가합니다. 그리고 리소스를 반환하는 규칙은 다음과 같습니다. 리소스가 있고 읽을 수있는 경우 (파일이므로) 반환합니다. 그렇지 않으면 기본적으로 index.html 페이지를 반환합니다. HTML 5 URL을 처리 할 예상 동작은 무엇입니까?

    봄 부팅 1.X 응용 프로그램 :

    org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter를 확장하는 것이 길이다. 이 클래스는 WebMvcConfigurer 인터페이스의 어댑터입니다. 서브 클래스가 관심있는 메소드만을 오버라이드 (override) 할 수 있도록 (듯이)하는 빈 메소드가 있습니다.

    전체 코드는 다음과 같습니다.

    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");
                }
            });
        }
    }
    

    봄 부팅 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");
                }
            });
        }
    }
    
  3. ==============================

    3.사용자 정의 ErrorViewResolver를 제공하여 발견되지 않은 모든 자원을 기본 페이지로 전달할 수 있습니다. 이 작업을 @Configuration 클래스에 추가하기 만하면됩니다.

    사용자 정의 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;
            }
        };
    }
    
  4. ==============================

    4.다음과 같이 Angular에 매핑되지 않은 모든 것을 전달할 수 있습니다 :

    다음과 같이 Angular에 매핑되지 않은 모든 것을 전달할 수 있습니다 :

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

    출처 : https://stackoverflow.com/a/44850886/3854385

    각도 용 내 스프링 부트 서버는 각도 페이지 앞에 로그인 페이지가 없도록 / api에 대한 API 호출이있는 게이트웨이 서버이기도하며 다음과 같은 것을 사용할 수 있습니다.

    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());
        }
    }
    
  5. ==============================

    5.좀 더 단순하게하기 위해 ErrorPageRegistrar를 직접 구현할 수 있습니다.

    좀 더 단순하게하기 위해 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:/";
        }
    }
    
  6. ==============================

    6.다음은 따라야 할 세 단계입니다.

    다음은 따라야 할 세 단계입니다.

    또는

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

    7.index.html을 사용하여 모든 각도 라우팅 전달. 기본 href 포함.

    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입니다.

  8. ==============================

    8.나는 평범한 오래된 필터로 그것을했다.

    나는 평범한 오래된 필터로 그것을했다.

    public class PathLocationStrategyFilter implements Filter {
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
    
            if(request instanceof HttpServletRequest) {
                HttpServletRequest servletRequest = (HttpServletRequest) request;
    
                String uri = servletRequest.getRequestURI();
                String contextPath = servletRequest.getContextPath();
                if(!uri.startsWith(contextPath + "/api") && 
                    !uri.startsWith(contextPath + "/assets") &&
                    !uri.equals(contextPath) &&
                    // only forward if there's no file extension (exclude *.js, *.css etc)
                    uri.matches("^([^.]+)$")) {
    
                    RequestDispatcher dispatcher = request.getRequestDispatcher("/");
                    dispatcher.forward(request, response);
                    return;
                }
            }        
    
            chain.doFilter(request, response);
        }
    }
    

    그런 다음 web.xml에서 :

    <web-app>
        <filter>
            <filter-name>PathLocationStrategyFilter</filter-name>
            <filter-class>mypackage.PathLocationStrategyFilter</filter-class>
        </filter>
    
        <filter-mapping>
            <filter-name>PathLocationStrategyFilter</filter-name>
            <url-pattern>*</url-pattern>
        </filter-mapping>
    </web-app>
    
  9. from https://stackoverflow.com/questions/38516667/springboot-angular2-how-to-handle-html5-urls by cc-by-sa and MIT license