目录
一、什么是Servlet
1.servlet的定义
2.servlet的结构
二、实现servlet的流程图
三、具体实现代码
1、server
2.实体类request&response
3.HttpServlet抽象类
4.再定义三个servlet进行测试
Tomcat原理(3)——静&动态资源以及运行项目的基本流程-CSDN博客文章浏览阅读414次,点赞2次,收藏2次。Tomcat原理(2)——注解及注解的实现-CSDN博客(1)注解一般用于对程序的说明,就像注释一样,但是区别是注释是给人看的,但是注解是给程序看的。(2)让编译器进行编译检查的作用,比如下边这个@Override注解是重写的意思,子类重写了父类的方法,但是改动了方法名,所以报错。https://blog.csdn.net/2301_78566776/article/details/144508887?spm=1001.2014.3001.5502 我们在上一篇博客中已经了解到了静动态资源和tomcat的基本流程
一、什么是Servlet
1.servlet的定义
Servlet,全称为Java Servlet,是运行在Java服务器端的程序,它主要用于接收和响应来自客户端基于HTTP协议的请求。Servlet可以看作是在服务器上运行的小程序,用于生成动态Web内容。
2.servlet的结构
这是一个servlet的基本结构。我们观察可以发现:
- Servlet继承了一个HttpServlet抽象类
- servlet文件包含两个主要的方法:doGet和doPost
- 观察这两个方法的入参:一个是request 一个是response。
二、实现servlet的流程图
1.我们首先需要构造一个Server服务器模拟,来接受HTTP请求,并且返回method(get/post)
2.创建request实体类和respons实体类,在request实体类中设置method和path变量
3.创建HttpServlet抽象类,在类里定义doGet和doPost两个抽象方法,并且判断所传method为什么类型,进行选择执行。
4.具体执行的doGet和doPost方法,要在具体的servlet中执行(找抽象类的具体实现方法)——即我们每一个servlet都要对doGet和doPost进行重写。
如图所示
三、具体实现代码
引入
我们尝试接收整个http请求的信息
package com.qcby.tomcat.webservlet;/* * 服务器端 tomcat ——》接收信息 * */import java.io.IOException; import java.io.InputStream; import java.net.ServerSocket; import java.net.Socket;public class SocketServer {public static void main(String[] args) throws IOException {run();}public static void run() throws IOException {ServerSocket serverSocket= new ServerSocket(8080);//端口的范围:0~65535while (true){//等待客户端连接Socket socket = serverSocket.accept();//阻塞监听:程序会在这里卡住。只有监听到客户端的信息后才会向下执行//输出客户端给我们发来的程序InputStream inputStream=socket.getInputStream();//打开输入流:接收输入的信息int count=0;while (count==0){count=inputStream.available();}byte[] bytes=new byte[count];//01010101010100001101010 用字节数组接收inputStream.read(bytes);String context=new String(bytes);System.out.println(context);}} }
结果如图
我们可以看到这个请求的全部信息。第一行的前两个词为其method/path,在一会的server文件中我们只要前两个词。
1、server
这个类中我们获取到了http请求的method(get/post)和path(@WebServlet中的path)
获取的方法是对所有请求信息进行切割。并且在最后我们将method和path放入了request中
package com.qcby.tomcat.socket;import com.qcby.tomcat.Request.Request;import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;public class Server {private static Request request=new Request();public static void main(String[] args) throws Exception {// 1.打开通信端口 tomcat:8080 3306 ---------》进行网络通信ServerSocket serverSocket = new ServerSocket(8080);System.out.println("****************server start.....");//2.接受请求数据while (true) {Socket socket = serverSocket.accept(); //--------------------->注意:此时监听网卡的是:主线程System.out.println("有客户进行了链接");new Thread(() -> {//处理数据---------》数据的处理在于读和写try {handler(socket);} catch (Exception e) {e.printStackTrace();}}).start();}}public static void handler(Socket socket) throws Exception {//读取请求的数据InputStream inputStream = socket.getInputStream();requestContext(inputStream);}public static void requestContext(InputStream inputStream) throws IOException {// 创建一个StringBuilder对象,用于构建请求的第一行StringBuilder sb = new StringBuilder();int context; // 用于存储每次从输入流中读取的单个字节// 读取输入流直到遇到换行符(\n)或文件结束(-1)while ((context = inputStream.read()) != -1) {// 如果读取到换行符,则停止读取if (context == '\n') {break; // 遇到换行符,退出循环}// 将读取到的字节转换为字符,并添加到StringBuilder中sb.append((char) context);}// 从StringBuilder中获取第一行字符串,并去除首尾空格String firstLine = sb.toString().trim();// 检查第一行是否为空if (firstLine.isEmpty()) {// 如果为空,则打印提示信息System.out.println("你输入了一个空请求");} else {// 如果不为空,则按空格分割第一行字符串为单词数组String[] words = firstLine.split("\\s+");// 打印出请求方法和请求URI(通常是数组的前两个元素)// 注意:这里没有检查数组长度,如果数组长度小于2,将会抛出ArrayIndexOutOfBoundsException// 在实际应用中,应该添加适当的错误处理或验证逻辑String method=words[0];String path=words[2];System.out.println(words[0] + " " + words[1]);request.setMethod(method);request.setPath(path);}}
}
@WebServlet接口
package com.qcby.tomcat.webservlet;import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;@Target(value = ElementType.TYPE) @Retention(value = RetentionPolicy.RUNTIME) public @interface WebServlet {String path() default ""; }
2.实体类request&response
生成了get和set方法
生成了全参和无参的构造函数
package com.qcby.tomcat.Request;public class Request {private String path;private String method;public Request(String path, String method) {this.path = path;this.method = method;}public Request() {}public String getPath() {return path;}public void setPath(String path) {this.path = path;}public String getMethod() {return method;}public void setMethod(String method) {this.method = method;}
}
在这里 response我并没有实现
package com.qcby.tomcat.Response;public class Response {
}
3.HttpServlet抽象类
抽象类中既可以有抽象方法也可以有具体方法。
package com.qcby.tomcat.HttpServlet;import com.qcby.tomcat.Request.Request;
import com.qcby.tomcat.Response.Response;public abstract class HttpServlet {public void service(Request request, Response response){if(request.getMethod().equals("GET")){doGet(request,response);}else if (request.getMethod().equals("POST")){doPost(request,response);}else if (request.getMethod().equals("")){System.out.println("未获取到方法类型");}}public abstract void doGet(Request request,Response response);public abstract void doPost(Request request,Response response);}
4.再定义三个servlet进行测试
注意!每个servlet都有继承HttpServlet,并且在每个servlet中都要重写doGet和doPost
package com.qcby.tomcat.MyWeb;import com.qcby.tomcat.HttpServlet.HttpServlet;
import com.qcby.tomcat.Request.Request;
import com.qcby.tomcat.Response.Response;
import com.qcby.tomcat.webservlet.WebServlet;@WebServlet(path ="myFirstServlet")
public class MyFirstServlet extends HttpServlet {@Overridepublic void doGet(Request request, Response response) {}@Overridepublic void doPost(Request request, Response response) {}
}
package com.qcby.tomcat.MyWeb;import com.qcby.tomcat.HttpServlet.HttpServlet;
import com.qcby.tomcat.Request.Request;
import com.qcby.tomcat.Response.Response;
import com.qcby.tomcat.webservlet.WebServlet;@WebServlet(path ="mySecondServlet")
public class MySecondServlet extends HttpServlet {@Overridepublic void doGet(Request request, Response response) {}@Overridepublic void doPost(Request request, Response response) {}
}
package com.qcby.tomcat.MyWeb;import com.qcby.tomcat.HttpServlet.HttpServlet;
import com.qcby.tomcat.Request.Request;
import com.qcby.tomcat.Response.Response;
import com.qcby.tomcat.webservlet.WebServlet;@WebServlet(path ="myThirdServlet")
public class MyThirdServlet extends HttpServlet {@Overridepublic void doGet(Request request, Response response) {}@Overridepublic void doPost(Request request, Response response) {}
}
我们会发现它已经很像Java的servlet文件模板了
补充:
如何读取一个软件包,遍历里面的servlet,返回其类名和注解的path值
package com.qcby.tomcat;import com.qcby.tomcat.webservlet.WebServlet;import java.io.File; import java.net.URL; import java.util.ArrayList; import java.util.Enumeration; import java.util.List;public class MyTomcat {public static void main(String[] args) {try {// 1. 扫描包路径 (com.wzh.tomcat.myweb)String packageName = "com.qcby.tomcat.MyWeb";List<Class<?>> classes = getClasses(packageName);// 2. 遍历所有类,检查是否有@WebServlet注解for (Class<?> clazz : classes) {if (clazz.isAnnotationPresent(WebServlet.class)) {// 3. 获取@WebServlet注解的值WebServlet webServlet = clazz.getAnnotation(WebServlet.class);System.out.println("类名: " + clazz.getName() + " | URL路径: " + webServlet.path());}}} catch (Exception e) {e.printStackTrace();}}/*** 获取指定包下的所有类** @param packageName 包名,例如 "com.wzh.tomcat.myweb"* @return 类对象列表* @throws Exception*/private static List<Class<?>> getClasses(String packageName) throws Exception {List<Class<?>> classes = new ArrayList<>();String path = packageName.replace('.', '/'); // 将包名转换为文件路径// 通过类加载器获取包的资源路径ClassLoader classLoader = Thread.currentThread().getContextClassLoader();Enumeration<URL> resources = classLoader.getResources(path);while (resources.hasMoreElements()) {URL resource = resources.nextElement();File directory = new File(resource.toURI());// 扫描文件夹下的所有类文件if (directory.exists()) {for (File file : directory.listFiles()) {if (file.getName().endsWith(".class")) {// 获取类的完整类名String className = packageName + "." + file.getName().replace(".class", "");classes.add(Class.forName(className));}}}}return classes;} }