文章目录
- Tomcat
- 概念
- 自制简易的服务器
- JavaEE规范
- Tomcat安装
- Tomcat启动
- Tomcat的资源部署
- 直接部署
- 虚拟映射
- Tomcat的设置
Tomcat
概念
- 服务器:两层含义。
- 软件层面:软件,可以将本地的资源发布到网络中,供网络上面的其他用户来访问,比如tomcat;
- 硬件层面:一台性能比较高效的计算机主机,云服务器。
- 服务器开发:指的是在服务器软件程序中进一步去编写程序来运行
- 静态资源:页面一成不变的。
- 动态资源:富有交互性、变化性。
- 目前访问的网站页面基本都是动态资源。本质就是程序。比如登录之后会显示各自的用户名。开发动态资源的技术有很多种,其中java语言中 servlet。
自制简易的服务器
单线程的服务器:
public class ServerDemo {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(8089);
Socket socket = serverSocket.accept();
// 怎么从socket获取信息
InputStream inputStream = socket.getInputStream();
byte[] bytes = new byte[20480];
//输入的数据会放到字节数组bytes里面;读出的长度会返回length
int length = inputStream.read(bytes);
String inputStr = new String(bytes, 0, length);
System.out.println(inputStr);
// 想根据url上面的信息,返回1.txt 1.png
// 应该拿出请求行; 再取出第二个数据
// \r\n表示回车
int index1 = inputStr.indexOf("\r\n");
String firstLine = inputStr.substring(0, index1);
// firstLine 为 GET /1.txt HTTP/1.1
System.out.println(firstLine);
// Strings = {GET, /1.txt, HTTP/1.1}
String[] strings = firstLine.split(" ");
System.out.println(strings[0]);
System.out.println(strings[1]);
System.out.println(strings[2]);
// split之后获取到了1.txt
// resourceName = 1.txt
String resourceName = strings[1].substring(1);
System.out.println(resourceName);
// data如果有数据
// 那么则传入1.txt
// 1. 把数据的字节数组写回来
// 2. 文件不存在,返回长度为0的字节数组
byte[] data = getDataFromFile(resourceName);
OutputStream outputStream = socket.getOutputStream();
StringBuffer stringBuffer = new StringBuffer();
if (data.length == 0) {
// 代表文件没找到
stringBuffer.append("HTTP/1.1 404 NotFound\r\n");
stringBuffer.append("Server: coo1heisenberg\r\n");
stringBuffer.append("Content-type: text/html\r\n");
stringBuffer.append("\r\n");
// 如果文件没找到,把data数组赋值
data = "<div style = 'font-size: 50px'>file not found</div>".getBytes("utf-8");
} else {
stringBuffer.append("HTTP/1.1 200 Ok\r\n");
stringBuffer.append("Server: coo1heisenberg\r\n");
stringBuffer.append("Content-type: text/html\r\n");
stringBuffer.append("\r\n");
}
// StringBuffer里面是响应行,响应头,空行的内容
outputStream.write(stringBuffer.toString().getBytes("utf-8"));
// data里面是文件的内容
outputStream.write(data);
outputStream.close();
}
private static byte[] getDataFromFile(String resourceName) throws IOException {
InputStream inputStream1 =
ServerDemo1.class.getClassLoader().getResourceAsStream(resourceName);
byte[] bytes = new byte[20480];
if (inputStream1 == null) {
return new byte[0];
} else {
int len = inputStream1.read(bytes);
byte[] bytes1 = Arrays.copyOf(bytes, len);
return bytes1;
}
}
}
多线程的服务器:
public class ServerDemo {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(8089);
while (true) {
Socket socket = serverSocket.accept();
new Thread(() -> {
// 怎么从socket获取信息
InputStream inputStream = null;
try {
inputStream = socket.getInputStream();
} catch (IOException e) {
throw new RuntimeException(e);
}
byte[] bytes = new byte[20480];
//输入的数据会放到字节数组bytes里面;读出的长度会返回length
int length = 0;
try {
length = inputStream.read(bytes);
} catch (IOException e) {
throw new RuntimeException(e);
}
String inputStr = new String(bytes, 0, length);
System.out.println(inputStr);
// 想根据url上面的信息,返回1.txt 1.png
// 应该拿出请求行; 再取出第二个数据
// \r\n表示回车
int index1 = inputStr.indexOf("\r\n");
String firstLine = inputStr.substring(0, index1);
// firstLine 为 GET /1.txt HTTP/1.1
System.out.println(firstLine);
// Strings = {GET, /1.txt, HTTP/1.1}
String[] strings = firstLine.split(" ");
System.out.println(strings[0]);
System.out.println(strings[1]);
System.out.println(strings[2]);
// split之后获取到了1.txt
// resourceName = 1.txt
String resourceName = strings[1].substring(1);
System.out.println(resourceName);
// data如果有数据
// 那么则传入1.txt
// 1. 把数据的字节数组写回来
// 2. 文件不存在,返回长度为0的字节数组
byte[] data = new byte[0];
try {
data = getDataFromFile(resourceName);
} catch (IOException e) {
throw new RuntimeException(e);
}
OutputStream outputStream = null;
try {
outputStream = socket.getOutputStream();
} catch (IOException e) {
throw new RuntimeException(e);
}
StringBuffer stringBuffer = new StringBuffer();
if (data.length == 0) {
// 代表文件没找到
stringBuffer.append("HTTP/1.1 404 NotFound\r\n");
stringBuffer.append("Server: coo1heisenberg\r\n");
stringBuffer.append("Content-type: text/html\r\n");
stringBuffer.append("\r\n");
// 如果文件没找到,把data数组赋值
try {
data = "<div style = 'font-size: 50px'>file not
found</div>".getBytes("utf-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
} else {
stringBuffer.append("HTTP/1.1 200 Ok\r\n");
stringBuffer.append("Server: coo1heisenberg\r\n");
stringBuffer.append("Content-type: text/html\r\n");
stringBuffer.append("\r\n");
}
// StringBuffer里面是响应行,响应头,空行的内容
try {
outputStream.write(stringBuffer.toString().getBytes("utf-8"));
} catch (IOException e) {
throw new RuntimeException(e);
}
// data里面是文件的内容
try {
outputStream.write(data);
} catch (IOException e) {
throw new RuntimeException(e);
}
try {
outputStream.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}).start();
}
}
private static byte[] getDataFromFile(String resourceName) throws IOException {
InputStream inputStream1 =
ServerDemo1.class.getClassLoader().getResourceAsStream(resourceName);
byte[] bytes = new byte[20480];
if (inputStream1 == null) {
return new byte[0];
} else {
int len = inputStream1.read(bytes);
byte[] bytes1 = Arrays.copyOf(bytes, len);
return bytes1;
}
}
}
抽象出一个Request方法:
public class Request {
// GET POST
String method;
String resourceName;
String protocol;
// 请求头用什么数据来装?
Map<String, String> Header = new HashMap<>();
public void parseContent(String content) {
//
parseFirstLine(content);
parseHeaders(content);
}
private void parseHeaders(String content) {
// 在windows下面是\n
// 在Linux下面是 \r\n
// 在mac下面是 \r
int index1 = content.indexOf("\r\n");
// 怎么确定请求头结束
int index2 = content.indexOf("\r\n\r\n");
String headersStr = content.substring(index1 + 2, index2);
System.out.println(headersStr);
// 1.按照\r\n切分split
// 2. 得到数组,代表一行
// 3. 一行切分,按照":"
}
private void parseFirstLine(String content) {
int index = content.indexOf("\r\n");
String firstLine = content.substring(0, index);
String[] strings = firstLine.split(" ");
method = strings[0];
resourceName = strings[1];
protocol = strings[2];
}
}
JavaEE规范
- 制定了一系列的接口。相应的厂商需要实现该接口,对于开发者来说,只需要面向接口编程即可。
- JDBC也是,定义了很多的接口
Tomcat安装
Tomcat控制台乱码解决办法:
- 原因:cmd是GBK编码,Tomcat是UTF8编码
- 解决:
- 修改
logging.properties
配置:- 打开
tomcat/conf/logging.properties
- 添加语句:
java.util.logging.ConsoleHandler.encoding = GBK
- 重启tomcat,查看日志数据即可
- 打开
- 修改
Tomcat启动
- 双击
startup.bat
文件 bin
目录下换出cmd,执行startup
常见的启动故障:
- 没有正确配置好
JAVA_HOME
,导致tomcat一闪而过
Tomcat的资源部署
直接部署
eg:
- 写ip+端口 --> 相当于找到了webapps目录
localhost:8080/test
- 如果你想访问
test
文件夹下的1.txt
。 只用写相对路径,http://localhost:8080/test/1.txt
- 如果想访问
test
文件夹里面的2.png
,怎么写呢?http://localhost:8080/test/2.png
注意:
不能将文件直接放置在webapps目录下。需要放在webapps目录下的文件夹内。
虚拟映射
不在webapps目录这种方式叫做虚拟映射。虚拟地映射到Tomcat的webapps目录下。
conf/Catalina/localhost
(掌握)- 新建一个
.xml
的配置文件 - 在
.xml
的文件(test1.xml
)里面配置context的节点信息
eg:
- 新建一个
第一行是一个标识,表示这是一个xml
<?xml version="1.0" encoding="UTF-8"?>
第二行表示在D盘有一个叫test_Photo的目录
<Context docBase="D:\test_Photo"/>
- 访问流程
localhost:8080/{xml的名称}
- 相当于会找到了
docBase
指定的文件夹
- 相当于会找到了
localhost:8080/{xml的名称}/{相对于docBase的相对路径}
- eg:
- eg:
服务器最终会把url的路径映射到本地磁盘的一个路径上面
conf/server.xml
(了解)
-
需要在
Host
节点下配置Context节点/app452-----Context
<Context path="/app452" docBase="D:\test_Photo" />
http://localhost:8080/{path}/{文件相对于docBase的相对路径}
- eg:
http://localhost:8080/app452/2.jpg
- eg:
Tomcat的设置
- 设置默认端口号
- 对于
http
协议来说,默认端口号是80
端口号。如果你也希望访问你的tomcat时,也不携带端口号,你只需要设置你的tomcat监听80端口号即可。 - 在
conf/server.xml
中配置
- 对于
<Connector port="80" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
- 设置缺省应用
- tomcat中存在着一个缺省应用,如果没有找到匹配的应用时,则将该请求交给缺省应用来处理。
- 具体步骤:
- 如果希望配置一个
ROOT
应用,那么webapps
目录下新建一个ROOT
目录 conf/Catalina/localhost
目录下新建一个ROOT.xml
- 如果希望配置一个
ROOT
应用下的资源文件在访问时,不需要携带应用的名称
以下为ROOT.xml的示例代码:
<?xml version="1.0" encoding="UTF-8"?>
<Context docBase="D:\test_Photo"/>
虚拟映射也可以配置一个ROOT.xml
,如果虚拟映射和直接部署都有,那么则是虚拟映射优先级高
- 设置欢迎页面(缺省页面)
-
比如:访问
http://localhost
,可以显示出一个页面,那么访问的是哪个页面:-
没有应用名,说明访问的是
ROOT
应用 -
没有页面,说明访问的是欢迎页面(
conf/web.xml
文件中有配置)- 表示的是:如果请求没有指明具体访问的是哪个页面,那么会在当前应用下依次去查找是否存在该文件,如果存在,则加载;如果不存在,则返回404
- 表示的是:如果请求没有指明具体访问的是哪个页面,那么会在当前应用下依次去查找是否存在该文件,如果存在,则加载;如果不存在,则返回404
-
eg:
现在在chrome里面输入localhost,直接访问到我的D:\app3
的1.jpg
的图片,那么分为几个步骤?
-
修改端口号,改成8080端口
-
虚拟映射
-
在
/conf/web.xml
下修改welcome-file-list
加上一个1.jpg