Netty In Action中文版 - 第十一章:WebSocket

本篇博客介绍如何利用 Netty 实现基于 WebSocket 的实时聊天应用,详细解释了 WebSocket 协议的基本概念、实现步骤及关键代码示例。

http://blog.youkuaiyun.com/abc_key/article/details/38323737

本章介绍

  • WebSocket
  • ChannelHandler,Decoder and Encoder
  • 引导一个Netty基础程序
  • 测试WebSocket
        “real-time-web”实时web现在随处可见,很多的用户希望能从web站点实时获取信息。Netty支持WebSocket实现,并包含了不同的版本,我们可以非常容易的实现WebSocket应用。使用Netty附带的WebSocket,我们不需要关注协议内部实现,只需要使用Netty提供的一些简单的方法就可以实现。本章将通过的例子应用帮助你来使用WebSocket并了解它是如何工作。

11.1 WebSockets some background

        关于WebSocket的一些概念和背景,可以查询网上相关介绍。这里不赘述。

11.2 面临的挑战

        要显示“real-time”支持的WebSocket,应用程序将显示如何使用Netty中的WebSocket实现一个在浏览器中进行聊天的IRC应用程序。你可能知道从Facebook可以发送文本消息到另一个人,在这里,我们将进一步了解其实现。在这个应用程序中,不同的用户可以同时交谈,非常像IRC(Internet Relay Chat,互联网中继聊天)。

上图显示的逻辑很简单:
  1. 一个客户端发送一条消息
  2. 消息被广播到其他已连接的客户端
        它的工作原理就像聊天室一样,在这里例子中,我们将编写服务器,然后使用浏览器作为客户端。带着这样的思路,我们将会很简单的实现它。

11.3 实现

        WebSocket使用HTTP升级机制从一个普通的HTTP连接WebSocket,因为这个应用程序使用WebSocket总是开始于HTTP(s),然后再升级。什么时候升级取决于应用程序本身。直接执行升级作为第一个操作一般是使用特定的url请求。
        在这里,如果url的结尾以/ws结束,我们将只会升级到WebSocket,否则服务器将发送一个网页给客户端。升级后的连接将通过WebSocket传输所有数据。逻辑图如下:

11.3.1 处理http请求

        服务器将作为一种混合式以允许同时处理http和websocket,所以服务器还需要html页面,html用来充当客户端角色,连接服务器并交互消息。因此,如果客户端不发送/ws的uri,我们需要写一个ChannelInboundHandler用来处理FullHttpRequest。看下面代码:
package netty.in.action;

import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.DefaultFileRegion;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.DefaultHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.codec.http.LastHttpContent;
import io.netty.handler.ssl.SslHandler;
import io.netty.handler.stream.ChunkedNioFile;

import java.io.RandomAccessFile;

/**
 * WebSocket,处理http请求
 * 
 * @author c.k
 * 
 */
public class HttpRequestHandler extends
		SimpleChannelInboundHandler<FullHttpRequest> {
	//websocket标识
	private final String wsUri;

	public HttpRequestHandler(String wsUri) {
		this.wsUri = wsUri;
	}

	@Override
	protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest msg)
			throws Exception {
		//如果是websocket请求,请求地址uri等于wsuri
		if (wsUri.equalsIgnoreCase(msg.getUri())) {
			//将消息转发到下一个ChannelHandler
			ctx.fireChannelRead(msg.retain());
		} else {//如果不是websocket请求
			if (HttpHeaders.is100ContinueExpected(msg)) {
				//如果HTTP请求头部包含Expect: 100-continue,
				//则响应请求
				FullHttpResponse response = new DefaultFullHttpResponse(
						HttpVersion.HTTP_1_1, HttpResponseStatus.CONTINUE);
				ctx.writeAndFlush(response);
			}
			//获取index.html的内容响应给客户端
			RandomAccessFile file = new RandomAccessFile(
					System.getProperty("user.dir") + "/index.html", "r");
			HttpResponse response = new DefaultHttpResponse(
					msg.getProtocolVersion(), HttpResponseStatus.OK);
			response.headers().set(HttpHeaders.Names.CONTENT_TYPE,
					"text/html; charset=UTF-8");
			boolean keepAlive = HttpHeaders.isKeepAlive(msg);
			//如果http请求保持活跃,设置http请求头部信息
			//并响应请求
			if (keepAlive) {
				response.headers().set(HttpHeaders.Names.CONTENT_LENGTH,
						file.length());
				response.headers().set(HttpHeaders.Names.CONNECTION,
						HttpHeaders.Values.KEEP_ALIVE);
			}
			ctx.write(response);
			//如果不是https请求,将index.html内容写入通道
			if (ctx.pipeline().get(SslHandler.class) == null) {
				ctx.write(new DefaultFileRegion(file.getChannel(), 0, file
						.length()));
			} else {
				ctx.write(new ChunkedNioFile(file.getChannel()));
			}
			//标识响应内容结束并刷新通道
			ChannelFuture future = ctx
					.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);
			if (!keepAlive) {
				//如果http请求不活跃,关闭http连接
				future.addListener(ChannelFutureListener.CLOSE);
			}
			file.close();
		}
	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
			throws Exception {
		cause.printStackTrace();
		ctx.close();
	}
}

11.3.2 处理WebSocket框架

        WebSocket支持6种不同框架,如下图:

我们的程序只需要使用下面4个框架:
  • CloseWebSocketFrame
  • PingWebSocketFrame
  • PongWebSocketFrame
  • TextWebSocketFrame
        我们只需要显示处理TextWebSocketFrame,其他的会自动由WebSocketServerProtocolHandler处理,看下面代码:
package netty.in.action;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;

/**
 * WebSocket,处理消息
 * @author c.k
 *
 */
public class TextWebSocketFrameHandler extends
		SimpleChannelInboundHandler<TextWebSocketFrame> {
	private final ChannelGroup group;

	public TextWebSocketFrameHandler(ChannelGroup group) {
		this.group = group;
	}

	@Override
	public void userEventTriggered(ChannelHandlerContext ctx, Object evt)
			throws Exception {
		//如果WebSocket握手完成
		if (evt == WebSocketServerProtocolHandler.ServerHandshakeStateEvent.HANDSHAKE_COMPLETE) {
			//删除ChannelPipeline中的HttpRequestHandler
			ctx.pipeline().remove(HttpRequestHandler.class);
			//写一个消息到ChannelGroup
			group.writeAndFlush(new TextWebSocketFrame("Client " + ctx.channel()
					+ " joined"));
			//将Channel添加到ChannelGroup
			group.add(ctx.channel());
		}else {
			super.userEventTriggered(ctx, evt);
		}
	}

	@Override
	protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg)
			throws Exception {
		//将接收的消息通过ChannelGroup转发到所以已连接的客户端
		group.writeAndFlush(msg.retain());
	}
}

11.3.3 初始化ChannelPipeline

        看下面代码:
package netty.in.action;

import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.group.ChannelGroup;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.stream.ChunkedWriteHandler;

/**
 * WebSocket,初始化ChannelHandler
 * @author c.k
 *
 */
public class ChatServerInitializer extends ChannelInitializer<Channel> {
	private final ChannelGroup group;
	
	public ChatServerInitializer(ChannelGroup group){
		this.group = group;
	}

	@Override
	protected void initChannel(Channel ch) throws Exception {
		ChannelPipeline pipeline = ch.pipeline();
		//编解码http请求
		pipeline.addLast(new HttpServerCodec());
		//写文件内容
		pipeline.addLast(new ChunkedWriteHandler());
		//聚合解码HttpRequest/HttpContent/LastHttpContent到FullHttpRequest
		//保证接收的Http请求的完整性
		pipeline.addLast(new HttpObjectAggregator(64 * 1024));
		//处理FullHttpRequest
		pipeline.addLast(new HttpRequestHandler("/ws"));
		//处理其他的WebSocketFrame
		pipeline.addLast(new WebSocketServerProtocolHandler("/ws"));
		//处理TextWebSocketFrame
		pipeline.addLast(new TextWebSocketFrameHandler(group));
	}

}
        WebSocketServerProtcolHandler不仅处理Ping/Pong/CloseWebSocketFrame,还和它自己握手并帮助升级WebSocket。这是执行完成握手和成功修改ChannelPipeline,并且添加需要的编码器/解码器和删除不需要的ChannelHandler。
        看下图:

        ChannelPipeline通过ChannelInitializer的initChannel(...)方法完成初始化,完成握手后就会更改事情。一旦这样做了,WebSocketServerProtocolHandler将取代HttpRequestDecoder、WebSocketFrameDecoder13和HttpResponseEncoder、WebSocketFrameEncoder13。另外也要删除所有不需要的ChannelHandler已获得最佳性能。这些都是HttpObjectAggregator和HttpRequestHandler。下图显示ChannelPipeline握手完成:

        我们甚至没注意到它,因为它是在底层执行的。以非常灵活的方式动态更新ChannelPipeline让单独的任务在不同的ChannelHandler中实现。

11.4 结合在一起使用

        一如既往,我们要将它们结合在一起使用。使用Bootstrap引导服务器和设置正确的ChannelInitializer。看下面代码:
package netty.in.action;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.util.concurrent.ImmediateEventExecutor;

import java.net.InetSocketAddress;

/**
 * 访问地址:http://localhost:2048
 * 
 * @author c.k
 * 
 */
public class ChatServer {

	private final ChannelGroup group = new DefaultChannelGroup(
			ImmediateEventExecutor.INSTANCE);
	private final EventLoopGroup workerGroup = new NioEventLoopGroup();
	private Channel channel;

	public ChannelFuture start(InetSocketAddress address) {
		ServerBootstrap b = new ServerBootstrap();
		b.group(workerGroup).channel(NioServerSocketChannel.class)
				.childHandler(createInitializer(group));
		ChannelFuture f = b.bind(address).syncUninterruptibly();
		channel = f.channel();
		return f;
	}

	public void destroy() {
		if (channel != null)
			channel.close();
		group.close();
		workerGroup.shutdownGracefully();
	}

	protected ChannelInitializer<Channel> createInitializer(ChannelGroup group) {
		return new ChatServerInitializer(group);
	}

	public static void main(String[] args) {
		final ChatServer server = new ChatServer();
		ChannelFuture f = server.start(new InetSocketAddress(2048));
		Runtime.getRuntime().addShutdownHook(new Thread() {
			@Override
			public void run() {
				server.destroy();
			}
		});
		f.channel().closeFuture().syncUninterruptibly();
	}

}


另外,需要将index.html文件放在项目根目录,index.html内容如下:
<html>
<head>
<title>Web Socket Test</title>
</head>
<body>
<script type="text/javascript">
var socket;
if (!window.WebSocket) {
  window.WebSocket = window.MozWebSocket;
}
if (window.WebSocket) {
  socket = new WebSocket("ws://localhost:2048/ws");
  socket.onmessage = function(event) {
    var ta = document.getElementById('responseText');
    ta.value = ta.value + '\n' + event.data
  };
  socket.onopen = function(event) {
    var ta = document.getElementById('responseText');
    ta.value = "Web Socket opened!";
  };
  socket.onclose = function(event) {
    var ta = document.getElementById('responseText');
    ta.value = ta.value + "Web Socket closed"; 
  };
} else {
  alert("Your browser does not support Web Socket.");
}

function send(message) {
  if (!window.WebSocket) { return; }
  if (socket.readyState == WebSocket.OPEN) {
    socket.send(message);
  } else {
    alert("The socket is not open.");
  }
}
</script>
	<form onsubmit="return false;">
		<input type="text" name="message" value="Hello, World!"><input
			type="button" value="Send Web Socket Data"
			onclick="send(this.form.message.value)">
		<h3>Output</h3>
		<textarea id="responseText" style="width: 500px; height: 300px;"></textarea>
	</form>
</body>
</html>
最后在浏览器中输入:http://localhost:2048,多开几个窗口就可以聊天了。

11.5 给WebSocket加密

        上面的应用程序虽然工作的很好,但是在网络上收发消息存在很大的安全隐患,所以有必要对消息进行加密。添加这样一个加密的功能一般比较复杂,需要对代码有较大的改动。但是使用Netty就可以很容易的添加这样的功能,只需要将SslHandler加入到ChannelPipeline中就可以了。实际上还需要添加SslContext,但这不在本例子范围内。
        首先我们创建一个用于添加加密Handler的handler初始化类,看下面代码:
package netty.in.action;

import io.netty.channel.Channel;
import io.netty.channel.group.ChannelGroup;
import io.netty.handler.ssl.SslHandler;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;

public class SecureChatServerIntializer extends ChatServerInitializer {
	private final SSLContext context;

	public SecureChatServerIntializer(ChannelGroup group,SSLContext context) {
		super(group);
		this.context = context;
	}

	@Override
	protected void initChannel(Channel ch) throws Exception {
		super.initChannel(ch);
		SSLEngine engine = context.createSSLEngine();
		engine.setUseClientMode(false);
		ch.pipeline().addFirst(new SslHandler(engine));
	}
}
        最后我们创建一个用于引导配置的类,看下面代码:
package netty.in.action;

import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.group.ChannelGroup;
import java.net.InetSocketAddress;
import javax.net.ssl.SSLContext;

/**
 * 访问地址:https://localhost:4096
 * 
 * @author c.k
 * 
 */
public class SecureChatServer extends ChatServer {
	private final SSLContext context;

	public SecureChatServer(SSLContext context) {
		this.context = context;
	}

	@Override
	protected ChannelInitializer<Channel> createInitializer(ChannelGroup group) {
		return new SecureChatServerIntializer(group, context);
	}

	/**
	 * 获取SSLContext需要相关的keystore文件,这里没有 关于HTTPS可以查阅相关资料,这里只介绍在Netty中如何使用
	 * 
	 * @return
	 */
	private static SSLContext getSslContext() {
		return null;
	}

	public static void main(String[] args) {
		SSLContext context = getSslContext();
		final SecureChatServer server = new SecureChatServer(context);
		ChannelFuture future = server.start(new InetSocketAddress(4096));
		Runtime.getRuntime().addShutdownHook(new Thread() {
			@Override
			public void run() {
				server.destroy();
			}
		});
		future.channel().closeFuture().syncUninterruptibly();
	}
}

11.6 Summary

springboot项目配置多数据源时,启动项目出现以下异常,请分析原因,并给出解决办法:D:\sofeware\jdk\jdk1.8\bin\java.exe -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:1522,suspend=y,server=n -XX:TieredStopAtLevel=1 -noverify -Dspring.output.ansi.enabled=always -Dcom.sun.management.jmxremote -Dspring.jmx.enabled=true -Dspring.liveBeansView.mbeanDomain -Dspring.application.admin.enabled=true -javaagent:C:\Users\Wyh\AppData\Local\JetBrains\IntelliJIdea2022.1\captureAgent\debugger-agent.jar -Dfile.encoding=UTF-8 -classpath "D:\sofeware\jdk\jdk1.8\jre\lib\charsets.jar;D:\sofeware\jdk\jdk1.8\jre\lib\deploy.jar;D:\sofeware\jdk\jdk1.8\jre\lib\ext\access-bridge-64.jar;D:\sofeware\jdk\jdk1.8\jre\lib\ext\cldrdata.jar;D:\sofeware\jdk\jdk1.8\jre\lib\ext\dnsns.jar;D:\sofeware\jdk\jdk1.8\jre\lib\ext\jaccess.jar;D:\sofeware\jdk\jdk1.8\jre\lib\ext\jfxrt.jar;D:\sofeware\jdk\jdk1.8\jre\lib\ext\localedata.jar;D:\sofeware\jdk\jdk1.8\jre\lib\ext\nashorn.jar;D:\sofeware\jdk\jdk1.8\jre\lib\ext\sunec.jar;D:\sofeware\jdk\jdk1.8\jre\lib\ext\sunjce_provider.jar;D:\sofeware\jdk\jdk1.8\jre\lib\ext\sunmscapi.jar;D:\sofeware\jdk\jdk1.8\jre\lib\ext\sunpkcs11.jar;D:\sofeware\jdk\jdk1.8\jre\lib\ext\zipfs.jar;D:\sofeware\jdk\jdk1.8\jre\lib\javaws.jar;D:\sofeware\jdk\jdk1.8\jre\lib\jce.jar;D:\sofeware\jdk\jdk1.8\jre\lib\jfr.jar;D:\sofeware\jdk\jdk1.8\jre\lib\jfxswt.jar;D:\sofeware\jdk\jdk1.8\jre\lib\jsse.jar;D:\sofeware\jdk\jdk1.8\jre\lib\management-agent.jar;D:\sofeware\jdk\jdk1.8\jre\lib\plugin.jar;D:\sofeware\jdk\jdk1.8\jre\lib\resources.jar;D:\sofeware\jdk\jdk1.8\jre\lib\rt.jar;D:\workspace\gssf-sjh-project\wisesys\taiji-system\target\classes;D:\sofeware\maven\dm-repository\org\springframework\cloud\spring-cloud-starter-bootstrap\3.1.1\spring-cloud-starter-bootstrap-3.1.1.jar;D:\sofeware\maven\dm-repository\org\springframework\cloud\spring-cloud-starter\3.1.1\spring-cloud-starter-3.1.1.jar;D:\sofeware\maven\dm-repository\org\springframework\security\spring-security-rsa\1.0.10.RELEASE\spring-security-rsa-1.0.10.RELEASE.jar;D:\sofeware\maven\dm-repository\org\bouncycastle\bcpkix-jdk15on\1.68\bcpkix-jdk15on-1.68.jar;D:\sofeware\maven\dm-repository\org\bouncycastle\bcprov-jdk15on\1.68\bcprov-jdk15on-1.68.jar;D:\sofeware\maven\dm-repository\org\springframework\cloud\spring-cloud-starter-loadbalancer\3.1.1\spring-cloud-starter-loadbalancer-3.1.1.jar;D:\sofeware\maven\dm-repository\org\springframework\cloud\spring-cloud-loadbalancer\3.1.1\spring-cloud-loadbalancer-3.1.1.jar;D:\sofeware\maven\dm-repository\io\projectreactor\reactor-core\3.4.14\reactor-core-3.4.14.jar;D:\sofeware\maven\dm-repository\org\reactivestreams\reactive-streams\1.0.3\reactive-streams-1.0.3.jar;D:\sofeware\maven\dm-repository\io\projectreactor\addons\reactor-extra\3.4.6\reactor-extra-3.4.6.jar;D:\sofeware\maven\dm-repository\org\springframework\boot\spring-boot-starter-cache\2.6.3\spring-boot-starter-cache-2.6.3.jar;D:\sofeware\maven\dm-repository\org\springframework\spring-context-support\5.3.15\spring-context-support-5.3.15.jar;D:\sofeware\maven\dm-repository\com\stoyanr\evictor\1.0.0\evictor-1.0.0.jar;D:\sofeware\maven\dm-repository\com\alibaba\cloud\spring-cloud-starter-alibaba-nacos-discovery\2021.0.1.0\spring-cloud-starter-alibaba-nacos-discovery-2021.0.1.0.jar;D:\sofeware\maven\dm-repository\com\alibaba\cloud\spring-cloud-alibaba-commons\2021.0.1.0\spring-cloud-alibaba-commons-2021.0.1.0.jar;D:\sofeware\maven\dm-repository\com\alibaba\nacos\nacos-client\1.4.2\nacos-client-1.4.2.jar;D:\sofeware\maven\dm-repository\com\alibaba\nacos\nacos-common\1.4.2\nacos-common-1.4.2.jar;D:\sofeware\maven\dm-repository\org\apache\httpcomponents\httpasyncclient\4.1.5\httpasyncclient-4.1.5.jar;D:\sofeware\maven\dm-repository\org\apache\httpcomponents\httpcore\4.4.15\httpcore-4.4.15.jar;D:\sofeware\maven\dm-repository\org\apache\httpcomponents\httpcore-nio\4.4.15\httpcore-nio-4.4.15.jar;D:\sofeware\maven\dm-repository\org\apache\httpcomponents\httpclient\4.5.13\httpclient-4.5.13.jar;D:\sofeware\maven\dm-repository\com\alibaba\nacos\nacos-api\1.4.2\nacos-api-1.4.2.jar;D:\sofeware\maven\dm-repository\io\prometheus\simpleclient\0.12.0\simpleclient-0.12.0.jar;D:\sofeware\maven\dm-repository\io\prometheus\simpleclient_tracer_otel\0.12.0\simpleclient_tracer_otel-0.12.0.jar;D:\sofeware\maven\dm-repository\io\prometheus\simpleclient_tracer_common\0.12.0\simpleclient_tracer_common-0.12.0.jar;D:\sofeware\maven\dm-repository\io\prometheus\simpleclient_tracer_otel_agent\0.12.0\simpleclient_tracer_otel_agent-0.12.0.jar;D:\sofeware\maven\dm-repository\org\yaml\snakeyaml\1.29\snakeyaml-1.29.jar;D:\sofeware\maven\dm-repository\com\alibaba\spring\spring-context-support\1.0.11\spring-context-support-1.0.11.jar;D:\sofeware\maven\dm-repository\org\springframework\cloud\spring-cloud-commons\3.1.1\spring-cloud-commons-3.1.1.jar;D:\sofeware\maven\dm-repository\org\springframework\security\spring-security-crypto\5.6.1\spring-security-crypto-5.6.1.jar;D:\sofeware\maven\dm-repository\org\springframework\cloud\spring-cloud-context\3.1.1\spring-cloud-context-3.1.1.jar;D:\sofeware\maven\dm-repository\com\alibaba\cloud\spring-cloud-starter-alibaba-nacos-config\2021.0.1.0\spring-cloud-starter-alibaba-nacos-config-2021.0.1.0.jar;D:\sofeware\maven\dm-repository\org\springframework\boot\spring-boot-starter-web\2.6.3\spring-boot-starter-web-2.6.3.jar;D:\sofeware\maven\dm-repository\org\springframework\boot\spring-boot-starter\2.6.3\spring-boot-starter-2.6.3.jar;D:\sofeware\maven\dm-repository\org\springframework\boot\spring-boot\2.6.3\spring-boot-2.6.3.jar;D:\sofeware\maven\dm-repository\org\springframework\boot\spring-boot-starter-logging\2.6.3\spring-boot-starter-logging-2.6.3.jar;D:\sofeware\maven\dm-repository\ch\qos\logback\logback-classic\1.2.9\logback-classic-1.2.9.jar;D:\sofeware\maven\dm-repository\ch\qos\logback\logback-core\1.2.10\logback-core-1.2.10.jar;D:\sofeware\maven\dm-repository\org\slf4j\jul-to-slf4j\1.7.33\jul-to-slf4j-1.7.33.jar;D:\sofeware\maven\dm-repository\jakarta\annotation\jakarta.annotation-api\1.3.5\jakarta.annotation-api-1.3.5.jar;D:\sofeware\maven\dm-repository\org\springframework\spring-core\5.3.15\spring-core-5.3.15.jar;D:\sofeware\maven\dm-repository\org\springframework\spring-jcl\5.3.15\spring-jcl-5.3.15.jar;D:\sofeware\maven\dm-repository\org\springframework\boot\spring-boot-starter-json\2.6.3\spring-boot-starter-json-2.6.3.jar;D:\sofeware\maven\dm-repository\com\fasterxml\jackson\datatype\jackson-datatype-jdk8\2.13.1\jackson-datatype-jdk8-2.13.1.jar;D:\sofeware\maven\dm-repository\com\fasterxml\jackson\datatype\jackson-datatype-jsr310\2.13.1\jackson-datatype-jsr310-2.13.1.jar;D:\sofeware\maven\dm-repository\com\fasterxml\jackson\module\jackson-module-parameter-names\2.13.1\jackson-module-parameter-names-2.13.1.jar;D:\sofeware\maven\dm-repository\org\springframework\boot\spring-boot-starter-tomcat\2.6.3\spring-boot-starter-tomcat-2.6.3.jar;D:\sofeware\maven\dm-repository\org\apache\tomcat\embed\tomcat-embed-core\9.0.56\tomcat-embed-core-9.0.56.jar;D:\sofeware\maven\dm-repository\org\apache\tomcat\embed\tomcat-embed-el\9.0.56\tomcat-embed-el-9.0.56.jar;D:\sofeware\maven\dm-repository\org\apache\tomcat\embed\tomcat-embed-websocket\9.0.56\tomcat-embed-websocket-9.0.56.jar;D:\sofeware\maven\dm-repository\org\springframework\spring-web\5.3.15\spring-web-5.3.15.jar;D:\sofeware\maven\dm-repository\org\springframework\spring-beans\5.3.15\spring-beans-5.3.15.jar;D:\sofeware\maven\dm-repository\org\springframework\spring-webmvc\5.3.15\spring-webmvc-5.3.15.jar;D:\sofeware\maven\dm-repository\org\springframework\spring-aop\5.3.15\spring-aop-5.3.15.jar;D:\sofeware\maven\dm-repository\org\springframework\spring-context\5.3.15\spring-context-5.3.15.jar;D:\sofeware\maven\dm-repository\org\springframework\spring-expression\5.3.15\spring-expression-5.3.15.jar;D:\sofeware\maven\dm-repository\mysql\mysql-connector-java\8.0.27\mysql-connector-java-8.0.27.jar;D:\sofeware\maven\dm-repository\com\google\protobuf\protobuf-java\3.11.4\protobuf-java-3.11.4.jar;D:\workspace\gssf-sjh-project\wisesys\taiji-common\taiji-common-datascope\target\classes;D:\workspace\gssf-sjh-project\wisesys\taiji-common\taiji-common-security\target\classes;D:\workspace\gssf-sjh-project\wisesys\taiji-common\taiji-common-log\target\classes;D:\workspace\gssf-sjh-project\wisesys\taiji-common\taiji-common-redis\target\classes;D:\sofeware\maven\dm-repository\org\springframework\boot\spring-boot-starter-data-redis\2.6.3\spring-boot-starter-data-redis-2.6.3.jar;D:\sofeware\maven\dm-repository\org\springframework\data\spring-data-redis\2.6.1\spring-data-redis-2.6.1.jar;D:\sofeware\maven\dm-repository\org\springframework\data\spring-data-keyvalue\2.6.1\spring-data-keyvalue-2.6.1.jar;D:\sofeware\maven\dm-repository\org\springframework\data\spring-data-commons\2.6.1\spring-data-commons-2.6.1.jar;D:\sofeware\maven\dm-repository\org\springframework\spring-tx\5.3.15\spring-tx-5.3.15.jar;D:\sofeware\maven\dm-repository\org\springframework\spring-oxm\5.3.15\spring-oxm-5.3.15.jar;D:\sofeware\maven\dm-repository\io\lettuce\lettuce-core\6.1.6.RELEASE\lettuce-core-6.1.6.RELEASE.jar;D:\sofeware\maven\dm-repository\io\netty\netty-common\4.1.73.Final\netty-common-4.1.73.Final.jar;D:\sofeware\maven\dm-repository\io\netty\netty-handler\4.1.73.Final\netty-handler-4.1.73.Final.jar;D:\sofeware\maven\dm-repository\io\netty\netty-resolver\4.1.73.Final\netty-resolver-4.1.73.Final.jar;D:\sofeware\maven\dm-repository\io\netty\netty-buffer\4.1.73.Final\netty-buffer-4.1.73.Final.jar;D:\sofeware\maven\dm-repository\io\netty\netty-codec\4.1.73.Final\netty-codec-4.1.73.Final.jar;D:\sofeware\maven\dm-repository\io\netty\netty-tcnative-classes\2.0.46.Final\netty-tcnative-classes-2.0.46.Final.jar;D:\sofeware\maven\dm-repository\io\netty\netty-transport\4.1.73.Final\netty-transport-4.1.73.Final.jar;D:\workspace\gssf-sjh-project\wisesys\taiji-common\taiji-common-core\target\classes;D:\sofeware\maven\dm-repository\org\springframework\cloud\spring-cloud-starter-openfeign\3.1.1\spring-cloud-starter-openfeign-3.1.1.jar;D:\sofeware\maven\dm-repository\org\springframework\cloud\spring-cloud-openfeign-core\3.1.1\spring-cloud-openfeign-core-3.1.1.jar;D:\sofeware\maven\dm-repository\org\springframework\boot\spring-boot-starter-aop\2.6.3\spring-boot-starter-aop-2.6.3.jar;D:\sofeware\maven\dm-repository\org\aspectj\aspectjweaver\1.9.7\aspectjweaver-1.9.7.jar;D:\sofeware\maven\dm-repository\io\github\openfeign\form\feign-form-spring\3.8.0\feign-form-spring-3.8.0.jar;D:\sofeware\maven\dm-repository\io\github\openfeign\form\feign-form\3.8.0\feign-form-3.8.0.jar;D:\sofeware\maven\dm-repository\io\github\openfeign\feign-core\11.8\feign-core-11.8.jar;D:\sofeware\maven\dm-repository\io\github\openfeign\feign-slf4j\11.8\feign-slf4j-11.8.jar;D:\sofeware\maven\dm-repository\org\apache\commons\commons-pool2\2.11.1\commons-pool2-2.11.1.jar;D:\sofeware\maven\dm-repository\com\github\pagehelper\pagehelper-spring-boot-starter\1.4.1\pagehelper-spring-boot-starter-1.4.1.jar;D:\sofeware\maven\dm-repository\org\mybatis\spring\boot\mybatis-spring-boot-starter\2.2.2\mybatis-spring-boot-starter-2.2.2.jar;D:\sofeware\maven\dm-repository\org\mybatis\spring\boot\mybatis-spring-boot-autoconfigure\2.2.2\mybatis-spring-boot-autoconfigure-2.2.2.jar;D:\sofeware\maven\dm-repository\org\mybatis\mybatis\3.5.9\mybatis-3.5.9.jar;D:\sofeware\maven\dm-repository\com\github\pagehelper\pagehelper-spring-boot-autoconfigure\1.4.1\pagehelper-spring-boot-autoconfigure-1.4.1.jar;D:\sofeware\maven\dm-repository\com\github\pagehelper\pagehelper\5.3.0\pagehelper-5.3.0.jar;D:\sofeware\maven\dm-repository\com\github\jsqlparser\jsqlparser\4.2\jsqlparser-4.2.jar;D:\sofeware\maven\dm-repository\org\springframework\boot\spring-boot-starter-validation\2.6.3\spring-boot-starter-validation-2.6.3.jar;D:\sofeware\maven\dm-repository\org\hibernate\validator\hibernate-validator\6.2.0.Final\hibernate-validator-6.2.0.Final.jar;D:\sofeware\maven\dm-repository\jakarta\validation\jakarta.validation-api\2.0.2\jakarta.validation-api-2.0.2.jar;D:\sofeware\maven\dm-repository\org\jboss\logging\jboss-logging\3.4.3.Final\jboss-logging-3.4.3.Final.jar;D:\sofeware\maven\dm-repository\org\apache\commons\commons-lang3\3.12.0\commons-lang3-3.12.0.jar;D:\sofeware\maven\dm-repository\commons-io\commons-io\2.5\commons-io-2.5.jar;D:\sofeware\maven\dm-repository\commons-fileupload\commons-fileupload\1.3.3\commons-fileupload-1.3.3.jar;D:\sofeware\maven\dm-repository\commons-beanutils\commons-beanutils\1.9.3\commons-beanutils-1.9.3.jar;D:\sofeware\maven\dm-repository\commons-collections\commons-collections\3.2.2\commons-collections-3.2.2.jar;D:\sofeware\maven\dm-repository\cn\hutool\hutool-all\5.2.3\hutool-all-5.2.3.jar;D:\sofeware\maven\dm-repository\org\projectlombok\lombok\1.18.22\lombok-1.18.22.jar;D:\sofeware\maven\dm-repository\com\alibaba\fastjson\1.2.83\fastjson-1.2.83.jar;D:\sofeware\maven\dm-repository\dom4j\dom4j\1.6.1\dom4j-1.6.1.jar;D:\sofeware\maven\dm-repository\xml-apis\xml-apis\1.0.b2\xml-apis-1.0.b2.jar;D:\sofeware\maven\dm-repository\org\postgresql\postgresql\42.2.25\postgresql-42.2.25.jar;D:\sofeware\maven\dm-repository\org\checkerframework\checker-qual\3.5.0\checker-qual-3.5.0.jar;D:\sofeware\maven\dm-repository\com\newtec\license\2.3.0\license-2.3.0.jar;D:\sofeware\maven\dm-repository\com\dm\DmJdbcDriver\1.8.0\DmJdbcDriver-1.8.0.jar;D:\sofeware\maven\dm-repository\io\minio\minio\8.0.3\minio-8.0.3.jar;D:\sofeware\maven\dm-repository\com\carrotsearch\thirdparty\simple-xml-safe\2.7.1\simple-xml-safe-2.7.1.jar;D:\sofeware\maven\dm-repository\com\google\guava\guava\29.0-jre\guava-29.0-jre.jar;D:\sofeware\maven\dm-repository\com\google\guava\failureaccess\1.0.1\failureaccess-1.0.1.jar;D:\sofeware\maven\dm-repository\com\google\guava\listenablefuture\9999.0-empty-to-avoid-conflict-with-guava\listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar;D:\sofeware\maven\dm-repository\com\google\code\findbugs\jsr305\3.0.2\jsr305-3.0.2.jar;D:\sofeware\maven\dm-repository\com\google\errorprone\error_prone_annotations\2.3.4\error_prone_annotations-2.3.4.jar;D:\sofeware\maven\dm-repository\com\google\j2objc\j2objc-annotations\1.3\j2objc-annotations-1.3.jar;D:\sofeware\maven\dm-repository\com\fasterxml\jackson\core\jackson-annotations\2.13.1\jackson-annotations-2.13.1.jar;D:\sofeware\maven\dm-repository\com\fasterxml\jackson\core\jackson-core\2.13.1\jackson-core-2.13.1.jar;D:\sofeware\maven\dm-repository\com\fasterxml\jackson\core\jackson-databind\2.13.1\jackson-databind-2.13.1.jar;D:\sofeware\maven\dm-repository\com\huaweicloud\esdk-obs-java\3.21.11\esdk-obs-java-3.21.11.jar;D:\sofeware\maven\dm-repository\com\jamesmurty\utils\java-xmlbuilder\1.3\java-xmlbuilder-1.3.jar;D:\sofeware\maven\dm-repository\org\apache\logging\log4j\log4j-core\2.17.1\log4j-core-2.17.1.jar;D:\sofeware\maven\dm-repository\org\apache\logging\log4j\log4j-api\2.17.1\log4j-api-2.17.1.jar;D:\sofeware\maven\dm-repository\commons-net\commons-net\3.8.0\commons-net-3.8.0.jar;D:\sofeware\maven\dm-repository\com\squareup\okhttp3\okhttp\4.9.1\okhttp-4.9.1.jar;D:\sofeware\maven\dm-repository\org\jetbrains\kotlin\kotlin-stdlib\1.6.10\kotlin-stdlib-1.6.10.jar;D:\sofeware\maven\dm-repository\org\jetbrains\annotations\13.0\annotations-13.0.jar;D:\sofeware\maven\dm-repository\com\squareup\okio\okio\2.7.0\okio-2.7.0.jar;D:\sofeware\maven\dm-repository\org\jetbrains\kotlin\kotlin-stdlib-common\1.6.10\kotlin-stdlib-common-1.6.10.jar;D:\sofeware\maven\dm-repository\io\springfox\springfox-swagger2\2.9.2\springfox-swagger2-2.9.2.jar;D:\sofeware\maven\dm-repository\io\swagger\swagger-annotations\1.5.20\swagger-annotations-1.5.20.jar;D:\sofeware\maven\dm-repository\io\swagger\swagger-models\1.5.20\swagger-models-1.5.20.jar;D:\sofeware\maven\dm-repository\io\springfox\springfox-spi\2.9.2\springfox-spi-2.9.2.jar;D:\sofeware\maven\dm-repository\io\springfox\springfox-core\2.9.2\springfox-core-2.9.2.jar;D:\sofeware\maven\dm-repository\net\bytebuddy\byte-buddy\1.11.22\byte-buddy-1.11.22.jar;D:\sofeware\maven\dm-repository\io\springfox\springfox-schema\2.9.2\springfox-schema-2.9.2.jar;D:\sofeware\maven\dm-repository\io\springfox\springfox-swagger-common\2.9.2\springfox-swagger-common-2.9.2.jar;D:\sofeware\maven\dm-repository\io\springfox\springfox-spring-web\2.9.2\springfox-spring-web-2.9.2.jar;D:\sofeware\maven\dm-repository\com\fasterxml\classmate\1.5.1\classmate-1.5.1.jar;D:\sofeware\maven\dm-repository\org\slf4j\slf4j-api\1.7.33\slf4j-api-1.7.33.jar;D:\sofeware\maven\dm-repository\org\springframework\plugin\spring-plugin-core\1.2.0.RELEASE\spring-plugin-core-1.2.0.RELEASE.jar;D:\sofeware\maven\dm-repository\org\springframework\plugin\spring-plugin-metadata\1.2.0.RELEASE\spring-plugin-metadata-1.2.0.RELEASE.jar;D:\sofeware\maven\dm-repository\org\mapstruct\mapstruct\1.2.0.Final\mapstruct-1.2.0.Final.jar;D:\sofeware\maven\dm-repository\io\springfox\springfox-swagger-ui\2.9.2\springfox-swagger-ui-2.9.2.jar;D:\sofeware\maven\dm-repository\com\kingbase8\Driver\kingbase8\8.6.0\kingbase8-8.6.0.jar;D:\sofeware\maven\dm-repository\com\dameng\DmJdbcDriver18\8.1.1.193\DmJdbcDriver18-8.1.1.193.jar;D:\sofeware\maven\dm-repository\commons-httpclient\commons-httpclient\3.1\commons-httpclient-3.1.jar;D:\sofeware\maven\dm-repository\commons-logging\commons-logging\1.0.4\commons-logging-1.0.4.jar;D:\sofeware\maven\dm-repository\commons-codec\commons-codec\1.15\commons-codec-1.15.jar;D:\workspace\gssf-sjh-project\wisesys\taiji-system\src\main\lib\gaussdbjdbc.jar;D:\sofeware\maven\dm-repository\com\baomidou\mybatis-plus-boot-starter\3.4.1\mybatis-plus-boot-starter-3.4.1.jar;D:\sofeware\maven\dm-repository\com\baomidou\mybatis-plus\3.4.1\mybatis-plus-3.4.1.jar;D:\sofeware\maven\dm-repository\com\baomidou\mybatis-plus-extension\3.4.1\mybatis-plus-extension-3.4.1.jar;D:\sofeware\maven\dm-repository\com\baomidou\mybatis-plus-core\3.4.1\mybatis-plus-core-3.4.1.jar;D:\sofeware\maven\dm-repository\com\baomidou\mybatis-plus-annotation\3.4.1\mybatis-plus-annotation-3.4.1.jar;D:\sofeware\maven\dm-repository\org\mybatis\mybatis-spring\2.0.5\mybatis-spring-2.0.5.jar;D:\sofeware\maven\dm-repository\org\springframework\boot\spring-boot-autoconfigure\2.6.3\spring-boot-autoconfigure-2.6.3.jar;D:\sofeware\maven\dm-repository\org\springframework\boot\spring-boot-starter-jdbc\2.6.3\spring-boot-starter-jdbc-2.6.3.jar;D:\sofeware\maven\dm-repository\com\zaxxer\HikariCP\4.0.3\HikariCP-4.0.3.jar;D:\sofeware\maven\dm-repository\org\springframework\spring-jdbc\5.3.15\spring-jdbc-5.3.15.jar;D:\sofeware\maven\dm-repository\com\google\code\gson\gson\2.6.2\gson-2.6.2.jar;D:\sofeware\maven\dm-repository\com\alibaba\easyexcel\2.2.7\easyexcel-2.2.7.jar;D:\sofeware\maven\dm-repository\org\apache\poi\poi\3.17\poi-3.17.jar;D:\sofeware\maven\dm-repository\org\apache\commons\commons-collections4\4.4\commons-collections4-4.4.jar;D:\sofeware\maven\dm-repository\org\apache\poi\poi-ooxml\4.1.2\poi-ooxml-4.1.2.jar;D:\sofeware\maven\dm-repository\org\apache\commons\commons-compress\1.19\commons-compress-1.19.jar;D:\sofeware\maven\dm-repository\com\github\virtuald\curvesapi\1.06\curvesapi-1.06.jar;D:\sofeware\maven\dm-repository\org\apache\poi\poi-ooxml-schemas\3.17\poi-ooxml-schemas-3.17.jar;D:\sofeware\maven\dm-repository\org\apache\xmlbeans\xmlbeans\2.6.0\xmlbeans-2.6.0.jar;D:\sofeware\maven\dm-repository\stax\stax-api\1.0.1\stax-api-1.0.1.jar;D:\sofeware\maven\dm-repository\cglib\cglib\3.1\cglib-3.1.jar;D:\sofeware\maven\dm-repository\org\ow2\asm\asm\4.2\asm-4.2.jar;D:\sofeware\maven\dm-repository\org\ehcache\ehcache\3.9.9\ehcache-3.9.9.jar;D:\sofeware\maven\dm-repository\com\alibaba\fastjson2\fastjson2\2.0.52\fastjson2-2.0.52.jar;D:\IDEA2022\IntelliJ IDEA 2022.1.4\lib\idea_rt.jar" com.taiji.TaiJiSystemApplication Connected to the target VM, address: '127.0.0.1:1522', transport: 'socket' . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.6.3) 09:18:40.270 [main] INFO o.a.c.h.Http11NioProtocol - [log,173] - Initializing ProtocolHandler ["http-nio-9201"] 09:18:40.273 [main] INFO o.a.c.c.StandardService - [log,173] - Starting service [Tomcat] 09:18:40.273 [main] INFO o.a.c.c.StandardEngine - [log,173] - Starting Servlet engine: [Apache Tomcat/9.0.56] 09:18:40.350 [main] INFO o.a.c.c.C.[.[.[/] - [log,173] - Initializing Spring embedded WebApplicationContext 09:18:40.835 [main] INFO o.a.c.c.StandardService - [log,173] - Stopping service [Tomcat] 09:18:40.868 [main] ERROR org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter - *************************** APPLICATION FAILED TO START *************************** Description: Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured. Reason: Failed to determine a suitable driver class Action: Consider the following: If you want an embedded database (H2, HSQL or Derby), please put it on the classpath. If you have database settings to be loaded from a particular profile you may need to activate it (the profiles dev are currently active). Disconnected from the target VM, address: '127.0.0.1:1522', transport: 'socket' Process finished with exit code 1
08-20
评论 5
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值