Advertisement

基于ssm的航空订票系统

阅读量:

基于ssm的航空订票系统

一、技术栈

前端
Vue系列组件集合、CSS框架组件包、Moment脚本插件
后端
Spring Boot框架结合Spring MVC与MyBatis技术

二、功能描述

本系统是基于B/S架构的航空订票系统

系统包含三大核心用户群体--旅客(即乘客)、航空公司在编人员以及后台管理人员等

三、技术框架

1、界面设计

Vue 是一个旨在构建用户界面的渐进式框架 。相比其他大型框架而言,在设计上有所不同的是,在Vue中是可以自底向上逐层应用的。其核心库专注于视图层开发,并且在易用性和兼容性方面表现突出。

这段官方解释的核心含义是:Vue提供了以组件化方式进行设计的机制。你可以可以在单个Vue实例中构建实现特定功能的组件,并将这些组件整合到另一个Vue实例中以完成整体功能。熟悉面向对象编程的开发者通常能够轻松适应这种设计理念。就像编写自定义class那样,在其它类中通过引用实例和方法来完成操作。同样使用的是同一个关键字import

Element是一款专为开发者、设计师以及产品经理设计,并遵循Vue 2.0标准的桌面端组件集合。

Element UI 是新手前端设计师的重要宝库和强大工具包,在这个平台中集成了一整套便捷的操作元素与功能模块。它内置的各种标签与组件能够帮助那些因JavaScript复杂而感到困扰的设计者的开发路径。只要具备基本审美能力的人群都能轻松打造美观实用且简洁的画面。

这些组件可以借助Attribute、Event和Methods标签实现个性化的配置,并且大大降低了js函数的编写复杂度

2、前后端通信

在引入axios插件之后,在函数中可以通过借助 axios 对象向目标端口发送请求并触发回调函数的行为。例如,在 8181 端口处发起一个 POST 请求

复制代码
    this.$axios.post("http://localhost:8181/findAll").then(res => {})

后端可以通过设置一个跨域类CrosConfig来接收前端请求

复制代码
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.CorsRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
    
    @Configuration
    public class CrosConfig implements WebMvcConfigurer {
       @Override
       public void addCorsMappings(CorsRegistry registry) {
      registry.addMapping("/**")//拦截所有请求
            .allowedOrigins("*")
            .allowedMethods("GET","HEAD","POST","PUT","DELETE")//拦截所有类型
            .allowCredentials(true)
            .maxAge(3600)//最大线程数
            .allowedHeaders("*");//允许所有请求头
       }
    }

也有在src/resource/mybatis-config.xml中配置跨域的方法,这边不赘述

映射写法

主流有两种方法,一种是REST风格,一种是直接发送json的写法

*具体而言,在REST风格中会将需要发送的数据整合到请求中,并通过"/"分隔符明确区分各部分内容。在后端系统中使用@RequestMapping注解实现路径映射,并通过@PathVariable注解指定变量位置。

如:前端

复制代码
    this.$axios.post("http://localhost:8181/login/passenger/"+that.loginform.passengername+"/"+that.loginform.password)

后端

复制代码
    @RequestMapping
    (value = "/passenger/{passengername}/{password}",
                method = RequestMethod.POST,
                produces = {"application/json;charset=UTF-8"})
    public String passengerlogin(@PathVariable("passengername") String passengername,
                             @PathVariable("password") String password)

另外一种直接向后台发送数据的方式是使用@RequestBody来构造一个类实例,并通过调用get方法来获取数据。

如:前端

复制代码
    this.$axios.post("http://localhost:8181/order/refund", row)

后端

复制代码
    @RequestMapping
    (value = "refund", method = RequestMethod.POST, produces = {"application/json;charset=UTF-8"})
    public String refundOrder(@RequestBody OrderInfo orderInfo)

在数据量较小的情况下,REST风格要更加简洁干练

3、持久层

目前广泛应用于各个领域的两种主流持久化框架是Java Persistence API(JPA)和MyBatis。它们各自拥有一群忠诚的支持者。然而,在两者的优劣对比并不是一个技术新手能够清晰阐述的问题。我的观点是:如果你是一位刚开始学习持久化框架的新手,并在选择框架时感到迷茫,请你不妨按照本文的方法实践一下MyBatis,在初级阶段它绝不会比JPA更加复杂;同时也能保证完成你的各项设计目标。你可以将本文作为起点继续深入探索JPA,并通过后续实践去体会这两种工具之间的差异。

该款卓越的持久层框架提供了一系列强大功能与灵活配置选择。这款杰出的持久层框架提供了定制化 SQL 语句、存储过程以及高级映射功能。该框架省却了几乎所有 JDBC 代码及相关操作工作。允许用户通过简便的 XML 格式或注解轻松配置与映射原始类型、接口与 Java POJO(普通老式 Java 对象)至数据库表记录。

根据官方文档的表述, 持久层框架具有两个主要价值: 首先, 它主要实现了对 JDBC 连接逻辑的封装, 从而避免了大量重复性操作, 其工作的重点应当放在编写 SQL 语句以及数据库设计上; 其次, 它同时保持了 POJO 结构, 从而确保数据以对象形式长期稳定地存在于程序运行过程中, 显著提高了数据交互效率。

基本的SQL语句可以通过注解直接标注于方法中;对于复杂的查询语句或大量SQL代码,则更适合采用接口与XML文档相结合的方式来处理;为了使形式统一,并特别针对新手用户而言,在他们的解决方案中建议将所有的SQL代码都放置于XML文档之中。

该种数据对象间关联的方式由mybatis实现为数据实体与接口操作之间的关联,并采用查询SQL与XML之间的联动机制来完成数据转换。

数据实体类PassengerInfo

复制代码
    package com.oreki.ptss_rear.domain;
    
    import lombok.Data;
    
    @Data
    public class PassengerInfo {
       private Integer passengerId;
       private String passengerName;
       private String passengerPassword;
       private String passengerIdentity;
       private String passengerPhone;
       private Float passengerAccount;
    }

@Data注解源自Lombok插件库,该工具可帮助您隐式生成如Set、Get和ToString等常见方法(值得注意的是,默认情况下还会为获取器和设置器生成构造器,以减少显式的代码出现总是明智的选择)

此外,在功能上与JPA相比

接口类PassengerInfoMapper

复制代码
    package com.oreki.ptss_rear.mapper;
    
    import com.oreki.ptss_rear.domain.PassengerInfo;
    import org.apache.ibatis.annotations.Param;
    import java.util.List;
    
    public interface PassengerInfoMapper {
       int deleteByPrimaryKey(Integer passengerId);
    
       int insert(PassengerInfo record);
    
       int insertSelective(PassengerInfo record);
    
       int updateByPrimaryKeySelective(PassengerInfo record);
    
       int updateByPrimaryKey(PassengerInfo record);
    
       int updateByPrimaryKeyCharge(@Param(value = "passengerId") Integer passengerId,
                                @Param(value = "passengerAccount") Float passengerAccount);
    
       List<PassengerInfo> getList();
    
       PassengerInfo selectByPassengerName(String passengerName);
    
       PassengerInfo selectByPrimaryKey(Integer passengerId);
    
       List<PassengerInfo> selectListByName(String searchtext);
    }

在接口类中导入实体类后就建立起了方法与实体数据的联系

在MyBatis中使用时,默认会提供该标记符,在作为数据库访问接口的配置层(通常称为Dao层)中使用,默认会提供该标记符,在作为数据库访问接口的配置层(通常称为Dao层)中使用,默认会提供该标记符,在作为数据库访问接口的配置层(通常称为Dao层)中使用,默认会提供该标记符

书写sql语句的xml文档PassengerMapper.xml

复制代码
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.oreki.ptss_rear.mapper.PassengerInfoMapper">
    <resultMap id="BaseResultMap" type="com.oreki.ptss_rear.domain.PassengerInfo">
        <id column="passenger_id" jdbcType="INTEGER" property="passengerId" />
        <result column="passenger_name" jdbcType="VARCHAR" property="passengerName" />
        <result column="passenger_password" jdbcType="VARCHAR" property="passengerPassword" />
        <result column="passenger_identity" jdbcType="VARCHAR" property="passengerIdentity" />
        <result column="passenger_phone" jdbcType="VARCHAR" property="passengerPhone" />
        <result column="passenger_account" jdbcType="REAL" property="passengerAccount" />
    </resultMap>
    <sql id="Base_Column_List">
    passenger_id, passenger_name, passenger_password, 
    passenger_identity,passenger_phone, passenger_account
      </sql>
    
    <select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">
    select *
    from passenger_info
    where passenger_id = #{passengerId,jdbcType=INTEGER}
      </select>
    
    <select id="getList" resultMap="BaseResultMap">
    select *
    from passenger_info
      </select>
    
    <select id="selectByPassengerName" parameterType="java.lang.String" resultMap="BaseResultMap">
    select *
    from passenger_info
    where passenger_name = #{passengerName,jdbcType=VARCHAR}
      </select>
    
    <select id="selectListByName" parameterType="java.lang.String" resultMap="BaseResultMap">
    select *
    from passenger_info
    where passenger_name like concat ('%',#{searchtext},'%')
      </select>
    
    <delete id="deleteByPrimaryKey" parameterType="java.lang.Integer">
    delete from passenger_info
    where passenger_id = #{passengerId,jdbcType=INTEGER}
      </delete>
    
    <insert id="insert" parameterType="com.oreki.ptss_rear.domain.PassengerInfo">
    insert into passenger_info (passenger_id, avatar, passenger_name,
      passenger_password, passenger_gender, passenger_identity,
      passenger_phone, passenger_account, register_time
      )
    values (#{passengerId,jdbcType=INTEGER}, #{avatar,jdbcType=VARCHAR}, #{passengerName,jdbcType=VARCHAR},
      #{passengerPassword,jdbcType=VARCHAR}, #{passengerGender,jdbcType=VARCHAR}, #{passengerIdentity,jdbcType=VARCHAR},
      #{passengerPhone,jdbcType=VARCHAR}, #{passengerAccount,jdbcType=REAL}, #{registerTime,jdbcType=TIMESTAMP}
      )
      </insert>
    
    <insert id="insertSelective" parameterType="com.oreki.ptss_rear.domain.PassengerInfo">
        insert into passenger_info
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <if test="passengerId != null">
                passenger_id,
            </if>
            <if test="avatar != null">
                avatar,
            </if>
            <if test="passengerName != null">
                passenger_name,
            </if>
            <if test="passengerPassword != null">
                passenger_password,
            </if>
            <if test="passengerGender != null">
                passenger_gender,
            </if>
            <if test="passengerIdentity != null">
                passenger_identity,
            </if>
            <if test="passengerPhone != null">
                passenger_phone,
            </if>
            <if test="passengerAccount != null">
                passenger_account,
            </if>
            <if test="registerTime != null">
                register_time,
            </if>
        </trim>
        <trim prefix="values (" suffix=")" suffixOverrides=",">
            <if test="passengerId != null">
                #{passengerId,jdbcType=INTEGER},
            </if>
            <if test="avatar != null">
                #{avatar,jdbcType=VARCHAR},
            </if>
            <if test="passengerName != null">
                #{passengerName,jdbcType=VARCHAR},
            </if>
            <if test="passengerPassword != null">
                #{passengerPassword,jdbcType=VARCHAR},
            </if>
            <if test="passengerGender != null">
                #{passengerGender,jdbcType=VARCHAR},
            </if>
            <if test="passengerIdentity != null">
                #{passengerIdentity,jdbcType=VARCHAR},
            </if>
            <if test="passengerPhone != null">
                #{passengerPhone,jdbcType=VARCHAR},
            </if>
            <if test="passengerAccount != null">
                #{passengerAccount,jdbcType=REAL},
            </if>
            <if test="registerTime != null">
                #{registerTime,jdbcType=TIMESTAMP},
            </if>
        </trim>
    </insert>
    
    <update id="updateByPrimaryKeySelective" parameterType="com.oreki.ptss_rear.domain.PassengerInfo">
        update passenger_info
        <set>
            <!--<if test="avatar != null">
                avatar = #{avatar,jdbcType=VARCHAR},
            </if>-->
            <if test="passengerName != null">
                passenger_name = #{passengerName,jdbcType=VARCHAR},
            </if>
            <if test="passengerPassword != null">
                passenger_password = #{passengerPassword,jdbcType=VARCHAR},
            </if>
            <if test="passengerIdentity != null">
                passenger_identity = #{passengerIdentity,jdbcType=VARCHAR},
            </if>
            <if test="passengerPhone != null">
                passenger_phone = #{passengerPhone,jdbcType=VARCHAR},
            </if>
            <if test="passengerAccount != null">
                passenger_account = #{passengerAccount,jdbcType=REAL},
            </if>
        </set>
        where passenger_id = #{passengerId,jdbcType=INTEGER}
    </update>
    
    <update id="updateByPrimaryKey" parameterType="com.oreki.ptss_rear.domain.PassengerInfo">
    update Passenger_info
    set avatar = #{avatar,jdbcType=VARCHAR},
      passenger_name = #{passengerName,jdbcType=VARCHAR},
      passenger_password = #{passengerPassword,jdbcType=VARCHAR},
      passenger_gender = #{passengerGender,jdbcType=VARCHAR},
      passenger_identity = #{passengerIdentity,jdbcType=VARCHAR},
      passenger_phone = #{passengerPhone,jdbcType=VARCHAR},
      passenger_account = #{passengerAccount,jdbcType=REAL},
      register_time = #{registerTime,jdbcType=TIMESTAMP}
    where passenger_id = #{passengerId,jdbcType=INTEGER}
      </update>
    
    <update id="updateByPrimaryKeyCharge">
    update Passenger_info
    set passenger_account = #{passengerAccount,jdbcType=REAL}
    where passenger_id = #{passengerId,jdbcType=INTEGER};
      </update>
    
    </mapper>

头两行是一般xml文件的规范

标签通过namespace属性,可以确定该文档实现的是哪一个接口

标签标识了当前对应集类型,默认为BaseResultMap;type属性明确了操作所使用的数据库表及其关联的实体类型。

resultMap内部的标签标识了主键;每个标签对应地将Table中的列名与实体的对象名称一一对应(请注意,在MySQL中大小写不敏感)

4.MVC框架

体系结构Model—呈现方式View—执行机构Controller(MVC)是一种在上个世纪出现的软件设计体系结构,在该体系结构经历Model1和Model2时代的发展阶段后如今已有诸如SpringMVC等成熟解决方案来实现这一架构

这对仅凭小型程序编程经验的学习者而言,掌握大型软件模块间相互作用与数据传输机制这一项成熟且高效的模式具有重要意义。其具有松散的结构特征和较低的耦合度,并且能够无缝集成Spring框架系统,在实际应用中展现出显著的优势。

四、功能展示

image-20201204153044023

主界面,进行搜索或点击图片都可进入购票详情页

image-20201204154107997

机票详情

image-20201204153308834

机票检索

image-20201204153425844

钱包界面

image-20201204153550672

订单中心,可进行改签/退票等操作

image-20201204154507213

改签界面,多退少补

五、DEBUG记录

Tip1

数据库:实体类中的variable name与 database中的 table name及column name匹配时需要注意以下几点:
Java variable names are case-sensitive, allowing the use of uppercase letters to separate compound words in a long variable name.
However, most database management systems (DBMS) are case-insensitive and do not enforce any specific display format for case.
It is important to note that in reality, the case of the actual characters serves as the key factor for distinguishing different database columns.
Therefore, when designing data structures, pay close attention to this aspect.

复制代码
    e.g
    错误×:
    	变量passengerId对应数据库字段passengerId
    正确√:
    	passengerId → passenger_id

修改图片路径报错
复制代码
      Module not found Can't resolve './src/assets/img/Aurora.jpg' in 'C:\Users\HP\myproject\passenger_ticket_sell\src\views\passenger\home'

解决办法:项目内绝对路径改写为相对路径

当第一次将代码改为相对路径并进行编译后,在使用绝对路径或者@标签的情况下都能够方便地定位到相应的资源。其中原因之一可能是需要先注册一次。

复制代码
    url("src/assets/img/Paris.jpg");	→	url("../../../assets/img/Paris.jpg");

前端500

可能是因为服务器未返回有效数据,在这种情况下(响应体为对象类型),若后端接收到的数据字段全部为null,则需使用@RequestBody标签以与响应体内变量建立关联。

如果后端以参数形式接收数据的话,建议REST风格

josn直接装配到后端参数解决ing


动态读取图片(数据库路径)

img属性

复制代码
    <img
      @click="showdetial(item.ticketId)"
      :src="imgUrl(item.ticketImg)"
      width="250px"
      height="200px"
    />

该方法返回的是动态路径,在调用require操作时必须紧跟路径指示。对于所有访问的资源而言,请确保它们均需预先添加'.../.../.../assets/img/'这一前缀,并将上述部分连接后视为完整的文件路径。建议不要直接将img字段注入到此位置以避免可能出现的问题:直接注入会导致错误。

复制代码
    imgUrl(img){
      return require("../../../assets/img/" + img);
    }

全部评论 (0)

还没有任何评论哟~