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 = "
";
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 = "
";
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);
}
}
}
用的电脑还算比较新 没啥压力。