我可以创建一个带有接口和实现类的restful服务吗?
如果是,所有与JAX-RS相关的导入都会进入接口吗?
我用的是球衣2.4和喷气式飞机8.1。
这是我的MyService
接口:
package foo.bar;
@Path("/abc")
public interface MyService {
@GET
@JSONP
@Path("/method/{id}")
public MyResponse getStuff(@PathParam("id") Integer id);
}
以及与接口的CCD_ 2的实现
package foo.bar.impl;
public class MyServiceImpl implements MyService {
public MyServiceImpl() {}
@Override
public MyResponse getStuff(Integer id) {
// do stuff
return MyResponse;
}
}
这是web.xml文件:
<servlet>
<servlet-name>Scivantage REST Service</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>foo.bar</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
我注册了这个服务提供商包(foo.bar
),但它抱怨说这个
javax.servlet.ServletException: A MultiException has 1 exceptions. They are:|1. java.lang.NoSuchMethodException: Could not find a suitable constructor in foo.bar.MyService class.
当我尝试使用实现类包(foo.bar.impl
)时,它抱怨说这个
I get HTTP ERROR 404; doesn't do anything else; no exceptions on console
当我同时尝试这两种方法时,它的抱怨与上面相同:
javax.servlet.ServletException: A MultiException has 1 exceptions. They are:|1. java.lang.NoSuchMethodException: Could not find a suitable constructor in foo.bar.MyService class.
我做错了什么?
这是我在几次试用后遇到的一个解决方案(我正在使用jetty 9和jersey 2.13):不要注释接口(使用@Path("/abc")
),而是尝试注释实现类。
我认为这很有道理,因为接口是"抽象的",不应该绑定到物理路径。这样,接口可以在不同的路径中重用。
如果您想使用带有JAX-RS注释的接口,则不能再使用web.xml 扫描包
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>XXX</param-value>
您需要手动将接口与资源实现绑定
bind(YourResource.class).to(YourResourceImpl.class);
原因:
出于性能原因,我们决定在扫描过程中忽略接口。此外,我们还修复了Jersey不会尝试实例化接口的问题。
https://java.net/jira/browse/JERSEY-1004
我也遇到了"找不到合适的构造函数"的问题。我想把我所有的注释(包括@Path)都放在我的接口上。我能够通过自己管理资源的生命周期来实现它,而不是让Jersey实例化它们。
例如,如果您有实现YourRestInterface
的YourImplementation
,那么您可以执行这样的操作来向Jersey注册该实现的实例:
public class RestConfig extends ResourceConfig {
@Inject
public RestConfig(ServiceLocator locator) {
super();
DynamicConfiguration c = Injections.getConfiguration(locator);
Object implInstance = new YourImplementation();
ServiceBindingBuilder<Object> bb = Injections.newFactoryBinder(new BeanFactory(locator, implInstance));
// tell Jersey to use the factory below to get an instance of YourRestInterface.class
bb.to(YourRestInterface.class);
Injections.addBinding(bb, c);
c.commit();
}
private static class BeanFactory implements Factory<Object> {
private ServiceLocator locator;
private Object bean;
BeanFactory(ServiceLocator locator, Object bean)
{
this.locator = locator;
this.bean = bean;
}
@Override
public Object provide() {
// have Jersey inject things annotated with @Context
locator.inject(bean);
return bean;
}
@Override
public void dispose(Object instance) {
}
}
}
在类ResourceConfig
中,有一个类似的构造函数
ResourceConfig(Class<?>... classes)
构造函数创建一个新的资源配置,该配置使用给定的一组资源/提供程序类初始化
因此,您可以扩展ResourceConfig
来注册实现类。
public class RestConfig extends ResourceConfig {
public RestConfig() {
// register the implementation class
super(MyServiceImpl.class);
}
}
然后,配置web.xml
。
<servlet>
<servlet-name>Scivantage REST Service</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<!-- the path of RestConfig -->
<param-value>foo.bar.RestConfig</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
但最简单的方法是在web.xml
中注册实现类。
<servlet>
<servlet-name>Scivantage REST Service</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<!-- the path of implementation class -->
<param-value>foo.bar.impl.MyServiceImpl</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
是的,您可以使用接口进行注释。在我们的应用程序中,我们已经通过这种方式实现了。以下引用自Jersy规范。
JAX-RS注释可以用于的方法和方法参数超类或实现的接口。此类注释由相应的子类或实现类方法继承前提是该方法及其参数没有任何JAX-RS它自己的注释。超类上的注释优先而不是实现接口上的那些。如果子类或实现方法具有任何JAX-RS注释,然后所有超类或接口方法上的注释被忽略
我认为在你的情况下,由于你可能错过了地图绘制,所以出现了错误,请检查。<servlet-mapping>
<servlet-name>api</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>