NETCTOSS代码实现第三版

前言

登录模块功能需求分析与程序设计

根据需求拆分请求,并推导程序内部执行过程

  • 因此啊,一定是想办法,想尽一切办法,在我们学习过程当中,掌握这个套路,那我所讲的基本套路是什么呢,第一点,看需求看操作对吧,然后呢,好根据需求,根据操作,我做出一个分析来,做出一个设计来,那我们就看一下这个登录功能,它的操作啊,它的操作其实,大家也都懂,一看就懂啊,为什么呢,咱们天天登录,对吧,登录tts,登录淘宝,登录这个那个的,天天登录啊。那你看,它的使用方式是这样,首先呢,我要打开浏览器,在地址栏,敲一个地址,好打开登录页面对吧,这是我们整个项目的入口,是第一个网页对吧,这个路径得记下来,得会敲,当然了,如果项目上线以后呢,这个路径可能就会变的简短,可以把它绑定一个IP啊,绑定一个域名啊,什么什么点com,就简短了,但目前的话,我们得敲localhost什么什么,就长一点,但这个不影响啊,知道就可以了。
    在这里插入图片描述
  • 总之呢,第一步是,敲个地址,我们打开这个这个网页,打开以后,你就填账号密码,这里再额外说一下,就是目前呢,我们在做这个登录功能的时候啊,你就假设验证码没有,因为目前呢,咱们还没法做验证码验证的功能,因为咱们那个session没有学,差点事啊。所以我们现在呢,先不管这个验证码,当它没有啊,我们只输入账号,密码,然后点登录,那如果登录成功了,就可以进去对吧,就可以跳转到这个主页啊,那如果登录失败,去哪呢,失败怎么办,还是回到这个网页对吧,给个提示,我们在这啊,给个提示啊,比如说,账号错误,密码错误等等,给个提示,就这样。
  • 那这个操作大概就这样,很容易就能理解,然后呢,我的建议是,我们根据这个操作,推导出什么呢,推导出什么啊,我们根据操作想知道的是什么,请求是吧,不知道是不想说呢,还是不屑于说呢,还是就是真忘了啊,我就怕你是真忘了, 我给你讲这几个功能,主要是让你去,把我说的这个办法,这个入手的办法掌握了,你一定要去用这种方式去思考,去解决问题,你从何入手,否则的话,如果你不从这入手的话,容易,容易跑偏了,容易这个发散了啊,抓不住这个主线啊。根据这个功能,我们分析有几个请求啊,我也说了,通常我们是输出个地址啊,点个什么按钮啊,就能发出一个请求,对吧,你看,刚才我说了,我们首先要写个地址,得到这个登录页面对吧,这就是一个请求啊,敲路径,一回车,打开登录页面,是一个请求。
  • 然后呢,你输入账号密码,点登录,判断账号密码对不对,对吧,这是一个请求,那如果对了,跳转到主页,打开主页是不是个请求呢,是的,那主页和登录,是不是两个彼此独立的功能呢,是不是啊,是的,主页是个独立的功能,我们可以,直接在任何页面上点它,尽管这个功能啊,没啥用,就是给人看的,看一眼这个图标的,没啥用,但是呢,也算是个功能,然后呢,如果说,这成功了,那如果说失败了呢,再跳转回登录页对吧,又是给请求,总之呢,大概是4个请求啊,打开登录页面,登录,检查账号密码对不对,成功时,失败时,对吧,4种情况,4种请求。那么,大概了解以后,那每一个请求,它是怎么执行的,肯定是有的简单,有的复杂,那我们把这个画一画,串接一下,好清楚啊,每个请求需要写什么,然后呢,我们再按部就班的,一步一步来写,这样就不会乱啊。
  • 那我把这个,这个流程画一下啊,这是浏览器啊,然后呢,服务器,然后呢,刚才我们说了,我们要想登录,首先的话,得敲一个访问路径,对吧,敲个路径,敲路径就是在地址栏 写个地址,这个我有要求,我要求呢,咱们登录时这个路径,叫/toLogin.do,行吧,login是登录,我们打开登录页面,是要去登录,对吧,/toLogin.do,然后呢,发出请求,访问服务器,服务器呢,MVC模式,我们按照这个,使用这个Servlet处理一切请求,MainServlet,那么,开发到现在啊,我们应该是有这样的一个,怎么说呢,一个意识了,我们平时在开发项目时,基本上所有的网页都是动态的,几乎没有静态的,就哪怕说,即便当前这个网页是静态的,我也要把它做成动态的,因为,万一将来说这个网页上,要有动态的元素呢,万一将来要挂个广告呢,万一要显示一个用户名呢,对吧,很有可能会有变化,所以我们与其将来变,不如我们把它全做成动态的,如果你没有动态的逻辑,先把它摆成静态的内容对吧,也可以,万一有的话,好加,不用去重改代码的结构,所以,基本上就是这样一个原则啊,就是所有请求,都按照动态的处理就好了。
  • 然后呢,我们访问的还是,MainServlet,然后呢,调什么方法呢,和这个路径相对,toLogin()方法,MainServlet.toLogin(),我敲这个路径/toLogin.do,访问它,MainServlet.toLogin(),然后呢,MainSerlvet.toLogin(),它处理请求,打开登录页面,这个没有什么逻辑对吧,不要求怎么样,就打开个页面,所以呢,和打开增加页面,没什么区别,怎么办呢,就转发就行了,我们把请求呢,转发到这个,某一个jsp,那当然了,jsp呢,我们都要把它放到哪去呢,/WEB-INF之下,然后呢,那你看登录的话,它不属于资费模块,对吧,你要是把这个网页,放到cost之下就不太合适了,我们最好再建一个新的目录对吧,建个新的目录,这个目录叫什么呢,我个人,我习惯于叫main,表示说,一看到main啊,表示这是一个主要的,一个应用程序的入口,登入功能放到这里来,/WEB-INF/main,还算比较合理啊,叫main 。
  • 然后呢,这个页面的名字就叫login.jsp,就这样,/WEB-INF/main/login.jsp,当然了,页面的名字,目录,叫什么都行,这是我个人的习惯。然后呢,由它,/WEB-INF/main/login.jsp,向浏览器呢,做出响应,到这,第一个请求结束,那么这个请求,非常简单,它和我们呢,那个打开资费增加的网页,没什么区别对吧,几乎是一样的方式,这是第一个请求。那么,当这个请求结束以后,服务器就会给浏览器呢,传过来一个表单啊,一个网页,网页中有表单,表单中呢,主要有账号密码,验证码先不管,是吧,最后还有个按钮,叫登录。然后呢,显然点登录按钮的时候,你是不是得访问服务器,得把数据呢,提交给服务器,又得访问服务器,那这是咱们登录功能的第二个请求,那数据,我们还是要传给Servlet,MainServlet.login(),把数据呢,传给这个Servlet啊,那咱们再换个方法,就不叫toLogin了,这个登录是正在登录是吧,这我就叫login吧,toLogin去登录,login登录,那么它的路径,相应的也做一个要求啊,就是/login.do,这是第2个请求。
  • 那么在这个请求之内啊,我们需要呢,把账号密码,输入的帐号密码传给服务器,服务器接收账号密码,那你想啊,这个跟我们增加,保存是不是类似,是吧,一样,这回数据还少了,对吧,只有这个账号密码,就俩框,还没有选择框啊,就还更简单了,然后呢,MainServlet.login(),接收这个参数,接收两个参数,收到以后,收到以后得怎么办呢,得判断这个账号密码对不对,是吧。那你看啊,我要判断账号密码对不对,这个得访问,我得怎么办,我得跟数据库里比对吧,数据库里提前,得有一张用户表对吧,与之相比,不过,我们这个项目中啊,那个用户表,它不叫用户表,它叫管理员表,管理员表admin,那个表名叫admin_info,一会我们创建一下,但虽然说叫管理员吧,其实就是用户表,这个数据库不知道谁设计的啊,这个很很奇怪,很别扭啊,你就把它当作用户就可以了,那我们要访问这个用户表,好知道这个账号密码对不对,我们访问用户表的话,我们执行的是什么操作,增删改查当中的什么,查,是这样吧,你得查。
  • 那我们要查的话,那显然,还得写个dao呗,这是一个新的模块,一个新的表,我们是不是得写一个新的dao啊,对吧,写个新的dao,我们叫AdminDao,行吧,因为它那个表名叫admin,我们就叫AdminDao算了。然后呢,查findBy,那你说根据什么查,根据账号查,为啥呢,有人说账号密码一起查呗,那到底怎么办呢,我是根据账号查,根据密码查,根据账号密码一起查,用哪种方式,一起查,首先是账号密码一起查,行不行呢,就是我账号密码传入,一起查,如果查到数据,就表明账号密码,ok的是吧,如果没有数据,就表明账号或密码,某一个错了,是这样吧,但是,我账号密码一起查,我得到一个,如果没查到数据,我能知道是谁错了么,账号错了,还是密码错了,知道么,知不知道啊,就不能知道,如果我想,我想知道具体是谁错了,我就不能一起查,是这意思吧,那我就得,通过什么查呢,账号查。
  • 那有人说,那一般情况下,到底是怎么样呢,一般是这样啊,如果是互联网的项目,比如说淘宝啊,京东啊,这样的项目,它通常账号密码一起查,如果有问题,给你一个笼统的提示,比如说,账号或密码错误,很多网站是这样提示的对吧,它不明确提示你是账号错了,还是密码错了,为啥呢,怕这个,就是增加破解难度,如果你告诉它,账号错了,它反复破解账号明白吧,暴力破解啊,就无限制输入这个各种账号,它容易被破解,但是呢,如果它告诉你,账号或密码错了,那你可能是,得两个一起破解对吧,难度就增加了,是为了避免破解,这是互联网的软件,但是如果我们做一个办公软件的话,像什么oa啊,财务啊,等等,这样的软件的话,那对于企业来说呢,这个软件,它最终呢,不是运行在公网上,它运行在企业的内网里,明白么,我们外人访问不到对吧,我想访问阿里巴巴内网,访问不到吧,访问不到,访问百度内网,访问不到,所以它只局限在内网之内,而内网的话,是和外网隔离的,是有防火墙的,明白吧,所以我们认为这防火墙很安全啊,我在内网的话,我给提示帐号错了,还是密码错了,其实更精确,为了让企业员工更好用,也可以,明白么,这就没关系,因为有防火墙。
  • 有人说,那企业员工不会去暴力破解么,他疯了吧,你想一想啊,企业就那么点人,几百人,几千人,上万人,他去破解,那那个记录,一抓就抓到了对吧,跑不了,所以说它不会的,总之啊,一般的原则是这样的,对于这个互联网这个软件,我们以这个安全为主,以避免破解为主,所以账号密码一起查,给个模糊的提示,对于这个,办公软件,因为它局限在内网使用,我们就是说,可以认为防火墙很安全,不管它被破解的这个情况,因为如果这个人有能力突破防火墙,它这个软件,也就,也就够呛,明白吧,也防不住它,所以说,我们不管这一套,就是提示的更精确,更好用啊,那我们这个软件,它是什么软件呢,是互联网软件,还是办公软件呢,办公软件啊,所以,我们就用后者,我希望呢,账号或密码错了以后啊,你给个明确的,清楚的提示,你的账号错了,密码错了,清楚的提示,所以呢,我用账号查询,findByCode,AdminDao.findByCode(),根据账号查询。
  • 那你想啊,根据账号查询,如果说,我没查到数据,说明什么问题,账号没有对吧,是吧,如果查到数据,表明账号对了,密码呢,密码是对了,还是错了呢,还不知道对吧,还不知道,你还得把得到的数据,这个密码,和输入的密码相比对吧,再进一步比较,分两步来做就可以了。好了,所以我们采用的是这种方式啊,那么用这种方式的话,Servlet要调用dao,是不是得传入个条件呢,得把浏览器传过来的账号,传进去对吧,我们假设这个账号就叫,就叫code可以吧,假设这个账号就叫,叫code吧,这个别叫code,咱们叫,叫什么呢,叫那个adminCode吧,因为叫adminCode,因为表里是这么取的名字,最好和它对应,就是页面传过来的账号,叫adminCode,我把这个adminCode,传给这个dao,把它传进去,这个adminCode传进去,然后呢,这个dao利用这个条件去做查询,然后呢,AdminDao.findByCode(),查到数据以后,要返回给, MainServlet.login(),Servlet好加以判断。
  • 那想一想啊,AdminDao.findByCode(),这个方法,我返回什么类型的值比较好,findByCode(),条件是账号对吧,查询,我们结果返回什么比较合适,能解决这个需求,你不用说类型,你就说返回什么值,你想返回哪个值比较合适。有人说返回密码,我根据账号查到密码,我得到密码以后和输入密码相比,是这意思吧,可以解决,那就是字符串对吧,密码,行吧,可以。还有别的意见吗,这样其实是可以的啊,但是,怎么说呢,一般情况下呢,为了程序的更好的复用,就这个方法,我们可能是不单单是在登录时用,也可能是在别的地方也会用,明白吧,为了它能够在不同的场景里复用,我们最好返回什么呢,哎,就返回一个Admin对象,比较合适,那这个对象里,是不是也包含密码啊,也包含其他的数据,明白吧,都包含,这样会好用啊,别的业务场景也可以复用。
  • 当然有人可能会想啊,你这样的话,我这个业务只需要一个密码,对吧,只需要你返回密码,结果你把这个账号,其他的信息也给我了,这样是不是会影响这个效率呢,会有一点影响,因为它查的数据,毕竟比我业务要求的数据多一点,是吧,会有一点点影响,但影响不大。然后呢,考虑到呢,我们当前做的是一个,这个企业项目,所以这个就,影响就更小了,为啥呢,企业项目,只局限在企业内部使用,一个企业员工呢,没有那么多,也就是最多,大的企业有几万人,对吧,是这样吧,它不能再多了,没有那么大的企业,几万人就不少了,然后呢,再一个,你这个企业几万人,我做个oa系统,也不是每个人都用明白吧,是吧,不是说每个人都用的,就财务软件,就这个企业的财务用明白吧,就那么几十人,百十来人啊,人力软件,就那个企业的一两百个人来用,它不会说太多的,所以呢,这个项目的并发量,这个用户量不会太大,是可控的,所以,这方面不用太考虑。
  • 但如果是个互联网的项目,我们要考虑这个性能的话,可能会,就是你查的更精确会好,总之呢,我们做这个软件呢,看这个实际的情况,看这个软件是什么性质,那这个不同行业的软件,它的性质不同,要求也是截然不同的。总之,怎么说呢,就是说,互联网的软件,要求是更高的,因为它要支持大并发,要支持大数据量,要求是更高的,而企业软件相对来说呢,没有那么高,而且企业软件,也远远没有互联网软件那么易用,是很难用的啊,以前,我在用友,我们开发那erp(Enterprise Resource Planning),还算是这个行业内,好用的了,结果呢,很多我们自己员工也是不会用,就我们自己开发人员都不会用,就我只开发这个模块,我就会用这个模块,其他模块不会用,只有测试会用,需求会用,别人不会用,太复杂了啊。就拿现在我们正在用的就是,达内用的那个oa啊,也是买的用友的,我现在,我用起来,我也感觉很恶心,这谁做的,这么恶心,确实不好用啊,但是呢,但是都这样,都这样。
  • 所以你啊,就是你学好一点啊,你将来争取去一个互联网企业,发展的会更快,没有那么,学的没有那么好,那只能是去一个,这个比较传统的软件开发行业,那就是,没有互联网那么,那么快啊,好了,这有点扯远了,总之啊,就是说,第二个请求,浏览器要把数据传给服务器,服务器接收到的是账号密码,那么,它呢,MainServlet.login(),把这个账号,传给这个dao,AdminDao.findByCode(),根据账号查询一条用户过来,然后呢,进而判断一下,查到的密码,和得到的密码,浏览器传过来的密码,是不是一致的,判断密码对不对,总之做出判断啊。那判断完以后啊,有两种情况, 一种情况是对了,是吧,对了怎么办呢,这说了,对了你得去,去它主页对吧,这叫主页,去到主页:
    在这里插入图片描述
  • 而主页又是个独立的功能,我们要过来的话,你得怎么过来呢,转发还是重定向呢,重定向,因为这是两个独立的功能,对吧,互不依赖,要重定向,所以,我们需要重定向到主页,那主页,我们应该还是啊,就是有一个MainServlet,里面有个方法,那打开主页这个方法,我叫toIndex(),主页啊,一般,我们在开发时,主页习惯于叫index,也叫首页,MainServlet.toIndex(),到这来,然后呢,它这里面,没啥逻辑,它就是转发到jsp就可以啊,就转发到jsp就行了啊,MainServlet.toIndex(),它里面没什么逻辑,我们访问这个Servlet,它将请求转发到,/WEB-INF/main/index.jsp,这吧,还是main之下啊,index.jsp,转发到这来。然后呢,由它,/WEB-INF/main/index.jsp,做出响应,这算是我们这个功能当中的第3个请求。
  • 那么,我们在这啊,AdminDao.findByCode(),调了dao的方法,得到了数据,对数据做出判断以后,如果说账号密码没问题,我们就到浏览器这,MainServlet.login(),通过重定向给浏览器一个建议,访问MainServlet.index(),对吧,重定向过来,就这样,这是账号密码对的时候,我标一下,y吧,对的时候,重定向过来。那么还有一种情况是错,对吧,或者账号错了,或者密码错了,那不管是谁错,我们最终回到哪去呢,就你错了,还得回到这个登录页面对吧,给个提示,不能进去啊,那登录页面是谁呢,其实,是不是就这个啊,/WEB-INF/main/login.jsp,就它,那我怎么去访问它呢,我怎么去访问它呢,有两种办法,一种是我在这MainServlet.login(),可以转发到,/WEB-INF/main/login.jsp,可以转发过来,一种是在这,MainServlet.login(),我重定向到/toLogin.do,你说是不是可以这样呢,是吧,或者是重定向过来,或者是转发过来,那这块我们是,用转发还是重定向,比较好,为什么是转发呢,为啥啊。
  • 其是吧,这块,更好的方案呢,是用重定向,因为什么呢,你看咱们点登录,是检查账号密码,我们/toLogin.do,是打开登录页面,是两件事对吧,是吧,打开登录页面,和检查账号密码,其实是两件事,那我们应该是,最好是重定向,但目前的话,我们还真的没法用重定向,因为有个问题呢,不好解决,对,你到这个网页上来,/WEB-INF/main/login.jsp,是不是得给它提示啊,提示账号错了,或密码错了,要传个错误信息过去对吧,你最终MainServlet.login(),要传给它,/WEB-INF/main/login.jsp,一个错误信息,那你看,我们重定向,我这一重定向,是不是请求就变了啊,请求一变,这个数据就不好携带了,对吧,没法传数据了。
  • 因为你看,我们当前说的是什么呢,我们当前探讨的是,这啊,MainServlet.login(),就是说,我们当去探讨的业务是登录时,是第2个请求,我访问的是它,MainServlet.login(),它已经判断出了账号或密码错了,对吧,那如果要重定向过来,那是不是从第2个请求/login.do ,又跳到第一个请求了啊,/toLogin.do,请求一跳,我们没法传数据了,对吧,说白了我们现在只会用request传数据对吧,你要是重定向,数据没法传了。但不是说做不了,将来我们学了session也可以明白吧,但没学呢,所以,先不能这么办,先只能这么办,这么办反正也能说的过去吧,因为什么呢,这个转发过来,我们可以这样理解,打开登录页面和登录,这两个请求,这个两个功能,它们共用一个jsp,/WEB-INF/main/login.jsp,明白吧,这块是共用了一下,反正也能说的过去啊,也可以说的过去,因为毕竟吧,都是一个体系之内的功能啊,都是一个相关的功能啊,就这样,这种请求呢,是什么呢,是错误的时候啊,n,就是有不对的东西,我们就转发。
    在这里插入图片描述
  • 那转发的时候,是不是得给它传个消息啊,传一个错误信息啊,这个错误信息呢,咱们就传个字符串吧,叫error,行吧,可以吧,传个提示过来就行了,就这样。那这个登录功能啊,大致的流程,我们就分析完了,串一下,别乱啊,首先呢,左侧浏览器,右侧服务器啊,首先,我们整个功能的起点,是我在地址栏敲了个地址,对吧,是吧,我要求这个地址就是,/toLogin.do,访问服务器,那么,按照,MVC的原则,我们请求交给Servlet处理对吧,那我们项目中呢,只有一个Servlet,就是它MainServlet.toLogin(),写个新方法toLogin()就可以处理,然后呢,打开页面,没什么逻辑,直接转发,就行了,转发到login.jsp,响应给浏览器。即便是没有业务,我也要这样做,也要满足MVC模式,那么将来的话,我们可以好利用什么呢,filter,统一解决一些问题,一些共性问题,如果呢你不按照这个套路来,有些地方,不好统一解决问题,什么叫统一问题呢,就比如说,统一记录日志啊,统一进行一些检查啊, 登录检查啊,统一过滤一些敏感词啊,是需要做的,那将来再说了,那你要做那件事的前提是结构,他们的这个请求的结构相似,相同啊,都满足MVC模式。
  • 那第一个请求完成以后,我们会看到一个表单,账号密码登录,用户呢,填数据,点登录,登录的路径有要求,然后呢,按照MVC模式,我们还是,把请求交给了Servlet统一处理,这回是login方法, MainServlet.login(),那这个方法要处理登录的逻辑,无非就是查询呗,对吧,查询数据,判断结果,对不对,如果对了,没什么好说的 ,重定向到主页对吧,MainServlet.toIndex(),这一步很容易理解,那不对,我要回到查询页面,我们为了携带数据方便,我们从MainServlet.login()转发到/WEB-INF/main/login.jsp,并且给它携带一个错误消息过去,它好显示,可能是,就是说,打开登录页面,问题不大,登录时处理的流程,也问题不大,重定向问题不大,主要是这块,从MainServlet.login()转发到/WEB-INF/main/login.jsp,转发这块,好好想一想。那这个是,咱们登录的,就是开发的流程。把这图先存一下。

代码设计与实现之第一个请求和第三个请求:/toLogin.do和/toIndex.do

  • 那么,下面呢,我们就基于这个流程啊,去写这个代码,当然了,有人也说啊,画这个设计图,你画的这挺溜啊,我自己画,挺费劲啊,我不知道该从何画起,那这个吧,你得慢慢练啊,这个还得有代码的积累啊,有代码量的积累,有解决问题的积累,然后的话呢,你逐渐的,代码越写越多了,尤其是自己的代码越写越多的话,尤其是问题解决越多的时候,当你对这个web项目,有了自己的深刻的理解的时候,到那个时候,慢慢就能画出来了啊,一开始的话确实,因为你对这个项目还是陌生,还是不熟,某一个环节,你还是,就是还是什么呢,脑海里出现不了那个场景,说明什么呢,我们见识还是少,啊,这个得慢慢来,别着急,但你要有意识的,自己去画啊,尝试去画,正是因为不会,我才要试着去画啊,解决问题,你要会的话,就没必要了。
控制层之业务逻辑处理与控制分发:/web/MainServlet.java
  • 那咱们来写这个代码啊,那我们写这个案例吧,第一个请求,打开登录页面/WEB-INF/main/login.jsp,第3个请求,打开主页,/WEB-INF/main/index.jsp,都是打开页面,咱们能不能就是,这两个请求一起写,行吧,可以一起写,比如我先写toLogin()方法,处理MainServlet.toLogin()这个请求,然后再写toIndex()方法,处理MainServlet.toIndex()这个请求,行吧,这两可以一起写,因为它很简单啊,这个逻辑很简单,这个请求路径忘说了,我补充一下,这请求路径呢,我要求,其实不用写,应该也知道了啊,第3个请求路径,它就是/toIndex.do啊,都是有这个规则的。那么,这样,我们先来写第一个请求和第3个请求,我们先写Servlet,就是处理请求,判断,处理请求转发啊,那么打开你的这个eclipse,然后呢,打开我们之前呢,所写的这个MainServlet。
  • 然后呢,在MainServlet当中呢,我们找到那个service方法,我们要在这个方法里处理请求,哎呀,你看,现在这个类的代码越来越多了,是吧,我在找的时候,这么拖拽挺费劲,挺笨的啊,有什么办法,能够快速的找到某个方法呢,这以前好像说过是吧,也不是搜,搜的话,你不是还得敲字啊,还有别的办法么,全部折叠,那也太麻烦了,我们讲过么,我讲过记得,对,有一个叫大纲,类的大纲,说过吧,不可能,就是类,它的层次结构叫大纲,我们可以通过大纲,快速的看到它的结构,点到某一个地方去,怎么看这个类的大纲呢,Window/Show View/,你想看哪个界面,就Window/Show View,明白吧,这个工具呢,给我们提供了很多的视图,很多界面,能够做不同的操作,我现在想打开一个新的视图,Show View什么呢,Outline,有吧,Outline就大纲的意思,能找着吧,没有啊,Window/Show View/,如果没有Outline,你点Other…去搜Outline,可以吧,它会打开这样一个窗口对吧:
    在这里插入图片描述
  • 你看这样的窗口里,是不是每一个方法里,都一目了然呢,我想跳到某个方法上,我可不可以点这个方法,就过去啊,是吧,这就方便了啊,这就方便了。其实呢,我平时开发的时候,我一般呢,这个大纲,我会这么摆在这,一直放在这,然后写代码,但我上课的时候,这不方便,为啥呢,它占了一大半窗口对吧,碍事,再一个,我这个显示器,分辨率太低了,1024x768,咱们现在谁还用这么低的分辨率的显示器呢,都会用很高的,所以,它这个,而且我这字还特别大,总之我这个,显得我这写代码的地方太小了,是吧,我就一般不会打开啊,你写代码时,可以放开,那我就关掉了,还有个办法,这个大纲呢,你把它关掉以后,还有个快捷键,也可以很快的打开,打开它啊,快捷键呢,是什么呢,是你在这个类里点快捷键啊,Ctrl+O,Outline,首字母O,可以吧,Ctrl+O,能整明白么,会弹出个大框,对吧,这个类的层次结构也是一目了然的,你想要找哪个方法,一点它就过去了,明白吧,可以吧:
    在这里插入图片描述
  • 这很方便啊,所以说,我刚才那么拖拽的去找一个方法,这个太笨了啊,所以用这种方式好,就是不管你用哪种方式,现在,我们要找到的是MainServlet当中的,这个service方法,然后呢,进一步,按照我的要求,去处理路径,对路径做出判断,那么,在此之前,我们判断了/addCost.do,你们可能还判断了/update.do对吧,那我这没有/update.do,我就不管它了啊,我就往下写别的啊,再次判断,我们判断呢,这个登录页面的请求啊,else if("/toLogin.do".equals(path)){ toLogin(req,res); },那么如果,请求路径是/toLogin.do,那么我就调MainServlet.toLogin()方法,处理这个请求,我现不急于呢,写这个方法,我先把那个/toIndex.do也判断一下,可以吧,这俩简单,一起写啊。
  • 其实呢,你看啊,我说啊,这是我们,按照这种套路啊,就是,根据功能,分析请求,根据操作,分析请求,一步一步开发,这种方式呢,适合这个初学者,但我们工作时呢,时间久了,你熟了,就不这么开发了,你像我,我要写代码,我开发怎么开发呢,我会先想一下,我这个模块,一共有几个功能,那我要先把实体类写好,表建好,实体类写好以后,我要先写Dao,我可以一次性把Dao里的增删改查方法全写完,明白吧,因为我现在写熟了,我一下就能想出来,到底有哪些东西要写,都写出来,但是可能你现在呢,想不出来,你不知道呢,这个功能到底要怎么做,到底有哪些方法需要做,需要去处理,所以你就最好,按照这种方式来做啊,这是需要一个演化的过程。
  • 那其实呢,现在,我们就是按照一个发展的方式来处理问题啊,就是,毕竟我们已经做了一些功能了,对这个web项目,对于我们当前项目的结构,已经有所熟悉了,那像打开登录页面呢,打开主页啊,和打开增加页面呢,打开修改页面,没什么大的区别,我就可以一起处理,熟了就好了。接着判断啊,再判断那个主页的请求啊,是 /toIndex.do啊,好了,那么,这俩路径呢,/toLogin.do/toIndex.do,我都判断了,判断以后啊,写这两个方法,toLogin(req,res)toIndex(req,res),这两方法都很简单,都是转发,就一句话啊。那下面呢,这样吧,我就在service之后写这俩方法,我就别往后去拖拽了,太麻烦了啊,而且拖拽的话,那么远,容易卡啊,所以我就在这,service方法之后,直接写了啊,然后呢,这两个方法的声明啊,它和其他的方法一样,所以,我们可以随便找个方法,一复制,一粘贴,改个名就行了。
  • 那我就近呢,找一个方法,复制,粘贴,然后呢,改名啊,protected void toLogin(HttpServletRequest req, HttpServletResponse res){...},那这个方法啊,它的作用就是打开登录页面,不着急实现,我们把那个toIndex,打开首页,也把它声明一下,那那个方法的结构跟它一样,复制一下,一粘贴就有了啊,这个方法呢,叫toIndex,这是打开主页啊。那这两个方法都有了,我们就来处理呢,这里的逻辑,逻辑很简单就是转发,那么转发就一句话,也没有什么数据,然后呢,我们从Servlet,把请求转发给jsp,那么在写jsp的相对路径的时候,咱们以前也写过,比如说资费查询,那个转发到查询页面,对吧,打开增加资费页面的时候呢,转发到增加的jsp,我们都是从/WEB-INF开始写对吧。
  • 所以到这,我们已经了解这个套路了,都一样,我们这也是啊,从/WEB-INF开始写,跟以前一样就可以了,好,就一句话啊,req.getRequestDispatcher("WEB-INF/main/login.jsp").forward(req, res);。那么登录时转发,这个打开主页时也是转发,那么这个方式呢,都一样,就是jsp的名字不一样啊,所以这段话你可以复制粘贴一下啊,改下名字就好了啊,复制一下啊,我把这句话呢,写到这里来,打开主页这里,然后呢,把jsp呢,改为index就行了。req.getRequestDispatcher("WEB-INF/main/index.jsp").forward(req, res);
视图层之业务基本逻辑与视图显示:/WEB-INFO/main目录下的login.jsp和index.jsp
  • 那么,service当中啊,这两个方法,我们就处理完了,处理完以后 呢,下面我们要写的就是,这两个jsp啊,那么,下面呢,我们就在这个WEB-INF之下,创建一个名为main的目录,然后呢,在这个目录之下,我们创建两个jsp,login.jsp,还有index.jsp,那在/WEB-INF之下啊,我们再重新的创建一个目录叫main,接下来,我们在main之下,创建两个jsp啊,第一个叫login.jsp,第2个叫index.jsp,把他俩创建好。那么创建完这两个jsp以后啊,那么这两个jsp啊,它的第一句话,还是写个指令是吧,我们把这个指令写一下,<%@page pageEncoding="utf-8"%>,这两个jsp呢,你都把这句话呢,写上去啊,都声明好文件的编码,然后呢,这个jsp上面的代码,我们先把那个网页的静态代码粘贴过来。
  • 那么找一下那个静态页面啊,在NETCTOSS_V02的下面,那个登录和主页 ,它就在NETCTOSS根目录下,NETCTOSS_V02,那下面呢有一个文件叫login.html,这就是登录啊,index.html就是首页,主页。那咱们分别处理啊,我们先呢,就是复制,这个login.html网页中的内容,把它粘帖过去,粘贴到logn.jsp之内,那么,粘贴过来以后啊,我们得看一下,就是我们这个网页上的,那个图片和样式的路径对不对,检查一下,你看,这个网页的七八行上面也有link,link上面的路径是,没有点点杠是吧,就对了,是吧,正好,那这个网页上有没有图片呢,搜一下,img,有图片,但是图片的路径上也没有点点杠对吧,正好啊,那它的路径呢,就不需要处理了。
  • 同理呢,我们再去copy那个主页里面的代码,你再打开NETCTOSS_V02,打开完以后啊,用文本编辑器,打开index.html, 然后呢,把这个文件里的代码,全部复制一下,然后粘贴到index.jsp之内,粘贴过来以后,看一下路径,七八行有link,link路径没有点点杠对吧,没有问题。那么到这啊,咱们这个打开登录页面和打开主页,就完成了,总之呢,这个环节是最简单的。这里没有任何业务,就是访问Servlet,然后转发到jsp, 就完了,只是对请求路径加以判断就可以了,那么写完以后啊,咱们可以测一下,看行不行,有没有 问题,那我们把这个项目呢,这个重新部署一下,启动tomcat,启动以后呢,我们打开浏览器,然后,我直接访问这个登录页面啊,这个登录网页的访问路径,是localhost:8080/netctoss/toLogin.do,没错啊,然后呢,再访问这个主页,主页是/toIndex.do,也没问题。

登录模块代码实现之第一个请求和第三个请求:/toLogin.do和/toIndex.do

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 {

	@Override
	protected 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 {
			throw new RuntimeException("没有这个页面");
		}
	}
	
	//打开登录页面
	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();
		//将请求转发到jsp
		req.setAttribute("costs", list);
		//当前:/netctoss/findCost.do
		//目标:/netctoss/WEB-INF/cost/find.jsp
		req.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.do
		res.sendRedirect("findCost.do");	
	}
}
2.servlet-doc/NETCTOSS_HTML/login.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" /> 
    </head>
    <body class="index">
        <div class="login_box">
            <table>
                <tr>
                    <td class="login_info">账号:</td>
                    <td colspan="2"><input name="" 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="" 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="index.html"><img src="images/login_btn.png" /></a>
                    </td>    
                    <td><span class="required">用户名或密码错误,请重试</span></td>                
                </tr>
            </table>
        </div>
    </body>
</html>
3.servlet-doc/NETCTOSS_HTML/index.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" /> 
    </head>
    <body class="index">
        <!--导航区域开始-->
        <div id="index_navi">
            <ul id="menu">
                <li><a href="index.html" class="index_on"></a></li>
                <li><a href="role/role_list.html" class="role_off"></a></li>
                <li><a href="admin/admin_list.html" class="admin_off"></a></li>
                <li><a href="fee/fee_list.html" class="fee_off"></a></li>
                <li><a href="account/account_list.html" class="account_off"></a></li>
                <li><a href="service/service_list.html" class="service_off"></a></li>
                <li><a href="bill/bill_list.html" class="bill_off"></a></li>
                <li><a href="report/report_list.html" class="report_off"></a></li>
                <li><a href="user/user_info.html" class="information_off"></a></li>
                <li><a href="user/user_modi_pwd.html" class="password_off"></a></li>
            </ul>
        </div>
    </body>
</html>
4.src/main/webapp/WEB-INFO/main/login.jsp

<%@page pageEncoding="utf-8"%>

  • 略(同login.html)
5.src/main/webapp/WEB-INFO/main/index.jsp

<%@page pageEncoding="utf-8"%>

  • 略(同index.html)

代码设计与实现之第二个请求:/login.do

  • 那么关于登录功能呢,3个请求当中的两个,1和3请求已经完成了。当然,还剩下关键的第2个请求。那这个登录功能当中的3个请求,已经完成了两个,但这两个呢,逻辑非常简单,然后呢,关键的还是得看第2个请求,但怎么说呢,第2个请求呢,它还是相对于咱们做的那个修改啊,这个增加啊,要这个简单一点,因为什么呢,表单的数据比较少,我们现在就传俩数据,然后呢,也没有什么这个单选什么呢,得到数据呢,只是说查询一下,简单判断一下啊,所以总之呢,相对来说 还是比较容易的,只不过呢,大家没做过,没见过,所以呢,感觉比较,可能有的地方呢,比较陌生,或者说想的话 ,有的地方想不清楚,这样正常啊,那这个代码呢,你一开始这个功能没见过,等你见过以后,下回再去做类似的,你就会了,或者说,我们这个项目的案例,它就是你日后开发其他项目的一个基础,就是说,为什么说有经验的人,在开发新的项目,他就快呢,因为他有基础,他有别的项目的经验,我们现在还没有,那这算是你的一个经验,将来云笔记呢,也算是一个啊,然后呢,将来你工作时,第一份工作的项目,也算是一个,慢慢积累啊,然后以后的话,会越来越好。
登录模块数据库表的创建及准备
  • 那么要做第2个功能啊,第2个请求 ,第2个请求呢,它这个啊,流程比第3个请求要长,比打开登录页面请求和打开主页请求要长,要复杂一点,那么我们开发这样的请求时呢,也是啊 ,按照倒序开发啊,我们按照依赖关系的倒序,你比如说,表单依赖于Servlet,我们先开发Servlet,然后呢,Servlet依赖于Dao,我们去先开发Dao对吧,而Dao的方法要依赖于Admin这个实体类,对吧,先开发实体类,所以就按照依赖关系倒序来写,这就很合理,所以呢,我们首先呢,写这个实体类Admin,不过呢,我们在写实体类之前,还得把表建好对吧,如果没有表的话,就不知道有什么字段,这个实体类没法写了啊,所以呢,下面我们先建表,那这个项目当中啊,所有的建表的脚步,都在那个netctoss.sql里,我们把这个文件打开啊,这个文件啊,就在之前,我给你们传的那个servlet-doc之下,然后呢,文件名叫netctoss.sql。我们用这个编辑器啊,把它打开,找到了么,打开以后啊,那个表呢叫admin_info,这个是设计表的人,就这样取的名字,我们就这样用,其实就是用户表。
代码实现:admin_info

--管理员表
create table admin_info(
   	admin_id 	number(8) primary key not null,
   	admin_code 	varchar2(30) not null,
   	password 	varchar2(30) not null,
   	name 		varchar2(30) not null,
   	telephone 	varchar2(15),
   	email 		varchar2(50),
   	enrolldate 	date default sysdate not null
);

create sequence admin_seq start with 10000;

--管理员表
insert into admin_info values(2000,'admin','123','ADMIN','123456789','admin@tarena.com.cn',sysdate);
insert into admin_info values(3000,'zhangfei','123','ZhangFei','123456789','zhangfei@tarena.com.cn',sysdate);
insert into admin_info values(4000,'liubei','123','LiuBei','123456789','liubei@tarena.com.cn',sysdate);
insert into admin_info values(5000,'caocao','123','CaoCao','123456789','caocao@tarena.com.cn',sysdate);
insert into admin_info values(6000,'aaa','123','AAA','123456789','aaa@tarena.com.cn',sysdate);
insert into admin_info values(7000,'bbb','123','BBB','123456789','bbb@tarena.com.cn',sysdate);
commit;

  • 那我们找一下这张表,在比较靠后的位置,往后找啊,哎呀,我终于找到了,比较靠后啊,它在171行,这个管理员表就是用户表,这个表中的字段呢,它的含义呢,是比较这个简单的,咱们看这个单词,就能看明白,你像admin_id,主键,admin_code,账号,password,密码,name,是管理员姓名,然后呢,telephone,电话,email,邮箱,是吧,都很容易懂,最后呢,这个enrolldate就是创建时间,这个怎么说呢,设计表的这个人啊,我也不知道是谁啊,这个各个表的这个设计的规则,不太一样,你看之前资费表,创建时间叫creatime对吧,这叫enrolldate,这个风格不太一样,也可能是什么呢,也可能是这个表,是不同的人设计的,像以前我们做开发时,那每个人负责呢,设计自己的这个模块的表,有可能呢,这个选的单词,有所偏差,也很正常啊。
  • 然后呢,我们要建表啊,那建完表以后,这个表里呢,我们给它加几条数据啊,那个,这个表里的默认的数据,insert语句,在后面,再往后找啊,再往后,这个220行,一直到226行,是往这张表里插入6条默认数据啊,我们数据加进去,也好用啊,当然这块我多说一句啊,大家想一想啊,咱们开发完一个软件以后,这个软件当中的用户,是怎么出来的,就是软件中的正常,能够登录的用户,是从何而来的呢,是注册的,是吧,那你注意啊,咱们互联网软件是这样,因为互联网软件谁动能用对吧,大家注册,谁想用谁就注册,是这样的。但是企业软件不是,我这个企业啊,比如说有一万人,我这个财务软件是谁都能注册,谁都能看的么,不是,只有财务人员能用,是吧,不是谁都能看的,要谁都能看就遭了,那企业的话,谁都能看到这个财务数据,一看啊,咱们公司今年亏损了,那我离职吧,是吧,明年说,唉,我们公司今年增长了200%,我得跟老板谈谈待遇对吧,出现这个就麻烦了,所以不能让你随便看。
  • 所以说呢,那企业软件的这个账号从哪来呢,是你员工入职的时候,由这个企业的mis,就是mis(Management Information System),然后这个,给你创建了一个账号,是人家给你的账号,明白吧,一般就你的邮箱,总之呢,企业当中员工的账号,是由mis给你创建的,那mis由哪个功能创建呢,它由这个,我们系统中的管理员模块,管理员用户模块,增加,明白吧,给增加一个员工就可以了,就这个意思,不过呢,这个模块,咱们没有做啊,大家就了解这个来龙去脉,简单了解一下啊。这样建表啊,我们回到那个sql里啊,我先把那个create语句复制一下,这个管理员的序列不用了啊,因为怎说呢,我们不做那个管理员的增加功能,序列用不上,不用了啊,就把create,复制一下,然后粘贴到你的sqldeveloper里面,然后把这个表建好 ,建表时注意啊,加后缀啊。
    在这里插入图片描述
  • 另外还要加入几条数据啊,你再把那个insert语句,关于这张表的insert,复制一下,然后呢,我们向这张表之内插入6条数据,别忘了commit,当然了,你插入的时候呢,表名的后缀,别忘了加上去啊。
    在这里插入图片描述
  • 建好以后,看一下这个数据啊,这6个数据有谁,不多说了,比如说我这个caocao,然后,6个用户的密码都是123,对吧,是这样,一会啊,我们做完登录以后啊,我就利用caocao登录,密码123啊,就这样。
    在这里插入图片描述
登录模块业务层之数据建模实体类:/entity/Admin.java
  • 这表建好了没有,行了吧,建好以后,我们说了,我们首先开发谁呢,实体类,这东西,我们直接写吧,没什么好讲的啊,我们在这个entity包下,创建一个新的实体类,类名,我就叫Admin,实现序列化接口,满足规范:
    在这里插入图片描述
  • 那这个表里呢,是几个字段,我看一下啊,表里是1234567个字段,那么实体类中,我们写7个属性与之对应,写一下,一共7个属性,写完之后,生成get/set。这个实体类当中啊,一共有7个属性,然后呢,第一个主键是整数啊,然后中间的5个是字符串,账号,密码姓名 ,账号,邮箱,最后呢,创建时间,记载数据的创建时间,是时间戳,java.sql.Timestamp,这个类型不要引错了,写完以后生成get和set,写完了么,那下一步啊。
业务层之业务数据处理与数据存储:/dao/AdminDao.java
方法准备之创建连接:AdminDao.findByCode()
  • 实体类写完了以后啊,下一步,写这个Dao对吧,写个查询,AdminDao.findByCode(),你像之前,咱们学这个资费的时候,咱们写过findAll()对吧,查询所有数据,我们也写过呢findById对吧,根据id查出一个对吧,一个数据,那这个AdminDao,是findByCode(),那你想,findByCode(),它能查到一条数据,还是多条数据,一条,因为账号显然是唯一的对吧,所以呢,返回的数据是一个Admin,不是集合对吧,一条,那我们写一下,那这个方法,和之前资费模块的findById(),一样的啊。
  • 那下面呢,我们因为这是一个新的模块啊,我们在这个,dao这个包下,再创建一个新的Dao,那这个类呢,我取名叫,AdminDao,看一下,我们当前的代码结构,那么目前啊,Servlet只有一个,实体类两个对吧,Dao两个,那么随着项目的功能越来越完善,这个实体类和Dao,会越来越多的,但是呢,我们Servlet还是只有一个对吧,这个没有,并没有矛盾啊,那下面呢,我们就来写这个Dao, 那么它里面呢,主要是提供一个查询方法啊,我们写查询方法,那么这个方法呢,因为呢,要被别人调用,被复用,所以呢,公有的,谁都能调啊,那么这个方法呢,因为,根据账号查询,所以呢,它的返回值是一个,一个管理员,一个Admin啊,条件就是账号,那么这是一个查询方法,我们写一下它的逻辑啊,首先呢,先创建连接啊。

public Admin findByCode(String adminCode) {
	Connection conn = null; 
	try {
		conn = DBUtil.getConnection();
	} catch (SQLException e) {
		e.printStackTrace();
		throw new RuntimeException("查询管理员失败",e);
	} finally {
		DBUtil.close(conn);
	}
	return null;
}

  • 我们创建了这个连接啊,有异常,我们就捕获,往上抛,然后呢,最终连接要关闭。那么连接创建好以后呢,我们要写一个查询语句啊,写个查询语句,String sql = "select * from admin_info_lhh "+"where admin_code=?";,那你注意啊,咱们这个现在呢,是做项目,我们是以项目来贯穿,这个体会,我们之前呢,所讲的这些技术点啊,那么在项目里,你会发现呢,这个项目呢,它是怎么说呢,它前后会有关联的,你要是查询没做的话,直接做增加好像有点别扭是吧,你要是增加没做好,你做修改,就更别扭,它是层层递进的,所以说,说白了,这个项目前后,这个代码,可能有一些依赖,尤其是我们后面,讲什么session啊,cookie啊,filter啊,这些内容,我都会在这个项目内演示,如果你这个项目,我没做,或者没做好,我去演示那个东西,没法演示。
项目心得:学习状态与游戏心态
  • 就总之呢,我们到这个阶段,我们这几天的课程,前后之间呢,是有一个依赖性的,而且依赖的还挺紧啊,所以你哪一天呢,万一没跟上,确实对后面有影响,有人说老师,你这个,你像有同学跟我说,老师你这个课程,设计的不太合理吧,你这个,你耦合度太高了,是吧,你是不是得解耦啊,我想一想,好像有点道理,我就问苍老师,我说,我这耦合度太高了,我是不是得解耦啊,苍老师说,如果你解耦的话,你就讲helloworld就可以了,我想一想还是算了吧,咱都写helloworld,这个,你进步的空间太小了,咱们不能凡事都用这个解耦去解释,明白吧。像那么讲,咱们人和人之间都解耦,谁都没有关系得了是吧,都出家去算了是吧,不是那么回事啊,那出家也有耦合度是吧,你没法解耦,就是说,我们说解耦是,以管理者角度,去看待代码是吧,是这个意思,我们生活中,这个讲课也好,还是生活也好,过日子也好,这个不能说用这个角度去,去解释这件事。
  • 然后呢,我们做项目,项目是必然会有耦合度的,你工作时,你就会发现,你工作时,我们肯定是先,先做注册功能,再做登录功能对吧,再做各个增删改查,然后呢,很多企业的这个业务是连续的,你必须呢,先做前一步,才能做后一步,你像我要去淘宝买东西,我就必须得先注册账号对吧,然后,登录,才能买,必须得这样,我还得有这个支付宝和网银才能买,它有前提条件,它就必须有一个依赖关系,有耦合度,这是拆不开的,所以呢,没有办法,那么,那万一有同学说,那老师啊,我确实这块就没跟上,我今天就是没跟上,我就有点问题卡住了,或者今天我就没来,我就请假了,有点事,我跟不上,就是跟不上,明天受影响怎么办呢,那课后的话,你把这个内容呢,赶紧复习一下,赶紧跟一跟,当然了,可能你还是跟不上,怎么办呢,你把我之前所写的代码,你下载下来,你用我的代码执行一下明白吧,你把这个查询啊,增加啊,登录啊,一执行,哎,可以用了,大概看一下代码结构,或者让项目经理给你讲一下,你了解了,了解完以后,我们后面的功能,你就在我代码基础上再写,课后你再去补,明白吧,你不要说,哎我这个,这块没跟上,我就松懈了,我就算了。
  • 很多人呢,对待这个学习啊,我感觉,或者说对待这个生活呢,有点受游戏的影响啊,我们打游戏什么套路呢,这个区没练好,怎么办,换个区重来一遍,我又没练好,怎么办,我再来个区,我三番五次,我不嫌腻歪,但是你过日子你这么干,这有点不太合适,是吧,你说我,哎呀,我这个当初我这个学习没学好,我大学没考好,我重来一遍,还行,你重来两遍怎么办,或者现在你说我学这个编程,哎,我感觉,我当时没读本科,我读了个专科, 我这个当时没学好,我从来一遍,那代价太高了,对吧,你只能去弥补啊,咱们过日子和游戏不一样,你不要老用游戏的态度,用在这个生活上,这会吃亏的啊。
  • 而且是什么呢,你说我这个,这次,我讲课,我没跟上,得了,我等我那个下次课,下个班我去留级了,再来一遍,那你想一想,你再来一遍的时候,有没有可能又有事,又请了一天假,或者说,我下次,我感冒了,我不是诅咒你感冒啊,你万一感冒了,又请一天假,又没跟上怎么办,再留级一次,下次又有事怎么办,没完没了了,这个生活和游戏不一样啊,你呢,有遇到问题,你要去弥补啊,要去把以前拉下的内容,补上去,争取赶上去,而不是说,我放弃从来一遍,你的人生没有那么多时间,给你去放弃,所以说呢,最好是一次想办法搞定,想办法解决问题,而不是说,我必须重来一遍啊,对自己要求,可能要求太完美了啊,这个没有人能够活的完美啊,没有人能学的完美,最好一次搞定就算了。
方法主体之数据持久化:AdminDao.findByCode()
  • 总之啊,就是说,万一你由于各种各样原因呢,就是这个内容没跟上,为了不影响明天或者后面的进度,你呀,课后,把我的代码一下载,执行通,下次课要在这个基础上演示什么东西,你用我的代码演示,明白吧,接着写,跟上后面的进度,这段的进度没跟上,课后周末,补一补,是吧,可以补,不是不可以啊。好了,这有点扯远了,回来啊,那刚才呢,我们写了一个sql啊,查询这张表admin_info,条件是账号,等于某值,admin_code=?。那么因为是这个sql有条件,要执行它,我得用PreparedStatement啊,我就创建这个对象啊,PreparedStatement ps = conn.prepareStatement(sql);,我创建对象,发送并编译sql,然后呢,给这个sql的参数赋值,就一个参数,很好办啊,参数1啊, 它的值就是,传入了条件adminCode,ps.setString(1, adminCode);,然后呢是,执行查询,返回的是结果集啊,ResultSet rs = ps.executeQuery();
  • 我给参数呢,赋了值,我执行了查询,得到了结果集,那因为是根据账号做的查询,结果集中顶多就一条数据,对吧,那我们不用遍历了,判断一下就好了,对吧,判断一下啊,有数据呢,就封装返回,没有数据就算了。

if(rs.next()) {
	Admin a = new Admin();
	
	return a;
}

  • 那么,如果呢,有数据,我就实例化一个Admin对象,最终呢,return这个对象,返回这个对象,那如果说呢,没有数据,比如你账号传入错了,没有数据,那没有数据,我们最终return null;对吧,空值。那么有数据的时候呢,我们需要把,这个结果集当中的数据,封装到对象里,那封装的方式,和我们资费时的方式差不多对吧,一样的啊,那封装吧,我们查到的结果集当中,一共是7个字段,然后呢,我依次的把它取到,取到以后呢,把这个值依次呢,设置给对象,7个,完成以后呢,return啊,那么这个Dao呢,很关键啊。

if(rs.next()) {
	Admin a = new Admin();
	a.setAdminId(rs.getInt("admin_id"));
	a.setAdminCode(rs.getString("admin_code"));
	a.setPassword(rs.getString("password"));
	a.setName(rs.getString(rs.getString("name")));
	a.setTelephone(rs.getString("telephone"));
	a.setEmail(rs.getString("email"));
	a.setEnrolldate(rs.getTimestamp("enrolldate"));
	return a;
}

  • 然后呢,通常我们写完以后,我们都需要呢,进行一个测试,没有问题,我们再继续,有问题一定要把它搞定,所以呢,下面我写个main方法,把这个这个方法测一下。我们在这个AdminDao这个类当中呢,写个main方法测试啊,调用它的findByCode()方法,比如说,账号我传入的是caocao,我看一下,能不能查到这条数据,我调这个方法呢,传入caocao这个账号,然后呢,得到的数据,我随便输出两个,输出id,输出name,看一下,这俩属性没问题,其他的应该也没有问题。

public static void main(String[] args) {
	AdminDao dao = new AdminDao();
	Admin a = dao.findByCode("caocao");
	System.out.println(a.getAdminId());
	System.out.println(a.getName());
}

  • 那下面呢,我来执行一下这个方法,一执行呢,有数据,5000,caocao没错啊,那么如果你执行有问题的话,通常,这个问题呢,容易出现在哪里呢,sql里,是不是表名写错了,是不是,这个字段名写错了,甚至呢,是不是这个关键字写错了,也或者呢,是我们在取值的时候,这个字段名,容易写错了,好好检查一下。
    在这里插入图片描述
控制层之业务逻辑处理与控制分发:/web/MainServlet.java
  • 那dao写完以后,下一个环节,看啊,下一个环节,就是写Servlet,那么,在Servlet之内,我们需要接收浏览器传过来的参数 对吧,账号密码,两个参数,然后呢,加以判断,那我们来写这段判断的逻辑,那大家呢,打开MainServlet,然后呢,回到那个service方法,然后呢,我们需要在这个方法之内,再加一次判断,再加一个判断,那么如果呢,else if("/login.do".equals(path)){ login(req,res); },传入的路径是/login.do,我们调login方法, login是登录啊,正式登录,那么我们写这个方法,这个方法的声明,和其他的方法一模一样,所以复制粘贴,改名就可以啊。
  • 我随便找个方法复制一下,然后呢,粘贴一下改名啊,我把这个方法,就写在service之后,我就不想往下拖拽了啊,改名为login啊,这个方法是登录啊,然后呢,还是那句话,就是说,我们以MVC模式去处理这个请求,那基本上呢,每个请求的处理方式都差不多,啊,接收参数,处理业务,或转发,或重定向,那我们这个案例呢,有参数,所以得先接收参数对吧,是吧,先接收参数啊,那大家想一想,我们接收的参数里面,有没有中文啊,有,在哪呢,你的观察不够细致,你看,咱们登录功能时,后面不有一句提醒么,就告诉你要输入什么格式的数据,对吧,提示你了,有字母,数字,下划线是吧,密码也是字幕数字下划线,明白吗,是这样吧,有提示,没有中文啊,我们写完整的话,应该写js验证明白吧,这里我就不写js验证了,你要像自己写的话,自己写一写,和我们讲js时,那个讲模拟做的登录,那个套路一样。
  • 总之呢,没有中文,没有中文的话,那个,那句话可以不用写了,是吧,我就不写了,那当然了,这个登录功能,虽然说,只有账号密码两个数据,但是也是的用post对吧,是吧,因为有密码,你要保密啊,肯定是post,反正,直接接收参数就可以了,接收参数啊。

//接收参数
String adminCode = req.getParameter("adminCode");
String password = req.getParameter("password");

  • 接收到了账号密码以后,我们所要处理的业务是干什么呢,是要对帐号密码进行一个验证,或者说检查,看它对不对,那么验证的话,我们得查询对吧,调AdminDao,实现查询啊,那么我实例化AdmDao,调了dao的方法,findByCode(),查询方法啊,得到了这个 Admin啊,然后呢,我对这个结果判断就知道,账号对不对,判断一下,那么如果查到的结果是空的,表明什么呢,账号不存在对吧,或者说账号是错的, 那么如果说呢,这个得到的结果a不为空 ,我们还得怎么样呢,看a中的密码和我们得到的密码,接收的密码一不一致对吧,还得看密码,就再判断啊,else if啊,判断一下,我们查询的密码和输入的密码是否一致,然后呢,要注意,你看我在这个判断相等之前,加了个感叹号,表示不等对吧,不等,那如果两个密码不等的话,说明什么呢,密码是错误的。然后呢,否则,否则什么情况,账号密码都对,对吧,那么验证就通过了。

//验证 
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)) {
	//密码错误
	req.setAttribute("error", "密码错误");
	req.getRequestDispatcher("WEB-INF/main/login.jsp").forward(req, res);
} else {
	//验证通过
	res.sendRedirect("toIndex.do");
}

  • 那你看啊,如果说最终,验证通过怎么办,就成功了,怎么办呢,看这条线从MainServlet.login()/toIndex.do这条线,到哪去啊,主页,重定向到主页对吧,哎,这一步先写一下,重定向 ,重定向的路径,我不再重复了,参考资费查询和增加,那个逻辑,就直接写了啊,res.sendRedirect("toIndex.do");,就重定向到首页,主页啊,/toIndex.do啊,然后呢,另外两种情况,账号错了,或者是密码错了,无论是哪种错误,都是错了对吧,错了怎么办呢,转发到login.jsp对吧,那这两个错了,都转发到这login.jsp,区别是什么呢,这个error提示不同对吧,error不同。那我们写一下啊,这种情况,账号错误,那个错误提示,应该是error等于账号错误对吧,我们把这个错误信息呢,传给login.jsp啊。就req.setAttribute("error", "账号错误");,那密码错误时也是要发送一句,这样一句话,对吧,传一个这个消息,所以还是写这句话,在密码错误时,再写一遍,只不过呢,这个信息啊,改为密码错误啊。这句话在这,密码错误时,再写一遍啊,然后呢改为密码错误,req.setAttribute("error", "密码错误");
  • 总之啊,那无论呢,是账号错了,还是密码错了,我们都是向login.jsp,传一个错误的消息啊,加以提示啊,然后呢,传过去这个信息以后,我们得转发对吧,转发,在账号错误这先写啊,req.getRequestDispatcher("WEB-INF/main/login.jsp").forward(req, res);啊,这个转发的路径,我也不再说了,参考咱之前做的,其他的jsp,啊,一参考就有了,都一样的套路。那么密码错误时呢,也要转发,这句话呢,复制账号错误就行,然后密码错误时呢,粘贴一下,再来一遍,req.getRequestDispatcher("WEB-INF/main/login.jsp").forward(req, res);。那么这段呢,判断的逻辑,到这就写完了,这个逻辑啊,还是比较这个清楚的,比较容易理解,总之呢,就判断呗,就是我们接收账号密码,然后呢,根据账号查询,如果查到结果为null,账号错了,账号错了,给个错误提示,转发到错误页面啊,密码错了,给个错误提示,转发到这个登录页面啊,否则就都对了,重定向到主页,啊,就这么一个逻辑啊。
视图层之业务基本逻辑与视图显示:/WEB-INFO/main/login.jsp
  • 那这个类,写完以后,还有最后一个环节,最后最后一个环节啊,最后一个环节呢,就是,咱们这个登录页面,表单得处理,对吧,账号密码,表单得配置啊,那我们配置一下,那我们打开这个login.jsp啊,我们找到这个网页上,表单所处的位置,但是很遗憾,找不着啊,没有,这个美工呢,她这个,怎么说呢,她手艺比较潮啊,她没写form,没写form的话,这怎么办呢,咱们自己加上去呗,没招啊,那么,它这个账号密码,验证码,都在table之内,那我把它table之外,套个form,行吧,<form action="login.do" method="post">,这个范围就可以了啊,所以你看,我在12行啊,这个table之外,这写个form,当然了table这是表单的开始,表单结束于table之后,对吧,所以,你把表单的结束的符号,把它弄到这个table的后面去。所以, 整个table,就涵盖到了form之内。
  • 然后呢,这个form之上,我们需要加以声明,声明要提交给谁啊,我得写action,还得写呢,请求方式啊,method,请求方式为什么呢,post,然后啊,这个提交给谁啊,看一下,action提交给的是/login.do对吧,根据增加功能,保存时的那个参考,我们这个路径应该写成什么呢,就是/login.do啊,参考增加就知道了, 这是第一项配置,第一个配置,还没完,那表单上的框,还得有name,对吧,那账号啊,这个name,在16行,16行,name等于adminCode和AdminDao中的getParameter保持一致。然后呢,同理啊,密码,密码的框呢,是在21行,name="password",最后我们,验证码先别管,先当它没有啊,账号密码的name都有了。
  • 最后,我们看一下,登录按钮啊,美工的手艺呢,比较潮,它没有按钮,登录是个啥呢,登录是个,登录按钮是个图片,图片外面套了个超链接,是吧,他这么干的,两种办法,一种是我们自己加个submit,明白吧,不要超链接这个东西,但是我们还得写样式,我懒着写了,第2种是,我们就将就吧,就将就这个超链接啊,那我点超链接时要提交表单,这得怎么办呢,我们需要写js,我们用js可以提交表单,那怎么,写js怎么提交表单呢,这个我这块写一下注释啊,这是表单提交的方式,其实不只是一种,有两种,第一种是,点击submit按钮,触发表单的onsubmit事件,这是一种方式,这是第一种方式,以前都是这么办,现在呢,没有这个submit按钮,我们没法去触发这个事件,其实还有第2种方式啊,第2种方式是这样的,是通过js调用表单的submit方法,就是说呢,这个表单元素,不单有onsubmit事件,还有一个submit方法,你要是调这个方法也能提交表单也可以,那现在我们用js调下这个方法也行啊。
  • 那这个js呢,显然我要写在这个href="index.html",这个超链接上,那显然,我需要把href中index.html这个网址去掉,要写js啊,在这里写,那你注意这里啊,href当中,不能直接写js,你要想写js,必须得声明,javascript冒号,冒号之后再写js,这是要求,以前没有说过,遇到了就说一下。后面呢,我们写一句话就可以了,我们通过js获取到form,调它的方法就行,那我们在网页上想获取到一个元素,可以用id获取对吧,你可以加个id啊,document.getElementById,可以,但我懒着加了,还有更简单的办法,这以前也没讲,咱们现在呢,遇到了,就也可以用一下,可以这样写啊,document.forms,forms呢,是得到网页上所有的form,得到是一个form数组,那你想我们网页上,有几个form啊,就一个,所以数组下标为0对吧,得到唯一的这一个form,然后呢,调用它的submit方法啊,就可以了,然后呢,分号结束即可,href="javascript:document.forms[0].submit();",即<a href="javascript:document.forms[0].submit();"><img src="images/login_btn.png" /></a>
  • 然后呢,还有一个小的细节要处理,就是说,我们在转发时,不还传了个error给它么,对吧,这个error还得显示对吧,显示在哪呢,我们就把这个error显示到这个,这个span里就行了,在这个span里显示error,用el输出就可以了,<td><span class="required">${error }</span></td>,那么就完成了,我们就可以测试了,那我测一下啊,把这个项目呢,重新部署一下,启动tomcat,启动以后呢,我打开这个登录的页面啊,登录,打开登录网页,不用管验证码,填账号啊,比如说我随便瞎填一个,瞎填个密码,一点登录,它告诉我账号不对,我填一个正确账号,caocao,填一个错误的密码,1,登录,它说密码不对,我填正确账号,caocao,正确密码123,点登录,进去了。这个登录功能就完成了。

登录模块代码实现之第二个请求:/login.do

1.src/main/java/entity/Admin.java
package entity;

import java.io.Serializable;
import java.sql.Timestamp;

public class Admin implements Serializable {
	
	private Integer adminId;
	private String adminCode;
	private String password;
	private String name;
	private String telephone;
	private String email;
	private Timestamp enrolldate;
	
	public Integer getAdminId() {
		return adminId;
	}
	public void setAdminId(Integer adminId) {
		this.adminId = adminId;
	}
	public String getAdminCode() {
		return adminCode;
	}
	public void setAdminCode(String adminCode) {
		this.adminCode = adminCode;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getTelephone() {
		return telephone;
	}
	public void setTelephone(String telephone) {
		this.telephone = telephone;
	}
	public String getEmail() {
		return email;
	}
	public void setEmail(String email) {
		this.email = email;
	}
	public Timestamp getEnrolldate() {
		return enrolldate;
	}
	public void setEnrolldate(Timestamp enrolldate) {
		this.enrolldate = enrolldate;
	}
}
2.src/main/java/dao/AdminDao.java
package dao;

import java.io.Serializable;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import entity.Admin;
import util.DBUtil;

public class AdminDao implements Serializable {

	public Admin findByCode(String adminCode) {
		Connection conn = null; 
		try {
			conn = DBUtil.getConnection();
			String sql = "select * from admin_info_lhh "+"where admin_code=?";
			PreparedStatement ps = conn.prepareStatement(sql);
			ps.setString(1, adminCode);
			ResultSet rs = ps.executeQuery();
			if(rs.next()) {
				Admin a = new Admin();
				a.setAdminId(rs.getInt("admin_id"));
				a.setAdminCode(rs.getString("admin_code"));
				a.setPassword(rs.getString("password"));
				a.setName(rs.getString("name"));
				a.setTelephone(rs.getString("telephone"));
				a.setEmail(rs.getString("email"));
				a.setEnrolldate(rs.getTimestamp("enrolldate"));
				return a;
			}
		} catch (SQLException e) {
			e.printStackTrace();
			throw new RuntimeException("查询管理员失败",e);
		} finally {
			DBUtil.close(conn);
		}
		return null;
	}
	
	public static void main(String[] args) {
		AdminDao dao = new AdminDao();
		Admin a = dao.findByCode("caocao");
		System.out.println(a.getAdminId());
		System.out.println(a.getName());
		System.out.println(a.getPassword());
	}
}
3.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 {

	@Override
	protected 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 {
			//将账号存入cookie
			Cookie cookie = new Cookie("user", adminCode);
			res.addCookie(cookie);
			//将账号存入session
//			HttpSession session = req.getSession();
			session.setAttribute("user", adminCode);
			//验证通过
			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();
		//将请求转发到jsp
		req.setAttribute("costs", list);
		//当前:/netctoss/findCost.do
		//目标:/netctoss/WEB-INF/cost/find.jsp
		req.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.do
		res.sendRedirect("findCost.do");	
	}	
}
4.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" 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" 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>

写在后面

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值