springboot整合cxf-jaxrs中json轉換問題和簡單解決方案
阿新 • • 發佈:2019-02-16
前言
我在將專案用boot重構時, 關於cxf的使用出了一些問題, 主要在實體類和json轉換這一方面。
在看了一些晚上的相關答案後, 瞭解到jaxb預設支援xml格式, 而實現物件轉json是需要額外的轉換器的,然後在stackoverflow上找到一個解決方法是宣告一個bean,注入JsonProvider,但我發現這個可以解決服務端將物件轉為json的問題,而客戶端還是會報一個異常:
No message body reader has been found for class ......, ContentType: application/json
後面在cxf的WebClient類的原始碼中發現:create()方法有很多過載方法,其中有一個是可以指定provider來轉換格式,最後通過這個過載方法解決了客戶端json格式轉換問題。
最後的解決方案:在單獨使用cxf的基礎上做出改動,主要有兩方面
1. 服務端:在啟動類上宣告一個bean, 注入JacksonJaxbJsonProvider
2. 客戶端:在WebClient呼叫create()方法時,指定轉json的provider
由於本人剛接觸boot,只能簡單地實現功能。如果有大佬們有別的方案,可評論中留言,多謝
下面是一個簡單的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, args); } // 配置一個物件與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.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轉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> {
// 在構造方法中, 新增JacksonJaxbJsonProvider
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)