1.1 体检预约流程
用户可以通过如下操作流程进行体检预约:
1、在移动端首页点击体检预约,页面跳转到套餐列表页面
2、在套餐列表页面点击要预约的套餐,页面跳转到套餐详情页面
3、在套餐详情页面点击立即预约,页面跳转到预约页面
4、在预约页面录入体检人信息,包括手机号,点击发送验证码
5、在预约页面录入收到的手机短信验证码,点击提交预约,完成体检预约
1.2 体检预约
1.2.1 前端页面
在预约页面(/pages/orderInfo.html)进行调整
1.2.1.1 展示预约的套餐信息
- 第一步:从请求路径中获取当前套餐的id
- 第二步:定义模型数据setmeal,用于套餐数据展示
- 第三步:在VUE的钩子函数中发送ajax请求,根据id查询套餐信息。
1.2.1.2 手机号校验
- 第一步:在页面导入的healthmobile.js文件中已经定义了校验手机号的方法
- 第二步:为发送验证码按钮绑定事件sendValidateCode
1.2.1.3 发送验证码之后30秒倒计时效果
前面在sendValidateCode方法中进行了手机号校验,如果校验通过,需要显示30秒倒计时效果
其中,validateCodeButton和clock是在healthmobile.js文件中定义的变量,doLoop是 在healthmobile.js文件中定义的方法。
1.2.1.4 发送ajax请求
在按钮上显示30秒倒计时效果的同时,需要发送ajax请求,在后台给用户发送手机验证码。
1.2.2 后台代码
1.2.2.1 Controller
在heath_mobile中创建ValidateCodeController,提供方法发送短信验证码,并将验证码保存到redis中
@RestController
@RequestMapping("/validateCode")
public class ValidateCodeController {
@Autowired
JedisPool jedisPool;
@RequestMapping("/send4Order")
public Result send4Order(String telephone){
Integer code = ValidateCodeUtils.generateValidateCode(4);//生成4位数字验证码
try {
SMSUtils.sendShortMessage(SMSUtils.VALIDATE_CODE,telephone,code.toString());
} catch (ClientException e) {
e.printStackTrace();
//发送验证码失败
return new Result(false, MessageConstant.SEND_VALIDATECODE_FAIL);
}
System.out.println("发送到手机验证码是:" + code);
//将生成的验证码缓存到redis,并指定过期时间
jedisPool.getResource().setex(telephone+ RedisMessageConstant.SENDTYPE_ORDER,5*60,code.toString());
return new Result(true,MessageConstant.SEND_VALIDATECODE_SUCCESS);
}
}
1.2.3 日历展示
页面中使用DatePicker控件来展示日历。根据需求,最多可以提前一个月进行体检预 约,所以日历控件只展示未来一个月的日期。
其中getSpecifiedDate方法定义在healthmobile.js文件中。
1.2.4 提交预约请求
1.2.4.1 前端页面
为提交预约按钮绑定事件。
其中checkIdCard方法是在healthmobile.js文件中定义的。
1.2.4.2 后台代码
(1) Controller
在health_mobile工程中创建OrderController并提供submitOrder方法.
@RestController
@RequestMapping("/order")
public class OrderController {
@Reference
OrderService orderService;
@Autowired
JedisPool jedisPool;
@RequestMapping("/submit")
public Result submitOrder(@RequestBody Map map){
//获取前台提交过来的手机验证码
String telephone = (String)map.get("telephone");
//获取从redis缓存中存储的验证码
String codeInRedis = jedisPool.getResource().get(telephone+ RedisMessageConstant.SENDTYPE_ORDER);
//获取页面上的验证码
String validateCode = (String)map.get("validateCode");
//校验页面输入的验证码是否输入正确
if(codeInRedis==null||!codeInRedis.equals(validateCode)){
//验证码输入错误
return new Result(false, MessageConstant.VALIDATECODE_ERROR);
}
//如果验证码输入成功,则调用体检预约服务、
Result result = null;
try {
map.put("orderType", Order.ORDERTYPE_WEIXIN);
result = orderService.addOrder(map);
} catch (Exception e) {
e.printStackTrace();
}
if(result.isFlag()){
//预约成功 发送短信通知
String orderDate = (String) map.get("orderDate");
try {
SMSUtils.sendShortMessage(SMSUtils.ORDER_NOTICE,telephone,orderDate);
} catch (ClientException e) {
e.printStackTrace();
}
}
return result;
}
}
(2) 服务接口
在health_interface工程中创建体检预约服务接口OrderService并提供预约方法
public interface OrderService {
//体检预约
Result addOrder(Map map) throws Exception;
}
(3) 服务实现类
在health_service_provider工程中创建体检预约服务实现类OrderServiceImpl并实现体检预约方法。
体检预约方法处理逻辑比较复杂,需要进行如下业务处理:
1、检查用户所选择的预约日期是否已经提前进行了预约设置,如果没有设置则无法进行预约
2、检查用户所选择的预约日期是否已经约满,如果已经约满则无法预约
3、检查用户是否重复预约(同一个用户在同一天预约了同一个套餐),如果是重复预约 则无法完成再次预约
4、检查当前用户是否为会员,如果是会员则直接完成预约,如果不是会员则自动完成注 册并进行预约
5、预约成功,更新当日的已预约人数 实现代码如下:
public class OrderServiceImpl implements OrderService {
@Autowired
OrderDao orderDao;
@Autowired
OrderSettingDao orderSettingDao;
@Autowired
MemberDao memberDao;
@Override
public Result addOrder(Map map) throws Exception {
//检查当前时间是否进行了预约设置
String orderDate = (String)map.get("orderDate");
Date date = DateUtils.parseString2Date(orderDate);
//根据预约日期查询t_ordersetting表是否存在对应的日期,如果存在 才可以预约,如果不存在就不能预约
OrderSetting orderSetting = orderSettingDao.findByOrderDate(date);
if(orderSetting==null){
//预约日期不存在,不能预约
return new Result(false, MessageConstant.SELECTED_DATE_CANNOT_ORDER);
}
//检查预约日期是否约满 如果约满 也不能预约
int number = orderSetting.getNumber();//可预约人数
int reservations = orderSetting.getReservations();//已预约人数
if(reservations==number){
//预约已满,不能预约
return new Result(false,MessageConstant.ORDER_FULL);
}
//检查当前用户是否是会员,如果不是会员也不能预约 根据手机号判断当前用户是否是会员
//检查当前用户是否为会员,根据手机号判断
String telephone = (String) map.get("telephone");
Member member = memberDao.findByTelephone(telephone);
//防止重复预约 需要查询对应会员是否已经预约
if(member!=null){
Integer memberId = member.getId();//会员ID
Integer setmealId = Integer.parseInt((String)map.get("setmealId"));
Order order = new Order(memberId,date,null,null,setmealId);
List<Order> list = orderDao.findByCondition(order);
if(list!=null&&list.size()>0){
//该会员已经预约过,不能再次预约
return new Result(false,MessageConstant.HAS_ORDERED);
}
}
//可以预约 设置预约人数+1
orderSetting.setReservations(orderSetting.getReservations()+1);
orderSettingDao.upateOrderSetting(orderSetting);
if(member==null){
//当前用户不是会员,需要添加到会员列表
member = new Member();
member.setName((String) map.get("name"));
member.setPhoneNumber(telephone);
member.setIdCard((String) map.get("idCard"));
member.setSex((String) map.get("sex"));
member.setRegTime(new Date());
memberDao.add(member);
}
//将预约信息保存到预约表里面
Order order = new Order(member.getId(),date,(String)map.get("orderType"),Order.ORDERSTATUS_NO,Integer.parseInt((String)map.get("setmealId")));
orderDao.add(order);
return new Result(true,MessageConstant.ORDER_SUCCESS,order.getId());
}
}
(4) Dao接口
OrderDao
public interface OrderDao {
List<Order> findByCondition(Order order);
void add(Order order);
Map findDetailsById(Integer id);
}
OrderSettingDao
public interface OrderSettingDao {
Integer findCountByOrderDate(Date orderDate);
void upateOrderSetting(OrderSetting orderSetting);
void insertOrderSetting(OrderSetting orderSetting);
List<OrderSetting> findOrderSettingsByOrderDate(Map<String, String> map);
OrderSetting findByOrderDate(Date date);
}
memberDao
public interface MemberDao {
Member findByTelephone(String telephone);
void add(Member member);
}
1.2.4.3 Mapper映射文件
OrderSettingDao.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.bianyi.dao.OrderSettingDao">
<select id="findCountByOrderDate" resultType="int" parameterType="date">
SELECT COUNT(*) FROM t_ordersetting WHERE orderDate=#{orderDate}
</select>
<update id="upateOrderSetting" parameterType="com.bianyi.pojo.OrderSetting">
UPDATE t_ordersetting SET number=#{number} where orderDate=#{orderDate}
</update>
<insert id="insertOrderSetting" parameterType="com.bianyi.pojo.OrderSetting">
INSERT INTO t_ordersetting(orderDate,number,reservations) VALUES(#{orderDate},#{number},#{reservations})
</insert>
<select id="findOrderSettingsByOrderDate" parameterType="map" resultType="com.bianyi.pojo.OrderSetting">
select * from t_ordersetting where orderDate between #{begin} and #{end}
</select>
<!--
根据预约日期查询对应的预约是否存在
-->
<select id="findByOrderDate" parameterType="date" resultType="com.bianyi.pojo.OrderSetting">
select * from t_ordersetting where orderDate = #{orderDate}
</select>
</mapper>
OrderDao.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.bianyi.dao.OrderDao">
<resultMap id="baseResultMap" type="com.bianyi.pojo.Order">
<id column="id" property="id"/>
<result column="member_id" property="memberId"/>
<result column="orderDate" property="orderDate"/>
<result column="orderType" property="orderType"/>
<result column="orderStatus" property="orderStatus"/>
<result column="setmeal_id" property="setmealId"/>
</resultMap>
<select id="findByCondition" parameterType="com.bianyi.pojo.Order" resultMap="baseResultMap">
select * from t_order
<where>
<if test="id != null">
and id = #{id}
</if>
<if test="memberId != null">
and member_id = #{memberId}
</if>
<if test="orderDate != null">
and orderDate = #{orderDate}
</if>
<if test="orderType != null">
and orderType = #{orderType}
</if>
<if test="orderStatus != null">
and orderStatus = #{orderStatus}
</if>
<if test="setmealId != null">
and setmeal_id = #{setmealId}
</if>
</where>
</select>
<!--
添加预约信息到预约表
-->
<insert id="add" parameterType="com.bianyi.pojo.Order">
<selectKey resultType="java.lang.Integer" order="AFTER"
keyProperty="id">
SELECT LAST_INSERT_ID()
</selectKey>
insert into t_order(member_id,orderDate,orderType,orderStatus,setmeal_id)
values(#{memberId},#{orderDate},#{orderType},#{orderStatus},#{setmealId})
</insert>
<!--
根据预约id查询对应的预约信息(预约信息 会员信息 套餐信息)
-->
<select id="findDetailsById" parameterType="int" resultType="map">
select m.name member ,s.name setmeal,o.orderDate orderDate,o.orderType orderType from
t_order o,
t_member m,
t_setmeal s
where o.member_id=m.id and o.setmeal_id=s.id and o.id=#{id}
</select>
</mapper>
memberDao.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.bianyi.dao.MemberDao">
<!--
根据电话号码查询是否是会员
-->
<select id="findByTelephone" parameterType="String" resultType="com.bianyi.pojo.Member">
select * from t_member where phoneNumber = #{phoneNumber}
</select>
<!--
添加会员
-->
<insert id="add" parameterType="com.bianyi.pojo.Member">
<selectKey resultType="java.lang.Integer" order="AFTER"
keyProperty="id">
SELECT LAST_INSERT_ID()
</selectKey>
insert into t_member(fileNumber,name,sex,idCard,phoneNumber,
regTime,password,email,birthday,remark)
values(#{fileNumber},#{name},#{sex},#{idCard},#{phoneNumber},
#{regTime},#{password},#{email},#{birthday},#{remark})
</insert>
</mapper>
1.3 预约成功页面展示
前面已经完成了体检预约,预约成功后页面会跳转到成功提示页面 (orderSuccess.html)并展示预约的相关信息(体检人、体检套餐、体检时间等)。
1.3.1 前端页面
提供orderSuccess.html页面,展示预约成功后相关信息。
1.3.2 后台代码
1.3.2.1 controller
在OrderController中提供findById方法,根据预约id查询预约相关信息.
/**
* 根据id查询预约信息,包括套餐信息和会员信息
* @param id
* @return
*/
@RequestMapping("/findById")
public Result findById(Integer id){
try {
Map map = orderService.findById(id);
//查询预约信息成功
return new Result(true,MessageConstant.QUERY_ORDER_SUCCESS,map);
} catch (Exception e) {
e.printStackTrace();
//查询预约信息失败
return new Result(false,MessageConstant.QUERY_ORDER_FAIL);
}
}
1.3.2.2 服务接口
在OrderService服务接口中扩展findById方法
public interface OrderService {
//体检预约
Result addOrder(Map map) throws Exception;
Map findById(Integer id) throws Exception;
}
1.3.2.3服务实现类
在OrderServiceImpl服务实现类中实现findById方法
/**
* 根据id查询预约信息,包括套餐信息和会员信息
* @param id
* @return
*/
@Override
public Map findById(Integer id) throws Exception{
Map map = orderDao.findDetailsById(id);
System.out.println("MAP:"+map);
if(map!=null){
Date orderDate = (Date)map.get("orderDate");
map.put("orderDate",DateUtils.parseDate2String(orderDate));
}
return map;
}
1.3.2.4 Dao接口
在OrderDao接口中扩展findDetailsById方法。
public interface OrderDao {
List<Order> findByCondition(Order order);
void add(Order order);
Map findDetailsById(Integer id);
}
1.3.2.5 Mapper映射文件
在OrderDao.xml映射文件中提供SQL语句
<!--
根据预约id查询对应的预约信息(预约信息 会员信息 套餐信息)
-->
<select id="findDetailsById" parameterType="int" resultType="map">
select m.name member ,s.name setmeal,o.orderDate orderDate,o.orderType orderType from
t_order o,
t_member m,
t_setmeal s
where o.member_id=m.id and o.setmeal_id=s.id and o.id=#{id}
</select>