programing

Spring Boot에서 특정 패턴 대신 모든 요청 매핑

javamemo 2023. 6. 29. 19:41
반응형

Spring Boot에서 특정 패턴 대신 모든 요청 매핑

나는 봄 부팅 애플리케이션 안에 VueJS 단일 페이지 애플리케이션이 있고, 나는 URL이 다음으로 시작하는 이러한 요청 대신 모든 요청을 처리할 수 있는 vue-router를 만들고 싶습니다./rest/**.

그래서 저는 정규 표현을 썼습니다.^(?!/rest/).*시작하지 않는 모든 것을 일치시키기 위해./rest/그리고 저는 다음과 같은 요청 매핑을 만들려고 노력합니다.

@Controller
public class MainController {

@RequestMapping(value = "/{path:^(?!/rest/).*}")
    public String forwardRequests() {
        return "forward:/";
    }
}

하지만 효과가 없습니다.내가 뭘 잘못하고 있는 거지?

편집

rest 컨트롤러 파일이 있습니다.

@RestController
@RequestMapping(path = "/rest/project")
public class ProjectController {

    @Autowired
    private ProjectService projectService;

    @GetMapping(value = "/{id}")
    public Project getProjectById(@PathVariable Long id) {
        return projectService.getProjectById(id);
    }
}

프로젝트 세부 정보가 포함된 JSON을 반환합니다.다음과 같은 페이지가 있습니다./login그리고./projekty그래서 나는 그것들을 전달해야 합니다.index.html값을 사용하여 라우팅을 처리합니다.저는 제가 다음과 같은 일을 할 수 있다는 것을 압니다.

@Controller
public class MainController {

    @RequestMapping(value = {"/login", "/projekty"}, method = RequestMethod.GET)
    public String forwardRequests() {
        return "forward:/";
    }
}

그리고 잘 작동하지만 모든 URL을 명시적으로 지정하고 싶지 않아서 정규 표현을 사용하려고 합니다.그리고 나는 내가 잘못 사용했다고 생각합니다.path변수입니다. 하지만 어떻게 하는지는 모르겠습니다.

https://spring.io/guides/tutorials/spring-security-and-angular-js/ 섹션Using "Natural" Routes

음, @JDB가 말했듯이,AntPathMatcher경로를 비교하고 가장 적합한 경로를 찾습니다.따라서 지정된 경로가 있는 엔드포인트에 대해 걱정할 필요가 없습니다./restAPI.

다음을 추가할 수 있습니다.

@RequestMapping(value = "/{path:[^\\.]*}")
public String redirect() {
  return "forward:/";
}

그리고 당신의 모든 요청, 예를 들어. /login에 올바르게 전달됩니다.index.htmlJavascript에서 처리할 수 있습니다.

문제는 다음과 같은 URL에 있습니다./project/edit/33이 정규식과 일치하지 않으므로 다음과 같이 표시됩니다.Whitelabel Error Page 404 Not Found다음과 같이 쓸 수 있습니다.

@RequestMapping(value = "/**/{path:[^\\.]*}")
public String redirect() {
  return "forward:/";
}

그리고 그것은 잘 작동하지만, 만약 당신이 보안이 활성화되어 있다면,/ouath/token반환됨:

{  
   "timestamp":"2018-02-05T09:13:28.104+0000",
   "status":405,
   "error":"Method Not Allowed",
   "exception":"org.springframework.web.HttpRequestMethodNotSupportedException",
   "message":"Request method 'POST' not supported",
   "path":"/oauth/token"
}

따라서 oauth URL을 제외해야 합니다.

@RequestMapping(value = {"/{path:[^\\.]*}", "/**/{path:^(?!oauth).*}/{path:[^\\.]*}"}, method = RequestMethod.GET)
public String forward() {
    return "forward:/";
}

그리고 그것은 잘 작동합니다.

프레임워크에서 제공하는 다른 엔드포인트에 문제가 있는 경우 다음과 같이 하십시오./health정규식을 로 변경할 수 있습니다./**/{path:^(?!oauth|health).*}/{path:[^\\.]*}

보기에는 엉망이지만 효과가 있습니다.저는 누군가가 여기에 더 좋고 깨끗한 해결책을 게시할 것이라고 믿습니다.

저는 봄을 구체적으로 알지 못해서 다른 틀에 대한 경험을 바탕으로 최선의 추측을 하고 있을 뿐입니다.

먼저, 당신은 이미 당신의 경로에 슬래시를 포함하고 있기 때문에 패턴에서 슬래시를 제외해야 하지 않나요?

/{path:^(?!rest/).*}

만약 그것이 효과가 없다면, 제가 생각할 수 있는 것은 AntPathMatcher가 룩헤드를 지원하지 않는다는 것뿐입니다.

이 설계의 일반적인 패턴은 두 가지를 모두 구현하는 것입니다./rest/*그리고./*항로일부 프레임워크에서는 올바른 순서를 지정하는 것에 불과합니다.Spring MVC의 문서에 따르면, 당신은 규칙을 가지고 놀 필요가 있을 수 있습니다./rest/*경로 "더 구체적".

다음은 규칙입니다.

여러 패턴이 URL과 일치하는 경우 가장 적합한 패턴을 찾기 위해 비교해야 합니다.이 작업은 보다 구체적인 패턴을 찾는 AntPathMatcher.getPatternComparator(문자열 경로)를 통해 수행되었습니다.

패턴이 URI 변수의 수가 적고 단일 와일드카드가 1로 카운트되고 이중 와일드카드가 2로 카운트되는 경우 패턴의 구체성이 떨어집니다.점수가 같으면 더 긴 패턴이 선택됩니다.점수와 길이가 동일할 경우 와일드카드보다 URI 변수가 많은 패턴이 선택됩니다.

기본 매핑 패턴 /**은 스코어링에서 제외되며 항상 마지막으로 정렬됩니다.또한 /public/**와 같은 접두사 패턴은 이중 와일드카드가 없는 다른 패턴보다 구체적이지 않은 것으로 간주됩니다.

자세한 내용은 AntPathMatcher의 AntPatternComparator를 참조하고 사용되는 PathMatcher 구현을 사용자 지정할 수 있습니다.구성 섹션의 경로 일치를 참조하십시오.

그래서, 그 규칙들과 당신의 코드에 대한 나의 해석에 근거하여, 나는 다음과 같은 방법이 효과가 있을 것이라고 생각합니다.

// Your more specific patterns will take precedence
@RequestMapping(value = "/rest/**")
    public String handleRestRequests() {
        // forward this to your rest services
    }
}

// Your less specific patterns will only apply if the more specific ones don't match
@RequestMapping(value = "/**")
    public String forwardRequests() {
        // Everything else
        return "forward:/";
    }
}

기본 처리기 메서드를 추가할 수 있습니다.

  @RequestMapping()
  String defaultHandler() { 
    return "This is a default method";
  }

다시 한 번 살펴보니... 당의현은입니다./{path:^(?!/rest/).*}.

번째 첫가있습다니째가 ./ 첫 ▁a다니▁declare선합▁then를 선언합니다./은 이정식일니다합치와 합니다./rest/*은 것이증기때문에하명그를 확인하기 입니다./(?!/rest/).*그리고 아닌(?!/rest/).*.

오래된 답과 틀렸습니다. @JDB 설명 참조

/문자는 정규식의 특수 문자이므로 이스케이프해야 합니다.

@Controller
public class MainController {

    @RequestMapping(value = "/{path:^(?!\\/rest\\/).*}")
    public String forwardRequests() {
        return "forward:/";
    }
}

때부터\또한 Java에서 문자열에 대한 이스케이프 문자입니다. 두 개가 필요합니다.

일반적으로 제외하려는 경우에는 요청 경로 일치를 사용하는 것이 번거롭습니다.Resource Resolver를 사용하여 웹 히스토리 리디렉션의 특정 사례를 처리할 수 있습니다.

나의 경우는 다음과 같습니다.

/admin/index.html => backoffice vuejs entry-point
/admin/css/**     => backoffice css files
/admin/js/**      => backoffice js files
/admin/**         => backoffice routes
/**               => API endpoints

SpringBoot에서 정적 되었습니다./admin나는 봉사할 필요가 있었습니다./admin/** 입니다.index.html그사사를위해간방단다구니습현했법을한례용ed▁a를 구현했습니다.ResourceResolver.

public class WebHistoryPathResourceResolver implements ResourceResolver {

    private final PathResourceResolver pathResourceResolver = new PathResourceResolver();
    private final String fallbackPath;

    public WebHistoryPathResourceResolver(String fallbackPath) {
        this.fallbackPath = fallbackPath;
    }

    @Override
    public Resource resolveResource(HttpServletRequest request, String requestPath, List<? extends Resource> locations, ResourceResolverChain chain) {
        Resource resource = pathResourceResolver.resolveResource(request, requestPath, locations, chain);
        if (resource == null) {
            return pathResourceResolver.resolveResource(request, fallbackPath, locations, chain);
        }

        return resource;
    }

    @Override
    public String resolveUrlPath(String resourcePath, List<? extends Resource> locations, ResourceResolverChain chain
    ) {
        return pathResourceResolver.resolveUrlPath(resourcePath, locations, chain);
    }
}

그런 다음 처리기를 인스턴스화합니다.

@Bean
public WebMvcConfigurer adminWebMvcConfigurer() {
    final String prefix = "/admin";

    return new WebMvcConfigurer() {
        @Override
        public void addResourceHandlers(ResourceHandlerRegistry registry) {
            registry
                .addResourceHandler(prefix + "/**")
                .addResourceLocations("classpath:" + prefix + "/")
                .resourceChain(true)
                .addResolver(new WebHistoryPathResourceResolver("index.html"));
        }

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

언급URL : https://stackoverflow.com/questions/48565550/map-all-requests-instead-of-specific-pattern-in-spring-boot

반응형