学习内容》:

    //========学习内容=========
    请求与响应(4)
    请求与响应(5)

    《代码内容》:
    主要思路—-> 封装response在controller操作完后把responese装满然后响应回浏览器
    浏览器解析HTML标签,按照需求格式解析在浏览器上
    并把port单独做一个文件的读写,用户用的时候就可以在配置文件中修改服务器端口

    //===================================================================================//

    服务器的封装与更新优化
    ServerHandler

    1. package server;
    2. import controller.IndexController;
    3. import java.io.*;
    4. import java.lang.reflect.Method;
    5. import java.net.Socket;
    6. import java.util.HashMap;
    7. import java.util.Properties;
    8. public class ServerHandler extends Thread{
    9. private Socket socket = null;
    10. public ServerHandler(Socket socket){
    11. this.socket = socket;
    12. }
    13. //重写线程的run方法 也就是我们的Handler需要做的事情
    14. public void run(){
    15. /**
    16. * 分析:我们需要启动服务器后,通过socket获取流读取请求过来的资源名
    17. * 那么--->我们就设计一个方法 来读这个请求资源名
    18. * **/
    19. this.ReadRequestContentAndParams(socket);
    20. }
    21. //设计一个方法 来读取浏览器发送过来的请求
    22. private void ReadRequestContentAndParams(Socket socket) {
    23. try {
    24. //因为 浏览器 发送过来的是一行的信息--->资源名 用高级流来读取一行
    25. BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    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. //index?uname=武伟&upassword=123123
    37. String content = null;
    38. HashMap paramsMap = null;
    39. if (contentAndParams.contains("?")){
    40. content = contentAndParams.substring(0, contentAndParams.indexOf("?"));
    41. String[] params = contentAndParams.substring(content.length() + 1).split("&");
    42. for (String keyAndValue : params){
    43. String[] KV = keyAndValue.split("=");
    44. paramsMap = new HashMap<String,String>();
    45. paramsMap.put(KV[0],KV[1]);
    46. }
    47. }else{
    48. content = contentAndParams;
    49. }
    50. //解析完后 把解析好的资源名 和 参数 包装成一个request对象
    51. HttpServletRequest request = new HttpServletRequest(content,paramsMap);
    52. HttpServletResponse response = new HttpServletResponse();
    53. //解析好了之后 我们可以通过拿到的 资源名 去找 Controller
    54. ServletController.findController(request,response);
    55. //响应回去
    56. this.responseToBrower(response);
    57. }
    58. public void responseToBrower(HttpServletResponse response){
    59. try {
    60. System.out.println(response.getResponse());
    61. PrintWriter writer = new PrintWriter(socket.getOutputStream());
    62. writer.println(response.getResponse());
    63. writer.flush();
    64. } catch (IOException e) {
    65. e.printStackTrace();
    66. }
    67. }
    68. }

    ReadServerFilePorperties

    1. package server;
    2. import java.io.FileReader;
    3. import java.io.IOException;
    4. import java.util.Enumeration;
    5. import java.util.HashMap;
    6. import java.util.Properties;
    7. public class ReadServerProperties {
    8. private static HashMap<String,String> serverFileMap= new HashMap<>();
    9. static {
    10. Properties properties = new Properties();
    11. try {
    12. properties.load(new FileReader("src/server.properties"));
    13. Enumeration<?> enumeration = properties.propertyNames();
    14. while (enumeration.hasMoreElements()){
    15. String key = (String)enumeration.nextElement();
    16. String value = properties.getProperty(key);
    17. serverFileMap.put(key,value);
    18. }
    19. } catch (IOException e) {
    20. e.printStackTrace();
    21. }
    22. }
    23. public static Integer getServerConfig(String key){
    24. return Integer.parseInt(serverFileMap.get(key));
    25. }
    26. }

    HttpServletResponse

    1. package server;
    2. public class HttpServletResponse {
    3. private StringBuilder builder = new StringBuilder();
    4. public void write(String str){
    5. this.builder.append(str);
    6. }
    7. public String getResponse(){
    8. return this.builder.toString();
    9. }
    10. }

    ServletController

    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. /**
    10. * 这个类的目的是为了管理 findController方法
    11. * 1.方法与之前服务器Handler做的事情不一致 抽离出来
    12. * 2.每一次找寻Controller类的时候都需要参考一下web.properties
    13. * 读取文件性能会比较低 增加一个缓存机制
    14. * 3.每一个Controller类都是由findController方法来找寻
    15. * 找到了Controller类的目的是为了执行里面的方法
    16. * 让类中的方法有一个统一的规则----便于查找和使用
    17. * 4.发现Controller类与之前的Service和Dao相似 只有方法执行 没有属性
    18. * 让Controller类的对象变成单例模式
    19. * **/
    20. //定义一个Map集合 用来做缓存,在类加载的时候就把配置文件读取到集合中
    21. private static HashMap<String,String> controllerNameMap = new HashMap<>();
    22. //定义一个Map集合 用来做缓存,用到这个对象的时候,就把这个对象new出来,存到集合中
    23. private static HashMap<String,HttpServlet> controllerObjectMap = new HashMap<>();
    24. //静态块,只用一次所以静态吗,来执行读取配置文件和存入集合中
    25. static {
    26. Properties properties = new Properties();
    27. try {
    28. properties.load(new FileReader("src//web.properties"));
    29. //获取配置文件的所有key
    30. Enumeration<?> enumeration = properties.propertyNames();
    31. //遍历所有的key,通过每个key找值
    32. while (enumeration.hasMoreElements()){
    33. String content = (String)enumeration.nextElement();
    34. String controllerClassName = properties.getProperty(content);
    35. controllerNameMap.put(content,controllerClassName);
    36. }
    37. } catch (IOException e) {
    38. e.printStackTrace();
    39. }
    40. }
    41. //通过资源名拿到配置文件中对应的控制层的类全名,进行反射类全名,执行控制层方法
    42. public static void findController(HttpServletRequest request,HttpServletResponse response) {
    43. Properties properties = new Properties();
    44. String content = request.getContent();
    45. try {
    46. //通过配置文件的key找到对应的控制层的名字
    47. String realControllerName = controllerNameMap.get(content);
    48. //我拿到 类全名之后 进行反射然后执行对应的方法
    49. Class clazz = Class.forName(realControllerName);
    50. if (controllerObjectMap.get(content) == null){
    51. /**如果对象集合中,当前请求的这个对象不存在,就new一个,然后放入集合中**/
    52. HttpServlet httpServlet = (HttpServlet)clazz.newInstance();
    53. controllerObjectMap.put(content,httpServlet);
    54. System.out.println("在对象集合中缓存了一次对象");
    55. }
    56. HttpServlet httpServlet = controllerObjectMap.get(content);
    57. Method controllerMethod = clazz.getMethod("service", HttpServletRequest.class, HttpServletResponse.class);
    58. controllerMethod.invoke(httpServlet,request,response);
    59. } catch (Exception e) {
    60. e.printStackTrace();
    61. }
    62. }
    63. }

    IndexController

    1. package controller;
    2. import server.HttpServlet;
    3. import server.HttpServletRequest;
    4. import server.HttpServletResponse;
    5. public class IndexController extends HttpServlet {
    6. public void service(HttpServletRequest request,HttpServletResponse response){
    7. response.write("银行系统<br>");
    8. response.write("账号<br>");
    9. response.write("密码<br>");
    10. }
    11. }

    //===================================================================================//
    浏览器的更新—>解析响应信息

    1. package brower;
    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 Brower {
    9. private Socket socket;
    10. private Scanner scanner = new Scanner(System.in);
    11. //设计一个方法 来模拟输入浏览器中的URL
    12. public void openBrower(){
    13. System.out.println("请输入url地址");
    14. String url = scanner.nextLine();
    15. //将输入的url地址进行解析 拆分开 ip prot 用来创建socket对象
    16. //资源名用来发出请求资源
    17. this.parseUrl(url);
    18. }
    19. //设计一个方法 用来解析拆分Url
    20. //localhost:9999/index.jsp
    21. public void parseUrl(String url){
    22. String ip = url.substring(0,url.indexOf(":"));
    23. String port = url.substring(ip.length()+1,url.indexOf("/"));
    24. String contentAndParam = url.substring(ip.length()+1 + port.length()+1);
    25. //用当前截取到的信息创建socket并发出请求
    26. this.createSocketAndRequest(ip,port,contentAndParam);
    27. }
    28. //设计一个方法 用来创建Socket并发出请求
    29. public void createSocketAndRequest(String ip,String port,String contentAndParam){
    30. try {
    31. socket = new Socket(ip, Integer.parseInt(port));
    32. PrintWriter writer = new PrintWriter(socket.getOutputStream());
    33. writer.println(contentAndParam);
    34. writer.flush();
    35. //等待响应信息
    36. this.readAndParseServerResponse();
    37. } catch (IOException e) {
    38. e.printStackTrace();
    39. }
    40. }
    41. //接收服务器的响应信息
    42. public void readAndParseServerResponse(){
    43. try {
    44. BufferedReader builder = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    45. String responseStr = builder.readLine();
    46. String brResponse = responseStr.replace("<br>", "\r\n");
    47. int lessThanIndex = responseStr.indexOf("<");
    48. int grentThanIndex = responseStr.indexOf(">");
    49. if (lessThanIndex != -1 && grentThanIndex != -1 && grentThanIndex > lessThanIndex){
    50. }
    51. System.out.println(brResponse);
    52. } catch (IOException e) {
    53. e.printStackTrace();
    54. }
    55. }
    56. public static void main(String[] args) {
    57. Brower brower = new Brower();
    58. brower.openBrower();
    59. }
    60. }

    学习总结:
    学懂的:
    熟练掌握了如果做缓存机制,更加透彻的理解static关键字的用法
    理解了Servlet如果管理Controller机制
    请求响应—图:
    请求响应流程.jpg

    有问题的地方: