Servlet背景介绍
J2EE的13种技术之一
EJB、CORBA、RMI、JSP、Java Servlet、JavaBean、JDBC、XML、……
serlvet+jsp ->java web开发[使用java技术做 web开发]
bs 和 cs的比较
(1)BS:browser server 浏览器服务器
(2)cs client server 客户服务
为什么需要的web服务器/web究竟是干什么的?
我们先模拟一个web服务器 MyWebServer.java
import java.io.*;
import java.net.*;
public class MyWebServer
{
public static void main(String []args) throws Exception{
ServerSocket ss=new ServerSocket(80);
Socket s=ss.accept();
//提示一句话
System.out.println("在 9999 上等待连接...");
OutputStream os=s.getOutputStream();
BufferedReader br=new BufferedReader(new FileReader("d:\\hello.html"));
String buf="";
while((buf=br.readLine())!=null){
os.write(buf.getBytes());
}
//关闭流
br.close();
os.close();
s.close();
}
}
Tomcat介绍
- 通过tomcat来讲解BS结构
- 安装tomcat服务器
- 配置
①在环境变量中添加
JAVA_HOME= 指向你的jdk的主目录(并不是bin文件目录)
-
-
-
- 在不配置JAVAHOME的前提下启动tomcat
-
-
在startup.bat的第25行中添加set JAVA_HOME=JKD路
- 启动tomcat服务器
到 tomcat 主目录下 bin/startup.bat
- 验证是否安装成功
http://localhost:8080(8080是默认端口如果该端口已经被占用需要修改端口)
- tomcat安装后问题解决
(1)tomcat无法正常启动的原因分析
- JAVA_HOME 配置错误,或者没有配置
- 如果你的机器已经占有了8080 端口,则无法启动,
解决方法
(1) 你可以8080 先关闭
netstat –an
netstat –anb 来查看谁占用该8080
(2) 主动改变tomcat的端口.
到 conf/server.xml 文件中修改
<Connector connectionTimeout="20000" port="8088" (去修给config->server.xml的端口号)protocol="org.apache.coyote.http11.Http11NioProtocol" redirectPort="8443"/>
(3) 能够正常启动,但是会导航到另外一个页面.
去修改工具->管理加载项,把默认的导航给禁用即可.
(4) 在访问 tomcat时候,一定保证 tomcat 服务器是启动
tomcat的目录结构文件
bin: 启动和关闭tomcat的bat文件
conf: 配置文件
-->server.xml : 该文件用于配置和 server 相关的信息, 比如 tomcat启动端口后,配置Host, 配置Context 即web应用
-->web.xml : 该文件配置与 web应用(web应用就相当于是一个 web站点)
-->tomcat-users.xml: 该文件用户配置tomcat 的用户密码 和 权限
lib 目录: 该目录放置运行tomcat 运行需要的jar包
logs 目录:存放日志, 当我们需要去查看日志的时候,很有用!,当我们启动tomcat错误时候,可以查询信息.
webapps 目录: 该目录下,放置我们的web应用(web 站点), 比如:
建立 web1 目录 下面放置我们的html 文件 jsp 文件..图片... 则 web1就被当做一个web应用管理起来(☞ 特别说明tomcat 6.0 以后支持 tomcat 5 版本 还有别的设置)
work: 工作目录: 该目录用于存放jsp被访问后 生成的对应的 server文件 和.class文件
如何去访问一个 web 应用的某个文件
将项目布置在tomcat上,启动tomcat,访问本地ip和事先设置好的端口号(这里默认是8080)
http://localhost:8080/web
- 首页面设置及目录规范结构
现在我们要求:把hello.html文件设置成 该 web应用的首页,则需要把web应用的目录格式做的更加规范
①在web文件夹下配置WEB-INF文件夹
②在 web.xml 文件中添加配置的代码:
<welcome-file-list>
<welcome-file>hello1.html</welcome-file>
</welcome-file-list>
③通过http://localhost:8088/web1来访问hello1.html
web-inf目录下的 classes目录将来是存放 class文件
lib 目录将来时存放 jar文件
web.xml 配置当前这个web应用的信息.
tomcat如何去管理虚拟目录
需求: 当我们把 web 应用放到 webapps目录,tomcat会自动管理,如果我们希望tomcat可以管理其它目录下的web应用?->虚拟目录配置
我在d 盘有一个web应用.
- 虚拟目录配置步骤:
- 找到server.xml文件
-
- 编辑host节点 添加Context path
在server.xml中添加:<Context path="/myweb2" docBase="d:\web2"/>
myweb2:是访问时输入的web名,实际取出的是web2中的资源
"d:\web2":绝对路径下web2中存放资源如:hello2.html
实际访问时输入的地址:http://localhost:8088/myweb2/hello2.html
绝对路径:从根分区找某个文件
相对路径:从该文件位置去找另一个文件
③ 需要重启tomcat,才能生效.(因为是采用的dom技术讲信息加载到内存中)
context 的几个属性的说明
path:
docbase:
reloadable ;如果设为ture ,表示 tomcat 会自动更新 web应用,这个开销大,建议在开发过程中,可以设为true, 但是一旦真的发布了,则应当设为false;
upackWAR: 如果设为 ture ,则自动解压,否则不自动解压.
①:打war包 cd:d/web2 然后jar –cvf web2.war *
②:
浏览打好的war包 Deploy发布后会在webapps中自动生存改文件
- 配置域名
我们看和一个如何配置自己的主机名:
我们在实际访问网站的过程中,不可能使用http://localhost:8080/web应用/资源名 的方式去访问网站,实际上使用类似
http://news.sina.com.cn 的方式去访问网站,这个又是怎么实现的呢?
看看ie浏览器访问一个web站点的流程.
实现的步骤如下:
(1) 在C:\WINDOWS\system32\drivers\etc 下的host文件 添加127.0.0.1 www.sina.com.cn
(2) 在tomcat 的server.xml文件添加主机名
<Host name="www.sina.com" appBase="d:\web3”>
<Context path="/" docBase="d:\web3" />
</Host>
(3) 在d:\web3 加入了一个 /WEB-INF/web.xml 把 hello2.html设为首页面
如果连端口都不希望带,则可以吧tomcat的启动端口设为80即可.
(4) 重启生效
这里就不介绍Tomcat的体系了
如何配置默认主机:
在tomcat/conf/server.xml 文件
<Engine name="Catalina" defaultHost="主机名">
如:<Engine name="Catalina" defaultHost="www.show.com">
Servlet常用技术注意点
- 为什么需要servlet技术?
比如需求:我们希望用户可以贴,用户还可以回复 ....这样一些和用户可以交互的功能,用普通的java技术就完成不了, sun 就开发了 servlet技术供程序员使用.
- servlet的介绍
- servlet 其实就是java程序(java类)
- 该 java 程序(java 类)要遵循servlet开发规范
- serlvet是运行在服务端
- serlvet 功能强大,几乎可以完成网站的所有功能
- 是学习jsp基础
servlet的生命周期(工作流程)
①WEB服务器首先会检查是否已经装载并创建了该servlet实例对象。如果是直接进行第④步,否则执行第②步。
②装载并创建该Servlet的一个实例对象。
③调用Servlet实例对象的init()方法。
④创建一个用于封装HTTP请求消息的HttpServletRequest对象和一个代表HTTP响应消息的HttpServletResponse对象,然后调用service()方法并将请求和响应作为参数传递进去。
⑤WEB应用被停止或重启之前,Servlet引擎将卸载Servlet,在卸载之前调用Servlet的destroy()方法
- 当serlvet 第一次被调用的时候,会触发init函数,该函数会把servlet实例装载到内存.init函数只会被调用一次
- 然后去调用servlet 的 service 函数
- 当第二次后访问该servlet 就直接调用 service 函数.
- 当 web应用 reload 或者 关闭 tomcat 或者 关机 都会去调用destroy函数,该函数就会去销毁serlvet
- Servlet的生命周期
当客户端第一次向web服务器发出一个servlet请求时,web服务器将会创建一个该servlet的实例,并且调用servlet的init()方法;如果当服务器已经存在了一个servlet实例,那么,将直接使用此实例;然后再调用service()方法,service()方法将根据客户端的请求方式来决定调用对应的doXXX()方法;当 web应用 reload 或者 关闭 tomcat 或者 关机,web服务器将调用destroy()方法,将该servlet从服务器内存中删除。
生命全过程:
1.加载
2.实例化
3.初始化
4.处理请求
5.退出服务
- 开发servlet有三种方法
- 实现 Servlet接口
- 通过继承 GenericServlet
- 通过继承 HttpServlet
<!--根据serlvet规范,需要将Servlet部署到web.xml文件,该部署配置可以从examples下拷贝-->
<servlet>
<!--servlet-name 给该Servlet取名, 该名字可以自己定义:默认就使用该Servlet的名字-->
<servlet-name>MyFirstServlet</servlet-name>③
<!--servlet-class要指明该Servlet 放在哪个包下 的,形式是 包/包/../类-->
<servlet-class>com.hsp.MyFirstServlet</servlet-class> 注意:后面不要带.java④
</servlet>
<!--Servlet的映射-->
<servlet-mapping>
<!--这个Servlet-name要和上面的servlet-name名字一样-->
<servlet-name>MyFirstServlet</servlet-name>②
<!--url-pattern 这里就是将来访问该Servlet的资源名部分-->
<url-pattern>/ABC</url-pattern>①
</servlet-mapping>
</web-app>
服务器调用流程:http://localhost:8088/ABC--->①--->②--->③--->④
- get 提交 和 post的提交的区别
- 从安全看 get<post 因为get 会把提交的信息显示到地址栏
- 从提交内容看 get<post get 一般不要大于1k, post理论上无限制,但是在实际 开发中,建议不要大于64k
- 从速度看 get>post
- Get可以保留uri中的参数,利于收藏
2.使用通配符在servlet映射到URL中
有两种格式:
第一种格式 *.扩展名 比如 *.do *.ss
第二种格式 以 / 开头 同时以 /* 结尾 比如 /* /news/*
在匹配的时候,要参考的标准:
- 看谁的匹配度高,谁就被选择
- *.do 的优先级最低
- Servlet单例问题
当Servlet被第一次访问后,就被加载到内存,以后该实例对各个请求服务.即在使用中是单例.
因为 Servlet是单例,因此会出现线程安全问题: 比如:
售票系统. 如果不加同步机制,则会出现问题:
- ServletConfig对象
该对象主要用于 读取 servlet的配置信息.
<servlet>
<servlet-name>ServletConfigTest</servlet-name>
<servlet-class>com.hsp.servlet.ServletConfigTest</servlet-class>
<!-- 这里可以给servlet配置信息,这里配置的信息,只能被该servlet 读取 -->
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</servlet>
如何使用
String encoding=this.getServletConfig().getInitParameter("encoding");
补充说明:这种配置参数的方式,只能被某个Servlet独立使用.如希望让所有的Servlet都去读取某个参数,这样配置:
<!-- 如果这里配置参数,可被所有servlet读取 -->
<!--
<context-param>
<param-name></param-name>
<param-value></param-value>
</context-param>
-->
http协议介绍
- http协议是建立在tcp/ip协议基础上
- http协议全称 超文本传输协议
- http协议1.0 , 1.1版本 ,目前通用的是1.1版本
http1.0 称为短连接
http1.1 称为长连接.
所谓长,和短指的是 持续时间的 长连接 1.1 30s ,短连接是发送完数据就断掉.
- http的请求部分:
基本结构:
GET /test/hello.html HTTP/1.1 [请求行]
Accept: */* [消息名] 消息名:内容
Referer: http://localhost:8080/test/abc.html
Accept-Language: zh-cn
User-Agent: Mozilla/4.0
Accept-Encoding: gzip, deflate
Host: http://www.sohu.com:80
Connection: Keep-Alive [消息头格式 (消息名: 内容 )
特别说明: 并不是每一次请求的消息头都一样.]
空行
发送的内容 [格式 : 内容名字=内容体]
- 请求方式
请求行中的GET称之为请求方式,请求方式有:POST,GET,HEAD,OPTIONS,DELETE,TRACE,PUT
常用的有:POST,GET
- get和post
之前说过
GET News/abc.jsp
- http请求消息头
- Accept: text/html,image/* [告诉服务器,我可以接受 文本,网页,图片]
- Accept-Charset: ISO-8859-1 [接受字符编码 iso-8859-1]
- Accept-Encoding: gzip,compress [可以接受 gzip,compress压缩后数据.]
- Accept-Language: en-us,zh-cn [浏览器支持中,英文]
- Host: www.sohu.com:80 [我要找主机是 www.sohu.com:80]
- If-Modified-Since: Tue, 11 Jul 2000 18:23:51 GMT [ 告诉服务器,我的缓冲中有这个资源文件,该文件的时间是 。。。]
- Referer: http://www.sohu.com/index.jsp [告诉服务器,我来自哪里,该消息头,常用于防止盗链]
- User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0)[告诉服务器,浏览器内核]
- Cookie [cookie??]
- Connection: close/Keep-Alive [保持连接,发完数据后,我不关闭连接]
- Date: Tue, 11 Jul 2000 18:23:51 GMT [浏览器发送该http请求的时间]
- http的响应
格式:HTTP版本号 状态码 原因叙述
举例:HTTP/1.1 200 OK
状态码 含义
100-199 表示成功接收请求,要求客户端继续提交下一次请求才能完成整个处理过程
200-299 表示成功接收请求并完成整个处理过程,常用200
300-399 为完成请求,客户需要进行一步细化请求。例如:请求的资源已经移动一个新的地址,常用302,307
400-499 客户端的请求有错误 404
500-599 服务器端出现错误,常用500
- http响应的状态行举例说明
200 就是整个请求和响应过程没有发生错误,这个最常见.
302: 表示当你请求一个资源的时候,服务器返回302 表示,让浏览器转向到另外一个资源,比如: response.sendRedirect(“/web应用/资源名”)
案例:
response.setStatus(302);
response.setHeader("Location", "/servletPro/Servlet2");
// 上面两句话等价 response.sendRedirect("/servletPro/Servlet2");
404: 找不到资源
500: 服务器端错误
- http响应消息头详解
- Location: http://www.baidu.org/index.jsp 【让浏览器重新定位到url】
- Server:apache tomcat 【告诉浏览器我是tomcat】
- Content-Encoding: gzip 【告诉浏览器我使用 gzip】
- Content-Length: 80 【告诉浏览器会送的数据大小80节】
- Content-Language: zh-cn 【支持中文】
- Content-Type: text/html; charset=GB2312 [内容格式text/html; 编码gab2312]
- Last-Modified: Tue, 11 Jul 2000 18:23:51 GMT 【告诉浏览器,该资源上次更新时间】
- Refresh: 1;url=http://www.baidu.com 【过多久去,刷新到 http://www.baidu.com】
- Content-Disposition: attachment; filename=aaa.zip 【告诉浏览器,有文件下载】
- Transfer-Encoding: chunked [传输的编码]
- Set-Cookie:SS=Q0=5Lb_nQ; path=/search[后面详讲]
- Expires: -1[告诉浏览器如何缓存页面IE]
- Cache-Control: no-cache [告诉浏览器如何缓存页面火狐]
- Pragma: no-cache [告诉浏览器如何缓存页面]
- Connection: close/Keep-Alive [保持连接 1.1是Keep-Alive]
- Date: Tue, 11 Jul 2000 18:23:51 GMT
①定时刷新Refresh使用
response.setHeader("Refresh", "5;url=/servletPro/Servlet2");
②文件下载 Content-Disposition
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
//PrintWriter out = response.getWriter();
//演示下载文件
response.setHeader("Content-Disposition", "attachment; filename=winter.jpg");
//打开文件.说明一下web 站点下载文件的原理
//1.获取到要下载文件的全路径
String path=this.getServletContext().getRealPath("/images/Winter.jpg");
//System.out.println("path="+path);
//2创建文件输入流
FileInputStream fis=new FileInputStream(path);
//做一个缓冲字节数组
byte buff[]=new byte[1024];
int len=0;//表示实际每次读取了多个个字节
OutputStream os=response.getOutputStream();
while((len=fis.read(buff))>0){
os.write(buff, 0, len);
}
//缺点: 没有进度条./图标/
//关闭
os.close();
fis.close();
}
③缓存讲解
提出问题:浏览器默认情况下,会缓存我们的页面,这样出现一个问题:如果我们的用户习惯把光标停留在地址栏,然后回车来取页面,就会默认调用cache中取数据。
-
-
- 有些网站要求及时性很高,因此要求我们不缓存页面
-
代码:
//指定该页面不缓存 Ie
response.setDateHeader("Expires", -1);【针对IE浏览器设置不缓存】
//为了保证兼容性.
response.setHeader("Cache-Control", "no-cache");【针对火狐浏览器等】
response.setHeader("Pragma", "no-cache");【其他浏览器】
-
-
- 有些网站要求网页缓存一定时间,比如缓存一个小时
-
response.setDateHeader("Expires", System.currentTimeMillis()+3600*1000*24);后面一个参数表示设置的缓存保持时间,-1表示永远缓存
加入防止盗链下载.
- HttpServletResponse的再说明
getWriter()
getOutputStream();
区别
- getWriter() 用于向客户机回送字符数据
- getOutputStream() 返回的对象,可以回送字符数据,也可以回送字节数据(二进制数据)
OutputStream os=response.getOutputStream();
os.write("hello,world".getBytes());
如何选择:
如果我们是回送字符数据,则使用 PrintWriter对象 ,效率高
如果我们是回送字节数据(binary date) ,则只能使用 OutputStream
☞ 这两个流不能同时使用.
比如:
OutputStream os=response.getOutputStream();
os.write("hello,world".getBytes());
PrintWriter out=response.getWriter();
out.println("abc");
就会报错:
java.lang.IllegalStateException: getOutputStream() has already been called for this response
不能同时使用printWriter和outputstream的原因
- 参数的传递方式sendRedirect()和session()
需求: 当用户登录成功后,把该用户名字显示在登录成功页面;
①使用sendRedirect()来传递字符参数
解决思路:
- 使用java基础 static
- 使用sendRedirect()
代码:
response.sendRedirect("/UsersManager/MainFrame?uname="+username+"&pwd="+password);
- 使用session 传递
这里,我们先预热.
说明:
基本格式:
response.sendRedirect(“servlet的地址?参数名=参数值&参数名=参数值...”);
☞ 参照值是String , 参数名应当使用 字母组合
在接受数据的Servlet中:
String 参数=request.getParameter(“参数名”);
②使用session()来传递字符参数和对象
A.传递字符串
放入session request.getSession.setAttribute("loginUser",username);
取出session 在JSP中通过session取出 request.getSession.getAttribute("loginUser");
B.传递对象
User user= new User();
user.setName(“xiaoli”);
user.setPassWord(“123”);
放入session request.getSession.setAttribute("userObj",userObj);
取出session User user=(User)request.getSession.getAttribute(“userObj”);
中文乱码处理
发生中文乱码有三种情况
- 表单form
- post
在服务器端设置成浏览器端的编码方式。
解决方法: request.setCharacterEncoding("utf-8"); //gbk gb2312 big5
- get
newString=new String(str.getBytes("iso-8859-1"),"utf-8");
该方法和get处理方法一样.
- sendRedirect() 发生乱码
response.sendRedirect(“servlet地址?username=顺平”);
☞版本低导致的乱码
特别说明,如果你的浏览器是 ie6 或以下版本,则我们的 ② 和 ③中情况会出现乱码(当中文是奇数的时候)
解决方法是 :
String info=java.net.URLEncoder.encode("你好吗.jpg", "utf-8");
<a href=”http://www.sohu.com?name=”+ info >测试</a>
response.sendRedirect(“servlet地址?username=”+info);
说明: 我们应当尽量使用post 方式提交;
☞返回浏览器显示乱码
在服务端是中文,在response的时候,也要考虑浏览器显示是否正确,一般我们通过
response.setContentType(“text/html;charset=utf-8”); ok
☞下载提示框中文乱码
补充一个知识点: 当我们下载文件的时候,可能提示框是中文乱码
String temp=java.net.URLEncoder.encode("传奇.mp3","utf-8");
response.setHeader("Content-Disposition","attachment; filename="+temp);
HttpServletRequest对象的详解
该对象表示浏览器的请求(http请求), 当web 服务器得到该请求后,会把请求信息封装成一个HttpServletRequest 对象
-
- getRequestURL方法返回客户端发出请求时的完整URL。
- getRequestURI方法返回请求行中的资源名部分。
- getQueryString 方法返回请求行中的参数部分(参数名+值)。
该函数可以获取请求部分的数据 比如
http://localhost/web名?username=abc&pwd=123
request.getQueryString(); 就会得到 username=abc&pwd=123
getRemoteAddr方法返回发出请求的客户机的IP地址
getRemoteHost方法返回发出请求的客户机的完整主机名
getRemotePort方法返回客户机所使用的网络端口号
客户机的端口号是随机选择的,web服务器的端口号是一定的
getLocalPort方法返回web服务器所使用的网络端口号
getLocalAddr方法返回WEB服务器的IP地址。
getLocalName方法返回WEB服务器的主机名
url 和 uri 的区别
比如:
Url=http://localhost:8088/servletPort3/GetinfoServlet 完整的请求
Uri=/servletPort3/GetinfoServlet web应用的名称+资源的名称
//如果接受复选框的内容,则使用getparameterValues
String [] xxxx=request.getParameterValues("xxx");
//如果接受的单选框或input 等等
String xx=request.getParameter("xxx");
- 请求转发requeset.getRequestDispatcher(资源地址).forward(request,response);
资源地址:不需要项目名。因为它只是在WEB服务器内部转发。
Request.getRequestDispatcher(资源地址).forward(request,response);
我们现在使用 请求转发的方法来实现上次我们使用 response.sendRedirect() 实现效果
使用 request提供的转发方法.
Request中的Attribute在一次请求有效。一次请求:没有返回到浏览器,就为一次请求。
- 使用 forward 不能转发到 该web应用外的 url
- 因为 forward 是发生在web服务器,所以 Servlet1 和 Servlet 2使用的是用一个request 和response.
- 使用sendRedirect() 方法不能通过request.setAttribute() 把 属性传递给下一个Servlet
- 比较sendRedirect()和request.getRequestDispatcher().forward(request,response)
sendRedirect() 和 forward 的区别是什么
叫法 sendRedirect() 重定向,转发 forward() 叫转向
1、实际发生的位置不一样
sendRedirect 发生 浏览器
forward 发生 web服务器
2、用法不一样
request.getRequestDispatcher(“/资源URI”).forward(request,response)
response.sendRedirect(“/web应用/资源URI”);
3、能够去URL 范围不一样
sendRedirect 可以去 外边URL
forward 只能去当前的WEB应用的资源
- 什么是一次 http请求:
只要没有停止,也没有回到浏览器重定向,就算一次
- 如果转发多次,我们的浏览器地址栏,保留的是第一次 转向的那个Servlet Url
Jdbc 、Oracle
//1加载驱动
Class.forName("oracle.jdbc.driver.OracleDriver");
//2.得到连接
ct=DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:1521:ORCLHSP","scott","tiger");
//3.创建PreparedSatement
ps=ct.prepareStatement("select * from users where id=? and passwd=?");
//给? 赋值
ps.setObject(1, id);
ps.setObject(2, password);
//4.执行操作
rs=ps.executeQuery();
//5.根据结果左处理
if(rs.next()){
//说明该用户合法
request.getRequestDispatcher("/MainFrame").forward(request, response);
}else{
request.getRequestDispatcher("/LoginServlet").forward(request, response);
}
} catch (Exception e) {
e.printStackTrace();
// TODO: handle exception
}finally{
//关闭资源
if(rs!=null){
try {
rs.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
rs=null;
}
if(ps!=null){
try {
ps.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
ps=null;
}
if(ct!=null){
try {
ct.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
ct=null;
}
}
注意点
- 业务逻辑代码和界面分离
- 把常用的代码(对数据库的连接和操作) 封装到工具类
具体的方法
- 每一张表对应 一个 domain类(表示数据) 还要对应一个 Service 类
比如 users 表 对应 Users 类(domain 类) UserService类(该类会封装对users表的各种操作) ,实际上这里体现出 数据 和 操作分离的思想
会话技术cookie和session
- 什么是会话
基本概念: 指用户开一个浏览器,访问一个网站,只要不关闭该浏览器,不管该用户点击多少个超链接,访问多少资源,直到用户关闭浏览器,整个这个过程我们称为一次会话.
比如打电话.
- 为什么需要cookie技术(会话技术)
如何保存用户上次登录时间
如何显示用户浏览历史?
如何把登录的用户名和密码电脑,下次登录,不需要重新输入
解决之道—cookie
- cookie的小结
- cookie 是在服务端创建
- cookie 是保存在浏览器这端
- cookie 的生命周期可以通过
cookie.setMaxAge(2000);
如果不设置setMaxAge则该cookie的生命周期当浏览器关闭时,就消亡.
- cookie 可以被多个浏览器共享(与session的区别)
- 怎么理解
我们可以把cookie 想成一张表
?如果cookie重名会有什么问题?
如果重名就会替换存在的cookie值.
- 一个web应用可以保存多个cookie,但保存在同一个cookie文本在客户端浏览器下
- cookie存放的时候是以明文方式存放,因此安全较低.,我们可以通过加密后保存.md5加密算法 :
请大家注意,以后我们的密码都要使用加密存放,在验证密码的时候,对用户输入密码,进行md5加密,然后该到数据库去验证。
md5算法
package com.hsp;
import java.security.*;
import java.security.spec.*;
class MD5_test {
public final static String MD5(String s) {
char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'a', 'b', 'c', 'd', 'e', 'f' };
try {
byte[] strTemp = s.getBytes();
MessageDigest mdTemp = MessageDigest.getInstance("MD5");
mdTemp.update(strTemp);
byte[] md = mdTemp.digest();
int j = md.length;
char str[] = new char[j * 2];
int k = 0;
for (int i = 0; i < j; i++) {
byte byte0 = md[i];
str[k++] = hexDigits[byte0 >>> 4 & 0xf];
str[k++] = hexDigits[byte0 & 0xf];
}
return new String(str);
} catch (Exception e) {
return null;
}
}
public static void main(String[] args) {
// MD5_Test aa = new MD5_Test();
System.out.print(MD5_test.MD5("疯狂的逗妇乳"));
}
}
- 保存上次登录时间
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
//先获取cookie
// 假设我们 保存上次登录时间的cookie "lasttime"
// 这里我们要考虑一个情况: 用户第一次登录 '您是第一次登录..'
Cookie []cookies=request.getCookies();
boolean b=false;//假设没有lasttime cookie
if(cookies!=null){ //保证有cookie,取遍历
for(Cookie cookie: cookies){
//取出名
String name=cookie.getName();
if("lasttime".equals(name)){
//显示
out.println("您上次登录时间是 "+cookie.getValue());
//更新时间
//把当前日期保存cookie
SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String nowTime=simpleDateFormat.format(new java.util.Date());
Cookie mycookie=new Cookie("lasttime",nowTime);
mycookie.setMaxAge(7*3600*24);//保存一周
response.addCookie(mycookie);
b=true;
break;
}
}
}
if(!b){
//没有找到
out.println("您是第一次登录..");
//把当前日期保存cookie
SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String nowTime=simpleDateFormat.format(new java.util.Date());
Cookie cookie=new Cookie("lasttime",nowTime);
cookie.setMaxAge(7*3600*24);//保存一周
response.addCookie(cookie);
}
}
cookie的细节
- 一个浏览器最多放入 300cookie,一个web站点,最多 20cookie,而且一个cookie大小限制子4k
- cookie生命周期的再说明:
- cookie默认生命周期是会话级别
- 通过setMaxAge() 可以设置生命周期
setMaxAge(正数) , 即多少秒后该cookie失效
setMaxAge(0) ,删除该cookie
setMaxAge(负数), 相当于该cookie生命周期是会话级别.
案例 :
//先得到该cookie
Cookie cookies[]=request.getCookies();
for(Cookie cookie: cookies){
if(cookie.getName().equals("id")){
System.out.println("id");
//删除
cookie.setMaxAge(0);
response.addCookie(cookie);//一定带上这句话,否则不能删除
}
}
特别说明: 如果该web应用只有一个cookie ,则删除该cookie后,在浏览器的临时文件夹下没有该cookie文件,如果该web应用有多个cookie,则删除一个cookie后,文件还在,只是该cookie没有
- cookie存放中文,怎么处理
存放:
String val=java.net.URLEncoder.encode("逗妇乳","utf-8");
Cookie cookie=new Cookie("name",val);
取出:
String val=java.net.URLDecoder.decode(cookie.getValue(), "utf-8");
out.println("name ="+val);
session
- session是存在服务器的内存中
- 一个用户浏览器,独享一个session域对象
- session中的属性的默认生命周期是30min ,你可以通过 web.xml来修改
- 3种session生命周期的设置
(1)一个地方是 tomcat/conf/web.xml
<session-config>
<session-timeout>30</session-timeout>//表示30分钟的意思
</session-config>
对所有的web应用生效
(2)另外一个地方,就是在单个web应用的下去修改 web.xml
<session-config>
<session-timeout>30</session-timeout>session精确到分钟,cookie精确到秒
</session-config>
如果发生冲突,则以自己的web应用优先级高
(3)session.setMaxInactiveinterval(60)发呆六十秒后session失效
- session中可以存放多个属性
- session 可以存放对象
- 如果 session.setAttribute(“name”,val) , 如果名字重复,则会替换该属性.
如果同一个用户浏览器,向session设置一个属性的时候,如果名字相同了,会出现什么情况?
结论: 会替换该对象值.
- session的更深入理解:
为什么服务器能够为不同的浏览器提供不同session?
因为每个浏览器去访问web站点的时候,如果发出的http请求头没有带JSESSIONID头就会自动给你创建一个并返回
过滤器(filter)
①开发过滤器的步骤:
- 创建 继承HttpServlet 同时实现Filter接口
- 默认filter不生效,需要配置.
<!-- 自己配置的一个filter -->
<filter>
<filter-name>MyFilter</filter-name>
<filter-class>com.zhy.filter.MyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>MyFilter</filter-name>
<url-pattern>/*</url-pattern> /*表示对该WEB的所有网页都过滤
</filter-mapping>
- 在filter的方法中添加业务逻辑.
package com.hsp.filter;
import java.io.IOException;
import java.io.PrintWriter;
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.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import com.hsp.domain.User;
public class MyFilter1 extends HttpServlet implements Filter {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
System.out.print("myfilter1...");
//获取session
HttpServletRequest httpServletRequest=
(HttpServletRequest)request;
//看看请求的资源是什么
String uri=httpServletRequest.getRequestURI();
if(uri.startsWith("/UsersManager3/imgs")||uri.startsWith("/UsersManager3/Login")){
//直接放行.
chain.doFilter(request, response);
}else{
HttpSession session=httpServletRequest.getSession();
User user=(User) session.getAttribute("loginuser");
if(user!=null){
//该用户合法,放行
chain.doFilter(request, response);
}else{
request.setAttribute("err", "请好好登陆");
httpServletRequest.getRequestDispatcher("/LoginServlet")
.forward(request, response);
}
}
}
public void init(FilterConfig arg0) throws ServletException {
// TODO Auto-generated method stub
}
}
过滤器链
实现方式 :
- 在创建一个过滤器 (继承HttpServlet 同时还要实现Filter接口)
- 配置过滤器
配置过滤器的顺序就可以决定调用过滤器的顺序.
jsp
jsp为什么会出现?
因为在开发web网站时候,发现servlet做界面比较麻烦,于是又有一个新的技术jsp
jsp是什么?
- jsp运行在服务器
- jsp(java server page)
- jsp的基础是servlet(相当于对servlet进行一个包装)
- jsp是综合技术 jsp=html+css+javascript+java代码+jsp标签(servlet)
- jsp无需配置.直接使用,如果你修改了jsp文件,不需要重新reload web应用.
- jsp如何方法 http://ip:8088/web应用名/jsp路径
- jsp是一种动态网页技术.
- 就是有多个<% %>
- 在<% %> 中定义的变量,会成为service函数的局部变量.
- Web服务器在调用jsp时,会给jsp提供一些什么java对象?
供提供了九个
JSP的9个内置对象
对象名 类型 作用域
request:请求对象 javax.servlet.ServletRequest的子类 Request
response:响应对象 javax.servlet.ServletResponse的子类 Page
pageContext:页面上下文对象 javax.servlet.jsp.PageContext Page
session:会话对象 javax.servlet.http.HttpSession Session
application:应用程序对象 javax.servlet.ServletContext Application
out:输出对象 javax.servlet.jsp.JspWriter Page
config:配置对象 javax.servlet.ServletConfig Page
page:页面对象 java.lang.Object Page
exception:异常对象 java.lang.Throwable Page
jsp的语法
- 指令元素
概念: 用于从jsp发送一个信息到容器,比如设置全局变量,文字编码,引入包
- page指令
<%@ page contentType="text/html;charset=gb2312"%>
常用的属性:
contentType 和 pageEncoding的区别
contentType=“text/html;charset=utf-8” 指定网页以什么方式显示页面
pageEncoding=“utf-8” 指定Servlet引擎以什么方法翻译jsp->servlet 并 指定网页以什么方式显示页面
- include指令
用法:<%@ include file=”文件路径” %>
- taglib指令
<mytag:xx 属性 />
- 脚本元素
java片段:<% java 代码 %>
表达式:<%=表达式 %>
定义变量:<%! int i=90; %>
定义函数:<%! public int getResult(int a,int b){return a+b;}%>
函数不能在<% %> 定义.
- 动作元素
<jsp:forward file=””> 的作用
在开发jsp的过程中,我们通常把jsp放入WEB-INF目录,目的是为了防止用户直接访问这些jsp文件.
在WebRoot下我们有一个入口页面,它的主要转发
<jsp:forword file=”/WEB-INF/xx.jsp”></jsp:forword> 写.
<jsp:incluce file=””></jsp:inclcue>
动态引入:
<%@ include file=””%> 静态引入
<jsp:incluce file=””></jsp:incule> 动态引入
相同点: 把一个文件引入到另外一个文件
区别:静态引入 把两个jsp翻译成一个Servlet,所以被引入的文件不要包含<body><html>..
动态引入 把两个jsp分别翻译,所以被引入的jsp包含有<html><body>也可以.