俗话说金三银四金九银十,这不,我昨天就跑去面试了一家公司,然后感觉自己萌萌哒,什么都不会,开口就要一万,然后别人二话不说,上来就是一套试题,结果懵逼了吧,期望薪资都不敢写了,好吧,是在下放肆了。总结一下面试题,后续面试遇到的题都会记录下来,闲来无事翻看一下。
一.tomcat优化经验
1.把jsp提前编辑成servlet,有多余物理内存的情况,加大tomcat实用的jvm的内存。
2.利用缓存和压缩。用Nginx作为缓存服务器,将图片、css、js文件进行缓存,减少后端tomcat的访问。
开启gzip压缩(交给前端Nginx完成,压缩文本、图片等)
3.采用集群。单个服务器的性能是有限的,实现横向扩展,组件tomcat集群,采用Nginx作为请求分流的服务器,后端多个tomcat共享session来协同工作。
4.优化tomcat参数,修改conf/server.xml文件,主要优化连接配置,关闭客户端dns查询。
二.servlet生命周期,servlet和CGI的区别
servlet容器创建servlet类的实例;
servlet通过调用init()方法进行初始化;
调用service()方法来处理客户端的请求;
调用destroy()方法结束;
最后servlet由JVM的垃圾回收器进行垃圾回收。
CGI(Common Gateway Interface通用网关接口)程序来实现数据在Web上的传输,使用的是如Perl这样的语言编写的,它对于客户端作出的每个请求,必须创建CGI程序的一个新实例,这样占用大量的内存资源。由此才引入了Servlet技术。
Servlet是一个用java编写的应用程序,在服务器上运行,处理请求信息并将其发送到客户端。对于客户端的请求,只需要创建Servlet的实例一次,因此节省了大量的内存资源。Servlet在初始化后就保留在内存中,因此每次作出请求时无需加载。
CGI应用开发比较困难,因为它要求程序员有处理参数传递的知识,这不是一种通用的技能。CGI不可移植,为某一特定平台编写的CGI应用只能运行于这一环境中。每一个CGI应用存在于一个由客户端请求激活的进程中,并且在请求被服务后被卸载。这种模式将引起很高的内存、CPU开销,而且在同一进程中不能服务多个客户。
Servlet提供了Java应用程序的所有优势——可移植、稳健、易开发。使用Servlet Tag技术,Servlet能够生成嵌于静态HTML页面中的动态内容。
Servlet对CGI的最主要优势在于一个Servlet被客户端发送的第一个请求激活,然后它将继续运行于后台,等待以后的请求。每个请求将生成一个新的线程,而不是一个完整的进程。多个客户能够在同一个进程中同时得到服务。一般来说,Servlet进程只是在Web Server卸载时被卸载。
三.servlet API中forward()和redirect()的区别
1.从url来说
forward是服务器请求资源,服务器直接访问目标地址的URL,把那个URL的响应内容读取过来,然后把这些内容再发给浏览器.浏览器根本不知道服务器发送的内容从哪里来的,所以它的地址栏还是原来的地址。
redirect是服务端根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址.所以地址栏显示的是新的URL.所以redirect等于客户端向服务器端发出两次request,同时也接受两次response。
2.从数据共享来说
forward:转发页面和转发到的页面可以共享request里面的数据。
redirect:不能共享数据。
redirect不仅可以重定向到当前应用程序的其他资源,还可以重定向到同一个站点上的其他应用程序中的资源,甚至是使用绝对URL重定向到其他站点的资源。
forward,方法只能在同一个Web应用程序内的资源之间转发请求.forward 是服务器内部的一种操作.
redirect 是服务器通知客户端,让客户端重新发起请求。
3.从运用地方来说
forward:一般用于用户登陆的时候,根据角色转发到相应的模块。
redirect:一般用于用户注销登陆时返回主页面和跳转到其它的网站等。
4.从效率来说
forward:高。
redirect:低。
四.request.getParameter()和request.getAttribute()的区别
首先request对象代表客户端的一次请求,可以用它来存储客户端请求的一些参数。
getParameter()方法
该方法是用于客户端通过get或者post传递过来的参数,它的返回值类型永远是是字符串类型
注意:这里强调的是客户端请求时,是客户端发送给服务器的参数,这个赋值动作是有客户端完成的。
getAttribute()方法
该方法用于获取request对象中的attribute值,这个值是之前在服务器端才放入到request对象里的,即通过setAttribute(key ,value)放入request
注意:这里强调的是attribute中的值是在服务器端赋予的,而非客户端送过来的。
其实getParameter()和getAttribute()最简单的两点区别就是
1)赋值方式不一样,前者是客户端如浏览器端将请求参数值送给服务器端,而后者则是在请求到达服务器端之后,在服务器进行存放进去
2)两者的返回值类型不一样,前者永远返回字符串,后者返回任意对象。
五.jsp有哪些动作?作用分别是什么
JSP共有以下6种基本动作 作用如下:
jsp:include:在页面被请求的时候引入一个文件。
includ两种方法的实现 :
有两种实现方法,动态,静态。
动态:用于包含动态页面,并且可以随时检查页面的变化,采用jsp:include动作可以实现,例如:
<jsp:includepage="***.jsp" flush="true"/>
静态,适合于包含静态页面,不检查页面的变化,采用include伪码实现
<%@include file="***.html"%>
jsp:useBean:寻找或者实例化一个JavaBean。
jsp:setProperty:设置JavaBean的属性。
jsp:getProperty:输出某个JavaBean的属性。
jsp:plugin:根据浏览器类型为Java插件生成OBJECT或EMBED标记。
jsp:forward:把请求转到一个新的页面。
六.jsp中动态include和静态include的区别
1.静态包含指令<%@include file=“fileurl”%>
两个jsp页面的<%@page contentType=“text/html;charset=gbk”%>应该保持一致
不能通过fileurl向被包含的jsp页面传递参数,因为此静态包含是发生在jsp页面转换为servlet的转换期间,此时的参数是服务器端设置的死的参数,完全没有经过客户端,这种参数是没有意义的,如<%@include file=“fileurl?user=admin”%>,而且此时会报错。
包含的jsp页面与被包含的jsp页面共用一个request内置对象。
比如说在客户端访问包含页面时地址栏后面直接加上参数后传递,这种形式的传参是客户端送来的,两个页面都能够访问此参数。我们可以通过这两个页面合成的servlet中可以看到有传递的参数成为servlet的成员变量。
包含的jsp页面与被包含的jsp页面最好没有重复的html标签。否则会发生覆盖现象。
2.动态包含<jsp :include page=“a.jsp”/>与静态包含<%@include file=“fileurl”%>的区别
动态包含用的元素是page,而且有两种形式。静态包含用的是file,只有一种形式。
生成的文件不同,静态的包含是将两个jsp文件二合一,生成一个以包含页面命名的servlet和class文件,动态包含的两个jsp文件各自生成自己的servlet和class文件。
传参方式一:<jsp:include page=“a.jsp?param=123”/>时被包含的jsp页面是可以访问该参数的。
传参方式二:
<jsp:include page=“a.jsp”>
<jsp:param name=“” value=“”>
<jsp:param name=“” value=“”>
</ jsp:include >
3.在客户端访问包含页面时地址栏后面直接加上参数后传递,这种形式的传参是客户端送来的,但是这两个页面的request对象不是同一个,因为3中已经说了包含的页面可以向被包含的页面传递参数,所以被包含的request对象含的参数个数应该大于等于包含页面的参数个数的。所以它们各有各的request对象。而且被包含的jsp页面可以访问传到包含页面的参数。
4. 动态包含只有在执行到它的时候才加载,所以它才叫动态包含。
5.另一种简答说法:
动态INCLUDE用jsp:include动作实现<jsp:include page = included.jsp flush = "true">它总会检查所含文件中的变化,适用于动态页面并且可以带参数。
静态INCLUDE用include伪码实现,定不会检查所含文件的变化,适用于包含静态页面<%@include file=included.html%>
七.在web应用并发过程中遇到输出某种编码的字符,如何输出某种编码的字符串?
/**
* 对传入的str字符串进行转换
* @Param str 要转换的字符串
*@return 转码后的字符串
*/
public String translate (String str) {
String tempStr = "";
try {
//把"ISO-8859-1"转化为“GBK”编码
tempStr = tempStr.trim();
}catch (Exception e) {
System.err.println(e.getMessage());
}
return tempStr;
}
八.jsp四种范围
JSP的四种范围,分别为:page、request、session、application。
application:
全局作用范围,整个应用程序共享,就是在部署文件中的同一个webApp共享,生命周期为:应用程序启动到停止。
session:
会话作用域,当用户首次访问时,产生一个新的会话,以后服务器就可以记住这个会话状态。生命周期:会话超时,或者服务器端强制使会话失效。
request:
请求作用域,就是客户端的一次请求。
page:
一个JSP页面。
九.j2ee是技术、平台还是框架?
J2ee本身是一个标准,应用于企业分布式开发的标准平台;
j2ee也是一个框架,包括JDBC、EJB、JNDI、JMS、JTA 、RMI等技术。
名词解析:
JDBC: 是一种执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组由java语言编写的类和接口组成,简单的说JDBC可做三件事情:与数据库建立连接、发
送SQL语句、处理结果。
EJB: 是一种服务器端组件体系结构,简化了JAVA开发企业级分布式组件应用程序的过程,EJB是J2ee的一部分,在J2ee里,EJB称为JAVA企业bean,是java的核心代码,
分别是会话(session) bean,实体(entity)bean,消息驱动(MessageDriver)bean。简单点说,就是别人已经写好了一些javabean,你只需要去学习如何应用现成的框
架去更快更快捷的开发。
JNDI:Java命名服务目录,提供一个目录系统,让其他各地的应用程序在上面留下自己的索引,从而快速的定位和查询分布式应用系统。
JMS:(Java Message Server)Java消息服务,提供各个应用程序之间的通讯,包括点对点的广播。
JTA:(Java Transaction Api) JAVA事务服务,提供各种分布式事务服务,用于程序只需调用现成的接口就行。
RMI:对象请求中介协议,应用于通过远程调用服务,例如,一台计算机上运行一个程序,它提供股票分析服务,我们可以在本地计算机上直接调用它的服务,当然,这要通过一定的规范才能实现在异构系统之间进行通讯, RMI是Java特有的。
十.jsp页面如何被执行?jsp效率比servlet低吗?
当客户端向一个JSP页面发出请求时,Web Container将JSP转化成Servlet的源代码(只在第一次请求时),然后编译转化后的Servlet并加载到内存中执行,执行的结果Response到客户端。
JSP只在第一次执行的时候会转化为Servlet,以后每次执行Web容器都是直接执行编译后的Servlet,所以JSP和Servlet只是在第一次执行的时候不一样,JSP慢一点,以后的执行都是相同的。
十一.如果jsp表单元素的值为空,如何避免null出现在页面上
pubilc static String formatString(String src){
if(src == null)
src == "";
return src;
}
这个没有找到比较好的答案,有知道的大神请在评论留下言~~~
十二.在servlet和jsp之间能共享session对象吗?
jsp最后都是要变成servlet才执行的 所以 它们没有区别 能共享
request.getSession().setAttribute("username", "admin");
=============================================================
HttpSession session = request.getSession(true);
session.putValue(“variable”,”value”);
十三.EL表达式功能?为什么要用EL表达式?
1.获取数据:
EL表达式主要用于替换JSP页面中的脚本表达式,以从各种类型的web域 中检索java对象、获取数据。(某个web域 中的对象,访问javabean的属性、访问list集合、访问map集合、访问数组)
2.执行运算:
利用EL表达式可以在JSP页面中执行一些基本的关系运算、逻辑运算和算术运算,以在JSP页面中完成一些简单的逻辑运算。${user==null}
3.获取web开发常用对象
EL 表达式定义了一些隐式对象,利用这些隐式对象,web开发人员可以很轻松获得对web常用对象的引用,从而获得这些对象中的数据。
4.调用Java方法
EL表达式允许用户开发自定义EL函数,以在JSP页面中通过EL表达式调用Java类的方法。
使用EL表达式获取数据语法:“${标识符}”EL表达式语句在执行时,会调用pageContext.findAttribute方法,用标识符为关键字,分别从page、requestsession、application四个域中查找相应的对象,找到则返回相应对象,找不到则返回”” (注意,不是null,而是空字符串)。
示例:${user}
1.代码量小,并且不需要使用尖括号;
2.支持从pageContext,request,session,application中取值,它会自动检查四个作用域,不需要特别指定;
3.如果变量不存在,会输出空字符串"",而不是null,省去了手工判断的工作。
十四.JSTL的功能,为什么要用JSTL?
1.简化了JSP的开发,减少了JSP中的scriptlet代码数量。JSP主要用于显示业务逻辑代码处理以后的数据结果,不可避免地会使用循环、布尔逻辑、数据格式转换等语句,如果使用JSP脚本的for、if或其他语句的话,不仅需要导入必要的包,而且每个类似的地方都要写相同的代码,非常不利于维护。使用JSTL就可以大大简化这方面的开发。
2.在应用程序服务器之间提供了一致的接口,最大程度地提高了Web应用在各应用服务器之间的移植。JSTL属于JavaEE规范以内,所有符合规范的Web容器都必须支持JSTL,所以将Web应用程序进行移植完全不存在的问题。反过来,如果是其他的第三方标签库,就需要提供另外的资源才能进行移植。
3.JSTL的开源性决定了它具有很有的扩展性。JSTL的各类标签已经涵盖了几乎所有Web应用程序的常用功能,如果这些功能还不能满足开发者需求的话,可以对它本身的实现类进行继承扩展,既利用了JSTL良好的设计,又可以满足特定的需求。
(就是啊,为什么要用JSTL啊,我工作一年都没有遇到过这个东西)
十五.说说自动登录功能的编码实现
面试题叫说说自动登录功能的编码实现,我百度了一下,都是一堆代码,这让我怎么说???好吧,我直接复制粘贴过来找的答案。。。
通常我们登录某网站,会有选择保存几天,或者是几个星期不用登录,之后输入该网站地址无需登录直接进入主页面,那么这就叫做自动登录,怎么实现呢,下面我以一个小例子来演示一下
登录页面:login.jsp
- <span style="font-size: medium;"><%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
- <html>
- <head>
- </head>
- <body>
- <form action="login.do">
- 用户名:<input type="text" name="username" ><br/>
- 密 码:<input type="text" name="password" ><br/>
- <input type="submit" value="登录" /><select name="saveTime">
- <option value="366">一年</option>
- <option value="183">半年</option>
- <option value="30">一个月</option>
- <option value="7">一周</option>
- </select>
- </form>
- </body>
- </html>
- </span>
那么从上面可看到可选择保存自动登录的期限,可以是一年,半年,一个月,一周,当然这都是以天为单位的
服务类:LoginService
- <span style="font-size: medium;">package com.login.servlet;
- public class LoginService {
- public static boolean login(String username, String password) {
- if ("admin".equals(username) && "123456".equals(password)) {
- return true;
- } else {
- return false;
- }
- }
- }
- </span>
业务处理servlet:LoginServlet
- <span style="font-size: medium;">package com.login.servlet;
- import java.io.IOException;
- import javax.servlet.ServletException;
- import javax.servlet.http.Cookie;
- import javax.servlet.http.HttpServlet;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- public class LoginServlet extends HttpServlet {
- public void doGet(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- this.doPost(request, response);
- }
- public void doPost(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- String username=request.getParameter("username");
- String password=request.getParameter("password");
- String savetime=request.getParameter("saveTime");
- if(LoginService.login(username, password)){
- if(null!=savetime&&!savetime.isEmpty()){
- int saveTime=Integer.parseInt(savetime);//这里接受的表单值为天来计算的
- int seconds=saveTime*24*60*60;
- Cookie cookie = new Cookie("user", username+"=="+password);
- cookie.setMaxAge(seconds);
- response.addCookie(cookie);
- }
- request.setAttribute("username",username);
- request.getRequestDispatcher("/main.jsp").forward(request,response);
- }else{
- request.getRequestDispatcher("/index.jsp").forward(request,response);
- }
- }
- }
- </span>
看清上面处理Cookie的方式步骤:其实这是为第一次登录该网站时【前提是选择了保存自动登录期限时间】处理Cookie,只要这一步处理成功,以后都无需经过这个Servlet因为我们接下来要在请求到达前,从Cookie中取出我们的用户名和密码,这样的话就需要一个过滤器了
- <span style="font-size: medium;">package com.login.servlet;
- 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.http.Cookie;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- public class IndexFilter implements Filter {
- public void destroy() {
- // TODO Auto-generated method stub
- }
- public void doFilter(ServletRequest arg0, ServletResponse arg1,
- FilterChain arg2) throws IOException, ServletException {
- HttpServletRequest request = (HttpServletRequest) arg0;
- HttpServletResponse response = (HttpServletResponse) arg1;
- Cookie[] cookies = request.getCookies();
- String[] cooks = null;
- String username = null;
- String password = null;
- if (cookies != null) {
- for (Cookie coo : cookies) {
- String aa = coo.getValue();
- cooks = aa.split("==");
- if (cooks.length == 2) {
- username = cooks[0];
- password = cooks[1];
- }
- }
- }
- if (LoginService.login(username, password)) {
- request.getSession().setAttribute("username",username);
- response.sendRedirect("main.jsp");
- //request.getRequestDispatcher("/main.jsp").forward(request, response);
- }else{
- arg2.doFilter(request,response );
- }
- }
- public void init(FilterConfig arg0) throws ServletException {
- // TODO Auto-generated method stub
- }
- }
- </span>
我这里所说的请求到达之前,不是指的某个路径匹配的servlet而是指的就是在输入网址到达登录页面前就要进行自动登录的处理,那么web.xml中应该怎么配置呢
- <span style="font-size: medium;"><?xml version="1.0" encoding="UTF-8"?>
- <web-app version="2.5"
- xmlns="http://java.sun.com/xml/ns/javaee"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
- http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
- <filter>
- <filter-name>loginFilter</filter-name>
- <filter-class>com.login.servlet.IndexFilter</filter-class>
- </filter>
- <filter-mapping>
- <filter-name>loginFilter</filter-name>
- <url-pattern>/index.jsp</url-pattern>
- </filter-mapping>
- <servlet>
- <servlet-name>LoginServlet</servlet-name>
- <servlet-class>com.login.servlet.LoginServlet</servlet-class>
- </servlet>
- <servlet-mapping>
- <servlet-name>LoginServlet</servlet-name>
- <url-pattern>/login.do</url-pattern>
- </servlet-mapping>
- <welcome-file-list>
- <welcome-file>login.jsp</welcome-file>
- </welcome-file-list>
- </web-app>
- </span>
看见了没有,上面的filter匹配路径只是针对一个页面,与通常写/*匹配所有请求到达之前是不一样的写法哦
主页面:main.jsp
- <span style="font-size: medium;"><%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
- <html>
- <head>
- <title>My JSP 'maiin.jsp' starting page</title>
- </head>
- <body>
- 登录成功,欢迎${username}的到来
- </body>
- </html>
- </span>
输入地址:http://localhost:8080/WebApp/login.jsp,出现登录页面
然后输入:admin,123456 ,选择一个保存日期
这样第一次登录成功之后,是经由LoginServlet处理了,由于选择了日期,所以Cookie中保存了用户信息,所以之后再输入同样地址后,不会出现登录页面,就不再经过LoginServlet处理【因为LoginServlet处理的是登陆页面上登录按钮请求的】,而直接提前交由IndexFilter处理,直接进入主页面。
十六.如何防止表单重复提交?
1、js禁掉提交按钮。
表单提交后使用Javascript使提交按钮disable。这种方法防止心急的用户多次点击按钮。但有个问题,如果客户端把Javascript给禁止掉,这种方法就无效了。
2、使用Post/Redirect/Get模式。
在提交后执行页面重定向,这就是所谓的Post-Redirect-Get (PRG)模式。简言之,当用户提交了表单后,你去执行一个客户端的重定向,转到提交成功信息页面。
这能避免用户按F5导致的重复提交,而其也不会出现浏览器表单重复提交的警告,也能消除按浏览器前进和后退按导致的同样问题。
3.在session中存放一个特殊标志。
在服务器端,生成一个唯一的标识符,将它存入session,同时将它写入表单的隐藏字段中,然后将表单页面发给浏览器,用户录入信息后点击提交,在服务器端,获取表单中隐藏字段的值,与session中的唯一标识符比较,相等说明是首次提交,就处理本次请求,然后将session中的唯一标识符移除;不相等说明是重复提交,就不再处理。
这使你的web应用有了更高级的XSRF保护。
4.使用header函数转向
除了上面的方法之外,还有一个更简单的方法,那就是当用户提交表单,服务器端处理后立即转向其他的页面,代码如下所示。
if (isset($_POST['action']) && $_POST['action'] == 'submitted') {
//处理数据,如插入数据后,立即转向到其他页面
header('location:submits_success.php');
}
这样,即使用户使用刷新键,也不会导致表单的重复提交,因为已经转向新的页面,而这个页面脚本已经不理会任何提交的数据了。
5.在数据库里添加约束。
在数据库里添加唯一约束或创建唯一索引,防止出现重复数据。这是最有效的防止重复提交数据的方法。
十七.tomcat根目录下有哪些文件?
1、bin目录
主要是用来存放tomcat的命令,主要有两大类,一类是以.sh结尾的(linux命令),另一类是以.bat结尾的(windows命令)。
很多环境变量的设置都在此处,例如可以设置JDK路径、TOMCAT路径,startup 用来启动tomcat,shutdown 用来关闭tomcat修改catalina可以设置tomcat的内存。
2、conf目录
主要是用来存放tomcat的一些配置文件。
3、lib目录
主要用来存放tomcat运行需要加载的jar包。
4、logs目录
用来存放tomcat在运行过程中产生的日志文件,非常重要的是在控制台输出的日志。(清空不会对tomcat运行带来影响)
5、temp目录
用来让用户存放tomcat在运行过程中产生的临时文件。(清空不会对tomcat运行带来影响)
6、webapps目录
用来存放应用程序,当tomcat启动时会去加载webapps目录下的应用程序。可以以文件夹、war包、jar包的形式发布应用。
7、work目录
用来存放tomcat在运行时的编译后文件,例如JSP编译后的文件。清空work目录,然后重启tomcat,可以达到清除缓存的作用。
这次的总结就写到这,哦不,是抄到这。