版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u014252478/article/details/88805419
在做这个欧洲项目的webService已经过了好几个月了,现在还是得及时总结一下。(不觉得技术很老吗,哈哈哈)
原生webService和CXF框架发布服务,其实没有太大的区别,尽管前者没有后者功能那么强大,但在实际使用中,前者在中间件使用中显得更加轻量级,后者则更加重。但是前者也不是万能的,在实际项目开发中已有证明,问题就在于发送请求的格式设置,最后实在无法,笔者使用了http字节流方式,虽然发布服务没有那么便捷,但达到了满足客户需求的目的。
下面介绍原生webService发布服务:
1、发布流程
2、基本功能使用
3、坑点
1、发布流程:
.config文件
import com.chargedot.webdemo.handler.InAccessHandler;
import com.chargedot.webdemo.handler.OutAccessHandler;
import com.chargedot.webdemo.service.UserServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.xml.ws.Binding;
import javax.xml.ws.Endpoint;
import javax.xml.ws.handler.Handler;
import java.util.ArrayList;
import java.util.List;
/**
* @author yanghao
* @Description:
* @date 2019/1/31 10:39
*/
@Configuration
public class SoapConfig {
@Autowired
private InAccessHandler inAccessHandler;
@Autowired
private OutAccessHandler outAccessHandler;
@Bean
public Endpoint endpoint(){
Endpoint endpoint = Endpoint.publish(MessageConstant.ADDRESS, new UserServiceImpl());
List<Handler> handlersList = new ArrayList<Handler>();
handlersList.add(inAccessHandler);
handlersList.add(outAccessHandler);
Binding binding = endpoint.getBinding();
binding.setHandlerChain(handlersList);
System.out.println("endpoint success");
return endpoint;
}
}
由代码知道,加入输入拦截器和输出拦截器
Service.java接口
/**
* @author yanghao
* @Description:
* @date 2019/1/29 14:29
*/
@WebService(name = "UserService",
targetNamespace = "urn://Ocpp/Cs/2015/10/"
)
@SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)
//@Addressing(enabled = true)
public interface UserService {
@WebMethod(operationName = "Authorize", action = "/Authorize")
@Action(input = "/Authorize", output = "/AuthorizeResponse")
@WebResult(name = "authorizeResponse", /*targetNamespace = "urn://Ocpp/Cs/2015/10/",*/ partName = "parameters")
AuthorizeResponse authorize(
@WebParam(partName = "chargeBoxIdentity", name = "chargeBoxIdentity", header = true, targetNamespace = "urn://Ocpp/Cs/2015/10/")
String chargeBoxIdentity,
@WebParam(partName = "parameters", name = "authorizeRequest", targetNamespace = "urn://Ocpp/Cs/2015/10/")
AuthorizeRequest parameters,
@WebParam(partName = "Action", name = "Action", header = true, targetNamespace = "urn://Ocpp/Cs/2015/10/")
String action,
@WebParam(partName = "MessageID", name = "MessageID", header = true, targetNamespace = "urn://Ocpp/Cs/2015/10/")
String messageID,
@WebParam(partName = "From", name = "From", header = true, targetNamespace = "urn://Ocpp/Cs/2015/10/")
String from,
@WebParam(partName = "ReplyTo", name = "ReplyTo", header = true, targetNamespace = "urn://Ocpp/Cs/2015/10/")
String replyTo,
@WebParam(partName = "To", name = "To", header = true, targetNamespace = "urn://Ocpp/Cs/2015/10/")
String to
);
ServiceImpl.java
/**
* @author yanghao
* @Description:
* @date 2019/1/29 14:29
*/
@WebService(serviceName = "UserService",
targetNamespace = "urn://Ocpp/Cs/2015/10/",
endpointInterface = "com.chargedot.webdemo.service.UserService"
)
@BindingType(SOAPBinding.SOAP12HTTP_BINDING)
@Slf4j
@Component
public class UserServiceImpl implements UserService {
@Autowired
private KafkaProducer kafkaProducer;
@Autowired
private KafkaConsumer kafkaConsumer;
@Resource
private WebServiceContext webServiceContext;
public String getMessageId() {
System.out.println("getMessageId");
String messageId = null;
SOAPHeader header = null;
SOAPMessageContext msgContext = (SOAPMessageContext) webServiceContext.getMessageContext();
SOAPMessage soapMessage = msgContext.getMessage();
try {
header = soapMessage.getSOAPPart().getEnvelope().getHeader();
} catch (SOAPException e) {
log.info("soapException: {}", e);
}
if (header != null) {
Node messageNode = header.getElementsByTagName("MessageId").item(1);
if (messageNode != null) {
log.info("MessageId is not exist");
}
messageId = messageNode.getTextContent();
if (messageId == null) {
log.warn("messageId is not exist");
}
log.info("MessageId:{}", messageId);
}
return messageId;
}
@Override
public AuthorizeResponse authorize(String chargeBoxIdentity, AuthorizeRequest authorizeRequest, String action, String messageID,
String from, String replyTo, String to) {
// 1. 构造响应
AuthorizeResponse response = new AuthorizeResponse();
IdTagInfo idTagInfo = new IdTagInfo();
idTagInfo.setExpiryDate(null);
idTagInfo.setParentIdTag("");
// 2. 封装传递centralService参数
HashMap<String, Object> map = new HashMap<>();
String messageId = getMessageId();
map.put("MessageId", messageId);
map.put("OperatorType", MessageConstant.AUTHORIZE_TYPE);
map.put("IdTag", authorizeRequest.getIdTag());
log.info("[ChargeBoxIdentity]:{} [MessageId]:{} [IdTag]:{}", chargeBoxIdentity, messageId, authorizeRequest.getIdTag());
// 3. kafka send to centralService
kafkaProducer.send(MessageConstant.OCPP16_D2S_TOPIC, chargeBoxIdentity, JacksonUtil.map2Json(map));
// 4. 根据centralService回复,应答chargePoint
if (Objects.nonNull(kafkaConsumer.hashMap.get(messageId))) {
AuthorizationStatus status = (AuthorizationStatus) kafkaConsumer.hashMap.get(messageId);
log.info("状态status: {}", status);
idTagInfo.setStatus(status);
}
response.setIdTagInfo(idTagInfo);
return response;
}
}
2、功能使用:
(1)输入拦截器
/**
* @author yanghao
* @Description: 服务端过滤处理
* @date 2019/1/30 17:45
*/
@Slf4j
@Component
public class InAccessHandler implements SOAPHandler<SOAPMessageContext> {
@Override
public boolean handleMessage(SOAPMessageContext context) {
log.info("InAccessHandler.");
Boolean out = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
// false 表示进的方向,即接收客户端请求(解析)
if (!out) {
SOAPMessage message = context.getMessage();
try {
SOAPHeader header = message.getSOAPPart().getEnvelope().getHeader();
if (header != null) {
Node chargeBoxIdentityNode = header.getElementsByTagName("ChargeBoxIdentity").item(0);
if (chargeBoxIdentityNode == null) {
log.info("chargeBoxIdentity invalid");
return false;
}
String chargeBoxIdentity = chargeBoxIdentityNode.getTextContent();
Node messageNode = header.getElementsByTagName("MessageId").item(1);
if (messageNode == null) {
log.info("MessageId invalid");
return false;
}
String messageId = messageNode.getTextContent();
Node fromNode = header.getElementsByTagName("From").item(2);
if (fromNode == null) {
log.info("fromNode invalid");
return false;
}
String fromUrl = fromNode.getTextContent();
Node toNode = header.getElementsByTagName("To").item(3);
if (toNode == null) {
log.info("toNode invalid");
return false;
}
String toUrl = fromNode.getTextContent();
log.info("ChargeBoxIdentity:{} MessageId:{}", chargeBoxIdentity, messageId);
new SOAPInfo(chargeBoxIdentity, fromUrl, toUrl, MessageConstant.NAMESPACE_CENTRALSYSTEM);
} else {
log.info("SoapMessage header invalid");
return false;
}
message.writeTo(System.out);
} catch (SOAPException e) {
log.info("SOAPException: {}", e);
} catch (IOException e) {
log.info("IOException: {}", e);
}
}
return true;
}
@Override
public boolean handleFault(SOAPMessageContext context) {
SOAPFault fault = null;
try {
SOAPEnvelope envelope = context.getMessage().getSOAPPart().getEnvelope();
fault = (SOAPFault) envelope.getBody().getFault();
} catch (SOAPException e) {
e.printStackTrace();
return false;
}
log.info("run handleFault method!");
return false;
}
@Override
public void close(MessageContext context) {
}
@Override
public Set<QName> getHeaders() {
return null;
}
}
(2)输出拦截器
/**
* @author yanghao
* @Description:
* @date 2019/1/30 18:20
*/
@Slf4j
@Component
public class OutAccessHandler implements SOAPHandler<SOAPMessageContext> {
@Autowired
private WebServiceWrapper webServiceWrapper;
@Autowired
private KafkaConsumer kafkaConsumer;
@Override
public boolean handleMessage(SOAPMessageContext context) {
Boolean out = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
// true 表示出的方向,即发送请求到服务端
if (out) {
SOAPEnvelope envelope = null;
try {
SOAPMessage message = context.getMessage();
envelope = message.getSOAPPart().getEnvelope();
SOAPHeader header = envelope.getHeader();
if (header != null) {
Node node = header.getElementsByTagName("MessageId").item(0);
String messageId = node.getTextContent();
if (messageId == null) {
log.info("OutAccessHandler messageId invalid");
return false;
}
String operatorType = (String) kafkaConsumer.hashMap.get("OperatorType" + messageId);
if (operatorType == null) {
log.info("operatorType invaild");
return false;
}
webServiceWrapper.wrapper(operatorType, messageId, message);
}
message.writeTo(System.out);
} catch (SOAPException e) {
log.info("SOAPException: {}", e);
} catch (IOException e) {
log.info("IOException: {}", e);
}
}
return false;
}
@Override
public Set<QName> getHeaders() {
return null;
}
@Override
public boolean handleFault(SOAPMessageContext context) {
return false;
}
@Override
public void close(MessageContext context) {
}
}
3、坑点:
有2服务实现代码知道,那里我本想是获取messageId的,而这个messageId是通过webServiceContext获取的,看起来没有错误,实际上在测试时候,根本注入不进来,哪怕是获取bean的方式也无法注入进来,当然后来解决了就是在springboot+cxf下可以注入。
4、总结
可以看到在2 Service.java接口上可以看到我在配置soap协议的请求格式,是不是很笨重?确实!而且这只是一个接口,如果来个十来个不得疯掉啊,所以原生的webService也是无法完美解决分装soap协议格式的,因此最后使用http字节流的方式完美解决了,这个等以后在介绍,就到这吧,先下班了。