Tomcat服务器源代码手动写,简易版——实现欢迎页跳转以及注册登录等功能
2017-10-26 20:17
513 查看
一.项目根目录下需要的相关文件:
1.配置文件conf下的文件:
(1)web.xml文件
(2)server.xml文件
2.访问文件web-apps文件下:
2.1 myweb文件里的文件:
2.1.1 myweb根目录下的文件:
(1)index.html文件
2.1.2 web文件里的文件:
(1)bee0.png图片
(2)reg.html文件:注意form表单里的方法为post,则名字密码等信息在请求正文里(隐藏,看不到)
若方法改为GET则,名字,密码等信息在请求行里
(3)reg_success.html文件
(4)reg_fail.html文件
(6)login_success.html文件:
(7)login_fail.html文件:
(8)500.html文件
2.1.3 WEB-INF文件里的文件:
(1)web.xml文件
2.2 ROOT文件里的文件:
(1)404.html文件
二.建9个类,一个服务器,一个请求解析,一个响应用户,一个服务器配置信息,一个Http协议相关定义信息,
一个处理注册用户的信息的子类,一个处理登陆用户的信息的子类,一个处理用户请求的父类,
一个服务器请求项目配置信息
(1)服务器请求项目配置信息
(2)服务器配置信息的类
(3)Http协议相关定义信息的类
(4)处理用户请求的父类
(5)处理注册用户的信息的子类
(6)处理登陆用户的信息的子类
(7)请求解析的类
(8)响应用户的类
(9)服务器的类
注意:各个文件里的内容跟文件的访问路径,Maven导入dom4j包解析xml文件
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> <welcome-file-list> <welcome-file>myweb/index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </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文件下:
2.1 myweb文件里的文件:
2.1.1 myweb根目录下的文件:
(1)index.html文件
<html> <head> <title>hello</title> <meta charset="UTF-8"> </head> <body> <center> <h1>这是我的第一个页面</h1> <img src="web/bee0.png"> <a href="web/reg.html">去注册</a> <a href="web/login.html">去登陆</a> </center> </body> </html>
2.1.2 web文件里的文件:
(1)bee0.png图片
(2)reg.html文件:注意form表单里的方法为post,则名字密码等信息在请求正文里(隐藏,看不到)
若方法改为GET则,名字,密码等信息在请求行里
<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>(5)login.html文件:
<html> <head> <title>欢迎登陆</title> <meta charset="UTF-8 11792 "> </head> <body> <center> <h1>用户登陆</h1> <form method="post" action="loginUser"> <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>
(6)login_success.html文件:
<html> <head> <title>登陆成功</title> <meta charset="UTF-8"> </head> <body> <center> <h1>登陆成功</h1> <form method="post" action="../loginUser"> </center> </body> </html>
(7)login_fail.html文件:
<html> <head> <title>登陆失败</title> <meta charset="UTF-8"> </head> <body> <center> <h1>登陆失败</h1> <form method="post" action="../loginUser"> <a href="login.html">重新登陆</a> </center> </body> </html>
(8)500.html文件
<html> <head> <meta charset="utf-8"> </head> <body> <center> <h1>500</h1> <h2>服务器异常!</h2> </center> </body> </html>
2.1.3 WEB-INF文件里的文件:
(1)web.xml文件
<?xml version="1.0" encoding="UTF-8"?> <web-app> <!-- 配置一个Servlet的类名,用于反射 --> <servlet> <servlet-name>RegServlet</servlet-name> <servlet-class>web.v5.RegServlet</servlet-class> </servlet> <servlet> <servlet-name>LoginServlet</servlet-name> <servlet-class>web.v5.LoginServlet</servlet-class> </servlet> <!-- mapping用于将请求与Servlet关联 --> <servlet-mapping> <servlet-name>RegServlet</servlet-name> <url-pattern>/myweb/web/regUser</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>LoginServlet</servlet-name> <url-pattern>/myweb/web/loginUser</url-pattern> </servlet-mapping> </web-app>
2.2 ROOT文件里的文件:
(1)404.html文件
<html> <head> <meta charset="utf-8"> </head> <body> <center> <h1>404</h1> <h2>没有找到该资源!</h2> </center> </body> </html>
二.建9个类,一个服务器,一个请求解析,一个响应用户,一个服务器配置信息,一个Http协议相关定义信息,
一个处理注册用户的信息的子类,一个处理登陆用户的信息的子类,一个处理用户请求的父类,
一个服务器请求项目配置信息
(1)服务器请求项目配置信息
package web.v5; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.util.HashMap; import java.util.List; import java.util.Map; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.Element; import org.dom4j.io.SAXReader; /** * 对应项目WEB-INF目录中web.xml中的配置信息 * @author soft01 * */ public class ApplicationConfig { /* * 保存web.xml文件中所有<servlet>中的信息 * key:子标签<servlet-name>中间的文本信息 * value:子标签<servlet-class>中间的文本信息 */ private Map<String,String> servletMap = new HashMap<String,String>(); /* * 保存web.xml文件中所有<servlet-mapping> * 中的信息 * key:子标签<url-pattern>中间的文本信息 * value:子标签<servlet-name>中间的文本信息 */ private Map<String,String> servletMappingMap = new HashMap<String,String>(); /** * 根据给定的文件初始化配置对象 * @param file */ public ApplicationConfig(File file) { try { SAXReader reader = new SAXReader(); Document doc = reader.read(new FileInputStream(file)); Element root = doc.getRootElement(); List<Element> list1 = root.elements("servlet"); for(Element ele : list1) { String key = ele.elementText("servlet-name"); String value = ele.elementText("servlet-class"); servletMap.put(key,value); } List<Element> list2 = root.elements("servlet-mapping"); for(Element ele : list2) { String value = ele.elementText("servlet-name"); String key = ele.elementText("url-pattern"); servletMappingMap.put(key,value); } } catch (FileNotFoundException | DocumentException e) { e.printStackTrace(); } } public Map<String, String> getServletMap() { return servletMap; } public Map<String, String> getServletMappingMap() { return servletMappingMap; } }
(2)服务器配置信息的类
package web.v5; import java.io.File; import java.io.FileInputStream; import java.util.ArrayList; 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; /** * 服务端配置数据 * 通过解析conf/server.xml文件得到配置数据 * 通过解析WEB-INF目录web.xml文件得到请求配置数据 * @author soft01 * */ public class Server { public static String URIENCODING; public static int PORT; public static String PROTOCOL; public static int MAX_THREADS; /** * 每个项目对应的配置文件web.xml信息 * 当前Map的结构 * Key:web-apps中每个项目的名字(web-apps * 中每个目录的名字作为该项目的名字) * Value:对应该项目中WEB-INFO中web.xml文件的 * 配置信息,一个ApplicationConfig实例 */ public static Map<String,ApplicationConfig> appConfigs; public static List<String> welcomeFileList; static { //初始化服务端主配置信息conf/server.xml initServerConfig(); //初始化首页信息,以及HttpContext相关信息conf/web.xml initWebConfig(); //初始化所有web项目配置信息 initApplicationConfigs(); } /** * 初始化WebServer主要配置信息端口, * 线程池信息等。 */ private static void initServerConfig() { // 解析server.xml文件 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 (Exception e) { e.printStackTrace(); } } /** * 加载conf/web.xml文件的相关配置信息 */ private static void initWebConfig(){ try { welcomeFileList = new ArrayList<String>(); /* * 加载conf/web.xml初始化首页 * 信息 * 再初始化HttpContext的相关信息 */ SAXReader reader = new SAXReader(); Document doc = reader.read(new FileInputStream("conf/web.xml")); Element root = doc.getRootElement(); /* * 获取<welcome-file-list>标签中的 * 每一项,并存入welcomeFileList集合中 */ Element welcomeFileListEle = root.element("welcome-file-list"); List<Element> welcomeFileEleList = welcomeFileListEle.elements("welcome-file"); for(Element welcomeFileEle : welcomeFileEleList){ welcomeFileList.add(welcomeFileEle.getTextTrim()); } /* * 将跟标签传递给HttpContext的初始化 * Content-Type映射信息 */ HttpContext.initMimeMapping(root); } catch (Exception e) { e.printStackTrace(); } } /* * 初始化每个项目配置信息 */ private static void initApplicationConfigs() { appConfigs = new HashMap<String,ApplicationConfig>(); /* * 表示web-apps目录 */ File root = new File("web-apps"); /* * 获取web-apps下的所有应用项目目录 */ File[] applications = root.listFiles((f) -> f.isDirectory()); /* * 目标,将web-apps中每个应用项目中的 WEB-INF目录里的web.xml初始化为一个 ApplicationConfig对象,并将应用 * 目录的名字做为Key,ApplicationConfig 对象作为value,存入到Server的静态属性: appConfigs当中 */ /* * 遍历每个应用目录,获取其中的WEB-INF目录 */ for (File application : applications) { File[] webInfo = application.listFiles((f) -> f.getName().equals("WEB-INF")); // 若含有WEB-INF目录 if(webInfo.length>0) { //获取其中的web.xml文件 File webInfDir = webInfo[0]; File[] webXmlFile = webInfDir.listFiles((f) -> f.getName().equals("web.xml")); //是否含有web.xml文件 if(webXmlFile.length>0) { //根据该web.xml文件初始化配置对象 ApplicationConfig app = new ApplicationConfig(webXmlFile[0]); appConfigs.put("/"+application.getName(), app); } } } } }
(3)Http协议相关定义信息的类
package web.v5; import java.util.HashMap; import java.util.List; import java.util.Map; import org.dom4j.Element; /** * 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_REDIRECT = 302; 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(); } private static void initCodeMapping() { STATUS_CODE_MAPPING.put(200, "ok"); STATUS_CODE_MAPPING.put(302, "found"); STATUS_CODE_MAPPING.put(404, "not found"); STATUS_CODE_MAPPING.put(500, "internal server error"); } public static void initMimeMapping(Element root) { /* * 解析当前目录下的子目录conf中的文件web.xml * 将该文件中所有<mime-mapping>标签中内容 * 存入MIME_MAPPING这个Map中 * 其中Key为<extension>标签中的文本信息 * value为<mime-type>标签中的文本信息 */ try { 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(); } } }
(4)处理用户请求的父类
package web.v5; import java.io.File; /** * 跳转到指定请求资源路径 * @author soft01 * */ public class HttpServlet { public void service(HttpRequest request,HttpResponse response) { } public void forward(HttpRequest request,HttpResponse response,String url) { File file = new File("web-apps"+url); response.setStatusCode(HttpContext.STATUS_CODE_OK); response.setContentType(HttpContext.MIME_MAPPING.get("html")); response.setContentLength(file.length()); response.setEntity(file); } }
(5)处理注册用户的信息的子类
package web.v5; 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 extends HttpServlet{ 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(name=="" && pwd=="") { forward(request,response, File.separator + "myweb" + File.separator + "web"+ File.separator+ "reg_fail.html"); }else { if (have) { forward(request,response, File.separator + "myweb" + File.separator + "web"+ File.separator+ "reg_fail.html"); } else { /* * 将用户的注册信息写入服务端本地的一个 * 文件user.txt中 */ // 写入文件 pw = new PrintWriter(new OutputStreamWriter(new FileOutputStream("user.txt", true), "utf-8")); pw.println(name + "," + pwd); pw.flush(); /* * 响应用户注册成功页面 */ forward(request,response, File.separator + "myweb" + File.separator + "web"+ File.separator+ "reg_success.html"); } } }catch(Exception e) { e.printStackTrace(); forward(request,response,File.separator + "myweb" + File.separator + "web" + File.separator + "500.html"); }finally { if(br != null){ try { br.close(); } catch (IOException e) { e.printStackTrace(); } } if(pw!=null) { pw.close(); } } } }
(6)处理登陆用户的信息的子类
package web.v5; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; public class LoginServlet extends HttpServlet{ public void service(HttpRequest request,HttpResponse response) { 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]) && pwd.equals(data[1])) { have = true; break; } } } if (have) { forward(request,response, File.separator + "myweb" + File.separator + "web"+ File.separator+ "login_success.html"); } else { /* * 响应用户登陆失败页面 */ forward(request,response, File.separator + "myweb" + File.separator + "web"+ File.separator+ "login_fail.html"); } }catch(Exception e) { e.printStackTrace(); forward(request,response,File.separator + "myweb" + File.separator + "web" + File.separator + "500.html"); }finally { if(br != null){ try { br.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
(7)请求解析的类
package web.v5; 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("="); if(querys[i].indexOf("=") != querys[i].length()-1) { parasMap.put(data1[0],data1[1]); }else{ parasMap.put(data1[0],""); } } } 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(); } } } } /** * 获取应用项目名 * @return */ public String getContextPath() { /* * 常见的requestLine格式: * 目标,获取下面地址中[]中间的内容 * http://localhost:8088[/web]/web/regUser * http://localhost:8088/ * * 解析URL后,request中的requestLine如下: * /web/web/regUser * /web/index.html * /index.html */ if(requestLine.length()>1) { //查找第二个"/"的位置 int index = requestLine.indexOf("/",1); if(index>0) { return requestLine.substring(0,index); } } return ""; } 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 getUrl() { return url; } public String getRequestLine() { return requestLine; } public String getParameter(String name) { return parasMap.get(name); } }
(8)响应用户的类
package web.v5; 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 sendRedirect(String url) { //设置响应中的状态行的状态代码为302(重定向) this.setStatusCode(HttpContext.STATUS_CODE_REDIRECT); /* * 在响应头中添加一个为重定向指定的路径 * Location头,它的值就是告知浏览器访问该地址 */ this.headers.put("Location", url); } public void sendReResponseContent(){ if(entity==null || entity.isDirectory()) { return; } 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; } }
(9)服务器的类
package web.v5; 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()); //是否去首页 if(request.getUrl().equals("/")) { toWelcomPage(request,response); // 判断是否为请求业务 }else if(checkServletRequest(request)) { executeServlet(request,response); //响应静态资源 } else { responseFile(request,response); System.out.println("响应完毕"); } response.flush(); } catch (Exception e) { e.printStackTrace(); }finally { try { socket.close(); } catch (IOException e) { e.printStackTrace(); } } } /** * 跳转首页 * @param request * @param response */ private void toWelcomPage(HttpRequest request,HttpResponse response) { /* * 遍历所有配置的首页信息,找到可用首页并进行跳转 */ boolean have = false;//是否首页可用 for(String path : Server.welcomeFileList) { File welcomPage = new File("web-apps"+File.separator+path); if(welcomPage.exists()) { //重定向到该页面 response.sendRedirect(path); have=true; } } if(!have) { response404(request,response); } } /** * 根据request判断该请求是否为请求Servlet * @param request * @return */ private boolean checkServletRequest(HttpRequest request) { /* * 1:根据请求获取对应应用项目的配置文件 * 2:根据请求路径查看配置文件中是否有对应的 * Servlet,并将判断结果返回。 */ //找到"web"项目的配置文件 ApplicationConfig config = Server.appConfigs.get(request.getContextPath()); //找到对应性用项目的配置文件 if(config !=null) { return config.getServletMappingMap().containsKey(request.getRequestLine()); } //返回false表示该请求不是对应Servlet return false; } /** * 执行Servlet * @param request * @param response */ private void executeServlet(HttpRequest request,HttpResponse response) { try { ApplicationConfig config = Server.appConfigs.get(request.getContextPath()); //找到请求对应的Servlet的名字 String servletName = config.getServletMappingMap().get(request.getRequestLine()); String servletClassName = config.getServletMap().get(servletName); /* * 利用反射机制加载Servlet并调用service方法 */ ClassLoader loader = ClassLoader.getSystemClassLoader(); Class c = loader.loadClass(servletClassName); HttpServlet servlet = (HttpServlet)c.newInstance(); servlet.service(request, response); }catch(Exception e) { e.printStackTrace(); } } /** * 响应一个静态资源(静态页面,图片等) * @param request * @param response */ private void responseFile(HttpRequest request,HttpResponse response) { try { File file = new File("web-apps" + request.getRequestLine()); if (file.exists() && file.isFile()) { // 响应用户请求的资源 // 设置状态码 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); // 设置Content-Type response.setContentType(contentType); response.setContentLength(file.length()); // 设置实体数据 response.setEntity(file); } else { response404(request,response); } }catch(Exception e) { e.printStackTrace(); } } /** * 响应404页面 * @param request * @param response */ private void response404(HttpRequest request,HttpResponse response) { //响应404页面 File notFoundPage = new File("web-apps"+File.separator+"ROOT"+File.separator+"404.html"); response.setStatusCode(HttpContext.STATUS_CODE_NOT_FOUND); response.setContentType("text/html"); response.setContentLength(notFoundPage.length()); response.setEntity(notFoundPage); } } }
注意:各个文件里的内容跟文件的访问路径,Maven导入dom4j包解析xml文件
相关文章推荐
- 利用简易Tomcat服务器结合MysqL实现Android手机注册与登录(客户端部分)
- 利用简易Tomcat服务器结合MysqL实现Android手机注册与登录(服务器部分)
- 用友nc手动注册功能节点以及弹窗JDialog并实现其功能(二次登录总结)
- 利用简易Tomcat服务器结合MysqL实现Android手机注册与登录(客户端部分)
- 利用简易Tomcat服务器结合MysqL实现Android手机注册与登录(服务器部分)
- iOS实战演练之关于数据交互的问题(利用XAMPP搭建本地服务器, 编写PHP代码实现iOS端注册登录功能)
- ssm中登录功能的实现以及页面跳转
- 简易 的QQ APP登录以及注册页面的实现
- ssm中登录功能的实现以及页面跳转
- 简单的登录、注册以及带有验证码功能
- 淘宝界面实现以及登录注册界面
- 创建并部署一个Servlet,要求在实现用户登录功能,当用户名和密码正确时跳转到欢迎页面,否则提示出错信息
- [置顶] JSP+Servlet+JavaBean传统方式实现简易留言板制作(注册、登录、留言)
- php实现登录注册功能
- 用servlet实现登录注册功能时遇到的问题和解决方法
- 加入数据库mysql实现android注册登陆功能的客户端服务器源码与解析socket
- Yale cas服务器端/客户端环境配置以及其在tomcat服务器下SSL安全协议得部署之完全实现篇
- Yale cas服务器端/客户端环境配置以及其在tomcat服务器下SSL安全协议得部署之完全实现篇
- Java小程序之集合框架模拟数据库实现用户登录和注册功能
- 实现简单的登录注册以及增删查改(二)