Многократная конфигурация resouceBean в CXF с использованием Spring - PullRequest
4 голосов
/ 15 марта 2012

Я использую CXF RS 2.5.1 с Spring 3.0.6-RELEASE.Я хотел бы иметь несколько классов реализации для «одной конечной точки».Я вижу, что об этой проблеме сообщили и исправили 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>

account-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.

Ответы [ 4 ]

4 голосов
/ 10 июля 2015

Я решил эту проблему, переместив часть отображения @Path в класс служебного компонента. В вашем случае:

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) {
       ...      
    }
}
3 голосов
/ 19 марта 2012

Так что я потратил некоторое время на поиск в интернете, но не нашел решения этой проблемы. В документации есть примечание, которое можно использовать для вывода решения.

http://cxf.apache.org/docs/jax-rs-basics.html#JAX-RSBasics-Customselectionbetweenmultipleresources

Поэтому я написал собственный компаратор ресурсов, сделал соответствующие jaxrs: конфигурация сервера и Eureka! это сработало!. Теперь у меня есть 2 класса реализации, сопоставленных одному ресурсу / адресу в адресе javax: rs.

Обратите внимание, что приведенная ниже логика в настраиваемом компараторе ресурсов может отличаться в зависимости от шаблона URL.

Предоставление источника всех файлов. Надеюсь, что это поможет кому-то в будущем:)

web.xml

<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>

account-servlet.xml (applicationContext)

<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>

pom.xml

  <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;
    }

}

Реализация классов / бинов

AccountService.java

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();
    }

}

TransferService.java

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();
    }


}

URL-адрес:

http://localhost:8080/rest/account/balance/12
http://localhost:8080/rest/transfer/balance/13
0 голосов
/ 14 октября 2014

Я бы решил проблему следующим образом:

  • Удаление " Настраиваемый компаратор ресурсов " (в этом нет необходимости)

  • Удаление этого:

    <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>
    
  • В реализации bean / class :

    ...
    @Context("accountServiceImpl")
    @Path("/account")
    public class Accountservice{
    ...
    

И это все.:)

0 голосов
/ 20 марта 2012

Вы, вероятно, можете упростить логику, связанную со сравнением корневых ресурсов, например, зная, что URI запроса и имя класса корневых ресурсов могут быть достаточными для принятия решения, проверка отдельных методов выглядит сложной.Кстати, пользовательские компараторы ресурсов нужны только тогда, когда корневые ресурсы и / или отдельные методы ресурсов могут стать равными кандидатами

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...