上面是静态页面
下面进行我们的操作
下面是用户名的验证
下面是密码的验证
确认密码
邮箱验证
为了防止有人在验证码中输入一堆空格
下面我们要将在客户端(浏览器)中输入的用户名,密码等信息发送给服务器,
并且将其保存到数据库的
上面的登录信息也一样,我们同样发送给服务器,服务器获取用户名和密码,
并到数据库进行检查,正确则登入成功。
下面我们在WEB-INF中新建lib,放入Druid(德鲁伊)和mysql驱动
下面我们添加jar包
一个librarys类似于一个分组效果,一个组里面可以有多个jar,我现在将某个组挂在某个module下面,就将组里面所有的jar挂在了这个module下面
我们其实也可以右击直接添加到项目中(直接右键单击jar包,add as library即可),上面这样是为了方便管理
我们再将book_lib这个jar包添加到book这个module下
jar包前出现了 > 的标记
使用druid需要下面的配置文件
下面对其进行测试
记得每次用完都要关闭数据库,释放资源
其中新加入的两个jar是用来,运行@Test的
要使用DbUtils操作数据库,要先导入包
这里直接将这个包加入book_lib中就行了,不需要后续的操作
下面是查询返回一个对象
记得关闭连接
下面为查询返回多个对象
下面为查询某一列某一行的情况
下面我们要编写具体的Dao,BaseDao是为了让UersDao继承才写出来的
我们先写接口
下面为接口的实现体
下面我们测试一下
返回-1表示插入失败,1表示插入成功
Service是业务层,比如登入和注册都是service
我们先写接口
下面写实现体
下面的三个操作我们都要去操作数据库
下面我们new一个数据库对象进行操作
下面我们依旧进行一下测试
配置
Regist.html就是注册页面
下面是它的form表单,表单的提交对象是registServlet
这里表单的提交对象只要写registServlet就可以
因为前面已经有了base标签,如果没有base,写绝对路径
下面我们进行写服务器代码
验证码错误的话,跳回注册页面
我们由下图知道,web层只能调用service,是不能直接操作Dao
所以我们要在其中准备一个userService
在html页面上面填下面这句话,并且将文件的html后缀改为jsp即可
其中的一些页面调转可能还含有html后缀,我们可以批量的查找替换
我们点击ctrl+R,这个就是查找替换
我们也可以点击ctrl + shift + R
*.jsp表示以jsp为后缀的文件
Directory表示按照目录进行搜索
Module表示按照模块进行搜索
右下角的replace all表示替换全部
新建common文件夹存放所有相同的内容
将其中 登入成功 的内容提取出来单独放一个jsp文件中
在其他jsp文件中直接引用这部分
比如将下面的部分进行替换
其他的也进行替换
下面同样的,我们将一些头部信息提取出来,单独放一个jsp文件中
(要将所有页面全部替换掉,下面没有截图)
最后我们再将页脚部分全部提取出来
同样要将所有页脚全部替换
下面我们将文本中相同的内容继续提取出来
同样将所有jsp页面中的内容全部替换
假如我登入的时候是用具体的ip地址时,我们发现登入book时是服务器的ip地址
但在其他界面就是localhost(本机)。
这里如果是我自己访问页面,就没有任何问题,但是其他人访问,这个localhost是到你的电脑上面去访问的
出现这个的原因是我们的base标签定死了路径
所以这里的ip地址,工程路径我们都有必要动态获取
下面我们就动态的得道完整的路径
我们将其替换即可
在登录或者注册的时候,如果发生错误,应该给用户一些提示,
告知用户是密码错误还是用户名错误
并且之前的输入的用户名密码等信息还要留在表单框内
下面在输入错误的用户名或者密码时的情况
下面实践一下,随机输入一个错误的用户名或者密码
下面我们进行用户名和密码的回显操作,表单框中的值是由value决定的
这里我们假如由于验证码错误,注册失败
另一种注册错误是用户名已经存在
以上两种错误我们都回显了错误原因,并且回显了错误信息,
以及回显了填写的用户名和密码信息
下面在页面中进行修改
LoginServlet和RegistServlet都是用户模块的功能,我们将其合并为一个userServlet,
这样的话,一个UserServlet就可以处理两个功能
下面在登入注册的页面中添加隐藏域
我们将userServlet地址放到登入注册里面
我们在userServlet中写两个功能login和regist,
将loginServlet和registServlet的代码复制粘贴到其中
我们上面每添加一个功能,旁边就要用else if做一个判断
这样我们每次都要修改dopost中的代码,要是有种方法可以一次性写好,不管调用什么功能,右边就能调用相应的功能,我们可以通过反射实现
下面我们先模拟一下
到这里我们已经得到了方法,下面我们要进行方法的调用
下面我们在进行实际代码的优化
这里我们的实际代码中有参数req和resp,所以action后面要跟两个参数
Invoke后面:
this是对象实例
req是第一个对象参数
resp是第二个对象参数
由BaseServlet去继承HttpServlet,
而其他的模块,比如UserServlet模块继承BaseServlet即可
如下所示,我们在登入注册中都要将请求参数封装成一个User对象
此项目中的参数比较少,
但实际开发中,我们可能有十几个参数
我们不仅需要获取参数,还要new对象,调用set方法等
非常麻烦
BeanUtils类可以解决这个问题
下面演示一下如何使用(上面的get方法全不用)
我们可以将上面的方法封装到一个JavaBean中
下面我们来看一下他的原理
当我们改了set方法后,这个值无发注入
这就是为什么我们改了set方法后,无法注入
下面还有一个点需要注意,我们将HttpServlet改为Map
下面主要讲req改为req.getParameterMap()即可
上面修改之后,功能没有任何的影响
那么我们为什么要这样改呢
我们项目还有Dao层和Service层,而这两个是没有HttpServletRequest的
我们下面还可以再做简化
下面代码就变成了一行,但我需要一个类型转换
我们可以直接使用泛型
这样写就不用类型转换了
EL输出空值的时候就是空串,我们可以省去判断
img_path表达存储的图片的路径
在其中存储一些用来测试的数据
img_path中放的为图书的默认地址
下面为测试
我们在接口处点击快捷键ctrl + shift + t
Destination package是测试的地址
下面勾上5个要测试的方法
实现接口
我们访问的时候是Get请求,而方法只有doPost
我们可以在doGet方法中调用doPost方法,这样他们做的工作就是一样的了
首先其中要添加隐藏域,告诉系统要调用哪个方法
这里的name中的属性值要和Book类中的属性值一致,这样才能使用BeanUtils中注入
下面是实际的代码
bookServlet?action=List是指请求转发到bookServlet并且调用List方法
List方法是生成图书页面的
这里就是重新生成一下页面,将新增的图书添加其中
上面我们发现时间简史已经添加完成
但有一个bug,就是我们在这个页面点击F5刷新的时候,又一个时间简史会生成
这个bug就是表单重复提交
所以这里我们不应该使用请求转发,请求转发是一次请求。
应该使用重定向,重定向是两次请求。
这里注意,请求转发的 / 是到工程名
重定向的 / 是到端口号,所以前面要加上工程名
这里的将字符串转化为int会用到很多次,
我们将其做成一个方法,放到webUtils中,以便随时调用
defaultValue是一个默认值,当我们转换失败的时候就返回这个默认值,
我们这里将默认值设置为0
上面写错了
我们有时候会不小心点到删除,所以我们在删除的时候,需要提示一些内容
下面我们给删除提供一个单机事件
this是当前正在响应的dom对象,我们要找到他父元素的父元素里面的第一个文本内容
下面我点击一个修改
下面应该显示我刚刚点击那一条记录
最后到book_edit.jsp页面中输出信息(下面是直接用EL输出的,我自己写的个人基因组存储系统是用jsp输出的)
我们的添加和修改都是在下面这个book_edit.jsp的页面中实现的
而我们的book_edit.jsp中已经有了一个隐藏域add
先在还需要一个update
实现方案一:
下面我们点击添加图书
页面上面就有一个参数add
我们代码中的value就通过${param.method}得到这个参数
当我们在页面点击修改的时候
代码变为
解决方案二:
当我点击添加的时候,上面没有参数
当我点击修改的时候,上面有参数id
我们将其放到value中
解决方案三:
我们在添加时,直接进去book_edit页面
我们在修改操作时,会经过bookServlet(查询有没有这个图书)
如果request域中有一个图书对象的话,就是修改
没有的话,就是添加
这里我们就采用方案二
这里操作会失败,因为我们这边修改需要根据id,而我们上面没有上传id
我们再添加一个隐藏域,用来获取id
在我进入这个页面的时候,就是点击图书管理的时候,我就应该请求这个分页方法page了
下面是web层的代码
下面是service层的代码
下面是Dao的代码
最后我们在jsp页面进行遍历,之前是遍历books,现在是遍历page中的items
下面就是展示出了第一页的数据
这里还有个问题,就是我们在首页和尾页的时候,再点击上一页和下一页就没有意义了
我们在首页和尾页的时候,让上一页和下一页隐藏起来
输入3,要调到第三页
我们先给按钮绑上单击事件(这里jQuery单机事件直接写在了body体中,似乎也是可以的)
比如这里填写的是百度的地址
点击确定后,直接跳转到百度
这里我们将上面的地址,复制粘贴到其中,页面变为当前页码即可
这里还有一个小问题,当我跳转到第5页的时候
虽然页面跳转了过去,但是输入框中的内容还是显示的4
下面我们做一个修改
这里还有一个问题,下面的ip地址是localhost,其他人访问的时候会出现问题
下面我们修改一下
假如我们输入50(超过了最大页数),或者一些负数
下面我们调整一下
我们在单机事件中加入if判断(这里没有写)
下面提示了一下,下面给出了总页码
我们输入的值,不能>1,也不能<总页码
很多老程序员,可以越过我们的前端jsp页面,直接在网页栏输入pageNo=50
但这个一定会经过服务器,我们可以在服务器做一个校验,
思路:如果下面这个Pageno值 < 1,我们就将其设置为1
如果 > 最大值,我们就将其设置为最大值
我们在bookService的page方法中去实现这个思路
这个代码从功能角度来说已经实现了
但从合理范围,或者优雅的角度来说不行,这个有效边境检查,每个模块只要有分页,我们都要做,我们可以将其放到下面的部分中
我们下面可以进行一下优化,其中有部分是一模一样的,只是begin和end不同
上面的代码就是判断一下begin,end的值
判断完之后,在执行最后的这个代码
添加完后没有数据,添加完后,它重新跳到了列表管理的list页面
分页做完之后,我们要将但凡跳转到list页面的,全部转化到page
添加提交后,跳转到了第一页,第一页并没有看见我们最后提交的记录
这种情况我们可以在跳转的时候,将最后一页的页码发过去,让其跳转到最后一页
改为
然后这个最后一页来到这个book_edit这边
我们现在添加图书,最后一页为11, 11就进入隐藏域中,服务器就会知道一共有11页,
跳到最后一页
我们重定向的时候也要加上这个页数,以便直接跳转过去
我们现在再添加数据
确实是跳到当时的最后一页11页了,但此时还是没有看见添加的记录,因为此时一共有12页了
下面有个简单的方法,直接加1即可(不用担心有空位,之前做了校验,
超出最大页数,直接转到最后一页)
下面我们进行删除的调整,
删除同样要将当前页面发过去,然后转到当前页码看删除的记录还在不在
修改
同样将当前页码发过去,以便跳转到当前的修改页面,进行查看
上面的网址只写到了工程路径,所以会默认访问index.jsp页面
ClientBookServlet中也有一个page分页方法
他的请求地址换一下
配置一下
将原来的index.jsp的内容复制过来
原来的index.jsp只负责请求转发一件事
下面我们写index.jsp的内容
循环遍历page的内容
下面看一下,只有两条信息
两条是因为前面做分页的时候设置PAGE_SIZE的大小为2
下面的分页条从之前做的复制粘贴过去即可
但是其中的地址要变一下,manger变为client
Ctrl + shift + r 或者ctrl + r
前台和后台的分页部分,除了前面的地址不同,其他部分全部一样
我们可以将地址抽取出来
我们将client/bookServlet?action=page替换为 ${requestScope.page.url}
除了首页这个,后台也需要替换
下面我们再进行其它的设置(下面是后台)
下面是前台
改完之后有个好处,后面改地址更加方便
前后台分页操作完全一样
我们可以将分页代码提取出来了
然后再调用
前台
后台
比如这里我们查出价格10-50全部的图书,并且做一个分页的处理
Integer.MAX_VALUE是一个特别大的默认值(包含数据库里面图书的最大价格)
下面实现这个接口方法
下面是数据库的接口方法
这里看起来很乱,我们进行一个排序
下面是@Test得到的结果,我们截屏Test
当我点击下一页的时候,上面的价格区间就不见了
而且我们的页数还变多了
我们可以看见下面的请求地址中,没有带上面的价格区间
这表示我们在设置下面的url的地址的时候,要带上价格区间