NETCTOSS代码实现第五版:Cookie的使用场景与使用方式

  • 前言
    • Cookie的使用场景与使用方式
      • 模拟Cookie的使用场景
      • Cookie的创建,存储,获取与修改
      • Cookie的生存时间
      • 小总结:Cookie的关键API及代码实现
        • 1.Cookie关键API代码实现:jsp4/src/main/java/web/LoginServlet.java
        • 2.Cookie关键API代码实现:jsp4/src/main/java/web/IndexServlet.java
        • 3.Cookie关键API代码实现:jsp4/src/main/webapp/WEB-INF/web.xml
      • Cookie的中文编码问题
      • Cookie的中文编码问题代码实现
        • 1.jsp4/src/main/java/web/LoginServlet.java
        • 2.jsp4/src/main/java/web/IndexServlet.java
        • 3.jsp4/src/main/webapp/WEB-INF/web.xml
      • 关于Cookie的路径问题
      • Cookie的路径问题代码实现
        • 1.jsp4/src/main/java/web/LoginServlet.java
        • 2.jsp4/src/main/java/web/IndexServlet.java
        • 3.jsp4/src/main/java/web/FindCostServlet.java
        • 4.jsp4/src/main/webapp/WEB-INF/web.xml
      • 关于Cookie的限制问题
      • Cookie在NetCTOSS中的应用:登录记录保存并显示账号
        • 利用Cookie保存登录账号
        • JSP代码重构之提取页面公共的账号显示logo区:logo.jsp
      • Cookie在NetCTOSS中的应用代码实现
        • 1.src/main/java/web/MainServlet.java
        • 2.src/main/webapp/WEB-INF/logo.jsp
        • 3.src/main/webapp/WEB-INF/cost/add.jsp
        • 4.src/main/webapp/WEB-INF/cost/find.jsp
      • JSP中关于page指令include属性引入jsp的路径问题
  • 写在后面

前言

  • 返回 NETCTOSS

Cookie的使用场景与使用方式

模拟Cookie的使用场景

  • 所以,下一个话题是,第4个话题,第4个话题啊,我们讲一下啊,这个cookie的使用方式。因为呢,cookie的使用比较简单,主要是理解它的使用场景,所以呢,我们模拟出一个场景,然后演示一下这个cookie,模拟哪个场景呢,就是我之前举的这个典型的场景啊,登录,查询啊,登录时我要这个记帐号,后面查询是要用账号,这个意思,那我没有在netctoss项目里直接演示cookie,为啥呢,因为cookie的语法呢,还很琐碎,你都演示的话,会把这个项目,搞的很乱,明白吧,咱们不是说项目中,每个语法都要用上,所以我们先模拟一个这个项目,在模拟项目中演示这个cookie,一会都演示完,然后呢,我们项目中一会要用哪一个呢,再用明白吧,我是为了怕把这个项目搞乱了。
  • 所以我们模拟一个,模拟一下这个netctoss当中的一些功能,演示cookie啊,我说一下这个模拟的思路啊,那么首先,我们要模拟这个登录,当然我模拟的话,就简化一下,尽量简化,那么要登录的话,首先我要,打开登录页面我们就省略了,我就直接呢,敲路径访问服务器登录啊,那这个路径呢,我有一个要求啊,咱们这个案例需要新写一个项目啊,这个项目名,我看叫什么呢,咱们就叫jsp4吧,就往下排啊,jsp4,然后呢,登录功能,项目名先不写了,先省略了吧,咱们直接从路径开始写起啊,这个呢,我把这个路径设计的,稍微复杂一点,因为啥呢,为了演示一下cookie的这个一些特点,我要把路径设计的复杂一点,之前我们netctoss里,路径都是一级对吧,现在我们搞成两级啊,那登录功能,我希望它的路径是,/main,然后呢,/login,是这样的,/main/login,两级,是为了演示cookie的一些特点。
  • 那你注意啊,我这个/main/login,相当于咱们netctoss里的谁呢,login.do,明白么,登录,那这个请求需要传参,传账号密码,这里我也省略了,我就直接输入啊。就是账号啊,就是code等于xxx,就得了,咱们就简化处理,假如说登录时呢,就传了个账号啊,/main/login?code=xxx,code等于某某某,密码,这里用不上,我就不写了啊,然后呢,把这个一发请求啊,把这个数据呢,会提交给这个服务器,那服务器呢,我们需要写一个Servlet来处理这个请求,那因为是模拟案例,我们尽量简化,我就直接写一个Servlet,专门处理一个请求啊,那这个Servlet,我叫什么呢,叫LoginSerlvet,我专门写一个LoginServlet,来处理这个请求,然后呢,它这里呢,要接收这个账号code,接收以后,要把code,别叫code,叫user吧,这样比较好啊,用户啊,user,接收到以后啊,要把它存入cookie,我们先演示cookie,那怎么存cookie呢,我们需要new一个cookie,那new完了cookie,我给它取名叫c1吧,那我就把这个账号,就是存入这个c1,new c1,把账号存入c1,是这样,账号就是user,那new的话,存数据的话,是非常容易的,咱们后面演示的话,你一看,一写就明白了。
  • 然后呢,那么登录时把账号存入cookie,那登录之后的逻辑,我就省略了,然后呢,我们直接呢,向浏览器做出一个响应,响应时,这里我就不这个重定向了,就直接响应了,就输出一句话就完了,然后呢,响应的时候,我们需要把这个cookie发送给浏览器,因为什么呢,咱们之前说了,cookie是要由浏览器保存的,对吧,你要把cookie给浏览器啊,把c1给浏览器,怎么给,我们后面会演示。那么这个浏览器得到cookie以后,它会自动保存,并且呢,当浏览器再次访问服务器时,比如说这是登录了,登录以后比如说,浏览器就可以访问这个,咱们项目中的主页啊,查询啊,等功能,那假设浏览器,再发出请求,访问服务器的这个主页,那访问主页,咱们还是模拟还是,尽量简化,我要求呢,还是尽量敲路径,访问这个服务器,那主页的路径,我要求是要,/main/index,这是访问主页的路径,模拟啊。
  • 然后呢,浏览器在访问服务器的时候啊,它会自动的把这个c1,把它之前,把它保存的cookie发送给服务器,这件事就好像什么呢,我第一次去理发店,我办了个理发卡,理发卡里存了我的信息,然后呢,我离开的时候,理发店把理发卡给我,我带着了,明白吧,我自己保存了,那我下次去理发店,你想想,我是不是会带着这个卡啊,是吧,会主动出示这个卡,那么浏览器也是有这个功能啊,浏览器呢,在首次访问服务器时,它可以呢,服务器可以给它创建一个cookie啊,那浏览器呢,再访问服务器时,它会自动的携带这个cookie,那访问的是谁呢,我们这回访问的是index啊,我再写一个Servlet啊,模拟写一个IndexServlet,然后呢,我们演示一下,如果在IndexServlet里呢,得到这个cookie,怎么去获得cookie啊,我们在这里呢,可以获取cookie啊,那怎么获取,我们需要加以演示啊,然后呢,我们在这呢,把取到的cookie,就是输出,内容啊,输出给浏览器,我们看一下,能不能得到这个值,这是我们要演示的第2个请求,之前呢,登录是第一个,主页是第2个,就是这样。
  • 总之啊,就是说,还是想演示我所说的那个业务啊,登录的时候,我传入了账号,那么服务器呢,把账号传入了cookie,把cookie给浏览器,浏览器呢,再访问服务器时,访问服务器其他的功能时,它会自动传入cookie,我们可以得到它,得到它以后呢,输出给浏览器,就相当于在那个网页的顶部,显示了一个用户名,就实现了,只不过这只是简单的,简化的实现而已啊,不是正式的啊。然后呢,在这个案例里啊,我们去体会一下这个cookie的一些使用的语法啊,就这样,当然后续的话,还有其他的业务,我把这个空呢,留出来啊,大概就这个意思啊。然后呢,具体怎么操作啊,下面我们就来写这个案例啊。
  • 首先呢,我们新建个项目,在这个项目之内呢,我们直接呢,写一个Serlvet,那这个因为是模拟案例,我们尽量简化,我用的是 model1模式,就没有用MVC模式啊,咱们就是省点事啊。那么我们在开发工具里啊,创建一个新的项目,叫jsp4,打包方式war,按照顺序呢,往下写,那么创建好这个项目以后呢,别忘了,点那个Generate...,把叉去掉,别忘了导包,我们要导入那个javaee那个包。那么处理完以后啊,下面我们就写这个Servlet啊,那么我在这个src/main/java下,创建一个包,叫web。
  • 然后呢,在web之下创建这个Servlet,LoginServlet。
  • 那创建完这个Servlet以后,咱们就重写这个service方法,然后呢,在这个方法里,我们模拟啊,处理这个登录的业务,这样,我们在重写之前呢,我写个注释啊,就是声明一下,就是我将要写的这个方法呢,相当于什么呢,就是相当于,或者说模拟吧,模拟netctoss,这个MainServlet当中的login方法,我们模拟的是这个方法MainServlet.login(),不是别的。在这呢,我们要处理请求,我们得重写service方法,我们用service模拟这个方法,重写父类的方法,一会啊,我们访问这个方法的时候呢,我们直接给它传入一个账号,然后呢,我们在这个方法之内啊,就接收一下这个账号,然后呢,要把这个账号存入cookie。

Cookie的创建,存储,获取与修改

  • 那我就直接接收账号了,String user = req.getParameter("user");,我调了getParameter方法,接收了浏览器传过来的参数啊,然后呢,当然我们正式的登录当中呢,我们需要对账号密码进行验证,这是模拟,我们就省略了,那下面呢,我直接把这个参数呢,存入cookie。这是将这个账号存入cookie,这个cookie啊,它没有无参构造器,我们在new的时候呢,必须呢,传入两个参数,那么第一个参数,是你要存的数据的名字,Cookie c1 = new Cookie("user", user);,第2个参数呢,是数据的值,说白了,就是key-value,而且呢,一个cookie对象里啊,只能存一组值,一个key,一个value,那如果说,你有更多的数据,想这个保存,怎么办呢,再来个cookie,明白吧,反正一个cookie只能存一条数据啊,那么数据的值,就是这个user,这个变量,那么数据的名字呢,随意,那我还叫user吧 ,这样比较方便一点。
  • 那么cookie呢,它的这个条件,或者说要求,比较多啊,写一下,就是cookie当中,只能存一条数据,然后呢,并且只能存字符串,总而言之啊,这个cookie,它里面数据呢,要求比较高,它只能存一条数据,而且呢,只能存字符串,那为什么cookie中只能存字符串呢,其实这个也容易理解,因为什么呢,最终啊,这个cookie,我们需要呢,发送给浏览器的,那么,因为你要给浏览器,如果说这里面你存了个List,你存了个Map,浏览器不认对吧,浏览器上不能直接运行这个java语言,所以存字符串,传个字符串过去才行,所以只支持字符串。
  • 那么cookie呢,实例化完以后啊,我们需要呢,把cookie发送给浏览器啊,怎么发送呢,一句话,这样写res.addCookie(c1);,那这句话呢,解释一下啊,这句话的意思啊,是把这个cookie,添加到response里,或者说,存到response里对吧,绑定到这个response对象上,那什么时候会发送呢,当响应时,那么服务器呢,向浏览器发送响应的时候,这个数据就传过去了啊,写一下,就是说,将cookie绑定到response之上啊,那么,当服务器发送响应时会自动发送cookie,那就完成了。就是说我们使用cookie啊,非常简单。
  • 那么你想往cookie中存数据 ,new一下,传入就可以了,然后呢,add一下,发送就可以了,就两句话啊,当然了,如果说呢,我们就只写这一个Servlet,LoginServlet的话,咱们这个案例呢,还这个,看不到这个效果啊,因为服务器呢,确实能够创建cookie,发送cookie,浏览器也会自动保存,但是呢,它存到内存里,咱们看不到,明白吧,看不到啊,那如果你想看到怎么办呢,我们再访问IndexServlet,在这里我们获取cookie,再加以显示啊,就把这个也写出来,才能把这个案例呢,串通起来,完整啊。那这样,下面呢,我们先不着急呢,给它配置,我们先把这个IndexServlet啊,也一起写一下,写完之后呢,一起再进行配置,写一下它,那下面呢,我们在这个web这个包下啊,再创建一个Servlet,这个叫IndexServlet。
  • 那么这个类啊,我们模拟的是,就是打开首页那个请求,所以我们也在这个类中呢,也再重写下service啊,处理这个请求啊,那这个service方法,我们模拟的是谁呢,我们模拟的是之前netctoss的MainServlet当中的toIndex方法啊,即MainServlet.toIndex(),那这个方法里要做什么呢,就是我们在,假设在主页上,我想显示账号,那账号的获取,我要取的是cookie中的账号。
  • 那cookie就是,浏览器呢,再访问服务器呢,会再传过来给服务器,我们可以直接获取啊(浏览器会根据服务器的path判断,到底应该传回浏览器缓存的那些Cookie)。
  • 怎么取呢,你看,传过来,/main/index,这是请求对吧,那获取cookie用谁呢,用谁啊,显然是request啊。那我们就获取这个cookie啊,这个取之前,我把这个逻辑再写一下啊,就是说浏览器,访问服务器时会自动传入,它之前保存的cookie,req.getCookies();,这个你不要问我为什么是自动的啊,这是w3c规定的。那么,任何浏览器,任何服务器,都是这么干的,这是规范,规定啊。
  • 那么我们想获取这个cookie啊,通过request,即request.getCookies(),然后呢,我们getCookies,得到的是什么呢,不是一个cookie,是一组cookie,因为我说了,一个cookie只能存一条数据对吧,很有可能是有多条数据,需要这样存的,所以呢,是一组cookie啊,我们得到的是一个数组。Cookie[] cookies = req.getCookies();,那得到这一组cookie以后啊,就是我想输出呢,其中的那个user,那我遍历一下,根据呢,cookie的名字找到user,然后,把user呢,往外输出一下,那我们这个遍历之前啊,最好先做个判断,因为万一没有cookie呢,判断一下,if(cookies != null) { for(Cookie c : cookies) { } },总之啊,我们得到一组cookie啊,那么如果呢,你想输出其中的某一个,做出判断,找到其中的一个,把它输出了啊,那这里干脆我们就全输出算了,那后面我们会演示有多个cookie,我们输出看一下。
  • 那要输出的话呢,我们之前呢,应该先做一些声明啊,我要向浏览器输出一个网页,网页上显示了相关的值,所以,要加以声明啊,res.setContentType("text/html;charset=utf-8");,那么啊,我在循环之前啊,向浏览器声明,我要输出一个网页,页面编码为utf-8,就这个文件的编码为utf-8,然后呢,我获取呢,输出流,然后,每次循环,我就把cookie中的数据呢,输出看一下啊,这个我们所存的数据的名字,叫getName,是name,然后呢,我们再把这个值呢,也一起输出一下看看啊,值呢,是getValue,那经过循环啊,我们会把每一组值呢,都输出了啊,输出完以后,最后呢,别忘了把流关掉,w.close();

Cookie[] cookies = req.getCookies();
if(cookies != null) {res.setContentType("text/html;charset=utf-8");PrintWriter w = res.getWriter();for(Cookie c : cookies) {w.println(c.getName()+":"+c.getValue());}w.close();
}

  • 那这两个Servlet啊,LoginServlet和IndexServlet,我们都写完了,写完以后呢,我们需要对它们进行配置啊,那配置的时候呢,我之前有要求啊,要求呢,它们的访问路径都是两级啊,那两级路径是为了演示cookie的一个特点,后面呢,会有说明啊,我们先这样配。那下面呢,我们打开这个项目之下的,那个配置文件啊,我们对这两个类呢,加以配置,web.xml,同理呢,那个主页,也需要加以配置啊,那么,它的路径也是两级啊。

<servlet><servlet-name>login</servlet-name><servlet-class>web.LoginServlet</servlet-class>
</servlet>
<servlet-mapping><servlet-name>login</servlet-name><url-pattern>/main/login</url-pattern>
</servlet-mapping><servlet><servlet-name>index</servlet-name><servlet-class>web.IndexServlet</servlet-class>
</servlet>
<servlet-mapping><servlet-name>index</servlet-name><url-pattern>/main/index</url-pattern>
</servlet-mapping>

  • 那么配置完以后啊,咱们可以进行测试啊,测试的话啊,我们打开两个浏览器啊,比如说,我打开chrome,我以张三的身份去登录,然后呢,访问主页,看主页上能不能显示张三;然后呢,我再打开,另外的一个浏览器,比如说360,我用360以lisi的身份,去访问这个登录,然后呢,再访问主页,看一下主页上,是否显示lisi;然后呢,你两个浏览器啊,各再刷新一下,看一下张三还是不是张三,lisi还是不是lisi,有没有这个覆盖的情况,有没有呢,这个冲突的情况。那如果说没有问题的话,就证明了啊,这个cookie,它是可以在多请求之间,多组件之间,多浏览器之间共用的啊,
  • 那我把这个项目呢,部署一下啊,部署以后啊,启动tomcat,启动好以后,我先打开chrome,然后啊,我在chrome里,以张三的身份去访问这个登录功能,我这样写,localhost:8080,然后呢,项目名是jsp4,然后呢,登录功能的路径是,main/login啊,即localhost:8080/jsp4/main/login,因为呢,这个案例是模拟案例,我偷懒了,我没有写表单,对吧,直接拼个参数传过去啊,问号user,等于 zhangsan,即localhost:8080/jsp4/main/login?user=zhangsan,等于张三啊,回车,回车以后啊,这个浏览器得到的是一片空白,为啥是一片空白呢,因为咱们没有输出响应信息,对吧,没有写具体的内容,但是呢,因为我们将这个cookie啊,绑定到了response之上,所以啊,服务器呢,在向浏览器呢,自动响应的时候,这个cookie是传过来了,浏览器得到了,浏览器也保存了,那存到哪去了呢,存到了浏览器的内存里,我们看不到。
  • 那有人说,那我在这个网页上,如果想获取这个cookie,怎么办呢,也好办,如果呢,你想在浏览器上,在这个网页里得到cookie,我们用哪个对象呢,叫document,document有个属性啊,叫cookie啊,document.cookie,就能得到这个值,就是个字符串啊。那现在呢,我不是要得到它,我是要看一下,这个首页上,有没有zhangsan那个字对吧,所以我们再访问首页啊,localhost:8080/jsp4/main/index,一看确实有啊,user:zhangsan。
  • 那这是一个浏览器,一个用户,我们再来一个用户啊,再看一下,啊,我再打开一个浏览器啊,360,然后呢,也是像刚才一样啊,首先呢,我们先这个登录,然后呢,再访问主页,这回换个人就是了,localhost:8080/jsp4/main/login?user=lisi。那我用另外的浏览器又访问了这个功能,传入的用户呢,是lisi,然后呢,我在这个浏览器之上啊,我再访问主页,看一下能不能看到lisi啊,localhost:8080/jsp4/main/index,显示user: lisi,没问题。

  • 那么lisi登录了啊,对张三有没有影响呢,你回到chrome,刷新一下,还是zhangsan对吧,互不影响。那么经过这个小例子啊,咱们就验证了之前啊,上午我们所说的这几点啊,3点,第一点,cookie它里面的数据,可以在多请求之间共用啊,登录,主页,两个请求,可以共用这一份数据,然后呢,它的数据可以在多个Servlet之间共用,那么,LoginServlet,还有这个IndexServlet,可以共用,然后呢,每个浏览器,是一组cookie,我们看了也确实,chrome和360,都各有各的cookie是吧,不互相影响。如果说呢,这个规则,你不好记,或者还有地方你不理解,那你还是啊,想想之前,给你举的例子,就是那个理发店的例子,就想想理发店的例子。
  • 那么,如果呢,我们把cookie看成是一张被客户带走的理发卡的话,那你想啊,不同浏览器是不同客户,是不是你每个人有一张卡是吧,zhangsan不可能去跟lisi要是吧,自己用自己的,每个人有自己的cookie,自己的理发卡,然后呢,这个理发卡,那我第一次去理发店可以用,第2次去,还可以用对吧,多个请求之间共用,还有,那我去理发店,这回会找的是小张,下回找的是小王理发师,也可以共用对吧,也没有问题,所以你通过这个理发店的例子啊,去想一想,还是比较容易能想懂的啊,就做这么一个类比去想啊。那么通过呢,这个例子啊,我们就验证了,我们之前所阐述的这么几点啊,初步了解cookie以后啊,下面我们要对cookie,做一个更详细的介绍啊,我们需要呢,将这个对象了解的更全面,然后呢,再去解决项目中的问题啊,一步到位解决问题。
  • 那么,一般这个书上,关于cookie的介绍,也是这样的:

什么是Cookie:浏览器向Web服务器发送请求时,服务器会将少量的数据以set-Cookie消息头的方式发送给浏览器,浏览器将这些数据保存下来;当浏览器再次访问服务器时,会将这些数据以Cookie消息头的方式发送给服务器
如何创建Cookie:Servlet API为了使用Cookie提供了javax.servlet.http.Cookie。创建:
1.Cookie c = new Cookie(String name, String value);
2.response.addCookie(c);
name:用于区分不同的Cookie的名字
value:Cookie的值

  • 我们详细介绍了一些cookie的API啊,首先说,怎么去创建cookie,new啊,new的时候呢,必须要传入key-value,必须这样啊,然后呢,这个cookie创建好以后,要把它发送给浏览器,所以你要addCookie,这两句话,首先要记住,刚才也演示了。那么除了这两句话之外,除了能够创建Cookie之外,那么,如果我们想获取Cookie,刚才也演示了啊,就是request.getCookies(),得到数组。

如何查询Cookie
Cookie[] request.getCookies();
注:该方法有可能返回null
获取一个Cookie对象的名称或值:
String Cookie.getName();
String Cookie.getValue();

  • 那还有什么API呢,再看,这个Cookie呢,是可以改的啊,那怎么改呢,setValue啊,改它的值,当然了,我们要改cookie的话呢,之前得先取到Cookie,我们取到的是一个数组,那取到数组以后,如果说你想改众多Cookie当中的某一个,那我们需要遍历,然后呢,判断它的name,假如说,我想改name等于city这个cookie,我就判断一下啊,name等于city,我就改,否则就不改,就这样啊。

**如何修改Cookie**:
step1,获取客户端发送的所有Cookie
step2,根据name找到要修改的Cookie
step3,调用Cookie的setValue(String newValue)方法修改该Cookie的值
step4,将修改后的Cookie加入到response发送回客户端
如何修改Cookie(续):
Cookie[] Cookies = request.getCookies();
if(Cookies != null){for(Cookie c : Cookies){String name = c.getName();if(name.equals("city")){c.setValue("ShangHai");response.addCookie(c);//同名Cookie会覆盖,以达到修改的目的}}
}

Cookie的生存时间

  • 然后呢,总之你想改cookie啊,setValue,set以后,还得在addCookie一下,再发送给浏览器,覆盖一下,明白吧,就这样,那么,咱们刚才呢,演示了getCookie,这个set,我就不演示了,因为,相反的,你get会了,那set没什么好演示的,咱们这里呢,也没有什么业务要改cookie,就是了解一下,反正可以改,用set改。那么关于cookie呢,我们再往下看,那么下一个话题呢,说的是Cookie的生存时间啊:

Cookie的生存时间:默认情况下,浏览器会将Cookie保存在内存中,只要浏览器不关闭,Cookie就会一直存在;如果希望关闭浏览器后Cookie仍在,可以通过设置过期时间:
void Cookie.setMaxAge(int seconds);
注:seconds 单位是秒,精度不是很高

  • 这个Cookie,浏览器得到以后,它会存到哪呢,它存在浏览器的内存当中,那什么时候,这个cookie会消失呢,那我们关闭浏览器,cookie就没了啊,我们一关闭浏览器,cookie就没了,不信我们试一下啊,你看我打开这个chrome,打开以后,我把这个路径,localhost:8080/jsp4/main/index,把它copy一下,一会还要用啊,省的忘,省的还得敲,麻烦,那你看当前,我们刷新浏览器,这个 zhangsan还在对吧,还有呢,那如果我把浏览器一关,这个cookie就没了,那我关了啊,关了以后,我再重新打开浏览器,哎,怎么是360,它不让我用chrome了啊,它是把主页给串改了啊,应该还是chrome啊,主页给串改了,那太流氓了,那不管它了,你看啊,我打开了这是chrome,不是360啊,我打开chrome了,然后啊,我把刚才的路径,一copy,我直接访问,index,访问主页,看还能有zhangsan么,还有么,没了,就说明什么呢,浏览器一关,这个cookie就消失了,对吧,是这样。

  • 所以啊,就是说,这个cookie,它默认是存到浏览器的内存当中,浏览器关闭,cookie就没,那么cookie呢,我们可以,也可以呢,告诉浏览器,把它存到硬盘上,那么如果存到硬盘上的话,这个存的时间会比较长,你可以存一天,可以存一周,可以存一个月,甚至是一年,明白吧,存多久都行,你可以存很久。那什么情况下这个cookie,可能要存很久呢,你比如说,咱们平时上网的时候,很多网站都提供一个功能,记住账号,记住我,是吧,你一勾上记住账号,哪怕是我把电脑关了,我下回再访问这个网站,还能记住账号对吧,它靠什么记的呢,cookie。
  • 然后你也有经验,如果说啊,我现在用360清理这个系统的垃圾,清理完之后,往往再登录,那个账号就没了,是吧,被清掉了,是这样吧,所以说总之呢,这个cookie,可以存到硬盘上,存很久,但是一旦你清理了垃圾,清理了缓存什么的,这就没了,那怎么样才能把这个cookie存到硬盘上呢,咱们看一下。那么你想把cookie存到硬盘上,需要写这句话啊,void Cookie.setMaxAge(int seconds);,最大的年龄,就最大的时长吧,单位是秒,然后呢,这个时间啊,seconds,它大于0,等于0,小于0,是不同的含义,那么这个时间,如果你不写,它默认是负数,那如果时间小于0的话,这个cookie会被浏览器保存到内存里,默认是这样,然后呢,如果呢,你把这个时间大于0,那么浏览器呢,会把cookie呢,存到硬盘上,你这个时间写成多少,它就存多少,你写10秒,它就存10秒,你写1小时,就存一小时,明白吧,写多久存多久,那到了这个时间以后就自动删除了,这样的。

Cookie的生存时间:默认情况下,浏览器会将Cookie保存在内存中,只要浏览器不关闭,Cookie就一直存在;如果希望关闭浏览器后Cookie仍在,可以通过设置过期时间:
void Cookie.setMaxAge(int seconds);
注:seconds 单位是秒,精度不是很高
Cookie的生存时间(续):
1.seconds>0:浏览器要保存Cookie的最长时间为设置的参数,如果超过指定的时间,浏览器会删除这个Cookie。
此时Cookie保存在硬盘上。
2.seconds=0:删除Cookie。在修改Cookie的生存时间为0后,随着response发送回给客户端,替换原有Cookie,
因生命周期到了即将该Cookie删除。
3.seconds<0:缺省值,浏览器会将Cookie保存到内存中。

  • 还有,如果说呢,你把时间改为0,那么浏览器呢,会立刻删掉cookie,立刻删除。那关于cookie啊,它没有直接的删除方法,反正你想删除的话,把时间改为0啊,这样,我们演示一下,这个大于0的情况。咱们一般呢,也不会说存个3秒,5秒,几秒,因为什么,很快就过期了对吧,没有意义,一般我们存的话,都是,比如说10分钟啊,半小时啊,甚至是1天啊,一周啊,都是这样,都比较长的,一般很少说存几秒,没有意义,马上就过期了,没有意义。
  • 那咱们试一下,回到之前的那个案例中来,我们回到LoginServlet啊,你看,咱们之前啊,这个Cookie c1,它是存到内存里,那现在呢,我把这个c1,加一句话,想办法把它存到硬盘上,那我需要呢,在这个发送之前,写这句话,就是将cookie存到硬盘上,c1.setMaxAge(60*30);,这个时间啊,单位是妙,那我写了60*30,那一分钟是60秒对吧,乘30,这是30分钟,这样好看啊,写成1800的话,没那么容易看,那写完以后,咱们可以再测一下,我们还像刚才一样,就是把项目重新部署一下,然后呢,我们访问,我们去登录一下,然后呢,访问主页,能看到zhangsan,把浏览器关了,直接访问主页看一下,看还能不能看到zhangsan,明白吧,看它是否存在硬盘里。
  • 那我把这个项目啊,重新部署一下,重启tomcat,那我还是打开chrome浏览器,为了避免呢,之前这个操作,对我们当前的操作有影响,我把浏览器关了,重来。那我已经呢,把浏览器呢关了,我重新打开浏览器,然后呢,先登录啊,登录时呢,还是啊,要输入?user=zhangsan,那我访问,localhost:8080/jsp4/main/login?user=zhangsan;,登录以后啊,我再去访问主页index,localhost:8080/jsp4/main/index,然后呢,在主页之上,我就看到了这个zhangsan。
  • 那这回呢,这个zhangsan存到了硬盘里,30分钟之内,它一直存着,明白吧,不会消失的啊,那这样,我把这个路径,复制一下,然后呢,我把浏览器关了,关了以后啊,我再打开浏览器,直接呢,输入这个主页,localhost:8080/jsp4/main/index,这个路径,然后回车,这回呢,发现呢,zhangsan还在。

小总结:Cookie的关键API及代码实现

  • 那么关于cookie的使用啊,我把这个cookie的API的关键内容,总结一下。那关于cookie啊,第一个主要的内容,我们先讲的是什么呢,这个cookie的基本的用法,那我们需要了解的是如何创建cookie,如何发送cookie,如何获取cookie,非常容易,创建cookie,就是new对吧,发送response.addCookie(),获取request.getCookie(),对吧,很容易。然后呢,第2个,咱刚刚说的,就是cookie的什么呢,生存时间,那我们需要知道啊,这个如何修改cookie的生存时间,怎么改呢,setMaxAge(n),是这样吧,然后写个数进去就可以了。

1.Cookie关键API代码实现:jsp4/src/main/java/web/LoginServlet.java

package web;import java.io.IOException;
import java.net.URLEncoder;import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class LoginServlet extends HttpServlet {//模拟MainServlet.login()@Overrideprotected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {String user = req.getParameter("user");//将账号存入cookie//cookie中只能存一条数据,//并且只能存字符串。Cookie c1 = new Cookie("user", user);//将cookie存到硬盘上c1.setMaxAge(60*30);//将cookie绑定到response上,//当服务器发送响应时会自动发送cookie。res.addCookie(c1);}

2.Cookie关键API代码实现:jsp4/src/main/java/web/IndexServlet.java

package web;import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLDecoder;import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class IndexServlet extends HttpServlet {//模拟MainServlet.toIndex()@Overrideprotected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {//浏览器访问服务器时,会自动传入//之前保存的cookie。Cookie[] cookies = req.getCookies();if(cookies != null) {res.setContentType("text/html;charset=utf-8");PrintWriter w = res.getWriter();for(Cookie c : cookies) {w.println(c.getName()+":"+c.getValue());}w.close();}  }
}

3.Cookie关键API代码实现:jsp4/src/main/webapp/WEB-INF/web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5"><display-name>jsp4</display-name><welcome-file-list><welcome-file>index.html</welcome-file><welcome-file>index.htm</welcome-file><welcome-file>index.jsp</welcome-file><welcome-file>default.html</welcome-file><welcome-file>default.htm</welcome-file><welcome-file>default.jsp</welcome-file></welcome-file-list><servlet><servlet-name>login</servlet-name><servlet-class>web.LoginServlet</servlet-class></servlet><servlet-mapping><servlet-name>login</servlet-name><url-pattern>/main/login</url-pattern></servlet-mapping><servlet><servlet-name>index</servlet-name><servlet-class>web.IndexServlet</servlet-class></servlet><servlet-mapping><servlet-name>index</servlet-name><url-pattern>/main/index</url-pattern></servlet-mapping>
</web-app>

Cookie的中文编码问题

  • 那么关于cookie呢,还有一些内容,需要介绍,再看,下面我们说一下cookie的编码,这个Cookie里啊,它默认只能存英文,不允许存中文,而且呢,你存中文的话,它不是简单的乱码的那种情况,你存了中文以后呢,它直接抛异常了,报错了,这个挺过分的啊,那么如果我们非想存中文不可的话,怎么办呢,你得处理一下啊,我们得把中文进行转码,那么cookie,它只支持呢,ASCII码,反正就不带中文,我们就必须把中文,想办法编回ASCII码,那怎么编呢,这有工具,用工具就可以了。
  • 那么这个编码的工具叫URLEncoder,这工具呢,给我们提供了一个方法叫encode方法,这个方法呢,它允许我们呢,把一个中文,按照指定的编码编为ASCII码,明白吧,Cookie c = new Cookie("city",URLEncoder.encode("北京","utf-8"));,就这个中文,北京,它本身原来的编码是这个utf-8,我们把它,就把北京这个中文,由utf-8编为ASCII,明白这意思吧,这个意思,是把北京由utf-8编为ASCII。这是你存的时候,要对中文编码,那你想,你取的时候是不得有还原啊,还得把ASCII再还原回utf-8,对吧,还原,那还原怎么还原呢,用另外一个类,叫URLDecoder,解码。调用decode方法,然后呢,传入value这个值,就是编码以后的那个ASCII那个值,然后呢,要求将其还原为utf-8的编码,这个意思。

Cookie编码:Cookie只能保存合法的ASCII字符。如果要保存中文,需要将中文转换成合法的ASCII字符,即编码。
Cookie c = new Cookie("city",URLEncoder.encode("北京","utf-8"));
Cookie解码:编码后的Cookie为了看到实际的中文,需要还原后再显示:
Cookie[] Cookies = request.getCookies();
if(Cookies != null){Cookie c = Cookies[0];String value = c.getValue();value  = URLDecoder.decode(value,"utf-8");//与编码时格式保持一致
}

  • 就总而言之吧,就是Cookie当中呢,默认不让存中文,那么只让存ASCII,如果说你想存这个中文,我们需要对它进行转码,我们将中文,由utf-8转为ASCII,然后,读取时,再相反的方式再转回来,就可以了啊,然后呢,需要用两个工具来处理,那下面我们也试一下,我们就像书上一样,假设我想往cookie中呢,存一个城市,中文的城市看一下,那这样啊,大家再打开这个LoginServlet啊,登录,那么,在LoginServlet之后啊,我们在res.addCookie(c1)这个地方啊,再往下接着写,我们再创建一个新的Cookie,这写一下,就是再创建一个Cookie,存入中文。Cookie c2 = new Cookie("city", URLEncoder.encode("北京", "utf-8"));,那么这个数据的名字呢,叫city,它的值啊,数据啊,叫URLEncoder,调用它的encode方法,进行转码。
  • 那么创建完cookie以后啊,我们还需要呢,把这个新的cookie也发送给浏览器,让浏览器保存,所以还是写那句话,就写res.addCookie(c2);,这是我们创建cookie时,这个进行了转码,那咱们读的时候,先不处理,我们先看一下,就看一下它转完码以后,我们得到的是什么东西,然后我们再转,先试一下啊,把这个项目呢,重新部署一下,然后呢,启动呢这个tomcat,启动以后啊,我还是这个,先访问这个登录功能,登录的时候呢,传入zhangsan,即localhost:8080/jsp4/main/login?user=zhangsan,然后呢,我再访问主页啊,你注意咱们登录时,那个城市也传进去了对吧,是吧,城市也存了啊,那我们再访问主页,看一下主页上,能不能看到那个城市啊。
  • 访问localhost:8080/jsp4/main/index,看到了吧,user:zhangsan city:%E5%8C%97%E4%BA%AC,这个city是这样的一个字符串,但这个字符串,并不是乱码,因为以前,我们见过乱码,乱码的话,会出现一些问号啊,还有一些特别的字符,比如说一个尖^啊,什么的,对吧,奇葩的一个字符之类的啊,乱码是这样的,很奇葩的。它这个字符是有规律的,是百分号,加英文数字对吧,这是一个有规律的字符串,就是进行有意的编码得到的字符串,当然我们看,不能看这个,我们需要对它再转码,对吧,再转换为utf-8才可以,那我们再转一下啊。
  • 那我们是在首页index里读取的啊,所以,我们再打开这个index,即IndexServlet,那我们是在这个地方w.println(c.getName()+":"+c.getValue());,获取到的这个,编码以后的字符串。

Cookie[] cookies = req.getCookies();
if(cookies != null) {res.setContentType("text/html;charset=utf-8");PrintWriter w = res.getWriter();for(Cookie c : cookies) {w.println(c.getName()+":"+c.getValue());}w.close();
}

  • 我们需要加以处理,我在这处理w.println(c.getName()+":"+c.getValue());。那么我们要对c.getValue(),进行一个转码,怎么转呢,用URLDecoder调用它的decode方法,String value = URLDecoder.decode(c.getValue(), "utf-8");,那么我调用URLDecoder的decode方法,我把这个cookie中的value传入,要求呢,把这个数据,转为utf-8的编码,得到了一个变量叫value,value是转换之后的结果,那我们输出的话,就别输出c.getValue了,我们该输出什么呢,value啊,w.println(c.getName()+":"+value);,注:对于英文部分,UTF-8编码和ASCII码矢相同的,因此,为了考虑中文编码情况,对传入中英文的Cookie也进行了统一的,从ASCII码转为UTF-8的解码处理操作,实际上这个操作只是为传入中文的Cookie做处理,而对原本的英文字符是没有任何影响的。

Cookie[] cookies = req.getCookies();
if(cookies != null) {res.setContentType("text/html;charset=utf-8");PrintWriter w = res.getWriter();for(Cookie c : cookies) {String value = URLDecoder.decode(c.getValue(), "utf-8");w.println(c.getName()+":"+value);}w.close();
}

  • 那写完以后啊,咱们可以试一下啊,把这个项目再部署一下,然后呢,再启动这个服务器啊,打开浏览器,我们还是先登录啊,先登录,localhost:8080/jsp4/main/login?user=zhangsan,登录以后呢,再访问主页,看那个城市啊,city:北京,对吧,就可以了。
  • 就总之吧,这个cookie里呢,默认不让传中文,那么如果想存的话,需要加以处理,不过一般情况下,咱们存中文的时候也比较少,我们一般就存个账号,而一般的账号都没有中文,或者一般存一些状态啊,一些标志啊,一般存中文的情况少,就了解一下吧。那这个cookie的第3个话题就说完了,就是说如何这个解决编码问题,或者说如何存中文啊,那么,cookie中如果你想存中文的话,首先呢,我们需要使用URLEncoding啊,对中文转码,然后呢,这个怎么说呢,存入数据时,使用URLEncoder对中文转码,然后呢,取数据时,我们需要使用,URLDecoder对中文解码,总之啊,需要做一些这个特殊的处理,然后一般,我们在cookie中存中文的时候呢,相对少啊,所以了解一下。

Cookie的中文编码问题代码实现

1.jsp4/src/main/java/web/LoginServlet.java

package web;import java.io.IOException;
import java.net.URLEncoder;import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class LoginServlet extends HttpServlet {//模拟MainServlet.login()@Overrideprotected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {String user = req.getParameter("user");//将账号存入cookie//cookie中只能存一条数据,//并且只能存字符串。Cookie c1 = new Cookie("user", user);//将cookie存到硬盘上c1.setMaxAge(60*30);//将cookie绑定到response上,//当服务器发送响应时会自动发送cookie。res.addCookie(c1);//再创建一个Cookie,存入中文Cookie c2 = new Cookie("city", URLEncoder.encode("北京", "utf-8"));res.addCookie(c2);}
}

2.jsp4/src/main/java/web/IndexServlet.java

package web;import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLDecoder;import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class IndexServlet extends HttpServlet {//模拟MainServlet.toIndex()@Overrideprotected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {//浏览器访问服务器时,会自动传入//之前保存的cookie。Cookie[] cookies = req.getCookies();if(cookies != null) {res.setContentType("text/html;charset=utf-8");PrintWriter w = res.getWriter();for(Cookie c : cookies) {String value = URLDecoder.decode(c.getValue(), "utf-8");w.println(c.getName()+":"+value);}w.close();}  }
}

3.jsp4/src/main/webapp/WEB-INF/web.xml

同上:小总结:Cookie的关键API及代码实现

关于Cookie的路径问题

  • 然后呢,再看啊,那么关于cookie还有一个话题啊,是cookie的路径问题,这个路径问题,咱们就是怎么说呢,用一两句话概括,还不太好概括啊,最好是通过例子去体会啊,那我直接呢,在之前的那个图里,再说明这件事,就这个登录这个图啊,那你注意啊,咱们之前啊,是在登录的时候,我们创建了cookie啊,那我们是在登录功能时,在/main/login,我在这个路径下,创建的cookie,那它只对哪个路径有效呢,这样的,就是在/main/login路径下创建的cookie,它只对/main极其下级路径有效,就是我们创建一个cookie,这个cookie呢,发送给浏览器,浏览器保存了,那并不是说浏览器在访问这个服务器时,访问谁,都会发送这个cookie。
  • 那样的话,就会很乱,你比如说,我访问淘宝,淘宝呢,创建个cookie给我,我存了,存完以后的话,我访问京东,我有必要,把淘宝的cookie传个京东么,没必要对吧,它也不会用,所以呢,这个cookie啊,它是有这个有效路径的,那么,我说的这句话就是,在/main/login路径下创建的cookie,它只对/main及其下级路径有效,就是它的原则啊。我们在/main/login这个路径下创建cookie,那么它只对/main和main的下级路径有效,所以你看,我在这/main/login创建的cookie,那么对于主页是否有效呢,有没有效,有效,因为主页/main/index,它也是main,main的下级,对吧,有效。
  • 那我们再继续举这个例子啊,比如说,我接着做这个功能,我再做这个查询啊,资费查询,那比如说,我再访问这个资费查询功能,资费查询功能,我们再模拟写一个Servlet啊,比如说,我写这个,咱们简单取名吧,就写就叫FindCostServlet,这也不太简单,就这样吧,FindCostServlet,访问它啊,然后呢,它向浏览器呢,做出响应,输出一些东西,这是咱们这功能当中呢,第3个请求,然后呢,我要求呢,FindCostServlet它的路径是什么呢,不是main,因为Cost是一个独立的模块对吧,它和登录不是一个模块,我希望呢,它的路径是这样的,是/cost/find,行吧,这也很直观,那你想,咱们所创建的那个cookie c1的话,浏览器会发送给FindCostServlet么,不会。那下面我们演示一下这一点啊,说不会,咱们演示一下,确认一下啊。
  • 那么要演示的话呢,我们需要呢,再写这个FindCostServlet,那么打开开发工具啊,然后啊,我们在web这个包下创建一个新的Serlvet,叫做FindCostServlet。那么创建好这个类以后啊,我们在这个类当中呢,也要重写service方法,处理资费查询的请求,当然是模拟啊,重写它父类的方法。

  • 那在这个service方法之内啊,我想啊,还是获取到这个,所有的cookie啊,然后呢,我遍历cookie,把这个cookie呢,输出给浏览器,想看一下啊,我们在访问资费查询的时候,我们能不能得到登录时的那个cookie。那写一下,那获取cookie啊,那个方式和那个主页index一样啊,就再写一遍巩固一下啊。

@Override
protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {Cookie[] cookies = req.getCookies();if(cookies != null) {res.setContentType("text/html;charset=utf-8");PrintWriter w = res.getWriter();for(Cookie c : cookies) {w.println(c.getName()+":"+c.getValue());}w.close();}
}

  • 总之啊,是这个获取cookie的这个逻辑啊,输出的逻辑,和这个IndexServlet里的代码呢,差不多,一样,那当然了,这个类写完以后,我们也得对它进行配置对吧,那么我们再打开这个配置文件啊,把这个类配置好,然后呢,要求它的访问路径是,/cost/find,两级。那我打开这个配置文件啊,配置它,

<servlet><servlet-name>findCost</servlet-name><servlet-class>web.FindCostServlet</servlet-class>
</servlet>
<servlet-mapping><servlet-name>findCost</servlet-name><url-pattern>/cost/find</url-pattern>
</servlet-mapping>

  • 那么配置好以后呢,咱们可以测一下,那我们需要把项目先部署一下,然后呢,先登录,登录完以后啊,你去访问这个资费查询这个功能,看一看我们在查询页面上,能不能看到那个cookie中的数据,试一下。把项目呢,重新部署一下,当前啊,咱们这个tomcat之内啊,已经部署了很多项目,你看这么多项目,然后啊,因为大家的电脑呢,可能会性能一般是吧,然后呢,有的同学呢,部署的项目一多,这个一启动的话,会运行比较慢,那你可以把这些项目啊,不用的就把它,就是把部署的项目删掉,因为tomcat一启动的话,它会加载呢,它里面部署的每一个项目,所以项目越多越慢,明白吧,不过我这个还好,我这个电脑还行,我就不用了,你看我一启动还挺快的,啊,一共才1千多毫秒。
  • 就是说,我们从这个服务器啊,启动的时间上,就能够看出来,我们所做的项目和企业中的项目,这个规模差多少,以前我在用友的时候,我那个电脑,启动一次,一个项目要启动两分钟多一点,两分钟多,你想那代码,得多少,得启动那么久,光读那配置文件就读半天啊,我们这多快,这么多项目,一秒啊,一秒钟搞定了。那试一下啊,我打开那个浏览器,还是先登录一下,localhost:8080/jsp4/login?user=zhangsan,那么登录完以后,访问主页localhost:8080/jsp4/main/index,看到user:zhangsan,city:北京,没问题。那主页没问题啊 ,然后,看什么呢,localhost:8080/jsp4/cost/find,看这回行不行啊,什么都没有,对吧,没有啊。

  • 所以呢,经过这个案例的演示,发现呢,确实是这样,这个浏览器呢,发送cookie,它得看情况,如果说呢,是/main/login,这样的路径,或者说呢,是/main的子路径,有效,它会发cookie,如果呢,路径,你完全换了,就不会传这个cookie了,但是呢,有一个问题啊,比如说,我就想在资费查询上,也显示这个账号,有这种可能吧,是吧,有这种可能,那怎么办呢,我们可以去修改这个cookie的有效路径,可以改啊。那怎么改呢,那我们想修改cookie的有效路径啊,也非常简单啊,就是一句话,cookie点setPath:

1.什么是Cookie的路径问题:浏览器在访问服务器上的某个地址时,会比较Cookie的路径与该路径是否匹配,只有匹配的Cookie才会发送给服务器。Cookie的默认路径等于添加这个Cookie的Web组件的路径。如:/appName/file/addCookie.jsp添加了一个Cookie,则该Cookie的路径等于/appName/file
2.发送Cookie的条件:要访问的地址必须是Cookie的路径或者其子路径时,浏览器才会发送Cookie,如:Cookie的路径是 /appName/file;则访问/appName/file/a.jsp 或 /appName/file/b.jsp时会发送Cookie;如果访问 /appName/c.jsp则不会发送Cookie
3.如何设置Cookie的路径:使用如下代码段可以设置Cookie的路径
Cookie c = new Cookie("uname","Jack");
c.setPath("/appName");
response.addCookie(c);

  • 那你看啊,比如说啊,我把这个cookie c1的setPath,把它的path改为cost,那你说对FindCostServlet有没有效呢,就我c1.setPath("cost"),cookie对FindCostServlet有没有效,有效,但对它有效的同时,对IndexServlet还有效么,就无效了,那如果我既想对FindCostServlet有效,又想对IndexServlet有效呢,怎么办,对,你得把这个cookie的有效路径,再往上提,提到/main之前对吧,/cost之前,那么,/main/cost之前是什么,项目对吧,我们可以把这个cookie的有效路径,设置到项目那一级,那这个cookie对整个项目内都有效,明白吧,咱们就这样处理一下啊。

  • 那我们再回到这个登录啊,LoginServlet,这样吧,我们就别改之前的cookie了,我们再写一个新的啊,然后这个cookie呢,有效路径设置的大一点,做个对比,再来一个啊,再创建一个cookie,然后呢,设置其有效路径,那我创建了一个新的Cookie,叫c3啊,然后呢,往里存了一个,随便存了一个数据,这个数据叫status状态,状态为1,我们将来呢,做项目时啊,这个项目中经常会有一些状态啊,1,2,3,表示某种情况,比如说1,代表程序执行成功了,2代表比如说,这个比如说邮箱已存在,3比如说,代表的这个后缀不对,等等啊,就是说,这个状态代表不同的情况啊,很多会有这种情况啊,会这样用啊。然后呢,把这个cookie呢,发送给浏览器啊,当然了,发送之前,我们说了,还要改它的有效路径对吧,怎么改呢,是c3.setPath("/jsp4"),这个地方啊,我们应该写这个项目名,项目名,我们可以这样写,斜线啊,jsp4,可以这么写。

    //再创建一个cookie,设置其有效路径
    Cookie c3 = new Cookie(“status”,“1”);
    c3.setPath("/jsp4");
    res.addCookie(c3);

  • 那写完以后呢,咱们再试一下啊,把这个项目还要重新再部署一遍,然后呢,启动tomcat啊 ,启动好以后,我们还要再打开浏览器,再重新测一遍啊,还是先访问这个登录啊,localhost:8080/jsp4/main/login?user=zhangsan,登录以后呢,我们再访问主页,localhost:8080/jsp4/main/index,那index之上,我能够看到3个数据啊,user,city,status,即user:zhangsan city:北京 status:1。

  • 那说到这啊,有一个小小的疑问啊,就是说,我输出了3个数据不假,但是呢,我输出的是写了println,对吧,println有换行的,那为啥这个数据没换行呢,你看,为啥在一行之上,为啥没有换行呢,那有人说了,很到位了,叫什么呢,空格折叠原则,你想啊,我们向浏览器输出的是什么,我们拼的是网页对吧,只是呢,我把网页中的标签省略了,没有写那个doctype,html,body对吧,省略了,直接写内容,我在写内容的时候,连个p都没写对吧,啥都没写,就写字,那你想啊,我们在网页上写的字,这个换行,它会当作空格来对待对吧,空格折叠原则,所以没换行,你想换行怎么办呢,加个p对吧,或者br什么的,我这里就解释一下啊。

  • 那访问主页以后,我们这主页能取到这status,我们再访问查询啊,资费查询,localhost:8080/jsp4/cost/find,那么资费查询页面上,也可以得到这个status。

  • 就总之啊,这个项目之下,任何的页面,任何的路径,我们都能,得到这个数据,这是我们关于cookie的第4个内容啊,这个内容就是有效路径啊,那么设置有效路径,就一句话啊,就是setPath(""),里面写的是这个路径啊,那么关于cookie啊,基本上,就这么点内容,就是基本用法,创建cookie,发送cookie,获取cookie,然后呢,一些高级的设置啊,如何设置生存时间,如何呢,存中文啊,如何呢,设置有效路径,那么尤其是生存时间和有效路径,通常都是要进行设置的。

Cookie的路径问题代码实现

1.jsp4/src/main/java/web/LoginServlet.java

package web;import java.io.IOException;
import java.net.URLEncoder;import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class LoginServlet extends HttpServlet {//模拟MainServlet.login()@Overrideprotected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {String user = req.getParameter("user");//将账号存入cookie//cookie中只能存一条数据,//并且只能存字符串。Cookie c1 = new Cookie("user", user);//将cookie存到硬盘上c1.setMaxAge(60*30);//将cookie绑定到response上,//当服务器发送响应时会自动发送cookie。res.addCookie(c1);//再创建一个Cookie,存入中文Cookie c2 = new Cookie("city", URLEncoder.encode("北京", "utf-8"));res.addCookie(c2);//再创建一个cookie,设置其有效路径Cookie c3 = new Cookie("status","1");c3.setPath("/jsp4");res.addCookie(c3); }
}

2.jsp4/src/main/java/web/IndexServlet.java

同上:Cookie的中文编码问题代码实现

3.jsp4/src/main/java/web/FindCostServlet.java

package web;import java.io.IOException;
import java.io.PrintWriter;import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class FindCostServlet extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {Cookie[] cookies = req.getCookies();if(cookies != null) {res.setContentType("text/html;charset=utf-8");PrintWriter w = res.getWriter();for(Cookie c : cookies) {w.println(c.getName()+":"+c.getValue());}w.close();}}
}

4.jsp4/src/main/webapp/WEB-INF/web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5"><display-name>jsp4</display-name><welcome-file-list><welcome-file>index.html</welcome-file><welcome-file>index.htm</welcome-file><welcome-file>index.jsp</welcome-file><welcome-file>default.html</welcome-file><welcome-file>default.htm</welcome-file><welcome-file>default.jsp</welcome-file></welcome-file-list><servlet><servlet-name>login</servlet-name><servlet-class>web.LoginServlet</servlet-class></servlet><servlet-mapping><servlet-name>login</servlet-name><url-pattern>/main/login</url-pattern></servlet-mapping><servlet><servlet-name>index</servlet-name><servlet-class>web.IndexServlet</servlet-class></servlet><servlet-mapping><servlet-name>index</servlet-name><url-pattern>/main/index</url-pattern></servlet-mapping><servlet><servlet-name>findCost</servlet-name><servlet-class>web.FindCostServlet</servlet-class></servlet><servlet-mapping><servlet-name>findCost</servlet-name><url-pattern>/cost/find</url-pattern></servlet-mapping>
</web-app>

关于Cookie的限制问题

  • 那我们关于cookie呢,还有最后一个小的话题,这个话题呢,就是了解一下,那我们在使用cookie的时候啊,这个cookie呢,它限制比较多啊,像之前我们也看到了,cookie中呢,只能存字符串啊,而且呢,这个cookie中的数据量,以及呢,cookie的个数,都是有限制的啊,浏览器呢,不能够存任意多个cookie,不能够存任意多个数据,是有限制的,总之呢,cookie只能存比较少量的数据,一般是4k,但4k的话,存文字也存不少了啊。再有呢,cookie呢,还能够怎么样呢,还能够被浏览器,被用户禁止,我们可以禁止cookie,我们也可以呢,把cookie删掉,总之呢,cookie可以受到用户的种种的,这个限制。

Cookie的限制:
Cookie可以被用户禁止。
Cookie会将状态保存在浏览器端,不安全。对于敏感数据,需要加密后再使用Cookie来保存。
Cookie只能保存少量的数据,大约4kb左右。
Cookie的个数是有限制的。
Cookie只能保存字符串。

  • 那有人说,cookie怎么禁止呢,怎么删掉呢,咱们演示一下,了解一下啊。我是以这个chrome浏览器来演示啊,打开浏览器啊,那么我们想,禁止cookie,或者是删除cookie,需要在浏览器的设置里,去处理啊,所以呢,我点浏览器的右上方,这个三条线,然后呢,在这个展开的窗口里啊,有一个设置对吧,有吧,设置,在设置里呢,往后找,然后呢,最后有一个叫,显示高级设置,对吧,在高级设置之内,那么高级设置里啊,你看,高级设置一展开,第一项是隐私设置,对吧,展开以后,你看啊,它有两个按钮,一个按钮,这个按钮叫,清除浏览数据...,看到了吧,你点清除浏览数据,然后这里面,你看,清除的内容有什么呢,有浏览记录,下载记录,缓存的图片和文件啊,密码,什么什么什么,然后还有一项叫cookie对吧,cookie其实也是缓存到我们客户端上的一份数据,一份字符串,我们可以呢,把它清掉,算了,就别清了啊,我这里呢,告诉你下,看一下啊。
  • 当然,你真的清了也没关系,问题不大啊,那这是清除cookie,那如果你想把这个cookie呢,禁用,怎么办呢,还有第一个按钮,内容设置,然后呢,我点这个按钮啊,它会弹出个框,是吧,弹出框的第一项,就是cookie的设置,然后呢,默认它勾选了,允许本地数据,就是允许cookie,也可以呢,选择什么呢,阻止,禁止cookie,当然,别禁止,还是允许的好。总之啊,这个cookie啊,是浏览器缓存的一份数据,这份数据,我们可以呢,通过浏览器的设置进行禁止,或者是清理啊,那么如果说用户把这个cookie禁用,或者是删除了,怎么办呢,这件事,咱们不用去管,就通常不用去管,为啥呢,我们认为呢,一个,怎么说呢,一个正常的正经的用户,它是不会去禁用cookie的,你想啊,咱们要不说这件事的话,你闲着没事,你会去禁用cookie么,是吧,你甚至都,都不知道cookie是什么东西,对吧,你不会去禁用的,你也很少会删除,但删除也没关系,删除你再登录,就又有了对吧,问题不大,咱一般不会禁用。
  • 那么,如果有个别人,想搞事情,对吧,它非要禁用话,那怎办呢,我们就不管他了,我们认为他不是我们的目标客户啊。就是对于这个企业软件,这件事很容易解释,企业软件,他一用这个企业的,比如OA系统一用,说哎,这有问题啊,不好使啊,为啥不好使呢,这个工程师一看啊,你禁用了cookie,见到领导一说,说你告诉你们员工别禁用cookie,禁用cookie,软件不好使了,领导一句话,谁也不敢禁用明白吧,都会开着cookie,然后呢,如果是互联网的用户,互联网用户,一般也不会禁用cookie,因为绝大多数人,不知道cookie是什么,再一个呢,如果你真的把cookie禁用的话,你像京东啊,淘宝啊,各大网站,它们也用cookie,明白吧,这些网站使用起来,也会受到影响,所以没有人会闲着没事,会禁用cookie,总而言之呢,就是 一句话啊,就是关于用户禁用cookie的行为,我们无视,我们认为呢,正常用户不会做这件事,少量人做这件事,我们把他忽视掉啊。
  • 当然也有人会想啊,说那既然浏览器提供了这个功能, 我就应该,我就可以用对吧,凭啥不能用呢,其实这是一个历史遗留问题啊,这个,怎么回事呢,就早先啊,10多年前,那个时候啊,互联网还不是呢,特别的发达,带宽呢,还比较低,那么,在那个年代呢,咱们上网,是浏览一些东西,有的时候呢,我们还得把这个图片禁掉,因为速度太慢了明白吧,下载图片太慢了,我们把图片禁掉,如果还慢,可以把cookie也禁掉,我就想看这个新闻啊,别的东西,我都不要,那时候,就是大家怎么说呢,有的时候,不太在乎这个用户体验啊,只要是能看到这个东西,就不错了,因为带宽低,没办法,所以,那个年代呢,浏览器呢,怕用户呢,加载网页慢,允许你禁用cookie,你禁用cookie的话,少存点数据,可能就会快了,但是现在的话呢,咱们这个带宽啊,都数以,数以几十兆计,对吧,真实的流量,也能达到几兆了,所以你传个cookie,传那么几个字,根本就没有任何影响,所以,到现在为止呢,基本上,没有人会禁用cookie了。那么这是关于cookie的这个内容啊。

Cookie在NetCTOSS中的应用:登录记录保存并显示账号

利用Cookie保存登录账号

  • 那么在了解了cookie以后啊,下面我们就用一下这个cookie,我们使用cookie呢,去解决咱们那个项目中问题,什么问题呢,是我之前所说的那个经典的场景,我要在登录时存账号,我要在其他的网页上显示账号,其他的网页,就包括这个,资费查询,资费增加,修改,等等,明白吧,所有的其他的jsp啊,都要显示啊,我们就解决这个问题,那么要解决问题的话呢,首先呢,我们得在登录时把账号记下来,所以呢,咱们就打开之前的netctoss项目啊,然后呢,在这个项目下,我们找到这个登录的那个方法,那个方法是在MainServlet当中,方法名就叫login对吧,是吧,叫login,找到它啊。那我在MainServlet这个类当中呢,找到login()这个方法,那我在这个方法之内呢,要记帐号,那想一下啊,我在哪一行去记呢,得验证通过对吧,你得账号对,对吧,你账号不对,我记也没有用啊,所以我们找到验证通过的那个地方,是在else这个位置对吧,

else {//验证通过res.sendRedirect("toIndex.do");
}

  • 那现在我要创建这个cookie,保存这个账号,那想一想,这个这句话,我是写在sendRedirect之前,还是之后,因为Redirect,就重定向,就跳了是吧,在跳之前要存啊,所以在这啊,就是,将怎么说呢,将账号存入cookie,那么这个账号啊,账号这个值是谁呢,账号那个值,是不是就是这个,之前的那个adminCode啊,就它对吧,我要存它啊,那我要new一个cookie啊,直接就像刚才那么new Cookie啊,Cookie cookie = new Cookie("user", adminCode);,然后呢,存入这个key-value,那么这个value呢,是adminCode,这个key我不叫adminCode行不行,比如我叫user行吧,叫user,那么创建完以后呢,我们需要把这个cookie发送给浏览器啊,所以那句话,还得写一遍,res.addCookie(cookie);,那这两句话呢,是cookie的基本的用法。
  • 那我们创建cookie以后啊,你要想一下,这个cookie,它的这个需不需要啊,存到硬盘上,这个cookie,它有没有中文,这个cookie的有效路径,需不需要加以设置,考虑这3方面,那想一下,第一点啊,这个cookie,我是把它存到硬盘里,还是内存上,你说存哪个好啊,内存里就可以,因为每次登录,只要你成功了就会存对吧,然后,你下次再用还得再登录对吧,每次登录都存一遍,内存里就可以了,没有必要存硬盘上,那什么数据需要存到硬盘上呢,像之前我给你举的例子,比如说记住的账号,明白吧,记住的账户要长久保存,还有什么呢,你像浏览器,咱们访问些网页都会有一些历史记录对吧,是这样吧,其实也是cookie存的,还有,比如说呢,我们去什么淘宝啊,京东啊,浏览器一些宝贝,是有浏览记录的明白么,那个也是cookie存的,这种需要长久保存的内容,我们存在硬盘上,像这个登录时,就不用啊,这个不需要啊。
  • 还有啊,这个cookie有没有中文呢,没有,这个账号是没有中文对吧,不用处理乱码,然后第3点,它的有效路径,我们需不需要进行设置呢,需不需要啊,那你要把它设置为什么呢,项目名,那你想啊,咱们当前所访问的是login.dologin.do的完整路径,或者说绝对路径是什么呢,是不是/netctoss/login.do,是这样吧,那在这个路径下,我们创建的cookie,它对谁有效呢,对/netctoss和netctoss下级有效对吧,就已经ok了吧,因为它是一级路径对吧,就可以了,没必要了,不用设置,所以我们在正式使用的时候啊,发现那3点特殊的地方,都不用声明,一般都是这样,就可以了。那么我们向浏览器啊,发送了cookie,浏览器得到以后,要在各个网页上显示,那它显示,怎么处理,我们找到呢,这个项目中的jsp啊,因为我们是在jsp所生成的网页里显示对吧,要改jsp的代码,那么在哪显示呢,主页就不用了,因为主页那个没有login区啊,我想在哪里显示呢,在那个login区显示啊,那我们就把这个资费查询啊,资费增加啊,资费修改啊,等功能处理下。

JSP代码重构之提取页面公共的账号显示logo区:logo.jsp

  • 那你想啊,因为很多功能都要显示这个账号,这也是要复用的对吧,那么,要想复用的话,是不是我们还得把那个代码,include一下,是吧,单独再写一个jsp啊,那我们看一下,我随便打开一个,比如说find.jsp,我们看一下,是哪段代码需要复用啊。我打开find.jsp啊,33行,34行,这两行,

<!--Logo区域开始-->
<div id="header"><img src="data:images/logo.png" alt="logo" class="left"/><a href="#">[退出]</a>
</div>

  • 我希望呢,把这个位置复用,这个不直观,我还是给你,这个看一下啊,看一下这个页面啊,直观一点,那登录以后呢,因为主页没有logo区,它没有地方显示,所以这个就不显示了。
  • 那么资费查询等等,其他的增删改查的功能,在logo区,退出按钮之前显示啊,用户名,那么就是在这个退出之前对吧,退出之前啊。
  • 那我们看一下啊,退出的话,就是一个超链接,在它之前,所以,我得把这个,这个<a href="#">[退出]</a>,这个提出来对吧,或者说把这个logo图片和退出都提出来,这个也有必要提出来,为啥呢,你想呢,将来咱们这个退出,不得做么,也是要做的,那你要做的话,每个页面上,都有退出对吧,你要提出来的话,是不是就改这一个地方就可以了,是这样吧,还有这个logo,你想啊,我们这个软件做好以后,给用户上线了,上线的时候,用户可能是要换logo对吧,他可能是要换,那所以呢,我们把这个logo呢,提出来以后,换的话,只换一个位置对吧,方便。
  • 所以呢,把这两段代码提出来啊,那我们在新建一个jsp啊,那么这个jsp啊,它也是被其他的jsp复用的啊,所以呢,我就在WEB-INF之下创建,你选择WEB-INF,右键new/File,因为呢,咱们所提取出来的是logo区的内容,所以呢,这个页面,我们叫logo.jsp,那然后呢,我们打开logo.jsp啊,先写上指令,<%@page pageEncoding="utf-8" %>,那么,写好指令以后啊,我们把那个其他的页面上,要复用的那段代码,粘贴过来,那么我从这个find.jsp里啊,把33行,34行,两行,复制一下粘贴过去,把它粘贴到呢,logo.jsp里啊,那么粘贴过来以后啊,我要加点东西,那么我想在退出之前显示用户名,对吧,所以我这块呢,我再这个换一行,在退出之前呢,我们加一个span,在span里显示用户名,那么为什么要在span里显示用户名呢,因为可能将来这个用户名,需要调整样式对吧,比如说加粗啊,什么字体,有什么颜色啊,有个元素好处理,那么为什么是span呢,因为它和退出,这个账号和退出和logo,是左右排列对吧,是吧,左右排列,所以别用这个块,用行内元素span。
  • 那么在span里呢,我想输出那个user,那想想我得怎么写,有两种办法啊,第一种啊,我们可以呢,直接写jsp脚本,在脚本里,我可以写啊,<%request.getCookies()%>,得到数组,遍历它,找到我想要的那个名为user的cookie,然后呢,在span这输出,明白吧,可以这样,但这样很麻烦啊,所以,一般不这么写,然后呢,说白了,咱们那种方式,就和那个演示的Servlet里写的一样,明白吧,就之前我们讲的IndexServlet,还是那个FindCostServlet,那里面的代码是一样的,然后呢,还有第2种办法,我们可以用el去获取cookie中的值,那大家想一下,这个el啊,它默认的取值范围,有几个,4个,分别是谁呢,page,然后呢,request,然后呢,session,然后呢,application,有没有cookie啊,没有啊,就el表达式呢,它默认不会从cookie中取值,它是从4个隐含对象中取值。
  • 那隐含对象一共有几个呢,9个,那分别是什么呢,背一下,你看,这个面试时很常见的一道面试题啊,回顾一下啊,有request对吧,response对吧,out,按顺序来啊,不然容易乱,然后是config,是这样么,然后呢,application,对吧,这5个了,然后呢,exception对吧,6个,然后呢,session对吧,7个,然后page和pagecontext,9个,那你看,这9个对象中有没有cookie,没有,那尽管说9个内置对象中,没有cookie,但是呢,el表达式,它依然可以,有能力从cookie中取值啊。我把这个,这句话写一下,就是说el表达式啊,它默认从4个隐含对象中取值,4个隐含对象分别是page,request,session和application,那el啊,它默认从4个隐含对象中取值,这4个隐含对象要记住,然后呢,它也有能力从cookie中取值,那么语法是这样的,cookie.name.value,就这个cookie的语法是固定的,就是cookie.name.value,其中呢,这个cookie固定,就写cookie,value固定就写value,而name是你要取的那个数据的名字,明白么,比如说,当前我们要取的那个数据的名字,叫user对吧,所以你得写cookie.user.value,明白吧,中间这个name,是要有所变化的,而cookie和value是固定的,写一下,我在这里写了<span>${cookie.user.value }</span>
  • 那写完以后,还没完,我们还得把logo.jsp引入到其他的页面上去,对吧,还没引入呢,对吧,那我们把它引入到资费查询,资费增加,还有资费修改的页面上去,那我们打开,先打开资费查询页面find.jsp啊。那么,你把这个33和34两行,删掉,不要了,换成这个include就可以了,<%@include file="../logo.jsp" %>

<!--Logo区域开始-->
<div id="header"><%@include file="../logo.jsp" %>
</div>
<!--Logo区域结束-->

  • 然后啊,我们把这句话呢,<%@include file="../logo.jsp" %>,复制一下,然后呢,把它粘帖到这个,再把它粘贴到那个add.jsp里啊,那么资费增加的那个页面上,那个logo在哪呢,看一下,60和61行对吧,你把60和61呢,这两句话删掉,换成include,<%@include file="../logo.jsp" %>,然后呢,你写了资费修改的话,你把资费修改页面也处理一下,我这没写,我就不处理了,那么处理完以后啊,咱们可测试了啊,把这个项目呢,再重新部署一下,然后呢,重启tomcat,启动以后啊,我试一下,我们先去登录啊,登录,localhost:8080/netctoss/toLogin.do,然后呢,我用这个caocao登录,登录以后呢,访问资费查询,有caocao啊,访问资费增加,也有caocao。
  • 那这个cookie啊,在项目中的使用,就这样了。我们已经用这个案例啊,模拟案例,把这个cookie的语法演示完了,再一个呢,我们也利用了cookie解决了项目中的问题,解决了我们这个经典的业务场景,那么在解决问题的时候啊,可能有人就有疑问了,解决问题时,你是先登录,然后的话,去访问查询,但是我发现呢,我不登录,直接查询是不是也可以,比如我们使用这个软件呢,本来是应该是先登录对吧,但如果我没登录,我直接敲,localhost:8080/netctoss/findCost.do,也能访问对吧,这就是bug。
  • 那当然了,这个问题呢,怎么解决呢,我们是要加以判断,我们应该啊,在这个用户啊,访问任何功能之前,判断他有没有登录,如果登录了,你可以继续访问,如果没登录应该拒绝对吧,应该把他一脚踢回到登录页面上,登录去,强制登录去,那么这件事呢,我们要做的方便,做的好的话,我们需要呢,学到后面那个filter,由filter解决才好,所以,这件事我们后面讲filter时会解决,明白吧,先别着急,现在如果没有filter,硬要解决的话,不是说不能解决,只不过很麻烦,明白吧,有filter会更方便,所以这个话题,我们后面再讲,先别着急。

Cookie在NetCTOSS中的应用代码实现

1.src/main/java/web/MainServlet.java

package web;import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;import dao.AdminDao;
import dao.CostDao;
import entity.Admin;
import entity.Cost;
import util.ImageUtil;public class MainServlet extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {//获取访问路径String path = req.getServletPath();//根据规范(图)处理路径if("/findCost.do".equals(path)) {findCost(req,res);} else if("/toAddCost.do".equals(path)) {toAddCost(req,res);} else if("/addCost.do".equals(path)){addCost(req,res);} else if("/toLogin.do".equals(path)){toLogin(req,res);} else if("/toIndex.do".equals(path)){toIndex(req,res);} else if("/login.do".equals(path)){login(req,res);} else {throw new RuntimeException("没有这个页面");}}//登录protected void login(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {//接收参数String adminCode = req.getParameter("adminCode");String password = req.getParameter("password");//验证 AdminDao dao = new AdminDao();Admin a = dao.findByCode(adminCode);if(a == null) {//帐号错误 req.setAttribute("error", "账号错误");req.getRequestDispatcher("WEB-INF/main/login.jsp").forward(req, res);} else if(!a.getPassword().equals(password)) {System.out.println(password);System.out.println(adminCode);//密码错误req.setAttribute("error", "密码错误");req.getRequestDispatcher("WEB-INF/main/login.jsp").forward(req, res);} else {//将账号存入cookieCookie cookie = new Cookie("user", adminCode);res.addCookie(cookie);//验证通过res.sendRedirect("toIndex.do");}}//打开登录页面protected void toLogin(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {req.getRequestDispatcher("WEB-INF/main/login.jsp").forward(req, res);}//打开主页protected void toIndex(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {req.getRequestDispatcher("WEB-INF/main/index.jsp").forward(req, res);}//查询资费protected void findCost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {//查询所有的资费CostDao dao = new CostDao();List<Cost> list = dao.findAll();//将请求转发到jspreq.setAttribute("costs", list);//当前:/netctoss/findCost.do//目标:/netctoss/WEB-INF/cost/find.jspreq.getRequestDispatcher("WEB-INF/cost/find.jsp").forward(req, res);}//打开增加资费protected void toAddCost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {req.getRequestDispatcher("WEB-INF/cost/add.jsp").forward(req, res);}//增加资费数据protected void addCost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {//接收传入的参数req.setCharacterEncoding("utf-8");String name = req.getParameter("name");String costType = req.getParameter("costType");String baseDuration = req.getParameter("baseDuration");String baseCost = req.getParameter("baseCost");String unitCost = req.getParameter("unitCost");String descr = req.getParameter("descr");//保存该数据Cost c = new Cost();c.setName(name);c.setCostType(costType);if(baseDuration != null && baseDuration.length()>0){c.setBaseDuration(Integer.valueOf(baseDuration));}if(baseCost != null && baseCost.length()>0) {c.setBaseCost(Double.valueOf(baseCost));}if(unitCost != null && unitCost.length()>0) {c.setUnitCost(Double.valueOf(unitCost));}c.setDescr(descr);CostDao dao = new CostDao();dao.save(c);//重定向到查询//当前:/netctoss/addCost.do//目标:/netctoss/findCost.dores.sendRedirect("findCost.do"); }
}

2.src/main/webapp/WEB-INF/logo.jsp

<%@page pageEncoding="utf-8" %>
<img src="data:images/logo.png" alt="logo" class="left"/>
<!-- EL默认从4个隐含对象中取值:page,request,session,application它也有能力从cookie中取值,语法:cookie.name.value -->
<span>${cookie.user.value }</span>
<a href="#">[退出]</a>

3.src/main/webapp/WEB-INF/cost/add.jsp

<%@page pageEncoding="utf-8" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><title>达内-NetCTOSS</title><link type="text/css" rel="stylesheet" media="all" href="styles/global.css" /><link type="text/css" rel="stylesheet" media="all" href="styles/global_color.css" /><script language="javascript" type="text/javascript">//保存结果的提示function showResult() {showResultDiv(true);window.setTimeout("showResultDiv(false);", 3000);}function showResultDiv(flag) {var divResult = document.getElementById("save_result_info");if (flag)divResult.style.display = "block";elsedivResult.style.display = "none";}//切换资费类型function feeTypeChange(type) {var inputArray = document.getElementById("main").getElementsByTagName("input");if (type == 1) {inputArray[4].readOnly = true;inputArray[4].value = "";inputArray[4].className += " readonly";inputArray[5].readOnly = false;inputArray[5].className = "width100";inputArray[6].readOnly = true;inputArray[6].className += " readonly";inputArray[6].value = "";}else if (type == 2) {inputArray[4].readOnly = false;inputArray[4].className = "width100";inputArray[5].readOnly = false;inputArray[5].className = "width100";inputArray[6].readOnly = false;inputArray[6].className = "width100";}else if (type == 3) {inputArray[4].readOnly = true;inputArray[4].value = "";inputArray[4].className += " readonly";inputArray[5].readOnly = true;inputArray[5].value = "";inputArray[5].className += " readonly";inputArray[6].readOnly = false;inputArray[6].className = "width100";}}</script></head><body><!--Logo区域开始--><div id="header"><%@include file="../logo.jsp" %>            </div><!--Logo区域结束--><!--导航区域开始--><div id="navi"><%@include file="../menu.jsp" %></div><!--导航区域结束--><!--主要区域开始--><div id="main">            <div id="save_result_info" class="save_fail">保存失败,资费名称重复!</div><form action="addCost.do" method="post" class="main_form"><div class="text_info clearfix"><span>资费名称:</span></div><div class="input_info"><input type="text" class="width300" name="name"/><span class="required">*</span><div class="validate_msg_short">50长度的字母、数字、汉字和下划线的组合</div></div><div class="text_info clearfix"><span>资费类型:</span></div><div class="input_info fee_type"><input type="radio" name="costType"  value="1"  id="monthly" onclick="feeTypeChange(1);" /><label for="monthly">包月</label><input type="radio" name="costType"  value="2"  checked="checked" id="package" onclick="feeTypeChange(2);" /><label for="package">套餐</label><input type="radio" name="costType"  value="3"   id="timeBased" onclick="feeTypeChange(3);" /><label for="timeBased">计时</label></div><div class="text_info clearfix"><span>基本时长:</span></div><div class="input_info"><input type="text" name="baseDuration" class="width100" /><span class="info">小时</span><span class="required">*</span><div class="validate_msg_long">1-600之间的整数</div></div><div class="text_info clearfix"><span>基本费用:</span></div><div class="input_info"><input type="text" name="baseCost" class="width100" /><span class="info">元</span><span class="required">*</span><div class="validate_msg_long error_msg">0-99999.99之间的数值</div></div><div class="text_info clearfix"><span>单位费用:</span></div><div class="input_info"><input type="text" name="unitCost" class="width100" /><span class="info">元/小时</span><span class="required">*</span><div class="validate_msg_long error_msg">0-99999.99之间的数值</div></div><div class="text_info clearfix"><span>资费说明:</span></div><div class="input_info_high"><textarea class="width300 height70" name="descr"></textarea><div class="validate_msg_short error_msg">100长度的字母、数字、汉字和下划线的组合</div></div>                    <div class="button_info clearfix"><input type="submit" value="保存" class="btn_save"  onclick="showResult();" /><input type="button" value="取消" class="btn_save"  onclick="history.back();"/></div></form>  </div><!--主要区域结束--><div id="footer"><span>[源自北美的技术,最优秀的师资,最真实的企业环境,最适用的实战项目]</span><br /><span>版权所有(C)加拿大达内IT培训集团公司 </span></div></body>
</html>

4.src/main/webapp/WEB-INF/cost/find.jsp

<%@page pageEncoding="utf-8" %>
<%@taglib uri="http://java.sun.com/jsp/jstl/core"  prefix="c"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><title>达内-NetCTOSS</title><link type="text/css" rel="stylesheet" media="all" href="styles/global.css" /><link type="text/css" rel="stylesheet" media="all" href="styles/global_color.css" /><script language="javascript" type="text/javascript">//排序按钮的点击事件function sort(btnObj) {if (btnObj.className == "sort_desc")btnObj.className = "sort_asc";elsebtnObj.className = "sort_desc";}//启用function startFee() {var r = window.confirm("确定要启用此资费吗?资费启用后将不能修改和删除。");document.getElementById("operate_result_info").style.display = "block";}//删除function deleteFee() {var r = window.confirm("确定要删除此资费吗?");document.getElementById("operate_result_info").style.display = "block";}</script>        </head><body><!--Logo区域开始--><div id="header"><%@include file="../logo.jsp" %>            </div><!--Logo区域结束--><!--导航区域开始--><div id="navi">                        <%@include file="../menu.jsp" %>  </div><!--导航区域结束--><!--主要区域开始--><div id="main"><form action="" method=""><!--排序--><div class="search_add"><div><!--<input type="button" value="月租" class="sort_asc" onclick="sort(this);" />--><input type="button" value="基费" class="sort_asc" onclick="sort(this);" /><input type="button" value="时长" class="sort_asc" onclick="sort(this);" /></div><!-- 当前:/netctoss/findCost.do目标:/netctoss/toAddCost.do--><input type="button" value="增加" class="btn_add" onclick="location.href='toAddCost.do';" /></div> <!--启用操作的操作提示--><div id="operate_result_info" class="operate_success"><img src="data:images/close.png" onclick="this.parentNode.style.display='none';" />删除成功!</div>    <!--数据区域:用表格展示数据-->     <div id="data">            <table id="datalist"><tr><th>资费ID</th><th class="width100">资费名称</th><th>基本时长</th><th>基本费用</th><th>单位费用</th><th>创建时间</th><th>开通时间</th><th class="width50">状态</th><th class="width200"></th></tr><c:forEach var="c" items="${costs }">                <tr><td>${c.costId }</td><td><a href="fee_detail.html">${c.name }</a></td><td>${c.baseDuration }</td><td>${c.baseCost }</td><td>${c.unitCost }</td><td>${c.creatime }</td><td>${c.startime }</td><td><c:if test="${c.status==0 }">开通</c:if><c:if test="${c.status==1 }">暂停</c:if></td><td>                                <input type="button" value="启用" class="btn_start" onclick="startFee();" /><input type="button" value="修改" class="btn_modify" onclick="location.href='fee_modi.html';" /><input type="button" value="删除" class="btn_delete" onclick="deleteFee();" /></td></tr></c:forEach></table><p>业务说明:<br />1、创建资费时,状态为暂停,记载创建时间;<br />2、暂停状态下,可修改,可删除;<br />3、开通后,记载开通时间,且开通后不能修改、不能再停用、也不能删除;<br />4、业务账号修改资费时,在下月底统一触发,修改其关联的资费ID(此触发动作由程序处理)</p></div><!--分页--><div id="pages"><a href="#">上一页</a><a href="#" class="current_page">1</a><a href="#">2</a><a href="#">3</a><a href="#">4</a><a href="#">5</a><a href="#">下一页</a></div></form></div><!--主要区域结束--><div id="footer"><p>[源自北美的技术,最优秀的师资,最真实的企业环境,最适用的实战项目]</p><p>版权所有(C)加拿大达内IT培训集团公司 </p></div></body>
</html>

JSP中关于page指令include属性引入jsp的路径问题

  • 然后呢,还有一个话题,还有一个问题啊,就是,我们在写这个jsp的时候,我在jsp上引入,什么logo.jsp,什么menu.jsp的时候,我们写了点点杠,点点杠表示说,向上跳一级对吧,相对路径,有的同学说,哎,你说这个地方的时候,怎么没有讲这个路径呢,那我们当前访问的是谁,目标又是谁,两者又是怎么相对的呢,那为啥就是点点杠呢,为啥就不是平级了呢,就这个话题,那我把这个路径也在说一下,就是include这个地方的路径,和其他的地方的路径,还有区别,区别是什么呢,在原则上没有区别,就是说这个,怎么说呢,基本原则不变,但是呢,我们所站的角度是不一样的,还是那句话,你想呢,看相对路径,你要找一个角度,我是以浏览器为角度,还是以服务器为角度。
  • 咱们一般呢,讲一些查询啊,增加等功能的时候呢,通常是以浏览器为角度,而这个地方恰恰是以服务器为角度,为啥呢,因为这件事是服务器干的,要想解释清楚这件事,还得回顾一下,之前我们所说的jsp的原理,它和那个是有关系的,所以你看啊,就是我所讲的这些内容啊,很多内容,其实就是在以前我们所讲的,最基本Servlet原理或者是jsp原理的过程中去阐述的啊。因此呢,之前的那些个原理,你要时常的回顾一下,这样的话,遇到问题,想一想那个原理,想一想那个过程,才能解释清楚,不然的话,就很容易就乱了,解释一下啊,为什么是这样的。
  • 那我们就以这个资费查询为例,比如说,浏览器要访问资费查询功能,那么访问这个资费查询功能,我们是点这个图标发出访问的,就是资费管理的图标,当然了,我们访问的,我们直接访问的是Servlet,然后呢,由Servlet转发了是吧,这里呢,我还需要呢,画出这个服务器的通信组件啊,要是没有这个通信组件呢,有的事还不太好说啊,不太好画,那么浏览器向服务器发请求,请求提交给了服务器的通信组件啊,它负责处理请求,然后呢,这个一些细节我就省略了,比如说它会创建request和response,对吧,这个我省略了,不说了,然后呢,它会调用,我们要访问的那个Servlet,访问是谁呢,MainSerlvet里边的findCost方法,是这样吧,它访问的是它,MainServlet.findCost(),调用它。
  • 调用它以后呢,那这个Servlet,查出数据,最终把数据转发给了jsp,对吧,它把数据转发给了这个find.jsp,完整路径我不写了,就是简单写啊,find.jsp,然后呢,那转发到这,这个服务器会调它对吧,会执行它,那服务器怎么执行这个jsp呢,jsp不能执行,它要执行的是它生成的那个Servlet,是吧,它是要翻译的,是吧,它是要调用jsp所对应的那个,翻译后的那个类,那翻译后的那个类啊,你到workspace下能找到啊,它的名字应该叫find_jsp.java,对吧,它是这样的一个规则,find_jsp.java,它调用的是这个,它中间呢,有一个翻译的过程,当然了,强调一下,不是每次都翻译,第一次翻译,以后的话,有的话,直接就过来了明白吧,直接就调用find_jsp.java了,总之呢,它会有一个翻译的过程。
  • 那你想啊,它翻译的时候,因为呢,咱们在这个find.jsp上写了include,那相当于这个jsp还包含另外的一部分对吧,它是不是得把那一部分也翻译了啊,也得一起翻译了,所以呢,在这个时候,服务器就需要找到,它所include的那个jsp,把它也一起翻译了啊,所以服务器呢,会去找,哎,它include的是谁呢,一看是,比如说是logo.jsp,所以,服务器呢,会去找这个jsp,然后呢,读取它的内容,把logo.jsp的内容呢,把它粘帖到find.jsp里,作为find.jsp的一部分,然后一起翻译,明白这意思吧,那么,你看啊,就是说logo.jsp,是什么时候,在什么时候被这个访问的,是在翻译的时候,当翻译时,那在翻译的时候,那么tomcat要找到,你所引入的那个jsp,把它的内容也一起翻译了,把它的内容作为find.jsp的一部分而翻译。
  • 所以呢,这个logo.jsp,我们找到它,是从哪找到它呢,是从find.jsplogo.jsp,而且呢,这件事是在翻译时干的,所以呢,是tomcat去访问logo.jsp的,明白吧,是tomcat去找的,所以呢,相对路径是写给谁呢,是写给tomcat,是写给服务器啊,所以呢,对于服务器来说啊,它就是两个文件啊,它存到哪去了呢,我要翻译,它俩存放的目录,你部署以后,它也差一级,对吧,所以,这个就不是看那个什么什么点do,那个东西了,这个就是看jsp存放的目录,这有点特别啊,尽量去体会一下,最终请求结束,大概是这么个过程。
  • 总而言之啊,就是说,一个页面上,它所引入的另外一个jsp,要被tomcat一起翻译,所以这个tomcat在翻译find.jsp的时候,需要找到这个logo.jsp,是从find.jsp这,找到logo.jsp这,是这两者的相对关系,find.jsplogo.jsp,那这两个jsp,确实存储的时候,差了一级,所以这个路径,你要想说起来的话,真的很麻烦,因为呢,有的时候,我们是以浏览器为这个角度,有的时候呢,是以服务器为角度,那具体是以谁为角度,我们要看,这是转发,还是重定向,还是include,还是什么,我们看这件事是谁干的,谁干的,就一般以谁为角度,这么来想问题。这是我们插入的一个话题啊,解释有一些同学的一些疑问啊,那这个,这是我们按着顺序来写,这算是第5个话题,就是说啊,include当中的相对路径。

写在后面

NETCTOSS代码实现第五版相关推荐

  1. NETCTOSS代码实现第八版

    NETCTOSS代码实现第八版:过滤器之登录检查功能与监听器 前言 模拟案例jsp6:演示过滤器的使用 过滤器模拟案例需求分析与设计以及代码分析 模拟资费增加和资费查询功能组件:AddCostServ ...

  2. NETCTOSS代码实现第六版

    NETCTOSS代码实现第六版:Session的原理与应用 前言 Session的原理与应用 模拟Session应用案例需求分析:Session的运行原理 模拟Session应用案例代码分析:Sess ...

  3. 开发人员必备:微软发布示例代码浏览器 (Sample Browser) 第五版,让您尽享3500个示例代码...

    今天早上,微软一站式示例代码库 携手MSDN和微软创新空间 正式发布了示例代码浏览器(Sample Browser)第五版.这是继去年10月第四版发布以来的一次重大升级.有了它,3500多高质量示例代 ...

  4. 谭浩强C程序设计第五版课后答案视频+代码讲解完整版(合集)持续跟新中~~~

    这里是一个谭浩强C程序设计第五版课后答案的合集 请看下面: 工欲善其事必先利其器 写C语言代码,首先得有安装一个趁手的工具,那么VS系列是最合适不过的了 这里是安装教程: VS2013安装教程和使用 ...

  5. C++ Primer 第五版 第6章——函数阅读笔记及习题答案(完整,附C++代码)

    C++Primer(第五版)第6章函数的阅读笔记及课后习题答案总结,课后习题答案是自己学习写出来的,如果有误,欢迎指正 还不完整,后续会更新添加 阅读笔记 C++ Primer 第五版 第6章 6.1 ...

  6. 书籍记录——C++大学基础教程(第五版)

    C++大学基础教程(第五版) Small C++ How to Program,Fifth Edition,H.M.Deitel,P.J.Deitel 第一章 计算机.互联网和万维网简介 第二章 C+ ...

  7. 《C++ Primer 第五版》(第6.3~6.7节)——返回指向数组/函数的指针,函数重载,默认形参、inline函数和constexpr函数

    1.返回指向数组/函数的指针 顾名思义,就是函数返回值为指向数组/函数的指针. 数组的性质:不能被拷贝,函数也不能返回数组.但可以返回数组指针/引用,声明一个返回数组指针的函数,有四种方式,一种是直接 ...

  8. 《C++ Primer 第五版》(第4.11节类型转换) ————关于无符号数和有符号数的运算探究

    1.关于无符号数和有符号数的运算 关于无符号数和有符号数的运算,在我看来一直是觉得只要有无符号数和有符号数的运算,有符号数就转化为无符号数,但是在<C++ Primer 第五版>的p142 ...

  9. 计算机科学导论第五版_五月份将开始提供438项免费在线编程和计算机科学课程

    计算机科学导论第五版 Five years ago, universities like MIT and Stanford first opened up free online courses to ...

最新文章

  1. 原生JS修改html内容不影响绑定的点击事件 请认准insertAdjacentHTML、insertAdjacentText方法
  2. 微型计算机原理 考试试题,微机原理期末考试试卷(有答案)
  3. 人工智能 信道估计 深度学习_DEMO演示|基于IVP02D 人工智能工作站的深度学习引擎,实现人群热力估计...
  4. [html] 如何给table中的某一列设置固定宽度
  5. SpringMVC学习--参数绑定
  6. SCCM 2012 R2---安装客户端代理软件
  7. python课程_大整理!程序员最爱的13个免费Python课程
  8. Revit2018下载和安装教程
  9. Nokia最新PC套件下载 Nokia PC Suite 6.86.9.0 手机型号和PC套件对应表最新7.1
  10. python列表获取最后一项_如何在Python中获取列表的最后一项?
  11. 迄今见过最好的职业规划的文章
  12. 3 MyBatis动态SQL
  13. React中useMemo函数【调优的不二选则】的使用及一看就会的案例(个人觉得很详细了,而且包含了很多知识点呀)
  14. 视频可以裁剪尺寸吗?教你裁剪尺寸的小妙招
  15. 网页中加入最新款百度天气预报样式代码
  16. 安装 CentOS Ubuntu
  17. 学习英语的电影推荐!
  18. 开学!可怕的日本,无情到令人感到恐惧!
  19. 产品经理的职责-----产品经理深入浅出课程
  20. java(JDK)环境安装步骤以及环境变量配置

热门文章

  1. VisualStudio 调试时会不断刷新 WPF 应用渲染
  2. 同一个controller中同一个service不同的方法调用怎么有的会为null
  3. Mysql5.1 , Mysql5.5, Mysql5.7, Mysql8.0各个版本性能对比
  4. 大一上计算机导论期末试题及答案,大一计算机导论试题
  5. 培训机构炒出来的Unity就业没问题吗
  6. jersey number什么意思_Jersey是什么布料?
  7. VK2C22A替代16C22,是段码低功耗LCD液晶显示驱动芯片/段码液晶驱动IC,44SEG*4COM/40*4,高抗干扰.稳定性强
  8. 计算机开机右下角无显示桌面,电脑开机后不显示桌面的原因
  9. Go语言学习笔记之基础语法(一)
  10. 在太平洋人寿保险公司工作好不好?