programing

봄에는 index.html의 모든 루트를 캐치합니다.

testmans 2023. 2. 24. 13:20
반응형

봄에는 index.html의 모든 루트를 캐치합니다.

리액트 라우터를 사용하여 클라이언트 측 루팅을 수행하는 리액트 기반 단일 페이지 애플리케이션용 스프링 백엔드를 개발하고 있습니다.

index.html의 합니다./api/**.

index.html에서 index.을 src/main/resources/public/index.html 패스 " " " "/했습니다.

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler("/").addResourceLocations("/index.html");
}

index.html 이외의 때 등 때 항상 할 수 ./api.

봄철에 이런 캐치올 루트를 설정하려면 어떻게 해야 하나요?

리액트 앱이 루트를 포워드 타깃으로 사용할 수 있기 때문에, 이것은 나에게 있어서 기능하게 되었다.

@Configuration
public class WebConfiguration extends WebMvcConfigurerAdapter {

  @Override
  public void addViewControllers(ViewControllerRegistry registry) {
      registry.addViewController("/{spring:\\w+}")
            .setViewName("forward:/");
      registry.addViewController("/**/{spring:\\w+}")
            .setViewName("forward:/");
      registry.addViewController("/{spring:\\w+}/**{spring:?!(\\.js|\\.css)$}")
            .setViewName("forward:/");
  }
}

솔직히 무한 전송 루프를 피하기 위해 이 포맷이 필요한 이유를 알 수 없습니다.

Spring Boot 앱 내에서 폴리머 기반의 PWA를 호스트하고 이미지와 같은 정적 웹 리소스와 "/api/..." 아래의 REST API를 사용하고 있습니다.클라이언트측 앱에서 PWA의 URL 루팅을 처리해 주었으면 합니다.사용법은 다음과 같습니다.

@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
    /**
     * Ensure client-side paths redirect to index.html because client handles routing. NOTE: Do NOT use @EnableWebMvc or it will break this.
     */
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        // Map "/"
        registry.addViewController("/")
                .setViewName("forward:/index.html");

        // Map "/word", "/word/word", and "/word/word/word" - except for anything starting with "/api/..." or ending with
        // a file extension like ".js" - to index.html. By doing this, the client receives and routes the url. It also
        // allows client-side URLs to be bookmarked.

        // Single directory level - no need to exclude "api"
        registry.addViewController("/{x:[\\w\\-]+}")
                .setViewName("forward:/index.html");
        // Multi-level directory path, need to exclude "api" on the first part of the path
        registry.addViewController("/{x:^(?!api$).*$}/**/{y:[\\w\\-]+}")
                .setViewName("forward:/index.html");
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/**").addResourceLocations("classpath:/webapp/");
    }
}

이는 Angular 앱과 React 앱에서도 작동합니다.

@EnableWebMvc 회피

은 "Spring-Boot"에 를 제공합니다.src/main/resources:

  • /META-INF/리소스/
  • /timeout/
  • /static/
  • /public/

이것과 이것 좀 보세요.

또는 @EnableWebMvc를 유지하고 addViewControllers를 덮어씁니다.

@EnableWebMvc이 페이지를 보세요.Java Spring Boot: 앱 루트("/")를 index.html에 매핑하는 방법

@하거나 @EnableWebMvc를 다시 할 수 .addViewControllers:

@Override
public void addViewControllers(ViewControllerRegistry registry) {
    registry.addViewController("/").setViewName("forward:/index.html");
}

하여 는는포 or or or or or or or를 잡습니다./

github에서 이 spring-boot-reactjs 샘플프로젝트를 보실 수 있습니다.

컨트롤러를 사용하여 원하는 작업을 수행합니다.

@Controller
public class HomeController {

    @RequestMapping(value = "/")
    public String index() {
        return "index";
    }

}

index.html에 있다src/main/resources/templates

, react-router에 있는 .이거는 매핑이 있는 컨트롤러를 만드는 것만큼이나 간단합니다./웹 사이트의 하위 트리는 다음과 같습니다./users/** 내 이 있다.

@Controller
public class SinglePageAppController {
    @RequestMapping(value = {"/", "/users/**", "/campaigns/**"})
    public String index() {
        return "index";
    }
}

API 호출이 이 컨트롤러에 의해 포착되지 않고 리소스가 자동으로 처리됩니다.

질문을 보고 답을 찾았습니다.

@Bean
public EmbeddedServletContainerCustomizer notFoundCustomizer() {
    return new EmbeddedServletContainerCustomizer() {
        @Override
        public void customize(ConfigurableEmbeddedServletContainer container) {
            container.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/"));
        }
    };
}

솔루션)myurl1,myurl2 : , ...( ) :

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

import javax.servlet.http.HttpServletRequest;

@Controller
public class SinglePageAppController {

    /**
     * If the user refreshes the page while on a React route, the request will come here.
     * We need to tell it that there isn't any special page, just keep using React, by
     * forwarding it back to the root.
     */
    @RequestMapping({"/myurl1/**", "/myurl2/**"})
    public String forward(HttpServletRequest httpServletRequest) {
        return "forward:/";
    }
}

주의: 사용방법public String index()또한 정상적으로 동작하지만 템플릿을 사용하는 경우에만 작동합니다. ,의 ,WebMvcConfigurerAdapter을 사용하다

여기의 /api 루트를 제외한 모든 경우에 Single Page App(SPA)을 제공하는 것과 관련된 당신의 질문에 답하기 위해 저는 Petri의 답변을 수정했습니다.

SPA용 index.html이 포함된 폴리머라는 이름의 템플릿이 있습니다.따라서 /api 및 /public-api를 제외한 모든 경로를 해당 뷰로 전송해야 합니다.

WebMvcConfigurerAdapter I에서 addViewController를 덮어쓰고 정규 표현 ^(?/api/|/public-api/)을 사용했습니다.*$

이 경우 정규 표현은 ^((?/api/))입니다.*$

public class WebMvcConfiguration extends WebMvcConfigurerAdapter {

@Override
public void addViewControllers(ViewControllerRegistry registry) {
    registry.addViewController("/{spring:^((?!/api/).)*$}").setViewName("polymer");
    super.addViewControllers(registry);
}

그 결과 http://localhost 또는 http://localhost/community접속하여 SPA를 지원할 수 있으며 SPA가 발신하는 나머지 콜은 모두 http://localhost/public-api/posts 등에 정상적으로 라우팅됩니다.

많은 시도 끝에 다음과 같은 가장 간단한 해결책을 찾았습니다.기본적으로 처리하기가 매우 어려웠던 스프링 핸들링을 모두 우회할 수 있습니다.

@Component
public class StaticContentFilter implements Filter {
    
    private List<String> fileExtensions = Arrays.asList("html", "js", "json", "csv", "css", "png", "svg", "eot", "ttf", "woff", "appcache", "jpg", "jpeg", "gif", "ico");
    
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        doFilter((HttpServletRequest) request, (HttpServletResponse) response, chain);
    }
    
    private void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        String path = request.getServletPath();
        
        boolean isApi = path.startsWith("/api");
        boolean isResourceFile = !isApi && fileExtensions.stream().anyMatch(path::contains);
        
        if (isApi) {
            chain.doFilter(request, response);
        } else if (isResourceFile) {
            resourceToResponse("static" + path, response);
        } else {
            resourceToResponse("static/index.html", response);
        }
    }
    
    private void resourceToResponse(String resourcePath, HttpServletResponse response) throws IOException {
        InputStream inputStream = Thread.currentThread()
                .getContextClassLoader()
                .getResourceAsStream(resourcePath);
        
        if (inputStream == null) {
            response.sendError(NOT_FOUND.value(), NOT_FOUND.getReasonPhrase());
            return;
        }
        
        inputStream.transferTo(response.getOutputStream());
    }
}

언급URL : https://stackoverflow.com/questions/39331929/spring-catch-all-route-for-index-html

반응형