黑马旅游网站

news/2024/5/13 16:23:06/文章来源:https://blog.csdn.net/qq_45502336/article/details/105326632

第一次写CSDN所以不太会!

   我接下来会记录这一段时间,完成黑马旅游网站的代码!我们使用的是maven框架,原因很简单,因为黑马提供了大部分的数据跟我们,里面有数据库表,数据库网页整体的容,我们通过写数据库代码,Servlet代码,还有前端ajax的交互代码,的学习,开始会比较难,持之以恒会发现你会不断的提升。
注:这里面的有些是我自己总结的可能有错,也希望多包涵!

   注意:接下来所有关于Servlet的类,我们都要把他继承BaseServlet 这个类,因为这个充当着,方法的方法工作!

准备工作

1. 项目导入

点击绿色+按钮

  选择travel项目的pom.xml文件,点击ok,完成项目导入。需要等待一小会,项目初始化完成。
在这里插入图片描述

2.启动项目

2.1 方式一:
在这里插入图片描述
2.2方式二:配置maven快捷启动在这里插入图片描述
在这里插入图片描述

4.技术选型

4.1Web层

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

4.2 Service层

  1. f)Javamail:java发送邮件工具
  2. g)Redis:nosql内存数据库
  3. h)Jedis:java的redis客户端

4.3Dao层

  1. i)Mysql:数据库
  2. j)Druid:数据库连接池
  3. k)JdbcTemplate:jdbc的工具

5.创建数据库

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

6注册功能

6.1页面效果
在这里插入图片描述

6.2功能分析
在这里插入图片描述

6.3.1前台代码实现
6.3.2表单校验
  提升用户体验,并减轻服务器压力。

//校验用户名
//单词字符,长度820
function checkUsername() {//1.获取用户名值var username = $("#username").val();//2.定义正则var reg_username = /^\w{8,20}$/;//3.判断,给出提示信息var flag = reg_username.test(username);if(flag){//用户名合法$("#username").css("border","");}else{//用户名非法,加一个红色边框$("#username").css("border","1px solid red");}return flag;}//校验密码function checkPassword() {//1.获取密码值var password = $("#password").val();//2.定义正则var reg_password = /^\w{8,20}$/;//3.判断,给出提示信息var flag = reg_password.test(password);if(flag){//密码合法$("#password").css("border","");}else{//密码非法,加一个红色边框$("#password").css("border","1px solid red");}return flag;}//校验邮箱
function checkEmail(){//1.获取邮箱var email = $("#email").val();//2.定义正则      itcast@163.comvar 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(){return checkUsername() && checkPassword() && checkEmail();//如果这个方法没有返回值,或者返回为true,则表单提交,如果返回为false,则表单不提交});//当某一个组件失去焦点是,调用对应的校验方法$("#username").blur(checkUsername);$("#password").blur(checkPassword);$("#email").blur(checkEmail);});

6.3.3异步(ajax)提交表单
  在此使用异步提交表单是为了获取服务器响应的数据。因为我们前台使用的是html作为视图层,不能够直接从servlet相关的域对象获取值,只能通过ajax获取响应数据
在这里插入图片描述

6.3.4后台代码实现:为什么要优化Servlet
  减少Servlet的数量,现在是一个功能一个Servlet,将其优化为一个模块一个Servlet,相当于在数据库中一张表对应一个Servlet,在Servlet中提供不同的方法,完成用户的请求。
在这里插入图片描述
  因为我使用的是IDEA开发工具!控制台会出现乱码解决方法:
Idea控制台中文乱码解决:-Dfile.encoding=gb2312
在这里插入图片描述

7.BaseServlet编写:

public class BaseServlet extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//System.out.println("baseServlet的service方法被执行了...");//完成方法分发//1.获取请求路径String uri = req.getRequestURI(); //   /travel/user/addSystem.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@4903d97etry {//获取方法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();}}
}

在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);
}

**

7.1 过滤器:

  作用解决全站乱码问题,处理所有的请求!

在这里插入图片描述
  CharchaterFilter代码:


/*** 解决全站乱码问题,处理所有的请求*/
@WebFilter("/*")
public class CharchaterFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void doFilter(ServletRequest req, ServletResponse rep, FilterChain filterChain) throws IOException, ServletException {//将父接口转为子接口HttpServletRequest request = (HttpServletRequest) req;HttpServletResponse response = (HttpServletResponse) rep;//获取请求方法String method = request.getMethod();//解决post请求中文数据乱码问题if(method.equalsIgnoreCase("post")){request.setCharacterEncoding("utf-8");}//处理响应乱码response.setContentType("text/html;charset=utf-8");filterChain.doFilter(request,response);}@Overridepublic void destroy() {}
}

8.验证码类:用于注册和登入
  效果:
在这里插入图片描述
  前端代码:

<input name="check" type="text" placeholder="请输入验证码" autocomplete="off"><span><img src="checkCode" alt="" onclick="changeCheckCode(this)"></span><script type="text/javascript">//图片点击事件function changeCheckCode(img) {img.src="checkCode?"+new Date().getTime();}</script>

在这里插入图片描述
后端代码:
  CheckCodeServlet代码:


/*** 验证码*/
@WebServlet("/checkCode")
public class CheckCodeServlet extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {//服务器通知浏览器不要缓存response.setHeader("pragma","no-cache");response.setHeader("cache-control","no-cache");response.setHeader("expires","0");//在内存中创建一个长80,宽30的图片,默认黑色背景//参数一:长//参数二:宽//参数三:颜色int width = 80;int height = 30;BufferedImage image = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);//获取画笔Graphics g = image.getGraphics();//设置画笔颜色为灰色g.setColor(Color.GRAY);//填充图片g.fillRect(0,0, width,height);//产生4个随机验证码,12EyString checkCode = getCheckCode();//将验证码放入HttpSession中request.getSession().setAttribute("CHECKCODE_SERVER",checkCode);//设置画笔颜色为黄色g.setColor(Color.YELLOW);//设置字体的小大g.setFont(new Font("黑体",Font.BOLD,24));//向图片上写入验证码g.drawString(checkCode,15,25);//将内存中的图片输出到浏览器//参数一:图片对象//参数二:图片的格式,如PNG,JPG,GIF//参数三:图片输出到哪里去ImageIO.write(image,"PNG",response.getOutputStream());}/*** 产生4位随机字符串 */private String getCheckCode() {String base = "0123456789ABCDEFGabcdefg";int size = base.length();Random r = new Random();StringBuffer sb = new StringBuffer();for(int i=1;i<=4;i++){//产生0到size-1的随机值int index = r.nextInt(size);//在base字符串中获取下标为index的字符char c = base.charAt(index);//将c放入到StringBuffer中去sb.append(c);}return sb.toString();}public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doGet(request,response);}
}

User用户的方法:

8.1.1注册和邮箱激活的方法

黑马的分析都在后面:我只不过把代码注册和邮箱验证的都写在了一起。

  1. UserDaoImpl数据库的方法集合:用于连接本地数据库进行,查询,添加,删除等操作!
  2. UserServiceImpl的代码方法:用于服务器UserServlet的使用,别人在这里调用数据库的对象,进行判断等
  3. UserServlet服务代码方法:用于接收客服端服务我们的服务器,接收请求和响应的。
    注意接下来所有关于Servlet的类,我们都要把他继承BaseServlet 这个类,因为这个充当着,方法的方法工作!

  UserDaoImpl 代码:

 public class UserDaoImpl implements UserDao {//1.首先创建Jdbc对象private JdbcTemplate template=new JdbcTemplate(JDBCUtils.getDataSource());@Overridepublic User findByUserNmae(String username) {//为什么要try原因是,数据库查询到数据会返回,如果查询不到数据,只会报错,返回的不是null所以需要定义.User user = null;try {//1.定义sqlString sql="select * from tab_user where username= ?";//2.执行sqluser = template.queryForObject(sql, new BeanPropertyRowMapper<User>(User.class), username);} catch (DataAccessException e) {System.out.println("注册的用户已经存在!");}return user;}/*** 用户保存方法* @param user*/@Overridepublic void save(User user) {//1.定义sqlString sql="insert into tab_user(username,password,name,birthday,sex,telephone,email,status,code) values(?,?,?,?,?,?,?,?,?)";//2.执行sqltemplate.update(sql,user.getUsername(),user.getPassword(),user.getName(),user.getBirthday(),user.getSex(),user.getTelephone(),user.getEmail(),user.getStatus(),user.getCode());}/*** 激活码查询* @param code* @return*/@Overridepublic User findByCode(String code) {User user = null;try {//1.定义sqlString sql="select * from tab_user where code=?";//2.执行sqluser = template.queryForObject(sql, new BeanPropertyRowMapper<User>(User.class), code);} catch (DataAccessException e) {e.printStackTrace();}return user;}/*** 修改激活码状态* @param user*/@Overridepublic void updateStatus(User user) {//为什么使用uid,因为user前面通过findByCode查询到了用户的所有信息所有通过uid可以修改//1.定义sqlString sql="update tab_user set status = 'Y' where uid=? ";//2.执行sqltemplate.update(sql,user.getUid());}
}

  UserServiceImpl 代码:

public class UserServiceImpl implements UserService {//业务对象private UserDao userDao=new UserDaoImpl();/*** 注册方法* @param user* @return*/@Overridepublic boolean regist(User user) {//通过查询数据库// 判断用户名称是否存在User u=userDao.findByUserNmae(user.getUsername());//如果查询到证明用户已经存在if (u!=null){//用户存在return false;}else{//用户不存在,可以保存//通过邮箱激活//原理发送唯一的code码用户点击,通过请求我们服务器,然后把初始的N改为Y//设置code码user.setCode(UuidUtil.getUuid());System.out.println("激活码:"+user.getCode());//设置激活状态user.setStatus("N");userDao.save(user);//然后调用工具类的发邮件方法String content="<a href='http://localhost/travel/user/active?code="+user.getCode()+"'>点击激活!</a>";//调用发送邮箱方法;  在类里面要填写 你的邮箱和 授权码MailUtils.sendMail(user.getEmail(),content,"邮箱注册!");return true;}}/*** 激活功能* @param code* @return*/@Overridepublic boolean active(String code) {//1.查询数据库,是否有code码信息User user=userDao.findByCode(code);if (user!=null){//有code码。那么调用数据库把sautus改为YuserDao.updateStatus(user);return true;}return false;}

  UserServlet代码:

@WebServlet("/user/*")
public class UserServlet extends BaseServlet {//注意:创建方法的时候用public 全局//业务类private UserService service=new UserServiceImpl();/*** 用户注册方法* @param request* @param response* @throws Exception*/public void regist(HttpServletRequest request, HttpServletResponse response)  throws Exception {//验证码是否正确String check = request.getParameter("check");//获取session对象HttpSession session = request.getSession();//这里强制转换为string,为了可以使用大小写不区分方法(这里没有执行String的大小写,而是从session对象中获取CHECKCODE_SERVER字段的值,而这个字段是从CheckCodeServlet类中通过session存储的)String checkcode_server = (String) session.getAttribute("CHECKCODE_SERVER");//为了防止重复使用验证码session.removeAttribute("CHECKCODE_SERVER");//判断客服端返回check是否相同if (checkcode_server==null || !checkcode_server.equalsIgnoreCase(check)){ //equalsIgnoreCase才是不区分大小写比较//验证码不正确ResultInfo info=new ResultInfo();info.setFlag(false);info.setErrorMsg("验证码错误!");writeValue(info,response);return;}//1.获取用户返回的数据Map<String, String[]> map = request.getParameterMap();//2.创建封装对象User user=new User();BeanUtils.populate(user,map);//3.调用serivceboolean flag=service.regist(user);ResultInfo info=new ResultInfo();//用于传递返回的数据对象(里面有Flag,ErrorMsg错误提示信息)//4.响应判断if (flag){//注册成功info.setFlag(true);}else{//注册失败info.setFlag(false);info.setErrorMsg("用户名已经存在!");}//5.返回数据到客服端ObjectMapper mapper=new ObjectMapper();String json = mapper.writeValueAsString(info);response.setContentType("applcation/json;charset=utf-8");response.getWriter().write(json);}/*** 用户激活功能* @param request* @param response* @throws ServletException* @throws IOException* @throws InvocationTargetException* @throws IllegalAccessException*/public void active(HttpServletRequest request, HttpServletResponse response) throws Exception{//1.获取code码String code = request.getParameter("code");//处理输入空code重复请求if (code==null){return;}//2.调用serivce完成激活boolean flag=service.active(code);//3.判断标记String msg=null;if (flag){//激活成功msg="激活成功,请<a href='/travel/login.html'>登入</a>!";}else{msg="激活失败,联系管理员!";}//4.响应数据response.setContentType("text/html;charset=utf-8");response.getWriter().write(msg);}

7.2邮件激活
  为什么要进行邮件激活?为了保证用户填写的邮箱是正确的。将来可以推广一些宣传信息,到用户邮箱中。
7.2.1 发送邮件
 1.申请邮箱
 2.开启授权码
 3.在MailUtils中设置自己的邮箱账号和密码(授权码)
在这里插入图片描述
  邮件工具类:MailUtils,调用其中sendMail方法可以完成邮件发送
7.3.1用户点击邮件激活
  经过分析,发现,用户激活其实就是修改用户表中的status为‘Y’
在这里插入图片描述
 发送邮件代码:
在这里插入图片描述
注意: 因为我们一开始就使用了BaseServlet ,所以可以分发查询不同的方法,则在浏览器访问时我们都是用ajax的请求方式。如:user/findOne等方式。
页面路径改写
register.html
在这里插入图片描述
login.html
在这里插入图片描述
UserServiceImpl发送邮件
在这里插入图片描述
header.html
在这里插入图片描述
**从 7.2邮件激活到这里,这些都是黑马的截图和解释思路,搞得我头大,又想自己写,都是我不会把思路什么的总结,我只会把解释写代码里面,所以有些图片和解释是黑马的,我自己解释的有点不清楚不知道你们会不会听的懂,可能只有我能看得懂了,抱歉!加油加油!
在这里插入图片描述

9.登入
 9.1分析:
在这里插入图片描述
9.2代码实现
 9.2.1前台代码

  login.html
在这里插入图片描述
9.2.2后台代码
  UserServlet代码:

/*** 登入方法* @param request* @param response* @throws Exception*/public void login(HttpServletRequest request, HttpServletResponse response) throws Exception {//验证码是否正确String check = request.getParameter("check");//获取session对象HttpSession session = request.getSession();//这里强制转换为string,为了可以使用大小写不区分方法String checkcode_server = (String) session.getAttribute("CHECKCODE_SERVER");//为了防止重复使用验证码session.removeAttribute("CHECKCODE_SERVER");//判断客服端返回check是否相同if (checkcode_server==null || !checkcode_server.equalsIgnoreCase(check)){//验证码不正确ResultInfo info=new ResultInfo();info.setFlag(false);info.setErrorMsg("验证码错误!");writeValue(info,response);return;}//1.获取请求信息Map<String, String[]> map = request.getParameterMap();//2.创建封装对象User user=new User();BeanUtils.populate(user,map);//创建info对象传输信息,ResultInfo实体类ResultInfo info=new ResultInfo();//3.调用serivce//如果u有值那么,查询出来的是用户的所有信息。User u=service.login(user);//4.判断返回结果if (u==null){//登入失败info.setFlag(false);info.setErrorMsg("账号或密码错误!");}if (u!=null && !u.getStatus().equals("Y")){//登入失败,账号密码正确但是没有激活info.setFlag(false);info.setErrorMsg("用户还未激活,请登入邮箱激活!");}if (u!=null && u.getStatus().equals("Y")){//登入成功info.setFlag(true);//把用户信息存到sessionrequest.getSession().setAttribute("user",u);}//5.响应数据writeValue(info,response);}

  UserServiceImpl代码:

/*** 登入方法* @param user* @return*/@Overridepublic User login(User user) {//1.调用dao查询数据库//如果u有值那么,查询出来的是用户的所有信息。User u= userDao.findByUserNameAndPassword(user.getUsername(),user.getPassword());return u;}

  UserDaoImpl代码:

  /*** 查询账号和密码* @param username* @param password* @return*/@Overridepublic User findByUserNameAndPassword(String username, String password) {User user=null;try {//1.定义sqlString sql="select * from tab_user where username=? and password=? ";//2.执行sqluser = template.queryForObject(sql, new BeanPropertyRowMapper<User>(User.class), username, password);} catch (DataAccessException e) {System.out.println("账号密码错误!.....");}return user;}

9.2.2 index页面中用户姓名的提示信息功能
在这里插入图片描述
header.html代码
在这里插入图片描述
  UserServlet代码:

//从session中获取登录用户
Object user = request.getSession().getAttribute("user");
//将user写回客户端ObjectMapper mapper = new ObjectMapper();
response.setContentType("application/json;charset=utf-8");
mapper.writeValue(response.getOutputStream(),user);

10 .退出
  什么叫做登录了?session中有user对象。
实现步骤:
  1.访问servlet,将session销毁
  2.跳转到登录页面
代码实现:
Header.html

  <!-- 登录状态  --><div class="login"><span id="span_username"></span><a href="myfavorite.html" class="collection">我的收藏</a><a href="javascript:location.href='user/Exit';">退出</a></div>

在这里插入图片描述
  UserServlet代码:

 /*** 用户的退出* @param request* @param response* @throws Exception*/public void Exit(HttpServletRequest request, HttpServletResponse response) throws Exception {//1.退出方法就是让session对象失效request.getSession().invalidate();//2.跳转登入界面response.sendRedirect(request.getContextPath()+"/login.html");}

11.分类数据展示

效果:
在这里插入图片描述
11.2 分析:
在这里插入图片描述
11.3代码实现:
  CategoryServlet代码:


@WebServlet("/category/*")
public class CategoryServlet extends BaseServlet {//记住要继承BaseServlet才可以实现分发方法//方法名称一定要public,否则找不到!//创建业务类private CategorySerivce serivce=new CategorySerivceImpl();/*** 查询所有* @param request* @param response* @throws ServletException* @throws IOException*/public void findAll(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//1.调用service查询所有List<Category> cs=serivce.findAll();//2.序列化返回客服端ObjectMapper mapper=new ObjectMapper();String json = mapper.writeValueAsString(cs);System.out.println("查询的结果:"+json);//定义返回格式response.setContentType("application/json;charset=utf-8");response.getWriter().write(json);}}

  CategoryService代码:

//查询路线类别
public class CategoryServiceImpl implements CategoryService {private CategoryDao categoryDao = new CategoryDaoImpl();@Overridepublic List<Category> findAll() {return categoryDao.findAll();}
}

  CategoryDao代码: 这是重新的一个类哦!

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

11.3.2前台代码
hader.html加载后,发送ajax请求,请求category/findAll

//查询分类数据$.get("category/findAll",{},function (data) {//[{cid:1,cname:国内游},{},{}]var lis = '<li class="nav-active"><a href="index.html">首页</a></li>';//遍历数组,拼接字符串(<li>)for (var i = 0; i < data.length; i++) {var li = '<li><a href="route_list.html">'+data[i].cname+'</a></li>';lis += li;}//拼接收藏排行榜的li,<li><a href="favoriterank.html">收藏排行榜</a></li>lis+= '<li><a href="favoriterank.html">收藏排行榜</a></li>';//将lis字符串,设置到ul的html内容中$("#category").html(lis);});

页面传递cid
header.html传递cid

var li = '<li><a href="route_list.html?cid='+data[i].cid+'">'+data[i].cname+'</a></li>';

获取cid

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

11.4对分类数据进行缓存优化
   分析发现,分类的数据在每一次页面加载后都会重新请求数据库来加载,对数据库的压力比较大,而且分类的数据不会经常产生变化,所有可以使用redis来缓存这个数据。
分析:在这里插入图片描述
11.5优化代码实现
修改  CategoryService代码: redis是一款非关系性数据库,需要安装redis才可以使用!如果没有redis请使用上面不优化的代码,实验的时候最好,不要用redis,因为本地不启动会报错,连接不上redis超时的错误!
 期望数据中存储的顺序就是将来展示的顺序,使用redis的sortedset
注意: 使用的是zrangeWithScores这个方法,而不是zrangeByScoreWithScores这个方法


/*** 查询导航栏路线类别*/
public class CategorySerivceImpl implements CategorySerivce {private CategoryDao categoryDao=new CategoryDaoImpl();@Overridepublic List<Category> findAll() {//1从redis中获取数据//1.1创建redis对象Jedis jedis=JedisUtil.getJedis();//1.2可使用sortedset排序查询// 用这个方法zrangeWithScoresSet<Tuple> categorys = jedis.zrangeWithScores("category", 0, -1);List<Category> cs=null;//2.判断是否有值if (categorys==null || categorys.size()==0){//3.如果为空,需要从数据库查询,在将数据存入redis//3.1 从数据库查询System.out.println("从数据库查询....");cs = categoryDao.findAll();for (int i=0;i<cs.size();i++){//3.2存入redis中jedis.zadd("category",cs.get(i).getCid(),cs.get(i).getCname());}}else{System.out.println("redis中查询数据....");//4.如果不为空,将set的数据存入listcs=new ArrayList<>();//使用for增强打印for (Tuple tuple:categorys) {//这一步操作就是为了把查询出来的set数据,传递到list中Category category=new Category();category.setCid((int) tuple.getScore());//获取cidcategory.setCname(tuple.getElement());//获取路线名称cs.add(category);}}//5返回数据return cs;}
}

路线方法:

作用:查询路线信息等
 2020-4-6
12.1根据id查询不同类别的旅游线路数据
12.2.1 分析
在这里插入图片描述
12.2.2编码
前端代码

注意:

1. 里面的rname需要url解码:rname = window.decodeURIComponent(rname);
2. 按钮点击中,调用load方法 传递rname时,要使用转义字符!,不然点击没有效果
   如:οnclick="javascipt:load(’+cid+’,’+beforeNum+’,’’+rname+’’)"

    <script src="js/jquery-3.3.1.js"></script><script src="js/getParameter.js"></script><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);/*<li><a href="">首页</a></li><li class="threeword"><a href="#">上一页</a></li><li class="curPage"><a href="#">1</a></li><li><a href="#">2</a></li><li><a href="#">3</a></li><li><a href="#">4</a></li><li><a href="#">5</a></li><li><a href="#">6</a></li><li><a href="#">7</a></li><li><a href="#">8</a></li><li><a href="#">9</a></li><li><a href="#">10</a></li><li class="threeword"><a href="javascript:;">下一页</a></li><li class="threeword"><a href="javascript:;">末页</a></li>*/var lis = "";var fristPage = '<li οnclick="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  οnclick="javascipt:load('+cid+','+beforeNum+',\''+rname+'\')" class="threeword"><a href="javascript:void(0)">上一页</a></li>';lis += fristPage;lis += beforePage;//1.2 展示分页页码/*1.一共展示10个页码,能够达到前54的效果2.如果前边不够5个,后边补齐103.如果后边不足4个,前边补齐10*/// 定义开始位置begin,结束位置 endvar begin; // 开始位置var end ; //  结束位置//1.要显示10个页码if(pb.totalPage < 10){//总页码不够10begin = 1;end = pb.totalPage;}else{//总页码超过10begin = pb.currentPage - 5 ;end = pb.currentPage + 4 ;//2.如果前边不够5个,后边补齐10if(begin < 1){begin = 1;end = begin + 9;}//3.如果后边不足4个,前边补齐10if(end > pb.totalPage){end = pb.totalPage;begin = end - 9 ;}}for (var i = begin; i <= end ; i++) {var li;//判断当前页码是否等于iif(pb.currentPage == i){li = '<li class="curPage" οnclick="javascipt:load('+cid+','+i+',\''+rname+'\')"><a href="javascript:void(0)">'+i+'</a></li>';}else{//创建页码的lili = '<li οnclick="javascipt:load('+cid+','+i+',\''+rname+'\')"><a href="javascript:void(0)">'+i+'</a></li>';}//拼接字符串lis += li;}/* for (var i = 1; i <= pb.totalPage ; i++) {var li;//判断当前页码是否等于iif(pb.currentPage == i){li = '<li class="curPage" οnclick="javascipt:load('+cid+','+i+')"><a href="javascript:void(0)">'+i+'</a></li>';}else{//创建页码的lili = '<li οnclick="javascipt:load('+cid+','+i+')"><a href="javascript:void(0)">'+i+'</a></li>';}//拼接字符串lis += li;}*///设置最后一页的按钮var last=pb.totalPage;var lastPage = '<li class="threeword" οnclick="javascript:load('+cid+','+last+',\''+rname+'\')"><a href="javascript:;">末页</a></li>';//设置下一页按钮var nest=pb.currentPage+1;if (nest>last){nest=last;}var nextPage = '<li class="threeword" οnclick="javascript:load('+cid+','+nest+',\''+rname+'\')"><a href="javascript:;">下一页</a></li>';lis += nextPage;lis += lastPage;//将lis内容设置到 ul$("#pageNum").html(lis);/*<li><div class="img"><img src="images/04-search_03.jpg" alt=""></div><div class="text1"><p>【减100 含除夕/春节出发】广州增城三英温泉度假酒店/自由行套票</p><br/><p>1-2月出发,网付立享¥1099/2人起!爆款位置有限,抢完即止!</p></div><div class="price"><p class="price_num"><span>&yen;</span><span>299</span><span></span></p><p><a href="route_detail.html">查看详情</a></p></div></li>*///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>

12.3.1.服务器端代码编写

12.3.2在domin中创建一个类为PagBend类 :用于封装对象
在这里插入图片描述
a)创建PageBean对象

public class PageBean<T> {private int totalCount;//总记录数private int totalPage;//总页数private int currentPage;//当前页码private int pageSize;//每页显示的条数private List<T> list;//每页显示的数据集合public int getTotalCount() {return totalCount;}public void setTotalCount(int totalCount) {this.totalCount = totalCount;}public int getTotalPage() {return totalPage;}public void setTotalPage(int totalPage) {this.totalPage = totalPage;}public int getCurrentPage() {return currentPage;}public void setCurrentPage(int currentPage) {this.currentPage = currentPage;}public int getPageSize() {return pageSize;}public void setPageSize(int pageSize) {this.pageSize = pageSize;}public List<T> getList() {return list;}public void setList(List<T> list) {this.list = list;}
}

12.4旅游线路名称查询
   可以通过搜索框查询路线
在这里插入图片描述
12.4.1查询参数的传递
在header.html中

 //给搜索按钮绑定单击事件,获取搜索输入框的内容$("#search-button").click(function () {//线路名称var rname = $("#search_input").val();var cid = getParameter("cid");// 跳转路径 http://localhost/travel/route_list.html?cid=5,拼接上rname=xxxlocation.href="http://localhost/travel/route_list.html?cid="+cid+"&rname="+rname;});

在route_list.html

v //获取cid的参数值var cid = getParameter("cid");//获取rname的参数值var rname = getParameter("rname");//判断rname如果不为null或者""if(rname){//url解码rname = window.decodeURIComponent(rname);}

其中getParameter这个前端方法哪里来的呢,我们写了一个js到时候,引入就好。
getParameter.js

//根据传递过来的参数name获取对应的值
function getParameter(name) {var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)","i");var r = location.search.substr(1).match(reg);if (r!=null) return (r[2]); return null;
}

12.5 服务器后端代码:
  RouteServlet 代码:


@WebServlet("/route/*")
public class RouteServlet extends BaseServlet {//业务类private RouteService routeService=new RouteServiceImpl();/*** 查询当前页所有数据* @param request* @param response* @throws ServletException* @throws IOException*/public void pageQuery(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//1.获取数据String cidStr = request.getParameter("cid");String currentPageStr = request.getParameter("currentPage");String pageSizeStr = request.getParameter("pageSize");//接受rname 线路名称//注意:rname要格式定义String rname = request.getParameter("rname");rname=new String(rname.getBytes("iso-8859-1"),"utf-8");//2.处理参数int cid=0;//类别idif (cidStr!=null && cidStr.length()>0 && !"null".equals(cidStr)){cid=Integer.parseInt(cidStr);}int currentPage=0;//第几页if (currentPageStr!=null && currentPageStr.length()>0 && !"null".equals(currentPageStr)){currentPage=Integer.parseInt(currentPageStr);}else{currentPage=1;//不传值为第一页}int pageSize=0;//当前页显示条数if (pageSizeStr!=null && pageSizeStr.length()>0){pageSize=Integer.parseInt(pageSizeStr);}else{pageSize=5;//不传值为5条数据}//3. 调用service查询PageBean对象PageBean<Route> route=routeService.PageQuery(cid,currentPage,pageSize,rname);//4.返回数据writeValue(route,response);}}

  RouteServiceImpl 代码:

  1. 这个方法主要是查询数据库把当前页的所有信息返回!
  2. 其中currentPage和pageSize是传递的值是已知的!
  3. 设置查询出的所有数据信息,设置总条数信息,这两个是需要数据库查询返回!
  4. 设置一共有多少页,这里采用了三元运算,当不够取模则加1页;

public class RouteServiceImpl implements RouteService {//业务类private RouteDao routeDao=new RouteDaoImpl();/*** 查询一页的信息* @param cid* @param currentPage* @param pageSize* @param rname* @return*/@Overridepublic PageBean<Route> PageQuery(int cid, int currentPage, int pageSize, String rname) {//1.创建封装对象PageBean<Route> pb=new PageBean<Route>();//2.设置传输信息//2.1设置条数pb.setPageSize(pageSize);//2.2设置第几页pb.setCurrentPage(currentPage);//2.3设置总条数信息int count=routeDao.findTotalCount(cid,rname);pb.setTotalCount(count);//3.设置查询出的所有数据信息int start=(currentPage-1)*pageSize;List<Route> list=routeDao.findByPage(cid,start,pageSize,rname);pb.setList(list);//4.设置一共有多少页int pagecount =count%pageSize==0 ? count/pageSize:(count/pageSize)+1;pb.setTotalPage(pagecount);return pb;}
}

  RouteDaoImpl 代码:

  1. 初学者需要注意的是:定义好sql要记得放到StringBuilder方法里面,最后拼接完成也要通过对象的toString方法赋值给sql
  2. 这里采用了拼接式查询,当传递了cid路线id和搜索框输入的查询做一个字符串的拼接。
  3. 其中List params=new ArrayList();的对象用于存入参数,最后通过执行sql把params.toArray()传递,相当于?的条件们!.
  4. 查询当前页的信息我们采用了传递limit方式查询数据库的条数,记得最后要把开始(start)和结束(pageSize)存入到params.add方法中去。
  5. 搜索框里面的值,在数据库里面我们用的是模糊查询所以配上了%西安%

public class RouteDaoImpl implements RouteDao {private JdbcTemplate template=new JdbcTemplate(JDBCUtils.getDataSource());/*** 查询总条数* @return*/@Overridepublic int findTotalCount(int cid,String rname) {//1.定义SQL模板String sql="select count(*) from tab_route where 1=1 ";//2.创建字符串拼接对象StringBuilder sb=new StringBuilder(sql);//2.1创建 ?的条件们List params=new ArrayList();//3.处理参数if (cid!=0){//拼接字符串sb.append(" and cid =? ");params.add(cid);//? 的条件}if (rname!=null && rname.length()>0&&!"null".equals(rname)){//拼接字符串sb.append(" and  rname  like ? ");params.add("%"+rname+"%");//因为是模糊查询}//4.把拼接好的字符串赋值给sqlsql=sb.toString();//5.执行sqlInteger count = template.queryForObject(sql, Integer.class, params.toArray());return count;}/*** 查询一页所有信息* @param cid* @param start* @param pageSize* @param rname* @return*/@Overridepublic List<Route> findByPage(int cid, int start, int pageSize, String rname) {//1.定义SQL模板String sql="select * from tab_route where 1=1 ";//2.创建字符串拼接对象StringBuilder sb=new StringBuilder(sql);List params=new ArrayList();//?的条件们//3.处理参数if (cid!=0){//拼接字符串sb.append(" and cid= ? ");params.add(cid);}if (rname!=null && rname.length()>0 && !"null".equals(rname)){//拼接字符串sb.append(" and rname like ? ");params.add("%"+rname+"%");}//因为查询的是有条数的所以要跟 limitsb.append(" limit ? , ?  ");//4.把拼接好的字符串赋值给sqlsql=sb.toString();params.add(start);params.add(pageSize);//5.执行sqlList<Route> query = template.query(sql, new BeanPropertyRowMapper<Route>(Route.class), params.toArray());return query;}
}

13旅游线路的详情展示

13.1分析
在这里插入图片描述
在这里插入图片描述

13.2代码实现

13.2.1后台代码
  RouteServlet代码:
    添加一个findOne方法用于查询单个路线详情:

 /*** 用于查询单个路线详情* @param request* @param response* @throws ServletException* @throws IOException*/public void findOne(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//1.获取数据ridString rid = request.getParameter("rid");//2.调用serivce查询Route route=routeService.findOne(rid);//3.响应数据//通过方法返回writeValue(route,response);}

  RouteServiceImpl代码:

  需要创建2个对象
在这里插入图片描述

  /*** 查询单个路线的详细信息* @param rid* @return*/@Overridepublic Route findOne(String rid) {//1.通过rid 查询路线的详细信息Route route = routeDao.findOne(rid);//2.通过查询的所有信息route里面有商家信息sid//根据route的sid(商家id)查询商家对象Seller seller=sellerDao.findSeller(route.getSid());route.setSeller(seller);//3.通过route 可以知道数据库存放图片是通过rid查询List<RouteImg> routeImgList=routeImgDao.findImg(route.getRid());route.setRouteImgList(routeImgList);//返回对象return route;}

  SellerDaoImpl 代码:
    在Dao查询数据里面添加SellerDaoImpl 类:用于数据库查询商家!

public class SellerDaoImpl implements SellerDao {//创建Jdbc对象private JdbcTemplate template=new JdbcTemplate(JDBCUtils.getDataSource());/*** 查询商家方法* @param sid* @return*/@Overridepublic Seller findSeller(int sid) {//1.定义sqlString sql="select * from tab_seller where sid=? ";//2执行sqlSeller seller = template.queryForObject(sql, new BeanPropertyRowMapper<Seller>(Seller.class), sid);return seller;}
}

  RouteImgDaoImpl代码:
    在Dao查询数据里面添加RouteImgDaoImpl 类:用于数据库路线详情图片!


public class RouteImgDaoImpl implements RouteImgDao {//首先创建Jdbc对象private JdbcTemplate template=new JdbcTemplate(JDBCUtils.getDataSource());/*** 查询单个路线所有详情图片* @param rid* @return*/@Overridepublic List<RouteImg> findImg(int rid) {//1.定义sqlString sql="select * from tab_route_img where rid= ? ";//2执行sqlList<RouteImg> query = template.query(sql, new BeanPropertyRowMapper<RouteImg>(RouteImg.class), rid);return query;}
}

13.2.2 前台代码
route_detail.html

 $(function () {/*<dd><a class="up_img up_img_disable"></a><a title="" class="little_img" data-bigpic="http://www.jinmalvyou.com/Public/uploads/goods_img/img_size4/201703/m40920d0669855e745d97f9ad1df966ebb.jpg"><img src="http://www.jinmalvyou.com/Public/uploads/goods_img/img_size2/201703/m20920d0669855e745d97f9ad1df966ebb.jpg"></a><a title="" class="little_img cur_img" data-bigpic="http://www.jinmalvyou.com/Public/uploads/goods_img/img_size4/201703/m49788843d72171643297ccc033d9288ee.jpg"><img src="http://www.jinmalvyou.com/Public/uploads/goods_img/img_size2/201703/m29788843d72171643297ccc033d9288ee.jpg"></a><a title="" class="little_img" data-bigpic="http://www.jinmalvyou.com/Public/uploads/goods_img/img_size4/201703/m4531a8dbceefa2c44e6d0e35627cd2689.jpg"><img src="http://www.jinmalvyou.com/Public/uploads/goods_img/img_size2/201703/m2531a8dbceefa2c44e6d0e35627cd2689.jpg"></a><a title="" class="little_img" data-bigpic="http://www.jinmalvyou.com/Public/uploads/goods_img/img_size4/201703/m46d8cb900e9f6c0a762aca19eae40c00c.jpg"><img src="http://www.jinmalvyou.com/Public/uploads/goods_img/img_size2/201703/m26d8cb900e9f6c0a762aca19eae40c00c.jpg"></a><a title="" class="little_img" data-bigpic="http://www.jinmalvyou.com/Public/uploads/goods_img/img_size4/201703/m45ea00f6eba562a767b5095bbf8cffe07.jpg" style="display:none;"><img src="http://www.jinmalvyou.com/Public/uploads/goods_img/img_size2/201703/m25ea00f6eba562a767b5095bbf8cffe07.jpg"></a><a title="" class="little_img" data-bigpic="http://www.jinmalvyou.com/Public/uploads/goods_img/img_size4/201703/m4265ec488cd1bc7ce749bc8c9b34b87bc.jpg" style="display:none;"><img src="http://www.jinmalvyou.com/Public/uploads/goods_img/img_size2/201703/m2265ec488cd1bc7ce749bc8c9b34b87bc.jpg"></a><a title="" class="little_img" data-bigpic="http://www.jinmalvyou.com/Public/uploads/goods_img/img_size4/201703/m4e7e964909d7dd1a9f6e5494d4dc0c847.jpg" style="display:none;"><img src="http://www.jinmalvyou.com/Public/uploads/goods_img/img_size2/201703/m2e7e964909d7dd1a9f6e5494d4dc0c847.jpg"></a><a title="" class="little_img" data-bigpic="http://www.jinmalvyou.com/Public/uploads/goods_img/img_size4/201703/m467db00e1b76718fab0fe8b96e10f4d35.jpg" style="display:none;"><img src="http://www.jinmalvyou.com/Public/uploads/goods_img/img_size2/201703/m267db00e1b76718fab0fe8b96e10f4d35.jpg"></a><a title="" class="little_img" data-bigpic="http://www.jinmalvyou.com/Public/uploads/goods_img/img_size4/201703/m487bbbc6e43eba6aa6a36cc1a182f7a20.jpg" style="display:none;"><img src="http://www.jinmalvyou.com/Public/uploads/goods_img/img_size2/201703/m287bbbc6e43eba6aa6a36cc1a182f7a20.jpg"></a><a class="down_img down_img_disable" style="margin-bottom: 0;"></a></dd>*///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);//设置收藏次数$("#favoriteCount").html("已收藏"+route.count+"次");//图片展示var ddstr = '<a class="up_img up_img_disable"></a>';//遍历routeImgListfor (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();});});

**

14 .旅游线路收藏功能

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

    当页面加载完成后,发送ajax请求,获取用户是否收藏的标记
根据标记,展示不同的按钮样式
在这里插入图片描述
在这里插入图片描述
14.2编写代码
14.2.1 后台代码
  RouteServlet代码:
其中favoriteService对象是通过new出来的.
在这里插入图片描述

 /*** 查询用户是否收藏* @param request* @param response* @throws ServletException* @throws IOException*/public void isFavorite(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//1.获取数据ridString rid = request.getParameter("rid");//2. 获取当前登录的用户 user//强制转换成UserUser user = (User) request.getSession().getAttribute("user");//2.1判断user是否为nullint uid;if(user==null){//用户没有登入return;}else{//用户登入了uid=user.getUid();}//3. 调用FavoriteService查询是否收藏boolean flag=favoriteService.isFavorite(rid,uid);//4.返回数据writeValue(flag,response);}

  创建FavoriteServiceImpl 代码: 调用数据库对象查询和判断

public class FavoriteServiceImpl  implements FavoriteService {//业务对象private FavoriteDao favoriteDao=new FavoriteDaoImpl();/*** 查询是否收藏* @param rid* @param uid* @return*/@Overridepublic boolean isFavorite(String rid, int uid) {//1.调用Dao查询数据Favorite favorite=favoriteDao.findByRidAndUid(Integer.parseInt(rid),uid);// 2.判断查询结果是否为null/* if (favorite!=null){//数据不为空return true;}else {//数据对于null返回flasereturn false;}*/return favorite!=null ;//如果对象有值,则为true,反之,则为false,和上面if等价}
}

  创建FavoriteDaoImpl 代码: 用于查询数据库


public class FavoriteDaoImpl implements FavoriteDao {//创建Jdbcprivate JdbcTemplate template=new JdbcTemplate(JDBCUtils.getDataSource());/*** 查询用户是否收藏* @param rid* @param uid* @return*/@Overridepublic Favorite findByRidAndUid(int rid, int uid) {//因为数据库查询不出来会报错,所以我们try一下,出错返回nullFavorite favorite=null;try {//1.定义sqlString sql="select * from tab_favorite where rid= ? and uid =? ";//2.执行sqlfavorite = template.queryForObject(sql, new BeanPropertyRowMapper<Favorite>(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){// 用户已经收藏过//<a  class="btn already" disabled="disabled">//设置收藏按钮的样式$("#favorite").addClass("already");$("#favorite").prop("disabled",disabled);}else{// 用户没有收藏}});

14.3收藏次数的动态展示
前台:
route_detail.html

//设置收藏次数
$("#favoriteCount").html("已收藏"+route.count+"次");

后台:

  创建RouteServiceImpl代码: 中添加设置收藏
在这里插入图片描述

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

  创建FavoriteDaoImpl代码: 中添加该方法: 用于查询收藏数

    /*** 查询路线的收藏总数* @param rid* @return*/@Overridepublic int findOneCount(String rid) {//1.定义sqlString sql="select count(*) from tab_favorite where rid = ?";//2.执行sqlInteger count  = template.queryForObject(sql, Integer.class, rid);return count;}

14.4点击按钮收藏线路

14.4.1 分析

在这里插入图片描述
14.4.2 编码
前台代码
route_detail.html

  1. 我是通过点击按钮发送ajax添加路线收藏方法,如果使用location.reload();刷新界面,我感觉不太友好,所以我查询发送了个请求,请求用户是否收藏,这样就不会刷新界面,效果也可以出来。
  2. 因为请求用户是否收藏,这个我们可以写一个方法吧ajax代码放进去,我们就可以调用是否收藏这个方法来实现发送ajax。
  3. 为了方便我就直接复制了,因为我之前试过,这个是可行的,你们最后把是否收藏写成方法!
  //点击收藏按钮触发的方法function addFavorite(){var rid = getParameter("rid");//1. 判断用户是否登录$.get("user/findOne",{},function (user) {if(user){//用户登录了//添加功能$.get("route/addFavorite",{rid:rid},function () {//添加成功执行里面代码//代码刷新页面// location.reload();不友好我们通过ajax来加载页面$.get("route/isFavorite",{rid:rid},function (flag) {if (flag){// 用户已经收藏过//<a  class="btn already" disabled="disabled">//设置收藏按钮的样式$("#favorite").addClass("already");$("#favorite").attr("disabled","disabled");/*对于HTML元素本身就带有的固有属性,在处理时,使用prop方法。对于HTML元素我们自己自定义的DOM属性,在处理时,使用attr方法。*///删除按钮的点击事件$("#favorite").removeAttr("onclick");}else{// 用户没有收藏}})});}else{//用户没有登录alert("您尚未登录,请登录");location.href="http://localhost/travel/login.html";}})}

route_detail.html
  的方法抽出来写成方法,因为后面,点击收藏想要立马看见路线的收藏次数那么我们又要重新发送请求,有好多重复,所以抽离出来,想要的时候调用就好.

//查询用户是否收藏方法function isFavorite() {// 发送请求,判断用户是否收藏过该线路var rid = getParameter("rid");$.get("route/isFavorite",{rid:rid},function (flag) {if (flag){//当返回的数据是true,就是已经收藏的$("#shouchang").addClass("already");$("#shouchang").attr(display,display)//attr这个属性是style里面有的都可以定义// prop是固有属性可以直接定义} else{//当返回的数据是false,就是没有收藏的}})}//查询路线收藏次数方法function countFavorite() {//获取ridvar rid = getParameter("rid");$.get("route/findOne",{rid:rid},function (route) {$("#shouchangCount").html("已收藏"+route.count+"次");})}

  创建RouteServlet代码:添加该方法

 /*** 用户添加收藏* @param request* @param response* @throws ServletException* @throws IOException*/public void addFavorite(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//1.获取数据ridString rid = request.getParameter("rid");//2.获取用户信息User user = (User) request.getSession().getAttribute("user");int uid;//2.1判断用户是否登入if (user==null){//没有登入return;}else{//登入成功uid= user.getUid();}//3调用serivce添加favoriteService.addFavorite(rid,uid);}

  创建FavoriteServiceImpl代码:添加该方法

/*** 添加用户收藏* @param rid* @param uid*/@Overridepublic void addFavorite(String rid, int uid) {//1.调用数据库对象favoriteDao.add(Integer.parseInt(rid),uid);}

  创建FavoriteDaoImpl代码:添加该方法

    /*** 用户收藏* @param rid* @param uid*/@Overridepublic void add(int rid, int uid) {//1.定义sqlString sql="insert into tab_favorite values(?,?,?)";//2.执行sqltemplate.update(sql,rid,new Date(),uid);}

15.查看用户收藏列表!

在这里插入图片描述
在这里插入图片描述
前端代码
 myfavorite.html

  1. 点击我的收藏首先发送一个请求判断用户是否登入,如果没有登入则跳转到登入界面
  2. 登入成功,我们发送请求服务器接收当前页和当前页条数
$(function () {$.get("user/findOne",{},function (pb) {//判断用户是否登入if (pb==null){//用户没有登入alert("您还未登入,请登入查看!")location.href="login.html"} else{load(null)}})})function load(currentPage) {$.get("user/UserFavorite",{currentPage: currentPage},function (pb) {//1.分页工具条数据展示//1.1 展示总页码和总记录数$("#totalPage").html(pb.totalPage);$("#totalCount").html(pb.totalCount);/*<li><a href="">首页</a></li><li class="threeword"><a href="#">上一页</a></li><li><a href="#">1</a></li><li><a href="#">2</a></li><li><a href="#">3</a></li><li><a href="#">4</a></li><li><a href="#">5</a></li><li><a href="#">6</a></li><li><a href="#">7</a></li><li><a href="#">8</a></li><li><a href="#">9</a></li><li><a href="#">10</a></li><li class="threeword"><a href="javascript:;">下一页</a></li><li class="threeword"><a href="javascript:;">末页</a></li>*/var lis="";var frist='<li οnclick= "javascript:load('+1+')"><a href="">首页</a></li>';//计算上一页的页码var beforeNum =  pb.currentPage - 1;if(beforeNum <=0){var  shangyiye=''}else {var shangyiye='<li οnclick="javascript:load('+beforeNum+')"  class="threeword"><a href="#">上一页</a></li>';}lis+=frist;lis+=shangyiye;//1.2 展示分页页码/*1.一共展示10个页码,能够达到前54的效果2.如果前边不够5个,后边补齐103.如果后边不足4个,前边补齐10*/// 定义开始位置begin,结束位置 endvar begin;//开始位置var end;//结束位置if(pb.currentPage<10){begin=1;end=pb.totalPage;}else{//总页码超过10begin=pb.currentPage-5;end=pb.currentPage+4;//2.如果前边不够5个,后边补齐10if(begin<1){begin=1;end=begin+9;}//3.如果后边不足4个,前边补齐10if (end>pb.totalPage) {end=pb.totalPage;begin=end-9;}}for (var i=begin;i<=end;i++){var li;//判断当前页码是否等于iif(pb.currentPage==i){li='<li class="curPage" οnclick="javascript:load('+i+')"><a href="#">'+i+'</a></li>';}else{li='<li οnclick="javascript:load('+i+')"><a href="#">'+i+'</a></li>';}lis+=li;}//拼接后面2个按钮//计算下一页的值var nestNum=pb.currentPage+1;//判断下一页大于总页数那么直接等于当前页if (nestNum>pb.totalPage){var nest=''}else{var nest='<li οnclick="javascript:load('+nestNum+')" class="threeword"><a href="javascript:;">下一页</a></li>'}var mowei='<li οnclick="javascript:load('+pb.totalPage+')" class="threeword"><a href="javascript:;">末页</a></li>'lis+=nest;lis+=mowei;$("#pageNum").html(lis);//拼接喜欢的var lists;/* <div class="col-md-3"><a href="route_detail.html"><img src="images/collection_pic.jpg" alt=""><div class="has_border"><h3>上海直飞三亚54晚自由行(春节预售+亲子/蜜月/休闲游首选+豪华酒店任选+接送机)</h3><div class="price">网付价<em></em><strong>889</strong><em></em></div></div></a></div>*///2.列表数据展示var route_lis = "";for ( var i=0;i<pb.list.length;i++){//获取{rid:1,rname:"xxx"}var route = pb.list[i];var list='<div class="col-md-3">\n' +'                                    <a href="route_detail.html?rid='+route.rid+'">\n' +'                                        <img src="'+route.rimage+'" alt="">\n' +'                                        <div class="has_border">\n' +'                                            <h3>'+route.rname+'</h3>\n' +'                                        </div>\n' +'                                    </a>' +'                                    <div class="price">网付价<em>¥</em><strong>'+route.price+'</strong><em>起</em><input οnclick="nofavorite('+route.rid+');" style="float: right;background: yellow;border-radius:5px ;width: 80px;height: 30px" type="button" value="取消收藏"></div>\n' +'                                </div>'route_lis+=list;}$("#row").html(route_lis)});}

  UserServlet代码:添加该方法

    /*** 用户的收藏查看* @param request* @param response* @throws Exception*/public void UserFavorite(HttpServletRequest request, HttpServletResponse response) throws Exception {//1.从session中获取用户信息User user = (User) request.getSession().getAttribute("user");//1.获取数据String currentPageStr = request.getParameter("currentPage");String pageSizeStr = request.getParameter("pageSize");//2.处理参数int uid;if (user==null){return;}else{uid=user.getUid();}int currentPage=0;//当前第几页if (currentPageStr!=null&&currentPageStr.length()>0&&!"null".equals(currentPageStr)){currentPage=Integer.parseInt(currentPageStr);}else{currentPage=1;}int pageSize=0;//当前查询多少条数据if (pageSizeStr!=null && pageSizeStr.length()>0){pageSize= Integer.parseInt(pageSizeStr);}else {pageSize=8;}//3.调用serivce查询uid//创建收藏对象favoriteServicePageBean<Route> pb= favoriteService.MyFavorite(uid,currentPage,pageSize);//4.响应数据writeValue(pb,response);}

  FavoriteServiceImpl代码:添加该方法

 /*** 查询用户的收藏* @param uid* @param currentPage* @param pageSize* @return*/@Overridepublic PageBean<Route> MyFavorite(int uid, int currentPage, int pageSize) {//1.封装对象PageBean<Route> pb=new PageBean<Route>();//2.设置参数//2.1设置当前页pb.setCurrentPage(currentPage);//2.2设置当前页显示条数pb.setPageSize(pageSize);//2.3设置总条数int count=favoriteDao.findByCount(uid);pb.setTotalCount(count);//3.设置查询所有数据//先通过查询收藏表里面的uid ,获取到路线rid//因为我们要分页所以不能一次性查出rid,所以设置limit查询多少条int start=(currentPage-1)*pageSize;List<Route> rids=favoriteDao.findByUid(uid,start,pageSize);//创建list用来装每一条路线的信息List list=new ArrayList();//通过for循环打印for (int i=0;i<rids.size();i++){System.out.println("路线id:"+rids.get(i).getRid());int rid = rids.get(i).getRid();//获取一个rid//获取一条路线详细信息List<Route> li=favoriteDao.findByOneList(rid);//使用for增强输出for (Route routes:li) {//创建路线对象Route route=new Route();route.setRid(routes.getRid());//设置路线idroute.setRname(routes.getRname());//设置路线名称route.setRimage(routes.getRimage());//设置路线图片route.setPrice(routes.getPrice());//设置价格//把数据传递给listlist.add(route);}}pb.setList(list);//4.设置 页数=总条数/当前页显示条数int totalPage=count%pageSize==0 ?count/pageSize:(count/pageSize)+1;pb.setTotalPage(totalPage);return pb;}

  FavoriteDaoImpl代码:添加3个方法

 /*** 查询用户收藏对的总条数* @param uid* @return*/@Overridepublic int findByCount(int uid) {//1.定义sqlString sql="select count(*) from tab_favorite where uid= ? ";//2.执行sqlInteger count = template.queryForObject(sql, Integer.class, uid);return count;}/*** 查询用户uid获取rid* @param uid* @param start* @param pageSize* @return*/@Overridepublic List<Route> findByUid(int uid,int start,int pageSize) {//1.定义sqlString sql="select * from tab_favorite where uid= ? limit ?,? ";//2.执行sqlList<Route> query = template.query(sql, new BeanPropertyRowMapper<Route>(Route.class), uid,start,pageSize);return query;}/*** 获取收藏路线详细信息* @param rid* @return*/@Overridepublic List<Route> findByOneList(int rid) {//1.定义sqlString sql="select * from tab_route where rid= ?" ;//2.执行sqlList<Route> query = template.query(sql, new BeanPropertyRowMapper<Route>(Route.class), rid);return query;}
}

15.2取消用户收藏

在这里插入图片描述
前端代码:
myfavorite.html

  //用于取消收藏function nofavorite(rid,uid) {$.get("user/UserDelFavorite",{rid:rid},function (pb) {load(null)alert(pb.errorMsg)})

  UserServlet代码:添加该方法

/*** 取消收藏* @param request* @param response* @throws Exception*/public void UserDelFavorite(HttpServletRequest request, HttpServletResponse response) throws Exception {//1.从session中获取用户信息//获取路线信息User user = (User) request.getSession().getAttribute("user");String rid = request.getParameter("rid");int uid;if (user==null){return;}else {uid=user.getUid();}//2.调用serivceResultInfo info= favoriteService.delFavorite(rid,uid);//3.响应数据writeValue(info,response);}

  FavoriteServiceImpl代码:添加该方法

/*** 取消用户收藏* @param rid* @param uid* @return*/@Overridepublic ResultInfo delFavorite(String rid, int uid) {//1.调用数据库String s= favoriteDao.del(Integer.parseInt(rid),uid);ResultInfo info=new ResultInfo();if (s==null){info.setErrorMsg("取消失败!");}else{info.setErrorMsg("取消成功!");}return info;}

  FavoriteDaoImpl代码:添加该方法

 /*** 用户取消收藏* @param rid* @param uid* @return*/@Overridepublic String del(int rid, int uid) {String update = null;try {//1.定义sqlString sql="delete from tab_favorite where rid= ? and uid =? ";//2.执行sqlupdate = String.valueOf(template.update(sql, rid, uid));} catch (DataAccessException e) {e.printStackTrace();}return update;}

16.显示收藏路线最高的路线

在这里插入图片描述
前端代码
route_list.html

  1. 通过发送请求服务器查询路线
  2. 方法要在 入口函数通过调用方法发送请求
  3. 要实现跳转在里面加一个a标签标签跳转页面route_detail.html并且拼接rid
    入口函数:是载入这个页面就会进入的函数.
   $(function () {//当页码加载完成后,调用load方法,发送ajax请求加载数据load(cid,null,rname);//发送ajax请求设置最高路线的数据的方法lo(null);});
        //发送ajax请求设置最高路线的数据的方法function lo(currentPage) {//发送ajax请求设置最高路线的数据$.get("route/MostRoutes",{currentPage:currentPage},function (pb) {//2.列表数据展示var route_lis="";for (var i=0;i<pb.list.length;i++) {var route=pb.list[i];var li='<li >\n' +'                        <a href="route_detail.html?rid='+route.rid+'">\n' +'                        <div class="left"><img src="'+route.rimage+'" alt=""></div>\n' +'                        <div class="right">\n' +'                            <p>'+route.rname+'</p>\n' +'                            <p>网付价<span>&yen;<span>'+route.price+'</span>起</span>\n' +'                            </p>\n' +'                        </div>\n' +'                        </a>\n' +'                    </li>'route_lis+=li}$("#right").html(route_lis)})}

后端代码:
  RouteServlet代码:添加该方法

  1. 获取数据
  2. 处理参数:当前页值传入是空或者不是数字,把当前页默认返回第一页,当前页显示条数页数一个道理.
  3. 调用serivce
  4. 响应数据
/*** 用于查询最多收藏前5* @param request* @param response* @throws ServletException* @throws IOException*/public void MostRoutes(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//1.获取数据String currentPageStr = request.getParameter("currentPage");String pageSizeStr = request.getParameter("pageSize");//2.处理参数int currentPage=0;if(currentPageStr!=null && currentPageStr.length()>0 && !"null".equals(currentPageStr)){currentPage=Integer.parseInt(currentPageStr);}else{currentPage=1;}int pageSize=0;if (pageSizeStr!=null&&pageSizeStr.length()>0){pageSize=Integer.parseInt(pageSizeStr);}else{pageSize=5;}//3.调用serivcePageBean<Route> pb= favoriteService.MostRoutes(currentPage,pageSize);//4响应数据writeValue(pb,response);}}

  FavoriteServiceImpl代码:添加该方法

  1. 设置封装对象
  2. 设置已经知道的值
  3. 设置总共有多少条:这个有些问题会把重复路线算进去
  4. 设置所有路线的信息:1.首先查询收藏列表前5的路线rid,2.在通过findByOneList可以传递rid查询多个list,因为后面要使用for增强,只能打印集合对象,所以有没有办法使用路线查询单个信息的findOne方法,3.在通过for增强赋值,创建路线对象用来封装对象,在把需要的值传入route对象4.在把值传入list对象,list对象是传入了5次路线的全部信息并且,设置到封装对象pb中.
  5. 设置总页数:首先把总条数取模当前页显示条数 能不能余0,如果可以直接使用 总条数除当前页显示条数,如果能余0那么,我们还需要多显示一页.
 /*** 用户收藏最多路线前5个路线* @param currentPage* @param pageSize* @return*/@Overridepublic PageBean<Route> MostRoutes(int currentPage, int pageSize) {//1.设置封装对象PageBean<Route>pb=new PageBean<Route>();//2.设置已经知道的值pb.setPageSize(pageSize);pb.setCurrentPage(currentPage);//3.设置总共有多少条int count=favoriteDao.findMostCount();pb.setTotalCount(count);//4.设置所有路线的信息int start=(currentPage-1)*pageSize;//查询多个路线的idList<Route> rids= favoriteDao.findMost(start,pageSize);//用于存放路线对象List list=new ArrayList();//通过for循环输出ridfor (int i=0;i<rids.size();i++){//输出单个rid,在通过rid查询路线int rid = rids.get(i).getRid();List<Route> routes = favoriteDao.findByOneList(rid);//通过for增强for (Route ls:routes) {//设置路线对象用于封装Route route=new Route();route.setRname(ls.getRname());//设置路线名称route.setRid(ls.getRid());//设置路线idroute.setRimage(ls.getRimage());//设置图片route.setPrice(ls.getPrice());//设置价格list.add(route);}}pb.setList(list);//5.设置总页数int totalpage=count%pageSize==0?count/pageSize:(count/pageSize)+1;pb.setTotalPage(totalpage);return pb;}

  FavoriteDaoImpl代码:添加该方法

  1. 其中查询总条数里面会有些问题,比如说查询的路线有重复的她也算到总数里面。
  2. 因为我们可以不传递有多少条数据,因为前端压根就没有写显示出来
  3. 我们添加了查询多少条数据,是为了以后有需求可以增加翻页需求
 /*** 用于查询收藏总条数* @return*/@Overridepublic int findMostCount() {//1.定义sqlString sql="SELECT COUNT(*) FROM tab_favorite";//2.执行sqlInteger integer = template.queryForObject(sql, Integer.class);return integer;}/*** 查询前5最高路线的rid* @param start* @param pageSize* @return*/@Overridepublic List<Route> findMost(int start, int pageSize) {//1.定义sqlString sql="select rid,count(*) as count from tab_favorite group by rid order by count  desc limit ? ,?";//2.执行sqlList<Route> query = template.query(sql, new BeanPropertyRowMapper<Route>(Route.class), start, pageSize);return query;}

结尾:

    这些代码有时候真的看的头疼,虽然是这些代码,难度可能不是很高,但是我们也可以学习学习,通过不断的学习增加自己的技能,打代码真的很枯燥,刚开始不管是看视频还是什么,你都是懵懵懂懂,但是你要持之以恒,也不要钻牛角尖,现在不会不代表以后不会,特别是通过学习视频的小伙伴们,有些操作跟视频的不一样时,不要慌张,当你想了好久都没有想出来,你可能需要走一走放松放松你的脑子,我学习视频的时候就是发现和视频结果不一样特别是软件配置的问题,要么就百度,要么继续往后学习,你可能就会发现你的问题,可能下个视频就有解决答案,因为我好几次都这样,问题解决答案都在下一个视频展现,不要因为这些代码你看看就会,因为你脑子会了,可能手还不会,所以去练习练习,总会有收获,打这些代码我发费了很多时间,好多都是从下午1点打到下午4点,因为上午要上课,上完课还要把作业个做了,有时候真的很累,俗话说得好趁年轻年轻多吃点苦。还有每天强迫自己花几个小时打打代码,不懂都百度都去学习,可能学习写博客也可以让自己总结能了变得很好,加深印象。在此感谢你坚持看了这么多忍受了我排版的问题,希望一起加油 加油 加油!
在这里插入图片描述
2020-4-10 完

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_717758.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

beta技术沙龙:大型网站的Lucene应用

本文链接 beta技术沙龙&#xff1a;大型网站的Lucene应用 beta技术沙龙越办越有意思了&#xff0c;上次错过了阙宏宇的mod_cache&#xff08;还有关于线程进程的讨论&#xff09;就很可惜&#xff0c;这次关于Lucene的演讲&#xff0c;是无论如何不应该错过了。 到目前为止&am…

AjaxLoad动态生成加载图标的网站

Generator Indicator type : Circle ballIndicatorKitArrowsIndicator BigSnakeBouncing ballBarBar 2Bar 3Circling ballHypnotizeWheelExpanding CircleRadarRefreshFlowerBackground color : # Transparent background Foreground color : # 网址&#xff1a;http://www.aja…

Mono团队自立创业 .NET入侵苹果平台,徐汇区网站设计

众所周知&#xff0c;.NET其实并不是Windows上的专有技术&#xff0c;这一点很大程度上要感谢Miguel de Icaza所领导的Mono开发团队。他们多年不懈地工作&#xff0c;实现了跨平台的开源.NET实现&#xff08;包括CLR运行库、C#编译器和其他开发工具、组件&#xff09;。今天的M…

使用GitHub创建博客 第一篇-如何使用github.io创建自己的网站

第一篇-如何使用github.io创建自己的网站首先要有一个Github账号创建Repositories选择主题修改网站使用vscode编辑网站访问首先要有一个Github账号 用户名好像不能用汉字&#xff0c;其它的信息自己填好就可以了 创建Repositories 登录上GitHub后&#xff0c;创建一个 new R…

1月第二周域名主机网站排名TOP15 西部数码升至第二

据国际统计机构Alexa最新统计数据&#xff0c;在1月9日至15日一周时间内&#xff0c;用户覆盖数排名TOP15的国内域名主机网站分别为&#xff1a;中国万网、西部数码、易名中国、新网、网域科技、金名网、35互联、爱名网、新网互联、商务中国、主机屋、中资源、中国数据、阳光互…

微软云计算官方中文网站上线啦

公告 &#xff1a;本博客为微软云计算中文博客 的镜像博客。 部分文章因为博客兼容性问题 &#xff0c;会影响阅读体验 。如遇此情况&#xff0c;请访问 原博客 。 11月29日&#xff0c;微软云计算官方中文站http://www.microsoft.com/china/cloud 上线啦&#xff01; 还…

dw cs6 html建站点,dreamweaver cs6网页中制作锚点链接的教程方法

部分网友刚刚下载使用dreamweaver cs6的朋友们&#xff0c;可能还不是很熟悉其中制作锚点链接?下面这篇内容就为你们带来了dreamweavercs6网页中制作锚点链接的教程方法。dreamweaver cs6网页中制作锚点链接的教程方法我们需要先打开dreamweaver cs6软件&#xff0c;选择一个空…

【转】如何让虚拟目录里面的webconfig不继承网站

今天要部署一个网站和一个和网站相关的webservices接口,我把网站部署后,就把WEB接口作为它下面的一个虚拟目录来处理了,这样他们可以共享一个域名.他们各个都有一个webconfig配置文件,部署后发现网站正常,可是WEB接口却报错,说配置文件出了问题,仔细检查发现WEB接口用的是网站的…

学用MVC4做网站一:用户登陆1.2

一用户 1.1用户注册 1.2用户登陆 首先在Models里添加用户登陆模型类UserLogin&#xff0c;该类只要用用户名&#xff0c;密码和验证码三个字段。 /// <summary>/// 用户登陆模型/// </summary>public class UserLogin{/// <summary>/// 用户名/// </summa…

一年来网站开发之总结(中国传统路线:血淋淋的散乱道路)

一.序幕 去年年底来到现在这个公司&#xff0c;这段时间内发生很多事情&#xff0c;直接或者间接的改变了这个创业互联网公司的命运。 关键角色有BOSS&#xff0c;PM&#xff0c;CTO。 BOSS在这个行业做了十几年&#xff0c;有了积累&#xff0c;然后想做做行业网站。听说同…

小说阅读网站的‘作者’为何不用实名制?

我们注意到&#xff0c;绝大部分小说阅读网站对‘作者’不用实名制。是什么原因导致的呢&#xff1f; 一、原因分析 其实网络作者&#xff08;注意&#xff0c;不是‘作家’&#xff09;之所以大都非实名制&#xff0c;与其起源有关。 1&#xff09;因为TA们一开始都是草根&…

年度盛宴:2012年最佳25个响应式网站设计作品《上篇》

2012年&#xff0c;响应式网站设计成为主流&#xff0c;这个概念由著名网页设计师 Ethan Marcotte 在2010年5月份提出&#xff0c;其目标是要让设计的网站能够响应用户的行为&#xff0c;根据不同终端设备自动调整尺寸。 响应式设计不再只是一个概念&#xff0c;众多大公司也把…

牟长青:浅谈如何提高网站PR值

2019独角兽企业重金招聘Python工程师标准>>> PR值如何提高&#xff0c;已经不是什么好神秘的事情。唯一的方法就是大量的增加外链&#xff0c;因此我这篇文章&#xff0c;虽然标题是如何提高PR值&#xff0c;其实主要就是讲如何增加外部链接&#xff0c;提高PR值。 …

Win7下安装配置IIS 构建自己的网站

一、首先是安装IIS。打开控制面板&#xff0c;找到“程序与功能”&#xff0c;点进去 二、点击左侧“打开或关闭Windows功能” 三、找到“Internet 信息服务”&#xff0c;按照下图打勾即可 等待安装完成 四、安装完成后&#xff0c;再回到控制面板里面&#xff0c;找到“管理工…

使用Mitmproxy工具进行小姐姐图片(不管什么网站,只要是.jpg格式的图片都可自动下载)的批量下载

抓取目标: 1.首先Mitmproxy工具的下载及使用: 点我观看! 2.实战——小姐姐图片批量下载: 实现——在你使用浏览器欣赏你自备的小姐姐图片资源的时候自动下载哦! <

分享35个富有创意的蓝色网站设计作品

蓝色是网页设计中最流行的颜色之一&#xff0c;蓝色表现出一种美丽、冷静、理智、安详与广阔。由于蓝色沉稳的特性&#xff0c;具有理智、准确的意象&#xff0c;在商业设计中&#xff0c;强调科技&#xff0c;效率的商品或企业形象&#xff0c;大多选用蓝色当标准色。今天这篇…

从零开始Web自动化(三):通过selenium,9行代码实现打字网站的自动打字

写在前面&#xff1a; 这个专栏主要是分享一些python、Web自动化的相关知识。 需要你具备一定的python基础&#xff0c;参考教程&#xff1a;廖雪峰python教程 掌握红框中的内容即可&#xff01; 通过实战项目让你学会包括&#xff1a;python、selenium、测试报告、监听、特殊…

从零开始Web自动化(四):如何过打字网站的作弊检测,从而实现排行榜第一

一、分析和解决思路 上篇博文中&#xff0c;我们的程序被检测出作弊了&#xff0c;那如何过检测呢&#xff1f; 思路&#xff1a; 我们打的太快了&#xff0c;完全超出了人类的极限。 而且也不可能一直都是一个速度&#xff0c;也不可能每个字母都打正确。 那我们要让程序打的…

网站url过滤不严格造成下载任意文件漏洞

年底了很忙&#xff0c;最近一直在处理安全问题&#xff0c;其中有一例比较有代表性&#xff0c;于是想拿出来说说。大概是这样的&#xff0c;网站在某个目录下提供pdf文档下载&#xff0c;但是出现了安全问题&#xff0c;通过对路径和文件名的修改&#xff0c;指定下载linux系…

优化网站设计(二十三):减小Cookie的体积

前言 网站设计的优化是一个很大的话题,有一些通用的原则,也有针对不同开发平台的一些建议。这方面的研究一直没有停止过&#xff0c;我在不同的场合也分享过这样的话题。 作为通用的原则&#xff0c;雅虎的工程师团队曾经给出过35个最佳实践。这个列表请参考 Best Practices fo…