深入刨析tomcat 之---第1篇,解决第1,2章bug 页面不显示内容Hello. Roses are red.
writedby 张艳涛,
第一个问题是不显示index.html网页
19年才开始学java的第二个月,就开始第一遍看这本书,我估计当初,做第一章的一个案例,自己写代码,和验证就得一天吧,当初就发现了这个问题,chrome浏览器不显示localhost:8080/index.html页面,还特意在培训班的课堂上问了下,老师说是web服务器没有写http头,这个老师一眼就看出来了,还行;但通过ie浏览器就没这个问题,真是服气了~~~
先贴下解决这个问题的代码
package com.zyt.tomcat.ex01; import java.io.*; public class Response { private static final int BUFFER_SIZE=1024; Request request; OutputStream output; public Response(OutputStream output) { this.output = output; } public void setRequest(Request request) { this.request = request; } public void sendStaticResource() throws IOException{ byte[] bytes = new byte[BUFFER_SIZE]; FileInputStream fis=null; File file = new File(HttpServer.WEB_ROOT, request.getUri()); PrintWriter out=null; try { if (file.exists()) { out = new PrintWriter(output); fis = new FileInputStream(file); ByteArrayOutputStream baos = new ByteArrayOutputStream(); int ch = fis.read(bytes, 0, BUFFER_SIZE); while (ch != -1) { baos.write(bytes,0,ch); ch = fis.read(bytes, 0, BUFFER_SIZE); } byte[] array = baos.toByteArray(); out.println("HTTP/1.1 200 OK"); out.println("Server: Molly"); out.println("Content-Type: text/html; charset=UTF-8"); out.println("Content-Length: "+array.length); out.println(""); out.flush(); output.write(array,0,array.length); }else { // file not found String errorMessage = "HTTP/1.1 404 File Not Found\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 23\r\n" + "\r\n" + "<h1>File Not Found</h1>"; output.write(errorMessage.getBytes()); } } catch (IOException e) { e.printStackTrace(); } finally { if (fis != null) { fis.close(); } } } }
你别看这小段内容,其中有一个问题就是,你要写Content-Length的值,如果你先写http头,在读头文件,那你就没法知道文件的大小的值了,这里采取了一个第三变量array来保存文件的内容,这样子就可以先写http头内容,完成之后,接着写文件内容;
这全网独一份,不过我也是在java并发编程的艺术这边书上参考了4.4章,
再顺便提另外一个问题,这个index.html的代码如下
<html>
<head>
<title>Welcome to BrainySoftware</title>
</head>
<body>
<img src="./images/logo.gif">
<br>
Welcome to BrainySoftware.
</body>
</html>
这个图片加载的标签img src="",这个是加载静资源,要说的是静态资源是通过浏览器先接受index.html文件的内容,解析之后再进行了一次http请求得到了jpg图片
并不是一次返回全部内容,看证据,
浏览器端
服务器端
第二个问题是: 浏览器输入 http://localhost:8080/servlet/PrimitiveServlet ,不显示内容
问题描述,这个问题是,第二章的第一案例,加载servlet类,实现动态加载,这个问题,大概在2020年的4月份自己想解决,想了好几天都没想到方法.
这个问题也是一样,他的PrimitiveServlet代码主要是如下,他也没有写http头
import javax.servlet.*; import java.io.IOException; import java.io.PrintWriter; public class PrimitiveServlet implements Servlet { public void init(ServletConfig config) throws ServletException { System.out.println("init"); } public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException { System.out.println("from service"); PrintWriter out = response.getWriter(); out.println("Hello. Roses are red."); out.print("Violets are blue."); } public void destroy() { System.out.println("destroy"); } public String getServletInfo() { return null; } public ServletConfig getServletConfig() { return null; } }
去年4月份想的方法是,在
servlet = ((Servlet) myClass.newInstance());
servlet.service(((ServletRequest) request), ((ServletResponse) response));
service方法之前,给out写一个http 头文件,但是没有解决 out.println("Content-Length: " 是多少); 文件长度的值的问题;
自己就一直想一直想,没想出来,今天下午,同意遇到这个问题了,现在可能对java 的知识理解深入了还是怎么开窍了,
发现自己之前提的问题就是一个错误问题,我们在执行servlet.service()方法的时候,service的功能是什么???之前我理解的是servlet
是给浏览器返回网页,这是错误的,在servlet中,你可以只是sout("hello")回头打印一句话,你不给浏览器回复,那么浏览器只是没得到回复,(网页空白)
那么我的servlet功能实现了吗?实现了控制台已经打印了hello,那么如果你要给浏览器回复一个网页,那么你要在service()方法里面写http头文件和httpbody
不应该servletProcessor1.java这个里,在反射调用servket,service 之前写http头文件
更改后的文件为
import javax.servlet.*; import java.io.IOException; import java.io.PrintWriter; public class PrimitiveServlet implements Servlet { public void init(ServletConfig config) throws ServletException { System.out.println("init"); } public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException { System.out.println("from service"); PrintWriter out = response.getWriter(); out.println("HTTP/1.1 200 OK"); out.println("Server: Molly"); out.println("Content-Type: text/html; charset=UTF-8"); out.println(""); out.flush(); out.println("Hello. Roses are red."); out.print("Violets are blue."); } public void destroy() { System.out.println("destroy"); } public String getServletInfo() { return null; } public ServletConfig getServletConfig() { return null; } }
增加文件如标记所示,这个又遇到一个问题,你得javac编译他,但不能用idea 因为这个类没有包名
所以你要使用javac 带依赖编译,如何编译呢?将源码包中的lib文件方法webroot文件夹下面,运行如下指令
D:\wksp_study\designbook\webroot>javac -encoding UTF-8 -classpath .;D:\wksp_study\designbook\webroot\lib/servlet.jar PrimitiveServlet.java
如果你直接java 类名,会报错,提示
PrimitiveServlet.java:5: 错误: 找不到符号
public class PrimitiveServlet implements Servlet {
^
符号: 类 Servlet
PrimitiveServlet.java:7: 错误: 找不到符号
public void init(ServletConfig config) throws ServletException {
^
符号: 类 ServletConfig
位置: 类 PrimitiveServlet
PrimitiveServlet.java:7: 错误: 找不到符号
public void init(ServletConfig config) throws ServletException {
^
符号: 类 ServletException
位置: 类 PrimitiveServlet
PrimitiveServlet.java:11: 错误: 找不到符号
public void service(ServletRequest request, ServletResponse response)
^
符号: 类 ServletRequest
位置: 类 PrimitiveServlet
PrimitiveServlet.java:11: 错误: 找不到符号
public void service(ServletRequest request, ServletResponse response)
=====================================================
通过如上一番操作,你就能看到如下界面了
结束语:
1,之前打印一章的案例,得慢慢蹭蹭,现在熟练运用了idea的.var .if .nn .try .while 一点代码简直起飞呀,写代码行云流水,真是一种享受;
2,知识是需要循序渐进的,相关知识的积累对当前表面的知识是有很大影响的,比如我问你个问题,jvm的gc是处理垃圾对象,那么垃圾对象是怎么产生的呢? 答案是: A.func1 调用 B.func2 在调用C.func3 那么程序的栈帧中同时有三个方法栈,每个方法中都有自己的局部变量,每个局部变量对应一个jvm对象,如果你在func3中一直while 那么,这个时候jvm没有垃圾,事实是你func3调用玩了,你返回了,摧毁了func3的栈,局部变量给摧毁了,那么 局部变量 obj= new Obejct(); obj 没了, new Object()还在,那么这个new Object()就是jvm的垃圾,同样,你从func1中返回,那么fucn1,2,3中的局部变量都是垃圾了
3.这是我第三次敲这个案例才醒悟了,没那么简单呢,即使是涛哥这么牛逼的人~~~