基于ssm的航空订票系统
基于ssm的航空訂票系統
一、技術棧
? 前端
? vue全家桶、element-ui組件庫、moment.js插件
? 后端
? springboot + springmvc+ mybatis
二、功能描述
本系統是基于B/S架構的航空訂票系統
系統分為三大用戶–乘客、航空公司、后臺管理員,本次課程設計主要實現了乘客界面,包括購票、選座、充值、退款、改簽等
三、技術框架
1、界面設計
Vue是一套用于構建用戶界面的漸進式框架。與其它大型框架不同的是,Vue 被設計為可以自底向上逐層應用。Vue 的核心庫只關注視圖層,不僅易于上手,還便于與第三方庫或既有項目整合。
上面這段官方解釋的意思是,vue提供了一種組件化設計的方式,也就是說,你可以在單個vue對象中構建起實現某些功能compopent,再在下一個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 {@Overridepublic 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*,把json表封裝成類實例,再調用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、持久層
現在使用最廣泛的兩種持久層框架是JPA和mybatis,這兩者都有各自忠實的使用者,孰優孰劣也不是我這樣的技術小白講得清楚的,不過我的建議是,如果你剛剛接觸持久層框架而整糾結于二者的選擇,不妨就照著這篇博客試試mybatis,在初級階段,它絕不比JPA更復雜,同時也能保證完成你的各項設計目標。你可以在下一次實驗中嘗試JPA,再來體會一下二者的區別
MyBatis 是一款優秀的持久層框架,它支持自定義 SQL、存儲過程以及高級映射。MyBatis 免除了幾乎所有的 JDBC 代碼以及設置參數和獲取結果集的工作。MyBatis 可以通過簡單的 XML 或注解來配置和映射原始類型、接口和 Java POJO(Plain Old Java Objects,普通老式 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等方法(雖然也有getter、setter的Constructor自動生成器,不過減少顯式出現的代碼量總是好的)
另外,不同于JPA,mybatis不需要聲明數據實體類,也就不需要設置主鍵(對比于JPA的@Entity和@Id標簽)
接口類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); }在接口類中導入實體類后就建立起了方法與實體數據的聯系
@Param是MyBatis所提供的,作為Dao層的注解,作用是用于傳遞參數,從而可以與SQL中的的字段名相對應,解決了可讀性和直觀性的問題
書寫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_infowhere 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_infowhere passenger_name = #{passengerName,jdbcType=VARCHAR}</select><select id="selectListByName" parameterType="java.lang.String" resultMap="BaseResultMap">select *from passenger_infowhere passenger_name like concat ('%',#{searchtext},'%')</select><delete id="deleteByPrimaryKey" parameterType="java.lang.Integer">delete from passenger_infowhere 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_infoset 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_infoset passenger_account = #{passengerAccount,jdbcType=REAL}where passenger_id = #{passengerId,jdbcType=INTEGER};</update></mapper>頭兩行是一般xml文件的規范
標簽通過namespace屬性,可以確定該文檔實現的是哪一個接口
標簽,id屬性指定了當前對應集類型,一般是BaseResultMap;type屬性指明了操作的數據庫Table和項目中的Entity實體的對應關系。
resultMap內部的標簽說明了主鍵,標簽將Table中的列名和實體的對象名進行對應(注意MySql不區分大小寫)
4.MVC框架
模式Model—視圖View—控制器Controller(MVC)是上世紀出現的一種軟件設計模式,這一模式早期發展(Model1和Model2時代)后,現在有如SpringMVC這樣的方案
這對僅有過小型程序編程經驗的學習者來說是理解大型軟件模塊間相互作用和交流的一種優秀模式,結構松散、耦合、與 Spring 無縫集成等特性讓其大放異彩
四、功能展示
主界面,進行搜索或點擊圖片都可進入購票詳情頁
機票詳情
機票檢索
錢包界面
訂單中心,可進行改簽/退票等操作
改簽界面,多退少補
五、DEBUG記錄
Tip1
數據庫:實體類中的變量名(包括類名)與數據庫中的字段名(包括表名)匹配時,要注意這樣一條規則,java變量大小寫敏感,可以在一個長變量名中通過大寫字母分隔單詞;數據庫大小寫不敏感,通過數據庫管理工具看到的顯示大小寫只是一種展示,變量名映射為字段名、類名映射為表名,大寫分隔轉為橫杠分隔
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
有可能使因為后臺沒有傳回數據,這時如果出現后端接收的json數據全為null的情況,當接收體是對象時,需要@RequestBody標簽,即>json通過該標簽和對象內變量建立聯系(同名)
如果后端以參數形式接收數據的話,建議REST風格
josn直接裝配到后端參數解決ing
動態讀取圖片(數據庫路徑)
img屬性
<img@click="showdetial(item.ticketId)":src="imgUrl(item.ticketImg)"width="250px"height="200px" />方法中返回動態的路徑,require后必須接路徑,所有需要有"…/…/…/assets/img/“前綴,拼接起來解釋成路徑,
不能直接通過img傳入”…/…/…/assets/img/test.jpg"再require(img),這樣解釋成String,會報錯
總結
以上是生活随笔為你收集整理的基于ssm的航空订票系统的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 驱动06.触摸屏驱动程序
- 下一篇: 政务信息系统整合共享实施方案