servlet和jsp初探
servlet
Servlet是在服务器端运行的小程序,一般在容器中运行
Servlet是个接口,GenericServlet抽象类实现了Servlet接口,HttpServlet抽象类继承了GenericServlet抽象类
?
Servlet生命周期
在servlet整个生命周期当中,只实例化一个servlet对象
[在servlet提供给客户端的服务当中,在服务器内部只有一个servlet对象,这个对象是用户第一个访问这个servlet的时候实例化的,用户再次访问,不再实例化对象,还是用第一次实例化的对象,也就是说,只调用doGet/doPost方法,不再实例化对象和init初始化,当web应用程序退出了或者重新加载了,调用destroy()方法销毁这个servlet对象后,用户再次访问时,就实例化对象和init初始化,然后调用doGet/doPost方法]
?
周期全过程
加载:classLoader(class文件加载)
实例化对象:new一个servlet对象
初始化:调用init()初始化方法,初始化servlet的配置信息,也就是实例化ServletConfig对象
处理请求:调用service()方法,该方法分发到doGet/doPost方法,处理客户端的请求是以多线程的方式运行的
退出服务:当web应用程序退出了或者重新加载了,调用destroy()方法销毁这个servlet对象,这个时候servlet生命周期结束
?
注:在servlet中不要定义成员变量
?
为什么有init方法,一个没有参数,另一个有ServletConfig参数?
从servlet接口带过来的接收ServletConfig参数的init方法,对它进行重写的时候,如果忘了调用super.init(ServletConfig config)方法,那么在getServletConfig()的时候就会出现空指针异常,为了解决这个情况,就有了不接受参数的init()方法,只要重写了这个方法,服务器在初始化的时候,调用init(ServletConfig config)方法,这个方法中会自动调用init()方法,从而避免了错误。
?
Cookie
服务器可以向客户端写内容,只能是文本内容,长度有限制,最长是4K,客户端可以阻止服务器写入,服务器只能拿自己webapp写入的东西。Cookie是保存到客户端的一个文本文件,与特定客户无关,它是以“名-值”对的形式保存数据。
?
Cookie分为两种:
(1)???? 属于窗口/子窗口(暂时性的)
(2)???? 属于文本
/* (1)没有生命周期的cookie,是存活在浏览器的内存里面,浏览器一关掉,这个cookie就消失了 */
Cookie cookie = new Cookie("session-cookie", "session-cookie-value");
// 把cookie写到客户端
response.addCookie(cookie);
?
/* (2)有生命周期的cookie,是存放在客户端缓存的一个文本文件里面 */
cookie = new Cookie("persistent-cookie", "persistent-cookie-value");
// 设置客户端浏览器此cookie存留的最长时间,超过这个时间浏览器自动删除这个cookie
cookie.setMaxAge(3600);
response.addCookie(cookie);
?
Cookie[] cookies = request.getCookies();
for (int i = 0; i < cookies.length; i++) {
??? String name = cookies[i].getName();
??? String value = cookies[i].getValue();
}
一个servlet/jsp设置的cookie能被同一路径或者子路径下面的servlet/jsp读取到(路径=URL,而不是真实文件路径),反过来,一个servlet/jsp设置的cookie不能被父路径下面的servlet/jsp读取到
?
Session
如果想基于cookie编程,就得确认一件事,就是开发的代码不是核心的业务逻辑,因为客户端可以把cookie禁用掉,如果是核心的业务逻辑,应该用session编程。
?
HttpSession session = request.getSession(true/false);
如果为false,就是要拿这个session,如果没有,不会创建session;
如果为true,没有session,就会创建一个,如果有,就拿原来那个;
?
Session的两种实现方式:
(1)???? 通过cookie来实现[把sessionId放到cookie里面]
(2)???? 通过URL重写来实现
规则:
1.如果浏览器支持cookie,创建session的时候会把sessionId保存在cookie里面
2.如果不支持cookie,必须自己编程使用URL重写的方式实现session[response.encodeURL(),作用两个:(1)转码;(2)URL后面加sessionId,比如:response.encodeURL(request.getRequestURL().
toString)]
?
同一个app下的servlet/jsp可以共享同一个session,前提是同一个客户端窗口
?
Session总结:
1.? Session是服务器端的一块内存(key-value);
2.? Session和客户端窗口对应(子窗口)(独一无二);
3.? 客户端和服务器端有对应的sessionId;
4.? 客户端向服务器端发送sessionId的两种方式:(1)cookie;(2)重写URL;
5.? 浏览器禁用cookie,就不能使用session(使用cookie实现的session),如果想安全地使用session(不论客户端是否禁止cookie),只能使用URL重写,但这样的话就大大增加编程负担,所以很多网站要求客户端打开cookie。
Cookie 和session的区别
Cookie
session
存储在客户端
存储在服务器端
两种类型
l? 有生命周期(cookie.setMaxAge)
l? 无生命周期
两种实现方式
l? 依赖于cookie
l? url重写(response.encodeURL())
父路径不能访问子路径的cookie
同一个session的窗口共享一个session
典型应用:
l? 3个月不用再登陆
l? 购物车
典型应用:
l? 用户登陆
l? 购物车也可以用session实现
不可靠
可靠
注:cookie有时候禁不掉
Application(ServletContext)
用于保存整个webapp的生命周期内都可以访问的数据
ServletContext application = this.getServletContext();
Application.setAttribute("", "");
Application.getAttribute("");
乱码问题
场合:页面本身有中文的时候
解决办法:servlet:response.setContentType("text/html;charset=gbk");
jsp: <%@ page contentType="text/html;charset=gbk"%>
注意:一定要写在PrintWriter out = response.getWriter();之前
场合:解决get方式乱码问题
解决办法:修改server.xmlàURIEncoding="GBK"
场合:解决post方式提交内容的乱码
解决办法:request.setCharacterEncoding("GBK");
注意:一定要写在存取第一个参数之前,
不要调用response.setCharacterEncoding("GBK");
场合:<jsp:param name="user" value="<%=s%>"/>,url地址包含中文参数
解决办法:<%request.setCharacterEncoding("GBK");%>
Jsp(java server pages)
Jsp拥有servlet的特性和优点(本身就是一个servlet),直接在html中内嵌java代码,jsp程序由jsp引擎先将它转换成servlet java代码,然后将它编译成.class文件,最后载入执行,只有当客户端第一次请求jsp时,才需要将其转换并且编译,所以第一次访问会慢些。
?
Jsp传统语法:
(1)Declaration——声明,基本语法:<%! %>或<% %>,声明变量时,加!为成员变量,不加!为局部变量;声明方法时,必须加!
(2)Scriptlet——小程序段,基本语法:<%程序代码区%>
(3)Expression——表达式,基本语法:<%= %>,里面代码不需要以分号结束
(4)Comment——注释
三种注释:
<%--?? --%>,jsp的注释,客户端不能看见的注释
<%//?? %>或者<%/**/%>,java的注释
<!--?? -->,html的注释,客户端能看见的注释
<!-- <%=out.println("abc")%> -->,这个不能阻止服务器端运行其中的代码,只是运行的结果在客户端不显示罢了
(5)Directive——编译指令(编译期间的命令)
格式:<%@Directive 属性="属性值"%>
常见的Directive:page、include、taglib
<%@page language=""|目前只能写java
?????? ? import=""
?????? ? buffer="none|kb size"|none:不缓冲,默认8k
?????? ? session="true|false"|是否可以使用session,默认true
?????? ? autoFlush="true|false"|缓冲器是否自动清除,默认true
?????? ? isThreadSafe="true|false"|默认false,永远不要设置为true
?????? ? errorPage=""
?????? ? isErrorPage="true|false"|默认为false
?????? ? contentType="text/html;charset=GBK"
%>
一旦isErrorPage="true",就可以在当前jsp页面中使用exception对象了,比如:<%=exception.getMessage()%>
静态包含是指在jsp被转换成servlet之前,先把包含的页面包含进来,所以转换成的servlet只有一个,并且,包含和被包含的页面访问的是同一个request对象,两个页面的字符集编码必须设置一样。
格式:<%@include file="fileURL"%>
注:不能向fileURL中传递参数。
(6)Action——动作指令(运行期间的命令)
动态包含,包含和被包含的页面被转换成各自的servlet(两个),包含和被包含的页面访问的是不同的request对象,但是包含页面可以取到传递到被包含页面的参数。
格式:
第一种:<jsp:include page="fileURL?param1=paramValue" flush="true"/>,这个fileURL里面是可以传递参数的
第二种:<jsp:include page="fileURL" flush="true">
<jsp:param name="param1" value="paramValue"/>
</jsp:include>
静态包含和动态包含的区别
静态包含
动态包含
include编译指令是在JSP程序的转换时期就将file属性所指定的程序内容嵌入,然后再编译执行
include指令在转换时期是不会被编译的,只有在客户端请求时期如果被执行到才会被动态的编译载入
只生成一个class文件
多个
不能带参数
可以带参数
同一个request对象
不同的request对象,可以取得包含它的页面的参数,并添加了自己的参数
jsp:forword格式:
第一种:<jsp:forword page="fileURL?param1=paramValue" flush="true"/>
第二种:<jsp:forword page="fileURL" flush="true">
<jsp:param name="param1" value="paramValue"/>
</jsp:forword>
sendRedirect和forward的区别
sendRedirect
forward
不同的request对象
相同的request对象
sendRedirect后的语句会继续执行
forward后的语句不会继续执行
两次客户端请求,速度慢
一次客户端请求,速度块
地址栏变化
地址栏不变化
/代表http://127.0.0.1:8080/
/代表http://127.0.0.1:8080/app/
jsp:useBean,通过它可以在jsp中使用定义好的Bean,定义Bean时必须有一个不带参数的构造器,因为在jsp中实例化Bean时,会调用到这个构造器
格式:
<jsp:useBean id="beanName" style="margin: 0cm 0cm 0pt;"><jsp:setProperty name="beanName" property="propertyName" value=""/>
<jsp:getProperty name="beanName" property="propertyName"/>
在jsp中使用javaBean,要求Bean写在包里面,不能裸体
jsp:useBean各项属性说明:
id:实例化对象名称
scope:bean的作用范围,默认page
class:bean类名称
type:bean实例类型,可以是本类(默认)、父类、实现的接口
scope各项参数说明:
(1)???? page:仅涵盖使用bean的页面
(2)???? request:有效范围仅限于使用javaBean的请求
(3)???? session:有效范围是整个会话周期
(4)???? application:有效范围涵盖整个应用程序
建立表单参数和bean属性之间的关联:
(1) <jsp:useBean id="beanName" style="margin: 0cm 0cm 0pt;"><jsp:getProperty name="beanName" property="propertyName" param="表单参数"/>
或者
<jsp:getProperty name="beanName" property="propertyName" value="<%=request.getParameter("表单参数")%>"/>
(2) 通过*来设置所有属性和输入参数之间的关联:
<jsp:useBean id="beanName" style="text-indent: 6pt; margin: 0cm 0cm 0pt 57pt;"><jsp:getProperty name="beanName" property="*"/>
</jsp:useBean>
Servlet转jsp
(1)???? 转发
this.getServletConfig(),返回的ServletConfig代表的是web.xml对这个servlet的配置
this.getServletConfig().getServletContext(),返回的ServletContext代表的是servlet的上下文
this.getServletConfig().getServletContext().getRequestDispatcher("URL"),返回的RequestDispatcher代表的是一个请求分发器
this.getServletConfig().getServletContext().getRequestDispatcher("URL").forward(request,response);
(2)???? 重定向
response.sendRedirect("URL");