静态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];
}
//静态web
if (uri.indexOf("html") != -1)
contentType = "text/html";
else if (uri.indexOf("jpg") != -1)
contentType = "image/jepg";
else
contentType = "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){ //动态web
String servletName = "";
if (uri.indexOf("?")!=-1)
servletName = uri.substring(uri.indexOf("servlet/")+8,uri.indexOf("?"));
else
servletName = 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 {
//静态web
if (uri.indexOf("html") != -1)
contentType = "text/html";
else if (uri.indexOf("jpg") != -1)
contentType = "image/jepg";
else
contentType = "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{
@Override
public void init() {
}
@Override
public void service(String request, OutputStream out) throws IOException {
int endIndex = request.indexOf("/r/n");
String firstOfRequest = "";
if (endIndex!=-1)
firstOfRequest = request.substring(0,endIndex);
else
firstOfRequest = 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中,客户端可以与服务器交互,服务器通过与客户端的交互,来动态响应客户端。