1. 项目导入与启动
可在EditConfiguration中编辑启动命令
2. 技术选型
1. Web层
(1)Servlet :前端控制器
(2)html :视图
(3)Filter : 过滤器
(4)BeanUtils : 数据封装
(5)Jackson : json序列化工具
2. Service层
(1)Javamail :java发送邮件的工具
(2)Redis :nosql内存数据库
(3)Jedis :java的redis客户端
3. Dao层
(1)Mysql :数据库
(2)Druid :数据库连接池
(3)JDBCTemplate :jdbc的工具
3. 创建数据库
-- 创建数据库 CREATE DATABASE travel; -- 使用数据库 USE travel;
4. 用户注册功能
注册功能分析:
5. 邮箱激活
为什么要进行邮件激活?
* 为了保证用户填写的邮箱是正确的,将来可以推广一些宣传信息到用户邮箱中。
6. 用户登录功能
7. 退出登录功能
* 什么叫做登录了?session中有user对象
* 实现步骤:
1. 访问servlet,将session销毁
2. 跳转到登录页面
<a href="javascript:location.href='exitServlet';">退出</a>
// 销毁session request.getSession().invalidate(); // 跳转页面 response.sendRedirect(request.getContextPath()+"/login.html");
8. 优化Servlet
* 减少Servlet的数量,现在是一个功能一个Servlet,将其优化为一个模块一个Servlet
* 相当于在数据库中一张表对应一个servlet,在Servlet中提供不同的方法,完成用户的请求
* 抽取BaseServlet
service方法乱码问题: maven runner中设置:-Dfile.encoding=gb2312
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package cn.itcast.travel.web.servlet; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class BaseServlet extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //System.out.println("baseservlet的方法执行了"); // 完成方法的分发 // 1. 获取请求路径 String uri = req.getRequestURI(); // 返回如:/travel/user/add System.out.println(uri); // 2. 获取方法名称 String methodName = uri.substring(uri.lastIndexOf("/") + 1); System.out.println(methodName); // 3. 获取方法对象 this就是UserServlet对象 通过字节码文件 反射获取 System.out.println(this); // this就是UserServlet对象 try { // getDeclaredMethod会忽略方法访问权限修饰符 protected就能被访问 Method method = this.getClass().getMethod(methodName, HttpServletRequest.class, HttpServletResponse.class); // 4. 执行方法 // 暴力反射 //method.setAccessible(true); method.invoke(this,req,resp); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } }
9. 分类数据展示功能
分析:分析发现,分类的数据在每一次页面加载后都会重新请求数据库来加载 ,对数据库的压力比较大,而且分类的数据不会经常产生变化,所以可以使用redis来缓存这个数据
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package cn.itcast.travel.service.impl; import cn.itcast.travel.dao.CategoryDao; import cn.itcast.travel.dao.impl.CategoryDaoImpl; import cn.itcast.travel.domain.Category; import cn.itcast.travel.service.CategoryService; import cn.itcast.travel.util.JedisUtil; import redis.clients.jedis.Jedis; import java.util.ArrayList; import java.util.List; import java.util.Set; public class CategoryServiceImpl implements CategoryService { private CategoryDao dao = new CategoryDaoImpl(); @Override public List<Category> findAll() { // 1. 从redis中查询 // 1.1 获取jedis客户端 Jedis jedis = JedisUtil.getJedis(); // 1.2 使用sortedset排序查询 Set<String> categorys = jedis.zrange("category", 0, -1); List<Category> cs = null; // 2. 判断查询的集合是否为空 if(categorys == null || categorys.size() == 0){ // 3. 如果为空,需要从数据库中查询,再将数据存入redis // 3.1 从数据库查询 System.out.println("从数据库查询"); cs = dao.findAll(); // 3.2 将集合数据存储到redis中的key为category的sorted set中 for (int i = 0; i < cs.size(); i++) { jedis.zadd("category",cs.get(i).getCid(),cs.get(i).getCname()); } }else { // 4. 如果不为空,将set的数据存入list中,要做到数据结构统一,因为后期要返回一个list集合 System.out.println("从redis中查询"); cs = new ArrayList<Category>(); for (String name : categorys){ Category category = new Category(); category.setCname(name); cs.add(category); } } return cs; } }
10. 旅游线路的分页信息展示
类别id的传递:
* Redis中查询score(cid)
* index页面传递cid(通过location.search获取cid)
* 获取index页面传来的cid
分析:
11. 旅游线路名称查询
在header.html中
在route_list中获取参数
修改后台代码:
Servlet中:
route_list.html中:
12. 旅游线路详情展示