Jetty WebSocket API使用

Jetty提供了功能更强的WebSocket API,使用一个公共的核心API供WebSockets的服务端和client使用。

他是一个基于WebSocket消息的事件驱动的API。

WebSocket事件

每一个WebSocket都能接收多种事件:

On Connect Event

表示WebSocket升级成功,WebSocket如今打开。

 你将收到一个org.eclipse.jetty.websocket.api.Session对象,相应这个Open事件的session。

 为通常的WebSocket,应该紧紧抓住这个Session,并使用它与Remote Endpoint进行交流。

 假设为无状态(Stateless)WebSockets,这个Session将被传递到它出现的每个事件,同意你使用一个WebSocket的1个实例为多个Remote Endpoint提供服务。

On Close Event

表示WebSocket已经关闭。

 每一个Close事件将有一个状态码(Status Code)(和一个可选的Closure Reason Message)。

 一个通常的WebSocket终止将经历一个关闭握手,Local Endpoint和Remote Endpoint都会发送一个Close帧表示连接被关闭。

 本地WebSocket能够通过发送一个Close帧到Remote Endpoint表示希望关闭,可是Remote Endpoint能继续发送信息直到它送一个Close帧为止。这被称之为半开(Half-Open)连接,注意一旦Local Endpoint发送了Close帧后,它将不能再发送不论什么WebSocket信息。

 在一个异常的终止中,比如一个连接断开或者超时,底层连接将不经历Close Handshake就被终止,这也将导致一个On Close Event(和可能伴随一个On Error Event)。

On Error Event

假设一个错误出现,在实现期间,WebSocket将通过这个事件被通知。

On Message Event

表示一个完整的信息被收到,准备被你的WebSocket处理。

 这能是一个(UTF8)TEXT信息或者一个原始的BINARY信息。

WebSocket Session

Session对象能被用于:

获取WebSocket的状态

连接状态(打开或者关闭)

if(session.isOpen()) {
// send message
}

连接是安全的吗。

if(session.isSecure()) {
// connection is using 'wss://'
}

在升级请求和响应中的是什么。

UpgradeRequest req = session.getUpgradeRequest();
String channelName = req.getParameterMap().get("channelName"); UpgradeRespons resp = session.getUpgradeResponse();
String subprotocol = resp.getAcceptedSubProtocol();

本地和远端地址是什么。

InetSocketAddress remoteAddr = session.getRemoteAddress();

配置策略

获取和设置空暇超时时间。

session.setIdleTimeout(2000); // 2 second timeout

获取和设置最大信息长度。

session.setMaximumMessageSize(64*1024); // accept messages up to 64k, fail if larger

发送信息到Remote Endpoint

Session的最重要的特征是获取org.eclipse.jetty.websocket.api.RemoteEndpoint

使用RemoteEndpoint,你能选择发送TEXT或者BINARY Websocket信息,或者WebSocket PING和PONG控制帧。

堵塞式发送信息

其实大部分调用都是堵塞式的,直到发送完毕(或者抛出一个异常)才返回。

实例1 发送二进制信息(堵塞)
RemoteEndpoint remote = session.getRemote(); // Blocking Send of a BINARY message to remote endpoint
ByteBuffer buf = ByteBuffer.wrap(new byte[] { 0x11, 0x22, 0x33, 0x44 });
try
{
remote.sendBytes(buf);
}
catch (IOException e)
{
e.printStackTrace(System.err);
}

怎么使用RemoteEndpoint送一个简单的二进制信息。这将堵塞直到信息被发送完毕,假设不能发送信息可能将抛出一个IOException。

实例2 发送文本信息(堵塞)
RemoteEndpoint remote = session.getRemote(); // Blocking Send of a TEXT message to remote endpoint
try
{
remote.sendString("Hello World");
}
catch (IOException e)
{
e.printStackTrace(System.err);
}

怎么使用RemoteEndpoint发送文本信息。这将堵塞直到信息发送,假设不能发送信息可能将抛出一个IOException。

发送部分信息

假设你有一个大的信息须要被发送,而且想分多次发送,每次一部分,你能使用RemoteEndpoint发送部分信息的方法。仅须要确保你最后发送一个完毕发送的信息(isLast == true)

实例3 发送部分二进制信息(堵塞)
RemoteEndpoint remote = session.getRemote(); // Blocking Send of a BINARY message to remote endpoint
// Part 1
ByteBuffer buf1 = ByteBuffer.wrap(new byte[] { 0x11, 0x22 });
// Part 2 (last part)
ByteBuffer buf2 = ByteBuffer.wrap(new byte[] { 0x33, 0x44 });
try
{
remote.sendPartialBytes(buf1,false);
remote.sendPartialBytes(buf2,true); // isLast is true
}
catch (IOException e)
{
e.printStackTrace(System.err);
}

怎么分两次发送一个二进制信息,使用在RemoteEndpoint中的部分信息支持方法。这将堵塞直到每次信息发送完毕,假设不能发送信息可能抛出一个IOException。

实例4 发送部分文本信息(堵塞)
RemoteEndpoint remote = session.getRemote(); // Blocking Send of a TEXT message to remote endpoint
String part1 = "Hello";
String part2 = " World";
try
{
remote.sendPartialString(part1,false);
remote.sendPartialString(part2,true); // last part
}
catch (IOException e)
{
e.printStackTrace(System.err);
}

怎么通过两次发送一个文本信息,使用在RemoteEndpoint中的部分信息支持方法。这将堵塞直到每次信息发送完毕,假设不能发送信息可能抛出一个IOException。

发送Ping/Pong控制帧

你也能使用RemoteEndpoint发送Ping和Pong控制帧。

实例5 发送Ping控制帧(堵塞)
RemoteEndpoint remote = session.getRemote(); // Blocking Send of a PING to remote endpoint
String data = "You There?";
ByteBuffer payload = ByteBuffer.wrap(data.getBytes());
try
{
remote.sendPing(payload);
}
catch (IOException e)
{
e.printStackTrace(System.err);
}

怎么发送一个Ping控制帧,附带一个负载“You There?”(作为一个字节数组负载到达Remote Endpoint)。这将堵塞直到信息发送完毕,假设不能发送Ping帧,可能抛出一个IOException。

实例6 送Pong控制帧(堵塞)
RemoteEndpoint remote = session.getRemote(); // Blocking Send of a PONG to remote endpoint
String data = "Yup, I'm here";
ByteBuffer payload = ByteBuffer.wrap(data.getBytes());
try
{
remote.sendPong(payload);
}
catch (IOException e)
{
e.printStackTrace(System.err);
}

怎么发送一个Pong控制帧,附带一个"Yup I'm here"负载(作为一个字节数组负载到达Remote Endpoint)。这将堵塞直到信息被发送,假设不能发送Pong帧,可能抛出一个IOException。

为了正确的使用Pong帧,你应该返回你在Ping帧中收到的相同的字节数组数据。

异步发送信息

也存在来年改革异步发送信息的方法可用:

 1)RemoteEndpoint.sendBytesByFuture(字节信息)

 2)RemoteEndpoint.sendStringByFuture(字符串信息)

两个方法都返回一个Future<Void>,使用标准java.util.concurrent.Future行为,能被用于測试信息发送的成功和失败。

实例7 送二进制信息(异步)
RemoteEndpoint remote = session.getRemote(); // Async Send of a BINARY message to remote endpoint
ByteBuffer buf = ByteBuffer.wrap(new byte[] { 0x11, 0x22, 0x33, 0x44 });
remote.sendBytesByFuture(buf);

怎么使用RemoteEndpoint发送一个简单的二进制信息。这个信息将被放入发送队列,你将不知道发送成功或者失败。

实例8 发送二进制信息(异步,等待直到成功)
RemoteEndpoint remote = session.getRemote(); // Async Send of a BINARY message to remote endpoint
ByteBuffer buf = ByteBuffer.wrap(new byte[] { 0x11, 0x22, 0x33, 0x44 });
try
{
Future<Void> fut = remote.sendBytesByFuture(buf);
// wait for completion (forever)
fut.get();
}
catch (ExecutionException | InterruptedException e)
{
// Send failed
e.printStackTrace();
}

怎么使用RemoteEndpoint发送一个简单的二进制信息,追踪Future<Void>以确定发送成功还是失败。

实例9 送二进制信息(异步,发送超时)
RemoteEndpoint remote = session.getRemote(); // Async Send of a BINARY message to remote endpoint
ByteBuffer buf = ByteBuffer.wrap(new byte[] { 0x11, 0x22, 0x33, 0x44 });
Future<Void> fut = null;
try
{
fut = remote.sendBytesByFuture(buf);
// wait for completion (timeout)
fut.get(2,TimeUnit.SECONDS);
}
catch (ExecutionException | InterruptedException e)
{
// Send failed
e.printStackTrace();
}
catch (TimeoutException e)
{
// timeout
e.printStackTrace();
if (fut != null)
{
// cancel the message
fut.cancel(true);
}
}

怎么使用RemoteEndpoint发送一个简单的二进制信息,追踪Future<Void>并等待一个有限的时间,假设时间超限则取消该信息。

实例10 发送文本信息(异步)
RemoteEndpoint remote = session.getRemote(); // Async Send of a TEXT message to remote endpoint
remote.sendStringByFuture("Hello World"); 怎么使用RemoteEndpoint发送一个简单的文本信息。这个信息将被放到输出队列中,可是你将不知道发送成功还是失败。 实例11 发送文本信息(异步,等待直到成功)
RemoteEndpoint remote = session.getRemote(); // Async Send of a TEXT message to remote endpoint
try
{
Future<Void> fut = remote.sendStringByFuture("Hello World");
// wait for completion (forever)
fut.get();
}
catch (ExecutionException | InterruptedException e)
{
// Send failed
e.printStackTrace();
}

怎么使用RemoteEndpoint发送一个简单的二进制信息,追踪Future<Void>以直到发送成功还是失败。

实例12 发送文本信息(异步,发送超时)
RemoteEndpoint remote = session.getRemote(); // Async Send of a TEXT message to remote endpoint
Future<Void> fut = null;
try
{
fut = remote.sendStringByFuture("Hello World");
// wait for completion (timeout)
fut.get(2,TimeUnit.SECONDS);
}
catch (ExecutionException | InterruptedException e)
{
// Send failed
e.printStackTrace();
}
catch (TimeoutException e)
{
// timeout
e.printStackTrace();
if (fut != null)
{
// cancel the message
fut.cancel(true);
}
}

怎么使用RemoteEndpoint发送一个简单的二进制信息,追踪Future<Void>并等待有限的时间,假设超时则取消。

使用WebSocket凝视

WebSocket的最主要的形式是一个被Jetty WebSocket API提供的用凝视标记的POJO。

实例13 AnnotatedEchoSocket.java
package examples.echo; import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
import org.eclipse.jetty.websocket.api.annotations.WebSocket; /**
* Example EchoSocket using Annotations.
*/
@WebSocket(maxTextMessageSize = 64 * 1024)
public class AnnotatedEchoSocket { @OnWebSocketMessage
public void onText(Session session, String message) {
if (session.isOpen()) {
System.out.printf("Echoing back message [%s]%n", message);
session.getRemote().sendString(message, null);
}
}
}

上面的样例是一个简单的WebSocket回送端点,将回送全部它收到的文本信息。

这个实现使用了一个无状态的方法,因此对每一个出现的事件Session都会被传递到Message处理方法中。这将同意你在同多个port交互时能够重用AnnotatedEchoSocket的单实例。

你可用的凝视例如以下:

@WebSocket

一个必须的类级别的凝视。

标记这个POJO作为一个WebSocket。

类必须不是abstract,且是public。

@OnWebSocketConnect

一个可选的方法级别的凝视。

标记一个在类中的方法作为On Connect事件的接收者。

方法必须是public,且不是abstract,返回void,而且有且仅有一个Session參数。

@OnWebSocketClose

一个可选的方法级的凝视。

标记一个在类中的方法作为On Close事件的接收者。

方法标签必须是public,不是abstract,而且返回void。

方法的參数包含:

 1)Session(可选)

 2)int closeCode(必须)

 3)String closeReason(必须)

@OnWebSocketMessage

一个可选的方法级凝视。

标记在类中的2个方法作为接收On Message事件的接收者。

方法标签必须是public,不是abstract,而且返回void。

为文本信息的方法參数包含:

 1)Session(可选)

 2)String text(必须)

为二进制信息的方法參数包含:

 1)Session(可选)

 2)byte buf[](必须)

 3)int offset(必须)

 4)int length(必须)

@OnWebSocketError

一个可选的方法级凝视。

标记一个类中的方法作为Error事件的接收者。

方法标签必须是public,不是abstract,而且返回void。

方法參数包含:

 1)Session(可选)

 2)Throwable cause(必须)

@OnWebSocketFrame

一个可选的方法级凝视。

标记一个类中的方法作为Frame事件的接收者。

方法标签必须是public,不是abstract,而且返回void。

方法參数包含:

 1)Session(可选)

 2)Frame(必须)

收到的Frame将在这种方法上被通知,然后被Jetty处理,可能导致还有一个事件,比如On Close,或者On Message。对Frame的改变将不被Jetty看到。

用WebSocketListener

一个WebSocket的基本形式是使用org.eclipse.jetty.websocket.api.WebSocketListener处理收到的事件。

实例14 ListenerEchoSocket.java
package examples.echo; import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.WebSocketListener; /**
* Example EchoSocket using Listener.
*/
public class ListenerEchoSocket implements WebSocketListener { private Session outbound; @Override
public void onWebSocketBinary(byte[] payload, int offset, int len) {
} @Override
public void onWebSocketClose(int statusCode, String reason) {
this.outbound = null;
} @Override
public void onWebSocketConnect(Session session) {
this.outbound = session;
} @Override
public void onWebSocketError(Throwable cause) {
cause.printStackTrace(System.err);
} @Override
public void onWebSocketText(String message) {
if ((outbound != null) && (outbound.isOpen())) {
System.out.printf("Echoing back message [%s]%n", message);
outbound.getRemote().sendString(message, null);
}
}
}

假设listener做了太多的工作,你能使用WebSocketAdapter取代。

使用WebSocketAdapter

WebSocketListener的适配器。

实例15 AdapterEchoSocket.java
package examples.echo; import java.io.IOException;
import org.eclipse.jetty.websocket.api.WebSocketAdapter; /**
* Example EchoSocket using Adapter.
*/
public class AdapterEchoSocket extends WebSocketAdapter { @Override
public void onWebSocketText(String message) {
if (isConnected()) {
try {
System.out.printf("Echoing back message [%s]%n", message);
getRemote().sendString(message);
} catch (IOException e) {
e.printStackTrace(System.err);
}
}
}
}

这个类比WebSocketListener跟为便利,并提供了实用的方法检查Session的状态。

Jetty WebSocket Server API

Jetty通过WebSocketServlet和servlet桥接的使用,提供了将WebSocket端点到Servlet路径的相应。

内在地,Jetty管理HTTP升级到WebSocket,而且从一个HTTP连接移植到一个WebSocket连接。

这仅仅有当执行在Jetty容器内部时才工作。

Jetty WebSocketServlet

为了通过WebSocketServlet相应你的WebSocket到一个指定的路径,你将须要扩展org.eclipse.jetty.websocket.servlet.WebSocketServlet并指定什么WebSocket对象应该被创建。

实例16 MyEchoServlet.java
package examples; import javax.servlet.annotation.WebServlet;
import org.eclipse.jetty.websocket.servlet.WebSocketServlet;
import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory; @SuppressWarnings("serial")
@WebServlet(name = "MyEcho WebSocket Servlet", urlPatterns = { "/echo" })
public class MyEchoServlet extends WebSocketServlet { @Override
public void configure(WebSocketServletFactory factory) {
factory.getPolicy().setIdleTimeout(10000);
factory.register(MyEchoSocket.class);
}
}

这个样例将创建一个Sevlet,通过@WebServlet注解匹配到Servlet路径"/echo"(或者你能在你的web应用的WEB-INF/web.xml中手动的配置),当收到HTTP升级请求时将创建MyEchoSocket实例。

WebSocketServlet.configure(WebSocketServletFactory factory)是为你的WebSocket指定配置的地方。在这个样例中,我们指定一个10s的空暇超时,并注冊MyEchoSocket,即当收到请求时我们想创建的WebSocket类,使用默认的WebSocketCreator创建。

使用WebSocketCreator

全部WebSocket都是通过你注冊到WebSocketServletFactory的WebSocketCreator创建的。

默认,WebSocketServletFactory是一个简单的WebSocketCreator,能创建一个单例的WebSocket对象。 使用WebSocketCreator.register(Class<?> websocket)告诉WebSocketServletFactory应该实例化哪个类(确保它有一个默认的构造器)。

假设你有更复杂的创建场景,你能够提供你自己的WebSocketCreator,基于在UpgradeRequest对象中出现的信息创建的WebSocket。

实例17 MyAdvancedEchoCreator.java
package examples; import org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest;
import org.eclipse.jetty.websocket.servlet.ServletUpgradeResponse;
import org.eclipse.jetty.websocket.servlet.WebSocketCreator; public class MyAdvancedEchoCreator implements WebSocketCreator { private MyBinaryEchoSocket binaryEcho; private MyEchoSocket textEcho; public MyAdvancedEchoCreator() {
this.binaryEcho = new MyBinaryEchoSocket();
this.textEcho = new MyEchoSocket();
} @Override
public Object createWebSocket(ServletUpgradeRequest req, ServletUpgradeResponse resp) {
for (String subprotocol : req.getSubProtocols()) {
if ("binary".equals(subprotocol)) {
resp.setAcceptedSubProtocol(subprotocol);
return binaryEcho;
}
if ("text".equals(subprotocol)) {
resp.setAcceptedSubProtocol(subprotocol);
return textEcho;
}
}
return null;
}
}

这儿我们展示了一个WebSocketCreator,将利用来自请求的WebSocket子协议信息决定什么类型的WebSocket应该被创建。

实例18 MyAdvancedEchoServlet.java
package examples; import javax.servlet.annotation.WebServlet;
import org.eclipse.jetty.websocket.servlet.WebSocketServlet;
import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory; @SuppressWarnings("serial")
@WebServlet(name = "MyAdvanced Echo WebSocket Servlet", urlPatterns = { "/advecho" })
public class MyAdvancedEchoServlet extends WebSocketServlet { @Override
public void configure(WebSocketServletFactory factory) {
factory.getPolicy().setIdleTimeout(10000);
factory.setCreator(new MyAdvancedEchoCreator());
}
}

当你想要一个定制的WebSocketCreator时,使用WebSocketServletFactory.setCreator(WebSocketCreator creator),然后WebSocketServletFactory将为全部在这个servlet上收到的Upgrade请求用你的创造器。

一个WebSocketCreator还能够用于:

 1)控制WebSocket子协议的选择;

 2)履行不论什么你觉得重要的WebSocket源;

 3)从输入的请求获取HTTP头;

 4)获取Servlet HttpSession对象(假设它存在);

 5)指定一个响应状态码和原因;

假设你不想接收这个请求,简单的从WebSocketCreator.createWebSocket(UpgradeRequest req, UpgradeResponse resp)返回null。

Jetty WebSocket Client API

Jetty也提供了一个Jetty WebSocket Client库,为了更easy的与WebSocket服务端交互。

为了在你自己的Java项目上使用Jetty WebSocket Client,你将须要以下的maven配置:

<dependency>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>websocket-client</artifactId>
<version>${project.version}</version>
</dependency>

WebSocketClient

为了使用WebSocketClient,你将须要连接一个WebSocket对象实例到一个指定的目标WebSocket URI。

实例19 SimpleEchoClient.java
package examples; import java.net.URI;
import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
import org.eclipse.jetty.websocket.client.WebSocketClient; /**
* Example of a simple Echo Client.
*/
public class SimpleEchoClient { public static void main(String[] args) {
String destUri = "ws://echo.websocket.org";
if (args.length > 0) {
destUri = args[0];
}
WebSocketClient client = new WebSocketClient();
SimpleEchoSocket socket = new SimpleEchoSocket();
try {
client.start();
URI echoUri = new URI(destUri);
ClientUpgradeRequest request = new ClientUpgradeRequest();
client.connect(socket, echoUri, request);
System.out.printf("Connecting to : %s%n", echoUri);
socket.awaitClose(5, TimeUnit.SECONDS);
} catch (Throwable t) {
t.printStackTrace();
} finally {
try {
client.stop();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}

上面的样例连接到一个远端WebSocket服务端,而且连接后使用一个SimpleEchoSocket履行在websocket上的处理逻辑,等待socket关闭。

实例20 SimpleEchoSocket.java
package examples; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.StatusCode;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
import org.eclipse.jetty.websocket.api.annotations.WebSocket; /**
* Basic Echo Client Socket
*/
@WebSocket(maxTextMessageSize = 64 * 1024)
public class SimpleEchoSocket { private final CountDownLatch closeLatch; @SuppressWarnings("unused")
private Session session; public SimpleEchoSocket() {
this.closeLatch = new CountDownLatch(1);
} public boolean awaitClose(int duration, TimeUnit unit) throws InterruptedException {
return this.closeLatch.await(duration, unit);
} @OnWebSocketClose
public void onClose(int statusCode, String reason) {
System.out.printf("Connection closed: %d - %s%n", statusCode, reason);
this.session = null;
this.closeLatch.countDown();
} @OnWebSocketConnect
public void onConnect(Session session) {
System.out.printf("Got connect: %s%n", session);
this.session = session;
try {
Future<Void> fut;
fut = session.getRemote().sendStringByFuture("Hello");
fut.get(2, TimeUnit.SECONDS);
fut = session.getRemote().sendStringByFuture("Thanks for the conversation.");
fut.get(2, TimeUnit.SECONDS);
session.close(StatusCode.NORMAL, "I'm done");
} catch (Throwable t) {
t.printStackTrace();
}
} @OnWebSocketMessage
public void onMessage(String msg) {
System.out.printf("Got msg: %s%n", msg);
}
}

当SimpleEchoSocket连接成功后,它发送2个文本信息,然后关闭socket。

onMessage(String msg)收到来自远端WebSocket的响应,并输出他们到控制台。

Jetty开发指导:Jetty Websocket API的更多相关文章

  1. Jetty开发指导:WebSocket介绍

    WebSocket是一个新的基于HTTP的双向通讯的协议. 它是基于低级别的框架协议.使用UTF-8 TEXT或者BINARY格式传递信息. 在WebSocket中的单个信息能够是不论什么长度(然而底 ...

  2. Jetty开发指导:HTTP Client

    介绍 Jetty HTTP client模块提供易用的API.工具类和一个高性能.异步的实现来运行HTTP和HTTPS请求. Jetty HTTP client模块要求Java版本号1.7或者更高,J ...

  3. Jetty开发指导:框架

    Spring设置 你能嵌入Jetty到你的项目中,也能够使用差点儿全部的IoC类型框架,包含Spring.假设全部你想做的是在你的Spring中设置Jetty Server,那么以下的xml片段能够作 ...

  4. Jetty:开发指导Handlers

    Rewrite Handler RewriteHandler匹配一个基于该请求的规则集合,然后根据匹配规则的变更请求. 最常见的要求是改写URI.但不限于:规则可以被配置为重定向响应.设置cookie ...

  5. Jetty使用教程(四:24-27)—Jetty开发指南

    二十四.处理器(Handler ) 24.1 编写一个常用的Handler Jetty的Handler组件用来处理接收到的请求. 很多使用者不需要编写Jetty的Handler ,而是通过使用Serv ...

  6. Jetty使用教程(四:23)—Jetty开发指南

    二十三.Maven和Jetty 这一章节将说明如何通过Maven管理Jetty和使用Jetty的Maven插件. 23.1 使用Maven Apache Maven是一个款软件项目管理工具.基于项目对 ...

  7. Jetty使用教程(四:21-22)—Jetty开发指南

    二十一.嵌入式开发 21.1 Jetty嵌入式开发HelloWorld 本章节将提供一些教程,通过Jetty API快速开发嵌入式代码 21.1.1 下载Jetty的jar包 Jetty目前已经把所有 ...

  8. Jetty 开发指南: 嵌入式开发之HelloWorld

    Jetty 嵌入式之 HelloWorld 本节提供一个教程,演示如何快速开发针对Jetty API的嵌入式代码. 1. 下载 Jar 包 Jetty被分解为许多jar和依赖项,通过选择最小的jar集 ...

  9. Jetty 开发指南:Jetty 内嵌开发

    Jetty的口号是“不要在Jetty中部署你的应用程序,在你的应用程序中部署Jetty!” 这意味着,作为将应用程序捆绑为要部署在Jetty中的标准WAR的替代方案,Jetty旨在成为一个软件组件,可 ...

随机推荐

  1. java 控制表项删除、编辑、添加(实现接口)

    package com.platformda.optimize; import java.awt.BorderLayout; import java.awt.Point; import java.aw ...

  2. asp.net web api帮助文档的说明

    为asp.net的mvc web api填写自己的帮助文档 1. 加入Help的area(能够通过命令行或其它方式加入) 命令行:Install-Package Microsoft.AspNet.We ...

  3. POJ 1330 Nearest Common Ancestors(Tarjan离线LCA)

    Description A rooted tree is a well-known data structure in computer science and engineering. An exa ...

  4. 14.2.5.6 Adaptive Hash Indexes 自适应Hash Indexes

    14.2.5.6 Adaptive Hash Indexes 自适应Hash Indexes adaptive hash index(AHI) 让InnoDB 执行更加像在一个内存数据库里在, 在不牺 ...

  5. 这里的*号实际表示就是RAC中所有实例都使用

    您的位置: ITPUB个人空间 » cc59的个人空间 » 日志 发布新日志 我的日志我的足迹我的收藏 unix/linuxHA随笔backup&restoreperformance tuni ...

  6. OMR数据查询

    查询 1.查询所有的. var query = from p in _Context.Info select p; var query = _Context.Info; 2.单条件查询 等值查 var ...

  7. 生产者、消费者 C源码,gcc编译通过

    /*生产者.消费者*/ #include<stdio.h> #include<pthread.h> #define BUFFER_SIZE 16 /***struct prod ...

  8. LeetCode——Populating Next Right Pointers in Each Node II

    Follow up for problem "Populating Next Right Pointers in Each Node". What if the given tre ...

  9. 使用Android简单实现有道电子词典

    前言: 毕业设计的内容,仅仅有Java基础.没学过Android. 本着用到什么学什么.花费了10多个晚上完毕毕业设计. 当然,仅仅是简单的实线了电子词典功能,自始至终没有考虑过性能等问题. 本电子词 ...

  10. A Game of Thrones(19) - Jon

    The courtyard rang to the song of swords. Under black wool, boiled leather, and mail, sweat trickled ...