传智健康

  • 一、项目概述
    • 1.1 项目介绍
    • 1.2 技术架构
    • 1.3 功能架构
  • 二、环境搭建
    • 2.1 项目结构
    • 2.2 maven项目搭建
  • 三、Power Designer和ElementUI
    • 3.1 Power Designer
    • 3.2 ElementUI
  • 四、模块实现
    • 4.1 预约管理-检查项管理
      • 4.1.1 新增检查项
      • 4.1.2 检查项分页
      • 4.1.3 删除检查项
      • 4.1.4 编辑检查项
    • 4.2 预约管理-检查组管理
      • 4.2.1 新增检查组
      • 4.2.2 检查组分页
      • 4.2.3 编辑检查组(需要多次理清关系)
      • 4.2.4 删除检查组
    • 4.3 预约管理-套餐管理
      • 4.3.1 图片存储方案
      • 4.3.2 新增套餐
      • 4.3.3 体检套餐分页
      • 4.3.4 定期清理垃圾图片(定时任务组件Quartz)
    • 4.4 预约管理-预约设置
      • 4.4.1 Apache POI
      • 4.4.2 批量导入预约设置信息
      • 4.4.3 日历展示预约设置信息
      • 4.4.4 基于日历实现预约设置
    • 4.5 移动端开发-体检预约
      • 4.5.1 移动端开发
      • 4.5.2 需求分析和环境搭建
      • 4.5.3 套餐列表页面动态展示
      • 4.5.4 套餐详情页面动态展示
      • 4.5.5 短信发送
    • 4.6 页面静态化
      • 4.6.1 页面静态化介绍
      • 4.6.2 Freemarker
      • 4.6.3 生成移动端静态页面
    • 4.7 移动端开发-体检预约
      • 4.7.1 体检预约
      • 4.7.2 预约成功页面展示
    • 4.8 移动端开发-手机快速登录、权限控制
      • 4.8.1 手机快速登录
      • 4.8.2 权限控制
      • 4.8.3 在项目中应用Spring Security
      • 4.8.4 显示用户名
      • 4.8.5 用户退出
    • 4.9 图形报表ECharts
      • 4.9.1 会员数量折线图
      • 4.9.2 套餐预约占比饼形图
    • 4.10 POI报表
      • 4.10.1 运营数据统计
      • 4.10.2 运营数据统计报表导出(EXCEL形式)
      • 4.10.3 运营数据统计报表导出(PDF形式)
  • 五、目前存在的问题

一、项目概述

1.1 项目介绍

传智健康管理系统是一款应用于健康管理机构的业务系统,实现健康管理机构工作内容可视化、会员管理专业化、健康评估数字化、健康干预流程化、知识库集成化,从而提高健康管理师的工作效率,加强与会员间的互动,增强管理者对健康管理机构运营情况的了解。

1.2 技术架构

1.3 功能架构

二、环境搭建

2.1 项目结构

本项目采用maven分模块开发方式,即对整个项目拆分为几个maven工程,每个maven工程存放特定的一类代码,具体如下:

各模块职责定位:

health_parent:父工程,打包方式为pom,统一锁定依赖的版本,同时聚合其他子模块便于统一执行maven命令

health_common:通用模块,打包方式为jar,存放项目中使用到的一些工具类、实体类、返回结果和常量类

health_interface:打包方式为jar,存放服务接口

health_service_provider:Dubbo服务模块,打包方式为war,存放服务实现类、Dao接口、Mapper映射文件等,作为服务提供方,需要部署到tomcat运行

health_backend:传智健康管理后台,打包方式为war,作为Dubbo服务消费方,存放Controller、HTML页面、js、css、spring配置文件等,需要部署到tomcat运行

health_mobile:移动端前台,打包方式为war,作为Dubbo服务消费方,存放Controller、HTML页面、js、css、spring配置文件等,需要部署到tomcat运行

2.2 maven项目搭建

通过前面的项目功能架构图可以知道本项目分为传智健康管理后台和传智健康前台(微信端)

搭建后的目录结构如图所示:

三、Power Designer和ElementUI

3.1 Power Designer

PowerDesigner是Sybase公司的一款软件,使用它可以方便地对系统进行分析设计,他几乎包括了数据库模型设计的全过程。利用PowerDesigner可以制作数据流程图、概念数据模型、物理数据模型、面向对象模型。

在项目设计阶段通常会使用PowerDesigner进行数据库设计。使用PowerDesigner可以更加直观的表现出数据库中表之间的关系,并且可以直接导出相应的建表语句。

3.2 ElementUI

ElementUI是一套基于VUE2.0的桌面端组件库,ElementUI提供了丰富的组件帮助开发人员快速构建功能强大、风格统一的页面。
官网地址:http://element-cn.eleme.io/#/zh-CN

传智健康项目后台系统就是使用ElementUI来构建页面,在页面上引入 js 和 css 文件即可开始使用,如下:

<!-- 引入ElementUI样式 -->
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<!-- 引入ElementUI组件库 -->
<script src="https://unpkg.com/element-ui/lib/index.js"></script>

四、模块实现

需求分析:
传智健康管理系统是一款应用于健康管理机构的业务系统,实现健康管理机构工作内容可视化、患者管理专业化、健康评估数字化、健康干预流程化、知识库集成化,从而提高健康管理师的工作效率,加强与患者间的互动,增强管理者对健康管理机构运营情况的了解。

系统分为传智健康后台管理系统和移动端应用两部分。其中后台系统提供给健康管理机构内部人员(包括系统管理员、健康管理师等)使用,微信端应用提供给健康管理机构的用户(体检用户)使用。

功能架构图:

通过上面的功能架构图可以看到,传智健康后台管理系统有会员管理、预约管理、健康评估、健康干预等功能。移动端有会员管理、体检预约、体检报告等功能。后台系统和移动端应用都会通过Dubbo调用服务层发布的服务来完成具体的操作。本项目属于典型的SOA架构形式(面向服务的架构)。

项目开发过程中一般会提供一些公共资源,供多个模块或者系统来使用。这些放到health_common工程中。
MessageConstant:返回消息常量类

Result类:封装返回结果

PageResult类:分页结果封装对象

QueryPageBean类:封装查询条件

4.1 预约管理-检查项管理

4.1.1 新增检查项

每次点击新建按钮时清空表单输入项

实现过程:
页面完善动态效果(提交到 “/checkitem/add.do”)——>controller(新增 “/add”)——> service接口(add)
——>serviceimpl实现类(add)——>Dao接口(add)——>Mapper映射文件 (id=“add”)

4.1.2 检查项分页

本项目所有分页功能都是基于ajax的异步请求来完成的,请求参数和后台响应数据格式都使用json数据格式。
请求参数包括页码、每页显示记录数、查询条件。
请求参数的json格式为:{currentPage:1,pageSize:10,queryString:’‘itcast’’}
后台响应数据包括总记录数、当前页需要展示的数据集合。
响应数据的json格式为:{total:1000,rows:[]}

如下图:

1.在页面中提供了findPage方法用于分页查询,为了能够在checkitem.html页面加载后直接可以展示分页数据,可以在VUE提供的钩子函数created中调用findPage方法
2.分页方法执行时机:①点击查询 ②切换页码

实现过程:
页面完善动态效果(提交到 “/checkitem/findPage.do”,param)——>controller(分页查询 “/findPage”)——> service接口(扩展分页查询方法:pageQuery)——>serviceimpl实现类(基于Mybatis分页助手插件实现分页;pageQuery)——>Dao接口(扩展分页查询方法,根据条件进行查询; selectByCondition)——>Mapper映射文件 (id=“selectByCondition”)

4.1.3 删除检查项

注意:不能直接删除,需要判断当前检查项是否和检查组关联,如果已经和检查组进行了关联则不允许删除

实现过程:
页面完善动态效果(提交到 “/checkitem/delete.do?id=” + row.id)——>controller(删除 “/delete”)——> service接口(deleteById)
——>serviceimpl实现类(deleteById)——>Dao接口(扩展方法 findCountByCheckItemId和 deleteById)——>Mapper映射文件 (根据ID删除 id=“deleteById” 和 根据检查项id查询中间关系表 id=“findCountByCheckItemId”)

4.1.4 编辑检查项

用户点击编辑按钮时,需要弹出编辑窗口并且将当前记录的数据进行回显

实现过程:
页面完善动态效果(提交到 “/checkitem/findById.do?id=” + row.id 和 “/checkitem/edit.do”)——>controller(编辑“/edit” 和 根据id查询 “/findById”)——> service接口(edit 和 findById)——>serviceimpl实现类(edit 和 findById)——>Dao接口(edit 和 findById)——>Mapper映射文件 (id=“edit” 和 id=“findById”)

4.2 预约管理-检查组管理

检查组其实就是多个检查项的集合,例如有一个检查组为“一般检查”,这个检查组可以包括多个检查项:身高、体重、收缩压、舒张压等。所以在添加检查组时需要选择这个检查组包括的检查项。

检查组对应的实体类为CheckGroup,对应的数据表为t_checkgroup。检查组和检查项为多对多关系,所以需要中间表t_checkgroup_checkitem进行关联。

4.2.1 新增检查组

1.每次点击新建按钮时清空表单输入项
2.由于新增检查组时还需要选择此检查组包含的检查项,所以新增检查组窗口分为两部分信息:基本信息和检查项信息

现在虽然已经完成了新增窗口的弹出,但是在检查项信息标签页中需要动态展示所有的检查项信息列表数据,并且可以进行勾选。
1.动态展示检查项列表实现过程:
页面完善动态效果(提交到 “/checkitem/findAll.do”)——>controller(查询所有 “/findAll”)——> service接口(findAll)
——>serviceimpl实现类(findAll)——>Dao接口(findAll)——>Mapper映射文件 (id=“findAll”)

当用户点击新增窗口中的确定按钮时发送ajax请求将数据提交到后台进行数据库操作。提交到后台的数据分为两部分:检查组基本信息(对应的模型数据为formData)和检查项id数组(对应的模型数据为checkitemIds)。
2.提交请求实现过程:
页面完善动态效果(提交到 “/checkgroup/add.do?checkitemIds=” + this.checkitemIds,this.formData)——>controller(新增“/add”)——> service接口(add) ——>serviceimpl实现类(add 和 设置检查组合和检查项的关联关系 setCheckGroupAndCheckItem)——>Dao接口(add 和 setCheckGroupAndCheckItem)——>Mapper映射文件 (id=“add” 和 id=“setCheckGroupAndCheckItem”)

4.2.2 检查组分页

1.在页面中提供了findPage方法用于分页查询,为了能够在checkgroup.html页面加载后直接可以展示分页数据,可以在VUE提供的钩子函数created中调用findPage方法
2.分页方法执行时机:①点击查询 ②切换页码

实现过程:
页面完善动态效果(提交到 “/checkgroup/findPage.do”,param)——>controller(分页查询 “/findPage”)——> service接口(扩展分页查询方法:pageQuery)——>serviceimpl实现类(基于Mybatis分页助手插件实现分页;pageQuery)——>Dao接口(扩展分页查询方法,根据条件进行查询; selectByCondition)——>Mapper映射文件 (id=“selectByCondition”)

4.2.3 编辑检查组(需要多次理清关系)

用户点击编辑按钮时,需要弹出编辑窗口并且将当前记录的数据进行回显,用户修改完成后点击确定按钮将修改后的数据提交到后台进行数据库操作。此处进行数据回显的时候,除了需要检查组基本信息的回显之外,还需要回显当前检查组包含的检查项(以复选框勾选的形式回显)。

实现过程:
页面完善动态效果(提交到 “/checkgroup/findById.do?id=”+row.id 和 “/checkitem/findAll.do” 和 “/checkgroup/findCheckItemIdsByCheckGroupId.do?id=”+row.id 和 “/checkgroup/edit.do?checkitemIds=”+this.checkitemIds,this.formData)——>controller(根据id查询 “/findById” 和 根据检查组合id查询对应的所有检查项id “/findCheckItemIdsByCheckGroupId” 和 编辑"/edit")——> service接口(edit 和 findCheckItemIdsByCheckGroupId 和 findById)——>serviceimpl实现类(findById 和 findCheckItemIdsByCheckGroupId 和 edit 和setCheckGroupAndCheckItem)——>Dao接口(setCheckGroupAndCheckItem 和 findById 和 findCheckItemIdsByCheckGroupId 和edit 和 deleteAssociation)——>Mapper映射文件 (id=“findById” 和 id=“setCheckGroupAndCheckItem” 和 id=“deleteAssociation” 和id=“edit”)

4.2.4 删除检查组

注意:不能直接删除,需要判断当前检查项是否和检查组关联,如果已经和检查组进行了关联则不允许删除
删除时候,先删除检查项和检查组之间的关系表,然后再删除检查项

实现过程:
页面完善动态效果(提交到 “/checkgroup/delete.do?id=”+row.id)——>controller(删除 “/delete”)——> service接口(deleteById)
——>serviceimpl实现类(deleteById)——>Dao接口(deleteById 和 deleteAssociation)——>Mapper映射文件 (id=“deleteById” 和 id=“deleteAssociation”)

4.3 预约管理-套餐管理

4.3.1 图片存储方案

在实际开发中,我们会有很多处理不同功能的服务器。例如:
应用服务器:负责部署我们的应用
数据库服务器:运行我们的数据库
文件服务器:负责存储用户上传文件的服务器
分服务器处理的目的是让服务器各司其职,从而提高我们项目的运行效率。
常见的图片存储方案:
方案一:使用nginx搭建图片服务器
方案二:使用开源的分布式文件存储系统,例如Fastdfs、HDFS等
方案三:使用云存储,例如阿里云、七牛云等

本项目使用的是七牛云存储(主要使用的是七牛云提供的对象存储服务来存储图片。)
官网:https://www.qiniu.com/

本项目采用的是JavaSDK方式
地址:https://developer.qiniu.com/kodo/sdk/1239/java

使用Java SDK操作七牛云需要导入如下maven坐标:

<dependency><groupId>com.qiniu</groupId><artifactId>qiniu-java-sdk</artifactId><version>7.2.0</version>
</dependency>

此处将其封装成了一个工具类QiniuUtils,主要实现图片上传和删除功能

当使用这个工具类时候,注意修改这三处地方。

4.3.2 新增套餐

套餐其实就是检查组的集合,例如有一个套餐为“入职体检套餐”,这个体检套餐可以包括多个检查组:一般检查、血常规、尿常规、肝功三项等。所以在添加套餐时需要选择这个套餐包括的检查组。
套餐对应的实体类为Setmeal,对应的数据表为t_setmeal。套餐和检查组为多对多关系,所以需要中间表t_setmeal_checkgroup进行关联。

现在虽然已经完成了新增窗口的弹出,但是在检查组信息标签页中需要动态展示所有的检查组信息列表数据,并且可以进行勾选。
1.动态展示检查项列表实现过程:
页面完善动态效果(提交到"/checkgroup/findAll.do")——>controller(查询所有 “/findAll”)——> service接口(findAll)
——>serviceimpl实现类(findAll)——>Dao接口(findAll)——>Mapper映射文件 (id=“findAll”)

2.图片上传并预览:
图片文件上传成功后,通过触发上传成功后的钩子函数handleAvatarSuccess,为模型数据imageUrl赋值,用于页面图片预览。上传提交到action="/setmeal/upload.do",在SetmealController中通过upload函数来执行上传功能,需要调用骑牛工具类QiniuUtils中的upload2Qiniu函数来实现。

注意:可以在上图片之前通过触发上传前的钩子函数beforeAvatarUpload进行图片的验证:验证图片的大小、格式等

当用户点击新增窗口中的确定按钮时发送ajax请求将数据提交到后台进行数据库操作。提交到后台的数据分为两部分:套餐基本信息(对应的模型数据为formData)和检查组id数组(对应的模型数据为checkgroupIds)。
3.提交请求实现过程:
页面完善动态效果(提交到 “/setmeal/add.do?checkgroupIds=”+this.checkgroupIds,this.formData)——>controller(新增“/add”)——> service接口(add) ——>serviceimpl实现类(add 和 设置套餐和检查组的关联关系 setSetmealAndCheckGroup)——>Dao接口(add 和 setSetmealAndCheckGroup)——>Mapper映射文件 (id=“add” 和 id=“setSetmealAndCheckGroup”)

4.3.3 体检套餐分页

1.在页面中提供了findPage方法用于分页查询,为了能够在setmeal.html页面加载后直接可以展示分页数据,可以在VUE提供的钩子函数created中调用findPage方法
2.分页方法执行时机:①点击查询 ②切换页码

实现过程:
页面完善动态效果(提交到"/setmeal/findPage.do",param)——>controller(分页查询 “/findPage”)——> service接口(扩展分页查询方法:pageQuery)——>serviceimpl实现类(基于Mybatis分页助手插件实现分页;pageQuery)——>Dao接口(扩展分页查询方法,根据条件进行查询; findByCondiction)——>Mapper映射文件 (id=“findByCondiction”)

4.3.4 定期清理垃圾图片(定时任务组件Quartz)

Quartz介绍
Quartz是Job scheduling(作业调度)领域的一个开源项目,Quartz既可以单独使用也可以跟spring框架整合使用,在实际开发中一般会使用后者。使用Quartz可以开发一个或者多个定时任务,每个定时任务可以单独指定执行的时间,例如每隔1小时执行一次、每个月第一天上午10点执行一次、每个月最后一天下午5点执行一次等。

官网:http://www.quartz-scheduler.org/

maven坐标:

<dependency><groupId>org.quartz-scheduler</groupId><artifactId>quartz</artifactId><version>2.2.1</version>
</dependency>
<dependency><groupId>org.quartz-scheduler</groupId><artifactId>quartz-jobs</artifactId><version>2.2.1</version>
</dependency>

cron表达式(cron表达式可以灵活的定义出符合要求的程序执行的时间),自己编写表达式还是有一些困难的,我们可以借助一些cron表达式在线生成器来根据我们的需求生成表达式即可。http://cron.qqe2.com/

前面我们已经完成了体检套餐的管理,在新增套餐时套餐的基本信息和图片是分两次提交到后台进行操作的。也就是用户首先将图片上传到七牛云服务器,然后再提交新增窗口中录入的其他信息。如果用户只是上传了图片而没有提交录入的其他信息,此时的图片就变为了垃圾图片,因为在数据库中并没有记录它的存在。此时我们要如何处理这些垃圾图片呢?

解决方案就是通过定时任务组件定时清理这些垃圾图片。为了能够区分出来哪些图片是垃圾图片,我们在文件上传成功后将图片保存到了一个redis集合中,当套餐数据插入到数据库后我们又将图片名称保存到了另一个redis集合中,通过计算这两个集合的差值就可以获得所有垃圾图片的名称。

方案就是利用redis来保存图片名称,具体做法为:
1、当用户上传图片后,将图片名称保存到redis的一个Set集合中,例如集合名称为setmealPicResources
2、当用户添加套餐后,将图片名称保存到redis的另一个Set集合中,例如集合名称为setmealPicDbResources
3、计算setmealPicResources集合与setmealPicDbResources集合的差值,结果就是垃圾图片的名称集合,清理这些图片即可

在这里基于Quartz定时任务,通过计算redis两个集合的差值找出所有的垃圾图片,就可以将垃圾图片清理掉。

1.完善文件上传实现过程:
①.在health_backend项目中提供Spring配置文件spring-redis.xmlRedis常量类,完善SetmealController中的upload方法,在文件上传成功后将图片名称保存到redis集合中
②.在health_service_provider项目中提供Spring配置文件applicationContext-redis.xml,完善SetmealServiceImpl服务类中的add方法,在保存完成套餐信息后将图片名称存储到redis集合中

2.定时清理垃圾图片实现:
①:创建maven工程health_jobs,打包方式为war,导入Quartz等相关坐标,并配置web.xml,log4j.properties,applicationContext-redis.xml,applicationContext-jobs.xml
②:创建ClearImgJob定时任务类,实现定时清理垃圾图片(先是根据Redis中保存的两个set集合进行差值计算,获得垃圾图片名称集合;然后删除七牛云服务器上的图片;再从Redis集合中删除图片名称)

4.4 预约管理-预约设置

前面我们已经完成了检查项管理、检查组管理、套餐管理等。接下来我们需要进行预约设置,其实就是设置每一天的体检预约最大数量。客户可以通过微信端在线预约,在线预约时需要选择体检的时间,如果客户选择的时间已经预约满则无法进行预约。

4.4.1 Apache POI

Apache POI是用Java编写的免费开源的跨平台的Java API,Apache POI提供API给Java程序对Microsoft Office格式档案读和写的功能,其中使用最多的就是使用POI操作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 Power Point格式档案的功能
HDGF - 提供读Microsoft Visio格式档案的功能
HPBF - 提供读Microsoft Publisher格式档案的功能
HSMF - 提供读Microsoft Outlook格式档案的功能

4.4.2 批量导入预约设置信息

预约设置信息对应的数据表为t_ordersetting,预约设置操作对应的页面为ordersetting.html
orderDate:预约日期
number:可预约人数
reservations:已预约人数

批量导入预约设置信息操作过程:
1、点击模板下载按钮下载Excel模板文件
2、将预约设置信息录入到模板文件中
3、点击上传文件按钮将录入完信息的模板文件上传到服务器
4、通过POI读取上传文件的数据并保存到数据库

实现过程:
页面完善动态效果(提交到 action="/ordersetting/upload.do")——>controller("/upload")——> service接口(add)——>serviceimpl实现类(add)——>Dao接口(add)——>Mapper映射文件 (id=“add”)

注意:在实现类中,需要进行判断,如果当天已经进行了预约设置,则进行更新操作。

4.4.3 日历展示预约设置信息

前面已经完成了预约设置功能,现在就需要通过日历的方式展示出来每天设置的预约人数。
在页面中已经完成了日历的动态展示,我们只需要查询当前月份的预约设置信息并展示到日历中即可,同时在日历中还需要展示已经预约的人数

页面发送Ajax请求,根据当前对应的月份查询数据库,封装成响应结果赋值给leftobj模型数据,用于页面展示

实现过程:
页面完善动态效果(提交到 “/ordersetting/getOrderSettingByMonth.do?date=”+this.currentYear+"-"+this.currentMonth)——>controller("/getOrderSettingByMonth")——> service接口(getOrderSettingByMonth)——>serviceimpl实现类(getOrderSettingByMonth)
——>Dao接口(getOrderSettingByMonth)——>Mapper映射文件 (id=“getOrderSettingByMonth”)

4.4.4 基于日历实现预约设置

通过点击日历中的设置按钮来设置对应日期的可预约人数

点击设置,弹出预约设置窗口并发送ajax请求(在页面中需要将当天的日期和数量参数传给后台)

实现过程:
页面完善动态效果(提交到"/ordersetting/editNumberByDate.do",{orderDate:this.formatDate(day.getFullYear(),day.getMonth()+1,day.getDate()), number:value )——>controller("/editNumberByDate")——> service接口(editNumberByDate)——>serviceimpl实现类(editNumberByDate)
——>Dao接口(editNumberByDate)——>Mapper映射文件 (id="editNumberByDate"和id=“findCountByOrderDate”)

4.5 移动端开发-体检预约

4.5.1 移动端开发

一、移动端开发主要有三种方式:

1、基于手机API开发(原生APP)

手机端使用手机API,例如使用Android、ios等进行开发,服务端只是一个数据提供者。手机端请求服务端获取数据(json、xml格式)并在界面进行展示。这种方式相当于传统开发中的C/S模式,即需要在手机上安装一个客户端软件。

这种方式需要针对不同的手机系统分别进行开发,目前主要有以下几个平台:
1、苹果ios系统版本,开发语言是Objective-C
2、安卓Android系统版本,开发语言是Java
3、微软Windows phone系统版本,开发语言是C#
4、塞班symbian系统版本,开发语言是C++
此种开发方式举例:手机淘宝、抖音、今日头条、大众点评

2、基于手机浏览器开发(移动web)

生存在浏览器中的应用,基本上可以说是触屏版的网页应用。这种开发方式相当于传统开发中的B/S模式,也就是手机上不需要额外安装软件,直接基于手机上的浏览器进行访问。这就需要我们编写的html页面需要根据不同手机的尺寸进行自适应调节,目前比较流行的是html5开发。除了直接通过手机浏览器访问,还可以将页面内嵌到一些应用程序中,例如通过微信公众号访问html5页面。
这种开发方式不需要针对不同的手机系统分别进行开发,只需要开发一个版本,就可以在不同的手机上正常访问。

本项目会通过将我们开发的html5页面内嵌到微信公众号这种方式进行开发。

3、混合开发(混合APP)

是半原生半Web的混合类App。需要下载安装,看上去类似原生App,访问的内容是Web网页。其实就是把HTML5页面嵌入到一个原生容器里面。

二、微信公众号开发
微信公众平台,官网:https://mp.weixin.qq.com/

在微信公众平台可以看到,有四种帐号类型:服务号、订阅号、小程序、企业微信(原企业号)。

本项目会选择订阅号这种方式进行公众号开发。

4.5.2 需求分析和环境搭建

需求分析

用户在体检之前需要进行预约,可以通过电话方式进行预约,此时会由体检中心客服人员通过后台系统录入预约信息。用户也可以通过手机端自助预约。本章节开发的功能为用户通过手机自助预约。

预约流程如下:
1、访问移动端首页
2、点击体检预约进入体检套餐列表页面
3、在体检套餐列表页面点击具体套餐进入套餐详情页面
4、在套餐详情页面点击立即预约进入预约页面
5、在预约页面录入体检人相关信息点击提交预约

项目搭建
1.在health_common工程的pom.xml文件中导入阿里短信发送的maven坐标和导入通用组件工具类(ValidateCodeUtils,SMSUtils,RedisMessageConstant)

<dependency><groupId>com.aliyun</groupId><artifactId>aliyun-java-sdk-core</artifactId><version>3.3.1</version>
</dependency>
<dependency><groupId>com.aliyun</groupId><artifactId>aliyun-java-sdk-dysmsapi</artifactId><version>1.0.0</version>
</dependency>

2.创建移动端工程health_mobile,打包方式为war,用于存放Controller,在Controller中通过Dubbo可以远程访问服务层相关服务,所以需要依赖health_interface接口工程。

4.5.3 套餐列表页面动态展示

点击体检预约直接跳转到体检套餐列表页面,并展示套餐列表信息

实现过程:
页面完善动态效果(提交到"/setmeal/getAllSetmeal.do")——>controller( “/getAllSetmeal”)——> service接口(findAll)——>serviceimpl实现类(findAll)——>Dao接口(findAll)——>Mapper映射文件 (id=“findAll”)

4.5.4 套餐详情页面动态展示

前面我们已经完成了体检套餐列表页面动态展示,点击其中任意一个套餐则跳转到对应的套餐详情页面(/pages/setmeal_detail.html),并且会携带此套餐的id作为参数提交。

请求路径格式:http://localhost/pages/setmeal_detail.html?id=10

在套餐详情页面需要展示当前套餐的信息(包括图片、套餐名称、套餐介绍、适用性别、适用年龄)、此套餐包含的检查组信息、检查组包含的检查项信息等。

在页面中,需要将当前所要查询套餐id通过封装好的getUrlParam方法获取到。
此处会使用mybatis提供的关联查询,在根据id查询套餐时,同时将此套餐包含的检查组都查询出来,并且将检查组包含的检查项都查询出来。

实现过程:
页面完善动态效果(提交到"/setmeal/findById.do?id=" + id)——>controller( “/findById”)——> service接口(finById)——>serviceimpl实现类(finById)——>Dao接口(finById)——>Mapper映射文件 (id=“finById”)

4.5.5 短信发送

短信服务介绍

目前市面上有很多第三方提供的短信服务,这些第三方短信服务会和各个运营商(移动、联通、电信)对接,我们只需要注册成为会员并且按照提供的开发文档进行调用就可以发送短信。需要说明的是这些短信服务都是收费的服务。

本项目短信发送我们选择的是阿里云提供的短信服务。
短信服务(Short Message Service)是阿里云为用户提供的一种通信服务的能力,支持快速发送短信验证码、短信通知等。三网合一专属通道,与工信部携号转网平台实时互联。电信级运维保障,实时监控自动切换,到达率高达99%。短信服务API提供短信发送、发送状态查询、短信批量发送等能力,在短信服务控制台上添加签名、模板并通过审核之后,可以调用短信服务API完成短信发送等操作。

阿里云官网:https://www.aliyun.com/

实现过程:

  1. 导入maven坐标
 <dependency><groupId>com.aliyun</groupId><artifactId>aliyun-java-sdk-core</artifactId><version>3.3.1</version>
</dependency>
<dependency><groupId>com.aliyun</groupId><artifactId>aliyun-java-sdk-dysmsapi</artifactId><version>1.0.0</version>
</dependency>

2.短信发送工具类SMSUtils (使用时候需要在这个工具类中修改为自己的Access和密匙等其他内容)
3.在需要的使用的controller中进行调用SMSUtils

4.6 页面静态化

4.6.1 页面静态化介绍

我们已经实现了移动端套餐列表页面和套餐详情页面的动态展示。但是我们需要思考一个问题,就是对于这两个页面来说,每次用户访问这两个页面都需要查询数据库获取动态数据进行展示,而且这两个页面的访问量是比较大的,这就对数据库造成了很大的访问压力,并且数据库中的数据变化频率并不高。那我们需要通过什么方法为数据库减压并提高系统运行性能呢?答案就是页面静态化。

页面静态化其实就是将原来的动态网页(例如通过ajax请求动态获取数据库中的数据并展示的网页)改为通过静态化技术生成的静态网页,这样用户在访问网页时,服务器直接给用户响应静态html页面,没有了动态查询数据库的过程。

那么这些静态HTML页面还需要我们自己去编写吗?其实并不需要,我们可以通过专门的页面静态化技术帮我们生成所需的静态HTML页面,例如:Freemarker、thymeleaf等

4.6.2 Freemarker

Freemarker介绍

FreeMarker 是一个用 Java 语言编写的模板引擎,它基于模板来生成文本输出。FreeMarker与 Web 容器无关,即在 Web 运行时,它并不知道 Servlet 或 HTTP。它不仅可以用作表现层的实现技术,而且还可以用于生成 XML,JSP 或 Java等。

生成文件
使用步骤:
第一步:创建一个 Configuration 对象,直接 new 一个对象。构造方法的参数就是 freemarker的版本号。
第二步:设置模板文件所在的路径。
第三步:设置模板文件使用的字符集。一般就是 utf-8。
第四步:加载一个模板,创建一个模板对象。
第五步:创建一个模板使用的数据集,可以是 pojo 也可以是 map。一般是 Map。
第六步:创建一个 Writer 对象,一般创建 FileWriter 对象,指定生成的文件名。
第七步:调用模板对象的 process 方法输出文件。
第八步:关闭流。

4.6.3 生成移动端静态页面

1.在health_common工程的pom文件中导入Freemarker的maven坐标

<dependency><groupId>org.freemarker</groupId><artifactId>freemarker</artifactId><version>2.3.23</version>
</dependency>

2.创建模板文件

在health_service_provider工程的WEB-INF目录中创建ftl目录,在ftl目录中创建模板文件mobile_setmeal.ftl和mobile_setmeal_detail.ftl文件,前者是用于生成套餐列表页面的模板文件,后者是生成套餐详情页面的模板文件

3.配置文件

(1)在health_service_provider工程中创建属性文件freemarker.properties
out_put_path=D:/ideaProjects/health_parent/health_mobile/src/main/webapp/pages
通过上面的配置可以指定将静态HTML页面生成的目录位置
(2)在health_service_provider工程的Spring配置文件中配置

4.生成静态页面
在health_service_provider工程中的SetmealServiceImpl类中,加入生成静态页面的逻辑。

①.generateMobileStaticHtml(生成当前方法所需的静态页面)
②.generateMobileSetmealListHtml(生成套餐列表静态页面)
③.generateMobileSetmealDetailHtml(生成套餐详情静态页面(可能有多个))
④.generateHtml(用于生成静态页面)

4.7 移动端开发-体检预约

4.7.1 体检预约

体检预约流程
用户可以通过如下操作流程进行体检预约:
1、在移动端首页点击体检预约,页面跳转到套餐列表页面
2、在套餐列表页面点击要预约的套餐,页面跳转到套餐详情页面
3、在套餐详情页面点击立即预约,页面跳转到预约页面
4、在预约页面录入体检人信息,包括手机号,点击发送验证码
5、在预约页面录入收到的手机短信验证码,点击提交预约,完成体检预约

1.先是获取当前预约套餐的id,然后发送Ajax请求,根据获取的id查询套餐信息
2.在预约页面需要进行手机号格式的验证,30秒倒计时,验证码获取和身份证格式校验(第一个、第二个和第四个已经写好方法在healthmobile.js中)

验证码获取实现:
页面完善动态效果(提交到("/validateCode/send4Order.do?telephone=" +telephone)——>controller( 体检预约时发送手机验证码“/send4Order”)
注意:此处还将验证码存到redis中5分钟。

提交预约请求实现:
页面完善动态效果(提交到"/order/submit.do",this.orderInfo)——>controller( “/submit”)——> service接口(Order)——>serviceimpl实现类(Order)——>Dao接口(findByOrderDate、findByTelephone、findByCondition、add、editReservationsByOrderDate)——>Mapper映射文件 (id=“findByOrderDate”、id=“findByTelephone”、id=“findByCondition”、id=“add”、id=“editReservationsByOrderDate”)

注意:
1.在controller中处理预约请求时,需要将redis中的验证码取出来和用户输入的进行比对:成功的话通过dubbo远程调用服务实现在线预约业务处理,并且向用户发送预约成功的短信;不成功的话返回结果给页面。
2. 在serviceImpl实现类中

1、检查用户所选择的预约日期是否已经提前进行了预约设置,如果没有设置则无法进行预约
2、检查用户所选择的预约日期是否已经约满,如果已经约满则无法预约
3、检查用户是否重复预约(同一个用户在同一天预约了同一个套餐),如果是重复预约则无法完成再次预约
4、检查当前用户是否为会员,如果是会员则直接完成预约,如果不是会员则自动完成注册并进行预约
5、预约成功,更新当日的已预约人数

3.在Dao中,需要提供给实现类的接口(1的findByOrderDate)(2通过计算得出预约人数情况)(3的findByTelephone和findByCondition)(4的add)(5的add和editReservationsByOrderDate)

4.7.2 预约成功页面展示

前面已经完成了体检预约,预约成功后页面会跳转到成功提示页面(orderSuccess.html)并展示预约的相关信息(体检人、体检套餐、体检时间等)。

实现过程:
页面完善动态效果(提交到"/order/findById.do?id=" + id)——>controller( “/findById”)——> service接口(findById)——>serviceimpl实现类(finById)——>Dao接口(findById4Detail)——>Mapper映射文件 (id=“findById4Detail”)

4.8 移动端开发-手机快速登录、权限控制

4.8.1 手机快速登录

机快速登录功能,就是通过短信验证码的方式进行登录。这种方式相对于用户名密码登录方式,用户不需要记忆自己的密码,只需要通过输入手机号并获取验证码就可以完成登录,是目前比较流行的登录方式。

先是获取验证码(和预约页面获取验证码一样,只是提交的请求不一样),然后再提交登录

提交登录实现过程:
页面完善动态效果(提交到"/member/login.do",this.loginInfo)——>controller( “/login”)——> service接口(findByTelephone和add)——>serviceimpl实现类(findByTelephone和add)——>Dao接口(findByTelephone和add)——>Mapper映射文件 (id="findByTelephone"和id=“add”)

注意: 在controller中

1、校验用户输入的短信验证码是否正确,如果验证码错误则登录失败
2、如果验证码正确,则判断当前用户是否为会员,如果不是会员则自动完成会员注册
3、向客户端写入Cookie,内容为用户手机号
4、将会员信息保存到Redis,使用手机号作为key,保存时长为30分钟

4.8.2 权限控制

前面我们已经完成了传智健康后台管理系统的部分功能,例如检查项管理、检查组管理、套餐管理、预约设置等。接下来我们需要思考2个问题:
问题1:在生产环境下我们如果不登录后台系统就可以完成这些功能操作吗? 答案显然是否定的,要操作这些功能必须首先登录到系统才可以。
问题2:是不是所有用户,只要登录成功就都可以操作所有功能呢?
答案是否定的,并不是所有的用户都可以操作这些功能。不同的用户可能拥有不同的权限,这就需要进行授权了。

认证:系统提供的用于识别用户身份的功能,通常提供用户名和密码进行登录其实就是在进行认证,认证的目的是让系统知道你是谁。
授权:用户认证成功后,需要为用户授权,其实就是指定当前用户可以操作哪些功能。

本章节就是要对后台系统进行权限控制,其本质就是对用户进行认证和授权。

权限模块数据模型
前面已经分析了认证和授权的概念,要实现最终的权限控制,需要有一套表结构支撑:

用户表t_user、权限表t_permission、角色表t_role、菜单表t_menu、用户角色关系表t_user_role、角色权限关系表t_role_permission、角色菜单关系表t_role_menu。

表之间关系如下图:

通过上图可以看到,权限模块共涉及到7张表。在这7张表中,角色表起到了至关重要的作用,其处于核心位置,因为用户、权限、菜单都和角色是多对多关系。

接下来我们可以分析一下在认证和授权过程中分别会使用到哪些表:
认证过程:只需要用户表就可以了,在用户登录时可以查询用户表t_user进行校验,判断用户输入的用户名和密码是否正确。
授权过程:用户必须完成认证之后才可以进行授权,首先可以根据用户查询其角色,再根据角色查询对应的菜单,这样就确定了用户能够看到哪些菜单。然后再根据用户的角色查询对应的权限,这样就确定了用户拥有哪些权限。所以授权过程会用到上面7张表。

Spring Security简介
Spring Security是 Spring提供的安全认证服务的框架。 使用SpringSecurity可以帮助我们来简化认证和授权的过程。官网:https://spring.io/projects/spring-security
常用的权限框架除了Spring Security,还有Apache的shiro框架。

4.8.3 在项目中应用Spring Security

导入Spring Security环境
第一步:在health_parent父工程的pom.xml中导入Spring Security的maven坐标

<dependency><groupId>org.springframework.security</groupId><artifactId>spring-security-web</artifactId><version>${spring.security.version}</version>
</dependency>
<dependency><groupId>org.springframework.security</groupId><artifactId>spring-security-config</artifactId><version>${spring.security.version}</version>
</dependency>

第二步:在health_backend工程的web.xml文件中配置用于整合Spring Security框架的过滤器DelegatingFilterProxy

实现认证和授权

第一步:在health_backend工程中按照Spring Security框架要求提供SpringSecurityUserService,并且实现UserDetailsService接口(主要就是根据用户名来查询用户信息,并对用户授予角色与权限)
第二步:创建UserService服务接口、服务实现类、Dao接口、Mapper映射文件等

service接口(findByUsername)——>serviceimpl实现类(findByUsername)——>Dao接口(findByRoleId和findByUserId和findByUsername)——>Mapper映射文件 (id="findByRoleId"和id="findByUserId"和id=“findByUsername”)

第三步:在springmvc.xml文件,修改dubbo批量扫描的包路径(因为在SpringSecurityUserService的loadUserByUsername方法中需要通过dubbo远程调用名称为UserService的服务)

第四步:在health_backend工程中提供spring-security.xml配置文件

第五步:在springmvc.xml文件中引入spring-security.xml文件

第六步:在Controller的方法上加入权限控制注解,此处以CheckItemController为例

4.8.4 显示用户名

前面我们已经完成了认证和授权操作,如果用户认证成功后需要在页面展示当前用户的用户名。SpringSecurity在认证成功后会将用户信息保存到框架提供的上下文对象中,所以此处我们就可以调用Spring Security框架提供的API获取当前用户的username并展示到页面上。

实现: 前端页面提交请求到(’/user/getUsername.do’)——>controller(“/getUsername”)
注意:当springsecurity完成认证后,会将当前用户信息保存到框架提供的上下文对象

4.8.5 用户退出

在spring-security.xml文件中配置

<!--logout:退出登录logout-url:退出登录操作对应的请求路径logout-success-url:退出登录后的跳转页面
-->
<security:logout logout-url="/logout.do" logout-success-url="/login.html" invalidate-session="true"/>

4.9 图形报表ECharts

官方实例地址:https://echarts.apache.org/examples/zh/index.html

我们只需要将dist目录下的echarts.js文件引入到页面上就可以使用了

4.9.1 会员数量折线图

主要就是发送Ajax请求获取动态数据,并根据折线图对数据格式的要求,我们发送ajax请求后,服务端需要返回一定格式的数据

实现过程:
页面完善动态效果(提交到"/report/getMemberReport.do")——>controller( “/getMemberReport”)——> service接口(findMemberCountByMonth)——>serviceimpl实现类(findMemberCountByMonth)——>Dao接口(findMemberCountBeforeDate)——>Mapper映射文件 (id=“findMemberCountBeforeDate”)

4.9.2 套餐预约占比饼形图

通过饼形图直观的展示出会员预约的各个套餐占比情况
主要就是发送Ajax请求获取动态数据,并根据饼形图对数据格式的要求,我们发送ajax请求后,服务端需要返回一定格式的数据

实现过程:
页面完善动态效果(提交到"/report/getSetmealReport.do")——>controller( “/getSetmealReport”)——> service接口(findSetmealCount)——>serviceimpl实现类(findSetmealCount)——>Dao接口(findSetmealCount)——>Mapper映射文件 (id=“findSetmealCount”)

4.10 POI报表

4.10.1 运营数据统计

通过运营数据统计可以展示出体检机构的运营情况,包括会员数据、预约到诊数据、热门套餐等信息。本章节就是要通过一个表格的形式来展示这些运营数据。

实现过程:
页面完善动态效果(提交到"/report/getBusinessReportData.do")——>controller( “/getBusinessReportData”)——> service接口(getBusinessReportData)——>serviceimpl实现类(getBusinessReportData)——>Dao接口(findMemberCountByDate、findMemberTotalCount、findMemberCountAfterDate、findMemberCountAfterDate和findOrderCountByDate、findOrderCountAfterDate、findOrderCountAfterDate、findVisitsCountByDate、findVisitsCountAfterDate、findVisitsCountAfterDate、findHotSetmeal)——>Mapper映射文件 (和Dao中的一一对应)

4.10.2 运营数据统计报表导出(EXCEL形式)

运营数据统计报表导出就是将统计数据写入到Excel并提供给客户端浏览器进行下载,以便体检机构管理人员对运营数据的查看和存档。
在企业实际开发中,对于比较复杂的表格导出一般我们会提前设计一个Excel模板文件,在这个模板文件中提前将表格的结构和样式设置好,我们的程序只需要读取这个文件并在文件中的相应位置写入具体的值就可以了。

实现过程:
页面完善动态效果(提交到’/report/exportBusinessReport.do’)——>controller( “/exportBusinessReport”)——> service接口(getBusinessReportData)——>serviceimpl实现类(getBusinessReportData)——>Dao接口(findMemberCountByDate、findMemberTotalCount、findMemberCountAfterDate、findMemberCountAfterDate和findOrderCountByDate、findOrderCountAfterDate、findOrderCountAfterDate、findVisitsCountByDate、findVisitsCountAfterDate、findVisitsCountAfterDate、findHotSetmeal)——>Mapper映射文件 (和Dao中的一一对应)

在ReportController中提供exportBusinessReport方法,基于POI将数据写入到Excel中并通过输出流下载到客户端

4.10.3 运营数据统计报表导出(PDF形式)

JasperReports

JasperReports是一个强大、灵活的报表生成工具,能够展示丰富的页面内容,并将之转换成PDF,HTML,或者XML格式。该库完全由Java写成,可以用于在各种Java应用程序,包括J2EE,Web应用程序中生成动态内容。一般情况下,JasperReports会结合JaspersoftStudio(模板设计器)使用导出PDF报表。

JasperReports原理

JRXML:报表填充模板,本质是一个xml文件
Jasper:由JRXML模板编译成的二进制文件,用于代码填充数据
Jrprint:当用数据填充完Jasper后生成的对象,用于输出报表
Exporter:报表输出的管理类,可以指定要输出的报表为何种格式
PDF/HTML/XML:报表形式

使用JasperReports导出pdf报表,开发流程

  1. 制作报表模板
  2. 模板编译
  3. 构造数据
  4. 填充数据
  5. 输出文件

在项目中输出运营数据PDF报表
1.设计PDF模板文件
2.搭建环境

第一步:在health_common工程的pom.xml中导入JasperReports的maven坐标

<dependency><groupId>net.sf.jasperreports</groupId><artifactId>jasperreports</artifactId><version>6.8.0</version>
</dependency>

第二步:将资源中提供的模板文件health_business3.jrxml复制到health_backend工程的template目录下

第三步:修改report_business.html,添加PDF按钮事件

第四步:在health_backend工程的ReportController中提供exportBusinessReport4PDF方法

实现过程:
页面完善动态效果(提交到’/report/exportBusinessReport4PDF.do’)——>controller( “/exportBusinessReport4PDF”)——> service接口(getBusinessReportData)——>serviceimpl实现类(getBusinessReportData)——>Dao接口(findMemberCountByDate、findMemberTotalCount、findMemberCountAfterDate、findMemberCountAfterDate和findOrderCountByDate、findOrderCountAfterDate、findOrderCountAfterDate、findVisitsCountByDate、findVisitsCountAfterDate、findVisitsCountAfterDate、findHotSetmeal)——>Mapper映射文件 (和Dao中的一一对应)

五、目前存在的问题

1.图片上传后,虽然页面显示成功,但是七牛云云端并没有存储下来。(未解决)
2.图片上传成功后,页面并不能显示预览效果。(未解决)
3.模板下载不成功(未解决,不能直接使用模板的路径)
4.短信业务需要自己注册,不然key不能使用(我自己没有购买阿里云的短信服务)
5.第十一个:导出Excel一直显示–》“获取运营数据失败”也就是不能导出Excel表,但是“运营数据统计”中数据是能统计并显示出来的。(未解决)
6.第十二个:导出PDF也是显示失败,也是和5中的一样显示找不到路径(未解决)

【项目一】医疗实战-传智健康相关推荐

  1. 项目实战--传智健康

    传智健康项目 2022.3.2-2022.3.16 --BDY 文章目录 传智健康项目 项目介绍及技术架构 一.项目流程 1.后台管理系统编写 2.微信端预约系统编写 在这里插入图片描述 3.图形展示 ...

  2. Java实战项目《传智健康》超完整的企业级医疗行业项目

    Java实战项目<传智健康> 传智健康-企业级医疗行业项目 配套资料:https://pan.baidu.com/s/15yNdMDZtn4QDb3UA0n9zGA 视频观看:https: ...

  3. 【医疗健康项目】传智健康项目(五)

    第7章 移动端开发-页面静态化 1. 页面静态化介绍 本章课程中我们已经实现了移动端套餐列表页面和套餐详情页面的动态展示.但是我们需要思考一个问题,就是对于这两个页面来说,每次用户访问这两个页面都需要 ...

  4. 【医疗健康项目】传智健康项目(一)

    第1章 项目概述和环境搭建 1. 项目概述 1.1 前言 传智健康管理系统是一款应用于健康管理机构的业务系统,实现健康管理机构工作内容可视化.会员管理专业化.健康评估数字化.健康干预流程化.知识库集成 ...

  5. 【医疗健康项目】传智健康项目(六)

    第9章 移动端开发-手机快速登录 1. 需求分析 手机快速登录功能,就是通过短信验证码的方式进行登录.这种方式相对于用户名密码登录方式,用户不需要记忆自己的密码,只需要通过输入手机号并获取验证码就可以 ...

  6. 【医疗健康项目】传智健康项目(七)

    第11章 预约管理-图形报表 1. 图形报表ECharts 1.1 ECharts简介 ECharts缩写来自Enterprise Charts,商业级数据图表,是百度的一个开源的使用JavaScri ...

  7. 【医疗健康项目】传智健康项目(二)

    第2章 预约管理-检查项管理 1. 需求分析 传智健康管理系统是一款应用于健康管理机构的业务系统,实现健康管理机构工作内容可视化.患者管理专业化.健康评估数字化.健康干预流程化.知识库集成化,从而提高 ...

  8. 【医疗健康项目】传智健康项目(八)

    第13章 预约管理-JasperReports生成PDF报表 在前面的课程中我们完成了将运营数据导出到Excel文件的功能.在企业开发中,除了常见的Excel形式报表,还有PDF形式的报表.那么如何导 ...

  9. 【医疗健康项目】传智健康项目(三)

    第4章 预约管理-套餐管理 1. 图片存储方案 1.1 介绍 在实际开发中,我们会有很多处理不同功能的服务器.例如: 应用服务器:负责部署我们的应用 数据库服务器:运行我们的数据库 文件服务器:负责存 ...

最新文章

  1. 《动手学深度学习》PyTorch版本
  2. 聚焦“裂变”,又拍云推出直播云等多场景解决方案
  3. 【Python入门】Python字符串的45个方法详解
  4. NanoHTTPD web server的一个简单荔枝
  5. C语言判断某个字符串中 是否存在子字符串
  6. 短信验证-SMSSDk(Mob开发平台 )
  7. Android腾讯微博开放平台入门(四)发表一条文字微博
  8. 心理学和管理学的一些效应学习
  9. 想要学简单的office该用哪款软件?
  10. php 远程下载木马
  11. Android Q适配攻略(五)(存储权限变更)
  12. 细思恐极的星座分析(上) ——用大数据和机器学习揭开十二星座的真实面目!
  13. react-router(路由)
  14. 分形几何python代码_Python教程之绘制Mandelbrot集合
  15. c4d打开没反应_PS、AI、PR、AE、C4D零基础自学经验分享
  16. 谢国忠:大数据在金融(视频+图文)
  17. 别说眼科医生不做近视激光手术,眼科医生做给你看
  18. snap7通过NetToPLCsim工具接入模拟西门子PLC S7-1200步骤简介
  19. 杰力科创RGB低频加湿器芯片——DLT8W10SD
  20. 【有利可图网】绿色好心情!绿色系配色方案!

热门文章

  1. 解决Error: EPERM: operation not permitted, mkdir
  2. Linux常用命令——ps命令
  3. ALV 下载到EXCEL里出现的问题
  4. 如何设置桌面图标大小
  5. 英语中的商务电子邮件:5点实用技巧
  6. create与oncreate的区别
  7. png图片损坏打不开如何修复?
  8. 数据库通过出生日期计算年龄
  9. 存储过程和存储函数 练习
  10. mysql启动与登录