运行 开发或生产模式下的 JAX-WS Web 服务
Running a JAX-WS web service in development or production mode
我有一个使用 wsimport
生成的 Web 服务(在 ANT 任务中),我想为其处理发送无效 XML 时出现的 javax.xml.bind.UnmarshalException
异常请求。
为了抛出这个异常,我只是向服务器发送了一个不平衡的标签,然后我返回:
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<S:Fault xmlns:ns4="http://www.w3.org/2003/05/soap-envelope">
<faultcode>S:Server</faultcode>
<faultstring>javax.xml.bind.UnmarshalException
- with linked exception:
[com.ctc.wstx.exc.WstxParsingException: Unexpected close tag </m:BAR>; expected </m:BR>.
at [row,col {unknown-source}]: [16,38]]</faultstring>
</S:Fault>
</S:Body>
</S:Envelope>
不幸的是,在我的代码中我看不到捕获此异常并发回标准消息的方法,而不是自动发送客户端可能无法解析的一些 web 服务内部异常。
有没有办法告诉 JAX-Ws 在 生产 或 开发 模式下 运行?在 production 模式下,它允许我覆盖为回复错误请求而发送的消息吗?
或者至少实现某种挂钩,当 JAX-WS 代码中发生异常时调用我的方法...
我运行在 Glassfish 4.1.2 上安装服务。
我用于从 wsdl
构建网络服务的 ANT 脚本如下所示:
<!DOCTYPE project>
<project name="WSDL to Java generator" default="wsimport">
<path id="wsimport.classpath">
<fileset dir="../../EAR/EarContent/lib">
<include name="commons-beanutils-*.jar"/>
<include name="commons-lang-*.jar"/>
<include name="commons-logging-*.jar"/>
</fileset>
<fileset dir="../../Common/ant-libs">
<include name="*.jar"/>
</fileset>
</path>
<taskdef name="wsimport" classname="com.sun.tools.ws.ant.WsImport" classpathref="wsimport.classpath"/>
<target name="wsimport">
<wsimport verbose="true" wsdl="../schemas/WebService.wsdl" wsdlLocation="../schemas/WebService.wsdl" binding="./ws-build-bindings.xjb">
<xjcarg line="-Xannotate"/>
<xjcarg line="-Xinheritance"/>
<arg line="-keep"/>
<arg line="-d ../src"/>
<arg line="-p org.company.name.message"/>
<arg line="-Xnocompile"/>
</wsimport>
</target>
</project>
生成的界面如下所示:
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.ws.Holder;
/**
* This class was generated by the JAX-WS RI.
* JAX-WS RI 2.3.0
* Generated source version: 2.2
*
*/
@WebService(name = "WebService", targetNamespace = "http://company.com/foo/WebService/")
@SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)
@XmlSeeAlso({
ObjectFactory.class
})
public interface WebService {
@WebMethod(operationName = "PublishEvent", action = "PublishEvent")
@WebResult(name = "ResponseMessage", targetNamespace = "http://foo.bar/schema/message", partName = "response")
public ResponseMessageType publishEvent(
@WebParam(name = "EventMessage", targetNamespace = "http://foo.bar/schema/message", partName = "event")
EventMessageType event);
@WebMethod(operationName = "Request", action = "Request")
@WebResult(name = "ResponseMessage", targetNamespace = "http://foo.bar/schema/message", partName = "response")
public ResponseMessageType request(
@WebParam(name = "RequestMessage", targetNamespace = "http://foo.bar/schema/message", partName = "request")
RequestMessageType request);
@WebMethod(operationName = "Response", action = "Response")
public void response(
@WebParam(name = "ResponseMessage", targetNamespace = "http://foo.bar/schema/message", mode = WebParam.Mode.INOUT, partName = "response")
Holder<ResponseMessageType> response);
}
生成的class扩展Service
:
import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
import javax.xml.ws.WebEndpoint;
import javax.xml.ws.WebServiceClient;
import javax.xml.ws.WebServiceException;
import javax.xml.ws.WebServiceFeature;
/**
* This class was generated by the JAX-WS RI.
* JAX-WS RI 2.3.0
* Generated source version: 2.2
*
*/
@WebServiceClient(name = "WebService", targetNamespace = "http://company.com/foo/WebService/", wsdlLocation = "../schemas/WebService.wsdl")
public class WebService_Service
extends Service
{
private final static URL WebSERVICE_WSDL_LOCATION;
private final static WebServiceException WebSERVICE_EXCEPTION;
private final static QName WebSERVICE_QNAME = new QName("http://company.com/foo/WebService/", "WebService");
static {
WebSERVICE_WSDL_LOCATION = org.company.name.message.WebService_Service.class.getResource("../schemas/WebService.wsdl");
WebServiceException e = null;
if (WebSERVICE_WSDL_LOCATION == null) {
e = new WebServiceException("Cannot find '../schemas/WebService.wsdl' wsdl. Place the resource correctly in the classpath.");
}
WebSERVICE_EXCEPTION = e;
}
public WebService_Service() {
super(__getWsdlLocation(), WebSERVICE_QNAME);
}
public WebService_Service(WebServiceFeature... features) {
super(__getWsdlLocation(), WebSERVICE_QNAME, features);
}
public WebService_Service(URL wsdlLocation) {
super(wsdlLocation, WebSERVICE_QNAME);
}
public WebService_Service(URL wsdlLocation, WebServiceFeature... features) {
super(wsdlLocation, WebSERVICE_QNAME, features);
}
public WebService_Service(URL wsdlLocation, QName serviceName) {
super(wsdlLocation, serviceName);
}
public WebService_Service(URL wsdlLocation, QName serviceName, WebServiceFeature... features) {
super(wsdlLocation, serviceName, features);
}
@WebEndpoint(name = "WebServiceSOAP")
public WebService getWebServiceSOAP() {
return super.getPort(new QName("http://company.com/foo/WebService/", "WebServiceSOAP"), WebService.class);
}
@WebEndpoint(name = "WebServiceSOAP")
public WebService getWebServiceSOAP(WebServiceFeature... features) {
return super.getPort(new QName("http://company.com/foo/WebService/", "WebServiceSOAP"), WebService.class, features);
}
private static URL __getWsdlLocation() {
if (WebSERVICE_EXCEPTION!= null) {
throw WebSERVICE_EXCEPTION;
}
return WebSERVICE_WSDL_LOCATION;
}
}
这是我对接口的实现(省略了实际工作的代码),当发出无效请求时,我无法捕获它,因为我的以下方法未被调用:
import javax.jws.WebService;
import javax.xml.ws.Holder;
import org.company.name.message.ErrorType.ErrorLevelEnum;
import org.company.name.message.EventMessageType;
import org.company.name.message.HeaderType;
import org.company.name.message.WebService;
import org.company.name.message.RequestMessageType;
import org.company.name.message.ResponseMessageType;
@WebService(endpointInterface = "org.company.name.message.WebService")
public class Web implements WebService {
@Override
public ResponseMessageType publishEvent(EventMessageType event) {
ResponseMessageBuilder responseBuilder = new ResponseMessageBuilder();
try
{
// build response here
}
catch (WebException exception) {
// error building response
}
catch (Exception ex) {
// general error
}
return responseBuilder.build();
}
@Override
public ResponseMessageType request(RequestMessageType request) {
ResponseMessageBuilder responseBuilder = new ResponseMessageBuilder();
try
{
// build response here
}
catch (WebException exception) {
// error building response
}
catch (Exception ex) {
// general error
}
return responseBuilder.build();
}
@Override
public void response(Holder<ResponseMessageType> response) {
// TODO Auto-generated method stub
}
}
使用 SOAPHandler
(https://docs.oracle.com/middleware/1213/wls/WSGET/jax-ws-soaphandlers.htm#WSGET3446) 解决了这个问题。
处理程序拦截请求,尝试 unmarshal
它(通过 JAXB),如果抛出异常,我自定义响应消息(即通过在handleMessage
您的 SOAPHandler
方法)并将其发回(通过从 handleMessage
方法返回 false
。
此外,值得研究一下 SOAPFaultException
class (https://docs.oracle.com/javase/7/docs/api/javax/xml/ws/soap/SOAPFaultException.html),您可以抛出它并根据您的喜好自定义 soap 故障响应消息。
我有一个使用 wsimport
生成的 Web 服务(在 ANT 任务中),我想为其处理发送无效 XML 时出现的 javax.xml.bind.UnmarshalException
异常请求。
为了抛出这个异常,我只是向服务器发送了一个不平衡的标签,然后我返回:
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<S:Fault xmlns:ns4="http://www.w3.org/2003/05/soap-envelope">
<faultcode>S:Server</faultcode>
<faultstring>javax.xml.bind.UnmarshalException
- with linked exception:
[com.ctc.wstx.exc.WstxParsingException: Unexpected close tag </m:BAR>; expected </m:BR>.
at [row,col {unknown-source}]: [16,38]]</faultstring>
</S:Fault>
</S:Body>
</S:Envelope>
不幸的是,在我的代码中我看不到捕获此异常并发回标准消息的方法,而不是自动发送客户端可能无法解析的一些 web 服务内部异常。
有没有办法告诉 JAX-Ws 在 生产 或 开发 模式下 运行?在 production 模式下,它允许我覆盖为回复错误请求而发送的消息吗?
或者至少实现某种挂钩,当 JAX-WS 代码中发生异常时调用我的方法...
我运行在 Glassfish 4.1.2 上安装服务。
我用于从 wsdl
构建网络服务的 ANT 脚本如下所示:
<!DOCTYPE project>
<project name="WSDL to Java generator" default="wsimport">
<path id="wsimport.classpath">
<fileset dir="../../EAR/EarContent/lib">
<include name="commons-beanutils-*.jar"/>
<include name="commons-lang-*.jar"/>
<include name="commons-logging-*.jar"/>
</fileset>
<fileset dir="../../Common/ant-libs">
<include name="*.jar"/>
</fileset>
</path>
<taskdef name="wsimport" classname="com.sun.tools.ws.ant.WsImport" classpathref="wsimport.classpath"/>
<target name="wsimport">
<wsimport verbose="true" wsdl="../schemas/WebService.wsdl" wsdlLocation="../schemas/WebService.wsdl" binding="./ws-build-bindings.xjb">
<xjcarg line="-Xannotate"/>
<xjcarg line="-Xinheritance"/>
<arg line="-keep"/>
<arg line="-d ../src"/>
<arg line="-p org.company.name.message"/>
<arg line="-Xnocompile"/>
</wsimport>
</target>
</project>
生成的界面如下所示:
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.ws.Holder;
/**
* This class was generated by the JAX-WS RI.
* JAX-WS RI 2.3.0
* Generated source version: 2.2
*
*/
@WebService(name = "WebService", targetNamespace = "http://company.com/foo/WebService/")
@SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)
@XmlSeeAlso({
ObjectFactory.class
})
public interface WebService {
@WebMethod(operationName = "PublishEvent", action = "PublishEvent")
@WebResult(name = "ResponseMessage", targetNamespace = "http://foo.bar/schema/message", partName = "response")
public ResponseMessageType publishEvent(
@WebParam(name = "EventMessage", targetNamespace = "http://foo.bar/schema/message", partName = "event")
EventMessageType event);
@WebMethod(operationName = "Request", action = "Request")
@WebResult(name = "ResponseMessage", targetNamespace = "http://foo.bar/schema/message", partName = "response")
public ResponseMessageType request(
@WebParam(name = "RequestMessage", targetNamespace = "http://foo.bar/schema/message", partName = "request")
RequestMessageType request);
@WebMethod(operationName = "Response", action = "Response")
public void response(
@WebParam(name = "ResponseMessage", targetNamespace = "http://foo.bar/schema/message", mode = WebParam.Mode.INOUT, partName = "response")
Holder<ResponseMessageType> response);
}
生成的class扩展Service
:
import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
import javax.xml.ws.WebEndpoint;
import javax.xml.ws.WebServiceClient;
import javax.xml.ws.WebServiceException;
import javax.xml.ws.WebServiceFeature;
/**
* This class was generated by the JAX-WS RI.
* JAX-WS RI 2.3.0
* Generated source version: 2.2
*
*/
@WebServiceClient(name = "WebService", targetNamespace = "http://company.com/foo/WebService/", wsdlLocation = "../schemas/WebService.wsdl")
public class WebService_Service
extends Service
{
private final static URL WebSERVICE_WSDL_LOCATION;
private final static WebServiceException WebSERVICE_EXCEPTION;
private final static QName WebSERVICE_QNAME = new QName("http://company.com/foo/WebService/", "WebService");
static {
WebSERVICE_WSDL_LOCATION = org.company.name.message.WebService_Service.class.getResource("../schemas/WebService.wsdl");
WebServiceException e = null;
if (WebSERVICE_WSDL_LOCATION == null) {
e = new WebServiceException("Cannot find '../schemas/WebService.wsdl' wsdl. Place the resource correctly in the classpath.");
}
WebSERVICE_EXCEPTION = e;
}
public WebService_Service() {
super(__getWsdlLocation(), WebSERVICE_QNAME);
}
public WebService_Service(WebServiceFeature... features) {
super(__getWsdlLocation(), WebSERVICE_QNAME, features);
}
public WebService_Service(URL wsdlLocation) {
super(wsdlLocation, WebSERVICE_QNAME);
}
public WebService_Service(URL wsdlLocation, WebServiceFeature... features) {
super(wsdlLocation, WebSERVICE_QNAME, features);
}
public WebService_Service(URL wsdlLocation, QName serviceName) {
super(wsdlLocation, serviceName);
}
public WebService_Service(URL wsdlLocation, QName serviceName, WebServiceFeature... features) {
super(wsdlLocation, serviceName, features);
}
@WebEndpoint(name = "WebServiceSOAP")
public WebService getWebServiceSOAP() {
return super.getPort(new QName("http://company.com/foo/WebService/", "WebServiceSOAP"), WebService.class);
}
@WebEndpoint(name = "WebServiceSOAP")
public WebService getWebServiceSOAP(WebServiceFeature... features) {
return super.getPort(new QName("http://company.com/foo/WebService/", "WebServiceSOAP"), WebService.class, features);
}
private static URL __getWsdlLocation() {
if (WebSERVICE_EXCEPTION!= null) {
throw WebSERVICE_EXCEPTION;
}
return WebSERVICE_WSDL_LOCATION;
}
}
这是我对接口的实现(省略了实际工作的代码),当发出无效请求时,我无法捕获它,因为我的以下方法未被调用:
import javax.jws.WebService;
import javax.xml.ws.Holder;
import org.company.name.message.ErrorType.ErrorLevelEnum;
import org.company.name.message.EventMessageType;
import org.company.name.message.HeaderType;
import org.company.name.message.WebService;
import org.company.name.message.RequestMessageType;
import org.company.name.message.ResponseMessageType;
@WebService(endpointInterface = "org.company.name.message.WebService")
public class Web implements WebService {
@Override
public ResponseMessageType publishEvent(EventMessageType event) {
ResponseMessageBuilder responseBuilder = new ResponseMessageBuilder();
try
{
// build response here
}
catch (WebException exception) {
// error building response
}
catch (Exception ex) {
// general error
}
return responseBuilder.build();
}
@Override
public ResponseMessageType request(RequestMessageType request) {
ResponseMessageBuilder responseBuilder = new ResponseMessageBuilder();
try
{
// build response here
}
catch (WebException exception) {
// error building response
}
catch (Exception ex) {
// general error
}
return responseBuilder.build();
}
@Override
public void response(Holder<ResponseMessageType> response) {
// TODO Auto-generated method stub
}
}
使用 SOAPHandler
(https://docs.oracle.com/middleware/1213/wls/WSGET/jax-ws-soaphandlers.htm#WSGET3446) 解决了这个问题。
处理程序拦截请求,尝试 unmarshal
它(通过 JAXB),如果抛出异常,我自定义响应消息(即通过在handleMessage
您的 SOAPHandler
方法)并将其发回(通过从 handleMessage
方法返回 false
。
此外,值得研究一下 SOAPFaultException
class (https://docs.oracle.com/javase/7/docs/api/javax/xml/ws/soap/SOAPFaultException.html),您可以抛出它并根据您的喜好自定义 soap 故障响应消息。