【文档说明】Java-Web程序设计与案例教程-第3章-Cookie与Session.ppt,共(50)页,943.000 KB,由小橙橙上传
转载请保留链接:https://www.ichengzhen.cn/view-2272.html
以下为本文档部分文字说明:
第3章Cookie与Session本章内容基于Servlet的简单Web应用Cookie的含义和用法Session的含义和用法Session的工作原理个人信息模块的实现基于MVC的购物车3.1使用Se
rvlet编写简单Web应用使用Servlet开发一个模拟登录的Web应用主要功能登录个人信息的完善和查询3.1使用Servlet编写简单Web应用3.1.1Web应用功能说明3.1.2登录模块的实现3.1.1Web应用功能说明图3.1登录页面图3.2个人信息首页用户可通
过图3.1所示的登录页面填写用户名和密码进行登录操作,如果用户名和密码都不为空,则判定该登录有效,显示如图3.2所示的个人信息应用首页,该首页不仅显示了当前用户的个人信息的页面链接,以及完善个人信息的页面链接,还显示了当前的登录用户名,以及登录时间信息3.1.1W
eb应用功能说明当点击“查看个人信息”链接时,系统应显示当前登录用户完善后的个人信息。如果该用户从来没有点击“完善个人信息”链接,则需要对信息进行完善,此时系统会直接跳转至“完善个人信息”页面,如图3.3和图3.4所示。图3.
3完善个人信息1图3.4完善个人信息23.1.1Web应用功能说明如果当前用户已经完善过个人信息,则直接显示完善后的用户信息,如图3.5所示。图3.5查看个人信息详情3.1.2登录模块的实现工程结构如图3.6图3.6LoginDemo工程结构1.“cn.e
du.zzti.entity”包中包含User和PersonalInfo两个实体类,分别用来存储用户的登录信息和当前登录用户的具体个人信息2.“cn.edu.zzti.servlet.view”包中存放展现给用户的5个页面,包括登录页面、Web应用首页、个
人信息完善表单1、个人信息完善表单2、个人信息详情页面。3.“cn.edu.zzti.servlet”包中包含两个Servlet,“LoginServlet”的主要功能是对来自登录页面中的表单参数进行校验和存储,“PersonalInfoProcess”的主要功能
是接收来自个人信息完善表单中的数据,对完善后的个人信息进行封装和存储。3.1.2登录模块的实现本章的登录页面根据用户提交的参数正确与否来产生不同的响应,如果用户名密码都不为空,则跳转到图3.2;否则,跳转到,如图3.7所示的登录页面,并提示错误信息。图3.7登录异常响应结果页面登录模块
示例源码:loginDemo(ch3-1)3.1.2登录模块的实现“cn.edu.zzti.entity.User”用户实体类3.1.2登录模块的实现“cn.edu.zzti.entity.Person
alInfo”代码3.1.2登录模块的实现“cn.edu.zzti.servlet.view.LoginPageView”代码如下:1@WebServlet("/servlet/LoginPageView")2publicclassLoginP
ageViewextendsHttpServlet{3publicvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)4throwsServletException,IOE
xception{5request.setCharacterEncoding("utf-8");6response.setContentType("text/html;charset=utf-8");7PrintW
riterout=response.getWriter();8out.println("<!DOCTYPEHTML>");9out.println("<HTML>");10out.println("<HEAD><TITLE>登录页面</TITLE></HEAD>");11
out.println("<BODY>");12Objecterror=request.getAttribute("error");13if(error!=null){14out.println("请重新登录:<fontcolor='red'>"+error+"</font><br>");15}1
6Stringbody="<formaction='LoginServlet'method='post'>"+17"username:<inputtype='text'name='username'/><br/>"+18"password:<inputtype=
'password'name='password'/><br/>"+19"<inputtype='submit'value='登录'/></form>";20out.println(body);21out.prin
tln("</BODY>");22out.println("</HTML>");23out.flush();24out.close();25}26publicvoiddoPost(HttpServletReq
uestrequest,HttpServletResponseresponse)27throwsServletException,IOException{28doGet(request,response);29}30}3.1.2登录模块的实现“cn.edu.zzti.
servlet.LoginServlet”代码如下:1@WebServlet("/servlet/LoginServlet")2publicclassLoginServletextendsHttpServlet{3publicStringcheckLogin(Useru
ser){4StringerrorInfo=null;5if(user.getUsername()==null||"".equals(user.getUsername().trim())6||user.getPassword()==null||"".equals
(user.getPassword().trim())){7errorInfo="用户名或者密码不能为空";8}9returnerrorInfo;10}11publicvoiddoGet(HttpSe
rvletRequestrequest,HttpServletResponseresponse)12throwsServletException,IOException{13doPost(request,response);14}15publ
icvoiddoPost(HttpServletRequestrequest,HttpServletResponseresponse)16throwsServletException,IOExceptio
n{17request.setCharacterEncoding("utf-8");18Stringusername=request.getParameter("username");19Stringpassword=request.getParameter("passw
ord");20Useruser=newUser(username,password,newDate());21Stringerror=checkLogin(user);22StringtargetPath="Ind
exView";23if(error==null){24//登录成功,对登录信息进行保存25request.setAttribute("username",user);26}else{27//登录失败,返回登录页面,并将错误信息带回28targetPath="Lo
ginPageView";29request.setAttribute("error",error);30}31request.getRequestDispatcher(targetPath).forward(request,respons
e);32}33}3.1.2登录模块的实现“cn.edu.zzti.servlet.view.IndexView”代码如下:1@WebServlet("/servlet/IndexView")2publicc
lassIndexViewextendsHttpServlet{3publicvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)4throwsServletExcep
tion,IOException{5ObjectloginTag=request.getAttribute("user");6if(loginTag==null){7response.sendRedirect("LoginPageView?error="+8URLEncoder.enco
de("尚未登录","gbk"));9return;10}11Useruser=(User)loginTag;12response.setContentType("text/html;charset=gbk");13PrintWriterout=respons
e.getWriter();14out.println("<!DOCTYPEHTML>");15out.println("<HTML>");16out.println("<HEAD><TITLE>Web应用首页</TITLE></HEAD>");17out.println("<BODY>")
;18out.println("当前登录的用户是:"+user.getUsername());19SimpleDateFormatsdf=newSimpleDateFormat("yyyy-MM-ddHH:mm:ss");20out.println("<b
r>登录时间:"+sdf.format(user.getLoginTime()));21out.println("<br><ahref='IndexView'>进入首页</a>");22out.pri
ntln("<br><ahref='PersonalInfoView'>查看个人信息</a>");23out.println("<br><ahref='PersonalPage1'>完善个人信息</a>");24out.println("</BOD
Y>");25out.println("</HTML>");26out.flush();27out.close();28}29publicvoiddoPost(HttpServletRequestrequest,HttpServletResponsere
sponse)30throwsServletException,IOException{31doGet(request,response);32}33}3.1.2登录模块的实现假如在图3.2所示的页面中,单击“进入首页”的超级链接在该次对Web首页的请求中,将因为无法获得登
录者信息而跳转至登录页面,如图3.8所示。图3.8跳转至登录页面图3.2个人信息首页3.2CookieHTTP是一种无状态协议,即每次服务端接收到客户端的请求时,都是一个全新的请求,服务器并不知道客户
端的历史请求记录.如何解决上述问题?CookieSession3.2Cookie3.2.1Cookie简介3.2.2Cookie在登录中的应用3.2.3Cookie详解3.2.1Cookie简介Cookie实际上是服务
器在客户端浏览器上存储的小段文本,并通过每一个请求发送至同一个服务器。Web服务器用HTTP报头向客户端发送Cookie,客户端浏览器解析这些Cookie并将它们保存为一个本地文件。服务器set-cookieuser=admin;Expi
res=Wen,12-Apr-201704:38-55GMT②④读取Cookie文件⑤cookieuser=admin客户端user=admin&pw=123456&login=auto3.2.1Cookie简介在JavaEE中,使用“javax.servlet
.http.Cookie”类来代表一个Cookie。Cookie对象可以看作是一个key-value对,key和value都是String类型:publicCookie(Stringname,Stringvalue)3.2.1Cook
ie简介客户端浏览器接收到Cookie并进行存储,在后续的请求中会自动添加这个Cookie信息,服务端需要借助于“javax.servlet.http.HttpServletResponse”的addCookie()方法来获取客户端传递来的
Cookie信息,最终实现信息共享。publicvoidaddCookie(Cookiecookie)3.2.2Cookie在登录中的应用登录解决思路:在3.1.2节中的会话问题中,服务器端可以创建Cookie对象,将用户的登录信息保存在该Coo
kie对象中,然后通过HTTP响应消息写回到客户端。之后,客户端的每次请求都将会带上该登录信息,从而解决会话状态保持问题。将Cookie对象通过HTTP响应消息写回客户端时,首先修改“cn.edu.zzti.servlet.LoginServlet”类的doPost(
)方法,当用户登录系统后,将用户的登录信息通过HTTP响应消息写回客户端,修改后的LoginServlet中doPost方法的核心代码(完整代码参考P83)如下:7Stringerror=checkLogin(user);8StringtargetPath="IndexView";9i
f(error==null){10Cookiecookie1=newCookie("username",user.getUsername());11Cookiecookie2=newCookie("loginTime",user.getLoginTime());1
2response.addCookie(cookie1);13response.addCookie(cookie2);14}cookie保存会话登录模块示例源码:loginDemo(ch3-2)3.2.2Cookie在登录中的应用登录解决思路:
在“javax.servlet.http.HttpServletRequest”中提供了getCookies()方法,该方法可以获取HTTP请求所发送的所有Cookie信息,因为客户端发送的Cookie可以是0到多个,所以getCookies方法返回的是Cookie
数组。在工程中添加类“cn.edu.zzti.util.CookieUtil”来完成对Cookie的访问,具体代码如下。/***从cookie数组中查询键值为key的Cookie对象*@paramcookies*@paramkey*@return*/publicst
aticCookiegetCookie(Cookie[]cookies,Stringkey){if(cookies!=null){for(Cookiecookie:cookies){if(key!=null&&key.equals(cookie.getName(
))){returncookie;}}}returnnull;}3.2.2Cookie在登录中的应用登录解决思路:在“javax.servlet.http.HttpServletRequest”中提供了getCookies()方法,该方法
可以获取HTTP请求所发送的所有Cookie信息,因为客户端发送的Cookie可以是0到多个,所以getCookies方法返回的是Cookie数组。在工程中添加类“cn.edu.zzti.util.CookieUtil”来完成对Cookie的访问,具
体代码如下。/***从cookie数组中查询键值为key的Cookie的value值*@paramkey*@paramcookies*@return*/publicstaticStringgetValue(Strin
gkey,Cookie[]cookies){if(cookies!=null){for(Cookiecookie:cookies){if(key!=null&&key.equals(cookie.getName())){returncook
ie.getValue();}}}returnnull;}3.2.2Cookie在登录中的应用登录解决思路:改写“cn.edu.zzti.servlet.IndexView”类的doPost方法,增加登录判断的相关代码,具体实现如下。publicvoiddoPost(
HttpServletRequestrequest,HttpServletResponseresponse)2throwsServletException,IOException{3request.setCharacterE
ncoding("gbk");4Cookie[]cookies=request.getCookies();5if(CookieUtil.getValue("username",cookies)==null)
{6response.sendRedirect("LoginPageView?error="+URLEncoder.7encode("尚未登录","utf-8"));8return;9}10Stringusername=CookieUtil.getValue("usern
ame",cookies);11StringloginTime=CookieUtil.getValue("logintime",cookies);12response.setContentType("
text/html;charset=utf-8");13PrintWriterout=response.getWriter();14out.println("<!DOCTYPEHTML>");15out.println("<HTML>");16out.println("<HEA
D><TITLE>Web应用首页</TITLE></HEAD>");17out.println("<BODY>");18out.println("当前登录的用户是:"+username);19out.println("<br>登录时间:"+login
Time);20out.println("<br><ahref='IndexView'>进入首页</a>");21out.println("</BODY>");22out.println("</HTML>");23out.flush();24out.close();25}3.
2.3Cookie详解Cookie本身是保存在客户端浏览器中的一段文本,Cookie能否成功存储取决于浏览器的设置。3.2.3Cookie详解Cookie的内容主要包括名字、值、过期时间、路径和域。路径与域一起构成了Cookie的作用范围
。3.2.3Cookie详解JavaEE中的javax.servlet.http.Cookie类提供了对Cookie的上述各个属性进行操作的API,如表3.1所示。序号方法描述1Cookie(Stringname,
Stringvalue)实例化Cookie对象2publicStringgetName()取得Cookie的名字3publicStringgetValue()取得Cookie的值4publicvoidsetV
alue(StringnewValue)设置Cookie的值5publicvoidsetMaxAge(intexpiry)设置Cookie的最大保存时间,即Cookie有效期6publicintgetMaxAge()获取Cookies的有效期7publicvoidsetPath(Str
inguri)设置Cookies的有效路径8publicStringgetPath()获取Cookies的有效路径9publicvoidsetDomain(Stringpattern)设置Cookies的有效域10publicStringg
etDomain()获取Cookies的有效域表3.1Cookie的API3.2.3Cookie详解利用以上API完成有效时间和有效域的设置,详见P88。3.3Session通过Cookie实现了登录信息共享问题,但是该方法主要是依
靠客户端浏览器开发及服务器端Cookie写入的功能。如果客户端浏览器不接收任何Cookie,那么就无法实现登录信息的共享。如何解决上述问题?Session3.3Session3.3.1HttpSess
ion简介3.3.2HttpSession在登录中的应用3.3.3HttpSession详解3.3.1HttpSession简介HttpSession对象是Session概念在JavaWeb中的具体实现,通过这个对象可以实现服务端同一会话的多次请求之间
的数据共享。HttpSession对象是通过HttpServletRequest获得的,HttpServletRequest共包含两个获取HttpSession对象的方法,如下所示:publicHt
tpSessiongetSession(booleancreate)publicHttpSessiongetSession()3.3.1HttpSession简介其中,getSession(true)与getSession()的含义
相同,如果当前reqeust中的HttpSession为null,当create变量的值为true时,就创建一个新的HttpSession对象,否则返回当前HttpSession对象。getSession(false)的含义是,如果当前reqeust中的HttpSessi
on为null,返回null,否则返回当前HttpSession对象。3.3.1HttpSession简介HttpSession用于会话管理的4个方法为:publicvoidsetAttribute(Stringname,Objec
tvalue)publicObjectgetAttribute(Stringname)publicEnumerationgetAttributeNames()publicObjectremoveAttribute(Stringname)getAttribute(Stringna
me,Objectvalue)其中,getAttribute(Stringname,Objectvalue)方法与HttpServletRequest对象的setAttribute(Stringname,
Objectvalue)方法作用一致,都是将一个对象存放于某个空间,以方便对象在资源之间进行共享。两者之间的区别在于,HttpServletRequest对象存储的数据只能在同一次请求的不同资源之间实现共享,而HttpSession对象存储的数据可以在同一
个会话的不同请求之间进行共享,数据共享的范围更为广泛。3.3.1HttpSession简介思考:实现一个Servlet类SessionDemo1。在该类中获得当前会话的HttpSession对象,
并在这个HttpSession对象中存储一个key为“info”的字符串对象“存放于session中的信息”,并提供一个超级链接,访问另外一个Servlet资源,以方便发送一个新的请求,具体代码如P93。Session保存会话登录模块示例源码:loginDemo(ch3-3)3.3.2HttpS
ession在登录中的应用当一个浏览器窗口发出一个请求,并且Web应用服务第一次调用HttpServletRequest的getSession()或者getSession(true)的时候,当前浏览器窗口与Web应用服务之间建立了会话。在默
认情况下,只要当前建立会话的浏览器窗口没有关闭,该会话就不会结束。因此,若要在浏览器与Web应用服务之间保持会话信息,可以使用HttpSession来保存请求之间的相关信息。3.3.2HttpSession在登录中的应用在第3.1.2节中,出现的登录信息的保持问题,在这里就可以使用HttpSe
ssion进行解决。用户登录信息被提交给cn.edu.zzti.servlet.LoginServlet时,LoginServlet将该登录信息存储至HttpSession中,这样在当前浏览器窗口下,发送的所
有请求都可以共享HttpSession中的登录信息,具体代码实现如下。3.3.2HttpSession在登录中的应用1@WebServlet("/servlet/LoginServlet")2publicclassLoginServletextendsHttpServlet{3p
ublicStringcheckLogin(Useruser){/*代码略,看第3.1.2节*/}4publicvoiddoPost(HttpServletRequestrequest,HttpServl
etResponseresponse)5throwsServletException,IOException{6request.setCharacterEncoding("utf-8");7Stringusername=request.
getParameter("username");8Stringpassword=request.getParameter("password");9Useruser=newUser(username,password,newDate());
10Stringerror=checkLogin(user);11StringtargetPath="IndexView";12if(error==null){13//将获取的登录信息存在HttpSession中14request.getSession().setAttribute("user"
,user);15}else{16//登录失败,返回登录页面,并将错误信息带回17targetPath="LoginPageView";18request.setAttribute("error",error);19}20request.getRe
questDispatcher(targetPath).forward(request,response);21}22/*代码略,请查看第3.1.2节*/23}3.3.3HttpSession详解序号方法名说明1ObjectgetAttribute(Stringname)用于从当前Ht
tpSession对象中返回指定名称的属性对象2EnumerationgetAttributeNames()返回和会话有关的枚举值3StringgetId()返回分配给这个Session的标识符。一个HTTPsession的标识符是一个由服务器来建立和维持的唯一的
字符串4intgetMaxInactiveInterval()用于获得当前HttpSession对象可空闲的以秒为单位的最长时间5ObjectgetValue(Stringname)获取指定名称的Session对象。如果不存在这样的绑
定,返回空值6String[]getValueNames()以一个数组返回绑定到Session上的所有数据的名称7booleanisNew()判断当前HttpSession对象是否是新创建的8voidremoveAt
tribute(Stringname)用于从当前HttpSession对象中删除指定名称的属性9voidremoveValue(Stringname)取消指定名称在Session上的绑定10voidsetAttribute(Stringname,Objectvalue)用
于将一个对象与一个名称关联后存储到当前的HttpSession对象中11voidsetMaxInactiveInterval(intinterval)用于设置当前HttpSession对象可空闲的最长时间
,以秒为单位。也就是修改当前会话的默认超时间隔3.4Session工作原理与Cookie不同,Session采用在服务器端保持状态的解决方案。Session是针对每一个用户的,变量的值保存在服务器上,用一个sessionID来区分是哪个用户的Session变量,这个值是通过用户浏览器在
访问的时候返回给服务器,当客户禁用Cookie时,这个值也能设置为get来返回给服务器。3.4Session工作原理就安全性来说,当访问一个使用Session的站点时,需要在自己的计算机中建立一个Cookie。因此,为安全起见,用户使用时建议采用服务器端的Session机制,
因为它不会任意读取客户存储的信息。HttpSession在实际工作中是依靠Cookie来实现的,Cookie在HttpSession的工作中起到保护数据的作用3.5个人信息模块的实现图3.3完善个人信息1图3.4
完善个人信息2图3.5查看个人信息详情3.5个人信息模块的实现首先,需要新建一个完善个人信息表单页面“cn.edu.zn.servlet.view.PersonalPage1”,表单效果如图3.3所示,并在当
前页面中同样显示登录信息,具体代码如P98。在“cn.edu.zn.servlet.view.PersonalPage1”中填写的个人信息表单并不完整,还需要与一个完善个人信息表单页面“cn.edu.zn.servlet.view.PersonalPage2”
中的数据整合后,才能变成完整的用户个人信息。表单效果如图3.4所示,并在当前页面中同样显示登录信息,具体代码如P99示例源码:loginDemo(ch3-5)3.5个人信息模块的实现在“cn.edu.zzti.
servlet.PersonalServlet”类中对用户填写的所有表单数据进行封装、存储.1@WebServlet("/servlet/PersonalInfoProcess")2publicclassPersonalInfoProcessextendsHttpServlet{...
...7publicvoiddoPost(HttpServletRequestrequest,HttpServletResponseresponse)8throwsServletException,IOException{9request.setChara
cterEncoding("utf-8");10ObjectloginTag=request.getSession().getAttribute("user");11if(loginTag==null){12response.sendRedirect("LoginPageView");13
return;14}15Useruser=(User)loginTag;16ObjectpersonalObject=request.getSession().getAttribute("p");17if(
personalObject==null){18request.setAttribute("info","您还没有完善个人信息,请进行完善");19request.getRequestDispatcher("PersonalPage1").forward(request,respons
e);20return;21}else{22StringtargetPath="PersonalInfoView";23PersonalInfop=(PersonalInfo)request.getSes
sion().getAttribute("p");24p.setHighestEducation(request.getParameter("highestEducation"));25p.setGraduateSchool(request.getParameter("graduateSc
hool"));26p.setMajor("major");27response.sendRedirect(targetPath);//使用跳转重定向到展示页28}29}30}3.6基于MVC的临时购物车1979年,TrygveReenskaug首次提出
了MVC的概念,最初的时候叫作Model-View-Controller-Editor。TrygveReenskaug最初提出MVC的目的是为了把模型与视图分离开来,然后用控制器来组合Model和View之间的关系。这样做的目的是实现注意点分
离的设计理念,也就是让专业的对象做专业的事情,View负责视图相关的内容,Model负责描述数据模型,Controller负责总控,各自分工协作。3.6基于MVC的临时购物车3.6.1临时购物车设计需求3.6.2临时购物车代码
实现3.6.3Cookie详解3.6.1临时购物车设计需求在临时购物车中,需要购买的商品列表页面如图3.21所示。每个商品均包含有商品序号、商品名称和商品价格等信息。任意用户在商品列表页面都可以对商品进行购买。每当用户对某个商品输入购买数量后,单击“加入购物车”按钮,就会转向临时购物车页面
,实现效果如图3.22所示。如果用户需要继续购买,则可以通过一个超级链接返回商品列表页面,也可以对购物车中的现有商品进行删除操作。图3.21商品列表图3.22临时购物车列表临时购物车示例源码:loginDemo(ch3-6)3.6.2临时
购物车代码实现首先,对临时购物车中的数据模型(Model)进行分析。为了表示商品对象,需要定义商品类Goods,包含商品名称、价格、数量等私有属性及其相应的get和set方法,具体实现代码如下所示。1publicclassGoods{2privat
eStringname;3privatefloatprice;4privateintnumber;5publicStringgetName(){6returnname;7}8publicvoidsetName(Stringname){9t
his.name=name;10}11publicfloatgetPrice(){12returnprice;13}14publicvoidsetPrice(floatprice){15this.price=
price;16}17publicintgetNumber(){18returnnumber;19}20publicvoidsetNumber(intnumber){21this.number=number;22}23}3.6.2临时购物车代码实现为了在页面中展示商品列表,定义GoodsS
tore类,完成商品信息的初始化工作。此处,采用ArrayList对象进行存储,并将其放在静态代码块中,保证代码的优先执行。具体实现代码如下所示。1publicclassGoodsStore{2publicstaticL
ist<Goods>goodsList=newArrayList<Goods>();3static{4for(inti=0;i<10;i++){5goodsList.add(newGoods("商品"+(i+
1),50+i*10,0));6}7}8}3.6.2临时购物车代码实现定义好相关数据模型后,接下来定义商品列表展示页面,即完成临时购物车中视图(View)层的展示。因此,定义GoodsList类并使其继承HttpServlet,进行商品列表信息的页面展示。临时购物车中每个商品都可以加入购物车,当
用户单击“加入购物车”按钮时,将其交给临时购物车中的控制层,即在代码中定义“加入购物车”的action为“ShopCardController?type=addCard”。类似的,当用户在页面中单击“查看购物车”超链接时,将其转交给控制层,即将“查看购物车”的超链接定义为“
<ahref=„ShopCardController?type=cardList‟>查看购物车</a>”。具体代码如P105所示。根据MVC的设计理念,控制层负责数据模型和视图的交互。在临时购物车的商品列表页面中,当用户单击“加入购物车”按钮后,会将当前的
商品所在表单提交给ShopCardController。该类的具体代码如P106所示。3.6.2临时购物车代码实现用户在商品列表中选择商品后进入购物车页面,可以查看购物车中所选择的商品列表。购物车ShopCard类的代
码如P107。