转载自:http://www.cnblogs.com/happyfans/archive/2015/03/17/4343571.html
1.java web简介
1.1静态页面与动态页面
表现形式
所需技术
静态网页
网页内容固定,不会更新
html,css
动态网页
网页内容由程序动态显示,自动更新
html,css,DB,java/c#/php,javascript,xml,主流的动态网页脚本(jsp,asp.net,php)
1.2搭建java web开发环境
jdk1.7+tomcat7.0+MyEclipse10。关于MyEclipse的安装和配置请参见http://blog.sina.com.cn/s/blog_907043b301016jtp.html。Tomcat服务器是Apache Jakarta的开源项目,是Jsp/Servlet容器。安装Tomcat只需要解压zip包到指定目录即可。新建一个环境变量CATALINA_HOME,变量的值是Tomcat的根目录D:\Program Files (x86)\apache-tomcat-7.0.57。全部的环境变量如下:
变量名
变量值
JAVA_HOME
D:\Program Files (x86)\Java\jdk1.7.0_40
Path
C:\Program Files\Microsoft SQL Server\100\DTS\Binn\;%JAVA_HOME%\bin;D:\Program Files\Sublime Text 3;D:\Program Files\MySQL\MySQL Utilities 1.3.6\
classpath
.;%JAVA_HOME%\lib\rt.jar;%JAVA_HOME%\lib\tools.jar;
CATALINA_HOME
D:\Program Files (x86)\apache-tomcat-7.0.57
之后我们测试一下Tomcat的首页:
进入Tomcat服务器根目录下面的bin目录,以管理员方式运行startup.bat,如果运行结果如下就表示Tomcat服务器启动成功。
注意:不要关闭这个窗口(关闭窗口就意味着关闭了Tomcat服务器,将其最小化)。
在浏览器地址栏输入http://localhost:8080/回车得到如下页面:
1.3Tomcat目录结构
1.4手工编写第一个web应用程序
在项目文件夹中创建一个index.jsp:
1
2
3
4
5
手工编写的第一个java web项目6
7
8
这是手工编写的第一个java web项目——jsp
9
10
11
在项目目录中创建一个WEB-INF目录拷贝/webapps/examples/WEB-INFO/web.xm到自己项目的/myJspProject/WEB-INFO中,在/myJspProject/WEB-INFO中创建两个文件夹:classes和lib。最后的项目目录应该是这样:
测试:浏览器输入:http://localhost:8080/myJspProject/index.jsp回车,运行结果如下:
解决方法:更改浏览器编码为指定编码:
1.5WEB-INF目录详解
该目录是java web应用的安全目录。所谓安全目录就是客户端无法访问只有服务端可以访问的目录。其中web.xml是项目部署文件,classes目录:存放*.class文件,lib目录存放需要的jar包。例如:我们在WEB-INF中创建一个test.html,下面我们通过浏览器访问:
web.xml配置文件可以配置欢迎页面默认的欢迎页面是项目下面的index.jsp,加入我们需要将项目下的haha.jsp,在/WEB-INF/web.xml的web-app标记中添加以下代码:
1
2 /haha.jsp
3
运行结果:
1.6实用Eclipse编写第一个web应用程序
注意:如果要使用Eclipse编写java web应用应该使用Eclipse的J2EE版本。并在Eclipse中配置Tomcat服务器Window-Preference-Server-Runtime Environment-Add,然后在WebContent目录下新建jsp文件,按下Ctrl+F11(或者在项目中右键-Run On Server)就可以使用内置浏览器访问建立的网站。
1.7用MyEclipse编写第一个web应用程序
在新建项目之前首先在MyEclipse中配置jre和tomcat。步骤Window-Preference-Java-Install JREs-Add;Window-MyEclipse-Servers-Tomcat(注意设置tomcat的jre并将服务器设置为Enabled)。
接下来在MyEclipse中启动Tomcat服务器:
测试首页http://localhost:8080/证明Tomcat正常启动,我们就可以在MyEclipse中启动和发布Web应用程序了。
New一个WebProject会生成以下的目录结构(默认在WebRoot目录下有一个index.jsp)。
发布该WebApp。
1.8理解项目的虚拟路径
该虚拟路径是可以修改的项目上右键属性-MyEclipse-Web。
重新部署,浏览器需要使用使用http://localhost:8080/hello/index.jsp访问了。
1.7修改Tomcat默认端口
修改conf目录下的server.xml的以下标记:
2.jsp语法基础
2.1jsp简介
jsp的全名是Java Server Page,是一个简化的Servlet设计,它实现了在java当中使用html标记。jsp是一种动态网页技术,符合J2EE标准。jsp和Servlet一样也是在服务器端执行的。
2.2常见动态网站开发技术对比
平台
特点
jsp
跨平台,安全性高,适合开发大型的、企业级的Web应用、分布式应用(Hadoop)。例如:12306、10086.cn、网上银行
asp.net
简单易学,安全性和跨平台性差
php
简单、高效、成本低、开发周期短,适合中小型企业的Web应用开发(LAMP)
2.3jsp页面元素简介以及page指令
page指令语法:
属性
描述
默认值
language
jsp页面所使用的脚本语言
java
import
引用脚本语言中所要使用的类文件
无
contentType
指定jsp页面的编码
text/html,ISO-8859-1
新建一个java web工程默认的jsp页面开头有一个page指令:
默认的编码是ISO-8859-1,不支持中文,这里建议使用另一个属性contentType。将第一行改为如下:
这样就支持中文了。
page指令的全部属性如下:
1
2 [language="Java"]
3 [extends="package.class"] // 指定JSP页面编译所产生的Java类所继承的父类,或所实现的接口。
4 [import="package.class│package.*,…"]
5 [session="true│false"]
6 [buffer="none│8kb│size kb"]
7 [autoFlush="true│false"]
8 [isThreadSafe="true│false"]
9 [info="text"]
10 [errorPage="relativeURL"] // 指定错误处理页面。因为JSP内建了异常机制支持,所以JSP可以不处理异常。
11 [contentType="mimeType[;charset=characterSet]"│"text/html;charSet=ISO8859-1"]
12 [isErrorPage="true│false"] // 设置本JSP页面是否为错误处理程序。
13 %>
注意:除page指令中的import属性之外,其他属性均只能设置一次。
2.4jsp注释
分为3种:html注释,jsp注释,jsp脚本注释。语法:
1
2
3
4 /*这里是jsp脚本注释 有两种*/
5
6 //单行注释
7
8 /*多行注释*/
9 %>
例如:
1
2
3 String path = request.getContextPath();
4 String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
5 %>
6
7
8
9
10
11
12
My JSP 'index.jsp' starting page13
14
15
16
17
18
21
22
23
24
欢迎你
25
26
27
28 /*这里是jsp脚本注释
29 有两种*/
30 //单行注释
31 /*多行注释*/
32 %>
33
34
将项目部署到Tomcat,客户端用浏览器查看源代码:
2.5jsp脚本
在jsp页面中执行的java代码。语法:
1
2
3 String path = request.getContextPath();
4 String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
5 %>
6
7
8
9
10
11
12
My JSP 'index.jsp' starting page13
14
15
16
17
18
21
22
23
24
欢迎你
25
26
27 out.println("通过jsp内置对象out对象打印输出");
28 %>
29
30
2.6jsp声明
jsp页面中定义变量或者方法。语法:
例如:
1
2 String s = "张三"; //声明一个String类型的变量
3 int add(int x,int y){ //声明一个返回值为int类型的方法
4 return x+y;
5 }
6 %>
2.7jsp表达式
jsp页面中执行的表达式。语法(注意=紧挨着百分号,表达式末尾没有分号):
1
2
3 String path = request.getContextPath();
4 String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
5 %>
6
7
8
9
10
11
12
My JSP 'index.jsp' starting page13
14
15
16
17
18
21
22
23
24
欢迎你
25
26
27
28 String s = "张三"; //声明一个String类型的变量
29 int add(int x,int y){ //声明一个返回值为int类型的方法
30 return x+y;
31 }
32 %>
33 你好:
34 令x=10,y=5,则x+y =
35
36
运行结果:
2.8jsp页面生命周期
jspService()方法被调用来处理客户端的请求。对每一个请求,JSP引擎创建一个新的线程来处理该请求。如果有多个客户端同时请求你该jsp文件,则jsp引擎会创建多个线程(每一个客户端请求对应一个线程)。以多线程的方式执行可以大大降低对系统的资源需求,提高系统的并发量以及缩短服务器的响应时间——但是同时要注意多线程的同步问题。由于该Servlet常驻内存,所以响应是非常快的。
当页面没有被访问的时候work目录下没有相关的Servlet。如果页面被访问之后就会在work目录的对应目录生成响应的Servlet。如图:
打开index_jsp.java会看到以下的初始化方法:
然后该Servlet常驻内存,创建线程处理每一个客户端的请求。由每一个线程调用_jspService()方法来处理请求。
如果jsp页面内容发生了改变,jsp引擎就需要重新编译jsp页面。我们修改index.jsp,用浏览器重新访问,则:
2.9阶段项目(九九乘法表)
1
2
3 contentType="text/html; charset=utf-8"%>
4
5 String path = request.getContextPath();
6 String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
7 %>
8
9
10
11
12
13
14
My JSP 'multiplicationTable.jsp' starting page15
16
17
18
19
20
21
22
23
24
25
26
九九乘法表
27
表达式的方式打印乘法表
28
29 //声明表达式
30 String printMultiTable(){
31 StringBuilder s = new StringBuilder();
32 for(int i=1;i<=9;i++){
33 for(int j=1;j<=i;j++){
34 s.append(i+" * "+j+" = "+i*j+"\t");
35 }
36 s.append("
");//追加换行标记,注意不能使用\n
37 }
38 return s.toString();
39 }
40 %>
41
42 %>
43
44
使用脚本的方式打印九九乘法表
45
46 //jsp小脚本
47 void printMultiTable2(JspWriter out) throws IOException{
48 StringBuilder s = new StringBuilder();
49 for(int i=1;i<=9;i++){
50 for(int j =1;j<=i;j++){
51 s.append(i+" * "+j+" = "+i*j+"\t");
52 }
53 s.append("
");
54 }
55 out.println(s.toString());
56 }
57 %>
58
59
60 //调用脚本
61 printMultiTable2(out);
62 %>
63
64
运行结果:
3.jsp内置对象
3.1jsp内置对象简介
JSP内置对象是Web容器创建的一组对象,不需要使用new关键字,JSP规范将它们完成了默认初始化(由JSP页面对应Servlet的_jspService()方法来创建这些实例)。例如打印九九乘法表的jsp小脚本中使用的out对象就是jsp内置对象。
1
2 //jsp小脚本
3 void printMultiTable2(JspWriter out) throws IOException{
4 StringBuilder s = new StringBuilder();
5 for(int i=1;i<=9;i++){
6 for(int j =1;j<=i;j++){
7 s.append(i+" * "+j+" = "+i*j+"\t");
8 }
9 s.append("
");
10 }
11 out.println(s.toString());//这里的out就是jsp内置对象
12 }
13 %>
JSP一共有9个内置对象,其中常用的内置对象有5个,如图所示:
3.3out对象
缓冲区(Buffer)就是内存中用来保存临时数据的一块区域。关于缓冲区有一个很形象的例子:比如我们煮好了饭放在锅里,如果我们一粒一粒地来吃米饭就不知道吃到猴年马月,拿来一个碗来一碗一碗吃,岂不快哉!这里的碗就充当了缓冲区的概念。其实IO的本质就是直接操作字节,但是效率太慢所以引入了缓冲区。
out对象是JspWriter类的一个实例——是向客户端输出内容的常用对象,该对象的常用方法:
1 void println(String message); // 向客户端打印字符串
2 void clear(); // 清除缓冲区内容,如果在flush之后调用会抛出异常
3 void clearBuffer(); // 清除缓冲区内容,如果在flush之后调用不会抛出异常
4 void flush(); // 将缓冲区的内容输出到客户端
5 int getBufferSize(); // 返回缓冲区的大小(字节),默认是0
6 int getRemaining(); // 返回缓冲区可用容量
7 boolean isAutoFlush(); // 返回缓冲区满的时候是自动清空还是抛出异常
8 void close(); // 关闭输出流
下面是一个简单的示例:
1
JSP的out内置对象
2
3 //jsp脚本
4 out.println("
静夜思
");5 out.println("李白
");
6 out.println("窗前明月光,
");
7 out.println("疑是地上霜。
");
8 out.println("举头望明月,
");
9 out.println("低头思故乡。
");
10 %>
11
12 缓冲区大小:字节。
13 剩余缓冲区(可用缓冲区):字节。
14 是否自动清空缓冲区:
运行结果:
1
JSP的out内置对象
2
3 //jsp脚本
4 out.println("
静夜思
");5 out.println("李白
");
6 out.println("窗前明月光,
");
7 out.flush();//将缓冲区中的内容输出到客户端
8 out.println("疑是地上霜。
");
9 out.println("举头望明月,
");
10 out.println("低头思故乡。
");
11 %>
12
13 缓冲区大小:字节。
14 剩余缓冲区(可用缓冲区):字节。
15 是否自动清空缓冲区:
如果在第7行强制刷新缓冲区,则输出的页面不会有任何变化,仅仅是可用缓冲区的数量变多了而已【因为flush清空了缓冲区】
1
2 //jsp脚本
3 out.println("
静夜思
");4 out.println("李白
");
5 out.println("窗前明月光,
");
6
7 out.flush();//将缓冲区中的内容输出到客户端
8 out.clear();//在flush之后调用clear,将会抛出异常
9
10 out.println("疑是地上霜。
");
11 out.println("举头望明月,
");
12 out.println("低头思故乡。
");
13 %>
运行结果:
1
2 //jsp脚本
3 out.println("
静夜思
");4 out.println("李白
");
5 out.println("窗前明月光,
");
6
7 out.flush();//将缓冲区中的内容输出到客户端
8 out.clearBuffer();//在flush之后调用clearBuffer不会抛出异常
9
10 out.println("疑是地上霜。
");
11 out.println("举头望明月,
");
12 out.println("低头思故乡。
");
13 %>
运行结果:
3.4post和get提交方式的区别
get:以明文的方式通过URL提交数据,提交的数据最大不超过2K。适合提交数据量小,安全性不高的数据【例如:搜索和查询】
post:将用户提交的数据封装在URL HEADER内。适合提交数据量大,安全性高的数据【例如:注册、修改、上传】
下面以用户登录的例子比较两者的区别:
login.jsp页面
1 请输入用户名和密码:
2
3 用户名:
4 密码:
5
6
处理登录的动作脚本dologin.jsp仅仅是显示一句话"登录成功"。
运行结果:
将用户登录表单的get方式改为post。
3.5request对象
客户端的请求被封装在request对象中,通过它才能了解到客户端的需求,然后做出响应。它是HttpServletRequest对象的实例。request对象具有请求域,即:完成客户端的请求之前,该对象一直有效。常用方法如下:
/* 两个比较常用的方法 */
1 String getParameter(String name); // 返回name指定参数的参数值
2 String[] getParameterValues(String name); // 返回包含name的所有值的数组
3 void setAttribute(String,Object); // 存储此请求中的属性
4 String getContentType(); // 返回请求体的MIME类型
5 Stirng getProtocol(); // 返回请求所用的协议和版本号
6 String getServerName(); // 返回接受请求的服务器的主机名
7 int getServerPort(); // 返回服务器接受此请求所用的端口号
8 String getCharacterEncoding(); // 返回字符编码方式【只能解决post方式的乱码问题】
9 void setCharacterEncoding(); // 设置请求的字符编码方式
10 int getContentLength(); // 返回请求体的长度(字节)
11 String getRemoteAddr(); // 返回发送此请求的客户端IP
12 String getRealPath(String path); // 返回虚拟路径的真实路径
13 String request.getContextPath(); // 返回上下文路径
以用户注册页面为例(用户在注册页reg.jsp完善信息后提交给request.jsp来处理):
用户注册页reg.jsp
1 请输入相关信息完成注册
2
3 用户名:
4 密码:
5 爱好:
6 读书
7 音乐
8 电影
9 上网
10
11
处理用户注册页的request.jsp
1
request内置对象
2
3 用户名:
4 密码:
5 爱好:
6
7 String[]favorites = request.getParameterValues("favorite");
8 for(String str:favorites){
9 out.print(str+" ");
10 }
11 %>
运行结果:
但是以上页面存在一个问题:假如我们在用户名中输入中文:
这时只要再request.jsp中设置字符集和reg.jsp一样即可:
1
request内置对象
2
3
4 用户名:
5 密码:
6 爱好:
7
8 String[]favorites = request.getParameterValues("favorite");
9 for(String str:favorites){
10 out.print(str+" ");
11 }
12 %>
除了可以使用表单的方式传递数据给request对象,也可以使用URL传参的方式传递数据给request对象:
reg.jsp
request.jsp(不变)
1
request内置对象
2
3
4 用户名:
5 密码:
6 爱好:
7
8 String[]favorites;
9 if((favorites=request.getParameterValues("favorite"))!=null){
10 for(String str:favorites){
11 out.print(str+" ");
12 }
13 }
14 %>
运行结果:
如果我们在URL传参中传入了中文数据,同样会出现乱码问题:
此时通过request.setCharacterEncoding()方法就无法解决乱码问题了【一个良好的解决方案是修改tomcat的配置文件server.xml】
向request对象中添加键值对:
reg.jsp:
1 请输入相关信息完成注册
2
3 用户名:
4 密码:
5 爱好:
6 读书
7 音乐
8 电影
9 上网
10
11
request.jsp
1
request内置对象
2
3
4
5 //在request对象中保存一个email属性
6 request.setAttribute("email","io@gmail.com");
7
8 %>
9 用户名:
10 密码:
11 爱好:
12
13 String[]favorites;
14 if((favorites=request.getParameterValues("favorite"))!=null){
15 for(String str:favorites){
16 out.print(str+" ");
17 }
18 }
19 %>
20
邮箱:
运行结果:
1
request内置对象
2
3
4
5 //在request对象中保存一个email属性
6 request.setAttribute("email","io@gmail.com");
7
8 %>
9 用户名:
10 密码:
11 爱好:
12
13 String[]favorites;
14 if((favorites=request.getParameterValues("favorite"))!=null){
15 for(String str:favorites){
16 out.print(str+" ");
17 }
18 }
19 %>
20
邮箱:
21 请求体的MIME类型:
22 请求体的协议及版本号:
23 服务器主机名:
24 服务器端口号:
25 请求的字符编码:
26 请求的文件长度:字节
27 请求的客户端的IP:
28 请求的真实路径:
29 请求的上下文路径:
运行结果:
3.6response对象
response对象包含了响应客户请求的相关信息,但是在JSP中很少直接使用到它。它是HttpServletResponse类的实例。response对象具有页面作用域——即:访问一个页面时,该页面的response只对本次访问有效,其他页面的response对象对当前页面无效。常用方法如下:
1 String getCharacterEncoding(); // 返回响应所用的编码
2 void setContentType(); // 设置响应的MIME类型
3 PrintWriter getPrintWriter(); // 返回一个可以向客户端输出字符的对象【注意区别于out内置对象】
4 sendRedirect(String location); // 重定向客户端的请求
response.jsp
1
2
3
4 response.setContentType("text/html;charset=utf-8");//设置响应的MIME类型
5
6 out.println("
response内置对象
");
7
8 PrintWriter outer = response.getWriter();//获得输出流对象
9 outer.println("我是response对象生成的outter对象,在页面中总是在前面输出");
10 %>
运行结果:
运行结果很是奇怪:明明out对象的输出在代码中位于前面。但是结果却是PrintWriter的打印结果在前面,根本原因就是:PrintWriter的对象的输出总是在最前面。如果我们需要让标题先输出,可以使用内置对象out的flush()方法强制刷新缓冲,向页面输出——保证标题出现在最前面。
请求重定向——当用户请求response.jsp的时候马上跳转到login.jsp
response.sendRedirect("login.jsp"); // 请求重定向
%>
3.7请求重定向与请求转发的区别
请求重定向:客户端行为response.sendResponse(),从本质上讲相当于两次请求,前一次的请求对象不会保存,浏览器的URL栏会改变。
请求转发:服务器行为request.getRequestDipatcher().forword(req,resp);是一次请求,转发后请求对象会被保存,浏览器的URL不会改变。
例如还是用原来的例子:我们在reg.jsp中指定处理页面的脚本是response.jsp而在response.jsp中我们重定向到request.jsp。观察request.jsp的输出:
如果我们在response.jsp中使用请求转发:
1
2
3 //请求转发
4 request.getRequestDispatcher("request.jsp").forward(request, response);
5 %>
运行结果:
3.8session对象
Session客户端与服务器的一次会话。Web中的Session表示用户在浏览某个网站时,从进入网站到浏览器关闭所经过的这段时间——也就是用户浏览这个网站所花费的时间。在服务器的内存中保存着不同用户的Session。
session对象的常用方法:
1 long getCreationTime(); // 返回session的创建时间
2 String getId(); // 返回session创建时JSP引擎为它设定的唯一ID号
3 Object setAttribute(String name,Object value); // 使用指定名称将对象绑定到此会话
4 Object getAttribute(String name); // 返回此会话中的指定名称绑定在一起的对象,如果没有对象绑定在该名称下则返回null
5 String[] getValueNames(); // 返回一个包含此Session所有可用属性的数组
6 int getMaxInactiveInterval(); // 返回两次请求间隔多长时间此session被取消【单位:秒】
sesseion_page1.jsp
1
session内置对象
2
session_page1.jsp
3
4 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
5 String date = sdf.format(new Date(session.getCreationTime()));
6 out.print("session的创建时间:" + date);
7 session.setAttribute("username", "admin"); // 向session中设置属性
8 %>
9
Session的ID号:
10 从session中获取用户名:
11
session_page2.jsp
1
session_page2.jsp
2
3 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
4 String date = sdf.format(new Date(session.getCreationTime()));
5 out.print("session的创建时间:" + date);
6 %>
7
Session的ID号:
8 从session中获取用户名:
运行结果:
可以获取session中保存的属性集合以及设置session的有效期:
1
2 session.setMaxInactiveInterval(5);//设置session的有效期为5s
3
4 session.setAttribute("username", "admin"); // 向session中设置属性
5 session.setAttribute("password", "123456");
6 session.setAttribute("age", 16);
7 %>
8
9
10 //获取session中保存的属性
11 String[]names=session.getValueNames();
12 if(names!=null){
13 for(String str:names){
14 out.print(str+"\t");
15 }
16 }
17 %>
Session的生命周期:
创建:当客户端第一次访问某个jsp页面或者Servlet的时候,服务器会为当前会话创建一个SessionId。每次客户端向服务器发送请求的时候都会携带此SessionId,服务端会对此SessionId进行检验——判断是否属于同一次会话。
活动阶段:某次会话中通过超链接打开新的页面;只要当前页面没有全部关闭,打开新的浏览器窗口访问同一项目资源也属于同一会话。注意:原有的会话仍然存在,只不过再也没有客户端会携带此sessionId交给服务器检验。——创建一个新的会话并不意味着原有会话消失,除非超时。
销毁。
Tomcat如何进入后台管理系统?
修改/conf/tomcat-user.xml为以下:
1 <?xml version="1.0" encoding="UTF-8"?>
2
3
4
5
6
在浏览器中打开session_page1.jsp然后通过session_page1.jsp的超链接打开session_page2.jsp在后台管理系统中查看:
如果我们在session创建之后调用session.invalidate()方法,例如:我们在session_page1.jsp中这样写:
1
session内置对象
2
session_page1.jsp
3
4 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
5 String date = sdf.format(new Date(session.getCreationTime()));
6 out.print("session的创建时间:" + date);
7
10 session.setAttribute("username", "admin"); // 向session中设置属性
11 session.setAttribute("password", "123456");
12 session.setAttribute("age", 16);
13 %>
14
Session的ID号:
15 session中保存的属性有:
16
17 //获取session中保存的属性
18 String[]names=session.getValueNames();
19 if(names!=null){
20 for(String str:names){
21 out.print(str+"\t");
22 }
23 }
24 session.invalidate();//销毁session
25 %>
26 点击在新标签页中打开session_page2.jsp
运行结果(不断刷新浏览器):
Session默认session超时是30min设置session对象的超时有两种方式:
session.setMaxInactiveInterval(5);单位是秒
在web.xml中配置(单位是分钟):
30
3.9application对象
application对象实现了用户间数据的共享,可以存放全局变量。
application对象开始于服务器的启动,结束于服务器的关闭。
在用户的前后连接或者不同用户之间,可以对统一个application对象的属性进行操作。
在任何地方对application对象属性的操作将会影响到其他用户对此的访问。
application对象是ServletContext类的实例。
该对象的常用方法如下:
1 void setAttribute(String name,Object value); // 指定名称将对象绑定到此会话
2 Object getAttribute(String name); // 返回此会话中和指定名称绑定在一起的对象,如果没有对象绑定在该名称下则返回null
3 Enumeration getAttributeNames(); // 返回所有可用属性名的枚举
4 String getServerInfo(); // 返回JSP(Servlet)引擎名和版本号
1
application对象
2
3 //在application中保存3个键值对
4 application.setAttribute("city", "北京");
5 application.setAttribute("zipcode", "10000");
6 application.setAttribute("email", "io@gmail.com");
7 %>
8 所在城市:
9 application中存放的属性有:
10
11 Enumeration attrs = application.getAttributeNames();
12 while(attrs.hasMoreElements()){
13 out.print(attrs.nextElement()+"
");
14 }
15 %>
16
17 jsp(Servlet)引擎:
运行效果:
3.10page对象
page对象就是指向当前jsp页面本身(就好像类中的this),是java.lang.Object类的实例,常用方法和Object类的方法一致。例如它的toString()方法:
1
page内置对象
2 当前页面的page对象的字符串描述:
3
运行结果:
我们打开tomcat的work目录(编译生成的Servlet目录)看到它的包结构是org.apache.jsp,在该目录下有一系列的*_jsp.java和*_jsp.class文件。我们打开page_jsp.java发现类名就是page_jsp。
3.11pageContext对象
提供了对JSP页面内所有的对象及名字空间的访问。
可以访问到本页所在的session,也可以取本页面所在的application的某一属性值
相当于页面中所有功能的集大成者。
pageContext对象的本类名也叫pageContext。
常用方法:
1 JspWriter getOut(); // 返回当前客户端响应被使用的JspWriter流(out)
2 HttpSession getSession(); // 返回当前页中的HttpSession对象(session)
3 Object getPage(); // 返回当前页面的Object对象(page)
4 ServletRequest getRequest(); // 返回当前页面的ServletRequest对象(request)
5 ServletResponse getResponse(); // 返回当前页面的ServletResponse对象(response)
6 void setAttribute(String name,Object value); // 设置属性键值对
7 Object getAttribute(String name,int scope); // 在指定范围内取属性值
8 void forward(String relativeUrlPath); // 将当前页面重定向到另一页面
9 void include(String relativeUrlPath); // 在当前页面包含另一文件
我们在session_page1.jsp中向session中设置了用户名:
session.setAttribute("username", "admin");
%>
现在我们在pageContext.jsp中取出session中存储的用户名(注意要先打开session_page1.jsp):
pageContext内置对象
用户名:
运行结果:
用pageContext实现页面跳转:
pageContext.forward("reg.jsp");
%>
运行结果:
新建一个include.jsp(页面用于向页面输出当前的日期):
1
2
3
4 out.print(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()));
5 %>
下面我们在pageContext.jsp页面中包含include.jsp:
1
pageContext内置对象
2 用户名:
3
4
5
3.12config对象
该对象是一个在servlet初始化时,jsp引擎向它传递信息时使用的,此信息包含Servlet初始化时所用到的参数(键-值对)以及服务器的相关信息(通过传递一个ServletContext对象),常用方法:
1 ServletContext getServletContext(); // 返回服务器相关信息的ServletContext对象
2 String getInitParameter(String name);// 返回初始化参数的值
3 Enumeration getInitParameterNames(); // 返回Servlet初始化时所有需要参数的枚举
3.13exception对象
该对象是一个异常对象,如果一个页面在运行过程中出现了异常就会产生这个对象。如果一个JSP页面需要应用此对象,就必须把isErrorPage设为true——否则无法编译。它实际上是java.lang.Throwable的对象,常用方法:
1 String getMessage(); // 返回异常的描述信息
2 String toString(); // 返回关于异常的简短描述信息
3 void printStackTrace(); // 显示异常及其栈轨迹
4 Throwable FillInStackTrace(); // 重写异常的执行栈轨迹
首先建立一个会出现异常的页面exception_text.jsp(并指定处理异常的页面):
1
2
3
4
5
6
这个页面肯定会出现异常7
8
9
10
测试异常对象
11
12 out.println(100/0);//肯定会抛出运行时异常【算术异常】
13 %>
14
15
然后建立处理异常的页面exception.jsp:
My JSP 'exception.jsp' starting pageException内置对象
异常消息是:
异常的字符串描述:
运行结果:
3.14阶段案例——实现用户登录
这个案例比较简单:用户名和密码都是admin(没有使用数据库),如果用户名和密码相符,则页面跳转到login_success.jsp【服务器内部转发】,提示用户登录成功;如果用户登录失败,则页面跳转到login_failure.jsp【请求重定向】,提示用户登录失败。
整个项目的截图:
4.java beans
JavaBean是使用Java语言开发的一个可重用的组件,在JSP的开发中可以使用JavaBean减少重复的代码,使整个JSP代码的开发更加简洁。JSP配置JavaBean使用有以下优点:
1. 将html和java大妈分离,为日后的维护提供了方便。
2. 可以利用JavaBean的优点将常用到的程序写成JavaBean组件,节省开发时间。
简单JavaBean有以下几个名词:
VO:值对象,存放所有的传递数据的操作上
POJO:简单java对象
TO:传输对象,必须实现Serializable接口
WEB开发的标准目录结构
实际上在WEB-INF中的lib和classes目录就相当于一个默认的classpath(类执行时所需要的一个重要的环境属性)。当Tomcat启动之后,WEB-INF/lib和WEB-INF/classes都会自动配置到classpath中。
4.1java bean简介与设计原则
Javabeans就是符合某种特定规范的的Java类。它的好处有:
一个Javabean要满足4个规范:
例如以下的学生类就是一个Javabean:
1 /**
2 * 这是一个典型的JavaBean
3 */
4
5 // 1.这是一个共有的类
6 public class Student {
7 // 2.属性私有
8 private String name;
9 private int age;
10
11 // 3.有共有的无参构造
12 public Student() {
13 }
14
15 // 4.getter和setter
16 public String getName() {
17 return name;
18 }
19
20 public void setName(String name) {
21 this.name = name;
22 }
23
24 public int getAge() {
25 return age;
26 }
27
28 public void setAge(int age) {
29 this.age = age;
30 }
31
32 }
JavaBean有2种应用方式:
4.2jsp动作元素【运行时】
JSP动作元素(action elements),动作元素为请求处理阶段提供信息。动作元素遵循XML元素的语法——有一个元素名的开始标签,可以有属性、可选的内容、与开始标签匹配的结束标签。
4.3普通方式应用java bean
像使用普通java类一样,创建javabean实例。在MyEclipse项目的src目录下新建类Users:
1 package org.po;
2
3 /**
4 * 用户类-符合Javabean的实际原则
5 */
6 public class Users {
7 private String username;
8 private String password;
9
10 public Users() {
11
12 }
13
14 public String getUsername() {
15 return username;
16 }
17
18 public void setUsername(String username) {
19 this.username = username;
20 }
21
22 public String getPassword() {
23 return password;
24 }
25
26 public void setPassword(String password) {
27 this.password = password;
28 }
29
30 }
下面我们在javabean_page1.jsp中使用以上的Javabean:
1
2
3
4
5
6
7
8
JavaBeans范例9
10
11
12
使用普通方式创建Javabean的实例
13
14 //使用普通方式创建JavaBean
15 Users user = new Users();
16 user.setUsername("admin");
17 user.setPassword("admin");
18 %>
19 用户名:
20 密码:
21
22
运行结果:
4.4useBean动作元素
用于在jsp页面中实例化或者在指定范围内使用JavaBean。基本操作是首先使用id和作用域查找一个现有的对象,如果在指定的作用域中没有找到具有指定id的对象,那么它会试图使用其他属性创建一个新实例。语法如下:
1
2
3
4
5
6
使用useBean动作指令来使用JavaBean7
8
9
10
使用<jsp:useBean>动作指令来使用JavaBean
11
12
13 用户名:
14 密码:
15
16
运行结果:
4.5setProperty
上一个jsp页面中取得的用户名和密码都为null,原因就是我们使用仅仅是实例化了Users对象,并没有为其成员变量执行属性。当然你也可以使用setXXX来给已经实例化的JavaBean设置属性,不过我更推荐使用setProperty指令。
的主要作用就是给已经实例化的JavaBean的属性赋值,一共有4种形式:
1
2
3
4
方式一:【表单内容的自动全部匹配】
新建一个用户登录表单login.jsp:
1
2 用户名:
3 密码:
4
5
处理用户登录的页面dologin.jsp
1
2
3 String path = request.getContextPath();
4 String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
5 %>
6
7
8
9
10
11
用户登录处理页面12
13
14
15
16
17
18
19
setPerpority动作元素
20
21
22
23 用户名:
24 密码:
25
26
27
运行结果:
这实际上以依靠表单中的name属性来匹配javabean中的成员变量。例如:在用户登录表单中input标记的属性有一个name="username",那么使用这种自动匹配的方式就会把这个username与javabean中的属性挨个查找,如果找到了就为这个字段设定相应的值——换言之:表单中的name属性要和要和javabean中的属性对应相同。
方式二:部分匹配表单的属性(dologin.jsp):
1
2
3 String path = request.getContextPath();
4 String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
5 %>
6
7
8
9
10
11
用户登录处理页面12
13
14
15
16
17
18
19
setPerpority动作元素
20
21
22
23 用户名:
24 密码:
25
26
27
运行结果:
仅仅匹配了用户名属性,由于密码属性没有匹配,所以为null。这种方式也要注意表单的name属性要和javabean的属性相同。
方式三:手工给javabean的属性赋值——与表单无关(dologin.jsp):
1
2
3 String path = request.getContextPath();
4 String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
5 %>
6
7
8
9
10
11
用户登录处理页面12
13
14
15
16
17
18
19
setPerpority动作元素
20
21
22
23
24 用户名:
25 密码:
26
27
28
方式四(通过URL传参的方式给javabean赋值):
login.jsp:
dologin.jsp:
1
2
3 String path = request.getContextPath();
4 String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
5 %>
6
7
8
9
10
11
用户登录处理页面12
13
14
15
16
17
18
19
setPerpority动作元素
20
21
22
23
24 用户名:
25 密码:
26
27
28
运行结果:
4.6getProperty
获取指定JavaBean对象的属性值【String类型】。语法:
前面的例子已经通过URL传递参数的方式指定了javabean的属性值,现在通过getProperty的方式获得javabean的属性值:
1
2
3 String path = request.getContextPath();
4 String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
5 %>
6
7
8
9
10
11
用户登录处理页面12
13
14
15
16
17
18
19
setPerpority动作元素
20
21
22
23
24
25
26
27 用户名:
28 密码:
29 --%>
30
31
32 用户名:
33 密码:
34
35
运行结果:
4.7java bean的4个作用域范围
使用useBean的scope属性可以指定javabean的作用域。
1 page // 当前页面有效,可以通过PageContext.getAttribute()获得JavaBean对象。
2 request // 同一个请求有效,可通过HttpRequest.getAttibute()方法获得JavaBean对象。
3 session // 同一个session有效,可通过HttpSession.getAttribute()方法获得JavaBean对象。
4 application // 同一个application有效,可通过application.getAttribute()方法获得JavaBean对象。
下面是一个简单的测试4个作用范围的示例:
dolog.jsp以URL传参的方式为javabean指定属性值:
1
2
3
4
5
用户登录处理页面6
7
8
9
10
11
12
13
setPerpority动作元素
14
15
16
17
18
20
21
22
dologin.jsp中有一个跳转链接test_scope.jsp用于跳转页面,下面是test_scope.jsp。
1
2
3
4
5
6
7
检验useBean的4个作用域8
9
10
11
检验useBean的4个作用域
12
13
14
15
用jsp动作元素获取javabean的属性值
16 用户名:
17 密码:
18
19
20
通过内置对象获取javabean的属性值
21 用户名:
22 密码:
23
24
按照上面的例子分别将scope换成session、request和page得到如下如下结果:javabean的作用域范围从大到小依次是:application、session、request、page。
4.8JavaBean的删除
JavaBean虽然使用了标签进行创建,但是其操作仍然依靠的是4种属性范围。如果一个JavaBean不再使用的话,则可以使用对应的removeAttribute()方法进行删除。
1 pageContext.removeAttribute(JavaBean名称) // 删除page范围内的JavaBean
2 request.removeAttribute(JavaBean名称) // 删除request范围内的JavaBean
3 session.removeAttribute(JavaBean名称) // 删除session范围内的JavaBean
4 application.removeAttribute(JavaBean名称) // 删除application范围内的JavaBean
1 package org.gpf;
2
3 public class Count {
4
5 private int count = 0;
6
7 public Count() {
8 System.out.println("======== 一个新的Count实例产生了 ========");
9 }
10
11 public int getCount() {
12 return ++count;
13 }
14
15 }
1
2
3
4 count =
5
6 session.removeAttribute("c"); // 删除javaBean
7 %>
我们本来设置的是session范围内的JavaBean,刷新页面不应该有新的JavaBean产生,但是我们在最后使用了session.removeAttribute()方法将创建的JavaBean删除了,因而每次请求都会产生新的JavaBean。
4.9model 1(JSP+JavaBean)简介
Model 1模型出现以前,整个Web应用几乎全部由JSP页面组成,JSP页面接收处理客户端请求,对请求处理后直接响应。这样做的一个弊端就是:在界面层(JSP页面)中充斥着大量的业务逻辑代码和数据访问层的代码,Web程序的可扩展性和可维护性非常差。
JavaBean的出现可以使得可以在JSP页面中调用JavaBean封装的数据或者业务逻辑代码,大大提升了程序的可维护性。下面的这张图简单描述了Model 1.
模型一体现了一种Web应用的分层架构。
4.9阶段项目(使用Model 1完成用户登录)
首先建立一个用户类Users(javabean):
1 package org.po;
2
3 /**
4 * 用户类-javabean
5 */
6 public class Users {
7 private String username;
8 private String passwordString;
9
10 public Users() {
11 }
12
13 public String getUsername() {
14 return username;
15 }
16
17 public void setUsername(String username) {
18 this.username = username;
19 }
20
21 public String getPasswordString() {
22 return passwordString;
23 }
24
25 public void setPasswordString(String passwordString) {
26 this.passwordString = passwordString;
27 }
28
29 }
下面编写一个用户业务逻辑类:
1 package org.dao;
2
3 import org.po.Users;
4
5 /**
6 * 用户的业务逻辑类
7 */
8 public class UsersDAO {
9 public boolean isUserLogin(Users users) {
10 return "admin".equals(users.getUsername())
11 && "admin".equals(users.getPassword());
12 }
13 }
业务逻辑处理的页面dologin.jsp:
1
2 contentType="text/html; charset=utf-8"%>
3
4
5
6
7
8
9
10
11
12
13 request.setCharacterEncoding("utf-8");//防止中文乱码
14 if(userDAO.isUserLogin(loginUser)){
15 //如果用户登录成功则向session中设置用户名和密码
16 session.setAttribute("username", loginUser.getUsername());
17 session.setAttribute("password", loginUser.getPassword());
18 //请求转发
19 request.getRequestDispatcher("login_success.jsp").forward(request, response);
20 }else{
21 //重定向
22 response.sendRedirect("login_failure.jsp");
23 }
24 %>
该项目中主要的修改的dologin.jsp在该页面中没有使用request对象直接从表单中读出数据,而是从javabean中取出属性,并且用户合法性的判断也放在了javabean中很好的体现了Web的分层思想(逻辑与页面分离)。
5.jsp状态管理
5.1http协议的无状态性
http的无状态性是指:当浏览器发送请求给服务器的时候,服务器响应客户端的请求。但是当浏览器再次发送请求给服务器的时候,服务器并不知道它就是刚刚的那个浏览器。——服务器不会记住你。为了保存用户的状态有两种机制:
5.2Cookie
Cookie是Web服务器保存在客户端的一系列文本信息。
Cookie的典型应用一:判断注册用户是否已经登录网站。保存用户的登录状态,简化登录的手续(记住密码)。
Cookie的典型应用二:“购物车”的处理。
Cookie的典型应用三:视频网站播放记录的存储。
在JSP页面中创建和使用Cookie
1 Cookie newCookie = new Cookie(String key,Object value); // 创建Cookie对象
2 response.add(newCookie); // 写入Cookie对象
3 Cookie[] cookies = request.getCookies(); // 读取Cookie对象
Cooike对象的常用方法:
1 void setMaxAge(int expiry); // 设置cookie的有效期【秒】
2 void setValue(String value);// 对已经实例化的cookie对象赋值
3 String getName(); // 获得cookie的名称
4 String getValue(); // 获得cookie的值
5 int getMaxAge(); // 获得cookie的有效时间【秒】
注意:以上方法中的setValue(String value)和String getValue()方法的返回值都是字符串类型——因为Cookie本质上就是一个字符串存储在客户端,无论对它存值还是取值都应该是字符串类型。
5.3案例:Cookie在登录中的应用:
实现记忆用户名和密码的功能。
用户登陆页login.jsp
1
2 contentType="text/html; charset=utf-8"%>
3
4
5
6
用户登录7
8
9
10
11 /*获得Cookie中保存的用户名和密码*/
12 String username = "";
13 String password = "";
14
15 Cookie[]cookies = request.getCookies();
16 if(cookies!=null&&cookies.length>0){
17 for(Cookie c:cookies){
18 if(c.getName().equals("username")){
19 username = c.getValue();
20 }
21 if(c.getName().equals("password")){
22 password = c.getValue();
23 }
24 }
25 }
26 %>
27
28 请输入用户名和密码:
29
30
31 用户名:
32 密码:
33
34 十天内记住我
35
36
37
38
处理用户登录的页面dologin.jsp
1
2 contentType="text/html; charset=utf-8"%>
3
4
5
6
处理用户登录7
8
9
10
登录成功!
11
12
13 //判断用户是否选择了记住密码
14 String[] isUseCookie = request.getParameterValues("isUseCookie");
15 if(isUseCookie!=null&&isUseCookie.length>0){
16 /*把用户名和密码保存在Cookie对象中*/
17 String username = request.getParameter("username");
18 String password = request.getParameter("password");
19 //创建2个Cookie对象
20 Cookie usernameCookie = new Cookie("username",username);
21 Cookie passwordCookie = new Cookie("password",password);
22 usernameCookie.setMaxAge(3600*24*10);//设置cookie生存期10天
23 passwordCookie.setMaxAge(3600*24*10);
24
25 //在客户端保存Cookie对象,需要依赖response对象的addCookie方法
26 response.addCookie(usernameCookie);
27 response.addCookie(passwordCookie);
28 }else{
29 /*使已经保存的cookie对象失效*/
30 Cookie[]cookies = request.getCookies();//得到客户端保存的cookie
31 if(cookies!=null&&cookies.length>0){
32 //遍历Cookie数组
33 for(Cookie c:cookies){
34 if(c.getName().equals("username")||c.getName().equals("password")){
35 c.setMaxAge(0);//设置Cookie的有效期是0,让其马上失效
36 response.addCookie(c);//重新向客户端保存Cookie
37 }
38 }
39 }
40 }
41 %>
42 点击查看用户信息
43
44
用户信息显示页users.jsp
1
2 contentType="text/html; charset=utf-8"%>
3
4
5
6
用户信息显示7
8
9
10
用户信息
11
12
13 /*获得Cookie中保存的用户名和密码*/
14 String username = "";
15 String password = "";
16
17 Cookie[]cookies = request.getCookies();
18 if(cookies!=null&&cookies.length>0){
19 for(Cookie c:cookies){
20 if(c.getName().equals("username")){
21 username = c.getValue();
22 }
23 if(c.getName().equals("password")){
24 password = c.getValue();
25 }
26 }
27 }
28 %>
29 用户名:
密码:
30
31
该项目一般情况下能够正常运行,但是当我们输入中文用户名的时候,服务器会抛出一个500的错误。要解决这个问题就需要依靠java网络包中的URLEncoder和URLDecoder,除此之外不要忘记了在每次使用request对象之前首先要设置request对象的编码方式。完整的代码如下:
login.jsp
1
2 contentType="text/html; charset=utf-8"%>
3
4
5
6
7
用户登录8
9
10
11
12 /*获得Cookie中保存的用户名和密码*/
13 String username = "";
14 String password = "";
15
16 request.setCharacterEncoding("utf-8");
17 Cookie[]cookies = request.getCookies();
18 if(cookies!=null&&cookies.length>0){
19 for(Cookie c:cookies){
20 if (c.getName().equals("username")) {
21 username = URLDecoder.decode(c.getValue(), "utf-8");
22 }
23 if (c.getName().equals("password")) {
24 password = URLDecoder.decode(c.getValue(), "utf-8");
25 }
26 }
27 }
28 %>
29
30 请输入用户名和密码:
31
32
33 用户名:
34 密码:
35
36 十天内记住我
37
38
39
40
dologin.jsp
1
2
3 contentType="text/html; charset=utf-8"%>
4
5
6
7
处理用户登录8
9
10
11
登录成功!
12
13
14 //判断用户是否选择了记住密码
15 request.setCharacterEncoding("utf-8");
16 String[] isUseCookie = request.getParameterValues("isUseCookie");
17 if (isUseCookie != null && isUseCookie.length > 0) {
18 /*把用户名和密码保存在Cookie对象中*/
19 //得到登录表单中的内容并编码
20 String username = URLEncoder.encode(
21 request.getParameter("username"), "utf-8");
22 String password = URLEncoder.encode(
23 request.getParameter("password"), "utf-8");
24 //创建2个Cookie对象
25 Cookie usernameCookie = new Cookie("username", username);
26 Cookie passwordCookie = new Cookie("password", password);
27 usernameCookie.setMaxAge(3600 * 24 * 10);//设置cookie生存期10天
28 passwordCookie.setMaxAge(3600 * 24 * 10);
29
30 //在客户端保存Cookie对象,需要依赖response对象的addCookie方法
31 response.addCookie(usernameCookie);
32 response.addCookie(passwordCookie);
33 } else {
34 /*使已经保存的cookie对象失效*/
35 Cookie[] cookies = request.getCookies();//得到客户端保存的cookie
36 if (cookies != null && cookies.length > 0) {
37 //遍历Cookie数组
38 for (Cookie c : cookies) {
39 if (c.getName().equals("username")
40 || c.getName().equals("password")) {
41 c.setMaxAge(0);//设置Cookie的有效期是0,让其马上失效
42 response.addCookie(c);//重新向客户端保存Cookie
43 }
44 }
45 }
46 }
47 %>
48 点击查看用户信息
49
50
users.jsp
1
2
3 contentType="text/html; charset=utf-8"%>
4
5
6
7
用户信息显示8
9
10
11
用户信息
12
13
14 /*获得Cookie中保存的用户名和密码*/
15 String username = "";
16 String password = "";
17
18 request.setCharacterEncoding("utf-8");
19 Cookie[] cookies = request.getCookies();
20 if (cookies != null && cookies.length > 0) {
21 for (Cookie c : cookies) {
22 if (c.getName().equals("username")) {
23 username = URLDecoder.decode(c.getValue(), "utf-8");
24 }
25 if (c.getName().equals("password")) {
26 password = URLDecoder.decode(c.getValue(), "utf-8");
27 }
28 }
29 }
30 %>
31 用户名:
密码:
32
33
修正后的项目就支持中文用户名了。Cookie与Session的区别是Cookie存放于浏览器中,浏览器关闭后再打开,已经保存的cookie还是存在。
5.4Session与Cookie对比
Session
Cookie
保存位置
服务端保存用户信息
客户端保存用户信息
保存类型
Session中保存的是Object类型
Cookie中保存的是String类型
生命周期
会话结束,则存储的数据销毁
Cookie可长期保存在客户端
重要性
保存重要信息
保存不重要信息
6.jsp指令【编译时】与动作【运行时】元素
6.1include指令(可以包含其他页面)
语法:
例如我们要在include_command.jsp中包含date.jsp的页面——即:在include_command中显示date.jsp的内容:
date.jsp
1
2
3
4 out.print(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()));
5 %>
include_command.jsp
1
2
3
4
5
在该页面中使用include指令将刚刚写的date.jsp包含进来6
7
8
9
在该页面中使用include指令将刚刚写的date.jsp包含进来
10
11
12
运行结果:
6.2include动作
include动作实际上是JSP动作标签,语法:
其中page属性是需要包含的页面的URL,而flush属性制定了被包含的页面是否从缓冲区中读取。
demo:使用include动作在include_action.jsp中包含date.jsp
include_action.jsp
1
2
3
4
5
include动作6
7
8
9
在该页面中使用include动作将刚刚写的date.jsp包含进来
10
11
12
使用include动作和include指令在jsp页面的执行效果上没有任何区别。
6.3include指令与include动作的区别
在Tomcat服务器的work目录中删除刚刚发布的工程:
先访问include_command.jsp
work目录生成以下内容:
打开include_005fcommand_jsp.java发现在它的源代码中有date.jsp的源代码:
out.print(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()));
include指令主页面和被包含的页面转换成了同一个Servlet。
在Tomcat的work目录中删除编译生成的Servlet,访问include_action.jsp生成以下文件:
打开include_005faction_jsp.java发现源代码中并没有包含date.jsp的源代码,而是由下面的一条代码将date.jsp的输出结果包含到该jsp页面:
// 该语句相当于调用date.jsp,并将date.jsp的输出结果返回给该页面
org.apache.jasper.runtime.JspRuntimeLibrary.include(request, response, "date.jsp", out, false);
6.4forward动作
服务器内部转发指令,语法:
1
2
3 // 相当于
4 request.getRequestDispatcher("url").forward(request,response);
例如:在登陆页中将用户的表单处理交给forward_action.jsp页面处理,forward_action.jsp将该请求通过forward动作转发给users.jsp,users.jsp从request对象中取得用户名和密码给予显示:
login.jsp
1
2 contentType="text/html; charset=utf-8"%>
3
4
5
6
用户登录7
8
9
10 请输入用户名和密码:
11
12
13 用户名:
14 密码:
15
16
17
18
forward_action.jsp
1
2
3
4
5
forward动作6
7
8
9
该页面处理用户提交的表单信息
10
forward动作
11
12
13
14 request.getRequestDispatcher("users.jsp").forward(request, response);
15 --%>
16
17
users.jsp
1
2 contentType="text/html; charset=utf-8"%>
3
4
5
6
用户信息显示7
8
9
10
用户信息
11
12
13 request.setCharacterEncoding("utf-8");
14
15 String username = "";
16 String password = "";
17 if(request.getParameter("username")!=null){
18 username = request.getParameter("username");
19 }
20 if(request.getParameter("password")!=null){
21 password = request.getParameter("password");
22 }
23 %>
24 用户名:
密码:
25
26
运行结果:
6.5param动作
语法:
1
2
用户将提交的表单交给dologin.jsp处理,dologin.jsp通过forward动作把请求转发给users.jsp(并人为添加表单中没有的内容:邮箱,修改表单中提交的用户名为root),users.jsp通过request.getParamer()方法获得用户名、密码、邮箱并予以显示:
login.jsp
1
2 contentType="text/html; charset=utf-8"%>
3
4
5
6
用户登录7
8
9
10 请输入用户名和密码:
11
12
13 用户名:
14 密码:
15
16
17
18
dologin.jsp
1
2
3
4
5
users.jsp
1
2 contentType="text/html; charset=utf-8"%>
3
4
5
6
用户信息显示7
8
9
10
用户信息
11
12
13 request.setCharacterEncoding("utf-8");
14
15 String username = "";
16 String password = "";
17 String email = "";
18 if(request.getParameter("username")!=null){
19 username = request.getParameter("username");
20 }
21 if(request.getParameter("password")!=null){
22 password = request.getParameter("password");
23 }
24 if(request.getParameter("email")!=null){
25 email = request.getParameter("email");
26 }
27 %>
28 用户名:
密码:
邮箱:
29
30
效果图:
7.jsp案例项目——商品浏览记录的实现
该项目使用Model1(JSP+JavaBean)使用Cookie机制实现。该项目使用到了数据库(数据库中存放了商品表)。实现步骤如下:
DB-->JavaBean-->JSP。项目的目录结构:
一、实现DBHelper类:
该类的主要作用是取得数据库的连接并关闭相关资源。
1 package util;
2
3 import java.sql.Connection;
4 import java.sql.DriverManager;
5 import java.sql.PreparedStatement;
6 import java.sql.ResultSet;
7 import java.sql.SQLException;
8
9 public class DBHelper {
10 private static final String DRIVER = "com.mysql.jdbc.Driver";
11 private static final String URL = "jdbc:mysql://localhost:3306/shopping?useUnicode=true&characterEncoding=UTF-8";
12 private static final String USER = "root";
13 private static final String PASSWORD = "mysqladmin";
14
15 private static Connection coon = null;// DB连接对象
16
17 /** 静态代码块加载DB驱动 */
18 static {
19 try {
20 Class.forName(DRIVER);
21 } catch (ClassNotFoundException e) {
22 e.printStackTrace();
23 }
24 }
25
26 /** Singleton设计模式返回DB连接对象 */
27 public static Connection getConnection() throws SQLException {
28 if (coon == null) {
29 coon = DriverManager.getConnection(URL, USER, PASSWORD);
30 return coon;
31 }
32 return coon;
33 }
34
35 /** 清理资源-关闭DB结果集、释放语句对象 */
36 public static void relsaseResource(ResultSet rs,PreparedStatement pstmt){
37 // 释放结果集
38 if (rs != null) {
39 try {
40 rs.close();
41 rs = null;
42 } catch (SQLException e) {
43 e.printStackTrace();
44 }
45 }
46 // 释放语句对象
47 if (pstmt != null) {
48 try {
49 pstmt.close();
50 pstmt = null;
51 } catch (SQLException e) {
52 e.printStackTrace();
53 }
54 }
55 }
56
57 /** 测试DB连接 */
58 public static void main(String[] args) {
59 try {
60 Connection connection = DBHelper.getConnection();
61 if(connection!=null){
62 System.out.println("数据库连接成功!");
63 }else {
64 System.out.println("数据库连接异常!");
65 }
66 } catch (SQLException e) {
67 e.printStackTrace();
68 }
69 }
70 }
如果shopping数据库没有创建可能会抛出异常只需要执行:
create database shopping;
二、商品实体类的设计:
在创建实体类之前先建立好数据库表:
数据库脚本:items.sql
1 /*
2 Navicat MySQL Data Transfer
3
4 Source Server : MySQL50
5 Source Server Version : 50067
6 Source Host : localhost:3306
7 Source Database : shopping
8
9 Target Server Type : MYSQL
10 Target Server Version : 50067
11 File Encoding : 65001
12
13 Date: 2014-08-27 12:12:31
14 */
15
16 SET FOREIGN_KEY_CHECKS=0;
17
18 -- ----------------------------
19 -- Table structure for items
20 -- ----------------------------
21 DROP TABLE IF EXISTS `items`;
22 CREATE TABLE `items` (
23 `id` int(11) NOT NULL auto_increment,
24 `name` varchar(50) default NULL,
25 `city` varchar(50) default NULL,
26 `price` int(11) default NULL,
27 `number` int(11) default NULL,
28 `picture` varchar(500) default NULL,
29 PRIMARY KEY (`id`)
30 ) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8;
31
32 -- ----------------------------
33 -- Records of items
34 -- ----------------------------
35 INSERT INTO `items` VALUES ('1', '沃特篮球鞋', '佛山', '180', '500', '001.jpg');
36 INSERT INTO `items` VALUES ('2', '安踏运动鞋', '福州', '120', '800', '002.jpg');
37 INSERT INTO `items` VALUES ('3', '耐克运动鞋', '广州', '500', '1000', '003.jpg');
38 INSERT INTO `items` VALUES ('4', '阿迪达斯T血衫', '上海', '388', '600', '004.jpg');
39 INSERT INTO `items` VALUES ('5', '李宁文化衫', '广州', '180', '900', '005.jpg');
40 INSERT INTO `items` VALUES ('6', '小米3', '北京', '1999', '3000', '006.jpg');
41 INSERT INTO `items` VALUES ('7', '小米2S', '北京', '1299', '1000', '007.jpg');
42 INSERT INTO `items` VALUES ('8', 'thinkpad笔记本', '北京', '6999', '500', '008.jpg');
43 INSERT INTO `items` VALUES ('9', 'dell笔记本', '北京', '3999', '500', '009.jpg');
44 INSERT INTO `items` VALUES ('10', 'ipad5', '北京', '5999', '500', '010.jpg');
在MySQL中查询:
建立实体类(Items):也就是javabean其属性与DB中的各个字段一一对应。
1 package entity;
2
3 /**
4 * 商品类(与DB中的表名一致)-javabean 属性和DB中表的字段完全一致
5 */
6 public class Items {
7 private int id;
8 private String name;
9 private String city;
10 private int price;
11 private int number;
12 private String picture;
13
14 public Items() {
15 }
16
17 public int getId() {
18 return id;
19 }
20
21 public void setId(int id) {
22 this.id = id;
23 }
24
25 public String getName() {
26 return name;
27 }
28
29 public void setName(String name) {
30 this.name = name;
31 }
32
33 public String getCity() {
34 return city;
35 }
36
37 public void setCity(String city) {
38 this.city = city;
39 }
40
41 public int getPrice() {
42 return price;
43 }
44
45 public void setPrice(int price) {
46 this.price = price;
47 }
48
49 public int getNumber() {
50 return number;
51 }
52
53 public void setNumber(int number) {
54 this.number = number;
55 }
56
57 public String getPicture() {
58 return picture;
59 }
60
61 public void setPicture(String picture) {
62 this.picture = picture;
63 }
64
65 }
三、实现业务逻辑类(数据访问层DAO)
该类需要完成的功能:
分析:
1.在index.jsp中我们需要展示所有的商品信息。——获得所有商品
2.当用户点击任意一种商品后会将id通过URL传递给details.jsp,而在details.jsp中我们需要——根据id获得对应商品。
3.根据Cookie传入的字符串获得最近浏览的5条记录。
思考:如何将浏览记录保存在Cookie中?
回答:只需要保存商品的ID即可,因为每个商品的ID是唯一的。
实现:把每次浏览的商品ID保存一个字符串中,将这个字符串保存在Cookie中,ID和ID之间用分隔符分隔,每次取出前5条记录。
显示所有商品的主页index.jsp
1
2
3
4 contentType="text/html; charset=utf-8"%>
5
6
7
8
9
欢迎光临网上商城10
11 div {
12 float: left;
13 margin: 10px;
14 }
15
16 div dd {
17 margin: 0px;
18 font-size: 10pt;
19 }
20
21 div dd.dd_name {
22 color: blue;
23 }
24
25 div dd.dd_city {
26 color: #000;
27 }
28
29
30
31
32
商品展示
33
34
35
36 border="0">
37
38
39
40
41 ItemsDAO itemsDAO = new ItemsDAO();
42 ArrayListlist = itemsDAO.getAllItems();
43 if(list!=null&&list.size()>0){
44 //遍历所有的商品
45 for(Items item:list){
46 %>
47
58
59 }
60 }
61 %>
62
63
64
65
66
67
68
显示商品详细信息的details.jsp
1
2
3
4
5
6
7
8
欢迎光临网上商城9
10 div{
11 float:left;
12 margin-left: 30px;
13 margin-right:30px;
14 margin-top: 5px;
15 margin-bottom: 5px;
16 }
17 div dd{
18 margin:0px;
19 font-size:10pt;
20 }
21 div dd.dd_name
22 {
23 color:blue;
24 }
25 div dd.dd_city
26 {
27 color:#000;
28 }
29
30
31
32
33
商品详情
34
35
36
37
38
39 Items item = new ItemsDAO().getItemsById(Integer.parseInt(request.getParameter("id")));
40 if(item!=null){
41 %>
42
43
44
45
46
47
48
49
50
51
产地:52
53
54
价格:¥55
56
57
58
59 }
60 %>
61
62
63 String list = "";
64 // 从客户端获得Cookie集合
65 Cookie[]cookies = request.getCookies();
66 if(cookies!=null&&cookies.length>0){
67 for(Cookie c:cookies){
68 if(c.getName().equals("ListViewCookie")){
69 list = c.getValue();
70 }
71
72 String[] arr = list.split(",");
73 // 相同商品只在浏览记录中存放一次
74 if(Arrays.binarySearch(arr, request.getParameter("id"))<0){
75 list += request.getParameter("id") + ",";
76 }
77 // 如果浏览记录超过1000条,则清空Cookie
78 if(arr!=null&&arr.length>1000){
79 list = "";// 清零-置空串
80 }
81 Cookie cookie = new Cookie("ListViewCookie",list);
82 response.addCookie(cookie);
83 }
84 }
85 %>
86
87
88
89 您浏览过的商品
90
91
92 ArrayListitemsList = new ItemsDAO().getViewList(list);
93 if(itemsList!=null&&itemsList.size()>0){
94 for(Items i:itemsList){
95 %>
96
97
98
99
100
产地: 价格:¥101
102
103
104 }
105 }
106 %>
107
108
109
110
111
112
113
主业务逻辑类ItemsDAO
View Code
Tips:
解决中文乱码:
1)在执行获取请求参数前设置编码:
request.setCharacterEncoding(“汉字编码”);
2)转换字符编码:
1 //获取原始的请求参数值
2 String rawName = request.getParameter("name");
3 //将请求参数值使用ISO-8859-1字符串分解成字节数组
4 byte[] rawBytes = rawName.getBytes("ISO-8859-1");
5 //将字节数组重新编码成字符串
6 String name = new String(rawBytes , "gb2312");
3)获取请求参数同时转换编码:
request.getParameter(“name”).getBytes ("ISO-8859-1");