Loading...

Java EE入门(二十一)——Web综合案例

  iwehdio的博客园:https://www.cnblogs.com/iwehdio/

1、导入项目

  • 项目导入:使用 maven 导入项目,从 maven 创建项目并选择项目的 pom.xml 文件即可。(为了防止报错,先配置maven的阿里云镜像)

  • 启动项目:

    • 方法一:使用maven加载的Tomcat插件run。
    • 方法二:配置maven运行,命令为tomcat7:run。
  • 报错:Error: java: 非法字符 '\ufeff'。

  • 技术选型:

    • Web层:
      • Servlet:前端控制器。
      • html:视图展示。
      • Filter:过滤器。
      • BeanUtils:数据封装。
      • Jackson:JSON序列化。
    • Service层:
      • Javamail:使用java发送邮件。
      • redis:缓存。
      • Jedis:操作redis。
    • Dao层:
      • Mysql:数据库。
      • Druid:数据库连接池。
      • JdbcTemplate:jdbc工具。

2、登陆和注册

  • 创建数据库:

    CREATE DATABASE travel;
    USE travel;
    -- 创建表 travl.sql
    
  • 注册功能分析:

    • register.html:
      1. 使用 ajax 完成表单提交。
      2. 注册成功,跳转到登陆成功页面。
    • registUserServlet:
    1. 获取数据。
    2. 封装 User 对象。
    3. 调用 Service 完成注册。
    4. 根据 Service 的返回提示信息。
      • 将提示信息转为 json 。
      • 设置响应头 contentType 。
    • UserService:
      • registUser(User user)注册用户方法。
        1. 调用 Dao 根据用户名查询用户。
          • 用户存在则返回 False。
          • 用户不存在则调用 Dao 保存用户信息。
    • UserDao:
      1. findByUsername(String username):寻找用户的方法。
      2. save(User user):保存用户信息。
  • 注册功能实现:

    1. 使用 js 进行表单校验。

      • 校验规则:

        • 用户名:单词字符,长度8到20位
        • 密码:单词字符,长度8到20位
        • email:邮件格式
        • 姓名:非空
        • 手机号:手机号格式
        • 出生日期:非空
        • 验证码:非空
      • 校验用户名:

        function chechUsername() {
            //1、获取用户名
            var username = $("username").val();
            //2、定义正则
            var reg_username = /^\w{8,20}$/;
            //3、判断,给出提示信息
            flag = reg_username.test(username);
            if(flag) {
                $("#username").css("border","1px solid red");
            } else {
                $("#username").css("border","1px solid red");
            }
        }
        
      • 校验密码与用户名类似。

      • 校验邮箱:

        function checkEmail() {
            var email = $("#email").val();
            var reg_email = /^\w+@\w+\.\w+$/;
            var flag = reg_email.test(email);
            if(flag) {
                $("#email").css("border","1px solid red");
            } else {
                $("#email").css("border","1px solid red");
            }
        }
        
      • 表单提交时,调用所有的校验方法:

        $(function () {
            //当表单提交时,调用所有的校验方法
            $("#registerForm").submit(function(){
                return checkUsername() && checkPassword() && checkEmail();
            });
            //当某一个组件失去焦点是,调用对应的校验方法
            $("#username").blur(checkUsername);
            $("#password").blur(checkPassword);
            $("#email").blur(checkEmail);
        });
        
    2. 异步提交表单功能实现。

      • 使用异步的原因:为了获取服务器响应的数据,而html不能直接从servlet获取域对象数据。
      • 如果校验通过,发送 ajax 请求,提交表单的数据(而不是表单)。
      $(function () {
          //当表单提交时,调用所有的校验方法
          $("#registerForm").submit(function(){
              //1、发送数据到服务器
              if(checkUsername() && checkPassword() && checkEmail()) {
              //2、异步发送请求,内容为序列化的字符串
                  $.post("registUserServlet",$(this).serialize(),function(data) {
              //3、处理服务器返回的数据data
                      
                  });
              }
          });
          //当某一个组件失去焦点是,调用对应的校验方法
          $("#username").blur(checkUsername);
          $("#password").blur(checkPassword);
          $("#email").blur(checkEmail);
      });
      
    3. 后台代码实现。

      • 编写registUserSevletUserServiceUserServiceImplUserDaoUserDaoImpl

      • registUserSevlet.java:

      @WebServlet("/registUserServlet")
      public class RegistUserServlet extends HttpServlet {
          protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
      
              //1.获取数据
              Map<String, String[]> map = request.getParameterMap();
      
              //2.封装对象
              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();
              boolean flag = service.regist(user);
              ResultInfo info = new ResultInfo();
              //4.响应结果
              if(flag){
                  //注册成功
                  info.setFlag(true);
              }else{
                  //注册失败
                  info.setFlag(false);
                  info.setErrorMsg("注册失败!");
              }
      
              //将info对象序列化为json
              ObjectMapper mapper = new ObjectMapper();
              String json = mapper.writeValueAsString(info);
      
              //将json数据写回客户端
              //设置content-type
              response.setContentType("application/json;charset=utf-8");
              response.getWriter().write(json);
      
      
          }
      
          protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
              this.doPost(request, response);
          }
      }
      
      • 添加验证码功能:

        //验证校验
        String check = request.getParameter("check");
        //从sesion中获取验证码
        HttpSession session = request.getSession();
        String checkcode_server = (String) session.getAttribute("CHECKCODE_SERVER");
        session.removeAttribute("CHECKCODE_SERVER");//为了保证验证码只能使用一次
        //比较
        if(checkcode_server == null || !checkcode_server.equalsIgnoreCase(check)){
            //验证码错误
            ResultInfo info = new ResultInfo();
            //注册失败
            info.setFlag(false);
            info.setErrorMsg("验证码错误");
            //将info对象序列化为json
            ObjectMapper mapper = new ObjectMapper();
            String json = mapper.writeValueAsString(info);
            response.setContentType("application/json;charset=utf-8");
            response.getWriter().write(json);
            return;
        }
        
      • UserServiceImpl.java:

        public class UserServiceImpl implements UserService {
            private UserDao userDao = new UserDaoImpl();
            @Override
            public boolean regist(User user) {
                //1.根据用户名查询用户对象
                User u = userDao.findByUsername(user.getUsername());
                //判断u是否为null
                if(u != null){
                    //用户名存在,注册失败
                    return false;
                }
                userDao.save(user);
                return true;
            }
        
      • UserDaoImpl.java:

        public class UserDaoImpl implements UserDao {
        
            private JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());
        
            @Override
            public User findByUsername(String username) {
                User user = null;
                try {
                    //1.定义sql
                    String sql = "select * from tab_user where username = ?";
                    //2.执行sql
                    user = template.queryForObject(sql, new BeanPropertyRowMapper<User>(User.class), username);
                } catch (Exception e) {
        
                }
        		//这是因为如果查询不到不会返回null,而是直接报错,所以需要处理
                return user;
            }
        
            @Override
            public void save(User user) {
                //1.定义sql
                String sql = "insert into tab_user(username,password,name,birthday,sex,telephone,email,status,code) values(?,?,?,?,?,?,?,?,?)";
                //2.执行sql
        
                template.update(sql,user.getUsername(),
                            user.getPassword(),
                        user.getName(),
                        user.getBirthday(),
                        user.getSex(),
                        user.getTelephone(),
                        user.getEmail(),
                        user.getStatus(),
                        user.getCode()
                        );
            }
        }
        
      • 前台处理服务器返回数据:

        if(data.flag){
            //注册成功,跳转成功页面
            location.href="register_ok.html";
        }else{
            //注册失败,给errorMsg添加提示信息
            $("#errorMsg").html(data.errorMsg);
        
      • 邮件激活:

        • 发送邮件:使用邮件工具类。

        • 用户激活:其实就是把数据库中的激活状态由N改为Y。

        • 激活码:使用UUID工具类。

        • UserServiceImpl下的regist函数中,注册时同时生成唯一字符串并且发送邮件:

          //2.1设置激活码,唯一字符串
          user.setCode(UuidUtil.getUuid());
          //2.2设置激活状态
          user.setStatus("N");
          userDao.save(user);
          
          //3.激活邮件发送,邮件正文?
          String content="<a href='http://localhost/travel/activeUserServlet?code="+user.getCode()+"'>点击激活【黑马旅游网】</a>";
          MailUtils.sendMail(user.getEmail(),content,"激活邮件");
          
        • 点击超链接完成激活:

          • ActiveUserServlet

            @WebServlet("/activeUserServlet")
            public class ActiveUserServlet extends HttpServlet {
                protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
                    //1.获取激活码
                    String code = request.getParameter("code");
                    if(code != null){
                        //2.调用service完成激活
                        UserService service = new UserServiceImpl();
                        boolean flag = service.active(code);
            
                        //3.判断标记
                        String msg = null;
                        if(flag){
                            //激活成功
                            msg = "激活成功,请<a href='login.html'>登录</a>";
                        }else{
                            //激活失败
                            msg = "激活失败,请联系管理员!";
                        }
                        response.setContentType("text/html;charset=utf-8");
                        response.getWriter().write(msg);
                    }
            
                }
            
                protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
                    this.doPost(request, response);
                }
            }
            
          • UserServiceImpl中的active方法:

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

            @Override
            public User findByCode(String code) {
                User user = null;
                try {
                    String sql = "select * from tab_user where code = ?";
            
                    user = template.queryForObject(sql,new BeanPropertyRowMapper<User>(User.class),code);
                } catch (DataAccessException e) {
                    e.printStackTrace();
                }
            
                return user;
            }
            
            @Override
            public void updateStatus(User user) {
                String sql = " update tab_user set status = 'Y' where uid=?";
                template.update(sql,user.getUid());
            }
            
  • 登陆功能分析:

    • login.html:
      • 输入账号和密码。
    • LoginServlet:
      1. 获取用户信息。
      2. 调用 service 查询 user。
      3. 判断用户是否存在。
      4. 判断用户是否激活。
      5. 响应错误信息。
    • UserService:
      • login方法,接收用户名和密码,返回真正的User对象。
    • UserDao:
      • 根据用户名和密码查询用户。
  • 登陆功能实现:

    1. 后台代码实现。

      • loginServlet.java:

        @WebServlet("/loginServlet")
        public class LoginServlet extends HttpServlet {
            protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
                //1.获取用户名和密码数据
                Map<String, String[]> 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.判断用户对象是否为null
                if(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())){
                    request.getSession().setAttribute("user",u);//登录成功标记
        
                    //登录成功
                    info.setFlag(true);
                }
        
                //响应数据
                ObjectMapper mapper = new ObjectMapper();
        
                response.setContentType("application/json;charset=utf-8");
                mapper.writeValue(response.getOutputStream(),info);
        
            }
        
            protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
                this.doPost(request, response);
            }
        }
        
      • UserService中的login方法:

        @Override
        public User login(User user) {
            return userDao.findByUsernameAndPassword(user.getUsername(),user.getPassword());
        }
        
      • UserDao中的findByUsernameAndPassword方法:

        @Override
        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>(User.class), username,password);
            } catch (Exception e) {
        
            }
        
            return user;
        }
        
    2. 前台代码实现。

      • 给登陆按钮绑定单击事件,发送 ajax 请求提交表单数据,处理响应结果。

      • login.html:

        <script>
            $(function () {
                //1.给登录按钮绑定单击事件
                $("#btn_sub").click(function () {
                    //2.发送ajax请求,提交表单数据
                    $.post("loginServlet",$("#loginForm").serialize(),function (data) {
                        //data : {flag:false,errorMsg:''}
                        if(data.flag){
                            //登录成功
                            location.href="index.html";
                        }else{
                            //登录失败
                            $("#errorMsg").html(data.errorMsg);
                        }
                    });
                });
            });
            //3.处理响应结果
            //写在header.html中
        </script>
        
    3. index 页面提示用户名:

      • header.html:

        <script>
            $(function () {
               $.get("findUserServlet",{},function (data) {
                   //{uid:1,name:'李四'}
                   var msg = "欢迎回来,"+data.name;
                   $("#span_username").html(msg);
        
               }); 
            });
        </script>
        
      • findUserServlet.java:

        @WebServlet("/findUserServlet")
        public class FindUserServlet extends HttpServlet {
            protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
                //从session中获取登录用户
                Object user = request.getSession().getAttribute("user");
                //将user写回客户端
        
                ObjectMapper mapper = new ObjectMapper();
                response.setContentType("application/json;charset=utf-8");
                mapper.writeValue(response.getOutputStream(),user);
            }
        
            protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
                this.doPost(request, response);
            }
        }
        
  • 退出功能分析:

    • 登陆就是 session 中有 user 对象,退出就是销毁session 中的 user 对象。
    • 跳转到登陆页面。
  • 退出代码实现:

    1. 前台代码实现。

      • 点击退出,跳转到 exitServlet

        <a href="javascript:location.href='exitServlet';">退出</a>
        
    2. 后台代码实现。

      • ExitServlet.java:

        @WebServlet("/exitServlet")
        public class ExitServlet extends HttpServlet {
            protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
                //1.销毁session
                request.getSession().invalidate();
        
                //2.跳转登录页面
                response.sendRedirect(request.getContextPath()+"/login.html");
            }
        
            protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
                this.doPost(request, response);
            }
        }
        
  • 抽取 BaseServlet:

    • 减少 Servlet 的数量,优化为一个模块一个 Servlet ,数据库中一个表一个 Servlet 。

    • 在一个 Servlet 中写不同的方法。

    • 这些 Servlet 都继承自 BaseServlet ,BaseServlet 进行方法分发,继承自 HttpServlet 。

      1. 获取请求路径。
      2. 获取方法名称。
      3. 获取方法对象(反射)。
      4. 执行方法。
    • BaseServlet.java:

      public class BaseServlet extends HttpServlet {
      
      
          @Override
          protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
      
              //完成方法分发
              //1.获取请求路径
              String uri = req.getRequestURI(); //   /travel/user/add
              System.out.println("请求uri:"+uri);//  /travel/user/add
              //2.获取方法名称
              String methodName = uri.substring(uri.lastIndexOf('/') + 1);
              System.out.println("方法名称:"+methodName);
              //3.获取方法对象Method
              //谁调用我?我代表谁
              System.out.println(this);//UserServlet的对象cn.itcast.travel.web.servlet.UserServlet@4903d97e
              try {
                  //获取方法
                  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();
              }
      
          }
      }
      
  • UserServlet.java:

      @WebServlet("/user/*") // /user/add /user/find
      public class UserServlet extends BaseServlet {
      
          //声明UserService业务对象
          private UserService service = new UserServiceImpl();
      
          //注册功能
          public void regist(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
      	/* 方法体 */
          }
      }
    

3、旅游信息

  • 分类数据展示功能分析:

    • 前台功能:
      1. 发送 ajax 请求,访问服务器,加载真正的分类数据。
      2. 遍历数组完成展示。
    • Servlet:
      1. 调用 Service 查询,获取 List。
      2. 将List集合序列化为 Json 。
  • 分类数据展示实现:

    1. 后台代码实现。

      • categoryDao.java:

        public class CategoryDaoImpl implements CategoryDao {
        
            private JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());
        
            @Override
            public List<Category> findAll() {
                String sql = "select * from tab_category ";
                return template.query(sql,new BeanPropertyRowMapper<Category>(Category.class));
            }
        }
        
      • categoryService.java:

        public class CategoryServiceImpl implements CategoryService {
        
            private CategoryDao categoryDao = new CategoryDaoImpl();
        
            @Override
            public List<Category> findAll() {
               return categoryDao.findAll();
            }
        }
        
      • 将对 Json 的转换操作抽取到 BaseServlet 中:

        //直接将传入的对象序列化为json,并且写回客户端
        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,返回
        public String writeValueAsString(Object obj) throws JsonProcessingException {
            ObjectMapper mapper = new ObjectMapper();
            return mapper.writeValueAsString(obj);
        }
        
      • CategoryServlet.java:

        @WebServlet("/category/*")
        public class CategoryServlet extends BaseServlet {
        
            private CategoryService service = new CategoryServiceImpl();
        
            //查询所有
            public void findAll(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
                //1.调用service查询所有
                List<Category> cs = service.findAll();
                //2.序列化json返回
                ObjectMapper mapper = new ObjectMapper();
                response.setContentType("application/json;charset=utf-8");
                mapper.writeValue(response.getOutputStream(),cs);
                //writeValue(cs,response);
            }
        }
        
    2. 前台代码实现。

      • header.html加载后,发送请求到 category/findAll,根据返回的响应进行显示。

        //查询分类数据
        $.get("category/findAll",{},function (data) {
        //[{cid:1,cname:国内游},{},{}]
        

      var lis = '

    3. ';
      //遍历数组,拼接字符串(
    4. )
      for (var i = 0; i < data.length; i++) {
      var li = '
    5. <a href="route_list.html>'+data[i].cname+'
    6. ';
      lis += li;
      }

      //拼接收藏排行榜的li,

    7. 收藏排行榜
    8. lis+= '

    9. 收藏排行榜
    10. ';

      //将lis字符串,设置到ul的html内容中
      $("#category").html(lis);
      });

      
      
    11. Redis 优化。

      • 分类数据每次页面加载后都会重新请求数据库,而且分类的数据不经常变化,可以使用 Redis。

      • 先从 redis 中查询,判断集合是否为空,不为空则显示,为空则查询数据库并存入redis。

      • CategoryService.java:

        public class CategoryServiceImpl implements CategoryService {
        
            private CategoryDao categoryDao = 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) {
        
                    //System.out.println("从数据库查询....");
                    //3.如果为空,需要从数据库查询,在将数据存入redis
                    //3.1 从数据库查询
                    cs = categoryDao.findAll();
                    //3.2 将集合数据存储到redis中的 category的key
                    for (int i = 0; i < cs.size(); i++) {
        
                        jedis.zadd("category", cs.get(i).getCid(), cs.get(i).getCname());
                    }
                } else {
                    //System.out.println("从redis中查询.....");
                    //4.如果不为空,将set的数据存入list
                    cs = new ArrayList<Category>();
                    for (String name : categorys) {
                      Category category = new Category();
                        category.setCname(name);
                        cs.add(category);
                    }
         
                }
                return cs;
            }
        }
        
  • 分页数据展示分析:

    • 点击不同的分类后,看到的旅游线路是不一样的。旅游线路表和分类表是多对一的关系,查询分类数据时要传入对应的分类id即 cid。

    • 分页的实现:

      • 分页对象封装到PageBean对象中,需要总记录数、总页数、当前页码、每页显示的条数和每一页展示的数据。
        • 总记录数和每页展示数据的集合是需要从数据库查询的。
      • 请求时,需要携带当前页码、每页显示的条数和分类的cid。
      • 响应时,将PageBean对象序列化Json返回到html。
    • 路线图片通过查询 route_img 表,路线信息查询 route 表,经营信息查询 seller 表,价格查询 route 表。

    • RouteServlet接收页码 rid,调用 service 查询后转换为 json 返回。

    • RouteService根据 id 查询 route 对象;根据 rid 线路 id 查询 tab_route_img ,将结果设置到 route 对象;根据 sid 卖家 id 查询 tab_seller ,将结果设置到 route 对象。

    • Dao 层分别实现 RouteDaoRouteImgDaoSellerDao

  • 分页数据展示实现:

    • 前台 header.html 在点击分类时传入分类 cid:

      var li = '<li><a href="route_list.html?cid='+data[i].cid+'">'+data[i].cname+'</a></li>';
      
    • 后台 Redis 查询时,之前只查询了值,没有查询分数(cid),现在还需要查询分数:

      //同时查询分数和值
      Set<Tuple> categorys = jedis.zrangeWithScores("category", 0, -1);
      
      //从redis中查询数据
      cs = new ArrayList<Category>();
      for (Tuple tuple : categorys) {
          Category category = new Category();
          category.setCname(tuple.getElement());
          category.setCid((int) tuple.getScore());
          cs.add(category);
      }
      
    • 分页的后台实现:

      • PageBean.java:

        public class PageBean<T> {
        
            private int totalCount;//总记录数
            private int totalPage;//总页数
            private int currentPage;//当前页码
            private int pageSize;//每页显示的条数
            private List<T> list;//每页显示的数据集合
            /*  getter & setter  */
        }
        
      • RouteServlet.java:

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

        public class RouteDaoImpl implements RouteDao {
            JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());
            @Override
            public int findTotalCount(int cid) {
                String sql = "select count(*) from tab_route where cid = ?";
                return template.queryForObject(sql, Integer.class, cid);
            }
        
            @Override
            public List<Route> findByPage(int cid, int start, int pageSize) {
                String sql = "select * from tab_route where cid = ? limit ?, ?";
                return template.query(sql, new BeanPropertyRowMapper<Route>(Route.class), cid, start, pageSize);
            }
        }
    
  • RouteService.java:

        public class RouteServiceImpl implements RouteService {
            private RouteDao routeDao = new RouteDaoImpl();
            @Override
            public PageBean<Route> pageQuery(int cid, int currentPage, int pageSize) {
                PageBean<Route> pb = new PageBean<Route>();
                pb.setCurrentPage(currentPage);
                pb.setPageSize(pageSize);
                int totalCount = routeDao.findTotalCount(cid);
                pb.setTotalCount(totalCount);
                int start = (currentPage - 1) * pageSize;
                List<Route> list = routeDao.findByPage(cid, start, pageSize);
                pb.setList(list);
                int totalPage = totalCount % pageSize == 0 ? totalCount/pageSize : (totalCount/pageSize)+1;
                pb.setTotalPage(totalPage);
                return pb;
            }
        }
    
    • 前台代码实现:

      • route_list.html:

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

4、查询、详情与收藏

  • 查询功能传递参数:

    • 给搜索按钮加 id 属性。

    • header.html搜索按钮绑定单击事件。

      <script src="js/getParameter.js"></script>
      <script>
          $("#search_button").click(function () {
                  var rname = $("#search_input").val();
                  var cid = getParameter("cid");
                  location.href = "http://localhost/travel/route_list.html?cid="+cid+"&rname="+rname;
              })
      </script>
      
    • route_list.html中传递参数:

      $(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);
          }
      });
      
  • 查询功能的后台代码:

    • RouteServlet:

      • 获取 rname参数。
    • RouteService:

      • pageQuery方法增加一个参数 rname。
    • RouteDao:

      • findTotalCount和findByPage增加一个参数 rname。
      @Override
      public int findTotalCount(int cid, String rname) {
          String sql = "select count(*) from tab_route where 1=1 ";
          StringBuilder sb = new StringBuilder(sql);
          List params = new ArrayList();
          if(cid!=0){
              sb.append(" and cid= ?");
              params.add(cid);
          }
          if(rname!=null && rname.length()>0){
              sb.append(" and rname like ?");
              params.add("%"+rname+"%");
          }
          sql = sb.toString();
          System.out.println(sql);
          System.out.println(params);
          return template.queryForObject(sql, Integer.class, params.toArray());
      }
      
      @Override
      public List<Route> findByPage(int cid, int start, int pageSize, String rname) {
          String sql = "select * from tab_route where 1=1 ";
          StringBuilder sb = new StringBuilder(sql);
          List params = new ArrayList();
          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 ?, ?");
          params.add(start);
          params.add(pageSize);
          sql = sb.toString();
          return template.query(sql, new BeanPropertyRowMapper<Route>(Route.class), params.toArray());
      }
      
  • 查询功能的前台代码:

    • 处理 route_list.html中的load函数的参数问题。
    • 分页代码中拼接rname。
  • 线路详情:

    • 按照rid查询route_img表。
    • 按照sid查询route_seller表。
    • 其他查询route_list表。
  • 线路详情后台代码:

    • RouteServlet:

      public void findOne(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
          String rid = request.getParameter("rid");
          Route route = service.findOne(rid);
          writeValue(route, response);
      }
      
    • RouteDaoImpl:

      public Route findOne(int rid) {
          String sql = "select * from tab_route where rid = ?";
          return template.queryForObject(sql, new BeanPropertyRowMapper<Route>(Route.class), rid);
      }
      
    • RouteImgDaoImpl:

      public List<RouteImg> findImg(int rid) {
          String sql = "select * from tab_route_img where rid = ?";
          return template.query(sql, new BeanPropertyRowMapper<RouteImg>(RouteImg.class), rid);
      }
      
    • SellerDaoImpl:

      public Seller findSeller(int sid) {
          String sql = "select * from tab_seller where sid = ?";
          return template.queryForObject(sql, new BeanPropertyRowMapper<Seller>(Seller.class),sid);
      }
      
  • 线路详情前台代码:

    • Route_detail.html:

      $(function () {
      
      var rid = getParameter("rid");
      
      $.get("route/findOne",{rid:rid},function (route) {
      
      $("#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);
      
      var ddstr = '<a class="up_img up_img_disable"></a>';
          for (var i = 0; i < route.routeImgList.length; i++) {
              var astr ;
              if(i >= 4){
                  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{
                  astr = '<a title="" class="little_img" data-bigpic="'+route.routeImgList[i].bigPic+'">\n' +
                      '<img src="'+route.routeImgList[i].smallPic+'">\n' +
                      '</a>';
              }
              ddstr += astr;
          }
          ddstr+='<a class="down_img down_img_disable" style="margin-bottom: 0;"></a>';
      
          $("#dd").html(ddstr);
      
          goImg();
      });
      
  • 旅游线路收藏分析:

    • 页面加载完后,发送ajax请求,获取用户是否收藏的标记。传递rid。格局标记展示不同的按钮样式。
    • Servlet获取rid和当前用户对象,查询favorite表中有无此记录。数据标记写回客户端。
    • 点击按钮是,发送ajax请求判断用户是否登陆。如果没有登录则提示登录。
    • 登录后,添加收藏数据到数据库。
  • 线路收藏后台代码:

    • 显示按钮和收藏次数:

    • RouteServlet:

      public void isFavorite(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
          
          String rid = request.getParameter("rid");
          User user = (User) request.getSession().getAttribute("user");
          int uid;
          if(user == null){
              uid = 0;
          }else{
              uid = user.getUid();
          }
          boolean flag = favoriteService.isFavorite(rid, uid);
          writeValue(flag,response);
      }
      
    • favoriteService:

      public boolean isFavorite(String rid, int uid) {
      
          Favorite favorite = favoriteDao.findByRidAndUid(Integer.parseInt(rid), uid);
          return favorite != null;
      }
      
    • favoriteDao:

      public 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>(Favorite.class), rid, uid);
          } catch (DataAccessException e) {
              e.printStackTrace();
          }
          return favorite;
      }
      
      public int findCountByRid(int rid) {
          String sql = "SELECT COUNT(*) FROM tab_favorite WHERE rid = ?";
      
          return template.queryForObject(sql,Integer.class,rid);
      }
      
    • 点击按钮收藏:

    • RouteServlet:

      public void addFavorite(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
      
          String rid = request.getParameter("rid");
          User user = (User) request.getSession().getAttribute("user");
          int uid;/
          if(user == null){
              return ;
          }else{
              uid = user.getUid();
          }
          favoriteService.add(rid,uid);
      }
      
    • favoriteService:

      public void add(String rid, int uid) {
          favoriteDao.add(Integer.parseInt(rid),uid);
      }
      
    • favoriteDao:

      public void add(int rid, int uid) {
          String sql = "insert into tab_favorite values(?,?,?)";
      
          template.update(sql,rid,new Date(),uid);
      }
      
  • 线路收藏的前台代码:

    • 显示按钮和收藏次数:

      $(function () {
          var rid = getParameter("rid");
          $.get("route/isFavorite",{rid:rid},function (flag) {
              if(flag){
                  $("#favorite").addClass("already");
                  $("#favorite").attr("disabled","disabled");
      
                  $("#favorite").removeAttr("onclick");
              }else{
      
              }
          });
      });
      
    • 点击按钮添加:

      function addFavorite(){
          var rid = getParameter("rid");
          $.get("user/findOne",{},function (user) {
              if(user){
                  $.get("route/addFavorite",{rid:rid},function () {
                      location.reload();
                  });
              }else{
                  alert("您尚未登录,请登录");
                  location.href="http://localhost/travel/login.html";
              }
          })
      }
      

iwehdio的博客园:https://www.cnblogs.com/iwehdio/
posted @ 2020-06-13 15:21  iwehdio  阅读(173)  评论(0编辑  收藏  举报