映射所有请求而不是Spring Boot中的特定模式

时间:2018-02-01 14:50:26

标签: regex spring spring-boot spring-security

我在Spring Boot应用程序中有VueJS单页面应用程序,我想让vue-router处理所有请求,而不是那些url以/rest/**开头的请求。

所以我写了正则表达式^(?!/rest/).*以匹配所有不以/rest/开头的内容,我尝试将请求映射为:

@Controller
public class MainController {

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

但它不起作用。我做错了什么?

修改

我有休息控制器文件:

@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来处理使用vue的路由。我知道我可以这样做:

@Controller
public class MainController {

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

并且效果很好,但我不想明确指定每个网址,这就是我尝试使用正则表达式的原因。而且我认为我使用错误的path变量,但我不知道如何。

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

4 个答案:

答案 0 :(得分:4)

好吧,正如@JDB所说,AntPathMatcher比较路径并找到最佳匹配。因此,您不必担心具有指定路径的端点,例如我的/rest api。

您可以添加:

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

以及您的所有要求,例如。 /login,会正确转发到index.html,javascript可以处理它。

问题在于/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网址:

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

它工作正常。

如果您遇到框架提供的其他终结问题,例如/health,您可以将正则表达式更改为/**/{path:^(?!oauth|health).*}/{path:[^\\.]*}

它看起来很糟糕,但它确实有效。我相信有人会在这里发布一个更好,更清洁的解决方案。

答案 1 :(得分:1)

我并不专门了解春天,所以我只是根据其他框架的经验做出最好的猜测。

首先,该模式不应该排除正斜杠,因为您已经将它包含在路径中了吗?

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

如果这不起作用,那么我只能想到AntPathMatcher不支持前瞻。

此设计的典型模式是实现/rest/*/*路由。在某些框架中,这只是正确地排序它们。根据{{​​3}},您可能需要使用规则来制定/rest/*路线"更具体的"。

以下是规则:

  

当多个模式与URL匹配时,必须对它们进行比较以找到最佳匹配。这是通过AntPathMatcher.getPatternComparator(String path)完成的,它查找更具体的模式。

     

如果模式的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:/";
    }
}

答案 2 :(得分:0)

再看一下......你的字符串是/{path:^(?!/rest/).*}

有第一个/,然后正则表达式也声明第一个/。此正则表达式将匹配/rest/*,因为它会验证/(?!/rest/).*而非(?!/rest/).*

旧答案和错误,请参阅@JDB评论

/字符是正则表达式中的特殊字符,需要进行转义。

@Controller
public class MainController {

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

由于\也是Java中字符串的转义字符,因此需要其中2个。

答案 3 :(得分:0)

您可以添加默认的处理程序方法

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