学习内容》:
//========学习内容=========
请求与响应(4)
请求与响应(5)
《代码内容》:
主要思路—-> 封装response在controller操作完后把responese装满然后响应回浏览器
浏览器解析HTML标签,按照需求格式解析在浏览器上
并把port单独做一个文件的读写,用户用的时候就可以在配置文件中修改服务器端口
//===================================================================================//
服务器的封装与更新优化
ServerHandler
package server;import controller.IndexController;import java.io.*;import java.lang.reflect.Method;import java.net.Socket;import java.util.HashMap;import java.util.Properties;public class ServerHandler extends Thread{private Socket socket = null;public ServerHandler(Socket socket){this.socket = socket;}//重写线程的run方法 也就是我们的Handler需要做的事情public void run(){/*** 分析:我们需要启动服务器后,通过socket获取流读取请求过来的资源名* 那么--->我们就设计一个方法 来读这个请求资源名* **/this.ReadRequestContentAndParams(socket);}//设计一个方法 来读取浏览器发送过来的请求private void ReadRequestContentAndParams(Socket socket) {try {//因为 浏览器 发送过来的是一行的信息--->资源名 用高级流来读取一行BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));//读取到的资源名和参数String contentAndParams = reader.readLine();//现在我拿到了资源名和参数,我需要把他们做一个解析。this.parseContentAndParams(contentAndParams);} catch (IOException e) {e.printStackTrace();}}//设计一个方法 用来解析 资源名 和 参数private void parseContentAndParams(String contentAndParams) {//index?uname=武伟&upassword=123123String content = null;HashMap paramsMap = null;if (contentAndParams.contains("?")){content = contentAndParams.substring(0, contentAndParams.indexOf("?"));String[] params = contentAndParams.substring(content.length() + 1).split("&");for (String keyAndValue : params){String[] KV = keyAndValue.split("=");paramsMap = new HashMap<String,String>();paramsMap.put(KV[0],KV[1]);}}else{content = contentAndParams;}//解析完后 把解析好的资源名 和 参数 包装成一个request对象HttpServletRequest request = new HttpServletRequest(content,paramsMap);HttpServletResponse response = new HttpServletResponse();//解析好了之后 我们可以通过拿到的 资源名 去找 ControllerServletController.findController(request,response);//响应回去this.responseToBrower(response);}public void responseToBrower(HttpServletResponse response){try {System.out.println(response.getResponse());PrintWriter writer = new PrintWriter(socket.getOutputStream());writer.println(response.getResponse());writer.flush();} catch (IOException e) {e.printStackTrace();}}}
ReadServerFilePorperties
package server;import java.io.FileReader;import java.io.IOException;import java.util.Enumeration;import java.util.HashMap;import java.util.Properties;public class ReadServerProperties {private static HashMap<String,String> serverFileMap= new HashMap<>();static {Properties properties = new Properties();try {properties.load(new FileReader("src/server.properties"));Enumeration<?> enumeration = properties.propertyNames();while (enumeration.hasMoreElements()){String key = (String)enumeration.nextElement();String value = properties.getProperty(key);serverFileMap.put(key,value);}} catch (IOException e) {e.printStackTrace();}}public static Integer getServerConfig(String key){return Integer.parseInt(serverFileMap.get(key));}}
HttpServletResponse
package server;public class HttpServletResponse {private StringBuilder builder = new StringBuilder();public void write(String str){this.builder.append(str);}public String getResponse(){return this.builder.toString();}}
ServletController
package server;import java.io.FileReader;import java.io.IOException;import java.lang.reflect.Method;import java.util.Enumeration;import java.util.HashMap;import java.util.Properties;public class ServletController {/*** 这个类的目的是为了管理 findController方法* 1.方法与之前服务器Handler做的事情不一致 抽离出来* 2.每一次找寻Controller类的时候都需要参考一下web.properties* 读取文件性能会比较低 增加一个缓存机制* 3.每一个Controller类都是由findController方法来找寻* 找到了Controller类的目的是为了执行里面的方法* 让类中的方法有一个统一的规则----便于查找和使用* 4.发现Controller类与之前的Service和Dao相似 只有方法执行 没有属性* 让Controller类的对象变成单例模式* **///定义一个Map集合 用来做缓存,在类加载的时候就把配置文件读取到集合中private static HashMap<String,String> controllerNameMap = new HashMap<>();//定义一个Map集合 用来做缓存,用到这个对象的时候,就把这个对象new出来,存到集合中private static HashMap<String,HttpServlet> controllerObjectMap = new HashMap<>();//静态块,只用一次所以静态吗,来执行读取配置文件和存入集合中static {Properties properties = new Properties();try {properties.load(new FileReader("src//web.properties"));//获取配置文件的所有keyEnumeration<?> enumeration = properties.propertyNames();//遍历所有的key,通过每个key找值while (enumeration.hasMoreElements()){String content = (String)enumeration.nextElement();String controllerClassName = properties.getProperty(content);controllerNameMap.put(content,controllerClassName);}} catch (IOException e) {e.printStackTrace();}}//通过资源名拿到配置文件中对应的控制层的类全名,进行反射类全名,执行控制层方法public static void findController(HttpServletRequest request,HttpServletResponse response) {Properties properties = new Properties();String content = request.getContent();try {//通过配置文件的key找到对应的控制层的名字String realControllerName = controllerNameMap.get(content);//我拿到 类全名之后 进行反射然后执行对应的方法Class clazz = Class.forName(realControllerName);if (controllerObjectMap.get(content) == null){/**如果对象集合中,当前请求的这个对象不存在,就new一个,然后放入集合中**/HttpServlet httpServlet = (HttpServlet)clazz.newInstance();controllerObjectMap.put(content,httpServlet);System.out.println("在对象集合中缓存了一次对象");}HttpServlet httpServlet = controllerObjectMap.get(content);Method controllerMethod = clazz.getMethod("service", HttpServletRequest.class, HttpServletResponse.class);controllerMethod.invoke(httpServlet,request,response);} catch (Exception e) {e.printStackTrace();}}}
IndexController
package controller;import server.HttpServlet;import server.HttpServletRequest;import server.HttpServletResponse;public class IndexController extends HttpServlet {public void service(HttpServletRequest request,HttpServletResponse response){response.write("银行系统<br>");response.write("账号<br>");response.write("密码<br>");}}
//===================================================================================//
浏览器的更新—>解析响应信息
package brower;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.io.PrintWriter;import java.net.Socket;import java.util.Scanner;public class Brower {private Socket socket;private Scanner scanner = new Scanner(System.in);//设计一个方法 来模拟输入浏览器中的URLpublic void openBrower(){System.out.println("请输入url地址");String url = scanner.nextLine();//将输入的url地址进行解析 拆分开 ip prot 用来创建socket对象//资源名用来发出请求资源this.parseUrl(url);}//设计一个方法 用来解析拆分Url//localhost:9999/index.jsppublic void parseUrl(String url){String ip = url.substring(0,url.indexOf(":"));String port = url.substring(ip.length()+1,url.indexOf("/"));String contentAndParam = url.substring(ip.length()+1 + port.length()+1);//用当前截取到的信息创建socket并发出请求this.createSocketAndRequest(ip,port,contentAndParam);}//设计一个方法 用来创建Socket并发出请求public void createSocketAndRequest(String ip,String port,String contentAndParam){try {socket = new Socket(ip, Integer.parseInt(port));PrintWriter writer = new PrintWriter(socket.getOutputStream());writer.println(contentAndParam);writer.flush();//等待响应信息this.readAndParseServerResponse();} catch (IOException e) {e.printStackTrace();}}//接收服务器的响应信息public void readAndParseServerResponse(){try {BufferedReader builder = new BufferedReader(new InputStreamReader(socket.getInputStream()));String responseStr = builder.readLine();String brResponse = responseStr.replace("<br>", "\r\n");int lessThanIndex = responseStr.indexOf("<");int grentThanIndex = responseStr.indexOf(">");if (lessThanIndex != -1 && grentThanIndex != -1 && grentThanIndex > lessThanIndex){}System.out.println(brResponse);} catch (IOException e) {e.printStackTrace();}}public static void main(String[] args) {Brower brower = new Brower();brower.openBrower();}}
学习总结:
学懂的:
熟练掌握了如果做缓存机制,更加透彻的理解static关键字的用法
理解了Servlet如果管理Controller机制
请求响应—图:
有问题的地方:
无
