一.项目根目录下需要的相关文件:
1.配置文件conf下的文件:
(1)web.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1">
<mime-mapping>
<extension>html</extension>
<mime-type>text/html</mime-type>
</mime-mapping>
<mime-mapping>
<extension>jpg</extension>
<mime-type>image/jpeg</mime-type>
</mime-mapping>
<mime-mapping>
<extension>jpgm</extension>
<mime-type>video/jpm</mime-type>
</mime-mapping>
<mime-mapping>
<extension>7z</extension>
<mime-type>application/x-7z-compressed</mime-type>
</mime-mapping>
<mime-mapping>
<extension>png</extension>
<mime-type>image/png</mime-type>
</mime-mapping>
</web-app>
(2)server.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<server>
<!-- 配置和客户端连接相关的信息客户端传输数据的字符集服务端口等信息 -->
<Connector URIEncoding="utf-8" port="8088" protocol="HTTP/1.1"/>
<!-- 线程池的线程数 -->
<Executor maxThreads="50"/>
</server>
2.访问文件web-apps文件下,myweb文件里的文件:
图片bee0.png
(1)index.html文件
<html>
<head>
<title>hello</title>
<meta charset="UTF-8">
</head>
<body>
<center>
<h1>这是我的第一个页面</h1>
<img src="bee0.png">
<a href="reg.html">去注册</a>
</center>
</body>
</html>
(2)reg.html文件
<html>
<head>
<title>欢迎注册</title>
<meta charset="UTF-8">
</head>
<body>
<center>
<h1>用户注册</h1>
<form method="post" action="regUser">
<table border="1">
<tr>
<td>用户名:</td>
<td><input name ="username" type="text" size=30></td>
</tr>
<tr>
<td>密 码:</td>
<td><input name ="password" type="password" size=30></td>
</tr>
<tr>
<td colspan="2" align="center">
<input type="submit" value="注册">
</td>
</tr>
</table>
</center>
</body>
</html>
(3)reg_success.html文件
<html>
<head>
<title>注册成功</title>
<meta charset="UTF-8">
</head>
<body>
<center>
<h1>注册成功</h1>
<form method="post" action="../regUser">
</center>
</body>
</html>
(4)reg_fail.html文件
<html>
<head>
<title>注册失败</title>
<meta charset="UTF-8">
</head>
<body>
<center>
<h1>注册失败</h1>
<!-- <form method="post" action="../regUser"> -->
<a href="reg.html">重新注册</a>
</center>
</body>
</html>
二.建6个类,一个服务器,一个请求解析,一个响应用户,一个服务器配置信息,一个Http协议相关定义信息,
一个处理注册用户的信息
(1)服务器配置信息的类
package web.v3;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
/**
* 服务端配置数据
* 通过解析conf/server.xml文件得到配置数据
* @author soft01
*
*/
public class Server {
public static String URIENCODING;
public static int PORT;
public static String PROTOCOL;
public static int MAX_THREADS;
static {
try {
SAXReader reader = new SAXReader();
Document doc = reader.read(new FileInputStream("conf"+File.separator+"server.xml"));
Element root = doc.getRootElement();
Element ele1 = root.element("Connector");
URIENCODING = ele1.attributeValue("URIEncoding");
PORT = Integer.parseInt(ele1.attributeValue("port"));
PROTOCOL =ele1.attributeValue("protocol");
Element ele2 = root.element("Executor");
MAX_THREADS = Integer.parseInt(ele2.attributeValue("maxThreads"));
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (DocumentException e) {
e.printStackTrace();
}
}
}
(2)Http协议相关定义信息的类
package web.v3;
import java.io.File;
import java.io.FileInputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
/**
* Http协议相关定义信息
* @author soft01
*
*/
public class HttpContext {
public static final int CR = 13;
public static final int LF = 10;
public static final int STATUS_CODE_OK = 200;
public static final int STATUS_CODE_NOT_FOUND = 404;
public static final int STATUS_CODE_ERROR = 500;
public static final Map<Integer,String> STATUS_CODE_MAPPING = new HashMap<Integer,String>();
public static final Map<String,String> MIME_MAPPING = new HashMap<String,String>();
static {
initCodeMapping();
initMimeMapping();
}
private static void initCodeMapping() {
STATUS_CODE_MAPPING.put(200, "ok");
STATUS_CODE_MAPPING.put(404, "not found");
STATUS_CODE_MAPPING.put(500, "internal server error");
}
private static void initMimeMapping() {
/*
* 解析当前目录下的子目录conf中的文件web.xml
* 将该文件中所有<mime-mapping>标签中内容
* 存入MIME_MAPPING这个Map中
* 其中Key为<extension>标签中的文本信息
* value为<mime-type>标签中的文本信息
*/
try {
SAXReader reader = new SAXReader();
Document doc = reader.read(new FileInputStream("conf"+File.separator+"web.xml"));
Element root = doc.getRootElement();
List<Element> eles = root.elements("mime-mapping");
for(Element ele : eles) {
MIME_MAPPING.put(ele.elementText("extension"), ele.elementText("mime-type"));
}
}catch(Exception e) {
e.printStackTrace();
}
}
}
(3)处理注册用户的信息的类
package web.v3;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
public class RegServlet {
public void service(HttpRequest request,HttpResponse response) {
PrintWriter pw = null;
BufferedReader br = null;
try {
/*
* 将用户的注册信息写入服务端本地的一个
* 文件user.txt中
*/
//获取用户名
String name = request.getParameter("username");
String pwd = request.getParameter("password");
System.out.println(name);
System.out.println(pwd);
/*
* 首先检查该用户是否已经注册过,若注册过则跳转到提示页面。
*/
File userFile = new File("user.txt");
boolean have = false;
if(userFile.exists()) {
br = new BufferedReader(new InputStreamReader(new FileInputStream("user.txt"),"utf-8"));
String line = null;
while((line=br.readLine())!=null) {
String[] data = line.split(",");
if(name.equals(data[0])) {
have = true;
break;
}
}
}
if (have) {
File file = new File("web-apps"+File.separator + "myweb" + File.separator
+ "reg_fail.html");
response.setStatusCode(HttpContext.STATUS_CODE_OK);
response.setContentType(HttpContext.MIME_MAPPING.get("html"));
response.setContentLength(file.length());
response.setEntity(file);
} else {
// 写入文件
pw = new PrintWriter(new OutputStreamWriter(new FileOutputStream("user.txt", true), "utf-8"));
pw.println(name + "," + pwd);
pw.flush();
/*
* 响应用户注册成功页面
*/
File file = new File("web-apps"+File.separator + "myweb" + File.separator
+ "reg_success.html");
response.setStatusCode(HttpContext.STATUS_CODE_OK);
response.setContentType(HttpContext.MIME_MAPPING.get("html"));
response.setContentLength(file.length());
response.setEntity(file);
}
}catch(Exception e) {
e.printStackTrace();
}finally {
if(br != null){
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(pw!=null) {
pw.close();
}
}
}
}
(4)请求解析的类
package web.v3;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLDecoder;
import java.util.LinkedHashMap;
import java.util.Map;
public class HttpRequest {
/*
* 请求行相关信息
*/
// 请求方法
private String method;
// 请求资源路径
private String url;
// 请求使用的协议版本
private String protocol;
/*
* 消息头相关信息
*/
private Map<String,String> headers;
//请求路径
private String requestLine;
//参数部分
private String queryLine;
//保存所有传递过来的参数的Map
private Map<String,String> parasMap;
public HttpRequest(InputStream in) {
parseRequestLine(in);
parseHeaders(in);
parseEntity(in);
}
public void parseRequestLine(InputStream in) {
try {
String line = readLine(in);
if(line.length()==0){
throw new RuntimeException("无效请求");
}
String[] data = line.split("\\s");
method = data[0];
url = data[1];
parseUrl(this.url);
protocol = data[2];
} catch (Exception e) {
e.printStackTrace();
throw e;
}
}
private void parseUrl(String url) {
if (url.indexOf("?") != -1) {
String[] data = url.split("\\?");
requestLine = data[0];
queryLine = decodeUrl(data[1]);
parseQuery(queryLine);
}else {
requestLine = url;
}
}
private void parseQuery(String queryLine) {
parasMap = new LinkedHashMap<String, String>();
String[] querys = queryLine.split("&");
for (int i = 0; i < querys.length; i++) {
String[] data1 = querys[i].split("=");
parasMap.put(data1[0], data1[1]);
}
}
public void parseHeaders(InputStream in) {
headers = new LinkedHashMap<String, String>();
while (true) {
String line = readLine(in);
if ("".equals(line)) {
break;
}
String[] data = line.split(":");
headers.put(data[0].trim(), data[1].trim());
}
headers.forEach((k, v) -> System.out.println(k + ":" + v));
}
/**
* 解析消息正文
*/
private void parseEntity(InputStream in){
/*
* 通过消息头中获取正文长度
*/
if(this.headers.containsKey("Content-Length")){
int contentLength = Integer.parseInt(
this.headers.get("Content-Length")
);
String contentType
= this.headers.get("Content-Type");
//根据Content-Type判断是否为form表单
if("application/x-www-form-urlencoded".equals(contentType)){
System.out.println("开始处理Post请求中form表单内容!");
//通过流读取消息正文中的所有字节
try {
/* form表单中的数据还是字符串,跟Get请求中
* 地址栏中?右侧内容格式一致
*/
byte[] data = new byte[contentLength];
in.read(data);
String line = URLDecoder.decode(
new String(data,"ISO8859-1"),
Server.URIENCODING
);
System.out.println(line);
parseQuery(line);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
public String readLine(InputStream in) {
try {
StringBuilder builder = new StringBuilder();
char c1 = 0, c2 = 0;
int d=-1;
while ((d=in.read())!=-1) {
c2 = (char)d;
if (c1 == HttpContext.CR && c2 == HttpContext.LF) {
break;
}
builder.append(c2);
c1 = c2;
}
return builder.toString().trim();
} catch (IOException e) {
e.printStackTrace();
}
return "";
}
private String decodeUrl(String line) {
try {
String str;
System.out.println("解码前的内容:" + line);
str = URLDecoder.decode(line, Server.URIENCODING);
System.out.println("解码后的内容" + str);
return str;
} catch (Exception e) {
e.printStackTrace();
}
return line;
}
public String getRequestLine() {
return requestLine;
}
public String getParameter(String name) {
return parasMap.get(name);
}
}
(5)响应用户的类
package web.v3;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;
public class HttpResponse {
//状态代码
private int statusCode;
// 响应头
private Map<String,String> headers;
//响应实体
private File entity;
//输出流
private OutputStream out;
public HttpResponse(OutputStream out){
this.out=out;
this.headers = new HashMap<String,String>();
}
public void flush() {
// 发送状态行信息
sendResponseStatusLine();
// 发送响应头信息
sendReResponseHeaders();
// 发送响应正文
sendReResponseContent();
}
public void sendResponseStatusLine(){
String line = Server.PROTOCOL+" "+statusCode+" "+HttpContext.STATUS_CODE_MAPPING.get(statusCode);
println(line);
}
public void sendReResponseHeaders(){
headers.forEach((k,v)->println(k+":"+v));
println("");
}
public void sendReResponseContent(){
FileInputStream fis = null;
try {
fis = new FileInputStream(entity);
int len = -1;
byte[] data = new byte[1024*10];
while((len = fis.read(data))!=-1) {
out.write(data, 0, len);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}catch(IOException e) {
e.printStackTrace();
}finally {
if(fis!=null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public void println(String line) {
try {
out.write(line.getBytes("ISO8859-1"));
out.write(HttpContext.CR);//CR
out.write(HttpContext.LF);//LF
}catch(UnsupportedEncodingException e) {
e.printStackTrace();
}catch(IOException e) {
e.printStackTrace();
}
}
public void setContentType(String contentType) {
this.headers.put("Content-Type", contentType);
}
public void setContentLength(long length) {
this.headers.put("Content-Length", String.valueOf(length));
}
public void setStatusCode(int statusCode) {
this.statusCode = statusCode;
}
public void setEntity(File entity) {
this.entity = entity;
}
}
(6)服务器的类
package web.v3;
import java.io.File;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 读取网页发送过来的请求行,消息头信息
* @author soft01
*
*/
public class WebServer {
ServerSocket server;
Socket socket;
private ExecutorService threadPool;
public WebServer() {
try {
System.out.println("初始化客户端...");
server = new ServerSocket(Server.PORT);
threadPool = Executors.newFixedThreadPool(Server.MAX_THREADS);
System.out.println("客户端初始化完毕!");
} catch (IOException e) {
e.printStackTrace();
}
}
public void start() {
try {
while (true) {
System.out.println("等待客户端连接...");
socket = server.accept();
System.out.println("一个客户端已连接!");
// 1:请求行 method url protocol
// 2:消息头:根据请求资源的不同消息头中的内容也不完全一样。
// 消息头中每一个信息都以CRLF结束
// CR(13)LF(10) 单独读取到一个CRLF表示消息头全部发送完毕
// 3:消息正文
ClientHandler handler = new ClientHandler(socket);
threadPool.execute(handler);
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
try {
WebServer server = new WebServer();
server.start();
}catch(Exception e) {
e.printStackTrace();
}
}
private class ClientHandler implements Runnable {
private Socket socket;
public ClientHandler(Socket socket) {
this.socket=socket;
}
public void run() {
try {
HttpRequest request = new HttpRequest(socket.getInputStream());
HttpResponse response = new HttpResponse(socket.getOutputStream());
String requestLine = request.getRequestLine();
if ("/myweb/regUser".equals(requestLine)) {
//请求注册用户的功能
RegServlet servlet = new RegServlet();
servlet.service(request, response);
//处理完请求后,响应用户
response.flush();
}else {
File file = new File("web-apps" + requestLine);
if(file.exists()) {
// 设置状态码
response.setStatusCode(HttpContext.STATUS_CODE_OK);
// 设置Content-Type
String fileName = file.getName();
int index = fileName.lastIndexOf(".")+1;
String extension = fileName.substring(index);
String contentType = HttpContext.MIME_MAPPING.get(extension);
response.setContentType(contentType);
response.setContentLength(file.length());
// 设置实体数据
response.setEntity(file);
response.flush();
}else {
System.out.println("文件不存在!");
}
}
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
注意:(1)html里面的input代表输入框的意思,再次强调解析XML文档需要建MavenProject导入dom4j的架包,若MavenProject里下面搜索不到,请到http://maven.aliyun.com/nexus去搜索
(2)各文件里的信息同以前版本有些改动,请注意文件信息跟路径。