今日重新写了一遍请求响应前面的代码,第二次学习的时候确实会有不一样的感触。

浏览器端

浏览器执行:解析URL,得到ip port contentAndParams . 通过ip port 创建socke流,再得到一个高级流将contentAndParams发送给服务器。浏览器等待服务器发送信息,并展示信息

  1. package browser;
  2. import java.io.BufferedReader;
  3. import java.io.IOException;
  4. import java.io.InputStreamReader;
  5. import java.io.PrintWriter;
  6. import java.net.Socket;
  7. import java.util.Scanner;
  8. public class Browser {
  9. private Scanner sc = new Scanner(System.in);
  10. private Socket socket = null;
  11. public void openBrowser() {
  12. System.out.println("浏览器开始执行了");
  13. System.out.println("URL:");
  14. String url = sc.nextLine();
  15. this.parseURL(url);
  16. }
  17. //设计一个方法解析URL
  18. private void parseURL(String url) {
  19. //找寻冒号所在位置
  20. int colonIndex = url.indexOf(":");
  21. //找寻斜杠所在位置
  22. int slashIndex = url.indexOf("/");
  23. //获取Ip port contentAndParams
  24. String ip = url.substring(0, colonIndex);
  25. int port = Integer.parseInt(url.substring(colonIndex + 1, slashIndex));
  26. String contentAndParams = url.substring(slashIndex + 1);
  27. //创建连接并发送请求
  28. this.cerateSocketAndSendRequest(ip, port, contentAndParams);
  29. }
  30. //创建socket 将资源发送过去
  31. private void cerateSocketAndSendRequest(String ip, int port, String contenAndParams) {
  32. try {
  33. //通过ip port 创建socket流
  34. socket = new Socket(ip, port);
  35. //得到一个PrintWriter流将信息发送出去
  36. PrintWriter out = new PrintWriter(socket.getOutputStream());
  37. out.println(contenAndParams);
  38. out.flush();
  39. //浏览器等待响应信息
  40. this.receiveResponseContent();
  41. } catch (IOException e) {
  42. e.printStackTrace();
  43. }
  44. }
  45. //设计一个方法 接受服务器回写的响应信息
  46. private void receiveResponseContent() {
  47. try {
  48. BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
  49. String responseContent = reader.readLine();
  50. //解析响应信息并展示
  51. this.parseResponseContentAndShow(responseContent);
  52. } catch (IOException e) {
  53. e.printStackTrace();
  54. }
  55. }
  56. private void parseResponseContentAndShow(String responseContent){
  57. System.out.println(responseContent);
  58. }
  59. }

服务器

服务器开放一个端口号,等待接收。接收到一个连接开启一个ServerHandler线程。然后包装socket.getInputStream成高级流读取一行信息,再解析资源。
创建了两个类 HttpServletRequest 和 HttpServletResponse 目的是接收响应求情的信息,另一个是为了接受响应回去的结果。之后找到ServletController类做事情,找到请求名对应的真实类做事情
增加了一个缓存机制,读取到一个请求加载一个,性能提高了

  1. package server;
  2. import java.io.IOException;
  3. import java.net.ServerSocket;
  4. import java.net.Socket;
  5. public class Server {
  6. //开启服务器的方法
  7. public void serverStart(){
  8. try {
  9. System.out.println("浏览器开始执行了");
  10. //创建一个服务
  11. ServerSocket server=new ServerSocket(9999);
  12. while(true){
  13. //等待接收
  14. Socket socket=server.accept();
  15. //开启一个线程
  16. new ServerHandler(socket).run();
  17. }
  18. } catch (IOException e) {
  19. e.printStackTrace();
  20. }
  21. }
  22. }
  1. package server;
  2. import java.io.BufferedReader;
  3. import java.io.IOException;
  4. import java.io.InputStream;
  5. import java.io.InputStreamReader;
  6. import java.net.Socket;
  7. import java.util.HashMap;
  8. public class ServerHandler extends Thread{
  9. private Socket socket;
  10. public ServerHandler(Socket socket){
  11. this.socket=socket;
  12. }
  13. public void run(){
  14. //接收信息
  15. this.receiveRequest();
  16. //解析
  17. //找人做事
  18. //响应回去
  19. }
  20. //接受消息
  21. private void receiveRequest(){
  22. try {
  23. InputStream is=socket.getInputStream();
  24. InputStreamReader isr=new InputStreamReader(is);
  25. BufferedReader reader=new BufferedReader(isr);
  26. //读取消息
  27. String contentAndParams=reader.readLine();
  28. //解析
  29. this.parseContentAndParams(contentAndParams);
  30. } catch (IOException e) {
  31. e.printStackTrace();
  32. }
  33. }
  34. //解析资源
  35. private void parseContentAndParams(String contentAndParams){
  36. String content=null;
  37. HashMap<String,String> paramsMap=null;
  38. //content?key=value&key=value
  39. //找寻到问号的位置
  40. int questionMarkIndex=contentAndParams.indexOf("?");
  41. //判断是否携带了参数
  42. if(questionMarkIndex!=-1){
  43. //携带了参数
  44. content=contentAndParams.substring(0,questionMarkIndex);
  45. paramsMap=new HashMap<>();
  46. //处理后面携带的参数
  47. String params=contentAndParams.substring(questionMarkIndex+1);
  48. String []keyAndValues=params.split("&");
  49. for(String keyAndValue:keyAndValues){
  50. String []kv=keyAndValue.split("=");
  51. paramsMap.put(kv[0],kv[1]);
  52. }
  53. }else{
  54. //若没带参数
  55. content=contentAndParams;
  56. }
  57. //创建了两个类 一个是为了存储接受请求携带的信息
  58. //一个是为了接受响应回去的结果
  59. HttpServletRequest request=new HttpServletRequest(content,paramsMap);
  60. HttpServletResponse response=new HttpServletResponse();
  61. //找到一个人 让他去底层找到真实的类做事情 并将response填满
  62. ServletController.findController(request,response);
  63. //响应回去
  64. this.responseToBrowser(response);
  65. }
  66. //找人做事
  67. private void responseToBrowser(HttpServletResponse response){
  68. }
  69. }
  1. package server;
  2. import java.util.HashMap;
  3. public class HttpServletRequest {
  4. //自定义的一个类
  5. //目的存储浏览器发送请求和参数
  6. private String content;
  7. private HashMap<String,String> paramsMap;
  8. public HttpServletRequest() {
  9. }
  10. public HttpServletRequest(String content, HashMap<String, String> paramsMap) {
  11. this.content = content;
  12. this.paramsMap = paramsMap;
  13. }
  14. public String getContent() {
  15. return content;
  16. }
  17. public void setContent(String content) {
  18. this.content = content;
  19. }
  20. public HashMap<String, String> getParamsMap() {
  21. return paramsMap;
  22. }
  23. public void setParamsMap(HashMap<String, String> paramsMap) {
  24. this.paramsMap = paramsMap;
  25. }
  26. }
  27. package server;
  28. public class HttpServletResponse {
  29. private StringBuilder responseContent=new StringBuilder();
  30. public void write(String str){
  31. responseContent.append(str);
  32. }
  33. public String getResponseContent(){
  34. return this.responseContent.toString();
  35. }
  36. }
  1. package server;
  2. import java.io.FileReader;
  3. import java.io.IOException;
  4. import java.lang.reflect.Method;
  5. import java.util.Enumeration;
  6. import java.util.HashMap;
  7. import java.util.Properties;
  8. public class ServletController{
  9. //这个类的目的是为了管理 findController方法
  10. //方法之前与服务器做的事情不一样 抽离出来
  11. //每一次赵信controller类都需要参考web.properties配置文件
  12. //读取文件性能会变低 因此可以增加一个缓存机制
  13. //每一个Controller类都是由Controller方法来找寻类
  14. // 找到类之后执行他的方法
  15. //增加一个单例模式(controller类只有方法执行 没有属性)
  16. private static HashMap<String ,String>controllerNameMap=new HashMap<>();
  17. //添加一个集合 存储被管理的所有Controller类对象
  18. private static HashMap<String,HttpServlet> controllerObjectMap = new HashMap<>();
  19. //延迟加载对象的方式
  20. //创建一个静态块 在当前类加载的时候将配置文件中的所有信息读取出来存入缓存集合中
  21. static{
  22. try {
  23. Properties pro = new Properties();
  24. pro.load(new FileReader("src//web.properties"));
  25. Enumeration en = pro.propertyNames();
  26. while(en.hasMoreElements()){
  27. String content = (String)en.nextElement();
  28. String realControllerName = pro.getProperty(content);
  29. controllerNameMap.put(content,realControllerName);
  30. }
  31. } catch (IOException e) {
  32. e.printStackTrace();
  33. }
  34. }
  35. //找人干活---控制层 (controller action servlet)
  36. //content----index map-----{{name,zzt},{},{}}
  37. public static void findController(HttpServletRequest request,HttpServletResponse response){
  38. //获取request对象中的请求名字
  39. String content = request.getContent();
  40. try {
  41. //先去objectMap中找寻需要的对象
  42. HttpServlet controllerObject = controllerObjectMap.get(content);
  43. //若对象不存在 证明之前没有使用过
  44. if(controllerObject==null){
  45. //参考配置文件(缓存) 真实类名
  46. String realControllerName = controllerNameMap.get(content);
  47. //请求对应的真实类名是否存在
  48. if(realControllerName!=null){
  49. //反射获取类
  50. Class clazz = Class.forName(realControllerName);
  51. controllerObject = (HttpServlet) clazz.newInstance();
  52. //将新创建的对象放在上面的对象集合内
  53. controllerObjectMap.put(content,controllerObject);
  54. }
  55. }
  56. //----以上可以确保controllerObject对象肯定存在-------------
  57. //反射找寻类中的方法
  58. Class controllerClass = controllerObject.getClass();
  59. Method serviceMethod = controllerClass.getMethod("service",HttpServletRequest.class,HttpServletResponse.class);
  60. serviceMethod.invoke(controllerObject,request,response);
  61. } catch (ClassNotFoundException e) {
  62. response.write("请求的"+content+"Controller不存在");
  63. } catch (NoSuchMethodException e){
  64. response.write("405 没有可以执行的方法");
  65. } catch (Exception e){
  66. e.printStackTrace();
  67. }
  68. }
  69. }
  1. package controller;
  2. import server.HttpServlet;
  3. import server.HttpServletRequest;
  4. import server.HttpServletResponse;
  5. public class IndexController extends HttpServlet {
  6. @Override
  7. public void service(HttpServletRequest request, HttpServletResponse response) {
  8. //获取请求发送过来的参数
  9. System.out.println("控制层执行了");
  10. //找到业务层做事 业务层找dao层帮忙
  11. //将业务层得到最终结果 响应给浏览器
  12. response.write("XXX");
  13. }
  14. }

总结:学过的知识在复习一遍会有不一样的感触。特别现在对反射 IO流 单例 缓存机制有更深的记忆了。