来吧,好好理解一下Tomcat下的web.xml

对于web项目在部署后,启动tomcat后,通过浏览器访问如果只输入Context而没有具体的index.html/index.jsp系统如何指导去访问哪个页面一直没有搞清楚,这两天通过逆向思考,然后逐步抽丝剥茧,终于把这方面的内容搞清楚了,加下来便于以后查看也希望能帮助一些刚入门的朋友们,言归正传进入主题。

1、URL与web项目的对应

有些时候我们的输入页面是包含index.jsp/index.html的,对于这个基于映射目录是很好理解的,单对于有些URL在输入的时候只有Context,那么是怎么对照的呢?例如如下的URL输入:

http://localhost:8989/MyApp

这个MyApp就是在tomcat的webapps下的项目,也就是告诉tomcat我要访问这个app,当然webapps下面是可以放多个app的,那么问题来了,我们只输入MyApp,在地址栏是怎么显示出来我们的首页的呢?这是我百思不得其解的问题,通过这两天的努力,分享给大家。

2、关键的web.xml文件

Tomcat启动后会去读取这个web.xml文件,该文件就位于app文件夹下面的WEB-INF目录下

1、启动一个WEB项目的时候,容器(本文中就是Tomcat)会去读它的配置文件web.xml.读两个节点:

2、紧接着,容器创建一个ServletContext(上下文),这个WEB项目所有部分都将共享这个上下文.

3、容器将转化为键值对,并交给ServletContext.

4、容器创建中的类实例,即创建监听.

5、在监听中会有contextInitialized(ServletContextEvent args)初始化方法,在这个方法中获得ServletContext = ServletContextEvent.getServletContext();
context-param的值 = ServletContext.getInitParameter("context-param的键");

到这里,有点不好理解了,下面通过一段代码来说明一下,能更好的理解。

2.1、web.xml中的配置文件

我们拿一些实例代码说明一下原理。

A、自定义配置

接下来我们在web.xml中自定义context-param和listener标签,我们将那这个作为实例,方便后的输出,注意中为类的实例,即创建监听。


    urlrewrite
    false


    cluster
    false


    servletmapping
    *.bbscs

    
    poststoragemode
    1


    com.laoer.bbscs.web.servlet.SysListener

B、自定义监听listener类

对应上面代码的listener-class里面的名称SysListener,我们定义一个类就叫SysListener,如下:

public class SysListener extends HttpServlet implements ServletContextListener {
	private static final Log logger = LogFactory.getLog(SysListener.class);
	public void contextDestroyed(ServletContextEvent sce) {
		//用于在容器关闭时,操作
	}
	//用于在容器开启时,操作
	public void contextInitialized(ServletContextEvent sce) {
		String rootpath = sce.getServletContext().getRealPath("/");
		System.out.println("-------------rootPath:"+rootpath);
		if (rootpath != null) {
		rootpath = rootpath.replaceAll("\\\\", "/");
		} else {
			rootpath = "/";
		}
		if (!rootpath.endsWith("/")) {
			rootpath = rootpath + "/";
		}
		Constant.ROOTPATH = rootpath;
		logger.info("Application Run Path:" + rootpath);
		String urlrewrtie = sce.getServletContext().getInitParameter("urlrewrite");
		boolean burlrewrtie = false;
		if (urlrewrtie != null) {
			burlrewrtie = Boolean.parseBoolean(urlrewrtie);
		}
		Constant.USE_URL_REWRITE = burlrewrtie;
		logger.info("Use Urlrewrite:" + burlrewrtie);
		其它略之....
	}
}

代码的内容需要结合前面说的“监听中会有contextInitialized(ServletContextEvent args)初始化方法,在这个方法中获得ServletContext = ServletContextEvent.getServletContext();

上面代码里面就是:

public void contextInitialized(ServletContextEvent sce)这个方法里面有:

String rootpath = sce.getServletContext().getRealPath("/");

String urlrewrtie = sce.getServletContext().getInitParameter("urlrewrite");

注意结合上面的代码去理解,着重看一下getInitParameter("urlrewrite")即可,这个是从已经加载到Tomcat的ServletContext(上下文)中的键值,此处获取到的就是String urlrewrtie=false,这里这个类和方法就是为了说明Servelt内部如何读取键值的。

还可以:

6、得到这个context-param的值之后,你就可以做一些操作了.注意,这个时候你的WEB项目还没有完全启动完成.这个动作会比所有的Servlet都要早.
换句话说,这个时候,你对中的键值做的操作,将在你的WEB项目完全启动之前被执行.
7、举例.你可能想在项目启动之前就打开数据库.
那么这里就可以在中设置数据库的连接方式,在监听类中初始化数据库的连接.
8、这个监听是自己写的一个类,除了初始化方法,它还有销毁方法.用于关闭应用前释放资源.比如说数据库连接的关闭.


    
        contextConfigLocation
        /WEB-INF/applicationContext.xml,/WEB-INF/action-servlet.xml,
        /WEB-INF/jason-servlet.xml
    

    
    org.springframework.web.context.ContextLoaderListener
    

3、Tomcat如何处理请求

其实,我们在浏览器发起请求,请求了我们的后端web服务器(也就是内置的Tomcat)。而我们在开发web程序时呢,定义了一个控制器类Controller,请求会被部署在Tomcat中的Controller接收,然后Controller再给浏览器一个响应。

来吧,好好理解一下Tomcat下的web.xml_第1张图片

但是,这里要告诉大家的时,其实在Tomcat这类Web服务器中,是不识别我们自己定义的Controller的。但是我们前面讲到过Tomcat是一个Servlet容器,是支持Serlvet规范的,所以呢,在tomcat中是可以识别 Servlet程序的。 那我们所编写的XxxController 是如何处理请求的,又与Servlet之间有什么联系呢?

既然Tomcat不识别我们自定义的Controller,那么可以自己写servlet来跟自己写的Controller交互,现在的框架,例如Spring就是内置了一个核心的Servlet程序 DispatcherServlet,称之为 核心控制器。 DispatcherServlet 负责接收页面发送的请求,然后根据执行的规则,将请求再转发给后面的请求处理器Controller,请求处理器处理完请求之后,最终再由DispatcherServlet给浏览器响应数据。

来吧,好好理解一下Tomcat下的web.xml_第2张图片

浏览器发送请求,会携带请求数据,包括:请求行、请求头;请求到达tomcat之后,tomcat会负责解析这些请求数据,然后呢将解析后的请求数据会传递给Servlet程序的HttpServletRequest对象,那也就意味着 HttpServletRequest 对象就可以获取到请求数据。 而Tomcat,还给Servlet程序传递了一个参数 HttpServletResponse,通过这个对象,我们就可以给浏览器设置响应数据 。

4、Servelt请求转发和重定向

4.1、请求转发

请求转发是一种服务器行为,当客户端请求到达后,服务器进行转发,此时会将请求对象进行保存,地址栏中的URL地址不会改变,得到响应后服务器端再将响应发送给客户端,从始至终只有一个请求发出。实现方式如下,达到多个资源协同响应的效果。

request.getRequestDispatcher(url).forward(request,response);

请求转发就是让我们能够从后台跳转到前台,可以进行后台Servlet的跳转,也可以进行后台跳转到jsp和html页面等,

A、请求转发有以下特点

  • A.地址栏不发生改变。
  • B.服务端行为。
  • C.从始至终只有一个请求也就是04当中用的就是03的请求
  • D.request数据可以共享。

B、示例代码

​​
package com.classStudy.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;
 
/**
 * 请求转发 跳转
 *   request.getRequestDispatcher(url).forward(request,response);
 * 可以让请求从服务端跳转到我们的客户端
 * 或者跳转到指定的servlet
 * 服务端行为
 * 特点:
 * 1.地址栏不发生改变。
 * 2.服务端行为。
 * 3.从始至终只有一个请求也就是04当中用的就是03的请求
 * 4.request数据可以共享。
 *
 */
@WebServlet("/s03")
public class ServletClass03 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //接受客户端请求的参数
        String uname=request.getParameter("uname");
        System.out.println("ServletClass03 uname"+uname);
        //从03跳转到04
        //请求转发跳转到ServletClass04
        //request.getRequestDispatcher("s04").forward(request,response);
        //请求转发跳转到jsp页面
       // request.getRequestDispatcher("login.jsp").forward(request,response);
        //请求跳转到HTML页面
        request.getRequestDispatcher("login.html").forward(request,response);
 
    }
}

4.2、重定向

重定向是一种服务器指导客户端的行为。客户端发出第一个请求,被服务器接受处理后,服务器会响应,在响应的同时,服务器会给客户端一个新的地址(下次的请求地址:response.sendRedirect(url);),当客户端接受到响应后,会立刻,马上,自动根据服务器给的新地址发起第二个请求,服务器接受请求并作出响应,重定向完成。

response.sendRedirect("index.jsp");

A、重定向有以下特点

A、服务端指导,客户端行为
B、存在两次请求
C、地址栏会发生改变
D、request对象不共享response也不共享

B、示例代码

package com.classStudy2.servlet;
 
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
 
import java.io.IOException;
 
/**
 * 重定向
 * 特点:
 * 1.服务端指导,客户端行为
 * 2.存在两次请求
 * 3.地址栏会发生改变
 * 4.request对象不共享response也不共享
 */
@WebServlet("/s004")
public class ResponseClass04 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("Response04.......................");
        //接收参数
        String uname=request.getParameter("uname");
        System.out.println("Response04"+uname);
        //重定向跳转到05
        //请求先到04里面
        response.sendRedirect("s005");
    }
}

4.3、请求转发和重定向的区别

来吧,好好理解一下Tomcat下的web.xml_第3张图片

两者都可以进行跳转,根据实际需求进行选择
请求转发只能去找当前项目下的资源
重定向可以访问项目以外的资源
应用场景:大多数情况是客户端发送请求到我们的后台,后台Servlet处理好数据之后跳转到前台,也就是向页面中跳转。

 
package com.classStudy2.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处理好数据之后跳转到前台也就是向页面中跳转
 *
 */
@WebServlet("/s006")
public class ResponseClass06 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("Response06......................");
        //接收参数
        String uname=request.getParameter("uname");
        System.out.println("Response06"+uname);
       //设置request域对象
        request.setAttribute("upwd","123456");
        //请求转发
        //request.getRequestDispatcher("index02.jsp").forward(request,response);
        //重定向
        //response.sendRedirect("index02.jsp");
        //重定向到百度
        response.sendRedirect("http://www.baidu.com");
 
    }
}

5、疑问解决

回到我最前面的问题上来:

在我要查看的项目启动后,我在浏览器端输入的并不是一个ip:port/index.html or index.js等明确的页面,而是只输入了项目名或者字符串,也会显示一个页面,例如我输入了ip:port/myProject这样的地址,回车以后却直接显示了登录页面:ip:port/myProject/faces/login.html

也就是说我从浏览器端发送了ip:port/myProject,首先传递给DispatcherServlet的HttpServletRequest对象,DispatcherServlet根据输入的http内容调去做解析处理,Tomcat作为容器已经在启动时读取web.xml加载了servlet并读取了context-param和listener等,servlet处理完成后,Tomcat给相应的Servlet程序传递了一个参数 HttpServletResponse,通过这个对象去进行重定向到ip:port/myProject/faces/login.html,我们就可以给浏览器设置响应数据,更新我的浏览器地址 ,当客户端接受到响应后,会立刻自动根据服务器给的新地址发起第二个请求,服务器接受请求并作出响应,重定向完成,也就显示出我的login.html页面。

以上是针对自己的问题找到相关资料并整理的内容,难免有理解不到位的地方,欢迎大家指正。

6、参考资料

https://blog.csdn.net/CatEatApple/article/details/112393498

https://blog.csdn.net/qq_64744030/article/details/133770437

https://blog.csdn.net/weixin_67630324/article/details/128903036

你可能感兴趣的:(tomcat,前端,xml)