静态Web
说到Servlet自然就要说到Web,Web分为静态Web和动态Web,之前我一直都傻傻分不清两者的区别,直到用JAVA编写了一个服务器后才明白二者的区别,所谓静态Web,实际上就是指,客户端要请求的资源文件,服务器已经提前把它放在了文件系统(磁盘)上,看下面用Java实现的一个静态Web服务器public class HTTPService {private static HashMap<String,Servlet> servletCache = new HashMap<>();public static void init(){servletCache.put("HTTPServlet",new HTTPServlet());}public static void main(String[] args) {init();int port;ServerSocket serversocket;port=8080;try {serversocket = new ServerSocket(port); //默认服务器套接字ip为本地地址System.out.println("服务器正在监听端口:8080");while (true) {try{Socket socket = serversocket.accept();//会进入阻塞状态,直到客户端与服务器TCP建立System.out.println("建立了与客户端的一个新的tcp连接,客户端地址为" + socket.getInetAddress() + ":" + socket.getPort());service(socket);}catch (Exception e){System.out.println("客户端请求资源不存在");}}} catch (Exception e) {System.out.println("客户端请求资源不存在");}}public static void service(Socket socket) throws Exception {InputStream socketIn = socket.getInputStream();//获得客户端请求信息流Thread.sleep(500); //与客户端TCP请求已建立,还需要等待客户端发送http请求,如果在TCP后立马响应HTTP,socket内容可能为空int size = socketIn.available();byte[] buffer = new byte[size];socketIn.read(buffer);String request = new String(buffer);int endIndex = request.indexOf("\r\n");if (endIndex==-1)endIndex = request.length();String firstLineOfRequest = request.substring(0,endIndex);String[] parts = firstLineOfRequest.split(" ");String uri="";String contentType="";if (parts.length>=2){uri = parts[1];}//静态webif (uri.indexOf("html") != -1)contentType = "text/html";else if (uri.indexOf("jpg") != -1)contentType = "image/jepg";elsecontentType = "application/octet-stream";String firstLineOfResponse = "HTTP/1.1 200 OK\r\n"; //响应行String responseHeader = "Content-Type:" + contentType + "\r\n\r\n";// FileInputStream in = new FileInputStream("E:\\IDEA WORKSPACE\\ServiceDemo\\resources\\index.html");System.out.println(HttpServer.class.getResource(""));InputStream in = HTTPService.class.getResourceAsStream("root/" + uri);System.out.println(HTTPService.class.getResource("root/" + uri));OutputStream output = socket.getOutputStream();output.write(firstLineOfResponse.getBytes());output.write(responseHeader.getBytes());buffer = new byte[1024];int len = 0;while ((len = in.read(buffer)) != -1) {System.out.println(1);output.write(buffer, 0, len);}Thread.sleep(1000);//睡眠1秒,等待客户端接收http响应结果,socket代表两者间的tcp连接,如果立马断开,客户端可能就收不到响应结果了socket.close();}}
将事先准备好的index.html文件放在磁盘上,将代码运行起来,此时HTTPServer就作为一个服务开始监听电脑上的8080端口了,打开浏览器,在url地址栏输入localhost:8080/index.html,结果如下:
工作原理如下:
HTTPServer接收到来自客户端的请求后,就会在磁盘上查找客户端请求的资源文件,然后把文件响应给客户端,index.html就事先存放在磁盘上,然后当浏览器请求index.html,HTTPServer就把html文件响应给浏览器,浏览器再解析html文件后,就是我们看到的Hello页面了。
动态Web
网上经常能看见一句话,动态Web就是每个用户看到的东西是不一样的,这句话没错,但是还不太能够帮助我们理解动态Web。那么动态Web到底是什么,动态Web就是指客户端可以与服务器进行交互,并且客户端请求的资源文件,是由服务器动态生成的。举这么一个例子,假设D是一个在某城市居住了很久的人,这一天A向D问路X街怎么走,D经过思考后,告诉了A,此时B又来问路Y街怎么走,对于C来说,简直轻而易举。上述中A,B看作客户端,D是服务器,而问路可以看作客户端向服务器请求的资源文件,去某城市可以看作是客户端与服务器的交互,很明显,A和B得到的响应内容都是不同的,服务器在得到客户端的请求后,执行业务逻辑操作,得出了通往某城市怎么走,然后响应给客户端。public class HTTPService {private static HashMap<String,Servlet> servletCache = new HashMap<>();public static void init(){servletCache.put("HTTPServlet",new HTTPServlet());}public static void main(String[] args) {init();int port;ServerSocket serversocket;port=8080;try {serversocket = new ServerSocket(port); //默认服务器套接字ip为本地地址System.out.println("服务器正在监听端口:8080");while (true) {try{Socket socket = serversocket.accept();//会进入阻塞状态,直到客户端与服务器TCP建立System.out.println("建立了与客户端的一个新的tcp连接,客户端地址为" + socket.getInetAddress() + ":" + socket.getPort());service(socket);}catch (Exception e){System.out.println("客户端请求资源不存在");}}} catch (Exception e) {System.out.println("客户端请求资源不存在");}}public static void service(Socket socket) throws Exception {InputStream socketIn = socket.getInputStream();//获得客户端请求信息流Thread.sleep(500); //与客户端TCP请求已建立,还需要等待客户端发送http请求,如果在TCP后立马响应HTTP,socket内容可能为空int size = socketIn.available();byte[] buffer = new byte[size];socketIn.read(buffer);String request = new String(buffer);int endIndex = request.indexOf("\r\n");if (endIndex==-1)endIndex = request.length();String firstLineOfRequest = request.substring(0,endIndex);String[] parts = firstLineOfRequest.split(" ");String uri="";String contentType="";if (parts.length>=2){uri = parts[1];}System.out.println(uri);if(uri.indexOf("servlet")!=-1){ //动态webString servletName = "";if (uri.indexOf("?")!=-1)servletName = uri.substring(uri.indexOf("servlet/")+8,uri.indexOf("?"));elseservletName = uri.substring(uri.indexOf("servlet/")+8,uri.length());System.out.println(servletName);Servlet servlet = servletCache.get(servletName);System.out.println(servletCache);System.out.println(servlet);if (servlet == null)throw new Exception();servlet.init();servlet.service(request,socket.getOutputStream());}else {//静态webif (uri.indexOf("html") != -1)contentType = "text/html";else if (uri.indexOf("jpg") != -1)contentType = "image/jepg";elsecontentType = "application/octet-stream";String firstLineOfResponse = "HTTP/1.1 200 OK\r\n"; //响应行String responseHeader = "Content-Type:" + contentType + "\r\n\r\n";// FileInputStream in = new FileInputStream("E:\\IDEA WORKSPACE\\ServiceDemo\\resources\\index.html");System.out.println(HttpServer.class.getResource(""));InputStream in = HTTPService.class.getResourceAsStream("root/" + uri);System.out.println(HTTPService.class.getResource("root/" + uri));OutputStream output = socket.getOutputStream();output.write(firstLineOfResponse.getBytes());output.write(responseHeader.getBytes());buffer = new byte[1024];int len = 0;while ((len = in.read(buffer)) != -1) {System.out.println(1);output.write(buffer, 0, len);}}Thread.sleep(1000);//睡眠1秒,等待客户端接收http响应结果,socket代表两者间的tcp连接,如果立马断开,客户端可能就收不到响应结果了socket.close();}}
public class HTTPServlet implements Servlet{@Overridepublic void init() {}@Overridepublic void service(String request, OutputStream out) throws IOException {int endIndex = request.indexOf("/r/n");String firstOfRequest = "";if (endIndex!=-1)firstOfRequest = request.substring(0,endIndex);elsefirstOfRequest = request;String[] parts = firstOfRequest.split(" ");String method = parts[0];String uri = parts[1];String userName="";if (method.equalsIgnoreCase("get")){if (uri.indexOf("username=")!=-1){String[] params = uri.substring(uri.indexOf("?") + 8, uri.length()).split("&");String[] params_parts = params[0].split("=");userName = params_parts[1];}}if (method.equalsIgnoreCase("post")){if (request.indexOf("\r\n\r\n")!=-1){String content = request.substring(request.indexOf("\r\n\r\n"+4,request.length()));if (content.indexOf("username=")!=-1){String[] contentParts = content.split("&");userName = (contentParts[0].split("="))[1];}}}userName = URLDecoder.decode(userName,"utf-8");System.out.println(userName);out.write("HTTP/1.1 200 OK\r\n".getBytes());out.write("Content-Type:text/html\r\n\r\n".getBytes());out.write(("<meta charset=\"UTF-8\"> <h1>Hello,"+userName+"</h1>").getBytes());}
}
public interface Servlet {public void init();public void service(String request, OutputStream out) throws IOException;
}
前面说过,动态Web中服务器在接收到请求后,会执行业务逻辑操作,这个业务逻辑操作其实就是由服务器内的servlet模块实现的,下面的图就是上述的代码的执行原理
如果客户端的URL访问的是servlet目录下,那么就代表是访问动态资源,服务器就会交给servlet处理,否则就会当成普通静态文件处理,从磁盘上取出响应即可。学习过一点如何编写webapp的同学会发现,上述代码中的servlet缓冲池(servletCache)与web.xml中的servlet映射很相似,都是通过名字来映射到一个具体的servlet实现类,服务器动态加载servlet类实现业务逻辑操作也体现了动态Web的特性。
在浏览器的url地址栏输入http://localhost:8080/servlet/HTTPServlet?username=“王小虎”,结果如下
在动态Web中,客户端可以与服务器交互,服务器通过与客户端的交互,来动态响应客户端。