springboot 整合xcf 发布 webservice

Spring Boot集成webService

在pom添加依赖

<!--WerbService CXF依赖 start-->
<dependency>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-rt-frontend-jaxws</artifactId>
</dependency>
<dependency>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-rt-transports-http</artifactId>
</dependency>
<!--WerbService CXF依赖 end-->

提供webservice接口

@WebService(name = "MesService", // 暴露服务名称
        targetNamespace = "http://mes.jingchuang.com/"// 命名空间,一般是接口的包名倒序
)
public interface T100Service {
    /**
     * 1.【sendMaterialInfo】接收T100料件信息
     *
     * @param requestMaterialInfoData
     * @return Result
     */
    @WebMethod
    Result sendMaterialInfo(RequestMaterialInfoData requestMaterialInfoData);
}

实现webservice的方法

@Service
@Transactional
@WebService(
        // 对外发布的服务名,指定Web Service的服务名称:wsdl:service。缺省值为 Java 类的简单名称 + Service
        serviceName = "MesService",
        //portName:wsdl:portName的值。缺省值为WebService.name+Port
        portName = "UserServiceImpl",
        // 命名空间(默认的值为 “http://包名/” (也可为域名) ,可以通过此变量指定一个自定义的targetNamespace值)
        targetNamespace = "http://mes.jingchuang.com/",
        // 对外提供的接口
        endpointInterface = "com.jingchuang.mes.t100service.service.T100Service")
@Component
@Slf4j
public class T100ServiceImpl implements T100Service {
    /**
     * 1.【sendMaterialInfo】接收****料件信息 
     *
     * @param requestMaterialInfoData
     * @return
     */
    //region 接收料件信息
    @Override
    @Transactional
    public Result sendMaterialInfo(RequestMaterialInfoData requestMaterialInfoData) {
      return ResultGenerator.fail("请输入正确的操作码");
    }
    //endregion
}

配置并发布

@Configuration
public class WebServiceConfig {
    // 注意更改此方法名:public ServletRegistrationBean dispatcherServlet()  
    // 把默认映射覆盖掉了,把这个名字改掉,控制类方法就能访问了,可以正常其他请求url,webservice服务也正常。
    @Bean
    public ServletRegistrationBean disServlet(){
        return new ServletRegistrationBean(new CXFServlet(),"/service/*");//发布服务名称
    }

    @Bean(name = Bus.DEFAULT_BUS_ID)
    public SpringBus springBus()
    {
        return  new SpringBus();
    }

    @Autowired
    public T100Service t100Service;

    @Bean
    public Endpoint endpoint() {
        EndpointImpl endpoint=new EndpointImpl(springBus(), t100Service);//绑定要发布的服务
        endpoint.publish("/zhlxmes"); //显示要发布的名称
        endpoint.getInInterceptors().add(new AuthInterceptor()); //增加用户名密码验证
        return endpoint;
    }
}

增加用户名,密码验证配置

public class AuthInterceptor extends AbstractPhaseInterceptor<SoapMessage> {
    private static final Logger logger = LoggerFactory.getLogger(AuthInterceptor.class);
    private SAAJInInterceptor saa = new SAAJInInterceptor();

    private static final String USER_NAME = "t100";
    private static final String USER_PASSWORD = "t100";

    public AuthInterceptor() {
        super(Phase.PRE_PROTOCOL);
        getAfter().add(SAAJInInterceptor.class.getName());
    }

    @Override
    public void handleMessage(SoapMessage message) throws Fault {
        SOAPMessage mess = message.getContent(SOAPMessage.class);
        if (mess == null) {
            saa.handleMessage(message);
            mess = message.getContent(SOAPMessage.class);
        }
        SOAPHeader head = null;
        try {
            head = mess.getSOAPHeader();
        } catch (Exception e) {
            logger.error("getSOAPHeader error: {}", e.getMessage(), e);
        }
        if (head == null) {
            throw new Fault(new IllegalArgumentException("找不到Header,无法验证用户信息"));
        }

        NodeList users = head.getElementsByTagName("username");
        NodeList passwords = head.getElementsByTagName("password");
        if (users.getLength() < 1) {
            throw new Fault(new IllegalArgumentException("找不到用户信息"));
        }
        if (passwords.getLength() < 1) {
            throw new Fault(new IllegalArgumentException("找不到密码信息"));
        }

        String userName = users.item(0).getTextContent().trim();
        String password = passwords.item(0).getTextContent().trim();
        if (USER_NAME.equals(userName) && USER_PASSWORD.equals(password)) {
            logger.debug("admin auth success");
        } else {
            SOAPException soapExc = new SOAPException("认证错误");
            logger.debug("admin auth failed");
            throw new Fault(soapExc);
        }
    }
}

客户端

客户端可以通过两种方式调用服务端。

1 .通过JaxWsDynamicClientFactory方式

public static Object doPostSoap(Class<?> clazz, String postUrl, String methodName, String xml) {
        try {
            Object[] objects;
            if (postUrl.equals("dev")) {
                objects = new Object[]{TestConten};
            } else {
                log.info("【T00/doPostSoap发送】:\n" + xml);
                // 创建动态客户端
                JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();
                Client client = dcf.createClient(postUrl);

                // 设置超时单位为毫秒
                HTTPConduit conduit = (HTTPConduit) client.getConduit();
                HTTPClientPolicy policy = new HTTPClientPolicy();
                policy.setConnectionTimeout(15000);
                policy.setAllowChunking(false);
                policy.setReceiveTimeout(30000);
                conduit.setClient(policy);
                // invoke("方法名",参数1,参数2,参数3....);
                objects = client.invoke(methodName, xml);
                log.info("【T00/doPostSoap接收】:\n" + objects[0].toString());
                // 需要密码的情况需要加上用户名和密码
//                 client.getOutInterceptors().add(new ClientLoginInterceptor(USER_NAME,PASS_WORD));
            }
            Log loginfo = new Log();
            loginfo.setType("info");
            loginfo.setName("【请求T100接口】-doPostSoap");
            loginfo.setContent(xml);
            loginfo.setMethodName(methodName);
            loginfo.setCreateTime(new Date());
            loginfo.setCreateUserId(BaseContextHandler.getUserID());
            loginfo.setCreateUserName(BaseContextHandler.getUsername());
            loginfo.setResult(objects[0].toString());
            try {
                logService.save(loginfo);
            } catch (Exception ex) {
                log.info("保存日志错误" + ex.getMessage());
            }
            if (objects.length <= 0) {
                return null;
            }
            ReceivingData receivingData = (ReceivingData) XsteamUtil.toBean(ReceivingData.class, objects[0].toString());
//            receivingData = (ReceivingData)XsteamUtil.toBean(ReceivingData.class,TestConten);

            Object rulest = XsteamUtil.toBean(clazz, receivingData.getPayload().getParam().getData());
            return rulest;
        } catch (Exception e) {
            System.out.println("错误信息:" + e.getMessage());
            return null;
        }
    }

这种方式要注意的就是,如果调用的服务接口返回的是一个自定义对象,那么结果Object[]中的数据类型就成了这个自定义对象(组件帮你自动生成了这个对象),

但是你本地可能并没有这个类,所以需要自行转换处理,最简单的是新建一个跟返回结果一模一样的类进行强转。

客户端需要在header中添加用户信息,这样才能通过服务器的验证。

public class ClientLoginInterceptor  extends AbstractPhaseInterceptor<SoapMessage> {
 
    private String username;
    private String password;
 
    public ClientLoginInterceptor(String username, String password) {
        super(Phase.PREPARE_SEND);
        this.username = username;
        this.password = password;
    }
 
    @Override
    public void handleMessage(SoapMessage soap) throws Fault {
        List<Header> headers = soap.getHeaders();
        Document doc = DOMUtils.createDocument();
        Element auth = doc.createElement("authrity");
        Element username = doc.createElement("username");
        Element password = doc.createElement("password");
        username.setTextContent(this.username);
        password.setTextContent(this.password);
        auth.appendChild(username);
        auth.appendChild(password);
        headers.add(0, new Header(new QName("tiamaes"),auth));
    }
}

2、通过wsimport生成客户端代码
通过jdk自带的wsimport生成客户端代码。进入$JAVA_HOME/bin下,新建bin和src两个文件夹,执行以下命令:
wsimport -d ./bin -s ./src -keep http://localhost:8080/services/layout?wsdl
其中几个参数有以下几个,
-d:生成客户端执行类的class文件存放目录,
-s:生成客户端执行类的源文件存放目录,
-p:定义生成类的包名
  -verbose:显示生成过程
需要注意的是:无论-d或是-s后的目录必须在文件系统中存在,否则报错。

  将src下连同包一起复制到程序中,编写客户端入口类:


public class WSClient {
    private static final Logger LOG = LoggerFactory.getLogger(WSClient.class);
 
    private static final String USER_NAME = "admin";
    private static final String PASS_WORD = "pass";
 
    public static void main(String[] args) {
        
        //方式二:通过wsimport生成客户端代码
        LayoutServiceImpl impl = new LayoutServiceImpl();
        impl.setHandlerResolver(new HandlerResolver() {
            @Override
            public List<Handler> getHandlerChain(PortInfo portInfo) {
                List<Handler> handlerList = new ArrayList<Handler>();
                handlerList.add(new ClientHandler(USER_NAME, PASS_WORD));
                return handlerList;
            }
        });
        try {
            LayoutService layoutService = impl.getLayoutImpl();
            String result_1 = layoutService.sayHello("jack");
            LOG.debug("[2]sayHello:" + result_1);
            OperationResult result_2 = layoutService.addLayout("name", "content");
            LOG.debug("[2]addLayout result_succeed:" + result_2.isSucceed());
            LOG.debug("[2]addLayout result_msg:" + result_2.getMsg());
        } catch (SOAPFaultException e) {
            LOG.error("SOAPFaultException occurs:{}", e.getMessage());
        }
    }

 该方式的好处是可以像调用本地接口一样调用服务端方法,简单明了。缺点就是会生成一堆文件。

 用户的头信息设置类:

public class ClientHandler implements SOAPHandler<SOAPMessageContext> {
    private String username;
    private String password;
 
    public ClientHandler(String username, String password) {
        this.username = username;
        this.password = password;
    }
 
    public boolean handleMessage(SOAPMessageContext ctx) {
 
        //出站,即客户端发出请求前,添加表头信息
        Boolean request_p = (Boolean)ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
        if (request_p) {
            try {
                SOAPMessage msg = ctx.getMessage();
                SOAPEnvelope env = msg.getSOAPPart().getEnvelope();
                SOAPHeader hdr = env.getHeader();
                if (hdr == null) hdr = env.addHeader();
 
                //添加认证信息头
                QName name = new QName("http://service.webservice.com/", "LayoutImpl");
                SOAPHeaderElement header = hdr.addHeaderElement(name);
 
                SOAPElement userElement = header.addChildElement("username");
                userElement.addTextNode(username);
                SOAPElement passElement = header.addChildElement("password");
                passElement.addTextNode(password);
                msg.saveChanges();
 
                return true;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return false;
    }
 
    @Override
    public boolean handleFault(SOAPMessageContext context) {
        // TODO Auto-generated method stub
        return false;
    }
 
    @Override
    public void close(MessageContext context) {
        // TODO Auto-generated method stub
    }
 
    @Override
    public Set<QName> getHeaders() {
        // TODO Auto-generated method stub
        return null;
    }
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值