对于web项目在部署后,启动tomcat后,通过浏览器访问如果只输入Context而没有具体的index.html/index.jsp系统如何指导去访问哪个页面一直没有搞清楚,这两天通过逆向思考,然后逐步抽丝剥茧,终于把这方面的内容搞清楚了,加下来便于以后查看也希望能帮助一些刚入门的朋友们,言归正传进入主题。
有些时候我们的输入页面是包含index.jsp/index.html的,对于这个基于映射目录是很好理解的,单对于有些URL在输入的时候只有Context,那么是怎么对照的呢?例如如下的URL输入:
http://localhost:8989/MyApp
这个MyApp就是在tomcat的webapps下的项目,也就是告诉tomcat我要访问这个app,当然webapps下面是可以放多个app的,那么问题来了,我们只输入MyApp,在地址栏是怎么显示出来我们的首页的呢?这是我百思不得其解的问题,通过这两天的努力,分享给大家。
Tomcat启动后会去读取这个web.xml文件,该文件就位于app文件夹下面的WEB-INF目录下
1、启动一个WEB项目的时候,容器(本文中就是Tomcat)会去读它的配置文件web.xml.读两个节点:
2、紧接着,容器创建一个ServletContext(上下文),这个WEB项目所有部分都将共享这个上下文.
3、容器将
4、容器创建
5、在监听中会有contextInitialized(ServletContextEvent args)初始化方法,在这个方法中获得ServletContext = ServletContextEvent.getServletContext();
context-param的值 = ServletContext.getInitParameter("context-param的键");
到这里,有点不好理解了,下面通过一段代码来说明一下,能更好的理解。
我们拿一些实例代码说明一下原理。
接下来我们在web.xml中自定义context-param和listener标签,我们将那这个作为实例,方便后的输出,注意
urlrewrite
false
cluster
false
servletmapping
*.bbscs
poststoragemode
1
com.laoer.bbscs.web.servlet.SysListener
对应上面代码的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都要早.
换句话说,这个时候,你对
7、举例.你可能想在项目启动之前就打开数据库.
那么这里就可以在
8、这个监听是自己写的一个类,除了初始化方法,它还有销毁方法.用于关闭应用前释放资源.比如说数据库连接的关闭.
contextConfigLocation
/WEB-INF/applicationContext.xml,/WEB-INF/action-servlet.xml,
/WEB-INF/jason-servlet.xml
org.springframework.web.context.ContextLoaderListener
其实,我们在浏览器发起请求,请求了我们的后端web服务器(也就是内置的Tomcat)。而我们在开发web程序时呢,定义了一个控制器类Controller,请求会被部署在Tomcat中的Controller接收,然后Controller再给浏览器一个响应。
但是,这里要告诉大家的时,其实在Tomcat这类Web服务器中,是不识别我们自己定义的Controller的。但是我们前面讲到过Tomcat是一个Servlet容器,是支持Serlvet规范的,所以呢,在tomcat中是可以识别 Servlet程序的。 那我们所编写的XxxController 是如何处理请求的,又与Servlet之间有什么联系呢?
既然Tomcat不识别我们自定义的Controller,那么可以自己写servlet来跟自己写的Controller交互,现在的框架,例如Spring就是内置了一个核心的Servlet程序 DispatcherServlet,称之为 核心控制器。 DispatcherServlet 负责接收页面发送的请求,然后根据执行的规则,将请求再转发给后面的请求处理器Controller,请求处理器处理完请求之后,最终再由DispatcherServlet给浏览器响应数据。
浏览器发送请求,会携带请求数据,包括:请求行、请求头;请求到达tomcat之后,tomcat会负责解析这些请求数据,然后呢将解析后的请求数据会传递给Servlet程序的HttpServletRequest对象,那也就意味着 HttpServletRequest 对象就可以获取到请求数据。 而Tomcat,还给Servlet程序传递了一个参数 HttpServletResponse,通过这个对象,我们就可以给浏览器设置响应数据 。
请求转发是一种服务器行为,当客户端请求到达后,服务器进行转发,此时会将请求对象进行保存,地址栏中的URL地址不会改变,得到响应后服务器端再将响应发送给客户端,从始至终只有一个请求发出。实现方式如下,达到多个资源协同响应的效果。
request.getRequestDispatcher(url).forward(request,response);
请求转发就是让我们能够从后台跳转到前台,可以进行后台Servlet的跳转,也可以进行后台跳转到jsp和html页面等,
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);
}
}
重定向是一种服务器指导客户端的行为。客户端发出第一个请求,被服务器接受处理后,服务器会响应,在响应的同时,服务器会给客户端一个新的地址(下次的请求地址:response.sendRedirect(url);),当客户端接受到响应后,会立刻,马上,自动根据服务器给的新地址发起第二个请求,服务器接受请求并作出响应,重定向完成。
response.sendRedirect("index.jsp");
A、服务端指导,客户端行为
B、存在两次请求
C、地址栏会发生改变
D、request对象不共享response也不共享
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");
}
}
两者都可以进行跳转,根据实际需求进行选择
请求转发只能去找当前项目下的资源
重定向可以访问项目以外的资源
应用场景:大多数情况是客户端发送请求到我们的后台,后台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");
}
}
回到我最前面的问题上来:
在我要查看的项目启动后,我在浏览器端输入的并不是一个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页面。
以上是针对自己的问题找到相关资料并整理的内容,难免有理解不到位的地方,欢迎大家指正。
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