我正在使用ApacheCXF开发JAX-RSRest服务。在将它部署到Tomcat7服务器之后,如果我键入URL http://localhost:8080/Rest/rest?_wadl
,它将显示WADL。但是如果我输入URL http://localhost:8080/Rest/rest/retrieve
,它会给我404错误。
在以上URL中:Rest
是我的项目名称/rest
是在web.xml
中指定的我的CXFServlet
的url模式/
是在beans.xml
中指定的jaxrs:server
的地址retrieve
是在我的接口中指定的带有@Path
注释的服务路径。
(我很抱歉:我不能提供上面提到的XML文档。)
我认为这是一个CXF错误,它为restful web服务获取了不正确的基本URL。
类"org.apache.cxf.transport.servlet.ServletController"调用类"org.apache.cxf.ttransport.servole.BaseUrlHelper"的方法"getBaseURL"。
它从请求URL中获取基本URL,并忽略参数部分。这对于SOAP web服务是正确的,因为SOAP web服务URL就像:http://host:port/basepath?para=a
。不幸的是,对于restful web服务,URL就像http://host:port/basepath/method/parameter
一样。正确的基本URL应该是http://host:port/basepath
,但实际上,BaseUrlHelper提供了http://host:port/basepath/method/parameter
。它只是在"?"之前给出URL。这就是为什么当您访问http://localhost:8080/Rest/rest?_wadl
时结果是正确的,在这种情况下,它给出了正确的基本URL http://localhost:8080/Rest
。
如果您先访问http://localhost:8080/Rest/rest?_wadl
,然后再访问http://localhost:8080/Rest/rest/retrieve
,则这是正确的。因为,CXF只在第一次将基本URL设置为EndpointInfo的地址。这意味着,您必须在第一时间访问正确的基本URL!:(
解决方案是:覆盖"org.apache.cxf.transport.servlet.ServletController"的方法"getBaseURL(HttpServlet请求)",让它返回正确的基本URL。
例如,步骤1:扩展Servlet控制器。
public class RestfulServletController extends ServletController {
private final String basePath;
public RestfulServletController(DestinationRegistry destinationRegistry, ServletConfig config,
HttpServlet serviceListGenerator, String basePath) {
super(destinationRegistry, config, serviceListGenerator);
this.basePath = basePath;
}
@Override
protected String getBaseURL(HttpServletRequest request) {
// Fixed the bug of BaseUrlHelper.getBaseURL(request) for restful service.
String reqPrefix = request.getRequestURL().toString();
int idx = reqPrefix.indexOf(basePath);
return reqPrefix.substring(0, idx + basePath.length());
}
}
步骤2:扩展CXFNonSpringServlet并在子类中使用RestfulServlet控制器
public class RestfulCXFServlet extends CXFNonSpringServlet {
... ...
private ServletController createServletController(ServletConfig servletConfig) {
HttpServlet serviceListGeneratorServlet = new ServiceListGeneratorServlet(destinationRegistry, bus);
ServletController newController = new RestfulServletController(destinationRegistry, servletConfig,
serviceListGeneratorServlet, basePath);
return newController;
}
}
步骤3:使用派生类RestfulServlet控制器,而不是CXFNonSpringServlet。别忘了,您应该将"basePath"配置为/Rest/Rest。
希望这能帮助到你。