在springboot中创建webservice服务

发布时间:2023-05-15 18:30

        最近因为业务的需要,甲方让我在项目中提供webservice接口,然后他推送数据。然后我对甲方的那个技术说,你直接通过http的post访问我们的接口呗,然后他很无辜的用呆萌呆萌的语气和我说,啥post接口啊?接口不都是webservice的吗?再说了在sap中访问接口不就是用webservice吗?直接给我干不会了。我来这个新公司不长时间,因为业务的关系,以前没接触过sap的相关东西,sap是什么我也不知道,后来百度查了一下,我靠,好牛掰的样子,一套要十几万。我想,十几万的产品不能连post请求都办不到吧。算了,你说用webservice就用webservice吧,甲方是爹。

        然后,在创建webservice的过程中,遇到了许多的坑,躺了许多雷,为了避免大家采坑,现整理如下。

        首先是springboot的pom.xml文件,主要是引入以下依赖


	        javax.xml.bind
	        jaxb-api
	        2.3.0
	    
	    
	        com.sun.xml.bind
	        jaxb-impl
	        2.3.0
	    
	    
	        com.sun.xml.bind
	        jaxb-core
	        2.3.0
	    
	    
	        javax.activation
	        activation
	        1.1.1
	    

			org.springframework.boot
			spring-boot-starter-web-services
		

		
			org.apache.cxf
			cxf-spring-boot-starter-jaxws
			3.3.1
		
		
			org.apache.cxf
			cxf-rt-transports-http
			3.2.2
		
        
			org.codehaus.woodstox
			stax2-api
			4.0.0
		
		
			org.codehaus.woodstox
			woodstox-core-asl
			4.4.1
		
        
		
			org.apache.axis
			axis
			1.4
		

		
			axis
			axis-jaxrpc
			1.4
		

		
			commons-discovery
			commons-discovery
			0.2
		
		
			wsdl4j
			wsdl4j
			1.6.3
		

 我的jdk环境是jdk11,所以要引入最开始的4个依赖。

还有,springboot的版本不能太高,我原先的版本是2.3.3,跑不起来,后来在网上查到是版本不兼容导致的问题,于是把springboot的版本降到2.0.1,后来才跑起来。


        org.springframework.boot
        spring-boot-starter-parent
         2.0.1.RELEASE
        
        
    

然后,新建webservice的接口文件,如下所示:

package com.mango.jkm.webservice;

import java.util.List;

import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;

@WebService(name = "Wbceshijk", targetNamespace = "http://server.webservice.example.com")
public interface Wbceshijk {
	@WebMethod
    String emrService(@WebParam(name = "data") String data,@WebParam(name = "data2") String data2);
	@WebMethod
	String student1111(@WebParam(name = "data") String data,@WebParam(name = "data2") String data2);
	@WebMethod
	String aboutstudent(@WebParam(name="student") Student student);
	@WebMethod
	String studentlist(List list1);
}

然后是接口的实现类

package com.mango.jkm.webservice;

import java.util.List;

import javax.jws.WebParam;
import javax.jws.WebService;

import org.springframework.stereotype.Component;

@Component
@WebService( targetNamespace = "http://server.webservice.example.com",
        endpointInterface = "com.mango.jkm.webservice.Wbceshijk")
public class Webserviceceshi implements Wbceshijk{

	@Override
    public String emrService( String data,String data2) {
        if(null == data || "".equals(data.trim())){
            return "传入的参数为空";
        }
        return "data="+data+"@data2="+data2;
    }

	@Override
	public String student1111(String data, String data2) {
		// TODO 自动生成的方法存根
		return "22222data="+data+"@data2="+data2;
	}

	@Override
	public String aboutstudent(Student student) {
		// TODO 自动生成的方法存根
		System.out.println(student==null);
		return "student.getName()="+student.getName();
	}

	@Override
	public String studentlist(List list1) {
		// TODO 自动生成的方法存根
		return "list1.size()="+list1.size();
	}


}

 再然后是webservice的配置相关

package com.mango.jkm.webservice;

import javax.xml.ws.Endpoint;

import org.apache.cxf.Bus;
import org.apache.cxf.bus.spring.SpringBus;
import org.apache.cxf.jaxws.EndpointImpl;
import org.apache.cxf.transport.servlet.CXFServlet;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class WebServiceConfig {

    @Autowired
    private Wbceshijk serverServiceDemo;

    /**
     * Apache CXF 核心架构是以BUS为核心,整合其他组件。
     * Bus是CXF的主干, 为共享资源提供一个可配置的场所,作用类似于Spring的ApplicationContext,这些共享资源包括
     * WSDl管理器、绑定工厂等。通过对BUS进行扩展,可以方便地容纳自己的资源,或者替换现有的资源。默认Bus实现基于Spring架构,
     * 通过依赖注入,在运行时将组件串联起来。BusFactory负责Bus的创建。默认的BusFactory是SpringBusFactory,对应于默认
     * 的Bus实现。在构造过程中,SpringBusFactory会搜索META-INF/cxf(包含在 CXF 的jar中)下的所有bean配置文件。
     * 根据这些配置文件构建一个ApplicationContext。开发者也可以提供自己的配置文件来定制Bus。
     */
    @Bean(name = Bus.DEFAULT_BUS_ID)
    public SpringBus springBus() {
        return new SpringBus();
    }

    /**
     * 此方法作用是改变项目中服务名的前缀名,此处127.0.0.1或者localhost不能访问时,请使用ipconfig查看本机ip来访问
     * 此方法被注释后, 即不改变前缀名(默认是services), wsdl访问地址为 http://127.0.0.1:8080/services/ws/api?wsdl
     * 去掉注释后wsdl访问地址为:http://127.0.0.1:8080/soap/ws/api?wsdl
     * http://127.0.0.1:8080/soap/列出服务列表 或 http://127.0.0.1:8080/soap/ws/api?wsdl 查看实际的服务
     * 新建Servlet记得需要在启动类添加注解:@ServletComponentScan
     *
     * 如果启动时出现错误:not loaded because DispatcherServlet Registration found non dispatcher servlet dispatcherServlet
     * 可能是springboot与cfx版本不兼容。
     * 同时在spring boot2.0.6之后的版本与xcf集成,不需要在定义以下方法,直接在application.properties配置文件中添加:
     * cxf.path=/service(默认是services)
     */
//    @Bean
//    public ServletRegistrationBean dispatcherServlet() {
//        return new ServletRegistrationBean(new CXFServlet(), "/soap/*");
//    }

    @Bean
    public Endpoint endpoint() {
        EndpointImpl endpoint = new EndpointImpl(springBus(), serverServiceDemo);
        endpoint.publish("/ws/api");
        return endpoint;
    }
}

然后我在aplication.yml文件中添加了配置信息(非必要)

cxf:
  path: /service

这个是Student类

package com.mango.jkm.webservice;

import java.io.Serializable;

import javax.xml.bind.annotation.XmlAccessType;

import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;

@XmlRootElement(name="Student")
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(propOrder={"name", "address","age"})
public class Student implements Serializable {
	/**
	 * 
	 */
	private static final long serialVersionUID = 3428504463675931746L;
	public String name;
	public String address;
	public String age;
	
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getAddress() {
		return address;
	}

	public void setAddress(String address) {
		this.address = address;
	}

	public String getAge() {
		return age;
	}

	public void setAge(String age) {
		this.age = age;
	}

	@Override
	public String toString() {
		return  "#" + this.name + "#";
	}
}

 然后,启动springboot,访问对应的地址http://localhost:8081/service/ws/api?wsdl,得到熟悉的界面,可以看到webservice也启动成功了(webservice的端口号就是springboot项目自己的端口号)

在springboot中创建webservice服务_第1张图片

然后,可以用soupui工具进行访问,

 在springboot中创建webservice服务_第2张图片

点击ok,就可以看到在接口文件中定义的4个方法

在springboot中创建webservice服务_第3张图片

点击里面的emrService节点的request1,进行测试,可以看到返回数据结果

 在springboot中创建webservice服务_第4张图片

我感觉webservice也是post方式接口,因为我用apipost工具进行测试,body里放左侧的请求的xml,得到完全相同的的结果,为了验证我的猜想,我用springboot自带的RestTemplate类发送了一次post请求,发现也是得到了右侧的返回内容,这是我的测试类

package com.mango.jkm.webservice;

import javax.xml.namespace.QName;
import javax.xml.rpc.ParameterMode;
import javax.xml.rpc.encoding.XMLType;

import org.apache.axis.client.Call;
import org.apache.axis.client.Service;
import org.apache.axis.encoding.ser.BeanDeserializerFactory;
import org.apache.axis.encoding.ser.BeanSerializerFactory;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;

import com.alibaba.fastjson.JSONObject;


public class WbClient {
	public static void invokeService3() {
		  try {
	            //1、直接引用远程的wsdl文件  
	            String endpoint = "http://localhost:8081/service/ws/api?wsdl";  
	            Service service = new Service();
	            Call call = (Call) service.createCall(); //创建服务
	            call.setTargetEndpointAddress(endpoint);  
	            //2、定义报名和接口方法
	            QName qn=new QName("http://server.webservice.example.com", //wsdl文件中的targetNamespace
	                    "aboutstudent");
	            call.setOperationName(qn);

	            //3、设置参数
	        
	        
	            Student student=new Student();
	            student.setName("张小鑫");
	            student.setAddress("sssss");
	            student.setAge("10");
	            call.registerTypeMapping(Student.class,qn,  
                        new BeanSerializerFactory(Student.class, qn),  
                        new BeanDeserializerFactory(Student.class, qn));  
	            call.addParameter("student",
	            		new QName("http://server.webservice.example.com", "Student"), javax.xml.rpc.ParameterMode.IN);
//	            call.addParameter("student", org.apache.axis.encoding.XMLType.XSD_ANYTYPE,
//                        javax.xml.rpc.ParameterMode.IN);//接口的参数
	            call.setReturnType(org.apache.axis.encoding.XMLType.XSD_STRING);//设置返回类型  

	            call.setUseSOAPAction(true);
	            String result = (String)call.invoke(new Object[]{student});
	            System.out.println("result="+result); 
	           
	           
	        } catch (Exception e) {  
	            e.printStackTrace();
	        }
		
	}
	public static void invokeService_2(){

		  try {
	            //1、直接引用远程的wsdl文件  
	            String endpoint = "http://localhost:8081/service/ws/api?wsdl";  
	            Service service = new Service();
	            Call call = (Call) service.createCall(); //创建服务
	            call.setTargetEndpointAddress(endpoint);  
	            //2、定义报名和接口方法
	            call.setOperationName(new QName("http://server.webservice.example.com", //wsdl文件中的targetNamespace
	                    "emrService") //接口实现功能的方法
	                    );
	            
	            //3、设置参数
	            call.addParameter("data", XMLType.XSD_STRING,ParameterMode.IN);// 接口的参数  
	            call.addParameter("data2",XMLType.XSD_STRING,ParameterMode.IN);// 接口的参数  
	            call.setReturnType(XMLType.XSD_STRING);// 设置返回类型  
	           
	          
	            
	            //4、给方法传递参数,并且调用方法
	            String result = (String) call.invoke(new Object[] {"1111" ,"2222"});  
	            System.out.println("result="+result);
	        } catch (Exception e) {  
	            e.printStackTrace();
	        }

//		
	}
	public static void restfangwen() {
		RestTemplate restTemplate = new RestTemplate();
		HttpHeaders headers = new HttpHeaders();
		headers.setContentType(MediaType.APPLICATION_XML);
		String xml="\r\n"
				+ "   \r\n"
				+ "   \r\n"
				+ "      \r\n"
				+ "         \r\n"
				+ "         \r\n"
				+ "            \r\n"
				+ "            zx\r\n"
				+ "            \r\n"
				+ "            
address
\r\n" + " \r\n" + " 18\r\n" + "
\r\n" + "
\r\n" + "
\r\n" + "
"; HttpEntity requestEntity = new HttpEntity<>(xml, headers); ResponseEntity resEntity = restTemplate.postForEntity("http://localhost:8081/service/ws/api", requestEntity, String.class); String result=resEntity.getBody(); System.out.println("str="+result); } public static void main(String[] args) { WbClient.restfangwen(); } }

 在这个测试类中,我访问的是webservice里的aboutstudent方法,能得到对应的返回内容

str=student.getName()=zx

用axis能访问emrService方法,并且返回正确的数据。如果输入参数不是java基本类型而是类的话,怎么弄都不好使,网上各种办法都不好使,我也不知道为啥。各位大神如果你们成功了,就请在留言区说一下,小弟不胜感激。

ItVuer - 免责声明 - 关于我们 - 联系我们

本网站信息来源于互联网,如有侵权请联系:561261067@qq.com

桂ICP备16001015号