经典的Java面试题(第二部分),这部分主要是与Java Web和Web Service相关的面试题。php
9六、阐述Servlet和CGI的区别?css
答:Servlet与CGI的区别在于Servlet处于服务器进程中,它经过多线程方式运行其service()方法,一个实例能够服务于多个请求,而且其实例通常不会销毁,而CGI对每一个请求都产生新的进程,服务完成后就销毁,因此效率上低于Servlet。html
补充:Sun Microsystems公司在1996年发布Servlet技术就是为了和CGI (Common Gateway Interface) 进行竞争,Servlet是一个特殊的Java程序,一个基于Java的Web应用一般包含一个或多个Servlet类。Servlet不可以自行建立并执行,它是在Servlet容器中运行的,容器将用户的请求传递给Servlet程序,并将Servlet的响应回传给用户。一般一个Servlet会关联一个或多个JSP页面。之前CGI常常由于性能开销上的问题被诟病,然而Fast CGI早就已经解决了CGI效率上的问题,因此面试的时候大可没必要信口开河的诟病CGI,事实上有不少你熟悉的网站都使用了CGI技术。java
9七、Servlet接口中有哪些方法?git
答:Servlet接口定义了5个方法,其中前三个方法与Servlet生命周期相关:github
Web容器加载Servlet并将其实例化后,Servlet生命周期开始,容器运行其init()方法进行Servlet的初始化;请求到达时调用Servlet的service()方法,service()方法会根据须要调用与请求对应的doGet或doPost等方法;当服务器关闭或项目被卸载时服务器会将Servlet实例销毁,此时会调用Servlet的destroy()方法。web
9八、转发(forward)和重定向(redirect)的区别?面试
答:forward是容器中控制权的转向,是服务器请求资源,服务器直接访问目标地址的URL,把那个URL 的响应内容读取过来,而后把这些内容再发给浏览器,浏览器根本不知道服务器发送的内容是从哪儿来的,因此它的地址栏中仍是原来的地址。redirect就是服务器端根据逻辑,发送一个状态码,告诉浏览器从新去请求那个地址,所以从浏览器的地址栏中能够看到跳转后的连接地址,很明显redirect没法访问到服务器保护起来资源,可是能够从一个网站redirect到其余网站。forward更加高效,因此在知足须要时尽可能使用forward(经过调用RequestDispatcher对象的forward()方法,该对象能够经过ServletRequest对象的getRequestDispatcher()方法得到),而且这样也有助于隐藏实际的连接;在有些状况下,好比须要访问一个其它服务器上的资源,则必须使用重定向(经过HttpServletResponse对象调用其sendRedirect()方法实现)。spring
9九、JSP有哪些内置对象?做用分别是什么?sql
答:JSP有9个内置对象:
补充:若是用Servlet来生成网页中的动态内容无疑是很是繁琐的工做,另外一方面,全部的文本和HTML标签都是硬编码,即便作出微小的修改,都须要进行从新编译。JSP解决了Servlet的这些问题,它是Servlet很好的补充,能够专门用做为用户呈现视图(View),而Servlet做为控制器(Controller)专门负责处理用户请求并转发或重定向到某个页面。基于Java的Web开发不少都同时使用了Servlet和JSP。JSP页面实际上是一个Servlet,可以运行Servlet的服务器(Servlet容器)一般也是JSP容器,能够提供JSP页面的运行环境,Tomcat就是一个Servlet/JSP容器。第一次请求一个JSP页面时,Servlet/JSP容器首先将JSP页面转换成一个JSP页面的实现类,这是一个实现了JspPage接口或其子接口HttpJspPage的Java类。JspPage接口是Servlet的子接口,所以每一个JSP页面都是一个Servlet。转换成功后,容器会编译Servlet类,以后容器加载和实例化Java字节码,并执行它一般对Servlet所作的生命周期操做。对同一个JSP页面的后续请求,容器会查看这个JSP页面是否被修改过,若是修改过就会从新转换并从新编译并执行。若是没有则执行内存中已经存在的Servlet实例。咱们能够看一段JSP代码对应的Java程序就知道一切了,并且9个内置对象的神秘面纱也会被揭开。
JSP页面:
<%@ page pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/";
%>
<!DOCTYPE html>
<html>
<head>
<base href="<%=basePath%>">
<title>首页</title>
<style type="text/css">
* { font-family: "Arial"; }
</style>
</head>
<body>
<h1>Hello, World!</h1>
<hr/>
<h2>Current time is: <%= new java.util.Date().toString() %></h2>
</body>
</html>
复制代码
对应的Java代码:
/* * Generated by the Jasper component of Apache Tomcat * Version: Apache Tomcat/7.0.52 * Generated at: 2014-10-13 13:28:38 UTC * Note: The last modified time of this file was set to * the last modified time of the source file after * generation to assist with modification tracking. */
package org.apache.jsp;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
public final class index_jsp extends org.apache.jasper.runtime.HttpJspBase implements org.apache.jasper.runtime.JspSourceDependent {
private static final javax.servlet.jsp.JspFactory _jspxFactory = javax.servlet.jsp.JspFactory
.getDefaultFactory();
private static java.util.Map<java.lang.String, java.lang.Long> _jspx_dependants;
private javax.el.ExpressionFactory _el_expressionfactory;
private org.apache.tomcat.InstanceManager _jsp_instancemanager;
public java.util.Map<java.lang.String, java.lang.Long> getDependants() {
return _jspx_dependants;
}
public void _jspInit() {
_el_expressionfactory = _jspxFactory.getJspApplicationContext(
getServletConfig().getServletContext()).getExpressionFactory();
_jsp_instancemanager = org.apache.jasper.runtime.InstanceManagerFactory
.getInstanceManager(getServletConfig());
}
public void _jspDestroy() {
}
public void _jspService( final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response) throws java.io.IOException, javax.servlet.ServletException {
// 内置对象就是在这里定义的
final javax.servlet.jsp.PageContext pageContext;
javax.servlet.http.HttpSession session = null;
final javax.servlet.ServletContext application;
final javax.servlet.ServletConfig config;
javax.servlet.jsp.JspWriter out = null;
final java.lang.Object page = this;
javax.servlet.jsp.JspWriter _jspx_out = null;
javax.servlet.jsp.PageContext _jspx_page_context = null;
try {
response.setContentType("text/html;charset=UTF-8");
pageContext = _jspxFactory.getPageContext(this, request, response,
null, true, 8192, true);
_jspx_page_context = pageContext;
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();
_jspx_out = out;
out.write('\r');
out.write('\n');
String path = request.getContextPath();
String basePath = request.getScheme() + "://"
+ request.getServerName() + ":" + request.getServerPort()
+ path + "/";
// 如下代码经过输出流将HTML标签输出到浏览器中
out.write("\r\n");
out.write("\r\n");
out.write("<!DOCTYPE html>\r\n");
out.write("<html>\r\n");
out.write(" <head>\r\n");
out.write(" <base href=\"");
out.print(basePath);
out.write("\">\r\n");
out.write(" <title>首页</title>\r\n");
out.write(" <style type=\"text/css\">\r\n");
out.write(" \t* { font-family: \"Arial\"; }\r\n");
out.write(" </style>\r\n");
out.write(" </head>\r\n");
out.write(" \r\n");
out.write(" <body>\r\n");
out.write(" <h1>Hello, World!</h1>\r\n");
out.write(" <hr/>\r\n");
out.write(" <h2>Current time is: ");
out.print(new java.util.Date().toString());
out.write("</h2>\r\n");
out.write(" </body>\r\n");
out.write("</html>\r\n");
} catch (java.lang.Throwable t) {
if (!(t instanceof javax.servlet.jsp.SkipPageException)) {
out = _jspx_out;
if (out != null && out.getBufferSize() != 0)
try {
out.clearBuffer();
} catch (java.io.IOException e) {
}
if (_jspx_page_context != null)
_jspx_page_context.handlePageException(t);
else
throw new ServletException(t);
}
} finally {
_jspxFactory.releasePageContext(_jspx_page_context);
}
}
}
复制代码
100、get和post请求的区别?
答: ①get请求用来从服务器上得到资源,而post是用来向服务器提交数据; ②get将表单中数据按照name=value的形式,添加到action 所指向的URL 后面,而且二者使用"?"链接,而各个变量之间使用"&"链接;post是将表单中的数据放在HTTP协议的请求头或消息体中,传递到action所指向URL; ③get传输的数据要受到URL长度限制(1024字节);而post能够传输大量的数据,上传文件一般要使用post方式; ④使用get时参数会显示在地址栏上,若是这些数据不是敏感数据,那么可使用get;对于敏感数据仍是应用使用post; ⑤get使用MIME类型application/x-www-form-urlencoded的URL编码(也叫百分号编码)文本的格式传递参数,保证被传送的参数由遵循规范的文本组成,例如一个空格的编码是"%20"。
10一、经常使用的Web服务器有哪些?
答:Unix和Linux平台下使用最普遍的免费HTTP服务器是Apache服务器,而Windows平台的服务器一般使用IIS做为Web服务器。选择Web服务器应考虑的因素有:性能、安全性、日志和统计、虚拟主机、代理服务器、缓冲服务和集成应用程序等。下面是对常见服务器的简介:
10二、JSP和Servlet是什么关系?
答:其实这个问题在上面已经阐述过了,Servlet是一个特殊的Java程序,它运行于服务器的JVM中,可以依靠服务器的支持向浏览器提供显示内容。JSP本质上是Servlet的一种简易形式,JSP会被服务器处理成一个相似于Servlet的Java程序,能够简化页面内容的生成。Servlet和JSP最主要的不一样点在于,Servlet的应用逻辑是在Java文件中,而且彻底从表示层中的HTML分离开来。而JSP的状况是Java和HTML能够组合成一个扩展名为.jsp的文件。有人说,Servlet就是在Java中写HTML,而JSP就是在HTML中写Java代码,固然这个说法是很片面且不够准确的。JSP侧重于视图,Servlet更侧重于控制逻辑,在MVC架构模式中,JSP适合充当视图(view)而Servlet适合充当控制器(controller)。
10三、讲解JSP中的四种做用域。
答:JSP中的四种做用域包括page、request、session和application,具体来讲:
10四、如何实现JSP或Servlet的单线程模式?
答: 对于JSP页面,能够经过page指令进行设置。
<%@page isThreadSafe=”false”%>
复制代码
对于Servlet,可让自定义的Servlet实现SingleThreadModel标识接口。
说明:若是将JSP或Servlet设置成单线程工做模式,会致使每一个请求建立一个Servlet实例,这种实践将致使严重的性能问题(服务器的内存压力很大,还会致使频繁的垃圾回收),因此一般状况下并不会这么作。
10五、实现会话跟踪的技术有哪些?
答:因为HTTP协议自己是无状态的,服务器为了区分不一样的用户,就须要对用户会话进行跟踪,简单的说就是为用户进行登记,为用户分配惟一的ID,下一次用户在请求中包含此ID,服务器据此判断究竟是哪个用户。 ①URL 重写:在URL中添加用户会话的信息做为请求的参数,或者将惟一的会话ID添加到URL结尾以标识一个会话。 ②设置表单隐藏域:将和会话跟踪相关的字段添加到隐式表单域中,这些信息不会在浏览器中显示可是提交表单时会提交给服务器。 这两种方式很难处理跨越多个页面的信息传递,由于若是每次都要修改URL或在页面中添加隐式表单域来存储用户会话相关信息,事情将变得很是麻烦。 ③cookie:cookie有两种,一种是基于窗口的,浏览器窗口关闭后,cookie就没有了;另外一种是将信息存储在一个临时文件中,并设置存在的时间。当用户经过浏览器和服务器创建一次会话后,会话ID就会随响应信息返回存储在基于窗口的cookie中,那就意味着只要浏览器没有关闭,会话没有超时,下一次请求时这个会话ID又会提交给服务器让服务器识别用户身份。会话中能够为用户保存信息。会话对象是在服务器内存中的,而基于窗口的cookie是在客户端内存中的。若是浏览器禁用了cookie,那么就须要经过下面两种方式进行会话跟踪。固然,在使用cookie时要注意几点:首先不要在cookie中存放敏感信息;其次cookie存储的数据量有限(4k),不能将过多的内容存储cookie中;再者浏览器一般只容许一个站点最多存放20个cookie。固然,和用户会话相关的其余信息(除了会话ID)也能够存在cookie方便进行会话跟踪。 ④HttpSession:在全部会话跟踪技术中,HttpSession对象是最强大也是功能最多的。当一个用户第一次访问某个网站时会自动建立HttpSession,每一个用户能够访问他本身的HttpSession。能够经过HttpServletRequest对象的getSession方法得到HttpSession,经过HttpSession的setAttribute方法能够将一个值放在HttpSession中,经过调用HttpSession对象的getAttribute方法,同时传入属性名就能够获取保存在HttpSession中的对象。与上面三种方式不一样的是,HttpSession放在服务器的内存中,所以不要将过大的对象放在里面,即便目前的Servlet容器能够在内存将满时将HttpSession中的对象移到其余存储设备中,可是这样势必影响性能。添加到HttpSession中的值能够是任意Java对象,这个对象最好实现了Serializable接口,这样Servlet容器在必要的时候能够将其序列化到文件中,不然在序列化时就会出现异常。
补充:HTML5中可使用Web Storage技术经过JavaScript来保存数据,例如可使用localStorage和sessionStorage来保存用户会话的信息,也可以实现会话跟踪。
10六、过滤器有哪些做用和用法?
答: Java Web开发中的过滤器(filter)是从Servlet 2.3规范开始增长的功能,并在Servlet 2.4规范中获得加强。对Web应用来讲,过滤器是一个驻留在服务器端的Web组件,它能够截取客户端和服务器之间的请求与响应信息,并对这些信息进行过滤。当Web容器接受到一个对资源的请求时,它将判断是否有过滤器与这个资源相关联。若是有,那么容器将把请求交给过滤器进行处理。在过滤器中,你能够改变请求的内容,或者从新设置请求的报头信息,而后再将请求发送给目标资源。当目标资源对请求做出响应时候,容器一样会将响应先转发给过滤器,在过滤器中你能够对响应的内容进行转换,而后再将响应发送到客户端。
常见的过滤器用途主要包括:对用户请求进行统一认证、对用户的访问请求进行记录和审核、对用户发送的数据进行过滤或替换、转换图象格式、对响应内容进行压缩以减小传输量、对请求或响应进行加解密处理、触发资源访问事件、对XML的输出应用XSLT等。
和过滤器相关的接口主要有:Filter、FilterConfig和FilterChain。
编码过滤器的例子:
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;
@WebFilter(urlPatterns = { "*" },
initParams = {@WebInitParam(name="encoding", value="utf-8")})
public class CodingFilter implements Filter {
private String defaultEncoding = "utf-8";
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
req.setCharacterEncoding(defaultEncoding);
resp.setCharacterEncoding(defaultEncoding);
chain.doFilter(req, resp);
}
@Override
public void init(FilterConfig config) throws ServletException {
String encoding = config.getInitParameter("encoding");
if (encoding != null) {
defaultEncoding = encoding;
}
}
}
复制代码
下载计数过滤器的例子:
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
@WebFilter(urlPatterns = {"/*"})
public class DownloadCounterFilter implements Filter {
private ExecutorService executorService = Executors.newSingleThreadExecutor();
private Properties downloadLog;
private File logFile;
@Override
public void destroy() {
executorService.shutdown();
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
final String uri = request.getRequestURI();
executorService.execute(new Runnable() {
@Override
public void run() {
String value = downloadLog.getProperty(uri);
if(value == null) {
downloadLog.setProperty(uri, "1");
}
else {
int count = Integer.parseInt(value);
downloadLog.setProperty(uri, String.valueOf(++count));
}
try {
downloadLog.store(new FileWriter(logFile), "");
}
catch (IOException e) {
e.printStackTrace();
}
}
});
chain.doFilter(req, resp);
}
@Override
public void init(FilterConfig config) throws ServletException {
String appPath = config.getServletContext().getRealPath("/");
logFile = new File(appPath, "downloadLog.txt");
if(!logFile.exists()) {
try {
logFile.createNewFile();
}
catch(IOException e) {
e.printStackTrace();
}
}
downloadLog = new Properties();
try {
downloadLog.load(new FileReader(logFile));
} catch (IOException e) {
e.printStackTrace();
}
}
}
复制代码
说明:这里使用了Servlet 3规范中的注解来部署过滤器,固然也能够在web.xml中使用<filter>和<filter-mapping>标签部署过滤器,如108题中所示。
10七、监听器有哪些做用和用法?
答:Java Web开发中的监听器(listener)就是application、session、request三个对象建立、销毁或者往其中添加修改删除属性时自动执行代码的功能组件,以下所示: ①ServletContextListener:对Servlet上下文的建立和销毁进行监听。 ②ServletContextAttributeListener:监听Servlet上下文属性的添加、删除和替换。 ③HttpSessionListener:对Session的建立和销毁进行监听。
补充:session的销毁有两种状况:1). session超时(能够在web.xml中经过<session-config>/<session-timeout>标签配置超时时间);2). 经过调用session对象的invalidate()方法使session失效。
④HttpSessionAttributeListener:对Session对象中属性的添加、删除和替换进行监听。 ⑤ServletRequestListener:对请求对象的初始化和销毁进行监听。 ⑥ServletRequestAttributeListener:对请求对象属性的添加、删除和替换进行监听。
下面是一个统计网站最多在线人数监听器的例子。
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
/** 上下文监听器,在服务器启动时初始化onLineCount和maxOnLineCount两个变量 并将其置于服务器上下文(ServletContext)中,其初始值都是0 */
@WebListener
public class InitListener implements ServletContextListener {
@Override
public void contextDestroyed(ServletContextEvent evt) {
}
@Override
public void contextInitialized(ServletContextEvent evt) {
evt.getServletContext().setAttribute("onLineCount", 0);
evt.getServletContext().setAttribute("maxOnLineCount", 0);
}
}
复制代码
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.servlet.ServletContext;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
/** 会话监听器,在用户会话建立和销毁的时候根据状况 修改onLineCount和maxOnLineCount的值 */
@WebListener
public class MaxCountListener implements HttpSessionListener {
@Override
public void sessionCreated(HttpSessionEvent event) {
ServletContext ctx = event.getSession().getServletContext();
int count = Integer.parseInt(ctx.getAttribute("onLineCount").toString());
count++;
ctx.setAttribute("onLineCount", count);
int maxOnLineCount = Integer.parseInt(ctx.getAttribute("maxOnLineCount").toString());
if (count > maxOnLineCount) {
ctx.setAttribute("maxOnLineCount", count);
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
ctx.setAttribute("date", df.format(new Date()));
}
}
@Override
public void sessionDestroyed(HttpSessionEvent event) {
ServletContext app = event.getSession().getServletContext();
int count = Integer.parseInt(app.getAttribute("onLineCount").toString());
count--;
app.setAttribute("onLineCount", count);
}
}
复制代码
说明:这里使用了Servlet 3规范中的@WebListener注解配置监听器,固然你能够在web.xml文件中用<listener>标签配置监听器,如108题中所示。
10八、web.xml文件中能够配置哪些内容?
答:web.xml用于配置Web应用的相关信息,如:监听器(listener)、过滤器(filter)、 Servlet、相关参数、会话超时时间、安全验证方式、错误页面等,下面是一些开发中常见的配置:
①配置Spring上下文加载监听器加载Spring配置文件并建立IoC容器:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
复制代码
②配置Spring的OpenSessionInView过滤器来解决延迟加载和Hibernate会话关闭的矛盾:
<filter>
<filter-name>openSessionInView</filter-name>
<filter-class>
org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
</filter-class>
</filter>
<filter-mapping>
<filter-name>openSessionInView</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
复制代码
③配置会话超时时间为10分钟:
<session-config>
<session-timeout>10</session-timeout>
</session-config>
复制代码
④配置404和Exception的错误页面:
<error-page>
<error-code>404</error-code>
<location>/error.jsp</location>
</error-page>
<error-page>
<exception-type>java.lang.Exception</exception-type>
<location>/error.jsp</location>
</error-page>
复制代码
⑤配置安全认证方式:
<security-constraint>
<web-resource-collection>
<web-resource-name>ProtectedArea</web-resource-name>
<url-pattern>/admin/*</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>admin</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
</login-config>
<security-role>
<role-name>admin</role-name>
</security-role>
复制代码
说明:对Servlet(小服务)、Listener(监听器)和Filter(过滤器)等Web组件的配置,Servlet 3规范提供了基于注解的配置方式,能够分别使用@WebServlet、@WebListener、@WebFilter注解进行配置。
补充:若是Web提供了有价值的商业信息或者是敏感数据,那么站点的安全性就是必须考虑的问题。安全认证是实现安全性的重要手段,认证就是要解决“Are you who you say you are?”的问题。认证的方式很是多,简单说来能够分为三类: A. What you know? — 口令 B. What you have? — 数字证书(U盾、密保卡) C. Who you are? — 指纹识别、虹膜识别 在Tomcat中能够经过创建安全套接字层(Secure Socket Layer, SSL)以及经过基本验证或表单验证来实现对安全性的支持。
10九、你的项目中使用过哪些JSTL标签?
答:项目中主要使用了JSTL的核心标签库,包括<c:if>、<c:choose>、<c: when>、<c: otherwise>、<c:forEach>等,主要用于构造循环和分支结构以控制显示逻辑。
说明:虽然JSTL标签库提供了core、sql、fmt、xml等标签库,可是实际开发中建议只使用核心标签库(core),并且最好只使用分支和循环标签并辅以表达式语言(EL),这样才能真正作到数据显示和业务逻辑的分离,这才是最佳实践。
1十、使用标签库有什么好处?如何自定义JSP标签?
答:使用标签库的好处包括如下几个方面:
自定义JSP标签包括如下几个步骤:
Tag/BodyTag/IterationTag
接口(开发中一般不直接实现这些接口而是继承TagSupport/BodyTagSupport/SimpleTagSupport
类,这是对缺省适配模式的应用),重写doStartTag()
、doEndTag()
等方法,定义标签要完成的功能下面是一个自定义标签库的例子。
步骤1 - 标签类源代码TimeTag.java:
package com.jackfrued.tags;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.TagSupport;
public class TimeTag extends TagSupport {
private static final long serialVersionUID = 1L;
private String format = "yyyy-MM-dd hh:mm:ss";
private String foreColor = "black";
private String backColor = "white";
public int doStartTag() throws JspException {
SimpleDateFormat sdf = new SimpleDateFormat(format);
JspWriter writer = pageContext.getOut();
StringBuilder sb = new StringBuilder();
sb.append(String.format("<span style='color:%s;background-color:%s'>%s</span>",
foreColor, backColor, sdf.format(new Date())));
try {
writer.print(sb.toString());
} catch(IOException e) {
e.printStackTrace();
}
return SKIP_BODY;
}
public void setFormat(String format) {
this.format = format;
}
public void setForeColor(String foreColor) {
this.foreColor = foreColor;
}
public void setBackColor(String backColor) {
this.backColor = backColor;
}
}
复制代码
步骤2 - 编写标签库描述文件my.tld:
<?xml version="1.0" encoding="UTF-8" ?>
<taglib xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd" version="2.0">
<description>定义标签库</description>
<tlib-version>1.0</tlib-version>
<short-name>MyTag</short-name>
<tag>
<name>time</name>
<tag-class>com.jackfrued.tags.TimeTag</tag-class>
<body-content>empty</body-content>
<attribute>
<name>format</name>
<required>false</required>
</attribute>
<attribute>
<name>foreColor</name>
</attribute>
<attribute>
<name>backColor</name>
</attribute>
</tag>
</taglib>
复制代码
步骤3 - 在JSP页面中使用自定义标签:
<%@ page pageEncoding="UTF-8"%>
<%@ taglib prefix="my" uri="/WEB-INF/tld/my.tld" %>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/";
%>
<!DOCTYPE html>
<html>
<head>
<base href="<%=basePath%>">
<title>首页</title>
<style type="text/css">
* { font-family: "Arial"; font-size:72px; }
</style>
</head>
<body>
<my:time format="yyyy-MM-dd" backColor="blue" foreColor="yellow"/>
</body>
</html>
复制代码
提示:若是要将自定义的标签库发布成JAR文件,须要将标签库描述文件(tld文件)放在JAR文件的META-INF目录下,能够JDK中的jar工具完成JAR文件的生成,若是不清楚如何操做,能够请教谷歌和百度。
1十一、说一下表达式语言(EL)的隐式对象及其做用。
答:EL的隐式对象包括:pageContext、initParam(访问上下文参数)、param(访问请求参数)、paramValues、header(访问请求头)、headerValues、cookie(访问cookie)、applicationScope(访问application做用域)、sessionScope(访问session做用域)、requestScope(访问request做用域)、pageScope(访问page做用域)。
用法以下所示:
${pageContext.request.method}
${pageContext["request"]["method"]}
${pageContext.request["method"]}
${pageContext["request"].method}
${initParam.defaultEncoding}
${header["accept-language"]}
${headerValues["accept-language"][0]}
${cookie.jsessionid.value}
${sessionScope.loginUser.username}
复制代码
补充:表达式语言的.和[]运算做用是一致的,惟一的差异在于若是访问的属性名不符合Java标识符命名规则,例如上面的accept-language就不是一个有效的Java标识符,那么这时候就只能用[]运算符而不能使用.运算符获取它的值
1十二、表达式语言(EL表达式)支持哪些运算符?
答:除了.和[]运算符,EL还提供了:
11三、Java Web开发的Model 1和Model 2分别指的是什么?
答:Model 1是以页面为中心的Java Web开发,使用JSP+JavaBean技术将页面显示逻辑和业务逻辑处理分开,JSP实现页面显示,JavaBean对象用来保存数据和实现业务逻辑。Model 2是基于MVC(模型-视图-控制器,Model-View-Controller)架构模式的开发模型,实现了模型和视图的完全分离,利于团队开发和代码复用,以下图所示。
11四、Servlet 3中的异步处理指的是什么?
答:在Servlet 3中引入了一项新的技术可让Servlet异步处理请求。有人可能会质疑,既然都有多线程了,还须要异步处理请求吗?答案是确定的,由于若是一个任务处理时间至关长,那么Servlet或Filter会一直占用着请求处理线程直到任务结束,随着并发用户的增长,容器将会遭遇线程超出的风险,这这种状况下不少的请求将会被堆积起来然后续的请求可能会遭遇拒绝服务,直到有资源能够处理请求为止。异步特性能够帮助应用节省容器中的线程,特别适合执行时间长并且用户须要获得结果的任务,若是用户不须要获得结果则直接将一个Runnable对象交给Executor并当即返回便可。
补充:多线程在Java诞生初期无疑是一个亮点,而Servlet单实例多线程的工做方式也曾为其赢得美名,然而技术的发展每每会颠覆咱们不少的认知,就如同当年爱因斯坦的相对论颠覆了牛顿的经典力学通常。事实上,异步处理毫不是Serlvet 3独创,若是你了解Node.js的话,对Servlet 3的这个重要改进就不觉得奇了。
下面是一个支持异步处理请求的Servlet的例子。
import java.io.IOException;
import javax.servlet.AsyncContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet(urlPatterns = {"/async"}, asyncSupported = true)
public class AsyncServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 开启Tomcat异步Servlet支持
req.setAttribute("org.apache.catalina.ASYNC_SUPPORTED", true);
final AsyncContext ctx = req.startAsync(); // 启动异步处理的上下文
// ctx.setTimeout(30000);
ctx.start(new Runnable() {
@Override
public void run() {
// 在此处添加异步处理的代码
ctx.complete();
}
});
}
}
复制代码
11五、如何在基于Java的Web项目中实现文件上传和下载?
答:在Sevlet 3 之前,Servlet API中没有支持上传功能的API,所以要实现上传功能须要引入第三方工具从POST请求中得到上传的附件或者经过自行处理输入流来得到上传的文件,咱们推荐使用Apache的commons-fileupload。 从Servlet 3开始,文件上传变得无比简单,相信看看下面的例子一切都清楚了。
上传页面index.jsp:
<%@ page pageEncoding="utf-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Photo Upload</title>
</head>
<body>
<h1>Select your photo and upload</h1>
<hr/>
<div style="color:red;font-size:14px;">${hint}</div>
<form action="UploadServlet" method="post" enctype="multipart/form-data">
Photo file: <input type="file" name="photo" />
<input type="submit" value="Upload" />
</form>
</body>
</html>
复制代码
支持上传的Servlet:
package com.jackfrued.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
@WebServlet("/UploadServlet")
@MultipartConfig
public class UploadServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 能够用request.getPart()方法得到名为photo的上传附件
// 也能够用request.getParts()得到全部上传附件(多文件上传)
// 而后经过循环分别处理每个上传的文件
Part part = request.getPart("photo");
if (part != null && part.getSubmittedFileName().length() > 0) {
// 用ServletContext对象的getRealPath()方法得到上传文件夹的绝对路径
String savePath = request.getServletContext().getRealPath("/upload");
// Servlet 3.1规范中能够用Part对象的getSubmittedFileName()方法得到上传的文件名
// 更好的作法是为上传的文件进行重命名(避免同名文件的相互覆盖)
part.write(savePath + "/" + part.getSubmittedFileName());
request.setAttribute("hint", "Upload Successfully!");
} else {
request.setAttribute("hint", "Upload failed!");
}
// 跳转回到上传页面
request.getRequestDispatcher("index.jsp").forward(request, response);
}
}
复制代码
11六、服务器收到用户提交的表单数据,究竟是调用Servlet的doGet()仍是doPost()方法?
答:HTML的<form>元素有一个method属性,用来指定提交表单的方式,其值能够是get或post。咱们自定义的Servlet通常状况下会重写doGet()或doPost()两个方法之一或所有,若是是GET请求就调用doGet()方法,若是是POST请求就调用doPost()方法,那为何为何这样呢?咱们自定义的Servlet一般继承自HttpServlet,HttpServlet继承自GenericServlet并重写了其中的service()方法,这个方法是Servlet接口中定义的。HttpServlet重写的service()方法会先获取用户请求的方法,而后根据请求方法调用doGet()、doPost()、doPut()、doDelete()等方法,若是在自定义Servlet中重写了这些方法,那么显然会调用重写过的(自定义的)方法,这显然是对模板方法模式的应用(若是不理解,请参考阎宏博士的《Java与模式》一书的第37章)。固然,自定义Servlet中也能够直接重写service()方法,那么无论是哪一种方式的请求,均可以经过本身的代码进行处理,这对于不区分请求方法的场景比较合适。
11七、JSP中的静态包含和动态包含有什么区别?
答:静态包含是经过JSP的include指令包含页面,动态包含是经过JSP标准动做<jsp:include>包含页面。静态包含是编译时包含,若是包含的页面不存在则会产生编译错误,并且两个页面的"contentType"属性应保持一致,由于两个页面会合二为一,只产生一个class文件,所以被包含页面发生的变更在包含它的页面更新前不会获得更新。动态包含是运行时包含,能够向被包含的页面传递参数,包含页面和被包含页面是独立的,会编译出两个class文件,若是被包含的页面不存在,不会产生编译错误,也不影响页面其余部分的执行。代码以下所示:
<%-- 静态包含 --%>
<%@ include file="..." %>
<%-- 动态包含 --%>
<jsp:include page="...">
<jsp:param name="..." value="..." />
</jsp:include>
复制代码
11八、Servlet中如何获取用户提交的查询参数或表单数据?
答:能够经过请求对象(HttpServletRequest)的getParameter()方法经过参数名得到参数值。若是有包含多个值的参数(例如复选框),能够经过请求对象的getParameterValues()方法得到。固然也能够经过请求对象的getParameterMap()得到一个参数名和参数值的映射(Map)。
11九、Servlet中如何获取用户配置的初始化参数以及服务器上下文参数?
答:能够经过重写Servlet接口的init(ServletConfig)方法并经过ServletConfig对象的getInitParameter()方法来获取Servlet的初始化参数。能够经过ServletConfig对象的getServletContext()方法获取ServletContext对象,并经过该对象的getInitParameter()方法来获取服务器上下文参数。固然,ServletContext对象也在处理用户请求的方法(如doGet()方法)中经过请求对象的getServletContext()方法来得到。
120、如何设置请求的编码以及响应内容的类型?
答:经过请求对象(ServletRequest)的setCharacterEncoding(String)方法能够设置请求的编码,其实要完全解决乱码问题就应该让页面、服务器、请求和响应、Java程序都使用统一的编码,最好的选择固然是UTF-8;经过响应对象(ServletResponse)的setContentType(String)方法能够设置响应内容的类型,固然也能够经过HttpServletResponsed对象的setHeader(String, String)方法来设置。
说明:如今若是还有公司在面试的时候问JSP的声明标记、表达式标记、小脚本标记这些内容的话,这样的公司也不用去了,其实JSP内置对象、JSP指令这些东西基本上均可以忘却了。
12一、解释一下网络应用的模式及其特色。
答:典型的网络应用模式大体有三类:B/S、C/S、P2P。其中B表明浏览器(Browser)、C表明客户端(Client)、S表明服务器(Server),P2P是对等模式,不区分客户端和服务器。B/S应用模式中能够视为特殊的C/S应用模式,只是将C/S应用模式中的特殊的客户端换成了浏览器,由于几乎全部的系统上都有浏览器,那么只要打开浏览器就可使用应用,没有安装、配置、升级客户端所带来的各类开销。P2P应用模式中,成千上万台彼此链接的计算机都处于对等的地位,整个网络通常来讲不依赖专用的集中服务器。网络中的每一台计算机既能充当网络服务的请求者,又对其它计算机的请求做出响应,提供资源和服务。一般这些资源和服务包括:信息的共享和交换、计算资源(如CPU的共享)、存储共享(如缓存和磁盘空间的使用)等,这种应用模式最大的阻力是安全性、版本等问题,目前有不少应用都混合使用了多种应用模型,最多见的网络视频应用,它几乎把三种模式都用上了。
补充:此题要跟"电子商务模式"区分开,由于有不少人被问到这个问题的时候立刻想到的是B2B(如阿里巴巴)、B2C(如当当、亚马逊、京东)、C2C(如淘宝、拍拍)、C2B(如威客)、O2O(如美团、饿了么)。对于这类问题,能够去百度上面科普一下。
12二、什么是Web Service(Web服务)?
答:从表面上看,Web Service就是一个应用程序,它向外界暴露出一个可以经过Web进行调用的API。这就是说,你可以用编程的方法透明的调用这个应用程序,不须要了解它的任何细节,跟你使用的编程语言也没有关系。例如能够建立一个提供天气预报的Web Service,那么不管你用哪一种编程语言开发的应用均可以经过调用它的API并传入城市信息来得到该城市的天气预报。之因此称之为Web Service,是由于它基于HTTP协议传输数据,这使得运行在不一样机器上的不一样应用无须借助附加的、专门的第三方软件或硬件,就可相互交换数据或集成。
补充:这里必需要说起的一个概念是SOA(Service-Oriented Architecture,面向服务的架构),SOA是一种思想,它将应用程序的不一样功能单元经过中立的契约联系起来,独立于硬件平台、操做系统和编程语言,使得各类形式的功能单元可以更好的集成。显然,Web Service是SOA的一种较好的解决方案,它更多的是一种标准,而不是一种具体的技术。
12三、概念解释:SOAP、WSDL、UDDI。
答:
提示:关于Web Service的相关概念和知识能够在W3CSchool上找到相关的资料。
12四、Java规范中和Web Service相关的规范有哪些?
答:Java规范中和Web Service相关的有三个:
12五、介绍一下你了解的Java领域的Web Service框架。
答:Java领域的Web Service框架不少,包括Axis2(Axis的升级版本)、Jersey(RESTful的Web Service框架)、CXF(XFire的延续版本)、Hessian、Turmeric、JBoss SOA等,其中绝大多数都是开源框架。
提示:面试被问到这类问题的时候必定选择本身用过的最熟悉的做答,若是以前没有了解过就应该在面试前花一些时间了解其中的两个,并比较其优缺点,这样才能在面试时给出一个漂亮的答案。
本文永久更新地址:github.com/nnngu/Learn…