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代码如下:
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <form action="http://localhost:8000/person" method="get"> please input personid:<input id="personid" name="personid"/><input type="submit" value="query"/> </form> </body> </html>
启动服务器:
在浏览器端输入1,点query按钮:
可以看到,浏览器向服务器发送了如下数据:
GET /person?personid=1 HTTP/1.1
Host: localhost:8000
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: ja,en-US;q=0.9,en;q=0.8,zh-CN;q=0.7,zh;q=0.6
Cookie: 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 Map<String,String> parameterMap = new HashMap<String,String>(); 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(Map<String,String> requestParameterMap) { 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("<br/>username:"+personResult.username); 24 result.append("<br/>password:"+personResult.passwd); 25 26 // 返回结果 27 return result.toString(); 28 } 29 }
三. 测试
启动服务器:
在浏览器端输入1,点query按钮:
显示查询结果:
完整程序请大家从[这里]下载
如有问题,大家来我的网站进行提问。
https://www.java123.vip/qa
版权声明:本教程版权归java123.vip所有,禁止任何形式的转载与引用。