您的位置:首页 > 运维架构 > Tomcat

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>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息