1. 程式人生 > 程式設計 >解決springboot整合cxf-jaxrs中json轉換的問題

解決springboot整合cxf-jaxrs中json轉換的問題

前言

我在將專案用boot重構時,關於cxf的使用出了一些問題,主要在實體類和on轉換這一方面。

在看了一些晚上的相關答案後,瞭解到jaxb預設支援xml格式,而實現物件轉json是需要額外的轉換器的,然後在stackoverflow上找到一個解決方法是宣告一個bean,注入JsonProvider,但我發現這個可以解決服務端將物件轉為json的問題,

而客戶端還是會報一個異常:

No message body reader has been found for class ......,ContentType: application/json

後面在cxf的WebClient類的原始碼中發現:

create()方法有很多過載方法,其中有一個是可以指定provider來轉換格式,最後通過這個過載方法解決了客戶端json格式轉換問題。

解決springboot整合cxf-jaxrs中json轉換的問題

最後的解決方案:

在單獨使用cxf的基礎上做出改動,主要有兩方面

1. 服務端:在啟動類上宣告一個bean,注入JacksonJaxbJsonProvider

2. 客戶端:在WebClient呼叫create()方法時,指定轉json的provider

下面是一個簡單的demo:

一、webservice服務端(生產者)

1.maven依賴

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-test</artifactId>
	<scope>test</scope>
</dependency>
<!--cxf-jaxrs-starter-->
<dependency>
	<groupId>org.apache.cxf</groupId>
	<artifactId>cxf-spring-boot-starter-jaxrs</artifactId>
	<version>3.2.0</version>
</dependency>
<!--jaxrs轉json工具-->
<dependency>
	<groupId>com.fasterxml.jackson.jaxrs</groupId>
	<artifactId>jackson-jaxrs-json-provider</artifactId>
	<version>2.8.5</version>
</dependency>

2.application.yml配置檔案

配置cxf路徑和包掃描

server:
  port: 9001
cxf:
  path: /services
  servlet.init:
    service-list-path: /info
  jaxrs:
    component-scan: true

3.boot應用啟動類配置

在啟動類中宣告一個bean,自動注入JacksonJaxbJsonProvider 物件,這樣cxf在將物件轉為json時會自動使用這個物件

@SpringBootApplication
public class CxfServerApplication { 
	public static void main(String[] args) {
		SpringApplication.run(CxfServerApplication.class,arg
s); } // 配置一個物件與json轉換的工具 @Bean public JacksonJaxbJsonProvider jacksonJaxbJsonProvider() { return new JacksonJaxbJsonProvider(); } }

4.客戶服務介面

關於cxf的路徑註解,請參照其他cxf資料

@Path("/customerService")
public interface CustomerService { 
    /**
     * 客戶服務:根據id查詢客戶
     */
    @Path("/findById")
    @GET
    @Produces({"application/xml","application/json"})
    Customer findById(@QueryParam("id")Integer id);
}

5.客戶服務實現類

一個簡單的實現類,不需要加額外註解,注入dao從查詢資料返回(dao層程式碼未貼出,可自行實現)。

@Service
@Transactional
public class CustomerServiceImpl implements CustomerService { 
    @Autowired
    private CustomerDao customerDao; 
    @Override
    public Customer findById(Integer id) {
        // 呼叫dao,從資料庫查詢客戶
        return customerDao.findById(id);
    }
}

二、webservice客戶端(消費者)

1.maven依賴

<dependency>
	<groupId>org.http://www.cppcns.comspringframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--cxf-jaxrs-starter-->
<dependency>
	<groupId>org.apache.cxf</groupId>
	<artifactId>cxf-spring-boot-starter-jaxrs</artifactId>
	<version>3.2.0</version>
</dephttp://www.cppcns.comendency>
<!--jaxrs轉json工具-->
<dependency>
	<groupId>com.fasterxml.jackson.jaxrs</groupId>
	<artifactId>jackson-jaxrs-json-provider</artifactId>
	<version>2.8.5</version>
</dependency>

2.配置轉json工具

由於WebClient的create()方法需要的是List<Provider>形式的引數,所以建立一個繼承ArrayList類的JsonProvider,在構造方法中新增JacksonJaxbJsonProvider物件元素

@Component
public class JsonProvider extends ArrayList<JacksonJaxbJsonProvider> {    
    // 在構造方法中,新增JacksonJaxbJsonProwww.cppcns.comvider
    public JsonProvider(){
        this.add(new JacksonJaxbJsonProvider());
    }
}

3.使用WebClient呼叫webservice服務

在Controller內注入上面建立的自定義的JsonProvider,並在WebClient呼叫create()方法時,作為方法引數注入,以此達到手動指定json轉換器的目的

@Controller
public class CustomerController { 
    // 注入配置的轉json工具
    @Autowired
    private List<JacksonJaxbJsonProvider> jsonProvider; 
    @RequestMapping("/customer_findById")
    @ResponseBody
    public List<Customer> findById(Integer id) {
        //呼叫webservice獲取查詢資料
        Customer customer = WebClient
                .create("http://localhost:9001/services/customerService/findById?id="+id,jsonProvider)
                .accept(MediaType.APPLICATION_JSON).get(Customer.class);
        return customer;
    }
}

三、其他注意

1.需要用xml/json格式轉換後傳輸的實體類要在類名上加一個註解

@XmlRootElement(name = "xxx")

2.上面demo使用的cxf-spring-boot-starter-jaxrs版本為3.2.0

在3.2.1以後的版本需要手動配置ViewResolver

否則會報錯:

@ConditionalOnProperty(spring.mvc.locale) did not find property 'locale' (OnPropertyCondition)

以上為個人經驗,希望能給大家一個參考,也希望大家多多支援我們。