@@ -1,15 +1,15 @@
package com.gxwebsoft.common.system.controller ;
import cn.hutool.core.io.FileUtil ;
import cn.hutool.core.util.ObjectUtil ;
import cn.hutool.core.util.RandomUtil ;
import cn.hutool.core.util.StrUtil ;
import cn.hutool.http.HttpRequest ;
import cn.hutool.http.HttpUtil ;
import com.alibaba.fastjson.JSON ;
import com.alibaba.fastjson.JSONObject ;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper ;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper ;
import com.fasterxml.jackson.databind.JsonNode ;
import com.fasterxml.jackson.databind.ObjectMapper ;
import com.gxwebsoft.common.core.config.ConfigProperties ;
import com.gxwebsoft.common.core.exception.BusinessException ;
import com.gxwebsoft.common.core.security.JwtSubject ;
@@ -25,13 +25,18 @@ import com.gxwebsoft.common.system.result.LoginResult;
import com.gxwebsoft.common.system.service.* ;
import io.swagger.v3.oas.annotations.tags.Tag ;
import io.swagger.v3.oas.annotations.Operation ;
import okhttp3.* ;
import org.springframework.data.redis.core.StringRedisTemplate ;
import org.springframework.transaction.annotation.Transactional ;
import org.springframework.web.bind.annotation.* ;
import org.springframework.web.bind.annotation.RequestBody ;
import javax.annotation.Resource ;
import javax.servlet.http.HttpServletRequest ;
import javax.servlet.http.HttpServletResponse ;
import java.io.File ;
import java.io.IOException ;
import java.time.Instant ;
import java.util.HashMap ;
import java.util.concurrent.TimeUnit ;
@@ -43,6 +48,9 @@ import static com.gxwebsoft.common.core.constants.RedisConstants.ACCESS_TOKEN_KE
@Tag ( name = " 微信小程序登录API " )
public class WxLoginController extends BaseController {
private final StringRedisTemplate redisTemplate ;
private final OkHttpClient http = new OkHttpClient ( ) ;
private final ObjectMapper om = new ObjectMapper ( ) ;
private volatile long tokenExpireEpoch = 0L ; // 过期的 epoch 秒
@Resource
private SettingService settingService ;
@Resource
@@ -64,6 +72,8 @@ public class WxLoginController extends BaseController {
@Resource
private UserRefereeService userRefereeService ;
public WxLoginController ( StringRedisTemplate redisTemplate ) {
this . redisTemplate = redisTemplate ;
}
@@ -118,7 +128,6 @@ public class WxLoginController extends BaseController {
UserParam userParam2 = new UserParam ( ) ;
userParam2 . setCode ( userParam . getAuthCode ( ) ) ;
JSONObject result = getOpenIdByCode ( userParam2 ) ;
System . out . println ( " userInfo res: " + result ) ;
String openid = result . getString ( " openid " ) ;
// String unionid = result.getString("unionid");
userParam . setOpenid ( openid ) ;
@@ -288,7 +297,6 @@ public class WxLoginController extends BaseController {
String url = apiUrl . concat ( " ?grant_type=client_credential " ) . concat ( " &appid= " ) . concat ( setting . getString ( " appId " ) ) . concat ( " &secret= " ) . concat ( setting . getString ( " appSecret " ) ) ;
// 执行get请求
String result = HttpUtil . get ( url ) ;
System . out . println ( " result = " + result ) ;
// 解析access_token
JSONObject response = JSON . parseObject ( result ) ;
if ( response . getString ( " access_token " ) ! = null ) {
@@ -401,27 +409,96 @@ public class WxLoginController extends BaseController {
@Operation ( summary = " 获取微信小程序码-订单核销码-数量极多的业务场景 " )
@GetMapping ( " /getOrderQRCodeUnlimited/{orderNo} " )
public ApiResult < ? > getOrderQRCodeUnlimited( @PathVariable ( " orderNo " ) String orderNo ) {
String apiUrl = " https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token= " + getAccessToken ( ) ;
public void getOrderQRCodeUnlimited( @PathVariable ( " orderNo " ) String orderNo , HttpServletResponse response ) throws IOException {
System . out . println ( " orderNo = " + orderNo ) ;
String apiUrl = " https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token= " + getLocalAccessToken ( ) ;
final HashMap < String , Object > map = new HashMap < > ( ) ;
map . put ( " scene " , " orderNo= " . concat ( orderNo ) ) ;
map . put ( " page " , " package/admin/order-scan " ) ;
map . put ( " env_version " , " trial " ) ;
map . put ( " scene " , orderNo ) ;
map . put ( " page " , " pages/index/index " ) ;
map . put ( " env_version " , " develop " ) ;
String jsonBody = JSON . toJSONString ( map ) ;
System . out . println ( " 请求的 JSON body = " + jsonBody ) ;
// 获取图片 Buffer
byte [ ] qrCode = HttpRequest . post ( apiUrl )
. body ( JSON . toJSONString ( map ) )
. execute ( ) . bodyBytes ( ) ;
System . out . println ( " qrCode = " + qrCode ) ;
// 保存的文件名称
final String fileName = CommonUtil . randomUUID8 ( ) . concat ( " . png" ) ;
// 保存路径
String filePath = getUploadDir ( ) . concat ( " qrcode/ " ) + fileN ame;
File file = FileUtil . writeBytes ( qrCode , filePath ) ;
if ( file ! = null ) {
return success ( config . getFileServer ( ) . concat ( " / qrc ode/ " ) . concat ( fileName ) ) ;
// 设置响应头
response . setContentType ( " image/ png" ) ;
response . setHeader ( " Cache-Control " , " no-cache " ) ;
response . setHeader ( " Content-Disposition " , " inline; filen ame=encrypted_qrcode.png " ) ;
// 输出图片
response . getOutputStream ( ) . write ( qrC ode ) ;
System . out . println ( " response = " + response ) ;
}
@Operation ( summary = " 获取微信小程序码-用户ID " )
@GetMapping ( " /getQRCodeText " )
public byte [ ] getQRCodeText ( String scene , String page , Integer width ,
Boolean isHyaline , String envVersion ) throws IOException {
HttpUrl url = HttpUrl . parse ( " https://api.weixin.qq.com/wxa/getwxacodeunlimit " )
. newBuilder ( )
. addQueryParameter ( " access_token " , getLocalAccessToken ( ) )
. build ( ) ;
System . out . println ( " page = " + page ) ;
// 构造请求 JSON
// 注意: scene 仅支持可见字符,长度上限 32, 尽量 URL-safe( 字母数字下划线等)
// page 必须是已发布小程序内的路径(不带开头斜杠也可)
var root = om . createObjectNode ( ) ;
root . put ( " scene " , scene ) ;
if ( page ! = null ) root . put ( " page " , page ) ;
if ( width ! = null ) root . put ( " width " , width ) ; // 默认 430, 建议 280~1280
if ( isHyaline ! = null ) root . put ( " is_hyaline " , isHyaline ) ;
if ( envVersion ! = null ) root . put ( " env_version " , envVersion ) ; // release/trial/develop
okhttp3 . RequestBody reqBody = okhttp3 . RequestBody . create (
root . toString ( ) , MediaType . parse ( " application/json; charset=utf-8 " ) ) ;
Request req = new Request . Builder ( ) . url ( url ) . post ( reqBody ) . build ( ) ;
try ( Response resp = http . newCall ( req ) . execute ( ) ) {
if ( ! resp . isSuccessful ( ) ) {
throw new IOException ( " HTTP " + resp . code ( ) + " calling getwxacodeunlimit " ) ;
}
return fail ( " 获取失败 " , null ) ;
MediaType ct = resp . body ( ) . contentType ( ) ;
byte [ ] bytes = resp . body ( ) . bytes ( ) ;
// 微信出错时返回 JSON, 需要识别一下
if ( ct ! = null & & ct . subtype ( ) ! = null & & ct . subtype ( ) . contains ( " json " ) ) {
String err = new String ( bytes ) ;
throw new IOException ( " WeChat error: " + err ) ;
}
return bytes ; // 成功就是图片二进制( PNG)
}
}
/** 获取/刷新 access_token */
public String getLocalAccessToken ( ) throws IOException {
long now = Instant . now ( ) . getEpochSecond ( ) ;
String key = " AccessToken:Local:10550 " ;
if ( redisUtil . get ( key ) ! = null & & now < tokenExpireEpoch - 60 ) {
return redisUtil . get ( key ) ;
}
HttpUrl url = HttpUrl . parse ( " https://api.weixin.qq.com/cgi-bin/token " )
. newBuilder ( )
. addQueryParameter ( " grant_type " , " client_credential " )
. addQueryParameter ( " appid " , " wx51962d6ac21f2ed2 " )
. addQueryParameter ( " secret " , " d821f98de8a6c1ba7bc7e0ee84bcbc8e " )
. build ( ) ;
Request req = new Request . Builder ( ) . url ( url ) . get ( ) . build ( ) ;
try ( Response resp = http . newCall ( req ) . execute ( ) ) {
String body = resp . body ( ) . string ( ) ;
JsonNode json = om . readTree ( body ) ;
if ( json . has ( " access_token " ) ) {
String token = json . get ( " access_token " ) . asText ( ) ;
long expiresIn = json . get ( " expires_in " ) . asInt ( 7200 ) ;
redisUtil . set ( key , token , expiresIn , TimeUnit . SECONDS ) ;
tokenExpireEpoch = now + expiresIn ;
return token ;
} else {
throw new IOException ( " Get access_token failed: " + body ) ;
}
}
}
/**