JSP笔记
Tomcat服务器
端口:
端口就是指的某一个程序网络入口,Tomcat的初始化端口为:8080;
端口的个数:256*256=65536个;
一般常见协议的缺省端口为:
http 80
smtp 25
pop3 110
ftp 23
https 443
端口占用查看命令:dos中运行netstat –ano命令
conf文件夹下的server.xml配置文件中的
环境变量配置:
新增一个JAVA_HOME环境变量配置为JDK的根目录,因为Tomcat服务器是java写的所有也需要JVM来运行
文件共享:
第一种:
tomcat服务器会自动扫描webapps这个文件夹,所以我们要共享的web应用目录,就可以放在此文件夹下,也就是说Tomcat服务器webapp目录中的web应用,外界可以直接访问,不需要配置
第二种:
也可以修改conf文件夹下的server.xml配置文件,在Host标签中添加
第三种:
也可以在\conf\Catalina\localhost\目录下面 创建一个任意文件名的.xml文件,在里面配置
Tomcat的目录层次结构:
bin目录 存放的是启动和关闭Tomcat的脚步文件
conf 存放Tomcat服务器的各种配置文件
lib 存放Tomcat服务器的支持jar包
logs 存放Tomcat服务器的日志文件
temp 存放Tomcat运行时产生的临时文件
webapps web应用所在目录,即可以供外界访问的web资源的存放目录
work Tomcat的工作目录
Tomcat服务器的应用管理:(适用于Tomcat7.0,Tomcat6.0角色名用的是manager)
修改\conf文件中的tomcat-users.xml位置文件, 在
manager-gui是角色 然后在设置账号和密码
然后在Tomcat首页打开ManagerApp输入账号密码进入应用管理页面;Start 开始;Stop 停止;Reload 重装;Undeploy 卸载
当我们打开www.mybaidu.com时,运行E:\practice\JSP\practice1\Test\Demo\1.html文件
第一步:
设置Demo工程下WEB-INF中的web.xml配置文件;将1.html设置为缺省页,<welcome-file-list> <welcome-file>1.htmlwelcome-file> welcome-file-list>
第二步:
配置\conf中server.xml文件;在后面添加
第三步:
设置端口为80端口(只限定HTTP协议);配置\conf中server.xml文件;
新建一个主机
在conf文件夹下的server.xml配置文件中,添加一个
Tomcat体系结构
Tomcat服务器启动时会启动一个Server服务,Server服务启动时会启动多个连接器(Connector);
浏览器发送一个HTTP协议然后找到Server服务中与HTTP协议对应的连接器(Connector),然后通过连接器(Connector)找到引擎(Engine),然后再找主机,主机再找WEB应用,最后找到WEB资源
配置https连接器
web工程(Project)
注意:每次创建一个新的工程都需发布到Tomcat服务器,修改代码后需重新部署(Redeploy)一下
war包
jar –vcf 新的文件名.war 要打包的文件夹;用此命令将web工程打包为war包
当war包的文件,放入Tomcat的webapps文件夹中时,会自动解压
目录层次结构
Myeclipse 2013 工程目录结构
工程目录 |
存放java文件的目录 |
存放于java文件对应的class文件 |
存放Web应用目录 |
存放jar包 |
Web应用的配置文件 |
索引页 |
Tomcat工程物理结构
web.xml 配置文件
web.xml只能放在WEB-INF这个文件夹中;
设置项目的缺省首页(不能直接将servlet映射为首页,如果首页必须要经过serlvet转发,那么可以在index.jsp文件中转发至serlvet,再通过此servlet转发至首页)
<welcome-file-list>
<welcome-file>index.jspwelcome-file>
welcome-file-list>
在web应用中注册com.scxh.Test这个serlvet,并取名为Test
<servlet>
<servlet-name>Testservlet-name>
<servlet-class>com.scxh.Testservlet-class>
servlet>
当出现此链接到此工程后,出现.com的后缀就交给Test这个类处理;
<servlet-mapping>
<servlet-name>Testservlet-name>
<url-pattern>*.comurl-pattern>//不能在前面加字符了,如:<url-pattern>aa/*.comurl-pattern>;这样也是不允许的
servlet-mapping>
这个Test可以映射成多个URL(伪静态)这就是servlet的映射,如:
<servlet-mapping>
<servlet-name>Testservlet-name>
<url-pattern>/*url-pattern>//表示‘/‘后面不管跟什么都访问这个类(aa/*;这种方式也可以)
servlet-mapping>
一般Servlet在配置映射时,不要将url-pattern标签配置为”/”;因为’/’通配符表示所有缺省的(找不到的资源)都访问此Servlet;在Conf/web.xml文件中,系统向所有的Servlet都配置了此’/’,当我们访问所有静态资源(如直接访问web工程中的1.html)都会被系统配的’/’ 所捕获到,都是访问的系统自带的Servlet对象;然后再通过这个对象去找你web应用中是否有这个静态资源,有就直接返回,没有就抛404异常(如果我们再设置url-pattern标签配置为’/’就会覆盖系统的设置,当我们再访问有些静态资源时就访问不到)
修饰符的优先级(谁最符合就匹配谁;’*’号越在前面,优先级越低)
HTTP协议
请求头(客户端与服务器交互)
客户端连上服务器后,向服务器请求某个web资源,称之为客户端向服务器发生了一个HTTP请求,一个完整的HTTP请求包括:一个请求行、若干请求头、及实体内容
示例:
GET/books/java.html HTTP/1.1 请求行(请求行用于描述客户端的请求方式、请求的资源名称、及使用的HTTP协议版本)
请求方式:GET(缺省,特点:显示提交,在URL地址后附带的参数是有限的,其数据容量通常不能超过1K; 提交数据显示在url栏中”?”后面);
POST(一般用于表单的提交,则可以再请求的实体内容中向发武器发送数据,传送的数据量无限制,隐式提交);
Accept:*/*
Accept-Language:en-ue
Connection:Keep-Alive 多个请求头(用于描述客户端请求的主机
Host:localhost ,及客户端的一些环境信息等)
Referer:thp://localhost/links.asp
User-Agent:Mozilla/4.0
Accept-Encoding:gzip,deflate
Hello world! 实体内容(一般是表单所提交的内容)
请求头的描述:
Accept: 告诉服务器,客户机所支持的数据类型,如:text/html,image/*; 就是说支持text的html,支持所有的image; 如为:*/*;表示什么都支持
Accept-Charset:ISO-8859-1 告诉服务器,客户机所采用的编码格式
Accept-Encoding:gzip,compress 告诉服务器,客户机所支持的压缩格式
Accept-Language: en-us,zh-cn 告诉服务器,客户机的语言环境
Host:localhost:8080 客户机要访问的主机
If-Modified-Since:Tue,11 jul 2000 18:23:51 GMT 告诉服务器,资源的缓存时间; 我们上一次浏览此网页的时间,发送给服务器,服务器用于比对原网站的更新时间,如果原网站在此时间内更新过数据,就重新返回数据,如没有更新就直接用客户机中缓存内的所缓存的网页
Referer:www.baidu.com 告诉服务器,他是从哪个资源来访问服务器的; 这里表示这是从百度访问的该资源(可以用于防盗链)
User-Agent:Mozilla/4.0(compatible;MSIE 5.5;Windows NT 5.0) 告诉服务器,客户机的软件环境(系统,及浏览器版本等)
Cookie: 客户机通过这个可以向服务器带数据
Connection:close/Keep-Alive 告诉服务器,当这个请求完毕后,是保持连接还是关闭连接; close是关闭连接, Keep-Alive是保持连接
Date:Tue,11 jul 2000 18:23:51 GMT 告诉服务器,客户机当前的时间
UA-CPU:X86 告诉服务器,windows的运行平台,如64位,32位等
If-None-Match:W/* 182-1303717494234
响应头(服务器与客户端交互)
一个http相应代表服务器向客户端回送的数据它包括:一个状态行、若干消息头、以及实体内容
示例:
HTTP/1.1 200 OK 状态行(状态行用于描述服务器对请求的处理结果)
Server:Microsoft-IIS/5.0
Date:Tue,11 jul 2000 18:23:51 GMT 多个消息头(消息头用于描述服务器的基本信息,
Content-Length:2291 以及数据的描述,服务器通过这写数据的描述信息,
Content-Type:text/html 可以通知客户端如何处理等一会它(服务器)回送的数据。)
Cache-control:private
实体内容(一般是网页代码)
响应头的描述
HTTP/1.1 200 OK 描述返回数据的协议版本号、状态码、原因叙述
状态码用于表示服务器对请求的处理结果,它是一个三位的十进制数.相应状态码分为5类,如:
100~199 表示成功接收请求,要求客户端继续提交下一次请求才能完成整个处理过程
200~299 表示成功接收请求并已完成整个处理过程, 常用200
300~399 为完成请求,客户需进一步细化请求.例如,请求的资源已经移动到一个新的地址,常用302、307、304(307和304表示服务器的资源位做修改,可以用客户机上的缓存,302表示去访问Location: 这个头所返回的地址)
400~499 客户端的请求有误,常用404(404表示服务器没有这个资源;403表示服务器拒绝你访问这个资源,请检查是否有权限访问)
500~599 服务器端出现错误, 常用500,(如同一个response对象同时使用字符流和字节流时服务器就会返回此异常,因为它们是互斥的)
Location:www.baidu.com (请求重定向)这个头配合302状态码使用,用于告诉客户端应该转到的地址
Server:Apache-Coyote/1.1 服务器通过这个头,告诉客户端服务器的类型
Content-Encoding:gzip,compress 服务器通过这个头,告诉客户端数据的压缩格式
Content-Length: 服务器通过这个头,告诉客户端压缩后数据的大小
Content-Type:text/html; charset=UTF-8 服务器通过这个头,告诉客户端数据的类型(如要查询要返回的文件类型的详细请查询conf/web.xml)
Last-Modified:Tue,11 jul 2000 18:23:51 GMT 告诉客户端,当前资源最后发布时间
Refresh:1;[url=’http://www.baidu.com’] 告诉浏览器隔多长时间刷新一次[如果在分号后面加上一个地址,表示隔多久时间跳转到这个网站]
Content-Disposition:attachment;filename=文件名 告诉浏览器通过这个头,告诉浏览器以下载方式打开
Transfer-Encoding:chunked 告诉浏览器文件的传送格式
Set-Cookie:ss=Q0=5Lb_nQ;path=/search
Etag:W/”7777-1242234904000” 缓存相关的头
Expires:-1 告诉浏览器,这个资源的缓存时间,-1或0表示不缓存; 如果要缓存,设置为要缓存到的时间
也是控制浏览器要不要缓存数据(浏览器的内核不同,所以响应头比较多)如果要缓存, 设置为要缓存到的时间 |
Cache-Control:no-cache
Pragma:no-cache
Connection:close/Keep-Alive 告诉浏览器请求完毕后是否断开连接
Date:Tue,11 jul 2000 18:23:51 GMT 告诉浏览器,服务器当前的时间
断点下载
请求头
Range头指示服务器只传输一部分Web资源.这个头可以用来实现断点续传功能,Range字段可以通过三种格式设置要传输的字节范围:
Range: bytes=1000-2000
表示请求服务器发送这个资源中1000字节到2000字节之间的内容
Range: bytes=1000-
表示请求服务器发送这个资源中1000字节以后的所有内容
Range: bytes=1000
表示请求服务器发送这个资源中最后1000字节的内容
响应头
Accept-Ranges: 这个头告诉浏览器这个资源是否支持Ranges(断点下载) 支持返回:bytes 不支持返回:none
Content-Ranges:1000-3000/5000指定了返回的Web资源的字节范围。这里表示返回的数据是1000-3000字节之间的内容,这个资源总共有5000个字节
JSP中的路径(java中的路径相对于src目录)
访问资源:
访问时,如果从客户端访问服务器的资源: /工程名/要访问的资源路径; 一般在前端超链接时,后台从定向时使用
访问时,如果直接在服务器端直接访问资源: /要访问的资源路径; 一般在服务器端转发时使用;
服务器访问文件:
在web开发中如果要获取到用到一个文件的位置,只有用绝对路径,比如创建文件流、文件对象、等。
通过 类加载器的 getClassLoader().getResource("相对路径").getPath();返回此文件的绝对路径;或者用getClassLoader().getResourceAsStream("相对路径”) 直接将文件加载到内存中,并返回一个字节输入流对象。这里的相对路径,相对的是WEB-INF/classes 目录。
如果一个要在一个jar包中访问这个jar包中的文件,那么只能将此文件加载到内存中,通过字节输入流对象来获取此文件的数据,因为文件在jar包中,不能获取到绝对路径。
Servlet开发
Servlet生命周期:
l Servlet一般只会在第一次访问时创建,然后一直停留在内存中,直到服务器停止才会被释放(或者这个web应用被删除时),每产生一次请求都会创建一个request和response对象但它们的生命周期很短,当请求和响应完成后就销毁。但Servlet对象只会创建一个
l 服务器启动时创建servlet,需加上
l servlet中尽量使用局部变量,如果要用static全局变量,并要对static变量进行修改的话,就要考虑线程安全问题了,解决线程安全需用线程同步代码块,同步代码块中的代码不能太多,不然会影响性能
<servlet>
<servlet-name>ServletDemo1servlet-name>
<servlet-class>cn.webapp.ServletDemo1servlet-class>
servlet>
l Servlet创建的时候会调用init方法结束时会调destroy方法
新建一个Servlet类它必须继承HttpServlet类或GenericServlet类
继承GenericServlet类需重写service(ServletRequestarg0, ServletResponse arg1)这个方法
继承HttpServlet类需重写doGet或doPost方法是(修改模板路径:MyEclipse\plugins\com.genuitec.eclipse.wizards_11.0.0.me201303311935.jar中templates\Servlet.java文件中修改doGet和doPost)
地址的用法(最好都在前面加上/)
当给浏览器用时,是相对于当前的主机(要在最前面加上项目名称)
当给服务器用时, 是相对于当前的web应用
线程安全
//线程安全
/*SingleThreadModel接口是一个空的接口;如果实现了此接口就表示此对象时一个线程安全的对象;
当一个用户访问当前的Servlet后,下一个用户访问当前的Servlet时发现Servlet有用户,
就会创建出一个新的Servlet对象,这也是在一个服务器中创建两个Servlet的方法
(此方法不推荐使用;太消耗资源,因为Servlet创建后只有关闭服务器才会销毁)
*/
public class ThreadSafe extends HttpServlet implements SingleThreadModel{
public int i = 0;
public void doGet(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
response.setContentType("text/html; charser=utf-8");
response.setCharacterEncoding("utf-8");
request.setCharacterEncoding("utf-8");
i++;
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
// TODO Auto-generatedcatch block
e.printStackTrace();
}
System.out.println(i);
}
public void doPost(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
doGet(request, response);
}
}
Servlet中的六大对象
ServletConfig(servlet配置对象及servlet对象域)
用于封装Servlet的配置信息
可以在工程下的web.xml配置文件中,注册Servlet标签中加上:
<servlet>
<servlet-name>ConfigDemoservlet-name>
<servlet-class>cn.java.ConfigDemoservlet-class>
servlet>
获取方法
import java.io.IOException;
import java.util.Enumeration;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
//获取ServletConfig对象中的值(此值需要在web.xml中注册此servlet标签中加)
public class Test extends HttpServlet {
//privateServletConfig config;//方式一所需定义的全局变量
public void doGet(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
response.setContentType("text/html; charser=utf-8");
response.setCharacterEncoding("utf-8");
request.setCharacterEncoding("utf-8");
//第一种方式获取值
//输出config对象中name1和name2中所映射的值
// System.out.println(config.getInitParameter("name1"));
// System.out.println(config.getInitParameter("name2"));
/*
//第二种方式获取(用第二种方式时不能重写init(ServletConfig config)方法)
//先通过this.getServletConfig()获取到config对象,再通过getInitParameter("name1")获取到name1和name2中所映射的值
System.out.println(this.getServletConfig().getInitParameter("name1"));
System.out.println(this.getServletConfig().getInitParameter("name2"));
*/
/*
//第三种方式,使用迭代(获取全部的config值)
ServletConfigconfig1 = this.getServletConfig();//获取config对象
Enumeration en =config1.getInitParameterNames();//获取config1对象中所有的name,并返回一个列表
while(en.hasMoreElements()){//用这个列表的迭代器进行遍历
String key = (String) en.nextElement();
String value =this.getServletConfig().getInitParameter(key);
System.out.println(value);
}
*/
//第四种直接获取
System.out.println(this.getInitParameter("name1"));
}
public void doPost(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
doGet(request, response);
}
/*
//第一种方式:重写HttpServet父类GenericServlet中的init(ServletConfig config)方法
//此方法会在服务器启动时调用,并将config对象传入进来
@Override
public void init(ServletConfig config)throws ServletException {//获取config对象
// TODO Auto-generated method stub
this.config=config;
}
*/
}
servletContext(代表一个web应用(域))此对象的生命周期为:当web应用发布时创建,卸载web应用时销毁,如果在servlet中要对servletContext域对象中的key值进行更改的话,需考虑线程安全问题
ServletContext.removeAttribute(Stringkey); 删除servletContext对象域中键值的映射关系,不然此键值会一直存活到服务器关闭,会浪费资源
WEB容器在启动时,它会为每个WEB应用程序都创建一个对应的ServletContext对象,它代表”当前web应用”。
SerletConfig对象中维护了ServletContext对象的引用,开发人员在编写servlet时,可以通过servletConfig.getServletContext方法获得ServletContext对象
由于一个WEB应用中的所有Servlet共享同一个ServletContext对象,所以多个Servlet可以通过servletContext对象实现数据共享(ServletContext对象通常也被称之为context域(域就是一个范围,Context域是一个应用范围的域)对象)
n 获取web应用的参数(配置数据库)
<context-param>这是配置整个web应用初始化参数的标签;一个web应用中可以有多个初始化参数的标签-->
<param-name>nameparam-name>
<param-value>haorenparam-value>
context-param>
Stringsex = this.getServletContext().getInitParameter("name");//取出context-param标签中的值;也可以用this.getServletContext().getInitParameterNames();方法获取全部的key;然后再迭代取出value(在ServletConfig对象中有讲过取出value的方式)
System.out.print(sex);
n 数据共享
ServeltDemo1:
this.getServletContext().setAttribute("address", "chengdu");//存入servletContext对象中
ServeltDemo2:
String address =(String) this.getServletContext().getAttribute("address");//取出servletContext对象中的值
n 利用ServletContext对象读取源文件
读取properties文件
//第一种方式
ServletContext servletContext = this.getServletContext();//获取到servletContext对象
InputStream inStream = servletContext.getResourceAsStream("/config.properties");//把/config.properties资源作为一个输入流返回(这里"/" 路径指的是web工程的根目录)
//如果此处的路径写的是相对路径,相对的是Tomcat的bin目录,因为Tomcat的是在此目录中启动的
Properties properties = new Properties();//创建一个properties对象(properties对象中底层是用map集合维护的)
properties.load(inStream);//properties对象中提供了load方法,从流中获取properties文件的值
String name = properties.getProperty("name");//获取properties对象中key是name的value
String url = properties.getProperty("url");//获取properties对象中key是url的value
System.out.println(name+" "+url);
//第二种方式(通过硬盘上的绝对路径访问config.properties文件),此方法可以获取到文件的名称
ServletContext servletContext = this.getServletContext();//获取到servletContext对象
String path = servletContext.getRealPath("/config.properties");//会返回这个路径在硬盘上的绝对路径;这里会返回
//E:\practice\JSP\practice2\Tomcat7.0\webapps\servletContext\config.properties这个路径
String fileName = path.substring(path.lastIndexOf("\\")+1);//这样可以获取到文件的名称;在下载时需要用到
System.out.println("文件名称为:"+fileName);//打印这个文件名称
FileInputStream in = new FileInputStream(path);//有了绝对路径后就可以创建 文件字节流了
Properties properties = new Properties();//创建一个properties对象(properties对象中底层是用map集合维护的)
properties.load(in);//properties对象中提供了load方法,从流中获取properties文件的值
in.close();//关闭流
String name = properties.getProperty("name");//获取properties对象中key是name的value
String url = properties.getProperty("url");//获取properties对象中key是url的value
System.out.println(name+" "+url);
//第三种方式(通过一个普通类加载config.properties文件的方式)
//如果在一个普通类中用ServletContext对象来获取;就是前台应用耦合了后台应用;所以我们应该避免这个用法
//在一个普通类中读取config.properties文件;
public class Test4 {
public static void print() throws IOException {
/*
//此方法获取的输入流(in)不能实时更新(因为是类加载器加载器只加载一次到内存中)
InputStream in = Test4.class.getClassLoader().getResourceAsStream("../../config.properties");
//这里相对的是Tomcat中webapps\servletContext\WEB-INF\classes这个文件夹(如果用类加载器加载文件,这个文件不能太大)
*/
//此方法获取的输入流(in)可以实现实时更新(此方法是得到绝对路径后在创建输出流)
URL url1 = Test4.class.getClassLoader().getResource("../../config.properties");//获取到这个文件的URL
String path = url1.getPath();//通过url获取到这个config.properties文件的绝对路径
InputStream in = new FileInputStream(path);//通过这个绝对路径来创建输入流
Properties properties = new Properties();//创建一个Properties对象
properties.load(in);//properties对象中提供了load方法,从流中获取properties文件的值
in.close();//关闭流
String name = properties.getProperty("name");//获取properties对象中key是name的value
String url = properties.getProperty("url");//获取properties对象中key是url的value
System.out.println("Test4:"+name+" "+url);
}
public static void main(String[] args) {
try {
Test4.print();
} catch (IOException e) {
// TODO Auto-generatedcatch block
e.printStackTrace();
}
}
}
request(请求头对象)用于获取客户端传入的数据
获取表单中的值:
//获取表单提交的数据
public class Test extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponseresponse)//request:请求;response:响应
throws ServletException, IOException{
response.setContentType("text/html; charser=utf-8");//设置浏览器的编码格式
response.setCharacterEncoding("utf-8");//设置响应回传数据的编码格式
request.setCharacterEncoding("utf-8");//设置请求数据的编码格式
//获取表单的参数,除多选框外,其它表单的取值方式都一样
String username = request.getParameter("username");
String password = request.getParameter("password");
String sex = request.getParameter("sex");
String country = request.getParameter("country");
String [] enjoy = request.getParameterValues("enjoy");//多选框用getParameterValues(String arg0)这个方法,并会返回一个String []的数组
String remark = request.getParameter("remark");
PrintWriter out = response.getWriter();//获取到响应对象的输出流
out.print("你的用户名为:"+username+";你的密码为:"+password+";你的性别为:"+sex+";你的国籍为:"+country+";备注为:"+remark);
out.println(";你的爱好为:");
for(int i=0; i
out.print(enjoy[i]+" ");
}
}
public void doPost(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
doGet(request, response);
}
}
//解决提交表单方式为get时出现的乱码问题
public class getMessyCodeextends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException{
response.setContentType("text/html; charser=utf-8");
response.setCharacterEncoding("utf-8");
request.setCharacterEncoding("utf-8");
String text = request.getParameter("text");//获取提交表单的参数
String temp = new String(text.getBytes("ISO8859-1"),"UTF-8");//将ISO8859-1的参数,转换为字节数组后,再传入一个新的字符串,并重新指定编码格式
response.getWriter().print("你提交的为:"+temp);//将数据传送给响应对象的输出流
}
public void doPost(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException{
doGet(request, response);
}
}
通过request对象实现转发:
/*转发
请求重定向与转发的区别
请求重定向: 是向客户端发回一个网址,让浏览器重新去访问(向服务器发出了两次请求;并且网址会变。重定向完成后,再刷新,刷新的是重定向后的网页)
转发: 是通过服务器直接转发到某一个网址(向服务器只发出一次请求;网址不会变。当转发完成后,再刷新,由于网址没变,刷新的还是没转发前的资源,并会再次转发(提交数据时要注意));
总结:所以一般不用请求重定向,一般用转发完成,因为请求重定向会向服务器发出两次请求;转发时要避免因刷新而导致数据重复提交的问题;
*/
//通过request对象实现转发,
public class Test1 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException,IOException {
response.setContentType("text/html; charser=utf-8");
response.setCharacterEncoding("utf-8");
request.setCharacterEncoding("utf-8");
//获取表单中的值
String text = request.getParameter("text");
//向request对象域中存入值
request.setAttribute("text", text);
//如果用转发时不能关闭response对象的流,不然调用forward方法时会抛出异常(但可以设置response响应对象的头,并且转发后还是有效的)
// PrintWriter out = response.getWriter();//Error
//out.print(“asdf”); //Error
//out.close();//Error
//转发到Test12.jsp,并将request, response对象提交过去(最好在跳转完成之后return)
request.getRequestDispatcher("/Test12.jsp").forward(request, response);
return;
}
public void doPost(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
doGet(request, response);
}
}
通过request对象获取请求头的请求资源和所有请求头的值
public class Test2 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
response.setContentType("text/html; charser=utf-8");
response.setCharacterEncoding("utf-8");
request.setCharacterEncoding("utf-8");
//获取请求方式(结果为:GET或POST等)
System.out.println(request.getMethod());
//当后缀名为/com/*时,都会访问到此servlet(我输入的是:http://localhost:8080/request/com/1.html )
//获取请求资源的URI(结果为:/request/com/1.html )
System.out.println(request.getRequestURI());
//获取请求资源的URL(结果为:http://localhost:8080/request/com/1.html )
System.out.println(request.getRequestURL());
//URL代表的是互联网上面的资源地址
//URI代表的是任意一个资源的地址(可以理解为某个服务器上的地址)
//通过request请求头对象,获取一个头的值(这里获取的是客户端所支持的压缩格式)
System.out.println(request.getHeader("Accept-Encoding"));
System.out.println("获取所有的头");
//通过request请求对象得到所有头的名称
Enumeration
while(headerNames.hasMoreElements()){ //判断此枚举是否还有下一个值
String headerName = headerNames.nextElement();//返回它的下一个值
System.out.println(headerName+":"+request.getHeader(headerName));
}
//request.getHeaders("");//当一个头设置了两个值,就用此方法获取
}
public void doPost(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
doGet(request, response);
}
}
通过request对象防止盗链
//防止盗链
public class Test5 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
response.setContentType("text/html; charser=utf-8");
response.setCharacterEncoding("utf-8");
request.setCharacterEncoding("utf-8");
//防止重复提交,此处是验证提交的次数
System.out.println("提交的次数");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generatedcatch block
e.printStackTrace();
}
//获取来访者的url
String path = request.getHeader("referer");
//获取本服务器的主机名
String server = "http://"+request.getServerName();
//判断path的前端是否是server(也就是判断主机名是否相同)
if(path != null && path.startsWith(server)){
//将path和server转入request对象域
request.setAttribute("path", path);
request.setAttribute("server", server);
//转发至Test52.jsp
request.getRequestDispatcher("/Test52.jsp").forward(request, response);
}else{
//不转发
response.getWriter().print("不是本网页的连接");
}
}
public void doPost(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
doGet(request, response);
}
}
比较常用的方法:
request.getRequestURL(); 获取完整的URL
request.getRequestURI(); 只获取请求资源的地址
request.getQueryString(); 获取在地址栏中’?’号后面的所有字符串(所以它只针对get的提交方式有效)
request.getRemoteAddr(); 获取客户机的IP地址
request.getRemoteHost(); 获取客户机的完整主机名(但是客户机的IP要在DNS上注册后才能显示主机名,不然还是显示IP地址)
request.getRemotePort(); 获取浏览器所使用的端口号(当浏览器关闭后再重新打开时端口号会随机变化)
request.getLocalAddr(); 获取WEB服务器的IP地址
request.getLocalName(); 获取WEB服务的主机名
request.getServerName(); 获取WEB服务器的主机名
request.getServerPort(); 货物WEB服务器的端口
request.getMethod(); 获取浏览器的请求方式
request.getHeader(headerName); 根据相应的响应头名字来获取响应的值
request.getHeaders(headerName); 如果同一个响应头有多个值,就用此方法获取,并返回一个Enumeration
request.getContextPath(); 得到当前的工程名:如:/dy19
request.getServletContext().getContextPath(); 得到当前的工程名:如:/dy19
request.getServletPath(); 得到web配置文件<url-pattern>/servlet/UploadServleturl-pattern>此标签中的值
URL与URI的区别
www.sina.com/news/1.html 这就是一个URL
news/1.html 这就是一个URI
URL代表的是互联网上面的资源地址
URI代表的是任意一个资源的地址(可以理解为某个服务器上的地址)
通过request对象获取客户端所提交的数据(通过get或post等,提交的数据)(在上面request对象的第一个知识点中已做过笔记)
//通过request对象获取客户端所提交的数据(通过get或post等,提交的数据)(先要检查用户提交的数据中是否有str这个key)
public class Test3 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
response.setContentType("text/html; charser=utf-8");
response.setCharacterEncoding("utf-8");
request.setCharacterEncoding("utf-8");
System.out.println("-------------------直接通过key获取提交的value--------------------------------");
/*
//客户端用get或post方式提交的数据,都可以用以下方式获取
//如我们在访问时在后面加上数据如:http://localhost:8080/request/servlet/Test3?name=abc&password=123
//或者用表单提交都能获取到
String value = request.getParameter("name");//获取指定名称的值
if(value!=null && !value.trim().equals("")){ //判断是否是没有输入或输入的全部为空格(检查提交的数据合格再使用)
System.out.println("name="+value);//value.trim()方法会删除字符串两边的空格,如果字符串全部都是空格,那么返回的字符串相等于new Stirng("");
}
System.out.println("-------------------先获取到所有请求数据key,再通过迭代取出请求的值--------------------------------");
//获取所有的数据的key,再通过key遍历所有的值
Enumeration
while(names.hasMoreElements()){ //判断此枚举是否还有下一个key
String name = names.nextElement();//获取下一个key
String value1 = request.getParameter(name);//通过key遍历所有的value
System.out.println(name+"="+value1);
}
System.out.println("--------------------获取同一个key有两个value的方法-------------------------------");
//如果提交的数据key有多个相同如:http://localhost:8080/request/servlet/Test3?str=abc&str=123
//这里的str有两个值,就用request.getParameterValues("str");来获取
String[] values = request.getParameterValues("str");//返回str中的多个值
for(int i=0; values!=null && i
System.out.println(values[i]);
}
*/
System.out.println("----------------------将请求的数据以一个map集合返回-----------------------------");
//将提交的数据返回到一个Map集合中提交方式为:http://localhost:8080/request/servlet/Test3?name=abc&name=111&password=123
Map
//遍历输出这个map集合
//获取map中所有的key,以Set集合的方式返回
Set
//获取set集合的迭代器
Iterator
//遍历这个迭代器
while(it.hasNext()){ //判断迭代器是否还有下一个key值
String key = it.next();//获取下一个key
//输出key
System.out.print(key);
//通过key返回所对应的value;返回一个数组,因为同一个key可能有两个以上value
String [] values = map.get(key);
//遍历输入这个values
for(String s:values){
System.out.print(":"+s);
}
//换行
System.out.println();
}
}
public void doPost(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
doGet(request, response);
}
}
通过request.getRequestDispatcher("").include(request,response);方法实现多个页面动态包含(也就是将多个页面的数据同时传给前台)
public class Test6 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
response.setContentType("text/html; charser=utf-8");
response.setCharacterEncoding("utf-8");
request.setCharacterEncoding("utf-8");
//在response对象的返回数据的尾部加上了/Test61.jsp中的内容
request.getRequestDispatcher("/Test61.jsp").include(request, response);
//在response对象的返回数据的尾部添加了我是servlet
response.getWriter().print("我是servlet
");
//在response对象的返回数据的尾部添加了/Test62.jsp中的内容
request.getRequestDispatcher("/Test62.jsp").include(request, response);
/*
所以输出的结果为:
This is my Test61.JSP page.
我是servlet
This is my Test62.JSP page.
*/
}
public void doPost(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
doGet(request, response);
}
}
response(响应头对象)用于向客户端返回数据
根据response对象向浏览器发送数据
//通过response对象的字节流返回数据
response.setHeader("Content-type","text/thml;charset=UTF-8"); //设置头的值,这是是设置Content-type告诉浏览器回送的数据,为html格式,它编码格式为UTF-8
response.setContentType("text/html;charser=utf-8");//设置ContentType(返回数据类型)响应头的数据类型为html格式,编码格式为utf-8
//也相当于是告诉浏览器以什么样的编码格式打开这段数据
response.setCharacterEncoding("utf-8");//设置response对象的编码格式(response对象里面也有对数据进行转码,所以也需要编码格式)
request.setCharacterEncoding("utf-8");//设置request对象的编码格式(request对象里面也有对数据进行转码,所以也需要编码格式)
PrintWriter out = response.getWriter();//获取到字符输出流
out.write("中国");//向字符流中写入数据
out.flush();//移除流中的缓存
out.close();//关闭流
//通过response对象的字符流返回数据
public class Test2 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
response.setContentType("text/html; charser=utf-8");//设置ContentType(返回数据类型)响应头的数据类型为html格式,编码格式为utf-8
//也相当于是告诉浏览器以什么样的编码格式打开这段数据
response.setCharacterEncoding("utf-8");//设置response对象的编码格式(response对象里面也有对数据进行转码,所以也需要编码格式)
request.setCharacterEncoding("utf-8");//设置request对象的编码格式(request对象里面也有对数据进行转码,所以也需要编码格式)
String data = "中国";
PrintWriter out = response.getWriter();//获取到字符输出流
out.write(data);//向字符流中写入数据
out.flush();//移除流中的缓存
out.close();//关闭流
}
public void doPost(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
doGet(request, response);
}
}
提示: 字符流和字节流是互斥的,如果同一个response对象,用了字符流就不能用字节流了,最好都用字节流(从response或request对象中获取的流不需要关闭,因为当servlet对象在销毁时会自动检测这些流是否调用了close方法,然后关闭,但是如果是我们自己new的流必须关闭它,不然会浪费资源)
从浏览器中下载web应用中的资源
String path = this.getServletContext().getRealPath("/image/美女.zip");//获取这个文件的绝对路径
String fileName = path.substring(path.lastIndexOf(File.separator)+1);//获取到这个文件的名字
fileName = URLEncoder.encode(fileName, "UTF-8");//如果为中文名字需要进行转码
response.setHeader("Content-Disposition", "attachment;filename="+fileName);//设置响应头Content-Disposition的值为attachment表示以下载方式打开,后面跟文件名字
FileInputStream in = new FileInputStream(path);//创建一个字节输入流,并指向这个图片
byte[] buffer = new byte[1024];//创建一个缓冲字节数组
int len=0;//定义一个缓冲大小的变量
OutputStream out = response.getOutputStream();//获取response的字节输出流
while((len=in.read(buffer)) > 0){ //判断从输入流中获取的字节数,如果小于或等于0表示没有读取到字节
out.write(buffer,0,len);//将buffer中的缓存写入到 response的字节输出流中
}
//关闭流
in.close();
out.flush();
out.close();
请求重定向
/*请求重定向
请求重定向与转发的区别
请求重定向: 是向客户端发回一个网址,让浏览器重新去访问(向服务器发出了两次请求,并且网址会变)
转发: 是通过服务器直接转发到某一个网址(向服务器只发出一次请求,网址不会变)
总结:所以一般不用请求重定向,一般用转发完成,因为请求重定向会向服务器发出两次请求;
*/
public class Test7 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
response.setContentType("text/html; charser=utf-8");
response.setCharacterEncoding("utf-8");
request.setCharacterEncoding("utf-8");
/*
response.setStatus(302);//设置response对象中状态行的状态码为302,表示请求重定向
response.setHeader("Location","/response/welcome.jsp");//Location此头为请求重定向头,重定向到welcomem.jsp文件
*/
//此方法也可以直接重定向到welcomem.jsp文件
response.sendRedirect("/response/welcome.jsp");
}
public void doPost(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
doGet(request, response);
}
}
设置浏览器定时反复刷新页面或定时重定向
public class Test5 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
response.setContentType("text/html; charser=utf-8");
response.setCharacterEncoding("utf-8");
request.setCharacterEncoding("utf-8");
/*
//不停的刷新
response.setHeader("refresh","3");//表示每隔3秒钟就访问一次此servlet
//产生一个随机数并通过字符流返回
PrintWriter out = response.getWriter();
out.write(new Random().nextInt()+"");
*/
/*
//3秒钟以后可以重定向到其他的网页
response.setHeader("refresh", "3;url='http://www.baidu.com'");//设置refresh(刷新头,设置其值,表示3秒钟后跳转至百度)
PrintWriter out = response.getWriter();
out.write("本网页将在3秒钟后重定向到百度;如果未跳转,情点击href='http://www.baidu.com'>百度");
*/
//最实用的方式,用jsp文件控制页面跳转
//通过meta表示设置jsp文件response对象的响应头,隔3秒跳转至/response/welcome.jsp网页
String str = "" +
//将数据存入ServletContext应用域对象中
this.getServletContext().setAttribute("str", str);
//跳转至MyJsp网页;但先要在web工程下建一个MyJsp.jsp文件,并在body标签中用java代码获取ServletContext应用域对象str中的value如:
//<%//获取servletContext应用域对象中的值String str =(String)application.getAttribute("str"); //通过流向当前的位置输出数据 out.write(str);%>
this.getServletContext().getRequestDispatcher("/MyJsp.jsp").forward(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
doGet(request, response);
}
}
请求重定向时,通过url方式将数据提交给Test41.jsp
Servlet中的代码
//请求重定向时,通过url方式将数据提交给Test41.jsp
public class Test4 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
response.setContentType("text/html; charser=utf-8");
response.setCharacterEncoding("utf-8");
request.setCharacterEncoding("utf-8");
/*
//第一种方式:
//数据
String str = new String("中国");
str = new String(str.getBytes("utf-8"),"ISO-8859-1");
//请求重定向,并将数据传过去
response.sendRedirect("/request/Test41.jsp?str="+str);
*/
/*
//第二种方式:
String value = new String("四川");//数据
String value1 = URLEncoder.encode(value, "UTF-8");//加码
response.sendRedirect("/request/Test41.jsp?value="+value1); //如果直接在url后面跟中文数据,需要对中文进行转码
*/
//加码与解码
String temp = new String("中文数据");
//加码(就是将temp这个UTF-8编码的字符串转换为ISO-8859-1;当某些时候进行中文数据传输时,需要进行加码与解码)
String temp1 = URLEncoder.encode(temp, "UTF-8");
//也就是说加码过后,将temp的值的存储格式变为了默认的ISO-8859-1编码格式
System.out.println(temp1);//打印为:%E4%B8%AD%E6%96%87%E6%95%B0%E6%8D%AE
//解码(将加码过的字符串(ISO-8859-1),转换为对应的编码格式)
String temp2 = URLDecoder.decode(temp1, "UTF-8");
System.out.println(temp2);//打印为:中文数据
}
public void doPost(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
doGet(request, response);
}
}
Jsp中的代码
<body>
<%=new String(request.getParameter("value").getBytes("ISO-8859-1"), "UTF-8") %>
body>
通过修改服务器配置文件,来设置服务器默认的编码格式(但此方法一般不用)
在apache-tomcat-7.0.6\conf\servlet.xml文件中的
或者在末尾添加一个useBodyEncodingForURI=”true”;这个属性是设置URL地址的默认编码格式
控制浏览器对数据的缓存
public class Test6 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
response.setContentType("text/html; charser=utf-8");
response.setCharacterEncoding("utf-8");
request.setCharacterEncoding("utf-8");
/*
//设置浏览器不要缓存(为了使更多的浏览器兼容,所以设置的头比较多)
response.setHeader("expires","-1");
response.setHeader("cache-Control","no-cache");
response.setHeader("pragma","no-cache");
*/
//设置浏览器缓存数据
//设置数据缓存的时间为当前时间加上1小时
response.setDateHeader("expires", System.currentTimeMillis()+(1000*3600));//1000毫秒*3600 ==一小时
String data = new String("aaaaaaaaa");//数据
response.getWriter().write(data);//data的数据会被保存1小时
}
public void doPost(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
doGet(request, response);
}
}
将数据压缩后才传给客户端
public class Test8 extends HttpServlet{
public void doGet(HttpServletRequest request, HttpServletResponseresponse)//request为请求;response为响应头
throws ServletException, IOException {
response.setContentType("text/html; charser=utf-8");
String str = new String("要压缩的数据");
//创建一个字节缓存输出流
ByteArrayOutputStream bout = newByteArrayOutputStream();
//把输出流作为参数,创建一个gzip压缩对象,将压缩后的数据放到缓存流中
GZIPOutputStream gout = new GZIPOutputStream(bout);
//将要压缩数据的字节数组传入压缩对象的write方法中进行压缩
gout.write(str.getBytes());
//关闭压缩
gout.close();
//从缓存输出流中获取压缩后的byte数组数据
byte[] gzip = bout.toByteArray();
//关闭缓存输出流
bout.close();
//设置Content-Encoding(服务器返回数据的压缩格式)响应头的返回值
response.setHeader("Content-Encoding", "gzip");
//设置Content-Length(服务器返回数据压缩后的长度)响应头的返回值
response.setHeader("Content-Length", String.valueOf(gzip.length));
//设置response的传出数据
response.getOutputStream().write(gzip);
//传送过去后浏览器会自动解压显示
}
public void doPost(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
doGet(request, response);
}
}
cookie(缓存数据)
把数据缓存在客户端的硬盘上,一个Cookie只能表示一种信息,它至少含有一个键值
一个WEB站点可以给一个WEB浏览器发送多个Cookie,一个浏览器也可以存储多个WEB站点提供的Cookie
可以调用Cookie对象的setMaxAge()方法设置此Cookie的存储时间即生命周期(单位秒),设置为0表示删除该Cookie;如果不设置保存时间,此Cookie只会保存在用户的内存中,当浏览器关闭释放内存,此Cookie会被删除,删除cookie时,path必须一致,否则不会被删除
浏览器一般只允许存放300个Cookie,每个站点最多存放20个Cookie,每个Cookie的大小限制为4KB
输出用户访问此servlet的次数
public class Test1 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
response.setContentType("text/html; charser=utf-8");
response.setCharacterEncoding("utf-8");
request.setCharacterEncoding("utf-8");
//获得本web应用(/cookie)存储在客户端的cookie
Cookie [] cookies = request.getCookies();
//标记访问的次数
int time = 1;
//判断本web应用是否在客户端存有cookie
if(cookies!=null && cookies.length>0){
//遍历这些cookie
for(int i=0; i
//判断是否是numberOfTimes(次数)这个key
if("numberOfTimes".equals(cookies[i].getName())){
//获得numberOfTimes这个key的值(上次访问的次数)
String value = cookies[i].getValue();
//并删除当前的Cookie
cookies[i].setMaxAge(0);//将存储时间设置为0表示删除此cookie
//将获取的值转换为int类型
int temp = Integer.valueOf(value);
//上次访问的次数加上1,并赋值给time标记
time = ++temp;
}
}
}
//创建一个新的cookie并把numberOfTimes的值设为本次的次数
Cookie cookie = new Cookie("numberOfTimes",time+"");
//设置cookie的保留时间,单位为秒
cookie.setMaxAge(3600);
//设置标识(表示当前cookie是/cookieWEB工程的)
cookie.setPath("/cookie");
//向浏览器返回此cookie(保存在客户机的硬盘上)
response.addCookie(cookie);
//打印用户访问的次数
response.getWriter().print("你是第"+time+"次访问本servlet");
}
public void doPost(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
doGet(request, response);
}
}
session(会话对象)
把数据缓存在服务器端
在WEB开发中,服务器可以为每个用户浏览器创建一个会话对象(session对象),也就是说一个浏览器独占一个session对象(默认情况下).因此,在需要保存用户数据时,服务器可以把用户数据写到用户浏览器独占的session对象中,当用户用浏览器访问其他程序时,其他程序可以从用户的session中取出该用户的数据,为用户服务
Session对象是由服务器创建,我们可以调用request对象的getSession方法得到用户的session对象
Session与cookie的区别:
Cookie是把用户的数据写在用户本地硬盘上
Session是把用户的数据写到服务器为每个用户单独分配的session对象中
当session对象超过30分钟(默认)无访问,就销毁此session对象;调用session对象的getLastAccessedTime()方法返回此session对象最后的访问时间(时间戳)
Session对象的生命周期设置
Session也是依附于cookie的,当服务器新建了一个session对象,就会生成一个id,然后通过cookie将此id返回到客户端上id的key为”JSESSIONID”,然后当用户下次来访问此web应用时是带着session对象的id来的,通过此id我们就可以找到与之对应的session对象 ; 但此cookie对象没有设置保存时间,所以并没有写到客户机的硬盘上,而是在客户机的内存中,当用户关闭浏览器时,此cookie会被自动释放,再打开浏览器就访问不到原有的session对象了; 为了解决此问题我们需要重写一个key为”JSESSIONID”,并设置了保存时间(一般与在web.xml配置文件中配置了的时间一致)的cookie 覆盖掉原有的cookie;session的id可以通过session对象的getId()方法获得; 作用域:此session对象只在本工程中有效
在WEB工程的配置文件web.xml文件中添加一个标签: <session-config>
<session-timeout>10session-timeout>
session-config>
表示session对象在10分钟无人使用的情况下,将被自动销毁
也可以直接调用session对象的invalidate();方法,立即销毁此用户的session对象
通过一个servlet向session对象中存值,一个servlet输出session对象中的值的例题:
Jsp中的代码:
<body>
<a href="servlet/Test1">存a><br/>
<a href="servlet/Test2">取a>
body>
存值的servlet的代码:
//用户访问此Test1 servlet时,向此用户的session对象中存入一个值,当用户访问Test2 servlet时取出用户的session对象所存入的值
//也就是说,当我们第一此获取用户的session对象时,服务器如果没有给此用户创建session对象,那么就给用户新建一个
//session对象的生命周期是:服务器第一次获取用户的session对象 到 此session对象30分钟(默认)不用时就自动释放
public class Test1 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
response.setContentType("text/html; charser=utf-8");
response.setCharacterEncoding("utf-8");
request.setCharacterEncoding("utf-8");
//获取在服务器中获取用户的session对象,如果有就返回,没有就创建一个新的session对象再返回
HttpSession session = request.getSession();
//向此用户的session对象总存入值
String str = "hello";
session.setAttribute("data", str);
//打印此值
response.getWriter().print("存入了:"+str);
/*
Session也是依附于cookie的,当服务器新建了一个session对象,就会生成一个id,
然后通过cookie将此id返回到客户端上id的key为”JSESSIONID”,然后当用户下次来
访问此web应用时是带着session对象的id来的,通过此id我们就可以找到与之对应的session对象 ;
但此cookie对象没有设置保存时间,所以并没有写到客户机的硬盘上,而是在客户机的内存中,
当用户关闭浏览器时,此cookie会被自动释放,再打开浏览器就访问不到原有的session对象了;
为了解决此问题我们需要重写一个key为”JSESSIONID”,并设置了保存时间(一般与在web.xml配置文件中配置了的时间一致)
的cookie 覆盖掉原有的cookie;session的id可以通过session对象的getId()方法获得;
*/
//下面就是覆盖原有cookie的代码
//获取到session对象的id
String sessionId = session.getId();
//创建一个新的cookie对象(并设置一个键值,key必须为JSESSIONID才能覆盖原有的cookie,value为当前session对象的id)
Cookie cookie = new Cookie("JSESSIONID",sessionId);
//设置cookie的存活时间(一般和web.xml配置的session对象的存活时间一致,缺省为30分钟)
cookie.setMaxAge(1800);//存活时间为30分钟,不调用此方法设置值,此cookie将不会被写入客户机的硬盘上
//设置此cookie的站点
cookie.setPath("/session");
//返回给客户机
response.addCookie(cookie);
}
public void doPost(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
doGet(request, response);
}
}
取值的servlet的代码:
//用户访问取出Test1 servlet存在session对象中的值
public class Test2 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
response.setContentType("text/html; charser=utf-8");
response.setCharacterEncoding("utf-8");
request.setCharacterEncoding("utf-8");
//取出此用户的session对象
HttpSession session = request.getSession(false);//传入一个false,表示此方法只获取session对象,并不创建session对象(当没有session对象时)
//HttpSessionsession = request.getSession();//此方法虽然也可以,但如果此用户没有session对象时,此处并不需要创建一个session对象,所以最好用上面这种方法,(可以增加效率)
//再取出此session对象中的data的值
String str = "no";
//判断是否获取到了session对象
if(session != null){
str = (String)session.getAttribute("data");
}
//打印此值
response.getWriter().print("取出了:"+str);
}
public void doPost(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
doGet(request, response);
}
}
当用户禁用cookie后怎么解决传入session对象的id问题(通过url想servlet带入session对象的id,但用户关闭浏览器后将失去session对象,无法避免(上面用cookie可以避免))
上面的servlet中的代码不变 jsp中代码为:
<body>
<%
//当访问首页时就创建此session对象
request.getSession();
//encodeURL()是本应用级别的,encodeRedirectURL()是跨应用的
//此方法会在servlet/Test1后面自动加上session对象的id(重要:如果在servlet重定向跳转时,这里重写url的方法是:response.encodeRedirectURL("servlet/Test1")
Stringurl1 = response.encodeURL("servlet/Test1"); //这里是重写在jsp中跳转页面的url 所以用response.encodeURL("servlet/Test1"))
//此方法会在servlet/Test2后面自动加上session对象的id
Stringurl2 = response.encodeURL("servlet/Test2");
%>
<a href="<%=url1 %>">存a><br/>
<a href="<%=url2 %>">取a>
body>
还有在做登录时需要用到session对象,当用户登录成功后就把user对象存入session中,当注销时就需要调用session对象的invalidate();方法,立即销毁此session对象,也可用session.removeAttribute("user");值删除指定的映射关系(推荐)
base64编码
如果一个字符串用dase64编码, 会将这个字符串的二进制代码的3个字节转换为4个字节,在最高位补0的形式;
如 :
10100110 11110010 00010100
dase64编码后:
00101001 00101111 00001000 00010100
这样每个字节的第值就在0-63之间了,再经过dase64的码表转换过来后就是只有包括了键盘上的所有字符
在java中获得dase64编码对象
sun.misc.BASE64Encoder base64Encoder = new sun.misc.BASE64Encoder();//获得dase64编码对象
String str = base64Encoder.encode(byte[] arg0);//传入一个byte[]数组,将将这个数组用dase64编码,并返回一个新的字符串
在java 中获得dase64解码对象
sun.misc.BASE64Decoderbase64Decoder = new BASE64Decoder();//创建解码对象
byte[] buff =base64Decoder.decodeBuffer(str);//将要解码字符串传入,返回一个byte数组
String token = new String(buff);//通过这个byte数组创建一个字符串
一般在MyEclipse不能用,需用以下方法进行设置
只需要在projectbuild path中的JRE System Library中的Accessible,再重新添加库JRE System Library 的Accessible,Rule Pattarn为**,重新编译后就一切正常了(如下图)
JSP开发
jsp是SUN公司定义的一种用于开发动态web页面的计算,和html不同的是,jsp允许在页面中编写java代码及在页面中获取request、response等对象实现与浏览器交互,所以jsp也是一种web资源开发技术
jsp文件在访问时服务器会将其转换为servlet的java文件(转换后文件的位置Tomcat7.0\work\Catalina\localhost\工程名\org\apache\jsp;
一、jsp中的代码转换后,会被放到此java文件中的_jspService( )方法中
二、因为第一次访问一个jsp文件时,会将此jsp翻译成servlet,所以 jsp文件在第一次访问时会很慢,第二次访问时引擎(就是将jsp转换为servlet的程序)发现jsp文件没有改变就不在翻译,直接访问此servlet所以速度快
三、并且JSP引擎在调用_jspService( )方法时,会传入9个隐式对象(下面JSP隐式对象中讲)
JSP模版元素
JSP中的模板元素定义了网页的基本骨架,即定义了页面的结构和外观
JSP表达式
JSP表达式用于将程序数据输出到客户端 语法<%=变量或表达式 %> 也就是直接在此位置输出数据
服务器会将此语法直接转换为 out.print(变量或表达式);
JSP脚本片断
就是在jsp文件中嵌套<% java代码 %>这就是脚本片断, 可以出现在jsp中的任意位置,脚本片断中只能出现java代码;
Jsp中可以出现多个脚本片断,在两个脚本片断之间可以嵌套文本、HTML标签及其他jsp元素
多个脚本片断中的代码可以相互访问,单个脚本片断中的java语句可以是不完整的,但是多个脚本片断组合后的结果必须是完整的java语句,例如:
<%
for(inti=0; i<5; i++){
%>
hello world!
<%
}
%>
这表示把
hello world!
输出5遍JSP声明
如果在用以下方式定义脚本片断,表示把此脚本片断中的代码放到_jspService( )方法的外面去,例如:
<%!
Publicstatic void fun(){
System.out.println(“helloworld!”);
}
%>
,如果不将此java代码放到_jspService( )方法的外面去,相当于在_jspService()方法的内部定义了一个fun()方法,这样java语法是不允许的;这样我们就也可以在JSP中定义一个成员变量或静态域等功能了
JSP注释
在JSP中的注释方法是<%--被注释的内容 --%>
此方法注释是,当服务器将jsp文件转换为servlet时,会丢弃此注释,并不会向用户返回此注释的代码;如果用 此方法注释,服务器会将此代码发送给客户,会增加网络数据;用此种注释,被注释的javaBean标签也会被servlet翻译,所以在jsp中尽量注意
JSP模板更改
修改模板路径:MyEclipse\plugins\com.genuitec.eclipse.wizards_11.0.0.me201303311935.jar中templates\jsp\Jsp.vtl文件中修改
JSP指令
Jsp指令是为了JSP引擎(就是将jsp转换为servlet的程序)而设计的,它们并不是直接生产任何可见输出,而只告诉引擎如何将jsp页面翻译成servlet,指令只是用于传给引擎,并不会发送给客户机,在jsp2.0中共定义了三个指令:
page指令
语法<%@ 指令 属性名=”值” %>
示例:
<%@ page contentType=”text/html;charset=gb2312” %>
表示告诉引擎 此文件的格式及编码
多个属性可以写在一个指令中(用空格分隔),也可以写在多个指令中
示例:
<%@page contentType=”text/html; charset=gb2312” %>
<%@page import=”java.Util.Date” %>
和
<%@ pagecontentType=”text/html; charset=gb2312” import=”java.Util.Date” %>
是一样的效果
page指令和存放在jsp中的任意位置,但最好放在JSP页面的起始位置
page指令的属性
language=”java” 表示在JSP脚本片断中的代码是java代码
extends=”package.class” 表示此jsp翻译成servlet后继承谁(一般不改)
import=”java.util.Date,java.sql.* ” 表示在此jsp中的脚本片断中的java代码需要导入的包,多个包可以用”,”隔开,也可以写多个page指令导入
jsp中以下包会自动导入
java.lang.*;
javax.servlet.*;
javax.servlet.jsp.*;
javax.servlet.http.*;
session=”true| false” 是否获取此用户的session对象(默认值为true, 获取),如果设为不自动获取, 我们也可以手动通过request对象来获取session对象
buffer=”none| 20kb” 设置out隐式对象的缓存,缺省默认为8KB的缓存,none为不缓存
autoFlush=”true| false” 设置out隐式对象的缓存满后是否自动刷新,一般不改(默认为true, 自动刷新)
isThreadSafe=”true| false” 设置此jsp的线程是否是安全的(默认为true, 是线程安全的),如果设置为false 那么此jsp翻译成servlet后会实现SingleThreadModel接口以确保线程安全(SingleThreadModel接口上面已讲过);
info=”text” 可以通过此属性带信息
errorPage=”relative_url” 指定当此jsp页面出现异常后,转向哪个页面,此路径必须使用相对路径,如果以”/”开头表示相对于当前应用的程序的根目录, 否则相对于当前的页面位置
此属性只是设置此jsp异常时跳转的页面,也可以再web.xml文件中配置全局的异常跳转页面,如:
<error-page>
<exception-type>java.lang.ArithmeticExceptionexception-type>
<location>/error.jsplocation>
error-page>
表示当前web应用中所有的serlvet及jsp文件抛出java.lang.ArithmeticException异常后将跳转至/error.jsp这个jsp文件
<error-page>
<error-code>404error-code>
<location>/error.jsplocation>
error-page>
表示当前web应用抛出404(找不到资源)异常后,就跳转至/error.jsp这个jsp文件
如果在一个jsp文件中设置了errorPage的属性,那么在web.xml文件中设置的异常跳转,将不对此jsp页面起作用
isErrorPage=”true | false” 设置当前页面是否为错误处理页面(默认值为false,不是错误处理页面),如果将此属性设为true,那么此jsp会接收一个异常对象(exception)
contentType=”text/html;charset=ISO-8859-1” 告诉告诉浏览器打开此文件的格式及编码 (也就是设置response的Content-Type头属性的值)
pageEncoding=”characterSet |ISO-8859-1” 也是设置编码格式的
isELIgnored="true | false" 是否忽略EL表达式,默认为false(不忽略);
include指令
语法<%@ includefile=” /Test1/head.jsp” %>
用此指令包含 属于静态包含
静态包含,在将jsp转换为servlet时就将要包含的jsp文件整合成一个servlet,在返回给客户机,所以静态包含只有一个serlvet,效率高
用request.getRequestDispatcher("/Test1/head.jsp").include(request,response);方法包含就是动态包含
动态包含,就是包含者需要访问被包含者时,再去访问被包含者的servlet,所以包含了多少个jsp文件就会多出多少个servlet,效率低
注意事项: 被包含者不能有外部的框架(框架代码) ,因为包含时会将被包含者文件中的所有字符都包含到其中
taglib指令
taglib指令用于在JSP页面中导入标签库,语法:<%@ taglib url=” http://java.sun.com/jsp/jstl/core” prifix=”c”%>
JSP隐式对象
JSP引擎在调用_jspService()方法时,会传入9个隐式对象(注意cookie不是一个隐式对象)
request 请求对象(已讲)
response 响应对象(已讲)
session 回话对象(已讲)
application servletContext对象(已讲)
config servletConfig对象(已讲)
page 当前的servlet(this)对象,因接收时转换成了Object对象,所以用时要强转为org.apache.jasper.runtime.HttpJspBase(已讲)
exception 错误对象,当只有page指令的isErrorPage属性设置为”true”(表示此页面是错误处理页面)时才会传入此对象(此对象继承了Exception对象, 已讲)
out
out 隐式对象用于向客户发送字符数据
out对象通过pageContext对象的getOut方法获得,其作用和用法与response.getWriter()方法非常相似。
此out隐式对象的类型为JspWriter,JspWriter相当于一种带缓存功能的PringtWriter,设置JSP页面的page指令的buffer属性可以调整此out对象的缓存大小,也可以关闭缓存
只有向此out对象中写入了内容,且满足以下任何一个条件, out对象才去调用response.getWriter()方法,并通过该方法返回的PrintWriter输出流对象将out对象的缓冲区的内容正真写入到Servlet引擎提供的缓冲区域中;
1、设置page指令的buffer属性的值为:none,关闭out对象的缓存
2、out对象的缓存区已满
3、jsp页面结束
注意事项: 此out对象不要和response.getWriter流对象一起使用 ,不然会出现输出顺序不一致的异常
pageContext
1、 pageContext对象是JSP技术中最中意的一个对象,它代表JSP页面的运行环境
2、 pageContext对象封装了其他8大隐式对象的引用
3、 pageContext对象它自身就是一个域对象,可以用来存储数据
4、 pageContext对象还封装了web开发中经常涉及到的一些常用的操作, 如包含和转发到其他资源, 检索其他域对象中的属性等
5、 生命周期: 当jsp文件执行完成后,此域就被销毁了
获取其它隐式对象的方法
pageContext.getEcception(); 获取exception隐式对象
pageContext.getPage(); 获取page隐式对象(this)
pageContext.getRequest(); 获取request(请求)隐式对象
pageContext.getResponse(); 获取response(响应)隐式对象
pageContext.getServletConfig(); 获取servletConfig隐式对象
pageContext.getServletContext(); 获取servletContext隐式对象
pageContext.getSession(); 获取session隐式对象
pageContext.getOut(); 获取out隐式对象
pageContext对象中域方法
pageContext.setAttribute(Stringkey,String value); 向pageContext域中存入值,注意pageContext对象的生命周期是:当前的jsp文件执行完成后就消失了,所以要注意pageContext的使用范围
pageContext.getAttribute(Stringkey); 获取pageContext对象域中的映射值
pageContext.removeAttribute(Stringkey); 删除pageContext对象中的映射关系
pageContext对象中访问其它三个域的方法
pageContext对象中有代表各个域的常量(int 类型)
pageContext.APPLICATION_SCOPE 表示application (servletContext)对象
pageContext.SESSION_SCOPE 表示session对象
pageContext.REQUEST_SCOPE 表示request对象
pageContext.PAGE_SCOPE 表示当前的pageContext对象
pageContext对象中有获取其他域中键值的方法
pageContext.getAttribute(Stringkey, pageContext.SESSION_SCOPE); 表示获取session对象中的映射关系pageContext.SESSION_SCOPE这个常量代表session对象
pageContext.setAttribute(Stringkey, String value, pageContext.SESSION_SCOPE); 表示设置session对象中的映射关系
pageContext.removeAttribute(Stringkey, pageContext.SESSION_SCOPE); 表示删除session对象中的映射关系
pageContext.findAttribute方法
pageContext.findAttribute(String key); 此方法是遍历获取所有域中的键值关系(顺序: pageContext-> request -> session -> application(servletContext))如果在request对象中找到了此映射关系的值,那么将不会在向下继续寻找,如四个域中都没找到此键值关系,就返回一个“”字符串,并不是“null”
pageContext对象中定义了forward(转发)方法和include(动态包含)方法分别用来简化和代替request.getRequestDispatcher(“url”).forward(request, response)方法;参数是要转发的url(加”/”表示当前的web应用根目录)。但这两个方法,会将除了pageContext这个域对象以外的所有对象转发或包含过去
servlet中的四大域对象有:
pageContext 当jsp文件执行完成后,此域就被销毁了
request 当request对象销毁是,此域就被销毁了
session session对象域的存活时间是可以调整的,默认情况下30分钟无操作自动销毁
servletContext 当前web应用中的所有资源都可以访问此域,此对象的存活时间为, 当服务器启动就创建, 当服务器关闭时销毁(一般存储在此域中的键值在不用时都要用.removeAttribute(String key)方法来删除此键值,不然会浪费资源)
JSP标签
JSP标签页称为JSP Action(JSP动作)元素,它用于在jsp页面中提供业务逻辑功能,避免在JSP页面中直接编写java代码造成jsp页面难以维护
jsp中有如下三个常用的标签:
语法:
语法:
语法:
用法:
这样我们就可以在/servlet中用request. getParameter("key");方法来获取key的值, 也就是说可以通过
JSP映射与serlvet的映射
servlet的映射(前面已讲过)
在web应用中注册com.scxh.Test这个serlvet,并取名为Test
<servlet>
<servlet-name>Testservlet-name>
<servlet-class>com.scxh.Testservlet-class>//不加“/”相对于classes目录,加上相对于当前的web目录,此处不用加
servlet>
serlvet的映射
<servlet-mapping>
<servlet-name>Testservlet-name>
<url-pattern>*.comurl-pattern>//不能在前面加字符了,如:<url-pattern>aa/*.comurl-pattern>;这样也是不允许的
servlet-mapping>
JSP的映射
在web应用中注册这个head.jsp文件并取名为head
<servlet>
<servlet-name>headservlet-name>
<jsp-file>/Test1/head.jspjsp-file>//不加“/”相对于classes目录,加上相对于当前的web目录,此处需加上
servlet>
映射这个jsp
<servlet-mapping>
<servlet-name>headservlet-name>
<url-pattern>/head.htlmurl-pattern>//这样我们就可以再浏览器值直接工程名/head.htlm 访问head.jsp文件了
servlet-mapping>
JavaBean
JavaBean一般用于封装数据的实体,JavaBean是一个遵循特定写法的java类, 它通常具有如下特点:
1. 这个java类必须具有一个无参的构造函数
2. 属性必须私有化
3. 私有化的属性必须有public类型的set和get方法(set方法称为对属性的修改器,get方法称为属性的访问)
4. 必须放在一个java文件中并且此类必须为public类型的
JSP中提供了三个标签用于操作javaBean
示例:
JSP中的代码:
<jsp:useBean id="ren" class="cn.Demo1" scope="page">jsp:useBean> <%--如果这个scope属性不缺省,默认值为“page“--%>
<%=ren.getName() %>
转换为servlet后的代码
cn.Demo1ren= null; //创建一个cn.Demo1这个类的引用变量,取名为
//到pageContext域对象中去取ren这个映射关系
ren =(cn.Demo1)_jspx_page_context.getAttribute("ren", PageContext.PAGE_SCOPE);
//判断是否取到,没有取到就在内存中创建个新的对象
if (ren == null){
//创建一个新的对象
ren = new cn.Demo1();
//并把此对象存入pageContext域中,key值为引用的变量名
_jspx_page_context.setAttribute("ren",ren, PageContext.PAGE_SCOPE);
}
也就是说当我们在
注意事项:
嵌套的代码
在
通过Bean对象的属性名来给此属性赋值(配合
<%--
<%-- 通过Bean为"ren"对象中的"gender"属性赋值为”女“ --%>
<jsp:setProperty name="ren" property="gender"value="女"/>
<%=ren.getGender() %><%-- 打印的值为:”女“ --%>
<%="
1-----------------------------------------------------------------
" %>
<%-- 可以用字符串为8大基本类型赋值(会自动将字符串转换为向对应的类) --%>
<jsp:setProperty name="ren" property="id"value="13"/><%--这里的id属性为int类型,赋值字符串会自动转换 --%>
<%=ren.getId() %><%-- 打印的值为:”13“ --%>
<%="
2-----------------------------------------------------------------
" %>
<%-- 通过请求参数为ren对象的password赋值 --%>
<%-- 提交的方式为:http://localhost:8080/javaBean/Test1/Demo1.jsp?password=abc123 --%>
<jsp:setProperty name="ren" property="password"param="password"/>
<%=ren.getPassword() %><%-- 打印的值为:”abc123“ --%>
<%--param="password" 这句话会被翻译成 request.getParameter("password");
也就是所从我们提交的数据中去找password这可以key的值,找到了就赋值,没有这个key就不赋值--%>
<%="
3-----------------------------------------------------------------
" %>
<%-- 通过请求参数为ren对象的date赋值(date为Date日期对象) --%>
<%-- 提交的方式为:http://localhost:8080/javaBean/Test1/Demo1.jsp?date=2012-5-19 --%>
<%-- Date date = newSimpleDateFormat("yyyy-MM-dd").parse(request.getParameter("date"));--%>
<%--
<%=ren.getDate() %><%--打印的值为:Sat May 19 00:00:00 CST 2012 --%>
<%--从以上value="<%=date %>代码出可以看出,value的值可以引用java代码所返回的值 --%>
<%="
4-----------------------------------------------------------------
" %>
<%-- 通过请求参数自动为ren对象对应的属性赋值 --%>
<%-- 提交的方式为:http://localhost:8080/javaBean/Test1/Demo1.jsp?name=lishi&gender=nan
注意此处用中文会出现get方式提交乱码问题(前面已讲过怎么解决)--%>
<jsp:setProperty name="ren"property="*" /><%--还可以写为<jsp:setProperty name="ren"property="name" />表示从请求中找到name这个key,并赋值给ren这个对象-->
<%=ren.getName() %><%--打印的值为:lishi --%>
<%=ren.getGender() %><%--打印的值为:nan --%>
<%-- 如果property="*"的话,那么表示根据名称自动匹配请求参数的key给ren对象中和此key一样的属性赋值--%>
此标签用于读取JavaBean对象的属性,也就是调用属性的get方法,然后将读取属性的值转换成字符串后插入响应的正文中,如果某个属性的值为null,那么输出的内容为字符串”null”
语法:
<jsp:getProperty name="ren" property="name"/>
<%--表示直接输出ren这个Bean对象的name属性,如果此属性的值为null,那么将输出"null"字符串 --%>
JSP设计模式
JSP+JavaBean模式
此模式适合开发逻辑不太复杂的web应用程序,这种模式下,JavaBean用于封装业务数据,JSP即负责处理用户请求,又显示数据
Servlet(controller)+JSP(view)+JavaBean(model)称为MVC模式
此模式适合开发复杂的web应用,在这种模式下,serlvet复杂处理用户请求,JSP负责显示数据,JavaBean负责封装数据,采用此MVC模式各个模块之间层次清晰,web开发推荐采用此模式
此模式分为三层:web层、业务逻辑层(service)、数据访问层(dao)
Web层分
处理用户请求
Service(业务逻辑层)
处理dao层返回的数据,及封装这些数据
Dao(数据访问层)
访问数据库
包名规范
cn.itcast.domain 存放javaBean的类
cn.itcast.dao 存放Dao层的类
cn.itcast.dao.impl 存放Dao层的接口
cn.itcast.servce 存放Service层的类
cn.itcast.servce.impl 存放servlce层的接口
cn.itcast.web.serlvet名 存放处理用户请求的servlet+JSP
cn.itcast.web.listener
cn.itcast.web.filter
cn.itcast.utils 存放工具类的包
Junit.test 存放测试的程序
在MVC模式下的jsp文件必须放在WEB-INF/jsp目录中防止客户端直接访问
MVC模式开发的流程图:
EL表达式
EL表达式语法:${date }如果在jsp中用此语句,那么表示到每个域中去找date的映射关系,找到了就返回此date的value,如果没有找到就返回一个“”为空的字符串;
此表达式会翻译成servlet的代码:pageContext.findAttribute(date); 此方法是遍历获取所有域中的键值关系(顺序: pageContext-> request -> session -> application(servletContext))如果在request对象中找到了此映射关系的值,那么将不会在向下继续寻找,如四个域中都没找到此键值关系,就返回一个“”字符串,并不是“null”(上面已讲过)(可以从指定域中获取指定的映射关系)
如果存入的是一个key键所对应的是一个Bean对象,EL表达式语法为:${date.name}; 那么当取出date对象后会去调用name属性的get方法,并返回其值
在WEB开发中,如果JS中要用到EL表达式,在JSP引入JS文件时,可以把js文件命名为.jsp文件就可以了,这样里面el就能运行,也就是服务器可以执行这个文件了。无非页面引用的时候引用jsp就可以了。
如: