目录
4.3 创建一个webapp包,里面在创建index.html文件
5.2 修改mvc-framework中的Tomcat配置代码
mvc 的架构
model ----------> 业务领域的核心对象(Entity,Service,Dao)
View ----------> 视图层,做数据的提交和渲染 (JSP、HTML.........)
Controller --------> 控制层,专门用于处理Http请求(Servlet)
MVC 框架
简化控制层以及视图渲染的操作,将这些API进行更高层封装,使用起来更加简便,可以隐藏Servlet的操作,同时还可以提供简便的部署方式。
传统web开发的弊端
1.每一个请求都必须要有一个对应的Servlet去处理:
在传统的Servlet开发中,每个请求都需要对应一个Servlet类来处理。这导致了项目结构的臃肿,且难以维护和扩展。特别是对于大型项目,Servlet的数量可能会非常庞大,给代码的管理和维护带来挑战。
2.请求参数的处理相对繁琐 :
在Servlet开发中,通常需要手动解析请求参数,包括从URL中解析参数或者从请求体中读取参数。这样的处理方式相对繁琐,容易出错,尤其是在处理复杂的参数结构时更加困难。
3.请求响应的统一性比较繁杂:
在Servlet开发中,通常需要手动设置响应的内容类型、编码等信息,并且手动编写响应内容。这样的操作需要开发者自行管理,容易导致响应的不一致性,增加了维护成本。
4.部署Web应用相对繁杂,肯能存在缓存的问题:
在传统的Servlet开发中,部署Web应用通常需要手动将Servlet类部署到Servlet容器中,并且需要手动处理依赖关系、配置信息等。这样的部署方式相对繁琐,容易出错。此外,由于Servlet容器会缓存Servlet类,当修改了Servlet类但未正确地刷新缓存时,可能会导致旧版本的Servlet类被执行,从而引发一系列问题。
为了解决这传统web开发的弊端,我们自己写一个MVC框架简易实现
1.创建一个maven项目
2.添加maven依赖
对应的依赖为:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.xr</groupId>
<artifactId>mvc-framework</artifactId>
<version>0.9</version>
<!--打包方式为jar-->
<packaging>jar</packaging>
<properties>
<!--maven编译源代码的jdk版本-->
<maven.compiler.source>21</maven.compiler.source>
<!--maven编译目标代码的jdk版本-->
<maven.compiler.target>21</maven.compiler.target>
<!--项目构建编码格式-->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!--Tomcat依赖-->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<version>10.1.19</version>
</dependency>
<!--JSP解析器依赖-->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<version>10.1.19</version>
</dependency>
<!--EL表达式依赖-->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-el</artifactId>
<version>10.1.19</version>
</dependency>
<!--servlet依赖-->
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>6.0.0</version>
<!--这个依赖是运行环境提供的,不需要打包到jar中,为什么一定要是provided,如果不是当其他项目中引用,因为Tomcat自带Servlet,如果将这个依赖打包到jar中,
那么tomcat会识别到这个jar中的Servlet,tomcat就不知道使用哪个Servlet-->
<scope>provided</scope>
</dependency>
<!--yml文件解析器-->
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>1.33</version>
</dependency>
<!--底层工具库(Guava,Hutool)-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.27</version>
</dependency>
</dependencies>
</project>
注意:
1.这里的项目打包方式一定是jar包
2.servlet依赖范围一定是provided
如果不是Provided,当其他项目引用这个项目的依赖,那么这个依赖会打包到jar中,而Tomcat自带Servlet,那么tomcat会识别到这个jar中的Servlet,tomcat就不知道使用哪个Servlet
3.创建TomCatService类
3.1 创建TomcatService类
作用:
启动一个嵌入式的Tomcat服务器。在Java Web开发中,通常使用Tomcat作为Servlet容器来运行Web应用,而这个类的目的是通过代码的方式启动一个Tomcat服务器,而不是通过传统的部署方式
3.2 TomcatService类讲解
package com.xr.embed;
import cn.hutool.core.io.FileUtil;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.startup.Tomcat;
import java.io.File;
/**
* Tomcat容器
* @author xr
* @Date 2024/5/13 11:32
*/
public class TomcatServer {
/**
* 容器的端口号
*/
private final Integer port = 8080;
/**
* ContextPath路径,默认值是"/",表示项目的根
*/
private final String contextPath = "/";
/**
* web资源的部署目录
*/
private String webRoot = "src/main/webapp";
/**
* 启动Tomcat服务器
*/
public void startServer() {
// 实例化Tomcat对象
Tomcat tomcat = new Tomcat();
// 设置端口
tomcat.setPort(port);
// 将webRoot构建为绝对路径
webRoot = FileUtil.getWebRoot().getAbsolutePath()+ File.separator + webRoot;
// 设置contextPath和web资源目录
tomcat.addWebapp(contextPath, webRoot);
// 创建连接
tomcat.getConnector();
try {
//启动tomcat
tomcat.start();
//将Tomcat进行阻状态,保持运行状态
tomcat.getServer().await();
} catch (LifecycleException e) {
throw new RuntimeException("启动Tomcat失败!!!",e);
}
}
}
属性:
port : 配置Tomcat服务器的端口
ContextPath : 应用的根路径
webRoot : 指定了Web资源的部署目录,即Web应用的根目录。在实际运行时,会将这个目录构建为绝对路径,并传递给Tomcat
方法 :
startServer() : 首先实例化了Tomcat对象,然后设置了端口和Web资源目录。接着,通过调用addWebapp()方法将Web应用部署到Tomcat的ContextPath下。最后,启动了Tomcat服务器并使其保持运行状态
注意 :
为什么要让Tomcat进入阻塞装填???
如果Tomcat进入阻塞状态的话,只要一启动,Tomcat就直接结束了,所以要让Tomcat保持运行状态
3.3 安装项目到本地仓库,给其他项目使用
4.测试启动Tomcat
4.1 创建一个新的maven项目
4.2 引用mvc-framework项目的依赖
对应的依赖:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.xr</groupId>
<artifactId>webapp-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>com.xr</groupId>
<artifactId>mvc-framework</artifactId>
<version>0.9</version>
</dependency>
</dependencies>
</project>
4.3 创建一个webapp包,里面在创建index.html文件
有则不用创建,没有则创建
具体代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h2>Hello Tomcat</h2>
</body>
</html>
4.4 创建一个测试类
具体代码:
package com.xr;
import com.xr.embed.TomcatServer;
/**
* 测试方法
* @author xr
* @Date 2024/5/13 11:50
*/
public class Main {
public static void main(String[] args) {
// 创建TomcatServer对象
TomcatServer server = new TomcatServer();
// 启动Tomcat
server.startServer();
}
}
4.5 启动项目
项目启动成功!!!!
之前是要配置了Tomcat才能启动项目,我们这里并没有配置Tomcat
发现 :
我们并没有在Idea中配置Tomcat,按照之前的方法,我们需要在IDEA中配置Tomcat,而这里所使用的,间接让项目内嵌了Tomcat,所以无需配置Tomcat
4.6 访问项目
5. 让Tomcat可以访问Servlet
前面的使用我们只能访问webapp下的静态页面,那我想servelt也能使用该怎么办呢???
5.1 创建一个Servlet类
在测webapp-demo项目中创建一个servlet包,在到里面创建一个DemoServlet类(servelt类)
DemoServlet类具体代码:
package com.xr.servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 测试
* @author xr
* @WebServlet :该注解的作用是将一个类声明为Servlet组件, 并指定该Servlet组件的访问路径
* HttpServlet: 继承了HttpServlet类,该类提供了一些方法,用于处理HTTP请求和响应。
* @Date 2024/5/13 14:59
*/
@WebServlet("/hello")
public class DemoServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 设置响应类型为HTML和编码格式
resp.setContentType("text/html;charset=utf-8");
// 输出响应到页面上
resp.getWriter().println("<h2>Servlet Page</h2>");
}
}
启动项目后,通过路径【localhost:8080/hello】访问servelt,发现访问不了,为什么???
1. 因为我们编写的mvc-framework项目中的Tomcat并没有设置对应的Servlet访问配置
解决思路:
1.我们声明一个Servlet类的时候,使用@WebServlet注解声明该类是一个servlet类,并给注解赋值有一个访问路径,通过这个访问路径来访问对应Servlet
2.可以获取@WebServlet注解来确定哪些是Servlet类,获取到了Servlet类之后,就知道了有对应的访问路径了
5.2 修改mvc-framework中的Tomcat配置代码
项目中的所有类编译后会存放在targe/classes目录下,我们通过Hutool工具类来过滤没有@WebServlet的类,过滤完成之后将这些编译好的类存放在webapp/WEB-INF/classes下,
再将这些类设置到Tomcat的Context中,这时候,Tomcat启动的时候,通过加载Context就知道哪些是Serlvet类了,最后就可以访问了Servlet
改写TomcatService类:
package com.xr.embed.server;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ClassUtil;
import org.apache.catalina.Context;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.WebResourceRoot;
import org.apache.catalina.startup.Tomcat;
import org.apache.catalina.webresources.DirResourceSet;
import org.apache.catalina.webresources.StandardRoot;
import java.io.File;
/**
* Tomcat容器
* @author xr
* @Date 2024/5/13 11:32
* extends AbstractWebServer
*/
public class TomcatServer {
/**
* 容器的端口号
*/
private final Integer port = 8080;
/**
* ContextPath路径,默认值是"/",表示项目的根
*/
private final String contextPath = "/";
/**
* web资源的部署目录,静态资源的路径
*/
private String webRoot = "src/main/webapp";
/**
* 启动tomcat
*/
public void startServer() {
// 实例化Tomcat对象
Tomcat tomcat = new Tomcat();
// 设置端口
tomcat.setPort(port);
// 将webRoot构建为绝对路径
webRoot = FileUtil.getWebRoot().getAbsolutePath()+ File.separator + webRoot;
// 设置contextPath和web资源目录
Context context = tomcat.addWebapp(contextPath, webRoot);
// 设置应用程序的编译路径,这样容器启动时会从classpath路径下查找对应Servlet注解的组件
// 例如: @webServlet、@WebFilter、@WebListener
// 管理Web应用中的所有资源(静态资源和类文件)
WebResourceRoot resourceRoot = new StandardRoot(context);
// 过滤出有注解的Servlet类,并将这些类放在/WEB-INF/classes目录下
DirResourceSet resourceSet = new DirResourceSet(resourceRoot, "/WEB-INF/classes", ClassUtil.getClassPath(), "/");
// 将过滤之后的结果添加到容器中
resourceRoot.addPreResources(resourceSet);
// 将容器设置回Tomcat上下文中
context.setResources(resourceRoot);
// 创建连接
tomcat.getConnector();
try {
//启动tomcat
tomcat.start();
//将Tomcat进行阻状态,保持运行状态
tomcat.getServer().await();
} catch (LifecycleException e) {
throw new RuntimeException("启动Tomcat失败!!!",e);
}
}
5.3 测试访问Servlet
5.3.1
上面已经重新修改了TomcatServer类,使用maven先clean清理,在install安装到本地仓库
5.3.2
在webapp-demo项目中重新刷新mvc-framework的依赖
5.3.3
启动项目,并访问对应的servlet路径
启动项目:
访问Servlet:
访问Servlet也成功了!!!
6.Tomcat可以使用YML文件配置
之前的TomcatServer中已经有3个属性:
port: tomcat端口号,(如:8080)
contextPath: 项目的根路径,(如: "/index.html"访问静态页面)
webRoot: 静态资源的路径 (如:“src/main/webapp")
如果其他项目想要修改这些配置怎么办?不可能去这个TomcatService类中修改叭,而且如果直接去修改也违反了开辟原则!!!
解决方法:
使用yml文件进行对Tomcat的配置
思路:
1.创建一个ServiceConfig类,这个类定义web容器的配置信息
2.定义一个Configure类,配置对象(也是所有配置的根),将ServletConfig类作为属性
3. 通过Hutool工具类获取yml文件里面中的配置信息,在映射到Configure类中的ServiceConfig属性中
4.在Tomcat创建后,初始化配置对象,并获取对应的配置信息,并设置对应的配置
6.1 添加配置信息类
在mvc-framework项目中创建config包,在这个包下添加2个类ServiceConfig,Configure
ServiceConfig 配置信息类 :
package com.xr.config;
/**
* web容器的配置信息
* @author xr
* @Date 2024/5/13 15:28
*/
public class ServerConfig {
/**
* 这里的所有字段名字必须与yml中子节点名字相同
*/
private Integer port = 8080; // 端口
private String contextPath = "/"; //访问项目的根路径
private String webRoot = "src/main/webapp"; // 静态资源根目录
public Integer getPort() {
return port;
}
public void setPort(Integer port) {
this.port = port;
}
public String getContextPath() {
return contextPath;
}
public void setContextPath(String contextPath) {
this.contextPath = contextPath;
}
public String getWebRoot() {
return webRoot;
}
public void setWebRoot(String webRoot) {
this.webRoot = webRoot;
}
}
Configure 配置类:
package com.xr.config;
/**
* 配置对象(也是所有配置的根),作用是将yml解析的数据库封装到该对象中
* @author xr
* @Date 2024/5/13 15:26
*/
public class Configure {
/**
* 这里的字段命名必须与yml中节点名称相同
* 这里的server对应的父节点的名字
*/
private ServerConfig server;
public ServerConfig getServer() {
return server;
}
public void setServer(ServerConfig server) {
this.server = server;
}
}
6.2 修改TomcatServer类
package com.xr.embed.server;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.setting.yaml.YamlUtil;
import com.xr.config.Configure;
import org.apache.catalina.Context;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.WebResourceRoot;
import org.apache.catalina.startup.Tomcat;
import org.apache.catalina.webresources.DirResourceSet;
import org.apache.catalina.webresources.StandardRoot;
import java.io.File;
/**
* Tomcat容器
* @author xr
* @Date 2024/5/13 11:32
* extends AbstractWebServer
*/
public class TomcatServer {
/**
* 容器的端口号
*/
private final Integer port = 8080;
/**
* ContextPath路径,默认值是"/",表示项目的根
*/
private final String contextPath = "/";
/**
* web资源的部署目录,静态资源的路径
*/
private String webRoot = "src/main/webapp";
/**
* 启动Tomcat容器
*/
public void startServer() {
// 实例化Tomcat对象
Tomcat tomcat = new Tomcat();
// 创建配置对象
Configure configure = initConfigure();
// 获取配置文件中的端口,并设置在Tomcat中
tomcat.setPort(configure.getServer().getPort());
// 获取配置文件中的静态资源的路径src/main/webapp
webRoot = configure.getServer().getWebRoot();
// 将webRoot构建为绝对路径
webRoot = FileUtil.getWebRoot().getAbsolutePath()+ File.separator + webRoot;
// 设置contextPath和web资源目录
Context context = tomcat.addWebapp(configure.getServer().getContextPath(), webRoot);
// 设置应用程序的编译路径,这样容器启动时会从classpath路径下查找对应Servlet注解的组件
// 例如: @webServlet、@WebFilter、@WebListener
// 管理Web应用中的所有资源(静态资源和类文件)
WebResourceRoot resourceRoot = new StandardRoot(context);
// 过滤出有注解的Servlet类
DirResourceSet resourceSet = new DirResourceSet(resourceRoot, "/WEB-INF/classes", ClassUtil.getClassPath(), "/");
// 将过滤之后的结果添加到容器中
resourceRoot.addPreResources(resourceSet);
// 将容器设置回Tomcat上下文中
context.setResources(resourceRoot);
// 创建连接
tomcat.getConnector();
try {
//启动tomcat
tomcat.start();
//将Tomcat进行阻状态,保持运行状态
tomcat.getServer().await();
} catch (LifecycleException e) {
throw new RuntimeException("启动Tomcat失败!!!",e);
}
}
/**
* 初始化配置对象,将yml的配置信息映射到Configure
*/
private Configure initConfigure() {
// 获取配置文件路径
String configFilePath = ClassUtil.getClassPath() + "application.yml";
// 定义配置对象
Configure configure;
// 判断配置文件是否存在
if (FileUtil.exist(configFilePath)) {
// 解析yml并映射到Configure对象中
configure = YamlUtil.loadByPath("application.yml", Configure.class);
// 有肯能用户只创建一个application.yml文件但未设置任何节点,因此返回的对象肯能是null
if(configure == null) {
configure = new Configure();
}
} else {
// 如果配置文件不存在,则创建一个空的Configure对象
configure = new Configure();
}
return configure;
}
}
startServer()方法中:
当Tomcat一创建,就调用了initConfigure()方法,这个方法就是初始化配置对象,将yml文件中的配置映射到配置类中
6.3 测试读取YML文件
6.3.1
将mcv-framework重新安装
6.3.2
在webapp-demo项目中刷新依赖
6.3.3
在webapp-demo项目中resources目录增加application.yml文件
YML对应的设置:
server:
port: 8082 # 端口号
contextPath: "/" # 访问项目的根路径
webRoot: "src/main/webapp" # 静态资源根路径
6.3.4
启动项目,并访问
启动项目:
通过8082端口访问静态页面:
访问Servlet :
6.3.5
修改YML配置文件的端口配置,将端口号修改8088测试!!!
启动项目:
通过8088端口访问静态页面:
通过8088端口访问Servlet :
最后通过yml形式配置Tomcat完成!!!!
7. 扩展代码(扩展不同的容器)
我所做的目前只有Tomcat容器,但是市场的容器有许多种,比如(Jetty容器),但是之前的代码只是专门争对于Tocamt容器进行一个处理,当我想使用其他容器的时候,不肯能又写一套代码叭,所以我们对其扩展
之前配置的Tomcat是不是都是先初始化Configure对象来获取yml文件的配置,然后在配置Tomcat启动Tomcat方法。
那其他容器是不是也可以照着这样的方式来配置其他容器,也是先初始化配置,在接着启动容器
这样多种容器都是先初始化配置,在启动容器,是不是都是同一个步骤,这里我们就可以使模板方法来做处理了
思路:
1. 定义接口,因为不同的容器有不同的实现
2.定义抽象类实现接口,抽象类中使用模板方法
3. TomcatServlet继承抽象类,实现具体的实现
7.1 在embed包下定义WebServlet接口
WebServlet接口具体代码 :
package com.xr.embed;
/**
* 抽象的容器接口,不止Tomcat容器,还有其他容器比如Jetty容器
* @author xr
* @Date 2024/5/14 8:39
*/
public interface WebServer {
/**
* 抽象的启动方法,不同的容器有不同的实现
* @throws Exception 启动异常
* Class<?> mainClass
*/
void run() throws Exception;
}
7.2 在定义AbstractWebServer抽象类并实现WebServlet接口
AbstractWebServer具体代码 :
package com.xr.embed;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.setting.yaml.YamlUtil;
import com.xr.config.Configure;
/**
* 使用模板方法
* @author xr
* @Date 2024/5/14 8:42
*/
public abstract class AbstractWebServer implements WebServer{
/**
* 启动容器
* @throws Exception
*/
@Override
public void run() throws Exception {
// 1. 解析配置返回Configure
Configure configure = initConfigure();
// 2.启动容器,不同的容器有不同的具体实现
start(configure);
}
/**
* 抽象的启动方法,由子类不同的实现
* @param configure
*/
public abstract void start (Configure configure);
/**
* 初始化配置对象,将yml的配置信息映射到Configure
*
*/
private Configure initConfigure() {
// 获取配置文件路径
String configFilePath = ClassUtil.getClassPath() + "application.yml";
// 定义配置对象
Configure configure;
// 判断配置文件是否存在
if (FileUtil.exist(configFilePath)) {
// 解析yml并映射到Configure对象中
configure = YamlUtil.loadByPath("application.yml", Configure.class);
// 有肯能用户只创建一个application.yml文件但未设置任何节点,因此返回的对象肯能是null
if(configure == null) {
configure = new Configure();
}
} else {
// 如果配置文件不存在,则创建一个空的Configure对象
configure = new Configure();
}
return configure;
}
}
7.3 TomcatServer继承AbstractWebServer抽象类
TomcatServer具体代码:
package com.xr.embed.server;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ClassUtil;
import com.xr.config.Configure;
import com.xr.embed.AbstractWebServer;
import org.apache.catalina.Context;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.WebResourceRoot;
import org.apache.catalina.startup.Tomcat;
import org.apache.catalina.webresources.DirResourceSet;
import org.apache.catalina.webresources.StandardRoot;
import java.io.File;
/**
* Tomcat容器
* @author xr
* @Date 2024/5/13 11:32
* extends AbstractWebServer
*/
public class TomcatServer extends AbstractWebServer {
/**
* 容器的端口号
*/
private final Integer port = 8080;
/**
* ContextPath路径,默认值是"/",表示项目的根
*/
private final String contextPath = "/";
/**
* web资源的部署目录,静态资源的路径
*/
private String webRoot = "src/main/webapp";
//1.1
@Override
public void start(Configure configure) {
// 创建一个Tomcat容器
Tomcat tomcat = new Tomcat();
// 获取配置文件中的端口,并设置在Tomcat中
tomcat.setPort(configure.getServer().getPort());
// 获取配置文件中静态资源的路径src/main/webapp
String webRoot = configure.getServer().getWebRoot();
// 将静态资源设置成绝对路径 比如 D:\store\webapp-demo\src\main\webapp
webRoot = FileUtil.getWebRoot().getAbsolutePath()+ File.separator + webRoot;
// 设置contextPath和web资源目录
Context context = tomcat.addWebapp(configure.getServer().getContextPath(), webRoot);
// 设置应用程序的编译路径,这样容器启动时会从classpath路径下查找对应Servlet注解的组件
// 例如: @webServlet、@WebFilter、@WebListener
// 管理Web应用中的所有资源(静态资源和类文件)
WebResourceRoot resourceRoot = new StandardRoot(context);
// 过滤出有注解的Servlet类
DirResourceSet resourceSet = new DirResourceSet(resourceRoot, "/WEB-INF/classes", ClassUtil.getClassPath(), "/");
// 将过滤之后的结果添加到容器中
resourceRoot.addPreResources(resourceSet);
// 将容器设置回Tomcat上下文中
context.setResources(resourceRoot);
// 创建连接
tomcat.getConnector();
try {
//启动tomcat
tomcat.start();
//将Tomcat进行阻状态,保持运行状态
tomcat.getServer().await();
} catch (LifecycleException e) {
throw new RuntimeException("启动Tomcat失败!!!",e);
}
}
}
这里tomcatServlet类继承了抽象类,之前的Tomcat是不是创建了Tomcat之后要初始化Configure类来获取yml,但是我们的抽象类已经实现了那一步,这是让运行Tomcat的第一步,接着在将这些配置设置在Tomcat中,而我们的抽象类,有一个的抽象方法叫start方法,我们的tomcatServlet类重写start方法,将对应的设置和启动tomcat是不是对应的实现完成了!!!
最后测试项目中是不是只需要调用run方法,就可以完成tomcat的初始化和启动了,因为run方法里面有两个操作,一个是初始化,一个是启动Tomcat,这是不是一个步骤
7.4 测试扩展后的代码
7.4.1
先清理,在安装
7.4.2
在webapp-demo项目中刷新mvc-framework依赖
7.4.3
在Main测试类中修改Tomcat启动方式
Main启动类具体代码:
package com.xr;
import com.xr.embed.server.TomcatServer;
/**
* 测试方法
* @author xr
* @Date 2024/5/13 11:50
*/
public class Main {
public static void main(String[] args) throws Exception {
// 创建Tomcat
TomcatServer tomcatServer = new TomcatServer();
// 启动Tomcat,调用run方法来启动Tomcat
tomcatServer.run();
}
}
7.4.4
启动项目并测试访问servlet和静态资源页面
启动项目:
访问静态资源页面:
访问Servlet:
扩展代码成功,可以实现不同容器的扩展!!!!
8. 解决多个请求对应多个Servlet问题
之前完成了内嵌Tomcat容器,也可以多个内嵌其他容器。
现在来解决传统的web开发的弊端:
1. 解决多个请求对应多个Servlet
原因 :
传统的web开发的时候,我们每发送一个请求,Tomcat内部会创建一个Servlet,如果项目很大,请求很多,那么我们的程序会不会变得非常臃肿
解决方案 :
为了解决这一个弊端,我们采用用一个Servlet处理所有请求,并将这些请求分发给对应的控制器去处理,这样解决了频繁创建Servlet的问题
8.1 创建DispatcherServlet类
创建一个DispatcherServlet(Servlet类),重写Tomcat的(默认的servlet)DefaultServlet
将所有请求统一交给该DispatcherServlet类处理
创建Servlet包,在创建DispatcherServlet类:
DispatcherServlet类具体代码:
1. 多个请求对应多个servlet,简化成多个请求1个servlet处理
2.请求总控器,负责接收所有请求,然后更具请求地址分配给不同的后端控制器(Controller)
3.当@WebServlet注解中的url-pattern设置为"/"时,会覆盖默认的DefaultServlet
4.所有的web服务器都会由一个默认的Servlet,这个Servlet专门用于处理静态资源
5.Tomcat有3个自带的servlet:1.DefaultServlet 2.JspServlet 3.ServletFileUpload
6.默认的Servlet会处理静态资源,例如:html、css、js、图片等
7.jspServlet: 处理jsp页面
8.ServletFileUpload: 处理文件上传
package com.xr.servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 多个请求对应多个servlet,简化成多个请求1个servlet处理
* 请求总控器,负责接收所有请求,然后更具请求地址分配给不同的后端控制器(Controller)
* 当url-pattern设置为"/"时,会覆盖默认的DefaultServlet,
* 所有的web服务器都会由一个默认的Servlet,这个Servlet专门用于处理静态资源
* Tomcat有3个自带的servlet:1.DefaultServlet 2.JspServlet 3.ServletFileUpload
* 默认的Servlet会处理静态资源,例如:html、css、js、图片等
* jspServlet: 处理jsp页面
* ServletFileUpload: 处理文件上传
* @author xr
* @Date 2024/5/14 9:09
*/
@WebServlet("/")
public class DispatcherServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("进入了统一处理请求的Servlet");
// 获取请求路径
String uri = req.getRequestURI();
System.out.println("请求路径:"+uri);
}
}
8.2 测试处理请求
8.2.1
先清理,在安装
8.2.2
在webapp-demo中刷新mvc-framework依赖
8.2.3
在webapp文件创建WEB-INF文件,在创建web.xml文件配置Tomcat默认的Servlet
作用:
将多个请求统一交给该Serlvet处理
web.xml文件具体配置:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!--配置DispatcherServlet,覆盖默认的Servlet类,将所有请求交给该Servlet类处理-->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>com.xr.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
8.2.4
启动测试项目,测试!!!
启动:
注意:
我们原本在测试项目中创建了一个Servlet,而我们在mvc-framework中也创建了一个Servlet类(DispatcherServlet),所以该测试项目中一共有两个Servlet,他们两个互不相关,都可以访问
访问测试项目创建的Serlvet:
访问静态资源页面:
访问其他任意请求:
控制台输出:
访问任意请求:
控制台输出:
发现:
除了自己创建的Servlet类和静态资源页面,我们不管访问其他任意请求都会被DispatcherServlet(默认Servlet)类处理
多个请求被一个Servlet处理完成
8.3 将接收的请求进行处理
上面已经解决了多个请求需要创建了多个Servlet进行处理,但是还没有做具体的处理。
------------------------------------------------------待更新------------------------------------------------------------------