我有一个项目使用 Spring Boot 生成一个可执行 JAR,该 JAR 公开了一个带有 Spring Data REST 的 REST API。它还与 Spring Security OAuth 集成。那很好用。我的问题如下,
我想为 REST API 使用不同的模块,仅当具有 JPA 存储库的相应 JAR 在类路径中(它已被定义为依赖项)时,我才想启用这些模块。
问题是我希望它们彼此独立。我希望能够在具有不同映射的不同调度程序 servlet 下为它们提供服务,这样我就可以为每个指定不同的 baseUri,并为资源发现设置不同的根 URL。
我会尽量让它更清楚:
API 模块 A:
API 模块 B:
更多模块...
除此之外,我还可以拥有另一个调度程序 servlet,其中包含/oauth/* 端点以及其他自定义 Controller ,并且安全配置必须对所有 (/*) 正常工作
我知道我可以通过 ServletRegistrationBean 定义更多的调度程序 servlet,但我不知道如何附加到每个不同的 spring 数据 rest 配置。
我也一直在尝试通过在每个子上下文中定义每个调度程序 servlet 的配置、每个 RepositoryRestMvcConfiguration 和每个 @EnableJpaRepositories 注释定义要扫描的不同包来使用 SpringApplicationBuilder 对分层应用程序上下文执行此操作。无论如何,我什至无法加载上下文,因为它们不是作为 WebApplicationContext 创建的,因此失败,因为没有可用的 ServletContext。
有什么帮助/建议吗?提前致谢。
最佳答案
我刚才找到了解决方案,但我忘了在这里分享,所以感谢 Jan 提醒我。
我通过使用具有不同配置 (RepositoryRestMvcConfiguration) 的新 Web 应用程序上下文和一个公共(public)父级(即 Spring Boot 应用程序的根应用程序上下文)创建和注册多个调度程序 servlet 来解决此问题。为了根据类路径中包含的不同 jar 自动启用 API 模块,我或多或少地模拟了 Spring Boot 所做的事情。
该项目分为几个 gradle 模块。像这样:
project-server 模块是主要模块。它声明了对 project-api-autoconfigure 的依赖,同时排除了 project-api-autoconfigure 对 project-module-? -api 模块。
在 project-server.gradle 中:
dependencies {
compile (project(':project-api-autoconfigure')) {
exclude module: 'project-module-a-api'
exclude module: 'project-module-b-api'
...
}
...
}
project-api-autoconfigure 依赖于所有 API 模块,因此依赖项在 project-api-autoconfigure.gradle 上看起来像这样:
dependencies {
compile project(':project-module-a-api')
compile project(':project-module-b-api')
...
}
project-api-autoconfigure 是我为每个 API 模块创建具有自己的 Web 应用程序上下文的调度程序 servlet bean 的地方,但此配置取决于位于内部的每个 API 模块的配置类每个 API 模块 jar。
我创建了一个抽象类,每个自动配置类都继承自该类:
public abstract class AbstractApiModuleAutoConfiguration<T> {
@Autowired
protected ApplicationContext applicationContext;
@Autowired
protected ServerProperties server;
@Autowired(required = false)
protected MultipartConfigElement multipartConfig;
@Value("${project.rest.base-api-path}")
protected String baseApiPath;
protected DispatcherServlet createApiModuleDispatcherServlet() {
AnnotationConfigWebApplicationContext webContext = new AnnotationConfigWebApplicationContext();
webContext.setParent(applicationContext);
webContext.register(getApiModuleConfigurationClass());
return new DispatcherServlet(webContext);
}
protected ServletRegistrationBean createApiModuleDispatcherServletRegistration(DispatcherServlet apiModuleDispatcherServlet) {
ServletRegistrationBean registration = new ServletRegistrationBean(
apiModuleDispatcherServlet,
this.server.getServletMapping() + baseApiPath + "/" + getApiModulePath() + "/*");
registration.setName(getApiModuleDispatcherServletBeanName());
if (this.multipartConfig != null) {
registration.setMultipartConfig(this.multipartConfig);
}
return registration;
}
protected abstract String getApiModuleDispatcherServletBeanName();
protected abstract String getApiModulePath();
protected abstract Class<T> getApiModuleConfigurationClass();
}
现在,模块 A 的自动配置类将如下所示:
@Configuration
@ConditionalOnClass(ApiModuleAConfiguration.class)
@ConditionalOnProperty(prefix = "project.moduleA.", value = "enabled")
public class ApiModuleAAutoConfiguration extends AbstractApiModuleAutoConfiguration<ApiModuleAConfiguration> {
public static final String API_MODULE_A_DISPATCHER_SERVLET_BEAN_NAME = "apiModuleADispatcherServlet";
public static final String API_MODULE_A_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME = "apiModuleADispatcherServletRegistration";
@Value("${project.moduleA.path}")
private String apiModuleAPath;
@Bean(name = API_MODULE_A_DISPATCHER_SERVLET_BEAN_NAME)
public DispatcherServlet apiModuleADispatcherServlet() {
return createApiModuleDispatcherServlet();
}
@Bean(name = API_MODULE_A_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)
public ServletRegistrationBean apiModuleADispatcherServletRegistration() {
return createApiModuleDispatcherServletRegistration(apiModuleADispatcherServlet());
}
@Override
protected String getApiModuleDispatcherServletBeanName() {
return API_MODULE_A_DISPATCHER_SERVLET_BEAN_NAME;
}
@Override
protected String getApiModulePath() {
return apiModuleAPath;
}
@Override
protected Class<ApiModuleAConfiguration> getApiModuleConfigurationClass() {
return ApiModuleAConfiguration.class;
}
}
现在,您的 ApiModuleAConfiguration、ApiModuleBConfiguration... 配置类将位于每个 api 模块 project-module-a-api 上, 项目模块-b-api...
它们可以是RepositoryRestMvcConfiguration,也可以从它扩展,也可以是导入 Spring Data REST 配置的任何其他配置类。
最后但同样重要的是,我在主模块 project-server 中创建了不同的 gradle 脚本,以根据传递给 gradle 的属性加载以模拟 Maven 配置文件。每个脚本都将需要包含的 api 模块声明为依赖项。它看起来像这样:
- project-server
/profiles/
profile-X.gradle
profile-Y.gradle
profile-Z.gradle
例如,profile-X 启用 API 模块 A 和 B:
dependencies {
compile project(':project-module-a-api')
compile project(':project-module-b-api')
}
processResources {
from 'src/main/resources/profiles/profile-X'
include 'profile-x.properties'
into 'build/resources/main'
}
其他配置文件可以启用不同的 API 模块。
配置文件以这种方式从 project-server.gradle 加载:
loadProfile()
processResources {
include '**/*'
exclude 'profiles'
}
dependencies {
compile (project(':project-api-autoconfigure')) {
exclude module: 'project-module-a-api'
exclude module: 'project-module-b-api'
...
}
...
}
...
def loadProfile() {
def profile = hasProperty('profile') ? "${profile}" : "dev"
println "Profile: " + profile
apply from: "profiles/" + profile + ".gradle"
}
差不多就这些了。我希望它能帮助你简。
干杯。
关于java - 带有 Spring Data REST 的不同 REST API 的多个调度程序 servlet 的 Spring Boot (JAR),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27319051/
Rails2.3可以选择随时使用RouteSet#add_configuration_file添加更多路由。是否可以在Rails3项目中做同样的事情? 最佳答案 在config/application.rb中:config.paths.config.routes在Rails3.2(也可能是Rails3.1)中,使用:config.paths["config/routes"] 关于ruby-on-rails-Rails3中的多个路由文件,我们在StackOverflow上找到一个类似的问题
我有多个ActiveRecord子类Item的实例数组,我需要根据最早的事件循环打印。在这种情况下,我需要打印付款和维护日期,如下所示:ItemAmaintenancerequiredin5daysItemBpaymentrequiredin6daysItemApaymentrequiredin7daysItemBmaintenancerequiredin8days我目前有两个查询,用于查找maintenance和payment项目(非排他性查询),并输出如下内容:paymentrequiredin...maintenancerequiredin...有什么方法可以改善上述(丑陋的)代
我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何
我有一个具有一些属性的模型:attr1、attr2和attr3。我需要在不执行回调和验证的情况下更新此属性。我找到了update_column方法,但我想同时更新三个属性。我需要这样的东西:update_columns({attr1:val1,attr2:val2,attr3:val3})代替update_column(attr1,val1)update_column(attr2,val2)update_column(attr3,val3) 最佳答案 您可以使用update_columns(attr1:val1,attr2:val2
我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/
我正在尝试修改当前依赖于定义为activeresource的gem:s.add_dependency"activeresource","~>3.0"为了让gem与Rails4一起工作,我需要扩展依赖关系以与activeresource的版本3或4一起工作。我不想简单地添加以下内容,因为它可能会在以后引起问题:s.add_dependency"activeresource",">=3.0"有没有办法指定可接受版本的列表?~>3.0还是~>4.0? 最佳答案 根据thedocumentation,如果你想要3到4之间的所有版本,你可以这
我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www
我正在尝试按0-9和a-z的顺序创建数字和字母列表。我有一组值value_array=['0','1','2','3','4','5','6','7','8','9','a','b','光盘','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','','u','v','w','x','y','z']和一个组合列表的数组,按顺序,这些数字可以产生x个字符,比方说三个list_array=[]和一个当前字母和数字组合的数组(在将它插入列表数组之前我会把它变成一个字符串,]current_combo['0','0','0']
是否有可能:before_filter:authenticate_user!||:authenticate_admin! 最佳答案 before_filter:do_authenticationdefdo_authenticationauthenticate_user!||authenticate_admin!end 关于ruby-on-rails-before_filter运行多个方法,我们在StackOverflow上找到一个类似的问题: https://
我正在使用Rails3.1并在一个论坛上工作。我有一个名为Topic的模型,每个模型都有许多Post。当用户创建新主题时,他们也应该创建第一个Post。但是,我不确定如何以相同的形式执行此操作。这是我的代码:classTopic:destroyaccepts_nested_attributes_for:postsvalidates_presence_of:titleendclassPost...但这似乎不起作用。有什么想法吗?谢谢! 最佳答案 @Pablo的回答似乎有你需要的一切。但更具体地说...首先改变你View中的这一行对此#