第5章 預約管理-預約設置
1. 需求分析
前面我們已經完成了檢查項管理、檢查組管理、套餐管理等。接下來我們需要進行預約設置,其實就是設置每一天的體檢預約最大數量。客戶可以通過微信端在線預約,在線預約時需要選擇體檢的時間,如果客戶選擇的時間已經預約滿則無法進行預約。
2. Apache POI
2.1 POI介紹
Apache POI是用Java編寫的免費開源的跨平台的Java API,Apache POI提供API給Java程序對Microsoft Office格式檔案讀和寫的功能,其中使用最多的就是使用POI操作Excel文件。
jxl:專門操作Excel
maven坐標:
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.14</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.14</version>
</dependency>
POI結構:
HSSF - 提供讀寫Microsoft Excel XLS格式檔案的功能
XSSF - 提供讀寫Microsoft Excel OOXML XLSX格式檔案的功能
HWPF - 提供讀寫Microsoft Word DOC格式檔案的功能
HSLF - 提供讀寫Microsoft PowerPoint格式檔案的功能
HDGF - 提供讀Microsoft Visio格式檔案的功能
HPBF - 提供讀Microsoft Publisher格式檔案的功能
HSMF - 提供讀Microsoft Outlook格式檔案的功能
2.2 入門案例
2.2.1 從Excel文件讀取數據
使用POI可以從一個已經存在的Excel文件中讀取數據
//創建工作簿
XSSFWorkbook workbook = new XSSFWorkbook("D:\\hello.xlsx");
//獲取工作表,既可以根據工作表的順序獲取,也可以根據工作表的名稱獲取
XSSFSheet sheet = workbook.getSheetAt(0);
//遍歷工作表獲得行對象
for (Row row : sheet) {
//遍歷行對象獲取單元格對象
for (Cell cell : row) {
//獲得單元格中的值
String value = cell.getStringCellValue();
System.out.println(value);
}
}
workbook.close();
通過上面的入門案例可以看到,POI操作Excel表格封裝了幾個核心對象:
XSSFWorkbook:工作簿
XSSFSheet:工作表
Row:行
Cell:單元格
上面案例是通過遍歷工作表獲得行,遍歷行獲得單元格,最終獲取單元格中的值。
還有一種方式就是獲取工作表最后一個行號,從而根據行號獲得行對象,通過行獲取最后一個單元格索引,從而根據單元格索引獲取每行的一個單元格對象,代碼如下:
//創建工作簿
XSSFWorkbook workbook = new XSSFWorkbook("D:\\hello.xlsx");
//獲取工作表,既可以根據工作表的順序獲取,也可以根據工作表的名稱獲取
XSSFSheet sheet = workbook.getSheetAt(0);
//獲取當前工作表最后一行的行號,行號從0開始
int lastRowNum = sheet.getLastRowNum();
for(int i=0;i<=lastRowNum;i++){
//根據行號獲取行對象
XSSFRow row = sheet.getRow(i);
short lastCellNum = row.getLastCellNum();
for(short j=0;j<lastCellNum;j++){
String value = row.getCell(j).getStringCellValue();
System.out.println(value);
}
}
workbook.close();
2.2.2 向Excel文件寫入數據
使用POI可以在內存中創建一個Excel文件並將數據寫入到這個文件,最后通過輸出流將內存中的Excel文件下載到磁盤
//在內存中創建一個Excel文件
XSSFWorkbook workbook = new XSSFWorkbook();
//創建工作表,指定工作表名稱
XSSFSheet sheet = workbook.createSheet("傳智播客");
//創建行,0表示第一行
XSSFRow row = sheet.createRow(0);
//創建單元格,0表示第一個單元格
row.createCell(0).setCellValue("編號");
row.createCell(1).setCellValue("名稱");
row.createCell(2).setCellValue("年齡");
XSSFRow row1 = sheet.createRow(1);
row1.createCell(0).setCellValue("1");
row1.createCell(1).setCellValue("小明");
row1.createCell(2).setCellValue("10");
XSSFRow row2 = sheet.createRow(2);
row2.createCell(0).setCellValue("2");
row2.createCell(1).setCellValue("小王");
row2.createCell(2).setCellValue("20");
//通過輸出流將workbook對象下載到磁盤
FileOutputStream out = new FileOutputStream("D:\\itcast.xlsx");
workbook.write(out);
out.flush();
out.close();
workbook.close();
3. 批量導入預約設置信息
預約設置信息對應的數據表為t_ordersetting,預約設置操作對應的頁面為ordersetting.html
t_ordersetting表結構:
orderDate:預約日期
number:可預約人數
reservations:已預約人數
批量導入預約設置信息操作過程:
1、點擊模板下載按鈕下載Excel模板文件
2、將預約設置信息錄入到模板文件中
3、點擊上傳文件按鈕將錄入完信息的模板文件上傳到服務器
4、通過POI讀取上傳文件的數據並保存到數據庫
3.1 完善頁面
3.1.1 提供模板文件
資料中已經提供了Excel模板文件ordersetting_template.xlsx,將文件放在health_backend工程的template目錄
3.1.2 實現模板文件下載
為模板下載按鈕綁定事件實現模板文件下載
<el-button style="margin-bottom: 20px;margin-right: 20px" type="primary"
@click="downloadTemplate()">模板下載</el-button>
//模板文件下載
downloadTemplate(){
window.location.href="../../template/ordersetting_template.xlsx";
}
3.1.3 文件上傳
使用ElementUI的上傳組件實現文件上傳並綁定相關事件
<el-upload action="/ordersetting/upload.do"
name="excelFile"
:show-file-list="false"
:on-success="handleSuccess"
:before-upload="beforeUpload">
<el-button type="primary">上傳文件</el-button>
</el-upload>
handleSuccess(response, file) {
if(response.flag){
this.$message({
message: response.message,
type: 'success'
});
}else{
this.$message.error(response.message);
}
}
beforeUpload(file){
const isXLS = file.type === 'application/vnd.ms-excel';
if(isXLS){
return true;
}
const isXLSX = file.type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
if (isXLSX) {
return true;
}
this.$message.error('上傳文件只能是xls或者xlsx格式!');
return false;
}
3.2 后台代碼
3.2.1 Controller
將資料中的POIUtils工具類復制到health_common工程
在health_backend工程創建OrderSettingController並提供upload方法
package com.itheima.controller;
import com.alibaba.dubbo.config.annotation.Reference;
import com.itheima.constant.MessageConstant;
import com.itheima.entity.Result;
import com.itheima.pojo.OrderSetting;
import com.itheima.service.OrderSettingService;
import com.itheima.utils.POIUtils;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
* 預約設置
*/
@RestController
@RequestMapping("/ordersetting")
public class OrderSettingController {
@Reference
private OrderSettingService orderSettingService;
/**
* Excel文件上傳,並解析文件內容保存到數據庫
* @param excelFile
* @return
*/
@RequestMapping("/upload")
public Result upload(@RequestParam("excelFile")MultipartFile excelFile){
try {
//讀取Excel文件數據
List<String[]> list = POIUtils.readExcel(excelFile);
if(list != null && list.size() > 0){
List<OrderSetting> orderSettingList = new ArrayList<>();
for (String[] strings : list) {
OrderSetting orderSetting =
new OrderSetting(new Date(strings[0]), Integer.parseInt(strings[1]));
orderSettingList.add(orderSetting);
}
orderSettingService.add(orderSettingList);
}
} catch (IOException e) {
e.printStackTrace();
return new Result(false, MessageConstant.IMPORT_ORDERSETTING_FAIL);
}
return new Result(true,MessageConstant.IMPORT_ORDERSETTING_SUCCESS);
}
}
3.2.2 服務接口
創建OrderSettingService服務接口並提供新增方法
package com.itheima.service;
import com.itheima.pojo.OrderSetting;
import java.util.List;
import java.util.Map;
public interface OrderSettingService {
public void add(List<OrderSetting> list);
}
3.2.3 服務實現類
創建服務實現類OrderSettingServiceImpl並實現新增方法
package com.itheima.service;
import com.alibaba.dubbo.config.annotation.Service;
import com.itheima.dao.OrderSettingDao;
import com.itheima.pojo.OrderSetting;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
/**
* 預約設置服務
*/
@Service(interfaceClass = OrderSettingService.class)
@Transactional
public class OrderSettingServiceImpl implements OrderSettingService {
@Autowired
private OrderSettingDao orderSettingDao;
//批量添加
public void add(List<OrderSetting> list) {
if(list != null && list.size() > 0){
for (OrderSetting orderSetting : list) {
//檢查此數據(日期)是否存在
long count = orderSettingDao.findCountByOrderDate(orderSetting.getOrderDate());
if(count > 0){
//已經存在,執行更新操作
orderSettingDao.editNumberByOrderDate(orderSetting);
}else{
//不存在,執行添加操作
orderSettingDao.add(orderSetting);
}
}
}
}
}
3.2.4 Dao接口
創建Dao接口OrderSettingDao並提供更新和新增方法
package com.itheima.dao;
import com.itheima.pojo.OrderSetting;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public interface OrderSettingDao {
public void add(OrderSetting orderSetting);
public void editNumberByOrderDate(OrderSetting orderSetting);
public long findCountByOrderDate(Date orderDate);
}
3.2.5 Mapper映射文件
創建Mapper映射文件OrderSettingDao.xml並提供相關SQL
<?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.itheima.dao.OrderSettingDao" >
<!--新增-->
<insert id="add" parameterType="com.itheima.pojo.OrderSetting">
insert into t_ordersetting
(orderDate,number,reservations)
values
(#{orderDate},#{number},#{reservations})
</insert>
<!--根據日期更新預約人數-->
<update id="editNumberByOrderDate" parameterType="com.itheima.pojo.OrderSetting">
update t_ordersetting set number = #{number} where orderDate = #{orderDate}
</update>
<!--根據預約日期查詢-->
<select id="findCountByOrderDate" parameterType="java.util.Date" resultType="long">
select count(*) from t_ordersetting where orderDate = #{orderDate}
</select>
</mapper>
4. 日歷展示預約設置信息
前面已經完成了預約設置功能,現在就需要通過日歷的方式展示出來每天設置的預約人數。
在頁面中已經完成了日歷的動態展示,我們只需要查詢當前月份的預約設置信息並展示到日歷中即可,同時在日歷中還需要展示已經預約的人數,效果如下:
4.1 完善頁面
4.1.1 使用靜態數據調試
為了能夠快速看到效果,我們可以先使用靜態數據模擬,然后再改為發送ajax請求查詢數據庫。
實現步驟:
(1)預約設置數據對應的模型數據為leftobj,在initData方法最后為leftobj模型數據賦值:
this.leftobj = [
{ date: 1, number: 120, reservations: 1 },
{ date: 3, number: 120, reservations: 1 },
{ date: 4, number: 120, reservations: 120 },
{ date: 6, number: 120, reservations: 1 },
{ date: 8, number: 120, reservations: 1 }
];
其中date表示日期,number表示可預約人數,reservations表示已預約人數
(2)使用VUE的v-for標簽遍歷上面的leftobj模型數據,展示到日歷上:
<template>
<template v-for="obj in leftobj">
<template v-if="obj.date == dayobject.day.getDate()">
<template v-if="obj.number > obj.reservations">
<div class="usual">
<p>可預約{{obj.number}}人</p>
<p>已預約{{obj.reservations}}人</p>
</div>
</template>
<template v-else>
<div class="fulled">
<p>可預約{{obj.number}}人</p>
<p>已預約{{obj.reservations}}人</p>
<p>已滿</p>
</div>
</template>
</template>
</template>
<button v-if="dayobject.day > today"
@click="handleOrderSet(dayobject.day)" class="orderbtn">設置</button>
</template>
4.1.2 發送ajax獲取動態數據
將上面的靜態模擬數據去掉,改為發送ajax請求,根據當前頁面對應的月份查詢數據庫獲取預約設置信息,將查詢結果賦值給leftobj模型數據
//發送ajax請求,根據當前頁面對應的月份查詢預約設置信息
axios.post(
"/ordersetting/getOrderSettingByMonth.do?date="+this.currentYear+'-'+this.currentMonth
).then((response)=>{
if(response.data.flag){
//為模型數據賦值,通過雙向綁定展示到日歷中
this.leftobj = response.data.data;
}else{
this.$message.error(response.data.message);
}
});
4.2 后台代碼
4.2.1 Controller
在OrderSettingController中提供getOrderSettingByMonth方法,根據月份查詢預約設置信息
/**
* 根據日期查詢預約設置數據(獲取指定日期所在月份的預約設置數據)
* @param date
* @return
*/
@RequestMapping("/getOrderSettingByMonth")
public Result getOrderSettingByMonth(String date){//參數格式為:2019-03
try{
List<Map> list = orderSettingService.getOrderSettingByMonth(date);
//獲取預約設置數據成功
return new Result(true,MessageConstant.GET_ORDERSETTING_SUCCESS,list);
}catch (Exception e){
e.printStackTrace();
//獲取預約設置數據失敗
return new Result(false,MessageConstant.GET_ORDERSETTING_FAIL);
}
}
4.2.2 服務接口
在OrderSettingService服務接口中擴展方法getOrderSettingByMonth
public List<Map> getOrderSettingByMonth(String date);//參數格式為:2019-03
4.2.3 服務實現類
在OrderSettingServiceImpl服務實現類中實現方法getOrderSettingByMonth
//根據日期查詢預約設置數據
public List<Map> getOrderSettingByMonth(String date) {//2019-3
String dateBegin = date + "-1";//2019-3-1
String dateEnd = date + "-31";//2019-3-31
Map map = new HashMap();
map.put("dateBegin",dateBegin);
map.put("dateEnd",dateEnd);
List<OrderSetting> list = orderSettingDao.getOrderSettingByMonth(map);
List<Map> data = new ArrayList<>();
for (OrderSetting orderSetting : list) {
Map orderSettingMap = new HashMap();
orderSettingMap.put("date",orderSetting.getOrderDate().getDate());//獲得日期(幾號)
orderSettingMap.put("number",orderSetting.getNumber());//可預約人數
orderSettingMap.put("reservations",orderSetting.getReservations());//已預約人數
data.add(orderSettingMap);
}
return data;
}
4.2.4 Dao接口
在OrderSettingDao接口中擴展方法getOrderSettingByMonth
public List<OrderSetting> getOrderSettingByMonth(Map date);
4.2.5 Mapper映射文件
在OrderSettingDao.xml文件中擴展SQL
<!--根據月份查詢預約設置信息-->
<select id="getOrderSettingByMonth"
parameterType="hashmap"
resultType="com.itheima.pojo.OrderSetting">
select * from t_ordersetting where orderDate between #{dateBegin} and #{dateEnd}
</select>
5. 基於日歷實現預約設置
本章節要完成的功能為通過點擊日歷中的設置按鈕來設置對應日期的可預約人數。效果如下:
5.1 完善頁面
5.1.1 為設置按鈕綁定事件
為日歷中的設置按鈕綁定單擊事件,當前日期作為參數
<button v-if="dayobject.day > today"
@click="handleOrderSet(dayobject.day)" class="orderbtn">設置</button>
//預約設置
handleOrderSet(day){
alert(day);
}
5.1.2 彈出預約設置窗口並發送ajax請求
完善handleOrderSet方法,彈出預約設置窗口,用戶點擊確定按鈕則發送ajax請求
//預約設置
handleOrderSet(day){
this.$prompt('請輸入可預約人數', '預約設置', {
confirmButtonText: '確定',
cancelButtonText: '取消',
inputPattern: /^[0-9]*[1-9][0-9]*$/,
inputErrorMessage: '只能輸入正整數'
}).then(({ value }) => {
//發送ajax請求根據日期修改可預約人數
axios.post("/ordersetting/editNumberByDate.do",{
orderDate:this.formatDate(day.getFullYear(),day.getMonth()+1,day.getDate()), //日期
number:value //可預約人數
}).then((response)=>{
if(response.data.flag){
this.initData(this.formatDate(day.getFullYear(), day.getMonth() + 1, 1));
this.$message({
type: 'success',
message: response.data.message
});
}else{
this.$message.error(response.data.message);
}
});
}).catch(() => {
this.$message({
type: 'info',
message: '已取消'
});
});
}
5.2 后台代碼
5.2.1 Controller
在OrderSettingController中提供方法editNumberByDate
/**
* 根據指定日期修改可預約人數
* @param orderSetting
* @return
*/
@RequestMapping("/editNumberByDate")
public Result editNumberByDate(@RequestBody OrderSetting orderSetting){
try{
orderSettingService.editNumberByDate(orderSetting);
//預約設置成功
return new Result(true,MessageConstant.ORDERSETTING_SUCCESS);
}catch (Exception e){
e.printStackTrace();
//預約設置失敗
return new Result(false,MessageConstant.ORDERSETTING_FAIL);
}
}
5.2.2 服務接口
在OrderSettingService服務接口中提供方法editNumberByDate
public void editNumberByDate(OrderSetting orderSetting);
5.2.3 服務實現類
在OrderSettingServiceImpl服務實現類中實現editNumberByDate
//根據日期修改可預約人數
public void editNumberByDate(OrderSetting orderSetting) {
long count = orderSettingDao.findCountByOrderDate(orderSetting.getOrderDate());
if(count > 0){
//當前日期已經進行了預約設置,需要進行修改操作
orderSettingDao.editNumberByOrderDate(orderSetting);
}else{
//當前日期沒有進行預約設置,進行添加操作
orderSettingDao.add(orderSetting);
}
}
5.2.4 Dao接口
在OrderSettingDao接口中提供方法
public void editNumberByOrderDate(OrderSetting orderSetting);
public long findCountByOrderDate(Date orderDate);
5.2.5 Mapper映射文件
在OrderSettingDao.xml映射文件中提供SQL
<!--根據日期更新可預約人數-->
<update id="editNumberByOrderDate" parameterType="com.itheima.pojo.OrderSetting">
update t_ordersetting set number = #{number} where orderDate = #{orderDate}
</update>
<!--根據預約日期查詢-->
<select id="findCountByOrderDate" parameterType="java.util.Date" resultType="long">
select count(*) from t_ordersetting where orderDate = #{orderDate}
</select>