springboot集成jersey后发布到tomcat/jetty后,调用接口,报错如下:
测试url:http://localhost:80/test/webapi/account/login
工程jersey配置类
jersey配置类代码:
@Component @ApplicationPath("/webapi/*") public class AppResourceConfig extends ResourceConfig { public AppResourceConfig() { packages("com.test.rs"); register(MultiPartFeature.class); } }
错误原因:springboot加载该配置时,默认以ServletRegistrationBean方式加载,在加载时,会在配置的ApplicationPath后面再加上"/*"作为servlet的urlMapping。
jersey自动将ResourceConfig加载为servlet的代码在org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration类。注册servlet代码:
public ServletRegistrationBean jerseyServletRegistration() { ServletRegistrationBean registration = new ServletRegistrationBean(new ServletContainer(this.config), new String[]{this.path}); this.addInitParameters(registration); registration.setName(this.getServletRegistrationName()); registration.setLoadOnStartup(this.jersey.getServlet().getLoadOnStartup()); return registration; }
处理ApplicationPath源码:
private void resolveApplicationPath() { if (StringUtils.hasLength(this.jersey.getApplicationPath())) { this.path = parseApplicationPath(this.jersey.getApplicationPath()); } else { this.path = findApplicationPath((ApplicationPath)AnnotationUtils.findAnnotation(this.config.getApplication().getClass(), ApplicationPath.class)); } } 判断注解ApplicationPath配置的参数,生成新的path。 private static String parseApplicationPath(String applicationPath) { if (!applicationPath.startsWith("/")) { applicationPath = "/" + applicationPath; } return applicationPath.equals("/") ? "/*" : applicationPath + "/*"; }
因此,如果像前面代码所示,配置为"/webapi/*"时,实际servlet对应的urlMapping为"/webapi/*/*",这样调用接口实际的url就需要写成 http://localhost:80/test/webapi/*/account/login才能找到正确的path。
如果需要以开始的url访问接口,即不带*的url,那么jersey的配置类ApplicationPath注解需改为@ApplicationPath("/webapi")。这样用http://localhost:80/test/webapi/account/login调用接口就正常了。
另外:springboot启动servlet代码入口:
org.springframework.boot.web.servlet.ServletRegistrationBean类的onStartup方法: public void onStartup(ServletContext servletContext) throws ServletException { Assert.notNull(this.servlet, "Servlet must not be null"); String name = this.getServletName(); if (!this.isEnabled()) { logger.info("Servlet " + name + " was not registered (disabled)"); } else { logger.info("Mapping servlet: '" + name + "' to " + this.urlMappings); Dynamic added = servletContext.addServlet(name, this.servlet); if (added == null) { logger.info("Servlet " + name + " was not registered (possibly already registered?)"); } else { this.configure(added); } } }