javaweb医院预约项目


title: 1 在线预约案例
项目首页


Snipaste_2023-04-14_09-40-08

学习目标:

熟悉jsp servlet ajax mysql 等 二阶段技术的应用,进一步熟悉前后端交互的流程,培养javaweb方面的编程思想

需求文档

开发文档

准备数据库

// 数据字典表
CREATE TABLE `h_type` (
  `tid` INT(11) NOT NULL,
  `tname` VARCHAR(200) DEFAULT NULL,
  `tgroup` INT(11) DEFAULT NULL,
  `tdesc` VARCHAR(500) DEFAULT NULL,
  PRIMARY KEY (`tid`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;


INSERT  INTO `h_type`(`tid`,`tname`,`tgroup`,`tdesc`) VALUES (1,'未审批',1,NULL),(2,'已同意',1,NULL),(3,'不同意',1,NULL),(4,'儿科',2,NULL),(5,'妇科',2,NULL),(6,'眼科',2,NULL),(7,'骨科',2,NULL),(21,'预约中',7,NULL),(22,'已付款',7,NULL),(23,'已取消',7,NULL),(24,'已完成',7,NULL),(25,'已作废',7,NULL),(43,'院长',3,NULL),(44,'副院长',3,NULL),(45,'主任',3,NULL),(46,'主治医生',3,NULL),(47,'博士生导师',4,NULL),(48,'博士',4,NULL),(49,'研究生',4,NULL),(50,'本科',4,NULL),(51,'遗传学,神经学',5,NULL),(52,'解剖学',5,NULL),(53,'中医理疗',5,NULL),(54,'中医学术',5,NULL),(55,'8:00-10:00',6,NULL),(56,'10:00-12:00',6,NULL),(57,'14:00-16:00',6,NULL),(58,'16:00-18:00',6,NULL);


// 轮休表
CREATE TABLE `h_break` (
  `bid` INT(11) NOT NULL,
  `tid` INT(11) DEFAULT NULL,
  `bstime` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `betime` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `bday` INT(11) DEFAULT NULL,
  `breason` VARCHAR(500) DEFAULT NULL,
  PRIMARY KEY (`bid`),
  KEY `FK_Reference_10` (`tid`),
  CONSTRAINT `FK_Reference_10` FOREIGN KEY (`tid`) REFERENCES `h_type` (`tid`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;

// 角色表
CREATE TABLE `h_role` (
  `rid` INT(11) NOT NULL,
  `rname` VARCHAR(20) DEFAULT NULL,
  PRIMARY KEY (`rid`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;


INSERT  INTO `h_role`(`rid`,`rname`) VALUES (1,'管理员'),(2,'医生'),(3,'用户'),(4,'新闻发布');


// 用户登录表
CREATE TABLE `h_user` (
  `uuid` INT(11) NOT NULL,
  `uname` VARCHAR(16) DEFAULT NULL,
  `upwd` VARCHAR(50) DEFAULT NULL,
  `rid` INT(11) DEFAULT NULL,
  PRIMARY KEY (`uuid`),
  KEY `FK_Reference_1` (`rid`),
  CONSTRAINT `FK_Reference_1` FOREIGN KEY (`rid`) REFERENCES `h_role` (`rid`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;


INSERT  INTO `h_user`(`uuid`,`uname`,`upwd`,`rid`) VALUES (1,'11','1',3),(2,'凯','ICy5YqxZB1uWSwcVLSNLcA==',3),(3,'李白','rZQpOINKNlfY3PUnnXSbjw==',3),(4,'妲己','ICy5YqxZB1uWSwcVLSNLcA==',4),(5,'ys','rZQpOINKNlfY3PUnnXSbjw==',2),(6,'ys2','rZQpOINKNlfY3PUnnXSbjw==',2),(7,'小林哪','ICy5YqxZB1uWSwcVLSNLcA==',2),(8,'admin','ICy5YqxZB1uWSwcVLSNLcA==',1),(9,'貂蝉','ICy5YqxZB1uWSwcVLSNLcA==',3),(10,'妖风','ICy5YqxZB1uWSwcVLSNLcA==',2);



//用户信息表  包含 所有用户信息
CREATE TABLE `h_userinfo` (
  `did` INT(11) NOT NULL AUTO_INCREMENT,
  `dage` INT(11) DEFAULT NULL,
  `drealname` VARCHAR(16) DEFAULT NULL,
  `dsex` INT(11) DEFAULT NULL,
  `dtext` VARCHAR(500) DEFAULT NULL,
  `bid` INT(11) DEFAULT NULL,
  `uuid` INT(11) DEFAULT NULL,
  `ksid` INT(11) DEFAULT NULL,
  `zwid` INT(11) DEFAULT NULL,
  `xlid` INT(11) DEFAULT NULL,
  `zyid` INT(11) DEFAULT NULL,
  `dphone` VARCHAR(15) DEFAULT NULL,
  `didcard` VARCHAR(20) DEFAULT NULL,
  `demail` VARCHAR(30) DEFAULT NULL,
  `dqq` VARCHAR(15) DEFAULT NULL,
  `dnum` INT(11) DEFAULT NULL COMMENT '某时间段内最多预约人数',
  `durl` VARCHAR(200) DEFAULT NULL,
  `dmoney` FLOAT DEFAULT NULL,
  PRIMARY KEY (`did`),
  KEY `FK_Reference_11` (`ksid`),
  KEY `FK_Reference_12` (`zwid`),
  KEY `FK_Reference_15` (`xlid`),
  KEY `FK_Reference_16` (`bid`),
  KEY `FK_Reference_17` (`zyid`),
  KEY `FK_Reference_9` (`uuid`),
  CONSTRAINT `FK_Reference_11` FOREIGN KEY (`ksid`) REFERENCES `h_type` (`tid`),
  CONSTRAINT `FK_Reference_12` FOREIGN KEY (`zwid`) REFERENCES `h_type` (`tid`),
  CONSTRAINT `FK_Reference_15` FOREIGN KEY (`xlid`) REFERENCES `h_type` (`tid`),
  CONSTRAINT `FK_Reference_16` FOREIGN KEY (`bid`) REFERENCES `h_break` (`bid`),
  CONSTRAINT `FK_Reference_17` FOREIGN KEY (`zyid`) REFERENCES `h_type` (`tid`),
  CONSTRAINT `FK_Reference_9` FOREIGN KEY (`uuid`) REFERENCES `h_user` (`uuid`)
) ENGINE=INNODB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8;



INSERT  INTO `h_userinfo`(`did`,`dage`,`drealname`,`dsex`,`dtext`,`bid`,`uuid`,`ksid`,`zwid`,`xlid`,`zyid`,`dphone`,`didcard`,`demail`,`dqq`,`dnum`,`durl`,`dmoney`) VALUES (2,1,'1',1,NULL,NULL,1,NULL,NULL,NULL,NULL,'13663718227','1','1@qq.com','1',NULL,NULL,0),(5,11,'凯皇',1,NULL,NULL,2,NULL,NULL,NULL,NULL,'15738826013','110','1@qq.com','11',NULL,NULL,0),(6,11,'李太白',1,NULL,NULL,3,NULL,NULL,NULL,NULL,'15738826013','111','1@qq.com','22',NULL,NULL,0),(7,11,'ys',1,'牛逼的医生',NULL,5,4,43,47,51,NULL,NULL,NULL,NULL,NULL,'upload/1.jpg',NULL),(8,12,'妲己',NULL,NULL,NULL,4,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(9,13,'ys2',1,NULL,NULL,6,4,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'upload/1.jpg',NULL),(10,18,'林财政',1,'妇科圣手',NULL,7,5,44,47,53,'123',NULL,NULL,NULL,4,'upload/lincaizheng.jpg',100),(11,11,'貂小婵',0,NULL,NULL,9,NULL,NULL,NULL,NULL,'13663718227','11','1@qq.com','11',NULL,NULL,0),(12,12,'姚枫',1,'儿科圣手',NULL,10,4,45,47,51,NULL,NULL,NULL,NULL,5,'upload/yf.jpg',200);






//预约单表
CREATE TABLE `h_order` (
  `oid` INT(11) NOT NULL AUTO_INCREMENT,
  `edid` INT(11) DEFAULT NULL,
  `udid` INT(11) DEFAULT NULL,
  `sjdid` INT(11) DEFAULT NULL,
  `yyztid` INT(11) DEFAULT NULL,
  `sickness` VARCHAR(200) DEFAULT NULL,
  `ghf` FLOAT DEFAULT NULL,
  `odate` DATE DEFAULT NULL,
  `rdate` DATETIME DEFAULT NULL,
  PRIMARY KEY (`oid`),
  KEY `FK_Reference_18` (`sjdid`),
  KEY `FK_Reference_19` (`yyztid`),
  KEY `FK_Reference_7` (`edid`),
  KEY `FK_Reference_8` (`udid`),
  CONSTRAINT `FK_Reference_18` FOREIGN KEY (`sjdid`) REFERENCES `h_type` (`tid`),
  CONSTRAINT `FK_Reference_19` FOREIGN KEY (`yyztid`) REFERENCES `h_type` (`tid`),
  CONSTRAINT `FK_Reference_7` FOREIGN KEY (`edid`) REFERENCES `h_userinfo` (`did`),
  CONSTRAINT `FK_Reference_8` FOREIGN KEY (`udid`) REFERENCES `h_userinfo` (`did`)
) ENGINE=INNODB AUTO_INCREMENT=28 DEFAULT CHARSET=utf8;






INSERT  INTO `h_order`(`oid`,`edid`,`udid`,`sjdid`,`yyztid`,`sickness`,`ghf`,`odate`,`rdate`) VALUES (9,10,8,55,24,'			1',100,'2018-12-20','2018-12-19 09:46:22'),(10,10,8,55,24,'			2',100,'2018-12-20','2018-12-19 09:47:32'),(11,10,8,55,23,'			3',100,'2018-12-20','2018-12-19 10:23:07'),(14,10,8,56,25,'			1',100,'2018-12-20','2018-12-19 09:58:23'),(15,10,8,56,23,'			1',100,'2018-12-26','2018-12-24 09:45:17'),(16,10,8,56,25,'			2',100,'2018-12-26','2018-12-24 09:46:05'),(17,10,8,56,24,'			3',100,'2018-12-26','2018-12-24 09:46:45'),(18,10,5,55,22,'胸口痛	',100,'2019-01-23','2019-01-22 14:26:33'),(19,12,11,55,24,'			xxx',200,'2019-01-25','2019-01-23 14:46:54'),(20,12,11,55,21,'			xxx',200,'2019-01-25','2019-01-23 16:58:26'),(21,12,11,55,21,'			xxx',200,'2019-01-25','2019-01-23 16:59:23'),(22,12,11,55,21,'			1111',200,'2019-01-28','2019-01-25 09:41:45'),(23,12,11,55,22,'		123	',200,'2019-01-28','2019-01-25 09:42:07'),(25,12,11,55,24,'			111',200,'2019-01-28','2019-01-25 09:57:48'),(26,12,11,55,23,'			129',200,'2019-01-29','2019-01-25 16:02:24'),(27,12,11,56,25,'			1292',200,'2019-01-29','2019-01-25 14:18:26');



//评论表

CREATE TABLE `h_comment` (
  `pid` INT(11) NOT NULL AUTO_INCREMENT,
  `oid` INT(11) DEFAULT NULL,
  `ptime` DATETIME DEFAULT NULL,
  `ptext` VARCHAR(200) DEFAULT NULL,
  `pname` VARCHAR(20) DEFAULT NULL,
  `pnm` INT(11) DEFAULT NULL,
  PRIMARY KEY (`pid`),
  KEY `FK_Reference_13` (`oid`),
  CONSTRAINT `FK_Reference_13` FOREIGN KEY (`oid`) REFERENCES `h_order` (`oid`)
) ENGINE=INNODB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;



INSERT  INTO `h_comment`(`pid`,`oid`,`ptime`,`ptext`,`pname`,`pnm`) VALUES (1,10,'2018-12-19 10:57:53','<p>大夫很贴心<br/></p>','妲己',1),(2,9,'2018-12-19 10:59:06','<p>大夫水平很高<br/></p>','妲己',0),(3,17,'2018-12-24 09:49:00','<p>我感觉很好<br/></p>','妲己',0),(4,19,'2019-01-23 14:48:08','<p>大夫很贴心 我感觉很好<br/></p>','貂小婵',1),(5,19,'2019-01-25 15:21:35','<p><img src=\"http://img.baidu.com/hi/tsj/t_0002.gif\"/></p>','貂小婵',1);



//新闻表
CREATE TABLE `h_news` (
  `uuid` INT(11) DEFAULT NULL,
  `nid` INT(11) NOT NULL AUTO_INCREMENT,
  `nname` VARCHAR(30) DEFAULT NULL,
  `ntext` VARCHAR(1000) DEFAULT NULL,
  `ntime` DATETIME DEFAULT NULL,
  `nurl` VARCHAR(50) DEFAULT NULL,
  PRIMARY KEY (`nid`),
  KEY `FK_Reference_21` (`uuid`),
  CONSTRAINT `FK_Reference_21` FOREIGN KEY (`uuid`) REFERENCES `h_user` (`uuid`)
) ENGINE=INNODB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;


INSERT  INTO `h_news`(`uuid`,`nid`,`nname`,`ntext`,`ntime`,`nurl`) VALUES (4,2,'妲己','<p>121212<img alt=\"girl(1).jpg\" src=\"ueditor/jsp/upload/image/20181218/1545099837571015541.jpg\" title=\"1545099837571015541.jpg\"/></p>','2018-12-18 10:24:03','upload/20160202095456.jpg'),(4,3,'123','<p>456<br/></p>','2019-01-26 09:19:50','upload/美女.jpg');



//页面表   暂未使用
CREATE TABLE `h_page` (
  `pid` INT(11) NOT NULL,
  `pname` VARCHAR(50) DEFAULT NULL,
  `prurl` VARCHAR(100) DEFAULT NULL,
  `porder` INT(11) DEFAULT NULL,
  PRIMARY KEY (`pid`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;



CREATE TABLE `h_page_role` (
  `hprid` INT(11) NOT NULL,
  `pid` INT(11) DEFAULT NULL,
  `rid` INT(11) DEFAULT NULL,
  PRIMARY KEY (`hprid`),
  KEY `FK_Reference_22` (`pid`),
  KEY `FK_Reference_23` (`rid`),
  CONSTRAINT `FK_Reference_22` FOREIGN KEY (`pid`) REFERENCES `h_page` (`pid`),
  CONSTRAINT `FK_Reference_23` FOREIGN KEY (`rid`) REFERENCES `h_role` (`rid`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;


//验证码表   暂未使用
CREATE TABLE `h_yzm` (
  `yzmid` INT(11) NOT NULL,
  `uuid` INT(11) DEFAULT NULL,
  `yzmcode` VARCHAR(10) DEFAULT NULL,
  PRIMARY KEY (`yzmid`),
  KEY `FK_Reference_20` (`uuid`),
  CONSTRAINT `FK_Reference_20` FOREIGN KEY (`uuid`) REFERENCES `h_user` (`uuid`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;

2,创建maven的web工程

准备pom文件

<dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>

    <!--添加servlet依赖-->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.1.0</version>
      <scope>provided</scope>
    </dependency>
    <!-- 引入jsp依赖 -->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>jsp-api</artifactId>
      <version>2.0</version>
      <scope>provided</scope>
    </dependency>

    <!--    lombok依赖-->
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.12</version>
    </dependency>

    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>jstl</artifactId>
      <version>1.2</version>
    </dependency>
    <!--druid连接池的依赖-->
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>1.2.3</version>
    </dependency>
    <!--mysql驱动 注意 8 的驱动 对应的 url 和  driverClass 的写法-->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>8.0.21</version>
    </dependency>

    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>fastjson</artifactId>
      <!--      <version>1.2.21</version>-->
      <version>1.2.83</version>
    </dependency>

    <!-- 使用QueryRunner等api -->
    <dependency>
      <groupId>commons-dbutils</groupId>
      <artifactId>commons-dbutils</artifactId>
      <version>1.7</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/commons-beanutils/commons-beanutils -->
    <dependency>
      <groupId>commons-beanutils</groupId>
      <artifactId>commons-beanutils</artifactId>
      <version>1.9.4</version>
    </dependency>

  </dependencies>
 
        Copied!
    

准备实体类

package com.glls.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @date 2023/4/10
 * @desc HUser
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class HUser {

    private Integer uuid;

    private String uname;

    private String upwd;

    private Integer rid;

}

 
        Copied!
    
package com.glls.pojo;

/**
 * @date 2023/4/10
 * @desc HUserinfo
 */
public class HUserinfo {
    //主键
    private Integer did;
    //年龄
    private Integer dage;
    //真实姓名
    private String drealname;
    // 性别
    private Integer dsex;
    // 个人描述
    private String dtext;
    // 调休id
    private Integer bid;
    // 关联 用户表 主键
    private Integer uuid;
    //科室id
    private Integer ksid;
    //职位
    private Integer zwid;
    //学历
    private Integer xlid;
    //专业
    private Integer zyid;
    //联系电话
    private String dphone;
    //身份证号
    private String didcard;
    //邮箱
    private String demail;
    //QQ号码
    private String dqq;

    // 预约最大人数
    private Integer dnum;
    //医生头像
    private String durl;
    // 挂号费
    private double dmoney;


}

 
      
    

MD5工具类

package com.glls.utils;

import sun.misc.BASE64Encoder;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 * @date 2023/4/10
 * @desc
 */
public class MD5Util {
	// 输入一个 明文 字符串 返回一个加密之后的字符串
    public static String EncoderPwdByMd5(String str){
        try {
            MessageDigest md5 = MessageDigest.getInstance("MD5");

            BASE64Encoder encoder = new BASE64Encoder();

            return encoder.encode(md5.digest(str.getBytes("utf-8")));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    public static void main(String[] args) {

        String s = MD5Util.EncoderPwdByMd5("123456");

        System.out.println(s);
    }
}

 
       
    

准备静态资源文件

bootstrap的资源文件

image-20230414091914238

//bs.jsp的内容
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<link rel="stylesheet" href="bs/css/bootstrap.min.css">
<link rel="stylesheet" href="bs/css/bootstrap-theme.min.css">
<script src="bs/js/jquery.min.js"></script>
<script src="bs/js/bootstrap.min.js"></script>
 
       
    

哪个页面需要用bootstrap的资源文件 ,去包含 bs.jsp就可以了

准备公共的包含页 common/top.jsp ,这个页面 里面 是 bootstrap 的 导航条

image-20230410174238177

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<jsp:include page="../bs/bs.jsp"></jsp:include>

<nav class="navbar navbar-inverse">
    <div class="container-fluid">
        <!-- Brand and toggle get grouped for better mobile display -->
        <div class="navbar-header">
            <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
                <span class="sr-only">Toggle navigation</span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
            </button>
            <a class="navbar-brand" href="#">市第二人民医院</a>
        </div>

        <!-- Collect the nav links, forms, and other content for toggling -->
        <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
            <ul class="nav navbar-nav">
                <li class="active"><a href="#">首页</a></li>
                <li><a href="#about">关于我们</a></li>
                <li><a href="#contact">在线预约</a></li>
                <li><a href="#contact">医疗咨询</a></li>
                <li><a href="#contact">联系我们</a></li>
            </ul>

            <ul class="nav navbar-nav navbar-right">
                <c:if test="${empty u }">
                    <li><a href="login.jsp">登录</a></li>
                    <li><a href="reg.jsp">注册</a></li>
                </c:if>
                <c:if test="${!empty u }">
                    <li><a href="info.jsp">欢迎你${u.ui.drealname }</a></li>
                    <li><a href="#">注销</a></li>
                </c:if>
                <li><a href="#contact">   </a></li>
                <li><a href="#contact"></a></li>
            </ul>

        </div><!-- /.navbar-collapse -->
    </div><!-- /.container-fluid -->
</nav>
 
       
    

准备公共的包含页 common/footer.jsp ,这个页面 里面 是 bootstrap 的 导航条

<%@ page contentType="text/html;charset=UTF-8" language="java" %>


<%--</div>--%>
<div class="container">

    <!-- FOOTER -->
    <footer>
        <p class="pull-right"><a href="#">返回顶部</a></p>
        <p>&copy; 市第二人民医院 &middot; 菜鸟的成长之路- <a href="http://blog.javanewbie.cn" target="_blank">by2301</a> &middot; <a href="#"></a></p>
    </footer>
</div>

 
       
    

默认欢迎页 index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<html>
<head>
    <title>Title</title>
</head>
<body>
<jsp:include page="common/top.jsp"></jsp:include>

<div class="container">
    <div class="col-lg-8">
        <!-- Carousel
    ================================================== -->
        <div id="myCarousel" class="carousel slide" data-ride="carousel">
            <!-- Indicators -->
            <ol class="carousel-indicators">
                <li data-target="#myCarousel" data-slide-to="0" class="active"></li>
                <li data-target="#myCarousel" data-slide-to="1"></li>
                <li data-target="#myCarousel" data-slide-to="2"></li>
            </ol>
            <div class="carousel-inner" role="listbox">
                <div class="item active">
                    <img class="first-slide" src="image/lb1.jpg" alt="First slide">
                    <div class="container">
                        <div class="carousel-caption">
                            <h3>一流化的医疗设备</h3>
                        </div>
                    </div>
                </div>
                <div class="item">
                    <img class="second-slide" src="image/lb2.jpg" alt="Second slide">
                    <div class="container">
                        <div class="carousel-caption">
                            <h3>专业的服务团队</h3>
                        </div>
                    </div>
                </div>
                <div class="item">
                    <img class="third-slide" src="image/lb3.jpg">
                    <div class="container">
                        <div class="carousel-caption">
                            <h3>顶级一流医疗团队</h3>
                        </div>
                    </div>
                </div>
            </div>
            <a class="left carousel-control" href="#myCarousel" role="button" data-slide="prev">
                <span class="glyphicon glyphicon-chevron-left" aria-hidden="true"></span>
                <span class="sr-only">Previous</span>
            </a>
            <a class="right carousel-control" href="#myCarousel" role="button" data-slide="next">
                <span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
                <span class="sr-only">Next</span>
            </a>
        </div><!-- /.carousel -->

    </div>
    <div class="col-lg-4" style="border:1px solid #ccc">
        <table align="center" style="line-height: 30px">
            <tr>
                <td colspan="2"><h2>营业时间</h2></td>
            </tr>
            <tr>
                <td>星期一</td>
                <td>08:30-17:30</td>
            </tr>
            <tr>
                <td>星期二</td>
                <td>08:30-17:30</td>
            </tr>
            <tr>
                <td>星期三</td>
                <td>08:30-17:30</td>
            </tr>
            <tr>
                <td>星期四</td>
                <td>08:30-17:30</td>
            </tr>
            <tr>
                <td>星期五</td>
                <td>08:30-17:30</td>
            </tr>
            <tr>
                <td>星期六</td>
                <td>休息</td>
            </tr>
            <tr>
                <td>星期日</td>
                <td>休息</td>
            </tr>

        </table>
        <br>
        <br>
        <br>

    </div>

</div>


<div class="container">
    <div style="border:1px solid #ccc; height: 300px; " class="col-lg-4">
        <br><br>
        19547月生,广东湛江市人。1983年毕业于广州中医学院医疗专业本科。现任广东医学院专家门诊部副主任、主治中医师。长期从事中医临床和教学工作,在中西医结合治疗皮肤病、慢性鼻炎、过敏性鼻炎、痔瘘及小儿呼吸道反复感染等疾病中颇有见地和经验。发表的主要论文有“祛瘀通窍膏治疗慢性肥厚性鼻炎107例”、“温阳益气汤治疗变态反应性鼻炎疗效观察”、“红外线仪治疗内痔156例”、“蜂胶酊治疗扁平疣24例疗效观察”等。

    </div>
    <div style="border:1px solid #ccc; height: 300px;" class="col-lg-4">
        <img src="image/index-1.jpg" height="298px">
    </div>
    <div style="border:1px solid #ccc; height: 300px;" class="col-lg-4">
        <c:if test="${!empty hs}">
            <c:forEach items="${hs}" var="h">
                <div class="media">
                    <div class="media-left media-middle">
                        <a href="showNews?nid=${h.nid}">
                            <img class="media-object" src="${h.nurl}" width="60" height="60" alt="...">
                        </a>
                    </div>
                    <div class="media-body">
                        <br>
                        <a href="showNews?nid=${h.nid}">
                            <h4 class="media-heading">${h.nname}</h4>
                        </a>
                    </div>
                </div>
            </c:forEach>
        </c:if>

    </div>

</div>


<div class="container">
    <div  style="border:1px solid #ccc; height: 300px;"  class="col-lg-8">
        <br><br>
        所著《性功能障碍中西医诊治》一书获延安市科技进步一等奖,《腹腔镜手术108例临床分析》获科技进步二等奖,发表论文20余篇。本人多次被评为省、市、院先进个人、“十佳服务明星”,2002年被评为省“第十届妇代会代表”,2003年省工会授予“十五女职工双文明建功立业创新能手”、2004年被陕西省妇联评为第六届“三秦巾帼十杰”、授予“三八红旗手”称号,2005年所带领的延安大学附属医院产科被授予“全国三八红旗集体”称号。

    </div>
    <div id="map"  style="border:1px solid #ccc; height: 300px;"  class="col-lg-4"></div>
</div>

<script type="text/javascript">
    // 百度地图API功能
    var map = new BMap.Map("map");  // 创建Map实例
    map.centerAndZoom(new BMap.Point(113.657982,34.727432),17);
    map.enableScrollWheelZoom(true);
    // 覆盖区域图层测试
    map.addTileLayer(new BMap.PanoramaCoverageLayer());

    var stCtrl = new BMap.PanoramaControl(); //构造全景控件
    stCtrl.setOffset(new BMap.Size(20, 20));
    map.addControl(stCtrl);//添加全景控件
    var point = new BMap.Point(113.657982,34.727432);
    var marker = new BMap.Marker(point);  // 创建标注
    map.addOverlay(marker);               // 将标注添加到地图中
    marker.setAnimation(BMAP_ANIMATION_BOUNCE); //跳动的动画
</script>

<jsp:include page="common/footer.jsp"></jsp:include>
</body>
</html>

 
      
    

登录页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>用户登录</title>
    <style type="text/css">


        .form-signin {
            max-width: 330px;
            padding: 15px;
            margin: 0 auto;
        }
        .form-signin .form-signin-heading,
        .form-signin .checkbox {
            margin-bottom: 10px;
        }
        .form-signin .checkbox {
            font-weight: normal;
        }
        .form-signin .form-control {
            position: relative;
            height: auto;
            -webkit-box-sizing: border-box;
            -moz-box-sizing: border-box;
            box-sizing: border-box;
            padding: 10px;
            font-size: 16px;
        }
        .form-signin .form-control:focus {
            z-index: 2;
        }
        .form-signin input[type="email"] {
            margin-bottom: -1px;
            border-bottom-right-radius: 0;
            border-bottom-left-radius: 0;
        }
        .form-signin input[type="password"] {
            margin-bottom: 10px;
            border-top-left-radius: 0;
            border-top-right-radius: 0;
        }

    </style>
</head>
<body>
<c:if test="${!empty u }">
    <c:redirect url="index.jsp"></c:redirect>
</c:if>
<%--头部导航条--%>
<jsp:include page="common/top.jsp"></jsp:include>




<div class="container" style="height:500px;">
    <form class="form-signin" action="${pageContext.request.contextPath}/login" method="post">
        <h2 class="form-signin-heading">用户登录</h2>
        <label for="inputName" class="sr-only">用户名</label>
        <input type="text" name="uname" id="inputName" class="form-control" placeholder="用户名" required autofocus>
        <label for="inputPassword" class="sr-only">密码</label>
        <input type="password" name="upwd" id="inputPassword" class="form-control" placeholder="密码" required>
        <div class="checkbox">
            <label>
                <input type="checkbox" value="remember-me"> 记住密码
            </label>
        </div>
        <button class="btn btn-lg btn-primary btn-block" type="submit">登录</button>
        <br>
        ${login_info }
    </form>
</div>



<jsp:include page="common/footer.jsp"></jsp:include>
</body>
</html>

 
       
    

image-20230414092110997

3.登录功能

登录 表单请求 LoginServlet

@Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        String uname = req.getParameter("uname");
        //接的是明文密码
        String upwd = req.getParameter("upwd");
        String remember = req.getParameter("remember");

        HUser hUser = new HUser();
        hUser.setUname(uname);
        //把明文密码 改为密文
        String pwd = MD5Util.EncoderPwdByMd5(upwd);
        hUser.setUpwd(pwd);

        UserService userService = new UserServiceImpl();

        HUser result = userService.login(hUser);

        if(result!=null){

            //登录成功  判断用户是否勾选了记住我
            if(!StringUtils.isEmpty(remember)){
                //发送cookie
                Cookie cookie = new Cookie("remember", uname + "-" + upwd);
                // 设置cookie的有效期
                cookie.setMaxAge(Integer.parseInt(remember));

                resp.addCookie(cookie);
            }

            HttpSession session = req.getSession();
            //登陆成功 把用户信息放在session
            session.setAttribute("u",result);
            resp.sendRedirect(req.getContextPath()+"/index.jsp");
        }else{

            req.setAttribute("login_info","用户名或密码错误");
            //失败 跳转到登录页面
            req.getRequestDispatcher("/login.jsp").forward(req,resp);
        }

    }
 
       
    

service层

 @Override
    public HUser login(HUser hUser) {
        return userDao.login(hUser);
    }
 
 
    

dao层的代码

知识点 commons-dbutils

1.添加依赖

 <dependency>
      <groupId>commons-dbutils</groupId>
      <artifactId>commons-dbutils</artifactId>
      <version>1.7</version>
    </dependency>
 
 
    

2.准备数据库的配置文件

driverClass=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/hosp?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false
username=root
password=123456
# ----- 加入druid的一些连接配置
#<!-- 初始化连接 -->
initialSize=10
#最大连接数量
maxActive=50
#<!-- 最小空闲连接 -->
minIdle=5
#<!-- 超时等待时间以毫秒为单位 60000毫秒/1000等于60-->
maxWait=5000
 
       
    

3.准备工具类DbUtils

package com.glls.utils;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;

import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

/**
 * @date 2023/4/11
 * @desc  使用数据库连接池
 */
public class DbUtils {
    // 声明Druid连接池对象
    private static DruidDataSource druidDataSource;

    static {
        try {

            Properties properties = new Properties( );
            // 将配置文件读作输入流
            InputStream stream = DbUtils.class.getResourceAsStream("/db.properties");
            // properties对象加载流,即配置信息都在properties对象里面
            properties.load(stream);
            // 通过配置信息创建出druidDataSource数据源
            druidDataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(properties);
        } catch (Exception e) {
            e.printStackTrace( );
        }
    }


    /**
     * 通过DruidDataSource获得连接
     */
    public static Connection getConnection() {
        Connection conn = null;
        try {
            // 2 获得连接
            conn = druidDataSource.getConnection( );
        } catch (Exception e) {
            e.printStackTrace( );
        }
        return conn;
    }

    /**
     * 抽取关流的方法
     */
    public static void closeAll(Connection conn, Statement s) {
        if (conn != null) {
            try {
                conn.close( );
            } catch (SQLException e) {
                e.printStackTrace( );
            }
        }
        if (s != null) {
            try {
                s.close( );
            } catch (SQLException e) {
                e.printStackTrace( );
            }
        }
    }

    public static void closeAll(Connection conn, Statement s, ResultSet rs) {
        if (conn != null) {
            try {
                conn.close( );
            } catch (SQLException e) {
                e.printStackTrace( );
            }
        }
        if (s != null) {
            try {
                s.close( );
            } catch (SQLException e) {
                e.printStackTrace( );
            }
        }
        if (rs != null) {
            try {
                rs.close( );
            } catch (SQLException e) {
                e.printStackTrace( );
            }
        }
    }


    public static void main(String[] args) {
        System.out.println(getConnection());
    }
}

 
   
    

4.使用commons-dbutils的相关api

QueryRunner 对象

获取QueryRunner对象

// 构造方法创建    需要传入一个 数据源对象
QueryRunner queryRunner = new QueryRunner(DbUtils.getDataSource());
 
        Copied!
    

登录时 查询

@Override
    public HUser login(HUser hUser) {

        String sql = "select * from h_user where uname = ? and upwd = ? ";
        HUser result = null;
        try {

            result = queryRunner.query(sql, new BeanHandler<>(HUser.class), hUser.getUname(), hUser.getUpwd());

            if(result!=null){
                //因为 在页面上 要展示用户的真实姓名 所以  要把真实姓名信息查询出来 而真实姓名子在 h_userinfo 表中
                String sql2 = "select * from h_userinfo  where uuid = ?";
                HUserinfo userinfo = queryRunner.query(sql2, new BeanHandler<>(HUserinfo.class), result.getUuid());

                result.setUi(userinfo);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return result;
    }
 
      
    

登录之后 跳转到 index.jsp , 在 导航条 top.jsp 上 会展示 登录的用户的真实的姓名

 <ul class="nav navbar-nav navbar-right">
                <c:if test="${empty u }">
                    <li><a href="login.jsp">登录</a></li>
                    <li><a href="reg.jsp">注册</a></li>
                </c:if>
                <c:if test="${!empty u }">
                    <li><a href="info.jsp">欢迎你${u.ui.drealname }</a></li>
                    <li><a href="#">注销</a></li>
                </c:if>
                <li><a href="#contact">   </a></li>
                <li><a href="#contact"></a></li>
            </ul>
 
        Copied!
    

所以 实体类 HUser 中 需要封装 引用类型的属性

 private HUserinfo ui;
 
      
    

4.注销功能

image-20230414092414225

后端 LogoutServlet 销毁session,跳转到登录页面

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        HttpSession session = req.getSession();

        session.invalidate();

        resp.sendRedirect(req.getContextPath()+"/index.jsp");

    }
 
    
    

5.注册功能

image-20230414092803728

点注册 直接跳转到reg.jsp

image-20230414092503819

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
    String path = request.getContextPath();
    String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>

<html lang="zh-CN">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
    <meta name="description" content="">
    <meta name="author" content="">
    <link rel="icon" href="../../favicon.ico">
    <base href="<%=basePath%>">
    <title>用户注册</title>
    <jsp:include page="bs/bs.jsp"></jsp:include>
    <style type="text/css">


        .form-signin {
            max-width: 400px;
            margin: 0 auto;
        }.form-group {
             margin-bottom: 1px;
         }

    </style>
    <script type="text/javascript" src="js/md5.min.js"></script>
    <script>
      function check(){
           var pwd1 = $("#upwd").val();
           var pwd2 = $("#qrpwd").val();

           if(pwd1==pwd2){
               return true;
           }else{
                alert("两次输入的密码不一致");
               return false;
           }


      }

    </script>
</head>
<!-- NAVBAR
================================================== -->
<body>
<%--头部导航条--%>
<jsp:include page="common/top.jsp"></jsp:include>

<div class="container" >
    <form class="form-signin form-horizontal" onsubmit="return check()" action="${pageContext.request.contextPath}/register" method="post">
        <h2 class="form-signin-heading">用户注册</h2>
        <div class="form-group">
            <label class="col-sm-4" for="uname" ><h4>用户名</h4></label>
            <div class="col-sm-8">
                <input  type="text" name="uname" id="uname" class="form-control" placeholder="用户名" required autofocus>
            </div>
        </div>
        <div class="form-group">
            <label class="col-sm-4" for="upwd" ><h4>密码</h4></label>
            <div class="col-sm-8">
                <input type="password" name="upwd" id="upwd" class="form-control" placeholder="密码" required>

            </div></div>
        <div class="form-group">
            <label class="col-sm-4" for="qrpwd" ><h4>确认密码</h4></label>
            <div class="col-sm-8">
                <input type="password" id="qrpwd" onblur="check()" class="form-control" placeholder="确认密码" required>

            </div></div>
        <div class="form-group">
            <label class="col-sm-4" for="drealname" ><h4>真实姓名</h4></label>
            <div class="col-sm-8">
                <input type="text" id="drealname" name="drealname"  class="form-control" placeholder="真实姓名" required>

            </div></div>
        <div class="form-group">
            <label class="col-sm-4" for="dsex" ><h4>性别</h4></label>
            <div class="col-sm-8">
                <label class="radio-inline">
                    <input type="radio" name="dsex" checked="checked" id="dsex" value="1"></label>
                <label class="radio-inline">
                    <input type="radio" name="dsex" id="dsex" value="0"></label>

            </div></div>


        <div class="form-group">
            <label class="col-sm-4" for="dage" ><h4>年龄</h4></label>
            <div class="col-sm-8">
                <input type="number" id="dage" name="dage" class="form-control" placeholder="年龄" required>

            </div></div>
        <div class="form-group">
            <label class="col-sm-4" for="dphone" ><h4>手机号</h4></label>
            <div class="col-sm-8">
                <input type="text" id="dphone" name="dphone" class="form-control" placeholder="手机号" required>
                <%--<input type="text" class="form-control" name="checkCode" style="width:50%;display: inline;" placeholder="验证码" id="yzm"><input type="button" id="btn" class="btn" onclick="getYzm()" value="点击获取验证码">--%>
            </div></div>
        <div class="form-group">
            <label class="col-sm-4" for="didcard" ><h4>身份证号</h4></label>
            <div class="col-sm-8">
                <input type="text" id="didcard" name="didcard" class="form-control" placeholder="身份证号" required>

            </div></div>
        <div class="form-group">
            <label class="col-sm-4" for="demail" ><h4>邮箱</h4></label>
            <div class="col-sm-8">
                <input type="email" id="demail" name="demail"  class="form-control" placeholder="邮箱" required>

            </div></div>
        <div class="form-group">
            <label class="col-sm-4" for="dqq" ><h4>QQ</h4></label>
            <div class="col-sm-8">
                <input type="number" id="dqq" name="dqq" class="form-control" placeholder="QQ" >
            </div></div>
        <button class="btn btn-lg btn-primary btn-block" type="submit">注册</button>
        <br>
        ${reg_info }
    </form>
</div>


<jsp:include page="common/footer.jsp"></jsp:include>


</body>
</html>


 
       
    

后端RegisterServlet 接受注册的信息

@Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //接受 注册的表单数据
        //当表单数据过多时  可以使用下面的方式
        //以表单项的name 位key 以值为value
        Map<String, String[]> parameterMap = req.getParameterMap();

        HUser hUser = new HUser();
        HUserinfo hUserinfo = new HUserinfo();

        //这里 咱们借助BeanUtils 工具类 来拷贝对象间的属性
        try {
            // 把map 中的键值 赋值给user 对象的属性    当map的 键 等于 user的属性时
            BeanUtils.populate(hUser,parameterMap);
            BeanUtils.populate(hUserinfo,parameterMap);

            hUser.setUi(hUserinfo);

            String pwd = MD5Util.EncoderPwdByMd5(hUser.getUpwd());
            hUser.setUpwd(pwd);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

        UserService userService = new UserServiceImpl();

        int result = userService.register(hUser);

        if(result==1){
            //注册成功  跳转到登录页面
            req.getRequestDispatcher("/login.jsp").forward(req,resp);
        }else{
            //注册失败
            req.setAttribute("reg_info","注册失败");
            req.getRequestDispatcher("/reg.jsp").forward(req,resp);
        }
    }
 
       
    

service层代码

   @Override
    public int register(HUser hUser) {
        return userDao.register(hUser);
    }
 
     
    

dao层代码 这里 咱们自己控制事务 所以 改造了一下 DbUtils 的 getConnection 方法

@Override
    public int register(HUser hUser) {
        //开启事务
        DbUtils.begin();
        //用户注册  用户的信息 会存入 h_user  和  h_userinfo 表
        String sql="insert into h_user values (null,?,?,?)";

        int result2 = 0;
        try {
            //下面的方法 没有传connection  所以 会自动提交 ,这里 咱们要控制事务的提交   自己去传递连接对象
            //queryRunner.update(sql,hUser.getUname(),hUser.getUpwd(),hUser.getRid());
            int result1 = queryRunner.update(DbUtils.getConnection(), sql, hUser.getUname(), hUser.getUpwd(), hUser.getRid());

            //查询刚才那条插入语句的 主键值
            String sql2 = "select last_insert_id()";
            BigInteger lastId = queryRunner.query(DbUtils.getConnection(), sql2, new ScalarHandler<BigInteger>());

            HUserinfo ui = hUser.getUi();

            ui.setUuid(lastId.intValue());

            int i = 5/0;

            String sql3 = "insert into h_userinfo " +
                    "(did,drealname,dage,dsex,uuid,dphone,didcard,demail,dqq) " +
                    "values (null,?,?,?,?,?,?,?,?)";

            result2 = queryRunner.update(DbUtils.getConnection(),
                    sql3, ui.getDrealname(), ui.getDage(), ui.getDsex(),
                    ui.getUuid(), ui.getDphone(), ui.getDidcard(), ui.getDemail(), ui.getDqq());

            DbUtils.commit();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return result2;
    }
 
      
    

改造的DbUtils

package com.glls.utils;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

/**
 * @date 2023/4/11
 * @desc  使用数据库连接池
 *
 *
 * ThreadLocal  保证 一个线程 多次获取connection 获取的是同一个
 */
public class DbUtils {
    // 声明Druid连接池对象
    private static DruidDataSource druidDataSource;

    private static  final  ThreadLocal<Connection> THREAD_LOCAL = new ThreadLocal<>();
    static {
        try {

            Properties properties = new Properties( );
            // 将配置文件读作输入流
            InputStream stream = DbUtils.class.getResourceAsStream("/db.properties");
            // properties对象加载流,即配置信息都在properties对象里面
            properties.load(stream);
            // 通过配置信息创建出druidDataSource数据源
            druidDataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(properties);
        } catch (Exception e) {
            e.printStackTrace( );
        }
    }


    public static DataSource getDataSource(){
        return druidDataSource;
    }

    /**
     * 通过DruidDataSource获得连接
     */
    public static Connection getConnection() {

        Connection conn = THREAD_LOCAL.get();
        try {
            // 2 获得连接
            if(conn ==null){
                conn = druidDataSource.getConnection( );
                THREAD_LOCAL.set(conn);
            }
        } catch (Exception e) {
            e.printStackTrace( );
        }
        return conn;
    }

    //开启事务   关闭自动提交
    public static void begin(){
        Connection connection = getConnection();

        try {
            //关闭自动提交
            connection.setAutoCommit(false);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    // 提交事务
    public static void commit(){
        Connection connection = getConnection();
        try {
            connection.commit();
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            closeAll(connection,null,null);
        }
    }


    public static void rollback(){
        Connection connection = getConnection();

        try {
            connection.rollback();
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            closeAll(connection,null,null);
        }
    }


    /**
     * 关闭连接
     */
    public static void closeAll(Connection conn, Statement s) {
        if (conn != null) {
            try {
                conn.close( );
            } catch (SQLException e) {
                e.printStackTrace( );
            }
        }
        if (s != null) {
            try {
                s.close( );
            } catch (SQLException e) {
                e.printStackTrace( );
            }
        }
    }

    public static void closeAll(Connection conn, Statement s, ResultSet rs) {
        if (conn != null) {
            try {
                conn.close( );
            } catch (SQLException e) {
                e.printStackTrace( );
            }
        }
        if (s != null) {
            try {
                s.close( );
            } catch (SQLException e) {
                e.printStackTrace( );
            }
        }
        if (rs != null) {
            try {
                rs.close( );
            } catch (SQLException e) {
                e.printStackTrace( );
            }
        }
    }


    public static void main(String[] args) {

        System.out.println(getConnection());
        System.out.println(getConnection());
    }
}

 
        
    

6.在线预约功能

6.1 在线预约

image-20230414092717106

跳转到ol.jsp ,这个页面会展示科室信息 ,科室的这些数据 是在 数据字典表中 ,而且 这些数据 是所有人共享的数据 ,而且这些数据 不用每次都去数据库查询, 咱们把它放在 最大的域对象中, 创建一个监听器 ,在监听器中执行这个操作

准备数据字典表对应的实体类

package com.glls.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @date 2023/4/11
 * @desc 数据字典
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class HType {

    private Integer tid;

    private String tname;

    private Integer tgroup;

    private String tdesc;

}

 
  
    

监听器

package com.glls.listener;

import com.glls.pojo.HType;
import com.glls.service.HtypeService;
import com.glls.service.impl.HtypeServiceImpl;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import java.util.List;

/**
 * @date 2023/4/11
 * @desc  监听servletContext的监听器
 */
@WebListener
public class AppListener implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent sce) {

        System.out.println("应用初始化");
        //准备数据字典数据
        HtypeService htypeService = new HtypeServiceImpl();
        List<HType> typeList =  htypeService.findAllTypes();
        //放到最大的域对象中
        ServletContext servletContext = sce.getServletContext();

        servletContext.setAttribute("ts",typeList);

    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {

    }
}

 
        
    

service层代码

    @Override
    public List<HType> findAllTypes() {
        return htypeDao.findAllTypes();
    }
 
     
    

dao层代码

@Override
    public List<HType> findAllTypes() {

        String sql = "select * from h_type";

        List<HType> query = null;
        try {
            query = queryRunner.query(sql, new BeanListHandler<>(HType.class));
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return query;
    }
 
     
    

页面展示数据部分

 <div class="col-lg-8" style="border:1px solid #ccc;text-align: center;padding:0; font-size: 30px; height: 200px;">
	    	<c:if test="${!empty ts }">
	    	<c:forEach items="${ts }" var="t">
		    	<c:if test="${t.tgroup==2 }">
		    	   <div class="col-lg-3" onclick="f(${t.tid})" style="border: 1px solid #ccc;height: 100%;padding-top: 75px;">
				    	<div>${t.tname }</div>
				    </div>
		    	</c:if>
	    	</c:forEach>
	    </c:if>
	    </div>
 
        Copied!
    

image-20230414092922738

这里的科室信息 是在服务启动的时候 触发监听器的方法 查询数据字典数据 放在最大域对象中

6.2 查看科室医生列表

在ol.jsp 选择科室 把该科室的科室 tid 传到ShowDoctorServlet ,查询该科室下的医生信息 返回集合 跳转到sd.jsp 显示该科室下的医生信息

image-20230414093033938

//根军科室id 查询该科室下的医生信息   
@Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //科室id
        String tid = req.getParameter("tid");
        //根据科室id 查询 该科室下的医生信息
        UserService userService = new UserServiceImpl();
        List<HUserinfo> list =  userService.findUserByKsid(tid);
        req.setAttribute("uis",list);
        req.getRequestDispatcher("/sd.jsp").forward(req,resp);
    }
 
   
    

dao层代码

@Override
    public List<HUserinfo> findUserByKsid(String tid) {

        String sql="select * from h_userinfo where ksid = ?";

        List<HUserinfo> query = null;
        try {
            query = queryRunner.query(sql, new BeanListHandler<>(HUserinfo.class), tid);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return query;
    }
 
       
    

sd.jsp

 <div class="col-lg-8" style="border:1px solid #ccc;text-align: center;padding:0; font-size: 28px; height: 240px;">
	    	<c:if test="${!empty uis }">
	    	<c:forEach items="${uis}" var="t">
		    	   <div class="col-lg-3" style="border: 1px solid #ccc;">
				    	<img src="${t.durl }" width="160px" height="160px">
				    	${t.drealname }&nbsp; 医生
				    	<input type="button" class="btn btn-block" onclick="toXq(${t.did})" value="点击预约">
				    </div>
	    	</c:forEach>
	    </c:if>
	    </div>
 
        Copied!
    

6.3 预约详情

通过点击预约 按钮会展示医生的详细信息 以及 该医生的评论信息

image-20230414093120697

//ShowXqServlet

@Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        String did = req.getParameter("did");

        UserService userService = new UserServiceImpl();
		//准备医生的数据
        HUserinfo userinfo = userService.findUserInfoById(Integer.parseInt(did));

        req.setAttribute("doc",userinfo);

        //准备评论数据
        CommentService commentService = new CommentServiceImpl();

        List<HComment> comments = commentService.findCommentByDid(did);

        req.setAttribute("cs",comments);
        req.getRequestDispatcher("/xq.jsp").forward(req,resp);
    }
 
       
    

dao层代码

//查询医生的详细信息
@Override
public HUserinfo findUserInfoById(int did) {
    //预约详情页 会根据 医生的主键 did 查询医生的详情
    //其中 科室 职位 学历 专业 等 信息是在数据字典表中  所以 要多表联查

    String sql = "SELECT u.*,t1.`tname` AS ks,t2.`tname` AS zw,t3.`tname` AS xl,t4.`tname` AS zy FROM h_userinfo u \n" +
            " JOIN h_type t1 ON u.`ksid`=t1.`tid` \n" +
            " JOIN h_type t2 ON u.`zwid`=t2.`tid`\n" +
            " JOIN h_type t3 ON u.`xlid`=t3.`tid`\n" +
            " JOIN h_type t4 ON u.`zyid`=t4.`tid`\n" +
            "   WHERE did  = ?";
    HUserinfo query = null;
    try {
        query = queryRunner.query(sql, new BeanHandler<>(HUserinfo.class), did);
    } catch (SQLException e) {
        e.printStackTrace();
    }

    return query;
}
 
        
    
//查询该医生的评论列表
@Override
    public List<HComment> findCommentByDid(String did) {

        String sql="SELECT * FROM h_comment h JOIN h_order o ON h.oid = o.oid  \n" +
                " JOIN h_userinfo u ON o.edid=u.did WHERE did = ?";

        List<HComment> query = null;
        try {
            query = queryRunner.query(sql, new BeanListHandler<>(HComment.class), did);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return query;
    }
 
    
    

与之相关的实体类

package com.glls.pojo;

import java.util.Date;

/**
 * @date 2023/4/12
 * @desc 预约单
 */
public class HOrder {
    //预约单主键

    private Integer oid;
    //医生的id
    private Integer edid;

    //患者的id
    private Integer udid;
    //时间段id
    private Integer sjdid;
    //预约状态id
    private Integer yyztid;
    //病情
    private String sickness;
    //挂号费
    private Double ghf;
    //预约看病的日期
    private Date odate;
    //下单日期
    private Date rdate;

}

 
    
    
package com.glls.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;

/**
 * @date 2023/4/12
 * @desc 评论
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class HComment {
    //主键
    private Integer pid;
    //哪个预约单
    private Integer oid;
    //评论时间
    private Date ptime;
    //评论内容
    private String ptext;
    // 评论人名字
    private String pname;
    //是否匿名
    private Integer pnm;


}

 
      
    

6.4 校验能否预约

image-20230414093227362

选日期 和 时间,这里会有数据校验,预约日期不能是周末 不能是今天及今天之前的日期,时间段是下拉列表的形式 数据来自数据字典表 h_type 下拉列表有个 onchage 事件 发送 ajax请求 检查 这个医生 edid 在这个日期 odate 的这个时间段 sjdid 挂号人数(已经交过费的人数) 和 医生 接病人上限 dnum 比较 (已经交过费的 就是 已经预约过的单子yyztid=22的数量 查询h_order 表 ) 如果 已付款人数< dnum 就可以预约 否则不能预约。

image-20230414093354660

要去后端 查询 该医生的最大预约人数 和 已付款的预约单的个数 作比较, 如果 最大预约人数 大于 已付款的预约单的个数则可以预约,否则 不能预约

前端请求 οnchange=“check()”

function check(){
  		var rq = $("#odate").val();
  		var sj = $("#sjdid").val();
		  console.log(rq);
		  console.log(sj);
  		if(rq!=null && sj!=null){
  			$.ajax({
  				url:"${pageContext.request.contextPath}/checkDate",
				//odate 预约日期
				//edid 预约医生
				// sjdid 时间段id  页面显示预约时间段 向后台提交的是  tid
  				data:{odate:$("#odate").val(),edid:$("#edid").val(),sjdid:$("#sjdid").val()},
  				type:"get",
  				success:function(data){
  					if(data.code==200){
						$("#ss").html("可预约");
						$("#btn").attr("disabled",false);
  					}else{
						$("#ss").html("预约人数已满");
						$("#btn").attr("disabled",true);
					}
  				}, dataType:"json"
  			}

			);
  		}
  		
  	}
 
   
    

后端servlet

@Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        //预约日期
        String odate = req.getParameter("odate");
        //时间段id
        String sjdid = req.getParameter("sjdid");
        //预约的医生的id
        String edid = req.getParameter("edid");

        OrderService orderService = new OrderServiceImpl();

        //检查这个医生  的 这个日期 的 这个 时间段 还能不能被预约

        boolean b = orderService.checkDate(odate,edid,sjdid);

        //resp 响应ajax 请求 返回 json数据
        PrintWriter writer = resp.getWriter();
        String s = "";
        if(b){
            R<String> r = new R<>();
            r.setCode(200);
             s = JSON.toJSONString(r);

        }else{
            R<String> r = new R<>();
            r.setCode(500);
             s = JSON.toJSONString(r);
        }

        writer.write(s);

    }
 
    
    

service层

@Override
    public boolean checkDate(String odate, String edid, String sjdid) {

        //查询 该医生的  最大可预约人数
        int dnum = userService.getDoctorDnum(edid);

        //查询 当前在这个时间段  已经预约了多少人  查询h_order
        //yyztid  21  预约中
        //yyztid  22  已付款
        //yyztid  23  已取消
        //yyztid  24  已完成
        //yyztid  25  已作废

        int yyztid = 22;  // 查询已付款的单子
        int payOrder = orderDao.getPayOrderCount(odate,edid,sjdid,22);
        //如果 最大预约人数 大于 已经预约人数  则 说明 还可预约
        if(dnum-payOrder>0){
            return true;
        }
        return false;
    }
 
        Copied!
    

dao层

//UserDaoImpl 查询 该医生的 时间段最大可预约人数
@Override
    public int getDoctorDnum(String edid) {

        String sql= "select dnum from h_userinfo where did = ?";

        Integer query = null;
        try {
            query = queryRunner.query(sql, new ScalarHandler<Integer>(), edid);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return query;
    }
 
        Copied!
    
//OrderDaoImpl  查询 某医生  某日期 某时间段 已付款的 预约单的个数
@Override
    public int getPayOrderCount(String odate, String edid, String sjdid, int yyztid) {

        //查询 这个医生 的 这个日期 的 这个时间的   已付款的单子的个数

        String sql = "select count(*) from h_order where edid = ? and odate=? and sjdid = ? and  yyztid = ?";
        Long query = null;
        try {
            query = queryRunner.query(sql, new ScalarHandler<Long>(), edid, odate, sjdid, yyztid);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return query.intValue();
    }
 
        Copied!
    

6.5 现在预约

image-20230414093440202

image-20230414093547808

表单提交 把预约信息存入数据库

@Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

		//获取表单数据
        String edid = req.getParameter("edid");
        String dmoney = req.getParameter("dmoney");

        String odate = req.getParameter("odate");
        String sjdid = req.getParameter("sjdid");
        String sickness = req.getParameter("sickness");

        HttpSession session = req.getSession();

        HUser u = (HUser) session.getAttribute("u");
		
        //封装到HOrder 对象中
        HOrder hOrder = new HOrder();

        hOrder.setEdid(Integer.parseInt(edid));

        hOrder.setOdate(DateUtil.strToDate(odate));

        hOrder.setSjdid(Integer.parseInt(sjdid));

        hOrder.setSickness(sickness);

        hOrder.setGhf(Double.parseDouble(dmoney));

        //把用户提交的预约单的初始状态 改为 预约中
        hOrder.setYyztid(21);

        hOrder.setUdid(u.getUi().getDid());


        OrderService orderService = new OrderServiceImpl();
		//把order的数据存入数据库
        int result = orderService.addOrder(hOrder);
		
       // 放入域对象 是为了 数据回显
        session.setAttribute("oo",hOrder);


        resp.sendRedirect("/pay.jsp");
    }
 
       
    
// OrderDaoImpl
@Override
    public int addOrder(HOrder hOrder) {

        String sql = "insert into h_order (oid,edid,udid,sjdid,yyztid,sickness,ghf,odate,rdate) " +
                " values (null,?,?,?,?,?,?,?,now()) ";

        int update = 0;
        try {
            update = queryRunner.update(sql, hOrder.getEdid(), hOrder.getUdid(),
                    hOrder.getSjdid(), hOrder.getYyztid(), hOrder.getSickness(), hOrder.getGhf(), hOrder.getOdate());
        } catch (SQLException e) {
            e.printStackTrace();
        }

        return update;
    }
 
      
    

添加预约单之后 跳转到 pay.jsp 展示 预约相关信息

image-20230414093649022

确认支付

function pay(){
  			$.ajax({
  				url:"${pageContext.request.contextPath}/payOrder",
  				data:{oid:$("#oid").val()},
  				type:"get",
  				success:function(data){
  					if(data.code==200){
  						alert("付款成功,请在个人信息查看预约单");
  						location.href="index.jsp";
  					}else{
  						$("#sp").html("付款失败");
  					}
  				},
				dataType:"json"
  			});
  	}
 
     
    
//PayOrderServlet
@Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        String oid = req.getParameter("oid");


        OrderService orderService = new OrderServiceImpl();

        Integer yyztid= 22;
       int result =  orderService.updateOrderStatus(Integer.parseInt(oid),yyztid);

        PrintWriter writer = resp.getWriter();
        String s = "";
        if(result==1){
            R<String> r = new R<>();
            r.setCode(200);
            s = JSON.toJSONString(r);

        }else{
            R<String> r = new R<>();
            r.setCode(500);
            s = JSON.toJSONString(r);
        }

        writer.write(s);
    }

 
       
    

dao层

// 确认支付  把预约单的状态 改为 已支付
@Override
    public int updateOrderStatus(int oid, Integer yyztid) {
        String sql = "update h_order set yyztid = ? where oid = ?";

        int result = 0;
        try {
            result = queryRunner.update(sql, yyztid, oid);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return result;
    }
 
       
    

7.个人信息

页面是info.jsp ,用户的信息是在登录时 存入了session ,所以 这个页面可以直接显示

image-20230414093738679

<div class="container" >
    	<h1>${u.ui.drealname }<small>${u.ui.dsex==1?'男':'女' }</small></h1>
    	年龄:${u.ui.dage }<br>
    	手机号:${u.ui.dphone }<br>
    	身份证号:${u.ui.didcard}<br>
    	邮箱:${u.ui.demail }<br>
    	QQ:${u.ui.dqq }<br>
    	<form action="${pageContext.request.contextPath}/showOrder" >
    	<button type="submit" class="btn btn-primary" >点击查询我的预约</button>
    	</form>
    </div>
 
       
    

image-20230414093810575

1,我的预约

这个按钮 请求 ShowOrderServlet

@Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        HttpSession session = req.getSession();

        HUser huser = (HUser) session.getAttribute("u");

        HUserinfo ui = huser.getUi();

        OrderService orderService = new OrderServiceImpl();
		//查询患者的预约单集合
        List<HOrder> orders = orderService.findOrderByUdid(ui.getDid());

        req.setAttribute("os",orders);

        req.getRequestDispatcher("/info.jsp").forward(req,resp);
    }
 
        
    
//由于页面上展示的数据来自于多张表  多以需要多表查询
@Override
    public List<HOrder> findOrderByUdid(Integer did) {

        String sql = "SELECT o.oid,o.yyztid,ui.`drealname` as ename ,o.`sickness`,o.`odate`,t1.`tname` as sjd ,o.`ghf`,t2.`tname` as yyzt \n" +
                "\n" +
                " FROM h_order o JOIN h_userinfo ui ON o.edid = ui.did \n" +
                " JOIN h_type t1 ON o.`sjdid` = t1.`tid`\n" +
                " JOIN h_type t2 ON o.`yyztid` = t2.`tid` WHERE o.udid = ? ";

        List<HOrder> query = null;
        try {
            query = queryRunner.query(sql, new BeanListHandler<>(HOrder.class), did);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return query;
    }

 
       

2,预约单的操作

预约单的状态

21 预约中 22 已付款 23已取消 24已完成 25已作废

image-20230414093915305

预约中的 单子 可以取消 直接把改单子状态改为  已作废
预约中的 单子 可以付款 把单子状态改为 已付款 并且在页面上可以  取消 完成 操作

已付款的单子   可以取消 (但是 一天只能取消一次 一周只能取消两次 按照预约日期计算)  研究实现的代码

已付款的 单子 可以完成   完成后 状态改为已完成  页面上可以进行评论


页面 参考  info.jsp
servlet 参考   UpYyztServlet
难点为  如何判断  一天只能取消一次  一周只能取消两次

 
        
    

前端页面代码

function upYyzt(oid,zt,type){

  		// 获取 预约日期  传到后台
  		var odate = $("#"+oid+"").text();
		alert(odate);
  		$.ajax({
  			url:"${pageContext.request.contextPath}/upYyzt",
  			data:{"type":type,"oid":oid,"zt":zt,"odate":odate},
  			type:"get",
			dataType:"json",
  			success:function(d){
  				if(d.code==1){
  				    //页面刷新   重新加载页面
					alert("操作成功");
  					location.href="/showOrder";
  				}
  				if(d.code==0 && type==3){
  					alert("取消预约失败,当天只能取消1次,一周只能取消2次");
  				}
  				if(d.code==0 && type==1){
  					alert("作废失败");
  				}
  				if(d.code==0 && type==2){
  					alert("付款失败");
  				}
  				if(d.code==0 && type==4){
  					alert("操作失败");
  				}
  			}
  			
  		});
  		
  	}
 
    
    

后端UpdateYyztServlet

@Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //要更改哪一个单子的状态
        String oid = req.getParameter("oid");
        //要更改为什么状态
        String zt = req.getParameter("zt");

        //type
        // 1       未付款  要取消未付款的单子
        // 2       未付款  想要付款
        // 3       已付款  要取消已付款的单子  这个会有退款操作  ,  取消已付款的单子 是有限制的
        // 4       已付款  要完成已付款的单子   只有完成状态的单子 才可以评论

        String type = req.getParameter("type");
        //预约日期
        String odate = req.getParameter("odate");
        Date date = DateUtil.strToDate(odate);
        //从session 中 获取当前患者的信息
        HttpSession session = req.getSession();
        HUser hUser = (HUser) session.getAttribute("u");
        //拿到当前患者的信息
        HUserinfo ui = hUser.getUi();

        OrderService orderService = new OrderServiceImpl();
        //参数1  预约单id
        //参数2  要把这个预约单改为什么状态
        //参数3  这次操作的类型
        //参数4  患者的id
        //参数5  预约日期

        int result = orderService.updateOrderByType(Integer.parseInt(oid),Integer.parseInt(zt),Integer.parseInt(type),ui.getDid(),date);

        PrintWriter writer = resp.getWriter();
        R<Object> r = new R<>();
        if(result==1){
            r.setCode(1);

        }else{
            r.setCode(0);
        }
        writer.write(JSON.toJSONString(r));
    }
 
        
    

service

/**
     * @param oid   预约单id
     * @param yyztid  预约状态id
     * @param type  预约单 由什么状态 到 什么状态的 标识
     * @param did   患者的id
     * @param odate  预约日期
     * */
    @Override
    public int updateOrderByType(int oid, int yyztid, int type, Integer did, Date odate) {

        //预约中的取消
        if(type==1){
           return this.updateOrderStatus(oid,yyztid);
        }
        //预约中的付款
        if(type==2){
            return this.updateOrderStatus(oid,yyztid);
        }

        //付款的取消
        if(type==3){
            //判断 是否能够取消    一天只能取消一次   一周 只能取消两次
            boolean isQx = isQxOrder(oid,did,odate);
            if(isQx){
                return this.updateOrderStatus(oid,yyztid);
            }
        }
        //付款的完成
        if(type==4){
            return this.updateOrderStatus(oid,yyztid);
        }
        return 0;
    }

    private boolean isQxOrder(int oid, Integer did, Date odate) {
        //预约单 当天的取消个数
        int dayQxCount = orderDao.countDayQx(oid,did,odate);
        //预约单所在那一周的取消个数
        int weekQxCount = orderDao.countWeekQx(oid,did,odate);

        if(dayQxCount>=1 || weekQxCount>=2){
            return false;
        }
        return true;
    }
 
      
    

dao

//暂未实现

1 未付款 要取消未付款的单子
// 2 未付款 想要付款
// 3 已付款 要取消已付款的单子 这个会有退款操作 , 取消已付款的单子 是有限制的
// 4 已付款 要完成已付款的单子 只有完成状态的单子 才可以评论

    String type = req.getParameter("type");
    //预约日期
    String odate = req.getParameter("odate");
    Date date = DateUtil.strToDate(odate);
    //从session 中 获取当前患者的信息
    HttpSession session = req.getSession();
    HUser hUser = (HUser) session.getAttribute("u");
    //拿到当前患者的信息
    HUserinfo ui = hUser.getUi();

    OrderService orderService = new OrderServiceImpl();
    //参数1  预约单id
    //参数2  要把这个预约单改为什么状态
    //参数3  这次操作的类型
    //参数4  患者的id
    //参数5  预约日期

    int result = orderService.updateOrderByType(Integer.parseInt(oid),Integer.parseInt(zt),Integer.parseInt(type),ui.getDid(),date);

    PrintWriter writer = resp.getWriter();
    R<Object> r = new R<>();
    if(result==1){
        r.setCode(1);

    }else{
        r.setCode(0);
    }
    writer.write(JSON.toJSONString(r));
}

service

```java
/**
     * @param oid   预约单id
     * @param yyztid  预约状态id
     * @param type  预约单 由什么状态 到 什么状态的 标识
     * @param did   患者的id
     * @param odate  预约日期
     * */
    @Override
    public int updateOrderByType(int oid, int yyztid, int type, Integer did, Date odate) {

        //预约中的取消
        if(type==1){
           return this.updateOrderStatus(oid,yyztid);
        }
        //预约中的付款
        if(type==2){
            return this.updateOrderStatus(oid,yyztid);
        }

        //付款的取消
        if(type==3){
            //判断 是否能够取消    一天只能取消一次   一周 只能取消两次
            boolean isQx = isQxOrder(oid,did,odate);
            if(isQx){
                return this.updateOrderStatus(oid,yyztid);
            }
        }
        //付款的完成
        if(type==4){
            return this.updateOrderStatus(oid,yyztid);
        }
        return 0;
    }

    private boolean isQxOrder(int oid, Integer did, Date odate) {
        //预约单 当天的取消个数
        int dayQxCount = orderDao.countDayQx(oid,did,odate);
        //预约单所在那一周的取消个数
        int weekQxCount = orderDao.countWeekQx(oid,did,odate);

        if(dayQxCount>=1 || weekQxCount>=2){
            return false;
        }
        return true;
    }
 
      
    

dao

//暂未实现

文档+需求分析+sql文件+源码
提取:https://download.csdn.net/download/m0_49102053/87688385

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值