0


毕业设计——基于SSM+Mysql构建的完整在线旅游网站项目

基于SSM+Mysql构建的完整在线旅游网站项目

完整项目地址:https://download.csdn.net/download/lijunhcn/88430527

1、主要功能

实现旅游网

2、主要知识点

(1)目标
能正确理解分析旅游网功能需求;
能正确创建数据库和表;
能理解并熟练搭建SSM环境;
掌握基于SSM进行相关功能操作;
结合以前所学能灵活综合运用到项目中;
积累项目案例经验。
(2)任务
搭建SSM环境;
完成数据库和表的创建并添加测试数据;
完成旅游网相关功能。
(3)功能说明
主要功能概述
旅游网主要有以下八大功能需求:
    登录功能;
    注册功能;
    邮件处理;
    分类数据;
    线路分页;
    线路查询;
    线路详情;
    线路收藏。
(4)数据库表
(5)功能操作
1.环境搭建
导入数据库表及相关测试数据;
导入基础的素材(前端后台)。
2.注册功能
去注册页面

a、页面—在header.jsp里面添加这个超链接

<a href="toRegPage.do">注册</a>

b、控制层—在UserController.java中

@RequestMapping("/toRegPage.do")
public String toRegPage() {
    return "register";
}
验证输入的合法性
a、验证规则

用户名:不为空且由数字、字母、下划线组成的6-10个字符,不符合要求给出提示信息
密码:不为空且由数字、字母、下划线组成的6-15个字符,不符合要求给出提示信息
姓名:非空,不符合要求给出提示信息
出生日期:非空,不符合要求给出提示信息
邮箱:不为空且要合法,不符合要求给出提示信息
手机号:不为空且由11位符合规则的数字组成,不符合要求给出提示信息

b、验证时机-register.jsp

提交表单时

//点击时验证
$("#btn1").click(function(){
    $("#registerForm").submit(function(){
        return checkUname() && checkEmail() && checkPhone() &&checkPwd() && checkName() &&checkBirth();
    });
});

离开焦点时

//离开时验证
$("#username").blur(checkUname);
$("#email").blur(checkEmail);
$("#telephone").blur(checkPhone);
$("#password").blur(checkPwd);
$("#name").blur(checkName);
$("#birthday").blur(checkBirth);

验证代码

//验证用户名
function checkUname(){
    var uname=$("#username").val();
    //正则表达式
    var reg=/^\w{6,10}$/;
    if(!reg.test(uname)){
        //加红色,实线边框
        $("#username").css("border","1px solid red");
        $("#msg").html("用户名不能为空且由不为空且由数字、字母、下划线组成的6-10个字符!");
        return false;
    }
    //清空红色实线边框
    $("#username").css("border","");
    //清空消息
    $("#msg").html("");
    //发送ajax请求
    $.post("checkUname.do",{"username":uname},function(res){
        if(res=="false"){
            //加红色,实线边框
            $("#username").css("border","1px solid red");
            $("#msg").html("用户名重复不可用!");
            return false;
        }else{
            //清空红色实线边框
            $("#username").css("border","");
            //清空消息
            $("#msg").html("");
            return true;
        }
    })
    return true;
}
//验证邮箱
function checkEmail(){
    var email=$("#email").val();
    //邮箱正则表达式[email protected]
    var reg=/^[a-z0-9]{3,12}@[a-z0-9]{2,6}\.com$/;
    if(!reg.test(email)){
        //加红色,实线边框
        $("#email").css("border","1px solid red");
        $("#msg").html("邮箱不为空且要合法!");
        return false;
    }
    //清空红色实线边框
    $("#email").css("border","");
    //清空消息
    $("#msg").html("");
    return true;
}
//验证手机号
function checkPhone(){
    var telephone=$("#telephone").val();
    //手机号正则表达式
    var reg=/^1[356789]\d{9}$/;
    if(!reg.test(telephone)){
        //加红色,实线边框
        $("#telephone").css("border","1px solid red");
        $("#msg").html("手机号不为空且由11位符合规则的数字组成!");
        return false;
    }
    //清空红色实线边框
    $("#telephone").css("border","");
    //清空消息
    $("#msg").html("");
    return true;
}
//验证密码
function checkPwd(){
    var password=$("#password").val();
    //密码正则表达式
    var reg=/^\w{6,15}$/;
    if(!reg.test(password)){
        //加红色,实线边框
        $("#password").css("border","1px solid red");
        $("#msg").html("手机号不为空且由11位符合规则的数字组成!");
        return false;
    }
    //清空红色实线边框
    $("#password").css("border","");
    //清空消息
    $("#msg").html("");
    return true;
}
//验证姓名
function checkName(){
    var name=$("#name").val();
    if(name.length==0){
        //加红色,实线边框
        $("#name").css("border","1px solid red");
        $("#msg").html("姓名为必填项!");
        return false;
    }
    //清空红色实线边框
    $("#name").css("border","");
    //清空消息
    $("#msg").html("");
    return true;
}
//验证出生日期
function checkBirth(){
    var birthday=$("#birthday").val();
    if(birthday.length==0){
        //加红色,实线边框
        $("#birthday").css("border","1px solid red");
        $("#msg").html("出生日期为必填项!");
        return false;
    }
    //清空红色实线边框
    $("#birthday").css("border","");
    //清空消息
    $("#msg").html("");
    return true;
}
用户名合法性

用户名通过验证要发送异步Ajax请求-从后台验证用户名是否重复

数据层-UserMapper.java
/**
 * 根据用户名查询该用户
 */
@Select("select * from tab_user where username=#{username}")
User selectByUname(String username);
业务层接口-UserService.java
boolean checkUname(String username);
业务层实现-在UserServiceImpl.java中重写以下方法
@Override
public boolean checkUname(String username) {
    User user = uMapper.selectByUname(username);
    if (user != null) {
        return false;
    } else {
        return true;
    }
}
控制层-UserController.java
/**
 * 验证用户名是否重复
 */
@RequestMapping("/checkUname.do")
public String checkUserName(String username) {
    boolean flag = uService.checkUname(username);
    if (!flag) {
        // 用户名重复,返回false
        return "false";
    } else {
        return "true";
    }
}
表示层-在register.jsp的验证用户名中发送ajax请求部分
//发送ajax请求
$.post("checkUname.do",{"usernane":uname},function(res){
    if(res=="false"){
        //加红色,实线边框
        $("#username").css("border","1px solid red");
        $("#msg").html("用户名重复不可用!");
        return false;
    }else{
        //清空红色实线边框
        $("#username").css("border","");
        //清空消息
        $("#msg").html("");
        return true;
    }
})
保存数据
页面情况-register.jsp
<form id="registerForm" action="doReg.do" method="post">
数据层-UserMapper.java
/**
 * 增加用户-点击注册,增加数据到数据库中
 * 
 * @param user
 * @return
 */
int addUser(User user);
映射文件-/TravelProject/src/com/zk/dao/UserMapper.xml
<!-- 增加用户|注册 -->
<insert id="addUser" useGeneratedKeys="true" keyProperty="uid">
    insert into
    tab_user(username,password,name,birthday,sex,telephone,email,status,code)
    values(#{username},#{password},#{name},#{birthday},#{sex},#{telephone},#{email},#{status},#{code})
</insert>
业务层接口-/TravelProject/src/com/zk/service/UserService.java
/**
 * 只是关心是否增加成功,不关心是如何增加的
 * 
 * @return
 */
boolean registerUser(User user);
业务层实现-/TravelProject/src/com/zk/service/impl/UserServiceImpl.java
@Transactional
public boolean registerUser(User user) {
    // 生成随机的激活码
    user.setCode(UuidUtil.getUuid());
    // 设置用户激活状态为N-未激活
    user.setStatus("N");
    int num = uMapper.addUser(user);
    if (num > 0) {
        return true;
    }
    return false;
}
控制层-/TravelProject/src/com/zk/controller/UserController.java
/**
 * 注册功能
 * 
 * @param user
 * @return
 */
@RequestMapping("/doReg.do")
public ModelAndView doReg(User user) {
    ModelAndView mv = new ModelAndView();
    boolean flag = uService.registerUser(user);
    if (flag) {
        // 注册成功-去注册成功页面
        mv.setViewName("register_ok");
    } else {
        // 注册失败-重新回到注册页面
        mv.setViewName("register");
        mv.addObject("msg", "注册失败");
    }
    return mv;
}
注册失败页面-在/TravelProject/WebContent/WEB-INF/jsp/register.jsp页面注册按钮下
<!-- 提示信息 -->
<tr>
    <td class="td_left"></td>
    <td class="td_right">
        <span id="msg" style="color: red;">${msg==null?'':msg}</span>
    </td>
</tr>
3.邮件处理
邮箱设置-/TravelProject/src/com/zk/utils/MailUtils.java

例如:登录自己申请的QQ邮箱,在”设置-账户-POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务中开启POP3/SMTP服务“;然后在MailUtils中设置自己的邮箱账号和密码(授权码)。

// 发件人邮箱地址-一般为企业邮箱
private static final String USER = "[email protected]";
// 如果是qq邮箱使用客户端授权码,163邮箱的话就是开启客户端授权码
private static final String PASSWORD = "xxx";
发送邮件-在/TravelProject/src/com/zk/service/impl/UserServiceImpl.java中添加邮件发送代码
@Transactional
public boolean registerUser(User user) {
    // 生成随机的激活码
    user.setCode(UuidUtil.getUuid());
    // 设置用户激活状态为N-未激活
    user.setStatus("N");
    int num = uMapper.addUser(user);
    if (num > 0) {
        // 用户的信息已经保存到数据库中
        String context = "<a href='http://localhost:8080/TravelProject/activeMail.do?code=" + user.getCode()
            + "'>点击激活旅游网</a>";
        // 发件人邮箱-发送的内容-发送的标题
        MailUtils.sendMail(user.getEmail(), context, "旅游网激活邮件");
        return true;
    }
    return false;
}
4.邮件激活
数据层-/TravelProject/src/com/zk/dao/UserMapper.java
/**
 * 根据激活码查询用户
 * 
 * @param code
 * @return
 */
@Select("select * from tab_user where code=#{code}")
User selectByCode(String code);
/**
 * 更新用户信息
 * 
 * @param user
 * @return
 */
int updateUser(User user);
映射文件-/TravelProject/src/com/zk/dao/UserMapper.xml
<!-- 更新用户信息 -->
<update id="updateUser" parameterType="user">
    update tab_user
    <set>
        <if test="username!=null and username!=''">username=#{username},</if>
        <if test="password!=null and password!=''">password=#{password},</if>
        <if test="name!=null and name!=''">name=#{name},</if>
        <if test="birthday!=null and birthday!=''">birthday=#{birthday},</if>
        <if test="sex!=null and sex!=''">sex=#{sex},</if>
        <if test="telephone!=null and telephone!=''">telephone=#{telephone},</if>
        <if test="email!=null and email!=''">email=#{email},</if>
        <if test="status!=null and status!=''">status=#{status},</if>
        <if test="code!=null and code!=''">code=#{code}</if>
    </set>
    where uid=#{uid}
</update>
业务接口-/TravelProject/src/com/zk/service/UserService.java
/**
 * 激活用户
 * 
 * @param user
 * @return
 */
boolean activeUser(String code);
业务实现-/TravelProject/src/com/zk/service/impl/UserServiceImpl.java
@Transactional
public boolean activeUser(String code) {
    User user = uMapper.selectByCode(code);
    // 注册了也就是有这个用户存在-去激活-返回true
    if (user != null) {
        // 设置激活状态为Y
        user.setStatus("Y");
        // 更新激活状态为Y
        if (uMapper.updateUser(user) > 0) {
            return true;
        } else {
            return false;
        }
    }
    return false;
}
控制层
/**
 * 用户激活;激活成功-去登陆URL; 激活成功-给其提示信息(激活失败,请联系管理员)
 * 
 * @param code
 * @param res
 * @throws IOException
 */
@RequestMapping("/activeMail.do")
private void activeUser(String code, HttpServletResponse res) throws IOException {
    boolean flag = uService.activeUser(code);
    // 提示信息
    String msg = null;
    if (flag) {
        msg = "<h3><a href='toLogin.do'>激活成功,点击登录。</a></h3>";
    } else {
        msg = "<h3>激活失败,请联系管理员!</h3>";
    }
    res.setContentType("text/html;charset=utf-8");
    res.getWriter().write(msg);
}
激活成功去登录页面
/**
 * 去登录页面
 * 
 * @return
 */
@RequestMapping("/toLogin.do")
public String toLoginPage() {
    return "login";
}
5.用户登录
页面验证
验证规则

用户名:由6到15个字母、数字、下划线组成,不符合规则-边框变为红实线并给其提示,否则清空边框及提示信息
密码:由6到15个字母、数字、下划线组成,不符合规则-边框变为红实线并给其提示,否则清空边框及提示信息

验证时机

用户点击提交时验证
离开焦点时验证

验证实现
<script type="text/javascript">
    $(function(){
    //1、用户点击时验证
    $("#sub_login").click(function(){
        return checkUname() && checkPwd();
    });
    //2、离开焦点时验证
    $("#username").blur(checkUname);
    $("#password").blur(checkPwd);
});

//验证用户名-由6到15个字母、数字、下划线组成,不符合规则-边框变为红实线并给其提示,否则清空边框及提示信息
function checkUname(){
    //1、获取值
    var uname=$("#username").val();
    //2、正则表达式
    var reg_uname=/^\w{6,15}$/;
    //3、判断并提示
    if(!reg_uname.test(uname)){
        $("#username").css("border","1px solid red");
        $("#errorMsg").html("用户名由6到15个字母、数字、下划线组成!");
        return false;
    }
    //清空边框及提示信息
    $("#username").css("border","");
    $("#errorMsg").html("");
    return true;
}
//验证密码-由6到15个字母、数字、下划线组成,不符合规则-边框变为红实线并给其提示,否则清空边框及提示信息
function checkPwd(){
    //1、获取值
    var pwd=$("#password").val();
    //2、正则表达式
    var reg_pwd=/^\w{6,15}$/;
    //3、判断并提示
    if(!reg_pwd.test(pwd)){
        $("#password").css("border","1px solid red");
        $("#errorMsg").html("密码由6到15个字母、数字、下划线组成!");
        return false;
    }
    //清空边框及提示信息
    $("#password").css("border","");
    $("#errorMsg").html("");
    return true;
}
</script>
登录实现
数据接口-/TravelProject/src/com/zk/dao/UserMapper.java
/**
 * 登录方法
 * 
 * @param username
 * @param password
 * @return
 */
@Select("select * from tab_user where username=#{username} and password=#{password}")
User login(@Param("username") String username, @Param("password") String password);
业务接口-/TravelProject/src/com/zk/service/UserService.java
User login(String username, String password);
业务实现-/TravelProject/src/com/zk/service/impl/UserServiceImpl.java
@Override
public User login(String username, String password) {
    return uMapper.login(username, password);
}
控制层-/TravelProject/src/com/zk/controller/UserController.java
/**
 * 用户登录
 * 
 * @param username
 * @param password
 * @return
 */
@RequestMapping("/doLogin.do")
public ModelAndView login(String username, String password, HttpServletRequest req) {
    ModelAndView mv = new ModelAndView();
    // 1、用户和密码不正确-用户不存在-去登录页面并给其提示-用户名或密码不正确
    User user = uService.login(username, password);
    if (user == null) {
        mv.addObject("msg", "用户名或密码不正确!");
        mv.setViewName("forward:toLogin.do");
    }
    // 2、用户和密码正确-用户存在-用户的状态不为Y-请去邮箱激活用户
    if (user != null && !"Y".equals(user.getStatus())) {
        mv.addObject("msg", "登录失败,请在邮箱激活!");
        mv.setViewName("forward:toLogin.do");
    }
    // 3、用户和密码正确-用户存在-用户的状态为Y
    if (user != null && "Y".equals(user.getStatus())) {
        // 登录成功后将用户信息保存到session对象当中
        req.getSession().setAttribute("user", user);
        mv.setViewName("forward:indexPage.do");
    }
    return mv;
}
登录页面信息错误提示-/TravelProject/WebContent/WEB-INF/jsp/login.jsp
<!--登录错误提示消息-->
<div id="errorMsg" class="alert alert-danger" >${msg==null?'':msg }</div>
首页用户信息显示-/TravelProject/WebContent/WEB-INF/jsp/header.jsp
<!-- 此user为UserController.java中登录成功后将用户信息保存到session对象当中的user -->
<span>欢迎,${sessionScope.user.name==null?"游客":sessionScope.user.name}</span>
6.用户退出

退出本质-清空Session

页面连接-/TravelProject/WebContent/WEB-INF/jsp/header.jsp
<a href="toLogout.do">退出</a>
控制层代码-/TravelProject/src/com/zk/controller/UserController.java
/**
 * 用户退出
 * 
 * @param req
 * @return
 */
@RequestMapping("/toLogout.do")
public ModelAndView logout(HttpServletRequest req) {
    // 清空session
    req.getSession().invalidate();
    return new ModelAndView("forward:indexPage.do");
}
7.导航条分类
数据接口-src/com/zk/dao/CategoryMapper.java
@Select("select cid,cname from tab_category")
List<Category> selectAllCategory();
映射文件-src/com/zk/dao/CategoryMapper.xml
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zk.dao.CategoryMapper">
</mapper>
业务接口-src/com/zk/service/CategoryService.java
List<Category> selectAllCategory();
业务实现
@Autowired
private CategoryMapper cMapper;

@Override
public List<Category> selectAllCategory() {
    return cMapper.selectAllCategory();
}
控制层-src/com/zk/controller/CategoryController.java
@Autowired
private CategoryService categoryService;

/**
 * List可以返回普通的String,可以返回对象,也可以返回list集合包括map
 *
 * @return
 */
@RequestMapping("/cgList.do")
@ResponseBody
public List<Category> getCategoryList() {
    List<Category> categoryList = categoryService.selectAllCategory();
    if (categoryList != null) {
        return categoryList;
    }
    return null;
}
页面改造-WebContent/WEB-INF/jsp/header.jsp
<!-- 首页导航 -->
<div class="navitem">
    <ul class="nav" id="category">
        <li class="nav-active"><a href="index.html">首页</a></li>
        <li class='cg'></li>
        <li><a href="favoriterank.html">收藏排行榜</a></li>
    </ul>
</div>
Ajax请求
<script type="text/javascript">
    $(function () {
    $.post('cgList.do', function (res) {
        var html = "";
        for (var i = 0; i < res.length; i++) {
            html += "<a href='#'>" + res[i].cname + "</a>"
        }
        //将遍历出来的超链接放到li中
        $(".cg").html(html);
    })
});
</script>
8.分类数据模糊查
页面改造-WebContent/WEB-INF/jsp/header.jsp
<form action="routeList.do" method="post">
    <input name="rname" id="rname" type="text" placeholder="请输入路线名称" class="search_input"
           value="${rname==''?'':rname}">
    <input type="submit" value="搜索" class="search-button"/>
</form>
分类超链接改造
for (var i = 0; i < res.length; i++) {
    html += "<a href='routeList.do?cid=" + res[i].cid + "'>" + res[i].cname + "</a>"
}
数据接口-src/com/zk/dao/RouteMapper.java
/**
 * 查询
 * @param cid
 * @param rid
 * @return
 */
List<Route> selectRouteByCidOrRname(@Param("cid") Integer cid, @Param("rname") String rname);
映射文件-src/com/zk/dao/RouteMapper.xml
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zk.dao.RouteMapper">
    <!--根据分类id或者线路名称进行模糊查询-->
    <select id="selectRouteByCidOrRname" resultType="route">
        select rname,price,routeIntroduce,rimage from tab_route
        <trim prefix="where" prefixOverrides="and || or">
            <if test="cid!=null">
                cid=#{cid}
            </if>
            <if test="rname!=null and rname!=''">
                and rname like concat('%',#{rname},'%')
            </if>
        </trim>
    </select>
</mapper>
业务接口-src/com/zk/service/RouteService.java
List<Route> selectRouteByCidOrRname(Integer cid, String rname);
业务实现-src/com/zk/service/impl/RouteServiceImpl.java
@Autowired
private RouteMapper routeMapper;

@Override
public List<Route> selectRouteByCidOrRname(Integer cid, String rname) {
    return routeMapper.selectRouteByCidOrRname(cid, rname);
}
控制层-src/com/zk/controller/RouteController.java
@Autowired
private RouteService routeService;

@RequestMapping("/routeList.do")
public ModelAndView getRouteList(@RequestParam(name = "pno", required = true, defaultValue = "1") Integer pno,
                                 @RequestParam(name = "cid", required = true, defaultValue = "5") Integer cid,
                                 @RequestParam(name = "rname", required = true, defaultValue = "") String rname) {
    ModelAndView modelAndView = new ModelAndView();
    //开始分页
    PageHelper.startPage(pno, 10);
    List<Route> routeList = routeService.selectRouteByCidOrRname(cid, rname);
    //分好页的数据
    PageInfo<Route> pageInfo = new PageInfo<Route>(routeList);
    if (routeList != null) {
        modelAndView.addObject("rlist", routeList);
        modelAndView.addObject("rname", rname);
        //当前页码
        modelAndView.addObject("pno", pno);
        modelAndView.addObject("page", pageInfo);
        modelAndView.addObject("cid", cid);
        //逻辑视图名
        modelAndView.setViewName("route_list");
        return modelAndView;
    }
    return null;
}
页面展示-WebContent/WEB-INF/jsp/route_list.jsp
<ul>
    <c:forEach items="${rlist}" var="r">
        <li>
            <div class="img">
                
            </div>
            <div class="text1">
                <p>${r.rname}</p>
                <br/>
                <p>${r.routeIntroduce}</p>
            </div>
            <div class="price">
                <p class="price_num">
                    <span>&yen;</span> <span>${r.price}</span> <span>起</span>
                </p>
                <p>
                    <a href="routeDetail?rid=${r.rid}">查看详情</a>
                </p>
            </div>
        </li>
    </c:forEach>
</ul>
百度分页效果分析
1、判断上页和下页的形成条件
    上一页:当前页面大于1;
    下一页:当前页码大于1且当前页码小于总页数。
2、上一页和下一页中间遍历部分
    总页数小于等于10;
    总页数大于10时;
    当前页面小于等于6和大于6是的情况。
分页效果展示-WebContent/WEB-INF/jsp/route_list.jsp
<div class="page_num_inf">
    <i></i> 共 <span>${page.pages}</span>页<span>${page.total}</span>条
</div>
<div class="pageNum">
    <ul>
        <c:if test="${pno > 1}">
            <li class="threeword"><a
                                     href="routeList.do?pno=${page.prePage}&cid=${cid}&rname=${rname}">&lt;上一页</a></li>
        </c:if>
        <c:choose>
            <c:when test="${page.pages<=10}">
                <c:forEach begin="1" end="${page.pages}" var="i">
                    <c:if test="${pno==i}">
                        <li class="curPage"><a
                                               href="routeList.do?pno=${i}&cid=${cid}&rname=${rname}">${i}</a></li>
                    </c:if>
                    <c:if test="${pno!=i}">
                        <li><a href="routeList.do?pno=${i}&cid=${cid}&rname=${rname}">${i}</a></li>
                    </c:if>
                </c:forEach>
            </c:when>
            <c:when test="${page.pages>10}">
                <c:if test="${pno<=6}">
                    <c:forEach begin="1" end="10" var="i">
                        <c:if test="${pno==i}">
                            <li class="curPage"><a
                                                   href="routeList.do?pno=${i}&cid=${cid}&rname=${rname}">${i}</a></li>
                        </c:if>
                        <c:if test="${pno!=i}">
                            <li><a href="routeList.do?pno=${i}&cid=${cid}&rname=${rname}">${i}</a></li>
                        </c:if>
                    </c:forEach>
                </c:if>
                <c:if test="${pno>6}">
                    <c:forEach begin="${pno-5}"
                               end="${(pno+4)>page.pages?page.pages:(pno+4)}" var="i">
                        <c:if test="${pno==i}">
                            <li class="curPage"><a
                                                   href="routeList.do?pno=${i}&cid=${cid}&rname=${rname}">${i}</a></li>
                        </c:if>
                        <c:if test="${pno!=i}">
                            <li><a href="routeList.do?pno=${i}&cid=${cid}&rname=${rname}">${i}</a></li>
                        </c:if>
                    </c:forEach>
                </c:if>
            </c:when>
        </c:choose>
        <c:if test="${pno>=1 && pno<page.pages}">
            <li class="threeword"><a
                                     href="routeList.do?pno=${page.nextPage}&cid=${cid}&rname=${rname}">下一页&gt;</a></li>
        </c:if>
    </ul>
</div>
9.线路详情查询
功能分析
详情页的数据主要来自3张表:tab_route(线路表)、tab_route_img(线路图片表)、tab_seller(商家表);
线路表和商家表是一对一关系通过外键sid关联、线路表和线路图片表示一对多关系通过外键rid进行关联;
以线路表为主,在映射文件当中配置一对一和一对多关系。
数据接口-src/com/zk/dao/RouteMapper.java
/**
 * 根据线路id查询线路
 * @param rid
 * @return
 */
Route selectByRid(Integer rid);
映射文件-src/com/zk/dao/RouteMapper.xml
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zk.dao.RouteMapper">
    <resultMap id="rResultMap" type="Route">
        <id property="rid" column="rid"/>
        <result property="rname" column="rname"/>
        <result property="price" column="price"/>
        <result property="routeIntroduce" column="routeIntroduce"/>
        <result property="rflag" column="rflag"/>
        <result property="rdate" column="rdate"/>
        <result property="isThemeTour" column="isThemeTour"/>
        <result property="count" column="count"/>
        <result property="cid" column="cid"/>
        <result property="rimage" column="rimage"/>
        <result property="sid" column="sid"/>
        <result property="sourceId" column="sourceId"/>
        <!--一对一-->
        <association property="seller" javaType="Seller">
            <id property="sid" column="sid"/>
            <result property="sname" column="sname"/>
            <result property="address" column="address"/>
            <result property="consphone" column="consphone"/>
        </association>
        <!--一对多-->
        <collection property="routeImgList" ofType="RouteImg">
            <id property="rgid" column="rgid"/>
            <result property="rid" column="rid"/>
            <result property="bigPic" column="bigPic"/>
            <result property="smallPic" column="smallPic"/>
        </collection>
    </resultMap>
    <!--根据线路id查询线路-->
    <select id="selectByRid" resultMap="rResultMap">
        select r.*, i.*, s.*
        from tab_route r,
             tab_route_img i,
             tab_seller s
        where r.rid = i.rid
          and r.sid = s.sid
          and r.rid = #{rid}
    </select>
</mapper>
业务接口-src/com/zk/service/RouteService.java
Route selectByRid(Integer rid);
业务实现-src/com/zk/service/impl/RouteServiceImpl.java
@Override
public Route selectByRid(Integer rid) {
    return routeMapper.selectByRid(rid);
}
控制层-src/com/zk/controller/RouteController.java
/**
 * 根据线路id查询线路详情
 * @param rid
 * @return
 */
@RequestMapping("/routeDetail.do")
public ModelAndView routeDetail(@RequestParam(name = "rid", required = true, defaultValue = "") Integer rid) {
    ModelAndView modelAndView = new ModelAndView();
    Route route = routeService.selectByRid(rid);
    if (route != null) {
        List<RouteImg> imgList = route.getRouteImgList();
        Seller seller = route.getSeller();
        //线路对象
        modelAndView.addObject("rt", route);
        //图片集合
        modelAndView.addObject("imgList", imgList);
        //商家
        modelAndView.addObject("sl", seller);
        //去线路详情页面
        modelAndView.setViewName("route_detail");
        return modelAndView;
    }
    return null;
}
页面展示-WebContent/WEB-INF/jsp/route_detail.jsp
<div class="prosum_box">
    <dl class="prosum_left">
        <dt>
            
        </dt>
        <dd>
            <a class="up_img up_img_disable"></a>
            <c:forEach items="${imgList}" var="i" varStatus="v">
                <c:if test="${v.count>4}">
                    <a title="" class="little_img" data-bigpic="${i.bigPic}" style="display:none;">
                        
                    </a>
                </c:if>
                <c:if test="${v.count<=4}">
                    <a title="" class="little_img" data-bigpic="${i.bigPic}">
                        
                    </a>
                </c:if>
            </c:forEach>
            <a class="down_img down_img_disable" style="margin-bottom: 0;"></a>
        </dd>
    </dl>
    <div class="prosum_right">
        <p class="pros_title">${rt.rname}</p>
        <p class="hot">${rt.routeIntroduce}</p>
        <div class="pros_other">
            <p>经营商家 :${sl.sname}</p>
            <p>咨询电话 : ${sl.consphone}</p>
            <p>地址 :${sl.address}</p>
        </div>
        <div class="pros_price">
            <p class="price"><strong>¥${rt.price}</strong><span>起</span></p>
            <p class="collect">
                <a class="btn"><i class="glyphicon glyphicon-heart-empty"></i>点击收藏</a>
                <a class="btn already" disabled="disabled"><i class="glyphicon glyphicon-heart-empty"></i>点击收藏</a>
                <span>已收藏${rt.count}次</span>
            </p>
        </div>
    </div>
</div>
10.收藏功能
思路分析
    首先用户点击收藏时需要判断用户是否登录,如果没有登录给其提示并且跳转到登录页面;
如果已经登录,需要查询该用户是否已经收藏过该线路,如果有收藏,则提示您已收藏过;
如果已经登录,但是之前没有收藏过此线路,则将收藏的信息保存到数据库并更新线路的收藏次数。
底层方法
1、根据用户id和线路id查询是否有收藏
2、添加收藏的方法
3、更新线路收藏次数的方法
数据接口1-src/com/zk/dao/FavoriteMapper.java

在FavoriteMapper中

/**
 * 根据线路id和用户id查询是否有收藏信息
 *
 * @param rid
 * @param uid
 * @return
 */
@Select("select * from tab_favorite where rid=#{rid} and uid=#{uid}")
Favorite selectFtByRidAndUid(@Param("rid") Integer rid, @Param("uid") Integer uid);

/**
 * @param ft
 * @return
 */
@Insert("insert into tab_favorite(rid, date, uid) values (#{rid},now(),#{uid})")
int addCollect(Favorite ft);
数据接口2-src/com/zk/dao/RouteMapper.java

在RouteMapper接口中

/**
 * 更新某个线路的收藏次数
 * @param rid
 * @return
 */
@Update("update tab_route set count=#{count} where rid=#{rid}")
int updateCount(Route rt);
业务接口-src/com/zk/service/FavoriteService.java
/**
 * 收藏功能
 * @param favorite
 * @return
 */
boolean doCollect(Favorite favorite);
业务实现-src/com/zk/service/impl/FavoriteServiceImpl.java
@Autowired
private FavoriteMapper favoriteMapper;

@Autowired
private RouteMapper routeMapper;

@Transactional
public boolean doCollect(Favorite favorite) {
    Favorite favorite1 = favoriteMapper.selectFtByRidAndUid(favorite.getRid(), favorite.getUid());
    if (favorite1 == null) {
        if (favoriteMapper.addCollect(favorite) > 0) {
            Route route = routeMapper.selectByRid(favorite.getRid());
            route.setCount(route.getCount() + 1);
            routeMapper.updateCount(route);
            return true;
        }
        return false;
    }
    return false;
}
控制层-src/com/zk/controller/FavoriteController.java
@Autowired
private FavoriteService favoriteService;

/**
 * 收藏
 *
 * @param favorite
 * @return
 */
@RequestMapping("/doCollect.do")
@ResponseBody
public String doCollect(Favorite favorite) {
    boolean flag = favoriteService.doCollect(favorite);
    if (flag) {
        return "true";
    }
    return "false";
}
页面请求-
<script type="text/javascript">
    $(function () {
        $(".btn").click(function () {
            var uname = '${sessionScope.user.username}';
            if (uname == null || uname == "") {
                alert("请登录在收藏!");
                window.location.href = 'toLogin.do';
                return;
            }
            //已登录-发送ajax判断用户是否有收藏该线路
            var rid = '${rt.rid}';
            var uid = '${sessionScope.user.uid}';
            $.post('doCollect.do', {"rid": rid, "uid": uid}, function (res) {
                if (res == "false") {
                    alert("你已收藏过该线路!");
                    //禁用收藏按钮
                    $(".btn").attr("disabled", "disabled");
                }
                alert("收藏成功!");
                //禁用收藏按钮
                $(".btn").attr("disabled", "disabled");
            })
        });
    })
</script>
(6)项目总结

3、说明

项目中注意事项
转自:https://my.oschina.net/kkrgwbj/blog/734530
    通常我们的项目有时候是以jar包的形式发布出去,但是此时如果你直接使用lo4j2的api的话,相当于别人依赖你的jar的项目也必须加入log4j2的jar包。这样是高度耦合的。我们不建议这样使用,log4j2官方给出了适配slf4j,我们只需要在项目中加入以下依赖:
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-slf4j-impl -->
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-slf4j-impl</artifactId>
    <version>2.13.3</version>
    <scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.30</version>
</dependency>

4、出错

运行项目出错,控制台无错误输出
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zk.dao.UserMapper">
    
</mapper>

注意:namespace="com.zk.dao.UserMapper"要和包名对应,出错为namespace="com.SSM.dao.UserMapper",而包名为"com.zk.dao.UserMapper"
解决idea出现Error:(8, 26) java: 程序包javax.servlet.http不存在
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>servlet-api</artifactId>
    <version>2.5</version>
</dependency>
出现错误“Uncaught SyntaxError: Invalid left-hand side in assignment”,少些了一个等号;
if (uname == null || uname == "") {
    alert("请登录在收藏!");
    window.location.href = 'toLogin.do';
    return;
}
正则表达式(Regular Expression),常简称为regex、regexp
软件

regexBuilder:https://github.com/ScottLouvau/RegexBuilder
Regex Match Tracer:http://www.regexlab.com/

教程

菜鸟教程:https://www.runoob.com/regexp/regexp-tutorial.html
简单教程:https://www.twle.cn/l/yufei/regexp/regexp-basic-index.html
regular:http://www.regular-expressions.info/
MDN:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Regular_Expressions
微软:https://docs.microsoft.com/zh-cn/dotnet/standard/base-types/regular-expressions
w3cschool:https://www.w3cschool.cn/zhengzebiaodashi/regexp-tutorial.html

在线生成

在线工具:https://tool.lu/regex/
regex101:https://regex101.com/
Regulex:https://jex.im/regulex/
菜鸟教程:http://c.runoob.com/front-end/854
JSON在线:https://www.sojson.com/regex/generate
脚本之家:http://tools.jb51.net/regex
Jsonshttp://www.jsons.cn/regcode/
站长之家:http://tool.chinaz.com/regex/
开源中国社区:https://tool.oschina.net/regex/
debuggex:https://www.debuggex.com/
w3cschool:https://www.w3cschool.cn/zhengzebiaodashi/regexp-tutorial.html

web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
    id="WebApp_ID" version="3.0">
    <display-name>TravelProject</display-name>
    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
        <welcome-file>index.htm</welcome-file>
        <welcome-file>index.jsp</welcome-file>
        <welcome-file>default.html</welcome-file>
        <welcome-file>default.htm</welcome-file>
        <welcome-file>default.jsp</welcome-file>
    </welcome-file-list>

    <!--加载spring的配置文件 -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring-config.xml</param-value>
    </context-param>
    <!--配置一个监听器 web项目一启动 就加载spring配置文件 -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    
    <!--配置前端控制器-DispatcherServlet并加载springmvc的配置文件 -->
    <servlet>
        <servlet-name>ssm</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!--初始化参数 加载springmvc配置文件 -->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc-config.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>ssm</servlet-name>
        <url-pattern>*.do</url-pattern>
    </servlet-mapping>
    
    <!--加载过滤器-字符编码处理 -->
    <filter>
        <filter-name>encoding</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>utf-8</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>encoding</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>
MyBatis
官网:https://mybatis.org/mybatis-3/
中文官网:https://mybatis.org/mybatis-3/zh/index.html
mybatis.xml头文件:https://mybatis.org/mybatis-3/getting-started.html
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ssm.dao.UserMapper">
</mapper>
mybatis-config.xml头文件:https://mybatis.org/mybatis-3/getting-started.html
官网版
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC" />
            <dataSource type="POOLED">
                <property name="driver" value="${driver}" />
                <property name="url" value="${url}" />
                <property name="username" value="${username}" />
                <property name="password" value="${password}" />
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="org/mybatis/example/BlogMapper.xml" />
    </mappers>
</configuration>

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!--取别名 -->
    <typeAliases>
        <!-- <typeAlias type="com.ssm.entity.Student" alias="student"/> -->
        <!--批量设置实体类的别名,默认是类名称首字母小写 -->
        <package name="com.zk.entity" />
    </typeAliases>
    <!-- 加载mybatis分页插件PageHelper -->
    <plugins>
        <plugin interceptor="com.github.pagehelper.PageInterceptor">
            <!-- 设置数据库类型 Oracle,Mysql,MariaDB,SQLite,Hsqldb,PostgreSQL六种数据库方言,说明mysql数据库方言 -->
            <property name="helperDialect" value="mysql" />
        </plugin>
    </plugins>
    <!--映射器批量加载映射关系,告诉mybatis去哪里寻找映射关系 -->
    <mappers>
        <!-- <mapper resource="com/ssm/entity/StudentMapper.xml" /> -->
        <package name="com.zk.dao" />
    </mappers>
</configuration>
Spring
官网:https://spring.io/
Spring-Framework:https://spring.io/projects/spring-framework
spring-config.xml头文件

https://docs.spring.io/spring/docs/5.3.0-SNAPSHOT/spring-framework-reference/core.html#xsd-schemas-aop

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans 
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop 
        https://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context 
        https://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/tx 
        https://www.springframework.org/schema/tx/spring-tx.xsd">
        
    <!--配置数据源 -->
    <bean id="dataSource" class="com.jolbox.bonecp.BoneCPDataSource"
        p:driverClass="com.mysql.jdbc.Driver"
        p:jdbcUrl="jdbc:mysql://localhost:3306/travel" p:username="root"
        p:password="123456" />
    <!--SqlSessionFactory工厂对象 -->
    <bean id="factory"
        class="org.mybatis.spring.SqlSessionFactoryBean"
        p:dataSource-ref="dataSource"
        p:configLocation="classpath:mybatis-config.xml" />
    <!--引入映射器 -->
    <!--p:basePackage指定了批量生成映射器实例的基础包 -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"
        p:basePackage="com.zk.dao" />
    <!--配置支持注解扫描的Bean -->
    <context:component-scan base-package="com.zk" />
    <!--配置事务管理器 -->
    <bean id="txManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
        p:dataSource-ref="dataSource" />
    <!--配置支持注解 声明式事务 -->
    <tx:annotation-driven
        transaction-manager="txManager" />    
</beans>
springmvc-config.xml头文件:https://docs.spring.io/spring/docs/5.3.0-SNAPSHOT/spring-framework-reference/web.html#mvc-config
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc
        https://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">
    
    <!--扫描组件,作用扫描到的spring会自动帮创建对象及资源的注入 -->
    <context:component-scan
        base-package="com.zk.controller" />
    <!--配置支持注解 -->
    <mvc:annotation-driven />
    <!--配置视图解析器 -->
    <bean
        class="org.springframework.web.servlet.view.InternalResourceViewResolver"
        p:prefix="/WEB-INF/jsp/" p:suffix=".jsp" />
</beans>
用到的依赖
依赖官网:
<!-- mysql依赖 -->
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.48</version>
</dependency>

<!-- mybatis依赖 -->
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.4</version>
</dependency>

<!-- mybatis-spring依赖 -->
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>2.0.4</version>
</dependency>

<!-- mybatis分页插件-PageHelper -->
<!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper -->
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>5.1.11</version>
</dependency>

<!-- spring-webmvc依赖 -->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.2.4.RELEASE</version>
</dependency>

<!-- spring-jdbc依赖 -->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.2.4.RELEASE</version>
</dependency>

<!-- bonecp依赖 -->
<!-- https://mvnrepository.com/artifact/com.jolbox/bonecp -->
<dependency>
    <groupId>com.jolbox</groupId>
    <artifactId>bonecp</artifactId>
    <version>0.8.0.RELEASE</version>
</dependency>

<!-- Jstl依赖 -->
<!-- https://mvnrepository.com/artifact/javax.servlet/jstl -->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>jstl</artifactId>
    <version>1.2</version>
</dependency>

<!-- Log4J2依赖 -->
<!-- https://logging.apache.org/log4j/2.x/maven-artifacts.html -->
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-api</artifactId>
    <version>2.13.3</version>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.13.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-slf4j-impl -->
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-slf4j-impl</artifactId>
    <version>2.13.3</version>
    <scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.30</version>
</dependency>

<!-- jackson-databind依赖 -->
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.10.0</version>
</dependency>

<!-- javax.mail依赖 -->
<!-- https://mvnrepository.com/artifact/javax.mail/javax.mail-api -->
<dependency>
    <groupId>javax.mail</groupId>
    <artifactId>javax.mail-api</artifactId>
    <version>1.6.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.sun.mail/javax.mail -->
<dependency>
    <groupId>com.sun.mail</groupId>
    <artifactId>javax.mail</artifactId>
    <version>1.6.2</version>
</dependency>

<!--解决idea出现Error:(8, 26) java: 程序包javax.servlet.http不存在-->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>servlet-api</artifactId>
    <version>2.5</version>
</dependency>

本文转载自: https://blog.csdn.net/lijunhcn/article/details/135259872
版权归原作者 辣椒种子 所有, 如有侵权,请联系我们删除。

“毕业设计——基于SSM+Mysql构建的完整在线旅游网站项目”的评论:

还没有评论