不使用tomcat,仅适用javaSE手写服务器--模拟登陆

Posted 行者老夫

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了不使用tomcat,仅适用javaSE手写服务器--模拟登陆相关的知识,希望对你有一定的参考价值。

1、搭建框架

我们只是简单模拟,框架简单分三个模块

a,服务器端server包

b,servlet,根据不同的请求url,利用反射生产对应的servlet

c,IO工具包,用来关闭IO流

    d,编写web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app>
	<servlet>
		<servlet-name>login</servlet-name>
		<servlet-class>com.xzlf.servlet.LoginServlet</servlet-class>
	</servlet>
	<servlet>
		<servlet-name>register</servlet-name>
		<servlet-class>com.xzlf.servlet.RegisterServlet</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>login</servlet-name>
		<url-pattern>/login</url-pattern>	
		<url-pattern>/log</url-pattern>	
	</servlet-mapping>
	<servlet-mapping>
		<servlet-name>register</servlet-name>
		<url-pattern>/register</url-pattern>	
		<url-pattern>/reg</url-pattern>	
		<url-pattern>/r</url-pattern>	
	</servlet-mapping>
</web-app>
e,写一个简单的html用于测试
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>登录</title>
</head>
<body>
	<form action="http://localhost:8888/log" method="get">
		<p>
			用户名:<input type="text" name="uname" id="uname" />
		</p>
		<p>
			密码:<input type="password" name="pwd" id="pwd" />
		</p>
		<p>
			<input type="submit" value="登录" />
		</p>
	</form>
</body>
</html>
    f, IO工具包比比较简单,先写了:
package com.xzlf.util;

import java.io.Closeable;
import java.io.IOException;

/**
 * 关闭流
 * @author xzlf
 *
 */
public class IOUtil {
	public static void closeAll(Closeable...closeables) {
		for (Closeable close : closeables) {
			if(close != null) {
				try {
					close.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			
		}
	}
}

2、编写xml文件以及对xml解析以及数据存储程序

a,编写存放xml文件中servlet-name 和 servlet-class 的javabean 对象Entity
package com.xzlf.server;

/**
 * 映射servlet-name 和 servlet-class
 * @author xzlf
 *
 */
public class Entity {
	// servlet-name
	private String name;
	
	// servlet -class
	private String clazz;
	
	public Entity() {
		// TODO Auto-generated constructor stub
	}

	public Entity(String name, String clazz) {
		super();
		this.name = name;
		this.clazz = clazz;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getClazz() {
		return clazz;
	}

	public void setClazz(String clazz) {
		this.clazz = clazz;
	}
	
}

b,编写存放xml文件中servlet-name 和 url-pattern 的javabean 对象Mapping
package com.xzlf.server;

import java.util.ArrayList;
import java.util.List;

/**
 * 映射 servlet-name  和 url-pattern
 * @author xzlf
 *
 */
public class Mapping {

	// servlet-name
	private String name;
	
	// url-pattern
	private List<String> urlList;
	
	public Mapping() {
		this.urlList = new ArrayList<String>();
	}

	public Mapping(String name, List<String> urlList) {
		this();
		this.name = name;
		this.urlList = urlList;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public List<String> getUrlList() {
		return urlList;
	}

	public void setUrlList(List<String> urlList) {
		this.urlList = urlList;
	}
	
}

c,编写解析xml文件(使用Dom4j)的程序
package com.xzlf.server;

import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

/**
 * 解析xml
 * @author xzlf
 *
 */
public class WebDom4j {
	// 存储Entity
	private List<Entity> entityList;
	
	// 存储Mapping
	private List<Mapping> mappingList;
	
	public WebDom4j() {
		this.entityList = new ArrayList<Entity>();
		this.mappingList = new ArrayList<Mapping>();
	}

	public WebDom4j(List<Entity> entityList, List<Mapping> mappingList) {
		this();
		this.entityList = entityList;
		this.mappingList = mappingList;
	}

	public List<Entity> getEntityList() {
		return entityList;
	}

	public void setEntityList(List<Entity> entityList) {
		this.entityList = entityList;
	}

	public List<Mapping> getMappingList() {
		return mappingList;
	}

	public void setMappingList(List<Mapping> mappingList) {
		this.mappingList = mappingList;
	}
	
	public Document getDocument() {
		Document doc = null;
		try {
			// 1、穿件SAXReader 对象
			SAXReader reader = new SAXReader();
			// 2、调用 read() 方法
			doc = reader.read(new File("src/WEB_INFO/webxml.xml"));
		} catch (DocumentException e) {
			e.printStackTrace();
		}
		return doc;
	}
	
	
	public void parse(Document doc) {
		// 1、获取根元素
		Element rootElement = doc.getRootElement();
		// 2、获取servlet 子元素
		for(Iterator<Element> elementIterator = rootElement.elementIterator("servlet");
				elementIterator.hasNext();) {
			Element ele = elementIterator.next();
			Entity entity = new Entity();
			for (Iterator<Element> eleIterator = ele.elementIterator(); eleIterator.hasNext();) {
				Element e = eleIterator.next();
				if("servlet-name".equals(e.getName())) {
					entity.setName(e.getText());
				}else if("servlet-class".equals(e.getName())) {
					entity.setClazz(e.getText());
				}
			}
			this.entityList.add(entity);
		}
		// 3、获取servlet-mapping 子元素
		for(Iterator<Element> elementIterator = rootElement.elementIterator("servlet-mapping");
				elementIterator.hasNext();) {
			Element ele = elementIterator.next();
			Mapping mapping = new Mapping();
			for (Iterator<Element> eleIterator = ele.elementIterator(); eleIterator.hasNext();) {
				Element e = eleIterator.next();
				if("servlet-name".equals(e.getName())) {
					mapping.setName(e.getText());
				}else if("url-pattern".equals(e.getName())) {
					mapping.getUrlList().add(e.getText());
				}
			}
			this.mappingList.add(mapping);
		}
	}
	
	/* 测试
	 * public static void main(String[] args) {
		WebDom4j web = new WebDom4j();
		web.parse(web.getDocument());
		List<Entity> entityList2 = web.getEntityList();
		System.out.println(entityList2.size());
		for (Entity entity : entityList2) {
			System.out.println(entity.getName() + "--" + entity.getClazz());
		}
		System.out.println("============================");
		List<Mapping> mappingList2 = web.getMappingList();
		System.out.println(mappingList2.size());
		for (Mapping mapping : mappingList2) {
			for (String url : mapping.getUrlList()) {
				System.out.println(mapping.getName() + "-->" + url);
			}
			System.out.println("------------------------");
		}
	}*/
}

d,封装serlvet 和mapping 
package com.xzlf.server;

import java.util.HashMap;
import java.util.Map;

/**
 * Servlet 上下文 ,就是一个容器
 * 映射 Mapping 和 Entity 
 * url-pattern --> servlet-class
 * @author xzlf
 *
 */
public class ServletContext {
	// key:sevlet-name value:servlet-class
	private Map<String, String> servlet;
	
	// key:url-pattern value:servlet-name
	private Map<String, String> mapping;
	
	public ServletContext() {
		this.servlet = new HashMap<String, String>();
		this.mapping = new HashMap<String, String>();
	}

	public ServletContext(Map<String, String> servlet, Map<String, String> mapping) {
		this.servlet = servlet;
		this.mapping = mapping;
	}

	public Map<String, String> getServlet() {
		return servlet;
	}

	public void setServlet(Map<String, String> servlet) {
		this.servlet = servlet;
	}

	public Map<String, String> getMapping() {
		return mapping;
	}

	public void setMapping(Map<String, String> mapping) {
		this.mapping = mapping;
	}
	
	
}

e,处理Entity 和 Maping 找出url 和 servlet-class 的映射
package com.xzlf.server;

import java.util.List;
import java.util.Map;

import com.xzlf.servlet.Servlet;

/**
 * Web应用程序
 * @author xzlf
 *
 */
public class WebApp {
	private static ServletContext context;
	static {
		context = new ServletContext();
		// 获取对应的map关系
		Map<String, String> servlet = context.getServlet();
		Map<String, String> mapping = context.getMapping();
		// 创建xml解析
		WebDom4j web = new WebDom4j();
		web.parse(web.getDocument());
		// 获取解析xml 之后的List集合
		List<Entity> entityList = web.getEntityList();
		List<Mapping> mappingList = web.getMappingList();
		
		// 将List集合中的数据存储到Map中
		for(Entity entity : entityList) {
			servlet.put(entity.getName(), entity.getClazz());
		}
		
		for (Mapping mapp : mappingList) {
			for (String url : mapp.getUrlList()) {
				mapping.put(url, mapp.getName());
			}
		}
		
	}
	
	/**
	 * 根据不同的url创建不同的servlet对象
	 * @param url
	 * @return
	 */
	public static Servlet getServlet(String url) {
		if(url == null || url.trim().equals("")) {
			return null;
		}
		
		try {
			String servletName = context.getMapping().get(url);
			String servletClazz = context.getServlet().get(servletName);
//			System.out.println(servletName + "--" + servletClazz);
			Class<?> clazz = Class.forName(servletClazz);
			Object servlet = clazz.newInstance();
			return (Servlet) servlet;
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		return null;
	}
	/*测试
	public static void main(String[] args) {
		System.out.println(getServlet("/log"));
		System.out.println(getServlet("/reg"));
	}
	*/
}

3、封装请求数据request:包括请求的url,请求参数

package com.xzlf.server;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 封装请求
 * @author xzlf
 *
 */
public class Request {
	private InputStream is;
	private String requestInfo;
	private String method;
	private String url;
	private Map<String, List<String>> parameterValues;
	private static final String BLANK = " ";
	private static final String CRLF = "\\r\\n";
	
	public Request() {
		this.parameterValues = new HashMap<String, List<String>>();
	}

	public Request(InputStream is) {
		this();
		this.is = is;
		BufferedReader read = null;
		char[] buf = new char[20480];
		int len;
		try {
			read = new BufferedReader(new InputStreamReader(is, "utf8"));
			if ((len = read.read(buf)) != -1) {
				requestInfo = new String(buf, 0, len);
			}
		} catch (IOException e) {
			requestInfo = "";
			return;
		}
		this.parseRequestInfo();
	}


	private void parseRequestInfo() {
		if(this.requestInfo.equals("")) {
			return;
		}
		int index = this.requestInfo.indexOf(\'/\');
		this.method = this.requestInfo.substring(0,index - 1).toLowerCase();
		int end = this.requestInfo.indexOf("HTTP/1.1") - 1;
		String urlStr = this.requestInfo.substring(index,end);
		int paramIndex;// 请求参数拆分位置
		String parameterStr = "";
		if ("get".equals(method)) {
			if (urlStr.contains("?")) {
				paramIndex = urlStr.indexOf(\'?\');
				this.url = urlStr.substring(0, paramIndex);
				parameterStr = urlStr.substring(paramIndex + 1);
			}else {
				parameterStr = "";
			} 
		}else {
			this.url = urlStr;
			paramIndex = this.requestInfo.lastIndexOf(CRLF);
			parameterStr = this.requestInfo.substring(paramIndex).trim();
		}
		if(parameterStr != null && !"".equals(parameterStr)) {
			String[] paramArr = parameterStr.split("&");
			for (String string : paramArr) {
				String[]  paramKV = string.split("=");
				paramKV = Arrays.copyOf(paramKV, 2);
				convertMap(paramKV);
			}
		}
//		System.out.println(parameterStr);
		
	}

	private void convertMap(String[] paramKV) {
		String k = paramKV[0];
		String v = null;
		try {
			v = paramKV[1] == null ? null : new URLDecoder().decode(paramKV[1], "utf8");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		if(!this.parameterValues.containsKey(k)) {
			parameterValues.put(k, new ArrayList<String>());
		}
		this.parameterValues.get(k).add(v);
	}

	// 根据表单提交的内容获取多个值
	public String[] getParameterValues(String name) {
		List<String> list = this.parameterValues.get(name);
		return list == null ? null : list.toArray(new String[0]);
	}
	
	// 根据表单提交的内容获取一个值
	public String getParameter(String name) {
		String[] values = this.getParameterValues(name);
		return values == null ? null : values[0];
	}
	
	public String getMethod() {
		return method;
	}


	public String getUrl() {
		return url;
	}

	public Map<String, List<String>> getParameterValues() {
		return parameterValues;
	}

}

4、封装响应数据reponse:包括响应头和响应正文

package com.xzlf.server;

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;

import com.xzlf.util.IOUtil;

/**
 * 封装响应
 * @author xzlf
 *
 */
public class Response {
	private StringBuffer headInfo;
	private  StringBuffer content;
	private int length;
	
	private BufferedWriter bw;
	
	private static final String BLANK = " ";
	private static final String CRLF = "\\r\\n";
	public Response() {
		headInfo = new StringBuffer();
		content = new StringBuffer();
	}
	
	public Response(OutputStream os) {
		this();
		try {
			bw = new BufferedWriter(new OutputStreamWriter(os, "utf-8"));
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
	}
	
	public Response print(String info) {
		content.append(info);
		try {
			length += info.getBytes("utf-8").length;
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return this;
	}
	
	public Response println(String info) {
		content.append(info);
		content.append(CRLF);
		try {
			length += (info + CRLF).getBytes("utf-8").length;
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return this;
	}
	
	public void creatHeadInfo(int code) {
		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;
		default:
			headInfo.append("SERVER ERROR");
		}
		headInfo.append(CRLF);
		headInfo.append("Content-Type: text/html;charset=utf-8").append(CRLF);
		headInfo.append("Content-Length:").append(length).append(CRLF);
		headInfo.append(CRLF);
	}
	
	public void pushToClient(int code) {
		if(headInfo == null) {
			code = 500;
		}
		
		this.creatHeadInfo(code);
		try {
			bw.write(headInfo.toString());
			bw.write(content.toString());
			bw.flush();
		} catch (IOException e) {
			e.printStackTrace();
		}
		close();
	}
	
	public void close() {
		IOUtil.closeAll(bw);
	}
}

5、编写servelt 处理请求:

package com.xzlf.servlet;

import com.xzlf.server.Request;
import com.xzlf.server.Response;

/**
 * 所有servlet 父类
 * @author xzlf
 *
 */
public abstract class Servlet {
	public void service(Request request, Response response) throws Exception {
		this.doGet(request, response);
		this.doPost(request, response);
	}

	public abstract void doPost(Request request, Response response) throws Exception;

	public abstract void doGet(Request request, Response response) throws Exception;
}

package com.xzlf.servlet;

import com.xzlf.server.Request;
import com.xzlf.server.Response;

public class LoginServlet extends Servlet {

	@Override
	public void doPost(Request request, Response response) throws Exception {
		
	}

	@Override
	public void doGet(Request request, Response response) throws Exception {
		String uname = request.getParameter("uname");
		String pwd = request.getParameter("pwd");
//		System.out.println(uname+"--" + pwd);
		if(login(uname, pwd)) {
			response.print(uname + ":登录成功");
		}else {
			response.print(uname + " 登录失败,账号或密码错误");
		}
		
	}
	
	private boolean login(String uname, String pwd) {
		if("张三".equals(uname) && "123".equals(pwd)) {
			return true;
		}
		return false;
	}
}

package com.xzlf.servlet;

import com.xzlf.server.Request;
import com.xzlf.server.Response;

public class RegisterServlet extends Servlet {

	@Override
	public void doPost(Request request, Response response) throws Exception {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void doGet(Request request, Response response) throws Exception {
		// TODO Auto-generated method stub
		
	}

}

6、加入DIspatcher分发器,开启多线程

package com.xzlf.server;

import java.io.IOException;
import java.net.Socket;

import com.xzlf.servlet.Servlet;
import com.xzlf.util.IOUtil;

/**
 * 请求响应分发器
 * @author xzlf
 *
 */
public class Dispatcher implements Runnable{
	private Socket client;
	private Request req;
	private Response rep;
	int code = 200;
	public Dispatcher(Socket client) {
		this.client = client;
		try {
			req = new Request(this.client.getInputStream());
			rep = new Response(this.client.getOutputStream());
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	@Override
	public void run() {
		String url = req.getUrl();
		System.out.println(url);
		// 根据不同的url 创建不同的servlet对象
		Servlet servlet = WebApp.getServlet(url);
		if(servlet == null) {
			code = 404;
		}else {
			try {
				servlet.service(req, rep);
			} catch (Exception e) {
				code = 500;
			}
		}
		
		rep.pushToClient(code);
		IOUtil.closeAll(client);
	}
}

7、编写服务器端

package com.xzlf.server;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

import com.xzlf.util.IOUtil;

/**
 * 启动服务
 * @author xzlf
 *
 */
public class Server {
	private ServerSocket server;
	private boolean isRuning;
	private void start(int port) {
		isRuning = true;
		try {
			server = new ServerSocket(port);
			recive();
		} catch (IOException e) {
			isRuning = false;
		}
	}
	
	private void recive() {
		try {
			
			while (isRuning) {
				Socket client = server.accept();
				Dispatcher dispatcher = new Dispatcher(client);
				new Thread(dispatcher).start();
			}
			
		} catch (IOException e) {
			isRuning = false;
		}
	}

	private void stop() {
		isRuning = false;
		IOUtil.closeAll(server);
	}
	
	public static void main(String[] args) {
		Server s = new Server();
		s.start(8888);
	}
	
}

8、进行页面测试

9、简单写个多线程并发进行压测

package com.xzlf.csdnUtil;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;

/**
 * 对手写服务器进行压测
 * @author xzlf
 *
 */
public class TestMyServer {
	public static void main(String[] args) {
		String url = "http://localhost:8888/log?";
		for (int i = 0; i < 100; i++) {
			new Thread(new RunThread(url, "张三" + i, "123")).start();
			new Thread(new RunThread(url, "张三", "123")).start();
			try {
				Thread.sleep(200);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

	}

	public static void longin(String url, String uname, String pwd) {

		BufferedReader br = null;
		try {
			String loginUrl = url + "uname=" + uname + "&pwd=" + pwd;
			URL login = new URL(loginUrl);
			br = new BufferedReader(new InputStreamReader(login.openStream(), "utf-8"));
			char[] buf = new char[1024];
			int len = br.read(buf);
			System.out.println(new String(buf, 0, len));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	// 为了直接调用请求方法 用下静态内部类
	static class RunThread implements Runnable {
		String url;
		String uname;
		String pwd;

		public RunThread(String url, String uname, String pwd) {
			super();
			this.url = url;
			this.uname = uname;
			this.pwd = pwd;
		}

		@Override
		public void run() {
			TestMyServer.longin(url, uname, pwd);
		}

	}
}

用的电脑还算比较新 没啥压力。

以上是关于不使用tomcat,仅适用javaSE手写服务器--模拟登陆的主要内容,如果未能解决你的问题,请参考以下文章

手写Tomcat

从零开始手写Tomcat的教程4节---Tomcat默认连接器

手写迷你版 Tomcat - Minicat

tomcat部署

手写tomcat开机自启脚本

使用华夏移动办公产品时,在多普达android操作系统中,应用程序不支持中文手写输入法,怎么办?