一、 项目导入
-
点击侧边的maven(如果没有可以在view–>tool window 中找到),点击加号,选择文件中的pom.xml文档即可导入
-
首先预览一下静态页面
启动方式1:
启动方式2:添加启动方式,点击绿色三角形启动
二、技术选型
-
web:
servlet:前端控制器
HTML:数据展示
filter:过滤器
BeanUtils:数据封装
Jackson:json序列化工具 -
service:
Javaemail:Java发送文件
redis:nosql内存数据
jedis:Java的redis的客户端 -
Dao
Mysql:数据库
Druid:数据库连接池
jdbcTemplate:jdbc的工具类
三、创建数据库
四、实现登录、注册、退出
各层调用图:
注册:在html利用js完成表单校验,使用ajax完成表单提交
注册成功,跳转成功页面
注册失败,跳转失败页面
servlet:RegisterServlet
(0.设置编码已经利用统一过滤器完成)
1.获取数据
2.封装User对象
3.调用service完成注册
4.根据service返回,提示信息:
将提示信息信息转为json
设置相应头:contentType
service:
registerUser(User user)
调用dao根据用户名查询用户
存在,返回false
不存在,调用dao保存用户信息
Dao:
1.根据用户名查询用户信息 findByUsername(string username);
2.保存用户信息 save(User user)
异步Ajax提交表单:
$(this).serialize()将表单中的数据提交成 username=xxx&&password=123 的格式
使用异步提交是为了获取服务器响应的数据,前台使用html作为视图层,不能直接从servlet相关的域对象获取值,只能通过Ajax获取
**
在编写的时候,写错了一个愚蠢的问题,导致无法访问主页,就是注释名称写错了,webServlet写成了webFilter导致无法访问网页404
**
login.jsp
简单的jquery登录验证
<script type="text/javascript">//检查用户名格式function checkUsername() {var username = $("#username").val();var reg_username = /^[A-Za-z_0-9]{4,20}$/;var flag = reg_username.test(username);if(flag){$("#username").css("border","");}else{alert("用户名格式错误");$("#username").css("border","1px solid red");//$("#addusername").html("用户名格式错误"); //要记得添加一个新的html格式}return flag;}//检查密码格式function checkPassword(){var password = $("#password").val();var reg_password = /^[A-Za-z_0-9]{4,20}$/;var flag = reg_password.test(password);if(flag){$("#password").css("border","");}else{alert("密码格式错误");$("password").css("border","1px solid red");//$("#addusername").html("用户名格式错误"); //要记得添加一个新的html格式}return flag;}//提交时检查是否正确$(function () {$("#form").submit(function () {if(checkPassword()&&checkUsername()){return true;}return false;})//失去焦点时,判断格式$("#username").blur(checkUsername);$("#password").blur(checkPassword);})</script>
在body中添加form表单将值传入Servlet
<form id="form" name="form" action="indexServlet"><div>用户名:<input type="text" id="username" name="username" placeholder="请输入用户名"></div><div>密码:<input type="text" id="password" name="password" placeholder="请输入密码"></div><div><input type="submit" id="login" name="login" value="登录"></div></form>
可以用${error}来接收后台传递的错误信息
<!--得到从后台得到的错误信息-->
<div>${error}</div>
LoginServlet
//设置编码
req.setCharacterEncoding("utf-8");
//获取用户输入的数据
String username = req.getParameter("username");
String password = req.getParameter("password");//判断用户名和密码是否正确
if(username.equalsIgnoreCase("zhangsan")&&password.equalsIgnoreCase("123456")){//用户名和密码正确,跳转至主页面req.getRequestDispatcher("/home.jsp");
}else{//用户名和密码错误,存储错误信息req.setAttribute("error","用户名或密码错误");//携带错误信息,转发到登录页面req.getRequestDispatcher("/index.jsp").forward(req,resp);}
五、注册页面的邮件激活
原因:为了保证用户填写的邮箱是正确的。可以推送广告
发送邮件:利用emailutil工具类编写
激活邮件:
激活对于数据库来说,就是将status 状态改为激活态
邮件激活分析:
不要再return下写代码,Java报unreachable statement错误
详细看连接:https://blog.csdn.net/qq_33915826/article/details/79246482
六、登录
登录之后,动态展示个人用户名称
header.html
<script>$(function () {$.get("findUserServlet",{},function (data) {//{uid:1,name:"yangcichen"}var msg = "欢迎回来,"+data.name;$("#span_username").html(msg);})})
</script>
异步交互
当页面整个访问完成之后,用ajax访问服务器查询出信息
七、退出
首先,应该思考一下,什么时候称作登录成功?
登录成功,就是session中有user
那么退出功能实现:
header.html
<a href="javascript:location='exitServlet';">退出</a>
1.访问servlet,将session销毁
req.getSession().invalidate();
2.跳转到登录界面跳转页面,采用重定向(路径写法为虚拟目录)
resp.sendRedirect(req.getContextPath()+"/login.html");
八、优化Servlet——BaseServlet
优化方式:减少servlet的数量,将其优化为一个模块一个Servlet
写一个模块servlet 让各个功能的servlet继承
模块servlet继承HTTPServlet
“this”–谁调用我,我代表谁
报错说明没有匹配的方法:
原因:方法的声明为protected,访问的时候没有权限
解决方法:
①在访问的时候忽略访问权限修饰符,此方法会忽略所有的方法
//忽略访问权限修饰符
Method method = this.getClass().getDeclaredMethod(methodName, HttpServletRequest.class, HttpServletResponse.class);
//执行方法
//暴力反射
method.setAccessible(true);
method.invoke(this,req,resp);
②直接将方法权限修饰符改为public,这有利于其他的私有方法被保护
又犯了一个低级错误——findOne名称写错,导致浏览器找不到
九、旅游数据的显示
分类数据展示:
原来是假数据,后期通过从后台动态生成
<div class="navitem"><ul class="nav"><li class="nav-active"><a href="index.html">首页</a></li><li><a href="route_list.html">门票</a></li><li><a href="route_list.html">酒店</a></li><li><a href="route_list.html">香港车票</a></li><li><a href="route_list.html">出境游</a></li><li><a href="route_list.html">国内游</a></li><li><a href="route_list.html">港澳游</a></li><li><a href="route_list.html">抱团定制</a></li><li><a href="route_list.html">全球自由行</a></li><li><a href="favoriterank.html">收藏排行榜</a></li></ul></div>
数据库中信息:
进行代码优化:页面分类数据在每一次页面加载后都会重新要求数据库来加载,对数据库的压力比较大,而且分类的数据不会经常产生变化,所以可以用redis来缓存这个数据。
期望数据库中存储的顺序,就是展示的数据
十、旅游线路分页展示
点击了不同的分类后,看到的旅游路线不一致。
分类和旅游线路是一对多
如何携带cid:
//后台serviceSet<Tuple> categorys = jedis.zrangeWithScores("category", 0, -1);//2.判断查询的集合是否为空List<Category> cs=null;//2.1为空,第一次访问if(categorys==null||categorys.size()==0){//从数据库查询cs = categoryDao.findAll();//将集合存储到redis中的category的keyfor (int i = 0; i < cs.size(); i++) {//存储zaddjedis.zadd("category",cs.get(i).getCid(),cs.get(i).getCname());}}else{//2.2不为空,将set数据存入list//前端需要List,但是此方法中返回set,进行格式转换cs=new ArrayList<Category>();for (Tuple tuple:categorys) {Category category = new Category();category.setCname(tuple.getElement());category.setCid((int)tuple.getScore());cs.add(category);}}
前端:
for(var i=0;i<data.length;i++){var li = '<li><a href="favoriterank.html?cid='+data[i].cid+'">'+data[i].cname+'</a></li>';lis += li;
}
如何取cid:
<script>$(function () {var search = location.search;//alert(search);//切割获取到的字符串[?cid=5] 拿到5var cid = search.split("=")[1];})
</script>
根据cid获取不同的旅游线路数据:
十一、旅游线路名称查询
1.查询参数的传递
通过从route_list?cid=5 传递 route_list?cid=5&rname=xxx
传递xxx
首先获取到用户输入的rname
/*header.html*/
$("#search-button").click(function () {//后台根据这个名称进行模糊匹配var rname = $("#search_input").val();//alert(rname);var cid = getParameter("cid");//alert(cid);//跳转路径http://localhost/travel/route_list.html?cid=5//再拼接上rname=xxxlocation.href="http://localhost/travel/route_list.html?cid="+cid+"&rname="+rname;
})
/*route_list.html*/
//getParameter()方法为自己封装的字符切割函数
//获取cid
var cid = getParameter("cid");
//获取rname
var rname = getParameter("rname");
if(rname){//解码方法,获取到的rname为url需要解码rname=window.decodeURIComponent(rname);
}
2.修改之前的后台代码
Servlet、Service、Dao
tomcat7 从前端传值到后台乱码,解决办法:
//tomcat7,get请求出现乱码
rname = new String(rname.getBytes("iso-8859-1"),"utf-8");
出现了直接点击相关路线切换线路查询不到数据的问题:
传值load(5,2,‘null’)
解决办法链接
当rname为空时,前端传给RouteServlet的是“null”字符串,而不是null
所以在RouteDaoImpl中的判断参数是否有值的地方把rname当成“null”关键词(有值)来查询,而数据库没有关键词为“null”的旅游路线,所以返回0条记录,产生错误。
与之前判断为cid为’‘null’'时,有相似之处。
十二、查看旅游路线详情展示
出现图片展示有误:
通过前端断点调试发现标签使用了style="display:none;属性
如果删除其属性,图片可以正常显示,但是显示的数据css不正确
判断一下i 即每页的展示显示4个,超过4个进行隐藏
//遍历routeImgList
for (var i = 0; i < route.routeImgList.length; i++) {if(i>=4){var astr='<a title="" class="little_img" data-bigpic="'+route.routeImgList[i].bigPic+'" style="display:none;">\n' +' <img src="'+route.routeImgList[i].smallPic+'">\n' +' </a>'}else {var astr='<a title="" class="little_img" data-bigpic="'+route.routeImgList[i].bigPic+'" >\n' +' <img src="'+route.routeImgList[i].smallPic+'">\n' +' </a>'}ddstr+=astr;
}
十三、旅游路线收藏功能
页面加载完成后,发送ajax请求,查询数据库查看用户是否收藏过该线路
根据查询结果展示不同的样式
收藏字数的动态展示
点击收藏按钮:
给按钮绑定单击事件,点击了按钮调用js中的addFavorite()方法:
<a class="btn" id="favorite" onclick="addFavorite();"><i class="glyphicon glyphicon-heart-empty" ></i>点击收藏</a>