Java EE入门(二十一)——Web综合案例
iwehdio的博客园:https://www.cnblogs.com/iwehdio/
1、导入项目
-
项目导入:使用 maven 导入项目,从 maven 创建项目并选择项目的 pom.xml 文件即可。(为了防止报错,先配置maven的阿里云镜像)
-
启动项目:
- 方法一:使用maven加载的Tomcat插件run。
- 方法二:配置maven运行,命令为tomcat7:run。
-
报错:Error: java: 非法字符 '\ufeff'。
-
技术选型:
- Web层:
- Servlet:前端控制器。
- html:视图展示。
- Filter:过滤器。
- BeanUtils:数据封装。
- Jackson:JSON序列化。
- Service层:
- Javamail:使用java发送邮件。
- redis:缓存。
- Jedis:操作redis。
- Dao层:
- Mysql:数据库。
- Druid:数据库连接池。
- JdbcTemplate:jdbc工具。
- Web层:
2、登陆和注册
-
创建数据库:
CREATE DATABASE travel; USE travel; -- 创建表 travl.sql
-
注册功能分析:
- register.html:
- 使用 ajax 完成表单提交。
- 注册成功,跳转到登陆成功页面。
- registUserServlet:
- 获取数据。
- 封装 User 对象。
- 调用 Service 完成注册。
- 根据 Service 的返回提示信息。
- 将提示信息转为 json 。
- 设置响应头 contentType 。
- UserService:
registUser(User user)
注册用户方法。- 调用 Dao 根据用户名查询用户。
- 用户存在则返回 False。
- 用户不存在则调用 Dao 保存用户信息。
- 调用 Dao 根据用户名查询用户。
- UserDao:
findByUsername(String username)
:寻找用户的方法。save(User user)
:保存用户信息。
- register.html:
-
注册功能实现:
-
使用 js 进行表单校验。
-
校验规则:
- 用户名:单词字符,长度8到20位
- 密码:单词字符,长度8到20位
- email:邮件格式
- 姓名:非空
- 手机号:手机号格式
- 出生日期:非空
- 验证码:非空
-
校验用户名:
function chechUsername() { //1、获取用户名 var username = $("username").val(); //2、定义正则 var reg_username = /^\w{8,20}$/; //3、判断,给出提示信息 flag = reg_username.test(username); if(flag) { $("#username").css("border","1px solid red"); } else { $("#username").css("border","1px solid red"); } }
-
校验密码与用户名类似。
-
校验邮箱:
function checkEmail() { var email = $("#email").val(); var reg_email = /^\w+@\w+\.\w+$/; var flag = reg_email.test(email); if(flag) { $("#email").css("border","1px solid red"); } else { $("#email").css("border","1px solid red"); } }
-
表单提交时,调用所有的校验方法:
$(function () { //当表单提交时,调用所有的校验方法 $("#registerForm").submit(function(){ return checkUsername() && checkPassword() && checkEmail(); }); //当某一个组件失去焦点是,调用对应的校验方法 $("#username").blur(checkUsername); $("#password").blur(checkPassword); $("#email").blur(checkEmail); });
-
-
异步提交表单功能实现。
- 使用异步的原因:为了获取服务器响应的数据,而html不能直接从servlet获取域对象数据。
- 如果校验通过,发送 ajax 请求,提交表单的数据(而不是表单)。
$(function () { //当表单提交时,调用所有的校验方法 $("#registerForm").submit(function(){ //1、发送数据到服务器 if(checkUsername() && checkPassword() && checkEmail()) { //2、异步发送请求,内容为序列化的字符串 $.post("registUserServlet",$(this).serialize(),function(data) { //3、处理服务器返回的数据data }); } }); //当某一个组件失去焦点是,调用对应的校验方法 $("#username").blur(checkUsername); $("#password").blur(checkPassword); $("#email").blur(checkEmail); });
-
后台代码实现。
-
编写
registUserSevlet
、UserService
、UserServiceImpl
、UserDao
和UserDaoImpl
。 -
registUserSevlet.java:
@WebServlet("/registUserServlet") public class RegistUserServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //1.获取数据 Map<String, String[]> map = request.getParameterMap(); //2.封装对象 User user = new User(); try { BeanUtils.populate(user,map); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } //3.调用service完成注册 UserService service = new UserServiceImpl(); boolean flag = service.regist(user); ResultInfo info = new ResultInfo(); //4.响应结果 if(flag){ //注册成功 info.setFlag(true); }else{ //注册失败 info.setFlag(false); info.setErrorMsg("注册失败!"); } //将info对象序列化为json ObjectMapper mapper = new ObjectMapper(); String json = mapper.writeValueAsString(info); //将json数据写回客户端 //设置content-type response.setContentType("application/json;charset=utf-8"); response.getWriter().write(json); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } }
-
添加验证码功能:
//验证校验 String check = request.getParameter("check"); //从sesion中获取验证码 HttpSession session = request.getSession(); String checkcode_server = (String) session.getAttribute("CHECKCODE_SERVER"); session.removeAttribute("CHECKCODE_SERVER");//为了保证验证码只能使用一次 //比较 if(checkcode_server == null || !checkcode_server.equalsIgnoreCase(check)){ //验证码错误 ResultInfo info = new ResultInfo(); //注册失败 info.setFlag(false); info.setErrorMsg("验证码错误"); //将info对象序列化为json ObjectMapper mapper = new ObjectMapper(); String json = mapper.writeValueAsString(info); response.setContentType("application/json;charset=utf-8"); response.getWriter().write(json); return; }
-
UserServiceImpl.java:
public class UserServiceImpl implements UserService { private UserDao userDao = new UserDaoImpl(); @Override public boolean regist(User user) { //1.根据用户名查询用户对象 User u = userDao.findByUsername(user.getUsername()); //判断u是否为null if(u != null){ //用户名存在,注册失败 return false; } userDao.save(user); return true; }
-
UserDaoImpl.java:
public class UserDaoImpl implements UserDao { private JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource()); @Override public User findByUsername(String username) { User user = null; try { //1.定义sql String sql = "select * from tab_user where username = ?"; //2.执行sql user = template.queryForObject(sql, new BeanPropertyRowMapper<User>(User.class), username); } catch (Exception e) { } //这是因为如果查询不到不会返回null,而是直接报错,所以需要处理 return user; } @Override public void save(User user) { //1.定义sql String sql = "insert into tab_user(username,password,name,birthday,sex,telephone,email,status,code) values(?,?,?,?,?,?,?,?,?)"; //2.执行sql template.update(sql,user.getUsername(), user.getPassword(), user.getName(), user.getBirthday(), user.getSex(), user.getTelephone(), user.getEmail(), user.getStatus(), user.getCode() ); } }
-
前台处理服务器返回数据:
if(data.flag){ //注册成功,跳转成功页面 location.href="register_ok.html"; }else{ //注册失败,给errorMsg添加提示信息 $("#errorMsg").html(data.errorMsg);
-
邮件激活:
-
发送邮件:使用邮件工具类。
-
用户激活:其实就是把数据库中的激活状态由N改为Y。
-
激活码:使用UUID工具类。
-
在
UserServiceImpl
下的regist
函数中,注册时同时生成唯一字符串并且发送邮件://2.1设置激活码,唯一字符串 user.setCode(UuidUtil.getUuid()); //2.2设置激活状态 user.setStatus("N"); userDao.save(user); //3.激活邮件发送,邮件正文? String content="<a href='http://localhost/travel/activeUserServlet?code="+user.getCode()+"'>点击激活【黑马旅游网】</a>"; MailUtils.sendMail(user.getEmail(),content,"激活邮件");
-
点击超链接完成激活:
-
ActiveUserServlet
:@WebServlet("/activeUserServlet") public class ActiveUserServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //1.获取激活码 String code = request.getParameter("code"); if(code != null){ //2.调用service完成激活 UserService service = new UserServiceImpl(); boolean flag = service.active(code); //3.判断标记 String msg = null; if(flag){ //激活成功 msg = "激活成功,请<a href='login.html'>登录</a>"; }else{ //激活失败 msg = "激活失败,请联系管理员!"; } response.setContentType("text/html;charset=utf-8"); response.getWriter().write(msg); } } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } }
-
UserServiceImpl
中的active
方法:@Override public boolean active(String code) { //1.根据激活码查询用户对象 User user = userDao.findByCode(code); if(user != null){ //2.调用dao的修改激活状态的方法 userDao.updateStatus(user); return true; }else{ return false; } }
-
UserDaoImpl
中的findByCode
和updateStatus
方法:@Override public User findByCode(String code) { User user = null; try { String sql = "select * from tab_user where code = ?"; user = template.queryForObject(sql,new BeanPropertyRowMapper<User>(User.class),code); } catch (DataAccessException e) { e.printStackTrace(); } return user; } @Override public void updateStatus(User user) { String sql = " update tab_user set status = 'Y' where uid=?"; template.update(sql,user.getUid()); }
-
-
-
-
-
登陆功能分析:
- login.html:
- 输入账号和密码。
- LoginServlet:
- 获取用户信息。
- 调用 service 查询 user。
- 判断用户是否存在。
- 判断用户是否激活。
- 响应错误信息。
- UserService:
login
方法,接收用户名和密码,返回真正的User对象。
- UserDao:
- 根据用户名和密码查询用户。
- login.html:
-
登陆功能实现:
-
后台代码实现。
-
loginServlet.java:
@WebServlet("/loginServlet") public class LoginServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //1.获取用户名和密码数据 Map<String, String[]> map = request.getParameterMap(); //2.封装User对象 User user = new User(); try { BeanUtils.populate(user,map); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } //3.调用Service查询 UserService service = new UserServiceImpl(); User u = service.login(user); ResultInfo info = new ResultInfo(); //4.判断用户对象是否为null if(u == null){ //用户名密码或错误 info.setFlag(false); info.setErrorMsg("用户名密码或错误"); } //5.判断用户是否激活 if(u != null && !"Y".equals(u.getStatus())){ //用户尚未激活 info.setFlag(false); info.setErrorMsg("您尚未激活,请激活"); } //6.判断登录成功 if(u != null && "Y".equals(u.getStatus())){ request.getSession().setAttribute("user",u);//登录成功标记 //登录成功 info.setFlag(true); } //响应数据 ObjectMapper mapper = new ObjectMapper(); response.setContentType("application/json;charset=utf-8"); mapper.writeValue(response.getOutputStream(),info); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } }
-
UserService
中的login
方法:@Override public User login(User user) { return userDao.findByUsernameAndPassword(user.getUsername(),user.getPassword()); }
-
UserDao
中的findByUsernameAndPassword
方法:@Override public User findByUsernameAndPassword(String username, String password) { User user = null; try { //1.定义sql String sql = "select * from tab_user where username = ? and password = ?"; //2.执行sql user = template.queryForObject(sql, new BeanPropertyRowMapper<User>(User.class), username,password); } catch (Exception e) { } return user; }
-
-
前台代码实现。
-
给登陆按钮绑定单击事件,发送 ajax 请求提交表单数据,处理响应结果。
-
login.html:
<script> $(function () { //1.给登录按钮绑定单击事件 $("#btn_sub").click(function () { //2.发送ajax请求,提交表单数据 $.post("loginServlet",$("#loginForm").serialize(),function (data) { //data : {flag:false,errorMsg:''} if(data.flag){ //登录成功 location.href="index.html"; }else{ //登录失败 $("#errorMsg").html(data.errorMsg); } }); }); }); //3.处理响应结果 //写在header.html中 </script>
-
-
index 页面提示用户名:
-
header.html:
<script> $(function () { $.get("findUserServlet",{},function (data) { //{uid:1,name:'李四'} var msg = "欢迎回来,"+data.name; $("#span_username").html(msg); }); }); </script>
-
findUserServlet.java:
@WebServlet("/findUserServlet") public class FindUserServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //从session中获取登录用户 Object user = request.getSession().getAttribute("user"); //将user写回客户端 ObjectMapper mapper = new ObjectMapper(); response.setContentType("application/json;charset=utf-8"); mapper.writeValue(response.getOutputStream(),user); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } }
-
-
-
退出功能分析:
- 登陆就是 session 中有 user 对象,退出就是销毁session 中的 user 对象。
- 跳转到登陆页面。
-
退出代码实现:
-
前台代码实现。
-
点击退出,跳转到
exitServlet
。<a href="javascript:location.href='exitServlet';">退出</a>
-
-
后台代码实现。
-
ExitServlet.java:
@WebServlet("/exitServlet") public class ExitServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //1.销毁session request.getSession().invalidate(); //2.跳转登录页面 response.sendRedirect(request.getContextPath()+"/login.html"); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } }
-
-
-
抽取 BaseServlet:
-
减少 Servlet 的数量,优化为一个模块一个 Servlet ,数据库中一个表一个 Servlet 。
-
在一个 Servlet 中写不同的方法。
-
这些 Servlet 都继承自 BaseServlet ,BaseServlet 进行方法分发,继承自 HttpServlet 。
- 获取请求路径。
- 获取方法名称。
- 获取方法对象(反射)。
- 执行方法。
-
BaseServlet.java:
public class BaseServlet extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //完成方法分发 //1.获取请求路径 String uri = req.getRequestURI(); // /travel/user/add System.out.println("请求uri:"+uri);// /travel/user/add //2.获取方法名称 String methodName = uri.substring(uri.lastIndexOf('/') + 1); System.out.println("方法名称:"+methodName); //3.获取方法对象Method //谁调用我?我代表谁 System.out.println(this);//UserServlet的对象cn.itcast.travel.web.servlet.UserServlet@4903d97e try { //获取方法 Method method = this.getClass().getMethod(methodName, HttpServletRequest.class, HttpServletResponse.class); //4.执行方法 //暴力反射 //method.setAccessible(true); method.invoke(this,req,resp); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } }
-
-
UserServlet.java:
@WebServlet("/user/*") // /user/add /user/find public class UserServlet extends BaseServlet { //声明UserService业务对象 private UserService service = new UserServiceImpl(); //注册功能 public void regist(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { /* 方法体 */ } }
3、旅游信息
-
分类数据展示功能分析:
- 前台功能:
- 发送 ajax 请求,访问服务器,加载真正的分类数据。
- 遍历数组完成展示。
- Servlet:
- 调用 Service 查询,获取 List。
- 将List集合序列化为 Json 。
- 前台功能:
-
分类数据展示实现:
-
后台代码实现。
-
categoryDao.java:
public class CategoryDaoImpl implements CategoryDao { private JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource()); @Override public List<Category> findAll() { String sql = "select * from tab_category "; return template.query(sql,new BeanPropertyRowMapper<Category>(Category.class)); } }
-
categoryService.java:
public class CategoryServiceImpl implements CategoryService { private CategoryDao categoryDao = new CategoryDaoImpl(); @Override public List<Category> findAll() { return categoryDao.findAll(); } }
-
将对 Json 的转换操作抽取到 BaseServlet 中:
//直接将传入的对象序列化为json,并且写回客户端 public void writeValue(Object obj,HttpServletResponse response) throws IOException { ObjectMapper mapper = new ObjectMapper(); response.setContentType("application/json;charset=utf-8"); mapper.writeValue(response.getOutputStream(),obj); } //传入的对象序列化为json,返回 public String writeValueAsString(Object obj) throws JsonProcessingException { ObjectMapper mapper = new ObjectMapper(); return mapper.writeValueAsString(obj); }
-
CategoryServlet.java:
@WebServlet("/category/*") public class CategoryServlet extends BaseServlet { private CategoryService service = new CategoryServiceImpl(); //查询所有 public void findAll(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //1.调用service查询所有 List<Category> cs = service.findAll(); //2.序列化json返回 ObjectMapper mapper = new ObjectMapper(); response.setContentType("application/json;charset=utf-8"); mapper.writeValue(response.getOutputStream(),cs); //writeValue(cs,response); } }
-
-
前台代码实现。
-
header.html加载后,发送请求到 category/findAll,根据返回的响应进行显示。
//查询分类数据 $.get("category/findAll",{},function (data) { //[{cid:1,cname:国内游},{},{}]
var lis = '
'; -
- )
for (var i = 0; i < data.length; i++) {
var li = ' - <a href="route_list.html>'+data[i].cname+' ';
- 收藏排行榜
- 收藏排行榜 ';
-
Redis 优化。
-
分类数据每次页面加载后都会重新请求数据库,而且分类的数据不经常变化,可以使用 Redis。
-
先从 redis 中查询,判断集合是否为空,不为空则显示,为空则查询数据库并存入redis。
-
CategoryService.java:
public class CategoryServiceImpl implements CategoryService { private CategoryDao categoryDao = new CategoryDaoImpl(); @Override public List<Category> findAll() { //1.从redis中查询 //1.1获取jedis客户端 Jedis jedis = JedisUtil.getJedis(); //1.2可使用sortedset排序查询 Set<String> categorys = jedis.zrange("category", 0, -1); List<Category> cs = null; //2.判断查询的集合是否为空 if (categorys == null || categorys.size() == 0) { //System.out.println("从数据库查询...."); //3.如果为空,需要从数据库查询,在将数据存入redis //3.1 从数据库查询 cs = categoryDao.findAll(); //3.2 将集合数据存储到redis中的 category的key for (int i = 0; i < cs.size(); i++) { jedis.zadd("category", cs.get(i).getCid(), cs.get(i).getCname()); } } else { //System.out.println("从redis中查询....."); //4.如果不为空,将set的数据存入list cs = new ArrayList<Category>(); for (String name : categorys) { Category category = new Category(); category.setCname(name); cs.add(category); } } return cs; } }
-
//遍历数组,拼接字符串(
lis += li;
}//拼接收藏排行榜的li,
lis+= '
//将lis字符串,设置到ul的html内容中
$("#category").html(lis);
}); -
-
分页数据展示分析:
-
点击不同的分类后,看到的旅游线路是不一样的。旅游线路表和分类表是多对一的关系,查询分类数据时要传入对应的分类id即 cid。
-
分页的实现:
- 分页对象封装到
PageBean
对象中,需要总记录数、总页数、当前页码、每页显示的条数和每一页展示的数据。- 总记录数和每页展示数据的集合是需要从数据库查询的。
- 请求时,需要携带当前页码、每页显示的条数和分类的cid。
- 响应时,将
PageBean
对象序列化Json返回到html。
- 分页对象封装到
-
路线图片通过查询 route_img 表,路线信息查询 route 表,经营信息查询 seller 表,价格查询 route 表。
-
RouteServlet
接收页码 rid,调用 service 查询后转换为 json 返回。 -
RouteService
根据 id 查询 route 对象;根据 rid 线路 id 查询 tab_route_img ,将结果设置到 route 对象;根据 sid 卖家 id 查询 tab_seller ,将结果设置到 route 对象。 -
Dao 层分别实现
RouteDao
、RouteImgDao
和SellerDao
。
-
-
分页数据展示实现:
-
前台 header.html 在点击分类时传入分类 cid:
var li = '<li><a href="route_list.html?cid='+data[i].cid+'">'+data[i].cname+'</a></li>';
-
后台 Redis 查询时,之前只查询了值,没有查询分数(cid),现在还需要查询分数:
//同时查询分数和值 Set<Tuple> categorys = jedis.zrangeWithScores("category", 0, -1); //从redis中查询数据 cs = new ArrayList<Category>(); for (Tuple tuple : categorys) { Category category = new Category(); category.setCname(tuple.getElement()); category.setCid((int) tuple.getScore()); cs.add(category); }
-
分页的后台实现:
-
PageBean.java:
public class PageBean<T> { private int totalCount;//总记录数 private int totalPage;//总页数 private int currentPage;//当前页码 private int pageSize;//每页显示的条数 private List<T> list;//每页显示的数据集合 /* getter & setter */ }
-
RouteServlet.java:
@WebServlet("/route/*") public class RouteServlet extends BaseServlet { private RouteService routeService = new RouteServiceImpl(); //分页查询 public void pageQuery(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //1.接受参数 String currentPageStr = request.getParameter("currentPage"); String pageSizeStr = request.getParameter("pageSize"); String cidStr = request.getParameter("cid"); //接受rname 线路名称 String rname = request.getParameter("rname"); rname = new String(rname.getBytes("iso-8859-1"),"utf-8"); int cid = 0;//类别id //2.处理参数 if(cidStr != null && cidStr.length() > 0 && !"null".equals(cidStr)){ cid = Integer.parseInt(cidStr); } int currentPage = 0;//当前页码,如果不传递,则默认为第一页 if(currentPageStr != null && currentPageStr.length() > 0){ currentPage = Integer.parseInt(currentPageStr); }else{ currentPage = 1; } int pageSize = 0;//每页显示条数,如果不传递,默认每页显示5条记录 if(pageSizeStr != null && pageSizeStr.length() > 0){ pageSize = Integer.parseInt(pageSizeStr); }else{ pageSize = 5; } //3. 调用service查询PageBean对象 PageBean<Route> pb = routeService.pageQuery(cid, currentPage, pageSize,rname); //4. 将pageBean对象序列化为json,返回 writeValue(pb,response); } }
-
-
-
RouteDao.java:
public class RouteDaoImpl implements RouteDao { JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource()); @Override public int findTotalCount(int cid) { String sql = "select count(*) from tab_route where cid = ?"; return template.queryForObject(sql, Integer.class, cid); } @Override public List<Route> findByPage(int cid, int start, int pageSize) { String sql = "select * from tab_route where cid = ? limit ?, ?"; return template.query(sql, new BeanPropertyRowMapper<Route>(Route.class), cid, start, pageSize); } }
-
RouteService.java:
public class RouteServiceImpl implements RouteService { private RouteDao routeDao = new RouteDaoImpl(); @Override public PageBean<Route> pageQuery(int cid, int currentPage, int pageSize) { PageBean<Route> pb = new PageBean<Route>(); pb.setCurrentPage(currentPage); pb.setPageSize(pageSize); int totalCount = routeDao.findTotalCount(cid); pb.setTotalCount(totalCount); int start = (currentPage - 1) * pageSize; List<Route> list = routeDao.findByPage(cid, start, pageSize); pb.setList(list); int totalPage = totalCount % pageSize == 0 ? totalCount/pageSize : (totalCount/pageSize)+1; pb.setTotalPage(totalPage); return pb; } }
-
前台代码实现:
-
route_list.html:
<script> $(function () { /* var search = location.search; //alert(search);//?id=5 // 切割字符串,拿到第二个值 var cid = search.split("=")[1];*/ //获取cid的参数值 var cid = getParameter("cid"); //获取rname的参数值 var rname = getParameter("rname"); //判断rname如果不为null或者"" if(rname){ //url解码 rname = window.decodeURIComponent(rname); } //当页码加载完成后,调用load方法,发送ajax请求加载数据 load(cid,null,rname); }); function load(cid ,currentPage,rname){ //发送ajax请求,请求route/pageQuery,传递cid $.get("route/pageQuery",{cid:cid,currentPage:currentPage,rname:rname},function (pb) { //解析pagebean数据,展示到页面上 //1.分页工具条数据展示 //1.1 展示总页码和总记录数 $("#totalPage").html(pb.totalPage); $("#totalCount").html(pb.totalCount); var lis = ""; var fristPage = '<li onclick="javascipt:load('+cid+',1,\''+rname+'\')"><a href="javascript:void(0)">首页</a></li>'; //计算上一页的页码 var beforeNum = pb.currentPage - 1; if(beforeNum <= 0){ beforeNum = 1; } var beforePage = '<li onclick="javascipt:load('+cid+','+beforeNum+',\''+rname+'\')" class="threeword"><a href="javascript:void(0)">上一页</a></li>'; lis += fristPage; lis += beforePage; //1.2 展示分页页码 /* 1.一共展示10个页码,能够达到前5后4的效果 2.如果前边不够5个,后边补齐10个 3.如果后边不足4个,前边补齐10个 */ // 定义开始位置begin,结束位置 end var begin; // 开始位置 var end ; // 结束位置 //1.要显示10个页码 if(pb.totalPage < 10){ //总页码不够10页 begin = 1; end = pb.totalPage; }else{ //总页码超过10页 begin = pb.currentPage - 5 ; end = pb.currentPage + 4 ; //2.如果前边不够5个,后边补齐10个 if(begin < 1){ begin = 1; end = begin + 9; } //3.如果后边不足4个,前边补齐10个 if(end > pb.totalPage){ end = pb.totalPage; begin = end - 9 ; } } for (var i = begin; i <= end ; i++) { var li; //判断当前页码是否等于i if(pb.currentPage == i){ li = '<li class="curPage" onclick="javascipt:load('+cid+','+i+',\''+rname+'\')"><a href="javascript:void(0)">'+i+'</a></li>'; }else{ //创建页码的li li = '<li onclick="javascipt:load('+cid+','+i+',\''+rname+'\')"><a href="javascript:void(0)">'+i+'</a></li>'; } //拼接字符串 lis += li; } var lastPage = '<li class="threeword"><a href="javascript:;">末页</a></li>'; var nextPage = '<li class="threeword"><a href="javascript:;">下一页</a></li>'; lis += nextPage; lis += lastPage; //将lis内容设置到 ul $("#pageNum").html(lis); //2.列表数据展示 var route_lis = ""; for (var i = 0; i < pb.list.length; i++) { //获取{rid:1,rname:"xxx"} var route = pb.list[i]; var li = '<li>\n' + ' <div class="img"><img src="'+route.rimage+'" style="width: 299px;"></div>\n' + ' <div class="text1">\n' + ' <p>'+route.rname+'</p>\n' + ' <br/>\n' + ' <p>'+route.routeIntroduce+'</p>\n' + ' </div>\n' + ' <div class="price">\n' + ' <p class="price_num">\n' + ' <span>¥</span>\n' + ' <span>'+route.price+'</span>\n' + ' <span>起</span>\n' + ' </p>\n' + ' <p><a href="route_detail.html?rid='+route.rid+'">查看详情</a></p>\n' + ' </div>\n' + ' </li>'; route_lis += li; } $("#route").html(route_lis); //定位到页面顶部 window.scrollTo(0,0); }); } </script>
-
-
4、查询、详情与收藏
-
查询功能传递参数:
-
给搜索按钮加 id 属性。
-
header.html搜索按钮绑定单击事件。
<script src="js/getParameter.js"></script> <script> $("#search_button").click(function () { var rname = $("#search_input").val(); var cid = getParameter("cid"); location.href = "http://localhost/travel/route_list.html?cid="+cid+"&rname="+rname; }) </script>
-
route_list.html中传递参数:
$(function () { /* var search = location.search; //alert(search);//?id=5 // 切割字符串,拿到第二个值 var cid = search.split("=")[1];*/ //获取cid的参数值 var cid = getParameter("cid"); //获取rname的参数值 var rname = getParameter("rname"); //判断rname如果不为null或者"" if(rname){ //url解码 rname = window.decodeURIComponent(rname); } });
-
-
查询功能的后台代码:
-
RouteServlet:
- 获取 rname参数。
-
RouteService:
- pageQuery方法增加一个参数 rname。
-
RouteDao:
- findTotalCount和findByPage增加一个参数 rname。
@Override public int findTotalCount(int cid, String rname) { String sql = "select count(*) from tab_route where 1=1 "; StringBuilder sb = new StringBuilder(sql); List params = new ArrayList(); if(cid!=0){ sb.append(" and cid= ?"); params.add(cid); } if(rname!=null && rname.length()>0){ sb.append(" and rname like ?"); params.add("%"+rname+"%"); } sql = sb.toString(); System.out.println(sql); System.out.println(params); return template.queryForObject(sql, Integer.class, params.toArray()); } @Override public List<Route> findByPage(int cid, int start, int pageSize, String rname) { String sql = "select * from tab_route where 1=1 "; StringBuilder sb = new StringBuilder(sql); List params = new ArrayList(); if(cid!=0){ sb.append(" and cid=?"); params.add(cid); } if(rname!=null && rname.length()>0){ sb.append(" and rname like?"); params.add("%"+rname+"%"); } sb.append(" limit ?, ?"); params.add(start); params.add(pageSize); sql = sb.toString(); return template.query(sql, new BeanPropertyRowMapper<Route>(Route.class), params.toArray()); }
-
-
查询功能的前台代码:
- 处理 route_list.html中的load函数的参数问题。
- 分页代码中拼接rname。
-
线路详情:
- 按照rid查询route_img表。
- 按照sid查询route_seller表。
- 其他查询route_list表。
-
线路详情后台代码:
-
RouteServlet:
public void findOne(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String rid = request.getParameter("rid"); Route route = service.findOne(rid); writeValue(route, response); }
-
RouteDaoImpl:
public Route findOne(int rid) { String sql = "select * from tab_route where rid = ?"; return template.queryForObject(sql, new BeanPropertyRowMapper<Route>(Route.class), rid); }
-
RouteImgDaoImpl:
public List<RouteImg> findImg(int rid) { String sql = "select * from tab_route_img where rid = ?"; return template.query(sql, new BeanPropertyRowMapper<RouteImg>(RouteImg.class), rid); }
-
SellerDaoImpl:
public Seller findSeller(int sid) { String sql = "select * from tab_seller where sid = ?"; return template.queryForObject(sql, new BeanPropertyRowMapper<Seller>(Seller.class),sid); }
-
-
线路详情前台代码:
-
Route_detail.html:
$(function () { var rid = getParameter("rid"); $.get("route/findOne",{rid:rid},function (route) { $("#rname").html(route.rname); $("#routeIntroduce").html(route.routeIntroduce); $("#price").html("¥"+route.price); $("#sname").html(route.seller.sname); $("#consphone").html(route.seller.consphone); $("#address").html(route.seller.address); var ddstr = '<a class="up_img up_img_disable"></a>'; for (var i = 0; i < route.routeImgList.length; i++) { var astr ; if(i >= 4){ astr = '<a title="" class="little_img" data-bigpic="'+route.routeImgList[i].bigPic+'" style="display:none;">\n' + '<img src="'+route.routeImgList[i].smallPic+'">\n' + '</a>'; }else{ astr = '<a title="" class="little_img" data-bigpic="'+route.routeImgList[i].bigPic+'">\n' + '<img src="'+route.routeImgList[i].smallPic+'">\n' + '</a>'; } ddstr += astr; } ddstr+='<a class="down_img down_img_disable" style="margin-bottom: 0;"></a>'; $("#dd").html(ddstr); goImg(); });
-
-
旅游线路收藏分析:
- 页面加载完后,发送ajax请求,获取用户是否收藏的标记。传递rid。格局标记展示不同的按钮样式。
- Servlet获取rid和当前用户对象,查询favorite表中有无此记录。数据标记写回客户端。
- 点击按钮是,发送ajax请求判断用户是否登陆。如果没有登录则提示登录。
- 登录后,添加收藏数据到数据库。
-
线路收藏后台代码:
-
显示按钮和收藏次数:
-
RouteServlet:
public void isFavorite(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String rid = request.getParameter("rid"); User user = (User) request.getSession().getAttribute("user"); int uid; if(user == null){ uid = 0; }else{ uid = user.getUid(); } boolean flag = favoriteService.isFavorite(rid, uid); writeValue(flag,response); }
-
favoriteService:
public boolean isFavorite(String rid, int uid) { Favorite favorite = favoriteDao.findByRidAndUid(Integer.parseInt(rid), uid); return favorite != null; }
-
favoriteDao:
public Favorite findByRidAndUid(int rid, int uid) { Favorite favorite = null; try { String sql = " select * from tab_favorite where rid = ? and uid = ?"; favorite = template.queryForObject(sql, new BeanPropertyRowMapper<Favorite>(Favorite.class), rid, uid); } catch (DataAccessException e) { e.printStackTrace(); } return favorite; } public int findCountByRid(int rid) { String sql = "SELECT COUNT(*) FROM tab_favorite WHERE rid = ?"; return template.queryForObject(sql,Integer.class,rid); }
-
点击按钮收藏:
-
RouteServlet:
public void addFavorite(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String rid = request.getParameter("rid"); User user = (User) request.getSession().getAttribute("user"); int uid;/ if(user == null){ return ; }else{ uid = user.getUid(); } favoriteService.add(rid,uid); }
-
favoriteService:
public void add(String rid, int uid) { favoriteDao.add(Integer.parseInt(rid),uid); }
-
favoriteDao:
public void add(int rid, int uid) { String sql = "insert into tab_favorite values(?,?,?)"; template.update(sql,rid,new Date(),uid); }
-
-
线路收藏的前台代码:
-
显示按钮和收藏次数:
$(function () { var rid = getParameter("rid"); $.get("route/isFavorite",{rid:rid},function (flag) { if(flag){ $("#favorite").addClass("already"); $("#favorite").attr("disabled","disabled"); $("#favorite").removeAttr("onclick"); }else{ } }); });
-
点击按钮添加:
function addFavorite(){ var rid = getParameter("rid"); $.get("user/findOne",{},function (user) { if(user){ $.get("route/addFavorite",{rid:rid},function () { location.reload(); }); }else{ alert("您尚未登录,请登录"); location.href="http://localhost/travel/login.html"; } }) }
-
iwehdio的博客园:https://www.cnblogs.com/iwehdio/