黑马旅游网站

第一次写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.rhkb.cn/news/22474.html

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

相关文章

新加坡圣淘沙亲子游自助游景点购票攻略

新加坡圣淘沙岛有很多适合家庭亲子游的景点和游乐园&#xff0c;无论是想要感受肾上腺飙升的游乐设施&#xff0c;体验虚拟世界的惊险刺激&#xff0c;与众多名人约会&#xff0c;还是探索海洋世界&#xff0c;这里总有你想要的。 新加坡环球影城 新加坡环球影城分为七个主题景…

三亚旅游攻略-自由人实用指南

三亚&#xff0c;是个被大自然宠坏了的地方。大自然把最宜人的气候、最清新的空气、最和煦的阳光、最湛蓝的海水、最柔和的沙滩、最风情万种的少数民族、最美味的海鲜…都赐予了这座海南岛最南端的海滨旅游城市。 虽然三亚自古以来是贬官谪宦流放之地&#xff0c;可这段悲怆的历…

6-黑马旅游网-旅游线路详情

旅游线路详情 分析 后端 RouteServlet findOne方法 /*** 根据id查询一个旅游线路的详细信息* param request* param response* throws ServletException* throws IOException*/ public void findOne(HttpServletRequest request, HttpServletResponse response) throws Serv…

马来西亚之旅——吉隆坡、马六甲、槟城和亚庇攻略

之前就准备了在17年有个旅行计划&#xff0c;计划本来是台湾或者西藏&#xff0c;但是因为种种原因一直拖到清明节前半个月才定下来&#xff0c;看了一下机票&#xff0c;发现往返吉隆坡的机票价格很合适&#xff0c;所以才有了清明马来的行程。准备 机票 我们是从北京出发&a…

黑马旅游网编写练习(7)--某一旅游线路详情展示

黑马旅游网编写练习(7)–某一旅游线路详情展示 在分页展示的页面中&#xff0c;我们点击某一个旅游&#xff0c;想要查看详细信息&#xff0c;则点击了查看详情后&#xff0c;会跳转到该旅游路线对应的详细信息页面。接下来对该详细信息页面的查询与展示。 想要查看不同旅游线…

世界上唯一7星级酒店-阿联酋迪拜的Burj Al Arab旅店

全世界最贵的酒店&#xff0c;全世界曾经最高的酒店在迪拜。阿联酋迪拜的Burj Al-Arab酒店。 阿联酋迪拜的Burj Al-Arab酒店。 迪拜是阿拉伯联合酋长国的第二大城市。20世纪50年代&#xff0c;它还是阿拉伯湾一个朴素的海滨小镇&#xff0c;到了90年代以后&#xff0c;迪拜发生…

三亚自由行八天七晚旅行攻略

**文中报价为两人费用。**所有总支出低于1W 建议&#xff1a; 1、 住宿不要在一个地方住&#xff0c;三亚湾、亚龙湾等各住几天。 2、 带防晒霜和晒后修复霜&#xff0c;还有手机防水袋。 3、 自带泳衣&#xff0c;三亚买比较贵。 4、 直飞三亚比较好&#xff0c;海口转比较费时…

黑马旅游网-注册用户(二)

目录 一、注册用户-业务流程分析 1.页面效果 2.业务流程分析 二、注册用户-前端功能实现 修改register.html 1.校验用户名 2.校验密码 3.检验邮箱 4.使用ajax提交数据 5.完整代码参考 三、注册用户-后端功能实现 创建​​​​​​​RegisterUserServlet 创建UserServ…

黑马旅游网-旅游分类线路分页显示(七)

目录 一、先查旅游分类所有内容 二、查询分页数据 三、实现后端代码 RouteServlet RouteServiceImpl​​​​​​​ RouteService RouteDaoImpl RouteDao PageBean 四、分页与数据展示 修改route_list.html 修改header.html 五、测试 一、先查旅游分类所有内容 点…

ChatGPT最有实力的竞争对手Claude也开放API申请了

申请地址&#xff1a;https://www.anthropic.com/product 或者点击“阅读原文 ”直接申请

ChatGPT与低代码平台谁更适合快速开发

近来&#xff0c;关于生成式AI技术即将颠覆各个行业的预测在网络上随处可见。虽然生成式AI技术在自然语言处理、文本生成等领域已经取得了令人瞩目的成果&#xff0c;但是在低代码平台开发领域&#xff0c;尤其是在企业内部应用方面&#xff0c;其影响并不明显。 低代码平台作…

我曾做过陈士成,也做过孔乙己,还做过阿Q

一、 我现在是陈士成&#xff0c;陈士成现在是我。为什么这么说呢&#xff1f; 那年那天&#xff0c;天刚微微亮&#xff0c;似乎还在打着哈欠。我和父亲去得很早&#xff0c;为的就是在“小升初的考试成绩榜单”前面占一个有利的位置。我不记得当时穿的厚还是不厚&#xff0c;…

码农版孔乙己

改变自己 也许有一天你能改变这个世界&#xff0c;但是请在改变世界之前&#xff0c;先让自己存活下来&#xff0c;看到一篇文章分享一下不知道你们能从中看出什么呢 听人家背地里谈论&#xff0c;孔乙己原来也读过研&#xff0c;但终于没有实习经历&#xff0c;又没关系内推&a…

浅谈“孔乙己的长衫“是脱不下来还是难脱下?

名人说&#xff1a;往者不可谏&#xff0c;来者犹可追。——《论语微子篇》 创作者&#xff1a;Code_流苏(CSDN) ★温馨提示&#xff1a;以下仅代表个人观点&#xff0c;不代表其它任何人看法。 目录 〇、缘由一、社会对于学历和职业之间的关系认知是怎样的&#xff1f;二、学历…

Unity 蒙皮动画 SkinnedMesh 使用GPU Instance

GPU Instance合批技术是不支持 SkinnedMeshRender的&#xff0c;不过可以转换为Mesh Render以支持GPU Instance. 0x00 前言 我想很多开发游戏的小伙伴都希望自己的场景内能渲染越多物体越好&#xff0c;甚至是能同时渲染成千上万个有自己动作的游戏角色就更好了。 但不幸的是…

Unity毛发系统TressFX Exporter

Unity 数字人交流群&#xff1a;296041238 一&#xff1a;在Maya下的TressFX Exporter 插件安装步骤&#xff1a; 1. 下载Maya的TressFX Exporter插件 下载地址&#xff1a;TressFX Exporter 链接&#xff1a;https://github.com/Unity-China/cn.unity.hairfx.core/tree/m…

vscode配置go开发环境,插件超时问题解决

今天想试下golang&#xff0c;用goland太贵所以打算配置vscode来试一试&#xff0c;但是发现许多插件安装超时&#xff0c;查阅资料说是配置一下环境变量开启代理就好&#xff0c; go env -w GO111MODULEon go env -w GOPROXYhttps://goproxy.io,direct 但是尝试后发现依然没…

解决IDEA插件安装慢、超时、不成功问题

解决IDEA插件安装慢、超时、不成功问题 1.修改本地hosts文件&#xff0c;打开文件位置&#xff1a; Windows 系统 Hosts 文件路径&#xff1a;C:\Windows\System32\drivers\etc\hosts 用工具打开hosts文件 2.打开国内插件的节点IP地址 http://tool.chinaz.com/speedtest/pl…

chatgpt赋能python:Python如何突破VIP限制

Python如何突破VIP限制 在这个数字内容时代&#xff0c;我们经常使用各种网站和应用程序来获取视频、音乐、软件等数字资源。但是&#xff0c;某些资源可能受到VIP限制&#xff0c;这意味着我们需要付费才能获得完整的访问权限。但是&#xff0c;如果你了解Python编程&#xf…

武汉总部裁掉九成35岁以上员工?小米最新回应→

上一篇&#xff1a;00后太猛了&#xff0c;正强势整顿职场 导读&#xff1a;小米方面表示&#xff0c;在社交媒体平台上陆续出现有关小米武汉总部35岁以上员工只保留10%的信息&#xff0c;经查皆为谣言。 5月14日&#xff0c;微博端有消息称小米武汉总部正式裁掉90% 35岁以上员…