预备知识
编写服务器用到的知识点
1) Socket 编程
2) HTML
3) HTTP 协议
4) 反射
5) XML 解析
6) 服务器编写
Socket编程
https://www.cnblogs.com/bfcs/p/10790130.html
HTML知识
HTML:HyperText Markup Language 超文本标记语言用于描述网页文档的一种标记语言
表单(form):与用户之间进行交互
method:请求方式 get/post
get 数据量小,安全性低,默认方式
post 数据量大,安全性高
action:请求的服务器路径
id :(用户的的浏览器在文档里区分唯一性)前端区分唯一性,js 中
name:名称,后端(服务器)区分唯一性,获取值,只要提交数据给后台(服务器)必须存在 name


1 <html>
2 <head>
3 <title>登陆界面</title>
4 </head>
5 <body>
6 <form action="" method="post" >
7 <p>用户名:<input type="text" name="username" id="name"/></p>
8 <p>密码:<input type="password" name="password" id="pwd"/></p>
9 <input type="submit" value="提交"/>
10 </form>
11 </body>
12 </html>
HTTP协议
协议
1) 应用层:HTTP、FTP、TELNET、SNMP、DNS
2) 传输层:TCP、UDP
3) 网络层:IP
HTTP 协议简介
HTTP:超文本传输协议,是网络应用层的协议,建立在 TCP/IP 协议基础上,HTTP 使用可靠的 TCP 连接,默认端口为 80。
用户打开 Web 浏览器(常见的 HTTP 客户端),输入 URL地址,就能接收到远程 HTTP 服务器端发送过来的网页,即HTTP 遵循请求(Request)/应答(Response)模型。
Web 浏览器向 Web 服务器发送请求,Web 服务器处理请求并返回适当的应答,所有 HTTP 连接都被构造成一套请求与应答。
HTTP 协议严格规定了 HTTP 请求和 HTTP 响应的数据格式
HTTP 请求格式
1) 请求方式、URI(统一资源定位符)、HTTP 协议/版本
2) 请求头 Request Header
请求头包含许多有关客户端环境和请求正文的有用信息。例如,请求头可以声明浏览器所用的语言,请求正文的长度等。
3) 请求正文 Requet Content (只有在 post 方式才有)请求头和请求正文之间必须有符号行(回车符或行结束符),与请求头分开。这个行非常重要,它表示请求头已结束,接
下来的是请求正文。 通常 post 方式的数据存放于此,请求正文中可以包含客户提交的查询字符串等信息。在实际应用中,HTTP 请求正文可以包含更多的内容
HTTP响应格式
1) HTTP 协议版本、状态代码、描述
2) 响应头(Response Head)
3) 响应正文(Respose Content)
Tomcat
是 SUN 公司推出的小型 Servlet/JSP 调试工具)的基础上发展起来的一个优秀的 Servlet 容器,Tomcat本身完全用 Java 语言编写
Tomcat 使用
1) 配置 Tomcat
a) JAVA_HOME Java JDK 的根目录
b) CATALINA_HOME Tomcat 根目录
2) 启动和关闭 Tomcat
启动 Tomcat 服务器:startup.bat 本地主机8080端口
关闭 Tomcat 服务器:shutdown.bat
3) 部署项目到服务器
在 webapps 目录下新建目录存放.html 页面 访问页面
Tomcat 的运行原理
客户浏览器发出要求,访问特定的 Servlet 的请求。
1) Tomcat 服务器接收到客户请求并解析。
2) Tomcat 服 务 器 创 建 一 个 ServletRequest 对 象 , 在ServletRequest 对象中包含了客户请求信息及其他关于客户的信息,如请求头,请求正文,以及客户机的 IP 地址等。
3) Tomcat 服务器创建一个 ServletResponse 对象
4) Tomcat 服务器调用客户所请求的 Servlet 的 service 服务方法,并且把 ServletRequst 对象和 ServletResponse 对象做为参数传给该服务方法。
5) Servlet 从 ServletRequest 对象中可获取客户的请求信息。
6) Servlet 利用 ServletResponse 对象来生成响应结果。
7) Tomcat 服务器把 Servlet 生成的响应结果发送给客户。
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
手写服务器项目
1.搭建项目框架
2.编写XML文档


1 <?xml version="1.0" encoding="UTF-8"?>
2 <web-app>
3 <servlet>
4 <servlet-name>login</servlet-name>
5 <serlvet-class>com.bjsxt.servlet.LoginServlet</serlvet-class>
6 </servlet>
7 <servlet-mapping>
8 <serlvet-name>login</serlvet-name>
9 <url-pattern>/login</url-pattern>
10 <url-pattern>/log</url-pattern>
11 </servlet-mapping>
12 <servlet>
13 <servlet-name>register</servlet-name>
14 <serlvet-class>com.bjsxt.servlet.RegisterServlet</serlvet-class>
15 </servlet>
16 <servlet-mapping>
17 <serlvet-name>register</serlvet-name>
18 <url-pattern>/reg</url-pattern>
19 <url-pattern>/register</url-pattern>
20 <url-pattern>/regis</url-pattern>
21 </servlet-mapping>
22 <servlet>
23 <servlet-name>favicon</servlet-name>
24 <serlvet-class>com.bjsxt.servlet.FaviconServlet</serlvet-class>
25 </servlet>
26 <servlet-mapping>
27 <serlvet-name>favicon</serlvet-name>
28 <url-pattern>/favicon.ico</url-pattern>
29
30 </servlet-mapping>
31 </web-app>
3.编写 IOCloseUtil 类


1 import java.io.Closeable;
2 import java.io.IOException;
3
4 public class IOCloseUtil { //用于关闭所有流
5 public static void closeAll(Closeable...close) { //可变参数
6 for (Closeable closeable : close) {
7 if(closeable != null) {
8 try {
9 closeable.close();
10 } catch (IOException e) {
11 // TODO 自动生成的 catch 块
12 e.printStackTrace();
13 }
14 }
15 }
16 }
17 }
4.DOM4J 解析 XML 配置文件
1)Entity 实体类的编写


1 import java.io.File;
2 import java.util.ArrayList;
3 import java.util.Iterator;
4 import java.util.List;
5
6 import org.dom4j.Document;
7 import org.dom4j.DocumentException;
8 import org.dom4j.Element;
9 import org.dom4j.io.SAXReader;
10 import org.omg.CORBA.PUBLIC_MEMBER;
11
12 public class WebDom4j { //用于解析XML
13 private List<Entitty> entityList;//用于存储N多Entity,而每一个Entity都是servlet-name与servlet-class
14 private List<Mapping> mappingList;//用于存储N多Mapping,而每一个Mapping都是一个servlet-name与多个url-pattern
15
16 //公有取值赋值方法
17 public List<Entitty> getEntityList() {
18 return entityList;
19 }
20 public void setEntityList(List<Entitty> entityList) {
21 this.entityList = entityList;
22 }
23 public List<Mapping> getMappingList() {
24 return mappingList;
25 }
26 public void setMappingList(List<Mapping> mappingList) {
27 this.mappingList = mappingList;
28 }
29
30 //构造方法
31 public WebDom4j() {
32 entityList = new ArrayList<Entitty>();
33 mappingList = new ArrayList<Mapping>();
34 }
35 //获取Document对象的方法
36 public Document getDocument() { //Document英语翻译:文件;文档
37 //alt+shift+z包围异常快捷键
38 try {
39 //(1)创建SAXReader对象
40 SAXReader reader = new SAXReader();
41 //(2)调用read()方法
42 return reader.read(new File("src/WEB_INFO/web.xml"));
43 } catch (DocumentException e) {
44 // TODO 自动生成的 catch 块
45 e.printStackTrace();
46 }
47 return null;
48 }
49 //把获取到的Document对象解析
50 public void parse(Document doc) {
51 //(1)获取根元素
52 Element root = doc.getRootElement(); //web-app
53 //(2)解析servlet
54 for(Iterator<Element> ite = root.elementIterator("servlet"); ite.hasNext();) {
55 Element subElement = ite.next();//得到每一个servlet
56 //创建一个实体类
57 Entitty ent = new Entitty();//用于存储servlet-name与servlet-class
58 for(Iterator<Element> subite = subElement.elementIterator(); subite.hasNext();) {
59 Element ele = subite.next(); //可能是servlet-name,也可能是servlet-class
60 if("servlet-name".equals(ele.getName())) {
61 ent.setName(ele.getText()); //给实体类中的name赋值
62 }else if ("servlet-class".equals(ele.getName())) {
63 ent.setClazz(ele.getText());
64 }
65 }
66 //经过上面的循环后Entity有值了,把Entity添加到集合中
67 entityList.add(ent);
68 }
69 //解析servlet-mapping
70 for(Iterator<Element> ite = root.elementIterator("servlet-mapping"); ite.hasNext();) {
71 Element subEle = ite.next();//得到每一个servlet-mapping
72 //创建一个mapping类对象
73 Mapping map = new Mapping();
74 //解析servlet-mapping下的子元素
75 for(Iterator<Element> subite = subEle.elementIterator(); subite.hasNext();) {
76 Element ele = subite.next();//可能是servlet-name,也可能是url-pattern
77 if("servlet-name".equals(ele.getName())) {
78 map.setName(ele.getText());
79 }else if("url-pattern".equals(ele.getName())){
80 //获取集合对象,调用集合对象的添加方法,添加元素
81 map.getUrlPattern().add(ele.getText());
82 }
83 }
84 //mapping添加到集合中
85 mappingList.add(map);
86 }
87 }
88 }
2)Mapping 实体类的编写


1 /**
2 * <servlet-mapping>
3 <servlet-name>login</servlet-name>
4 <url-pattern>/login</url-pattern>
5 <url-pattern>/log</url-pattern>
6 </servlet-mapping>
7 * @author CHB
8 *
9 */
10
11 import java.util.ArrayList;
12 import java.util.List;
13
14 public class Mapping { //映射关系 多个路径访问共享资源 servlet-name和url-pattern对应的实体类 多个资源与小名之间的关系
15 private String name;//servlet-name
16 private List<String> urlPattern;//url-pattern
17
18 //公有取值赋值方法
19 public String getName() {
20 return name;
21 }
22 public void setName(String name) {
23 this.name = name;
24 }
25 public List<String> getUrlPattern() {
26 return urlPattern;
27 }
28 public void setUrlPattern(List<String> urlPattern) {
29 this.urlPattern = urlPattern;
30 }
31 //构造方法
32 public Mapping() {
33 urlPattern = new ArrayList<String>();
34 }
35 public Mapping(String name, List<String> urlPattern) {
36 super();
37 this.name = name;
38 this.urlPattern = urlPattern;
39 }
40 }
3)解析 XML 文件,WebDom4j类的编写
导入Dom4j的jar包:在项目下新建文件夹lib,把jar包复制进去,导入后右键jar包选择构建路径再选择添加至构建路径


1 import java.io.File;
2 import java.util.ArrayList;
3 import java.util.Iterator;
4 import java.util.List;
5
6 import org.dom4j.Document;
7 import org.dom4j.DocumentException;
8 import org.dom4j.Element;
9 import org.dom4j.io.SAXReader;
10 import org.omg.CORBA.PUBLIC_MEMBER;
11
12 public class WebDom4j { //用于解析XML
13 private List<Entitty> entityList;//用于存储N多Entity,而每一个Entity都是servlet-name与servlet-class
14 private List<Mapping> mappingList;//用于存储N多Mapping,而每一个Mapping都是一个servlet-name与多个url-pattern
15
16 //公有取值赋值方法
17 public List<Entitty> getEntityList() {
18 return entityList;
19 }
20 public void setEntityList(List<Entitty> entityList) {
21 this.entityList = entityList;
22 }
23 public List<Mapping> getMappingList() {
24 return mappingList;
25 }
26 public void setMappingList(List<Mapping> mappingList) {
27 this.mappingList = mappingList;
28 }
29
30 //构造方法
31 public WebDom4j() {
32 entityList = new ArrayList<Entitty>();
33 mappingList = new ArrayList<Mapping>();
34 }
35 //获取Document对象的方法
36 private Document getDocument() { //Document英语翻译:文件;文档
37 //alt+shift+z包围异常快捷键
38 try {
39 //(1)创建SAXReader对象
40 SAXReader reader = new SAXReader();
41 //(2)调用read()方法
42 return reader.read(new File("src/WEB_INFO/web.xml"));
43 } catch (DocumentException e) {
44 // TODO 自动生成的 catch 块
45 e.printStackTrace();
46 }
47 return null;
48 }
49 //把获取到的Document对象解析
50 public void parse(Document doc) {
51 //(1)获取根元素
52 Element root = doc.getRootElement(); //web-app
53 //(2)解析servlet
54 for(Iterator<Element> ite = root.elementIterator("servlet"); ite.hasNext();) {
55 Element subElement = ite.next();//得到每一个servlet
56 //创建一个实体类
57 Entitty ent = new Entitty();//用于存储servlet-name与servlet-class
58 for(Iterator<Element> subite = subElement.elementIterator(); subite.hasNext();) {
59 Element ele = subite.next(); //可能是servlet-name,也可能是servlet-class
60 if("servlet-name".equals(ele.getName())) {
61 ent.setName(ele.getText()); //给实体类中的name赋值
62 }else if ("servlet-class".equals(ele.getName())) {
63 ent.setClazz(ele.getText());
64 }
65 }
66 //经过上面的循环后Entity有值了,把Entity添加到集合中
67 entityList.add(ent);
68 }
69 //解析servlet-mapping
70 for(Iterator<Element> ite = root.elementIterator("servlet-mapping"); ite.hasNext();) {
71 Element subEle = ite.next();//得到每一个servlet-mapping
72 //创建一个mapping类对象
73 Mapping map = new Mapping();
74 //解析servlet-mapping下的子元素
75 for(Iterator<Element> subite = subEle.elementIterator(); subite.hasNext();) {
76 Element ele = subite.next();//可能是servlet-name,也可能是url-pattern
77 if("servlet-name".equals(ele.getName())) {
78 map.setName(ele.getText());
79 }else if("url-pattern".equals(ele.getName())){
80 //获取集合对象,调用集合对象的添加方法,添加元素
81 map.getUrlPattern().add(ele.getText());
82 }
83 }
84 //mapping添加到集合中
85 mappingList.add(map);
86 }
87 }
88 }
5.反射创建servlet对象
1)编写 ServletContext 类:Servlet 上下文,就是一个容器,用于存储映射关系


1 import java.util.HashMap;
2 import java.util.Map;
3
4 public class ServletContext { //上下文 Entity与Mapping的映射关系 实体与映射关系类
5 private Map<String, String> servlet;//key是servlet-name,值是servlet-class
6 private Map<String, String> mapping;//hashmap键不能重复,值却可以,key是url-pattern, 值是servlet-name
7
8 //公有的取值赋值方法
9 public Map<String, String> getServlet() {
10 return servlet;
11 }
12 public void setServlet(Map<String, String> servlet) {
13 this.servlet = servlet;
14 }
15 public Map<String, String> getMapping() {
16 return mapping;
17 }
18 public void setMapping(Map<String, String> mapping) {
19 this.mapping = mapping;
20 }
21
22 //构造方法
23 public ServletContext() {
24 servlet = new HashMap<String, String>();
25 mapping = new HashMap<String, String>();
26 }
27 }
2)编写 WebApp 类
a) 初始化程序运行的数据
b) 根据不同的 url 创建所请求的 Servlet 对象


1 import java.util.List;
2 import java.util.Map;
3
4 import javax.print.attribute.standard.Severity;
5
6 import cn.chb.servlet.Servlet;
7
8 /* a) 初始化程序运行的数据
9 b) 根据不同的 url 创建所请求的 Servlet 对象
10 * */
11
12 public class WebApp { //app应用程序
13 private static ServletContext context;
14 static {//静态初始化代码块
15 context = new ServletContext();
16 //分别获取对应关系的Map集合
17 Map<String, String> servlet = context.getServlet();
18 Map<String, String> mapping = context.getMapping();
19 //解析XML文件对象
20 WebDom4j web = new WebDom4j();
21 web.parse(web.getDocument());//解析XML并把数据放到了entityList和mappingList当中
22 //获取解析XML之后的List集合
23 List<Entitty> entityList = web.getEntityList();
24 List<Mapping> mappingList = web.getMappingList();
25
26 //将List集合中的数据存储到Map集合
27 for(Entitty entity:entityList) {
28 servlet.put(entity.getName(), entity.getClazz());
29 }
30 for(Mapping map:mappingList) {
31 //遍历url-pattern集合
32 List<String> urlPattern = map.getUrlPattern();
33 for(String s:urlPattern) {
34 mapping.put(s, map.getName());
35 }
36 }
37 }
38 /**
39 * 根据url创建不同的servlet对象
40 * @param url
41 * @return
42 *
43 */
44 public static Servlet getServlet(String url){
45 if(url == null||url.trim().equals("")) {
46 return null;
47 }
48 try {
49 //如果url正确
50 String servletName = context.getMapping().get(url);//根据key(url)获取值(servlet-name)
51 //根据servlet-name得到对应的servlet-class
52 String servletClass = context.getServlet().get(servletName);//等到的是一个完整的包名+类名字符串
53 //使用反射创建servlet对象
54 Class<?> clazz = Class.forName(servletClass);
55 //调用无参构造方法创建servlet对象
56 Servlet servlet = (Servlet)clazz.newInstance();
57 return servlet;
58 } catch (ClassNotFoundException e) {
59 // TODO 自动生成的 catch 块
60 e.printStackTrace();
61 } catch (InstantiationException e) {
62 // TODO 自动生成的 catch 块
63 e.printStackTrace();
64 } catch (IllegalAccessException e) {
65 // TODO 自动生成的 catch 块
66 e.printStackTrace();
67 }
68 return null;
69 }
70 }
6.封装 Request_method_url
1) 编写 Server: 启动服务 关闭服务


1 import java.io.BufferedWriter;
2 import java.io.IOException;
3 import java.io.InputStream;
4 import java.io.OutputStreamWriter;
5 import java.net.ServerSocket;
6 import java.net.Socket;
7
8 import com.bjsxt.servlet.Servlet;
9 import com.bjsxt.util.IOCloseUtil;
10
11 public class Server {//服务器,用于启动和停止服务
12 private ServerSocket server;
13 private boolean isShutDown=false;//默认没有出错
14 public static void main(String[] args) {
15 Server server=new Server();//创建服务器对象
16 server.start();
17 }
18 public void start(){
19 this.start(8888);
20 }
21 public void start(int port){
22 try {
23 server=new ServerSocket(port);
24 this.receive(); //调用接收请求信息的方法
25 } catch (IOException e) {
26 isShutDown=true;
27 }
28 }
29 private void receive() {
30 try {
31 while(!isShutDown){
32 //(1)监听
33 Socket client=server.accept();
34 //创建线程类的对象
35 Dispatcher dis=new Dispatcher(client);
36 //创建线程的代理类,并启动线程
37 new Thread(dis).start();
38 }
39
40 } catch (IOException e) {
41 this.stop();//关闭服务器
42 }
43
44 }
45 public void stop(){
46 isShutDown=true;
47 IOCloseUtil.closeAll(server);
48 }
49 }
2)编写 HTML


1 <html>
2 <head>
3 <title>登陆</title>
4 </head>
5 <body>
6 <form action="http://127.0.1:8888/log" method="get" >
7 <p>用户名:<input type="text" name="username" id="username"/></p>
8 <p>密码:<input type="password" name="pwd" id="password"/></p>
9 <p>
10 爱好:<input type="checkbox" name="hobby" value="ball"/>足球
11 <input type="checkbox" name="hobby" value="read"/>读书
12 <input type="checkbox" name="hobby" value="pain"/>画画
13 </p>
14 <p><input type="submit" value="登陆"/></p>
15 <input type="submit" value="提交"/>
16 </form>
17 </body>
18 </html>
3) 封装 Request_method_url


1 import java.io.InputStream;
2 import java.io.UnsupportedEncodingException;
3 import java.net.URLDecoder;
4 import java.util.ArrayList;
5 import java.util.Arrays;
6 import java.util.HashMap;
7 import java.util.List;
8 import java.util.Map;
9
10 public class Request { /*请求类*/
11 private InputStream is;//输入流
12 private String requestInfo;//请求字符串:请求方式,路径,参数,协议/协议版本,请求正文
13 private String method;//请求方式
14 private String url;//请求的url
15
16 //输入框中的name为key,值为输入的内容
17 /*
18 * key:username value:chb
19 * key:pwd value:123456
20 */
21 private Map<String, List<String>> parametermapValues;//参数
22 private static final String CRLF="\r\n";//换行
23 private static final String BLANK=" ";//空格
24 //构造方法,初始化属性
25 public Request() {
26 parametermapValues = new HashMap<String, List<String>>();
27 method = "";
28 requestInfo = "";
29 url = "";
30 }
31 public Request(InputStream is) {
32 this();
33 this.is = is;
34 try {
35 byte [] buf = new byte [20480];
36 int len = this.is.read(buf);
37 requestInfo = new String(buf, 0, len);
38 } catch (Exception e) {
39 // TODO 自动生成的 catch 块
40 e.printStackTrace();
41 }
42 //调用本类中分解请求信息的方法
43 this.parseRequestInfo();
44 }
45 //分解请求信息的方法 方式、路径、参数
46 private void parseRequestInfo() {
47 String paraString ="";//用于存储请求参数
48 //获取请求参数的第一行
49 String firstLine=requestInfo.substring(0, requestInfo.indexOf(CRLF)).trim();//从0开始到第一个换行
50 //分解出请求方式
51 int index = firstLine.indexOf("/");//找出斜线的位置GET /(这里) HTTP/1.1
52 this.method = firstLine.substring(0, index).trim();//trim()去掉空格
53 //分解url,可能包含参数,也可能不包含参数
54 String urlString = firstLine.substring(index, firstLine.indexOf("HTTP/")).trim();
55 //判断请求方式是GET还是POST
56 if("get".equalsIgnoreCase(this.method)) {//GET包含请求参数
57 if(urlString.contains("?")) {//包含有问号,说明有参数
58 String [] urlArray = urlString.split("\\?");//以?号分割获取参数
59 this.url = urlArray[0];
60 paraString = urlArray[1];
61 }else {
62 this.url = urlString;
63 }
64 }else {//POST不包含请求参数,参数在请求正文
65 this.url = urlString;
66 //最后一个换行到结尾是请求正文
67 paraString = requestInfo.substring(requestInfo.lastIndexOf(CRLF)).trim();
68 }
69 if(paraString.equals("")) {//如果没有参数
70 return;
71 }
72 }
73 //username=chbt&pwd=123&hobby=ball&hobby=paint
74 /**
75 * username=chb
76 * pwd=123
77 * hobby=ball
78 * hobby=paint
79 *
80 * username=
81 * @param prarString
82 */
83 private void parseParam(String prarString){
84 String [] token=prarString.split("&");
85 for(int i=0;i<token.length;i++){
86 String keyValues=token[i];
87 String []keyValue=keyValues.split("="); //username chb pwd 123
88 if (keyValue.length==1) { //username=
89 keyValue=Arrays.copyOf(keyValue, 2);
90 keyValue[1]=null;
91 }
92 //将 表单元素的name与name对应的值存储到Map集合
93 String key=keyValue[0].trim();
94 String value=keyValue[1]==null?null:decode(keyValue[1].trim(), "utf-8");
95 //放到集合中存储
96 if (!parametermapValues.containsKey(key)) {
97 parametermapValues.put(key, new ArrayList<String>());
98 }
99 List<String> values=parametermapValues.get(key);
100 values.add(value);
101 }
102 }
103 //根据表单元素的name获取多个值
104 private String [] getParamterValues(String name){
105 //根据key获取value
106 List<String> values=parametermapValues.get(name);
107 if (values==null) {
108 return null;
109 }else{
110 return values.toArray(new String [0] );
111 }
112
113 }
114 private String getParamter(String name){
115 //调用本类中根据name获取多个值的方法
116 String [] values=this.getParamterValues(name);
117 if (values==null) {
118 return null;
119 }else{
120 return values[0];
121 }
122 }
123
124 //处理中文,因类浏览器对中文进行了编码,进行解码
125 private String decode(String value,String code){
126 try {
127 return URLDecoder.decode(value, code);
128 } catch (UnsupportedEncodingException e) {
129 // TODO Auto-generated catch block
130 e.printStackTrace();
131 }
132 return null;
133 }
134 }
7.封装 Response
1) 构造响应头
2) 推送到客户端


1 import java.io.BufferedWriter;
2 import java.io.IOException;
3 import java.io.OutputStream;
4 import java.io.OutputStreamWriter;
5 import java.io.UnsupportedEncodingException;
6
7 import com.bjsxt.util.IOCloseUtil;
8
9 public class Response {//响应
10 private StringBuilder headInfo;//响应头
11 private StringBuilder content;//响应内容
12 private int length;//响应内容的长度
13 //流
14 private BufferedWriter bw;
15
16 //两个常量,换行和空格
17 private static final String CRLF="\r\n";//换行
18 private static final String BLANK=" ";//空格
19
20 //构造方法
21 public Response() {
22 headInfo=new StringBuilder();
23 content=new StringBuilder();
24
25 }
26 //带参构造方法
27 public Response(OutputStream os){
28 this();//调用本类的无参构造方法
29 try {
30 bw=new BufferedWriter(new OutputStreamWriter(os, "utf-8"));
31 } catch (UnsupportedEncodingException e) {
32 headInfo=null;
33 }
34
35 }
36 //构造正文部分
37 public Response print(String info){
38 content.append(info);
39 try {
40 length+=info.getBytes("utf-8").length;
41 } catch (UnsupportedEncodingException e) {
42 // TODO Auto-generated catch block
43 e.printStackTrace();
44 }
45 return this;
46 }
47 public Response println(String info){
48 content.append(info).append(CRLF);
49 try {
50 length+=(info+CRLF).getBytes("utf-8").length;
51 } catch (UnsupportedEncodingException e) {
52 // TODO Auto-generated catch block
53 e.printStackTrace();
54 }
55 return this;
56 }
57
58 //构造响应头
59
60 private void createHeadInfo(int code){
61 headInfo.append("HTTP/1.1").append(BLANK).append(code).append(BLANK);
62 switch (code) {
63 case 200:
64 headInfo.append("OK");
65 break;
66 case 500:
67 headInfo.append("SERVER ERROR");
68 break;
69 default:
70 headInfo.append("NOT FOUND");
71 break;
72 }
73 headInfo.append(CRLF);
74 headInfo.append("Content-Type:text/html;charset=utf-8").append(CRLF);
75 headInfo.append("Content-Length:"+length).append(CRLF);
76 headInfo.append(CRLF);
77 }
78 /**
79 * 推送到客户机的浏览器
80 * @param code
81 */
82 public void pushToClient(int code){
83 if (headInfo==null) {
84 code=500;
85 }
86 try {
87 //调用本类中的构造响应头
88 this.createHeadInfo(code);
89 bw.write(headInfo.toString());
90 bw.write(content.toString());
91 bw.flush();
92 this.close();
93 } catch (IOException e) {
94 // TODO Auto-generated catch block
95 e.printStackTrace();
96 }
97 }
98 public void close(){
99 IOCloseUtil.closeAll(bw);
100 }
101 }
3)编写相应的 Servlet 构造响应内容


1 import com.bjsxt.server.Request;
2 import com.bjsxt.server.Response;
3
4 public abstract class Servlet { //是所有的请求的Servlet的父类
5 public void service(Request req,Response rep) throws Exception{
6 this.doGet( req, rep);
7 this.doPost( req, rep);
8 }
9 public abstract void doGet(Request req,Response rep) throws Exception;
10 public abstract void doPost(Request req,Response rep) throws Exception;
11 }


1 import com.bjsxt.server.Request;
2 import com.bjsxt.server.Response;
3
4 public class LoginServlet extends Servlet {
5
6 @Override
7 public void doGet(Request req, Response rep) throws Exception {
8 //获取请求参数
9 String name=req.getParameter("username");
10 String pwd=req.getParameter("pwd");
11
12 if(this.login(name, pwd)){
13 //调用响应中的构建内容的方
14 rep.println(name+"登录成功");
15 }else{
16 rep.println(name+"登录失败,对不起,账号或密码不正确");
17 }
18
19 }
20 private boolean login(String name,String pwd){
21 if ("bjsxt".equals(name)&&"123".equals(pwd)) {
22 return true;
23 }
24 return false;
25 }
26
27 @Override
28 public void doPost(Request req, Response rep) throws Exception {
29 // TODO Auto-generated method stub
30
31 }
32 }


1 import com.bjsxt.server.Request;
2 import com.bjsxt.server.Response;
3
4 public class FaviconServlet extends Servlet {
5
6 @Override
7 public void doGet(Request req, Response rep) throws Exception {
8 // TODO Auto-generated method stub
9
10 }
11
12 @Override
13 public void doPost(Request req, Response rep) throws Exception {
14 // TODO Auto-generated method stub
15
16 }
17
18 }
8.封装分发器实现多线程


1 import java.io.IOException;
2 import java.net.Socket;
3
4 import com.bjsxt.servlet.Servlet;
5 import com.bjsxt.util.IOCloseUtil;
6
7 /**
8 * 一个请求与响应就是一个Dispatcher
9 * @author Administrator
10 *
11 */
12 public class Dispatcher implements Runnable {
13 private Request req;
14 private Response rep;
15 private Socket client;
16 private int code=200;//状态码
17 //构造方法初始化属性
18 public Dispatcher(Socket client) {
19 //将局部变量的值赋给成员变量
20 this.client=client;
21 try {
22 req=new Request(this.client.getInputStream());
23 rep=new Response(this.client.getOutputStream());
24 } catch (IOException e) {
25 code=500;
26 return ;
27 }
28 }
29 @Override
30 public void run() {
31 //根据不同的url创建指定的Servlet对象
32 //System.out.println(req.getUrl());
33 Servlet servlet=WebApp.getServlet(req.getUrl());
34 if (servlet==null) {
35 this.code=404;
36 }else{
37 //调用相应的Servlet中的service方法
38 try {
39 servlet.service(req,rep);
40 } catch (Exception e) {
41 this.code=500;
42 }
43 }
44 //将响应结果推送到客户机的浏览器
45 rep.pushToClient(code);
46 IOCloseUtil.closeAll(client);
47 }
48
49 }
来源:oschina
链接:https://my.oschina.net/u/4311204/blog/3541785