typora-copy-images-to: img
day02-黑马旅游
学习目标
- 能够完成用户登录案例
- 能够完成首页显示登录用户信息案例
- 能够完成用户退出案例
- 能够完成首页类别显示案例
- 能够完成首页旅游线路精选案例
- 能够完成分页获取国内游导航菜单旅游线路列表显示案例
- 能够完成头部搜索旅游线路分页展现数据案例
第一章 案例–用户登录
1.1 用户登录跳转首页
1.1.1 需求分析
用户到达登录页面,输入未激活的用户名与密码进行登录提示账号未激活(注意登录请求是ajax异步登录请求),用户输入已激活正确的用户名与密码进入网站首页。如果用户名与密码是错误的要有提示信息。
1.1.2 实现效果
【1】账号没激活
【2】账号或密码错误
【3】登录成功–跳转到首页
1.1.3 实现分析
1.1.4 实现步骤
【1】异步校验账号(email)是否已激活
对email输入框绑定离焦事件。
【前端】login.html
<script>
//校验账号是否激活
var emailCheckFlag = false;
$("input[name='email']").blur(function () {
var email = this.value;
//发请求校验账号是否已经激活
$.get("/userServlet?methodName=isEmailActive",{email:email},function (result) {
//没有激活
if(!result.checkFlag) {
$("#errorMsg").html(result.resultInfo);
emailCheckFlag = false;
}else {
$("#errorMsg").html("");
emailCheckFlag = true;
}
},"json");
});
</script>
【web层】UserServlet.java
/**
* 校验账号是否激活
* @param request
* @param response
* @throws Exception
*/
public void isEmailActive(HttpServletRequest request,HttpServletResponse response) throws Exception {
//1.获取请求数据
String email = request.getParameter("email");
//2.处理数据
boolean checkFlag = userService.isEmailActive(email);
//3.响应数据
Map<String, Object> result = new HashMap<>();
if (checkFlag) {
//已经激活
result.put("checkFlag", true);
}else{
//未激活
result.put("checkFlag", false);
result.put("resultInfo", "账号未激活,请先激活");
}
String jsonRes = JSON.toJSONString(result);
response.getWriter().println(jsonRes);
}
【service层】UserService.java
boolean isEmailActive(String email);
【service层】UserServiceImpl.jva
@Override
public boolean isEmailActive(String email) {
User user = userDao.queryUserByEmail(email);
return null != user;
}
【dao层】UserDao.java
User queryUserByEmail(String email);
【dao层】UserDaoImpl.java
@Override
public User queryUserByEmail(String email) {
String sql = "SELECT * FROM tab_user WHERE email=? AND status = 1";
try {
return jdbcTemplate.queryForObject(sql,new BeanPropertyRowMapper<>(User.class),email);
} catch (DataAccessException e) {
return null;
}
}
【2】处理登录业务
【前端】login.html
<script>
//异步提交登录页面表单---事件驱动
$("#loginForm").submit(function () {
//异步提交表单:ajax
//提交表单数据:==》表单序列化==》 name=value&name=value
var formData = $("#loginForm").serialize();
$.post("/userServlet?methodName=login",formData,function(result){
//处理响应数据
console.log(result);
if(result.loginFlag) {
//登录成功: 跳转到首页
location.href = "/index.html";
}else{
//登录失败:给出错误提示信息
$("#errorMsg").html(result.errorMsg);
}
},"json");
//阻止同步提交
return false;
});
</script>
【web层】UserServlet.java
/**
* 处理用户登录业务
* @param request
* @param response
* @throws IOException
*/
private void login(HttpServletRequest request,HttpServletResponse response)throws IOException {
//1、接收请求数据:整个表单
Map<String, String[]> map = request.getParameterMap();
//创建一个封装结果的map
Map<String, Object> result = new HashMap<>();
//把map中的数据封装到user中
User user = new User();
try {
BeanUtils.populate(user,map);
//2、处理数据:
//2.1 验证码校验:
//用户输入的验证码
String userCode = request.getParameter("checkCode");
//获取服务器端生成的验证码
String serverCode = (String) request.getSession().getAttribute("code");
if (!serverCode.equalsIgnoreCase(userCode)) {
//验证码校验不通过:1、给用户提示信息;2、登录失败;
result.put("loginFlag",false);
result.put("errorMsg", "验证码错误!");
//响应数据
response.getWriter().println(JSON.toJSONString(result));
//终止程序
return;
}
//2.2 用户登录:校验过程 email,password == 数据库
User loginUser = userService.login(user);
if (null == loginUser) {
//登录失败:
result.put("loginFlag",false);
result.put("errorMsg", "用户名或密码错误!");
}else{
//登录成功:把登录用户的数据保存在session中
request.getSession().setAttribute("loginUser",loginUser);
result.put("loginFlag",true);
}
} catch (Exception e) {
e.printStackTrace();
//登录失败:
result.put("loginFlag",false);
result.put("errorMsg", "服务器发生异常,请联系管理员!");
}
//3、响应数据
response.getWriter().println(JSON.toJSONString(result));
}
【service层】UserService.java
User login(User user) throws Exception;
/**
* 处理登录业务
* @param user
* @return
*/
@Override
public User login(User user) throws Exception {
//email password:123456
//把密码转换成密文
String password = user.getPassword();
String md5Pwd = Md5Util.encodeByMd5(password);
user.setPassword(md5Pwd);
//查询数据:email md5Pwd
return userDao.queryByEmailAndPassword(user);
}
【dao层】UserDao.java
User queryByEmailAndPassword(User user);
【dao层】UserDaoImpl.java
/**
*
* 根据email和password查询数据
* @param user
* @return
*/
@Override
public User queryByEmailAndPassword(User user) {
String sql = "SELECT * FROM tab_user WHERE email = ? AND password = ? AND status=1";
try {
return jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(User.class), user.getEmail(), user.getPassword());
} catch (DataAccessException e) {
e.printStackTrace();
return null;
}
}
1.2 登录成功后显示用户数据
1.2.1 案例需求
登录成功之后跳转到首页,在首页显示登录者的账号信息。
1.2.2 实现分析
1.2.3 实现步骤
- header.html页面加载完成之后,发送异步请求到UserServlet中,从session中获取用户数据;
- 如果能够获取数据:说明用户已登录,将session中的用户数据更新到页面上;
- 如果不能够获取数据:说明用户尚未登录,拼接信息提示用户登录;
1.2.4 实现代码
【前端】header.html
给显示用户信息的span添加一个id属性
/*
* 页面加载完成之后,加载用户信息
* */
$(function () {
$.get("userServlet?methodName=getLoginUserData",function (result) {
console.log(result);
//获取到数据 --- 用户已经登录
if(result.loginFlag) {
//显示登录信息 -- 隐藏未登录信息
$(".login_out").hide();
$("#userNameSpan").html(result.loginUser.name+" 欢迎回来");
console.log(result.loginUser.name);
//未获取到数据---用户未登录
}else{
$(".login").hide();
}
},"json");
});
【web层】UserServlet.java
/**
* 获取登录用户的数据
* @param request
* @param response
*/
public void getLoginUserData(HttpServletRequest request, HttpServletResponse response) throws Exception{
//从session中获取数据
User loginUser = (User) request.getSession().getAttribute("loginUser");
//封装返回数据
Map<String, Object> result = new HashMap<>();
if (null != loginUser) {
//用户已登录
result.put("loginFlag", true);
result.put("loginUser", loginUser);
}else{
//用户未登录
result.put("loginFlag", false);
}
//响应数据
String loginData = JSON.toJSONString(result);
response.getWriter().println(loginData);
}
第二章 用户退出(注销)
如果用户已经登录,可点击退出按钮进行退出登录操作。
2.1 需求分析
- 点击退出按钮向后台发请求进行退出操作;
- 退出后应该清除服务器session中的用户信息,并跳转到登录页面。
2.2 实现步骤
2.2.1 修改header.html退出链接
2.2.2 后台退出实现
/**
* 退出登录操作
* @param request
* @param response
* @throws Exception
*/
public void loginOut(HttpServletRequest request,HttpServletResponse response) throws Exception {
//销毁sesiion
User loginUser = (User) request.getSession().getAttribute("loginUser");
if (null != loginUser) {
//用户已登录 --- 销毁
request.getSession().invalidate();
}
//响应数据:跳转到登录页面 -- 转发,重定向
response.sendRedirect("/login.html");
}
第三章 首页类别显示
3.1 需求分析
- 从数据库表tab_category中查询所有的类别数据,并将其展示在网页导航位置,如下图:
- 要求:因为项目中所有页面均需要加载类别数据,而且类别数据不会经常发生变化,所以应将其放入 缓存,以提高查询效率减轻数据库压力。
3.2 实现分析
3.3 实现步骤
- header.html页面加载完成后,发送异步请求查询类别列表;
- CategoryServlet类处理请求和响应,具体业务交由CategoryService处理;
- CategoryService中,接收请求后:从redis中获取类别数据:
- 如果redis中有数据:直接将数据返回;
- 如果redis中没有数据:
- 从数据库中查询类别列表数据,并将其转化成json字符串;
- 将json字符串存储到redis中,然后返回给web层;
- header.html页面获取到类别列表后,将其展示到导航栏位置;
3.4 实现代码
3.4.1 header.html页面修改
注释原数据
发送异步请求加载数据
$(function () {
//加载类别列表信息
$.get("categoryServlet?methodName=queryAllCategory",function (result) {
console.log(result);
//遍历categoryList数组
var categoryHtml = "<li class='nav‐active'><a href='index.html'>首页</a></li>";
if(result){
$(result).each(function (index, element) {
categoryHtml+=' <li><a href="route_list.html">'+element.cname+'</a></li>';
});
}
categoryHtml+="<li><a href='favoriterank.html'>收藏排行榜</a></li>";
//把拼接的数据插入到ul中
$(categoryHtml).appendTo($("#categoryList"));
},"json");
});
3.4.2 后台实现
【web层】CategoryServlet.java
package com.heima.travel.web;
import com.heima.travel.service.CategoryService;
import com.heima.travel.service.impl.CategoryServiceImpl;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet(urlPatterns = "/categoryServlet")
public class CategoryServlet extends BaseServlet {
//创建service层对象
CategoryService categoryService = new CategoryServiceImpl();
/**
* 类别列表查询
* @param request
* @param response
* @throws Exception
*/
public void queryAllCategory(HttpServletRequest request,HttpServletResponse response) throws Exception {
//调用业务层处理数据
String categoryList = categoryService.queryAllCategory();
//响应数据
response.getWriter().println(categoryList);
}
}
【service层】CategoryService.java
package com.heima.travel.service;
public interface CategoryService {
String queryAllCategory();
}
【service层】CategoryServiceImpl.java
package com.heima.travel.service.impl;
import com.alibaba.fastjson.JSON;
import com.heima.travel.dao.CategoryDao;
import com.heima.travel.dao.impl.CategoryDaoImpl;
import com.heima.travel.model.Category;
import com.heima.travel.service.CategoryService;
import com.heima.travel.utils.JedisUtils;
import redis.clients.jedis.Jedis;
import java.util.List;
/**
* @author buguniao
* @version v1.0
* @date 2019/3/20 16:09
* @description 处理商品类别的Service
**/
public class CategoryServiceImpl implements CategoryService {
private CategoryDao categoryDao = new CategoryDaoImpl();
/**
* 查询所有的商品类别
* @return
*/
@Override
public String queryAll() {
//添加缓存业务
//1、优先从缓存中查:redis
Jedis jedis = JedisUtils.getJedis();
String categoryJson = jedis.get("HEIMA65_CATEGORY_LIST");
//缓存中没有:从数据库中查
if (categoryJson == null) {
//调用dao层查询数据
List<Category> categoryList = categoryDao.queryAll();
//把数据库中的数据 存储到redis中
categoryJson = JSON.toJSONString(categoryList);
jedis.set("HEIMA65_CATEGORY_LIST",categoryJson);
}
//释放资源
JedisUtils.close(jedis);
return categoryJson;
}
}
【dao层】CategoryDao.java
package com.heima.travel.dao;
import com.heima.travel.model.Category;
import java.util.List;
public interface CategoryDao {
List<Category> queryAll();
}
【dao层】CategoryDaoImpl.java
package com.heima.travel.dao.impl;
import com.heima.travel.dao.CategoryDao;
import com.heima.travel.model.Category;
import com.heima.travel.utils.C3p0Utils;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import java.util.List;
public class CategoryDaoImpl implements CategoryDao {
//创建jdbctemplate
private JdbcTemplate jdbcTemplate = new JdbcTemplate(C3p0Utils.getDataSource());
/**
* 查询所有的类别列表
* @return
*/
@Override
public List<Category> queryAll() {
String sql = "select * from tab_category";
return jdbcTemplate.query(sql,new BeanPropertyRowMapper<>(Category.class));
}
}
3.4.3 效果展示
第四章 首页精选旅游线路查询
4.1 需求分析
在首页index.html里面黑马精选位置,点击不同的人气旅游、最新旅游和主题旅游无刷新显示对应的信息。
人气旅游:是每个旅游线路收藏数量的降序获取前4条数据进行显示;
最新旅游:是每个旅游线路上架时间的降序获取前4条数据进行显示;
主题旅游:是每个旅游线路过滤为主题旅游的获取前4条数据进行显示;
4.2 实现效果
4.3 实现分析
浏览首页发现,目前已经实现了点击不同的选项(人气旅游、最新旅游和主题旅游)显示不同的内容,但是这里不同的内容是静态的,需要前端发起ajax异步请求后端这些数据。这里点击不同选项显示不同内容是使用了
bootstrap里面的组件完成的,观察静态选取切换数据代码发现如下:
通过观察图发现,用户点击popularity选项卡,会自动显示id为popularity里面的数据,所以只需要将数据库里面
对应的数据更新到id为popularity元素的体里面,其他选项卡实现原理一样。所以需要前端提交异步获取黑马精选
相关数据,具体操作分析如下:
4.4 实现步骤
- index.html页面加载完成事件提交获取黑马精选旅游线路的异步请求给RouteServlet
- RouteServlet处理请求,调用业务逻辑类RouteService实现获取黑马精选旅游线路业务方法
- RouteService业务类调用数据访问类RouteDao分别获取人气旅游线路列表、最新旅游线路列表和主题旅游线
路列表数据,并将这些列表数据存储到Map<String,List>对象中并返回 - RouteDao实现获取获取人气旅游线路列表、最新旅游线路列表和主题旅游线路列表数据。
- RouteServlet获取到黑马精选数据后,使用ResultInfo封装数据并返回json格式数据。
4.5 实现代码
【前端】发送异步请求
index.html
<script>
//页面加载完成之后 加载黑马精选数据--人气,最新,主题旅游
$(function () {
//发请求
$.get("routeServlet?methodName=routeCareChoose",function(result){
console.log(result);
},"json");
});
</script>
【web层】层接收,响应数据
RouteServlet.java
package com.heima.travel.web;
import com.heima.travel.service.RouteService;
import com.heima.travel.service.impl.RouteServiceImpl;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet(urlPatterns = "/routeServlet")
public class RouteServlet extends BaseServlet {
//创建RouteService对象处理路线业务
RouteService routeService = new RouteServiceImpl();
/**
* 查询黑马精选线路
* @param request
* @param response
* @throws Exception
*/
public void routeCareChoose(HttpServletRequest request, HttpServletResponse response) throws Exception {
//调用业务层获取数据
String jsonRouteData = routeService.getCareChoose();
//响应数据
response.getWriter().println(jsonRouteData);
}
}
【service层】处理业务逻辑
RouteService.java
package com.heima.travel.service;
public interface RouteService {
String getCareChoose();
}
【service层】实现类
package com.heima.travel.service.impl;
import com.alibaba.fastjson.JSON;
import com.heima.travel.dao.RouteDao;
import com.heima.travel.dao.impl.RouteDaoImpl;
import com.heima.travel.model.Route;
import com.heima.travel.service.RouteService;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class RouteServiceImpl implements RouteService {
//创建routeDao
private RouteDao routeDao = new RouteDaoImpl();
/**
* 查询精选路线
* @return
*/
public String getCareChoose() {
//查询人气旅游数据
List<Route> populateRouteList = routeDao.queryPopulateRoute();
//查询最新旅游
List<Route> newestRouteList = routeDao.queryNewestRoute();
//查询主题旅游
List<Route> themeRouteList = routeDao.queryThemeRoute();
//定义一个map封装数据
Map<String, List<Route>> result = new HashMap<>();
result.put("populate", populateRouteList);
result.put("newest", newestRouteList);
result.put("theme", themeRouteList);
//将数据转化成JSON字符串返回
String routeJson = JSON.toJSONString(result);
return routeJson;
}
}
【dao层】查询数据
RouteDao.java
package com.heima.travel.dao;
import com.heima.travel.model.Route;
import java.util.List;
public interface RouteDao {
List<Route> queryPopulateRoute();
List<Route> queryNewestRoute();
List<Route> queryThemeRoute();
}
【dao层】实现类
package com.heima.travel.dao.impl;
import com.heima.travel.dao.RouteDao;
import com.heima.travel.model.Route;
import com.heima.travel.utils.C3p0Utils;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import java.util.List;
public class RouteDaoImpl implements RouteDao {
//创建jdbcTemplate模板
JdbcTemplate jdbcTemplate = new JdbcTemplate(C3p0Utils.getDataSource());
/**
* 获取人气旅游列表4条数据,人气旅游就是收藏数量降序前4条数据
* @return List<Route>
*/
@Override
public List<Route> queryPopulateRoute() {
//sql语句 rflag='1'(未删除)筛选上架旅游线路,人气按照收藏数量降序
String sql="SELECT * FROM tab_route WHERE rflag='1' ORDER BY COUNT DESC LIMIT 0,4";
return jdbcTemplate.query(sql,new BeanPropertyRowMapper<>(Route.class));
}
/**
* 获取最新旅游列表4条数据,根据上架时间降序获取前4条数据
* @return List<Route>
*/
@Override
public List<Route> queryNewestRoute() {
//sql语句 rflag-未删除 rdate--上架时间
String sql = "SELECT * FROM tab_route WHERE rflag='1' ORDER BY rdate DESC LIMIT 0,4";
return jdbcTemplate.query(sql,new BeanPropertyRowMapper<>(Route.class));
}
/**
* 获取主题旅游列表4条数据
* @return List<Route>
*/
@Override
public List<Route> queryThemeRoute() {
//sql语句,isThemeTour='1'为主题旅游线路
String sql="SELECT * FROM tab_route WHERE rflag='1' AND isThemeTour='1' ORDER BY rdate DESC LIMIT 0,4";
return jdbcTemplate.query(sql,new BeanPropertyRowMapper<>(Route.class));
}
}
【前端】拼接数据
index.html
第一步:删除页面上的死数据
第二步:动态拼接查询到的数据
<script>
//页面加载完成之后 加载黑马精选数据--人气,最新,主题旅游
$(function () {
//发请求
$.get("routeServlet?methodName=routeCareChoose",function(result){
console.log(result);
//前端解析数据
var populateList = result.populate;
var newestList = result.newest;
var themeList = result.theme;
//人气旅游
var populateHtml = "";
$(populateList).each(function (index, route) {
populateHtml+='<div class="col-md-3">\n' +
' <a href="javascript:;">\n' +
' <img src='+route.rimage+' alt="">\n' +
' <div class="has_border">\n' +
' <h3>'+route.rname+'</h3>\n' +
' <div class="price">网付价<em>¥</em><strong>'+route.price+'</strong><em>起</em></div>\n' +
' </div>\n' +
' </a>\n' +
' </div>'
});
$("#populateHtmlList").html(populateHtml);
//TODO -- 作业
},"json");
});
</script>
第五章 今日作业
- 完成用户登录业务
- 完成首先显示登录用户信息
- 完成用户退出功能
- 完成首页类别显示和缓存添加功能
- 完成首页黑马精选旅游线路查询功能