Rhyme/ 手写服务器 实现一个基于xml解析的简单的Tomcat服务器
2017-10-25 00:59
1101 查看
手写服务器 实现一个基于xml解析的简单的Tomcat服务器
效果图:实现了基于xml配置的servlet动态匹配
源代码:
Server.java 服务器启动类
package com.maple.server; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import com.maple.util.IOUtil; /** * Server * * 1.request * 2.response * * @author RhymeChiang * @date 2017/10/23 */ /** * @author RhymeChiang * @date 2017/10/23 */ public class Server { private ServerSocket server = null; private boolean isShutDown = false; public void start() { start(8888); } public void start(int port) { try { server = new ServerSocket(port); this.receive(); } catch (IOException e) { // e.printStackTrace(); stop(); } } private void receive() { try { while(!isShutDown) { Socket client = server.accept(); new Thread(new Dispatcher(client)).start(); } } catch (IOException e) { //e.printStackTrace(); stop(); } } public void stop() { isShutDown = true; IOUtil.closeAll(server); } public static void main(String[] args) { Server server = new Server(); server.start(); } }
Request.java 处理解析浏览器的URL请求
package com.maple.server; import java.io.IOException; import java.io.InputStream; import java.net.Socket; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.StringTokenizer; /** * deal with client request * @author RhymeChiang * @date 2017/10/23 */ public class Request { /* * ===============Request================ * GET /index.jsp?name=Rhyme&pwd=123 HTTP/1.1 Host: localhost:8888 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*;q=0.8 Accept-Encoding: gzip, deflate, br Accept-Language: en-US,en;q=0.8,zh-CN;q=0.6,zh;q=0.4 Connection: close ==============Response================= POST /index.jsp HTTP/1.1 Host: localhost:8888 Content-Length: 18 Cache-Control: max-age=0 Upgrade-Insecure-Requests: 1 Origin: null Content-Type: application/x-www-form-urlencoded User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*;q=0.8 Accept-Encoding: gzip, deflate, br Accept-Language: en-US,en;q=0.8,zh-CN;q=0.6,zh;q=0.4 Connection: close name=Rhyme&pwd=123 */ private String requestMethod; private String requestURI; private String requestParams; private final String CRLF = "\r\n"; private final String BLANK = " "; private Map<String,List<String>>parmsMap = null; public Request(Socket client) { requestMethod = ""; requestURI = ""; requestParams = ""; parmsMap = new HashMap<>(); try { this.parseRequest(client); } catch (IOException e) { e.printStackTrace(); } } public void parseRequest(Socket client) throws IOException { InputStream in = client.getInputStream(); byte b [] = new byte[20480]; int len = in.read(b); String requestInfo = new 4000 String(b,0,len); requestMethod =requestInfo.substring(0,requestInfo.indexOf(BLANK)); requestURI =requestInfo.substring(requestInfo.indexOf("/"),requestInfo.indexOf("HTTP/1.1")).trim(); if(requestURI.contains("?")) { requestParams = requestURI.substring(requestURI.indexOf("?")+1); requestURI = requestURI.substring(0,requestURI.indexOf("?")); } if(requestMethod.equalsIgnoreCase("post")) { requestParams = requestInfo.substring(requestInfo.lastIndexOf(CRLF)+2); } parseParams(requestParams); } private void parseParams(String requestParams) { StringTokenizer tokens = new StringTokenizer(requestParams, "&"); while(tokens.hasMoreTokens()) { String token = tokens.nextToken(); String[] split = token.split("="); String key = split[0]; String values = split.length>1?split[1]:null; if(!parmsMap.containsKey(key)) { List<String>list = new ArrayList<>(); list.add(values); parmsMap.put(key, list); }else { parmsMap.get(key).add(values); } } } public String getParameter(String key) { if(parmsMap.containsKey(key)) { return parmsMap.get(key).get(0); } return null; } public String getParameters(String key) { if(parmsMap.containsKey(key)) { return parmsMap.get(key).toString(); } return null; } public String getRequestMethod() { return requestMethod; } public void setRequestMethod(String requestMethod) { this.requestMethod = requestMethod; } public String getRequestURI() { return requestURI; } public void setRequestURI(String requestURI) { this.requestURI = requestURI; } public String getRequestParams() { return requestParams; } public void setRequestParams(String requestParams) { this.requestParams = requestParams; } public Map<String, List<String>> getParmsMap() { return parmsMap; } public void setParmsMap(Map<String, List<String>> parmsMap) { this.parmsMap = parmsMap; } }
Response.java 返回响应给用户的数据
package com.maple.server; import java.io.BufferedWriter; import java.io.IOException; import java.io.OutputStreamWriter; import java.net.Socket; import java.util.Date; import com.maple.util.IOUtil; /** * package response * @author RhymeChiang * @date 2017/10/23 */ public class Response { private final String BLANK = " "; private final String CRLF = "\r\n"; private StringBuilder context = new StringBuilder(); /** * create the header of response * @param code * status code * 200 OK * 404 NOT FOUND * 500 SERVER ERROR * @param len * length of context * @return */ private StringBuilder createHeadInfo(int code,int len) { StringBuilder headInfo = new StringBuilder(); headInfo.append("HTTP/1.1").append(BLANK).append(code).append(BLANK); switch (code) { case 200: headInfo.append("OK"); break; case 404: headInfo.append("NOT FOUND"); break; case 500: headInfo.append("SERVER ERROR"); break; default: break; } headInfo.append(CRLF); headInfo.append("Server:Rhyme").append(BLANK).append("Rhyme/1.0.0").append(CRLF); headInfo.append("Date:").append(new Date()).append(BLANK).append("GMT").append(CRLF); headInfo.append("Content-Type:text/html;charset=utf-8").append(CRLF); headInfo.append("Content-Length:").append(len).append(CRLF); headInfo.append(CRLF); return headInfo; } /** * create the context of response * @param msg * the context of response * @return * Response */ public Response println(String msg) { context.append(msg).append(CRLF); return this; } /** * push repsonse to client * @param code */ public void pushToClient(int code,Socket client) { StringBuilder response = new StringBuilder(); int len = context.toString().getBytes().length; response.append(createHeadInfo(code, len)); response.append(CRLF); response.append(context.toString()); BufferedWriter bw = null; try { bw = new BufferedWriter(new OutputStreamWriter(client.getOutputStream())); bw.write(response.toString()); bw.flush(); } catch (IOException e) { //e.printStackTrace(); IOUtil.closeAll(bw); } } }
Dispatcher.java
package com.maple.server; import java.io.IOException; import java.net.Socket; import com.maple.servlet.Servlet; /** * Servlet Dispatcher * @author RhymeChiang * @date 2017/10/23 */ public class Dispatcher implements Runnable { private Request request; private Response response; private int code = 200; private Socket client; public Dispatcher(Socket client) { this.client = client; request = new Request(client); response = new Response(); } @Override public void run() { Servlet servlet = WebApp.getServlet(request.getRequestURI()); if (servlet == null) { response.pushToClient(404, client); return; }else { try { servlet.service(request, response); response.pushToClient(code, client); } catch (IOException e) { // e.printStackTrace(); response.pushToClient(500, client); } if (null != client) { try { client.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
Webapp.java
package com.maple.server; import java.io.IOException; import java.util.List; import java.util.Map; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.xml.sax.SAXException; import com.maple.servlet.Servlet; import com.maple.servlet.ServletContext; import com.maple.servlet.ServletEntity; import com.maple.servlet.ServletMappingEntity; /** * xml parse and prepare resourses * @author RhymeChiang * @date 2017/10/24 */ public class WebApp { public static ServletContext context; static { context = new ServletContext(); try { init(); } catch (ParserConfigurationException e) { e.printStackTrace(); } catch (SAXException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } public static void init() throws ParserConfigurationException, SAXException, IOException { SAXParserFactory factory = SAXParserFactory.newInstance(); SAXParser parser = factory.newSAXParser(); WebXmlHandler web = new WebXmlHandler(); parser.parse(Thread.currentThread().getContextClassLoader().getResourceAsStream("web.xml"), web); List<ServletEntity> l1 = web.getServletList(); List<ServletMappingEntity> l2 = web.getMappingList(); Map<String, String> servlet = context.getServlet(); Map<String, String> mapping = context.getServletMapping(); for(ServletEntity s:l1) { servlet.put(s.getServletName(), s.getServletClass()); } for(ServletMappingEntity s:l2) { mapping.put(s.getUrlPatterns(), s.getServletName()); } } public static Servlet getServlet(String requestURI) { if (null == requestURI || requestURI.trim().equals("")) { return null; } String url = context.getServletMapping().get(requestURI); if (url == null) { return null; } String reflect = context.getServlet().get(url); Servlet s = null; try { Class<?> clazz = Class.forName(reflect); s = (Servlet) clazz.newInstance(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } return s; } }
package com.maple.server; import java.util.ArrayList; import java.util.List; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; import com.maple.servlet.ServletEntity; import com.maple.servlet.ServletMappingEntity; /** * @author RhymeChiang * @date 2017/10/24 */ public class WebXmlHandler extends DefaultHandler { private List<ServletEntity> servletList; private List<ServletMappingEntity> mappingList; private ServletEntity servlet = null; private ServletMappingEntity mapping = null; private boolean isMapping = false; private String beginTag; public WebXmlHandler() { servletList = new ArrayList<>(); mappingList = new ArrayList<>(); } @Override public void startDocument() throws SAXException { } @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if (qName != null) { beginTag = qName; if (qName.equals("servlet")) { servlet = new ServletEntity(); isMapping = false; } else if (qName.equals("servlet-mapping")) { mapping = new ServletMappingEntity(); isMapping = true; } } } @Override public void characters(char[] ch, int start, int length) throws SAXException { String content = new String(ch, start, length); if (!isMapping) { if (beginTag.equals("servlet-name")) { servlet.setServletName(content); } else if (beginTag.equals("servlet-class")) { servlet.setServletClass(content); servletList.add(servlet); } } else if(isMapping){ if (beginTag.equals("servlet-name")) { mapping.setServletName(content); } else if (beginTag.equals("url-parttens")) { mapping.setUrlPatterns(content); mappingList.add(mapping); } } } @Override public void endElement(String uri, String localName, String qName) throws SAXException { beginTag = ""; } @Override public void endDocument() throws SAXException { } public List<ServletEntity> getServletList() { return servletList; } public void setServletList(List<ServletEntity> servletList) { this.servletList = servletList; } public List<ServletMappingEntity> getMappingList() { return mappingList; } public void setMappingList(List<ServletMappingEntity> mappingList) { this.mappingList = mappingList; } } package com.maple.servlet; import java.io.IOException; import com.maple.server.Request; import com.maple.server.Response; /** * @author RhymeChiang * @date 2017/10/23 */ public abstract class Servlet { public void service(Request request, Response response) throws IOException { this.doGet(request, response); this.doPost(request, response); } public abstract void doGet(Request request, Response response) throws IOException; public abstract void doPost(Request request, Response response) throws IOException; } package com.maple.servlet; import java.io.IOException; import com.maple.server.Request; import com.maple.server.Response; /** * @author RhymeChiang * @date 2017/10/23 */ public class LoginServlet extends Servlet { @Override public void doGet(Request request, Response response) throws IOException { } @Override public void doPost(Request request, Response response) throws IOException { System.out.println("doPost"); response.println("<html>"); response.println("<head>"); response.println("</head>"); response.println("<body>"); response.println("<h1>"); response.println("Hello,I'm " + request.getParameter("name")); response.println("My pwd is " + request.getParameter("pwd")); response.println("My Hobby is " + request.getParameters("hobby")); response.println("</h1>"); response.println("</body>"); response.println("<html>"); } } package com.maple.servlet; import java.util.HashMap; import java.util.Map; /** * @author RhymeChiang * @date 2017/10/24 */ public class ServletContext { private Map<String, String> servlet; private Map<String, String> servletMapping; public ServletContext() { super(); servlet = new HashMap<>(); servletMapping = new HashMap<>(); } public Map<String, String> getServlet() { return servlet; } public void setServlet(Map<String, String> servlet) { this.servlet = servlet; } public Map<String, String> getServletMapping() { return servletMapping; } public void setServletMapping(Map<String, String> servletMapping) { this.servletMapping = servletMapping; } } package com.maple.servlet; /** * @author RhymeChiang * @date 2017/10/25 */ public class ServletEntity { private String servletName; private String servletClass; public ServletEntity() { } public ServletEntity(String servletName, String servletClass) { this.servletName = servletName; this.servletClass = servletClass; } public String getServletName() { return servletName; } public void setServletName(String servletName) { this.servletName = servletName; } public String getServletClass() { return servletClass; } public void setServletClass(String servletClass) { this.servletClass = servletClass; } } package com.maple.servlet; /** * @author RhymeChiang * @date 2017/10/25 */ public class ServletMappingEntity { private String urlPatterns; private String servletName; public ServletMappingEntity() { } public ServletMappingEntity(String urlPatterns, String servletName) { this.urlPatterns = urlPatterns; this.servletName = servletName; } public String getUrlPatterns() { return urlPatterns; } public void setUrlPatterns(String urlPatterns) { this.urlPatterns = urlPatterns; } public String getServletName() { return servletName; } public void setServletName(String servletName) { this.servletName = servletName; } } package com.maple.util; import java.io.Closeable; import java.io.IOException; /** * @author RhymeChiang * @date 2017/10/23 */ public class IOUtil { public static void closeAll(Closeable...io) { for(Closeable i :io) { if(null!=i) { try { i.close(); } catch (IOException e) { e.printStackTrace(); } } } } } <?xml version="1.0" encoding="UTF-8"?> <web-app> <servlet> <servlet-name>login</servlet-name> <servlet-class>com.maple.servlet.LoginServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>login</servlet-name> <url-parttens>/login</url-parttens> </servlet-mapping> <servlet-mapping> <servlet-name>login</servlet-name> <url-parttens>/log</url-parttens> </servlet-mapping> </web-app>
相关文章推荐
- 基于Socket编程实现一个简单的Web服务器
- 带你实现一个简单的MyApacheTomcat,迷你并发服务器
- 基于epoll实现的一个简单web服务器
- 一个基于AIO实现的简单web服务器
- [Tomcat服务器 --- 一个简单的基于HTTP WEB服务器]
- java实现一个叫简单的xml解析
- java实现一个简单的Web服务器实例解析
- 带你实现一个简单的MyApacheTomcat,迷你并发服务器
- 使用一个超简单的类实现一个简易服务器,明白Tomcat的运行机制
- 分享:基于epoll实现的一个简单的web服务器
- Android上实现一个简单的天气预报APP(五) 解析XML
- 分享:基于epoll实现的一个简单的web服务器
- golang简单实现一个基于TLS/SSL的 TCP服务器和客户端
- Tomcat服务器的模拟实现学习解析Http协议、反射、xml解析等
- tomcat原理解析(一):一个简单的实现
- 基于Java web服务器简单实现一个Servlet容器
- tomcat解析(-)学习如何写一个servlet服务器
- java.beans包里面的两个类简单地实现XML解析
- 用java实现的一个简单web服务器程序
- Tomcat的服务器配置文件server.xml解析