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:

 <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>手工编写的第一个java web项目</title>
</head>
<body>
<h1>这是手工编写的第一个java web项目——jsp</h1>
<hr />
</body>
</html>

  在项目目录中创建一个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标记中添加以下代码:

 <welcome-file-list>
<welcome-file>/haha.jsp</welcome-file>
</welcome-file-list>

  运行结果:

  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的以下标记:

 <Connector connectionTimeout="20000" port="8888" protocol="HTTP/1.1" redirectPort="8443"/>

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指令语法:

<%@ 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指令的全部属性如下:

 <%@page
[language="Java"]
[extends="package.class"] // 指定JSP页面编译所产生的Java类所继承的父类,或所实现的接口。
[import="package.class│package.*,…"]
[session="true│false"]
[buffer="none│8kb│size kb"]
[autoFlush="true│false"]
[isThreadSafe="true│false"]
[info="text"]
[errorPage="relativeURL"] // 指定错误处理页面。因为JSP内建了异常机制支持,所以JSP可以不处理异常。
[contentType="mimeType[;charset=characterSet]"│"text/html;charSet=ISO8859-1"]
[isErrorPage="true│false"] // 设置本JSP页面是否为错误处理程序。
%>

    注意:除page指令中的import属性之外,其他属性均只能设置一次。

  2.4jsp注释

  分为3种:html注释,jsp注释,jsp脚本注释。语法:

 <!-- html注释 -->
<%-- jsp注释 --%>
<%
/*这里是jsp脚本注释 有两种*/ //单行注释 /*多行注释*/
%>

  例如:

 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>"> <title>My JSP 'index.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
</head> <body>
<h1>欢迎你</h1>
<!-- 这是html注释,客户端可可见 -->
<%-- 这是jsp注释,客户端不可见 --%>
<%
/*这里是jsp脚本注释
有两种*/
//单行注释
/*多行注释*/
%>
</body>
</html>

  将项目部署到Tomcat,客户端用浏览器查看源代码:

  2.5jsp脚本

    在jsp页面中执行的java代码。语法:

<% java代码 %>
 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>"> <title>My JSP 'index.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
</head> <body>
<h1>欢迎你</h1>
<hr>
<%
out.println("通过jsp内置对象out对象打印输出");
%>
</body>
</html>

  

  2.6jsp声明

      jsp页面中定义变量或者方法。语法:

<%! java代码 %>

  例如:

  <%!
String s = "张三"; //声明一个String类型的变量
int add(int x,int y){ //声明一个返回值为int类型的方法
return x+y;
}
%>

  2.7jsp表达式

    jsp页面中执行的表达式。语法(注意=紧挨着百分号,表达式末尾没有分号):

<%=表达式 %>
 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>"> <title>My JSP 'index.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
</head> <body>
<h1>欢迎你</h1>
<hr>
<!-- 这是html注释,客户端可可见 -->
<%!
String s = "张三"; //声明一个String类型的变量
int add(int x,int y){ //声明一个返回值为int类型的方法
return x+y;
}
%>
你好:<%=s %><br>
令x=10,y=5,则x+y = <%=add(10, 5) %>
</body>
</html>

  运行结果:

  2.8jsp页面生命周期

    

    jspService()方法被调用来处理客户端的请求。对每一个请求,JSP引擎创建一个新的线程来处理该请求。如果有多个客户端同时请求你该jsp文件,则jsp引擎会创建多个线程(每一个客户端请求对应一个线程)。以多线程的方式执行可以大大降低对系统的资源需求,提高系统的并发量以及缩短服务器的响应时间——但是同时要注意多线程的同步问题。由于该Servlet常驻内存,所以响应是非常快的。

    当页面没有被访问的时候work目录下没有相关的Servlet。如果页面被访问之后就会在work目录的对应目录生成响应的Servlet。如图:

  打开index_jsp.java会看到以下的初始化方法:

  然后该Servlet常驻内存,创建线程处理每一个客户端的请求。由每一个线程调用_jspService()方法来处理请求。

  如果jsp页面内容发生了改变,jsp引擎就需要重新编译jsp页面。我们修改index.jsp,用浏览器重新访问,则:

 2.9阶段项目(九九乘法表)

 <%@page import="java.io.IOException"%>
<%@ page language="java" import="java.util.*"
contentType="text/html; charset=utf-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>"> <title>My JSP 'multiplicationTable.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page"> </head> <body>
<h1>九九乘法表</h1>
<h2>表达式的方式打印乘法表</h2>
<%!
//声明表达式
String printMultiTable(){
StringBuilder s = new StringBuilder();
for(int i=1;i<=9;i++){
for(int j=1;j<=i;j++){
s.append(i+" * "+j+" = "+i*j+"\t");
}
s.append("<br />");//追加换行标记,注意不能使用\n
}
return s.toString();
}
%>
<%=printMultiTable() //调用表达式
%> <h2>使用脚本的方式打印九九乘法表</h2>
<%!
//jsp小脚本
void printMultiTable2(JspWriter out) throws IOException{
StringBuilder s = new StringBuilder();
for(int i=1;i<=9;i++){
for(int j =1;j<=i;j++){
s.append(i+" * "+j+" = "+i*j+"\t");
}
s.append("<br />");
}
out.println(s.toString());
}
%> <%
//调用脚本
printMultiTable2(out);
%>
</body>
</html>

  运行结果:

3.jsp内置对象

  3.1jsp内置对象简介

      JSP内置对象是Web容器创建的一组对象,不需要使用new关键字,JSP规范将它们完成了默认初始化(由JSP页面对应Servlet的_jspService()方法来创建这些实例)。例如打印九九乘法表的jsp小脚本中使用的out对象就是jsp内置对象。

 <%!
//jsp小脚本
void printMultiTable2(JspWriter out) throws IOException{
StringBuilder s = new StringBuilder();
for(int i=1;i<=9;i++){
for(int j =1;j<=i;j++){
s.append(i+" * "+j+" = "+i*j+"\t");
}
s.append("<br />");
}
out.println(s.toString());//这里的out就是jsp内置对象
}
%>

    JSP一共有9个内置对象,其中常用的内置对象有5个,如图所示:

  3.3out对象

    缓冲区(Buffer)就是内存中用来保存临时数据的一块区域。关于缓冲区有一个很形象的例子:比如我们煮好了饭放在锅里,如果我们一粒一粒地来吃米饭就不知道吃到猴年马月,拿来一个碗来一碗一碗吃,岂不快哉!这里的碗就充当了缓冲区的概念。其实IO的本质就是直接操作字节,但是效率太慢所以引入了缓冲区。

    out对象是JspWriter类的一个实例——是向客户端输出内容的常用对象,该对象的常用方法:

 void println(String message);   // 向客户端打印字符串
void clear(); // 清除缓冲区内容,如果在flush之后调用会抛出异常
void clearBuffer(); // 清除缓冲区内容,如果在flush之后调用不会抛出异常
void flush(); // 将缓冲区的内容输出到客户端
int getBufferSize(); // 返回缓冲区的大小(字节),默认是0
int getRemaining(); // 返回缓冲区可用容量
boolean isAutoFlush(); // 返回缓冲区满的时候是自动清空还是抛出异常
void close(); // 关闭输出流

    下面是一个简单的示例:

 <h1>JSP的out内置对象</h1>
<%
//jsp脚本
out.println("<h2>静夜思</h2>");
out.println("李白<br /><br />");
out.println("窗前明月光,<br />");
out.println("疑是地上霜。<br />");
out.println("举头望明月,<br />");
out.println("低头思故乡。<hr />");
%>
<!-- JSP表达式 -->
缓冲区大小:<%=out.getBufferSize() %>字节。<br />
剩余缓冲区(可用缓冲区):<%=out.getRemaining() %>字节。<br />
是否自动清空缓冲区:<%=out.isAutoFlush() %><br />

  运行结果:

 <h1>JSP的out内置对象</h1>
<%
//jsp脚本
out.println("<h2>静夜思</h2>");
out.println("李白<br /><br />");
out.println("窗前明月光,<br />");
out.flush();//将缓冲区中的内容输出到客户端
out.println("疑是地上霜。<br />");
out.println("举头望明月,<br />");
out.println("低头思故乡。<hr />");
%>
<!-- JSP表达式 -->
缓冲区大小:<%=out.getBufferSize() %>字节。<br />
剩余缓冲区(可用缓冲区):<%=out.getRemaining() %>字节。<br />
是否自动清空缓冲区:<%=out.isAutoFlush() %><br />

  如果在第7行强制刷新缓冲区,则输出的页面不会有任何变化,仅仅是可用缓冲区的数量变多了而已【因为flush清空了缓冲区】

 <%
//jsp脚本
out.println("<h2>静夜思</h2>");
out.println("李白<br /><br />");
out.println("窗前明月光,<br />"); out.flush();//将缓冲区中的内容输出到客户端
out.clear();//在flush之后调用clear,将会抛出异常 out.println("疑是地上霜。<br />");
out.println("举头望明月,<br />");
out.println("低头思故乡。<hr />");
%>

  运行结果:

  <%
//jsp脚本
out.println("<h2>静夜思</h2>");
out.println("李白<br /><br />");
out.println("窗前明月光,<br />"); out.flush();//将缓冲区中的内容输出到客户端
out.clearBuffer();//在flush之后调用clearBuffer不会抛出异常 out.println("疑是地上霜。<br />");
out.println("举头望明月,<br />");
out.println("低头思故乡。<hr />");
%>

  运行结果:

  3.4post和get提交方式的区别

<form name="regForm" action="处理脚本"  method="提交方式[post|get]"></form>
  • get:以明文的方式通过URL提交数据,提交的数据最大不超过2K。适合提交数据量小,安全性不高的数据【例如:搜索和查询】
  • post:将用户提交的数据封装在URL HEADER内。适合提交数据量大,安全性高的数据【例如:注册、修改、上传】 
  • 下面以用户登录的例子比较两者的区别:

    login.jsp页面
    请输入用户名和密码:
<form name = "loginForm" action = "dologin.jsp" method = "get">
用户名:<input type="text" name="username" value="" maxlength = "15" /><br />
密码:<input type="password" name="password" maxlength="16" value="" /><br />
<input type="submit" value="提交" />
</form>

  处理登录的动作脚本dologin.jsp仅仅是显示一句话"登录成功"。

  运行结果:

  将用户登录表单的get方式改为post。

  3.5request对象

    客户端的请求被封装在request对象中,通过它才能了解到客户端的需求,然后做出响应。它是HttpServletRequest对象的实例。request对象具有请求域,即:完成客户端的请求之前,该对象一直有效。常用方法如下:

/* 两个比较常用的方法 */
1 String getParameter(String name); // 返回name指定参数的参数值
String[] getParameterValues(String name); // 返回包含name的所有值的数组 void setAttribute(String,Object); // 存储此请求中的属性
String getContentType(); // 返回请求体的MIME类型
Stirng getProtocol(); // 返回请求所用的协议和版本号
String getServerName(); // 返回接受请求的服务器的主机名
int getServerPort(); // 返回服务器接受此请求所用的端口号
String getCharacterEncoding(); // 返回字符编码方式【只能解决post方式的乱码问题】
void setCharacterEncoding(); // 设置请求的字符编码方式
int getContentLength(); // 返回请求体的长度(字节)
String getRemoteAddr(); // 返回发送此请求的客户端IP
String getRealPath(String path); // 返回虚拟路径的真实路径
String request.getContextPath(); // 返回上下文路径

  以用户注册页面为例(用户在注册页reg.jsp完善信息后提交给request.jsp来处理):

  用户注册页reg.jsp

 1    请输入相关信息完成注册<br />
<form action="request.jsp" name="regForm" method="post">
用户名:<input type="text" name = "username" /><br />
密码:<input type="password" name = "password" /><br />
爱好:
<input type="checkbox" name = "favorite" value="read"/>读书
<input type="checkbox" name = "favorite" value="music"/>音乐
<input type="checkbox" name = "favorite" value="movie"/>电影
<input type="checkbox" name = "favorite" value="internet"/>上网<br />
<input type="submit" value="提交" />
</form>

   处理用户注册页的request.jsp

  <h1>request内置对象</h1><br  />

     用户名:<%=request.getParameter("username") %><br />
密码:<%=request.getParameter("password") %><hr />
爱好:<br />
<%
String[]favorites = request.getParameterValues("favorite");
for(String str:favorites){
9 out.print(str+"&nbsp;&nbsp;");
}
%>

    运行结果:

  但是以上页面存在一个问题:假如我们在用户名中输入中文:

  这时只要再request.jsp中设置字符集和reg.jsp一样即可:

 <h1>request内置对象</h1><br  />
<!-- 设置字符集,防止出现中文乱码 -->
<% request.setCharacterEncoding("utf-8"); %> 用户名:<%=request.getParameter("username") %><br />
密码:<%=request.getParameter("password") %><hr />
爱好:<br />
<%
String[]favorites = request.getParameterValues("favorite");
for(String str:favorites){
out.print(str+"&nbsp;&nbsp;");
}
%>

  除了可以使用表单的方式传递数据给request对象,也可以使用URL传参的方式传递数据给request对象:

  reg.jsp

<a href="request.jsp?username=root&password=toor&favorite=read&favorite=internet">测试URL传参</a>

  request.jsp(不变)

 <h1>request内置对象</h1><br  />
<!-- 设置字符集,防止出现中文乱码 -->
<% request.setCharacterEncoding("utf-8"); %>
用户名:<%=request.getParameter("username") %><br />
密码:<%=request.getParameter("password") %><hr />
爱好:<br />
<%
String[]favorites;
if((favorites=request.getParameterValues("favorite"))!=null){
for(String str:favorites){
out.print(str+"&nbsp;&nbsp;");
}
}
%>

  运行结果:

  如果我们在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:

   请输入相关信息完成注册<br />
<form action="request.jsp" name="regForm" method="post">
用户名:<input type="text" name = "username" /><br />
  密码:<input type="password" name = "password" /><br />
爱好:
<input type="checkbox" name = "favorite" value="read"/>读书
<input type="checkbox" name = "favorite" value="music"/>音乐
<input type="checkbox" name = "favorite" value="movie"/>电影
<input type="checkbox" name = "favorite" value="internet"/>上网<br />
<input type="submit" value="提交" />
</form>

  request.jsp

 <h1>request内置对象</h1><br  />
<!-- 设置字符集,防止出现中文乱码 -->
<% request.setCharacterEncoding("utf-8"); %>
<%
//在request对象中保存一个email属性
request.setAttribute("email","io@gmail.com"); %>
用户名:<%=request.getParameter("username") %><br />
密码:<%=request.getParameter("password") %><hr />
爱好:<br />
<%
String[]favorites;
if((favorites=request.getParameterValues("favorite"))!=null){
for(String str:favorites){
out.print(str+"&nbsp;&nbsp;");
}
}
%>
<br />邮箱:<%=request.getAttribute("email") %>

  运行结果:

  <h1>request内置对象</h1><br  />
<!-- 设置字符集,防止出现中文乱码 -->
<% request.setCharacterEncoding("utf-8"); %>
<%
//在request对象中保存一个email属性
request.setAttribute("email","io@gmail.com"); %>
用户名:<%=request.getParameter("username") %><br />
密码:<%=request.getParameter("password") %><hr />
爱好:<br />
<%
String[]favorites;
if((favorites=request.getParameterValues("favorite"))!=null){
for(String str:favorites){
out.print(str+"&nbsp;&nbsp;");
}
}
%>
<br />邮箱:<%=request.getAttribute("email") %> <hr />
请求体的MIME类型:<%=request.getContentType() %><br />
请求体的协议及版本号:<%=request.getProtocol() %><br />
服务器主机名:<%=request.getServerName() %><br />
服务器端口号:<%=request.getServerPort() %><br />
请求的字符编码:<%=request.getCharacterEncoding() %><br />
请求的文件长度:<%=request.getContentLength() %>字节<br />
请求的客户端的IP:<%=request.getRemoteAddr() %><br />
请求的真实路径:<%=request.getRealPath("request.jsp") %><br />
请求的上下文路径:<%=request.getContextPath() %>

  运行结果:

  3.6response对象

    response对象包含了响应客户请求的相关信息,但是在JSP中很少直接使用到它。它是HttpServletResponse类的实例。response对象具有页面作用域——即:访问一个页面时,该页面的response只对本次访问有效,其他页面的response对象对当前页面无效。常用方法如下:

 String getCharacterEncoding();     // 返回响应所用的编码
void setContentType(); // 设置响应的MIME类型
PrintWriter getPrintWriter(); // 返回一个可以向客户端输出字符的对象【注意区别于out内置对象】
sendRedirect(String location); // 重定向客户端的请求

  response.jsp

 <%@page import="java.io.PrintWriter"%>
<%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%>
<%
response.setContentType("text/html;charset=utf-8");//设置响应的MIME类型 out.println("<h1>response内置对象</h1><hr />"); PrintWriter outer = response.getWriter();//获得输出流对象
outer.println("我是response对象生成的outter对象,在页面中总是在前面输出");
%>

  运行结果:

  运行结果很是奇怪:明明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.sendResponse(),从本质上讲相当于两次请求,前一次的请求对象不会保存,浏览器的URL栏会改变。
  • 请求转发:服务器行为request.getRequestDipatcher().forword(req,resp);是一次请求,转发后请求对象会被保存,浏览器的URL不会改变。
  • 例如还是用原来的例子:我们在reg.jsp中指定处理页面的脚本是response.jsp而在response.jsp中我们重定向到request.jsp。观察request.jsp的输出:

  如果我们在response.jsp中使用请求转发:

 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%>
<%
//请求转发
request.getRequestDispatcher("request.jsp").forward(request, response);
%>

  运行结果:

  3.8session对象

    Session客户端与服务器的一次会话。Web中的Session表示用户在浏览某个网站时,从进入网站到浏览器关闭所经过的这段时间——也就是用户浏览这个网站所花费的时间。在服务器的内存中保存着不同用户的Session。

  session对象的常用方法:

 long getCreationTime();                          // 返回session的创建时间
String getId(); // 返回session创建时JSP引擎为它设定的唯一ID号
Object setAttribute(String name,Object value); // 使用指定名称将对象绑定到此会话
Object getAttribute(String name); // 返回此会话中的指定名称绑定在一起的对象,如果没有对象绑定在该名称下则返回null
String[] getValueNames(); // 返回一个包含此Session所有可用属性的数组
int getMaxInactiveInterval(); // 返回两次请求间隔多长时间此session被取消【单位:秒】

  sesseion_page1.jsp

    <h1>session内置对象</h1>
<h2>session_page1.jsp</h2>
<%
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
String date = sdf.format(new Date(session.getCreationTime()));
out.print("session的创建时间:" + date);
session.setAttribute("username", "admin"); // 向session中设置属性
%>
<br />Session的ID号:<%=session.getId() %><br />
从session中获取用户名:<%=session.getAttribute("username") %> <a href="session_page2.jsp" target="_blank">以新窗口的方式打开session_page2.jsp</a>

  session_page2.jsp

     <h2>session_page2.jsp</h2>
<%
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
String date = sdf.format(new Date(session.getCreationTime()));
out.print("session的创建时间:" + date);
%>
<br />Session的ID号:<%=session.getId() %><br />
从session中获取用户名:<%=session.getAttribute("username") %>

  运行结果:

  可以获取session中保存的属性集合以及设置session的有效期:

  <%
session.setMaxInactiveInterval(5);//设置session的有效期为5s session.setAttribute("username", "admin"); // 向session中设置属性
session.setAttribute("password", "123456");
session.setAttribute("age", 16);
%> <%
//获取session中保存的属性
String[]names=session.getValueNames();
if(names!=null){
for(String str:names){
out.print(str+"\t");
}
}
%>

  Session的生命周期:

  • 创建:当客户端第一次访问某个jsp页面或者Servlet的时候,服务器会为当前会话创建一个SessionId。每次客户端向服务器发送请求的时候都会携带此SessionId,服务端会对此SessionId进行检验——判断是否属于同一次会话。
  • 活动阶段:某次会话中通过超链接打开新的页面;只要当前页面没有全部关闭,打开新的浏览器窗口访问同一项目资源也属于同一会话。注意:原有的会话仍然存在,只不过再也没有客户端会携带此sessionId交给服务器检验。——创建一个新的会话并不意味着原有会话消失,除非超时。
  • 销毁。

  Tomcat如何进入后台管理系统?

   修改/conf/tomcat-user.xml为以下:

 <?xml version="1.0" encoding="UTF-8"?>
<tomcat-users>
<role rolename="admin-gui"/>
<role rolename="manager-gui"/>
<user username="admin" password="admin" roles="admin-gui,manager-gui"></user>
</tomcat-users>

  在浏览器中打开session_page1.jsp然后通过session_page1.jsp的超链接打开session_page2.jsp在后台管理系统中查看:

  如果我们在session创建之后调用session.invalidate()方法,例如:我们在session_page1.jsp中这样写:

  <h1>session内置对象</h1>
<h2>session_page1.jsp</h2>
<%
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
String date = sdf.format(new Date(session.getCreationTime()));
out.print("session的创建时间:" + date); session.setAttribute("username", "admin"); // 向session中设置属性
session.setAttribute("password", "123456");
session.setAttribute("age", 16);
%>
<br />Session的ID号:<%=session.getId() %><hr />
session中保存的属性有:<br />
<%
//获取session中保存的属性
String[]names=session.getValueNames();
if(names!=null){
for(String str:names){
out.print(str+"\t");
}
}
session.invalidate();//销毁session
%>
<a href = "session_page2.jsp" target = "_blank">点击在新标签页中打开session_page2.jsp</a>

  运行结果(不断刷新浏览器):

  Session默认session超时是30min设置session对象的超时有两种方式:

  • session.setMaxInactiveInterval(5);单位是秒
  • 在web.xml中配置(单位是分钟):
  • <session-config>
    <session-timeout>30</session-timeout>
    </session-config>

    3.9application对象

  • application对象实现了用户间数据的共享,可以存放全局变量。
  • application对象开始于服务器的启动,结束于服务器的关闭。
  • 在用户的前后连接或者不同用户之间,可以对统一个application对象的属性进行操作。
  • 在任何地方对application对象属性的操作将会影响到其他用户对此的访问。
  • application对象是ServletContext类的实例。
  • 该对象的常用方法如下:

 void setAttribute(String name,Object value); // 指定名称将对象绑定到此会话
Object getAttribute(String name); // 返回此会话中和指定名称绑定在一起的对象,如果没有对象绑定在该名称下则返回null
Enumeration getAttributeNames(); // 返回所有可用属性名的枚举
String getServerInfo(); // 返回JSP(Servlet)引擎名和版本号

  

     <h1>application对象</h1>
<%
//在application中保存3个键值对
application.setAttribute("city", "北京");
application.setAttribute("zipcode", "10000");
application.setAttribute("email", "io@gmail.com");
%>
所在城市:<%=application.getAttribute("city") %><hr>
application中存放的属性有:<br>
<%
Enumeration attrs = application.getAttributeNames();
while(attrs.hasMoreElements()){
out.print(attrs.nextElement()+"<br>");
}
%>
<hr>
jsp(Servlet)引擎:<%=application.getServerInfo() %><br>

  运行效果:

  3.10page对象

    page对象就是指向当前jsp页面本身(就好像类中的this),是java.lang.Object类的实例,常用方法和Object类的方法一致。例如它的toString()方法:

  <h1>page内置对象</h1>
当前页面的page对象的字符串描述:<br />
<%=page.toString() %>

  运行结果:

  我们打开tomcat的work目录(编译生成的Servlet目录)看到它的包结构是org.apache.jsp,在该目录下有一系列的*_jsp.java和*_jsp.class文件。我们打开page_jsp.java发现类名就是page_jsp。

  3.11pageContext对象

  • 提供了对JSP页面内所有的对象及名字空间的访问。
  • 可以访问到本页所在的session,也可以取本页面所在的application的某一属性值
  • 相当于页面中所有功能的集大成者。
  • pageContext对象的本类名也叫pageContext。
  • 常用方法:

 JspWriter getOut();                           // 返回当前客户端响应被使用的JspWriter流(out)
HttpSession getSession(); // 返回当前页中的HttpSession对象(session)
Object getPage(); // 返回当前页面的Object对象(page)
ServletRequest getRequest(); // 返回当前页面的ServletRequest对象(request)
ServletResponse getResponse(); // 返回当前页面的ServletResponse对象(response)
void setAttribute(String name,Object value); // 设置属性键值对
Object getAttribute(String name,int scope); // 在指定范围内取属性值
void forward(String relativeUrlPath); // 将当前页面重定向到另一页面
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(页面用于向页面输出当前的日期):

 <%@page import="java.text.SimpleDateFormat"%>
<%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%>
<%
out.print(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()));
%>

  下面我们在pageContext.jsp页面中包含include.jsp:

    <h1>pageContext内置对象</h1>
用户名:<%=pageContext.getSession().getAttribute("username") %><hr> <!-- 包含其他页面 -->
<%pageContext.include("include.jsp"); %>

  3.12config对象

      该对象是一个在servlet初始化时,jsp引擎向它传递信息时使用的,此信息包含Servlet初始化时所用到的参数(键-值对)以及服务器的相关信息(通过传递一个ServletContext对象),常用方法:

 ServletContext getServletContext();  // 返回服务器相关信息的ServletContext对象
String getInitParameter(String name);// 返回初始化参数的值
Enumeration getInitParameterNames(); // 返回Servlet初始化时所有需要参数的枚举

  3.13exception对象

    该对象是一个异常对象,如果一个页面在运行过程中出现了异常就会产生这个对象。如果一个JSP页面需要应用此对象,就必须把isErrorPage设为true——否则无法编译。它实际上是java.lang.Throwable的对象,常用方法:

 String getMessage();            // 返回异常的描述信息
String toString(); // 返回关于异常的简短描述信息
void printStackTrace(); // 显示异常及其栈轨迹
Throwable FillInStackTrace(); // 重写异常的执行栈轨迹

  首先建立一个会出现异常的页面exception_text.jsp(并指定处理异常的页面):

 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8" errorPage="exception.jsp"%>
<!-- 在errorPage中指定处理异常的页面 -->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>这个页面肯定会出现异常</title>
</head> <body>
<h1>测试异常对象</h1><hr />
<%
out.println(100/0);//肯定会抛出运行时异常【算术异常】
%>
</body>
</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>

  运行结果:

  

  3.14阶段案例——实现用户登录

      这个案例比较简单:用户名和密码都是admin(没有使用数据库),如果用户名和密码相符,则页面跳转到login_success.jsp【服务器内部转发】,提示用户登录成功;如果用户登录失败,则页面跳转到login_failure.jsp【请求重定向】,提示用户登录失败。

  整个项目的截图:

  项目地址:https://git.oschina.net/gaopengfei/JSPLogin.git

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:

 /**
* 这是一个典型的JavaBean
*/ // 1.这是一个共有的类
public class Student {
// 2.属性私有
private String name;
private int age; // 3.有共有的无参构造
public Student() {
} // 4.getter和setter
public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
} }

 JavaBean有2种应用方式: 

4.2jsp动作元素【运行时】

     JSP动作元素(action elements),动作元素为请求处理阶段提供信息。动作元素遵循XML元素的语法——有一个元素名的开始标签,可以有属性、可选的内容、与开始标签匹配的结束标签。

  

  4.3普通方式应用java bean

  像使用普通java类一样,创建javabean实例。在MyEclipse项目的src目录下新建类Users:

 package org.po;

 /**
* 用户类-符合Javabean的实际原则
*/
public class Users {
private String username;
private String password; public Users() { } public String getUsername() {
return username;
} public void setUsername(String username) {
this.username = username;
} public String getPassword() {
return password;
} public void setPassword(String password) {
this.password = password;
} }

    下面我们在javabean_page1.jsp中使用以上的Javabean:

 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%>
<!-- 使用import指令导入Javabean -->
<%@ page import="org.po.Users" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>JavaBeans范例</title>
</head> <body>
<h1>使用普通方式创建Javabean的实例</h1>
<%
//使用普通方式创建JavaBean
Users user = new Users();
user.setUsername("admin");
user.setPassword("admin");
%>
用户名:<%=user.getUsername() %><br />
密码:<%=user.getPassword() %>
</body>
</html>

  运行结果:

     

  4.4useBean动作元素

    <jsp:useBean>用于在jsp页面中实例化或者在指定范围内使用JavaBean。基本操作是首先使用id和作用域查找一个现有的对象,如果在指定的作用域中没有找到具有指定id的对象,那么它会试图使用其他属性创建一个新实例。语法如下:

<jsp:useBean id="标示符" class="java类名" scope="作用域" />
 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%>
<!-- 这里不需要page指令来导入User类了 -->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>使用useBean动作指令来使用JavaBean</title>
</head> <body>
<h1>使用&lt;jsp:useBean&gt;动作指令来使用JavaBean</h1>
<!-- useBean指令 -->
<jsp:useBean id="myUsers" class="org.po.Users" scope="page"></jsp:useBean>
用户名:<%=myUsers.getUsername() %><br/>
密码:<%=myUsers.getPassword() %>
</body>
</html>

  运行结果:

  4.5setProperty

    上一个jsp页面中取得的用户名和密码都为null,原因就是我们使用仅仅是实例化了Users对象,并没有为其成员变量执行属性。当然你也可以使用setXXX来给已经实例化的JavaBean设置属性,不过我更推荐使用setProperty指令。

    <jsp:setProperty>的主要作用就是给已经实例化的JavaBean的属性赋值,一共有4种形式:

 <jsp:setProperty name="JavaBean实例名" property="*" />                        <!-- 和表单关联,全部属性 -->
<jsp:setProperty name="JavaBean实例名" property="JavaBean属性名" />                 <!-- 和表单关联,指定属性 -->
<jsp:setProperty name="JavaBean实例名" property="JavaBean属性名" value = "BeanValue" />     <!-- 手工设置 -->
<jsp:setProperty name="JavaBean实例名" property="propertyName" param="request对象中的参数名"/> <!-- 和request参数关联,URL传参 -->

   方式一:【表单内容的自动全部匹配】  

   新建一个用户登录表单login.jsp:

 <form action="dologin.jsp" method="post" name="loginForm">
用户名:<input type="text" name="username"/><br />
密码:<input type="password" name="password" />
  <input type="submit" value="提交" />
</form>

    处理用户登录的页面dologin.jsp

 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>用户登录处理页面</title>
</head> <body> <!-- 实例化javaBean对象 -->
<jsp:useBean id="myUsers" class="org.po.Users"></jsp:useBean> <h1>setPerpority动作元素</h1><hr /> <!-- 根据表单自动匹配所有的属性并设置 -->
<jsp:setProperty property="*" name="myUsers"/>
用户名:<%=myUsers.getUsername() %><br>
密码:<%=myUsers.getPassword() %> </body>
</html>

    运行结果:

    这实际上以依靠表单中的name属性来匹配javabean中的成员变量。例如:在用户登录表单中input标记的属性有一个name="username",那么使用这种自动匹配的方式就会把这个username与javabean中的属性挨个查找,如果找到了就为这个字段设定相应的值——换言之:表单中的name属性要和要和javabean中的属性对应相同。

    方式二:部分匹配表单的属性(dologin.jsp):

 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>用户登录处理页面</title>
</head> <body> <!-- 实例化javaBean对象 -->
<jsp:useBean id="myUsers" class="org.po.Users"></jsp:useBean> <h1>setPerpority动作元素</h1><hr /> <!-- 根据表单匹配部分属性 -->
<jsp:setProperty property="username" name="myUsers"/>
用户名:<%=myUsers.getUsername() %><br>
密码:<%=myUsers.getPassword() %> </body>
</html>

    运行结果:

  仅仅匹配了用户名属性,由于密码属性没有匹配,所以为null。这种方式也要注意表单的name属性要和javabean的属性相同。

  方式三:手工给javabean的属性赋值——与表单无关(dologin.jsp):

 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>用户登录处理页面</title>
</head> <body> <!-- 实例化javaBean对象 -->
<jsp:useBean id="myUsers" class="org.po.Users"></jsp:useBean> <h1>setPerpority动作元素</h1><hr /> <!-- 与表单无关,通过手工给javabean的属性赋值 -->
<jsp:setProperty property="username" name="myUsers" value="root"/>
<jsp:setProperty property="password" name="myUsers" value="123456"/>
用户名:<%=myUsers.getUsername() %><br>
密码:<%=myUsers.getPassword() %> </body>
</html>

  

    方式四(通过URL传参的方式给javabean赋值):

    login.jsp:

<a href="dologin.jsp?id=root&sn=123456">通过url传参的方式给javabean的属性赋值</a>

    dologin.jsp:

 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>用户登录处理页面</title>
</head> <body> <!-- 实例化javaBean对象 -->
<jsp:useBean id="myUsers" class="org.po.Users"></jsp:useBean> <h1>setPerpority动作元素</h1><hr /> <!-- 通过URL传参的方式给javabean属性赋值-->
<jsp:setProperty property="username" name="myUsers" param="id"/>
<jsp:setProperty property="password" name="myUsers" param="sn"/>
用户名:<%=myUsers.getUsername() %><br>
密码:<%=myUsers.getPassword() %> </body>
</html>

    运行结果:

  4.6getProperty

    <jsp:getProperty>获取指定JavaBean对象的属性值【String类型】。语法:

<jsp:getProperty name="JavaBean实例名" property="属性名" />

    前面的例子已经通过URL传递参数的方式指定了javabean的属性值,现在通过getProperty的方式获得javabean的属性值:

 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>用户登录处理页面</title>
</head> <body> <!-- 实例化javaBean对象 -->
<jsp:useBean id="myUsers" class="org.po.Users"></jsp:useBean> <h1>setPerpority动作元素</h1><hr /> <!-- 通过URL传参的方式给javabean属性赋值-->
<jsp:setProperty property="username" name="myUsers" param="id"/>
<jsp:setProperty property="password" name="myUsers" param="sn"/> <!-- 通过getter获得javabean的属性值 -->
<%--
用户名:<%=myUsers.getUsername() %><br>
密码:<%=myUsers.getPassword() %>
--%> <!-- 通过getProperty获得javabean的属性值 -->
用户名:<jsp:getProperty property="username" name="myUsers"/><br />
密码:<jsp:getProperty property="password" name="myUsers"/>
</body>
</html>

  运行结果:

  4.7java bean的4个作用域范围

    使用useBean的scope属性可以指定javabean的作用域。

 page        // 当前页面有效,可以通过PageContext.getAttribute()获得JavaBean对象。
request // 同一个请求有效,可通过HttpRequest.getAttibute()方法获得JavaBean对象。
session // 同一个session有效,可通过HttpSession.getAttribute()方法获得JavaBean对象。
application // 同一个application有效,可通过application.getAttribute()方法获得JavaBean对象。

  下面是一个简单的测试4个作用范围的示例:

  dolog.jsp以URL传参的方式为javabean指定属性值:

 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>用户登录处理页面</title>
</head> <body> <!-- 实例化javaBean对象,并制定作用域为application -->
<jsp:useBean id="myUsers" class="org.po.Users" scope="application"></jsp:useBean> <h1>setPerpority动作元素</h1><hr /> <!-- 通过URL传参的方式给javabean的属性赋值-->
<jsp:setProperty property="username" name="myUsers" param="id"/>
<jsp:setProperty property="password" name="myUsers" param="sn"/> <a href="test_scope.jsp">测试javabean的4个作用域范围</a> </body>
</html>

    dologin.jsp中有一个跳转链接test_scope.jsp用于跳转页面,下面是test_scope.jsp。

 <%@page import="org.po.Users"%>
<%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>检验useBean的4个作用域</title>
</head> <body>
<h1>检验useBean的4个作用域</h1><hr> <jsp:useBean id="myUsers" class="org.po.Users" scope="application"></jsp:useBean>
<!-- 通过getProperty获取javabean属性值 -->
<h2>用jsp动作元素获取javabean的属性值</h2>
用户名:<jsp:getProperty property="username" name="myUsers"/><br />
密码:<jsp:getProperty property="password" name="myUsers"/><hr> <!-- 通过内置对象获取javabean的属性值 -->
<h2>通过内置对象获取javabean的属性值</h2>
用户名:<%=((Users)application.getAttribute("myUsers")).getUsername() %><br>
密码:<%=((Users)application.getAttribute("myUsers")).getPassword() %>
</body>
</html>

  按照上面的例子分别将scope换成session、request和page得到如下如下结果:javabean的作用域范围从大到小依次是:application、session、request、page。

  4.8JavaBean的删除

    JavaBean虽然使用了<jsp:useBean>标签进行创建,但是其操作仍然依靠的是4种属性范围。如果一个JavaBean不再使用的话,则可以使用对应的removeAttribute()方法进行删除。

 pageContext.removeAttribute(JavaBean名称)    // 删除page范围内的JavaBean
request.removeAttribute(JavaBean名称) // 删除request范围内的JavaBean
session.removeAttribute(JavaBean名称) // 删除session范围内的JavaBean
application.removeAttribute(JavaBean名称) // 删除application范围内的JavaBean 
 package org.gpf;

 public class Count {

     private int count = 0;

     public Count() {
System.out.println("======== 一个新的Count实例产生了 ========");
} public int getCount() {
return ++count;
} }

Count.java

 <%@ page language="java" contentType="text/html; charset=utf-8"%>
<!-- 创建JavaBean,指定作用域为session -->
<jsp:useBean id="c" class="org.gpf.Count" scope="session"></jsp:useBean>
count = <jsp:getProperty property="count" name="c"/>
<%
session.removeAttribute("c"); // 删除javaBean
%>

session_bean.jsp

  我们本来设置的是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):

 package org.po;

 /**
* 用户类-javabean
*/
public class Users {
private String username;
private String passwordString; public Users() {
} public String getUsername() {
return username;
} public void setUsername(String username) {
this.username = username;
} public String getPasswordString() {
return passwordString;
} public void setPasswordString(String passwordString) {
this.passwordString = passwordString;
} }

    下面编写一个用户业务逻辑类:

 package org.dao;

 import org.po.Users;

 /**
* 用户的业务逻辑类
*/
public class UsersDAO {
public boolean isUserLogin(Users users) {
return "admin".equals(users.getUsername())
&& "admin".equals(users.getPassword());
}
}

  业务逻辑处理的页面dologin.jsp:

 <%@ page language="java" import="java.util.*"
contentType="text/html; charset=utf-8"%>
<!-- 引入实体类Users -->
<jsp:useBean id="loginUser" class="org.po.Users"></jsp:useBean>
<!-- 引入业务逻辑类UsersDAO -->
<jsp:useBean id="userDAO" class="org.dao.UsersDAO"></jsp:useBean> <!-- 为javaBean loginUser设置属性,使用表单自动设置全部的值 -->
<jsp:setProperty property="*" name="loginUser"/> <!-- 调用业务逻辑代码 -->
<%
request.setCharacterEncoding("utf-8");//防止中文乱码
if(userDAO.isUserLogin(loginUser)){
//如果用户登录成功则向session中设置用户名和密码
session.setAttribute("username", loginUser.getUsername());
session.setAttribute("password", loginUser.getPassword());
//请求转发
request.getRequestDispatcher("login_success.jsp").forward(request, response);
}else{
//重定向
response.sendRedirect("login_failure.jsp");
}
%>

    项目地址:https://git.oschina.net/gaopengfei/loginDemoByModel1.git

    该项目中主要的修改的dologin.jsp在该页面中没有使用request对象直接从表单中读出数据,而是从javabean中取出属性,并且用户合法性的判断也放在了javabean中很好的体现了Web的分层思想(逻辑与页面分离)。

5.jsp状态管理

  5.1http协议的无状态性

    http的无状态性是指:当浏览器发送请求给服务器的时候,服务器响应客户端的请求。但是当浏览器再次发送请求给服务器的时候,服务器并不知道它就是刚刚的那个浏览器。——服务器不会记住你。为了保存用户的状态有两种机制:

  5.2Cookie

    Cookie是Web服务器保存在客户端的一系列文本信息。

  • Cookie的典型应用一:判断注册用户是否已经登录网站。保存用户的登录状态,简化登录的手续(记住密码)。
  • Cookie的典型应用二:“购物车”的处理。
  • Cookie的典型应用三:视频网站播放记录的存储。

    在JSP页面中创建和使用Cookie    

 Cookie newCookie = new Cookie(String key,Object value); // 创建Cookie对象
response.add(newCookie); // 写入Cookie对象
Cookie[] cookies = request.getCookies(); // 读取Cookie对象

    Cooike对象的常用方法:

 void setMaxAge(int expiry); // 设置cookie的有效期【秒】
void setValue(String value);// 对已经实例化的cookie对象赋值
String getName(); // 获得cookie的名称
String getValue(); // 获得cookie的值
int getMaxAge(); // 获得cookie的有效时间【秒】

    注意:以上方法中的setValue(String value)和String getValue()方法的返回值都是字符串类型——因为Cookie本质上就是一个字符串存储在客户端,无论对它存值还是取值都应该是字符串类型。

  5.3案例:Cookie在登录中的应用:

      实现记忆用户名和密码的功能。

      用户登陆页login.jsp

 <%@ page language="java" import="java.util.*"
contentType="text/html; charset=utf-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>用户登录</title>
</head> <body>
<%
/*获得Cookie中保存的用户名和密码*/
String username = "";
String password = ""; Cookie[]cookies = request.getCookies();
if(cookies!=null&&cookies.length>0){
for(Cookie c:cookies){
if(c.getName().equals("username")){
username = c.getValue();
}
if(c.getName().equals("password")){
password = c.getValue();
}
}
}
%> 请输入用户名和密码:
<br />
<form action="dologin.jsp" name="loginForm" method="post">
用户名:<input type="text" name="username" value="<%= username%>" /><br />
密码:<input type="password" name="password" value="<%= password%>"><br />
<input type="checkbox" checked="checked" name="isUseCookie">
十天内记住我<br /> <input type="submit" value="登录" />
</form> </body>
</html>

    处理用户登录的页面dologin.jsp

 <%@ page language="java" import="java.util.*"
contentType="text/html; charset=utf-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>处理用户登录</title>
</head> <body>
<h1>登录成功!</h1>
<hr />
<%
//判断用户是否选择了记住密码
String[] isUseCookie = request.getParameterValues("isUseCookie");
if(isUseCookie!=null&&isUseCookie.length>0){
/*把用户名和密码保存在Cookie对象中*/
String username = request.getParameter("username");
String password = request.getParameter("password");
//创建2个Cookie对象
Cookie usernameCookie = new Cookie("username",username);
Cookie passwordCookie = new Cookie("password",password);
usernameCookie.setMaxAge(3600*24*10);//设置cookie生存期10天
passwordCookie.setMaxAge(3600*24*10); //在客户端保存Cookie对象,需要依赖response对象的addCookie方法
response.addCookie(usernameCookie);
response.addCookie(passwordCookie);
}else{
/*使已经保存的cookie对象失效*/
Cookie[]cookies = request.getCookies();//得到客户端保存的cookie
if(cookies!=null&&cookies.length>0){
//遍历Cookie数组
for(Cookie c:cookies){
if(c.getName().equals("username")||c.getName().equals("password")){
c.setMaxAge(0);//设置Cookie的有效期是0,让其马上失效
response.addCookie(c);//重新向客户端保存Cookie
}
}
}
}
%>
<a href="users.jsp">点击查看用户信息</a>
</body>
</html>

    用户信息显示页users.jsp

 <%@ page language="java" import="java.util.*"
contentType="text/html; charset=utf-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>用户信息显示</title>
</head> <body>
<h1>用户信息</h1>
<hr />
<%
/*获得Cookie中保存的用户名和密码*/
String username = "";
String password = ""; Cookie[]cookies = request.getCookies();
if(cookies!=null&&cookies.length>0){
for(Cookie c:cookies){
if(c.getName().equals("username")){
username = c.getValue();
}
if(c.getName().equals("password")){
password = c.getValue();
}
}
}
%>
用户名:<%=username %><br /> 密码:<%=password %>
</body>
</html>

    该项目一般情况下能够正常运行,但是当我们输入中文用户名的时候,服务器会抛出一个500的错误。要解决这个问题就需要依靠java网络包中的URLEncoder和URLDecoder,除此之外不要忘记了在每次使用request对象之前首先要设置request对象的编码方式。完整的代码如下:

    login.jsp

 <%@ page language="java" import="java.util.*"
contentType="text/html; charset=utf-8"%>
<%@page import="java.net.URLDecoder"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>用户登录</title>
</head> <body>
<%
/*获得Cookie中保存的用户名和密码*/
String username = "";
String password = ""; request.setCharacterEncoding("utf-8");
Cookie[]cookies = request.getCookies();
if(cookies!=null&&cookies.length>0){
for(Cookie c:cookies){
if (c.getName().equals("username")) {
username = URLDecoder.decode(c.getValue(), "utf-8");
}
if (c.getName().equals("password")) {
password = URLDecoder.decode(c.getValue(), "utf-8");
}
}
}
%> 请输入用户名和密码:
<br />
<form action="dologin.jsp" name="loginForm" method="post">
用户名:<input type="text" name="username" value="<%= username%>" /><br />
密码:<input type="password" name="password" value="<%= password%>"><br />
<input type="checkbox" checked="checked" name="isUseCookie">
十天内记住我<br /> <input type="submit" value="登录" />
</form> </body>
</html>

    dologin.jsp

 <%@page import="java.net.URLEncoder"%>
<%@ page language="java" import="java.util.*"
contentType="text/html; charset=utf-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>处理用户登录</title>
</head> <body>
<h1>登录成功!</h1>
<hr />
<%
//判断用户是否选择了记住密码
request.setCharacterEncoding("utf-8");
String[] isUseCookie = request.getParameterValues("isUseCookie");
if (isUseCookie != null && isUseCookie.length > 0) {
/*把用户名和密码保存在Cookie对象中*/
//得到登录表单中的内容并编码
String username = URLEncoder.encode(
request.getParameter("username"), "utf-8");
String password = URLEncoder.encode(
request.getParameter("password"), "utf-8");
//创建2个Cookie对象
Cookie usernameCookie = new Cookie("username", username);
Cookie passwordCookie = new Cookie("password", password);
usernameCookie.setMaxAge(3600 * 24 * 10);//设置cookie生存期10天
passwordCookie.setMaxAge(3600 * 24 * 10); //在客户端保存Cookie对象,需要依赖response对象的addCookie方法
response.addCookie(usernameCookie);
response.addCookie(passwordCookie);
} else {
/*使已经保存的cookie对象失效*/
Cookie[] cookies = request.getCookies();//得到客户端保存的cookie
if (cookies != null && cookies.length > 0) {
//遍历Cookie数组
for (Cookie c : cookies) {
if (c.getName().equals("username")
|| c.getName().equals("password")) {
c.setMaxAge(0);//设置Cookie的有效期是0,让其马上失效
response.addCookie(c);//重新向客户端保存Cookie
}
}
}
}
%>
<a href="users.jsp">点击查看用户信息</a>
</body>
</html>

    users.jsp

 <%@page import="java.net.URLDecoder"%>
<%@ page language="java" import="java.util.*"
contentType="text/html; charset=utf-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>用户信息显示</title>
</head> <body>
<h1>用户信息</h1>
<hr />
<%
/*获得Cookie中保存的用户名和密码*/
String username = "";
String password = ""; request.setCharacterEncoding("utf-8");
Cookie[] cookies = request.getCookies();
if (cookies != null && cookies.length > 0) {
for (Cookie c : cookies) {
if (c.getName().equals("username")) {
username = URLDecoder.decode(c.getValue(), "utf-8");
}
if (c.getName().equals("password")) {
password = URLDecoder.decode(c.getValue(), "utf-8");
}
}
}
%>
用户名:<%=username%><br /> 密码:<%=password%>
</body>
</html>

    修正后的项目就支持中文用户名了。Cookie与Session的区别是Cookie存放于浏览器中,浏览器关闭后再打开,已经保存的cookie还是存在。

  5.4Session与Cookie对比

  Session Cookie
保存位置 服务端保存用户信息 客户端保存用户信息
保存类型 Session中保存的是Object类型 Cookie中保存的是String类型
生命周期 会话结束,则存储的数据销毁 Cookie可长期保存在客户端
重要性 保存重要信息 保存不重要信息

6.jsp指令【编译时】与动作【运行时】元素 

  6.1include指令(可以包含其他页面)

    语法:

<%@ include file="URL"%>

    例如我们要在include_command.jsp中包含date.jsp的页面——即:在include_command中显示date.jsp的内容:

date.jsp

 <%@page import="java.text.SimpleDateFormat"%>
<%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%>
<%
out.print(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()));
%>

include_command.jsp

 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>在该页面中使用include指令将刚刚写的date.jsp包含进来</title>
</head> <body>
<h1>在该页面中使用include指令将刚刚写的date.jsp包含进来</h1><hr />
<%@include file="date.jsp" %>
</body>
</html>

    运行结果:

  6.2include动作

    include动作实际上是JSP动作标签,语法:

<jsp:include page="URL" flush="true|false" />

  其中page属性是需要包含的页面的URL,而flush属性制定了被包含的页面是否从缓冲区中读取。

  demo:使用include动作在include_action.jsp中包含date.jsp

  include_action.jsp

 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>include动作</title>
</head> <body>
<h1>在该页面中使用include动作将刚刚写的date.jsp包含进来</h1><hr />
<jsp:include page="date.jsp" flush="false"></jsp:include>
</body>
</html>

    使用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动作

    服务器内部转发指令,语法:

 <jsp:forward page="URL" />

 // 相当于
request.getRequestDispatcher("url").forward(request,response);

    例如:在登陆页中将用户的表单处理交给forward_action.jsp页面处理,forward_action.jsp将该请求通过forward动作转发给users.jsp,users.jsp从request对象中取得用户名和密码给予显示:

  login.jsp

 <%@ page language="java" import="java.util.*"
contentType="text/html; charset=utf-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>用户登录</title>
</head> <body>
请输入用户名和密码:
<br />
<form action="forward_action.jsp" name="loginForm" method="post">
用户名:<input type="text" name="username" /><br />
密码:<input type="password" name="password" /><br />
<input type="submit" value="登录" />
</form>
</body>
</html>

  forward_action.jsp

 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>forward动作</title>
</head> <body>
<h1>该页面处理用户提交的表单信息</h1>
<h2>forward动作</h2>
<jsp:forward page="users.jsp"></jsp:forward>
<!-- 上面这条语句和下面的这条语句相当 -->
<%--
request.getRequestDispatcher("users.jsp").forward(request, response);
--%>
</body>
</html>

    users.jsp

 <%@ page language="java" import="java.util.*"
contentType="text/html; charset=utf-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>用户信息显示</title>
</head> <body>
<h1>用户信息</h1>
<hr />
<%
request.setCharacterEncoding("utf-8"); String username = "";
String password = "";
if(request.getParameter("username")!=null){
username = request.getParameter("username");
}
if(request.getParameter("password")!=null){
password = request.getParameter("password");
}
%>
用户名:<%=username %><br /> 密码:<%=password %>
</body>
</html>

    运行结果:

  6.5param动作

   语法:

 <jsp:param name="参数名" value="参数名" />
<!-- 该动作常常作为<jsp:forward>的子标签,和它一起使用 -->

  用户将提交的表单交给dologin.jsp处理,dologin.jsp通过forward动作把请求转发给users.jsp(并人为添加表单中没有的内容:邮箱,修改表单中提交的用户名为root),users.jsp通过request.getParamer()方法获得用户名、密码、邮箱并予以显示:

  login.jsp

 <%@ page language="java" import="java.util.*"
contentType="text/html; charset=utf-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>用户登录</title>
</head> <body>
请输入用户名和密码:
<br />
<form action="dologin.jsp" name="loginForm" method="post">
用户名:<input type="text" name="username" /><br />
密码:<input type="password" name="password" /><br />
<input type="submit" value="登录" />
</form>
</body>
</html>

  dologin.jsp

 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%>
<jsp:forward page="users.jsp">
<jsp:param value="io@gmail.com" name="email"/>
<jsp:param value="root" name="username"/>
</jsp:forward>

  users.jsp

 <%@ page language="java" import="java.util.*"
contentType="text/html; charset=utf-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>用户信息显示</title>
</head> <body>
<h1>用户信息</h1>
<hr />
<%
request.setCharacterEncoding("utf-8"); String username = "";
String password = "";
String email = "";
if(request.getParameter("username")!=null){
username = request.getParameter("username");
}
if(request.getParameter("password")!=null){
password = request.getParameter("password");
}
if(request.getParameter("email")!=null){
email = request.getParameter("email");
}
%>
用户名:<%=username %><br /> 密码:<%=password %><br>邮箱:<%=email %>
</body>
</html>

  效果图:

7.jsp案例项目——商品浏览记录的实现

    该项目使用Model1(JSP+JavaBean)使用Cookie机制实现。该项目使用到了数据库(数据库中存放了商品表)。实现步骤如下:

  DB-->JavaBean-->JSP。项目的目录结构:

一、实现DBHelper类:

 该类的主要作用是取得数据库的连接并关闭相关资源。

 package util;

 import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException; public class DBHelper {
private static final String DRIVER = "com.mysql.jdbc.Driver";
private static final String URL = "jdbc:mysql://localhost:3306/shopping?useUnicode=true&characterEncoding=UTF-8";
private static final String USER = "root";
private static final String PASSWORD = "mysqladmin"; private static Connection coon = null;// DB连接对象 /** 静态代码块加载DB驱动 */
static {
try {
Class.forName(DRIVER);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
} /** Singleton设计模式返回DB连接对象 */
public static Connection getConnection() throws SQLException {
if (coon == null) {
coon = DriverManager.getConnection(URL, USER, PASSWORD);
return coon;
}
return coon;
} /** 清理资源-关闭DB结果集、释放语句对象 */
public static void relsaseResource(ResultSet rs,PreparedStatement pstmt){
// 释放结果集
if (rs != null) {
try {
rs.close();
rs = null;
} catch (SQLException e) {
e.printStackTrace();
}
}
// 释放语句对象
if (pstmt != null) {
try {
pstmt.close();
pstmt = null;
} catch (SQLException e) {
e.printStackTrace();
}
}
} /** 测试DB连接 */
public static void main(String[] args) {
try {
Connection connection = DBHelper.getConnection();
if(connection!=null){
System.out.println("数据库连接成功!");
}else {
System.out.println("数据库连接异常!");
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
如果shopping数据库没有创建可能会抛出异常只需要执行:
 create database shopping;

  二、商品实体类的设计:

  在创建实体类之前先建立好数据库表:

  数据库脚本:items.sql

 /*
Navicat MySQL Data Transfer Source Server : MySQL50
Source Server Version : 50067
Source Host : localhost:3306
Source Database : shopping Target Server Type : MYSQL
Target Server Version : 50067
File Encoding : 65001 Date: 2014-08-27 12:12:31
*/ SET FOREIGN_KEY_CHECKS=0; -- ----------------------------
-- Table structure for items
-- ----------------------------
DROP TABLE IF EXISTS `items`;
CREATE TABLE `items` (
`id` int(11) NOT NULL auto_increment,
`name` varchar(50) default NULL,
`city` varchar(50) default NULL,
`price` int(11) default NULL,
`number` int(11) default NULL,
`picture` varchar(500) default NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8; -- ----------------------------
-- Records of items
-- ----------------------------
INSERT INTO `items` VALUES ('', '沃特篮球鞋', '佛山', '', '', '001.jpg');
INSERT INTO `items` VALUES ('', '安踏运动鞋', '福州', '', '', '002.jpg');
INSERT INTO `items` VALUES ('', '耐克运动鞋', '广州', '', '', '003.jpg');
INSERT INTO `items` VALUES ('', '阿迪达斯T血衫', '上海', '', '', '004.jpg');
INSERT INTO `items` VALUES ('', '李宁文化衫', '广州', '', '', '005.jpg');
INSERT INTO `items` VALUES ('', '小米3', '北京', '', '', '006.jpg');
INSERT INTO `items` VALUES ('', '小米2S', '北京', '', '', '007.jpg');
INSERT INTO `items` VALUES ('', 'thinkpad笔记本', '北京', '', '', '008.jpg');
INSERT INTO `items` VALUES ('', 'dell笔记本', '北京', '', '', '009.jpg');
INSERT INTO `items` VALUES ('', 'ipad5', '北京', '', '', '010.jpg');

  在MySQL中查询:

  建立实体类(Items):也就是javabean其属性与DB中的各个字段一一对应。

 package entity;

 /**
* 商品类(与DB中的表名一致)-javabean 属性和DB中表的字段完全一致
*/
public class Items {
private int id;
private String name;
private String city;
private int price;
private int number;
private String picture; public Items() {
} public int getId() {
return id;
} public void setId(int id) {
this.id = id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public String getCity() {
return city;
} public void setCity(String city) {
this.city = city;
} public int getPrice() {
return price;
} public void setPrice(int price) {
this.price = price;
} public int getNumber() {
return number;
} public void setNumber(int number) {
this.number = number;
} public String getPicture() {
return picture;
} public void setPicture(String picture) {
this.picture = picture;
} }

    三、实现业务逻辑类(数据访问层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

 <%@page import="entity.Items"%>
<%@page import="dao.ItemsDAO"%>
<%@ page language="java" import="java.util.*"
contentType="text/html; charset=utf-8"%>
<!-- 显示所有的商品信息 -->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>欢迎光临网上商城</title>
<style type="text/css">
div {
float: left;
margin: 10px;
} div dd {
margin: 0px;
font-size: 10pt;
} div dd.dd_name {
color: blue;
} div dd.dd_city {
color: #000;
}
</style>
</head> <body>
<h1>商品展示</h1>
<hr>
<center>
<table width="750" height="60" cellpadding="0" cellspacing="0"
border="0">
<tr>
<td>
<!-- 商品循环开始 -->
<%
ItemsDAO itemsDAO = new ItemsDAO();
ArrayList<Items>list = itemsDAO.getAllItems();
if(list!=null&&list.size()>0){
//遍历所有的商品
for(Items item:list){
%>
<div>
<dl>
<dt>
<a href="details.jsp?id=<%=item.getId() %>">
<img src="data:images/<%=item.getPicture() %>" width="120" height="90" border="1"/>
</a>
</dt>
<dd class="dd_name"><%=item.getName() %></dd>
<dd class="dd_city">产地:<%=item.getCity() %>&nbsp;&nbsp;价格:¥<%=item.getPrice() %></dd>
</dl>
</div>
<%
}
}
%>
<!-- 商品循环结束 -->
</td>
</tr>
</table>
</center>
</body>
</html>

  显示商品详细信息的details.jsp

 <%@page import="entity.Items"%>
<%@page import="dao.ItemsDAO"%>
<%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%>
<!-- 显示商品详情,并在右侧显示商品的浏览记录(最近5条记录) -->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>欢迎光临网上商城</title>
<style type="text/css">
div{
float:left;
margin-left: 30px;
margin-right:30px;
margin-top: 5px;
margin-bottom: 5px;
}
div dd{
margin:0px;
font-size:10pt;
}
div dd.dd_name
{
color:blue;
}
div dd.dd_city
{
color:#000;
}
</style>
</head> <body>
<h1>商品详情</h1><hr>
<center>
<table width="750" height="60" cellpadding="0" cellspacing="0" border="0">
<tr>
<!-- 商品详细信息 -->
<%
Items item = new ItemsDAO().getItemsById(Integer.parseInt(request.getParameter("id")));
if(item!=null){
%>
<td width="70%" valign="top">
<table>
<tr>
<td rowspan="4"><img src="data:images/<%=item.getPicture()%>" width="200" height="160"/></td>
</tr>
<tr>
<td><b><%=item.getName() %></b></td>
</tr>
<tr>
<td>产地:<%=item.getCity() %></td>
</tr>
<tr>
<td>价格:¥<font color="red"><b><%=item.getPrice() %></b></font></td>
</tr>
</table>
</td>
<%
}
%>
<!-- 取得Cookie -->
<%
String list = "";
// 从客户端获得Cookie集合
Cookie[]cookies = request.getCookies();
if(cookies!=null&&cookies.length>0){
for(Cookie c:cookies){
if(c.getName().equals("ListViewCookie")){
list = c.getValue();
} String[] arr = list.split(",");
// 相同商品只在浏览记录中存放一次
if(Arrays.binarySearch(arr, request.getParameter("id"))<0){
list += request.getParameter("id") + ",";
}
// 如果浏览记录超过1000条,则清空Cookie
if(arr!=null&&arr.length>1000){
list = "";// 清零-置空串
}
Cookie cookie = new Cookie("ListViewCookie",list);
response.addCookie(cookie);
}
}
%> <!-- 浏览过的商品 -->
<td width="30%" bgcolor="#EEE" align="center">
<br /><b>您浏览过的商品</b><br />
<!-- 循环开始 -->
<%
ArrayList<Items>itemsList = new ItemsDAO().getViewList(list);
if(itemsList!=null&&itemsList.size()>0){
for(Items i:itemsList){
%>
<div>
<dl>
<dt><img src="data:images/<%=i.getPicture() %>" width="120" height="90" border="1" /></dt>
<dd class="dd_name"><%=i.getName() %></dd>
<dd class="dd_city">产地:<%=i.getCity() %>&nbsp;&nbsp;价格:¥<%=i.getPrice() %></dd>
</dl>
</div>
<%
}
}
%>
<!-- 循环结束 -->
</td>
</tr>
</table>
</center>
</body>
</html>

  主业务逻辑类ItemsDAO

 package dao;

 import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays; import util.DBHelper; import entity.Items; /**
* 商品的业务逻辑类
*/
public class ItemsDAO {
/** 获得所有的商品信息 */
public ArrayList<Items> getAllItems() {
ArrayList<Items> itemsList = new ArrayList<Items>();// 商品集合 Connection coon = null;
PreparedStatement pstmt = null;
ResultSet rs = null; try {
coon = DBHelper.getConnection();
String sql = "select * from items;";// sql语句
pstmt = coon.prepareStatement(sql);
rs = pstmt.executeQuery(); while (rs.next()) {
Items items = new Items();
setItemsAttributes(rs, items);//为实体类【商品】设置属性【根据DB中的相关字段】
itemsList.add(items);// 把1个商品加入集合
}
return itemsList;
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
DBHelper.relsaseResource(rs, pstmt);
}
} /** 根据数据库的结果集设置实体类的属性 */
private void setItemsAttributes(ResultSet rs, Items items)
throws SQLException {
items.setId(rs.getInt("id"));
items.setName(rs.getString("name"));
items.setCity(rs.getString("city"));
items.setPrice(rs.getInt("price"));
items.setNumber(rs.getInt("number"));
items.setPicture(rs.getString("picture"));
} /** 根据商品的id获得商品资料 */
public Items getItemsById(int id) {
Connection coon = null;
PreparedStatement pstmt = null;
ResultSet rs = null; try {
coon = DBHelper.getConnection();
String sql = "select * from items where id=?;";
pstmt = coon.prepareStatement(sql);
pstmt.setInt(1, id);
rs = pstmt.executeQuery(); if (rs.next()) {
Items items = new Items();
setItemsAttributes(rs, items);
return items;
} else {
return null;
}
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
DBHelper.relsaseResource(rs, pstmt);
}
} /**获取最近浏览的前5条商品信息*/
public ArrayList<Items>getViewList(String list){
ArrayList<Items>itemsList = new ArrayList<Items>();
int iCount = 5;//每次返回5条
if (list!=null&&list.length()>0) {
String[]temp=list.split(",");
//显示最近浏览过的商品——倒序得到Cookie中保存的ID
if (temp.length>=iCount) {
System.out.println("浏览记录大于等于5条");
System.out.println(Arrays.toString(temp));
for(int i = temp.length-1;i>=temp.length-iCount;i--){
itemsList.add(getItemsById(Integer.parseInt(temp[i])));
}
}else {
System.out.println("浏览记录小于5条");
System.out.println(Arrays.toString(temp));
for(int i = temp.length-1;i>=0;i--){
itemsList.add(getItemsById(Integer.parseInt(temp[i])));
}
}
return itemsList;
}else {
return null;
}
}
}

  项目展示:(项目地址:https://git.oschina.net/gaopengfei/JSPLogin.git

Tips:

  解决中文乱码:

1)在执行获取请求参数前设置编码:

request.setCharacterEncoding(“汉字编码”);

2)转换字符编码:

   //获取原始的请求参数值
String rawName = request.getParameter("name");
//将请求参数值使用ISO-8859-1字符串分解成字节数组
byte[] rawBytes = rawName.getBytes("ISO-8859-1");
//将字节数组重新编码成字符串
String name = new String(rawBytes , "gb2312");

3)获取请求参数同时转换编码:

request.getParameter(“name”).getBytes ("ISO-8859-1");

最新文章

  1. Error:Execution failed for task &#39;:clean&#39;. &gt; Unable to delete directory :\build\intermediates (转)
  2. jquery限制文本框只能输入金额
  3. MVVM架构~knockoutjs系列之级联select
  4. 利用百度语音API进行语音识别。
  5. thinkPHP实现瀑布流的方法
  6. [ROS]1 小乌龟
  7. delphi 修改Hint的字体和颜色
  8. Masonry 控件详解
  9. JavaScript 作用域和作用域链
  10. UIImage载入图片的几种方式及差别
  11. CharMatch(括号匹配)
  12. sa账号无法登陆sqlserver2008
  13. James Munkres《拓扑学》笔记前言
  14. [angularjs] angularjs系列笔记(八)事件
  15. 题解——P1108低价购买(DP)
  16. /bin/sh^M:bad interpreter:
  17. QQList列表功能实现
  18. 分布式实时日志系统(二) 环境搭建之 flume 集群搭建/flume ng资料
  19. .NET中的三种Timer的区别和用法(收集)
  20. 我们要注意的Mysql基本安全设置

热门文章

  1. Game Center Achievements and Leaderboards part 1 &lt;转&gt;
  2. linux下Oracle11g RAC搭建(二)
  3. ICP备案的一些tips~
  4. 一个可变布局列表,有9种布局item大小,每个item可拖拽切换位置
  5. Linux-使用 screen 管理你的远程会话
  6. java.lang.NullPointerException org.apache.jsp.index_jsp._jspInit(index_jsp.java:22)
  7. css hacks
  8. Scrapy使用问题整理(转载)
  9. sell学习
  10. hdu4711Weather 概率dp