Jsp与Servlet技术
收集的网上一些关于HttpSession常见问题:
1.一个常见的误解是以为session在有客户端访问时就被创建,然而事实是直到某server端程序调用 HttpServletRequest.getSession(true)这样的语句时才被创建,注意如果JSP没有显示的使用 <% @page session="false"%> 关闭session,则JSP文件在编译成Servlet时将会自动加上这样一条语句 HttpSession session = HttpServletRequest.getSession(true);这也是JSP中隐含的 session对象的来历。由于session会消耗内存资源,因此,如果不打算使用session,应该在所有的JSP中关闭它。
2.Session删除的时间是:
1)Session超时:超时指的是连续一定时间服务器没有收到该Session所对应客户端的请求,并且这个时间超过了服务器设置的Session超时的最大时间。
2)程序调用HttpSession.invalidate()
3)服务器关闭或服务停止
3.session的id是从哪里来的,sessionID是如何使用的:当客户端第一次请求session对象时候,服务器会为客户端创建一个session,并将通过特殊算法算出一个session的ID,用来标识该session对象,当浏览器下次(session继续有效时)请求别的资源的时候,浏览器会偷偷地将sessionID放置到请求头中,服务器接收到请求后就得到该请求的sessionID,服务器找到该id的session返还给请求者(Servlet)使用。一个会话只能有一个session对象,对session来说是只认id不认人
4.如何做到在浏览器关闭时删除session
严格的讲,做不到这一点。可以做一点努力的办法是在所有的客户端页面里使用javascript代码window.oncolose来监视浏览器的关闭动作,然后向服务器发送一个请求来删除session。但是对于浏览器崩溃或者强行杀死进程这些非常规手段仍然无能为力
5.跨应用程序的session共享
常常有这样的情况,一个大项目被分割成若干小项目开发,为了能够互不干扰,要求每个小项目作为一个单独的web应用程序开发,可是到了最后突然发现某几个小项目之间需要共享一些信息,或者想使用session来实现SSO(single sign on),在session中保存login的用户信息,最自然的要求是应用程序间能够访问彼此的session。
然而按照Servlet规范,session的作用范围应该仅仅限于当前应用程序下,不同的应用程序之间是不能够互相访问对方的session的。各个应用服务器从实际效果上都遵守了这一规范,但是实现的细节却可能各有不同,因此解决跨应用程序session共享的方法也各不相同。
首先来看一下Tomcat是如何实现web应用程序之间session的隔离的,从 Tomcat设置的cookie路径来看,它对不同的应用程序设置的cookie路径是不同的,这样不同的应用程序所用的session id是不同的,因此即使在同一个浏览器窗口里访问不同的应用程序,发送给服务器的session id也可以是不同的。
6.访问*.html的静态资源因为不会被编译为Servlet,也就不涉及session的问题
7.有个HttpSessionListener是怎么回事
你可以创建这样的listener去监控session的创建和销毁事件,使得在发生这样的事件时你可以做一些相应的工作。注意是session的创建和销毁动作触发listener,而不是相反。类似的与HttpSession有关的listener还有 HttpSessionBindingListener,HttpSessionActivationListener和 HttpSessionAttributeListener
10.
3.J3.JSP的常用指令
isErrorPage(是否能使用Exception对象),isELIgnored(是否忽略表达式)
三个编译指令为:page、include、taglib。注意与jsp行为的区别,这三个指令值在编译期间的,动作或者行为是在运行期间。
1:page指令:(用来指明该jsp页面的一些属性)通常位于jsp页面的顶端,同一个页面可以有多个page指令。在page指令的属性中,IsErrorPage属性,设置本 JSP 页面是否为错误处理程序。如果该页面本身己是错误处理页面,则无须使用 errorPage 属性。errorPage属性表示出现错误以后跳转到哪一个网页。
2:include指令,使用 include 指令,可以将一个外部文件嵌入到当前 JSP 文件中,同时解析这个页面中的 JSP 语句(如果有的话)。这是个静态的 include 语旬,不会检查所包含 JSP 页面的变化。如果被嵌入的文件经常需要改变,建议使用<jsp:include>操作指令,因为它是动态的 include 语句。
3:taglib指令,该指令用来指明jsp页面内使用的jsp标签库,有两个属性uri(类库地址)和prefix;
4、什么情况下调用doGet()和doPost()?
Jsp页面中的form标签里的method属性为get时调用doGet(),为post时调用doPost()。
一般的运用都会在doget方法中调用doPost方法,那样不管是对于get请求方式还是post请求方式都可以用doPost()方法处理。
1、通过表单提交到的servlet,看form的method是get还是post
2、通过链接<a href....>访问的servlet,doGet
3、直接在IE地址栏中键入的servlet地址,doGet
1、get是吧参数数据队列加到提交表单的Action属性所指的url中,值和表单内各个字段--对应,在url中可以看到。
2、Get是不安全的,因为在传输过程,数据被放在请求的URL章,而如今现有的很多服务器,代理服务器或者用户代理都会将请求URL记录到日志文件中,然后放在某个地方,这样就可能会有一些隐私的信息被第三方看到
3、Get传输的数据量小,这主要是因为受URL长度限制;而Post方式提交,所以在上传文件只能使用Post
4、servlet的生命周期
(在继承HttpServlet几类的时候,其实可以说明什么都不用写,因为HttpServlet是一个抽象类,里面没有抽象方法要求我们必须实现,而是对对我们常用的doGet,doPost方法进行了简单的定义,我们要写自己的Servlet,就要继承HttpServlet类,然后显示的定义和httpServlet中类一直方法签名进行覆盖,在httpServlet类中的service方法会通过判断请求的是get还是post方法,然后调用doget方法还是dopost方法,因此我们也可以直接覆盖HttpServlet中的service方法,这要不管什么什么请求都可以用一个方法来解决掉,忽略了get和post方法。在HttpServlet类的父类是一个GenericServlet,该类就与servlet的初始化关系比较大了,该类中定义init()方法,service方法,destroy()方法,我们在自己的servlet中可以也可以显示覆盖这几个方法,这几个方法被上层调用的顺序是先调用init()方法,然后是调用servcie方法,最后调用destroy()方法,我们可以在这几个方法中写入自己的方法,以决定调用每一个servlet之前或者销毁之前都做什么样的动作)
web容器加载servlet(这里所说的servlet从GenericServlet方法开始说起,之后子类都属于该个servlet),生命周期开始。通过调用servlet的init()方法进行servlet的初始化。通过调用service()方法实现,根据请求的不同调用不同的do***()方法。结束服务,web容器调用servlet的destroy()方法。
Servlet生命周期分为三个阶段:
1,初始化阶段 调用init()方法
2,响应客户请求阶段 调用service()方法
3,终止阶段 调用destroy()方法(在这儿是销毁的时候调用destroy方法进行关闭资源等,而不是调用destroy()方法就可以销毁servlet实例,具体怎么销毁,我暂时不知道,有可能该servlet实例长时间不用的话容器直接交给虚拟机销毁)
一个servlet被载入内存以后,除非手动销毁或者关闭服务器,否则是不会被销毁的。
5、如何现实servlet的单线程模式
1:如果是通过jsp实现servlet单线程,则可以通过如下设置
<%@ page isThreadSafe=”false”%>,(记忆:之所以是false,是因为此时不用sychronized修饰每一个servlet对象的service方法了,所以就不是线程安全的)此时该servlet方法继承SimpleThreadModel接口,该接口是一个空接口,实现了该接口的servlet容器能保证只有一个线程调用该servlet的service方法,是保证servlet一次只能有一个请求,但是由于service方法都是线程私有,这样设计的目的是为了只有一个线程调用service方法,则在service中调用的成员属性就不会出现线程被两个线程同时更改的效果,此时达到加syschronized的目的(这样也就不用加锁了,节省了开支),但是在让一个servlet同一时刻只处理一个servlet,这样严重影响了容器的性能,所以会创建很多个继承了SimpleThreadModel的servlet的多个实例,然后存入servlet实例池,才能提高性能,所以这样的servlet并不是单例的。
2:Servlet容器默认是只创建一个servlet对象,:多个线程可以同时调用一个实例的service方法,所以在servlet中一般是不要用到成员属性,(要用的话就要加锁,这种事最安全的,继承SimpleThreadModel被认为是不安全的,因为他不加锁同步)。
3:servlet不是线程安全的;用到成员属性时需要加锁同步。
6、页面间对象传递的方法
request,session,application,cookie等
Request,session,application都是在服务器端传值,而cookie是在客户端和服务器端传值。
7、四种会话跟踪技术
1:(保存用户和服务器之间会话状态及信息技术叫会话跟踪技术),我们之前所说的只有三种,隐藏表单,url重定向,cookie,是因为我们用这三种来传输sessionid,他们的目的也是为了跟踪技术,如果没有session,他们也能一定程度上的实现跟踪;所以说跟踪技术其实是四种,cookie,url重定向,隐藏表单,session;
8、Request对象的主要方法:
setAttribute(String name,Object):设置名字为name的request的参数值
getAttribute(String name):返回由name指定的属性值
getAttributeNames():返回request对象所有属性的名字集合,结果是一个枚举的实例
getCookies():返回客户端的所有Cookie对象,结果是一个Cookie数组
getCharacterEncoding():返回请求中的字符编码方式
getContentLength():返回请求的Body的长度
getHeader(String name):获得HTTP协议定义的文件头信息
getHeaders(String name):返回指定名字的request Header的所有值,结果是一个枚举的实例
getHeaderNames():返回所以request Header的名字,结果是一个枚举的实例
getInputStream():返回请求的输入流,用于获得请求中的数据
getMethod():获得客户端向服务器端传送数据的方法
getParameter(String name):获得客户端传送给服务器端的有name指定的参数值
getParameterNames():获得客户端传送给服务器端的所有参数的名字,结果是一个枚举的实例
getParameterValues(String name):获得有name指定的参数的所有值
getProtocol():获取客户端向服务器端传送数据所依据的协议名称
getQueryString():获得查询字符串
getRequestURI():获取发出请求字符串的客户端地址
getRemoteAddr():获取客户端的IP地址
getRemoteHost():获取客户端的名字
getSession([Boolean create]):返回和请求相关Session
getServerName():获取服务器的名字
getServletPath():获取客户端所请求的脚本文件的路径
getServerPort():获取服务器的端口号
removeAttribute(String name):删除请求中的一个属性
9、Servlet执行时一般实现哪几个方法?
public void init(ServletConfig config)
public ServletConfig getServletConfig()
public String getServletInfo()
public void service(ServletRequest request,ServletResponse response)
public void destroy()JSP
10、跨域请求
1:做过跨越多个网站的Ajax开发的朋友都知道,如果在A网站中,我们希望使用Ajax来获得B网站中的特定内容,如果A网站与B网站不在同一个域中,那么就出现了跨域访问问题。(也就是当前网页是www.baidu.com/hello.jsp,现在在hello.jsp文件中通过ajax的url访问www.google.com/ok.jsp文件下的内容,以为baidu和googel不再一个域下面,就会出现跨域的问题)
2:IE对于跨域访问的处理是,弹出警告框,提醒用户。如果用户将该网站纳入可信任网站,或者调低安全级别,那么这个问题IE就不会在提醒你。
FireFox等其它非微软的浏览器遇到跨域访问,则解决方案统一是拒绝访问。
3:跨域访问的解决方式3中
1,<iframe src="http://localhost:8080/CmsUI/2.html" id="i">
2.使用javascript的<script src>标签的src,我们最常用了,去下载别的库文件
3.使用jsonp实现跨域
上面类似于http://localhost:2701/home/somejsonp?callback=jsonpcallback告诉服务端回调函数名是上面,上面图中是callback函数处理返回来的json格式的字符串。
4.浏览器的“同源策略(SOP:Same Origin Policy)”。 简而言之,就是浏览器限制脚本程序只能和同协议、同域名、同端口的脚本进行交互,这包括共享和传递变量等。cookie的传递也是遵从同样策略。这就造成一些涉及到多个服务器的应用在整合时一些麻烦。跨域访问的问题造成A站点的Ajax代码无法访问B站点的数据。
5:跨域访问浏览器会阻止;
11.说出在JSP页面里是怎么分页的?
页面需要保存以下参数:总行数:根据sql语句得到总行数,每页显示行数:设定值,当前页数:请求参数,页面根据当前页数和每页行数计算出当前页第一行行数,定位结果集到此行,对结果集取出每页显示行数的行即可
21:filter的作用是什么?主要实现什么方法?doFilter()方法中参数request,response的全称是什么?
1:filter使用户可以改变一个request和修改一个response,它并不是一个servlet,不能产生一个response。它能在一个request到达servlet之前预处理request,也可以在离开servlet时处理response.换句话说,filter其实是一个“servlet chaining”(servlet链)。
2:一个filter包括:在servlet调用之前截获在servlet调用之前检查servlet的request根据需要修改request头和request数据,根据需要修改response头和response数据,在servlet调用之后截获。
3:Filter接口定义了三个方法:1, void setFilterConfig(FilterConfig config); //设置filter的配置对象。
2, FilterConfig getFilterConfig();//返回filter的配置对象
过滤器中的servlet的FilterConfig对象和servlet中ServletConfig对象的作用一样,就是在web配置文件中读取该servlet或者给filter的配置的一些信息,如局部变量名之类的。
3, doFilter(ServletRequest req,ServletResponse res,FilterChain chain);//执行filer工作。
request 全称:HttpServletRequest,response全称:HttpServletResponse
4:过滤器链:ApplicationFilterChain这个是不是觉得和流水线的valve的设计模式很像呢,将各个过滤器加入到该链中,然后将该链的对象传给doFilter方法(doFilter(ServletRaquest request, ServletResponse response, FilterChain chain))然后第一个Filter处理器处理完以后,调用过滤器链上的第二个Filter的doFilter方法,当doFilter是最后一个方法的时候,就调用servlet的service方法。因为servlet的init()方法是servlet在加载的时候就执行,而且只执行一次,因此就他肯定是在Filter被调用之前的。
22,我们没有写servlet的构造方法,那么容器是怎么创建servlet的实例呢?
容器会自动为servlet写一个无参的构造方法,并通过Class.forName(className).newInstance()来创建servlet实例
12:单点登录怎么实现?
1:单点登录SSO(Single Sign On)说得简单点就是在一个多系统共存的环境下,用户在一处登录后,就不用在其他系统中登录,也就是用户的一次登录能得到其他所有系统的信任。单点登录在大型网站里使用得非常频繁,例如像阿里巴巴这样的网站,在网站的背后是成百上千的子系统,
方法1:将登录的session持久化到数据库,在访问另一的主机上的应用的时候遍历数据库中的session,通过sessionid找到对应的session来辨别。(我自己的思路)(持久化到缓存服务器中也可以,就是不可靠,这样就不用每访问一次就去数据库中找,)
方法2:使用最简单的方法就是cookie,在第一层登录成功以后,给客户端一个cookie,然后每次访问别的子系统的时候,都带上该cookie信息,就ok啦。(缺点,不安全,不能跨域登录)
方法3:普遍采用的方案,当第一次登录成功以后,服务器产生可以免登录的url传送到客户端,客户端用免登录的url去访问分系统的时候,分系统就验证该客户端的一些信息,验证通过就免登录,不通过就不允许登录,这样的问题也就有,服务端还是得存储相关的临时信任数据,有可能不是session,但是这里就可以用缓存了,一般临时信息不需要持久化。