我正在使用带有Spring 3.0.6-RELEASE的CXF RS 2.5.1。我想为“单个端点”提供多个实现类。我看到此问题已报告并已修复https://issues.apache.org/jira/browse/CXF-2439,但是,当我尝试执行此操作时,CXF只从jaxrs:serviceBeans标记中选择第一个资源类。对于其他请求,我在tomcat控制台上看到此消息为“找不到匹配请求路径/帐户/休息/传输的操作”。以下是配置。感谢任何意见。
的web.xml
<listener>
<listener-class> org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:account-servlet.xml</param-value>
</context-param>
<servlet>
<servlet-name>CXF Servlet</servlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>CXF Servlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
帐户-servlet.xml中
<jaxrs:server id="accountService" address="/rest">
<jaxrs:serviceBeans>
<ref bean="transferService" />
<ref bean="balanceService"/>
</jaxrs:serviceBeans>
<jaxrs:extensionMappings>
<entry key="xml" value="application/xml" />
</jaxrs:extensionMappings>
</jaxrs:server>
<bean id="transferService" class="com.mycompany.service.TransferService"/>
<bean id="balanceService" class="com.mycompany.service.BalanceService"/>
BalanceService.java(省略导入)
package com.mycompany.service;
@Path("/")
@Produces("application/xml")
public class BalanceService{
@GET
@Path("/balance")
public String getBalance() {
StringBuilder response = new StringBuilder(128);
response.append("<Balance>")
.append("<amount>").append("250.00").append("</amount>")
.append("</Balance>");
return response.toString();
}
}
TransferService.java(省略导入)
package com.mycompany.service;
@Path("/")
@Produces("application/xml")
public class TransferService {
@GET
@Path("/transfer")
public String getTransfer() {
StringBuilder response = new StringBuilder(128);
response.append("<Transfer>")
.append("<amount>").append("350.00").append("</amount>")
.append("</Transfer>");
return response.toString();
}
}
请忽略任何编程违规/标准,因为它只是POC的示例应用程序。
答案 0 :(得分:4)
我通过将部分@Path映射移动到服务bean类来解决了这个问题。在你的情况下:
BalanceService
@Path("/balance")
@Produces("application/xml")
public class BalanceService {
@GET
@Path("/{id}")
public String getBalance(@PathParam("id") long id) {
...
}
}
TransferService
@Path("/transfer")
@Produces("application/xml")
public class TransferService {
@GET
@Path("/{id}")
public String getTransfer(@PathParam("id") long id) {
...
}
}
答案 1 :(得分:3)
所以我花了一些时间搜索互联网,但没有找到解决这个问题的方法。文档中有一个可用于推断解决方案的注释。
http://cxf.apache.org/docs/jax-rs-basics.html#JAX-RSBasics-Customselectionbetweenmultipleresources
因此我写了一个自定义资源比较器,做了相应的jaxrs:服务器配置和Eureka!有效!。现在,我有2个实现类映射到javax:rs地址中的单个资源/地址。
请注意,下面显示的自定义资源比较器中的逻辑可能会因URL模式而异。
提供所有文件的来源。希望这将有助于将来的某人:)
<web-app>
<display-name>Archetype Created Web Application</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/account-servlet.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>CXF Servlet</servlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>CXF Servlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
<beans>
<jaxrs:server id="accountService" address="/rest">
<jaxrs:serviceBeans>
<ref bean="accountServiceImpl" />
<ref bean="transferServiceImpl" />
</jaxrs:serviceBeans>
<jaxrs:resourceComparator>
<bean id="accountServiceComparator" class="com.etrade.comparator.AccountServiceComparator"/>
</jaxrs:resourceComparator>
<jaxrs:extensionMappings>
<entry key="xml" value="application/xml" />
</jaxrs:extensionMappings>
</jaxrs:server>
<bean id="accountServiceImpl" class="com.etrade.service.AccountService" />
<bean id="transferServiceImpl" class="com.etrade.service.TransferService" />
</beans>
<modelVersion>4.0.0</modelVersion>
<groupId>cxf.rest</groupId>
<artifactId>account</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>account Maven Webapp</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-bundle-jaxrs</artifactId>
<version>2.5.0</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>3.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>3.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>3.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.0.5.RELEASE</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<!-- This plugin is needed for the servlet example -->
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>7.2.0.v20101020</version>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.1</version>
<executions>
<execution><goals><goal>java</goal></goals></execution>
</executions>
</plugin>
</plugins>
<finalName>account</finalName>
</build>
</project>
package com.etrade.comparator;
import java.lang.reflect.Method;
import javax.ws.rs.Path;
import org.apache.cxf.jaxrs.ext.ResourceComparator;
import org.apache.cxf.jaxrs.impl.UriInfoImpl;
import org.apache.cxf.jaxrs.model.ClassResourceInfo;
import org.apache.cxf.jaxrs.model.OperationResourceInfo;
import org.apache.cxf.message.Message;
public class AccountServiceComparator implements ResourceComparator{
public int compare(ClassResourceInfo arg0, ClassResourceInfo arg1,
Message message) {
UriInfoImpl uriInfo = new UriInfoImpl(message);
String path = uriInfo.getPath();
String[] pathArray = path.split("/");
String resourceUrlName = pathArray[1];
System.out.println("Path : "+resourceUrlName);
Method[] methods = arg0.getServiceClass().getMethods();
int value = 1;
String resource = null;
for(Method method : methods) {
Path annotationPath = method.getAnnotation(javax.ws.rs.Path.class);
if(null != annotationPath){
String pathValue = annotationPath.value();
String[] parts = pathValue.split("/");
resource = parts[1];
System.out.println("resource : "+resource);
}
if(resourceUrlName.contains(resource)){
value = -1;
}
}
return value;
}
public int compare(OperationResourceInfo arg0, OperationResourceInfo arg1,
Message arg2) {
return 0;
}
}
package com.etrade.service;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
@Path("/account")
@Produces("application/xml")
public class AccountService {
@GET
@Produces("application/xml")
@Path("/balance/{id}")
public String accountBalance(@PathParam("id") long id) {
System.out.println("id : "+id);
StringBuilder response = new StringBuilder(256);
response.append("<Response>").append("<id>").append(id)
.append("</id>").append("<balance>").append("250.00").append("</balance>")
.append("</Response>");
return response.toString();
}
}
package com.etrade.service;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
@Path("/account")
@Produces("application/xml")
public class TransferService {
@GET
@Produces("application/xml")
@Path("/transfer/{id}")
public String accountTransfer(@PathParam("id") long id) {
System.out.println("transfer id : "+id);
StringBuilder response = new StringBuilder(256);
response.append("<Response>").append("<id>").append(id)
.append("</id>").append("<transfer>").append("250.00").append("</transfer>")
.append("</Response>");
return response.toString();
}
}
http://localhost:8080/rest/account/balance/12
http://localhost:8080/rest/transfer/balance/13
答案 2 :(得分:0)
您可以简化逻辑来比较根资源,例如,知道请求URI和根资源类的名称就足以做出决定,检查各个方法看起来很复杂。顺便说一句,只有当根资源和/或个别资源方法成为平等候选人时才需要自定义资源比较器
答案 3 :(得分:0)
我以这种方式解决问题:
删除&#34; 自定义资源比较器&#34; (没有必要)
删除此内容:
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-bundle-jaxrs</artifactId>
<version>2.5.0</version>
</dependency>
在 account-servlet.xml / applicationContext 中:
<beans>
<jaxrs:server id="accountService" address="/rest">
<jaxrs:serviceBeans>
<ref bean="accountServiceImpl" />
<ref bean="transferServiceImpl" />
</jaxrs:serviceBeans>
</jaxrs:server>
</beans>
在 beans / class implementation :
中...
@Context("accountServiceImpl")
@Path("/account")
public class Accountservice{
...
这就是全部。 :)