设为首页 收藏本站
查看: 1259|回复: 0

[经验分享] [How Tomcat Works]第1章 一个简单的Web服务器

[复制链接]

尚未签到

发表于 2017-2-10 10:35:09 | 显示全部楼层 |阅读模式
译者 jarfield





博客 http://jarfield.javaeye.com

 
   




  • 超文本传输协议(HTTP


  • HTTP
    请求

  • HTTP
    响应

  • Socket


  • ServerSocket


  • 应用程序


    • HttpServer


    • Request


    • Response


    • 运行应用程序



  • 总结

      本章解释了Java
Web

服务器是如何工作的。Web
服务器又被称为超文本传输
协议(Hypertext Transport  Protocol
, HTTP
)服务器,因为它和客户端(通常是浏览器)使用HTTP
协议进行通信。基于Java

发的Web
服务器都使用到两个重要的类
java.net.Socket

java.net.ServerSocket
, 并通过HTTP
消息完成通信。因此,本章的开头就开始讨论HTTP
和这两个类。然后,继续介绍
本章附带的应用程序。


超文本传输协议
HTTP

      HTTP
协议,允许Web
服务器和浏览器在Internet
上发送和接受数据。HTTP
是一种基于“请求-响应”模式的协议。客户端请求一
个文件(file
),服务器针对该请求给出响应。HTTP
使用可靠的TCP

接——默认端口是80
。HTTP的最初版本是HTTP/0.9
,后来被HTTP/1.0

写。HTTP/1.0
的替代者是当前的HTTP/1.1
HTTP/1.1

义在RFC 2612
中,可以从
http://www.w3.org/Protocols/HTTP/1.1/rfc2616.pdf
下载。

  

    提示:本节只是简短地介绍HTTP
,目的是帮助你理解Web

务器发送的HTTP
消息。如果你想更深入得了解HTTP
,可以读读RFC
2616






    HTTP

通信总是由客户端主动初始化:建立连接并发送HTTP
请求。Web
服务器从来不主动联系(contact

客户端,或者建立到客户端的回调(callback
)连接。无论客户端还是服务器,都可以随时(prematurely
)中断连接。例如,当你在下载文件时,点击浏览器的“停止”按钮,就关闭了浏览器和服务器之间的HTTP

接。



HTTP
请求

      HTTP
请求包含3
个组成部分:



  • Method-Uniform
    Resource Identifier (URI)-Protocol/Version

  • Request headers
    (请求头部)

  • Entity body
    (实体主体)
      下面是HTTP
请求的一个例子:


    POST /examples/default.jsp HTTP/1.1
Accept: text/plain; text/html
Accept-Language: en-gb
Connection: Keep-Alive
Host: localhost
User-Agent: Mozilla/4.0 (compatible; MSIE 4.01; Windows 98)
Content-Length: 33
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip, deflate
lastName=Franks&firstName=Michael
      Method-URI-Protocol/Version
是请求的第一行


POST /examples/default.jsp HTTP/1.1
      POST
Method
/examples/default.jsp
URI
HTTP/1.1
就是Protocol/Version



    每个HTTP
请求都可以使用HTTP

准中众多Method
中的一个。HTTP/1.1
共支持7
Method
: GET
,
POST
, HEAD
,
OPTIONS
, PUT
, DELETE
TRACE
GET
POST
是互联网应用使用最普遍的Method



     URI

识了互联网上的资源。URI
的解析通常都是相对与服务器根目录的。因此,URI
总是从正斜线/

始。统一资源定位器(Uniform Resource Locator
, URL
)实际上是一种URI
(参

http://www.ietf.org/rfc/rfc2396.txt
)。Protocol
version

表示使用了哪个版本的HTTP
协议。


    Request header
包含了关于客户端环境和entity body的有用信息
。例如,headers
可能包括浏览器的语言,entity body

长度等等。Header
之间通过回车/换行符(CRLF
)分隔。


    在headers
entity body

间,是一个空行(CRLF
)。这个CRLF
对于HTTP
请求内容的格式是相当重要的,它告诉HTTP
服务器:entify body
从哪开始。在一些介绍互联网编程的书中,该CRLF
被认为是HTTP
请求的第4
个组成部分。


    在前面的HTTP
请求中,entify
body

仅仅只有这一行:


    lastName=Franks&firstName=Michael
  
   
这里只是一个例子,实际的HTTP
请求中,entity body
当然可以更长一些。



HTTP
响应

      和HTTP请求一样,HTTP
响应也包含3
个组成部分:




  • Protocol—Status
    code—Description

     

  • Response
    headers

    (响应头部)

  • Entity body
    (实
    体主体)
      下面是HTTP

应的一个例子:


    HTTP/1.1 200 OK
Server: Microsoft-IIS/4.0
Date: Mon, 5 Jan 2004 13:13:33 GMT
Content-Type: text/html
Last-Modified: Mon, 5 Jan 2004 13:13:12 GMT
Content-Length: 112
<html>
<head>
<title>HTTP Response Example</title>
</head>
<body>
Welcome to Brainy Software
</body>
</html>
      HTTP
响应的第一行类似于HTTP
请求的第一行。第一行告诉你:使用的HTTP
版本是HTTP/1.1
,请求处理成功了(200
= 成功),一切运行正常。


    响应headers
和请求headers
类似,包含了很多有用的信息。响应数据中的entity body
是响应本身的HTML
内容。Headers
entity body
之间通过CRLF
分隔。



Socket

      套接字是网络连接的一个端点(endpoint
)。
应用程序使用套接字从网络上读取数据、向网络写入数据。两台不同机器上的应用,在同一个连接上以字节流的格式向(从)对方发送(接收)数据。
为了向一个应用发送消息,你需要知道该应用的IP
地址和端口。在Java
中,套接字用
java.net.Socket
类来表示。


    你可以使用
Socket
类众多
构造函数中的一个来创建
套接字
对象。其中一个构造函数接收主机名和端口作为参数:


public Socket (java.lang.String host, int port)
  
    其中,host
是远程机器的名称或IP

址,port
是远程应用的端口号。例如,要连接上
yahoo.com
80
端口,你可以创建下面的
Socket
对象:


new Socket("yahoo.com", 80);
  
    只要你成功创建了
Socket
的一个实例,就可以使用它发送和读取字节流。如果要发送字节流,你可以调用
Socket
类的
getOutputStream
方法获取一个
java.io.OutputStream
对象。如果要发送文本信息,你可以将上述
java.io.OutputStream
对象包装成一个
java.io.PrintWriter
对象。如果要读取字节流,你可以调用Socket
类的
getInputStream
方法获取一个
java.io.InputStream
对象


    下面的代码片段创建了一个能够与本地HTTP
服务器(127.0.0.1

示本地主机)通信的
Socket
对象,发送了一个HTTP

求,并
从服务器
接收了HTTP

应。另外,这段代码还创建了一个
StringBuffer
对象来存储响应数据,并将其打印在控制台上。


    Socket socket = new Socket("127.0.0.1", "8080");
OutputStream os = socket.getOutputStream();
boolean autoflush = true;
PrintWriter out = new PrintWriter(socket.getOutputStream(), autoflush);
BufferedReader in = new BufferedReader(new InputStreamReader( socket.getInputstream() ));
// send an HTTP request to the web server
out.println("GET /index.jsp HTTP/1.1");
out.println("Host: localhost:8080");
out.println("Connection: Close");
out.println();
// read the response
boolean loop = true;
StringBuffer sb = new StringBuffer(8096);
while (loop) {
if ( in.ready() ) {
int i=0;
while (i!=-1) {
i = in.read();
sb.append((char) i);
}
loop = false;
}
Thread.currentThread().sleep(50);
}
// display the response to the out console
System.out.println(sb.toString());
socket.close();
  
    需要注意的是,为了从Web
服务器得到恰当
的响应,你发送的HTTP
请求必须遵守HTTP
协议。如果你读了
前一节,超文本传输协议(HTTP
),应该就会理解上面代码中的HTTP
请求。



    提示:你可以使用本书源代码中的com.brainysoftware.pyrmont.util.HttpSniffer
类发送HTTP
请求和显示HTTP

应。为了使用这个Java
程序,你必须连接到Internet
。不过,提醒一句,如果你在防火墙后面,那么这个类可能不能正常工作。





ServerSocket

  
前面介绍的Socket

类,代表的是客户端套接字,即当你为了连接到远程服务程序而创建的
套接字
对象。现在,如果你想要实现一个服务器程序,比如HTTP

务器或FTP
服务器,你需要一种不同的做法。因为,服务器程序必须一直驻守,
它不知道客户端何时会连接过来。为了使你的程序能够驻守,你需要使用
java.net.ServerSocket
类。这是服务器端socket
的一个实现类。



    ServerSocket
类和
Socket
类并不相同。服务器套接字的职责是等待来自客户端的连接请求。当服务器套接字收到一个连接请求后,创建一个
Socket
对象来
与客户端通信。 为了创建服务器套接字,你需要使用
ServerSocket
类提供的4

构造函数之一。你需要指定服务器套接字将要监听的IP
地址和端口。通常,IP
地址是127.0.0.1
,表示服务器套接字将监听本地机器。服务器套接字监听的IP
地址被称为绑定地址
binding address
)。服务器套接字的另一个重要属性是backlog
,服务器套接字有一个保存尚未处理的连接请求的队列,backlog
就是该队列的的最大长度。如果达到最大长度,服务器套接字将拒绝新的连接请
求。


    下面是
ServerSocket
类的一个构造函数原型:


public ServerSocket(int port, int backLog, InetAddress bindingAddress);
  
   
注意这个构造函数,binding address
必须是一个
java.net.InetAddress
对象。创建
InetAddress
对象的一个简单方法就是调用该类的静态方法
getByName

并把主机名作为
String
对象传给该方法,就像下面这样:


InetAddress.getByName("127.0.0.1");
  
    下面这行代码创建了一个监听本地8080

口的、backlog
1
ServerSocket
对象。


new ServerSocket(8080, 1, InetAddress.getByName("127.0.0.1"));
      有了ServerSocket
对象后,你就可以告诉它:在指定的端口上监听绑定地址的连接请求吧。告
诉的办法就是调用
ServerSocket

accept
方法。当有一个连接请求到达时,该方法就会返回,返回值是一个
Socket

象。这个Socket
对象就像
前一节,
Socket

类”,描述的那样,可以用来向(从)客户端发送(读取)数据。实际上,accept
方法也是本章应用程序唯一使用的(
ServerSocket
类的)方法。



应用程序

      本章的应用程序是一个Web服务器程序,放在
ex01.pyrmont
包中,由3
个类组成:



  • HttpServer
  • Request
  • Response  
      本章应用程序的入口(静态的
main
方法)在
HttpServer
类中。
main
方法创建了一个
HttpServer
对象,并调用了它的
await
方法。人如其名,
await
方法在指定端口上等待HTTP

求,然后处理HTTP
请求,最后将HTTP
响应发送回客户端。而且,
await
方法保持等待,只有接收到
shutdown
命令,才退出运行。该应用只能发
送静态资源,诸如特性目录下的HTTP
文件和图像文件。同时,还在控制台上显
HTTP
请求的字节流。然而,该应用不向浏览器发送任何header
date
cookies
等)。


    下面各小节,我们将会看一看这3
个类。



HttpServer

      HttpServer

表示了一个Web
服务器,代码在
Listing 1.1
中。需要注意的是,为了节省篇幅,await
方法没被列在
Listing 1.1
中,可以在
Listing 1.2
中找到。



Listing
1.1: The HttpServer class


   


package ex01.pyrmont;
import java.net.Socket;
import java.net.ServerSocket;
import java.net.InetAddress;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;
import java.io.File;
public class HttpServer {
/** WEB_ROOT is the directory where our HTML and other files reside.
*  For this package, WEB_ROOT is the "webroot" directory under the
*  working directory.
*  The working directory is the location in the file system
*  from where the java command was invoked.
*/
public static final String WEB_ROOT =
System.getProperty("user.dir") + File.separator  + "webroot";
// shutdown command
private static final String SHUTDOWN_COMMAND = "/SHUTDOWN";
// the shutdown command received
private boolean shutdown = false;
public static void main(String[] args) {
HttpServer server = new HttpServer();  
server.await();
}
public void await() {
...
}
}
  

Listing
1.2: The HttpServer class's await method





public void await() {
ServerSocket serverSocket = null;
int port = 8080;
try {
serverSocket =  new ServerSocket(port, 1,
InetAddress.getByName("127.0.0.1"));
}
catch (IOException e) {
e.printStackTrace();
System.exit(1);
}
// Loop waiting for a request
while (!shutdown) {
Socket socket = null;
InputStream input = null;
OutputStream output = null;
try {
socket = serverSocket.accept();
input = socket.getInputStream();
output = socket.getOutputStream();
// create Request object and parse
Request request = new Request(input);
request.parse();
// create Response object
Response response = new Response(output);
response.setRequest(request);
response.sendStaticResource();
// Close the socket
socket.close();  
//check if the previous URI is a shutdown command
shutdown = request.getUri().equals(SHUTDOWN_COMMAND);
}
catch (Exception e) {
e.printStackTrace ();
continue;
}
}
}
      这个Web
服务器可以提供静态资源服务,可访问的资源位于
public static
final WEB_ROOT

表示的
目录及子
目录下。WEB_ROOT
是这样初始化的:


public static final String WEB_ROOT =  System.getProperty("user.dir") + File.separator + "webroot";
  
    这段代码中有一个名为webroot
的目录,该目录
包含了可以用于测试该应用的的静态资源。你还可以从该目录下找到几个用于测试下一章应用的servlet



   
如果要请求一个静态资源,你可以在浏览器的地址栏中敲入以下URL



    http://machineName:port/staticResource
  
   
如果你从另一台机器上发送请求,
machineName
应该是该应用所在机器的主机名或IP
地址。如果你的浏览器运行在同一台机器上,可以使用
localhost
作为
machineName
。端口是8080

staticResource
是被请求的文件(静态资源)名,该文件必须位于
WEB_ROOT
下。


   
例如,你在同一台机器上测试该应用,想让HttpServer
发送文件index.html
,你可以使用下面的URL

 

   
如果要停止服务器,你可以通过特定的URL从浏览器发送shutdown命令:host:port的后面加上预先定义的、表示shutdown的字符串即可。
HttpServer
类的静态常量
SHUTDOWN
定义了
shutdown命令:


private static final String SHUTDOWN_COMMAND = "/SHUTDOWN";
  
   
因此,如果要停止服务器,你可以使用下面的URL



    http://localhost:8080/SHUTDOWN
  
   
现在,我们看一看
Listing 1.2
中的await

法。


   
    方法名使用await
而不用wait
,是因为wait
java.lang.Object
类中一个重要的、与多线程紧密相关的方法。


    await
方法首先创建了一个ServerSocket

象,然后进入一个
while
循环。


    serverSocket =  new ServerSocket(port, 1, InetAddress.getByName("127.0.0.1"));
...
// Loop waiting for a request
while (!shutdown) {
...
}
  
    while
循环中的代码运行到
ServerSocket

accept
方法就停止下来,直到在8080

口上收到HTTP
请求才返回:


socket = serverSocket.accept();
     
收到一个请求后,
await
方法从
accept
方法返回的
Socket
对象中获取了
java.io.InputStream
对象和
java.io.OutputStream
对象。


input = socket.getInputStream();
output = socket.getOutputStream();
  await
方法然后创建了一个
ex01.pyrmont.Request
对象,并调用它的
parse
方法来解析HTTP请求的原始数据(raw data
)。


    // create Request object and parse
Request request = new Request(input);
request.parse ();
  
    之后,
await
方法创建了一个
Response
对象,将上面的
Request
对象设置成
Response
对象的成员,并调用
Response
对象的
sendStaticResponse
方法。


   // create Response object
Response response = new Response(output);
response.setRequest(request);
response.sendStaticResource();
      最后,
await
方法关闭

Socket
对象,并调用了
Request
对象的
getUri
方法,检查本次HTTP

求的URI
似乎否是shutdown

令。如果是(shutdown
命令)的话,
shutdown

量会被设置成
true
,从而程序将退出
while
循环。


    // Close the socket
socket.close ();
//check if the previous URI is a shutdown command
shutdown = request.getUri().equals(SHUTDOWN_COMMAND);

Request

  
ex01.pyrmont.Request
类代表了HTTP

求。要创建
Reuqest
对象,我们可以先从处理客户端通信的
Socket
对象中
获得的
InputStream
对象,然后将其作为参数调用
Request
类的构造函数。通过调用
InputStream
对象的
read
方法簇之一,就可以获取HTTP
请求的原始数据。



    Listing 1.3
列出了
Request
类的代码。
Request
类有两个public
方法,
parse

getUri

Listing
1.4


Listing 1.5
分别列出了这两个方法的代码。


 

Listing
1.3: The Request class




package ex01.pyrmont;
import java.io.InputStream;
import java.io.IOException;
public class Request {
private InputStream input;
private String uri;
public Request(InputStream input) {
this.input = input;
}
public void parse() {
...
}
private String parseUri(String requestString) {     
...
}
public String getUri() {
return uri;
}
}
  

  
Listing 1.4: The Request
class's parse method

   


public void parse() {
// Read a set of characters from the socket
StringBuffer request = new StringBuffer(2048);
int i;
byte[] buffer = new byte[2048];
try {
i = input.read(buffer);
}
catch (IOException e) {
e.printStackTrace();
i = -1;
}
for (int j=0; j<i; j++) {
request.append((char) buffer[j]);
}
System.out.print(request.toString());
uri = parseUri(request.toString());
}
  

  
Listing 1.5:
the Request class's parseUri method




private String parseUri(String requestString) {
int index1, index2;
index1 = requestString.indexOf(' ');
if (index1 != -1) {
index2 = requestString.indexOf(' ', index1 + 1);
if (index2 > index1)
return requestString.substring(index1 + 1, index2);
}
return null;
}
  
    除了解析HTTP
请求的原始数据,
parse
方法也
没做更多的事情。该方法从HTTP
请求中获取的唯一信息,就是通过调用private
方法
parseUri
解析出的URI

parseUri

法将HTTP
请求的URI

储在成员变量
uri
中。调用public
方法
getUri
可以返
HTTP
请求的URI




    提示:第3
章及后续章节将对HTTP
请求原始数据进行更多的处理。




    为了理解
parse

parseUri
方法是如何工作的,你需要知道HTTP
请求的协议格式,这在
前面小节,“超文本传输协议(HTTP
)”,已经讨论过。本章,我们只对HTTP
请求的第一部分,请求行(request line
),感兴趣。请求行以method
标记开头,后面是请求URI
和协议版本,最后以回车换行符(CRLF
)结束。请求行中的元素是以空格分隔的。例如,使用GET
方法请求index.html
的请求行如下所示:


    GET /index.html HTTP/1.1
  

    parse
方法从传给
Request
对象的
InputStream
对象中读取整个字节流,并保存在字节数组
buffer
中。然后,使用
buffer
中的字节数据创建一个名为
request

StringBuffer
对象,并将
StringBuffer
对象的
String
表示(representation

传给
parseUri
方法。


    parse
方法的代码列在
Listing 1.4
中。



    parseUri
方法负责从请求行中获取URI

Listing 1.5
列出了
parseUri
方法的代码。
parseUri
方法在请求行中搜索第一个和第二个空格,获取(两个空格)之间的URI




Response

  ex01.pyrmont.Response
类代表了HTTP
响应数据,Listing 1.6
列出了其代码。


Listing
1.6: The Response class




package ex01.pyrmont;
import java.io.OutputStream; import java.io.IOException;
import java.io.FileInputStream;
import java.io.File;
/*
HTTP Response = Status-Line
*(( general-header | response-header | entity-header ) CRLF)
CRLF
[ message-body ]
Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
*/
public class Response {
private static final int BUFFER_SIZE = 1024;
Request request;
OutputStream output;
public Response(OutputStream output) {
this.output = output;
}
public void setRequest(Request request) {
this.request = request;
}
public void sendStaticResource() throws IOException {
byte[] bytes = new byte[BUFFER_SIZE];
FileInputStream fis = null;
try {
File file = new File(HttpServer.WEB_ROOT, request.getUri());
if (file.exists()) {
fis = new FileInputStream(file);
int ch = fis.read(bytes, 0, BUFFER_SIZE);
while (ch!=-1) {
output.write(bytes, 0, ch);
ch = fis.read(bytes, 0, BUFFER_SIZE);
}
}
else {
// file not found
String errorMessage = "HTTP/1.1 404 File Not Found\r\n" +
"Content-Type: text/html\r\n" +
"Content-Length: 23\r\n" +            "\r\n" +
"<h1>File Not Found</h1>";
output.write(errorMessage.getBytes());
}
}
catch (Exception e) {
// thrown if cannot instantiate a File object
System.out.println(e.toString() );
}
finally {
if (fis!=null)
fis.close();
}
}
}
     
我们首先注意到,该类的构造函数接收一个
java.io.OutputStream
对象作为参数,如下所示。



    public Response(OutputStream output) {
this.output = output;
}
  

    HttpServer
类的
await
方法从
Socket
对象中获取
OutputStream
对象,将其作为参数构造了一个
Response
对象。
Response

有两个
public
方法:
setRequest

sendStaticResource

setRequest
方法用来将
Request
对象设置成
Response
对象的成员变量。



    sendStaticResource
方法用来发送静态资源,比如HTML
文件。该方法首先将父路径和子路径传递给
java.io.File
的构造函数,创建一个File

象。


    File file = new File(HttpServer.WEB_ROOT, request.getUri());
     
然后检查该文件是否存在。如果存在,那么
sendStaticResource
方法以File

象为参数构造一个
java.io.FileInputStream
对象。接着,调用
FileInputStream
对象的
read
方法,并向
OutputStream
对象
output
写入字节数组。请注意,这种情况下,静态资源的内容是作为原始数据发送给浏览器的。


    if (file.exists()) {
fis = new FileInputstream(file);
int ch = fis.read(bytes, 0, BUFFER_SIZE);
while (ch!=-1) {
output.write(bytes, 0, ch);
ch = fis.read(bytes, 0, BUFFER_SIZE);
}
}
      
如果文件不存在,那么
sendStaticResource
方法就将错误信息发送给浏览器。


    String errorMessage = "HTTP/1.1 404 File Not Found\r\n" +
"Content-Type: text/html\r\n" +
"Content-Length: 23\r\n" +
"\r\n" +
"<h1>File Not Found</h1>";
output.write(errorMessage.getBytes());

运行应用程序

       要从工作目录运行该应用,需要敲入下面的命令:


java ex01.pyrmont.HttpServer
     
要测试该应用,可以打开浏览器,在地址栏敲入下面的URL





http://localhost:8080/index.html
  
    正如Figure 1.1
所示,你会看到index.html
显示在浏览器(原图是IE6

这里是译者的IE8
)中。

DSC0000.jpg



                                                                                           
Figure 1.1: The output from the web server



    在控制台上,你可以看到类似于下面的HTTP
请求:


    GET /index.html HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-excel, application/msword, application/vnd.ms- powerpoint, application/x-shockwave-flash, application/pdf, */*
Accept-Language: en-us
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322)
Host: localhost:8080
Connection: Keep-Alive
GET /images/logo.gif HTTP/1.1
Accept: */*
Referer: http://localhost:8080/index.html
Accept-Language: en-us
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322)
Host: localhost:8080
Connection: Keep-Alive


总结

      从本章你已经看到了简单的Web
服务器是如
何工作的。本章附带的应用只包括3
个类,功能还不完整。无论如何,该应用仍是
一个很好的学习工具。下一章,我们将讨论对动态内容(dynamic content

的处理。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-340091-1-1.html 上篇帖子: 如何将tomcat控制台输出的内容直播用日志文件保存起来 下篇帖子: Eclipse中拷贝J2EE项目,发布到tomcat中名字一样的解决办法
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表