Java WEB面试系列-02

2022年7月17日
大约 12 分钟

Java WEB面试系列-02

1. Servlet 中如何获取 Session 对象?

使用HttpServletRequest对象的getSession方法获取session,通过getCookies获取Cookie。

2. Servlet 中过滤器有什么作用?

Servlet监听器对特定的事件进行监听,当产生这些事件的时候,会执行监听器的代码。可以对应用的加载、卸载,对session的初始化、销毁,对session中值变化等事件进行监听。

void doFilter(..) { 
    // do stuff before servlet gets called

    // invoke the servlet, or any other filters mapped to the target servlet
    chain.doFilter(..);

    // do stuff after the servlet finishes
}

3. ServletContext 接口包括哪些功能?分别用代码示例。

1、获取web应用的初始化参数

使用getInitParameterNames()和getInitParameter(String name)来获得web应用中的初始化参数。

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	request.setCharacterEncoding("utf-8");
	response.setContentType("text/html;charset=utf-8");
	PrintWriter outPrintWriter = response.getWriter();
	ServletContext context = this.getServletContext();                  //定义一个ServletContext对象
	Enumeration<String> enumeration = context.getInitParameterNames();  //用集合得方式存储配置文件中所有的name
	while(enumeration.hasMoreElements()){                              //判断是否为空
		String nameString = enumeration.nextElement();                 //跨过头部  提取第一个name
		String passString = context.getInitParameter(nameString);    //用getInitParameter(name)提取value
		outPrintWriter.print(nameString+"  "+passString);            //输出
	}
}

2、实现多个servlet的数据共享

setAttribute(String name,String value) 来设置共享的数据 
getAttribute(String name) 来获得共享得数据值
removeAttribute(String name) 删除
getAttributeNames()

写数据:ServletSet类

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	// TODO Auto-generated method stub
	ServletContext context = this.getServletContext();
	context.setAttribute("公众号:Java精选", "123456");
}

读数据:ServletGet类

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	// TODO Auto-generated method stub
	request.setCharacterEncoding("utf-8");
	response.setContentType("text/html;charset=utf-8");
	PrintWriter out = response.getWriter();
	ServletContext context = this.getServletContext();
	String pasString = (String) context.getAttribute("公众号:Java精选"); //要强制类型转换getAttribute的返回值为object
	out.print(pasString);
}

3、获取web应用下的资源文件(配置文件或图片)

InputStream getResourceAsInputstream(String path)
String getRealPath(String path)
URL getResource(String path)

1)在src路径下创建配置文件创建文件source.properties(项目被发布后资源文件的路径发生改变)

2)获取资源文件定义的InoutStream and load()方法getProperty()方法

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	response.setContentType("text/html");
	PrintWriter out = response.getWriter();
	ServletContext context = this.getServletContext();
	InputStream in = context.getResourceAsStream("D:/source.properties");
	Properties pros = new Properties();   //定义内容对象
	pros.load(in);     加载InputStream对象
	out.print(pros.getProperty("name"));  //使用getProperty函数输出文件里的哈希值对
	out.print(pros.getProperty("password"));
}

4. 如何实现 Servlet 单线程模式?

<%@ page isThreadSafe="false"%>

5. Servlet 的生命周期有哪几个阶段?

Servlet 的生命周期分为三个阶段,分别对应Servlet中的三个接口。

init()初始化。

service()处理客户端的请求,具体业务逻辑。ServletRequest对象用于获得客户端信息,ServletResponse对象用于向客户端返回信息(客户端可以理解为浏览器)

destroy()结束时调用。这个方法只有在servlet的service方法内的所有线程都退出的时候,或在超时的时候才会被调用。

init()和destroy()方法在servlet的生命周期中只调用一次。其中init()方法在首次创建servlet时调用,在处理每个用户的请求时不再调用。init()方法主要用于一次性初始化;destroy()会在销毁时调用一次;service()则会在响应不同请求时多次调用。

web容器加载servlet,生命周期开始。通过调用servlet的init()方法进行servlet的初始化。通过调用service()方法实现根据请求的不同调用不同的do**()方法。结束服务,web容器调用servlet的destroy()方法。

注意的是Servlet是一个接口,实现了servlet的类,是不能直接处理请求的。请求需要通过Servlet容器来发送到Servlet,Servlet是运行在Servlet容器中的。

Servlet容器是Web服务器和servlet进行交互的必不可少的组件。常见Web服务器有Tomcat、jetty、resin等,它们也可以称为应用服务器。

6. 说一说 Servlet 容器对 url 匹配过程?

当一个请求发送到servlet容器的时候,容器先会将请求的url减去当前应用上下文的路径作为servlet的映射url,比如我访问的是http://localhost/test/aaa.html,我的应用上下文是test,容器会将http://localhost/test去掉,剩下的/aaa.html部分拿来做servlet的映射匹配。这个映射匹配过程是有顺序的,而且当有一个servlet匹配成功以后,就不会去理会剩下的servlet了(filter不同,后文会提到)。open in new window

匹配规则和顺序如下:

1)精确路径匹配。例子:比如servletA 的url-pattern为 /test,servletB的url-pattern为 /* ,这个时候,如果我访问的url为http://localhost/testopen in new window ,这个时候容器就会先 进行精确路径匹配,发现/test正好被servletA精确匹配,那么就去调用servletA,也不会去理会其他的servlet了。

2)最长路径匹配。例子:servletA的url-pattern为/test/,而servletB的url-pattern为/test/a/,此时访问http://localhost/test/a时,容器会选择路径最长的servlet来匹配,也就是这里的servletB。open in new window

3)扩展匹配,如果url最后一段包含扩展,容器将会根据扩展选择合适的servlet。例子:servletA的url-pattern:*.action

4)如果前面三条规则都没有找到一个servlet,容器会根据url选择对应的请求资源。如果应用定义了一个default servlet,则容器会将请求丢给default servlet(什么是default servlet?后面会讲)。

根据这个规则表,就能很清楚的知道servlet的匹配过程,所以定义servlet的时候也要考虑url-pattern的写法,以免出错。

对于filter,不会像servlet那样只匹配一个servlet,因为filter的集合是一个链,所以只会有处理的顺序不同,而不会出现只选择一个filter。Filter的处理顺序和filter-mapping在web.xml中定义的顺序相同。

url-pattern详解

在web.xml文件中,以下语法用于定义映射:

以”/’开头和以”/”结尾的是用来做路径映射的。 以前缀”.”开头的是用来做扩展映射的。 “/” 是用来定义default servlet映射的。 剩下的都是用来定义详细映射的。比如: /aa/bb/cc.action

所以,为什么定义”/*.action”这样一个看起来很正常的匹配会错?因为这个匹配即属于路径映射,也属于扩展映射,导致容器无法判断。

7. jsp/servlet 中如何保证 browser 保存在 cache 中?

JSP文件头部增加如下信息即可:

<%
response.setHeader("Cache-Control","no-store"); //HTTP 1.1
response.setHeader("Pragma","no-cache"); //HTTP 1.0
response.setDateHeader ("Expires", 0); //prevents caching at the proxy server
%>

8. Servlet 中如何获取客户端机器的信息?

Servlet使用getRemoteAddr()和getRemoteHost()来得到客户端的IP地址和host。

public String ServletRequest.getRemoteAddr()
public Stirng ServletRequest.getRemoteHost()

实现对客户端配置进行检查并把相关消息发送到客户端的功能:

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class JingXuanServlet extends HttpServlet {

	private static final long serialVersionUID = 1L;

	public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {

		res.setContentType("text/plain");
		PrintWriter out = res.getWriter();
		String remoteHost = req.getRemoteHost();
		if (!isHostAllowed(remoteHost)) {
			out.println("拒绝关注“Java精选”公众号,3000+面试题看不到");
		} else {
			out.println("允许关注“Java精选”公众号,3000+面试题免费看");
		}
	}

	private boolean isHostAllowed(String host) {
		return (host.endsWith(".com")) || (host.indexOf('.') == -1);
	}
}

9. 什么是 Servlet 链?

与UNIX和DOS命令中的管道类似,你也可以将多个servlet以特定顺序链接起来。在servlet链中,一个servlet的输出被当作下一个servlet的输入,而链中最后一个servlet的输出被返回到浏览器。

servlet链接提供了将一个servlet的输出重定向为另一个servlet的输入的能力。这样,你就可以划分工作,从而使用一系列servlet来实现它。另外,你还可以将servlet组织在一起以提供新的功能。

10. Java 中 Servlet 主要功能作用是什么?

Servlet通过创建一个框架来扩展服务器的能力,以提供在Web上进行请求和响应服务。

当客户机发送请求至服务器时,服务器可以将请求信息发送给Servlet ,并让Servlet建立起服务器返回给客户机的响应。当启动Web服务器或客户机第一次请求服务时,可以自动装入Servlet。装入后Servlet继续运行直到其它客户机发出请求。

Servlet完成如下功能:

  1. 创建并返回一个包含基于客户请求性质的动态内容的完整的HTML页面。

  2. 创建可嵌入到现有HTML页面中的一部分HTML页面(HTML片段)。

  3. 与其它服务器资源(包括数据库和基于Java的应用程序)进行通信。

  4. 用多个客户机处理连接,接收多个客户机的输入,并将结果广播到多个客户机上。例如,Servlet可以是多参与者的游戏服务器。

  5. 当允许在单连接方式下传送数据的情况下,在浏览器上打开服务器至 applet的新连接,并将该连 接保持在打开状态。当允许客户机和服务器简单、高效地执行会话的情况下, applet也可以启动客户浏览器和服务器之间的连接。可以通过定制协议或标准(如IIOP)进行通信。

  6. 对特殊的处理采用MIME类型过滤数据,例如图像转换和服务器端包括(SSI)。

  7. 将定制的处理提供给所有服务器的标准例行程序。例如,Servlet可以修改如何认证用户。

11. JavaWeb 中四大域对象及作用范围?

PageContext:作用范围在整个页面(一个页面)。

HttpRequest:作用范围在一次请求。

HttpSession:这是JavaWeb的一种会话机制,作用在整个会话中。

ServletContext:作用范围在整个web应用。

12. JSP 中静态包含和动态包含有什么区别?

动态包含

<jsp:include page="jingxuan.jsp" flush="true"/> 

比如a.jsp动态导入了b.jsp,只有当服务器访问a.jsp中的b.jsp模块时,java才会编译执行b.jsp文件,将其结果动态包含进来。

1、会将多个jsp页面分别再编写成java文件,编译成class文件。 2、jsp文件中允许有相同的变量名,每个页面互不影响。 3、当java代码比较多优先选用动态导入。 4、效率相对较低,耦合性低。

动态包含用于加载经常变化的、要求显示最新版本内容的数据。

静态包含

<%@ include file="jingxuan.htm"%> 

1、会将多个jsp页面合成一个jsp页面,再编写成java文件,编译成class文件。 2、jsp文件中不允许有相同的变量名。 3、当java代码比较少或者没有java代码是优先选用静态导入。 4、效率相对较高,耦合性高。

静态包含一般用于加载进页面显示后就再也不变的数据。

13. JSP 中动态 include 和静态 include 有什么区别?

include指令用于把另一个页面包含到当前页面中,在转换成servlet时包含进去。

动态include用jsp:include动作实现 <jsp:include page="jingxuan.jsp" flush="true" />它总是会检查所含文件中的变化,适合用于包含动态页面,并且可以带参数。

静态include用include伪码实现,定不会检查所含文件的变化,适用于包含静态页面<%@ include file="jingxuan.htm" %>。

Cookie是客户端保存用户信息的一种机制,用来记录用户的一些信息,它的过期时间可以任意设置,如果不主动清除,很长一段时间都能保留。

15. 什么是 Session?

Session是在无状态的HTTP协议下,服务端记录用户状态时用于标识具体用户的机制,它是在服务端保存的用来跟踪用户的状态的数据结构,可以保存在文件、数据库、或者集群中。

Session和Cookie都是一种会话技术。

Session

数据存放在服务端,安全(只存放和状态相关的)。

session不仅仅是存放字符串,还可以存放对象。

session是域对象(session本身是不能跨域的,但可以通过相应技术来解决)。

sessionID的传输默认是需要cookie支持的。

Cookie

数据存放在客户端,不安全(存放的数据一定是和安全无关紧要的数据)。

cookie只能存放字符串,不能存放对象。

cookie不是域对象(Cookie是支持跨域的)。

17. 什么是 B/S 和 C/S?

Browser/Server 浏览器/服务器(瘦客户端)

Custom/Server 客户端/服务器(胖客户端)

18. B/S 和 C/S 有什么联系与区别?

B/S

B/S模式是指在TCP/IP的支持下,以HTTP为传输协议,客户端通过Browser访问Web服务器以及与之相连的后台数据库的技术及体系结构。它由浏览器、Web服务器、应用服务器和数据库服务器组成。

客户端的浏览器通过URL访问Web服务器,Web服务器请求数据库服务器,并将获得的结果以HTML形式返回客户端浏览器。

C/S

C/S在系统机构上和B/S相似,不过需要在客户端安装一个客户端软件,由这个软件对服务器的数据进行读写,就像我们常用的qq,就是这种模式。

19. Servlet 接口的层次结构?

Servlet->genericServlet->HttpServlet->自定义servlet

GenericServlet实现Servlet接口,同时为它的子类屏蔽了不常用的方法,子类只需要重写service方法即可。

HttpServlet继承GenericServlet,根据请求类型进行分发处理,GET进入doGet方法,POST进入doPost方法。

开发者自定义的Servlet类只需要继承HttpServlet即可,重新doGet和doPost。

20. 什么是 ServletContext?

ServletContext是一个接口,它表示Servlet上下文对象一个工程或者一个模块只会有一个ServletContext对象实例,即意思是无论获取到多少个ServletContext对象其实就是一个对象,只是名字可能不一样。

ServletContext也可以理解成是一块所有客户都可以访问的共享的服务器端空间,类似Session。