springBoot+CXF開發webservice服務

前言

最近一直開發一個webservice的接口,因爲是第一次接觸webservice,並且仍是在結合spingBoot和CXF框架的狀況下開發的,因此剛開始有點懵逼,遇到了各類問題。可是,終究仍是完成了,以此分享一下個人開發過程。html

開發流程

添加CXF依賴

根據項目使用的構建工具,添加相應的jar包,由於個人項目用到是gradle,添加依賴以下:web

compile group: 'org.apache.cxf', name: 'cxf', version: '2.7.6'
複製代碼

接口目錄結構以下: spring

接口目錄結構

實體類

請求實體類:

@XmlRootElement(name = "ReceiveDisposalPlanMassageRequest")
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "ReceiveDisposalPlanMassageRequest", propOrder = {
        "year",
        "disposalNumber",
        "planName",
        "planCode",
        "orgId",
        "orgName",
        "estimateAmount",
        "baseAmount",
        "fillUserId",
        "fillUserName",
        "remark",
        "billType",
        "dataAreaName",
        "creatorId",
        "creator",
        "auctionMaterialList",
        "disposalPlanAttachmentList"
})
public class ReceiveDisposalPlanMassageRequest {

    @XmlElement(required = true)
    private String year;//年度

    @XmlElement(required = true)
    private String disposalNumber;//處置批次號

    @XmlElement(required = true)
    private String planName;//處置計劃名稱

    @XmlElement(required = true)
    private String planCode;//處置計劃編號

    @XmlElement(required = true)
    private String orgId;//物資所屬單位ID

    @XmlElement(required = true)
    private String orgName;//物資所屬單位名稱

    @XmlElement(required = true)
    private Double estimateAmount;//預估金額

    @XmlElement(required = true)
    private Double baseAmount;//底價

    @XmlElement(required = true)
    private String fillUserId;//填報人ID

    @XmlElement(required = true)
    private String fillUserName;//填報人

    @XmlElement(required = false)
    private String remark;//備註

    @XmlElement(required = true)
    private String billType;//登記類型

    @XmlElement(required = true)
    private String dataAreaName;//產權持有單位

    @XmlElement(required = true)
    private String creatorId;//制單人ID

    @XmlElement(required = true)
    private String creator;//制單人

    @XmlElement(required = true)
    private List<AuctionMaterial> auctionMaterialList;//物資明細列表

    @XmlElement(required = true)
    private List<SyncAttachmentVO> disposalPlanAttachmentList;//附件列表
    //省略set,get方法
}
複製代碼

返回值類:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "SoaResponse", propOrder = {
    "status",
    "message"
})
public class SoaResponse {
    @XmlElement(nillable = true)
    protected int status;  //同步結果
    @XmlElement(nillable = true)
    protected String message; //返回信息
    //省略set,get方法
}
複製代碼

關於@XmlAccessorType,@XmlType,@XmlElement相關注解的用處,能夠參考如下教程: JABX 教程apache

接口

@WebService(name = "ReceiveDisposalPlanMassageSer",targetNamespace = Constants_soa.NAME_SPACE)
public interface ReceiveDisposalPlanMassageFacade {

    @WSDLDocumentation("接收處置計劃信息")
    @WebResult(name = "receiveDisposalPlanMassageResponse", targetNamespace = Constants_soa.NAME_SPACE)
    @RequestWrapper(localName = "request")
    @ResponseWrapper(localName = "response")
    @WebMethod()
    public SoaResponse receiveDisposalPlanMassage(@WebParam(name = "receiveDisposalPlanMassageRequest", targetNamespace = Constants_soa.NAME_SPACE)ReceiveDisposalPlanMassageRequest receiveDisposalPlanMassageRequest) throws SoaFault;
}
複製代碼

接口實現

@WebService(name = "ReceiveDisposalPlanMassageSer",targetNamespace = Constants_soa.NAME_SPACE)
@Component("ReceiveDisposalPlanMassageSer")
public class ReceiveDisposalPlanMassageFacadeImpl implements ReceiveDisposalPlanMassageFacade {

    private static final Logger logger = LoggerFactory.getLogger(ReceiveDisposalPlanMassageFacadeImpl.class);
    @Autowired
    private DisposalPlanFacade disposalPlanFacade;
    @Autowired
    private AuctionMaterialFacade auctionMaterialFacade;
    @Autowired
    private AttachmentFacade attachmentFacade;

    @Override
    public SoaResponse receiveDisposalPlanMassage(ReceiveDisposalPlanMassageRequest request)throws SoaFault {

        SoaResponse response = new SoaResponse();

        try {
            if (request != null) {
            //此處省略業務代碼
            }
            response.setStatus(0);
            response.setMessage("ok");
        }catch (Exception e){
            logger.error("服務器發生未知異常!" + e.getMessage());
            response.setStatus(-1);
            response.setMessage(e.getMessage());
        }
        return response;
    }
}
複製代碼

服務發佈工具類

@Configuration
public class CxfConfig {
    private static final Logger logger = LoggerFactory.getLogger(CxfConfig.class);

    private String scanPath = "xxx";//此處是接口所在的包路徑

    @Bean(name = Bus.DEFAULT_BUS_ID)
    public SpringBus springBus() {
        SpringBus bus = new SpringBus();
        // 日誌打印
        bus.getInInterceptors().add(new LoggingInInterceptor());
        bus.getOutInterceptors().add(new LoggingOutInterceptor());
        return bus;
    }

    /**
     * 發佈服務名稱
     * 訪問該路徑能夠查看發佈的服務
     * @return
     */
    @Bean
    public ServletRegistrationBean disServlet() {
        return new ServletRegistrationBean(new CXFServlet(), "/webservice/*");
    }

    @Bean
    @ConditionalOnMissingBean
    public WadlGenerator wadlGenerator() {
        WadlGenerator wadlGenerator = new WadlGenerator();
        return wadlGenerator;
    }

    @Bean
    @ConditionalOnMissingBean
    public ObjectMapper objectMapper() {
        return new ObjectMapper();
    }

    @Bean
    @ConditionalOnMissingBean
    public JacksonJsonProvider jsonProvider(ObjectMapper objectMapper) {
        JacksonJaxbJsonProvider provider = new JacksonJaxbJsonProvider();
        provider.setMapper(objectMapper);
        return provider;
    }

    @Bean
    @ConditionalOnMissingBean
    public JAXBElementProvider xmlProvider() {
        return new JAXBElementProvider();
    }

    /*
     * 使用cxf發佈soap服務
     * */
    @Bean
    public List<Endpoint> endpoints(ApplicationContext ctx) {
        ArrayList<Endpoint> endpoints = new ArrayList<Endpoint>();
        try {
            //從spring上下文裏獲取含有WebService註解的對象
            List<Object> serviceBeans = new ArrayList<Object>(ctx.getBeansWithAnnotation(WebService.class).values());
            if (ListUtils.isEmpty(serviceBeans)) {
                logger.info("serviceBeans is empty");
                return endpoints;
            }
            EndpointImpl endpoint = null;
            //遍歷serviceBeans 發佈soap接口
            for (Object webService : serviceBeans) {
                String webServiceClassName = webService.getClass().getName();
                boolean startsWith = webServiceClassName.startsWith(scanPath);
                logger.info("SOAP endpoints:\nwebServiceClassName:{}\nscanPath:{}\nwebServiceClassName.startsWith(scanPath):{}",webServiceClassName,scanPath,startsWith);

                if (startsWith) {
                    WebService annotation = AnnotationUtils.findAnnotation(webService.getClass(),WebService.class);
                    if (annotation == null){
                        continue;
                    }
                    String name = annotation.name();
                    if (StringUtil.isEmpty(name)) {
                        name = annotation.serviceName();
                    }
                    if (StringUtil.isEmpty(name)) {
                        logger.error("webservice " + webService.getClass().getSimpleName() + " 實現類沒有 @WebService(name='xxx') 的註解");
                        continue;
                    }
                    endpoint = new EndpointImpl(springBus(), webService);
                    endpoint.publish("/" + name);
                    endpoints.add(endpoint);
                }
            }
        } catch (Exception e) {
            logger.error("cxf soap error……");
            logger.error(e.getMessage(), e);
        }
        return endpoints;
    }


    /*
     * 發佈rest
     * */
    @Bean
    @ConditionalOnMissingBean
    public Server jaxRsServer(ApplicationContext ctx) {
        try {
            List<Object> serviceBeans = new ArrayList<Object>(ctx.getBeansWithAnnotation(Path.class).values());
            if(ListUtils.isEmpty(serviceBeans)){
                logger.info("found serviceBeans is empty in spring application context.");
                return null;
            }
            logger.info("serviceBeans:{}",serviceBeans.size());
            Iterator<Object> iterator = serviceBeans.iterator();
            while (iterator.hasNext()) {
                Object next = iterator.next();

                String serviceBeanClassName = next.getClass().getName();
                boolean startsWith = serviceBeanClassName.startsWith(scanPath);
                logger.info("REST endpoints:\nserviceBeanClassName:{}\nscanPath:{}\nwebServiceClassName.startsWith(scanPath):{}",serviceBeanClassName,scanPath,startsWith);
                if (!startsWith) {
                    iterator.remove();
                }
            }
            if (ListUtils.isEmpty(serviceBeans)){
                logger.info("found serviceBeans is empty in {}.",scanPath);
                return null;
            }
            logger.info("serviceBeans:{}",serviceBeans.size());
            List<Object> providers = new ArrayList<Object>(ctx.getBeansWithAnnotation(Provider.class).values());
            providers.add(wadlGenerator());

            Map<Object, Object> extensionMappings = new HashMap<>();
            extensionMappings.put("xml", "application/xml");
            extensionMappings.put("json", "application/json");

            JAXRSServerFactoryBean factory = new JAXRSServerFactoryBean();
            factory.setBus(springBus());
            factory.setAddress("/rest");
            factory.setServiceBeans(serviceBeans);
            factory.setProviders(providers);
            factory.setExtensionMappings(extensionMappings);
            Server server = factory.create();
            return server;
        } catch (Exception e) {
            logger.error("cxf rest error……");
            logger.error(e.getMessage(), e);
            return null;
        }
    }
}
複製代碼

代碼已經完了,接下來就是啓動項目,訪問服務。個人服務發佈成功以後以下所示:json

  • 服務接口對應的方法:
  • wsdl文檔:

結語

以上內容就是我開發webservice接口的所有過程,但願對你們有所幫助,謝謝!bash

相關文章
相關標籤/搜索