解決springboot整合cxf-jaxrs中json轉(zhuǎn)換的問題
前言
我在將項(xiàng)目用boot重構(gòu)時(shí), 關(guān)于cxf的使用出了一些問題, 主要在實(shí)體類和json轉(zhuǎn)換這一方面。
在看了一些晚上的相關(guān)答案后, 了解到j(luò)axb默認(rèn)支持xml格式, 而實(shí)現(xiàn)對(duì)象轉(zhuǎn)json是需要額外的轉(zhuǎn)換器的,然后在stackoverflow上找到一個(gè)解決方法是聲明一個(gè)bean,注入JsonProvider,但我發(fā)現(xiàn)這個(gè)可以解決服務(wù)端將對(duì)象轉(zhuǎn)為json的問題,
而客戶端還是會(huì)報(bào)一個(gè)異常:
No message body reader has been found for class ......, ContentType: application/json
后面在cxf的WebClient類的源碼中發(fā)現(xiàn):
create()方法有很多重載方法,其中有一個(gè)是可以指定provider來轉(zhuǎn)換格式,最后通過這個(gè)重載方法解決了客戶端json格式轉(zhuǎn)換問題。

最后的解決方案:
在單獨(dú)使用cxf的基礎(chǔ)上做出改動(dòng),主要有兩方面
1. 服務(wù)端:在啟動(dòng)類上聲明一個(gè)bean, 注入JacksonJaxbJsonProvider
2. 客戶端:在WebClient調(diào)用create()方法時(shí),指定轉(zhuǎn)json的provider
下面是一個(gè)簡(jiǎn)單的demo:
一、webservice服務(wù)端(生產(chǎn)者)
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轉(zhuǎn)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應(yīng)用啟動(dòng)類配置
在啟動(dòng)類中聲明一個(gè)bean,自動(dòng)注入JacksonJaxbJsonProvider 對(duì)象,這樣cxf在將對(duì)象轉(zhuǎn)為json時(shí)會(huì)自動(dòng)使用這個(gè)對(duì)象
@SpringBootApplication
public class CxfServerApplication {
public static void main(String[] args) {
SpringApplication.run(CxfServerApplication.class, args);
}
// 配置一個(gè)對(duì)象與json轉(zhuǎn)換的工具
@Bean
public JacksonJaxbJsonProvider jacksonJaxbJsonProvider() {
return new JacksonJaxbJsonProvider();
}
}
4.客戶服務(wù)接口
關(guān)于cxf的路徑注解,請(qǐng)參照其他cxf資料
@Path("/customerService")
public interface CustomerService {
/**
* 客戶服務(wù):根據(jù)id查詢客戶
*/
@Path("/findById")
@GET
@Produces({"application/xml", "application/json"})
Customer findById(@QueryParam("id")Integer id);
}
5.客戶服務(wù)實(shí)現(xiàn)類
一個(gè)簡(jiǎn)單的實(shí)現(xiàn)類, 不需要加額外注解, 注入dao從數(shù)據(jù)庫(kù)查詢數(shù)據(jù)返回(dao層代碼未貼出, 可自行實(shí)現(xiàn))。
@Service
@Transactional
public class CustomerServiceImpl implements CustomerService {
@Autowired
private CustomerDao customerDao;
@Override
public Customer findById(Integer id) {
// 調(diào)用dao, 從數(shù)據(jù)庫(kù)查詢客戶
return customerDao.findById(id);
}
}
二、webservice客戶端(消費(fèi)者)
1.maven依賴
<dependency> <groupId>org.springframework.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> </dependency> <!--jaxrs轉(zhuǎn)json工具--> <dependency> <groupId>com.fasterxml.jackson.jaxrs</groupId> <artifactId>jackson-jaxrs-json-provider</artifactId> <version>2.8.5</version> </dependency>
2.配置轉(zhuǎn)json工具
由于WebClient的create()方法需要的是List<Provider>形式的參數(shù),所以創(chuàng)建一個(gè)繼承ArrayList類的JsonProvider,在構(gòu)造方法中添加JacksonJaxbJsonProvider對(duì)象元素
@Component
public class JsonProvider extends ArrayList<JacksonJaxbJsonProvider> {
// 在構(gòu)造方法中, 添加JacksonJaxbJsonProvider
public JsonProvider(){
this.add(new JacksonJaxbJsonProvider());
}
}
3.使用WebClient調(diào)用webservice服務(wù)
在Controller內(nèi)注入上面創(chuàng)建的自定義的JsonProvider,并在WebClient調(diào)用create()方法時(shí),作為方法參數(shù)注入,以此達(dá)到手動(dòng)指定json轉(zhuǎn)換器的目的
@Controller
public class CustomerController {
// 注入配置的轉(zhuǎn)json工具
@Autowired
private List<JacksonJaxbJsonProvider> jsonProvider;
@RequestMapping("/customer_findById")
@ResponseBody
public List<Customer> findById(Integer id) {
//調(diào)用webservice獲取查詢數(shù)據(jù)
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格式轉(zhuǎn)換后傳輸?shù)膶?shí)體類要在類名上加一個(gè)注解
@XmlRootElement(name = "xxx")
2.上面demo使用的cxf-spring-boot-starter-jaxrs版本為3.2.0
在3.2.1以后的版本需要手動(dòng)配置ViewResolver
否則會(huì)報(bào)錯(cuò):
@ConditionalOnProperty(spring.mvc.locale) did not find property 'locale' (OnPropertyCondition)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
一段眼睛跟著鼠標(biāo)轉(zhuǎn)動(dòng)的跟蹤眼代碼
java實(shí)現(xiàn)的眼睛跟著鼠標(biāo)轉(zhuǎn)動(dòng)的跟蹤眼代碼2008-10-10
java?Export大量數(shù)據(jù)導(dǎo)出和打包
這篇文章主要為大家介紹了java?Export大量數(shù)據(jù)的導(dǎo)出和打包實(shí)現(xiàn)過程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-06-06
SpringBoot與spring security的結(jié)合的示例
這篇文章主要介紹了SpringBoot與spring security的結(jié)合的示例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-03-03
SpringBoot結(jié)合JWT登錄權(quán)限控制的實(shí)現(xiàn)
本文主要介紹了SpringBoot結(jié)合JWT登錄權(quán)限控制的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07
Java利用策略模式實(shí)現(xiàn)條件判斷,告別if else
策略模式定義了一系列算法,并且將每個(gè)算法封裝起來,使得他們可以相互替換,而且算法的變化不會(huì)影響使用算法的客戶端。本文將通過案例講解如何利用Java的策略模式實(shí)現(xiàn)條件判斷,告別if----else條件硬編碼,需要的可以參考一下2022-02-02
ThreadLocal使用案例_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
這篇文章主要介紹了ThreadLocal使用案例分析,需要的朋友可以參考下2017-08-08
SpringBoot2.0整合Shiro框架實(shí)現(xiàn)用戶權(quán)限管理的示例
這篇文章主要介紹了SpringBoot2.0整合Shiro框架實(shí)現(xiàn)用戶權(quán)限管理的示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08

