原文:Mkyong
JAX-WS Hello World 示例-文档样式
在本教程中,我们将向您展示如何使用 JAX-WS 来创建一个基于 SOAP 的 web 服务(文档样式)端点。与 RPC 风格相比,它需要一些额外的努力来使它工作。
本例的目录结构
JAX-WS Web 服务端点
下面是在 JAX WS 中创建文档样式 web 服务的步骤。
1.创建 Web 服务端点接口
实际上,用@SOAPBinding
标注是可选的,因为默认样式是 document。
文件:HelloWorld.java
package com.mkyong.ws;
import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.Style;
//Service Endpoint Interface
@WebService
@SOAPBinding(style = Style.DOCUMENT, use=Use.LITERAL) //optional
public interface HelloWorld{
@WebMethod String getHelloWorldAsString(String name);
}
Note
In JAX-WS development, convert from “RPC style” to “Document style” is very easy, just change the @SOAPBinding
style option. ## 2.创建 Web 服务端点实现
文件:HelloWorldImpl.java
package com.mkyong.ws;
import javax.jws.WebService;
//Service Implementation
@WebService(endpointInterface = "com.mkyong.ws.HelloWorld")
public class HelloWorldImpl implements HelloWorld{
@Override
public String getHelloWorldAsString(String name) {
return "Hello World JAX-WS " + name;
}
}
3.创建端点发布者。
文件:HelloWorldPublisher.java
package com.mkyong.endpoint;
import javax.xml.ws.Endpoint;
import com.mkyong.ws.HelloWorldImpl;
//Endpoint publisher
public class HelloWorldPublisher{
public static void main(String[] args) {
Endpoint.publish("http://localhost:9999/ws/hello", new HelloWorldImpl());
}
}
等等,当您运行端点发布器时,您会遇到以下错误消息:
Wrapper class com.mkyong.ws.jaxws.GetHelloWorldAsString is not found.
Have you run APT to generate them?
见此文。您需要使用“ wsgen 工具来生成必要的 JAX-WS 可移植工件。让我们进入下一步。
4.wsgen 命令
文档样式需要额外的类来运行,您可以使用" wsgen “来生成所有必需的 Java 工件(映射类、wsdl 或 xsd 模式)。需要” wsgen "命令来读取服务端点实现类:
wsgen -keep -cp . com.mkyong.ws.HelloWorldImpl
它将生成两个类,将其复制到您的“ package.jaxws 文件夹中。
文件:GetHelloWorldAsString.java
package com.mkyong.ws.jaxws;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
@XmlRootElement(name = "getHelloWorldAsString", namespace = "http://ws.mkyong.com/")
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "getHelloWorldAsString", namespace = "http://ws.mkyong.com/")
public class GetHelloWorldAsString {
@XmlElement(name = "arg0", namespace = "")
private String arg0;
/**
*
* @return
* returns String
*/
public String getArg0() {
return this.arg0;
}
/**
*
* @param arg0
* the value for the arg0 property
*/
public void setArg0(String arg0) {
this.arg0 = arg0;
}
}
文件:GetHelloWorldAsStringResponse.java
package com.mkyong.ws.jaxws;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
@XmlRootElement(name = "getHelloWorldAsStringResponse", namespace = "http://ws.mkyong.com/")
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "getHelloWorldAsStringResponse", namespace = "http://ws.mkyong.com/")
public class GetHelloWorldAsStringResponse {
@XmlElement(name = "return", namespace = "")
private String _return;
/**
*
* @return
* returns String
*/
public String getReturn() {
return this._return;
}
/**
*
* @param _return
* the value for the _return property
*/
public void setReturn(String _return) {
this._return = _return;
}
}
Note
The “wsgen” tool is available in the “JDK_Path\bin\” folder. For detail, please read this JAX-WS : wsgen tool example article.
5.完成的
完成,发布并通过 URL 测试:http://localhost:9999/ws/hello?wsdl 。
Web 服务客户端
创建 web 服务客户端以访问您发布的服务。
文件:HelloWorldClient.java
package com.mkyong.client;
import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
import com.mkyong.ws.HelloWorld;
public class HelloWorldClient{
public static void main(String[] args) throws Exception {
URL url = new URL("http://localhost:9999/ws/hello?wsdl");
QName qname = new QName("http://ws.mkyong.com/", "HelloWorldImplService");
Service service = Service.create(url, qname);
HelloWorld hello = service.getPort(HelloWorld.class);
System.out.println(hello.getHelloWorldAsString("mkyong"));
}
}
输出
Hello World JAX-WS mkyong
跟踪 SOAP 流量
从上到下,展示了 SOAP 信封如何在这个文档风格的 web 服务中在客户机和服务器之间流动。
1.申请一份 WSDL 档案
首先,客户端向服务端点发送一个 wsdl 请求:
客户端发送请求:
GET /ws/hello?wsdl HTTP/1.1
User-Agent: Java/1.6.0_13
Host: localhost:9999
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Connection: keep-alive
服务器发送响应:
HTTP/1.1 200 OK
Transfer-encoding: chunked
Content-type: text/xml;charset=utf-8
<?xml version="1.0" encoding="UTF-8"?>
<!-- Published by JAX-WS RI at http://jax-ws.dev.java.net.
RI's version is JAX-WS RI 2.1.1 in JDK 6\. -->
<!-- Generated by JAX-WS RI at http://jax-ws.dev.java.net.
RI's version is JAX-WS RI 2.1.1 in JDK 6\. -->
<definitions
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://ws.mkyong.com/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://ws.mkyong.com/"
name="HelloWorldImplService">
<types>
<xsd:schema>
<xsd:import namespace="http://ws.mkyong.com/"
schemaLocation="http://localhost:9999/ws/hello?xsd=1"></xsd:import>
</xsd:schema>
</types>
<message name="getHelloWorldAsString">
<part name="parameters" element="tns:getHelloWorldAsString"></part>
</message>
<message name="getHelloWorldAsStringResponse">
<part name="parameters" element="tns:getHelloWorldAsStringResponse"></part>
</message>
<portType name="HelloWorld">
<operation name="getHelloWorldAsString">
<input message="tns:getHelloWorldAsString"></input>
<output message="tns:getHelloWorldAsStringResponse"></output>
</operation>
</portType>
<binding name="HelloWorldImplPortBinding" type="tns:HelloWorld">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document">
</soap:binding>
<operation name="getHelloWorldAsString">
<soap:operation soapAction=""></soap:operation>
<input>
<soap:body use="literal"></soap:body>
</input>
<output>
<soap:body use="literal"></soap:body>
</output>
</operation>
</binding>
<service name="HelloWorldImplService">
<port name="HelloWorldImplPort" binding="tns:HelloWorldImplPortBinding">
<soap:address location="http://localhost:9999/ws/hello"></soap:address>
</port>
</service>
</definitions>
2.getHelloWorldAsString(字符串名称)
第二次调用,客户端将方法调用请求放入 SOAP 信封,并将其发送到服务端点。在服务端点,调用请求的方法,将结果放入 SOAP 信封,并将其发送回客户端。
客户端发送请求:
POST /ws/hello HTTP/1.1
SOAPAction: ""
Accept: text/xml, multipart/related, text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Content-Type: text/xml; charset=utf-8
User-Agent: Java/1.6.0_13
Host: localhost:9999
Connection: keep-alive
Content-Length: 224
<?xml version="1.0" ?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<ns2:getHelloWorldAsString xmlns:ns2="http://ws.mkyong.com/">
<arg0>mkyong</arg0>
</ns2:getHelloWorldAsString>
</S:Body>
</S:Envelope>
服务器发送响应:
HTTP/1.1 200 OK
Transfer-encoding: chunked
Content-type: text/xml; charset=utf-8
<?xml version="1.0" ?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<ns2:getHelloWorldAsStringResponse xmlns:ns2="http://ws.mkyong.com/">
<return>Hello World JAX-WS mkyong</return>
</ns2:getHelloWorldAsStringResponse>
</S:Body>
</S:Envelope>
下载源代码
Download It – JAX-WS-HelloWorld-Document-Example.zip (10KB)hello world jax-ws web services
JAX-WS Hello World 示例 RPC 风格
JAX-WS 与 JDK 1.6 捆绑在一起,这使得 Java web 服务开发更容易开发。本教程向您展示了如何执行以下任务:
- 使用 JAX-WS 创建一个基于 SOAP 的 RPC 样式的 web 服务端点。
- 手动创建 Java web 服务客户端。
- 通过 wsimport 工具创建一个 Java web 服务客户端。
- 创建一个 Ruby web 服务客户端。
你会惊奇地发现在 JAX WS 中开发一个 RPC 样式 web 服务是多么简单。
Note
In general words, “web service endpoint” is a service which published outside for user to access; where “web service client” is the party who access the published service.
JAX-WS Web 服务端点
以下步骤显示了如何使用 JAX-WS 来创建 RPC 样式的 web 服务端点。
freestar.config.enabled_slots.push({ placementName: “mkyong_incontent_1”, slotId: “mkyong_incontent_1” });
1.创建 Web 服务端点接口
文件:HelloWorld.java
package com.mkyong.ws;
import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.Style;
//Service Endpoint Interface
@WebService
@SOAPBinding(style = Style.RPC)
public interface HelloWorld{
@WebMethod String getHelloWorldAsString(String name);
}
2.创建 Web 服务端点实现
文件:HelloWorldImpl.java
package com.mkyong.ws;
import javax.jws.WebService;
//Service Implementation
@WebService(endpointInterface = "com.mkyong.ws.HelloWorld")
public class HelloWorldImpl implements HelloWorld{
@Override
public String getHelloWorldAsString(String name) {
return "Hello World JAX-WS " + name;
}
}
3.创建端点发布者
文件:HelloWorldPublisher.java
package com.mkyong.endpoint;
import javax.xml.ws.Endpoint;
import com.mkyong.ws.HelloWorldImpl;
//Endpoint publisher
public class HelloWorldPublisher{
public static void main(String[] args) {
Endpoint.publish("http://localhost:9999/ws/hello", new HelloWorldImpl());
}
}
运行端点发布器,您的“ hello world web 服务部署在 URL“http://localhost:9999/ws/hello”中。
4.测试一下
您可以通过这个 URL "http://localhost:9999/ws/hello?wsdl ”。
Web 服务客户端
好了,web 服务已正确部署,现在让我们看看如何创建 web 服务客户端来访问已发布的服务。
1.Java Web 服务客户端
无需工具,您可以创建一个 Java web 服务客户端,如下所示:
package com.mkyong.client;
import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
import com.mkyong.ws.HelloWorld;
public class HelloWorldClient{
public static void main(String[] args) throws Exception {
URL url = new URL("http://localhost:9999/ws/hello?wsdl");
//1st argument service URI, refer to wsdl document above
//2nd argument is service name, refer to wsdl document above
QName qname = new QName("http://ws.mkyong.com/", "HelloWorldImplService");
Service service = Service.create(url, qname);
HelloWorld hello = service.getPort(HelloWorld.class);
System.out.println(hello.getHelloWorldAsString("mkyong"));
}
}
输出
Hello World JAX-WS mkyong
2.通过 wsimport 工具的 Java Web 服务客户端
或者,您可以使用" wsimport 工具来解析发布的 wsdl 文件,并生成必要的客户端文件(存根)来访问发布的 web 服务。
Where is wsimport?
This wsimport tool is bundle with the JDK, you can find it at “JDK_PATH/bin” folder.
发出“ wsimport 命令。
wsimport -keep http://localhost:9999/ws/hello?wsdl
它将生成必要的客户端文件,这取决于所提供的 wsdl 文件。在这种情况下,它将生成一个接口和一个服务实现文件。
文件:HelloWorld.java
package com.mkyong.ws;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
/**
* This class was generated by the JAX-WS RI.
* JAX-WS RI 2.1.1 in JDK 6
* Generated source version: 2.1
*
*/
@WebService(name = "HelloWorld", targetNamespace = "http://ws.mkyong.com/")
@SOAPBinding(style = SOAPBinding.Style.RPC)
public interface HelloWorld {
/**
*
* @param arg0
* @return
* returns java.lang.String
*/
@WebMethod
@WebResult(partName = "return")
public String getHelloWorldAsString(
@WebParam(name = "arg0", partName = "arg0")
String arg0);
}
文件:HelloWorldImplService.java
package com.mkyong.ws;
import java.net.MalformedURLException;
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.WebServiceFeature;
/**
* This class was generated by the JAX-WS RI.
* JAX-WS RI 2.1.1 in JDK 6
* Generated source version: 2.1
*
*/
@WebServiceClient(name = "HelloWorldImplService",
targetNamespace = "http://ws.mkyong.com/",
wsdlLocation = "http://localhost:9999/ws/hello?wsdl")
public class HelloWorldImplService
extends Service
{
private final static URL HELLOWORLDIMPLSERVICE_WSDL_LOCATION;
static {
URL url = null;
try {
url = new URL("http://localhost:9999/ws/hello?wsdl");
} catch (MalformedURLException e) {
e.printStackTrace();
}
HELLOWORLDIMPLSERVICE_WSDL_LOCATION = url;
}
public HelloWorldImplService(URL wsdlLocation, QName serviceName) {
super(wsdlLocation, serviceName);
}
public HelloWorldImplService() {
super(HELLOWORLDIMPLSERVICE_WSDL_LOCATION,
new QName("http://ws.mkyong.com/", "HelloWorldImplService"));
}
/**
*
* @return
* returns HelloWorld
*/
@WebEndpoint(name = "HelloWorldImplPort")
public HelloWorld getHelloWorldImplPort() {
return (HelloWorld)super.getPort(
new QName("http://ws.mkyong.com/", "HelloWorldImplPort"),
HelloWorld.class);
}
/**
*
* @param features
* A list of {@link javax.xml.ws.WebServiceFeature} to configure on the proxy.
* Supported features not in the <code>features</code> parameter will have their default values.
* @return
* returns HelloWorld
*/
@WebEndpoint(name = "HelloWorldImplPort")
public HelloWorld getHelloWorldImplPort(WebServiceFeature... features) {
return (HelloWorld)super.getPort(
new QName("http://ws.mkyong.com/", "HelloWorldImplPort"),
HelloWorld.class,
features);
}
}
现在,创建一个依赖于上面生成的文件的 Java web 服务客户机。
package com.mkyong.client;
import com.mkyong.ws.HelloWorld;
import com.mkyong.ws.HelloWorldImplService;
public class HelloWorldClient{
public static void main(String[] args) {
HelloWorldImplService helloService = new HelloWorldImplService();
HelloWorld hello = helloService.getHelloWorldImplPort();
System.out.println(hello.getHelloWorldAsString("mkyong"));
}
}
这是输出
Hello World JAX-WS mkyong
3.Ruby Web 服务客户端
web 服务开发经常与其他编程语言混合使用。所以,这里有一个 Ruby web 服务客户端的例子,它被用来访问已发布的 JAX-WS 服务。
# package for SOAP-based services
require 'soap/wsdlDriver'
wsdl_url = 'http://localhost:9999/ws/hello?wsdl'
service = SOAP::WSDLDriverFactory.new(wsdl_url).create_rpc_driver
# Invoke service operations.
data1 = service.getHelloWorldAsString('mkyong')
# Output results.
puts "getHelloWorldAsString : #{data1}"
输出
getHelloWorldAsString : Hello World JAX-WS mkyong
跟踪 SOAP 流量
从上到下,展示了 SOAP 信封如何在客户机和服务器之间流动。再次参见#1 web 服务客户端:
URL url = new URL("http://localhost:9999/ws/hello?wsdl");
QName qname = new QName("http://ws.mkyong.com/", "HelloWorldImplService");
Service service = Service.create(url, qname);
HelloWorld hello = service.getPort(HelloWorld.class);
System.out.println(hello.getHelloWorldAsString("mkyong"));
Note
To monitor SOAP traffic is very easy, see this guide – “How to trace SOAP message in Eclipse IDE“.
1.申请一份 WSDL 档案
首先,客户端向服务端点发送 wsdl 请求,请参见下面的 HTTP 流量:
客户端发送请求:
GET /ws/hello?wsdl HTTP/1.1
User-Agent: Java/1.6.0_13
Host: localhost:9999
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Connection: keep-alive
服务器发送响应:
HTTP/1.1 200 OK
Transfer-encoding: chunked
Content-type: text/xml;charset=utf-8
<?xml version="1.0" encoding="UTF-8"?>
<definitions
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://ws.mkyong.com/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://ws.mkyong.com/"
name="HelloWorldImplService">
<types></types>
<message name="getHelloWorldAsString">
<part name="arg0" type="xsd:string"></part>
</message>
<message name="getHelloWorldAsStringResponse">
<part name="return" type="xsd:string"></part>
</message>
<portType name="HelloWorld">
<operation name="getHelloWorldAsString" parameterOrder="arg0">
<input message="tns:getHelloWorldAsString"></input>
<output message="tns:getHelloWorldAsStringResponse"></output>
</operation>
</portType>
<binding name="HelloWorldImplPortBinding" type="tns:HelloWorld">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="rpc"></soap:binding>
<operation name="getHelloWorldAsString">
<soap:operation soapAction=""></soap:operation>
<input>
<soap:body use="literal" namespace="http://ws.mkyong.com/"></soap:body>
</input>
<output>
<soap:body use="literal" namespace="http://ws.mkyong.com/"></soap:body>
</output>
</operation>
</binding>
<service name="HelloWorldImplService">
<port name="HelloWorldImplPort" binding="tns:HelloWorldImplPortBinding">
<soap:address location="http://localhost:9999/ws/hello"></soap:address>
</port>
</service>
</definitions>
2.hello.getHelloWorldAsString()
第二次调用,客户端将方法调用请求放入 SOAP 信封,并将其发送到服务端点。在服务端点,调用请求的方法,将结果放入 SOAP 信封,并将其发送回客户端。
客户端发送请求:
POST /ws/hello HTTP/1.1
SOAPAction: ""
Accept: text/xml, multipart/related, text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Content-Type: text/xml; charset=utf-8
User-Agent: Java/1.6.0_13
Host: localhost:9999
Connection: keep-alive
Content-Length: 224
<?xml version="1.0" ?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<ns2:getHelloWorldAsString xmlns:ns2="http://ws.mkyong.com/">
<arg0>mkyong</arg0>
</ns2:getHelloWorldAsString>
</S:Body>
</S:Envelope>
服务器发送响应:
HTTP/1.1 200 OK
Transfer-encoding: chunked
Content-type: text/xml; charset=utf-8
<?xml version="1.0" ?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<ns2:getHelloWorldAsStringResponse xmlns:ns2="http://ws.mkyong.com/">
<return>Hello World JAX-WS mkyong</return>
</ns2:getHelloWorldAsStringResponse>
</S:Body>
</S:Envelope>
完成,任何意见,不胜感激。
下载源代码
Download It – JAX-WS-HelloWorld-RPC-Example.zip (14KB)Tags : hello world jax-ws web servicesfreestar.config.enabled_slots.push({ placementName: “mkyong_leaderboard_btf”, slotId: “mkyong_leaderboard_btf” });
JAX-WS 教程
原文:http://web.archive.org/web/20230101150211/https://mkyong.com/tutorials/jax-ws-tutorials/
Java API for XML Web Services(JAX-WS),是一组用于创建 XML 格式(SOAP)的 Web 服务的 API。JAX-WS 提供了许多注释来简化 web 服务客户端和 web 服务提供者(端点)的开发和部署。
在本教程中,它提供了许多关于 JAX-WS 2.0 和 JAXWS 2.1 的分步示例和解释。
快乐学习 JAX🙂
快速启动
JAX-WS 2.x 的一些快速入门示例
图:JAX-WS 通讯-图片来源
- JAX-WS hello world 示例-RPC 样式
教程向您展示如何使用 JAX-WS,以及 Java、wsimport 和 Ruby 中的 web 服务客户端来创建 RPC 样式的 web 服务端点。 - JAX-WS Hello World 示例-文档样式
教程向您展示了如何使用 JAX-WS 创建文档样式的 web 服务端点,并展示了客户端和服务器之间的 SOAP 信封流。 - 如何在 Eclipse IDE 中跟踪 SOAP 消息
教程向您展示了如何在 Eclipse IDE 中启用这个“TCP/IP Monitor ”,并且还拦截 web 服务生成的 SOAP 消息。 - JAX-WS : wsimport 工具示例
WS import 工具用于解析现有的 web 服务描述语言(WSDL)文件,并生成 web 服务客户端访问已发布的 Web 服务所需的文件(JAX-WS 可移植工件)。 - JAX-WS : wsgen 工具示例
wsgen 工具用于解析现有的 web 服务实现类,并生成 web 服务部署所需的文件(JAX-WS 可移植工件)。
JAX-WS 附件
如何在 JAX-WS 2.x 中处理附件
- 一个完整的基于 JAX-WS SOAP 的例子,展示了如何使用消息传输优化机制(MTOM)和 XML-二进制优化打包(XOP)技术在服务器和客户端之间发送二进制附件(图像)。
JAX-WS 处理器
SOAP handler 是一个 SOAP 消息拦截器,它能够拦截传入或传出的 SOAP 消息并操纵其值。
- 第 1 部分:JAX-WS–服务器端的 SOAP 处理程序
在本文中,我们将向您展示如何创建一个 SOAP 处理程序并将其附加到服务器端,以便从每个传入的 SOAP 消息中检索 SOAP 头块中的 mac 地址。并进行验证以仅允许 MAC 地址为“90-4C-E5-44-B9-8F”计算机访问此发布的服务。 - 第 2 部分:JAX-WS–客户端的 SOAP 处理程序
在本文中,您将开发一个 web 服务客户端来访问上一篇文章中发布的服务,并附加一个处理程序来将客户端的 MAC 地址注入报头块,用于客户端发送的每个传出 SOAP 消息。 - 第 3 部分:JAX-WS–客户端和服务器端的 SOAP 处理程序测试
以上两篇 SOAP 处理程序文章的测试结果。
JAX-WS 集成
如何将 JAX WS 与 Web 应用和 Spring 框架集成?
- JAX-WS + Java Web 应用集成示例
这里我们向你展示如何将 JAX-WS 与 Java Web 应用集成。 - JAX-WS + Spring 集成示例
这里我们向你展示如何将 JAX-WS 与 Spring 框架集成。 - 无法定位 XML 模式名称空间的 Spring namespace handler【http://jax-ws.dev.java.net/spring/servlet】
将 JAX-WS 与 Spring 框架集成时的常见错误消息。
Tomcat 中的 JAX-WS 安全性
如何在 Tomcat 中实现 JAX-WS 安全性?
- 在 Tomcat
上部署 JAX-WS 网络服务这里有一个指南向你展示如何在 Tomcat servlet 容器上部署 JAX-WS 网络服务。 - 在 Tomcat + SSL 连接上部署 JAX-WS web 服务
这里有一个指南向您展示如何在启用了 Tomcat + SSL 连接的情况下部署 JAX-WS web 服务。 - 用 JAX-WS 进行应用程序认证这里有一个详细的例子向你展示如何用 JAX-WS 处理应用程序级认证。
- 用 JAX-WS + (Tomcat 版本)
进行容器认证这里有一个详细的例子来展示如何在 Tomcat 下用 JAX-WS 实现容器认证。 - 让 Tomcat 支持 SSL 或 https 连接
- 如何在 Java web 服务客户端中绕过证书检查
- Java . security . cert . certificate 异常:找不到与本地主机匹配的名称
- SunCertPathBuilderException:无法找到请求目标的有效认证路径
JAX-WS 错误消息
JAX-WS 开发中的一些常见错误消息。
- WebSphere 7 上的 Metro–com . IBM . XML . xlxp 2 . JAXB . jaxbcontextimpl 不兼容异常
- Spring + jax-ws : 'xxx '是接口,JAXB 不能处理接口
- Spring + jax-ws : '#xxx ‘不是’ NCName '的有效值
- javax . XML . stream . XML stream exception:parse error at[row,col]:[x,xx]
- java.net.BindException:地址已被使用:bind
- 找不到包装类 package.jaxws.methodName。你有没有倾向于生成它们?
- Java . lang . classnotfoundexception:com . sun . XML . ws . transport . http . servlet . wsservletcontextlistener
- Java . lang . classnotfoundexception:com/sun/XML/bind/v2/model/annotation/annotation reader
- Java . lang . classnotfoundexception:com/sun/XML/stream/buffer/XML stream buffer
- Java . lang . classnotfoundexception:com/sun/XML/ws/policy/policy exception
- Java . lang . classnotfoundexception:javax . XML . ws . soap . addressing feature $ Responses
- Java . lang . classnotfoundexception:org . jvnet . staxex . XML streamreaderex
- Java . lang . classnotfoundexception:org . glassfish . gmbal . managedobjectmanager
- Java . lang . classnotfoundexception:org . glassfish . external . amx . amx glassfish
- Java . lang . classnotfoundexception:org . spring framework . beans . factory . support . reader context
- Java . lang . classnotfoundexception:org . Apache . xbean . spring . context . v2 . xbean namespace handler
参考
- http://jax-ws.java.net/
- http://download.oracle.com/javaee/5/tutorial/doc/bnayn.html
- http://Java . sun . com/developer/technical articles/web services/high _ performance/
- http://Java . sun . com/developer/technical articles/J2SE/jax _ ws _ 2/
- http://blogs.sun.com/kamna/entry/using_jax_ws_handlers_to
- http://tomcat.apache.org/tomcat-6.0-doc/realm-howto.html
- http://www . IBM . com/developer works/web services/library/ws-doc style . html
- http://www . Oracle . com/technology/sample _ code/tech/Java/J2EE/jind demo/tutorials/web services . html
- http://www.coderanch.com/how-to/java/WebServicesFaq
- http://www . Oracle . com/tech network/articles/javase/index-137171 . html
JAXB hello world 示例
原文:http://web.archive.org/web/20230101150211/https://mkyong.com/java/jaxb-hello-world-example/
Jakarta XML 绑定(JAXB;以前的 Java Architecture for XML Binding)是一个 XML 绑定框架,用于在 Java 对象和 XML 之间进行转换。
- XML 编组–将 Java 对象转换成 XML。
- XML 解组——将 XML 转换回 Java 对象。
注
本文将重点介绍 Java 11 ,JAXB 3 和 EclipseLink MOXy JAXB RI 。
目录
- 1。Java 6、7、8、Java 9、10、11 以及更高版本上的 JAXB
- 2。Java 11 和 JAXB RI 依赖关系
- 3。JAXB hello world 示例
- 4。什么是@XmlAccessorType(XmlAccessType。场)
- 5。javax.xml.和 jakarta.xml. 的区别
- 【JAXB 版本 2 的 5.1 Java EE,javax . XML . *
- 5.2 Jakarta EE,jakarta.xml.*适用于 JAXB 版本 3
- 6。JAXB 示例、列表、时间和 CDATA 适配器
- 7。JAXB 提示
- 8。下载源代码
- 9。参考文献
1。Java 6、7、8、Java 9、10、11 以及更高版本上的 JAXB
下面是 Jakarta XML 绑定的简史(JAXB 以前的 XML 绑定 Java 架构)。
- 随着基于 XML 的 web 服务的兴起,JAXB 成为了 Java 6 的一部分。
- 基于 JSON 的 web 服务或 REST web 结构的兴起,使得开发者从 XML 迁移到 JSON 和 REST。
- JAXB 仍然是 Java 7 和 Java 8 的一部分。
- Java 9 弃用了 Java EE 模块,包括 JAXB
javax.xml.*
,并将其标记为弃用以移除,这意味着 JAXB 仍然是 Java 9 的一部分,未来的 Java 版本将移除它们。 - JAXB
javax.xml.*
仍然被弃用,并且是 Java 10 的一部分。 - JAXB 仍然是 Java 9 和 Java 10 的一部分,但是被禁用或者不包含在默认的模块路径中;但是,我们仍然可以通过
--add-modules
显式启用它(不推荐)。推荐的解决方案是添加一个单独的 JAXB API 和 JAXB 实现。 - 微服务的兴起,开发者想要一个小巧轻便的 Java 运行时。
- Java 11 完全移除了 JAXB
javax.xml.*
。现在,我们需要添加一个单独的 JAXB API 和 JAXB 实现来使用 JAXB 特性。 - Oracle 向 Eclipse Foundation 提交了 Java EE,Java EE 更名为 Jakarta EE 是因为商标“Java”。JAXB
javax.xml.*
从 3.0 版本开始也重新打包到了jakarta.xml.*
。
延伸阅读
2。Java 11 和 JAXB RI 依赖关系
JAXB 是一个规范 JSR-222 ,下面是两个常见的 JAXB 实现:
2.1 EclipseLink MOXy
下面是 Maven EclipseLink MOXy 依赖。
pom.xml
<!-- JAXB API only -->
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>3.0.0</version>
</dependency>
<!-- JAXB RI, EclipseLink MOXy -->
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>org.eclipse.persistence.moxy</artifactId>
<version>3.0.0</version>
</dependency>
2.1 Jakarta XML 绑定
下面是 Maven Jakarta XML 绑定依赖。
pom.xml
<!-- JAXB API only -->
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>3.0.0</version>
</dependency>
<!-- JAXB RI, Jakarta XML Binding -->
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>3.0.0</version>
<scope>runtime</scope>
</dependency>
如果我们仍然喜欢旧的 JAXB 包javax.xml.*
,那么坚持使用 JAXB 版本 2.x。
pom.xml
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>2.3.3</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-ri</artifactId>
<version>2.3.3</version>
</dependency>
注
- 在 Java 6、7 和 8 中,JAXB 是 JDK 的一部分。
- 在 Java 9、10、11 和更高版本中,我们需要添加单独的 JAXB API 和 JAXB RI 或实现库来使用 JAXB 特性。
3。JAXB hello world 示例
带有 JAXB 注释的类。
Fruit.java
package com.mkyong.xml.jaxb.model;
import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlAccessorType;
import jakarta.xml.bind.annotation.XmlAttribute;
import jakarta.xml.bind.annotation.XmlElement;
import jakarta.xml.bind.annotation.XmlRootElement;
@XmlRootElement
// order of the fields in XML
// @XmlType(propOrder = {"price", "name"})
@XmlAccessorType(XmlAccessType.FIELD)
public class Fruit {
@XmlAttribute
int id;
@XmlElement(name = "n")
String name;
String price;
// getter, setter and toString...
}
3.1 JAXB XML 编组——将 Java 对象转换成 XML
下面的 XML 编组 JAXB 示例将 Java 对象转换成 XML。
JaxbExampleFruit1.java
package com.mkyong.xml.jaxb;
import com.mkyong.xml.jaxb.model.Fruit;
import jakarta.xml.bind.JAXBContext;
import jakarta.xml.bind.JAXBException;
import jakarta.xml.bind.Marshaller;
import java.io.File;
public class JaxbExampleFruit1 {
public static void main(String[] args) {
JAXBContext jaxbContext = null;
try {
// Normal JAXB RI
//jaxbContext = JAXBContext.newInstance(Fruit.class);
// EclipseLink MOXy needs jaxb.properties at the same package with Fruit.class
// Alternative, I prefer define this via eclipse JAXBContextFactory manually.
jaxbContext = org.eclipse.persistence.jaxb.JAXBContextFactory
.createContext(new Class[]{Fruit.class}, null);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
// output pretty printed
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
Fruit o = new Fruit();
o.setId(1);
o.setName("Banana");
o.setPrice("9.99");
// output to a xml file
jaxbMarshaller.marshal(o, new File("C:\\test\\fruit.xml"));
// output to console
// jaxbMarshaller.marshal(o, System.out);
} catch (JAXBException e) {
e.printStackTrace();
}
}
}
输出
C:\test\fruit.xml
<?xml version="1.0" encoding="UTF-8"?>
<fruit id="1">
<n>Banana</n>
<price>9.99</price>
</fruit>
3.2 JAXB XML 解组——将 XML 转换成 Java 对象
下面是 XML 解组的 JAXB 示例,将 XML 转换回 Java 对象。
JaxbExampleFruit2.java
package com.mkyong.xml.jaxb;
import com.mkyong.xml.jaxb.model.Fruit;
import jakarta.xml.bind.JAXBContext;
import jakarta.xml.bind.JAXBException;
import jakarta.xml.bind.Unmarshaller;
import java.io.File;
public class JaxbExampleFruit2 {
public static void main(String[] args) {
JAXBContext jaxbContext = null;
try {
// Normal JAXB RI
//jaxbContext = JAXBContext.newInstance(Fruit.class);
// EclipseLink MOXy needs jaxb.properties at the same package with Fruit.class
// Alternative, I prefer define this via eclipse JAXBContextFactory manually.
jaxbContext = org.eclipse.persistence.jaxb.JAXBContextFactory
.createContext(new Class[]{Fruit.class}, null);
File file = new File("C:\\test\\fruit.xml");
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
Fruit o = (Fruit) jaxbUnmarshaller.unmarshal(file);
System.out.println(o);
} catch (JAXBException e) {
e.printStackTrace();
}
}
}
输出
Terminal
Fruit{id=1, name='Banana', price='9.99'}
4。什么是@XmlAccessorType(XmlAccessType。场)
默认情况下,JAXB 实现将 getter/setter 对、公共字段和 JAXB 注释的非公共字段用于 XML 转换。
4.1 再次检查Fruit
类,如果我们注释掉@XmlAccessorType(XmlAccessType.FIELD)
,并重新运行上面的 JAXB 程序。
Fruit.java
@XmlRootElement
//@XmlAccessorType(XmlAccessType.FIELD)
public class Fruit {
@XmlAttribute
int id;
@XmlElement(name = "n")
String name;
String price;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPrice() {
return price;
}
public void setPrice(String price) {
this.price = price;
}
@Override
public String toString() {
return "Fruit{" +
"id=" + id +
", name='" + name + '\'' +
", price='" + price + '\'' +
'}';
}
4.2 我们将得到下面的Class has two properties of the same name
错误信息。
Terminal
Class has two properties of the same name "id"
this problem is related to the following location:
at public int com.mkyong.xml.jaxb.model.Fruit.getId()
at com.mkyong.xml.jaxb.model.Fruit
this problem is related to the following location:
at int com.mkyong.xml.jaxb.model.Fruit.id
at com.mkyong.xml.jaxb.model.Fruit
Class has two properties of the same name "name"
this problem is related to the following location:
at public java.lang.String com.mkyong.xml.jaxb.model.Fruit.getName()
at com.mkyong.xml.jaxb.model.Fruit
this problem is related to the following location:
at java.lang.String com.mkyong.xml.jaxb.model.Fruit.name
at com.mkyong.xml.jaxb.model.Fruit
JAXB 将把Fruit.getId()
和Fruit.id
(因为我们用@XmlAttribute
或@XmlElement
标注)视为同一个属性;为了解决这个问题,我们在类上添加了一个@XmlAccessorType(XmlAccessType.FIELD)
,告诉 JAXB 只将Fruit.id
作为属性。
注
eclipse link MOXy JAXB 不存在上述问题。
5。javax.xml.和 jakarta.xml.
的区别
Eclipse foundation 将 Java EE javax.xml.*
更名为 Jakarta EE jakarta.xml.*
。
下面是版本 2 和 3 中的一些 JAXB APIs。
// Jakarta EE
// @Since 3.0.0, rebrand to jakarta.xml
import jakarta.xml.bind.JAXBContext;
import jakarta.xml.bind.JAXBException;
import jakarta.xml.bind.Marshaller;
// Java EE
// old APIs JAXB version 2.*
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
【JAXB 版本 2 的 5.1 Java EE,javax . XML . *
在 JAXB 版本 2 中,API 使用旧的 Java EE 包javax.xml.*
。
pom.xml
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
<!-- JAXB RI -->
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>org.eclipse.persistence.moxy</artifactId>
<version>2.7.8</version>
</dependency>
5.2 Jakarta EE,jakarta.xml.*适用于 JAXB 版本 3
在 JAXB 版本 3.x 和更高版本中,API 被重新打包到 Jakarta EE 包jakarta.xml.*
。
pom.xml
<!-- JAXB API -->
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>3.0.0</version>
</dependency>
<!-- JAXB RI -->
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>org.eclipse.persistence.moxy</artifactId>
<version>3.0.0</version>
</dependency>
6。JAXB 示例、列表、时间和 CDATA 适配器
下面的 JAXB 例子涉及以下内容:
- 一个
Company.class
包含一个Staff.class
列表,带有用于 XML 转换的 JAXB 注释。 - 使用
@XmlJavaTypeAdapter
转换 Java 8ZonedDateTime
。 - 对于特殊字符的 XML CDATA,
@XmlCDATA
只在 EclipseLink MOXy JAXB RI 中可用。
6.1 JAXB 域类
两个带有 JAXB 注释的域类。
Staff.java
package com.mkyong.xml.jaxb.model;
import com.mkyong.xml.jaxb.adaptor.TimeZoneAdaptor;
// @Since 3.0
import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlAccessorType;
import jakarta.xml.bind.annotation.XmlAttribute;
import jakarta.xml.bind.annotation.XmlRootElement;
import jakarta.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import org.eclipse.persistence.oxm.annotations.XmlCDATA;
// Java 8?
//import com.sun.xml.internal.txw2.annotation.XmlCDATA;
// jaxb 2
//import javax.xml.bind.annotation.*;
import java.time.ZonedDateTime;
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Staff {
@XmlAttribute
int id;
String name;
String Salary;
@XmlCDATA
String bio;
@XmlJavaTypeAdapter(TimeZoneAdaptor.class)
ZonedDateTime joinDate;
//getters, setters
}
Company.java
package com.mkyong.xml.jaxb.model;
//import javax.xml.bind.annotation.*;
// @Since 3.0.0
import jakarta.xml.bind.annotation.*;
import java.util.List;
@XmlRootElement
@XmlType(propOrder = {"name", "list"})
@XmlAccessorType(XmlAccessType.FIELD)
public class Company {
@XmlElement(name = "staff")
List<Staff> list;
String name;
// getters, and setters
}
6.2 JAXB 适配器
我们可以使用@XmlJavaTypeAdapter
将ZonedDateTime
(或其他类型)与String
相互转换。
TimeZoneAdaptor.java
package com.mkyong.xml.jaxb.adaptor;
// @Since 3.0.0
import jakarta.xml.bind.annotation.adapters.XmlAdapter;
//import javax.xml.bind.annotation.adapters.XmlAdapter;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
public class TimeZoneAdaptor extends XmlAdapter<String, ZonedDateTime> {
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ISO_OFFSET_DATE_TIME;
@Override
public ZonedDateTime unmarshal(String v) throws Exception {
ZonedDateTime parse = ZonedDateTime.parse(v, dateTimeFormatter);
return parse;
}
@Override
public String marshal(ZonedDateTime v) throws Exception {
return dateTimeFormatter.format(v);
}
}
6.3 JAXB 和 CDATA
对于 XML 文档中的一些特殊字符,比如<
和&
,我们需要 CDATA 。
我们选择 EclipseLink MOXy JAXB RI 是因为有一个内置的@XmlCDATA
自动用CDATA
将文本换行。
Staff.java
import org.eclipse.persistence.oxm.annotations.XmlCDATA;
//...
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Staff {
//...
@XmlCDATA
String bio;
6.4 运行 JAXB
下面的 JAXB 示例尝试将对象列表转换为 XML 文档。
JaxbExample.java
package com.mkyong.xml.jaxb;
import com.mkyong.xml.jaxb.model.Company;
import com.mkyong.xml.jaxb.model.Staff;
// @Since 3.0.0, rebrand to jakarta.xml
import jakarta.xml.bind.JAXBContext;
import jakarta.xml.bind.JAXBException;
import jakarta.xml.bind.Marshaller;
// old APIs 2.3.*,
//import javax.xml.bind.JAXBContext;
//import javax.xml.bind.JAXBException;
//import javax.xml.bind.Marshaller;
import java.io.File;
import java.time.ZonedDateTime;
import java.util.Arrays;
public class JaxbExample {
public static void main(String[] args) {
JAXBContext jaxbContext = null;
try {
//jaxbContext = JAXBContext.newInstance(Company.class);
// EclipseLink MOXy needs jaxb.properties at the same package with Company.class or Staff.class
// Alternative, I prefer define this via eclipse JAXBContextFactory manually.
jaxbContext = org.eclipse.persistence.jaxb.JAXBContextFactory
.createContext(new Class[] {Company.class}, null);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
// output pretty printed
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
//jaxbMarshaller.marshal(createCompanyObject(), new File("C:\\test\\company.xml"));
jaxbMarshaller.marshal(createCompanyObject(), System.out);
// XML Unmarshalling
/*File file = new File("C:\\test\\company.xml");
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
Company o = (Company) jaxbUnmarshaller.unmarshal(file);
System.out.println(o);*/
} catch (JAXBException e) {
e.printStackTrace();
}
}
private static Company createCompanyObject() {
Company comp = new Company();
comp.setName("ABCDEFG Enterprise");
Staff o1 = new Staff();
o1.setId(1);
o1.setName("mkyong");
o1.setSalary("8000 & Bonus");
o1.setBio("<h1>support</h1>");
o1.setJoinDate(ZonedDateTime.now().minusMonths(12));
Staff o2 = new Staff();
o2.setId(2);
o2.setName("yflow");
o2.setSalary("9000");
o2.setBio("<h1>developer & database</h1>");
o2.setJoinDate(ZonedDateTime.now().minusMonths(6));
comp.setList(Arrays.asList(o1, o2));
return comp;
}
}
输出
Terminal
<?xml version="1.0" encoding="UTF-8"?>
<company>
<name>ABCDEFG Enterprise</name>
<staff id="1">
<name>mkyong</name>
<Salary>8000 & Bonus</Salary>
<bio><![CDATA[<h1>support</h1>]]></bio>
<joinDate>2020-04-21T12:19:28.5450719+08:00</joinDate>
</staff>
<staff id="2">
<name>yflow</name>
<Salary>9000</Salary>
<bio><![CDATA[<h1>developer & database</h1>]]></bio>
<joinDate>2020-10-21T12:19:28.5450719+08:00</joinDate>
</staff>
</company>
7 .。JAXB 提示
一些常见的 JAXB 问题和技巧。
7.1 XML 漂亮打印
默认情况下,JAXB 以紧凑模式输出 XML。
<?xml version="1.0" encoding="UTF-8"?><fruit id="1">
<n>Banana</n><price>9.99</price></fruit>
为了让 JAXB 以漂亮的打印或格式化模式输出 XML,我们可以将属性Marshaller.JAXB_FORMATTED_OUTPUT
设置为true
。
// default false
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
输出
<?xml version="1.0" encoding="UTF-8"?>
<fruit id="1">
<n>Banana</n>
<price>9.99</price>
</fruit>
7.2 更改 XML 编码
JAXB 默认 XML 编码为encoding="UTF8"
,我们可以通过属性Marshaller.JAXB_ENCODING
配置指定的 XML 编码。
// change XML encoding
jaxbMarshaller.setProperty(Marshaller.JAXB_ENCODING, "ISO-8859-1");
输出
<?xml version="1.0" encoding="ISO-8859-1"?>
7.3 删除 XML 声明
将属性Marshaller.JAXB_FRAGMENT
设置为true
,它将删除开始的 XML 声明。
// default false
// remove <?xml version="1.0" encoding="UTF-8"?>
jaxbMarshaller.setProperty(Marshaller.JAXB_FRAGMENT, true);
输出
<fruit id="1">
<n>Banana</n>
<price>9.99</price>
</fruit>
7.4 改变字段的顺序
我们可以使用@XmlType propOrder
来改变写入 XML 文档的字段的顺序。
再次复习Fruit
课。
Fruit.java
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Fruit {
@XmlAttribute
int id;
@XmlElement(name = "n")
String name;
String price;
//...
}
输出
<?xml version="1.0" encoding="UTF-8"?>
<fruit id="1">
<n>Banana</n>
<price>9.99</price>
</fruit>
我们可以使用@XmlType propOrder
来控制字段的顺序;例如,下面的例子想要首先显示price
。
Fruit.java
package com.mkyong.xml.jaxb.model;
import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlAccessorType;
import jakarta.xml.bind.annotation.XmlAttribute;
import jakarta.xml.bind.annotation.XmlElement;
import jakarta.xml.bind.annotation.XmlRootElement;
import jakarta.xml.bind.annotation.XmlType;
@XmlRootElement
@XmlType(propOrder = {"price", "name"})
@XmlAccessorType(XmlAccessType.FIELD)
public class Fruit {
@XmlAttribute
int id;
@XmlElement(name = "n")
String name;
String price;
//...
}
输出
<?xml version="1.0" encoding="UTF-8"?>
<fruit id="1">
<price>9.99</price>
<n>Banana</n>
</fruit>
7.5 隐藏指定的映射字段
我们可以使用@XmlTransient
来隐藏或阻止特定字段转换成 XML。
Fruit.java
import jakarta.xml.bind.annotation.XmlTransient;
//...
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Fruit {
@XmlAttribute
int id;
@XmlElement(name = "n")
String name;
// Prevents the mapping
@XmlTransient
String price;
输出
<?xml version="1.0" encoding="UTF-8"?>
<fruit id="1">
<n>Banana</n>
</fruit>
7.6 没有找到 JAXB-API 的实现
我们需要提供一个 JAXB RI 或实现,参考这篇文章。
相关错误
- Java . lang . noclassdeffounderror:javax/XML/bind/JAXB exception
- Java . lang . classnotfoundexception:com . sun . XML . bind . v2 . context factory
8。下载源代码
$ git 克隆https://github.com/mkyong/core-java
$ cd java-xml
$ CD src/main/Java/com/mkyong/XML/JAXB/
9。参考文献
- JAXB 规格 JSR-222
- Oracle–JAXB 简介
- Wikipedia – Jakarta EE
- 维基百科–Jakarta XML 绑定
- JAXB 用户指南
- EclipseLink MOXy
- 用于 XML 绑定的 Java 架构(JAXB)
- Jakarta XML 绑定
- Java 11–JEP 320:移除 Java EE 和 CORBA 模块
- Java 8 – ZonedDateTime examples
- Java 8–如何将字符串转换为本地日期
- JAXB 异常:没有找到 JAXB-API 的实现
- stack overflow——如何使用 JAXB 生成 CDATA 块?
- Java 9、10、11 及更高版本上的 JAXB
JDBC 可调用语句–PostgreSQL 存储函数
一个 JDBC 的例子向你展示了如何从 PostgreSQL 数据库中调用一个存储函数。
PS 用 PostgreSQL 11 和 Java 8 测试
pom.xml
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.2.5</version>
</dependency>
1.呼叫功能
1.1 创建一个存储函数并通过 JDBC 调用它。
FunctionReturnString.java
package com.mkyong.jdbc.callablestatement;
import java.sql.*;
public class FunctionReturnString {
public static void main(String[] args) {
String createFunction = "CREATE OR REPLACE FUNCTION hello(p1 TEXT) RETURNS TEXT "
+ " AS $$ "
+ " BEGIN "
+ " RETURN 'hello ' || p1; "
+ " END; "
+ " $$ "
+ " LANGUAGE plpgsql";
String runFunction = "{ ? = call hello( ? ) }";
try (Connection conn = DriverManager.getConnection(
"jdbc:postgresql://127.0.0.1:5432/test", "postgres", "password");
Statement statement = conn.createStatement();
CallableStatement callableStatement = conn.prepareCall(runFunction)) {
// create or replace stored function
statement.execute(createFunction);
//----------------------------------
// output
callableStatement.registerOutParameter(1, Types.VARCHAR);
// input
callableStatement.setString(2, "mkyong");
// Run hello() function
callableStatement.executeUpdate();
// Get result
String result = callableStatement.getString(1);
System.out.println(result);
} catch (SQLException e) {
System.err.format("SQL State: %s\n%s", e.getSQLState(), e.getMessage());
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
输出
hello mkyong
1.2 SQL 版本。
CREATE OR REPLACE FUNCTION hello(p1 TEXT) RETURNS TEXT
AS $$
BEGIN
RETURN 'hello ' || p1;
END;
$$
LANGUAGE plpgsql;
-- run it
select hello('mkyong');
-- output: hello mkyong
2.函数返回 SETOF
2.1 对于作为SETOF
返回数据的函数,我们应该使用普通的Statement
或PreparedStatement
,而不是CallableStatement
P.S 表 pg_roles
是包含数据库角色的系统表
FunctionReturnResultSet.java
package com.mkyong.jdbc.callablestatement;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
public class FunctionReturnResultSet {
public static void main(String[] args) {
List<String> users = new ArrayList<>();
String createFunction = "CREATE OR REPLACE FUNCTION getRoles() RETURNS SETOF pg_roles "
+ " AS 'select * from pg_roles' LANGUAGE sql;";
String runFunction = "select * from getRoles();";
try (Connection conn = DriverManager.getConnection(
"jdbc:postgresql://127.0.0.1:5432/test", "postgres", "password");
Statement statement = conn.createStatement()) {
// create a function returns as SETOF
statement.execute(createFunction);
// run it
ResultSet resultSet = statement.executeQuery(runFunction);
while (resultSet.next()) {
users.add(resultSet.getString("rolname"));
}
System.out.println("Database roles...");
users.forEach(x -> System.out.println(x));
} catch (SQLException e) {
System.err.format("SQL State: %s\n%s", e.getSQLState(), e.getMessage());
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
输出
Database roles...
pg_signal_backend
pg_read_server_files
postgres
pg_write_server_files
pg_execute_server_program
pg_read_all_stats
pg_monitor
pg_read_all_settings
pg_stat_scan_tables
2.2 SQL 版本。
CREATE OR REPLACE FUNCTION getRoles() RETURNS SETOF pg_roles
AS 'select * from pg_roles' LANGUAGE sql;
-- run it
select * from getRoles();
3.函数返回光标
3.1 JDBC +参考光标示例。
FunctionReturnRefCursor.java
package com.mkyong.jdbc.callablestatement;
import java.sql.*;
public class FunctionReturnRefCursor {
public static void main(String[] args) {
String createFunction = "CREATE OR REPLACE FUNCTION getUsers(mycurs OUT refcursor) "
+ " RETURNS refcursor "
+ " AS $$ "
+ " BEGIN "
+ " OPEN mycurs FOR select * from pg_user; "
+ " END; "
+ " $$ "
+ " LANGUAGE plpgsql";
String runFunction = "{? = call getUsers()}";
try (Connection conn = DriverManager.getConnection(
"jdbc:postgresql://127.0.0.1:5432/test", "postgres", "password");
Statement statement = conn.createStatement();
CallableStatement cs = conn.prepareCall(runFunction);
) {
// We must be inside a transaction for cursors to work.
conn.setAutoCommit(false);
// create function
statement.execute(createFunction);
// register output
cs.registerOutParameter(1, Types.REF_CURSOR);
// run function
cs.execute();
// get refcursor and convert it to ResultSet
ResultSet resultSet = (ResultSet) cs.getObject(1);
while (resultSet.next()) {
System.out.println(resultSet.getString("usename"));
System.out.println(resultSet.getString("passwd"));
}
} catch (SQLException e) {
System.err.format("SQL State: %s\n%s", e.getSQLState(), e.getMessage());
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
输出–该数据库包含一个用于测试的用户🙂
postgres
********
3.2 SQL 版本。
CREATE OR REPLACE FUNCTION getUsers(mycurs OUT refcursor) RETURNS refcursor
AS $$
BEGIN
OPEN mycurs FOR select * from pg_user;
END;
$$
LANGUAGE plpgsql;
下载源代码
$ git clone https://github.com/mkyong/java-jdbc.git
参考
- PostgreSQL–调用存储函数
- PostgreSQL–pg _ roles
- PostgreSQL–创建函数
- JDBC PL/SQL 示例
- 语句 JavaDocs
- Java JDBC 教程
- PostgreSQL 11 中的新存储过程
JDBC 可调用语句–存储过程游标示例
对于 Oracle 存储过程返回的游标参数,您可以
- 通过 JDBC 注册
CallableStatement.registerOutParameter(index,OracleTypes.CURSOR)
。 - 通过
callableStatement.getObject(index)
取回。
查看代码片段
//getDBUSERCursor is a stored procedure
String getDBUSERCursorSql = "{call getDBUSERCursor(?,?)}";
callableStatement = dbConnection.prepareCall(getDBUSERCursorSql);
callableStatement.setString(1, "mkyong");
callableStatement.registerOutParameter(2, OracleTypes.CURSOR);
// execute getDBUSERCursor store procedure
callableStatement.executeUpdate();
// get cursor and cast it to ResultSet
rs = (ResultSet) callableStatement.getObject(2);
// loop it like normal
while (rs.next()) {
String userid = rs.getString("USER_ID");
String userName = rs.getString("USERNAME");
}
JDBC 可调用语句光标示例
关于输出光标参数,参见完整的 JDBC CallableStatement
示例。
1.存储过程
一个 Oracle 存储过程,有一个 IN 和一个 OUT 游标参数。后来,称之为经 JDBC。
CREATE OR REPLACE PROCEDURE getDBUSERCursor(
p_username IN DBUSER.USERNAME%TYPE,
c_dbuser OUT SYS_REFCURSOR)
IS
BEGIN
OPEN c_dbuser FOR
SELECT * FROM DBUSER WHERE USERNAME LIKE p_username || '%';
END;
/
2.通过 CallableStatement 调用存储过程
JDBC 示例调用上述存储过程,将返回的光标转换为结果集,并按顺序遍历记录。
文件:JDBCCallableStatementCURSORExample.java
package com.mkyong.jdbc;
import java.sql.CallableStatement;
import java.sql.Date;
import java.sql.DriverManager;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import oracle.jdbc.OracleTypes;
public class JDBCCallableStatementCURSORExample {
private static final String DB_DRIVER = "oracle.jdbc.driver.OracleDriver";
private static final String DB_CONNECTION = "jdbc:oracle:thin:@localhost:1521:MKYONG";
private static final String DB_USER = "user";
private static final String DB_PASSWORD = "password";
public static void main(String[] argv) {
try {
callOracleStoredProcCURSORParameter();
} catch (SQLException e) {
System.out.println(e.getMessage());
}
}
private static void callOracleStoredProcCURSORParameter()
throws SQLException {
Connection dbConnection = null;
CallableStatement callableStatement = null;
ResultSet rs = null;
String getDBUSERCursorSql = "{call getDBUSERCursor(?,?)}";
try {
dbConnection = getDBConnection();
callableStatement = dbConnection.prepareCall(getDBUSERCursorSql);
callableStatement.setString(1, "mkyong");
callableStatement.registerOutParameter(2, OracleTypes.CURSOR);
// execute getDBUSERCursor store procedure
callableStatement.executeUpdate();
// get cursor and cast it to ResultSet
rs = (ResultSet) callableStatement.getObject(2);
while (rs.next()) {
String userid = rs.getString("USER_ID");
String userName = rs.getString("USERNAME");
String createdBy = rs.getString("CREATED_BY");
String createdDate = rs.getString("CREATED_DATE");
System.out.println("UserName : " + userid);
System.out.println("UserName : " + userName);
System.out.println("CreatedBy : " + createdBy);
System.out.println("CreatedDate : " + createdDate);
}
} catch (SQLException e) {
System.out.println(e.getMessage());
} finally {
if (rs != null) {
rs.close();
}
if (callableStatement != null) {
callableStatement.close();
}
if (dbConnection != null) {
dbConnection.close();
}
}
}
private static Connection getDBConnection() {
Connection dbConnection = null;
try {
Class.forName(DB_DRIVER);
} catch (ClassNotFoundException e) {
System.out.println(e.getMessage());
}
try {
dbConnection = DriverManager.getConnection(
DB_CONNECTION, DB_USER,DB_PASSWORD);
return dbConnection;
} catch (SQLException e) {
System.out.println(e.getMessage());
}
return dbConnection;
}
}
完成了。
参考
- http://www.oradev.com/ref_cursor.jsp
- http://download . Oracle . com/javase/6/docs/API/Java/SQL/callable statement . html
- http://docsrv . SCO . com/JDK _ guide/JDBC/getstart/callable statement . doc . html
- http://on Java . com/pub/a/on Java/2003/08/13/stored _ procedures . html
JDBC 可调用语句–参数示例中的存储过程
代码片段向您展示了如何通过 JDBC CallableStatement
调用 Oracle 存储过程,以及如何从 Java 向存储过程传递参数。
//insertDBUSER is stored procedure
String insertStoreProc = "{call insertDBUSER(?,?,?,?)}";
callableStatement = dbConnection.prepareCall(insertStoreProc);
callableStatement.setInt(1, 1000);
callableStatement.setString(2, "mkyong");
callableStatement.setString(3, "system");
callableStatement.setDate(4, getCurrentDate());
callableStatement.executeUpdate();
JDBC 可调用语句示例
参见完整的 JDBC CallableStatement
例子。
1.存储过程
Oracle 数据库中的存储过程。后来,称之为经 JDBC。
CREATE OR REPLACE PROCEDURE insertDBUSER(
p_userid IN DBUSER.USER_ID%TYPE,
p_username IN DBUSER.USERNAME%TYPE,
p_createdby IN DBUSER.CREATED_BY%TYPE,
p_date IN DBUSER.CREATED_DATE%TYPE)
IS
BEGIN
INSERT INTO DBUSER ("USER_ID", "USERNAME", "CREATED_BY", "CREATED_DATE")
VALUES (p_userid, p_username,p_createdby, p_date);
COMMIT;
END;
/
2.通过 CallableStatement 调用存储过程
JDBC 通过CallableStatement
调用存储过程的例子。
文件:JDBCCallableStatementINParameterExample.java
package com.mkyong.jdbc;
import java.sql.CallableStatement;
import java.sql.DriverManager;
import java.sql.Connection;
import java.sql.SQLException;
public class JDBCCallableStatementINParameterExample {
private static final String DB_DRIVER = "oracle.jdbc.driver.OracleDriver";
private static final String DB_CONNECTION = "jdbc:oracle:thin:@localhost:1521:MKYONG";
private static final String DB_USER = "user";
private static final String DB_PASSWORD = "password";
public static void main(String[] argv) {
try {
callOracleStoredProcINParameter();
} catch (SQLException e) {
System.out.println(e.getMessage());
}
}
private static void callOracleStoredProcINParameter() throws SQLException {
Connection dbConnection = null;
CallableStatement callableStatement = null;
String insertStoreProc = "{call insertDBUSER(?,?,?,?)}";
try {
dbConnection = getDBConnection();
callableStatement = dbConnection.prepareCall(insertStoreProc);
callableStatement.setInt(1, 1000);
callableStatement.setString(2, "mkyong");
callableStatement.setString(3, "system");
callableStatement.setDate(4, getCurrentDate());
// execute insertDBUSER store procedure
callableStatement.executeUpdate();
System.out.println("Record is inserted into DBUSER table!");
} catch (SQLException e) {
System.out.println(e.getMessage());
} finally {
if (callableStatement != null) {
callableStatement.close();
}
if (dbConnection != null) {
dbConnection.close();
}
}
}
private static Connection getDBConnection() {
Connection dbConnection = null;
try {
Class.forName(DB_DRIVER);
} catch (ClassNotFoundException e) {
System.out.println(e.getMessage());
}
try {
dbConnection = DriverManager.getConnection(
DB_CONNECTION, DB_USER,DB_PASSWORD);
return dbConnection;
} catch (SQLException e) {
System.out.println(e.getMessage());
}
return dbConnection;
}
private static java.sql.Date getCurrentDate() {
java.util.Date today = new java.util.Date();
return new java.sql.Date(today.getTime());
}
}
完成了。当执行上述 JDBC 示例时,将通过存储过程"insertDBUSER
"向数据库中插入一条新记录。
参考
- http://download . Oracle . com/javase/6/docs/API/Java/SQL/callable statement . html
- http://docsrv . SCO . com/JDK _ guide/JDBC/getstart/callable statement . doc . html
- http://on Java . com/pub/a/on Java/2003/08/13/stored _ procedures . html
callablestatement jdbc store procedure
JDBC 可调用语句–存储过程输出参数示例
一个 JDBC CallableStatement
例子来调用一个接受输入和输出参数的存储过程。
使用 Java 8 和 Oracle database 19c 进行测试
pom.xml
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc</artifactId>
<version>8</version>
<scope>system</scope>
<systemPath>path.to/ojdbc8.jar</systemPath>
</dependency>
1.JDBC 可赎回声明
1.1 接受 IN 和 OUT 参数的 PL/SQL 存储过程。
CREATE OR REPLACE PROCEDURE get_employee_by_id(
p_id IN EMPLOYEE.ID%TYPE,
o_name OUT EMPLOYEE.NAME%TYPE,
o_salary OUT EMPLOYEE.SALARY%TYPE,
o_date OUT EMPLOYEE.CREATED_DATE%TYPE)
AS
BEGIN
SELECT NAME , SALARY, CREATED_DATE INTO o_name, o_salary, o_date from EMPLOYEE WHERE ID = p_id;
END;
1.2 JDBC 调用上述存储过程的例子。
StoreProcedureOutParameter.java
package com.mkyong.jdbc.callablestatement;
import java.math.BigDecimal;
import java.sql.*;
public class StoreProcedureOutParameter {
public static void main(String[] args) {
String createSP = "CREATE OR REPLACE PROCEDURE get_employee_by_id( "
+ " p_id IN EMPLOYEE.ID%TYPE, "
+ " o_name OUT EMPLOYEE.NAME%TYPE, "
+ " o_salary OUT EMPLOYEE.SALARY%TYPE, "
+ " o_date OUT EMPLOYEE.CREATED_DATE%TYPE) "
+ " AS "
+ " BEGIN "
+ " SELECT NAME, SALARY, CREATED_DATE INTO o_name, o_salary, o_date from EMPLOYEE WHERE ID = p_id; "
+ " END;";
String runSP = "{ call get_employee_by_id(?,?,?,?) }";
try (Connection conn = DriverManager.getConnection(
"jdbc:oracle:thin:@localhost:1521:orcl", "system", "Password123");
Statement statement = conn.createStatement();
CallableStatement callableStatement = conn.prepareCall(runSP)) {
// create or replace stored procedure
statement.execute(createSP);
callableStatement.setInt(1, 3);
callableStatement.registerOutParameter(2, java.sql.Types.VARCHAR);
callableStatement.registerOutParameter(3, Types.DECIMAL);
callableStatement.registerOutParameter(4, java.sql.Types.DATE);
// run it
callableStatement.executeUpdate();
// java.sql.SQLException: operation not allowed: Ordinal binding and Named binding cannot be combined!
/*String name = callableStatement.getString("NAME");
BigDecimal salary = callableStatement.getBigDecimal("SALARY");
Timestamp createdDate = callableStatement.getTimestamp("CREATED_DATE");*/
String name = callableStatement.getString(2);
BigDecimal salary = callableStatement.getBigDecimal(3);
Timestamp createdDate = callableStatement.getTimestamp(4);
System.out.println("name: " + name);
System.out.println("salary: " + salary);
System.out.println("createdDate: " + createdDate);
} catch (SQLException e) {
System.err.format("SQL State: %s\n%s", e.getSQLState(), e.getMessage());
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
下载源代码
$ git clone https://github.com/mkyong/java-jdbc.git