表现形式 | 所需技术 | |
静态网页 | 网页内容固定,不会更新 | html,css |
动态网页 | 网页内容由程序动态显示,自动更新 | html,css,DB,java/c#/php,javascript,xml,主流的动态网页脚本(jsp,asp.net,php) |
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/回车得到如下页面:
在项目文件夹中创建一个index.jsp:
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>手工编写的第一个java web项目</title> 6 </head> 7 <body> 8 <h1>这是手工编写的第一个java web项目——jsp</h1> 9 <hr /> 10 </body> 11 </html>
在项目目录中创建一个WEB-INF目录拷贝/webapps/examples/WEB-INFO/web.xm到自己项目的/myJspProject/WEB-INFO中,在/myJspProject/WEB-INFO中创建两个文件夹:classes和lib。最后的项目目录应该是这样:
测试:浏览器输入:http://localhost:8080/myJspProject/index.jsp回车,运行结果如下:
解决方法:更改浏览器编码为指定编码:
该目录是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 <welcome-file-list> 2 <welcome-file>/haha.jsp</welcome-file> 3</welcome-file-list>
运行结果:
注意:如果要使用Eclipse编写java web应用应该使用Eclipse的J2EE版本。并在Eclipse中配置Tomcat服务器Window-Preference-Server-Runtime Environment-Add,然后在WebContent目录下新建jsp文件,按下Ctrl+F11(或者在项目中右键-Run On Server)就可以使用内置浏览器访问建立的网站。
在新建项目之前首先在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。
该虚拟路径是可以修改的项目上右键属性-MyEclipse-Web。
重新部署,浏览器需要使用使用http://localhost:8080/hello/index.jsp访问了。
修改conf目录下的server.xml的以下标记:
<Connector connectionTimeout="20000" port="8888" protocol="HTTP/1.1" redirectPort="8443"/>
jsp的全名是Java Server Page,是一个简化的Servlet设计,它实现了在java当中使用html标记。jsp是一种动态网页技术,符合J2EE标准。jsp和Servlet一样也是在服务器端执行的。
平台 | 特点 |
jsp | 跨平台,安全性高,适合开发大型的、企业级的Web应用、分布式应用(Hadoop)。例如:12306、10086.cn、网上银行 |
asp.net | 简单易学,安全性和跨平台性差 |
php | 简单、高效、成本低、开发周期短,适合中小型企业的Web应用开发(LAMP) |
page指令语法:
<%@ page 属性1="属性值" 属性2="属性值1,属性值2" 属性n="属性值n"%>
属性 | 描述 | 默认值 |
language | jsp页面所使用的脚本语言 | java |
import | 引用脚本语言中所要使用的类文件 | 无 |
contentType | 指定jsp页面的编码 | text/html,ISO-8859-1 |
新建一个java web工程默认的jsp页面开头有一个page指令:
<%@ page language="java" import="java.util.*" pageEncoding="ISO-8859-1"%>
默认的编码是ISO-8859-1,不支持中文,这里建议使用另一个属性contentType。将第一行改为如下:
<%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%>
这样就支持中文了。
page指令的全部属性如下:
1 <%@page 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属性之外,其他属性均只能设置一次。
分为3种:html注释,jsp注释,jsp脚本注释。语法:
1 <!-- html注释 --> 2 <%-- jsp注释 --%> 3 <% 4 /*这里是jsp脚本注释 有两种*/ 5 6 //单行注释 7 8 /*多行注释*/ 9 %>
例如:
1 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%> 2 <% 3 String path = request.getContextPath(); 4 String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; 5 %> 6 7 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 8 <html> 9 <head> 10 <base href="<%=basePath%>"> 11 12 <title>My JSP 'index.jsp' starting page</title> 13 <meta http-equiv="pragma" content="no-cache"> 14 <meta http-equiv="cache-control" content="no-cache"> 15 <meta http-equiv="expires" content="0"> 16 <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> 17 <meta http-equiv="description" content="This is my page"> 18 <!-- 19 <link rel="stylesheet" type="text/css" href="styles.css"> 20 --> 21 </head> 22 23 <body> 24 <h1>欢迎你</h1> 25 <!-- 这是html注释,客户端可可见 --> 26 <%-- 这是jsp注释,客户端不可见 --%> 27 <% 28 /*这里是jsp脚本注释 29 有两种*/ 30 //单行注释 31 /*多行注释*/ 32 %> 33 </body> 34 </html>
将项目部署到Tomcat,客户端用浏览器查看源代码:
在jsp页面中执行的java代码。语法:
<% java代码 %>
1 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%> 2 <% 3 String path = request.getContextPath(); 4 String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; 5 %> 6 7 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 8 <html> 9 <head> 10 <base href="<%=basePath%>"> 11 12 <title>My JSP 'index.jsp' starting page</title> 13 <meta http-equiv="pragma" content="no-cache"> 14 <meta http-equiv="cache-control" content="no-cache"> 15 <meta http-equiv="expires" content="0"> 16 <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> 17 <meta http-equiv="description" content="This is my page"> 18 <!-- 19 <link rel="stylesheet" type="text/css" href="styles.css"> 20 --> 21 </head> 22 23 <body> 24 <h1>欢迎你</h1> 25 <hr> 26 <% 27 out.println("通过jsp内置对象out对象打印输出"); 28 %> 29 </body> 30 </html>
jsp页面中定义变量或者方法。语法:
<%! java代码 %>
例如:
1 <%! 2 String s = "张三"; //声明一个String类型的变量 3 int add(int x,int y){ //声明一个返回值为int类型的方法 4 return x+y; 5 } 6 %>
jsp页面中执行的表达式。语法(注意=紧挨着百分号,表达式末尾没有分号):
<%=表达式 %>
1 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%> 2 <% 3 String path = request.getContextPath(); 4 String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; 5 %> 6 7 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 8 <html> 9 <head> 10 <base href="<%=basePath%>"> 11 12 <title>My JSP 'index.jsp' starting page</title> 13 <meta http-equiv="pragma" content="no-cache"> 14 <meta http-equiv="cache-control" content="no-cache"> 15 <meta http-equiv="expires" content="0"> 16 <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> 17 <meta http-equiv="description" content="This is my page"> 18 <!-- 19 <link rel="stylesheet" type="text/css" href="styles.css"> 20 --> 21 </head> 22 23 <body> 24 <h1>欢迎你</h1> 25 <hr> 26 <!-- 这是html注释,客户端可可见 --> 27 <%! 28 String s = "张三"; //声明一个String类型的变量 29 int add(int x,int y){ //声明一个返回值为int类型的方法 30 return x+y; 31 } 32 %> 33 你好:<%=s %><br> 34 令x=10,y=5,则x+y = <%=add(10, 5) %> 35 </body> 36 </html>
运行结果:
jspService()方法被调用来处理客户端的请求。对每一个请求,JSP引擎创建一个新的线程来处理该请求。如果有多个客户端同时请求你该jsp文件,则jsp引擎会创建多个线程(每一个客户端请求对应一个线程)。以多线程的方式执行可以大大降低对系统的资源需求,提高系统的并发量以及缩短服务器的响应时间——但是同时要注意多线程的同步问题。由于该Servlet常驻内存,所以响应是非常快的。
当页面没有被访问的时候work目录下没有相关的Servlet。如果页面被访问之后就会在work目录的对应目录生成响应的Servlet。如图:
打开index_jsp.java会看到以下的初始化方法:
然后该Servlet常驻内存,创建线程处理每一个客户端的请求。由每一个线程调用_jspService()方法来处理请求。
如果jsp页面内容发生了改变,jsp引擎就需要重新编译jsp页面。我们修改index.jsp,用浏览器重新访问,则:
1 <%@page import="java.io.IOException"%> 2 <%@ page language="java" import="java.util.*" 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 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 10 <html> 11 <head> 12 <base href="<%=basePath%>"> 13 14 <title>My JSP 'multiplicationTable.jsp' starting page</title> 15 16 <meta http-equiv="pragma" content="no-cache"> 17 <meta http-equiv="cache-control" content="no-cache"> 18 <meta http-equiv="expires" content="0"> 19 <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> 20 <meta http-equiv="description" content="This is my page"> 21 22 23 </head> 24 25 <body> 26 <h1>九九乘法表</h1> 27 <h2>表达式的方式打印乘法表</h2> 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("<br />");//追加换行标记,注意不能使用\n 37 } 38 return s.toString(); 39 } 40 %> 41 <%=printMultiTable() //调用表达式 42 %> 43 44 <h2>使用脚本的方式打印九九乘法表</h2> 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("<br />"); 54 } 55 out.println(s.toString()); 56 } 57 %> 58 59 <% 60 //调用脚本 61 printMultiTable2(out); 62 %> 63 </body> 64 </html>
运行结果:
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("<br />"); 10 } 11 out.println(s.toString());//这里的out就是jsp内置对象 12 } 13 %>
JSP一共有9个内置对象,其中常用的内置对象有5个,如图所示:
缓冲区(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 <h1>JSP的out内置对象</h1> 2 <% 3 //jsp脚本 4 out.println("<h2>静夜思</h2>"); 5 out.println("李白<br /><br />"); 6 out.println("窗前明月光,<br />"); 7 out.println("疑是地上霜。<br />"); 8 out.println("举头望明月,<br />"); 9 out.println("低头思故乡。<hr />"); 10 %> 11 <!-- JSP表达式 --> 12 缓冲区大小:<%=out.getBufferSize() %>字节。<br /> 13 剩余缓冲区(可用缓冲区):<%=out.getRemaining() %>字节。<br /> 14 是否自动清空缓冲区:<%=out.isAutoFlush() %><br />
运行结果:
1 <h1>JSP的out内置对象</h1> 2 <% 3 //jsp脚本 4 out.println("<h2>静夜思</h2>"); 5 out.println("李白<br /><br />"); 6 out.println("窗前明月光,<br />");
7 out.flush();//将缓冲区中的内容输出到客户端
8 out.println("疑是地上霜。<br />"); 9 out.println("举头望明月,<br />"); 10 out.println("低头思故乡。<hr />"); 11 %> 12 <!-- JSP表达式 --> 13 缓冲区大小:<%=out.getBufferSize() %>字节。<br /> 14 剩余缓冲区(可用缓冲区):<%=out.getRemaining() %>字节。<br /> 15 是否自动清空缓冲区:<%=out.isAutoFlush() %><br />
如果在第7行强制刷新缓冲区,则输出的页面不会有任何变化,仅仅是可用缓冲区的数量变多了而已【因为flush清空了缓冲区】
1 <% 2 //jsp脚本 3 out.println("<h2>静夜思</h2>"); 4 out.println("李白<br /><br />"); 5 out.println("窗前明月光,<br />"); 6 7 out.flush();//将缓冲区中的内容输出到客户端 8 out.clear();//在flush之后调用clear,将会抛出异常 9 10 out.println("疑是地上霜。<br />"); 11 out.println("举头望明月,<br />"); 12 out.println("低头思故乡。<hr />"); 13 %>
运行结果:
1 <% 2 //jsp脚本 3 out.println("<h2>静夜思</h2>"); 4 out.println("李白<br /><br />"); 5 out.println("窗前明月光,<br />"); 6 7 out.flush();//将缓冲区中的内容输出到客户端 8 out.clearBuffer();//在flush之后调用clearBuffer不会抛出异常 9 10 out.println("疑是地上霜。<br />"); 11 out.println("举头望明月,<br />"); 12 out.println("低头思故乡。<hr />"); 13 %>
运行结果:
<form name="regForm" action="处理脚本" method="提交方式[post|get]"></form>
1 请输入用户名和密码: 2 <form name = "loginForm" action = "dologin.jsp" method = "get"> 3 用户名:<input type="text" name="username" value="" maxlength = "15" /><br /> 4 密码:<input type="password" name="password" maxlength="16" value="" /><br /> 5 <input type="submit" value="提交" /> 6 </form>
处理登录的动作脚本dologin.jsp仅仅是显示一句话"登录成功"。
运行结果:
将用户登录表单的get方式改为post。
客户端的请求被封装在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 请输入相关信息完成注册<br /> 2 <form action="request.jsp" name="regForm" method="post"> 3 用户名:<input type="text" name = "username" /><br /> 4 密码:<input type="password" name = "password" /><br /> 5 爱好: 6 <input type="checkbox" name = "favorite" value="read"/>读书 7 <input type="checkbox" name = "favorite" value="music"/>音乐 8 <input type="checkbox" name = "favorite" value="movie"/>电影 9 <input type="checkbox" name = "favorite" value="internet"/>上网<br /> 10 <input type="submit" value="提交" /> 11 </form>
处理用户注册页的request.jsp
1 <h1>request内置对象</h1><br /> 2 3 用户名:<%=request.getParameter("username") %><br /> 4 密码:<%=request.getParameter("password") %><hr /> 5 爱好:<br /> 6 <% 7 String[]favorites = request.getParameterValues("favorite"); 8 for(String str:favorites){ 9 out.print(str+" "); 10 } 11 %>
运行结果:
但是以上页面存在一个问题:假如我们在用户名中输入中文:
这时只要再request.jsp中设置字符集和reg.jsp一样即可:
1 <h1>request内置对象</h1><br /> 2 <!-- 设置字符集,防止出现中文乱码 --> 3 <% request.setCharacterEncoding("utf-8"); %>
4 用户名:<%=request.getParameter("username") %><br /> 5 密码:<%=request.getParameter("password") %><hr /> 6 爱好:<br /> 7 <% 8 String[]favorites = request.getParameterValues("favorite"); 9 for(String str:favorites){ 10 out.print(str+" "); 11 } 12 %>
除了可以使用表单的方式传递数据给request对象,也可以使用URL传参的方式传递数据给request对象:
reg.jsp
<a href="request.jsp?username=root&password=toor&favorite=read&favorite=internet">测试URL传参</a>
request.jsp(不变)
1 <h1>request内置对象</h1><br /> 2 <!-- 设置字符集,防止出现中文乱码 --> 3 <% request.setCharacterEncoding("utf-8"); %> 4 用户名:<%=request.getParameter("username") %><br /> 5 密码:<%=request.getParameter("password") %><hr /> 6 爱好:<br /> 7 <% 8 String[]favorites; 9 if((favorites=request.getParameterValues("favorite"))!=null){ 10 for(String str:favorites){ 11 out.print(str+" "); 12 } 13 } 14 %>
运行结果:
如果我们在URL传参中传入了中文数据,同样会出现乱码问题:
<a href="request.jsp?username=你好&password=toor&favorite=read&favorite=internet">测试URL传参</a>
此时通过request.setCharacterEncoding()方法就无法解决乱码问题了【一个良好的解决方案是修改tomcat的配置文件server.xml】
<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443" URIEncoding="utf-8"/>
向request对象中添加键值对:
reg.jsp:
1 请输入相关信息完成注册<br /> 2 <form action="request.jsp" name="regForm" method="post"> 3 用户名:<input type="text" name = "username" /><br /> 4 密码:<input type="password" name = "password" /><br /> 5 爱好: 6 <input type="checkbox" name = "favorite" value="read"/>读书 7 <input type="checkbox" name = "favorite" value="music"/>音乐 8 <input type="checkbox" name = "favorite" value="movie"/>电影 9 <input type="checkbox" name = "favorite" value="internet"/>上网<br /> 10 <input type="submit" value="提交" /> 11 </form>
request.jsp
1 <h1>request内置对象</h1><br /> 2 <!-- 设置字符集,防止出现中文乱码 --> 3 <% request.setCharacterEncoding("utf-8"); %> 4 <% 5 //在request对象中保存一个email属性 6 request.setAttribute("email","[email protected]"); 7 8 %> 9 用户名:<%=request.getParameter("username") %><br /> 10 密码:<%=request.getParameter("password") %><hr /> 11 爱好:<br /> 12 <% 13 String[]favorites; 14 if((favorites=request.getParameterValues("favorite"))!=null){ 15 for(String str:favorites){ 16 out.print(str+" "); 17 } 18 } 19 %> 20 <br />邮箱:<%=request.getAttribute("email") %>
运行结果:
1 <h1>request内置对象</h1><br /> 2 <!-- 设置字符集,防止出现中文乱码 --> 3 <% request.setCharacterEncoding("utf-8"); %> 4 <% 5 //在request对象中保存一个email属性 6 request.setAttribute("email","[email protected]"); 7 8 %> 9 用户名:<%=request.getParameter("username") %><br /> 10 密码:<%=request.getParameter("password") %><hr /> 11 爱好:<br /> 12 <% 13 String[]favorites; 14 if((favorites=request.getParameterValues("favorite"))!=null){ 15 for(String str:favorites){ 16 out.print(str+" "); 17 } 18 } 19 %> 20 <br />邮箱:<%=request.getAttribute("email") %> <hr /> 21 请求体的MIME类型:<%=request.getContentType() %><br /> 22 请求体的协议及版本号:<%=request.getProtocol() %><br /> 23 服务器主机名:<%=request.getServerName() %><br /> 24 服务器端口号:<%=request.getServerPort() %><br /> 25 请求的字符编码:<%=request.getCharacterEncoding() %><br /> 26 请求的文件长度:<%=request.getContentLength() %>字节<br /> 27 请求的客户端的IP:<%=request.getRemoteAddr() %><br /> 28 请求的真实路径:<%=request.getRealPath("request.jsp") %><br /> 29 请求的上下文路径:<%=request.getContextPath() %>
运行结果:
response对象包含了响应客户请求的相关信息,但是在JSP中很少直接使用到它。它是HttpServletResponse类的实例。response对象具有页面作用域——即:访问一个页面时,该页面的response只对本次访问有效,其他页面的response对象对当前页面无效。常用方法如下:
1 String getCharacterEncoding(); // 返回响应所用的编码 2 void setContentType(); // 设置响应的MIME类型 3 PrintWriter getPrintWriter(); // 返回一个可以向客户端输出字符的对象【注意区别于out内置对象】 4 sendRedirect(String location); // 重定向客户端的请求
response.jsp
1 <%@page import="java.io.PrintWriter"%> 2 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%> 3 <% 4 response.setContentType("text/html;charset=utf-8");//设置响应的MIME类型 5 6 out.println("<h1>response内置对象</h1><hr />"); 7 8 PrintWriter outer = response.getWriter();//获得输出流对象 9 outer.println("我是response对象生成的outter对象,在页面中总是在前面输出"); 10 %>
运行结果:
运行结果很是奇怪:明明out对象的输出在代码中位于前面。但是结果却是PrintWriter的打印结果在前面,根本原因就是:PrintWriter的对象的输出总是在最前面。如果我们需要让标题先输出,可以使用内置对象out的flush()方法强制刷新缓冲,向页面输出——保证标题出现在最前面。
请求重定向——当用户请求response.jsp的时候马上跳转到login.jsp
<%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%> <% response.sendRedirect("login.jsp"); // 请求重定向 %>
3.7请求重定向与请求转发的区别
如果我们在response.jsp中使用请求转发:
1 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%> 2 <% 3 //请求转发 4 request.getRequestDispatcher("request.jsp").forward(request, response); 5 %>
运行结果:
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 <h1>session内置对象</h1> 2 <h2>session_page1.jsp</h2> 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 <br />Session的ID号:<%=session.getId() %><br /> 10 从session中获取用户名:<%=session.getAttribute("username") %> 11 12 <a href="session_page2.jsp" target="_blank">以新窗口的方式打开session_page2.jsp</a>
session_page2.jsp
1 <h2>session_page2.jsp</h2> 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 <br />Session的ID号:<%=session.getId() %><br /> 8 从session中获取用户名:<%=session.getAttribute("username") %>
运行结果:
可以获取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 %>
修改/conf/tomcat-user.xml为以下:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <tomcat-users> 3 <role rolename="admin-gui"/> 4 <role rolename="manager-gui"/> 5 <user username="admin" password="admin" roles="admin-gui,manager-gui"></user> 6 </tomcat-users>
在浏览器中打开session_page1.jsp然后通过session_page1.jsp的超链接打开session_page2.jsp在后台管理系统中查看:
如果我们在session创建之后调用session.invalidate()方法,例如:我们在session_page1.jsp中这样写:
1 <h1>session内置对象</h1> 2 <h2>session_page1.jsp</h2> 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 <br />Session的ID号:<%=session.getId() %><hr /> 15 session中保存的属性有:<br /> 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 <a href = "session_page2.jsp" target = "_blank">点击在新标签页中打开session_page2.jsp</a>
运行结果(不断刷新浏览器):
Session默认session超时是30min设置session对象的超时有两种方式:
<session-config> <session-timeout>30</session-timeout> </session-config>
1 void setAttribute(String name,Object value); // 指定名称将对象绑定到此会话 2 Object getAttribute(String name); // 返回此会话中和指定名称绑定在一起的对象,如果没有对象绑定在该名称下则返回null 3 Enumeration getAttributeNames(); // 返回所有可用属性名的枚举 4 String getServerInfo(); // 返回JSP(Servlet)引擎名和版本号
1 <h1>application对象</h1> 2 <% 3 //在application中保存3个键值对 4 application.setAttribute("city", "北京"); 5 application.setAttribute("zipcode", "10000"); 6 application.setAttribute("email", "[email protected]"); 7 %> 8 所在城市:<%=application.getAttribute("city") %><hr> 9 application中存放的属性有:<br> 10 <% 11 Enumeration attrs = application.getAttributeNames(); 12 while(attrs.hasMoreElements()){ 13 out.print(attrs.nextElement()+"<br>"); 14 } 15 %> 16 <hr> 17 jsp(Servlet)引擎:<%=application.getServerInfo() %><br>
运行效果:
page对象就是指向当前jsp页面本身(就好像类中的this),是java.lang.Object类的实例,常用方法和Object类的方法一致。例如它的toString()方法:
1 <h1>page内置对象</h1> 2 当前页面的page对象的字符串描述:<br /> 3 <%=page.toString() %>
运行结果:
我们打开tomcat的work目录(编译生成的Servlet目录)看到它的包结构是org.apache.jsp,在该目录下有一系列的*_jsp.java和*_jsp.class文件。我们打开page_jsp.java发现类名就是page_jsp。
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):
<h1>pageContext内置对象</h1> 用户名:<%=pageContext.getSession().getAttribute("username") %>
运行结果:
用pageContext实现页面跳转:
<% pageContext.forward("reg.jsp"); %>
运行结果:
新建一个include.jsp(页面用于向页面输出当前的日期):
1 <%@page import="java.text.SimpleDateFormat"%> 2 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%> 3 <% 4 out.print(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date())); 5 %>
下面我们在pageContext.jsp页面中包含include.jsp:
1 <h1>pageContext内置对象</h1> 2 用户名:<%=pageContext.getSession().getAttribute("username") %><hr> 3 4 <!-- 包含其他页面 --> 5 <%pageContext.include("include.jsp"); %>
该对象是一个在servlet初始化时,jsp引擎向它传递信息时使用的,此信息包含Servlet初始化时所用到的参数(键-值对)以及服务器的相关信息(通过传递一个ServletContext对象),常用方法:
1 ServletContext getServletContext(); // 返回服务器相关信息的ServletContext对象 2 String getInitParameter(String name);// 返回初始化参数的值 3 Enumeration getInitParameterNames(); // 返回Servlet初始化时所有需要参数的枚举
该对象是一个异常对象,如果一个页面在运行过程中出现了异常就会产生这个对象。如果一个JSP页面需要应用此对象,就必须把isErrorPage设为true——否则无法编译。它实际上是java.lang.Throwable的对象,常用方法:
1 String getMessage(); // 返回异常的描述信息 2 String toString(); // 返回关于异常的简短描述信息 3 void printStackTrace(); // 显示异常及其栈轨迹 4 Throwable FillInStackTrace(); // 重写异常的执行栈轨迹
首先建立一个会出现异常的页面exception_text.jsp(并指定处理异常的页面):
1 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8" errorPage="exception.jsp"%> 2 <!-- 在errorPage中指定处理异常的页面 --> 3 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 4 <html> 5 <head> 6 <title>这个页面肯定会出现异常</title> 7 </head> 8 9 <body> 10 <h1>测试异常对象</h1><hr /> 11 <% 12 out.println(100/0);//肯定会抛出运行时异常【算术异常】 13 %> 14 </body> 15 </html>
然后建立处理异常的页面exception.jsp:
<%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8" isErrorPage="true"%> <!-- isErrorPage设为true表示这是一个异常处理页面 --> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>My JSP 'exception.jsp' starting page</title> </head> <body> <h1>Exception内置对象</h1> 异常消息是:<%=exception.getMessage() %><br> 异常的字符串描述:<%=exception.toString() %> </body> </html>
运行结果:
这个案例比较简单:用户名和密码都是admin(没有使用数据库),如果用户名和密码相符,则页面跳转到login_success.jsp【服务器内部转发】,提示用户登录成功;如果用户登录失败,则页面跳转到login_failure.jsp【请求重定向】,提示用户登录失败。
整个项目的截图:
项目地址:https://git.oschina.net/gaopengfei/JSPLogin.git
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中。
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种应用方式:
JSP动作元素(action elements),动作元素为请求处理阶段提供信息。动作元素遵循XML元素的语法——有一个元素名的开始标签,可以有属性、可选的内容、与开始标签匹配的结束标签。
像使用普通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 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%> 2 <!-- 使用import指令导入Javabean --> 3 <%@ page import="org.po.Users" %> 4 5 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 6 <html> 7 <head> 8 <title>JavaBeans范例</title> 9 </head> 10 11 <body> 12 <h1>使用普通方式创建Javabean的实例</h1> 13 <% 14 //使用普通方式创建JavaBean 15 Users user = new Users(); 16 user.setUsername("admin"); 17 user.setPassword("admin"); 18 %> 19 用户名:<%=user.getUsername() %><br /> 20 密码:<%=user.getPassword() %> 21 </body> 22 </html>
运行结果:
<jsp:useBean>用于在jsp页面中实例化或者在指定范围内使用JavaBean。基本操作是首先使用id和作用域查找一个现有的对象,如果在指定的作用域中没有找到具有指定id的对象,那么它会试图使用其他属性创建一个新实例。语法如下:
<jsp:useBean id="标示符" class="java类名" scope="作用域" />
1 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%> 2 <!-- 这里不需要page指令来导入User类了 --> 3 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 4 <html> 5 <head> 6 <title>使用useBean动作指令来使用JavaBean</title> 7 </head> 8 9 <body> 10 <h1>使用<jsp:useBean>动作指令来使用JavaBean</h1> 11 <!-- useBean指令 --> 12 <jsp:useBean id="myUsers" class="org.po.Users" scope="page"></jsp:useBean> 13 用户名:<%=myUsers.getUsername() %><br/> 14 密码:<%=myUsers.getPassword() %> 15 </body> 16 </html>
运行结果:
上一个jsp页面中取得的用户名和密码都为null,原因就是我们使用仅仅是实例化了Users对象,并没有为其成员变量执行属性。当然你也可以使用setXXX来给已经实例化的JavaBean设置属性,不过我更推荐使用setProperty指令。
<jsp:setProperty>的主要作用就是给已经实例化的JavaBean的属性赋值,一共有4种形式:
1 <jsp:setProperty name="JavaBean实例名" property="*" /> <!-- 和表单关联,全部属性 --> 2 <jsp:setProperty name="JavaBean实例名" property="JavaBean属性名" /> <!-- 和表单关联,指定属性 --> 3 <jsp:setProperty name="JavaBean实例名" property="JavaBean属性名" value = "BeanValue" /> <!-- 手工设置 --> 4 <jsp:setProperty name="JavaBean实例名" property="propertyName" param="request对象中的参数名"/> <!-- 和request参数关联,URL传参 -->
方式一:【表单内容的自动全部匹配】
新建一个用户登录表单login.jsp:
1 <form action="dologin.jsp" method="post" name="loginForm"> 2 用户名:<input type="text" name="username"/><br /> 3 密码:<input type="password" name="password" /> 4 <input type="submit" value="提交" /> 5 </form>
处理用户登录的页面dologin.jsp
1 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%> 2 <% 3 String path = request.getContextPath(); 4 String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; 5 %> 6 7 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 8 <html> 9 <head> 10 <base href="<%=basePath%>"> 11 <title>用户登录处理页面</title> 12 </head> 13 14 <body> 15 16 <!-- 实例化javaBean对象 --> 17 <jsp:useBean id="myUsers" class="org.po.Users"></jsp:useBean> 18 19 <h1>setPerpority动作元素</h1><hr /> 20 21 <!-- 根据表单自动匹配所有的属性并设置 --> 22 <jsp:setProperty property="*" name="myUsers"/> 23 用户名:<%=myUsers.getUsername() %><br> 24 密码:<%=myUsers.getPassword() %> 25 26 </body> 27 </html>
运行结果:
这实际上以依靠表单中的name属性来匹配javabean中的成员变量。例如:在用户登录表单中input标记的属性有一个name="username",那么使用这种自动匹配的方式就会把这个username与javabean中的属性挨个查找,如果找到了就为这个字段设定相应的值——换言之:表单中的name属性要和要和javabean中的属性对应相同。
方式二:部分匹配表单的属性(dologin.jsp):
1 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%> 2 <% 3 String path = request.getContextPath(); 4 String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; 5 %> 6 7 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 8 <html> 9 <head> 10 <base href="<%=basePath%>"> 11 <title>用户登录处理页面</title> 12 </head> 13 14 <body> 15 16 <!-- 实例化javaBean对象 --> 17 <jsp:useBean id="myUsers" class="org.po.Users"></jsp:useBean> 18 19 <h1>setPerpority动作元素</h1><hr /> 20 21 <!-- 根据表单匹配部分属性 --> 22 <jsp:setProperty property="username" name="myUsers"/> 23 用户名:<%=myUsers.getUsername() %><br> 24 密码:<%=myUsers.getPassword() %> 25 26 </body> 27 </html>
运行结果:
仅仅匹配了用户名属性,由于密码属性没有匹配,所以为null。这种方式也要注意表单的name属性要和javabean的属性相同。
方式三:手工给javabean的属性赋值——与表单无关(dologin.jsp):
1 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%> 2 <% 3 String path = request.getContextPath(); 4 String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; 5 %> 6 7 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 8 <html> 9 <head> 10 <base href="<%=basePath%>"> 11 <title>用户登录处理页面</title> 12 </head> 13 14 <body> 15 16 <!-- 实例化javaBean对象 --> 17 <jsp:useBean id="myUsers" class="org.po.Users"></jsp:useBean> 18 19 <h1>setPerpority动作元素</h1><hr /> 20 21 <!-- 与表单无关,通过手工给javabean的属性赋值 --> 22 <jsp:setProperty property="username" name="myUsers" value="root"/> 23 <jsp:setProperty property="password" name="myUsers" value="123456"/> 24 用户名:<%=myUsers.getUsername() %><br> 25 密码:<%=myUsers.getPassword() %> 26 27 </body> 28 </html>
方式四(通过URL传参的方式给javabean赋值):
login.jsp:
<a href="dologin.jsp?id=root&sn=123456">通过url传参的方式给javabean的属性赋值</a>
dologin.jsp:
1 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%> 2 <% 3 String path = request.getContextPath(); 4 String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; 5 %> 6 7 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 8 <html> 9 <head> 10 <base href="<%=basePath%>"> 11 <title>用户登录处理页面</title> 12 </head> 13 14 <body> 15 16 <!-- 实例化javaBean对象 --> 17 <jsp:useBean id="myUsers" class="org.po.Users"></jsp:useBean> 18 19 <h1>setPerpority动作元素</h1><hr /> 20 21 <!-- 通过URL传参的方式给javabean属性赋值--> 22 <jsp:setProperty property="username" name="myUsers" param="id"/> 23 <jsp:setProperty property="password" name="myUsers" param="sn"/> 24 用户名:<%=myUsers.getUsername() %><br> 25 密码:<%=myUsers.getPassword() %> 26 27 </body> 28 </html>
运行结果:
<jsp:getProperty>获取指定JavaBean对象的属性值【String类型】。语法:
<jsp:getProperty name="JavaBean实例名" property="属性名" />
前面的例子已经通过URL传递参数的方式指定了javabean的属性值,现在通过getProperty的方式获得javabean的属性值:
1 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%> 2 <% 3 String path = request.getContextPath(); 4 String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; 5 %> 6 7 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 8 <html> 9 <head> 10 <base href="<%=basePath%>"> 11 <title>用户登录处理页面</title> 12 </head> 13 14 <body> 15 16 <!-- 实例化javaBean对象 --> 17 <jsp:useBean id="myUsers" class="org.po.Users"></jsp:useBean> 18 19 <h1>setPerpority动作元素</h1><hr /> 20 21 <!-- 通过URL传参的方式给javabean属性赋值--> 22 <jsp:setProperty property="username" name="myUsers" param="id"/> 23 <jsp:setProperty property="password" name="myUsers" param="sn"/> 24 25 <!-- 通过getter获得javabean的属性值 --> 26 <%-- 27 用户名:<%=myUsers.getUsername() %><br> 28 密码:<%=myUsers.getPassword() %> 29 --%> 30 31 <!-- 通过getProperty获得javabean的属性值 --> 32 用户名:<jsp:getProperty property="username" name="myUsers"/><br /> 33 密码:<jsp:getProperty property="password" name="myUsers"/> 34 </body> 35 </html>
运行结果:
使用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 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%> 2 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 3 <html> 4 <head> 5 <title>用户登录处理页面</title> 6 </head> 7 8 <body> 9 10 <!-- 实例化javaBean对象,并制定作用域为application --> 11 <jsp:useBean id="myUsers" class="org.po.Users" scope="application"></jsp:useBean> 12 13 <h1>setPerpority动作元素</h1><hr /> 14 15 <!-- 通过URL传参的方式给javabean的属性赋值--> 16 <jsp:setProperty property="username" name="myUsers" param="id"/> 17 <jsp:setProperty property="password" name="myUsers" param="sn"/> 18 19 <a href="test_scope.jsp">测试javabean的4个作用域范围</a> 20 21 </body> 22 </html>
dologin.jsp中有一个跳转链接test_scope.jsp用于跳转页面,下面是test_scope.jsp。
1 <%@page import="org.po.Users"%> 2 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%> 3 4 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 5 <html> 6 <head> 7 <title>检验useBean的4个作用域</title> 8 </head> 9 10 <body> 11 <h1>检验useBean的4个作用域</h1><hr> 12 13 <jsp:useBean id="myUsers" class="org.po.Users" scope="application"></jsp:useBean> 14 <!-- 通过getProperty获取javabean属性值 --> 15 <h2>用jsp动作元素获取javabean的属性值</h2> 16 用户名:<jsp:getProperty property="username" name="myUsers"/><br /> 17 密码:<jsp:getProperty property="password" name="myUsers"/><hr> 18 19 <!-- 通过内置对象获取javabean的属性值 --> 20 <h2>通过内置对象获取javabean的属性值</h2> 21 用户名:<%=((Users)application.getAttribute("myUsers")).getUsername() %><br> 22 密码:<%=((Users)application.getAttribute("myUsers")).getPassword() %> 23 </body> 24 </html>
按照上面的例子分别将scope换成session、request和page得到如下如下结果:javabean的作用域范围从大到小依次是:application、session、request、page。
JavaBean虽然使用了<jsp:useBean>标签进行创建,但是其操作仍然依靠的是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 <%@ page language="java" contentType="text/html; charset=utf-8"%> 2 <!-- 创建JavaBean,指定作用域为session --> 3 <jsp:useBean id="c" class="org.gpf.Count" scope="session"></jsp:useBean> 4 count = <jsp:getProperty property="count" name="c"/> 5 <% 6 session.removeAttribute("c"); // 删除javaBean 7 %>
我们本来设置的是session范围内的JavaBean,刷新页面不应该有新的JavaBean产生,但是我们在最后使用了session.removeAttribute()方法将创建的JavaBean删除了,因而每次请求都会产生新的JavaBean。
Model 1模型出现以前,整个Web应用几乎全部由JSP页面组成,JSP页面接收处理客户端请求,对请求处理后直接响应。这样做的一个弊端就是:在界面层(JSP页面)中充斥着大量的业务逻辑代码和数据访问层的代码,Web程序的可扩展性和可维护性非常差。
JavaBean的出现可以使得可以在JSP页面中调用JavaBean封装的数据或者业务逻辑代码,大大提升了程序的可维护性。下面的这张图简单描述了Model 1.
模型一体现了一种Web应用的分层架构。
首先建立一个用户类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 <%@ page language="java" import="java.util.*" 2 contentType="text/html; charset=utf-8"%> 3 <!-- 引入实体类Users --> 4 <jsp:useBean id="loginUser" class="org.po.Users"></jsp:useBean> 5 <!-- 引入业务逻辑类UsersDAO --> 6 <jsp:useBean id="userDAO" class="org.dao.UsersDAO"></jsp:useBean> 7 8 <!-- 为javaBean loginUser设置属性,使用表单自动设置全部的值 --> 9 <jsp:setProperty property="*" name="loginUser"/> 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 %>
项目地址:https://git.oschina.net/gaopengfei/loginDemoByModel1.git
该项目中主要的修改的dologin.jsp在该页面中没有使用request对象直接从表单中读出数据,而是从javabean中取出属性,并且用户合法性的判断也放在了javabean中很好的体现了Web的分层思想(逻辑与页面分离)。
http的无状态性是指:当浏览器发送请求给服务器的时候,服务器响应客户端的请求。但是当浏览器再次发送请求给服务器的时候,服务器并不知道它就是刚刚的那个浏览器。——服务器不会记住你。为了保存用户的状态有两种机制:
Cookie是Web服务器保存在客户端的一系列文本信息。
在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本质上就是一个字符串存储在客户端,无论对它存值还是取值都应该是字符串类型。
实现记忆用户名和密码的功能。
用户登陆页login.jsp
1 <%@ page language="java" import="java.util.*" 2 contentType="text/html; charset=utf-8"%> 3 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 4 <html> 5 <head> 6 <title>用户登录</title> 7 </head> 8 9 <body> 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 <br /> 30 <form action="dologin.jsp" name="loginForm" method="post"> 31 用户名:<input type="text" name="username" value="<%= username%>" /><br /> 32 密码:<input type="password" name="password" value="<%= password%>"><br /> 33 <input type="checkbox" checked="checked" name="isUseCookie"> 34 十天内记住我<br /> <input type="submit" value="登录" /> 35 </form> 36 37 </body> 38 </html>
处理用户登录的页面dologin.jsp
1 <%@ page language="java" import="java.util.*" 2 contentType="text/html; charset=utf-8"%> 3 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 4 <html> 5 <head> 6 <title>处理用户登录</title> 7 </head> 8 9 <body> 10 <h1>登录成功!</h1> 11 <hr /> 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 <a href="users.jsp">点击查看用户信息</a> 43 </body> 44 </html>
用户信息显示页users.jsp
1 <%@ page language="java" import="java.util.*" 2 contentType="text/html; charset=utf-8"%> 3 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 4 <html> 5 <head> 6 <title>用户信息显示</title> 7 </head> 8 9 <body> 10 <h1>用户信息</h1> 11 <hr /> 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 用户名:<%=username %><br /> 密码:<%=password %> 30 </body> 31 </html>
该项目一般情况下能够正常运行,但是当我们输入中文用户名的时候,服务器会抛出一个500的错误。要解决这个问题就需要依靠java网络包中的URLEncoder和URLDecoder,除此之外不要忘记了在每次使用request对象之前首先要设置request对象的编码方式。完整的代码如下:
login.jsp
1 <%@ page language="java" import="java.util.*" 2 contentType="text/html; charset=utf-8"%> 3 <%@page import="java.net.URLDecoder"%> 4 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 5 <html> 6 <head> 7 <title>用户登录</title> 8 </head> 9 10 <body> 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 <br /> 32 <form action="dologin.jsp" name="loginForm" method="post"> 33 用户名:<input type="text" name="username" value="<%= username%>" /><br /> 34 密码:<input type="password" name="password" value="<%= password%>"><br /> 35 <input type="checkbox" checked="checked" name="isUseCookie"> 36 十天内记住我<br /> <input type="submit" value="登录" /> 37 </form> 38 39 </body> 40 </html>
dologin.jsp
1 <%@page import="java.net.URLEncoder"%> 2 <%@ page language="java" import="java.util.*" 3 contentType="text/html; charset=utf-8"%> 4 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 5 <html> 6 <head> 7 <title>处理用户登录</title> 8 </head> 9 10 <body> 11 <h1>登录成功!</h1> 12 <hr /> 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 <a href="users.jsp">点击查看用户信息</a> 49 </body> 50 </html>
users.jsp
1 <%@page import="java.net.URLDecoder"%> 2 <%@ page language="java" import="java.util.*" 3 contentType="text/html; charset=utf-8"%> 4 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 5 <html> 6 <head> 7 <title>用户信息显示</title> 8 </head> 9 10 <body> 11 <h1>用户信息</h1> 12 <hr /> 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 用户名:<%=username%><br /> 密码:<%=password%> 32 </body> 33 </html>
修正后的项目就支持中文用户名了。Cookie与Session的区别是Cookie存放于浏览器中,浏览器关闭后再打开,已经保存的cookie还是存在。
Session | Cookie | |
保存位置 | 服务端保存用户信息 | 客户端保存用户信息 |
保存类型 | Session中保存的是Object类型 | Cookie中保存的是String类型 |
生命周期 | 会话结束,则存储的数据销毁 | Cookie可长期保存在客户端 |
重要性 | 保存重要信息 | 保存不重要信息 |
语法:
<%@ include file="URL"%>
例如我们要在include_command.jsp中包含date.jsp的页面——即:在include_command中显示date.jsp的内容:
date.jsp
1 <%@page import="java.text.SimpleDateFormat"%> 2 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%> 3 <% 4 out.print(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date())); 5 %>
include_command.jsp
1 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%> 2 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 3 <html> 4 <head> 5 <title>在该页面中使用include指令将刚刚写的date.jsp包含进来</title> 6 </head> 7 8 <body> 9 <h1>在该页面中使用include指令将刚刚写的date.jsp包含进来</h1><hr /> 10 <%@include file="date.jsp" %> 11 </body> 12 </html>
运行结果:
include动作实际上是JSP动作标签,语法:
<jsp:include page="URL" flush="true|false" />
其中page属性是需要包含的页面的URL,而flush属性制定了被包含的页面是否从缓冲区中读取。
demo:使用include动作在include_action.jsp中包含date.jsp
include_action.jsp
1 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%> 2 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 3 <html> 4 <head> 5 <title>include动作</title> 6 </head> 7 8 <body> 9 <h1>在该页面中使用include动作将刚刚写的date.jsp包含进来</h1><hr /> 10 <jsp:include page="date.jsp" flush="false"></jsp:include> 11 </body> 12 </html>
使用include动作和include指令在jsp页面的执行效果上没有任何区别。
在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);
服务器内部转发指令,语法:
1 <jsp:forward page="URL" /> 2 3 // 相当于 4 request.getRequestDispatcher("url").forward(request,response);
例如:在登陆页中将用户的表单处理交给forward_action.jsp页面处理,forward_action.jsp将该请求通过forward动作转发给users.jsp,users.jsp从request对象中取得用户名和密码给予显示:
login.jsp
1 <%@ page language="java" import="java.util.*" 2 contentType="text/html; charset=utf-8"%> 3 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 4 <html> 5 <head> 6 <title>用户登录</title> 7 </head> 8 9 <body> 10 请输入用户名和密码: 11 <br /> 12 <form action="forward_action.jsp" name="loginForm" method="post"> 13 用户名:<input type="text" name="username" /><br /> 14 密码:<input type="password" name="password" /><br /> 15 <input type="submit" value="登录" /> 16 </form> 17 </body> 18 </html>
forward_action.jsp
1 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%> 2 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 3 <html> 4 <head> 5 <title>forward动作</title> 6 </head> 7 8 <body> 9 <h1>该页面处理用户提交的表单信息</h1> 10 <h2>forward动作</h2> 11 <jsp:forward page="users.jsp"></jsp:forward> 12 <!-- 上面这条语句和下面的这条语句相当 --> 13 <%-- 14 request.getRequestDispatcher("users.jsp").forward(request, response); 15 --%> 16 </body> 17 </html>
users.jsp
1 <%@ page language="java" import="java.util.*" 2 contentType="text/html; charset=utf-8"%> 3 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 4 <html> 5 <head> 6 <title>用户信息显示</title> 7 </head> 8 9 <body> 10 <h1>用户信息</h1> 11 <hr /> 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 用户名:<%=username %><br /> 密码:<%=password %> 25 </body> 26 </html>
运行结果:
语法:
1 <jsp:param name="参数名" value="参数名" /> 2 <!-- 该动作常常作为<jsp:forward>的子标签,和它一起使用 -->
用户将提交的表单交给dologin.jsp处理,dologin.jsp通过forward动作把请求转发给users.jsp(并人为添加表单中没有的内容:邮箱,修改表单中提交的用户名为root),users.jsp通过request.getParamer()方法获得用户名、密码、邮箱并予以显示:
login.jsp
1 <%@ page language="java" import="java.util.*" 2 contentType="text/html; charset=utf-8"%> 3 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 4 <html> 5 <head> 6 <title>用户登录</title> 7 </head> 8 9 <body> 10 请输入用户名和密码: 11 <br /> 12 <form action="dologin.jsp" name="loginForm" method="post"> 13 用户名:<input type="text" name="username" /><br /> 14 密码:<input type="password" name="password" /><br /> 15 <input type="submit" value="登录" /> 16 </form> 17 </body> 18 </html>
dologin.jsp
1 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%> 2 <jsp:forward page="users.jsp"> 3 <jsp:param value="[email protected]" name="email"/> 4 <jsp:param value="root" name="username"/> 5 </jsp:forward>
users.jsp
1 <%@ page language="java" import="java.util.*" 2 contentType="text/html; charset=utf-8"%> 3 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 4 <html> 5 <head> 6 <title>用户信息显示</title> 7 </head> 8 9 <body> 10 <h1>用户信息</h1> 11 <hr /> 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 用户名:<%=username %><br /> 密码:<%=password %><br>邮箱:<%=email %> 29 </body> 30 </html>
效果图:
该项目使用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 <%@page import="entity.Items"%> 2 <%@page import="dao.ItemsDAO"%> 3 <%@ page language="java" import="java.util.*" 4 contentType="text/html; charset=utf-8"%> 5 <!-- 显示所有的商品信息 --> 6 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 7 <html> 8 <head> 9 <title>欢迎光临网上商城</title> 10 <style type="text/css"> 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 </style> 29 </head> 30 31 <body> 32 <h1>商品展示</h1> 33 <hr> 34 <center> 35 <table width="750" height="60" cellpadding="0" cellspacing="0" 36 border="0"> 37 <tr> 38 <td> 39 <!-- 商品循环开始 --> 40 <% 41 ItemsDAO itemsDAO = new ItemsDAO(); 42 ArrayList<Items>list = itemsDAO.getAllItems(); 43 if(list!=null&&list.size()>0){ 44 //遍历所有的商品 45 for(Items item:list){ 46 %> 47 <div> 48 <dl> 49 <dt> 50 <a href="details.jsp?id=<%=item.getId() %>"> 51 <img src="images/<%=item.getPicture() %>" width="120" height="90" border="1"/> 52 </a> 53 </dt> 54 <dd class="dd_name"><%=item.getName() %></dd> 55 <dd class="dd_city">产地:<%=item.getCity() %> 价格:¥<%=item.getPrice() %></dd> 56 </dl> 57 </div> 58 <% 59 } 60 } 61 %> 62 <!-- 商品循环结束 --> 63 </td> 64 </tr> 65 </table> 66 </center> 67 </body> 68 </html>
显示商品详细信息的details.jsp
1 <%@page import="entity.Items"%> 2 <%@page import="dao.ItemsDAO"%> 3 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%> 4 <!-- 显示商品详情,并在右侧显示商品的浏览记录(最近5条记录) --> 5 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 6 <html> 7 <head> 8 <title>欢迎光临网上商城</title> 9 <style type="text/css"> 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 </style> 30 </head> 31 32 <body> 33 <h1>商品详情</h1><hr> 34 <center> 35 <table width="750" height="60" cellpadding="0" cellspacing="0" border="0"> 36 <tr> 37 <!-- 商品详细信息 --> 38 <% 39 Items item = new ItemsDAO().getItemsById(Integer.parseInt(request.getParameter("id"))); 40 if(item!=null){ 41 %> 42 <td width="70%" valign="top"> 43 <table> 44 <tr> 45 <td rowspan="4"><img src="images/<%=item.getPicture()%>" width="200" height="160"/></td> 46 </tr> 47 <tr> 48 <td><b><%=item.getName() %></b></td> 49 </tr> 50 <tr> 51 <td>产地:<%=item.getCity() %></td> 52 </tr> 53 <tr> 54 <td>价格:¥<font color="red"><b><%=item.getPrice() %></b></font></td> 55 </tr> 56 </table> 57 </td> 58 <% 59 } 60 %> 61 <!-- 取得Cookie --> 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 <td width="30%" bgcolor="#EEE" align="center"> 89 <br /><b>您浏览过的商品</b><br /> 90 <!-- 循环开始 --> 91 <% 92 ArrayList<Items>itemsList = new ItemsDAO().getViewList(list); 93 if(itemsList!=null&&itemsList.size()>0){ 94 for(Items i:itemsList){ 95 %> 96 <div> 97 <dl> 98 <dt><img src="images/<%=i.getPicture() %>" width="120" height="90" border="1" /></dt> 99 <dd class="dd_name"><%=i.getName() %></dd> 100 <dd class="dd_city">产地:<%=i.getCity() %> 价格:¥<%=i.getPrice() %></dd> 101 </dl> 102 </div> 103 <% 104 } 105 } 106 %> 107 <!-- 循环结束 --> 108 </td> 109 </tr> 110 </table> 111 </center> 112 </body> 113 </html>
主业务逻辑类ItemsDAO
1 package dao; 2 3 import java.sql.Connection; 4 import java.sql.PreparedStatement; 5 import java.sql.ResultSet; 6 import java.sql.SQLException; 7 import java.util.ArrayList; 8 import java.util.Arrays; 9 10 import util.DBHelper; 11 12 import entity.Items; 13 14 /** 15 * 商品的业务逻辑类 16 */ 17 public class ItemsDAO { 18 /** 获得所有的商品信息 */ 19 public ArrayList<Items> getAllItems() { 20 ArrayList<Items> itemsList = new ArrayList<Items>();// 商品集合 21 22 Connection coon = null; 23 PreparedStatement pstmt = null; 24 ResultSet rs = null; 25 26 try { 27 coon = DBHelper.getConnection(); 28 String sql = "select * from items;";// sql语句 29 pstmt = coon.prepareStatement(sql); 30 rs = pstmt.executeQuery(); 31 32 while (rs.next()) { 33 Items items = new Items(); 34 setItemsAttributes(rs, items);//为实体类【商品】设置属性【根据DB中的相关字段】 35 itemsList.add(items);// 把1个商品加入集合 36 } 37 return itemsList; 38 } catch (Exception e) { 39 e.printStackTrace(); 40 return null; 41 } finally { 42 DBHelper.relsaseResource(rs, pstmt); 43 } 44 } 45 46 /** 根据数据库的结果集设置实体类的属性 */ 47 private void setItemsAttributes(ResultSet rs, Items items) 48 throws SQLException { 49 items.setId(rs.getInt("id")); 50 items.setName(rs.getString("name")); 51 items.setCity(rs.getString("city")); 52 items.setPrice(rs.getInt("price")); 53 items.setNumber(rs.getInt("number")); 54 items.setPicture(rs.getString("picture")); 55 } 56 57 /** 根据商品的id获得商品资料 */ 58 public Items getItemsById(int id) { 59 Connection coon = null; 60 PreparedStatement pstmt = null; 61 ResultSet rs = null; 62 63 try { 64 coon = DBHelper.getConnection(); 65 String sql = "select * from items where id=?;"; 66 pstmt = coon.prepareStatement(sql); 67 pstmt.setInt(1, id); 68 rs = pstmt.executeQuery(); 69 70 if (rs.next()) { 71 Items items = new Items(); 72 setItemsAttributes(rs, items); 73 return items; 74 } else { 75 return null; 76 } 77 } catch (Exception e) { 78 e.printStackTrace(); 79 return null; 80 } finally { 81 DBHelper.relsaseResource(rs, pstmt); 82 } 83 } 84 85 /**获取最近浏览的前5条商品信息*/ 86 public ArrayList<Items>getViewList(String list){ 87 ArrayList<Items>itemsList = new ArrayList<Items>(); 88 int iCount = 5;//每次返回5条 89 if (list!=null&&list.length()>0) { 90 String[]temp=list.split(","); 91 //显示最近浏览过的商品——倒序得到Cookie中保存的ID 92 if (temp.length>=iCount) { 93 System.out.println("浏览记录大于等于5条"); 94 System.out.println(Arrays.toString(temp)); 95 for(int i = temp.length-1;i>=temp.length-iCount;i--){ 96 itemsList.add(getItemsById(Integer.parseInt(temp[i]))); 97 } 98 }else { 99 System.out.println("浏览记录小于5条"); 100 System.out.println(Arrays.toString(temp)); 101 for(int i = temp.length-1;i>=0;i--){ 102 itemsList.add(getItemsById(Integer.parseInt(temp[i]))); 103 } 104 } 105 return itemsList; 106 }else { 107 return null; 108 } 109 } 110 }
项目展示:(项目地址:https://git.oschina.net/gaopengfei/JSPLogin.git)
解决中文乱码:
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");