V-1.0 帮助文档
前言
本文实例中使用语言:后台为Java,前台为AngularJS,移动框架为Ionic
启动服务(初始化监听器)
在启动服务器的时候,server -> src/com.artway/artogether/app/controller/postProcessor/AutoInitHandlerPostProcessor
和server -> src/com.artway/artogetherapp/controller/postProcessor/DateInitPostProcessor
会自动执行,通过继承Spring
中ApplicationListener
的onApplicationEvent
方法,完成程序中单接口(动态生成Handler
中的invoke
方法(较反射而言,性能更好))、加密和权限的准备工作。
涉及到的工具类
server -> src/com.artway/utils
中,具体如下:
- AppPermissionCache
- Captcha
- CarryObject
- Common
- Const
- Converter
- Cryptos
- DateUtils
- Digests
- Encodes
- ExcelReader
- Page
- PagePlugin
- PasswordHelper
- PluginResGenerator
- ReflectHelper
- RegExpUtil
- SensitiveWord
- SensitiveWordHandler
- ThumbnailUtil
- TokenCache
- ZipUtil
client-> plugins
中,具体如下:
- cordova-plugin-camera
- cordova-plugin-console
- cordova-plugin-device
- cordova-plugin-dialogs
- cordova-plugin-file
- cordova-plugin-inappbrowser
- cordova-plugin-splashscreen
- cordova-plugin-statusbar
- cordova-plugin-websocket
- cordova-plugin-whitelist
- cordova-plugin-x-toast
- ionic-plugin-keyboard
- plugin-aescrypt
- plugin-picture
- plugin-share
技术点
1. 单接口
描述:前后台交互只用一个接口。请求进入后台后解析附带参数,再进行相应接口的调用。这样做便于加密数据,以提高接口安全性。
需要:
- server -> src/com/artway/artogeher/app/controller.java
- client -> www/js/service.js -> arthttp
实现:
a. 前台请求方法: 接口+参数
artHttp.post(interfacePath, {data: data})
.success(function (data, status, headers, config) {
//success
})
.error(function (data, status, headers, config) {
//error
})
.networkError(function(){
//networkError
});
b. 前台单接口转化方法:client -> www/js/service
中artHttp
服务;
c. 后台处理:前台请求进入单接口后,主要通过执行c步骤中动态生成的invoke
方法,完成获取参数、接口调用和返回结果值等操作。
2. 加密
描述:
1. 加密传输数据(AESCrypt对称加密算法)
2. 对密码加密后保存(盐)
3. 获取token(SHA-1,MD5)
需要:
server -> src/com/artway/Cryptos.java
server -> src/com/artway/Digests.java
server -> src/com/artway/TokenCache.java
server -> src/com/artway/PasswordHelper.java
client -> plugins/plugin-aescrypt
实现:
a. 前台登陆使用:1
- 首先要导入加密插件(涉及加密算法,无法用
js
实现),即client -> plugins/plugin-aescrypt
- 使用时检验插件是否可用,并声明是否使用
if(window.AESCrypt){
$scope.encryptUser.isEncrypt = true;
//ToDo
},function(data){
//error
})
- 调用以下方法加密,然后通过1a提交数据
window.AESCrypt.encrypt(source, function(result){
//success
},function(data){
//error
})
b. 后台接收:123
- Cryptos.java解密,PasswordHelper.java校验密码
//获取并转换参数
String password = Converter.to(String.class).convert(data.get("password"));
Boolean isEncrypt = (Boolean)data.get("isEncrypt");
//解密
if(isEncrypt!=null&&isEncrypt){
password = Cryptos.aesDecrypt(Encodes.decodeBase64(password), Const.AES_KEY.getBytes());
}
//获取盐,并对密码加密计算再和数据库中加密密码比对
String salt = user.getSalt();
if (!PasswordHelper.generatePassword(password, salt + password).equals(user.getPassword())) {
throw new ArtControllerException("密码错误");
}
- 专门一张表存放token
//作废原有token
atUserTokenMapper.disableUserToken(map);
TokenCache.clean(strUserId);
//Digests生成新的Token
String token = Encodes.encodeHex(Digests.sha1(strUserId.getBytes(), timeStr.getBytes()));
// 将Token放入缓存
TokenCache.put(strUserId, token);
c. 前台传输数据使用:
- 成功登陆后,将新的token保存在前台
localStorage.setItem('token', data.token);
artHttp
中加密真实接口后提交请求
function generateSign(map, token) {
var shaObj = new jsSHA("SHA-1", "TEXT", {encoding: "UTF8"});
shaObj.update(map);
shaObj.update(token);
return shaObj.getHash("HEX");
}
function initD(map, arguments) {
var d = {};
d.map = map;
d.arguments = arguments;
d.userId = localStorage.getItem("userId");
var token = localStorage.getItem("token");
d.sign = token ? generateSign(map, token) : null;
return d;
}
- 进入单接口处理请求,并返回数据
3. WebSocket
描述:实时消息通知及用户之间私信用到。区别于轮询。
需要:
server -> src/com/artway/artogether/app/websocket
client -> plugins/cordova-plugin-websocket
client -> www/js/app-socket.js
实现:
a. 后端启动websocket服务,为服务端,接口为@ServerEndpoint("/appSocket")
;前端插件启动websocket服务,为客户端;
b. 后端需要websocket服务发送消息的地方,按照业务逻辑添加如下代码:
//防止发送消息,导致业务逻辑阻塞
try {
AppSocket.sendMessage(targetId, msg);
} catch (Exception e) {
//Error
}
c. 前端连接:(- client -> www\js\app-socket.js
中connection()
方法有详解)
//wsPath = "ws://localhost:8080/"
//appSocket 后端websocket服务接口
var host = wsPath + "appSocket";
var userId = localStorage.getItem("userId");
var url = host + "?userId=" + userId;
//检测是否支持WebSocket
if ('WebSocket' in window) {
//前后端交互
appSocket.socket = new WebSocket(url);
}
4. 验证码
描述: java后端生成指定位数的、带干扰线和干扰点的验证码,并提供验证方法
需要:
server -> src\com\artway\common\service\utilService.java
server -> src\com\artway\utils\Captcha.java
实现:
a. 生成:业务逻辑需要的验证码的地方,调用如下代码,验证码保存在名为captcha
的sesson
里
utilService.createCaptchaImage(
response, //HttpServletResponse
session, //HttpSession
4, //验证码长度
129, //图片宽度 px
48); //图片高度 px
b. 验证:
//boolean型,验证通过返回true
utilService.validateCaptcha(userCaptcha, session)
5. 微信/支付宝支付
描述:
1. 微信为扫码支付,部分页面要自己绘制
2. 支付宝为网页支付
需要:
server -> WebRoot\WEB-INF\lib\pay_server
实现:
a. 前端传入支付类型和订单号:
var paras = {'payType': $scope.pay.type, 'orderCode': $scope.pay.orderCode};
b. 后台组装并生成订单:
Map<String, Object> result = null;
//微信支付
if (payType.equals("wx")) {
result = wepayService.doUnifiedOrder(buildWepayOrderData(orderVO, notifyUrl));
result.put("total_fee",orderVO.getTotalPrice());
} else if (payType.equals("zfb")) {
result = alipayService.doUnifiedOrder(buildAlipayOrderData(orderVO, notifyUrl, returnUrl, clientIp));
} else {
throw new ArtControllerException("不支持该支付类型:" + payType);
}
//组装微信订单
private Map<String, String> buildWepayOrderData(AtOrderVO orderVO, String notifyUrl) {
Map<String, String> orderData = new HashMap<>();
orderData.put("openId", null);
orderData.put("productId", String.valueOf(orderVO.getPackageId()));
orderData.put("body", orderVO.getPackageName());//商品描述
orderData.put("detail", orderVO.getPackageName());//商品详情
orderData.put("attach", null);//附加数据
orderData.put("totalFee", String.valueOf(Math.round(orderVO.getTotalPrice() * 100)));//总金额,微信使用分作为单位
orderData.put("outTradeNo", String.valueOf(orderVO.getOrderCode()));
orderData.put("spbillCreateIp", NetworkUtils.getLocalHostIP());
orderData.put("callbackUrl", notifyUrl);
orderData.put("tradeType", "NATIVE");//交易类型
return orderData;
}
//组装支付宝订单
private Map<String, String> buildAlipayOrderData(AtOrderVO orderVO, String notifyUrl, String returnUrl, String clientIp) {
Map<String, String> orderData = new HashMap<>();
orderData.put("notifyUrl", notifyUrl);
orderData.put("returnUrl", returnUrl);
orderData.put("outTradeNo", orderVO.getOrderCode());
orderData.put("subject", orderVO.getPackageName());
orderData.put("body", orderVO.getPackageName());
orderData.put("totalFee", orderVO.getTotalPrice().toString());//总金额,支付宝使用元作为单位
orderData.put("exterInvokeIp", clientIp);
return orderData;
}
6. 指令 —— imagePicker
描述:移动端获取设备内图片的指令。
需要:
client -> www/js/directives.js -> imagePicker
client -> plugins/plugin-picture
client -> www/js/service.js -> localCache
获取的图片暂时存放在这里,上传后删除client -> www/js/service.js -> appUtil
生成文件名
实现:需要使用图片选择的地方,调用以下代码
<image-picker image-uri-list="存放图片url列表的变量" image-count="图片数量" callback="回调函数"></image-picker>
7. 指令 —— showImgArray和showImg
描述:点击缩略图后调出原图浏览
需要:
- client -> www/js/directives.js -> showImgArray
- client -> www/js/directives.js -> showImg
- client -> www/index.html -> id='rightDisplay'的代码片段
将图片现实于最高图层
- client -> www/js/service.js -> bigImageManager
实现:需要显示大图的地方,如下调用
<img show-img-array="图片列表数据" show-img-index="{{$index}}">
<img show-img="图片数据" ng-click="showImg(showUserInfo,$event);">
//防止点击事件向上pop
$scope.showImg = function(image,$event){
$event.stopPropagation();
};
8. 指令 —— footerWithInput
描述:控制带输入框的footer,解决ios浏览器上滑出键盘时input被遮住的问题
需要:
client -> www/js/directives.js -> footerWithInput
实现:需要控制的地方,加上此属性即可,如下
<ion-footer-bar footer-with-input></ion-footer-bar>
9. 指令 —— autoFocusWhen
描述:自动获取焦点,多用于弹出输入框的位置
需要:
client -> www/js/directives.js -> autoFocusWhen
实现:需要控制的地方,加上此属性即可,如下
<textarea auto-focus-when="boolean"></textarea>
10. 服务 —— artHttp
描述:包装$http请求
需要:
client -> www/js/directives.js -> artHttp
client -> plugin/cordova-plugin-file
用于上传文件
实现:首先要在controller中添加相应的服务
//get/post请求
artHttp.post('interface', {parameter}).
success(function (data, status, headers, config) {
//success
}).
error(function (data, status, headers, config) {
//error
});
//上传文件
artHttp.uploadFiles('interface',fileList, {parameter},
function (data, status, headers, config) {
//success
}, function (data, status, headers, config) {
//error
});
10. 服务 —— platformUtil
描述:判断设备 iOS/Android
需要:
client -> www/js/directives.js -> platformUtil
实现:首先要在controller中添加相应的服务
//返回设备类型
platformUtil.getPlatform()
//返回boolean
platformUtil.isIos();
platformUtil.isAndroid();
11. 服务 —— securityInterceptor
描述:自定义拦截器。
需要:
client -> www/js/service.js -> securityInterceptor
client -> www/js/app.js -> config
统一数据请求接收方式
实现:设置在主config中
$httpProvider.interceptors.push('securityInterceptor');
问题及解决
e-moji表情代码存入mySql数据库中报错
- 需要存储emoji表情的字段选择utf8mb4_general_ci
ionic中$state.go跳转方式有bug,有时跳转之后回不到上一个页面
- 自定义
artState
服务,调用: client -> www/js/service.js -> artState
artState.go($scope, to, params, options});
app内打开外部网页
client -> plugins/cordova-plugin-inappbrowser
$scope.goWebContent = function (targetSrc) {
window.open(targetSrc
,'_blank'
,'location=yes
,clearcache=yes
,enableViewportScale=yes
,disallowoverscroll=yes');
};
分享的实现
client -> plugins/plugin-share
//path:服务器端网页的路劲
window.Share.share(title, content, path);