微信登录和微信支付
在上一章我们初步的完成了前端的编写,接下来我们来操作微信的登录和微信的支付
微信开放平台(针对开发者和公司):
对应的微信官方文档:
https://developers.weixin.qq.com/doc/oplatform/Website_App/WeChat_Login/Wechat_Login.html
登录用,对应的AppID和AppSecret需要申请才可操作,需要在管理中心创建申请对应的网站,一般是必须要上线的网站:
https://open.weixin.qq.com/
后面我给出了对应的信息(用来测试用),这样就不用你自己申请了
准备工作:
网站应用微信登录是基于OAuth2.0协议标准构建的微信OAuth2.0授权登录系统
在进行微信OAuth2.0授权登录接入之前,在微信开放平台注册开发者帐号
并拥有一个已审核通过的网站应用(或者其他应用,这里就以网站即网页为例子,后面的都说明网站)
并获得相应的AppID和AppSecret,申请微信登录且通过审核后,可开始接入流程
注册帐号和申请应用都是免费的,必须要有一个线上的网站,才能审核通过(过程还是挺麻烦的)
就可以使用微信的登录了,但是如果想使用微信支付的功能,就必须认证开发者资质(认证一次300块人民币)
名词解释:
OAuth2.0协议
玩抖音,发视频,抖音需要访问你相册的授权,话筒的授权,地理位置的授权等等
一句话,我不想帐号密码给第三方应用,但我还想用他们的功能,而他们的功能需要我的部分数据来协助
ok,咱玩令牌,令牌与密码的作用都可以进入系统,但是有三点差异:
1:令牌是短期的,到期会自动失效,用户自己无法修改,密码一般长期有效,用户不修改,就不会发生变化
2:令牌可以被数据所有者撤销,会立即失效,以上例而言,屋主可以随时取消快递员的令牌,密码一般不允许被他人撤销
3:令牌有权限范围,比如只能进小区的二号门,对于网络服务来说,只读令牌就比读写令牌更安全,密码一般是完整权限
上面这些设计,保证了令牌既可以让第三方应用获得权限,同时又随时可控,不会危及系统安全
OAuth的四种授权模式:
1:授权码模式(功能最完整,流程最严密的授权模式)
说白了,授权码模式,不再client和user之间商量授权,而是client想要被授权
所以client去找了一个和事佬大妈,大妈将client和user叫到了一起(认证服务器)
给大妈个面子,这事就这么定了,就是这样的一个过程,全程中认证服务器会发布一个认证码贯穿始终
下面的可以百度了解即可
2:密码模式
一般通过账号密码就可以访问,他们可以通过你的账号密码进行访问(保存在他们的数据库里)
3:简化模式
授权码模式的减低版,没有code授权码
4:客户端模式
最不安全的模式,基本上不需要什么操作就可以访问,他们保存了你的令牌(你给的),保存在数据库里
安全性:授权码模式 > 简化模式 > 密码模式 > 客户端模式
那么具体的信任程度,一般是:客户端模式>密码模式>简化模式>授权码模式
因为对应的第三方必须信任要高,才会放心的给出最简便,但最不安全的模式,但最好还是使用授权码模式
因为在不安全的情况下,黑客也更加容易得到你的信息
由于授权码模式总体来说是最好的,所以我们操作授权码模式
AppID:应用ID,唯一标识(身份证号)
AppSecret :应用的密钥(密码)
code:授权的临时凭证(例如:临时身份证)
access_token :接口调用凭证(例如:真正的身份证,虎符,令牌)
登录授权时序图 :
上面的二维码一般保存对应的地址,你可以进行测试,在百度上搜索"草料二维码生成器",进行官方网站
输入"中华人民共和国"这个内容,点击生成二维码,用微信扫一扫,就会出现该内容
当然多次生成一样的,对应的码基本都相同
当然你也可以输入网站,如http://www.baidu.com,那么会自动的进行跳转,那么为什么不会直接显示内容,而是跳转呢
主要是观察是否有": //“,其中单独的”//“,若前面没有值,那么默认”//"后面是一个网站,否则就是内容
而": //"代表整体是一个网站了(第一个开始,分割线)
具体可以自己进行测试,一般由于登录是用户自身来选择扫描的,所有基本上开发人员调用接口或者对应的地址即可,并不需要申请一些复杂东西,而不会像支付那样,需要一些申请,因为支付数额由开发人员调(可以在前端显示少的,但是底层支付了很多),比较不安全
接下来我们继续说明一下对应的模式
其中授权码模式,上面的图片中,就是一个授权码模式
code就是授权码,token就是令牌,AppID和AppSecret 是网站的对应唯一值,这样该网站可以通过令牌得到用户的信息了
而简化模式,就是没有code这个授权码
而密码模式,一般输入的密码是对应的第三方的,第三方直接通过你的密码进行授权并操作
而客户端模式,自己通过自己的信息得到令牌,然后将令牌给第三方
第三方可以说是我们要访问的客户端,或者网站等等,通过上面的描述,可以知道
的确客户端模式是最不安全的,因为他能直接操作最终的令牌
开发步骤:
vue项目安装
微信官方提供的生成二维码的js,有对应的组件,包含了对应的js
npm install vue-wxlogin
如果不是vue的项目,可以直接引用官方提供的js文件,来生成二维码
http://res.wx.qq.com/connect/zh_CN/htmledition/js/wxLogin.js
页面引入:
在对应的前端找到Header.vue(上一章的前端项目)
这里只会给出部分代码,需要自己去进行对比修改 ,由于是部分,对应的代码可能不是全的
< script>
import wxlogin from 'vue-wxlogin' ;
export default {
name : "Header" ,
components : {
wxlogin
} ,
< el-dialog
style = " width : 800px; margin : 0px auto; "
title = " "
:visible.sync = " dialogFormVisible" >
< div id = " loginForm" >
< el-form>
< el-form-item>
< h1 style = " font-size : 30px; color : #00B38A" > 拉勾</ h1>
</ el-form-item>
< el-form-item>
< el-input v-model = " phone" placeholder = " 请输入常用手机号..." > </ el-input>
</ el-form-item>
< el-form-item>
< el-input v-model = " password" placeholder = " 请输入密码..." > </ el-input>
</ el-form-item>
</ el-form>
< el-button
style = " width : 100%; margin : 0px auto; background-color : #00B38A; font-size : 20px"
type = " primary"
@click = " login" > 确 定</ el-button>
< p> </ p>
< img
@click = " goToLoginWX"
src = " http://www.lgstatic.com/lg-passport-fed/static/pc/modules/common/img/icon-wechat@2x_68c86d1.png"
alt = " "
/>
</ div>
< wxlogin id = " wxLoginForm" style = " display : none"
:appid = " appid" :scope = " scope" :redirect_uri = " redirect_uri" > </ wxlogin>
</ el-dialog>
data ( ) {
return {
isLogin : false ,
userDTO : null ,
isHasNewMessage : false ,
dialogFormVisible : false ,
phone : "" ,
password : "" ,
appid : "wxd99431bbff8305a0" ,
scope : "snsapi_login" ,
redirect_uri : "http://www.pinzhi365.com/wxlogin" ,
} ;
} ,
goToLoginWX ( ) {
document. getElementById ( "loginForm" ) . style. display= "none"
document. getElementById ( "wxLoginForm" ) . style. display= "block"
} ,
接下来点击对应的微信图标,那么就会出现二维码
假设:如果对应的网站Scope权限没有开通或者scope的值不正确,那么会提示对应错误,这是该网站的问题
具体可以百度,这里并没有问题
当然对应的appid的值不正确或者redirect_uri的值不正确,也会出现对应的提示错误,他们都会去验证的
所以申请时也一般只能是上线的网站或者其他应用,否则申请基本会失败,你可以自己试验一下(故意修改参数值)
总体来说,若二维码生成失败,那么就是上面三个参数的问题,只要都正确,基本才会生成出二维码
修改hosts文件(若有自己的远程服务器可以不用这样操作):
文件位置:C:\Windows\System32\drivers\etc\hosts
127.0 .0.1 www.pinzhi365.com
回调默认指定的是80端口(如果设置的参数中,指定了端口,一般会报错,即redirect_uri的值不正确,即redirect_uri参数错误)
所以也只能是80端口,即别忘记将对应的tomcat的端口修改成80后,再次启动该项目(web层项目的那个服务器)
可能80端口被占用,且杀死不了,主要是因为对应的服务是系统的服务,所以我们需要以管理员的方式进入命令行窗口(cmd)
执行net stop http,选择y,等待关闭,注意需要管理员方式,否则可能操作不了
这时80端口没有占用了(对应关闭的服务并不是特别需要)
但可能重启还是会继续占用,则继续执行sc config http start= disabled,使得重启不占用
来到后端的web层项目:
引入依赖:
< dependency>
< groupId> javax.servlet</ groupId>
< artifactId> servlet-api</ artifactId>
< version> 2.4</ version>
< scope> provided</ scope> </ dependency>
< dependency>
< groupId> org.apache.httpcomponents</ groupId>
< artifactId> httpclient</ artifactId>
< version> 4.5.12</ version>
</ dependency>
在lagou包下,创建wx包,并在里面创建WxLoginController类:
package com. lagou. wx ;
import org. springframework. web. bind. annotation. GetMapping ;
import org. springframework. web. bind. annotation. RestController ;
import javax. servlet. http. HttpServletRequest ;
@RestController
public class WxLoginController {
@GetMapping ( "wxlogin" )
public Object wxlogin ( HttpServletRequest request) {
String code = request. getParameter ( "code" ) ;
System . out. println ( "【临时凭证】code=" + code) ;
return null ;
}
}
记得观察对应扫描包时,是否包括这个包,否则相当于没有写(不会跳转)
< dubbo: annotation package = " com.lagou.controller,com.lagou.wx" />
这时我们进行扫描二维码(点击登录的框框中的微信图形,用手机扫描一下二维码,点击允许
在后端观看是否得到code的数据,若得到,则操作成功
注意:对应的不同的浏览器可能会有对应的问题(如谷歌,若出现问题,可以换一个浏览器)
特别是新的版本,现在一般会有,具体的问题在后面说明
至此我们最后来操作code这个临时数据(临时授权码或者临时凭证):
在程序上进行发送请求(这里是java):
在对应的web层项目上的java资源文件下,创建包commons,并在里面创建HttpClientUtil类:
package commons ;
import org. apache. http. client. methods. CloseableHttpResponse ;
import org. apache. http. client. methods. HttpGet ;
import org. apache. http. client. utils. URIBuilder ;
import org. apache. http. impl. client. CloseableHttpClient ;
import org. apache. http. impl. client. HttpClients ;
import org. apache. http. util. EntityUtils ;
import java. net. URI ;
import java. util. Map ;
public class HttpClientUtil {
public static String doGet ( String url) {
String s = doGet ( url, null ) ;
return s;
}
public static String doGet ( String url, Map < String , String > param) {
CloseableHttpClient aDefault = HttpClients . createDefault ( ) ;
String s = null ;
CloseableHttpResponse response = null ;
try {
URIBuilder uriBuilder = new URIBuilder ( url) ;
if ( param!= null ) {
for ( String key: param. keySet ( ) ) {
uriBuilder. addParameter ( key, param. get ( key) ) ;
}
}
URI uri = uriBuilder. build ( ) ;
HttpGet httpGet = new HttpGet ( uri) ;
response = aDefault. execute ( httpGet) ;
int statusCode = response. getStatusLine ( ) . getStatusCode ( ) ;
System . out. println ( response) ;
System . out. println ( "响应的状态:" + response. getStatusLine ( ) ) ;
System . out. println ( "响应的状态:" + statusCode) ;
if ( statusCode== 200 ) {
System . out. println ( response. getEntity ( ) ) ;
System . out. println ( "---" ) ;
s = EntityUtils . toString ( response. getEntity ( ) , "UTF-8" ) ;
System . out. println ( s) ;
System . out. println ( "---" ) ;
System . out. println ( 1 ) ;
}
} catch ( Exception e) {
e. printStackTrace ( ) ;
} finally {
try {
if ( response != null ) {
response. close ( ) ;
}
aDefault. close ( ) ;
} catch ( Exception e) {
e. printStackTrace ( ) ;
}
}
return s;
}
}
对应后端代码:
@GetMapping ( "wxlogin" )
public Object wxlogin ( HttpServletRequest request) {
String code = request. getParameter ( "code" ) ;
System . out. println ( "【临时凭证】code=" + code) ;
String getTokenByCode_url =
"https: / / api. weixin. qq. com/ sns/ oauth2/ access_token?
appid= wxd99431bbff8305a0& secret= 60f 78681d 063590 a469f1b297feff3c4& code= "+
code+ "&grant_type=authorization_code" ;
String tokenString = HttpClientUtil . doGet ( getTokenByCode_url) ;
System . out. println ( tokenString) ;
return null ;
}
扫描二维码允许后,就得到对应的json字符串
对应格式化之后是如下:
{
"access_token" : "59_Fvw_sDU0rnO6tuTiWrP4kONaE41_Fh9oJ5GyNLvrggiINj4WrZyIddJiwSgoaM2dnk1Ds9vshnTP-Wae3UaVzIz3V1giTrbkjU041nXjhRg" ,
"expires_in" : 7200 ,
"refresh_token" : "59_4V4PgKjvJ3JAGgRAH46VwqelRNNNgQ2-6FU48jtR98DgTWFWnVuFCMWgN0v5bI1DZ-VCL7a7IVP36dVddV-jkFlZVpLXPj3IW_Zys5P5Z6k" ,
"openid" : "od4PTw7JYdV2XYGkJPPqF4nZvlfA" ,
"scope" : "snsapi_login" ,
"unionid" : "oEg8VuHZxBTgpzcrTi3rAEvwsU88"
}
查看对应的微信官方文档中,是否是正确的格式:
对比发现,的确是是正确的,至此得到对应的token令牌成功(字符串有令牌参数及其值,简称为token字符串),即操作成功
接下来我们通过token字符串来获得微信用户的信息
在这之前我们需要先创建一个类:
在java资源文件夹下,创建entity包,并在里面创建Token类:
package entity ;
public class Token {
private String access_token;
private String expires_in;
private String refresh_token;
private String openid;
private String scope;
private String unionid;
public Token ( ) {
}
public Token ( String access_token, String expires_in, String refresh_token, String openid,
String scope, String unionid) {
this . access_token = access_token;
this . expires_in = expires_in;
this . refresh_token = refresh_token;
this . openid = openid;
this . scope = scope;
this . unionid = unionid;
}
@Override
public String toString ( ) {
return "Token{" +
"xxx'" + access_token + '\'' +
", expires_in='" + expires_in + '\'' +
", refresh_token='" + refresh_token + '\'' +
", openid='" + openid + '\'' +
", scope='" + scope + '\'' +
", unionid='" + unionid + '\'' +
'}' ;
}
public String getAccess_token ( ) {
return access_token;
}
public void setAccess_token ( String access_token) {
this . access_token = access_token;
}
public String getExpires_in ( ) {
return expires_in;
}
public void setExpires_in ( String expires_in) {
this . expires_in = expires_in;
}
public String getRefresh_token ( ) {
return refresh_token;
}
public void setRefresh_token ( String refresh_token) {
this . refresh_token = refresh_token;
}
public String getOpenid ( ) {
return openid;
}
public void setOpenid ( String openid) {
this . openid = openid;
}
public String getScope ( ) {
return scope;
}
public void setScope ( String scope) {
this . scope = scope;
}
public String getUnionid ( ) {
return unionid;
}
public void setUnionid ( String unionid) {
this . unionid = unionid;
}
}
创建User类:
package entity ;
public class User {
private String openid;
private String nickname;
private String sex;
private String province;
private String city;
private String country;
private String headimgurl;
private String privilege;
private String unionid;
public User ( ) {
}
public User ( String openid, String nickname, String sex, String province, String city, String
country, String headimgurl, String privilege, String unionid) {
this . openid = openid;
this . nickname = nickname;
this . sex = sex;
this . province = province;
this . city = city;
this . country = country;
this . headimgurl = headimgurl;
this . privilege = privilege;
this . unionid = unionid;
}
@Override
public String toString ( ) {
return "User{" +
"openid='" + openid + '\'' +
", nickname='" + nickname + '\'' +
", sex='" + sex + '\'' +
", province='" + province + '\'' +
", city='" + city + '\'' +
", country='" + country + '\'' +
", headimgurl='" + headimgurl + '\'' +
", privilege='" + privilege + '\'' +
", unionid='" + unionid + '\'' +
'}' ;
}
public String getOpenid ( ) {
return openid;
}
public void setOpenid ( String openid) {
this . openid = openid;
}
public String getNickname ( ) {
return nickname;
}
public void setNickname ( String nickname) {
this . nickname = nickname;
}
public String getSex ( ) {
return sex;
}
public void setSex ( String sex) {
this . sex = sex;
}
public String getProvince ( ) {
return province;
}
public void setProvince ( String province) {
this . province = province;
}
public String getCity ( ) {
return city;
}
public void setCity ( String city) {
this . city = city;
}
public String getCountry ( ) {
return country;
}
public void setCountry ( String country) {
this . country = country;
}
public String getHeadimgurl ( ) {
return headimgurl;
}
public void setHeadimgurl ( String headimgurl) {
this . headimgurl = headimgurl;
}
public String getPrivilege ( ) {
return privilege;
}
public void setPrivilege ( String privilege) {
this . privilege = privilege;
}
public String getUnionid ( ) {
return unionid;
}
public void setUnionid ( String unionid) {
this . unionid = unionid;
}
}
接下来继续修改对应的后端:
@GetMapping ( "wxlogin" )
public Object wxlogin ( HttpServletRequest request) {
String code = request. getParameter ( "code" ) ;
System . out. println ( "【临时凭证】code=" + code) ;
String getTokenByCode_url =
"https: / / api. weixin. qq. com/ sns/ oauth2/ access_token?
appid= wxd99431bbff8305a0& secret= 60f 78681d 063590 a469f1b297feff3c4& code= "+
code+ "&grant_type=authorization_code" ;
String tokenString = HttpClientUtil . doGet ( getTokenByCode_url) ;
System . out. println ( tokenString) ;
Token token = JSON . parseObject ( tokenString, Token . class ) ;
String getUserByToken =
"https://api.weixin.qq.com/sns/userinfo?access_token=" + token. getAccess_token ( ) +
"&openid=" + token. getOpenid ( ) ;
System . out. println ( "----------------------" ) ;
String UserString = HttpClientUtil . doGet ( getUserByToken) ;
System . out. println ( "UserString = " + UserString ) ;
User user = JSON . parseObject ( UserString , User . class ) ;
System . out. println ( "微信的用户昵称 = " + user. getNickname ( ) ) ;
System . out. println ( "微信的用户头像 = " + user. getHeadimgurl ( ) ) ;
return null ;
}
至此微信用户的信息就得到了,比如说"nickname":“king”,其中king就是我微信的名称
当然一些值是0或者是""的,则是我们微信并没有设置的,或者是默认的,也有可能需要其他方式才可获得,但这里并不需要理会
接下来我们修改对应的注册逻辑:
dao层:
Integer register ( @Param ( "phone" ) String phone, @Param ( "password" ) String
Password , @Param ( "nickname" ) String nickname, @Param ( "headimg" ) String headimg) ;
service层:
Integer register ( String phone, String Password , String nickname, String headimg) ;
@Override
public Integer register ( String phone, String Password , String nickname, String headimg) {
Integer register = userDao. register ( phone, Password , nickname, headimg) ;
return register;
}
web层:
Intege
对应的UserController类的ogin方法:
@GetMapping ( "login" )
public UserDTO login ( String phone, String password, String nickname, String headimg) {
UserDTO userDTO = new UserDTO < > ( ) ;
System . out. println ( phone) ;
System . out. println ( password) ;
System . out. println ( nickname) ;
System . out. println ( headimg) ;
User login = null ;
Integer integer = userService. checkPhone ( phone) ;
if ( integer == 0 ) {
userService. register ( phone, password, nickname, headimg) ;
userDTO. setMessage ( "手机号尚未注册,系统已帮您自动注册,请牢记密码!" ) ;
login = userService. login ( phone, password) ;
} else {
login = userService. login ( phone, password) ;
if ( login != null ) {
userDTO. setState ( 200 ) ;
userDTO. setMessage ( "登录成功" ) ;
} else {
userDTO. setState ( 300 ) ;
userDTO. setMessage ( "登录失败" ) ;
}
}
userDTO. setContent ( login) ;
System . out. println ( login) ;
return userDTO;
}
改变后,对应的xml配置文件也进行改变:
< insert id = " register" parameterType = " string" >
insert into user
(name,portrait,phone,password,create_time,update_time)
values
(#{nickname},#{headimg},#{phone},#{password},sysdate(),sysdate())
</ insert>
至此我们运行对应的测试类TestUser里的register方法:
@Test
public void register ( ) {
Integer integer = userDao. register ( "11544" , "123123" , "1" , "2" ) ;
System . out. println ( integer) ;
}
若数据库有对应的数据,则修改成功
对应的部分前端代码(Header.vue组件里面的代码):
return this . axios. get ( "http://localhost:8002/user/login" , {
params : {
phone : this . phone,
password : this . password,
nickname : "" ,
headimg : "" ,
}
} ) . then ( res => {
至此测试登录,随便写一个没有的,登录后,会自动注册,并登录,然后去数据库看看是否有对应数据,若有,则操作成功
我们在对应的wxlogin方法里添加如下代码:
System . out. println ( "微信的unionid参数值:" + user. getUnionid ( ) ) ;
return "user/login?phone=" + user. getUnionid ( ) + "&password="
+ user. getUnionid ( ) + "&nickname=" + user. getNickname ( ) + "&headimg=" + user. getHeadimgurl ( ) ;
至此启动对应的项目,并在前端扫描二维码进行登录,若返回了对应的数据,且数据库里也有对应数据,则登录成功
且你会发现,对应的url那里前端进行了访问,但后端的对应的请求并没有显示出来
也就是不依靠浏览器的显示了,安全性的确提高
但是对应的使用return会到其他的方法里面去,实际上我们操作该方法后,需要跳转到原来的前端页面
至此对应的wxlogin方法要进行改变,但对应的数据并不会得到,所以我们需要修改WxLoginController类:
package com. lagou. wx ;
import com. alibaba. dubbo. config. annotation. Reference ;
import com. alibaba. fastjson. JSON ;
import com. lagou. entity. UserDTO ;
import com. lagou. service. UserService ;
import commons. HttpClientUtil ;
import entity. Token ;
import entity. User ;
import org. springframework. web. bind. annotation. GetMapping ;
import org. springframework. web. bind. annotation. RestController ;
import javax. servlet. http. HttpServletRequest ;
import javax. servlet. http. HttpServletResponse ;
import java. io. IOException ;
@RestController
public class WxLoginController {
@Reference
private UserService userService;
private UserDTO userDTO = null ;
@GetMapping ( "wxlogin" )
public UserDTO wxlogin ( HttpServletRequest request, HttpServletResponse response) throws
IOException {
String code = request. getParameter ( "code" ) ;
System . out. println ( "【临时凭证】code=" + code) ;
String getTokenByCode_url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=wxd99431bbff8305a0&secret=60f78681d063590a469f1b297feff3c4&code=" + code + "&grant_type=authorization_code" ;
String tokenString = HttpClientUtil . doGet ( getTokenByCode_url) ;
System . out. println ( tokenString) ;
Token token = JSON . parseObject ( tokenString, Token . class ) ;
String getUserByToken = "https://api.weixin.qq.com/sns/userinfo?access_token=" +
token. getAccess_token ( ) + "&openid=" + token. getOpenid ( ) ;
System . out. println ( "----------------------" ) ;
String UserString = HttpClientUtil . doGet ( getUserByToken) ;
System . out. println ( "UserString = " + UserString ) ;
User user = JSON . parseObject ( UserString , User . class ) ;
System . out. println ( "微信的用户昵称 = " + user. getNickname ( ) ) ;
System . out. println ( "微信的用户头像 = " + user. getHeadimgurl ( ) ) ;
System . out. println ( "微信的unionid参数值:" + user. getUnionid ( ) ) ;
userDTO = new UserDTO < > ( ) ;
com. lagou. entity. User login = null ;
Integer integer = userService. checkPhone ( user. getUnionid ( ) ) ;
if ( integer == 0 ) {
userService. register ( user. getUnionid ( ) , user. getUnionid ( ) , user. getNickname ( ) ,
user. getHeadimgurl ( ) ) ;
userDTO. setMessage ( "手机号尚未注册,系统已帮您自动注册,请牢记密码!" ) ;
login = userService. login ( user. getUnionid ( ) , user. getUnionid ( ) ) ;
} else {
login = userService. login ( user. getUnionid ( ) , user. getUnionid ( ) ) ;
if ( login != null ) {
userDTO. setState ( 200 ) ;
userDTO. setMessage ( "登录成功" ) ;
} else {
userDTO. setState ( 300 ) ;
userDTO. setMessage ( "登录失败" ) ;
}
}
userDTO. setContent ( login) ;
response. sendRedirect ( "http://localhost:8080/" ) ;
return null ;
}
@GetMapping ( "checkWXStatus" )
public UserDTO checkWXStatus ( ) {
return userDTO;
}
@GetMapping ( "logout" )
public Object logout ( ) {
userDTO = null ;
return null ;
}
}
对应的前端Header.vue:
created ( ) {
console. log ( JSON . parse ( localStorage. getItem ( "user" ) ) ) ;
this . userDTO = JSON . parse ( localStorage. getItem ( "user" ) ) ;
console. log ( this . userDTO)
if ( this . userDTO != null ) {
this . isLogin = true
} else {
return this . axios. get ( "http://localhost:80/checkWXStatus" ) . then ( res => {
console. log ( 22 )
console. log ( res)
this . userDTO = res. data
if ( this . userDTO!= "" ) {
this . phone = this . userDTO. content. phone
this . password = this . userDTO. content. password
this . login ( )
}
} ) . catch ( err => {
this . $message. error ( "登录失败" )
} )
}
} ,
logout ( ) {
localStorage. setItem ( "user" , null )
this . isLogin = false
return this . axios. get ( "http://localhost:80/logout" ) . then ( res => {
this . $router. push ( "/" ) ;
window. location. reload ( )
alert ( "已登出" )
} ) . catch ( err => {
this . $message. error ( "登出失败" )
} )
alert ( 1 )
}
我们可以发现,对应的端口都是80(虽然也可以是其他端口),但最好相同,因为他们都是得到和设置值
需要在一个服务器里面操作(可以说,一个端口代表一个服务器的运行)
至此我们扫描二维码进行操作,若有对应的信息(登录那里),则微信登录完成
在前面应该说过,微信的扫描二维码并允许后,可能会出现浏览器的问题(一般是谷歌)
解决二维码在谷歌浏览器的bug :
通过官方js:http://res.wx.qq.com/connect/zh_CN/htmledition/js/wxLogin.js
可以知道,对应的二维码是放在iframe标签下的,但是一般新版本的谷歌可能并没有设置跨域问题
旧版的谷歌却可以(但不一定)也就是如下:
为什么不能让他跨域呢,因为是安全问题,iframe可以内嵌其他网页,而对应的网页我们却无法控制
也就是说,若该网页是恶意的网站,那么对应用户来说是非常危险的,所以一般会让他不能跨域
sandbox包含的属性及作用:
加上 sandbox="allow-scripts allow-top-navigation allow-same-origin"属性
即可解决官方js:http://res.wx.qq.com/connect/zh_CN/htmledition/js/wxLogin.js
由于基本无法修改微信服务器上的js文件,所以我们将js代码放在本地并进行修改(复制上面官方的js):
created ( ) {
! ( function ( a, b, c ) {
function d ( a ) {
var c = "default" ;
a. self_redirect === ! 0
? ( c = "true" )
: a. self_redirect === ! 1 && ( c = "false" ) ;
var d = b. createElement ( "iframe" ) ,
e =
"https://open.weixin.qq.com/connect/qrconnect?appid=" +
a. appid +
"&scope=" +
a. scope +
"&redirect_uri=" +
a. redirect_uri +
"&state=" +
a. state +
"&login_type=jssdk&self_redirect=" +
c +
"&styletype=" +
( a. styletype || "" ) +
"&sizetype=" +
( a. sizetype || "" ) +
"&bgcolor=" +
( a. bgcolor || "" ) +
"&rst=" +
( a. rst || "" ) ;
( e += a. style ? "&style=" + a. style : "" ) ,
( e += a. href ? "&href=" + a. href : "" ) ,
( d. src = e) ,
( d. frameBorder = "0" ) ,
( d. allowTransparency = "true" ) ,
( d. sandbox = "allow-scripts allow-top-navigation allow-same-origin" ) ,
( d. scrolling = "no" ) ,
( d. width = "300px" ) ,
( d. height = "400px" ) ;
var f = b. getElementById ( a. id) ;
( f. innerHTML = "" ) , f. appendChild ( d) ;
}
a. WxLogin = d;
} ) ( window, document) ;
}
我们直接将该代码放到对应的created()的钩子函数里面,使得操作我们自己的js,而不使用官方的
将对应的引入的注释:
组件也不同声明了:
components : {
} ,
对应的html也注释掉:
实际上对应的组件操作也是封装了二维码js的执行,我们可以直接自己定义来保存二维码:
< div id = " wxLoginForm" > </ div>
接下来我们找到对应的方法,因为组件操作了对应二维码的生成,和一些属性
但我们自己定义的,需要自己进行操作,这里当然是默认没有的,因为什么都没有操作,看如下代码:
goToLoginWX ( ) {
document. getElementById ( "loginForm" ) . style. display= "none"
this . $nextTick ( function ( ) {
this . createCode ( ) ;
} ) ;
} ,
createCode ( ) {
var obj = new WxLogin ( {
id : "wxLoginForm" ,
appid : "wxd99431bbff8305a0" ,
scope : "snsapi_login" ,
redirect_uri : "http://www.pinzhi365.com/wxlogin" ,
} )
} ,
至此,浏览器的问题就解决了,我们发现,对应的js实际上就是直接设置iframe的属性
可以得知,浏览器可能会给该标签默认设置其他不跨域的属性,所以需要我们手动设置,使得不操作默认
若我们需要修改二维码的样式,可以添加如下代码:
.impowerBox .qrcode { width : 200px; }
.impowerBox .title { display : none; }
.impowerBox .info { width : 200px; }
.status_icon { display : none} cs
.impowerBox .status { text-align : center; }
但是实际上要操作该样式,在对应的参数下面基本不能这样的写,因为{}不能对json格式不对,如:
href : "
. impowerBox . qrcode { width : 200px; }
. impowerBox . title { display : none; }
. impowerBox . info { width : 200px; }
. status_icon { display : none} cs
. impowerBox . status { text- align: center; }
"
那么如何使得可以操作对应的样式呢,我们可以在对应的WxLogin对象中(方法里的操作)
直接传递href值,由于该值会被请求的地址服务器解析(二维码的显示的请求)
使得进行对应的操作显示,而该解析我们需要对应的加密,这是规定的,因为对应地址服务的解析时,会解密进行操作
我们用站长工具对样式代码进行base64加密:http://tool.chinaz.com/Tools/Base64.aspx
LmltcG93ZXJCb3ggLnFyY29kZSB7d2lkdGg6IDIwMHB4O30NCi5pbXBvd2VyQm94IC50aXRsZSB7ZGlzcGxheTogbm9uZTt9DQouaW1wb3dlckJveCAuaW5mbyB7d2lkdGg6IDIwMHB4O30NCi5zdGF0dXNfaWNvbiB7ZGlzcGxheTogbm9uZX1jcw0KLmltcG93ZXJCb3ggLnN0YXR1cyB7dGV4dC1hbGlnbjogY2VudGVyO30=
这时,对应的js代码是:
var obj = new WxLogin ( {
id : "wxLoginForm" ,
appid : "wxd99431bbff8305a0" ,
scope : "snsapi_login" ,
redirect_uri : "http://www.pinzhi365.com/wxlogin" ,
href : "data:text/css;base64,LmltcG93ZXJCb3ggLnFyY29kZSB7d2lkdGg6IDIwMHB4O30NCi5pbXBvd2VyQm94IC50aXRsZSB7ZGlzcGxheTogbm9uZTt9DQouaW1wb3dlckJveCAuaW5mbyB7d2lkdGg6IDIwMHB4O30NCi5zdGF0dXNfaWNvbiB7ZGlzcGxheTogbm9uZX1jcw0KLmltcG93ZXJCb3ggLnN0YXR1cyB7dGV4dC1hbGlnbjogY2VudGVyO30="
} )
这时我们再次看看二维码,发现二维码变小的,至此样式也操作成功
我们操作完了微信的登录,接下来我们操作微信的支付:
创建二维码:
安装 qrcodejs2 (注意:安装的是qrcodejs2,不要安装qrcode —> 会报错),主要报错原因是
可能是因为二维码生成的错误,即生成不了二维码,即后面的new QRCode这个地方报错,类似于(相当于)某些语法错误一样
比如 alert(u),这个u不存在,也会使得报错,而这样的报错,自然会到catch里面执行
即如果操作了qrcode ,那么后面的代码就会执行this.$message.error(“生成二维码失败!”);
当然,你安装后不使用也可以,具体可以自己测试,只要是导入了qrcodejs2即可
即import QRCode from ‘qrcodejs2’;即可,所以qrcode 可以安装,但没有必要,因为这里并没有使用他
npm install qrcodejs2 --save
在Course.vue组件的页面中引入:
< el-dialog :visible.sync = " dialogFormVisible" style = " width : 800px; margin : 0px auto; " >
< h1 style = " font-size : 30px; color : #00B38A" > 微信扫一扫支付</ h1>
< div id = " qrcode" style = " width : 210px; margin : 20px auto; " > </ div>
</ el-dialog>
data ( ) {
return {
comment : null ,
activeName : "intro" ,
course : null ,
totalLessons : 0 ,
commentList : null ,
isLogin : false ,
isBuy : false ,
user : null ,
myCourseList : [ ] ,
dialogFormVisible : false
} ;
< script>
import Header from "./Header/Header" ;
import Footer from "./Footer/index" ;
import QRCode from 'qrcodejs2' ;
export default {
name : "Course" ,
components : {
Header,
Footer,
QRCode
} ,
这里有个问题,前面的操作问题
if ( this . user != null ) {
this . isLogin = true
if ( this . course!= null ) {
this . getMyCourseList ( )
}
this . getComment ( ) ;
}
buy ( courseid ) {
this . dialogFormVisible = true ;
this . $nextTick ( function ( ) {
this . createCode ( )
} ) ;
} ,
createCode ( ) {
document. getElementById ( "qrcode" ) . innerHTML = "" ;
let qrcode = new QRCode ( "qrcode" , {
width : 200 ,
height : 200 ,
text : "我爱你中国"
} ) ;
} ,
至此,点击立即购买,发现,对应的二维码出来了,用微信扫描,就会出现设置的信息"我爱你中国",至此二维码显示操作完毕
准备工作:
名词介绍:
如果获得这些信息,需要注册认证公众号,费用300元/次
获取认证的流程 :
注册公众号(类型:服务号) ,或者微信开发平台操作的网站(如企业),这里就操作公众号了
根据营业执照类型选择以下主体注册:个体工商户 | 企业/公司 | 政府 | 媒体 | 其他类型
认证公众号:
公众号认证后才基本可以去申请微信支付:300元/次
提交材料申请微信支付 :
登录公众平台,左侧菜单【微信支付】,开始填写资料等待审核,审核时间1~5工作日这里需要提交的资料有营业执照
开户成功,登录商户平台进行验证:
资料审核通过后,请登录联系人邮箱查收商户号和密码,并登录商户平台填写财付通备付金打的小额资金数额,完成账户验证
在线签署协议:
本协议为线上电子协议,签署后方可进行交易及资金结算,签署完立即生效
查看自己的公众号的参数 :
测试的数据,一般不能操作,下面只是用来看的,让你知道需要哪些数据
即当你使用下面的信息时,一个返回的数据中会说明签名错误,因为没有对应数据(如appid,企业一般是corpid,对应于appid)
他们一般是微信公众号和企业微信,都是微信,因为使用微信支付总得是微信吧
所以到这里,后面的可以进行了解 ,当你有对应企业的这些数据时或者微信公众号的这些数据时(自己进行申请)
可以回到这里再次查看进行操作:
public class PayConfig {
public static String appid = "wx8397f8696b538317" ;
public static String partner = "1473426802" ;
public static String partnerKey = "8A627A4578ACE384017C997F12D68B23" ;
public static String notifyurl = "http://a31ef7db.ngrok.io/WeChatPay/WeChatPayNotify" ;
}
支付流程:
工具介绍:
SDK(软开开发工具包,也有对应的其他介绍,如API列表):
https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=11_1
如果不是maven项目,一般需要下载对应的jar包,若是maven项目,则引入依赖即可
对应的依赖:
< dependency>
< groupId> com.github.wxpay</ groupId>
< artifactId> wxpay-sdk</ artifactId>
< version> 0.0.3</ version>
</ dependency>
主要使用sdk中的三个功能:
获取随机字符串(生成订单编号):
WXPayUtil . generateNonceStr ( ) ;
将map转换成xml字符串(自动添加签名,对应给微信支付的信息一般需要是xml信息):
WXPayUtil . generateSignedXml ( map, partnerKey) ;
将xml字符串转换整map:
WXPayUtil . xmlToMap ( result) ;
JFinal 框架:
JFinal 是基于Java 语言的极速 web 开发框架
其核心设计目标是开发迅速、代码量少、学习简单、功能强大、轻量级、易扩展
基本可以取代HttpClient(拥有后面的特殊的请求,比如加上了对应的xml格式的字符串,该字符串通常是用来作为参数的,所以用法多点),所以可以不使用HttpClient,而只使用JFinal (前面的就可以进行改变,当然这里就不改变了)
对应的依赖:
< dependency>
< groupId> com.jfinal</ groupId>
< artifactId> jfinal</ artifactId>
< version> 3.5</ version>
</ dependency>
构建二维码 :
外面需要将对应的支付连接放在二维码里面
在Course.vue组件里面:
createCode ( ) {
document. getElementById ( "qrcode" ) . innerHTML = "" ;
this . axios. get ( "http://localhost:80/createCode" , {
params : {
courseid : this . course. id,
coursename : this . course. courseName,
price : this . course. discounts
}
} ) . then ( res => {
console. log ( res)
let qrcode = new QRCode ( "qrcode" , {
width : 200 ,
height : 200 ,
text : res
} ) ;
} ) . catch ( err => {
this . $message. error ( "生成二维码失败" )
} )
} ,
在web层项目下的commons包下创建实体类PayConfig:
package commons ;
public class PayConfig {
public static String appid = "wx8397f8696b538317" ;
public static String partner = "1473426802" ;
public static String partnerKey = "8A627A4578ACE384017C997F12D68B23" ;
public static String notifyurl = "http://a31ef7db.ngrok.io/WeChatPay/WeChatPayNotify" ;
}
该类先放在这里,后面有可能会再次进行操作(如修改数值,虽然并不会)
在对应的web层项目中的wx包下,创建WxPayController类:
package com. lagou. wx ;
import com. github. wxpay. sdk. WXPayConfig ;
import com. github. wxpay. sdk. WXPayUtil ;
import com. jfinal. kit. HttpKit ;
import commons. PayConfig ;
import org. springframework. web. bind. annotation. GetMapping ;
import org. springframework. web. bind. annotation. RestController ;
import java. util. HashMap ;
import java. util. Map ;
@RestController
public class WxPayController {
@GetMapping ( "createCode" )
public Object createCode ( String courseid, String coursename, String price) throws Exception {
Map < String , String > map = new HashMap < > ( ) ;
map. put ( "appid" , PayConfig . appid) ;
map. put ( "mch_id" , PayConfig . partner) ;
map. put ( "nonce_str" , WXPayUtil . generateNonceStr ( ) ) ;
map. put ( "body" , coursename) ;
map. put ( "out_trade_no" , WXPayUtil . generateNonceStr ( ) ) ;
map. put ( "total_fee" , price) ;
map. put ( "spbill_create_ip" , "127.0.0.1" ) ;
map. put ( "notify_url" , PayConfig . notifyurl) ;
map. put ( "trade_type" , "NATIVE" ) ;
System . out. println ( "商户信息:" + map) ;
String xml = WXPayUtil . generateSignedXml ( map, PayConfig . partnerKey) ;
System . out. println ( "商户的xml信息:" + xml) ;
String url = "https://api.mch.weixin.qq.com/pay/unifiedorder" ;
String post = HttpKit . post ( url, xml) ;
System . out. println ( post) ;
Map < String , String > map1 = WXPayUtil . xmlToMap ( post) ;
System . out. println ( map1) ;
return map1;
}
}
对应的Course.vue:
let qrcode = new QRCode ( "qrcode" , {
width: 200 ,
height: 200 ,
text: res. data. code_url
} ) ;
这时打开你的手机,扫描对应的二维码,我的出现如下:
100分也就是1.00元
至此若出现如上的操作,那么说明链接正确,即操作完成
但是我们会发现有对应的乱码,对应解决方法:
coursename = new String ( coursename. getBytes ( "ISO-8859-1" ) , "UTF-8" ) ;
与前面的操作(好像是上一章的操作)一样,操作完成后,那么应该会出现如下(我这里是):
至此中文乱码解决
检查支付状态:
在这之前,我们需要修改一下对应后端的代码:
Map < String , String > map1 = WXPayUtil . xmlToMap ( post) ;
map1. put ( "orderId" , map. get ( "out_trade_no" ) ) ;
对应的前端(Course.vue):
createCode ( ) {
document. getElementById ( "qrcode" ) . innerHTML = "" ;
this . axios. get ( "http://localhost:80/createCode" , {
params : {
courseid : this . course. id,
coursename : this . course. courseName,
price : this . course. discounts
}
} ) . then ( res => {
let qrcode = new QRCode ( "qrcode" , {
width : 200 ,
height : 200 ,
text : res. data. code_url
} ) ;
this . axios. get ( "http://localhost:80/checkOrderStatus" , {
params : {
orderId : res. data. orderId
}
} ) . then ( res => {
} ) . catch ( err => {
this . $message. error ( "查询订单状态失败" )
} )
} ) . catch ( err => {
this . $message. error ( "生成二维码失败" )
} )
} ,
对应的后端:
@GetMapping ( "checkOrderStatus" )
public Object createCode ( String orderId) throws Exception {
Map < String , String > map = new HashMap < > ( ) ;
map. put ( "appid" , PayConfig . appid) ;
map. put ( "mch_id" , PayConfig . partner) ;
map. put ( "out_trade_no " , orderId) ;
map. put ( "nonce_str" , WXPayUtil . generateNonceStr ( ) ) ;
String xml = WXPayUtil . generateSignedXml ( map, PayConfig . partnerKey) ;
String url = "https://api.mch.weixin.qq.com/pay/orderquery" ;
String post = HttpKit . post ( url, xml) ;
Map < String , String > map1 = WXPayUtil . xmlToMap ( post) ;
return map1;
}
至此,我们点击二维码,不需要扫描,执行对应的方法
在对应的map集合中可以获得对应的状态(一般是订单未支付,一般保存在trade_state_desc字段)
对于状态的判断,我们一般需要在后端进行如下的编写,前面分析过
我们的支付成功与否,对应修改对应的编号的状态,所以我们需要循环获取:
String url = "https://api.mch.weixin.qq.com/pay/orderquery" ;
long l = System . currentTimeMillis ( ) ;
while ( true ) {
String post = HttpKit . post ( url, xml) ;
Map < String , String > map1 = WXPayUtil . xmlToMap ( post) ;
if ( map1. get ( "trade_state" ) . equalsIgnoreCase ( "SUCCESS" ) ) {
return map1;
}
if ( System . currentTimeMillis ( ) - l> 30 * 1000 ) {
return map1;
}
Thread . sleep ( 3000 ) ;
}
上面如果在30秒内支付成功,那对应前端界面会显示出来你已经支付
但是如果30秒内没有支付或者没有支付成功,前端界面会显示未支付
一般的我们会重新生成二维码,或者对应过期时间设置为二维码的过期时间
防止在前端返回未支付的情况下,可以支付,操作对应数据的不合理,甚至会购买不上
对应的前端:
< el-dialog :visible.sync = " dialogFormVisible" style = " width : 800px; margin : 0px auto; " >
< h1 style = " font-size : 30px; color : #00B38A" > 微信扫一扫支付</ h1>
< div id = " qrcode" style = " width : 210px; margin : 20px auto; " > </ div>
< h2 id = " statusText" > </ h2>
</ el-dialog>
this . axios. get ( "http://localhost:80/checkOrderStatus" , {
params : {
orderId : res. data. orderId
}
} ) . then ( res => {
console. log ( res)
if ( res. data. trade_state== "SUCCESS" ) {
document. getElementById ( "statusText" ) . innerHTML=
"<i style='color:#00B38A' class='el-icon-success'></i> 支付成功"
}
} ) . catch ( err => {
this . $message. error ( "查询订单状态失败" )
} )
至此可以扫描二维码,进行支付,发现,出现对应的样式,显示支付成功
当你再次扫描时一般会提示已经操作(因为一个已经支付的二维码一般是会销毁的,可能有些情况下会继续支付)
至此,微信支付完成
接下来操作关闭二维码:
< el-dialog :visible.sync = " dialogFormVisible" style = " width : 800px; margin : 0px auto; " >
< h1 style = " font-size : 30px; color : #00B38A" > 微信扫一扫支付</ h1>
< div id = " qrcode" style = " width : 210px; margin : 20px auto; " > </ div>
< h2 id = " statusText" > </ h2>
< p id = " closeTest" > </ p>
</ el-dialog>
data ( ) {
return {
comment : null ,
activeName : "intro" ,
course : null ,
totalLessons : 0 ,
commentList : null ,
isLogin : false ,
isBuy : false ,
user : null ,
myCourseList : [ ] ,
dialogFormVisible : false ,
time : null ,
} ;
} ,
console. log ( res)
if ( res. data. trade_state== "SUCCESS" ) {
document. getElementById ( "statusText" ) . innerHTML=
"<i style='color:#00B38A' class='el-icon-success'></i> 支付成功"
this . saveOrder ( ) ;
let s = 3 ;
this . closeQRForm ( s)
}
修改web层项目的对应的OrderController类的saveOrder方法:
@GetMapping ( "saveOrder/{userid}/{courseid}/{acid}/{stype}" )
public String saveOrder ( String orderNo, @PathVariable ( "userid" ) String userid,
@PathVariable ( "courseid" ) String courseid,
@PathVariable ( "acid" ) String acid, @PathVariable ( "stype" ) String stype) {
orderService. saveOrder ( orderNo, userid, courseid, acid, stype) ;
return orderNo;
}
给data加上对应的订单属性(这里就不全部写出来了):
orderNo : "" ,
let qrcode = new QRCode ( "qrcode" , {
width : 200 ,
height : 200 ,
text : res. data. code_url
} ) ;
this . orderNo = res. data. orderId;
this . axios. get ( "http://localhost:80/checkOrderStatus" , {
params : {
orderId : this . orderNo
}
saveOrder ( ) {
this . axios. get ( "http://localhost:8002/order/saveOrder/" + this . user. content. id+
"/" + this . course. id+ "/" + this . course. id+ "/1" , {
params : {
orderNo : this . orderNo
}
} ) . then ( res => {
console. log ( res)
} ) . catch ( err => {
this . $message. error ( "保存订单失败" )
} )
} ,
closeQRForm ( s ) {
let that = this ;
that. time = setInterval ( function ( ) {
document. getElementById ( "closeTest" ) . innerHTML = "(" + s-- + ")秒后关闭本窗口"
if ( s== 0 ) {
clearInterval ( that. time)
that. dialogFormVisible = false
that. isBuy = true ;
}
} , 1000 )
} ,
但是我们发现,对应的数据不对,因为订单中的status并不是20,使得还是试看,而不是播放
若还是播放,那么应该是设置了购买,或者已经购买
已经购买的话,一般保存订单会失败,即后端返回异常信息,使得前端报错
所以我们需要进行修改:
saveOrder ( ) {
this . axios. get ( "http://localhost:8002/order/saveOrder/" + this . user. content. id+
"/" + this . course. id+ "/" + this . course. id+ "/1" , {
params : {
orderNo : this . orderNo
}
} ) . then ( res => {
this . axios. get ( "http://localhost:8002/order/updateOrder/" + this . orderNo+ "/20" ) . then ( res => {
console. log ( res)
} ) . catch ( err => {
this . $message. error ( "设置订单状态失败" )
} )
} ) . catch ( err => {
this . $message. error ( "保存订单失败" )
} )
} ,
实际上对应的保存订单在查询支付状态里面,假如查询不了怎么办,那么订单也就不会生成,所以说
对应的订单应该在状态之前,而不会受任何影响,且是创建的订单
this . orderNo = res. data. orderId;
this . saveOrder ( ) ;
this . axios. get ( "http://localhost:80/checkOrderStatus" , {
if ( res. data. trade_state== "SUCCESS" ) {
document. getElementById ( "statusText" ) . innerHTML=
"<i style='color:#00B38A' class='el-icon-success'></i> 支付成功"
}
let s = 3 ;
this . closeQRForm ( s)
那么对应的保存订单中的设置20,就要进行位置变化了:
console. log ( res)
if ( res. data. trade_state== "SUCCESS" ) {
document. getElementById ( "statusText" ) . innerHTML=
"<i style='color:#00B38A' class='el-icon-success'></i> 支付成功"
this . axios. get ( "http://localhost:8002/order/updateOrder/" + this . orderNo+ "/20" ) . then ( res => {
console. log ( res)
} ) . catch ( err => {
this . $message. error ( "设置订单状态失败" )
} )
}
我们可以将对应的更新状态封装成一个函数:
updateOrder ( ss ) {
this . axios. get ( "http://localhost:8002/order/updateOrder/" + this . orderNo+ "/" + ss) . then ( res => {
console. log ( res)
} ) . catch ( err => {
this . $message. error ( "设置订单状态失败" )
} )
那么原来的可以这样写:
console. log ( res)
if ( res. data. trade_state== "SUCCESS" ) {
document. getElementById ( "statusText" ) . innerHTML=
"<i style='color:#00B38A' class='el-icon-success'></i> 支付成功"
this . updateOrder ( 20 )
}
至此可以进行测试,每次的购买后,去已购那里看看发现的确在那里了,且对应都是播放
但是这里有一个问题,如果是未支付的情况下,可能是有相同的保存,那么会报错
通过修改后端代码可以解决问题(在文章最后面)
若不修改后端代码,如何解决:
在查询支付状态里面可以解决此问题(位置没改变之前,就是这样,只是回来了而已)
因为和状态的设置是一起的(且是支付成功后的操作)
所以为了解决此问题,外面还是将对应的保存订单放回到对应的判断里面:
if ( res. data. trade_state== "SUCCESS" ) {
document. getElementById ( "statusText" ) . innerHTML=
"<i style='color:#00B38A' class='el-icon-success'></i> 支付成功"
this . saveOrder ( ) ;
}
saveOrder ( ) {
this . axios. get ( "http://localhost:8002/order/saveOrder/"
+ this . user. content. id+ "/" + this . course. id+ "/" + this . course. id+ "/1" , {
params: {
orderNo: this . orderNo
}
} ) . then ( res = > {
this . updateOrder ( 20 )
} ) . catch ( err = > {
this . $message. error ( "保存订单失败" )
} )
} ,
注意:这只是测试,实际情况下,外面需要修改对应的后端代码使得进行判断,而不是修改前端
因为该保存的订单也基本固定了20的状态,或者也可以将对应的方法加上参数,如:
this . saveOrder ( 20 ) ;
saveOrder ( ss ) {
this . axios. get ( "http://localhost:8002/order/saveOrder/"
+ this . user. content. id+ "/" + this . course. id+ "/" + this . course. id+ "/1" , {
params : {
orderNo : this . orderNo
}
} ) . then ( res => {
this . updateOrder ( ss)
} ) . catch ( err => {
this . $message. error ( "保存订单失败" )
} )
} ,
至此微信的操作完成
后端代码(修改后,就可以将保存方法放在查询状态外面,状态修改方法放在查询状态里面,他们都是单独的):
添加部分对应的OrderDap.xml:
< select id = " getOrder" resultMap = " UserCourseOrderMap" >
select * from user_course_order where user_id = #{user_id}
and course_id = #{course_id}
and source_type = #{source_type}
</ select>
对应的接口:
UserCourseOrder getOrder ( @Param ( "user_id" ) String user_id,
@Param ( "course_id" ) String course_id,
@Param ( "source_type" ) String source_type) ;
对应的service层的OrderServiceImpl实现类的saveOrder方法:
@Override
public void saveOrder ( String orderNo, String user_id,
String course_id, String activity_course_id, String source_type) {
UserCourseOrder order = orderDao. getOrder ( user_id, course_id, source_type) ;
System . out. println ( order) ;
if ( order == null ) {
orderDao. saveOrder ( orderNo, user_id, course_id, activity_course_id, source_type) ;
}
}
通过后端代码的编写,使得对应操作完成
这时候的前端可以是:
this . saveOrder ( ) ;
this . axios. get ( "http://localhost:80/checkOrderStatus" , {
params : {
orderId : this . orderNo
}
} ) . then ( res => {
console. log ( res)
if ( res. data. trade_state== "SUCCESS" ) {
document. getElementById ( "statusText" ) . innerHTML=
"<i style='color:#00B38A' class='el-icon-success'></i> 支付成功"
this . updateOrder ( 20 )
至此,微信的登录和微信的支付都操作完毕
但是要注意:除了在课程里购买,其他的地方的购买代码基本是类似的,即他们都是重复的代码
至此,并没有给出操作,可以自己进行尝试,还有些细节问题,可以自己进行查看,比如buy()方法,好像固定是7的参数
注意:当你的localhost被设置其他域名,虽然前端会执行,但还是默认本机,并不会执行对应ip
但是一些情况下,并不会显示,如富文本编辑器和对应的检查(有元素,网络,等等的)
说到富文本编辑器,接下来说明一下,如何在vue里操作吧:
很简单的步骤:
npm install mavon-editor --save
< template>
< div>
< mavon-editor
@save = " saveDoc"
@change = " updateDoc"
ref = " editor"
v-model = " doc" >
</ mavon-editor>
< button @click = " s" > sss</ button>
</ div>
</ template>
< script>
import { mavonEditor} from "mavon-editor" ;
import "mavon-editor/dist/css/index.css" ;
export default {
name : "jj" ,
components : { mavonEditor} ,
data ( ) {
return {
doc : "1"
} ;
} ,
methods : {
s ( ) {
alert ( 1 )
} ,
updateDoc ( markdown, html ) {
console. log ( "markdown内容: " + markdown) ;
console. log ( "html内容:" + markdown) ;
} ,
saveDoc ( markdown, html ) {
console. log ( "markdown内容:" + markdown) ;
console. log ( "html内容:" + html) ;
}
}
}
</ script>
< style>
</ style>
至此操作完成,简单吧