HTTP服务器
一. 前言
在前上一章教程中,介绍了Container容器。
本章将在上一章的基础上,进一步扩展程序。注:
1.本文针对初学Java的同学训练学习思路,请不要太纠结于细节问题。2.本文旨在达到抛砖引玉的效果,希望大家扩展本例子,以学到更多知识的精髓。学习本章需要准备的知识:
1.读完本系列教程的前面章节。2.了解Http协议,了解HTML。二. 步入正题
话不多说,大家自己理解,下面步入正题:本章我们通过浏览器来调用我们的程序。
首先我们看一下浏览器和服务器的交互过程:
比如点击页面上一个按钮提交请求的流程:
1. 浏览器发送请求和数据给服务器;2. 服务器读完请求和数据后,根据请求的参数调用系统逻辑;3. 然后将得到的结果用response方式传递给浏览器。这个通讯过程采用HTTP协议。
所以,我们首先要按照HTTP协议的格式解析发送来的请求,
然后读取我们想要的数据。下面我们做一个模拟服务器来接收浏览器发送来的请求,看一下请求的数据格式。
1 /** 2 * 3 * @author http://www.java123.vip 4 * 5 */ 6 public class MyServer { 7 8 private int port; 9 10 public MyServer(int port) {11 this.port = port;12 }13 14 public void startServer() {15 try {16 17 ServerSocket ss = new ServerSocket(port);18 System.out.println("listening at port:"+port);19 20 while(true) {21 Socket s = ss.accept();22 System.out.println("get connection:"+s.getInetAddress().toString());23 24 // 启动和浏览器通讯的线程25 ClientThread clientThread = new ClientThread(s);26 new Thread(clientThread).start();27 }28 29 } catch (IOException e) {30 e.printStackTrace();31 }32 }33 34 public static void main(String[] args) {35 MyServer fvs = new MyServer(8000);36 fvs.startServer();37 }38 }
1 /** 2 * 3 * @author http://www.java123.vip 4 * 5 */ 6 public class ClientThread implements Runnable{ 7 8 private Socket socket; 9 private BufferedReader br;10 private PrintWriter pw;11 12 public ClientThread(Socket socket) {13 try {14 15 InputStream is = socket.getInputStream();16 InputStreamReader isr = new InputStreamReader(is);17 br = new BufferedReader(isr);18 19 OutputStream os = socket.getOutputStream();20 OutputStreamWriter osw = new OutputStreamWriter(os);21 pw = new PrintWriter(osw,true);22 23 } catch (IOException e) {24 e.printStackTrace();25 }26 }27 28 public void run() {29 30 while(true) {31 try {32 33 String message = br.readLine();34 // 输出所有得到的消息35 System.out.println("get message:"+message);36 37 38 } catch(IOException e) {39 e.printStackTrace();40 } catch (Exception e) {41 e.printStackTrace();42 }43 }44 }45 46 }
我们做一个HTML页面如下:
HTML代码如下:
Insert title here
在浏览器端输入1,点query按钮:
可以看到,浏览器向服务器发送了如下数据:
GET /person?personid=1 HTTP/1.1Host: localhost:8000Connection: keep-aliveCache-Control: max-age=0Upgrade-Insecure-Requests: 1User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8Accept-Encoding: gzip, deflate, brAccept-Language: ja,en-US;q=0.9,en;q=0.8,zh-CN;q=0.7,zh;q=0.6Cookie: qa_noticed=1; _ga=GA1.1.462590489.1538429997
最后接收一个空字符串表示发送请求完毕:
我们需要的信息[请求的路径(/person)和参数(personid=1)]都在第一行,所以我们在第一行数据过来的时候,把需要的信息保存起来。
数据发送完毕后,用得到的信息来查询数据库,得到查询结果。再将查询结果发送Response传递给客户端。代码如下:1 /** 2 * 3 * @author http://www.java123.vip 4 * 5 */ 6 public class ClientThread implements Runnable{ 7 8 private Socket socket; 9 private BufferedReader br; 10 private PrintWriter pw; 11 12 public ClientThread(Socket socket) { 13 try { 14 15 InputStream is = socket.getInputStream(); 16 InputStreamReader isr = new InputStreamReader(is); 17 br = new BufferedReader(isr); 18 19 OutputStream os = socket.getOutputStream(); 20 OutputStreamWriter osw = new OutputStreamWriter(os); 21 pw = new PrintWriter(osw,true); 22 23 } catch (IOException e) { 24 e.printStackTrace(); 25 } 26 } 27 28 public void run() { 29 30 // 保存请求路径(/person) 31 String requestPath = ""; 32 // 保存请求参数(personid=1) 33 MapparameterMap = new HashMap (); 34 35 while(true) { 36 try { 37 // 读取一行请求 38 String message = br.readLine(); 39 System.out.println("get message:"+message); 40 41 if(message == null) { 42 break; 43 } 44 45 // 用空格分隔请求的内容 46 String[] messageDetails = message.split(" "); 47 48 // 对于包含get的第一行,得到路径 /person 49 if(messageDetails[0].equalsIgnoreCase("get")) { 50 requestPath = messageDetails[1]; 51 } 52 53 // 请求发送完毕(读到空字符串)后,根据请求参数查数据 54 if("".equals(message)) { 55 56 // 把得到的(/person?personid=1)拆分出/person和personid=1 57 int endPos = requestPath.indexOf("?"); 58 if(endPos == -1) { 59 requestPath = requestPath.substring(1); 60 }else { 61 String paramString = requestPath.substring(endPos+1); 62 requestPath = requestPath.substring(1,endPos); 63 64 String[] params = paramString.split("&"); 65 for(int i = 0; i < params.length; i ++) { 66 String[] keyValue = params[i].split("="); 67 parameterMap.put(keyValue[0], keyValue[1]); 68 } 69 } 70 71 System.out.println("request path:"+requestPath); 72 73 // 保存数据库查询结果用 74 String data = ""; 75 76 // 处理 /person请求 77 if(requestPath.equals("person")) { 78 79 // 将参数personid=1发送给PersonController来查数据 80 PersonController personController = new PersonController(); 81 data = personController.queryPerson(parameterMap); 82 83 }else if(requestPath.equals("favicon.ico")){ //不处理 84 data = ""; 85 } 86 87 // 发送Reponse到浏览器 88 pw.println("HTTP/1.1 200 OK"); 89 pw.println("Content-Type: text/html"); 90 pw.println("Content-length: "+data.length()); 91 pw.println(); 92 pw.println(data); 93 pw.println(); 94 break; 95 } 96 97 } catch(IOException e) { 98 e.printStackTrace(); 99 } catch (Exception e) {100 e.printStackTrace();101 }102 }103 }104 105 }
对于每个请求,我们做了一个Controller类来负责具体的逻辑,代码如下:
1 /** 2 * 3 * @author http://www.java123.vip 4 * 5 */ 6 public class PersonController { 7 8 public String queryPerson(MaprequestParameterMap) { 9 10 // 得到请求参数11 String personId = requestParameterMap.get("personid");12 13 // 创建Service实例14 MyContainer container = MyContainer.getInstance();15 PersonService personService = (PersonService)container.getObject(PersonService.class);16 17 // 查询结果18 Person personResult = personService.getPerson(personId);19 20 // 封装结果21 StringBuffer result = new StringBuffer();22 result.append("id:"+personResult.id);23 result.append(" username:"+personResult.username);24 result.append(" password:"+personResult.passwd);25 26 // 返回结果27 return result.toString();28 }29 }
三. 测试
启动服务器:
在浏览器端输入1,点query按钮:
显示查询结果:
完整程序请大家从[]下载
如有问题,大家来我的网站进行提问。
版权声明:本教程版权归java123.vip所有,禁止任何形式的转载与引用。