0.写WebServer类:“服务器”
- 1.写构造方法:里面给server实例变量赋值端口
- 2.写start方法:里面写accept()监听器
- 3.写main方法:新建对象,并调用start方法
- 7.在start方法里面写:写一个线程启动ClientHandler类
- 71.删除原来的线程调用,改为"线程池",容量为100ExecutorService threadPool = Executors.newFixed
ThreadPool(100);
4.写ClientHandler类"客户端操作类"
- 5.实现Runnable接口
- 6.写构造方法,要求传入一个Socket类型的参数:里面给socket实例变量赋值为形参
- 19.响应客户端:通过解析得到的url,读取本地文件,先判断该资源存不存在
- 20.如果存在该资源,获取服务端的输入流,发送状态行,就是协议 状态代码 状态描述
- 21.因为输入流只可以读取byte类型,所以要将状态行转换成byte形式:void getBytes(“ISO8859-1”)
- 22.每行后面加一个CRLF,最后一行要多加个CRLF
- 23.创建一个输出流,按数组读取该文件(服务器输出流会追加写发送),发送给(write)给客户端
- 32.如果不存在该资源,又新建一个HttpResponse实例对象和文件(404)对象,通过setentity方法,传入该文件对象
- 45.因为要判断是处理业务还是请求静态资源,所以在请求资源的方法上面加一个判断
- 55.再加一个分支:进入到处理业务的时候,判断是登录业务还是注册业务.它们所有下面一起"flush":发送响应
- 59.写:捕获 58 抛出的异常的处理方法,可以只写个输出
- 67.把总的分支变为两条路,处理业务的和加载静态资源的
- 68.处理业务的写:先传入url到ServerContext中判断是否为空,若不为空,则进行下面的步骤
- 69.Class.forName(“68获取到的className”);创建一个类对象
-
- 69 的类对象new一个实例(newInstance),然后"向下造型"为超类,值是对象的(如果对象(子类)没有重写就是父
类的),然后用得到超类引用类型对象,调用service()方法,完成处理该业务的步骤!
8.写HttpRequest类"Http解析类"
- 9.写五个实例变量,三个请求行相关信息的变量,两个和客户端连接相关的属性
- 10.写构造方法,要求传入一个Socket的形参
- 11.写三个"私有"方法,用来解析客户端请求
- 12.写第四个方法,用来读取一行请求行—一个一个字符的读取,然后拼接成一行字符串,不要最后的回车符和换行符
- 13.将三个解析方法调用到构造方法中,因为是私有方法,则其他类不可以调用,放在构造方法里面,创建对象的时候就会自
- 动调用
- 58.因为客户端可以发送空请求,所以取url的时候会数组下标越界,所以再调用读取一行的方法下面写:if 为"",则
- throw new EmptyRequestException();然后一直抛到ClientHandler里面
- 14.parseRequestLine()方法中写:先调用读取一行的方法,取出method,url,protocol这三个变量的值
- 15.设置get获取请求行三个变量的值
- 16.写一个散列表headers
- 17.parseHeaders()方法中写:也是调用读取一行的方法,取出每个消息头装入到散列表(headers)中,去:和空格
- 18.写一个获取map中value值的方法:传入一个String name,返回value的值
- 41.写一个解析url的私有方法,在解析请求行方法中的url赋值之后调用/myweb/reg?username=xxx&password=
- xxx&…
- 42.定义三个实例变量,requestURI,queryString,Map parameters;分别是装url"?"左边和右边的,以及装
- entry的
- 43.先判断存不存在"?",如果不存在URI就是URL的值,就是调用资源的,如果存在就是要处理业务的
- 44.所以要在下面写42的三个实例变量的get方法,让其他类可以获取值
- 72.写putParamenters方法要求传入String参数:先写:URLDecoder.decode(str,“utf-8”);将传入的str参数转换为"utf-8"字符集,将str按"&“拆分,再按”="拆分装入到Map entry中
- 73.解析消息正文:先判断消息头是否含有"Content-Length"单词,然后获取其value,用int形式装起来,然后用输入流
读取该长度的字节,然后再获取"Content-Type"的value,判断其类型是否为表单:"application/x-www-form-
“urlencoded”,然后用line = new String(data,“ISO8859-1”);去得到消息正文的内容,然后调用 72 方法
来将其转换为"utf-8"字符集,完成操作
24.写HttpResponse类:“Http响应类”
- 25.写两个实例变量socket和输入流out
- 26.写一个传入Socket类型参数构造方法,给前面两个变量赋值
- 27.写flush方法
- 28.写三个方法,发送状态行,发送响应头"注意!最后一个响应头末尾有两个CRLF",发送响应正文,就是20-23的步骤,并删
- 除这几步步骤"!!!"记得转码,如果发送的为字符串,一定记得要转换成:“ISO8859-1”!!/*注意!!在写发送响应正文
- 时fis的read()读取一定要在括号里面写data!!*/
- 29.将上面这三个方法调用到flush中
- 30.写一个File类型的变量entity:目的是将实际访问的文件路径传入,并传输给客户端该资源
- 31.写get,set:entity的获取和设置
- 33.创建变量statusCode,statusReason:状态代码,默认为200,状态描述,默认为:“OK”,并把它们设置到状态行中
- 39.在设置状态代码的方法里写:给状态描述赋值为传入状态代码到HttpContext中getvalue方法的返回值/*这一步可
- 以解决每次都要对状态描述进行设置的麻烦*/
- 41.因为每次设置路径之后都要对该文件进行Type设置,所以直接在setEntity方法里面设置Type的值
- 42.file.getName()获取文件名,用lastIndexOf+1和substring取出后缀名,然后传入HttpContext类获取type
34.写HttpContext类:“Map”
- 35.声明一个常量的散列表
- 36.写一个私有方法:里面给上面的散列表赋值
- 37.写一个静态块,里面调用该私有方法
- 38.写一个方法值为String类型的方法,并要求传参:将传入的参数作为key,用get方法,返回该key的value
- 40.再写一个私有方法,初始化资源后缀与Content-Type的值,再写和 38 一样的get方法,和35-38给状态描述赋值一样
46.写RegServlet类:“处理注册业务”
- 47.先写一个业务方法service;要求传入请求和响应的对象参数
- 48.获取请求参数里面的Map parameters(参数)散列表的指定key的value
- 49.用raf的方法新建一个文件,用户名,密码,昵称占32字节,年龄占固定4字节,然后写进去,调用响应参数,传入file
50.写LoginServlet类:“处理登录业务”
- 51.依旧传入请求和响应的对象参数
- 52.获取请求里面的用户名和密码
- 53.依旧用raf的方法去读取每一个用户名和密码(for 循环),并判断"!!这里一定要加去除空白符"
- 54.调用响应参数,传入file,成功一个,失败一个
56.写EmptyRequestException类:“处理空请求异常”
- 57.继承Exception类,加序列号,Alt+Shift+S里面的最后一个:from SuperClass,写父类里面的所有构造方法
60.写HttpServlet抽象类:“所有处理业务的超类”
- 61.写抽象方法service:让所有的子类都重写该方法(服务)
- 62.写一个公共方法forward:这个方法要求传入三个形参,里面主要设置文件的路径,request以后可以代替第一个参数
- 63.在reg类和login类中:继承该类,然后把所有的设置文件代码改成,forward方法
64.写ServerContext类:“解析自己写的servlets.xml”
- 65.将根元素将根元素下的所有元素取出,并将每个元素中的属性:url的值作为
- key,className的值作为value,保存到SERVLET_MAPPING这个Map中完成初始化,/*这里的calssName是完全
-
限定名*/
- 66.写:get 65 的Map的value的方法
备注:
- 文件路径: Demo下载地址
- 1.要解析XML文件需要在pom.xml中写:(下载第三方的jar)/dom4j/,下载地址看Maven快速入手
<dependencies>
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
</dependencies>
- 2.uri这里有 “/”
- 3.File:如果不写./ 就"直接写文件名",不用加/
- 4.一共 74 个步骤
- 5.initStatusMapping()方法
private static void initStatusMapping() {
STATUS_MAPPING.put(200, "ok");
STATUS_MAPPING.put(201, "Created");
STATUS_MAPPING.put(202, "Accepted");
STATUS_MAPPING.put(204, "No Content");
STATUS_MAPPING.put(301, "Moved Permanently");
STATUS_MAPPING.put(302, "Moved Temporarily");
STATUS_MAPPING.put(304, "Not Modified");
STATUS_MAPPING.put(400, "Bad Request");
STATUS_MAPPING.put(401, "Unauthorized");
STATUS_MAPPING.put(403, "Forbidden");
STATUS_MAPPING.put(404, "Not Found");
STATUS_MAPPING.put(500, "Internal Server Error");
STATUS_MAPPING.put(501, "Not Implemented");
STATUS_MAPPING.put(502, "Bad Gateway");
STATUS_MAPPING.put(503, "Service Unavailable");
}