NETCTOSS代码实现第四版

前言

对资费和登录模块的一些问题优化

1.完善登录功能账号密码默认值的显示问题

  • 然后啊,做这个登录功能,做完以后呢,其实登录功能还有一些细节,还要在处理一下啊,另外呢,登录以后,这个,还有一些地方也要处理一下,就这个功能,还有待于完善,所以下面呢,我们先把这个登录功能,完善一下,那你看啊,现在我这个登录功能啊,有什么需要完善的地方啊,演示一下,我先访问这个,localhost:8080/netctoss/toLogin.do,我打开了登录页面啊,然后我要去登录啊,当然,我们现在呢,先没有管这个验证码,只有账号密码,那比如说,我输入一个错误的帐号,错误的密码,一登录,它当然提示我账号错了,这个逻辑,那问题是什么呢,账号密码没了对吧,我们上网时呢,网站也不会这么干,它一般提示错了,账号密码还会保留住对吧,所以我们想一想,我们怎么去把这个账号密码给它留住,而不是没了。想想这个话题。
  • 那我们想这个话题啊,首先得想一下,这帐号密码,它为什么就没了呢,你看为啥就没了,看昨天我画的这个,登录功能的这个图,就我登录的时候,我登录的时候,第2次请求对吧,/login.do,传入了账号密码,MainServlet.login()这,接收了账号密码,那如果错误的时候,有人说重定向,那注意,错误的时候走这来了,这转发对吧,转发到/WEB-INF/main/login.jsp,和/toLogin.do无关了对吧,是这意思吧,这转发了,转发到/WEB-INF/main/login.jsp以后,jsp向浏览器输出了一个新的网页,对吧,把它原来的内容覆盖了,而这个输出的新的网页里,那个账号密码,有默认值么,所以是空的,页面刷新了对吧,被刷了。
    在这里插入图片描述
  • 那你想啊,我想啊,就是,走转发到login.jsp,这一条线的时候,让这个网页上,账号密码框里有默认值,怎么办, value="${}",那你想让框有默认值,那很显然,你是不是得写上value啊,是这样吧,所以,我们在写这个jsp的时候,我们还得在那个账号密码的那个框上,写上value等于什么什么,而这个值又不能写死,不能写死的话,你得写什么啊,el表达式,value="${}",是这样吧。那你看,我要写el表达式, 我要取值啊,这个值我从哪里取,从MainServlet.login()这取,因为这个Servlet,它已经得到了账号密码对吧,那转发时,不单单是传error,也把账号密码传过来,我就能取,是这意思吧,可以这样。
  • 还有别的办法么,想想还有别的办法么,就这样是可以的,有人说想想还有别的办法么,从何想起了,不知道,我给你提示一下啊,咱们从这个el表达式,它的作用开始想起,你回顾一下,el表达式,它有几种功能,几个作用,说个数是几,3,那第一个是什么,第一个功能是什么,访问bean属性,对吧,获取bean属性,这没问题;第2个呢,可以运算,是吧;然后呢,第3个呢,有人说,可以访问地址栏url,这个过于具体了,你能不能把它再,那叫什么,地址栏参数,那我用post请求,地址栏没有参数,它取的到么,这还是有点片面,意思你是记住了,这个得怎么说呢,是获取请求的参数,别管是get请求,还是post,只要浏览器给服务器传的参,这个参数我们用el,能直接获取,明白吧,讲过吧,好像没有发生这件事一样。
  • 这讲过啊,你自己复习一下,回顾一下,就是说el的3个功能,第一个获取bean属性,是吧,咱们反复用啊,所以大家都熟悉了,第二个,能运算,运算的话,咱们用没用过,在这个项目中,好像没有啊,然后第3个取请求参数,就用的更省对吧,请求参数,那你想啊,我们点do的时候,不是传了参么对吧,传了账号密码,那我是不是Servlet不用去向它去转发这个账号密码,我直接就从请求里取到对吧,你就直接去取请求参数就可以了,这样我少写两句话,转发少写什么request点set,为啥不用写了,你想啊,咱们这个请求的参数,它通过什么传给了Servlet,就通过request,就request里面本来就有这俩参数,你在MainServlet.login(),在这里面再设置一遍,重复了,明白吧,没有必要,所以,那el,如果说,想取请求参数,它得怎么写呢,它得这样写,当时我们写的是param.user是这样吧,那现在不叫user,叫什么呢,咱传的参不叫adminCode么,value="${param.adminCode}",是这样么。所以,你就这样写就行了,value="${param.adminCode}",就是,我直接从这个请求参数里得到这个数据,就可以了啊,不用那么费劲啊,就这样。
  • 那同理呢,密码也是这样,那大概了解以后,咱们就试一下啊,看行不行。打开你的这个开发工具啊,然后呢,我们打开这个login.jsp,打开以后,我们找到这个,账号密码的那两个框,我的账号啊,是在16行啊,input,那么如果呢,我想给它一个默认值,我需要在这个框上写上value对吧,我就写了,16行啊,value,按照刚才所说的,写个el表达式,然后写上param.adminCode<td colspan="2"><input name="adminCode" value="${param.adminCode }" type="text" class="width150" /></td>,然后呢,还有密码啊,密码是21行,也是类似的写法,<td colspan="2"><input name="password" value="${param.password }" type="password" class="width150" /></td>,那么写完以后啊,咱们可以测试一下。
  • 我打开这个浏览器,打开浏览器以后啊,我们登录的时候呢,首先要访问的是什么呢,是toLogin.do,而不是/login.do/login.do是要传账号密码,是检查的对吧 ,是/toLogin.do,那有同学可能会想啊,说那你怎限制用户说,他不会访问/login.do呢,他一定会先访问,/toLogin.do呢,是这样的,我们实际做完这个项目以后,系统用上线的时候,我们会把这个路径,就是IP地址,端口号,localhost/toLogin.do,这个路径和某一个网址相绑定,比如说taobao.com,我们访问taobao.com,它直接打开的是类似这个路径toLogin.do,明白吧,打开登录页面,而不是login.do,这是通过这个来解决的。
  • 那万一说,有的人知道了这个网站,它的一些个真实的路径,知道了IP地址,知道了端口号,知道了它真实的路径,去敲怎么办呢,那我们可以呢,进行一些检查,一些这个登录检查,那这个检查呢,我们后面讲filter时会讲啊,总之呢,这些问题是可以解决的,但是呢,别着急,现在的话呢,还没到那一刻啊。那我打开了登录页面以后啊,多刷几遍啊,因为你改了内容,有可能呢,这个浏览器有缓存,它可能没有生效,所以一般多刷几遍比较合适,然后呢,我就填数据了,我填这个账号,瞎填一个啊,账号密码,点登录,它提示我,账号错了,但是账号密码还在,我就继续填了,比如说,填个正确账号,错误密码,登录,它提示我密码错了,然后呢,再改,都改对了,哎就成功了。
  • 经过测试啊,是ok的啊,然后呢,还有一个小问题,就是说,你看,我现在呢,是在这个账号密码的框上写了value,给了它默认值,那为什么,我第一次打开登录页面时,我访问/toLogin.do的时候,这个没有默认值呢,就我访问/toLogin.do时,首次打开这个网页时,为啥没有默认值呢,因为你这个请求,/toLogin.do,传值了么,没传值,没传值的话,我们这个数据得不到对吧,就el还有一个好处是什么呢,它很多时候啊,它得不到数据,它不会给你写个null进去,明白吧,不会显示成null,它会呢,空串,空的,看不到啊,所以没有影响啊。那这是咱们关于这个,这个登录啊,第一个完善的地方,就是,主要是处理这个账号密码默认值的显示,我在这里呢,写一下啊,完善登录功能。
代码实现:src/main/webapp/WEB-INF/main/login.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" /> 
    </head>
    <body class="index">
        <div class="login_box">
	        <form action="login.do" method="post">
	            <table>
	                <tr>
	                    <td class="login_info">账号:</td>
	                    <td colspan="2"><input name="adminCode" value="${param.adminCode }"  type="text" class="width150" /></td>
	                    <td class="login_error_info"><span class="required">30长度的字母、数字和下划线</span></td>
	                </tr>
	                <tr>
	                    <td class="login_info">密码:</td>
	                    <td colspan="2"><input name="password"  value="${param.password }"  type="password" class="width150" /></td>
	                    <td><span class="required">30长度的字母、数字和下划线</span></td>
	                </tr>
	                <tr>
	                    <td class="login_info">验证码:</td>
	                    <td class="width70"><input name="" type="text" class="width70" /></td>
	                    <td><img src="images/valicode.jpg" alt="验证码" title="点击更换" /></td>  
	                    <td><span class="required">验证码错误</span></td>              
	                </tr>            
	                <tr>
	                    <td></td>
	                    <td class="login_button" colspan="2">
	                        <a href="javascript:document.forms[0].submit();"><img src="images/login_btn.png" /></a>
	                    </td>    
	                    <td><span class="required">${error }</span></td>    
	                </tr>
	            </table>
	        </form>
        </div>
    </body>
</html>

2.公共页面菜单栏图标问题优化

  • 那么,还没完,还有欠缺的地方啊。你看,比如说啊,我去登录啊,我用caocao登录啊,登录成功以后,我就进到主页了,那么主页上呢,是一排图标,这个图标应该是可以点对吧,我们平时用软件,不可能说,老敲路径,是可以点的啊,但目前呢,还点不了,点不了原因是什么呢,这个图标上的路径不对,是吧,是要改,所以下面我们探讨一下,这个路径怎么改,当然有人可能会想,那就改呗,你找到这个网页,对吧,把那个超链接,图标上面的超链接,你就改下路径就完了么,但是你要注意,我们改的话呢,还要考虑,这么一情况,什么情况呢,你看,我用这个demo来说啊,咱们这个主页上,有这10个图标,都能点,然后,资费管理模块,查询上,也有10个图标,是不是也能点,增加上也有图标,也能点,修改上,也能点。
  • 同理,其他模块,比如说账务账号啊,业务账号啊,账单啊,报表啊,角色啊,管理员啊,等等,那每一个模块的,它的查询啊,增加啊, 修改等功能,是不是都有这个图标啊,都能点,说白了,我们这项目当中呢,几乎每一个页面上,都有这一排图标,都能点,那我们第一种办法是,我每个网页都改一遍,设置一遍,可以吧,可以,但是很麻烦,得设置好多次啊,而且呢,万一说将来说这个路径要改,或者说我现在要加个图标,你就得挨个网页再重新处理一遍对吧,就很麻烦了。如果说我们要做个小项目还好,我们要做个大项目的话,这个功能,可能是上百个,模块,几十个上百个,那么页面,可能有几百个,上千个,都这样去改的话,太费劲了,所以呢,实际工作时 啊,一定得事先把它简化一下,最好是什么呢,最好是让这排图标呢,能把它提取出来能够复用对吧,是吧,所有网页可以复用就好了。
  • 那想一想啊,咱们能不能想办法把这个图标,把它拿出来,被其他的各个网页所复用呢,有没有什么办法呢,嗯,配置文件啊,这具体怎么配,xml啊,就是我xml声明了,声明说有多少功能,每个功能是什么图片,然后呢,这个链接链到哪去,然后这里去搞定对吧,这可以ok的,可以啊。但是什么呢,那你需要写一段代码,肯定得写段,还不只是js,还得写java,用java代码读xml得到一些信息给浏览器返回,浏览器还得通过js去创建这些图片,把它摆到这来,对吧,那这个逻辑的话,这个逻辑,最好也写一遍,也不能每个jsp都写一遍,你想想是不是这样,对吧,你写这个逻辑也得复用,那这个逻辑最终的话,在浏览器上,得通过js去实现,创建这图标,那这段逻辑也要复用,那这个逻辑怎么复用呢,其实还是没有,就这个怎么说呢,还是没有解决这个问题啊,这个想法是挺好的,还差点事,想想。
  • 这件事以前讲过的,不是说凭空捏造的,你想一想啊,又无从想起了,是吧,提示一下,这件事我们在什么时候讲的呢,就在我们讲jsp时讲的,有一个内容,能解决这个问题,有个指令,那指令叫啥,include,哎,你终于想到了,想的真对,是吧,你的感慨没白发,确实是对的,你想啊,咱们讲jsp时,我们先讲啊,jsp的,就什么是jsp对吧,然后讲了jsp的基本语法,jsp怎去写标签,怎么去写java代码对吧,说完这些基本语法以后,我们讲了指令,page指令,pageEncoding怎么回事,对吧,什么import,什么那个contentType,怎么回事,然后,还讲了一个指令叫include,当时呢,我们是写了一个time.jsp,我将time.jsp引入到了hello.jsp里对吧,是这意思吧。
  • 当时我举的场景就说了,说你看啊,将来我们工作时啊,我们可能有很多网页,有可能每个网页的顶部,都要显示这个时间对吧,最好是能复用,怎么复用呢,单独写一个jsp,include对吧,就解决问题,是吧,我还是带着业务场景跟你说的,而且将来我们做项目时还会用,就会用这个东西啊,所以到这就用了,但是到这你就忘了,所以呢,大家这个你学习的时候啊,复习这个知识点能解决什么问题,这一点至关重要啊,你了解这一点,才能够使得将来你,能不能想起来用它,如果这一点没有了解的话,就像现在一样,你可能想不出来怎么用它,这个就比较尴尬了,你工作时也是这种状态,所以呢,复习的时候啊,一定要全面,不要只是说写代码,写完代码后,立刻就over了,不是这样啊,好好想一想,背后的逻辑,多花点心思啊。
  • 所以呢,这个可以复用,我们可以单独写一个jsp,我们就把那个图标,放到那个jsp里对吧 ,然后呢,include,把这个jsp,include到其他的页面上,就可以了,是这样吧,然后呢,将来有所变化的时候,我们只是维护,那个独立的jsp对吧,就可以了,其他的jsp不用,不用改啊。那咱们处理一下啊,处理一下,大家呢,打开你的这个eclipse,那么,我们展开呢,webapp这个目录,你看啊,我展开了/webapp/WEB-INF,然后呢,现在我要新写一个jsp,专门放这个图标,那你说这个jsp,我放到哪比较好,我放到cost下合适么,不合适,因为它不只是给资费模块用对吧,其他模块也用,我放到main下呢,也不合适,因为这个jsp是给所有模块复用的,对吧,它是给所有模块复用的,那每一个目录是一个模块,所以,我干脆呢,就在/WEB-INF之下建这个网页,可以吧,就是说,我们在写项目时,一个文件的名字,和它所放的位置,就能够决定,或者说,能够给人传递一定信息,这个文件是什么作用,它的作用的范围是怎么样啊,是要合理啊。
  • 那我在/WEB-INF之下呢,创建一个jsp啊,new一个file叫什什么点jsp,那么这排图标啊,它是功能对吧,是菜单啊,我们就叫menu吧,menu.jsp。
    在这里插入图片描述
  • 你看在这了啊,创建完以后,那menu.jsp,首先,得写一个指令,声明编码对吧,写好page指令,<%@page pageEncoding="utf-8"%>,那么写完这句话以后,我要把那10个图标呢,写到这个位置来,那大家想一下,这个menu.jsp,我们需要把整个网页的结构,写的很完整么,不需要,因为咱们之前,写time.jsp也是那么干的对吧,那么这个jsp啊,它不是单独去访问的,它是被其他的网页,所引用的对吧,它是其他网页的一部分,不用写完整,写出一部分就好,那那个图标的一部分呢,是怎么写的呢,我们随便打开一个网页参考一下,你比如说,这个main下面的index.jsp里,不就有么对吧,我可以打开index.jsp,去找一下啊。
  • 我打开了index.jsp,我发现啊,在它的13行,有一个ul,这个ul就是那排图标对吧,咱们以前写那个css时,不也是用列表做的么,对吧,是要把它复用,所以我干脆呢,就把这个13到24行,这个ul,复制一下,copy完以后啊,我把这个ul呢,粘贴到menu.jsp之内,粘贴过来,粘贴过来以后啊,这个有点,缩进有点大啊,往左串串,shift+tap,快捷键,然后你看,可以吧,行吧,然后你看啊,这个 ,每一个li之内,有超链接,这个超链接,它里面的路径,目前对我们来说,都是错的对吧,因为我们现在做的是jsp,不是html了,所以,我们需要把这个路径呢,全给它删了,反正都是错的,不要了啊,都删掉了。然后呢,哪个模块有,我们就把哪个模块再加上,把这,应该是10个啊,10个这个超链接里面的啊,这个错误的路经都去掉啊,去掉以后呢,每做一个模块,我们把这模块的路径写好,那目前我们做了哪些模块呢,主要就是这个fee,对吧,就资费,当然还有一个,还有什么呢,主页index.jsp,是吧,主页也可以。
  • 那我们把这个主页,还有这个资费,这俩路径也写好,那我要写了啊,先写主页,怎么写呢,这个路径该怎么写,就我们现在呢,做了这些功能,你对路径应也有所领悟了,想一想这怎么写,斜杠,然后呢,没有斜杠,直接写啥,main/index.jsp啊,斜杠main,然后呢,就是,你心里还想着,是要直接访问jsp的同学,这个得反省一下,我就以前讲MVC时啊,我不止一次啊,反复强调过,那我们在这个MVC,这个项目结构之内,浏览器访问服务器,访问的永远都是Servlet是吧,永远都是Servlet处理这个请求,它负责处理java相关的逻辑,对吧,把结果给jsp,你永远都不要直接访问jsp,而且你看啊,你现在直接访问jsp,你能访问到么,有没有人试过,直接访问jsp能访问到么,访问不到,它都被WEB-INF保护起来了对吧,就访问不了了。
  • 所以,你访问的是谁呢,toIndex.do,那这块怎么写呢,就直接写toIndex.do么,还是说,得怎么办呢,直接写,为啥啊,有人说,因为它和其他的功能是平级,是吧,怎么怎么样,那你这样想啊,就是说,我们以前啊,在详细分析这个相对路径的时候,那你这样写是相对路径吧,是吧,我们在分析相对路径的时候,我一般都会列举一下,我要的目标是什么,目标现在很明确了,目标不就是主页么,对吧,toIndex.do,这个没错,来源呢,我是从哪去访问主页呢,我是在哪点这个图标访问主页呢,在哪啊,在浏览器,不是,在哪个页面上,有的人现在都乱了,我们现在写的这个menu.jsp,它将来会替换掉每个页面上的这块图标,对吧,所以,我是不是在任何页面的,这个图标上都能点,你看,我在资费查询上,能不能点这个东西,我在资费增加上能点么,包括角色管理,管理员,账务账号,业务账号,我在任何的页面上,其实都能点这个图标,所以这个来源,是不是不是很明确,你是不是无法确定,是这样吧,来源无法确定的时候,我们应该写什么路径呢,绝对路径,因为你相对,没有相对的条件,啊。
  • 当然了,如果有人就直接写/toIndex.do,在我们当前的场景下,也对,这是碰巧了,因为,我们项目比较简单,我们所有路径都是平级,明白么,是凑巧了,那我们工作时,很有可能不同模块,路径不同,比如说,这个功能,两级路径,那个功能3级路径,明白吧,它可能很有层次,有差别的,听明白了么,就是,我们实际,将来工作时,项目复杂了,那么,它这个路径可能是,不止一级,有的一级有的两级,有的3级明白吧,会有很多不同的情况,所以,如果说你直接就那么写了,就会有问题,我们这个项目,你要直接写的话,toIndex.do也没问题,是凑巧了,明白吧,但这个正常的,正确的解决方式,是写绝对路径。
  • 这块我写一下,就是说,该jsp被其他很多jsp所引用,那么,即在很多网页上,都可能点击如下的任何图标,所以,无法事先确定请求的来源啊,适合写绝对路径,咱们以前呢,一般呢,写的都是这个相对路径,基本上是这样,我们能写相对路径呢,尽量写相对路径,这块就不太合适了,这块就必须得写绝对路径了啊,那绝对路径啊,它的这个书写方式是固定的啊,有固定的这个格式,什么格式呢,就是,它必须以斜线开头,然后呢,直接写项目名,然后呢,往后接着写就可以了,就是以斜线,项目名开始写啊,/netctoss/toIndex.do,即<li><a href="/netctoss/toIndex.do" class="index_on"></a></li>,那首页,现在路径能写啊,这个资费也可以写,因为资费模块也做过了啊,那我们点这个图标呢,应该是访问资费查询对吧,所以这里写的是资费查询的路径啊,/netctoss/findCost.do,即<li><a href="/netctoss/findCost.do" class="fee_off"></a></li>
  • 那么这个menu.jsp啊,我们把它就弄好了啊,就这么点东西,然后呢,下面我们需要把menu.jsp,引入到其他的jsp上去,包括主页啊,包括资费查询啊,增加啊,修改等等,那咱们挨个处理啊,我先处理这个主页index.jsp,那么index.jsp呢,原先13到24行有列表,这列表是不是不要了啊,删了,13到24行啊,把它删了,删掉以后呢,我们替换的是什么呢,include,<%@include file="../menu.jsp" %>,同理啊,其他的页面上,也需要写一句,这句话啊,我把这句话呢,复制一下,然后呢,粘贴过去,下面呢,我再打开谁呢,我再打开这个资费模块的增加啊,查询等页面,这样,我先处理这个查询吧,那么资费查询页面上find.jsp,这个列表是在39行,39到50行,把它删了,替换成include,然后呢,资费增加啊,add.jspadd.jsp里啊,我们找到这个列表的位置,增加页面上呢,这个列表是在66行啊,也把它删了,替换成include,<%@include file="../menu.jsp" %>
  • 那么,如果呢,你做了修改的话,那么,修改的页面上,也替换啊,那修改的话呢,也是66行,那么,这几个jsp啊,我们把这句话,<%@include file="../menu.jsp" %>,都把它替换好以后,就可以测了,看一下,这样行不行啊 ,测试那我需要呢,把这个项目,就是重新部署一下,然后重启一下,重启以后呢,我先登录啊,/toLogin.do,然后呢 ,账号caocao,密码123,登录,登录进来以后呢,你点那个图标啊,看能不能点,点一下,可以过来,点主页没问题,你在增加啊,修改页面上,去点这个图标也可以。
代码实现:src/main/webapp/WEB-INF/menu.jsp
<%@page pageEncoding="utf-8"%>
<!-- 
	该jsp被其他很多jsp所引用,即在很多
	网页上都可能点击如下的任何图标,故
	无法事先确定请求的来源,适合写绝对路径。	
 -->
<ul id="menu">
    <li><a href="/netctoss/toIndex.do" class="index_on"></a></li>
    <li><a href="" class="role_off"></a></li>
    <li><a href="" class="admin_off"></a></li>
    <li><a href="/netctoss/findCost.do" class="fee_off"></a></li>
    <li><a href="" class="account_off"></a></li>
    <li><a href="" class="service_off"></a></li>
    <li><a href="" class="bill_off"></a></li>
    <li><a href="" class="report_off"></a></li>
    <li><a href="" class="information_off"></a></li>
    <li><a href="" class="password_off"></a></li>
</ul>
代码实现:src/main/webapp/WEB-INFO/main/index.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" /> 
    </head>
    <body class="index">
        <!--导航区域开始-->
        <div id="index_navi">
			<%@include file="../menu.jsp" %>
        </div>
    </body>
</html>
代码实现:src/main/webapp/WEB-INF/cost/find.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 sort(btnObj) {
                if (btnObj.className == "sort_desc")
                    btnObj.className = "sort_asc";
                else
                    btnObj.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">
            <img src="images/logo.png" alt="logo" class="left"/>
            <a href="#">[退出]</a>            
        </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>
                    <input type="button" value="增加" class="btn_add" onclick="location.href='fee_add.html';" />
                </div> 
                <!--启用操作的操作提示-->
                <div id="operate_result_info" class="operate_success">
                    <img src="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>
代码实现:src/main/webapp/WEB-INFO/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";
                else
                    divResult.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">
            <img src="../images/logo.png" alt="logo" class="left"/>
            <a href="#">[退出]</a>            
        </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>
  • 这个项目啊,现在做的也差不多了,告一段落了,那么,时间原因,还有其他的功能没有做,但是呢,把这一个模块,比如说资费 模块,把这个登录模块,把它做明白了,那么再有其他的模块呢,也大同小异啊,当然,可能其它的模块呢,也会有一些元素啊,有一些内容,比这个模块呢,略难一点,但这个某块是基础,反正你做10个模块,也基本上是这个套路啊,所以我们就是,想讲清楚啊,就是做项目的这个套路。

3.异常处理问题优化

  • 那下面主要说几个新的知识点,通过这些新内容再对进行一些完善,下面,主要讲什么呢,主要讲4个对象啊,一个对象叫cookie,一个对象叫session,一个对象叫filter,一个对象叫Listener,那这4个对象呢,它都不是解决咱们项目中,就是很常规的需求,增删改查等等不是,它解决的是呢,我们这个项目中啊,一些,具有共性的一些问题,或者说一些个高级的地方,所以呢, 是做一个补充的,那这个补充的内容,我们要,也要多理解啊,因为面试时呢,可能面试官,特别愿意问这些,这样的内容。再一个呢,那每一个内容讲完以后,就会利用这个内容,解决当前我们电信计费项目中的一些问题,会有所演示,所以呢,后面这些是我们对,这段课程的一段补充,是一个扩展,是一个高级的东西,然后呢,也会在项目中演示,进一步完善这个项目。
  • 那我们先不着急讲这4个对象,先说这两个内容,一个是异常处理,一个是路径的问题,那么路径的问题呢,不会再单独说了,因为我在项目时反复强调过路径对吧,在此之前也讲过部署,也讲过路径,项目中又讲过了,也结合着什么WEB-INF,讲讲它的作用,所以路径问题在项目中,相当于讲过了,如果你还有什么疑问的话,还是要去回顾,这个路径呢,就过去啊。还差一个内容是异常的处理,那咱们在这个开发项目时,比如说写dao的时候,很有可能呢,就会这个有问题,会抛一异常的,当然了,我们调用一个方法,我们会对它try-catch啊,当我们catch到异常以后呢,我们需要处理,通常处理不了,往上抛对吧,那这个异常抛去抛来,最终抛给了谁,怎么办呢,最终怎么处理,由谁处理呢,最终是由tomcat处理,为什么最终由tomcat处理呢,其实也比较容易理解啊,咱们看一下以往的一个图吧,随便找个图看一下啊。
    在这里插入图片描述
  • 就比如说,我们就以这个资费查询,这个功能为例啊,那么我们是在浏览器端啊,点了这个链接啊,/findCost.do,访问了服务器,那这个请求呢,提交给了服务器,那服务器端的这一些流程,这套逻辑,它都是由tomcat去调的的,对吧,是吧,服务器端的逻辑,服务器端程序的入口是这个Servlet,而Servlet是由tomcat调用的,而jsp也是由tomcat调用的,所以呢无论呢是Servlet这里出了异常,还是jsp这,还是实体类,Dao,DBUtil,db.properties,无论是哪有错误,都会往上抛,比如说DBUtil有问题,往上抛给CostDao对吧,CostDao有问题,又抛给Servlet,那Servlet有问题,再往上抛,抛给谁呢,抛给了调用者,我们往上抛,是抛给我们调用者,那服务器端的,它的程序最终,最初是谁调用的呢,tomcat,是这样吧,tomcat调了这个Servlet,所以最终呢,无论是哪发生了异常,往上抛抛抛,抛来抛去,都抛到Servlet这来,或者是jsp这来,然后呢,这两个组件最终会抛给tomcat,因此呢,tomcat就有这个,统一处理所有异常的这个,这么一个基础啊,那它也可以统一处理所有异常,其实它已经处理了。
  • 那tomcat是怎么处理的呢,咱们就,随便简单说一下啊,去理解一下,tomcat呢,它在调这个Servlet时啊,它是这样调的,它基本上是这样调的,它也是try,比如说new,某一个Servlet啊,然后呢,调它的service方法,它这样调了,然后呢,catch所有异常,那如果catch到异常,那怎么办呢,它已经处理了,它会判断啊,如果说这个,这个是我们的代码,出了问题,它就直接呢,就request.getRequestDispatcher("404"),其实也不能这么说啊,就这么说吧,它底层是这么处理的,大概是这样处理的啊,500.html, 然后呢,点 forward啊,request.getRequestDispatcher("500.html").forward();,所以tomcat底层呢,它是做了一些处理的:

try{
	new Servlet().service();
}catch(Exception e){
	request.getRequestDispatcher("500.html").forward();
}

  • 如果说,它发现我们的程序中有问题,它捕捉到这个异常以后,它直接将请求转发到了500的那个错误页面明白吧,当然了,这个错误页面呢,是tomcat内部的,它是动态拼的也好,还是写死的也好,不确定,反正是有这么个东西,它是转发到这来了,当然了,如果说呢,它在处理请求时,它早先呢,还会处理请求,如果它发现请求有问题,它就会转发到404,明白吧,它是这样处理的,所以,tomcat底层,它已经对异常做了处理,我们看到的404,500,各种网页,错误页面,就是它处理的结果。
  • 当然了,我们在工作时啊,如果说,我们就让用户看到404和500,这个不太好,对吧,不好,所以最好呢,还是,把这个网页能够换了,就是说,你让用户看到500的话,用户会崩溃的,他一看,好家伙,NonPointException,它不懂技术的话,它根本就不知道啥意思。然后呢,一看,还是一大堆英文,没有一个准确的说法,他不懂英文的话,更看不懂,我们都看的都费劲对吧,都看不懂,那么用户呢,看不懂以后呢,这个用户体验就不好,那么最终呢,用户会反馈,如果说是一个互联网的软件,他一看,这,这太恶心了啊,动不动就报这个,他就不用了,如果是个企业软件呢,它必须得用,因为领导让他用,他会向领导说啊,说着软件太烂了,老是出这个东西,啥意思啊,领导一看啊,也是软件不好,以后这个,不让我们做了,总之呢,影响很糟糕的啊。
  • 那么即便是呢,报了错,我们最好也是把错误页面呢,给它改版一下,最好这个错误页面呢,也能变的这个好看一点啊,在这个用户呢,比较这个怎么说呢,受伤,比较烦躁的时候,给点安慰啊,所以通常是这样,我们通常呢,会把我们最终,最终啊,给用户报的那个错误的页面,给它换了啊,那如果你想换这个错误页面,怎么换呢,在配置文件写配置就可以,不用写代码,直接配一下就好了。所以我们就讲一下,那怎么去配啊,然后我们直接在这个netctoss,这个项目里演示啊,那我们这个项目里呢,是有一个错误页面的,做的还挺好看的,咱们看一下,你看在这个servlet-doc之下,有NETCTOSS_V02,在NETCTOSS_V02之下,有一个网页叫error.html啊,打开看一下啊,就这样:
    在这里插入图片描述
  • 就这样啊,是啊,同样也是错了,但是我们这个错误信息呢,是比较明确的对吧,说软件出错了,再一个呢,放一个比较可爱的这个,玩偶,给用户一个抚慰吧,就这样,总之呢,都是错误,它一定是比500,更友好一点是吧,是这样的,当然了,这个不同的软件呢,它处理的方式不一样,有的软件是什么呢,404,一个错误页面,500一个错误页面,可能会有多个错误页面可以吧,有的软件呢,不管是什么错误,都是一个统一的页面,明白吧,我们这个就是,就简单点,咱们别管是什么错,都是呢,这一种错误页面,就得了啊,那如果呢,我们想把这个错误页面由404,500,换成我们想要的这个,这得怎么去弄呢,怎么去做呢,咱说一下这个配置方式啊,

容器中声明式处理
step1,将异常抛给容器,但底层的错误提示不要返回给用户。
- 注意:异常只允许抛service指定的异常,不能超出指定范围
- 使用如下写法:throw new ServletException(e);
step2,在web.xml文件中配置错误处理页面节点
//配置错误处理页面
<error-page>
	<exception-type>
		javax.servlet.ServletException
	</exception-type>
	<location>/error.jsp</location>
</error-page>

  • 我们在web.xml里啊,加配置,这个配置的标签呢叫<error-page></error-page>,错误页面,然后呢,error-page里面呢,有子标签,子元素,这个配置方式呢,有两种啊,就是说,一种呢,是通过异常的类型加以配置,一种呢,是通过异常的编号加以配置,就是说这个地方,<exception-type>,我们可以声明异常类型,<exception-type>,检查异常的类型,意思是呢,当捕获到javax.servlet.servletException,这种类型的异常时,就转发到/error.jsp,这个错误页面, 后面的location里面,写的是错误页面的路径啊,当发生javax.servlet.servletException,这个异常时,转发到这个/error.jsp错误页面。然后呢,你可以配置多个类型,配置多个页面,这是一种情况,还有一种情况,你可以不写exception-type,你可以写什么呢,error-code,把这个exception-type换成error-code,异常的编号,比如说,404,500,明白吧,都可以啊。
  • 然后呢,我们配的话呢,一般,你要么用异常的类型,要么用编号,不会混这来,因为说白了,你这个,你报了个异常,其实它对应的是500,对吧,它对应的是500,其实重复的,那一般我们工作时啊,更习惯于用这个编号,更多用编号,所以呢,我给你演示下,用编号怎么配。如果你想用异常类型配的话,<exception-type>javax.servlet.ServletException</exception-type>,这段话就是,就这样写,这个我就不给你演示了,那咱们回到这个eclipse啊,打开我们这个电信计费项目当中的那个配置文件啊,web.xml,这个配置文件啊,在此之前啊,我们只配了,MainServlet,没有别的东西了,现在,我们加一段配置,配置什么呢,就是配置这个异常的,配置这错误页面啊,然后呢,当tomcat这个捕获到这种错误时,会自动转发到对应页面啊,它是这个意思。
  • 那么你要配置错误页面啊,写这个标签啊,刚才说了,叫error-page,然后呢,它的里面我们需要写,你看啊,它的里面有3种子标签,一个叫error-code,一个叫exception-type,一个location,那么location里面写的是转发的错误页面明白吧,你想转发到哪,就写哪,而error-codeexception-type是判断条件,是判断错误的依据,那这两者选一个,我选error-code,因为我们工作时常用这个,error-code,比如说404,我希望发生404时啊,去那个错误页面啊,那个错误页面叫什么呢。那你注意啊,那个错误页面啊,一会我们把它做成error.jsp,那这个错误页面放哪呢,我把它放到,就放到/WEB-INF的下面,可以吧,/WEB-INF/error.jsp,就把它放到这来,为啥呢,因为你想啊,这个错误页面,是不是任何错误,都找这个页面啊,它是公用的,对吧,所以放到/WEB-INF之下就可以了。
  • 那我们这呢,就来配置这个这个路径啊,然后你得写上什么呢,location,那这个错误页面的访问路径,我们应该是写,绝对还是相对路径呢,绝对,因为你不知道哪报错,对吧,你不知道从哪,这个请求从哪来,所以通常呢,我们是写绝对路径,绝对路径的书写方式是固定的啊,斜线开头,项目名,然后呢,接着写,那jsp的访问路径是它存放的目录,所以写WEB-INF,然后呢,error.jsp,即<location>/netctoss/WEB-INF/error.jsp</location>,但是你注意啊 ,这块有点特殊啊,这个地方呢,我们在写绝对路径的时候呢,还不能写项目名,啊,就这个地方比较特殊,这个location这个地方,我们在写绝对路径时,不能写项目名,要把它去掉,啊,本来,应该是写,但这块特别,这块不要写,<location>/WEB-INF/error.jsp</location>
  • 那是为什么呢,咱们做个解释啊,因为你想啊,tomcat在发现有这个错误时,它会转发到这,/WEB-INF/error.jsp,它是转发对吧,转发的话,转发能不能转发到这个项目之外的地方去呢,可不可以,能不能转发到百度去,淘宝去,可不可以,不可以,转发只局限在当前项目之内对吧,想访问别人访问不了,所以呢,tomcat清楚的知道,这是转发,一定转发给netctoss,下面的东西明白吧,它知道,它就怕我们费事,它会把这个项目名自动加上去,听明白了么,听懂了么,转发的时候,你在写绝对路径时,不要写项目名,因为tomcat知道,一定是这个项目之内的东西,项目名它帮我们写了,明白吧,它怕我们累着,就这个意思,所以这块特别啊,我这强调一下。就是转发时,若写绝对路径啊,需省略项目名,因为tomcat会自动,这个增加项目名,那你这块啊,一定要注意,因为如果你把项目名写上了,转发时,它又给你加了一个,会出现两个项目名,明白吧,netctoss,又netctoss,就错了,所以别写啊。
  • 那当然了,我们开发时啊,不单单是有404的错误,还有500,对吧,还有可能405,你都配一下,那每一种编号都是这个错误页面,怎么办呢,error-page这句话,再写一份,明白吧,再来一份,复制粘贴,改个编号,比如说,405,再来一份,改个编号,500,那这样的话呢,这个我们项目之内啊,无论是报哪种类型的错误,它最终都是转发到了这个错误页面啊,这样的话呢,比较友好一点。

  <!-- 配置错误页面:当tomcat捕获
  	到这种错误时会自动转发到对面。
  	转发时若写绝对路径,需省略项目名,
  	因为tomcat会自动增加项目名。 -->
  <error-page>
  	<error-code>404</error-code>
  	<!-- <location>/netctoss/WEB-INF/error.jsp</location>写绝对路径时,只有此处特别,不能写项目名 -->
  	<location>/WEB-INF/error.jsp</location>
  </error-page>
  <error-page>
  	<error-code>405</error-code>
  	<location>/WEB-INF/error.jsp</location>
  </error-page>
  <error-page>
  	<error-code>500</error-code>
  	<location>/WEB-INF/error.jsp</location>
  </error-page>

  • 那么配完以后呢,这还没完,咱们还得写这个jsp对吧,下面我们写这个error.jsp,那么,大家呢,在WEB-INF之下,创建一个新的jsp啊,那这个jsp啊,首先我们也需要写这个page指令,<%@page pageEncoding="utf-8"%>,有人问说,唉你看,现在我们写这个转发的路径,写的是绝对路径,那我们以前写的转发是绝对路径么,以前我们写的转发是什么路径啊,是相对路径,什么是绝对路径呢,斜线开头对吧,什么是相对路径呢,没有写斜线,就看有没有斜线,所以以前,我们直接写WEB-INF,相对是吧,不是绝对。那你创建完这个jsp以后啊,需要把这个标签贴过来啊,所以我们再打开那个NETCTOSS_V02,然后你把error.html当中的代码,复制过来,把这个代码呢,粘贴过来啊,这代码很少,就40多行,粘贴过来以后啊,刚才那个静态的网页,咱们也看到了,它有个倒计时,再看一下啊,这个倒计时,一到这个错误页面以后,它就倒计时,5,4,3,2,1啊,然后呢,到0以后,跳转到登录对吧,还有,如果说你懒着等,这5秒,直接点返回,也可以到登录啊。
  • 所以呢,它这个登录啊,之前写的路径是html,现在我们登录做成了jsp对吧,所以这个路径得改。因此呢,我们打开这个error.jsp,我们需要呢,把这个页面上的,这两个路径改一下,这个页面上的倒计时啊,是用这个定时器实现的,那么如果你有兴趣的话,自己看一下,然后呢,我们找一下,在这个代码当中,哪个地方有路径,需要改啊,你看24行,对吧,24行,不是写了么,location.href对吧,改下路径,路径改为了登录页面,现在呢,我们把改为这个,toLogin.do,对吧,是吧,那这块写什么路径呢,其实还是绝对路径,有同学说,哎,你这怎么是绝对路径呢,咱们当前是error.jsp,不是确定了么,你看啊,对,有人,其实有人心里想到了,但是说的话,可能还是说的不是那么的清楚,也确实啊,就关于路径啊,你想用一两句,比较准确的话,把它表述清楚还不好表述,明白吧,就必须在项目中演示啊,遇到这个问题你看,我们这么解决,那么解决,它不是一两句话能说清楚的,非常的啰嗦。没法去概括啊。
  • 是这样的啊,比如说啊,本来用户呢,是想访问资费查询功能,所以呢,它的路径,一定是写了,或者说它点了按钮,按钮上写了啊,这个/findCost.do,它本来是要访问资费查询的。然后呢,也访问到了,但是呢,在访问的时候,这个比如说访问了这个MainServlet,里面的这个findCost()方法,那有没有可能,调这个方法时报错了呢,有可能吧,那如果说没报错,它正常来说应该转发到find.jsp,对吧,一报错,它被tomcat强制转发到哪去了呢,转发到了error.jsp,是这样吧,报错时,被tomcat强制转发到这来了,然后呢,响应,然后呢,响应以后我们在浏览器上,要写一段这个啊,定时器,你不能永远看这个错误页面对吧,要去这个登录页面,要访问登录啊。
  • 那登录的话呢,是什么呢,是MainServlet.toLogin()方法,到MainServlet.toLogin()这来,我们需要写路径啊,到这来,那你看是到MainServlet.toLogin()这来,这是去向,我们从哪到这来,是从error.jsp么,或者说,谁去访问登录呢,是浏览器对吧,浏览器访问登录,浏览器在哪个页面上访问登录呢,是在查询资费上,浏览器本来是输入这个路径,/findCost.do,访问的,MainServlet.findCost()这个功能,但得到是一个错误页面,浏览器会认为这个错误的页面时/findCost.do明白吧,能理解吧,你想一想,是/findCost.doMainServlet.toLogin(),它的关系,是MainServlet.findCost()MainServlet.findLogin()它的关系,浏览器并不知道有这error.jsp啊。
  • 我再好好画画,再想想,就是浏览器访问服务器,它本来是要做资费查询,然后呢,服务器也是,是用调MainServlet.findCost(),这个方法处理的请求,但是呢,它本来啊,本来按理说啊,应该是MainServlet.findCost(),它转发到find.jsp,这块我再,我再画的稍微完整一点啊,MainServlet.findCost()本来应该是去到find.jsp,那如果是 正常执行,要去这find.jsp,但是呢,现在出错了对吧,出错以后 呢,被浏览器呢,强制转发到了error.jsp啊,所以这里有服务器的事,这个服务器,这个服务器的通信组件画出来啊,很多事都是通信组件干的。那我们访问的是通信组件,通信组件呢,去访问Servlet(MainServlet.findCost()),然后呢,正常是转发到jsp(find.jsp)啊,由jsp(find.jsp)做出响应,但是呢,报错了,报错时,是怎么招呢,是由通信组件将这个请求转发到了error.jsp啊,报错时是这样的啊,报错时是通信组件,强制把这个findCost.do请求,转发给了error.jsp,最终呢,由这个error.jsp啊,给浏览器呢,做出了响应,是这么折腾了一下。
    在这里插入图片描述
  • 然后呢,在(由error.jsp)返回的网页上,有一段代码,那代码里像这样写啊,location.href等于,等于什么呢,我们要写toLogin.do,总之呢,你要,就是要访问它吧,MainServlet.toLogin(),主要要访问它location.href="netctoss/toLogin.do"。那你看,是浏览器,它本来是要查询,然后呢,得到了结果以后,然后呢,要访问登录,是谁和谁的相对关系呢,是/findCost.doMainServlet.findCost(),和toLogin.doMainServlet.toLogin(),那么,因为访问这个登录功能,是浏览器自己干的,所以啊,我们是站在浏览器的角度去思考这个问题,那么对于浏览器而言,它并不知道有error.jsp,它访问的是这个路径,它就认为,当前得到的结果,就是/findCost.do,明白吧,它就是这样认为的,所以说,是1和2,从/findCost.doMainServlet.findCost(),和toLogin.do到MainServlet.toLogin(),这个两个请求之间的相对关系,是这样的。
  • 总之啊,就是这块比较特殊啊,就是tomcat强制把这个jsp给换了,本来是find.jsp,换成error.jsp了啊,比较特殊了,但是你想啊,咱们这个报错,有可能一定是,查询么,不一定,我们增加时,也可能会报错对吧,修改时,等等,可能任何功能都会报错,所以你能确定这个findCost.do,就这个路径么,确定不了,就是我们,我们要访问的,我们去向,一定是去toLogin(),但来源还是没法确定对吧,没法确定啊,所以呢,没法确定怎么办呢,location.href这里,还是得写绝对路径啊。就是说,关于路径啊,这个确实,不同的场景,它这个,你思考的角度是不一样,通常是这样,就是转发也好,还是重定向也好,这件事由谁干的,我们就站在谁的角度去想这个问题,你像,这个跳转我们写的是location.href,这事是浏览器干的,我们在浏览器的角度思考这个问题,这样比较合适啊。
  • 所以,在error.jsp中,location.href这块写绝对路径啊,那绝对路径的话,这样写啊,"/netctoss/toLogin.do",即location.href = "/netctoss/toLogin.do";,那不止这一个地方有这个路径,下面不还有一个么对吧,我们把那个也改一下啊,也改成绝对路径,32行,location.href = "/netctoss/toLogin.do";,那改好以后啊,这个就处理完了,那处理完以后,这个行不行呢,还得进行测试啊,那目前呢,咱们项目中并没有什么错误对吧,那怎么办呢,我也能演示,我自己造个错啊,这个造错还是很容易的啊,比如说,我随便找一个类啊,造个错,比如说这个CostDao,我打开CostDao,资费Dao啊,假设啊,之前,我在写查询的时候,这个sql呢,我写错了,本来呢,应该是select * from cost_lhh,假设不小心我写成了form,你看有人马上就接上了,说明你也遇到这个问题,是吧,这个问题,还不止一个人遇到过,那写习惯了就,就写串了啊,写成form,然后乍一看,还看不出来是吧,还挺像那么回事,这就有问题了啊,那试一下。
  • 我改完以后啊,把这个项目呢,部署一下啊,然后启动,启动以后呢,打开浏览器,然后呢,我得这个,先登录一下,咱们做的正式点,先登录啊,toLogin.do,没问题啊,然后呢,填账号密码,登录,没问题,登录进来以后,点资费管理,就查询了对吧,那我点了,查询,报错了,然后,5,4,3,2,1,看它会去到登录页面么,会,再来一下。如果我等不及,5,4,3,2,1,我点返回,也可以对吧,就这样了,自己试试,那试完以后啊,大家有没有想过这样一个问题啊,就是说 ,它是这样设计的,一报错 ,5,4,3,2,1,就回到了登录,它回到登录这件事,你觉得它,它为什么这样做呢,那有意义么,有必要么,或者说那你认为没有必要的话,那我们错误时应该怎么办呢,访问到上个页面对吧,为啥呢,这也可以 ,但是呢,相对来说,回到登录页面,还是怎么说呢,它的易用性不好,但是呢,有的时候能避免能解决些问题,什么问题呢,就是一般系统报错,有可能是真的,系统有bug,有这种可能对吧,如果是真的有bug,无论是你回到登录 ,还是回到哪都解决不了是吧,解决不了,你回到哪都行,无所谓。
  • 但还有一种情况,有可能是什么呢 ,我刚才在那个,比如说点查询,或点增加,我在点查询,或增加的那一刻,有没有可能立刻那个,比如说数据库就断网了,有没有可能,就是用户呢,在网页上,点资费管理,想查询,结果程序,执行到,比如说CostDao这的时候,这一刻,数据库这网断了,连不上了,有可能吧,就一定会报错,是这样吧。当然了,数据库网断了,可能服务器网没断,数据库和服务器不在一个地方,明白吧,很有可能,所以数据网断了,服务器还能正常执行,然后呢,报了一个错,报错以后呢,我们强制用户去登录,那他如果重新登录以后没准,登录完以后,这个网又恢复了,ok了,能理解吧,这问题迎刃而解,没有问题,用户一看啊,又好了,好了就算了,他也不追究了,明白吧,我们也不用解决,像这种极端的情况,我们可以,就怎么说呢,有的时候也可以规避一些问题,要不然的话,客户也向你提这个问题,你又重现不了,你也不知道,它是怎么回事对吧,重现不了,不好解决,所以,这也算是合理的一种行为啊。
  • 那关于这个异常的处理啊,就介绍到这,就了解一下,工作时啊,这个异常怎么配,项目经理啊,他早就会在建立这个项目时,把它配好,所以你也不用去操心,但了解一下啊,这句话人家写了,你能看得懂就行了啊。
代码实现: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>netctoss</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>main</servlet-name>
  	<servlet-class>web.MainServlet</servlet-class>
  </servlet>
  <servlet-mapping>
  	<servlet-name>main</servlet-name>
  	<url-pattern>*.do</url-pattern>
  </servlet-mapping>
  
  <!-- 配置错误页面:当tomcat捕获
  	到这种错误时会自动转发到对面。
  	转发时若写绝对路径,需省略项目名,
  	因为tomcat会自动增加项目名。 -->
  <error-page>
  	<error-code>404</error-code>
  	<!-- <location>/netctoss/WEB-INF/error.jsp</location>写绝对路径时,只有此处特别,不能写项目名 -->
  	<location>/WEB-INF/error.jsp</location>
  </error-page>
  <error-page>
  	<error-code>405</error-code>
  	<location>/WEB-INF/error.jsp</location>
  </error-page>
  <error-page>
  	<error-code>500</error-code>
  	<location>/WEB-INF/error.jsp</location>
  </error-page>
</web-app>
代码实现:servlet-doc/NETCTOSS_HTML/error.html
<!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">
            var timer;
            //启动跳转的定时器
            function startTimes() {
                timer = window.setInterval(showSecondes,1000);
            }

            var i = 5;
            function showSecondes() {
                if (i > 0) {
                    i--;
                    document.getElementById("secondes").innerHTML = i;
                }
                else {
                    window.clearInterval(timer);
                    location.href = "login.html";
                }
            }

            //取消跳转
            function resetTimer() {
                if (timer != null && timer != undefined) {
                    window.clearInterval(timer);
                    location.href = "login.html";
                }
            }
        </script> 
    </head>
    <body class="error_page" onload="startTimes();">
        <h1 id="error">
	        遇到错误,&nbsp;<span id="secondes">5</span>&nbsp;秒后将自动跳转,立即跳转请点击&nbsp;
            <a  href="javascript:resetTimer();">返回</a>
        </h1>
    </body>
</html>
代码实现:src/main/webapp/WEB-INF/error.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">
            var timer;
            //启动跳转的定时器
            function startTimes() {
                timer = window.setInterval(showSecondes,1000);
            }

            var i = 5;
            function showSecondes() {
                if (i > 0) {
                    i--;
                    document.getElementById("secondes").innerHTML = i;
                }
                else {
                    window.clearInterval(timer);
                    location.href = "/netctoss/toLogin.do";//location.href = "login.html";
                }
            }

            //取消跳转
            function resetTimer() {
                if (timer != null && timer != undefined) {
                    window.clearInterval(timer);
                    location.href = "/netctoss/toLogin.do";
                }
            }
        </script> 
    </head>
    <body class="error_page" onload="startTimes();">
        <h1 id="error">
	        遇到错误,&nbsp;<span id="secondes">5</span>&nbsp;秒后将自动跳转,立即跳转请点击&nbsp;
            <a  href="javascript:resetTimer();">返回</a>
        </h1>
    </body>
</html>

写在后面

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值