自定义服务器整个项目结构
- 自定义请求类MyHttpServletRequest,处理请求
package com.myserver;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Map;
/**
* 自定义请求类,处理请求
* @author fang
*
*/
public class MyHttpServletRequest {
/**
* 请求的动作
*/
private String action;
/**
* 存放请求的参数
*/
private Map<String, String> paramMap = new HashMap<String, String>();
public MyHttpServletRequest() {
}
public MyHttpServletRequest(InputStream is) throws IOException {
// 创建一个用来接收的数据盒子
byte[] buf = new byte[1024];
// 接收并返回长度
int len = is.read(buf);
if (len == 0) {
return;
}
// 取得请求数据,进行解码,防止中文乱码
String data = new String(buf, 0, len);
data = URLDecoder.decode(data, "utf-8");
// 处理GET请求
if (data.startsWith("GET")) {
// 判断是否带参数
if (data.contains("?")) {
// 取得参数的字符串
String params = data.substring(data.indexOf("?") + 1, data.indexOf("HTTP/1.1") - 1);
// 取得带参数的请求动作
this.action = data.substring(data.indexOf("/"), data.indexOf("?"));
// 解析取得请求动作,将取得请求的参数存放到HashMap中
if (params != null && !"".equals(params)) {
parseParams(params);
}
} else {
this.action = data.substring(data.indexOf("/"), data.indexOf("HTTP") - 1);
}
}
// 处理PSOT请求
if (data.startsWith("POST")) {
int start = data.indexOf("POST") + 6;
int end = data.indexOf("HTTP/1.1") - 1;
// 取得请求动作
this.action = data.substring(start, end);
// 最后一个换行符
int beginIndex = data.lastIndexOf("\n") + 1;
// 取得请求参数的字符串
String params = data.substring(beginIndex);
// 解析参数
if (params != null && !"".equals(params)) {
parseParams(params);
}
}
}
/**
* 解析参数,将取得请求的参数存放到HashMap中
*
* @param params 参数字符串
* @return 请求动作
*/
private void parseParams(String params) {
// 解析参数字符串
if (params.contains("&")) {
// 多个参数以&为分割符
String[] temp = params.split("&");
if (temp != null) {
for (int i = 0; i < temp.length; i++) {
// key=value的形式
String[] t = temp[i].split("=");
// 存入集合
paramMap.put(t[0], t[1]);
}
}
} else {
String[] p = params.split("=");
// 存入集合
paramMap.put(p[0], p[1]);
}
}
/**
* 取得请求的动作
*
* @return action
*/
public String getAction() {
return action;
}
/**
* 取得属性值
*
* @param key 键值
* @return 属性值
*/
public String getAttributeValue(String key) {
if (paramMap.size() <= 0) {
return null;
}
return paramMap.get(key);
}
/**
* 设置属性
*
* @param key 键值
* @param value 属性值
*/
public void setAttribute(String key, String value) {
paramMap.put(key, value);
}
/**
* 移除属性
*
* @param key 属性对应的键值
*/
public void removeAttribute(String key) {
paramMap.remove(key);
}
}
- 自定义响应类MyHttpServletResponse,响应请求
package com.myserver;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
public class MyHttpServletResponse {
/**
* 输出流
*/
private OutputStream os;
/**
* 初始化OutputStream
* @param os 外部传入一个输出流
*/
public MyHttpServletResponse(OutputStream os) {
this.os = os;
}
/**
* 打印流
* @return
*/
public PrintWriter getPrintWriter() {
return new PrintWriter(os);
}
/**
* 将流写入到浏览器
* @param is
* @throws IOException
*/
public void write(InputStream is) throws IOException {
BufferedInputStream bis=new BufferedInputStream(is);
byte[] buf=new byte[1024];
int len=0;
while((len=bis.read(buf))!=-1) {
os.write(buf, 0, len);
}
os.flush();
}
/**
* 转发
* @param filePath 文件地址
* @throws IOException
*/
public void forward(String filePath) throws IOException {
if (filePath.startsWith("/")) {
filePath="webContent"+filePath;
}else {
filePath="webContent"+File.separator+filePath;
}
BufferedInputStream bis=new BufferedInputStream(new FileInputStream(filePath));
byte[] buf=new byte[1024];
int len=0;
while((len=bis.read(buf))!=-1) {
os.write(buf, 0, len);
}
bis.close();
os.flush();
}
}
- 定义处理请求线程类ProcessedThread
package com.myserver;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import com.servlet.LoginServlet;
/**
* 定义处理请求线程类
*
* @author fang
*
*/
public class ProcessedThread implements Runnable {
/**
* 客户端套接字
*/
private Socket socket = null;
public ProcessedThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
InputStream is = null;
OutputStream os = null;
try {
is = socket.getInputStream();
if (is == null) {
throw new NullPointerException();
}
os = socket.getOutputStream();
if (os == null) {
throw new NullPointerException();
}
// 创建响应对象实例
MyHttpServletResponse response = new MyHttpServletResponse(os);
// 创建请求对象
MyHttpServletRequest request = new MyHttpServletRequest(is);
// 取得请求动作
String action = request.getAction();
String filePath = null;
if (action == null || "".equals(action)) {
response.forward("404.html");
return;
}
boolean result = isSuffix(action);
// 处理静态业务类
if (result) {
filePath = "webContent" + request.getAction();
File file = new File(filePath);
if (!file.exists()) {
response.forward("404.html");
return;
}
response.write(new FileInputStream(filePath));
}
// 处理动态业务类
if (!result) {
if (action.endsWith("login.do")) {
LoginServlet loginServlet = new LoginServlet();
loginServlet.doService(request, response);
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
os.close();
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//静态业务 允许请求的后缀
String[] suffixs = { ".html", ".js", ".css", ".jpg", ".ico" };
public boolean isSuffix(String action) {
boolean isAllow = false;
// 判断是否有
for (String suffix : suffixs) {
if (action.endsWith(suffix)) {
isAllow = true;
break;
}
}
return isAllow;
}
}
- 实现自定义服务器类MyServer
package com.myserver;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 实现自定义服务器
* @author fang
*
*/
public class MyServer {
/**
* 服务端套接字
*/
private ServerSocket serverSocket=null;
/**
* 客户端套接字
*/
private Socket socket=null;
/**
* 初始化服务器
* @param port 端口号 默认80
* @throws IOException
*/
public MyServer(int port) throws IOException {
//开启服务端
serverSocket=new ServerSocket(port);
System.out.println("服务器开启成功");
while(true) {
//等待客户端连接
socket=serverSocket.accept();
//创建处理请求的线程
ProcessedThread processedThread=new ProcessedThread(socket);
//使用定长线程池
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5);
//开始执行
fixedThreadPool.execute(processedThread);
}
}
public Socket getSocket() {
return socket;
}
public static void main(String[] args) throws IOException {
new MyServer(80);
}
}
- 测试登录类
package com.servlet;
import java.io.FileNotFoundException;
import java.io.IOException;
import com.myserver.MyHttpServletRequest;
import com.myserver.MyHttpServletResponse;
/**
* 测试登录
* @author fang
*
*/
public class LoginServlet {
public void doService(MyHttpServletRequest request,MyHttpServletResponse response) throws FileNotFoundException, IOException{
//取得帐号和密码
String userName=request.getAttributeValue("userName");
String password=request.getAttributeValue("password");
if ("fangzi".equals(userName) && "666".equals(password)) {
response.forward("/main.html");
}else {
response.forward("/failed.html");
}
}
}
前端页面
首页index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>欢迎界面</title>
</head>
<body>
<h1>欢迎使用自定义服务器</h1>
</body>
</html>
登录界面login.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>登录</title>
</head>
<body>
<h1>登录界面</h1>
<form action="login.do" method="post">
<p>
账号:<input name="userName" />
</p>
<p>
密码:<input name="password" />
</p>
<p>
<button>登录</button>
</p>
</form>
</body>
</html>
登录成功main.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
登录成功
</body>
</html>
登录失败failed.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>登录失败</title>
</head>
<body>
<h1>账号或密码错误</h1>
<hr>
<p>
<a href="login.html">返回</a>
</p>
</body>
</html>
图标文件favicon.ico
注意:图标这个文件一定要有,可以新建一个文件后缀名设置为.ico