目录
多线程处理
在昨天的基础上,再进一步优化,能够有一条线程专门处理一个客户端的请求
在使用多线程之前,我们先优化一下目前的结构
1. 创建线程 thread
package com.shao.net;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class Tomcat {
public Tomcat() {
ServerSocket ss = null;
try {
ss = new ServerSocket(8080);
while (true) {
// 调用accept()方法阻塞等待,直到有客户端连接到服务器,返回一个Socket对象用于与该客户端通信
Socket socket = ss.accept();
System.out.println("客户端连接成功");
// 获取Socket对象的输入流,用于读取客户端发送的数据
InputStream is = socket.getInputStream();
// 获取Socket对象的输出流,用于向客户端发送数据
OutputStream os = socket.getOutputStream();
new Thread(new Runnable() {
@Override
public void run() {
// 定义一个字节数组,存放客户端发送的请求信息
byte[] bytes = new byte[1024];
// 读取客户端发送的数据,返回读取的字节数
int len = 0;
try {
len = is.read(bytes);
} catch (IOException e) {
e.printStackTrace();
}
// 将读取的字节数组转换为字符串
String msg = new String(bytes, 0, len);
// 调用HttpRequest类解析请求信息
HttpRequest httpRequest = new HttpRequest(msg);
// 拼接请求的静态资源的路径
// 路径是相对路径,从模块的根路径开始
String filePath = "webs/pages" + httpRequest.getRequestModule();
HttpResponse httpResponse = new HttpResponse(os, httpRequest);
// 响应数据
httpResponse.response(filePath);
}
}).start(); // 启动线程
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭连接通道
try {
ss.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
2. 使用 start() 启动线程
new Thread(new Runnable() { @Override public void run() { } }).start();
3. 启动服务端
在启动类的 main 方法中 创建 Tomcat 对象启动服务端
响应动态资源
现在已经可以响应静态资源了,如何响应动态资源呢?
JDBC
动态资源一般需要操作数据库,所以我们要使用 java 数据库连接 也就是JDBC
使用JDBC 操作数据库,需要使用到第三方 jar 包
因为java 提供了统一的接口,不同的数据库厂商实现这个接口,所以使用统一的语法就可以操作不同的数据库
在选择第三方 jar 包的时候需要根据所使用的数据库去下载
因为我使用的数据库是 Mysql ,所以 jar 包是从Mysql官网下载的
创建 lib 文件夹,存放第三方 jar包
JDBC 的7个步骤
1. 加载JDBC 驱动
2. 定义连接数据库的URL
3. 建立数据库连接
4. 创建可执行对象 statement
5. 执行SQL
6. 结果处理
7. 释放连接
定义响应动态资源的方法
响应静态资源 index.html 的时候是根据扩展名 .html 判断的
响应动态资源不需要写文件名了,只需要写功能的名称即可
比如登录功能,可以定义名称为 doLogin
1. 加载JDBC 驱动
2. 定义连接数据库的URL
3. 建立数据库连接
4. 创建可执行对象 statement
5. 执行SQL
6. 结果处理
这是我的数据库的 user 表
DTO 数据传输对象
DTO 是一种服务端给客户端传输数据的格式
package com.shao.Utils;
public class responseDTO {
private int statusCode;
private Object data;
private String msg;
private int count;
public responseDTO() {
}
public responseDTO(int statusCode, Object data, String msg) {
this.statusCode = statusCode;
this.data = data;
this.msg = msg;
}
public responseDTO(int statusCode, Object data, String msg, int count) {
this.statusCode = statusCode;
this.data = data;
this.msg = msg;
this.count = count;
}
/**
* 获取
*
* @return statusCode
*/
public int getStatusCode() {
return statusCode;
}
/**
* 设置
*
* @param statusCode
*/
public void setStatusCode(int statusCode) {
this.statusCode = statusCode;
}
/**
* 获取
*
* @return data
*/
public Object getData() {
return data;
}
/**
* 设置
*
* @param data
*/
public void setData(Object data) {
this.data = data;
}
/**
* 获取
*
* @return msg
*/
public String getMsg() {
return msg;
}
/**
* 设置
*
* @param msg
*/
public void setMsg(String msg) {
this.msg = msg;
}
/**
* 获取
*
* @return count
*/
public int getCount() {
return count;
}
/**
* 设置
*
* @param count
*/
public void setCount(int count) {
this.count = count;
}
public String toString() {
return "responseDTO{statusCode = " + statusCode + ", data = " + data + ", msg = " + msg + ", count = " + count + "}";
}
}
再创建一个响应方法
在 httpResponse 响应类中 再创建一个响应方法,响应动态资源
public void send(String content) {
// 转成字节数组
byte[] contentBytes = content.getBytes();
// 获取请求协议
String protocol = httpRequest.getRequestProtocol();
try {
os.write((protocol + " 200 OK\r\n").getBytes());
os.write(("Content-Type: " + "text/html;charset=utf-8" + "\r\n").getBytes());
os.write(("Content-Length: " + contentBytes.length + "\r\n").getBytes());
os.write("\r\n".getBytes());
os.write(contentBytes);
os.flush();
System.out.println("响应成功");
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
测试
在游览器的地址栏 输入 http://127.0.0.1:8080/doLogin?account=16701&password=Abc123456
http://127.0.0.1:8080 是本地地址
/doLogin 是功能的名称
account=16701&password=Abc123456 是请求的参数
可以看到请求的参数信息