目录
1、前期准备:
2、项目期间:
(1)注册功能的实现:
1、前端:
1、表单数据的校验:(js)
2、使用ajax完成表单提交
3、注册成功跳转页面
2、web:
1、获取表单数据、封装数据
2、调用service方法完成注册
3、响应注册信息给前端(json)
3、service:
1、提供注册方法:
4、dao:
1、查询用户------根据用户名
2、存储用户(就是注册)
(2)邮件注册激活功能实现:
1、前端:
2、web:(ActiveUserServlet)
1、获取激活码并判断:
2、根据激活码查询用户判断:
3、service:
1、发送信息:
2、激活:
4、dao:
1、查询用户的code:
2、修改用户的status:
(3)登录功能的实现:
1、前端:
2、web:
1、获取表单的信息初步验证
2、调用service层的登录方法
3、封装并返回信息给前端页面
3、service:
4、dao:
(4)退出功能的实现:
(5)servlet的优化:
(6)分类数据的展示:
1、前端:
2、web:
3、service:
4、dao:
(7)旅游线路的分页展示:
1、前端:
2、web:
3、service:
4、dao:
(8) 旅游线路名称查询功能的实现:
(9)旅游线路的详细展示的功能的实现:
1、前端:
2、web:
3、service:
4、dao:
(10)详情页面的收藏功能的实现:
3、项目的总结:
1、前期准备:
对于项目的大体构成做了一定的了解,然后主要是做后端的数据处理,前期的准备的话创建项目的大体结构,servlet、service、domain、dao、utils的项目结构。以及一些基础的代码的生成,我觉得最主要的是一些基础的配置。
Web层:
- Servlet:前端控制器
- html:视图
- Filter:过滤器
- BeanUtils:数据封装
- Jackson:json序列化工具
Service层:
- Javamail:java发送邮件工具
- Redis:nosql内存数据库
- Jedis:java的redis客户端
Dao层:
- Mysql:数据库
- Druid:数据库连接池
- JdbcTemplate:jdbc的工具
通过这大体的技术,可以根据这个导入依赖,管理maven的依赖,使用项目所需要的一些jar包,然后设置依赖的范围,其实大部分默认都不会出太大的问题,顶多是打包的时候会多出来几个jar包,但是对于有proviate的jar包比如javax.servlet的jar包的设置的依赖范围,是必要的。
另外再讲一下,如果不是必要的配置,一般不要修改依赖的版本,很多情况出现问题的时候就是版本的不匹配导致的!
比如数据库的导入的时候,可能存在的问题就是,不同的数据库版本所支持的一些基础的约束的设置不太一致,所以在导入的时候要进行替换,其次是可能存在编码的不一致也要注意。
另外是关于配置文件的修改,比如读取数据库的配置文件,高版本的数据库的连接驱动的加载方式和低版本的数据库的连接驱动的方式不太一致,这个要按照自己的配置进行修改。
2、项目期间:
(1)注册功能的实现:
1、前端:
1、表单数据的校验:(js)
/* 表单的校验 触发事件 点击提交按钮或者是当前的栏目失去焦点的时候
* 1 用户名:单词字符 ,长度8-20
* 2 密码: 单词字符,长度8-20
* 3 email: 邮件格式
* 4 姓名: 非空
* 5 手机号: 手机号的格式
* 6 出生日期: 非空
* 7 验证码: 非空
* */
这里出现一个小问题就是,离谱的是只要我调用方法的时候带有方法的括号就会出现异常,只要输错后就是一直显示红色的边框,即使刷新也是红色,就相当于当这个组件失去焦点的话然后这个调用函数就没有生效,也不是没有生效就是一上来刷新页面还没操作的时候就直接显示红色,然后去掉括号就可以。
然后我大概查啦一下资料关于这方面的比较少。可能就调用函数的问题吧!
//错误
$("#username").blur(checkUsername());
//正确
$("#username").blur(checkUsername);
2、使用ajax完成表单提交
为啥使用异步请求,因为我们现在使用的是html来呈现的前端页面,不是之前的jsp不能使用servlet的域中就获取值,所以就使用ajax来进行表单的提交。
发送请求是在所有的校验都为true不然就不发送,在发送数据前要将表单数格式化,使用JQuery的一个函数serialize()将表单上的数据转换成字符串。
3、注册成功跳转页面
这个就是根据服务器返回的数据进行相应的处理,如果注册成功跳转注册成功的页面,如果注册失败展示相应的信息到前端的页面。
2、web:
1、获取表单数据、封装数据
处理验证码:
首先进行的是验证码的比较,这里说的是用户填写的验证码数据和生成的验证码的比较,如两个数据一致,然后进行后续的操作就是调用service层的方法。当然如果不一致的话直接返回信息响应给前端页面。
从前端获取验证码-------->获取session中生成的验证码-------->判断数据-------->封装信息----->转换格式Json------->响应信息给前端。
调用service层:
获取所有的表单数据-------->创建数据封装对象进行数据封装-------->调用service层的方法获取数据------>判断数据------>根据结果生成响应信息------>响应信息封装格式化Json------->响应信息给前端
2、调用service方法完成注册
判断username是否存在,调用dao层的方法,查询数据,然后将查询信息返回给service层。
3、响应注册信息给前端(json)
这一阶段就是处理好信息的格式,以及返回什么样的信息。
3、service:
1、提供注册方法:
在方法中首先应该判断一下用户名是不是已经存在(调用dao的查询方法),如果存在直接返回 false,如果不存在,然后调用dao的注册方法,添加用户信息。
4、dao:
1、查询用户------根据用户名
这方法就是service层根据提供的username来查询数据并返回。
2、存储用户(就是注册)
这个没有返回值,就根据传递的用户信息去添加数据到数据库中。
(2)邮件注册激活功能实现:
哈哈哈哈,这个是我第一次用,有一点点的小激动,我也很期待它实现后是什么样子!这功能的实现一共分为两个大的部分:发送邮件以及激活。而且发送邮件是实用工具类来进行完成的,不用知道怎么写,会修改会用就可以啦!
1、前端:
2、web:(ActiveUserServlet)
1、获取激活码并判断:
在用户提交的get请求中会包含code字段,获取该字段的信息。首先进行初步的判断这个字段的信息是不是空,如果是那么就直接封装错误信息给前端页面。如果不是直接进行后续操作。
2、根据激活码查询用户判断:
验证码非空,然后调用servic层的方法得到返回结果,根据返回结果做出相应的操作,如果对比数据库中的code字段不一致封装错误信息返回给前端页面,如果一致那么也是封装信息给前端。
3、service:
1、发送信息:
在service下,在调用dao的注册方法后,然后就向用户填的邮箱地址发送邮件进行激活,激活的话,在user类里面有status激活状态、code激活码两个字段,在注册的时候表单是没有这两个的信息的,也就是说实际上的激活就是再一次的数据添加往uesr表里面,去修改这两个属性的值。
当用户激活后,修改setatus的激活状态,Y已激活、N未激活。
这里并没有相应的dao层的功能的添加,只是在原有的regiser注册功能添加两个字段,然后存储到数据库,这里存储的只是验证码,这验证码是生成的(将来和用户体提交的做对比,保持一一致),然后会发送给user注册时的邮箱,用户点击激活才会在修改status状态。
2、激活:
首先调用dao层的查询用户的code的方法,得到返回值判断一致,直接调用修该状态的方法,完成激活,如果不一致返回信息给web层。
4、dao:
1、查询用户的code:
根据service层传递过来的数据进行数据库的数据查询,对比数据库中的code和用户传递过来code的数据返回查询结果。
2、修改用户的status:
经过验证,符合注册条件让然后就可以调用方法修改对应用户的状态信息。
(3)登录功能的实现:
1、前端:
绑定单击事件然后然后进行提交表单数据,发送异步请求到服务器,在发送表单数据之前先进行数据的格式化,最后就是处理调回函数中返回的数据,根据不同的数据结果做出不同的相应或者处理。
2、web:
1、获取表单的信息初步验证
这里的初步验证就是进行验证码的校验,判断验证是不是一致,一致才进行后续的操作,如果不一致直接封装错误信息发送给前端页面。
2、调用service层的登录方法
这里只有一个方法,就是根据用户的信息查询。
3、封装并返回信息给前端页面
根据查询的信息,然后给返回信息对象info赋值,不同的返回值类型所不同的返回值信息,这里具体一点就是,没有查询到user数据,或者查询到user但未激活,再者就是查询到信息并且激活成功的。
3、service:
调用dao层的条件查询的方法
4、dao:
dao层提供一个方法,根据用户的username和password进行查询数据
(4)退出功能的实现:
离谱死啦,如果前端的页面显示的有问题,一开始可以怀疑自己,但是经过很多次检查后可以大胆一点认定自己的后端代码是正确的,自信一点你可以大胆的换一个浏览器,然后你就会发现是,妈的!是浏览器的错!
这里将讲一下,就是在登录后显示到前端页面的一些基础用户的基础信息,这里的做法是将登录查询出来的数据存入session中,然后在前端可以获得session中的数据,直接获取是不可以的,肯定要发送请求(异步请求),然后获取相应的session中的数据。
好滴言归正传,退出功能就是将前端展示的数据抹去就就可以啦,恢复成为原来的样子!在简洁一点就是说,将session中的数据删除就可以了。大概步骤就是访问servlet就是session数据的删除。然后跳转到登录的界面。
销毁session中的数据刚开始我想着使用removeAttribute(),然后又想到还有一个invalidate的方法,两个的功能好像差不多,就去查资料看一下两个有什么区别。对于removeAttribute():是删除session中的某一个用户状态属性,而invalidate():销毁session,是对session中所有的用户状态属性都将不存在。
(5)servlet的优化:
到现在也算数实现啦一个小模块,然后前前后后针对user操作做的servlet也写啦很多,后面还有对其他的模块的操作,如果都这样写那么这servlet的模块就很离谱,后期回顾的时候也不方便查看,现在希望的是能够将对uers操作的所有的方法写在一个servlet,让代码的可读性和可维护性提高。
大概的框架,就是前端的所有的对user操作的请求都直接访问UseServlet,基于之前的操作的servlet是直接继承HttpServlet,然后在HttpServlet中的service方法实现了根据请求方式的不同方法的分发(请求方法有七种),在子类一般使用的是get和post,然后之前的servlet的模块中只重写了这两个方法,在重写的方法的中实现啦复杂的功能。
然后就有啦一个大概的想法,我们可以写一个和Httpservlet类似的,在其中实现对方法的分发,这样我们就可以将我们的servlet进行优化。
知识点回顾:
subString常见用法:以 String a = “123456anbdc”;
用法一 | a.subString(1); | 得到的为字符串a从下标为1的位置开始截取到最后的值,也就是23456anbdc; |
用法二 | a.subString(1,5); | 得到的为字符串a从下标为1的位置开始截取到下标为5的位置的值(不包括下标为5的值),也就是2345; |
用法三 | a.subString(1,a.indexOf(“b”)); | 得到的为字符串a从下标为1的位置开始截取到指定字符串“b”的值,也就是23456an; (注:如指定字符串有多个,以第一个为主) (说明:a.indexOf(“b”)就是取字符串“b”的下标,和上面的用法本质是一样的) |
反射获取方法:
没有忽略权限修饰符,getmethod()是获取公共的方法也就是一般的,但是getDeclaredMethod()可以获取任意的方法就是很牛逼,然后加s就是获取方法数组,这里用不上嘿嘿嘿!对于这些经过权限修饰符的受保护或者私有的方法,想要调用的话就要暴力反射开启无视权限。
method.setAccessible(true);
(6)分类数据的展示:
1、前端:
前端页面加载完毕后发送异步请求到服务器,然后进行数据的查询,等待服务器返回数据后在回调函数中处理数据,然后呈现到前端页面。
2、web:
这里也就是servlet层,目前提供findAll方法去查询所有的分页信息。调用service层的方法
3、service:
service层的到调用dao层的方法来实现数据的访问。但是对于分页数据的话,一般就比较固定而且一般不做改变(就是增删改之类的操作),但是每一次打开页面都要经进行数据的查询到数据库中。
使用redis优化:
使用redis的优化是指和数据库相结合,对于一些不经常发生改变的数据,我们可以将其存入Redis的缓存中,然后减少对数据库的交互和访问。之所以使用Redis,是因为相比较之下redis的查询效果要访问sql数据库的查询效果要比较好。
这里大概做一个判断,首先访问Redis缓存,如果redis的缓存中有分页数据就直接获取Redis中的数据,返回给web层,但是如果Redis的缓存中没有数据,那么这时候就要调用dao层的方法去查询数据,并且将查询出来的数据返回到web层的同时将数据格式话后存入Redis。
4、dao:
查询数据,编写sql语句然后返回查询结果;
(7)旅游线路的分页展示:
1、前端:
通过点击不同的分类后,然后展示不同的旅游线路,也就是说旅游线路表和分类表时多对一的关系,其中cid就是关键去查询不同的旅游线路。当点击不同的的分页的标签,会传递不同的标签的cid到路线分类的页面。
在请求的旅游路线的页面取出来刚刚请求的cid的参数,使用的方法也就是location.search
和spilt两个简单的方法,接下来就是根据请求获取指定的数据然后展示在前端的页面。
这里的前端的页面的操作和后端的页面操作要麻烦很多很多,比如就是关于分页展示数据,要显示查询出来的数据,这里和之前使用的jsp不同,以前可以使用el表达式,很方便的可以获取数据填充数据到前端页面,使用html的话只能拼接很麻烦。
再者就是分页的页码的设置,要处理很多的关系,不像后端具有很强的逻辑性,写后端的时候我很清楚要干什么,但是修改前端的时候有一种走一步看一步的感觉。
2、web:
获取请求的参数,根据请求的 cid以及pagebean参数去查询数据,封装pagebean对象然后将数据响应到前端的页面。
3、service:
这里要进行一些业务的处理,怎么说就是从web层的传递过cid、currentPage、pageSize的三个参数,对与PageBean对象里面有五个参数,目前知道两个其他的数据要从数据库中获取,对于totalCount来讲很好处理就是查询数据的记录数就可以,然后根据记录数和pageSize的参数计算出totalPage总页码数,
然后就是展示的数据啦,这里使用的是分页查询。所以要向dao层转递三个数据,cid,start开始索引和pagesize显示的数据数,start等于(currentPage-1)*pageSzie,接下来就是传递参数掉方法。
4、dao:
dao层提供两个方法,一个是根据cid查询总记录数,然后另一个是根据cid、star、pagesize查询数据然后封装数据。
(8) 旅游线路名称查询功能的实现:
这会个功能的实现是在上一个分页查询的基础上进行的数据的查询,相当于前端传递的数据多啦一个字段rname,然后在rname的基础上做了一个模糊查询数据。然后后端的代码就是进行简单的修改就可以啦。
主要的是对于模糊查询的处理,因为数据传递过来是不确定的,所以对于模糊查询的sql语句的编写相对比较的麻烦,但是之前也这样处理过数据,然后进行拼接。
public List<Route> findByPage(int cid, int start, int pageSize, String rname) {String sql = " select * from tab_route where 1 = 1 ";//1.定义sql模板StringBuilder sb = new StringBuilder(sql);List params = new ArrayList();//条件们//2.判断参数是否有值if(cid != 0){sb.append( " and cid = ? ");params.add(cid);//添加?对应的值}if(rname != null && rname.length() > 0){sb.append(" and rname like ? ");params.add("%"+rname+"%");}sb.append(" limit ? , ? ");//分页条件sql = sb.toString();params.add(start);params.add(pageSize);return template.query(sql,new BeanPropertyRowMapper<Route>(Route.class),params.toArray());}
大概的流程就是根据传递过来的参数进行判断数据,如果数据不是空的话就直接拼接数据,这里值得注意的是数据参数的传递,如果传递的参数不存在的话那么也没必要添加相应的数据。定义啦一个stringbuilder和list的集合用来管理数据。
(9)旅游线路的详细展示的功能的实现:
1、前端:
当点击啦产看详情后,前端的页面会发送异步请求到服务器,然后前端的页面会根据异步请求的回调函数的返回值,将查询到的数据展示在前端的页面。
由于呈现的数据比较多,所以涉及多表的数据查询。
2、web:
调用service层的方法,封装数据,转换Json格式然后返回数据到前端页面。
3、service:
调用dao层的方法,然后根据返回的数据进行对route对象的数据的初始化,将所有的数据集成到route对象中并返回。
4、dao:
由于涉及多表的查询,所以这个功能设计多个dao层的操作,有route表,seller表以及img表,从这三个表中查询出来的数据返回给service层。
(10)详情页面的收藏功能的实现:
第一件事就是根据登陆的用户的信息去查询用户是否已经收藏啦该旅游的线路。第二件就是当页面加载完毕后查询当亲的路线的收藏的数据量展示在前端的页面。
点击收藏,当点击后获取当前线路的rid和当前的用户,然后发送异步请求到服务器,当服务器接收到请求参数后把数据添加到favorite表中。
前端判断当前用户有没有登录,没有登录的话,跳转到登录页面,如果登录就直接点击收藏的请求,进行后续的操作。
3、项目的总结:
虽然这个项目是别人带着一点一点的做的,但是也都是自己一步一步的完成的,对于在这个过程中出现的问题,解决不了的也没有想过直接复制粘贴,都是自己一点一点的写,不会的也是在网上去查找资料或者教程,讲真的就是实现一个功能后会有很大的满足感。很可惜的就是没有带着把所有的功能都实现,不过后端的接口我都已经写好并且也成功的测试达到预期的相应的结果。主要是对前端的知识不太了解,有想法知道思路 但是对于现在的我来讲可能有很多的难度,就先放一放,继续往后面学习。
说一下的收获吧,首先就是对数据库的操作,之前都是很笼统的概念,只知道存储数据,拿出来数据展示出来,但是对于这个过程就是很陌生,不理解客户端和浏览器的这种的交互方式,通过这小项目然后了解客户端是怎么发送请求的、服务器是如何获取请求的、以及处理请求的方式和步骤、了解啦三层架构,确实这种模式让人可以很清晰的知道自己要干什么和怎么处理一系列的问题,每一个阶段要干什么等等,当然现在也只是粗略的了解啦一些关于这三层架构的知识,在后期的还要系统的学习。
对于使用的技术,怎么说,先讲一下前端的知识吧,这次前端页面的呈现的方式是html,不是之前的jsp,我说一下感觉吧,因为直接使用的html也没有什么其他的前端的工具之类的,对于返回的数据处理不太友好,很麻烦这也是我写完接口后没办法实现前端数据展示的主要原因,使用到 js的框架JQuery,然后就是异步请求AJAX,对于JQuery来说其实就是别人写好的js使用比较方便,因为里面有基于js拓展的函数。对于AJAX来讲可以发送异步请求到服务器,使用异步请求的好处就是可以局部刷新数据,然后给用户有更好的体验。
对于后端来讲,首先就是数据库的连接池技术,使用的是德鲁伊druid连接池,数据库连接池的好处包括连接的复用、可靠性和稳定性的保证、数据库资源的优化利用以及额外功能的提供,使得数据库访问更高效、更可靠,并减少了系统开发和维护的工作量。
对于数据的序列化jackson是一个在Java平台上广泛使用的开源库,主要用于处理JSON格式的数据。它提供了强大而灵活的数据序列化和反序列化功能,可用于将Java对象转换为JSON字符串(序列化)和将JSON字符串转换为Java对象(反序列化)。通过其格式化的数据返回给前端跟方便对数据的处理。
对于数据库的操作的优化的时候,使用啦Redis数据库,我们对于一些不容易发生改变的数据的查询不优化前需要频繁的访问数据库,增加啦对数据库的交互的次数,导致效率降低。但是使用Redis的话我们将数据以键值对的方式存储到数据库中,对于Riders来讲它的查询的效率要高很多。然后这里用到一个jar包就是Jedis(Java Redis客户端)是一个用于Java语言的开源Redis客户端库,用于与Redis键值存储系统进行交互。Redis是一个高性能的键值存储数据库,广泛用于缓存、消息队列、会话存储等各种应用场景。
其他的还有比如可以发送邮件的javax.mail(给我很大的兴趣,在使用的时候和我的宝宝臭显摆),最后介绍一下一个工具Postman,因为要写前端和后端,两个不能同时测试(就是很麻烦,重启服务器,更新资源什么的,操作就很麻烦),我要是想测试后端的接口是不是可以,就一定要从前端页面测试,但是如果使用这测试软件的话就很方便,只要服务器开着,然后测试对应的接口,发送想要的从前端获取的请求数据就可以获得后端的相应结果,而且相应的结果还可以美化。
就说到这里吧,继续努力!