springboot第34集:ES 搜索,nginx

#用search after解决深分页性能问题
#第一页
GET /bank/_search
{"size": 10,"sort": [{"account_number": {"order": "asc"}}]
}#第二页
GET /bank/_search
{"size": 10,"sort": [{"account_number": {"order": "asc"}}],"search_after" : [13]
}
# true\false 指定是否返回_source
GET /bank/_search?size=5
{"query": {"match_all": {}},"_source": true
}#明确指定要返回的字段
GET /bank/_search
{"_source": ["address", "balance"]
}#将两个字段排除在外
GET /bank/_search
{"_source": {"excludes": ["address", "balance"]}
}

全文检索完全匹配,必须包含分词后的所有词

GET /songs_v1/_search
{"query": {"match": {"lyrics": {"query": "All I need is someone who makes me wanna sing","operator": "and"}}}
}
41a8200c113239bfdf791fb380f7ea15.png
image.png
014ac62a0e0fa930db3e7482a0e9faa9.png
image.png
647982e9df460a96f37d692310d67b37.png
image.png
f867676d1addd5a1706b67419b62aff7.png
image.png
7473ed768065c2547c2cc55b21db42b4.png
image.png

https://www.elastic.co/cn/downloads/elasticsearch

c251b34a26a7abf9ed6302e92ae3a5f0.png
image.png

1) 前台启动:bin/elasticsearch

2) 后台启动:bin/elasticsearch -d

1) 前台停止:ctrl+c

(2) 后台停止:kill -9 elasticsearch的进程号

  • 创建用户命令

adduser elasticsearch
  • 修改用户密码

passwd elasticsearch
  • 将es解压目录的所有者授予此用户

chown -R elasticsearch elasticsearch-7.8.0
  • 切换至elasticsearch用户

su elasticsearch
  • 进入es安装目录,运行启动脚本

/usr/local/elasticsearch-7.8.0/bin/elasticsearch -d

On this node:

⁃ Create an enrollment token with bin/elasticsearch-create-enrollment-token -s node.

⁃ Uncomment the transport.host setting at the end of config/elasticsearch.yml.

⁃ Restart Elasticsearch.

• On other nodes:

⁃ Start Elasticsearch with bin/elasticsearch --enrollment-token <token>, using the enrollment token that you generated.

https://www.elastic.co/cn/kibana

288fd92c3d3e32ead17f7069d1cb29ed.png
image.png
a71cc360bec62baec4d9b0ebd1c3856b.png
image.png
import http from '@/utils/request'//axios 拦截器
// 导出
export function exportData(params) {return http({url: '/customs/reimburse/export',method: 'post',params,responseType: 'arraybuffer', // 一定要加这一配置,否则导出文件打不开})
}
let res = await exportData({ ids: 5 })let href = window.URL.createObjectURL(new Blob([res],{ type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }))const downloadElement = document.createElement('a')downloadElement.href = hrefdownloadElement.download = '导出报表.xlsx' //下载后文件名document.body.appendChild(downloadElement)downloadElement.click() //点击下载document.body.removeChild(downloadElement) //下载完成移除元素window.URL.revokeObjectURL(href) //释放掉blob对象
import { saveAs } from 'file-saver';axios({method: 'post',url: '接口地址',responseType: 'blob' // 必须,此内容会告知后端返回数据为blob,否则会得到string内容
}).then(response => {saveAs(new Blob([response.data], { type: 'application/octet-stream' }),`download.xlsx`)
}).catch((error) => {});
download() {const data = {  }// 要发送到后台的数据axios({ method: 'get',url: '/downFile/file', // 请求地址data: data, // 参数responseType: 'blob' //  表明返回服务器返回的数据类型  这里注意    要加上responseType}).then((res) => { // 处理返回的文件流// 注意 返回的res 无需做任何处理,有时在用框架封装的请求之后会出    现返回response.text() 等情况导致文件流下载失败。const blob = new Blob([content])const fileName = 'down.xls'const alink = document.createElement('a')alink.download = fileNamealink.style.display = 'none'alink.href = URL.createObjectURL(blob)   // 这里是将文件流    转化为一个文件地址document.body.appendChild(alink)alink.click()URL.revokeObjectURL(alink.href) // 释放URL 对象document.body.removeChild(alink)})}

首先需要导入的插件有:

npm install element-plus[1] --save,//elementplus的组件库(这个可用可不用,我用的是组件的按钮所以需要使用到他)
npm install xlsx --save//xlsx的插件

当一张表的数据达到几千万时,查询一次所花的时间会变长。业界公认MySQL单表容量在 1千万 以下是最佳状态,因为这时它的BTREE索引树高在3~5之间。

数据切分可以分为:垂直切分水平切分

一、垂直切分

垂直切分又可以分为: 垂直分库垂直分表

1、垂直分库

概念 就是根据业务耦合性,将关联度低的不同表存储在不同的数据库。做法与大系统拆分为多个小系统类似,按业务分类进行独立划分。与"微服务治理"的做法相似,

每个微服务使用单独的一个数据库。

如图:

b238f32dc7325fa0afea4912eaccce43.jpeg

说明

一开始我们是单体服务,所以只有一个数据库,所有的表都在这个库里。

后来因为业务需求,单体服务变成微服务治理。所以将之前的一个商品库,拆分成多个数据库。每个微服务对于一个数据库。

2、垂直分表

概念 把一个表的多个字段分别拆成多个表,一般按字段的冷热拆分,热字段一个表,冷字段一个表。从而提升了数据库性能。

如图:

fd145e8e44aef61a674b6e63c1e8e779.jpeg

说明

一开始商品表中包含商品的所有字段,但是我们发现:

1.商品详情和商品属性字段较长2.商品列表的时候我们是不需要显示商品详情和商品属性信息,只有在点进商品商品的时候才会展示商品详情信息

所以可以考虑把商品详情和商品属性单独切分一张表,提高查询效率。

3、垂直切分优缺点

优点

- 解决业务系统层面的耦合,业务清晰
- 与微服务的治理类似,也能对不同业务的数据进行分级管理、维护、监控、扩展等
- 高并发场景下,垂直切分一定程度的提升IO、数据库连接数、单机硬件资源的瓶颈

缺点

- 分库后无法Join,只能通过接口聚合方式解决,提升了开发的复杂度
- 分库后分布式事务处理复杂
- 依然存在单表数据量过大的问题(需要水平切分)

二、水平切分

当一个应用难以再细粒度的垂直切分或切分后数据量行数巨大,存在单库读写、存储性能瓶颈,这时候就需要进行水平切分了。

水平切分也可以分为:水平分库水平分表

1、水平分库

水平分库的原因

上面虽然已经把商品库分成3个库,但是随着业务的增加一个订单库也出现QPS过高,数据库响应速度来不及,一般mysql单机也就1000左右的QPS,如果超过1000就要考虑分库。

如图

271c8484284c4589e80d6d68c88d7ffb.jpeg

2、水平分表

概念 一般我们一张表的数据不要超过1千万,如果表数据超过1千万,并且还在不断增加数据,那就可以考虑分表。

如图

3e7625d063e81bb68e991d44b0536607.jpeg

3、水平切分优缺点

优点

- 不存在单库数据量过大、高并发的性能瓶颈,提升系统稳定性和负载能力
- 应用端改造较小,不需要拆分业务模块

缺点

- 跨分片的事务一致性难以保证
- 跨库的Join关联查询性能较差
- 数据多次扩展难度和维护量极大

三、数据分片规则

我们我们考虑去水平切分表,将一张表水平切分成多张表,这就涉及到数据分片的规则,比较常见的有:Hash取模分表数值Range分表一致性Hash算法分表

1、Hash取模分表

概念 一般采用Hash取模的切分方式,例如:假设按goods_id分4张表。(goods_id%4 取整确定表)

530a7519de627405006f552bd45e696b.jpeg

优点

- 数据分片相对比较均匀,不容易出现热点和并发访问的瓶颈。

缺点

- 后期分片集群扩容时,需要迁移旧的数据很难。
- 容易面临跨分片查询的复杂问题。比如上例中,如果频繁用到的查询条件中不带goods_id时,将会导致无法定位数据库,从而需要同时向4个库发起查询,
再在内存中合并数据,取最小集返回给应用,分库反而成为拖累。

2、数值Range分表

概念 按照时间区间或ID区间来切分。例如:将goods_id为11000的记录分到第一个表,10012000的分到第二个表,以此类推。

如图

4cb692a72a9d49d2aa5057255ea54f5c.jpeg

优点

- 单表大小可控
- 天然便于水平扩展,后期如果想对整个分片集群扩容时,只需要添加节点即可,无需对其他分片的数据进行迁移
- 使用分片字段进行范围查找时,连续分片可快速定位分片进行快速查询,有效避免跨分片查询的问题。

缺点

- 热点数据成为性能瓶颈。
例如按时间字段分片,有些分片存储最近时间段内的数据,可能会被频繁的读写,而有些分片存储的历史数据,则很少被查询

3、一致性Hash算法

一致性Hash算法能很好的解决因为Hash取模而产生的分片集群扩容时,需要迁移旧的数据的难题

1、分布式事务问题

使用分布式事务中间件解决,具体是通过最终一致性还是强一致性分布式事务,看业务需求

2、跨节点关联查询 Join 问题

切分之前,我们可以通过Join来完成。而切分之后,数据可能分布在不同的节点上,此时Join带来的问题就比较麻烦了,考虑到性能,尽量避免使用Join查询。

表,会引入新的的问题

1、分布式事务问题

使用分布式事务中间件解决,具体是通过最终一致性还是强一致性分布式事务,看业务需求,这里就不多说。

2、跨节点关联查询 Join 问题

切分之前,我们可以通过Join来完成。而切分之后,数据可能分布在不同的节点上,此时Join带来的问题就比较麻烦了,考虑到性能,尽量避免使用Join查询。

解决这个问题的一些方法:

全局表

全局表,也可看做是 "数据字典表",就是系统中所有模块都可能依赖的一些表,为了避免跨库Join查询,可以将 这类表在每个数据库中都保存一份。这些数据通常

很少会进行修改,所以也不担心一致性的问题。

字段冗余

利用空间换时间,为了性能而避免join查询。例:订单表保存userId时候,也将userName冗余保存一份,这样查询订单详情时就不需要再去查询"买家user表"了。

数据组装

在系统层面,分两次查询。第一次查询的结果集中找出关联数据id,然后根据id发起第二次请求得到关联数据。最后将获得到的数据进行字段拼装。

3、跨节点分页、排序、函数问题

跨节点多库进行查询时,会出现Limit分页、Order by排序等问题。分页需要按照指定字段进行排序,当排序字段就是分片字段时,通过分片规则就比较容易定位到指定的分片;

当排序字段非分片字段时,就变得比较复杂了。需要先在不同的分片节点中将数据进行排序并返回,然后将不同分片返回的结果集进行汇总和再次排序,最终返回给用户。

4、全局主键避重问题

如果都用主键自增肯定不合理,如果用UUID那么无法做到根据主键排序,所以我们可以考虑通过雪花ID来作为数据库的主键

微信扫一扫功能开发前期准备

# 1、微信开放平台介绍(申请里面的网站应用需要企业资料)微信开放平台网站:https://open.weixin.qq.com/# 2、什么是appid、appsecret、授权码codeappid和appsecret是 资源所有者向申请人分配的一个id和秘钥code是授权凭证,A->B 发起授权,想获取授权用户信息,那a必须携带授权码,才可以向B获取授权信息(你要从我这里拿东西出去,就必须带身份证)#   3、先仔细阅读下微信开放平台 官方给出的微信登录开发指南:https://developers.weixin.qq.com/doc/oplatform/Website_App/WeChat_Login/Wechat_Login.html
ea6246d2a9f4d58a94d3d6af47692da6.png
image.png
48f95aaa007c6f7a68023b9ba480db36.png
image.png

微信开放平台注册并登录:

由于创建网站应用需要企业认证,而且进行微信验证 需要 交300块钱给腾讯,对于个人开发者来说成本过高,所以只能采用别人的或者自己花钱申请。

f24c2a07a5dedd61a166e772a2ee8924.png
image.png
92bf02d8db622261eb3fdc2ee4d4aac5.png
image.png

微信授权一键登录,授权URL获取

简介:获取微信开放平台扫码链接url地址

#  增加结果工具类,JsonData;  增加application.properties配置
#  微信开放平台配置wxopen.appid=wxopen.appsecret=#重定向urlwxopen.redirect_url=http://test/pub/api/v1/wechat/user/callback1

application.properties

# 微信相关配置:
# 公众号
wxpay.appid=wx5beXXXXX7cdd40c
wxpay.appsecret=55480123XXXXXXXXb382fe548215e9
# 微信开放平台配置
wxopen.appid=wx025XXXXX9a2d5b
wxopen.appsecret=f5b6730c59XXXXXXX5aeb8948a9f3
# 重定向url 重定向到首页,并根据code拿到token,从而获取微信扫码用户的登录信息
# 这个域名是别人认证过的,只能拿来做个参考,不能自己回调
wxopen.redirect_url=http://XXXX.cn/XXXX/wechat/user/callback
public class WeChatConfig {// 微信开放平台二维码连接// 待填充参数:appid=%s    redirect_uri=%s     state=%sprivate final static String OPEN_QRCODE_URL = "https://open.weixin.qq.com/connect/qrconnect?appid=%s&redirect_uri=%s&response_type=code&scope=snsapi_login&state=%s#wechat_redirect";// 微信开放平台获取access_token地址// 待填充参数:appid=%s    secret=%s     code=%sprivate final static String OPEN_ACCESS_TOKEN_URL="https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code";// 获取用户信息// 待填充参数:access_token=%s    openid=%sprivate final static String OPEN_USER_INFO_URL ="https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s&lang=zh_CN";@Value("${wxpay.appid}")private String appid;// 微信appid@Value("${wxpay.appsecret}")private String appsecret;// 微信秘钥@Value("${wxopen.appid}")private String openAppid;// 开放平台appid@Value("${wxopen.appsecret}")private String openAppsecret;// 开放平台秘钥@Value("${wxopen.redirect_url}")private String openRedirectUrl;// 开放平台回调地址public static String getOpenUserInfoUrl() {return OPEN_USER_INFO_URL;}public static String getOpenAccessTokenUrl() {return OPEN_ACCESS_TOKEN_URL;}public static String getOpenQrcodeUrl() {return OPEN_QRCODE_URL;}
@ResponseBody@GetMapping("/login_url")@CrossOriginpublic JsonData weChatloginUrl(@RequestParam(value = "state", required = true) String state) throws UnsupportedEncodingException {/*** state :* 用于保持请求和回调的状态,授权请求后原样带回给第三方。该参数可用于防* 止csrf攻击(跨站请求伪造攻击),建议第三方带上该参数,可设置为简单的随* 机数加session进行校验,例如:state=3d6be0a4035d839573b04816624a415e*/// 获取开放平台重定向地址String redirectUrl = weChatConfig.getOpenRedirectUrl();// 微信开放平台文档规定,需要先对回调的url使用urlEncode对链接进行编码处理String callbackUrl = URLEncoder.encode(redirectUrl, "GBK");// 为扫码链接qrcodeUrl填充参数 appid=%s redirect_uri=%s state=%s 到 OPEN_QRCODE_URLString qrcodeUrl = String.format(weChatConfig.getOpenQrcodeUrl(), weChatConfig.getOpenAppid(), callbackUrl, state);// 构建json对象返回return JsonData.buildSuccess(qrcodeUrl);}

UserMapper.java

/*** @Auther: csp1999* @Date: 2020/08/28/14:31* @Description: User Mapper*/
@Repository
public interface UserMapper {// 保存微信登录用户基本信息Integer saveUser(@Param("user") User user);// 根据openid 查询User findByUserOpenid(String openid);// 根据主键id 查询User findByUserId(Integer id);// 更新微信用户基本信息void updateUser(@Param("user") User user);
}
@Service
public class UserServiceImpl implements UserService {@Autowiredprivate WeChatConfig weChatConfig;@Autowiredprivate UserMapper userMapper;/*** 通过code并附带appId appSecret 向微信方索取access_token* 并通过 access_token 获得用户基本信息(昵称,地址,头像等) 保存数据到数据库* @param code* @return*/@Overridepublic User saveWeChatUser(String code) {// 通过 code 获取 access_tokenURLString accessTokenUrl = String.format(WeChatConfig.getOpenAccessTokenUrl(),weChatConfig.getOpenAppid(),weChatConfig.getOpenAppsecret(),code);// 通过 access_tokenURL 向微信开放平台发送请求, 获取access_tokenMap<String, Object> baseMap = HTTPUtils.doGet(accessTokenUrl);if (baseMap == null || baseMap.isEmpty()) {return null;}// 拿到 accessTokenString accessToken = (String) baseMap.get("access_token");String openId = (String) baseMap.get("openid");// 通过accessToken 得到向微信开放平台发送 用于获取用户基本信息的请求的urlString userInfoUrl = String.format(WeChatConfig.getOpenUserInfoUrl(), accessToken, openId);// 获取access_tokenMap<String, Object> baseUserMap = HTTPUtils.doGet(userInfoUrl);if (baseUserMap == null || baseUserMap.isEmpty()) {return null;}// 拿到用户基本信息String nickname = (String) baseUserMap.get("nickname");// 微信用户名System.out.println(baseUserMap.get("sex"));Double sexTemp = (Double) baseUserMap.get("sex");// 微信用户性别System.out.println(sexTemp);int sex = sexTemp.intValue();// Double => IntegerString province = (String) baseUserMap.get("province");// 微信用户所在省String city = (String) baseUserMap.get("city");// 微信用户所在市String country = (String) baseUserMap.get("country");// 微信用户所在国家String headimgurl = (String) baseUserMap.get("headimgurl");// 微信用户头像StringBuilder builder = new StringBuilder(country).append("||").append(province).append("||").append(city);String finalAddress = builder.toString();try {//解决中文乱码nickname = new String(nickname.getBytes("ISO-8859-1"), "UTF-8");finalAddress = new String(finalAddress.getBytes("ISO-8859-1"), "UTF-8");} catch (UnsupportedEncodingException e) {e.printStackTrace();}User user = new User();user.setName(nickname).setHeadImg(headimgurl).setCity(finalAddress).setOpenid(openId).setSex(sex).setCreateTime(new Date());User findUser = userMapper.findByUserOpenid(openId);if (findUser != null) { //如果数据库中已经有该微信用户信息,更新微信用户最新基本信息,并直接返回即可userMapper.updateUser(user);return user;}// 否则继续往下执行userMapper.saveUser(user);// 保存用户信息return user;}
}

通过扫码登录跳转页面携带的参数code而获取封装有user信息的token

@GetMapping("/user/callback")public String weChatUserCallback(@RequestParam(value = "code", required = true) String code,String state, // 根据实际情况而定可用作保存当前页面地址RedirectAttributes redirectAttributes){User user = userService.saveWeChatUser(code);System.out.println("user:"+user);redirectAttributes.addFlashAttribute("user",user);String token = null;if (user != null){// jwt 生成 tokentoken = JWTUtils.createJsonWebToken(user);redirectAttributes.addFlashAttribute("token",token);redirectAttributes.addFlashAttribute("state",token);return "redirect:/test/test03?token="+token;// 将token 拼接于url ,便于拦截器过滤}else{return "redirect:/error/error";}}

微信网页扫码支付简介

#   1、扫码支付文档:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=2_2#   2、名称理解appid:公众号唯一标识appsecret:公众号的秘钥mch_id:商户号,申请微信支付的时候分配的key:支付交易过程生成签名的秘钥,设置路径 微信商户平台(pay.weixin.qq.com)-->账户中心-->账户设置-->API安全-->密钥设置#   3、和微信支付交互方式1、post方式提交2、xml格式的协议3、签名算法MD54、交互业务规则 先判断协议字段返回,再判断业务返回,最后判断交易状态5、接口交易单位为 分6、交易类型:JSAPI--公众号支付、NATIVE--原生扫码支付、APP--app支付

微信支付业务流程说明:

(1)商户后台系统根据用户选购的商品生成订单。

(2)用户确认支付后调用微信支付【统一下单API】生成预支付交易;

(3)微信支付系统收到请求后生成预支付交易单,并返回交易会话的二维码链接code_url。

(4)商户后台系统根据返回的code_url生成二维码。

(5)用户打开微信“扫一扫”扫描二维码,微信客户端将扫码内容发送到微信支付系统。

(6)微信支付系统收到客户端请求,验证链接有效性后发起用户支付,要求用户授权。

(7)用户在微信客户端输入密码,确认支付后,微信客户端提交授权。

(8)微信支付系统根据用户授权完成支付交易。

(9)微信支付系统完成支付交易后给微信客户端返回交易结果,并将交易结果通过短信、微信消息提示用户。微信客户端展示支付交易结果页面。

(10)微信支付系统通过发送异步消息通知商户后台系统支付结果。商户后台系统需回复接收情况,通知微信后台系统不再发送该单的支付通知。

(11)未收到支付通知的情况,商户后台系统调用【查询订单API】。

(12)商户确认订单已支付后给用户发货。

微信扫码支付之统一下单接口开发之订单增删改查

统一下单微信官方文档:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_1

c1f76cebb86a2c4db99d5933b60d7d16.png
image.png
DROP TABLE IF EXISTS `video_order`;CREATE TABLE `video_order` (`id` int(11) unsigned NOT NULL AUTO_INCREMENT,`openid` varchar(32) DEFAULT NULL COMMENT '用户标示',`out_trade_no` varchar(64) DEFAULT NULL COMMENT '订单唯一标识',`state` int(11) DEFAULT NULL COMMENT '0表示未支付,1表示已支付',`create_time` datetime DEFAULT NULL COMMENT '订单生成时间',`notify_time` datetime DEFAULT NULL COMMENT '支付回调时间',`total_fee` int(11) DEFAULT NULL COMMENT '支付金额,单位分',`nickname` varchar(32) DEFAULT NULL COMMENT '微信昵称',`head_img` varchar(128) DEFAULT NULL COMMENT '微信头像',`video_id` int(11) DEFAULT NULL COMMENT '视频主键',`video_title` varchar(128) DEFAULT NULL COMMENT '视频名称',`video_img` varchar(256) DEFAULT NULL COMMENT '视频图片',`user_id` int(11) DEFAULT NULL COMMENT '用户id',`ip` varchar(64) DEFAULT NULL COMMENT '用户ip地址',`del` int(5) DEFAULT '0' COMMENT '0表示未删除,1表示已经删除',PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;LOCK TABLES `video_order` WRITE;
public class CommonUtils {// 生成 uuid, 即用来标识一笔单,也用做 nonce_strpublic static String generateUUID() {return UUID.randomUUID().toString().replaceAll("-", "")// 去掉默认自带的 - 分隔符.substring(0, 32);// 截取 32 位}// MD5 加密工具类public static String getMD5String(String data) {try {// 获取MD5 加密实例MessageDigest md = MessageDigest.getInstance("MD5");// 获得数组对象byte[] array = md.digest(data.getBytes("UTF-8"));// 拼接加密字符串StringBuilder builder = new StringBuilder();for (byte item : array) {builder.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));}return builder.toString().toUpperCase();// 所有字母大写} catch (Exception exception) {System.out.println("MD5加密算法出现异常...");}return null;}
}
# 1、统一下单参数需要微信签名,签名规则如下
-   文档地址:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=4_3
-   签名生成的通用步骤如下:第一步,设所有发送或者接收到的数据为集合M,将集合M内非空参数值的参数按照参数名ASCII码从小到大排序(字典序),使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串stringA。第二步,在stringA最后拼接上key得到stringSignTemp字符串,并对stringSignTemp进行MD5运算,再将得到的字符串所有字符转换为大写,得到sign值signValue。key设置路径:微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置<---  参数:SortedMap<String, String> params = new TreeMap<>();  params.put("appid", wxPayConfig.getAppId());  //公众账号ID  params.put("mch_id", wxPayConfig.getMchId());  //商户号  params.put("nonce_str", CommonUtil.generateNonceStr());  //随机字符串  params.put("body", videoOrder.getVideoTitle());  // 商品描述  //商户订单号,商户系统内部订单号,要求 32个字符内,只能是数字、大小写字母_-|* 且在同一个商户号下唯一params.put("out_trade_no", videoOrder.getOutTradeNo()); params.put("total_fee", videoOrder.getTotalFee().toString());  //标价金额 分params.put("spbill_create_ip", videoOrder.getIp());  //通知地址    params.put("notify_url", wxPayConfig.getDomain()+wxPayConfig.getCallbackUrl()); //交易类型 JSAPI 公众号支付 NATIVE 扫码支付 APP APP支付params.put("trade_type", "NATIVE");  //生成签名String sign = WXPayUtil.createSign(params, wxPayConfig.getKey());params.put("sign", sign); //参数转xmlString requestXMl = WXPayUtil.mapToXml(params);生成签名后,通过工具去校验https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=20_1
--->
#    2、测试地址:localhost:8081/api/v1/order/add?video_id=2#    3、课程测试签名结果:sign: 85118C91DFCB052FB02AC183BF3D57D2
#微信相关配置:
#公众号
wxpay.appid=wx252XXXXX1xs9h
wxpay.appsecret=qm4i2u43oXXXXXXXX7055s8c99a8#微信开放平台配置
wxopen.appid=wx025XXXXXXa2d5b
wxopen.appsecret=f5b6730c59XXXXXXXXeb8948a9f3
#重定向url 重定向到首页,并根据code拿到token,从而获取微信扫码用户的登录信息
#这个域名是别人认证过的,只能拿来做个参考,不能自己回调
wxopen.redirect_url=http://XXXXXXXXXXXXXX.cn/xdclass/wechat/user/callback#微信商户平台 商户id 订单秘钥 回调地址
wxpay.mer_id=8XXXXXX068
wxpay.key=MbZL0DiXXXXXXXXX5S51MK2
wxpay.callback=http://XXXXXXXXXXXXXXX.cn/xdclass/
public String unifiedOrder(VideoOrder videoOrder) throws Exception {WXPay wxPay = new WXPay();// 使用 map 封装 订单参数以及微信支付相关参数SortedMap<String, String> data = new TreeMap<>();data.put("appid", weChatConfig.getAppid());// 公众账号ID: 微信支付分配的公众账号ID(企业号corpid即为此appId)data.put("mch_id", weChatConfig.getMchId());// 商户号: 微信支付分配的商户号data.put("nonce_str", CommonUtils.getUUID());// 随机字符串: 自定义参数,可以为终端设备号(门店号或收银设备ID),PC网页或公众号内支付可以传"WEB"data.put("body", videoOrder.getVideoTitle());// 商品描述data.put("out_trade_no", videoOrder.getOutTradeNo());// 商户订单号: 要求32个字符内,只能是数字、大小写字母_-|* 且在同一个商户号下唯一。data.put("total_fee", videoOrder.getTotalFee().toString());// 标价金额: 单位为分data.put("spbill_create_ip", videoOrder.getIp());// 下单用户的客户端IPdata.put("notify_url", weChatConfig.getPayCallbackUrl());// 通知地址: 异步接收微信支付结果通知的回调地址,通知url必须为外网可访问的url,不能携带参数。data.put("trade_type", "NATIVE");// 交易类型: 此处指定为扫码支付// 生成 sign 签名String sign = WXPayUtil.generateSignature(data, weChatConfig.getKey());data.put("sign", sign);// 签名: 微信返回的签名值System.out.println("---------------------- xml 数据如下:----------------------");// map 转 xmlString payXmlData = WXPayUtil.mapToXml(data);System.out.println(payXmlData);// 统一下单,发送POST请求微信后台统一下单接口:https://api.mch.weixin.qq.com/pay/unifiedorder 获取返回xml格式的字符串 orderStrString orderStr = HTTPUtils.doPost(WeChatConfig.getUnifiedOrderUrl(), payXmlData, 4000);System.out.println("---------------------- 请求统一下单接口返回的 orderStr 数据如下:----------------------");System.out.println(orderStr);if (null == orderStr) {return null;}// 将统一下单接口返回的xml格式的字符串 orderStr 转成 mapMap<String, String> unifiedOrderMap = WXPayUtil.xmlToMap(orderStr);System.out.println("---------------------- 转换成 map 的 orderStr 数据如下:----------------------");// 这样做的目的是解决打印出的对象中文乱码问题,无法阅读错误提示信息String string = new String(unifiedOrderMap.toString().getBytes("ISO-8859-1"), "UTF-8");System.out.println(string);if (unifiedOrderMap != null) {System.out.println("支付二维码url:" + unifiedOrderMap.get("code_url"));return unifiedOrderMap.get("code_url");// 获取统一下单接口返回的 code_url(支付二维码图片的url) 数据}// 否则返回nullreturn null;}
932a72c74a1743a2dae962296ccb6711.png
image.png

Nginx文件的默认安装位置如下。

目录说明
/usr/sbin/nginx存放主程序
/etc/nginx存放配置文件
/usr/share/nginx存放静态文件
/var/log/nginx存放日志

执行以下命令打开Nginx配置文件nginx.conf。

sudo vi /etc/nginx/nginx.conf
server {listen       80 default_server;listen       [::]:80 default_server;server_name  _;root         /usr/share/nginx/html;# Load configuration files for the default server block.include /etc/nginx/default.d/*.conf;location / {proxy_pass https://bucketname.oss-cn-beijing-internal.aliyuncs.com;proxy_set_header Host $host;}
}
sudo cd /usr/sbin/
sudo ./nginx

https://developers.weixin.qq.com/doc/oplatform/Website_App/WeChat_Login/Wechat_Login.html?spm=a2c6h.12873639.article-detail.6.7d3c4912zCqPuf

https://open.weixin.qq.com/cgi-bin/showdocument?spm=a2c6h.12873639.article-detail.5.7d3c4912zCqPuf&action=dir_list&t=resource/res_list&verify=1&id=open1419316505&token=&lang=zh_CN

加群联系作者vx:xiaoda0423

仓库地址:https://github.com/webVueBlog/JavaGuideInterview

参考资料

[1]

element-plus: https://so.csdn.net/so/search?q=element-plus&spm=1001.2101.3001.7020

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/24483.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【WEB逆向】前端全报文加密的分析技巧

由于前端全报文加密&#xff0c;无法从变量的全文搜索来快速定位加密函数对加密参数的定位&#xff08;全局搜索还有个弊病是编码混淆的js也不能全局搜到&#xff0c;需要进一步分析判定混淆的编码形式后再全局搜编码后的变量名&#xff09;&#xff0c;因此可利用xhr断点全局拦…

LLM reasoners 入门实验 24点游戏

LLM reasoners Ber666/llm-reasoners 实验过程 实验样例24games&#xff0c;examples/tot_game24&#xff0c;在inference.py中配置使用代理和open ai的api key。 首先安装依赖 git clone https://github.com/Ber666/llm-reasoners cd llm-reasoners pip install -e .然后…

【雕爷学编程】Arduino动手做(187)---1.3寸OLED液晶屏模块2

37款传感器与模块的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止37种的。鉴于本人手头积累了一些传感器和执行器模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&#x…

Spring Security OAuth2.0(7):自定义认证连接数据库

自定义认证连接数据库 首先创建数据库和用户表 CREATE TABLE t_user (id bigint(20) NOT NULL AUTO_INCREMENT,username varchar(64) DEFAULT NULL,password varchar(64) DEFAULT NULL,fullname varchar(255) DEFAULT NULL,mobile varchar(20) DEFAULT NULL,PRIMARY KEY (id)…

MacOS使用brew如何下载Nginx

首先&#xff0c;第一步切换源&#xff1a; 切换 brew.git 仓库地址&#xff1a; cd "$(brew --repo)" git remote set-url origin https://mirrors.aliyun.com/homebrew/brew.git 替换 homebrew-core.git 仓库地址: cd "$(brew --repo)/Library/Taps/home…

LabVIEW 开发在不确定路况下自动速度辅助系统

LabVIEW 开发在不确定路况下自动速度辅助系统 智能驾驶辅助系统是汽车行业最先进的升级和尖端技术&#xff0c;智能交通系统依靠智能驾驶辅助系统在公共交通部门工作。该智能驾驶辅助系统技术包括自适应巡航控制&#xff0c;防抱死制动系统&#xff0c;安全气囊展开&#xff0…

【机器学习】编码、创造和筛选特征

在机器学习和数据科学领域中&#xff0c;特征工程是提取、转换和选择原始数据以创建更具信息价值的特征的过程。假设拿到一份数据集之后&#xff0c;如何逐步完成特征工程呢&#xff1f; 文章目录 一、特性类型分析1.1 数值型特征1.2 类别型特征1.3 时间型特征1.4 文本型特征1.…

图像 检测 - RetinaNet: Focal Loss for Dense Object Detection (arXiv 2018)

图像 检测 - RetinaNet: Focal Loss for Dense Object Detection - 密集目标检测中的焦点损失&#xff08;arXiv 2018&#xff09; 摘要1. 引言2. 相关工作References 声明&#xff1a;此翻译仅为个人学习记录 文章信息 标题&#xff1a;RetinaNet: Focal Loss for Dense Obje…

CentOS 搭建 Harbor 镜像仓库(图文详解)

本文目录 1. 下载 Harbor 安装包2. 解压3. 修改配置文件4. 安装 Harbor5. 修改 docker 配置6. docker 登录方式7. 访问 Harbor Web 界面8. 创建证书9. 生成证书10. 更新配置11. 网页登录 说明&#xff1a;在搭建 Harbor 镜像仓库之前&#xff0c;虚拟机要先安装 docker 和 dock…

数据安全治理5大关键技术实践分享

近年来&#xff0c;国内外对数据安全的重视程度持续提升&#xff0c;数据安全技术领域发展备受关注。从2017-2021年Gartner发布的“数据安全技术成熟度曲线”研究报告来看&#xff0c; 新兴数据安全技术呈逐年递增趋势&#xff0c;其中安全多方计算、同态加密、差分隐私等隐私增…

增强型Web安全网关在银行的应用

销售&#xff0c;绝不是降低身份去取悦客户&#xff0c;而是像朋友一样给予合理的建议。你刚好需要&#xff0c;我刚好专业&#xff01;仅此而已&#xff01; 乔.吉拉德 健康的安全体系&#xff0c;还可以更完善 浙江某商业银行股份有限公司是一家成立多年的商业银行&#xf…

linux 系统初始化基本yum命令

安装可能用到的系统工具 yum -y install vim telnet wget net-tools lrzsz unzip zip 安装常用工具和开发包 yum install -y which openssh-clients openssh-server less iproute bzip2 cmake gcc gcc-c gdb git libtool make man net-tools sysstat sudo psmisc nc net-t…

vue中transition动画的使用

1.vue文件 说明&#xff1a;加name属性 <transition name"sort"><div class"sort" v-show"show"><div class"all-sort-list2" click"goSearch"><div class"item bo" v-for"(item1, in…

windows系统的IP、路由、网关、内外网同时访问路由以及修改系统文件hosts的配置

当我们刚刚入职一家公司的时候、一般公司会给我下发一个ip地址和mac地址、还有访问一些公司的平台需要修改hosts之后的路由配置、以及第一次配置内网、如何内外网同时上网。 目录 一、ip的配置 1.1、IP的配置 1.2、mac地址的配置 1.3、内外网路由的配置&#xff08;w11系统需…

小程序学习(五):WXSS模板语法

1.什么是WXSS WXSS是一套样式语言,用于美化WXML的组件样式,类似于网页开发中的CSS 2.WXSS和CSS的关系 WXSS模板样式-rpx 3.什么是rpx尺寸单位 4.rpx的实现原理 5.rpx与px之间的单位换算* WXSS模板样式-样式导入 6.什么是样式导入 使用WXSS提供的import语法,可以导入外联的样式…

前端js--剪刀石头布

效果图 代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><linkrel"stylesheet"href"ht…

微服务——操作索引库+文档操作+RestClient操作索引库和文档(java程序)

索引库操作 mapping属性 mapping是对文档的约束&#xff0c;常见约束属性包括: 创建索引库 #创建索引库 PUT /heima {"mappings": {"properties": {"info":{"type": "text","analyzer": "ik_smart"},…

带头循环双向链表详解

目录 一、什么是带头循环双向链表&#xff1f; 1.特点&#xff1a; 2.优点&#xff1a; 二、实现接口 1.前置准备 1.1需要的三个文件 1.2结构体的创建和头文件的引用 2.接口实现 2.1函数创建新节点 2.2打印链表内容 2.3尾插新节点 2.4头插新节点 2.5头删节点 2.6尾删…

【CSS】倾斜按钮

效果 index.html <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"/><meta http-equiv"X-UA-Compatible" content"IEedge"/><meta name"viewport" content"widthdevice-…

Pytest简介及jenkins集成

一、pytest介绍 pytest介绍 - unittest\nose pytest&#xff1a;基于unittest之上的单元测试框架 自动发现测试模块和测试方法 断言使用assert表达式即可 可以设置测试会话级、模块级、类级、函数级的fixtures 数据准备 清理工作 unittest&#xff1a;setUp、teardown、…