服务端可以同时接受多客户端的连接,所以我们设置主线程仅负责接受客户端的连接,一旦一个客户端连接后则启动一个线程来处理(设置成死循环)
新建类ClientHandle(实现Runnable接口)作为线程任务,负责与连接的客户端进行HTTP交互。
浏览器发送一个请求,ClientHandler首先解析请求,实例化一个HTTP请求对象,
新建类HttpServletRequest,在这个类的构造方法里主要干三件事(解析请求行、解析消息头、解析消息正文)
解析请求行。请求行分为三部分(method、uri、protocol)定义一个readLine方法来读取一行字符串解析数据()
通过split方法拆分请求行中的空格符号(即\\s),把第一部分赋给method,第二部分赋给uri,第三部分赋给protocol,这个地方需要单独定义一个进一步解析uri的方法,因为用户访问的情况有两种,一种是访问一个固定的页面,另一种是访问一个业务程序(比如注册登录等),相对应的uri也就有静态和动态(即含参数和不含参数)的两种情况。先将uri按照“?”拆分(此时如果有参数那么问号左边的请求部分可以直接赋值给requestURI,如果没有参数,那字符串只有一部分,所以也是将第一部分赋值给requestURI),然后将问号右侧的参数部分赋值给queryString,将参数部分再按照&符号拆分为key和value存入Map中
解析消息头:循环调用readLine读取消息头,判断如果消息头为空,就break跳出循环,不为空就按照冒号加空格拆分,把拆分出来的放进Map
消息正文可以没有,本次需求中没有消息正文,所以解析消息正文中就是个空的方法
然后再ClientHandler实例化一个HTTP响应对象,因为在后面处理请求的时候需要用到设置响应文件,所以我们先把响应对象实例化出来(它并不是实例化请求对象那样实例化的过程就是解析的过程)
在HttpServletResponse类中定义setContentFile方法,变量ContentFile为正文对应的实体文件,用Files工具类方法得到Content-Type,若不为空则设置该响应头
下一步是处理请求,处理请求可以放到DispatcherServlet的service方法中,这里首先判断该请求是否为请求一个业务,是业务就交给Controller处理(判断是注册还是登录)。第二种情况就是请求的不是一个业务,请求的是页面,那就再做判断,如果请求的页面文件在static下有,就设置重定向发给浏览器,如果没有,就重定向404(即资源不存在)
最后就是发送响应
在HttpServletResponse类中分别定义发送状态行、响应头、响应正文的方法