SpringBoot整合CXF实例

Springboot整合CXF实例

添加依赖

<dependency>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-spring-boot-starter-jaxws</artifactId>
    <version>3.2.5</version>
</dependency>

定义要发布的接口和实现类

@WebService(name = "CommonService", // 暴露服务名称
targetNamespace = "http://www.service.mf.com")// 命名空间,一般是接口的包名倒序
public interface CommonService {

@WebMethod
Map<String, Object> addBills(@WebParam(name="bills")InBills bills);

@WebMethod
Map<String, Object> deleteBills(@WebParam(name="billNo")String billNo);
}
@WebService(serviceName = "CommonService", // webService的服务名称,与前面接口一致
		targetNamespace = "http://www.service.mf.com", // 与前面接口一致
		endpointInterface = "com.mf.service.CommonService") // 当前需要实现接口的完全限定名,指定做SEI服务端点接口
@Service
@Transactional
public class CommonServiceImpl implements CommonService {

	@Resource
	private InBillsRepository billsRepository;

	@Override
	public Map<String, Object> addBills(InBills bills) {
		Map<String, Object> map = new HashMap<String, Object>();
		InBills b = billsRepository.findByBillNo(bills.getBillNo());
		if (b != null) {
			Integer rows = billsRepository.updateInBills(bills);
			if (rows != 1) {
				map.put("success", false);
				map.put("errorInfo", "相同单据数据更新失败");
				return map;
			} else {
				map.put("success", true);
				return map;
			}
		} else {
			try {
				billsRepository.save(bills);
				map.put("success", true);
				return map;
			} catch (Exception e) {
				map.put("success", false);
				map.put("errorInfo", "添加失败");
				return map;
			}
		}

	}

	@Override
	public Map<String, Object> deleteBills(String billNo) {
		Map<String, Object> map = new HashMap<String, Object>();
		Integer rows = billsRepository.deleteByBillNo(billNo);
		if (rows != 1) {
			map.put("success", false);
			map.put("errorInfo", "删除失败");
			return map;
		} else {
			map.put("success", true);
			return map;
		}
	}
}

定义配置类

@Configuration
public class CxfWebServiceConfig {
	
	@Autowired
	private Bus bus;

	@Autowired
	CommonService service;
	
	/**
	 * 配置ServletRegistrationBean时,需要注意设置方法的名称或者bean的名称时,
	 * 不要和默认的DispatcherServlet类重名了,会导致原先的mvc接口无法使用,因为被覆盖了
	 * 修改访问的路径可以通过设置ServletRegistrationBean来修改,但同时,要注意需要设置bean的名称为cxfServletRegistration,
	 * 不然会造成注册多个CXFServlet的。具体原因可查看自动配置类:org.apache.cxf.spring.boot.autoconfigure.CxfAutoConfiguration。
	 * @return
	 */
//    @Bean("cxfServletRegistration")
//    public ServletRegistrationBean dispatcherServlet() {
//        //注册servlet 拦截/ws 开头的请求 不设置 默认为:/services/*
//        return new ServletRegistrationBean(new CXFServlet(), "/ws/*");
//    }
    
	
    /**
     * 申明业务处理类 当然也可以直接 在实现类上标注 @Service
     * @return
     */
//    @Bean
//    public CommonService authorService() {
//        return new CommonServiceImpl();
//    }

	/*
	 * 绑定接口类,描述接口实现方法,以及接口名称.如果有多个接口需要实现,可以添加多个该方法(设置方法名不同,发布路径不同即可)
     * 发布endpoint
     * 默认服务在Host:port/services/*路径下 
     * 修改路径为/services/CommonService
     * wsdl文档路径为,http://localhost:8380/services/CommonService?wsdl
     */
	@Bean
	public Endpoint endpoint() {
		EndpointImpl endpoint = new EndpointImpl(bus, service);
		endpoint.getInInterceptors().add(new AuthInterceptor());//添加校验拦截器
		endpoint.publish("/CommonService");//接口发布在 /CommonService 目录下
		return endpoint;
	}

}

添加用户名密码校验

package com.mf.config;

import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.phase.AbstractPhaseInterceptor;

import java.util.List;

import org.apache.cxf.headers.Header;
import org.apache.cxf.phase.Phase;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

public class AuthInterceptor extends AbstractPhaseInterceptor<SoapMessage> {

	// 由于AbstractPhaseInterceptor无无参数构造器,使用继承的方式,需要显示调用父类有参数的构造器
	public AuthInterceptor() {
		super(Phase.PRE_INVOKE);// 该拦截器将会调用之前拦截SOAP消息
	}

	// 实现自己的拦截器时,需要实现handleMessage方法。
	// handleMessage方法中的形参就是被拦截到的Soap消息
	// 一旦程序获取了SOAP消息,剩下的事情就可以解析SOAP消息或修改SOAP消息
	@Override
	public void handleMessage(SoapMessage msg) throws Fault {

		// 从这里可以看出,我们已经拦截到了SOAP消息
		System.out.println("-------" + msg);
		// 得到SOAP消息所有Header
		List<Header> headers = msg.getHeaders();
		// 如果没有Header
		if (headers == null || headers.size() < 1) {
			throw new Fault(new IllegalArgumentException("请输入用户名密码,不能调用"));
		}
		// 假如要求第一个Header携带了用户名,密码信息
		Header firstHeader = headers.get(0);
		Element ele = (Element) firstHeader.getObject();

		NodeList userName = ele.getElementsByTagName("userName");
		NodeList password = ele.getElementsByTagName("password");

		if (userName.getLength() != 1) {
			throw new Fault(new IllegalArgumentException("用户名的格式不正确!"));
		}
		if (password.getLength() != 1) {
			throw new Fault(new IllegalArgumentException("密码的格式不正确!"));
		}
		// 得到第一个userId元素里的文本内容,以该内容作为用户名字
		String user = userName.item(0).getTextContent();
		String pwd = password.item(0).getTextContent();
		// 实际项目中,应该去查询数据库,该用户名密码是否被授权调用web service
		if (!user.equals("root") || !pwd.equals("root")) {
			throw new Fault(new IllegalArgumentException("用户名密码不正确!"));
		}
	}
}
生成客户端
  1. 创建新项目(该项目也需要导入cxf的依赖)

  2. file–>new–>other–>Web Service Client

    测试

    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class TestCase {
    	public static void main(String[] args) {
    		CommonService_Service service = new CommonService_Service();
    		// 此处返回的只是远程Web Service的代理
    		CommonService comm = service.getCommonServiceImplPort();
    
    		Client client = ClientProxy.getClient(comm);
    		// 参数为输入的用户名,密码
    		client.getOutInterceptors().add(new LoginInterceptor("root","root"));
    		//数据准备
    		InBills bills = new InBills();
    		bills.setBillNo("11");
    		bills.setCtnNo("e21313,412fsf,5436g,greg");
    		bills.setInstockTime("20200816");
    		bills.setOriginalWarehouse("r2ds123");
    		bills.setSingle("14dcf");
    		bills.setTargetWarehouse("421eder");
    		bills.setType("11");
    		//添加
    		System.err.println("添加:"+comm.addBills(bills).getEntry().get(0).getValue());
    		//System.err.println(comm.deleteBills("20").getEntry().get(0).getValue());
    		System.out.println("-------------------------------");
    
    	}
    }
    

    服务端有用户名密码校验还需配置

    package com.mf.config;
    
    import java.util.List;
    
    import javax.xml.namespace.QName;
     
    import org.apache.cxf.binding.soap.SoapMessage;
    import org.apache.cxf.headers.Header;
    import org.apache.cxf.helpers.DOMUtils;
    import org.apache.cxf.interceptor.Fault;
    import org.apache.cxf.phase.AbstractPhaseInterceptor;
    import org.apache.cxf.phase.Phase;
    import org.w3c.dom.Document;
    import org.w3c.dom.Element;
    
    public class LoginInterceptor  extends AbstractPhaseInterceptor<SoapMessage>{
    
    	private String userName;
    	private String password;
    	public LoginInterceptor(String userName,String password) {
    		super(Phase.PREPARE_SEND);//在准备发送SOAP消息时启用该拦截器
    		this.userName=userName;
    		this.password=password;
    	}
    
    	@Override
    	public void handleMessage(SoapMessage msg) throws Fault {
    		List<Header> headers=msg.getHeaders();
    		//创建Document对象
    		Document doc=DOMUtils.createDocument();
    		Element ele=doc.createElement("authHeader");
    		
    		//此处创建的元素应该按照服务器那边的要求
    		Element idEle=doc.createElement("userName");
    		idEle.setTextContent(userName);
    		Element passEle=doc.createElement("password");
    		passEle.setTextContent(password);
    		
    		ele.appendChild(idEle);
    		ele.appendChild(passEle);
    		
    		/**
    		 * 上面代码生成了一个如下XML文档片段
    		 * <authHeader>
    		 * 		<userId>root</userId>
    		 * 		<userPass>root</userPass>
    		 * </authHeader>
    		 */
    		//把ele元素包装成Header,并添加到SOAP消息的Header列表中
    		headers.add(new Header(new QName("root"),ele));
    	}
    }
    

    Good Luck

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值