《旅游网》综合案例
源码地址:https://github.com/xu-hao-tian/travel

1 前言

巩固web基础知识,提升综合运用能力。

二项目导入

点击绿色+按钮
travel - 图1
选择travel项目的pom.xml文件,点击ok,完成项目导入。需要等待一小会,项目初始化完成。
travel - 图2

3 启动项目

3.1 方式一:

travel - 图3

3.2 方式二:配置maven快捷启动

travel - 图4
travel - 图5

4 技术选型

4.1 Web层

  1. Servlet:前端控制器
  2. html:视图
  3. Filter:过滤器
  4. BeanUtils:数据封装
  5. Jackson:json序列化工具

    4.2 Service层

  6. Javamail:java发送邮件工具

  7. Redis:nosql内存数据库
  8. Jedis:java的redis客户端

    4.3 Dao层

  9. Mysql:数据库

  10. Druid:数据库连接池
  11. JdbcTemplate:jdbc的工具

5 创建数据库

— 创建数据库
CREATE DATABASE travel;
— 使用数据库
USE travel;
—创建表
复制提供好的sql

6 注册功能

6.1 页面效果

travel - 图6

6.2 功能分析

travel - 图7

6.3 代码实现

6.3.1 前台代码实现

6.3.2 表单校验

  1. 提升用户体验,并减轻服务器压力。<br />//校验用户名<br />//单词字符,长度8到20位**function **_checkUsername_() {<br /> //1.获取用户名值<br /> **var **username = **$**(**"#username"**).val();<br /> //2.定义正则<br /> **var **reg_username = /^\w{8,20}$/;<br /> <br /> //3.判断,给出提示信息<br /> **var **flag = reg_username.test(username);<br /> **if**(flag){<br /> //用户名合法<br /> **$**(**"#username"**).css(**"border"**,**""**);<br /> }**else**{<br /> //用户名非法,加一个红色边框<br /> **$**(**"#username"**).css(**"border"**,**"1px solid red"**);<br /> }<br /> <br /> **return **flag;<br /> }
  2. //校验密码<br /> **function **_checkPassword_() {<br /> //1.获取密码值<br /> **var **password = **$**(**"#password"**).val();<br /> //2.定义正则<br /> **var **reg_password = /^\w{8,20}$/;
  3. //3.判断,给出提示信息<br /> **var **flag = reg_password.test(password);<br /> **if**(flag){<br /> //密码合法<br /> **$**(**"#password"**).css(**"border"**,**""**);<br /> }**else**{<br /> //密码非法,加一个红色边框<br /> **$**(**"#password"**).css(**"border"**,**"1px solid red"**);<br /> }
  4. **return **flag;<br /> }
  5. //校验邮箱**function **_checkEmail_(){<br /> //1.获取邮箱<br /> **var **email = **$**(**"#email"**).val();<br /> //2.定义正则 itcast@163.com<br /> **var **reg_email = /^\w+@\w+\.\w+$/;

//3.判断
var flag = reg_email.test(email);
if(flag){
$(“#email”).css(“border”,“”);
}else{
$(“#email”).css(“border”,“1px solid red”);
}

return flag;
}
$(function () {
//当表单提交时,调用所有的校验方法
$(“#registerForm”).submit(function(){

  1. **return **_checkUsername_() && _checkPassword_() && _checkEmail_();<br /> //如果这个方法没有返回值,或者返回为true,则表单提交,如果返回为false,则表单不提交<br /> });
  2. //当某一个组件失去焦点是,调用对应的校验方法<br /> **$**(**"#username"**).blur(_checkUsername_);<br /> **$**(**"#password"**).blur(_checkPassword_);<br /> **$**(**"#email"**).blur(_checkEmail_);
  3. });

6.3.3 异步(ajax)提交表单

  1. 在此使用异步提交表单是为了获取服务器响应的数据。因为我们前台使用的是html作为视图层,不能够直接从servlet相关的域对象获取值,只能通过ajax获取响应数据<br />![](https://cdn.nlark.com/yuque/0/2021/png/22277845/1627874035313-fb60126a-b16f-4662-a758-31034b78cbad.png#id=Uh5mX&originHeight=283&originWidth=789&originalType=binary&ratio=1&status=done&style=none)

6.3.4 后台代码实现

6.3.5 编写RegistUserServlet

@WebServlet(“/registUserServlet”)public class RegistUserServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

  1. //验证校验<br /> String check = request.getParameter(**"check"**);<br /> //从sesion中获取验证码<br /> HttpSession session = request.getSession();<br /> String checkcode_server = (String) session.getAttribute(**"CHECKCODE_SERVER"**);<br /> session.removeAttribute(**"CHECKCODE_SERVER"**);//为了保证验证码只能使用一次<br /> //比较<br /> **if**(checkcode_server == **null **|| !checkcode_server.equalsIgnoreCase(check)){<br /> //验证码错误<br /> ResultInfo info = **new **ResultInfo();<br /> //注册失败<br /> info.setFlag(**false**);<br /> info.setErrorMsg(**"验证码错误"**);<br /> //将info对象序列化为json<br /> ObjectMapper mapper = **new **ObjectMapper();<br /> String json = mapper.writeValueAsString(info);<br /> response.setContentType(**"application/json;charset=utf-8"**);<br /> response.getWriter().write(json);<br /> **return**;<br /> }
  2. //1.获取数据<br /> Map<String, String[]> map = request.getParameterMap();
  3. //2.封装对象<br /> User user = **new **User();<br /> **try **{<br /> BeanUtils._populate_(user,map);<br /> } **catch **(IllegalAccessException e) {<br /> e.printStackTrace();<br /> } **catch **(InvocationTargetException e) {<br /> e.printStackTrace();<br /> }
  4. //3.调用service完成注册<br /> UserService service = **new **UserServiceImpl();<br /> **boolean **flag = service.regist(user);<br /> ResultInfo info = **new **ResultInfo();<br /> //4.响应结果<br /> **if**(flag){<br /> //注册成功<br /> info.setFlag(**true**);<br /> }**else**{<br /> //注册失败<br /> info.setFlag(**false**);<br /> info.setErrorMsg(**"注册失败!"**);<br /> }
  5. //将info对象序列化为json<br /> ObjectMapper mapper = **new **ObjectMapper();<br /> String json = mapper.writeValueAsString(info);
  6. //将json数据写回客户端<br /> //设置content-type<br /> response.setContentType(**"application/json;charset=utf-8"**);<br /> response.getWriter().write(json);
  7. }
  8. **protected void **doGet(HttpServletRequest request, HttpServletResponse response) **throws **ServletException, IOException {<br /> **this**.doPost(request, response);<br /> }<br />}

6.3.6 编写UserService以及UserServiceImpl

public class UserServiceImpl implements UserService {

  1. **private **UserDao **userDao **= **new **UserDaoImpl();<br /> /**<br /> * 注册用户<br /> * **@param _user<br />__ _*** **@return<br /> ***/<br /> @Override<br /> **public boolean **regist(User user) {<br /> //1.根据用户名查询用户对象<br /> User u = **userDao**.findByUsername(user.getUsername());<br /> //判断u是否为null<br /> **if**(u != **null**){<br /> //用户名存在,注册失败<br /> **return false**;<br /> }<br /> //2.保存用户信息<br /> **userDao**.save(user);<br /> **return true**;<br /> }<br />}

6.3.7 编写UserDao以及UserDaoImpl

public class UserDaoImpl implements UserDao {

  1. **private **JdbcTemplate **template **= **new **JdbcTemplate(JDBCUtils._getDataSource_());
  2. @Override<br /> **public **User findByUsername(String username) {<br /> User user = **null**;<br /> **try **{<br /> //1.定义sql<br /> String sql = **"select **_*_** from tab_user where username = ?"**;<br /> //2.执行sql<br /> user = **template**.queryForObject(sql, **new **BeanPropertyRowMapper<User>(User.**class**), username);<br /> } **catch **(Exception e) {
  3. }
  4. **return **user;<br /> }
  5. @Override<br /> **public void **save(User user) {<br /> //1.定义sql<br /> String sql = **"insert into tab_user(username,password,name,birthday,sex,telephone,email) values(?,?,?,?,?,?,?)"**;<br /> //2.执行sql
  6. **template**.update(sql,user.getUsername(),<br /> user.getPassword(),<br /> user.getName(),<br /> user.getBirthday(),<br /> user.getSex(),<br /> user.getTelephone(),<br /> user.getEmail());<br /> }<br />}

6.3.8 邮件激活

  1. 为什么要进行邮件激活?为了保证用户填写的邮箱是正确的。将来可以推广一些宣传信息,到用户邮箱中。

6.3.9 发送邮件

  1. 申请邮箱
  2. 开启授权码
  3. 在MailUtils中设置自己的邮箱账号和密码(授权码)

travel - 图8

邮件工具类:MailUtils,调用其中sendMail方法可以完成邮件发送

6.3.10 用户点击邮件激活

经过分析,发现,用户激活其实就是修改用户表中的status为‘Y’
travel - 图9

分析:
travel - 图10

发送邮件代码:
travel - 图11

修改保存Dao代码,加上存储status和code 的代码逻辑
travel - 图12

激活代码实现:
ActiveUserServlet
//1.获取激活码String code = request.getParameter(“code”);if(code != null){
//2.调用service完成激活
UserService service = new UserServiceImpl();
boolean flag = service.active(code);

  1. //3.判断标记<br /> String msg = **null**;<br /> **if**(flag){<br /> //激活成功<br /> msg = **"激活成功,请<a href='login.html'>登录</a>"**;<br /> }**else**{<br /> //激活失败<br /> msg = **"激活失败,请联系管理员!"**;<br /> }<br /> response.setContentType(**"text/html;charset=utf-8"**);<br /> response.getWriter().write(msg);

UserService:active
@Overridepublic boolean active(String code) {
//1.根据激活码查询用户对象
User user = userDao.findByCode(code);
if(user != null){
//2.调用dao的修改激活状态的方法
userDao.updateStatus(user);
return true;
}else{
return false;
}

}

UserDao:findByCode updateStatus

/
根据激活码查询用户对象
@param code
__
* @return
*/@Overridepublic User findByCode(String code) {
User user =
null;
try {
String sql =
“select * from tab_user where code = ?”**;

  1. user = **template**.queryForObject(sql,**new **BeanPropertyRowMapper<User>(User.**class**),code);<br /> } **catch **(DataAccessException e) {<br /> e.printStackTrace();<br /> }
  2. **return **user;<br />}<br />/**<br /> * 修改指定用户激活状态<br /> * **@param _user<br />__ _***/@Override**public void **updateStatus(User user) {<br /> String sql = **" update tab_user set status = 'Y' where uid=?"**;<br /> **template**.update(sql,user.getUid());<br />}

7 登录

7.1 分析

travel - 图13

7.2 代码实现

7.2.1 前台代码

travel - 图14

7.2.2 后台代码

LoginServlet
//1.获取用户名和密码数据Map map = request.getParameterMap();//2.封装User对象User user = new User();try {
BeanUtils.populate(user,map);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
//3.调用Service查询UserService service = new UserServiceImpl();
User u = service.login(user);

ResultInfo info = new ResultInfo();
//4.判断用户对象是否为nullif(u == null){
//用户名密码或错误
info.setFlag(false);
info.setErrorMsg(“用户名密码或错误”);
}//5.判断用户是否激活if(u != null && !“Y”.equals(u.getStatus())){
//用户尚未激活
info.setFlag(false);
info.setErrorMsg(“您尚未激活,请激活”);
}//6.判断登录成功if(u != null && “Y”.equals(u.getStatus())){
//登录成功
info.setFlag(true);
}
//响应数据ObjectMapper mapper = new ObjectMapper();

response.setContentType(“application/json;charset=utf-8”);
mapper.writeValue(response.getOutputStream(),info);

UserService
public User login(User user) {
return userDao.findByUsernameAndPassword(user.getUsername(),user.getPassword());
}

UserDao
public User findByUsernameAndPassword(String username, String password) {
User user = null;
try {
//1.定义sql
String sql = “select * from tab_user where username = ? and password = ?”;
//2.执行sql
user = template.queryForObject(sql, new BeanPropertyRowMapper(User.class), username,password);
} catch (Exception e) {

  1. }
  2. **return **user;<br />}

7.2.3 index页面中用户姓名的提示信息功能

效果:
travel - 图15
header.html代码
travel - 图16
Servlet代码
//从session中获取登录用户Object user = request.getSession().getAttribute(“user”);//将user写回客户端
ObjectMapper mapper = new ObjectMapper();
response.setContentType(“application/json;charset=utf-8”);
mapper.writeValue(response.getOutputStream(),user);

8 退出

什么叫做登录了?session中有user对象。
实现步骤:

  1. 1. 访问servlet,将session销毁
  2. 1. 跳转到登录页面

代码实现:
Header.htmltravel - 图17
Servlet:
//1.销毁sessionrequest.getSession().invalidate();
//2.跳转登录页面response.sendRedirect(request.getContextPath()+“/login.html”);

9 优化Servlet

9.1 目的

减少Servlet的数量,现在是一个功能一个Servlet,将其优化为一个模块一个Servlet,相当于在数据库中一张表对应一个Servlet,在Servlet中提供不同的方法,完成用户的请求。
travel - 图18

Idea控制台中文乱码解决:-Dfile.encoding=gb2312
travel - 图19

9.2 BaseServlet编写:

  1. **public class **BaseServlet **extends **HttpServlet {
  2. @Override<br /> **protected void **service(HttpServletRequest req, HttpServletResponse resp) **throws **ServletException, IOException {<br /> //System.out.println("baseServlet的service方法被执行了...");
  3. //完成方法分发<br /> //1.获取请求路径<br /> String uri = req.getRequestURI(); // /travel/user/add<br /> System.**_out_**.println(**"请求uri:"**+uri);// /travel/user/add<br /> //2.获取方法名称<br /> String methodName = uri.substring(uri.lastIndexOf(**'/'**) + 1);<br /> System.**_out_**.println(**"方法名称:"**+methodName);<br /> //3.获取方法对象Method<br /> //谁调用我?我代表谁<br /> System.**_out_**.println(**this**);//UserServlet的对象cn.itcast.travel.web.servlet.UserServlet@4903d97e<br /> **try **{<br /> //获取方法<br /> Method method = **this**.getClass().getMethod(methodName, HttpServletRequest.**class**, HttpServletResponse.**class**);<br /> //4.执行方法<br /> //暴力反射<br /> //method.setAccessible(true);<br /> method.invoke(**this**,req,resp);<br /> } **catch **(NoSuchMethodException e) {<br /> e.printStackTrace();<br /> } **catch **(IllegalAccessException e) {<br /> e.printStackTrace();<br /> } **catch **(InvocationTargetException e) {<br /> e.printStackTrace();<br /> }
  4. }<br />}

9.3 UserServlet改写

将之前的Servlet实现的功能,抽取到UserServlet中的不同方法中实现,并且将UserService创建抽取到成员变量位置
@WebServlet(“/user/*”) // /user/add /user/findpublic class UserServlet extends BaseServlet {

  1. //声明UserService业务对象<br /> **private **UserService **service **= **new **UserServiceImpl();
  2. /**<br /> * 注册功能<br /> * **@param _request<br />__ _*** **@param _response<br />__ _*** **@throws **ServletException<br /> * **@throws **IOException<br /> */<br /> **public void **regist(HttpServletRequest request, HttpServletResponse response) **throws **ServletException, IOException {
  3. //验证校验<br /> String check = request.getParameter(**"check"**);<br /> //从sesion中获取验证码<br /> HttpSession session = request.getSession();<br /> String checkcode_server = (String) session.getAttribute(**"CHECKCODE_SERVER"**);<br /> session.removeAttribute(**"CHECKCODE_SERVER"**);//为了保证验证码只能使用一次<br /> //比较<br /> **if**(checkcode_server == **null **|| !checkcode_server.equalsIgnoreCase(check)){<br /> //验证码错误<br /> ResultInfo info = **new **ResultInfo();<br /> //注册失败<br /> info.setFlag(**false**);<br /> info.setErrorMsg(**"验证码错误"**);<br /> //将info对象序列化为json<br /> ObjectMapper mapper = **new **ObjectMapper();<br /> String json = mapper.writeValueAsString(info);<br /> response.setContentType(**"application/json;charset=utf-8"**);<br /> response.getWriter().write(json);<br /> **return**;<br /> }
  4. //1.获取数据<br /> Map<String, String[]> map = request.getParameterMap();
  5. //2.封装对象<br /> User user = **new **User();<br /> **try **{<br /> BeanUtils._populate_(user,map);<br /> } **catch **(IllegalAccessException e) {<br /> e.printStackTrace();<br /> } **catch **(InvocationTargetException e) {<br /> e.printStackTrace();<br /> }
  6. //3.调用service完成注册<br /> //UserService service = new UserServiceImpl();<br /> **boolean **flag = **service**.regist(user);<br /> ResultInfo info = **new **ResultInfo();<br /> //4.响应结果<br /> **if**(flag){<br /> //注册成功<br /> info.setFlag(**true**);<br /> }**else**{<br /> //注册失败<br /> info.setFlag(**false**);<br /> info.setErrorMsg(**"注册失败!"**);<br /> }
  7. //将info对象序列化为json<br /> ObjectMapper mapper = **new **ObjectMapper();<br /> String json = mapper.writeValueAsString(info);
  8. //将json数据写回客户端<br /> //设置content-type<br /> response.setContentType(**"application/json;charset=utf-8"**);<br /> response.getWriter().write(json);
  9. }
  10. /**<br /> * 登录功能<br /> * **@param _request<br />__ _*** **@param _response<br />__ _*** **@throws **ServletException<br /> * **@throws **IOException<br /> */<br /> **public void **login(HttpServletRequest request, HttpServletResponse response) **throws **ServletException, IOException {<br /> //1.获取用户名和密码数据<br /> Map<String, String[]> map = request.getParameterMap();<br /> //2.封装User对象<br /> User user = **new **User();<br /> **try **{<br /> BeanUtils._populate_(user,map);<br /> } **catch **(IllegalAccessException e) {<br /> e.printStackTrace();<br /> } **catch **(InvocationTargetException e) {<br /> e.printStackTrace();<br /> }
  11. //3.调用Service查询<br /> // UserService service = new UserServiceImpl();<br /> User u = **service**.login(user);
  12. ResultInfo info = **new **ResultInfo();
  13. //4.判断用户对象是否为null<br /> **if**(u == **null**){<br /> //用户名密码或错误<br /> info.setFlag(**false**);<br /> info.setErrorMsg(**"用户名密码或错误"**);<br /> }<br /> //5.判断用户是否激活<br /> **if**(u != **null **&& !**"Y"**.equals(u.getStatus())){<br /> //用户尚未激活<br /> info.setFlag(**false**);<br /> info.setErrorMsg(**"您尚未激活,请激活"**);<br /> }<br /> //6.判断登录成功<br /> **if**(u != **null **&& **"Y"**.equals(u.getStatus())){<br /> request.getSession().setAttribute(**"user"**,u);//登录成功标记
  14. //登录成功<br /> info.setFlag(**true**);<br /> }
  15. //响应数据<br /> ObjectMapper mapper = **new **ObjectMapper();
  16. response.setContentType(**"application/json;charset=utf-8"**);<br /> mapper.writeValue(response.getOutputStream(),info);<br /> }
  17. /**<br /> * 查询单个对象<br /> * **@param _request<br />__ _*** **@param _response<br />__ _*** **@throws **ServletException<br /> * **@throws **IOException<br /> */<br /> **public void **findOne(HttpServletRequest request, HttpServletResponse response) **throws **ServletException, IOException {<br /> //从session中获取登录用户<br /> Object user = request.getSession().getAttribute(**"user"**);<br /> //将user写回客户端
  18. ObjectMapper mapper = **new **ObjectMapper();<br /> response.setContentType(**"application/json;charset=utf-8"**);<br /> mapper.writeValue(response.getOutputStream(),user);<br /> }
  19. /**<br /> * 退出功能<br /> * **@param _request<br />__ _*** **@param _response<br />__ _*** **@throws **ServletException<br /> * **@throws **IOException<br /> */<br /> **public void **exit(HttpServletRequest request, HttpServletResponse response) **throws **ServletException, IOException {<br /> //1.销毁session<br /> request.getSession().invalidate();
  20. //2.跳转登录页面<br /> response.sendRedirect(request.getContextPath()+**"/login.html"**);<br /> }
  21. /**<br /> * 激活功能<br /> * **@param _request<br />__ _*** **@param _response<br />__ _*** **@throws **ServletException<br /> * **@throws **IOException<br /> */<br /> **public void **active(HttpServletRequest request, HttpServletResponse response) **throws **ServletException, IOException {<br /> //1.获取激活码<br /> String code = request.getParameter(**"code"**);<br /> **if**(code != **null**){<br /> //2.调用service完成激活<br /> //UserService service = new UserServiceImpl();<br /> **boolean **flag = **service**.active(code);
  22. //3.判断标记<br /> String msg = **null**;<br /> **if**(flag){<br /> //激活成功<br /> msg = **"激活成功,请<a href='login.html'>登录</a>"**;<br /> }**else**{<br /> //激活失败<br /> msg = **"激活失败,请联系管理员!"**;<br /> }<br /> response.setContentType(**"text/html;charset=utf-8"**);<br /> response.getWriter().write(msg);<br /> }<br /> }<br />}

9.4 页面路径改写

register.html
travel - 图20
login.html
travel - 图21
header.html
travel - 图22
UserServiceImpl发送邮件
travel - 图23

10 分类数据展示

10.1 效果:

  1. ![](https://cdn.nlark.com/yuque/0/2021/png/22277845/1627874044005-b315c937-bfb2-46a8-a25d-c531ef5c1d13.png#id=c6Ylb&originHeight=62&originWidth=1149&originalType=binary&ratio=1&status=done&style=none)

10.2 分析:

  1. ![](https://cdn.nlark.com/yuque/0/2021/png/22277845/1627874044520-45050930-80a4-4e77-975b-c8ce48bd6c85.png#id=o2cPJ&originHeight=381&originWidth=1219&originalType=binary&ratio=1&status=done&style=none)

10.3 代码实现:

10.3.1 后台代码

CategoryServlet
@WebServlet(“/category/*”)public class CategoryServlet extends BaseServlet {

  1. **private **CategoryService **service **= **new **CategoryServiceImpl();
  2. /**<br /> * 查询所有<br /> * **@param _request<br />__ _*** **@param _response<br />__ _*** **@throws **ServletException<br /> * **@throws **IOException<br /> */<br /> **public void **findAll(HttpServletRequest request, HttpServletResponse response) **throws **ServletException, IOException {<br /> //1.调用service查询所有<br /> List<Category> cs = **service**.findAll();<br /> //2.序列化json返回<br /> /* ObjectMapper mapper = new ObjectMapper();<br /> response.setContentType("application/json;charset=utf-8");<br /> mapper.writeValue(response.getOutputStream(),cs);*/<br /> writeValue(cs,response);
  3. }

}

CategoryService
public class CategoryServiceImpl implements CategoryService {

  1. **private **CategoryDao **categoryDao **= **new **CategoryDaoImpl();
  2. @Override<br /> **public **List<Category> findAll() {<br /> **return categoryDao**.findAll();<br /> }<br />}

CategoryDao
public class CategoryDaoImpl implements CategoryDao {

  1. **private **JdbcTemplate **template **= **new **JdbcTemplate(JDBCUtils._getDataSource_());
  2. @Override<br /> **public **List<Category> findAll() {<br /> String sql = **"select **_*_** from tab_category "**;<br /> **return template**.query(sql,**new **BeanPropertyRowMapper<Category>(Category.**class**));<br /> }<br />}

在BaseServlet中封装了序列化json的方法

/
直接将传入的对象序列化为json,并且写回客户端
@param obj
__
*/public void writeValue(Object obj,HttpServletResponse response) throws IOException {
ObjectMapper mapper =
new ObjectMapper();
response.setContentType(
“application/json;charset=utf-8”);
mapper.writeValue(response.getOutputStream(),obj);
}
/

将传入的对象序列化为json,返回
@param obj
__
*
@return
*
/public String writeValueAsString(Object obj) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
return mapper.writeValueAsString(obj);
}

10.3.2 前台代码

hader.html加载后,发送ajax请求,请求category/findAll
//查询分类数据
$.get(“category/findAll”,{},function (data) {
//[{cid:1,cname:国内游},{},{}]
var lis =

;
//遍历数组,拼接字符串(
  • )
    for (var i = 0; i < data.length; i++) {
    var li =
  • +data[i].cname+
  • ;

    1. lis += li;<br /> <br /> }<br /> //拼接收藏排行榜的li,<li><a href="favoriterank.html">收藏排行榜</a></li><br /> <br /> lis+= **'<li><a href="favoriterank.html">收藏排行榜</a></li>'**;
    2. //将lis字符串,设置到ul的html内容中<br /> **$**(**"#category"**).html(lis);<br /> });

    10.4 对分类数据进行缓存优化

    分析发现,分类的数据在每一次页面加载后都会重新请求数据库来加载,对数据库的压力比较大,而且分类的数据不会经常产生变化,所有可以使用redis来缓存这个数据。
    分析:
    travel - 图24

    10.5 优化代码实现

    期望数据中存储的顺序就是将来展示的顺序,使用redis的sortedset
    @Overridepublic List findAll() {
    //1.从redis中查询
    //1.1获取jedis客户端
    Jedis jedis = JedisUtil.getJedis();
    //1.2可使用sortedset排序查询
    Set categorys = jedis.zrange(“category”, 0, -1);
    List cs = null;
    //2.判断查询的集合是否为空
    if (categorys == null || categorys.size() == 0) {

    1. System.**_out_**.println(**"从数据库查询...."**);<br /> //3.如果为空,需要从数据库查询,在将数据存入redis<br /> //3.1 从数据库查询<br /> cs = **categoryDao**.findAll();<br /> //3.2 将集合数据存储到redis中的 category的key<br /> **for **(**int **i = 0; i < cs.size(); i++) {
    2. jedis.zadd(**"category"**, cs.get(i).getCid(), cs.get(i).getCname());<br /> }<br /> } **else **{<br /> System.**_out_**.println(**"从redis中查询....."**);
    3. //4.如果不为空,将set的数据存入list<br /> cs = **new **ArrayList<Category>();<br /> **for **(String name : categorys) {<br /> Category category = **new **Category();<br /> category.setCname(name);<br /> cs.add(category);
    4. }<br /> }
    5. **return **cs;<br />}

    11 旅游线路的分页展示

    点击了不同的分类后,将来看到的旅游线路不一样的。通过分析数据库表结构,发现,旅游线路表和分类表时一个多对一的关系
    travel - 图25
    查询不同分类的旅游线路sql
    Select * from tab_route where cid = ?;

    11.1 类别id的传递

    Redis中查询score(cid)
    public class CategoryServiceImpl implements CategoryService {

    1. **private **CategoryDao **categoryDao **= **new **CategoryDaoImpl();
    2. @Override<br /> **public **List<Category> findAll() {<br /> //1.从redis中查询<br /> //1.1获取jedis客户端<br /> Jedis jedis = JedisUtil._getJedis_();<br /> //1.2可使用sortedset排序查询<br /> //Set<String> categorys = jedis.zrange("category", 0, -1);<br /> //1.3查询sortedset中的分数(cid)和值(cname)<br /> Set<Tuple> categorys = jedis.zrangeWithScores(**"category"**, 0, -1);
    3. List<Category> cs = **null**;<br /> //2.判断查询的集合是否为空<br /> **if **(categorys == **null **|| categorys.size() == 0) {
    4. System.**_out_**.println(**"从数据库查询...."**);<br /> //3.如果为空,需要从数据库查询,在将数据存入redis<br /> //3.1 从数据库查询<br /> cs = **categoryDao**.findAll();<br /> //3.2 将集合数据存储到redis中的 category的key<br /> **for **(**int **i = 0; i < cs.size(); i++) {
    5. jedis.zadd(**"category"**, cs.get(i).getCid(), cs.get(i).getCname());<br /> }<br /> } **else **{<br /> System.**_out_**.println(**"从redis中查询....."**);
    6. //4.如果不为空,将set的数据存入list<br /> cs = **new **ArrayList<Category>();<br /> **for **(Tuple tuple : categorys) {<br /> Category category = **new **Category();<br /> category.setCname(tuple.getElement());<br /> category.setCid((**int**)tuple.getScore());<br /> cs.add(category);
    7. }<br /> }
    8. **return **cs;<br /> }<br />}

    页面传递cid
    header.html传递cid
    var li =

  • <a href=”route_list.html?cid=’+data[i].cid+‘“>’+data[i].cname+
  • ;

    获取cid

    $(function () {
    var search = location.search;
    //alert(search);//?id=5
    // 切割字符串,拿到第二个值
    var cid = search.split(“=”)[1];
    });

    11.2 根据id查询不同类别的旅游线路数据

    分页展示旅游线路数据:

    11.2.1 分析

    travel - 图26

    11.2.2 编码

    1. 客户端代码编写

    $(function () {
    var search = location.search;
    // 切割字符串,拿到第二个值
    var cid = search.split(“=”)[1];

    1. //当页码加载完成后,调用load方法,发送ajax请求加载数据<br /> _load_(cid);<br />});<br />**function **_load_(cid ,currentPage){<br /> //发送ajax请求,请求route/pageQuery,传递cid<br /> **$**.get(**"route/pageQuery"**,{**cid**:cid,**currentPage**:currentPage},**function **(pb) {<br /> //解析pagebean数据,展示到页面上
    2. //1.分页工具条数据展示<br /> //1.1 展示总页码和总记录数<br /> **$**(**"#totalPage"**).html(pb.totalPage);<br /> **$**(**"#totalCount"**).html(pb.totalCount);
    3. **var **lis = **""**;
    4. **var **fristPage = **'<li onclick="javascipt:**_load_**('**+cid+**')"><a href="javascript:void(0)">首页</a></li>'**;
    5. //计算上一页的页码<br /> **var **beforeNum = pb.**currentPage **- 1;<br /> **if**(beforeNum <= 0){<br /> beforeNum = 1;<br /> }
    6. **var **beforePage = **'<li onclick="javascipt:**_load_**('**+cid+**','**+beforeNum+**')" class="threeword"><a href="javascript:void(0)">上一页</a></li>'**;
    7. lis += fristPage;<br /> lis += beforePage;<br /> //1.2 展示分页页码<br /> /*<br /> 1.一共展示10个页码,能够达到前5后4的效果<br /> 2.如果前边不够5个,后边补齐10个<br /> 3.如果后边不足4个,前边补齐10个<br /> */
    8. // 定义开始位置begin,结束位置 end<br /> **var **begin; // 开始位置<br /> **var **end ; // 结束位置
    9. //1.要显示10个页码<br /> **if**(pb.totalPage < 10){<br /> //总页码不够10页
    10. begin = 1;<br /> end = pb.totalPage;<br /> }**else**{<br /> //总页码超过10页
    11. begin = pb.**currentPage **- 5 ;<br /> end = pb.**currentPage **+ 4 ;
    12. //2.如果前边不够5个,后边补齐10个<br /> **if**(begin < 1){<br /> begin = 1;<br /> end = begin + 9;<br /> }
    13. //3.如果后边不足4个,前边补齐10个<br /> **if**(end > pb.totalPage){<br /> end = pb.totalPage;<br /> begin = end - 9 ;<br /> }<br /> }
    14. **for **(**var **i = begin; i <= end ; i++) {<br /> **var **li;<br /> //判断当前页码是否等于i<br /> **if**(pb.**currentPage **== i){
    15. li = **'<li class="curPage" onclick="javascipt:**_load_**('**+cid+**','**+i+**')"><a href="javascript:void(0)">'**+i+**'</a></li>'**;
    16. }**else**{<br /> //创建页码的li<br /> li = **'<li onclick="javascipt:**_load_**('**+cid+**','**+i+**')"><a href="javascript:void(0)">'**+i+**'</a></li>'**;<br /> }<br /> //拼接字符串<br /> lis += li;<br /> }
    17. **var **lastPage = **'<li class="threeword"><a href="javascript:;">末页</a></li>'**;<br /> **var **nextPage = **'<li class="threeword"><a href="javascript:;">下一页</a></li>'**;
    18. lis += nextPage;<br /> lis += lastPage;
    19. //将lis内容设置到 ul<br /> **$**(**"#pageNum"**).html(lis);
    20. //2.列表数据展示<br /> **var **route_lis = **""**;
    21. **for **(**var **i = 0; i < pb.list.**length**; i++) {<br /> //获取{rid:1,rname:"xxx"}<br /> **var **route = pb.list[i];
    22. **var **li = **'<li>\n' **+<br /> **' <div class="img"><img src="'**+route.rimage+**'" style="width: 299px;"></div>\n' **+<br /> **' <div class="text1">\n' **+<br /> **' <p>'**+route.rname+**'</p>\n' **+<br /> **' <br/>\n' **+<br /> **' <p>'**+route.routeIntroduce+**'</p>\n' **+<br /> **' </div>\n' **+<br /> **' <div class="price">\n' **+<br /> **' <p class="price_num">\n' **+<br /> **' <span>&yen;</span>\n' **+<br /> **' <span>'**+route.price+**'</span>\n' **+<br /> **' <span>起</span>\n' **+<br /> **' </p>\n' **+<br /> **' <p><a href="route_detail.html">查看详情</a></p>\n' **+<br /> **' </div>\n' **+<br /> **' </li>'**;<br /> route_lis += li;<br /> }<br /> **$**(**"#route"**).html(route_lis);
    23. //定位到页面顶部<br /> **_window_**.scrollTo(0,0);<br /> });

    }

    1. 服务器端代码编写
      1. 创建PageBean对象

    public class PageBean {

    1. **private int totalCount**;//总记录数<br /> **private int totalPage**;//总页数<br /> **private int currentPage**;//当前页码<br /> **private int pageSize**;//每页显示的条数
    2. **private **List<T> **list**;//每页显示的数据集合
    3. **public int **getTotalCount() {<br /> **return totalCount**;<br /> }
    4. **public void **setTotalCount(**int **totalCount) {<br /> **this**.**totalCount **= totalCount;<br /> }
    5. **public int **getTotalPage() {<br /> **return totalPage**;<br /> }
    6. **public void **setTotalPage(**int **totalPage) {<br /> **this**.**totalPage **= totalPage;<br /> }
    7. **public int **getCurrentPage() {<br /> **return currentPage**;<br /> }
    8. **public void **setCurrentPage(**int **currentPage) {<br /> **this**.**currentPage **= currentPage;<br /> }
    9. **public int **getPageSize() {<br /> **return pageSize**;<br /> }
    10. **public void **setPageSize(**int **pageSize) {<br /> **this**.**pageSize **= pageSize;<br /> }
    11. **public **List<T> getList() {<br /> **return list**;<br /> }
    12. **public void **setList(List<T> list) {<br /> **this**.**list **= list;<br /> }<br />}
    1. RouteServlet

    @WebServlet(“/route/*”)public class RouteServlet extends BaseServlet {

    1. **private **RouteService **routeService **= **new **RouteServiceImpl();
    2. /**<br /> * 分页查询<br /> * **@param _request<br />__ _*** **@param _response<br />__ _*** **@throws **ServletException<br /> * **@throws **IOException<br /> */<br /> **public void **pageQuery(HttpServletRequest request, HttpServletResponse response) **throws **ServletException, IOException {<br /> //1.接受参数<br /> String currentPageStr = request.getParameter(**"currentPage"**);<br /> String pageSizeStr = request.getParameter(**"pageSize"**);<br /> String cidStr = request.getParameter(**"cid"**);
    3. **int **cid = 0;//类别id<br /> //2.处理参数<br /> **if**(cidStr != **null **&& cidStr.length() > 0){<br /> cid = Integer._parseInt_(cidStr);<br /> }<br /> **int **currentPage = 0;//当前页码,如果不传递,则默认为第一页<br /> **if**(currentPageStr != **null **&& currentPageStr.length() > 0){<br /> currentPage = Integer._parseInt_(currentPageStr);<br /> }**else**{<br /> currentPage = 1;<br /> }
    4. **int **pageSize = 0;//每页显示条数,如果不传递,默认每页显示5条记录<br /> **if**(pageSizeStr != **null **&& pageSizeStr.length() > 0){<br /> pageSize = Integer._parseInt_(pageSizeStr);<br /> }**else**{<br /> pageSize = 5;<br /> }
    5. //3. 调用service查询PageBean对象<br /> PageBean<Route> pb = **routeService**.pageQuery(cid, currentPage, pageSize);
    6. //4. 将pageBean对象序列化为json,返回<br /> writeValue(pb,response);
    7. }

    }

    1. RouteService

    public class RouteServiceImpl implements RouteService {
    private RouteDao routeDao = new RouteDaoImpl();
    @Override
    public PageBean pageQuery(int cid, int currentPage, int pageSize) {
    //封装PageBean
    PageBean pb = new PageBean();
    //设置当前页码
    pb.setCurrentPage(currentPage);
    //设置每页显示条数
    pb.setPageSize(pageSize);

    //设置总记录数
    int totalCount = routeDao.findTotalCount(cid);
    pb.setTotalCount(totalCount);
    //设置当前页显示的数据集合
    int start = (currentPage - 1) pageSize;//开始的记录数
    List list = *routeDao
    .findByPage(cid,start,pageSize);
    pb.setList(list);

    1. //设置总页数 = 总记录数/每页显示条数<br /> **int **totalPage = totalCount % pageSize == 0 ? totalCount / pageSize :(totalCount / pageSize) + 1 ;<br /> pb.setTotalPage(totalPage);
    2. **return **pb;<br /> }<br />}
    1. RouteDao

    public class RouteDaoImpl implements RouteDao {
    private JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());

    1. @Override<br /> **public int **findTotalCount(**int **cid) {<br /> String sql = **"select **_count_**(**_*_**) from tab_route where cid = ?"**;<br /> **return template**.queryForObject(sql,Integer.**class**,cid);<br /> }
    2. @Override<br /> **public **List<Route> findByPage(**int **cid, **int **start, **int **pageSize) {<br /> String sql = **"select **_*_** from tab_route where cid = ? limit ? , ?"**;
    3. **return template**.query(sql,**new **BeanPropertyRowMapper<Route>(Route.**class**),cid,start,pageSize);<br /> }<br />}

    12 旅游线路名称查询

    travel - 图27

    12.1 查询参数的传递

    在header.html中
    $(“#search-button”).click(function () {
    //线路名称
    var rname = $(“#search_input”).val();

    1. **var **cid = _getParameter_(**"cid"**);<br /> // 跳转路径 http://localhost/travel/route_list.html?cid=5,拼接上rname=xxx<br /> **_location_**.href=**"http://localhost/travel/route_list.html?cid="**+cid+**"&rname="**+rname;<br />});<br />在route_list.html<br />**var **cid = _getParameter_(**"cid"**);<br /> //获取rname的参数值<br /> **var **rname = _getParameter_(**"rname"**);<br /> //判断rname如果不为null或者""<br /> **if**(rname){<br /> //url解码<br /> rname = **_window_**._decodeURIComponent_(rname);<br /> }

    12.2 修改后台代码

    1. Servlet<br />@WebServlet(**"/route/*"**)**public class **RouteServlet **extends **BaseServlet {
    2. **private **RouteService **routeService **= **new **RouteServiceImpl();
    3. /**<br /> * 分页查询<br /> * **@param _request<br />__ _*** **@param _response<br />__ _*** **@throws **ServletException<br /> * **@throws **IOException<br /> */<br /> **public void **pageQuery(HttpServletRequest request, HttpServletResponse response) **throws **ServletException, IOException {<br /> //1.接受参数<br /> String currentPageStr = request.getParameter(**"currentPage"**);<br /> String pageSizeStr = request.getParameter(**"pageSize"**);<br /> String cidStr = request.getParameter(**"cid"**);
    4. //接受rname 线路名称<br /> String rname = request.getParameter(**"rname"**);<br /> rname = **new **String(rname.getBytes(**"iso-8859-1"**),**"utf-8"**);
    5. **int **cid = 0;//类别id<br /> //2.处理参数<br /> **if**(cidStr != **null **&& cidStr.length() > 0){<br /> cid = Integer._parseInt_(cidStr);<br /> }<br /> **int **currentPage = 0;//当前页码,如果不传递,则默认为第一页<br /> **if**(currentPageStr != **null **&& currentPageStr.length() > 0){<br /> currentPage = Integer._parseInt_(currentPageStr);<br /> }**else**{<br /> currentPage = 1;<br /> }
    6. **int **pageSize = 0;//每页显示条数,如果不传递,默认每页显示5条记录<br /> **if**(pageSizeStr != **null **&& pageSizeStr.length() > 0){<br /> pageSize = Integer._parseInt_(pageSizeStr);<br /> }**else**{<br /> pageSize = 5;<br /> }
    7. //3. 调用service查询PageBean对象<br /> PageBean<Route> pb = **routeService**.pageQuery(cid, currentPage, pageSize,rname);
    8. //4. 将pageBean对象序列化为json,返回<br /> writeValue(pb,response);
    9. }

    }

    Service
    public PageBean pageQuery(int cid, int currentPage, int pageSize,String rname ) {
    //封装PageBean
    PageBean pb = new PageBean();
    //设置当前页码
    pb.setCurrentPage(currentPage);
    //设置每页显示条数
    pb.setPageSize(pageSize);

    //设置总记录数
    int totalCount = routeDao.findTotalCount(cid,rname);
    pb.setTotalCount(totalCount);
    //设置当前页显示的数据集合
    int start = (currentPage - 1) pageSize;//开始的记录数
    List list = *routeDao
    .findByPage(cid,start,pageSize,rname);
    pb.setList(list);

    1. //设置总页数 = 总记录数/每页显示条数<br /> **int **totalPage = totalCount % pageSize == 0 ? totalCount / pageSize :(totalCount / pageSize) + 1 ;<br /> pb.setTotalPage(totalPage);
    2. **return **pb;<br />}

    Dao

    @Overridepublic int findTotalCount(int cid,String rname) {
    //String sql = “select count() from tabroute where cid = ?”;
    //1.定义sql模板
    String sql = “select _count
    (_
    _) from tab_route where 1=1 “;
    StringBuilder sb = new StringBuilder(sql);

    1. List params = **new **ArrayList();//条件们<br /> //2.判断参数是否有值<br /> **if**(cid != 0){<br /> sb.append( **" and cid = ? "**);
    2. params.add(cid);//添加?对应的值<br /> }
    3. **if**(rname != **null **&& rname.length() > 0){<br /> sb.append(**" and rname like ? "**);
    4. params.add(**"%"**+rname+**"%"**);<br /> }
    5. sql = sb.toString();
    6. **return template**.queryForObject(sql,Integer.**class**,params.toArray());<br />}<br />@Override**public **List<Route> findByPage(**int **cid, **int **start, **int **pageSize,String rname) {<br /> //String sql = "select * from tab_route where cid = ? and rname like ? limit ? , ?";<br /> String sql = **" select **_*_** from tab_route where 1 = 1 "**;<br /> //1.定义sql模板<br /> StringBuilder sb = **new **StringBuilder(sql);
    7. List params = **new **ArrayList();//条件们<br /> //2.判断参数是否有值<br /> **if**(cid != 0){<br /> sb.append( **" and cid = ? "**);
    8. params.add(cid);//添加?对应的值<br /> }
    9. **if**(rname != **null **&& rname.length() > 0){<br /> sb.append(**" and rname like ? "**);
    10. params.add(**"%"**+rname+**"%"**);<br /> }<br /> sb.append(**" limit ? , ? "**);//分页条件
    11. sql = sb.toString();
    12. params.add(start);<br /> params.add(pageSize);
    13. **return template**.query(sql,**new **BeanPropertyRowMapper<Route>(Route.**class**),params.toArray());<br />}

    12.3 修改前台代码

    $(function () {
    / var search = location.search;
    //alert(search);//?id=5
    // 切割字符串,拿到第二个值
    var cid = search.split(“=”)[1];
    /
    //获取cid的参数值
    var cid = getParameter(“cid”);
    //获取rname的参数值
    var rname = getParameter(“rname”);
    //判断rname如果不为null或者””
    if(rname){
    //url解码
    rname = window.decodeURIComponent(rname);
    }

    1. //当页码加载完成后,调用load方法,发送ajax请求加载数据<br /> _load_(cid,**null**,rname);<br />});<br />**function **_load_(cid ,currentPage,rname){<br /> //发送ajax请求,请求route/pageQuery,传递cid<br /> **$**.get(**"route/pageQuery"**,{**cid**:cid,**currentPage**:currentPage,**rname**:rname},**function **(pb) {<br /> //解析pagebean数据,展示到页面上
    2. //1.分页工具条数据展示<br /> //1.1 展示总页码和总记录数<br /> **$**(**"#totalPage"**).html(pb.totalPage);<br /> **$**(**"#totalCount"**).html(pb.totalCount);
    3. /*<br /> <li><a href="">首页</a></li><br /> <li class="threeword"><a href="#">上一页</a></li><br /> <li class="curPage"><a href="#">1</a></li><br /> <li><a href="#">2</a></li><br /> <li><a href="#">3</a></li><br /> <li><a href="#">4</a></li><br /> <li><a href="#">5</a></li><br /> <li><a href="#">6</a></li><br /> <li><a href="#">7</a></li><br /> <li><a href="#">8</a></li><br /> <li><a href="#">9</a></li><br /> <li><a href="#">10</a></li><br /> <li class="threeword"><a href="javascript:;">下一页</a></li><br /> <li class="threeword"><a href="javascript:;">末页</a></li>
    4. */<br /> **var **lis = **""**;
    5. **var **fristPage = **'<li onclick="javascipt:**_load_**('**+cid+**',1,\''**+rname+**'\')"><a href="javascript:void(0)">首页</a></li>'**;
    6. //计算上一页的页码<br /> **var **beforeNum = pb.**currentPage **- 1;<br /> **if**(beforeNum <= 0){<br /> beforeNum = 1;<br /> }
    7. **var **beforePage = **'<li onclick="javascipt:**_load_**('**+cid+**','**+beforeNum+**',\''**+rname+**'\')" class="threeword"><a href="javascript:void(0)">上一页</a></li>'**;
    8. lis += fristPage;<br /> lis += beforePage;<br /> //1.2 展示分页页码<br /> /*<br /> 1.一共展示10个页码,能够达到前5后4的效果<br /> 2.如果前边不够5个,后边补齐10个<br /> 3.如果后边不足4个,前边补齐10个<br /> */
    9. // 定义开始位置begin,结束位置 end<br /> **var **begin; // 开始位置<br /> **var **end ; // 结束位置
    10. //1.要显示10个页码<br /> **if**(pb.totalPage < 10){<br /> //总页码不够10页
    11. begin = 1;<br /> end = pb.totalPage;<br /> }**else**{<br /> //总页码超过10页
    12. begin = pb.**currentPage **- 5 ;<br /> end = pb.**currentPage **+ 4 ;
    13. //2.如果前边不够5个,后边补齐10个<br /> **if**(begin < 1){<br /> begin = 1;<br /> end = begin + 9;<br /> }
    14. //3.如果后边不足4个,前边补齐10个<br /> **if**(end > pb.totalPage){<br /> end = pb.totalPage;<br /> begin = end - 9 ;<br /> }<br /> }
    15. **for **(**var **i = begin; i <= end ; i++) {<br /> **var **li;<br /> //判断当前页码是否等于i<br /> **if**(pb.**currentPage **== i){
    16. li = **'<li class="curPage" onclick="javascipt:**_load_**('**+cid+**','**+i+**',\''**+rname+**'\')"><a href="javascript:void(0)">'**+i+**'</a></li>'**;
    17. }**else**{<br /> //创建页码的li<br /> li = **'<li onclick="javascipt:**_load_**('**+cid+**','**+i+**',\''**+rname+**'\')"><a href="javascript:void(0)">'**+i+**'</a></li>'**;<br /> }<br /> //拼接字符串<br /> lis += li;<br /> }
    18. /* for (var i = 1; i <= pb.totalPage ; i++) {<br /> var li;<br /> //判断当前页码是否等于i<br /> if(pb.currentPage == i){
    19. li = '<li class="curPage" onclick="javascipt:load('+cid+','+i+')"><a href="javascript:void(0)">'+i+'</a></li>';
    20. }else{<br /> //创建页码的li<br /> li = '<li onclick="javascipt:load('+cid+','+i+')"><a href="javascript:void(0)">'+i+'</a></li>';<br /> }<br /> //拼接字符串<br /> lis += li;<br /> }*/<br /> **var **lastPage = **'<li class="threeword"><a href="javascript:;">末页</a></li>'**;<br /> **var **nextPage = **'<li class="threeword"><a href="javascript:;">下一页</a></li>'**;
    21. lis += nextPage;<br /> lis += lastPage;
    22. //将lis内容设置到 ul<br /> **$**(**"#pageNum"**).html(lis);
    23. /*<br /> <li><br /> <div class="img"><img src="images/04-search_03.jpg" alt=""></div><br /> <div class="text1"><br /> <p>【减100元 含除夕/春节出发】广州增城三英温泉度假酒店/自由行套票</p><br /> <br/><br /> <p>1-2月出发,网付立享¥1099/2人起!爆款位置有限,抢完即止!</p><br /> </div><br /> <div class="price"><br /> <p class="price_num"><br /> <span>&yen;</span><br /> <span>299</span><br /> <span>起</span><br /> </p><br /> <p><a href="route_detail.html">查看详情</a></p><br /> </div><br /> </li>
    24. */
    25. //2.列表数据展示<br /> **var **route_lis = **""**;
    26. **for **(**var **i = 0; i < pb.list.**length**; i++) {<br /> //获取{rid:1,rname:"xxx"}<br /> **var **route = pb.list[i];
    27. **var **li = **'<li>\n' **+<br /> **' <div class="img"><img src="'**+route.rimage+**'" style="width: 299px;"></div>\n' **+<br /> **' <div class="text1">\n' **+<br /> **' <p>'**+route.**rname**+**'</p>\n' **+<br /> **' <br/>\n' **+<br /> **' <p>'**+route.routeIntroduce+**'</p>\n' **+<br /> **' </div>\n' **+<br /> **' <div class="price">\n' **+<br /> **' <p class="price_num">\n' **+<br /> **' <span>&yen;</span>\n' **+<br /> **' <span>'**+route.price+**'</span>\n' **+<br /> **' <span>起</span>\n' **+<br /> **' </p>\n' **+<br /> **' <p><a href="route_detail.html">查看详情</a></p>\n' **+<br /> **' </div>\n' **+<br /> **' </li>'**;<br /> route_lis += li;<br /> }<br /> **$**(**"#route"**).html(route_lis);
    28. //定位到页面顶部<br /> **_window_**.scrollTo(0,0);<br /> });

    }

    13 旅游线路的详情展示

    13.1 分析

    travel - 图28

    travel - 图29

    13.2 代码实现

    13.2.1 后台代码

    Servlet
    /
    根据id查询一个旅游线路的详细信息
    @param request
    __
    * @param response
    __
    * @throws ServletException
    *
    @throws IOException
    */
    public void findOne(HttpServletRequest request, HttpServletResponse response) throws **ServletException, IOException {

    1. //1.接收id<br /> String rid = request.getParameter(**"rid"**);<br /> //2.调用service查询route对象<br /> Route route = **routeService**.findOne(rid);<br /> //3.转为json写回客户端<br /> writeValue(route,response);<br />}

    Service

    @Overridepublic Route findOne(String rid) {
    //1.根据id去route表中查询route对象
    Route route = routeDao.findOne(Integer.parseInt(rid));

    1. //2.根据route的id 查询图片集合信息<br /> List<RouteImg> routeImgList = **routeImgDao**.findByRid(route.getRid());<br /> //2.2将集合设置到route对象<br /> route.setRouteImgList(routeImgList);<br /> //3.根据route的sid(商家id)查询商家对象<br /> Seller seller = **sellerDao**.findById(route.getSid());<br /> route.setSeller(seller);
    2. **return **route;<br />}

    SellerDao

    public class SellerDaoImpl implements SellerDao {

    1. **private **JdbcTemplate **template **= **new **JdbcTemplate(JDBCUtils._getDataSource_());
    2. @Override<br /> **public **Seller findById(**int **id) {
    3. String sql = **"select **_*_** from tab_seller where sid = ? "**;<br /> **return template**.queryForObject(sql,**new **BeanPropertyRowMapper<Seller>(Seller.**class**),id);<br /> }<br />}<br />routeDao<br />@Override**public **Route findOne(**int **rid) {<br /> String sql = **"select **_*_** from tab_route where rid = ?"**;<br /> **return template**.queryForObject(sql,**new **BeanPropertyRowMapper<Route>(Route.**class**),rid);<br />}<br />RouteImgDao

    public class RouteImgDaoImpl implements RouteImgDao {

    1. **private **JdbcTemplate **template **= **new **JdbcTemplate(JDBCUtils._getDataSource_());
    2. @Override<br /> **public **List<RouteImg> findByRid(**int **rid) {<br /> String sql = **"select **_*_** from tab_route_img where rid = ? "**;<br /> **return template**.query(sql,**new **BeanPropertyRowMapper<RouteImg>(RouteImg.**class**),rid);<br /> }<br />}

    13.2.2 前台代码

    Route_detail.html中加载后

    1. 获取rid
    2. 发送ajax请求,获取route对象
    3. 解析对象的数据

    //1.获取ridvar rid = getParameter(“rid”);
    //2.发送请求请求 route/findOne
    $.get(“route/findOne”,{rid:rid},function (route) {
    //3.解析数据填充html
    $(“#rname”).html(route.rname);
    $(“#routeIntroduce”).html(route.routeIntroduce);
    $(“#price”).html(“¥”+route.price);
    $(“#sname”).html(route.seller.sname);
    $(“#consphone”).html(route.seller.consphone);
    $(“#address”).html(route.seller.address);

    1. //图片展示
    2. **var **ddstr = **'<a class="up_img up_img_disable"></a>'**;
    3. //遍历routeImgList<br /> **for **(**var **i = 0; i < route.routeImgList.**length**; i++) {<br /> **var **astr ;<br /> **if**(i >= 4){<br /> astr = **'<a title="" class="little_img" data-bigpic="'**+route.routeImgList[i].bigPic+**'" style="display:none;">\n' **+<br /> **' <img src="'**+route.routeImgList[i].smallPic+**'">\n' **+<br /> **' </a>'**;<br /> }**else**{<br /> astr = **'<a title="" class="little_img" data-bigpic="'**+route.routeImgList[i].bigPic+**'">\n' **+<br /> **' <img src="'**+route.routeImgList[i].smallPic+**'">\n' **+<br /> **' </a>'**;<br /> }
    4. ddstr += astr;<br /> }<br /> ddstr+=**'<a class="down_img down_img_disable" style="margin-bottom: 0;"></a>'**;
    5. **$**(**"#dd"**).html(ddstr);
    6. //图片展示和切换代码调用<br /> _goImg_();<br /> });

    14 旅游线路收藏功能

    14.1 分析

    14.1.1 判断当前登录用户是否收藏过该线路

    当页面加载完成后,发送ajax请求,获取用户是否收藏的标记
    根据标记,展示不同的按钮样式

    travel - 图30

    travel - 图31

    14.2 编写代码

    14.2.1 后台代码

    RouteServlet:

    public void isFavorite(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    //1. 获取线路id
    String rid = request.getParameter(“rid”);

    1. //2. 获取当前登录的用户 user<br /> User user = (User) request.getSession().getAttribute(**"user"**);<br /> **int **uid;//用户id<br /> **if**(user == **null**){<br /> //用户尚未登录<br /> uid = 0;<br /> }**else**{<br /> //用户已经登录<br /> uid = user.getUid();<br /> }
    2. //3. 调用FavoriteService查询是否收藏<br /> **boolean **flag = **favoriteService**.isFavorite(rid, uid);
    3. //4. 写回客户端<br /> writeValue(flag,response);<br />}

    FavoriteService

    @Overridepublic boolean isFavorite(String rid, int uid) {

    1. Favorite favorite = **favoriteDao**.findByRidAndUid(Integer._parseInt_(rid), uid);
    2. **return **favorite != **null**;//如果对象有值,则为true,反之,则为false}

    FavoriteDao
    @Overridepublic Favorite findByRidAndUid(int rid, int uid) {
    Favorite favorite = null;
    try {
    String sql = “ select * from tab_favorite where rid = ? and uid = ?”;
    favorite = template.queryForObject(sql, new BeanPropertyRowMapper(Favorite.class), rid, uid);
    } catch (DataAccessException e) {
    e.printStackTrace();
    }
    return favorite;
    }

    14.2.2 前台代码

    route_detail.html

    $(function () {
    // 发送请求,判断用户是否收藏过该线路
    var rid = getParameter(“rid”);
    $.get(“route/isFavorite”,{rid:rid},function (flag) {
    if(flag){
    // 用户已经收藏过
    //
    //设置收藏按钮的样式
    $(“#favorite”).addClass(“already”);
    $(“#favorite”).prop(“disabled”,disabled);

    1. }**else**{<br /> // 用户没有收藏<br /> }<br /> });

    14.3 收藏次数的动态展示

    前台:
    //设置收藏次数$(“#favoriteCount”).html(“已收藏”+route.count+“次”);

    后台:
    RouteService
    //4. 查询收藏次数int count = favoriteDao.findCountByRid(route.getRid());
    route.setCount(count);

    FavoriteDao
    @Overridepublic int findCountByRid(int rid) {
    String sql = “SELECT COUNT(*) FROM tab_favorite WHERE rid = ?”;

    1. **return template**.queryForObject(sql,Integer.**class**,rid);<br />}

    14.4 点击按钮收藏线路

    14.4.1 分析:

    1. ![](https://cdn.nlark.com/yuque/0/2021/png/22277845/1627874049321-2199eecf-04e3-44b8-9d60-8fad17271e08.png#id=YhAND&originHeight=465&originWidth=1180&originalType=binary&ratio=1&status=done&style=none)

    14.4.2 编码

    前台代码
    $(function () {
    // 发送请求,判断用户是否收藏过该线路
    var rid = getParameter(“rid”);
    $.get(“route/isFavorite”,{rid:rid},function (flag) {
    if(flag){
    // 用户已经收藏过
    //
    //设置收藏按钮的样式
    $(“#favorite”).addClass(“already”);
    $(“#favorite”).attr(“disabled”,“disabled”);

    1. //删除按钮的点击事件<br /> **$**(**"#favorite"**).removeAttr(**"onclick"**); }**else**{<br /> // 用户没有收藏<br /> }<br /> });

    });
    //点击收藏按钮触发的方法function addFavorite(){
    var rid = getParameter(“rid”);
    //1. 判断用户是否登录
    $.get(“user/findOne”,{},function (user) {
    if(user){
    //用户登录了
    //添加功能
    $.get(“route/addFavorite”,{rid:rid},function () {

    1. //代码刷新页面<br /> **_location_**.reload();<br /> });
    2. }**else**{<br /> //用户没有登录<br /> _alert_(**"您尚未登录,请登录"**);<br /> **_location_**.href=**"http://localhost/travel/login.html"**;<br /> }<br /> })<br />}

    后台代码
    RouteServlet
    public void addFavorite(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    //1. 获取线路rid
    String rid = request.getParameter(“rid”);
    //2. 获取当前登录的用户
    User user = (User) request.getSession().getAttribute(“user”);
    int uid;//用户id
    if(user == null){
    //用户尚未登录
    return ;
    }else{
    //用户已经登录
    uid = user.getUid();
    }

    1. //3. 调用service添加<br /> **favoriteService**.add(rid,uid);

    }

    FavoriteService
    @Overridepublic void add(String rid, int uid) {
    favoriteDao.add(Integer.parseInt(rid),uid);
    }

    FavoriteDao
    @Overridepublic void add(int rid, int uid) {
    String sql = “insert into tab_favorite values(?,?,?)”;

    1. **template**.update(sql,rid,**new **Date(),uid);<br />}