第一次写CSDN所以不太会!
我接下来会记录这一段时间,完成黑马旅游网站的代码!我们使用的是maven框架,原因很简单,因为黑马提供了大部分的数据跟我们,里面有数据库表,数据库网页整体的容,我们通过写数据库代码,Servlet代码,还有前端ajax的交互代码,的学习,开始会比较难,持之以恒会发现你会不断的提升。
注:这里面的有些是我自己总结的可能有错,也希望多包涵!
注意:接下来所有关于Servlet的类,我们都要把他继承BaseServlet 这个类,因为这个充当着,方法的方法工作!
准备工作
1. 项目导入
点击绿色+按钮
选择travel项目的pom.xml文件,点击ok,完成项目导入。需要等待一小会,项目初始化完成。
2.启动项目
2.1 方式一:
2.2方式二:配置maven快捷启动
4.技术选型
4.1Web层
- a)Servlet:前端控制器
- b)html:视图
- c)Filter:过滤器
- d)BeanUtils:数据封装
- e)Jackson:json序列化工具
4.2 Service层
- f)Javamail:java发送邮件工具
- g)Redis:nosql内存数据库
- h)Jedis:java的redis客户端
4.3Dao层
- i)Mysql:数据库
- j)Druid:数据库连接池
- k)JdbcTemplate:jdbc的工具
5.创建数据库
- – 创建数据库
CREATE DATABASE travel;
– 使用数据库
USE travel;
–创建表
复制提供好的sql
6注册功能
6.1页面效果
6.2功能分析
6.3.1前台代码实现
6.3.2表单校验
提升用户体验,并减轻服务器压力。
//校验用户名
//单词字符,长度8到20位
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.com
var reg_email = /^\w+@\w+\.\w+$/;
//3.判断
var flag = reg_email.test(email);
if(flag){
$("#email").css("border","");
}else{
$("#email").css("border","1px solid red");
}
return flag;
}
$(function () {
//当表单提交时,调用所有的校验方法
$("#registerForm").submit(function(){
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 {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//System.out.println("baseServlet的service方法被执行了...");
//完成方法分发
//1.获取请求路径
String uri = req.getRequestURI(); // /travel/user/add
System.out.println("请求uri:"+uri);// /travel/user/add
//2.获取方法名称
String methodName = uri.substring(uri.lastIndexOf('/') + 1);
System.out.println("方法名称:"+methodName);
//3.获取方法对象Method
//谁调用我?我代表谁
System.out.println(this);//UserServlet的对象cn.itcast.travel.web.servlet.UserServlet@4903d97e
try {
//获取方法
Method method = this.getClass().getMethod(methodName, HttpServletRequest.class, HttpServletResponse.class);
//4.执行方法
//暴力反射
//method.setAccessible(true);
method.invoke(this,req,resp);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
在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 {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public 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);
}
@Override
public 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个随机验证码,12Ey
String 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注册和邮箱激活的方法
黑马的分析都在后面:我只不过把代码注册和邮箱验证的都写在了一起。
- UserDaoImpl数据库的方法集合:用于连接本地数据库进行,查询,添加,删除等操作!
- UserServiceImpl的代码方法:用于服务器UserServlet的使用,别人在这里调用数据库的对象,进行判断等
- UserServlet服务代码方法:用于接收客服端服务我们的服务器,接收请求和响应的。
注意:接下来所有关于Servlet的类,我们都要把他继承BaseServlet 这个类,因为这个充当着,方法的方法工作!
UserDaoImpl 代码:
public class UserDaoImpl implements UserDao {
//1.首先创建Jdbc对象
private JdbcTemplate template=new JdbcTemplate(JDBCUtils.getDataSource());
@Override
public User findByUserNmae(String username) {
//为什么要try原因是,数据库查询到数据会返回,如果查询不到数据,只会报错,返回的不是null所以需要定义.
User user = null;
try {
//1.定义sql
String sql="select * from tab_user where username= ?";
//2.执行sql
user = template.queryForObject(sql, new BeanPropertyRowMapper<User>(User.class), username);
} catch (DataAccessException e) {
System.out.println("注册的用户已经存在!");
}
return user;
}
/**
* 用户保存方法
* @param user
*/
@Override
public void save(User user) {
//1.定义sql
String sql="insert into tab_user(username,password,name,birthday,sex,telephone,email,status,code) values(?,?,?,?,?,?,?,?,?)";
//2.执行sql
template.update(sql,user.getUsername(),
user.getPassword(),
user.getName(),
user.getBirthday(),
user.getSex(),
user.getTelephone(),
user.getEmail(),
user.getStatus(),
user.getCode());
}
/**
* 激活码查询
* @param code
* @return
*/
@Override
public User findByCode(String code) {
User user = null;
try {
//1.定义sql
String sql="select * from tab_user where code=?";
//2.执行sql
user = template.queryForObject(sql, new BeanPropertyRowMapper<User>(User.class), code);
} catch (DataAccessException e) {
e.printStackTrace();
}
return user;
}
/**
* 修改激活码状态
* @param user
*/
@Override
public void updateStatus(User user) {
//为什么使用uid,因为user前面通过findByCode查询到了用户的所有信息所有通过uid可以修改
//1.定义sql
String sql="update tab_user set status = 'Y' where uid=? ";
//2.执行sql
template.update(sql,user.getUid());
}
}
UserServiceImpl 代码:
public class UserServiceImpl implements UserService {
//业务对象
private UserDao userDao=new UserDaoImpl();
/**
* 注册方法
* @param user
* @return
*/
@Override
public 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
*/
@Override
public boolean active(String code) {
//1.查询数据库,是否有code码信息
User user=userDao.findByCode(code);
if (user!=null){
//有code码。那么调用数据库把sautus改为Y
userDao.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.调用serivce
boolean 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);
//把用户信息存到session
request.getSession().setAttribute("user",u);
}
//5.响应数据
writeValue(info,response);
}
UserServiceImpl代码:
/**
* 登入方法
* @param user
* @return
*/
@Override
public User login(User user) {
//1.调用dao查询数据库
//如果u有值那么,查询出来的是用户的所有信息。
User u= userDao.findByUserNameAndPassword(user.getUsername(),user.getPassword());
return u;
}
UserDaoImpl代码:
/**
* 查询账号和密码
* @param username
* @param password
* @return
*/
@Override
public User findByUserNameAndPassword(String username, String password) {
User user=null;
try {
//1.定义sql
String sql="select * from tab_user where username=? and password=? ";
//2.执行sql
user = template.queryForObject(sql, new BeanPropertyRowMapper<User>(User.class), username, password);
} catch (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();
@Override
public List<Category> findAll() {
return categoryDao.findAll();
}
}
CategoryDao代码: 这是重新的一个类哦!
public class CategoryDaoImpl implements CategoryDao {
private JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());
@Override
public List<Category> findAll() {
String sql = "select * from tab_category ";
return template.query(sql,new BeanPropertyRowMapper<Category>(Category.class));
}
}
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();
@Override
public List<Category> findAll() {
//1从redis中获取数据
//1.1创建redis对象
Jedis jedis=JedisUtil.getJedis();
//1.2可使用sortedset排序查询
// 用这个方法zrangeWithScores
Set<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的数据存入list
cs=new ArrayList<>();
//使用for增强打印
for (Tuple tuple:categorys) {
//这一步操作就是为了把查询出来的set数据,传递到list中
Category category=new Category();
category.setCid((int) tuple.getScore());//获取cid
category.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个页码,能够达到前5后4的效果
2.如果前边不够5个,后边补齐10个
3.如果后边不足4个,前边补齐10个
*/
// 定义开始位置begin,结束位置 end
var begin; // 开始位置
var end ; // 结束位置
//1.要显示10个页码
if(pb.totalPage < 10){
//总页码不够10页
begin = 1;
end = pb.totalPage;
}else{
//总页码超过10页
begin = pb.currentPage - 5 ;
end = pb.currentPage + 4 ;
//2.如果前边不够5个,后边补齐10个
if(begin < 1){
begin = 1;
end = begin + 9;
}
//3.如果后边不足4个,前边补齐10个
if(end > pb.totalPage){
end = pb.totalPage;
begin = end - 9 ;
}
}
for (var i = begin; i <= end ; i++) {
var li;
//判断当前页码是否等于i
if(pb.currentPage == i){
li = '<li class="curPage" οnclick="javascipt:load('+cid+','+i+',\''+rname+'\')"><a href="javascript:void(0)">'+i+'</a></li>';
}else{
//创建页码的li
li = '<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;
//判断当前页码是否等于i
if(pb.currentPage == i){
li = '<li class="curPage" οnclick="javascipt:load('+cid+','+i+')"><a href="javascript:void(0)">'+i+'</a></li>';
}else{
//创建页码的li
li = '<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>¥</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>¥</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=xxx
location.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;//类别id
if (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 代码:
- 这个方法主要是查询数据库把当前页的所有信息返回!
- 其中currentPage和pageSize是传递的值是已知的!
- 设置查询出的所有数据信息,设置总条数信息,这两个是需要数据库查询返回!
- 设置一共有多少页,这里采用了三元运算,当不够取模则加1页;
public class RouteServiceImpl implements RouteService {
//业务类
private RouteDao routeDao=new RouteDaoImpl();
/**
* 查询一页的信息
* @param cid
* @param currentPage
* @param pageSize
* @param rname
* @return
*/
@Override
public 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 代码:
- 初学者需要注意的是:定义好sql要记得放到StringBuilder方法里面,最后拼接完成也要通过对象的toString方法赋值给sql
- 这里采用了拼接式查询,当传递了cid路线id和搜索框输入的查询做一个字符串的拼接。
- 其中List params=new ArrayList();的对象用于存入参数,最后通过执行sql把params.toArray()传递,相当于?的条件们!.
- 查询当前页的信息我们采用了传递limit方式查询数据库的条数,记得最后要把开始(start)和结束(pageSize)存入到params.add方法中去。
- 搜索框里面的值,在数据库里面我们用的是模糊查询所以配上了%西安%
public class RouteDaoImpl implements RouteDao {
private JdbcTemplate template=new JdbcTemplate(JDBCUtils.getDataSource());
/**
* 查询总条数
* @return
*/
@Override
public 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.把拼接好的字符串赋值给sql
sql=sb.toString();
//5.执行sql
Integer count = template.queryForObject(sql, Integer.class, params.toArray());
return count;
}
/**
* 查询一页所有信息
* @param cid
* @param start
* @param pageSize
* @param rname
* @return
*/
@Override
public 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+"%");
}
//因为查询的是有条数的所以要跟 limit
sb.append(" limit ? , ? ");
//4.把拼接好的字符串赋值给sql
sql=sb.toString();
params.add(start);
params.add(pageSize);
//5.执行sql
List<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.获取数据rid
String rid = request.getParameter("rid");
//2.调用serivce查询
Route route=routeService.findOne(rid);
//3.响应数据
//通过方法返回
writeValue(route,response);
}
RouteServiceImpl代码:
需要创建2个对象
/**
* 查询单个路线的详细信息
* @param rid
* @return
*/
@Override
public 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
*/
@Override
public Seller findSeller(int sid) {
//1.定义sql
String sql="select * from tab_seller where sid=? ";
//2执行sql
Seller 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
*/
@Override
public List<RouteImg> findImg(int rid) {
//1.定义sql
String sql="select * from tab_route_img where rid= ? ";
//2执行sql
List<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.获取rid
var 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>';
//遍历routeImgList
for (var i = 0; i < route.routeImgList.length; i++) {
var astr ;
if(i >= 4){
astr = '<a title="" class="little_img" data-bigpic="'+route.routeImgList[i].bigPic+'" style="display:none;">\n' +
' <img src="'+route.routeImgList[i].smallPic+'">\n' +
' </a>';
}else{
astr = '<a title="" class="little_img" data-bigpic="'+route.routeImgList[i].bigPic+'">\n' +
' <img src="'+route.routeImgList[i].smallPic+'">\n' +
' </a>';
}
ddstr += astr;
}
ddstr+='<a class="down_img down_img_disable" style="margin-bottom: 0;"></a>';
$("#dd").html(ddstr);
//图片展示和切换代码调用
goImg();
});
});
**
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.获取数据rid
String rid = request.getParameter("rid");
//2. 获取当前登录的用户 user
//强制转换成User
User user = (User) request.getSession().getAttribute("user");
//2.1判断user是否为null
int 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
*/
@Override
public 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返回flase
return false;
}*/
return favorite!=null ;//如果对象有值,则为true,反之,则为false,和上面if等价
}
}
创建FavoriteDaoImpl 代码: 用于查询数据库
public class FavoriteDaoImpl implements FavoriteDao {
//创建Jdbc
private JdbcTemplate template=new JdbcTemplate(JDBCUtils.getDataSource());
/**
* 查询用户是否收藏
* @param rid
* @param uid
* @return
*/
@Override
public Favorite findByRidAndUid(int rid, int uid) {
//因为数据库查询不出来会报错,所以我们try一下,出错返回null
Favorite favorite=null;
try {
//1.定义sql
String sql="select * from tab_favorite where rid= ? and uid =? ";
//2.执行sql
favorite = 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
*/
@Override
public int findOneCount(String rid) {
//1.定义sql
String sql="select count(*) from tab_favorite where rid = ?";
//2.执行sql
Integer count = template.queryForObject(sql, Integer.class, rid);
return count;
}
14.4点击按钮收藏线路
14.4.1 分析:
14.4.2 编码
前台代码
route_detail.html
- 我是通过点击按钮发送ajax添加路线收藏方法,如果使用location.reload();刷新界面,我感觉不太友好,所以我查询发送了个请求,请求用户是否收藏,这样就不会刷新界面,效果也可以出来。
- 因为请求用户是否收藏,这个我们可以写一个方法吧ajax代码放进去,我们就可以调用是否收藏这个方法来实现发送ajax。
- 为了方便我就直接复制了,因为我之前试过,这个是可行的,你们最后把是否收藏写成方法!
//点击收藏按钮触发的方法
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() {
//获取rid
var 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.获取数据rid
String 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
*/
@Override
public void addFavorite(String rid, int uid) {
//1.调用数据库对象
favoriteDao.add(Integer.parseInt(rid),uid);
}
创建FavoriteDaoImpl代码:添加该方法
/**
* 用户收藏
* @param rid
* @param uid
*/
@Override
public void add(int rid, int uid) {
//1.定义sql
String sql="insert into tab_favorite values(?,?,?)";
//2.执行sql
template.update(sql,rid,new Date(),uid);
}
15.查看用户收藏列表!
前端代码:
myfavorite.html
- 点击我的收藏首先发送一个请求判断用户是否登入,如果没有登入则跳转到登入界面
- 登入成功,我们发送请求服务器接收当前页和当前页条数
$(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个页码,能够达到前5后4的效果
2.如果前边不够5个,后边补齐10个
3.如果后边不足4个,前边补齐10个
*/
// 定义开始位置begin,结束位置 end
var begin;//开始位置
var end;//结束位置
if(pb.currentPage<10){
begin=1;
end=pb.totalPage;
}else{
//总页码超过10页
begin=pb.currentPage-5;
end=pb.currentPage+4;
//2.如果前边不够5个,后边补齐10个
if(begin<1){
begin=1;
end=begin+9;
}
//3.如果后边不足4个,前边补齐10个
if (end>pb.totalPage) {
end=pb.totalPage;
begin=end-9;
}
}
for (var i=begin;i<=end;i++){
var li;
//判断当前页码是否等于i
if(pb.currentPage==i){
li='<li class="curPage" ο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>上海直飞三亚5天4晚自由行(春节预售+亲子/蜜月/休闲游首选+豪华酒店任选+接送机)</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&¤tPageStr.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
//创建收藏对象favoriteService
PageBean<Route> pb= favoriteService.MyFavorite(uid,currentPage,pageSize);
//4.响应数据
writeValue(pb,response);
}
FavoriteServiceImpl代码:添加该方法
/**
* 查询用户的收藏
* @param uid
* @param currentPage
* @param pageSize
* @return
*/
@Override
public 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());//设置路线id
route.setRname(routes.getRname());//设置路线名称
route.setRimage(routes.getRimage());//设置路线图片
route.setPrice(routes.getPrice());//设置价格
//把数据传递给list
list.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
*/
@Override
public int findByCount(int uid) {
//1.定义sql
String sql="select count(*) from tab_favorite where uid= ? ";
//2.执行sql
Integer count = template.queryForObject(sql, Integer.class, uid);
return count;
}
/**
* 查询用户uid获取rid
* @param uid
* @param start
* @param pageSize
* @return
*/
@Override
public List<Route> findByUid(int uid,int start,int pageSize) {
//1.定义sql
String sql="select * from tab_favorite where uid= ? limit ?,? ";
//2.执行sql
List<Route> query = template.query(sql, new BeanPropertyRowMapper<Route>(Route.class), uid,start,pageSize);
return query;
}
/**
* 获取收藏路线详细信息
* @param rid
* @return
*/
@Override
public List<Route> findByOneList(int rid) {
//1.定义sql
String sql="select * from tab_route where rid= ?" ;
//2.执行sql
List<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.调用serivce
ResultInfo info= favoriteService.delFavorite(rid,uid);
//3.响应数据
writeValue(info,response);
}
FavoriteServiceImpl代码:添加该方法
/**
* 取消用户收藏
* @param rid
* @param uid
* @return
*/
@Override
public 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
*/
@Override
public String del(int rid, int uid) {
String update = null;
try {
//1.定义sql
String sql="delete from tab_favorite where rid= ? and uid =? ";
//2.执行sql
update = String.valueOf(template.update(sql, rid, uid));
} catch (DataAccessException e) {
e.printStackTrace();
}
return update;
}
16.显示收藏路线最高的路线
前端代码
route_list.html
- 通过发送请求服务器查询路线
- 方法要在 入口函数通过调用方法发送请求
- 要实现跳转在里面加一个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>¥<span>'+route.price+'</span>起</span>\n' +
' </p>\n' +
' </div>\n' +
' </a>\n' +
' </li>'
route_lis+=li
}
$("#right").html(route_lis)
})
}
后端代码:
RouteServlet代码:添加该方法
- 获取数据
- 处理参数:当前页值传入是空或者不是数字,把当前页默认返回第一页,当前页显示条数页数一个道理.
- 调用serivce
- 响应数据
/**
* 用于查询最多收藏前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.调用serivce
PageBean<Route> pb= favoriteService.MostRoutes(currentPage,pageSize);
//4响应数据
writeValue(pb,response);
}
}
FavoriteServiceImpl代码:添加该方法
- 设置封装对象
- 设置已经知道的值
- 设置总共有多少条:这个有些问题会把重复路线算进去
- 设置所有路线的信息:1.首先查询收藏列表前5的路线rid,2.在通过findByOneList可以传递rid查询多个list,因为后面要使用for增强,只能打印集合对象,所以有没有办法使用路线查询单个信息的findOne方法,3.在通过for增强赋值,创建路线对象用来封装对象,在把需要的值传入route对象4.在把值传入list对象,list对象是传入了5次路线的全部信息并且,设置到封装对象pb中.
- 设置总页数:首先把总条数取模当前页显示条数 能不能余0,如果可以直接使用 总条数除当前页显示条数,如果能余0那么,我们还需要多显示一页.
/**
* 用户收藏最多路线前5个路线
* @param currentPage
* @param pageSize
* @return
*/
@Override
public 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;
//查询多个路线的id
List<Route> rids= favoriteDao.findMost(start,pageSize);
//用于存放路线对象
List list=new ArrayList();
//通过for循环输出rid
for (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());//设置路线id
route.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代码:添加该方法
- 其中查询总条数里面会有些问题,比如说查询的路线有重复的她也算到总数里面。
- 因为我们可以不传递有多少条数据,因为前端压根就没有写显示出来
- 我们添加了查询多少条数据,是为了以后有需求可以增加翻页需求
/**
* 用于查询收藏总条数
* @return
*/
@Override
public int findMostCount() {
//1.定义sql
String sql="SELECT COUNT(*) FROM tab_favorite";
//2.执行sql
Integer integer = template.queryForObject(sql, Integer.class);
return integer;
}
/**
* 查询前5最高路线的rid
* @param start
* @param pageSize
* @return
*/
@Override
public List<Route> findMost(int start, int pageSize) {
//1.定义sql
String sql="select rid,count(*) as count from tab_favorite group by rid order by count desc limit ? ,?";
//2.执行sql
List<Route> query = template.query(sql, new BeanPropertyRowMapper<Route>(Route.class), start, pageSize);
return query;
}
结尾:
这些代码有时候真的看的头疼,虽然是这些代码,难度可能不是很高,但是我们也可以学习学习,通过不断的学习增加自己的技能,打代码真的很枯燥,刚开始不管是看视频还是什么,你都是懵懵懂懂,但是你要持之以恒,也不要钻牛角尖,现在不会不代表以后不会,特别是通过学习视频的小伙伴们,有些操作跟视频的不一样时,不要慌张,当你想了好久都没有想出来,你可能需要走一走放松放松你的脑子,我学习视频的时候就是发现和视频结果不一样特别是软件配置的问题,要么就百度,要么继续往后学习,你可能就会发现你的问题,可能下个视频就有解决答案,因为我好几次都这样,问题解决答案都在下一个视频展现,不要因为这些代码你看看就会,因为你脑子会了,可能手还不会,所以去练习练习,总会有收获,打这些代码我发费了很多时间,好多都是从下午1点打到下午4点,因为上午要上课,上完课还要把作业个做了,有时候真的很累,俗话说得好趁年轻年轻多吃点苦。还有每天强迫自己花几个小时打打代码,不懂都百度都去学习,可能学习写博客也可以让自己总结能了变得很好,加深印象。在此感谢你坚持看了这么多忍受了我排版的问题,希望一起加油 加油 加油!
2020-4-10 完