基于SpringBoot+MyBatis的旅行社管理系统设计与实现

       随着Web应用的成熟,越来越多的开发人员喜欢使用方便快捷的Web应用框架。这样可以开发出完善健壮的软件,对程序员的要求将会非常高。如果采用成熟,稳健的框架,那么一些基础的通用工作,比如,事物处理,安全性,数据流控制等都可以交给框架处理,那么程序员只需要集中精力完成系统的业务逻辑设计,可以降低开发难度。所以,我们在开发一个新的系统项目的时候不需要考虑要不要使用框架,而是考虑使用一个什么框架。在此系统中,我们就使用了SpringBoot框架。

       Springboot直接省去配置文件的过程,Springboot的代码架构是springMVC三层架构,M(model)模型、 V(view)视图、 C(controller)控制器,后台代码controlle层接收由view视图页面传过来的数据,再经过service层处理之后然后给到mapper层写sql语句调用数据库等操作。 Springboot内嵌了几个前段开发的模板比如:thymeleaf、velocity、freemaker等,Springboot搭建的话一般都会结合maven因为下载jar比较方便,并且Springboot的打包方式和之前的web项目有很大的区别。之前的web项目是打成war包的,然后放在服务器里面的tomcat运行,而Springboot省去了这个。Springboot有内置的Tomcat当然如果不需要的话可以在pom文件中给去掉。这样可以使得开发人员把精力主要集中在如何解决实际的业务逻辑问题,并且可以重用代码大大增加,软件生产效率和质量也得到了提高,更好的适应了用户的实际需求。

       另外,我们采用了MyBatis持久层框架。它与以前的持久层框架相比,减少了很多重复的代码,并且SQL语句写在XML文件里,减少了与程序代码的耦合性。


需求分析

  • 旅行社管理系统业务要求

       作为一个面向全国游客的管理系统。首先我们要保证系统的健壮和稳定,还得保证数据的安全性,尽可能定期对数据进行备份。其次,我们的系统界面需要尽可能的友好,能够保证用户在没有任何计算机基础的情况下稍加培训就能够对系统进行熟练的操作。最后,管理员能对旅行社相关信息进行管理,实现最基本的操作。

  • 旅行社管理系统功能分析

       根据我们前面的业务要求。我们的系统首先应该对用户进行权限管理,这样子才能保证我们的前后台分离开来,后台只对用户和数据进行管理,前端只能进行一些信息的查看。另外,作为旅行社管理系统。我们要对旅行社相关的信息进行管理和操作,比如景点、特色、旅行线路、旅游班次、酒店、导游和旅行团等信息进行增删查改和进行模糊查询,特别的旅行线路还需要有导入和导出等功能。

  • 系统用例

管理员用户管理用例图

 管理员旅行社基本信息管理用例图

旅行社基本信息管理包括了,景点,景点特色,线路,酒店,导游,班次,旅行团和游客信息管理。

     旅游客户用例图 

数据库设计

  • 数据库设计对系统的影响

 一个不按需求的数据库设计,肯定会造成很多问题,比如数据表设计不合理可能会造成字段的增减,主外和外键设计不合理、数据关系映射不对等原因可能会导致系统无法正常运行。所以,一个设计良好的数据库对系统开发至关重要。

  • 数据库的需求分析

根据我对系统的分析,在保证了功能齐全的前提下,可以将数据库分为以下几个功能模块:景点信息管理,特色景点管理,旅行线路管理,导游信息管理,酒店信息管理,旅行班次管理,游客信息管理,旅游团信息管理。我们的每个功能模块都具有增加,删除,修改和查询。旅行线路管理模块还添加了导出和导入的功能。因此我们根据我们的功能模块可以设计出对应的数据表:景点信息表,特色景点表,旅行线路表,导游信息,酒店信息表,旅行班次表,游客信息表和旅游团信息表,根据设计的数据表和我们的功能分析,可以得到我们每张数据表需要的属性如下:

景点信息表:景点名称,景点星级,景点介绍,景点图片,周边服务,当地天气。

特色景点表:特色名称,特色景点标记,特色景点介绍。

旅行线路表:路线名称,起点,终点,线路介绍。

导游信息表:导游姓名,性别,年龄,身份证号,住址,联系电话,导游等级,最近业绩。

酒店信息表:酒店名称,所在城市,详细地址,酒店星级,今日房价,外观图片,房间图片,负责人,负责人职务,负责人电话。

旅游班次表:班次名称,出发时间,返程时间。

游客信息表:游客姓名,性别,年龄,身份证号,住址,联系电话。

旅游团信息表:旅游团名称,介绍。

  • 数据库E-R图

数据库设计中常用E-R图来描绘数据库的结构。E-R图在可以让我们非常直观的知道数据库实体与实体之间的关系,以及每个实体是由哪些属性组合刻画而成的,这对我们设计数据库非常的重要。

下图为本系统的E-R图

  •  数据字典介绍

既要直观的让我们知道每个实体拥有哪些属性,并且这些属性的值是可以改变的,这个时候我们就可以考虑使用数据字段。本系统设计到的数据字典如以下表格所示:


系统设计:

  • 系统模块图

根据前面的需分析,以及对数据看的设计,可以将我们的旅行社管理系统总的分为两个大的模块:用户信息管理和旅行团基本信息管理模块。每个模块又可以分为每个单独的小模块,总的系统模块图如下

  • 系统流程图

1)系统管理员操作流程图

系统管理员操作流程,首先管理员登录,看是否登录成功,登录成功后可以对旅行社基本信息进行操作。

2)旅游客户操作流程图

  • 系统项目搭建过程

本项目使用的环境:

开发工具:Intellij IDEA 2017.3.6

JDK: 1.8.0_05

(1)第一步、创建一个SpringBoot项目

(2) 第二步、创建项目的文件结构以及jdk的版本

 

(3)第三步、选择项目中需要添加的依赖

(4)点击Next后点击Finish,项目目录图 

到此,基于SpringBootMyBatis框架的项目就搭建完成了。


系统实现

  • 旅行社管理系统后台功能实现

(一)登录注册模块功能实现

登录注册功能作为任何管理系统都必不可少的功能模块,足以显得其重要性。在我们系统实现的流程是:首先用户填写相应的信息,点击登录按钮,会向后台发起Ajax请求,把数据传到后台做检验,请求成功以后会给前端返回状态看是否登录或者注册成功。

 实现登录操作功能的JS代码

$("#submit").click(function(){
   if(checkLogin()){
   $.ajax({
      type:"POST",
        url:_ctx+"/login",
        data:{username:$("input[name='username']").val(), password:$("input[name='password']").val(),time:new Date().getTime()},
        dataType:"json",
        cache:false,
        success: function(data){
            if("success" == data.status){
                if(data.data[0].roleName == "普通用户"){
                       window.location.href=_ctx+"/home";
                       return;
                   }else{
                       window.location.href=_ctx+"/index";
                       return;
                   }
            }else{
               $("#error-msg").html(data.msg);
            }
        }
   })
}

 登录时,控制层的代码

@RequestMapping(value={"/login"},method=RequestMethod.POST)
@ResponseBody
public Object login(){
   return userService.login(this.getParameterMap(), this.getSession());
}

注册功能跟上述代码大同小异,在此不再累述。

(二)系统后台首页实现

旅行社管理系统管理员端首页,页面包括了一个常用的icon页面,系统菜单列表,个人信息操作的下拉效果。

实现代码:管理员登录成功后会去访问index这个路径,最终将用户的菜单传递到前台页面进行处理,代码如下 。

@RequestMapping("/index")
public String index(Model model){
   try {
      List<Menu> allMenu = (List<Menu>) this.getSession().getAttribute(Const.SESSION_ALL_MENU);
      if(allMenu != null){
         model.addAttribute("menus", allMenu);
      }
      model.addAttribute("adminName", adminName);
      model.addAttribute("userName", ((User)this.getSession().getAttribute(Const.SESSION_USER)).getNickName());
      model.addAttribute("userPath", ((User)this.getSession().getAttribute(Const.SESSION_USER)).getPicPath());
      model.addAttribute("userStatus", "在线");
   } catch (Exception e) {
      e.printStackTrace();
   }
   return "index";
}

(三)景点管理功能模块实现 

该功能模块包括了景点信息的添加,修改,删除,列表查看,根据景点名称进行模糊查询,分页操作。

查询景点全部信息界面如图

 核心代码如下:

@RequestMapping("/list")
@ResponseBody
public Msg getScenicSpotFeatureJson(@RequestParam(value = "pn", defaultValue = "1") Integer pn) {
    PageHelper.startPage(pn, 5);
    List<ScenicSpot> features = scenicSpotService.getAllByQuery();
    PageInfo page = new PageInfo(features, 5);
    return Msg.success().add("pageInfo", page);
}

 添加景点信息运行界面如图

前端对图片上传进行处理的代码,主要是要得到图片的Base64码,然后传到后台进行处理,核心代码如下: 

function chooseImg(imgId, imgBaseShowTag, showImgTag) {
    var input = document.getElementById(imgId);
    if (typeof (FileReader) === 'undefined') {
        result.innerHTML = "操作失败,请换个浏览器重试";
        input.setAttribute('disabled', 'disabled');
    } else {
        input.addEventListener('change', readFile, false);
    }
    function readFile() {
        var file = this.files[0];
        //判断是否是图片类型
        if (!/image\/\w+/.test(file.type)) {
            alert("只能选择图片");
            return false;
        }
        var reader = new FileReader();
        reader.readAsDataURL(file);
        reader.onload = function (e) {
            base64Code = this.result;
            $(imgBaseShowTag).val(this.result);
            $(showImgTag).attr("src", this.result);
        }
    }
}

修改景点信息运行界面如图 

修改景点信息核心代码,首先我们应该根据主键id去获取我们需要修改的数据,然后再将修改后的数据通过Ajax传到后台进行处理: 

@RequestMapping(value = "/{id}", method = RequestMethod.GET)
@ResponseBody
public Msg getSpot(@PathVariable("id") Long id) {

    ScenicSpot scenicSpot = scenicSpotService.getSpot(id);
    return Msg.success().add("spot", scenicSpot);
}

@RequestMapping(value = "/update", method = RequestMethod.POST)
@ResponseBody
public Msg updateSs() {
    scenicSpotService.update(this.getParameterMap());
    return Msg.success();
}

 删除景点信息运行界面如图

删除一定要注意发起Ajax的时候type要为delete,删除某一页中的记录,一定要调到这一页,我们才能看到数据是否删除成功,代码如下 :

$(document).on("click", ".delete_btn", function () {
    var scenicSpotName = $(this).parents("tr").find("td:eq(3)").text();
    var scenicSpotId = $(this).attr("del-id");
    if (confirm("确认删除[" + scenicSpotName + "]吗?")) {
        $.ajax({
            url: "/scenic/spot/delete/" + scenicSpotId,
            type: "DELETE",
            success: function (result) {
                alert(result.msg);
                to_page(currentPage);
            }
        });
    }
});

 (四)旅行线路信息管理功能模块实现

线路管理是此系统的其中一个功能模块,其中包括了线路的列表查看,新增,删除,修改,导入,导出和根据线路名称进行模糊查询。除此之外,我们对线路信息的查看进行了分页操作,每一页只显示5条记录。还对上一页,下一页,首页,尾页对应的按钮做了相应的判断,如果没有对应的页码,将禁用对应的按钮。而且,我还对线路做了可以查看该线路上对应的景点信息和该线路拥有哪些班次。

查询全部线路信息界面如图:

查询全部线路信息实现核心代码:我们通过Ajax发起请求后,后台会将数据获取后封装到Json数据(这个函数的result)中,而在前端,我们只需要解析Json数据后再显示到页面即可 :

function build_lines_table(result) {
    debugger;
    //清空table表格
    $("#lines_table tbody").empty();
    var lines = result.extend.pageInfo.list;
    $.each(lines, function (index, item) {
        var checkBoxTd = $("<td><input type='checkbox' class='check_item'/></td>");
        var lineId = $("<td></td>").append(item.lineId);
        var lineName = $("<td></td>").append(item.lineName);
        var lineStar = $("<td></td>").append(item.lineStar);
        var lineEnd = $("<td></td>").append(item.lineEnd);
        var lineSpendDay = $("<td></td>").append(item.lineSpendDay);
        var lineViewIntroduce = $("<td></td>").addClass("autocut").append(item.lineViewIntroduce);
        var showShiftTd = $("<td></td>").append(showShiftBtn);
        var btnTd = $("<td></td>").append(editBtn).append(" ").append(
            delBtn);
        //append方法执行完成以后还是返回原来的元素
$("<tr></tr>").append(checkBoxTd).append(lineId).append(lineName).append(
            lineStar).append(lineEnd).append(lineSpendDay).append(
lineViewIntroduce).append(showSpotTd).append(showShiftTd).append(btnTd).appendTo("#lines_table tbody");
    });
}

导出线路信息运行界面如图

 导出信息核心代码实现:首先我们采用的是第三方库的exportExcel方法:

public static void exportExcel(List<?> list, String title, String sheetName, Class<?> pojoClass,String fileName, HttpServletResponse response){
    defaultExport(list, pojoClass, fileName, response, new ExportParams(title, sheetName));
}
@RequestMapping("export")
public void export(HttpServletResponse response){
    List<TouristLine> features = touristLineService.getAll();
    //导出操作
    FileUtil.exportExcel(features,"线路信息","线路",TouristLine.class,"线路信息.xls",response);
}

 导入线路信息运行截图如图

代码实现:首先我们采用了第三方库的importExcel方法 :

public static <T> List<T> importExcel(String filePath,Integer titleRows,Integer headerRows, Class<T> pojoClass){
    if (StringUtils.isBlank(filePath)){
        return null;
    }
    ImportParams params = new ImportParams();
    params.setTitleRows(titleRows);
    params.setHeadRows(headerRows);
    List<T> list = null;
    try {
        list = ExcelImportUtil.importExcel(new File(filePath), pojoClass, params);
    }catch (NoSuchElementException e){
        e.getMessage();
    } catch (Exception e) {
        e.printStackTrace();
        e.getMessage();
    }
    return list;
}
@RequestMapping("import")
@ResponseBody
public Msg importExcel(){
    String filePath = "D:\\线路信息.xls";
    //解析excel,
    List<TouristLine> touristLines = FileUtil.importExcel(filePath,1,1,TouristLine.class);
    System.out.println("导入数据一共【"+touristLines.size()+"】行");
    for(TouristLine line:touristLines){
        touristLineService.add(line);
    }
    return Msg.success();
}
  •  旅行社管理系统前台功能实现

为了测试旅行社管理系统能否正常的运行,数据库设计有没有问题,我写了旅行网站的前端页面。首页顶端是旅游客户的功能菜单按钮,包括了跟团游、风景区查看、欢迎信息和退出登录,用户端首页如图:

网站前端首页核心代码:当旅游用户登录成功后,会去访问home路径,然后后台会返回给我们登陆成功和用户名等信息: 

@RequestMapping(value={"/home"},method= RequestMethod.GET)
public String toGroupPage(Model model){
   model.addAttribute("userName", ((User)this.getSession().getAttribute(Const.SESSION_USER)).getNickName());
   model.addAttribute("userId", ((User)this.getSession().getAttribute(Const.SESSION_USER)).getUserId());
   return "page/visitorPage/showTouristGroup";
}

 首页顶端功能菜单按钮和欢迎信息以及退出登录按钮的HTML代码:

<ul>
    <li class="active"><a th:href="@{/home}">首页</a></li>
    <li style="margin-left: 40px"><a th:href="@{/home}">跟团游</a></li>
    <li style="margin-left: 40px"><a th:href="@{/spot}">风景区</a></li>
    <li style="margin-left: 40px"><a href="#">关于</a></li>
    <li style="margin-left: 40px"><a href="#">联系我们</a></li>
</ul>
<ul>
    <li><a href="#">欢迎您:<span class="hidden-xs" th:text="${userName}">管理员</span></a></li>
    <li>|</li>
    <li><a th:href="@{/logout}">退出登录</a></li>
</ul>

网站首页还包含了所有的旅游团的基本信息,当点击查看详情,可以去到该旅游团的详细信息,包括了还旅游团所住的酒店安排,乘坐的班次信息,导游信息,旅游景点安排,前端旅行团信息界面如图: 

当点击我要参团按钮的时候,会弹出游客信息添加的框,填写相关信息才能参报旅行团,参报旅行团信息填写界面如图:

 参报旅行团核心代码:这段代码主要是要对旅游团的状态进行判断,只有当状态为待出发才能参报,否则为参报不成功并给出原因:

$("#join_group").click(function () {
    var status = document.getElementById("touristGroupsStatus");
    debugger;
    if(status.innerHTML == "待出发"){
        reloadModelData("信息填写", "确认", "/visitor/info/save", "", "18", "", "","");
        $("#visitorModal").modal("show");
    }else{
        alert("该旅行团处于已出发或取消状态!");
    }
});

到此,已经基本按照我们事先的功能预算,以及对数据库的需求分析,根据数据库的逻辑和我们系统的业务逻辑完成了我们旅行社管理系统全部功能。

 

欢迎扫描下面二维码关注我的微信公众号,一起学习交流。

猜你喜欢

转载自blog.csdn.net/qq_39331713/article/details/110114942