@TOC

第6章 移动端开发-体检预约

1. 移动端开发

1.1 移动端开发方式

随着移动互联网的兴起和手机的普及,目前移动端应用变得愈发重要,成为了各个商家的必争之地。例
如,我们可以使用手机购物、支付、打车、玩游戏、订酒店、购票等,以前只能通过PC端完成的事情,
现在通过手机都能够实现,而且更加方便,而这些都需要移动端开发进行支持,那如何进行移动端开发
呢?
移动端开发主要有三种方式:
1、基于手机API开发(原生APP) 2、基于手机浏览器开发(移动web) 3、混合开发(混合APP)

1.1.1 基于手机API开发

手机端使用手机API,例如使用Android、ios 等进行开发,服务端只是一个数据提供者。手机端请求服
务端获取数据(json、xml格式)并在界面进行展示。这种方式相当于传统开发中的C/S模式,即需要在
手机上安装一个客户端软件。
这种方式需要针对不同的手机系统分别进行开发,目前主要有以下几个平台:
1、苹果ios系统版本,开发语言是Objective-C
2、安卓Android系统版本,开发语言是Java
3、微软Windows phone系统版本,开发语言是C#
4、塞班symbian系统版本,开发语言是C++
此种开发方式举例:手机淘宝、抖音、今日头条、大众点评

1.1.2 基于手机浏览器开发

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

1.1.3 混合开发

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

1.2 微信公众号开发

1.2.1 帐号分类

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


注册,但因为个人不能链接跳转网址,所以没什么用。。

2. 套餐展示

2.1 需求分析

用户在体检之前需要进行预约,可以通过电话方式进行预约,此时会由体检中心客服人员通过后台系统
录入预约信息。用户也可以通过手机端自助预约。本章节开发的功能为用户通过手机自助预约。
预约流程如下:
1、访问移动端首页
2、点击体检预约进入体检套餐列表页面
3、在体检套餐列表页面点击具体套餐进入套餐详情页面
4、在套餐详情页面点击立即预约进入预约页面
5、在预约页面录入体检人相关信息点击提交预约

效果如下图:



2.2 搭建移动端工程

本项目是基于SOA架构进行开发,前面我们已经完成了后台系统的部分功能开发,在后台系统中都是通
过Dubbo调用服务层发布的服务进行相关的操作。本章节我们开发移动端工程也是同样的模式,所以我
们也需要在移动端工程中通过Dubbo调用服务层发布的服务,如下图

导入通用组件

ValidateCodeUiles

package com.ybb.utils;import java.util.Random;/*** 随机生成验证码工具类*/
public class ValidateCodeUtils {/*** 随机生成验证码* @param length 长度为4位或者6位* @return*/public static Integer generateValidateCode(int length){Integer code =null;if(length == 4){code = new Random().nextInt(9999);//生成随机数,最大为9999if(code < 1000){code = code + 1000;//保证随机数为4位数字}}else if(length == 6){code = new Random().nextInt(999999);//生成随机数,最大为999999if(code < 100000){code = code + 100000;//保证随机数为6位数字}}else{throw new RuntimeException("只能生成4位或6位数字验证码");}return code;}/*** 随机生成指定长度字符串验证码* @param length 长度* @return*/public static String generateValidateCode4String(int length){Random rdm = new Random();String hash1 = Integer.toHexString(rdm.nextInt());String capstr = hash1.substring(0, length);return capstr;}
}

RedisMessageConstant常量类:

package com.ybb.constant;public class RedisMessageConstant {public static final String SENDTYPE_ORDER = "001";//用于缓存体检预约时发送的验证码public static final String SENDTYPE_LOGIN = "002";//用于缓存手机号快速登录时发送的验证码public static final String SENDTYPE_GETPWD = "003";//用于缓存找回密码时发送的验证码
}

health_mobile

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

pox.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>health_parent</artifactId><groupId>com.ybb</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>health_mobile</artifactId><packaging>war</packaging><name>health_mobile Maven Webapp</name><!-- FIXME change it to the project's website --><url>http://www.example.com</url><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.source>1.8</maven.compiler.source><maven.compiler.target>1.8</maven.compiler.target></properties><dependencies><dependency><groupId>com.ybb</groupId><artifactId>health_interface</artifactId><version>1.0-SNAPSHOT</version></dependency></dependencies><build><plugins><plugin><groupId>org.apache.tomcat.maven</groupId><artifactId>tomcat7-maven-plugin</artifactId><configuration><!-- 指定端口 --><port>80</port><!-- 请求路径 --><path>/</path></configuration></plugin></plugins></build></project>

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"version="4.0"><display-name>Archetype Created Web Application</display-name><!-- 解决post乱码 --><filter><filter-name>CharacterEncodingFilter</filter-name><filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class><init-param><param-name>encoding</param-name><param-value>utf-8</param-value></init-param><init-param><param-name>forceEncoding</param-name><param-value>true</param-value></init-param></filter><filter-mapping><filter-name>CharacterEncodingFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping><servlet><servlet-name>springmvc</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!-- 指定加载的配置文件 ,通过参数contextConfigLocation加载 --><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:springmvc.xml</param-value></init-param><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>springmvc</servlet-name><url-pattern>*.do</url-pattern></servlet-mapping><welcome-file-list><welcome-file>/pages/index.html</welcome-file></welcome-file-list></web-app>

spring-redis

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:p="http://www.springframework.org/schema/p"xmlns:context="http://www.springframework.org/schema/context"xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"xmlns:mvc="http://www.springframework.org/schema/mvc"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc.xsdhttp://code.alibabatech.com/schema/dubbohttp://code.alibabatech.com/schema/dubbo/dubbo.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><context:property-placeholder location="classpath:redis.properties" /><!--Jedis连接池的相关配置--><bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig"><property name="maxTotal"><value>${redis.pool.maxActive}</value></property><property name="maxIdle"><value>${redis.pool.maxIdle}</value></property><property name="testOnBorrow" value="true"/><property name="testOnReturn" value="true"/></bean><bean id="jedisPool" class="redis.clients.jedis.JedisPool"><constructor-arg name="poolConfig" ref="jedisPoolConfig" /><constructor-arg name="host" value="${redis.host}" /><constructor-arg name="port" value="${redis.port}" type="int" /><constructor-arg name="timeout" value="${redis.timeout}" type="int" /></bean>
</beans>

springmvc

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:p="http://www.springframework.org/schema/p"xmlns:context="http://www.springframework.org/schema/context"xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"xmlns:mvc="http://www.springframework.org/schema/mvc"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc.xsdhttp://code.alibabatech.com/schema/dubbohttp://code.alibabatech.com/schema/dubbo/dubbo.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><mvc:annotation-driven><mvc:message-converters register-defaults="true"><bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter"><property name="supportedMediaTypes" value="application/json"/><property name="features"><list><value>WriteMapNullValue</value><value>WriteDateUseDateFormat</value></list></property></bean></mvc:message-converters></mvc:annotation-driven><!-- 指定应用名称 --><dubbo:application name="health_mobile" /><!--指定服务注册中心地址--><dubbo:registry address="zookeeper://127.0.0.1:2181"/><!--批量扫描--><dubbo:annotation package="com.ybb.controller" /><!--超时全局设置 10分钟check=false 不检查服务提供方,开发阶段建议设置为falsecheck=true 启动时检查服务提供方,如果服务提供方没有启动则报错--><dubbo:consumer timeout="600000" check="false"/><import resource="spring-redis.xml"></import>
</beans>

3.1 完善页面

3.1.1 展示套餐信息

setmeal.html

<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! --><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0,user-scalable=no,minimal-ui"><meta name="description" content=""><meta name="author" content=""><link rel="icon" href="../img/asset-favico.ico"><title>预约</title><link rel="stylesheet" href="../css/page-health-order.css" />
</head>
<body data-spy="scroll" data-target="#myNavbar" data-offset="150">
<div class="app" id="app"><!-- 页面头部 --><div class="top-header"><span class="f-left"><i class="icon-back" onclick="history.go(-1)"></i></span><span class="center">传智健康</span><span class="f-right"><i class="icon-more"></i></span></div><!-- 页面内容 --><div class="contentBox"><div class="list-column1"><ul class="list"><li class="list-item" v-for="setmeal in setmealList"><a class="link-page" :href="'setmeal_detail.html?id='+setmeal.id"><img class="img-object f-left" :src="setmeal.img" alt=""><div class="item-body"><h4 class="ellipsis item-title">{{setmeal.name}}</h4><p class="ellipsis-more item-desc">{{setmeal.remark}}</p><p class="item-keywords"><span>{{setmeal.sex == '0' ? '性别不限' : setmeal.sex == '1' ? '男':'女'}}</span><span>{{setmeal.age}}</span></p></div></a></li></ul></div></div>
</div>
<!-- 页面 css js -->
<script src="../plugins/vue/vue.js"></script>
<script src="../plugins/vue/axios-0.18.0.js"></script>
<!--<script src="../js/page-health-order.js"></script>-->
<script>var vue = new Vue({el:'#app',data:{setmealList:[]},mounted (){axios.post("/setmeal/getAllSetmeal.do").then((response)=>{if(response.data.flag){this.setmealList = response.data.data;}});}});
</script>
</body>

setmeal_detail

<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! --><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0,user-scalable=no,minimal-ui"><meta name="description" content=""><meta name="author" content=""><link rel="icon" href="../img/asset-favico.ico"><title>预约详情</title><link rel="stylesheet" href="../css/page-health-orderDetail.css" /><script src="../plugins/vue/vue.js"></script><script src="../plugins/vue/axios-0.18.0.js"></script><script src="../plugins/healthmobile.js"></script><script>var id = getUrlParam("id");</script>
</head>
<body data-spy="scroll" data-target="#myNavbar" data-offset="150">
<div id="app" class="app"><!-- 页面头部 --><div class="top-header"><span class="f-left"><i class="icon-back" onclick="history.go(-1)"></i></span><span class="center">传智健康</span><span class="f-right"><i class="icon-more"></i></span></div><!-- 页面内容 --><div class="contentBox"><div class="card"><div class="project-img"><img :src="imgUrl" width="100%" height="100%" /></div><div class="project-text"><h4 class="tit">{{setmeal.name}}</h4><p class="subtit">{{setmeal.remark}}</p><p class="keywords"><span>{{setmeal.sex == '0' ? '性别不限' : setmeal.sex == '1' ? '男':'女'}}</span><span>{{setmeal.age}}</span></p></div><!--<div class="project-know"><a href="orderNotice.html" class="link-page"><i class="icon-ask-circle"><span class="path1"></span><span class="path2"></span></i><span class="word">预约须知</span><span class="arrow"><i class="icon-rit-arrow"></i></span></a></div>--></div><div class="table-listbox"><div class="box-title"><i class="icon-zhen"><span class="path1"></span><span class="path2"></span></i><span>套餐详情</span></div><div class="box-table"><div class="table-title"><div class="tit-item flex2">项目名称</div><div class="tit-item  flex3">项目内容</div><div class="tit-item  flex3">项目解读</div></div><div class="table-content"><ul class="table-list"><li class="table-item" v-for="checkgroup in setmeal.checkGroups"><div class="item flex2">{{checkgroup.name}}</div><div class="item flex3"><label v-for="checkitem in checkgroup.checkItems">{{checkitem.name}}</label></div><div class="item flex3">{{checkgroup.remark}}</div></li></ul></div><div class="box-button"><a @click="toOrderInfo()" class="order-btn">立即预约</a></div></div></div></div>
</div>
<script>var vue = new Vue({el:'#app',data:{imgUrl:null,//套餐对应的图片链接setmeal:{}},methods:{toOrderInfo(){window.location.href = "orderInfo.html?id=" + id;}},mounted(){axios.post("/setmeal/find.do?id=" + id).then((response) => {if(response.data.flag){this.setmeal = response.data.data;}});}});
</script>
</body>

3.2后台代码

3.2.1 Controller

在health_mobile工程中创建SetmealController并提供getSetmeal方法,在此方法中通过Dubbo远程
调用套餐服务获取套餐列表数据

@RestController
@RequestMapping("/setmeal")
public class setmeal {@Referenceprivate SetmealService setmealService;@RequestMapping("/getAllSetmeal")public Result getAllSetmeal(){try {List<Setmeal>list=  setmealService.findAll();
return new Result(true,MessageConstant.GET_SETMEAL_LIST_SUCCESS,list);}catch (Exception e){e.printStackTrace();return new Result(false, MessageConstant.GET_SETMEAL_LIST_FAIL);}}

service,dao,就不说了,最基础的查询所有返回

4. 套餐详情页面动态展示

前面我们已经完成了体检套餐列表页面动态展示,点击其中任意一个套餐则跳转到对应的套餐详情页面
(/pages/setmeal_detail.html),并且会携带此套餐的id作为参数提交。
请求路径格式:http://localhost/pages/setmeal_detail.html?id=10
在套餐详情页面需要展示当前套餐的信息(包括图片、套餐名称、套餐介绍、适用性别、适用年龄)、
此套餐包含的检查组信息、检查组包含的检查项信息等。
4.1 完善页面
4.1.1 获取请求参数中套餐id
在页面中已经引入了healthmobile.js文件,此文件中已经封装了getUrlParam方法可以根据URL请求路
径中的参数名获取对应的值

//获取指定的URL参数值 http://localhost/pages/setmeal_detail.html?id=3&name=jack
function getUrlParam(paraName) {var url = document.location.toString();//alert(url);var arrObj = url.split("?");if (arrObj.length > 1) {var arrPara = arrObj[1].split("&");var arr;for (var i = 0; i < arrPara.length; i++) {arr = arrPara[i].split("=");if (arr != null && arr[0] == paraName) {return arr[1];}}return "";}else {return "";}
}//获得当前日期,返回字符串
function getToday() {var today = new Date();var year = today.getFullYear();var month = today.getMonth() + 1;//0表示1月,1表示2月var day = today.getDate();return (year + "-" + month + "-" + day);
}//获得指定日期后指定天数的日期
function getSpecifiedDate(date,days) {date.setDate(date.getDate() + days);//获取指定天之后的日期var year = date.getFullYear();var month = date.getMonth() + 1;var day = date.getDate();return (year + "-" + month + "-" + day);
}/*** 手机号校验1--以1为开头;2--第二位可为3,4,5,7,8,中的任意一位;3--最后以0-9的9个整数结尾。*/
function checkTelephone(telephone) {var reg=/^[1][3,4,5,7,8][0-9]{9}$/;if (!reg.test(telephone)) {return false;} else {return true;}
}/*** 身份证号码校验* 身份证号码为15位或者18位,15位时全为数字,18位前17位为数字,最后一位是校验位,可能为数字或字符X*/
function checkIdCard(idCard){var reg = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/;if(reg.test(idCard)){return true;}else{return false;}
}var clock = '';//定时器对象,用于页面30秒倒计时效果
var nums = 30;
var validateCodeButton;
//基于定时器实现30秒倒计时效果
function doLoop() {validateCodeButton.disabled = true;//将按钮置为不可点击nums--;if (nums > 0) {validateCodeButton.value = nums + '秒后重新获取';} else {clearInterval(clock); //清除js定时器validateCodeButton.disabled = false;validateCodeButton.value = '重新获取验证码';nums = 30; //重置时间}
}

在setmeal_detail.html中调用上面定义的方法获取套餐id的值

4.1.2 获取套餐详细信息

<script>var vue = new Vue({el:'#app',data:{setmealList:[]},mounted (){axios.post("/setmeal/getAllSetmeal.do").then((response)=>{if(response.data.flag){this.setmealList = response.data.data;}});}});
</script>

4.1.3 展示套餐信息

 <!-- 页面内容 --><div class="contentBox"><div class="card"><div class="project-img"><img :src="imgUrl" width="100%" height="100%" /></div><div class="project-text"><h4 class="tit">{{setmeal.name}}</h4><p class="subtit">{{setmeal.remark}}</p><p class="keywords"><span>{{setmeal.sex == '0' ? '性别不限' : setmeal.sex == '1' ? '男':'女'}}</span><span>{{setmeal.age}}</span></p></div><!--<div class="project-know"><a href="orderNotice.html" class="link-page"><i class="icon-ask-circle"><span class="path1"></span><span class="path2"></span></i><span class="word">预约须知</span><span class="arrow"><i class="icon-rit-arrow"></i></span></a></div>--></div><div class="table-listbox"><div class="box-title"><i class="icon-zhen"><span class="path1"></span><span class="path2"></span></i><span>套餐详情</span></div><div class="box-table"><div class="table-title"><div class="tit-item flex2">项目名称</div><div class="tit-item  flex3">项目内容</div><div class="tit-item  flex3">项目解读</div></div><div class="table-content"><ul class="table-list"><li class="table-item" v-for="checkgroup in setmeal.checkGroups"><div class="item flex2">{{checkgroup.name}}</div><div class="item flex3"><label v-for="checkitem in checkgroup.checkItems">{{checkitem.name}}</label></div><div class="item flex3">{{checkgroup.remark}}</div></li></ul></div><div class="box-button"><a @click="toOrderInfo()" class="order-btn">立即预约</a></div></div></div></div>

4.2 后台代码

Controller

在SetmealController中提供findById方法

    @RequestMapping("/find")public Result find(Integer id){try {Setmeal setmeal= setmealService.find1(id);return new Result(true,MessageConstant.QUERY_SETMEAL_SUCCESS,setmeal);}catch (Exception e){e.printStackTrace();return new Result(false, MessageConstant.QUERY_SETMEAL_FAIL);}}

service

@Overridepublic Setmeal find1(Integer id) {if (id < 0) {return null;} else {Setmeal setmeal = setmealDao.find1(id);return setmeal;}}

dao 配置文件方式

Setmeal find1(Integer id);//手机端用xml配置的查询方法

此处会使用mybatis提供的关联查询,在根据id查询套餐时,同时将此套餐包含的检查组都查询出来,
并且将检查组包含的检查项都查询出来。

SetmealDao.xml文件

    <select id="find1" resultMap="findgroups" parameterType="int">select * from t_setmeal where id = #{id}</select><resultMap id="findgroups" type="com.ybb.pojo.Setmeal"><id column="id" property="id"/><collection property="checkGroups" ofType="com.ybb.pojo.CheckGroup" column="id" select="com.ybb.dao.CheckGroupDao.findgroup"/></resultMap><resultMap id="finditems" type="com.ybb.pojo.CheckGroup"><id column="id" property="id"/><collection property="checkItems" ofType="com.ybb.pojo.CheckItem" column="id" select="com.ybb.dao.CheckItemDao.findById"/></resultMap>

CheckGroupDao.xml

    <select id="findgroup" parameterType="int" resultMap="finditem">select * from t_checkgroup where id in (select checkgroup_id from t_setmeal_checkgroup where setmeal_id=#{id})</select><resultMap id="finditem" type="com.ybb.pojo.CheckGroup"><id column="id" property="id"/><collection property="checkItems" column="id" ofType="com.ybb.pojo.CheckItem" select="com.ybb.dao.CheckItemDao.findBySelf"/></resultMap>

CheckItemDao.xml

  <select id="findBySelf" parameterType="int" resultType="com.ybb.pojo.CheckItem">select * from t_checkitem where id in (select checkitem_id from t_checkgroup_checkitem where checkgroup_id= #{id})</select>

dao java代码简化配置

sevice

 @Overridepublic Setmeal find(Integer id) {if (id < 0) {return null;} else {Setmeal setmeal = setmealDao.find(id);List<CheckGroup> findcheckgroup = setmealDao.findcheckgroup(setmeal.getId());setmeal.setCheckGroups(findcheckgroup);for (CheckGroup checkGroup : findcheckgroup) {List<CheckItem> checkitem = setmealDao.findCheckitem(checkGroup.getId());checkGroup.setCheckItems(checkitem);}return setmeal;}}

SetmealDao.xml

    <select id="find" resultType="com.ybb.pojo.Setmeal"  parameterType="int">select * from t_setmeal where id=#{id}</select><select id="findcheckgroup" resultType="com.ybb.pojo.CheckGroup" parameterType="int">select * from t_checkgroup tc,t_setmeal_checkgroup tscwhere tc.id=tsc.checkgroup_idand tsc.setmeal_id=#{id}</select><select id="findCheckitem" parameterType="int" resultType="com.ybb.pojo.CheckItem">select * from t_checkitem ti,t_checkgroup_checkitem tciwhere ti.id=tci.checkitem_idand tci.checkgroup_id=#{id}</select>

5. 短信发送

5.1 短信服务介绍

目前市面上有很多第三方提供的短信服务,这些第三方短信服务会和各个运营商(移动、联通、电信)
对接,我们只需要注册成为会员并且按照提供的开发文档进行调用就可以发送短信。需要说明的是这些
短信服务都是收费的服务。
本项目短信发送我们选择的是阿里云提供的短信服务。
短信服务(Short Message Service)是阿里云为用户提供的一种通信服务的能力,支持快速发送短信
验证码、短信通知等。 三网合一专属通道,与工信部携号转网平台实时互联。电信级运维保障,实时监
控自动切换,到达率高达99%。短信服务API提供短信发送、发送状态查询、短信批量发送等能力,在
短信服务控制台上添加签名、模板并通过审核之后,可以调用短信服务API完成短信发送等操作。

5.2 注册阿里云账号

阿里云官网:https://www.aliyun.com/
点击官网首页免费注册跳转到如下注册页面:

5.3 设置短信签名

注册成功后,点击登录按钮进行登录。登录后进入短信服务管理页面,选择国内消息菜单:

点击添加签名按钮:

目前个人用户只能申请适用场景为验证码的签名

5.4 设置短信模板

在国内消息菜单页面中,点击模板管理标签页:

点击添加模板按钮:

5.5 设置access keys

在发送短信时需要进行身份认证,只有认证通过才能发送短信。本小节就是要设置用于发送短信时进行
身份认证的key和密钥。鼠标放在页面右上角当前用户头像上,会出现下拉菜单:

点击accesskeys:


创建成功,其中AccessKeyID为访问短信服务时使用的ID,AccessKeySecret为密钥。
可以在用户详情页面下禁用刚刚创建的AccessKey

5.6 发送短信

5.6.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>
package com.ybb.utils;import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;/*** 短信发送工具类*/
public class SMSUtils {public static void main(String[] args) throws ClientException {sendShortMessage("SMS_","222","11111");}public static final String VALIDATE_CODE = "SMS_159620392";//发送短信验证码public static final String ORDER_NOTICE = "SMS_159771588";//体检预约成功通知/*** 发送短信* @param phoneNumbers* @param param* @throws ClientException*/public static void sendShortMessage(String templateCode,String phoneNumbers,String param) throws ClientException{// 设置超时时间-可自行调整System.setProperty("sun.net.client.defaultConnectTimeout", "10000");System.setProperty("sun.net.client.defaultReadTimeout", "10000");// 初始化ascClient需要的几个参数final String product = "Dysmsapi";// 短信API产品名称(短信产品名固定,无需修改)final String domain = "dysmsapi.aliyuncs.com";// 短信API产品域名(接口地址固定,无需修改)// 替换成你的AKfinal String accessKeyId = "LTAp8S";// 你的accessKeyId,参考本文档步骤2final String accessKeySecret = "uRQW5Veeap7Zp0";// 你的accessKeySecret,参考本文档步骤2// 初始化ascClient,暂时不支持多region(请勿修改)IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKeyId, accessKeySecret);DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", product, domain);IAcsClient acsClient = new DefaultAcsClient(profile);// 组装请求对象SendSmsRequest request = new SendSmsRequest();// 使用post提交request.setMethod(MethodType.POST);// 必填:待发送手机号。支持以逗号分隔的形式进行批量调用,批量上限为1000个手机号码,批量调用相对于单条调用及时性稍有延迟,验证码类型的短信推荐使用单条调用的方式request.setPhoneNumbers(phoneNumbers);// 必填:短信签名-可在短信控制台中找到request.setSignName("");// 必填:短信模板-可在短信控制台中找到request.setTemplateCode(templateCode);// 可选:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为// 友情提示:如果JSON中需要带换行符,请参照标准的JSON协议对换行符的要求,比如短信内容中包含\r\n的情况在JSON中需要表示成\\r\\n,否则会导致JSON在服务端解析失败request.setTemplateParam("{\"code\":\""+param+"\"}");// 可选-上行短信扩展码(扩展码字段控制在7位或以下,无特殊需求用户请忽略此字段)// request.setSmsUpExtendCode("90997");// 可选:outId为提供给业务方扩展字段,最终在短信回执消息中将此值带回给调用者// request.setOutId("yourOutId");// 请求失败这里会抛ClientException异常SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request);if (sendSmsResponse.getCode() != null && sendSmsResponse.getCode().equals("OK")) {// 请求成功System.out.println("请求成功");}}
}

移动端开发 套餐列表动态展示(多表联查) 短信发送相关推荐

  1. Android开发 亲测可用--多种方式获取手机短信验证码自动填入

    Android开发 静态注册.动态注册.短信中心库监控获取手机验证码,自动复制到剪切板或或填入输入框. 友情提醒初学者:这是广播接收器的类,写在xml中静态注册或写在启动类的Oncreate方法下动态 ...

  2. android 开发 短信,Android开发之短信发送

    今天要讲的是使用Android开发发送短信程序.我们先来看下运行效果 图(1)                                                              ...

  3. 阿里大鱼短信发送接口开发

    一. API接口介绍 alibaba.aliqin.fc.sms.num.send (短信发送) 向指定手机号码发送模板短信,模板内可设置部分变量.使用前需要在阿里大于管理中心添加短信签名与短信模板. ...

  4. 瑞吉外卖--套餐的添加修改等功能,短信验证登录原理操作及用户地址管理功能

    整理记录下学习整个瑞吉外卖项目,详细代码可在我的Gitee仓库瑞吉外卖实战克隆下载学习使用! 9.套餐管理 9.1 新增套餐 9.1.1 需求分析 9.1.2 数据模型 新增套餐就是将新增页面录入的套 ...

  5. 学校公文办公处理系统_基于ASP.NET和Swfupload、FlashPaper2.2、校讯通短信发送的开发

    学校新来了一个主管教学的副校长,他对他以前工作学校的公文处理系统表示高度留念,于是乎叫我们也开发一个. 我就参考了那个学校的办公管理系统,发现其实功能也蛮简单的,就是一个文件上传下载的功能,选择用户组 ...

  6. android开发之来电自动拒接并自动回复短信_上课模式app

    上课的时候老师说总是错过电话,对方打来没人接还一遍遍的打,觉得可以有个app在上课期间自动拒接电话,并自动回复短信过去. 当然了,需要权限的. 尝试做了个雏形出来. 界面如下: 主要代码如下: pac ...

  7. android 来电拒接_[置顶] android开发之来电自动拒接并自动回复短信_上课模式app...

    上课的时候老师说总是错过电话,对方打来没人接还一遍遍的打,觉得可以有个app在上课期间自动拒接电话,并自动回复短信过去. 当然了,需要权限的. 尝试做了个雏形出来. 界面如下: 主要代码如下: pac ...

  8. 移动应用程序设计基础——点菜单列表实现2.0(实现短信接受以及服务与广播的使用)

    <移动应用程序设计基础>实验四 Android基本组件交互 实验名称: 点菜单列表实现 所使用的工具软件及环境: JDK1.8,Android Studio 一.实验目的: [实验目的] ...

  9. 微信开发之移动手机WEB页面(HTML5)Javascript实现一键拨号及短信发送功能

    在做一个微信的微网站中的一个便民服务电话功能的应用,用到移动web页面中列出的电话号码,点击需要实现调用通讯录,网页一键拨号的拨打电话功能. 如果需要在移动浏览器中实现拨打电话,发送email,美国服 ...

最新文章

  1. php快排,网址快排 快速排名软件 thinkphp快排源码 网站快排程序 百度排名
  2. 上古时期的 TeX Users 都有哪些当今 TeX Users 无法想象的神级操作?
  3. [BSidesSF2019]slashslash
  4. 鉴机识变,面向未来|RocketMQ Summit 2022 即将来袭
  5. python入门神器_爬虫 (一) 神器准备篇
  6. php robots.txt,robots.txt的写法
  7. Deltix Round, Spring 2021 D. Love-Hate 随机化 + sos dp(高维前缀和)
  8. Swift字符串转换成类
  9. uni-app,v-for时 block 和 view 的使用
  10. android 自定义布局 根据布局获取类,android自定义布局中的平滑移动之ViewGroup实现...
  11. 微信小程序内嵌网页的一些(最佳)实践
  12. 人工智能写诗全程测试输出的诗句
  13. Mac下GitHub安装及使用教程
  14. 3Dmax材质编辑器是黑的,怎么解决
  15. Java8 Lambda表达式的特快处理流Stream快速入门
  16. Leetcode 1653. Minimum Deletions to Make String Balanced [Python]
  17. html5hr标签默认值,hr_标签 | Elements_HTML_参考手册_非常教程
  18. 电脑装windows和安卓双系统引导_Remix mini安卓电脑,玩的不只是Windows那张皮
  19. DVWA靶机-文件上传漏洞(File Upload)
  20. 你怎样理解需求分析师_我真正理解心理咨询是如何起效的,是从我成为来访者的那一刻开始...

热门文章

  1. jbd2 mysql_解决因jbd2导致mysql性能过低问题
  2. influxdb内存消耗分析及性能优化「追踪篇」
  3. 专题:Cortana 小娜
  4. 高级网络配置-网络桥接
  5. VMware虚拟机NAT模式配置静态IP
  6. Mac必备的解压缩神器
  7. Java线程池的原理
  8. 某程序员求助:简历上美化过往经历,把外包写成正编,入职会不会被发现?
  9. 少年有理想 国家有希望 | 盐城北大青鸟机电基地学员观新闻联播有感
  10. 怎么把图片转换成excel?原来这么简单