how2j.cn

下载区
文件名 文件大小
diytomcat.rar 7m
lib.rar 7m

10分20秒
本视频采用html5方式播放,如无法正常播放,请将浏览器升级至最新版本,推荐火狐,chrome,360浏览器。 如果装有迅雷,播放视频呈现直接下载状态,请调整 迅雷系统设置-基本设置-启动-监视全部浏览器 (去掉这个选项)。 chrome 的 视频下载插件会影响播放,如 IDM 等,请关闭或者切换其他浏览器

步骤 1 : 开始啦   
步骤 2 : 创建项目   
步骤 3 : Java 项目   
步骤 4 : 选择模板   
步骤 5 : 项目名称   
步骤 6 : 项目结构   
步骤 7 : jar 包   
步骤 8 : 设置库   
步骤 9 : 新建包   
步骤 10 : 新建类   
步骤 11 : 运行并测试   
步骤 12 : 代码讲解   
步骤 13 : 比较可运行项目,快速定位问题   

自己写一个Tomcat, 几乎使用到了除开框架外的所有Java 技术,如多线程,Socket, J2EE, 反射,Log4j, JSoup, JUnit, Html 等一整套技术栈, 从无到有,循序渐进涵盖全部74个知识点,549个开发步骤, 为竞争高薪资职位加上一个有吸引力的砝码.
增值内容,点击购买
前面絮絮叨叨了那么多,现在终于开始动手写代码啦,接下来就会用 idea 开始启动自己写个 tomcat 之旅。
自己写一个Tomcat, 几乎使用到了除开框架外的所有Java 技术,如多线程,Socket, J2EE, 反射,Log4j, JSoup, JUnit, Html 等一整套技术栈, 从无到有,循序渐进涵盖全部74个知识点,549个开发步骤, 为竞争高薪资职位加上一个有吸引力的砝码.
增值内容,点击购买
菜单->File->New -> Project
创建项目
自己写一个Tomcat, 几乎使用到了除开框架外的所有Java 技术,如多线程,Socket, J2EE, 反射,Log4j, JSoup, JUnit, Html 等一整套技术栈, 从无到有,循序渐进涵盖全部74个知识点,549个开发步骤, 为竞争高薪资职位加上一个有吸引力的砝码.
增值内容,点击购买
如图所示,在左侧IDEA提供了很多项目,Java是默认的,右侧是可以采纳的框架,目前不需要,所以直接点击Next
Java 项目
自己写一个Tomcat, 几乎使用到了除开框架外的所有Java 技术,如多线程,Socket, J2EE, 反射,Log4j, JSoup, JUnit, Html 等一整套技术栈, 从无到有,循序渐进涵盖全部74个知识点,549个开发步骤, 为竞争高薪资职位加上一个有吸引力的砝码.
增值内容,点击购买
有两个模板,一个是命令行,一个是Hello World,也不用理睬,直接点Next
选择模板
自己写一个Tomcat, 几乎使用到了除开框架外的所有Java 技术,如多线程,Socket, J2EE, 反射,Log4j, JSoup, JUnit, Html 等一整套技术栈, 从无到有,循序渐进涵盖全部74个知识点,549个开发步骤, 为竞争高薪资职位加上一个有吸引力的砝码.
增值内容,点击购买
输入项目名称:
Project name: diytomcat
Project location: d:\project\diytomcat

以前做项目的时候,大部分都在 e盘,不少同学反应,没有e盘,那么这一次站长就放在 d盘吧, d盘总有了吧。。。
点击Finish
项目名称
自己写一个Tomcat, 几乎使用到了除开框架外的所有Java 技术,如多线程,Socket, J2EE, 反射,Log4j, JSoup, JUnit, Html 等一整套技术栈, 从无到有,循序渐进涵盖全部74个知识点,549个开发步骤, 为竞争高薪资职位加上一个有吸引力的砝码.
增值内容,点击购买
此时看到的就是项目的样子了,这是一个空的 java 项目。
项目结构
自己写一个Tomcat, 几乎使用到了除开框架外的所有Java 技术,如多线程,Socket, J2EE, 反射,Log4j, JSoup, JUnit, Html 等一整套技术栈, 从无到有,循序渐进涵盖全部74个知识点,549个开发步骤, 为竞争高薪资职位加上一个有吸引力的砝码.
增值内容,点击购买
新建文件夹: D:\project\diytomcat\lib, 并且在右上角下载 lib.rar, 解压其中的 jar 到 lib 目录里。
解压之后如图所示,这些 jar 包的作用如下:

hutool-all-4.3.1.jar: hutool 工具类包,提供各种各样的便利工具。
jsoup-1.12.1.jar: 解析xml用
jspc_all.jar:把 jsp 编译成为 servlet 用,这是站长阅读了 tomcat源码,然后对其进行了修改与提取之后,专门提供给本项目使用。
junit-4.9.jar:单元测试
log4j-1.2.17.jar:log4j日志
servlet-api.jar:servlet 包
jar 包
自己写一个Tomcat, 几乎使用到了除开框架外的所有Java 技术,如多线程,Socket, J2EE, 反射,Log4j, JSoup, JUnit, Html 等一整套技术栈, 从无到有,循序渐进涵盖全部74个知识点,549个开发步骤, 为竞争高薪资职位加上一个有吸引力的砝码.
增值内容,点击购买
上个步骤只是创建了 lib 目录用于存放 jar, 但是项目并不能识别这些 jar, 所以需要右键点击 lib目录,然后选中 Add as Library,之后点击确认即可。
设置库
自己写一个Tomcat, 几乎使用到了除开框架外的所有Java 技术,如多线程,Socket, J2EE, 反射,Log4j, JSoup, JUnit, Html 等一整套技术栈, 从无到有,循序渐进涵盖全部74个知识点,549个开发步骤, 为竞争高薪资职位加上一个有吸引力的砝码.
增值内容,点击购买
右键点击src -> New -> Package -> cn.how2j.diytomcat
新建包
自己写一个Tomcat, 几乎使用到了除开框架外的所有Java 技术,如多线程,Socket, J2EE, 反射,Log4j, JSoup, JUnit, Html 等一整套技术栈, 从无到有,循序渐进涵盖全部74个知识点,549个开发步骤, 为竞争高薪资职位加上一个有吸引力的砝码.
增值内容,点击购买
右键点击包名cn.how2j.diytomca,New -> Java Class -> 输入 Bootstrap
package cn.how2j.diytomcat; import cn.hutool.core.util.NetUtil; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; public class Bootstrap { public static void main(String[] args) { try { int port = 18080; if(!NetUtil.isUsableLocalPort(port)) { System.out.println(port +" 端口已经被占用了,排查并关闭本端口的办法请用:\r\nhttps://how2j.cn/k/tomcat/tomcat-portfix/545.html"); return; } ServerSocket ss = new ServerSocket(port); while(true) { Socket s = ss.accept(); InputStream is= s.getInputStream(); int bufferSize = 1024; byte[] buffer = new byte[bufferSize]; is.read(buffer); String requestString = new String(buffer,"utf-8"); System.out.println("浏览器的输入信息: \r\n" + requestString); OutputStream os = s.getOutputStream(); String response_head = "HTTP/1.1 200 OK\r\n" + "Content-Type: text/html\r\n\r\n"; String responseString = "Hello DIY Tomcat from how2j.cn"; responseString = response_head + responseString; os.write(responseString.getBytes()); os.flush(); s.close(); } } catch (IOException e) { e.printStackTrace(); } } }
自己写一个Tomcat, 几乎使用到了除开框架外的所有Java 技术,如多线程,Socket, J2EE, 反射,Log4j, JSoup, JUnit, Html 等一整套技术栈, 从无到有,循序渐进涵盖全部74个知识点,549个开发步骤, 为竞争高薪资职位加上一个有吸引力的砝码.
增值内容,点击购买
运行Bootstrap, 然后访问地址:
http://127.0.0.1:18080/
即可看到如图所示的效果,这便是一个简单简单简单地不能再简单的 web 服务器了。
运行并测试
自己写一个Tomcat, 几乎使用到了除开框架外的所有Java 技术,如多线程,Socket, J2EE, 反射,Log4j, JSoup, JUnit, Html 等一整套技术栈, 从无到有,循序渐进涵盖全部74个知识点,549个开发步骤, 为竞争高薪资职位加上一个有吸引力的砝码.
增值内容,点击购买
接下来对 Bootstrap 进行讲解

int port = 18080;

这表示本服务器使用的端口号是 18080. tomcat 默认的端口号是8080,很多同学自己机器上是运行 tomcat的,所以为了避免造成不必要的困扰,站长选用18080来提供服务。

if(!NetUtil.isUsableLocalPort(port)) {
System.out.println(port +" 端口已经被占用了,排查并关闭本端口的办法请用:\r\nhttps://how2j.cn/k/tomcat/tomcat-portfix/545.html");
return;
}

NetUtil.isUsableLocalPort 用来判断端口是否被占用,返回 true 表示没有被占用。
在后续的开发过程中,会不断地重启项目进行改动与测试。 那么就会碰到端口号被占用的情况,这里做一个明显的提示,以免启动失败了,同学都不知道自己哪里搞错了。

ServerSocket ss = new ServerSocket(port);

在端口18080上启动 ServerSocket。 服务端和浏览器通信是通过 Socket进行通信的,所以这里需要启动一个 ServerSocket。 关于ServetSocket 在 Java 中级的网络编程部分有更多的介绍:网络编程

Socket s = ss.accept();

这表示收到一个浏览器客户端的请求

InputStream is= s.getInputStream();

打开输入流,准备接受浏览器提交的信息

int bufferSize = 1024;
byte[] buffer = new byte[bufferSize];
is.read(buffer);

准备一个长度是 1024 的字节数组,把浏览器的信息读取出来放进去。 浏览器提交的数据可能短于或者长于1024,所以这种做法是有缺陷的,后续会讲解如何改进。

String requestString = new String(buffer,"utf-8");
System.out.println("浏览器的输入信息: \r\n" + requestString);

把字节数组转换成字符串,并且打印出来


OutputStream os = s.getOutputStream();

打开输出流,准备给客户端输出信息

String response_head = "HTTP/1.1 200 OK\r\n" + "Content-Type: text/html\r\n\r\n";
String responseString = "Hello DIY Tomcat from how2j.cn";
responseString = response_head + responseString;

这里准备发送给给客户端的数据。

os.write(responseString.getBytes());
os.flush();

把字符串转换成字节数组发送出去

s.close();

关闭客户端对应的 socket

while(true) {...}

外面还套了一层循环,处理掉一个Socket链接请求之后,再处理下一个链接请求。

补充讲解:
发给浏览器的信息是Hello DIY Tomcat from how2j.cn, 但是在前面还增加了一个 response_head, 因为作为web 服务器,和浏览器之间通信,需要遵循 http 协议,所以需要加上一个头信息:response_head。 后面会更加详细地讲解 http 协议。
步骤 13 :

比较可运行项目,快速定位问题

edit
自己写一个Tomcat, 几乎使用到了除开框架外的所有Java 技术,如多线程,Socket, J2EE, 反射,Log4j, JSoup, JUnit, Html 等一整套技术栈, 从无到有,循序渐进涵盖全部74个知识点,549个开发步骤, 为竞争高薪资职位加上一个有吸引力的砝码.
增值内容,点击购买
跟着做了,但是还是有问题,跑不起来。
原有主要有二:
1. 自己做了改动,因为对项目还不熟悉,这些改动导致项目跑不起来。
2. 以为自己没做改动,其实还是做了改动,这个时常发生。
为了解决这个问题,站长特意把当前的可运行项目放在了右上角下载, 这样通过比较,就可以快速定位问题所在,大大地提高学习效率。

推荐使用diffmerge软件,进行文件夹比较。把你自己做的项目文件夹,和我的可运行项目文件夹进行比较。
这个软件很牛逼的,可以知道文件夹里哪两个文件不对,并且很明显地标记出来
这里提供了绿色安装和使用教程:diffmerge 下载和使用教程


HOW2J公众号,关注后实时获知最新的教程和优惠活动,谢谢。


问答区域    
2022-03-24 改一下输入流的while读取方法就打不开页面了,怎么回事
机器不学习




在idea控制台打印接收到的浏览器信息,为什么不能这样写,这样访问不了127.0.0.1:18080页面
加载中
      while(true) {
        int len = -1;
        Socket s =  ss.accept();
        InputStream is= s.getInputStream();
        int bufferSize = 1024;
        byte[] buffer = new byte[bufferSize];
        System.out.println("浏览器的输入信息: \r\n");
        while (-1 != (len = is.read(buffer))) {
          System.out.println(new String(buffer, 0, len, "utf-8"));
        }
        System.out.println("end");// 这行的调试输出语句执行不了
idea卡在如下位置:

D:\jdk8\bin\java.exe "-javaagent:D:\JetBrains\IntelliJ IDEA 2021.3.2\lib\idea_rt.jar=6419:D:\JetBrains\IntelliJ IDEA 2021.3.2\bin" -Dfile.encoding=UTF-8 -classpath D:\jdk8\jre\lib\charsets.jar;D:\jdk8\jre\lib\deploy.jar;D:\jdk8\jre\lib\ext\access-bridge-64.jar;D:\jdk8\jre\lib\ext\cldrdata.jar;D:\jdk8\jre\lib\ext\dnsns.jar;D:\jdk8\jre\lib\ext\jaccess.jar;D:\jdk8\jre\lib\ext\jfxrt.jar;D:\jdk8\jre\lib\ext\localedata.jar;D:\jdk8\jre\lib\ext\nashorn.jar;D:\jdk8\jre\lib\ext\sunec.jar;D:\jdk8\jre\lib\ext\sunjce_provider.jar;D:\jdk8\jre\lib\ext\sunmscapi.jar;D:\jdk8\jre\lib\ext\sunpkcs11.jar;D:\jdk8\jre\lib\ext\zipfs.jar;D:\jdk8\jre\lib\javaws.jar;D:\jdk8\jre\lib\jce.jar;D:\jdk8\jre\lib\jfr.jar;D:\jdk8\jre\lib\jfxswt.jar;D:\jdk8\jre\lib\jsse.jar;D:\jdk8\jre\lib\management-agent.jar;D:\jdk8\jre\lib\plugin.jar;D:\jdk8\jre\lib\resources.jar;D:\jdk8\jre\lib\rt.jar;D:\workspace\idea\mytomcat\out\production\mytomcat;D:\workspace\idea\mytomcat\lib\jspc_all.jar;D:\workspace\idea\mytomcat\lib\junit-4.9.jar;D:\workspace\idea\mytomcat\lib\servlet-api.jar;D:\workspace\idea\mytomcat\lib\jsoup-1.12.1.jar;D:\workspace\idea\mytomcat\lib\log4j-1.2.17.jar;D:\workspace\idea\mytomcat\lib\hutool-all-4.3.1.jar com.heyan.mytomcat.test.Bootstrap
浏览器的输入信息: 

GET / HTTP/1.1
Host: 127.0.0.1:18080
Connection: keep-alive
sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="99", "Google Chrome";v="99"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9

不往下走,浏览器页面打不开


1 个答案

how2j
答案时间:2022-04-01
因为浏览器有时候不发结束标记过来,所以会导致第二个while一直读。。。



回答已经提交成功,正在审核。 请于 我的回答 处查看回答记录,谢谢
答案 或者 代码至少填写一项, 如果是自己有问题,请重新提问,否则站长有可能看不到





2022-01-26 is输入流不用关吗?
G1g4lo




is输入流不用关吗?
package cn.how2j.diytomcat;

import cn.hutool.core.util.NetUtil;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class Bootstrap {

    public static void main(String[] args) {

        try {
            int port = 18080;

            if(!NetUtil.isUsableLocalPort(port)) {
                System.out.println(port +" 端口已经被占用了,排查并关闭本端口的办法请用:\r\nhttps://how2j.cn/k/tomcat/tomcat-portfix/545.html");
                return;
            }
            ServerSocket ss = new ServerSocket(port);

            while(true) {
                Socket s =  ss.accept();
                InputStream is= s.getInputStream();
                int bufferSize = 1024;
                byte[] buffer = new byte[bufferSize];
                is.read(buffer);
                String requestString = new String(buffer,"utf-8");
                System.out.println("浏览器的输入信息: \r\n" + requestString);

                OutputStream os = s.getOutputStream();
                String response_head = "HTTP/1.1 200 OK\r\n" + "Content-Type: text/html\r\n\r\n";
                String responseString = "Hello DIY Tomcat from how2j.cn";
                responseString = response_head + responseString;
                os.write(responseString.getBytes());
                os.flush();
                s.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

							


1 个答案

how2j
答案时间:2022-02-02
socket关闭的时候,对应的输入输出流自动会关闭的。



回答已经提交成功,正在审核。 请于 我的回答 处查看回答记录,谢谢
答案 或者 代码至少填写一项, 如果是自己有问题,请重新提问,否则站长有可能看不到





2021-04-14 题主大大,这里使用的输出流是OutputStream,是字节流,是不需要flush的(字符流才需要flush),其实点进去这个flush方法里查看时,这个方法是空的,什么也没做。
2021-01-05 输出中文乱码怎么解决?
2020-07-29 开学第一节课之踩坑警告!


提问太多,页面渲染太慢,为了加快渲染速度,本页最多只显示几条提问。还有 2 条以前的提问,请 点击查看

提问之前请登陆
提问已经提交成功,正在审核。 请于 我的提问 处查看提问记录,谢谢
关于 实践项目-DiyTomcat-Hello DIYTomcat 的提问

尽量提供截图代码异常信息,有助于分析和解决问题。 也可进本站QQ群交流: 578362961
提问尽量提供完整的代码,环境描述,越是有利于问题的重现,您的问题越能更快得到解答。
对教程中代码有疑问,请提供是哪个步骤,哪一行有疑问,这样便于快速定位问题,提高问题得到解答的速度
在已经存在的几千个提问里,有相当大的比例,是因为使用了和站长不同版本的开发环境导致的,比如 jdk, eclpise, idea, mysql,tomcat 等等软件的版本不一致。
请使用和站长一样的版本,可以节约自己大量的学习时间。 站长把教学中用的软件版本整理了,都统一放在了这里, 方便大家下载: https://how2j.cn/k/helloworld/helloworld-version/1718.html

上传截图