公众号关注、订阅、消息数量

This commit is contained in:
clunt 2024-07-09 16:17:59 +08:00
parent c922476602
commit 0cb7df196c
12 changed files with 357 additions and 11 deletions

View File

@ -24,6 +24,15 @@ public class WxController {
private final WxService wxService; private final WxService wxService;
@ApiOperation(value = "校验用户是否已经关注了公众号", httpMethod = "POST")
@PostMapping("checkKeepStatusByOpenId")
@ResponseBody
private Result<Boolean> checkKeepStatusByOpenId(@RequestParam(value = "openId") String openId,
@RequestParam(value = "appId") String appId,
@RequestParam(value = "secret") String secret) {
return Result.success(wxService.checkKeepStatusByOpenId(openId, appId, secret));
}
@ApiOperation(value = "获取openId", httpMethod = "POST") @ApiOperation(value = "获取openId", httpMethod = "POST")
@PostMapping("/getOpenidByCode") @PostMapping("/getOpenidByCode")
@ResponseBody @ResponseBody

View File

@ -22,4 +22,6 @@ public interface WxService {
String getCompanyByUserId(String userTicket); String getCompanyByUserId(String userTicket);
Boolean checkKeepStatusByOpenId(String openId, String appId, String secret);
} }

View File

@ -1,7 +1,12 @@
package com.playlet.web.service.app.impl; package com.playlet.web.service.app.impl;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONObject;
import com.playlet.common.utils.StringUtils;
import com.playlet.common.utils.http.HttpUtils;
import com.playlet.system.domain.PlayletPublicUser; import com.playlet.system.domain.PlayletPublicUser;
import com.playlet.system.service.IPlayletPublicUserService; import com.playlet.system.service.IPlayletPublicUserService;
import com.playlet.web.service.WxService;
import com.playlet.web.service.app.PlayletPublicUserAppService; import com.playlet.web.service.app.PlayletPublicUserAppService;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -18,6 +23,8 @@ public class PlayletPublicUserAppServiceImpl implements PlayletPublicUserAppServ
private final IPlayletPublicUserService iPlayletPublicUserService; private final IPlayletPublicUserService iPlayletPublicUserService;
private final WxService wxService;
@Override @Override
public PlayletPublicUser addPublicUser(PlayletPublicUser publicUser) { public PlayletPublicUser addPublicUser(PlayletPublicUser publicUser) {
iPlayletPublicUserService.insertPlayletPublicUser(publicUser); iPlayletPublicUserService.insertPlayletPublicUser(publicUser);
@ -31,6 +38,21 @@ public class PlayletPublicUserAppServiceImpl implements PlayletPublicUserAppServ
.eq(PlayletPublicUser::getUnionId, publicUser.getUnionId()) .eq(PlayletPublicUser::getUnionId, publicUser.getUnionId())
.list(); .list();
if(CollectionUtils.isNotEmpty(list)){ if(CollectionUtils.isNotEmpty(list)){
// 判断用户是否关注公众号
if(StringUtils.isNotEmpty(list.get(0).getOpenId())){
String accessToken = wxService.getAccessToken();
String url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=" + accessToken + "&openid=" + list.get(0).getOpenId() + "&lang=zh_CN";
log.info("调用微信获取用户信息,入参url:{}", url);
String result = HttpUtils.sendGet(url);
log.info("调用微信获取用户信息,响应内容:{}", result);
// 是否关注公众号
String watchPublic = JSONObject.parseObject(result).getString("subscribe");
if(!watchPublic.equals(list.get(0).getWatchPublic())){
list.get(0).setWatchPublic(watchPublic);
// 将状态更新到表中
iPlayletPublicUserService.updateById(list.get(0));
}
}
return list.get(0); return list.get(0);
} }
return null; return null;

View File

@ -61,11 +61,11 @@ public class PublicDetailShareAppServiceImpl implements PublicDetailShareAppServ
}else { }else {
playletPublicDetail.setTransmitCount(playletPublicDetail.getTransmitCount() + 1); playletPublicDetail.setTransmitCount(playletPublicDetail.getTransmitCount() + 1);
} }
if(playletPublicDetail.getReadCount() == null){ // if(playletPublicDetail.getReadCount() == null){
playletPublicDetail.setReadCount(1L); // playletPublicDetail.setReadCount(1L);
}else { // }else {
playletPublicDetail.setReadCount(playletPublicDetail.getReadCount() + 1); // playletPublicDetail.setReadCount(playletPublicDetail.getReadCount() + 1);
} // }
iPlayletPublicDetailService.updateById(playletPublicDetail); iPlayletPublicDetailService.updateById(playletPublicDetail);
} }
} }

View File

@ -1,5 +1,6 @@
package com.playlet.web.service.app.impl; package com.playlet.web.service.app.impl;
import com.playlet.system.domain.PlayletPublicDetail;
import com.playlet.system.domain.PublicUserRecord; import com.playlet.system.domain.PublicUserRecord;
import com.playlet.system.service.IPlayletPublicDetailService; import com.playlet.system.service.IPlayletPublicDetailService;
import com.playlet.system.service.IPublicUserRecordService; import com.playlet.system.service.IPublicUserRecordService;
@ -21,6 +22,16 @@ public class PublicUserRecordAppServiceImpl implements PublicUserRecordAppServic
@Override @Override
public void addRecord(PublicUserRecord userRecord) { public void addRecord(PublicUserRecord userRecord) {
iPublicUserRecordService.insertPublicUserRecord(userRecord); iPublicUserRecordService.insertPublicUserRecord(userRecord);
// 添加浏览记录时,同时需要增加一下文章表上面的阅读次数
PlayletPublicDetail playletPublicDetail = iPlayletPublicDetailService.getById(Long.valueOf(userRecord.getRemark()));
if(playletPublicDetail != null){
if(playletPublicDetail.getReadCount() == null){
playletPublicDetail.setReadCount(1L);
}else {
playletPublicDetail.setReadCount(playletPublicDetail.getReadCount() + 1);
}
iPlayletPublicDetailService.updateById(playletPublicDetail);
}
} }
@Override @Override

View File

@ -27,7 +27,13 @@ public class WxServiceImpl implements WxService {
@Override @Override
public String getAccessToken() { public String getAccessToken() {
String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + wxConfig.getAppId() + "&secret=" + wxConfig.getSecret(); String accessTokenResult = HttpUtils.sendGet("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=wx2b7d9259c1188067&secret=919165aae35838480986555f6c03ae6f");
log.info("accessTokenResult : {} ", accessTokenResult);
return JSONObject.parseObject(accessTokenResult).getString("access_token");
}
private String getAccessToken(String appid, String secret) {
String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appid + "&secret=" + secret;
log.info("调用微信获取access_token,入参url:{}", url); log.info("调用微信获取access_token,入参url:{}", url);
String result = HttpUtils.sendGet(url); String result = HttpUtils.sendGet(url);
log.info("调用微信获取access_token,响应内容:{}", result); log.info("调用微信获取access_token,响应内容:{}", result);
@ -91,6 +97,20 @@ public class WxServiceImpl implements WxService {
return result.body(); return result.body();
} }
@Override
public Boolean checkKeepStatusByOpenId(String openId, String appId, String secret) {
String accessToken = this.getAccessToken(appId, secret);
String url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=" + accessToken + "&openid=" + openId + "&lang=zh_CN";
log.info("调用微信获取用户信息,校验是否关注微信公众号,入参url:{}", url);
String result = HttpUtils.sendGet(url);
log.info("调用微信获取用户信息,校验是否关注微信公众号,响应内容:{}", result);
JSONObject json = JSONObject.parseObject(result);
if(json.containsKey(PlayletConstants.SUBSCRIBE)){
return "1".equals(json.getString(PlayletConstants.SUBSCRIBE));
}
return false;
}
@Override @Override
public String getOpenidByCode(String code, String appId, String secret) { public String getOpenidByCode(String code, String appId, String secret) {
String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid="+ appId + "&secret=" + secret + "&code=" + code + "&grant_type=authorization_code"; String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid="+ appId + "&secret=" + secret + "&code=" + code + "&grant_type=authorization_code";

View File

@ -30,6 +30,7 @@ server:
max: 800 max: 800
# Tomcat启动初始化的线程数默认值10 # Tomcat启动初始化的线程数默认值10
min-spare: 100 min-spare: 100
max-http-form-post-size: 104857600
# 日志配置 # 日志配置
logging: logging:
@ -78,9 +79,9 @@ spring:
servlet: servlet:
multipart: multipart:
# 单个文件大小 # 单个文件大小
max-file-size: 50MB max-file-size: 500MB
# 设置总上传的文件大小 # 设置总上传的文件大小
max-request-size: 100MB max-request-size: 1000MB
# 服务模块 # 服务模块
devtools: devtools:
restart: restart:

View File

@ -0,0 +1,261 @@
<!DOCTYPE html>
<html lang="zh" xmlns:th="http://www.thymeleaf.org" >
<head>
<th:block th:include="include :: header('修改图片')" />
<th:block th:include="include :: cropper-css" />
<style type='text/css'>
/* avator css start */
.container {
margin: 10px 5px 5px 5px;
}
.action {
padding: 5px 0px;
}
.cropped {
width: 200px;
border: 1px #ddd solid;
box-shadow: 0px 0px 12px #ddd;
}
.img-preview {
border-radius: 50%;
box-shadow: 0px 0px 12px #7e7e7e;
display: inline-block;
}
.preview-box {
text-align: center;
margin: 0px auto;
margin-top: 10px;
color: #bbb;
}
.preview-md {
width: 128px;
height: 128px;
}
.preview-sm {
width: 96px;
height: 96px;
}
.preview-xs {
width: 64px;
height: 64px;
}
.imageBox {
border: 1px solid #aaa;
overflow: hidden;
cursor: move;
box-shadow: 4px 4px 12px #B0B0B0;
margin: 0px auto;
}
.btn-custom {
float: right;
width: 46px;
display: inline-block;
margin-bottom: 10px;
height: 37px;
line-height: 37px;
font-size: 14px;
color: #FFFFFF;
margin: 0px 2px;
background-color: #f38e81;
border-radius: 3px;
text-decoration: none;
cursor: pointer;
box-shadow: 0px 0px 5px #B0B0B0;
border: 0px #fff solid;
}
/*选择文件上传*/
.new-contentarea {
width: 165px;
overflow: hidden;
margin: 0 auto;
position: relative;
float: left;
}
.new-contentarea label {
width: 100%;
height: 100%;
display: block;
}
.new-contentarea input[type=file] {
width: 188px;
height: 60px;
background: #333;
margin: 0 auto;
position: absolute;
right: 50%;
margin-right: -94px;
top: 0;
right/*\**/: 0px\9;
margin-right/*\**/: 0px\9;
width/*\**/: 10px\9;
opacity: 0;
filter: alpha(opacity=0);
z-index: 2;
}
a.upload-img {
width: 165px;
display: inline-block;
margin-bottom: 10px;
height: 37px;
line-height: 37px;
font-size: 14px;
color: #FFFFFF;
background-color: #f38e81;
border-radius: 3px;
text-decoration: none;
cursor: pointer;
border: 0px #fff solid;
box-shadow: 0px 0px 5px #B0B0B0;
}
a.upload-img:hover {
background-color: #ec7e70;
}
.tc {
text-align: center;
}
/* avator css end */
</style>
</head>
<body class="white-bg">
<div class="row container">
<div class="col-md-10">
<div class="imageBox">
<img id="avatar" th:src="(${#strings.isEmpty(user.avatar)}) ? @{/img/profile.jpg} : @{${user.avatar}}" th:onerror="'this.src=\'' + @{'/img/profile.jpg'} + '\''">
</div>
<div class="action">
<div class="new-contentarea tc">
<a href="javascript:void(0)" class="upload-img"><label for="inputImage">上传图像</label> </a>
<input type="file" name="avatar" id="inputImage" accept="image/*"/>
</div>
<button type="button" class="btn-custom" data-method="zoom" data-option="0.1"><i class="fa fa-search-plus"></i></button>
<button type="button" class="btn-custom" data-method="zoom" data-option="-0.1"><i class="fa fa-search-minus"></i></button>
<button type="button" class="btn-custom" data-method="rotate" data-option="-45"><i class="fa fa-rotate-left"></i></button>
<button type="button" class="btn-custom" data-method="rotate" data-option="45"><i class="fa fa-rotate-right"></i></button>
<button type="button" class="btn-custom" data-method="scaleX" data-option="-1"><i class="fa fa-arrows-h"></i></button>
<button type="button" class="btn-custom" data-method="scaleY" data-option="-1"><i class="fa fa-arrows-v"></i></button>
<button type="button" class="btn-custom" data-method="reset"><i class="fa fa-refresh"></i></button>
</div>
</div>
<div class="col-md-2">
<div class="cropped">
<div class="preview-box">
<div class="img-preview preview-xs"></div>
</div>
<div class="preview-box">
<div class="img-preview preview-sm"></div>
</div>
<div class="preview-box">
<div class="img-preview preview-md"></div>
</div>
</div>
</div>
</div>
<th:block th:include="include :: footer" />
<th:block th:include="include :: cropper-js" />
<script type="text/javascript">
var cropper;
var croppable = false;
$(window).on('load', function() {
var image = document.getElementById('avatar');
cropper = new Cropper(image, {
aspectRatio: 1,
viewMode: 1,
autoCropArea: 0.9,
preview: '.img-preview',
ready: function () {
croppable = true;
}
})
$('#inputImage').on('change', function() {
var reader = new FileReader();
var file = $('#inputImage')[0].files[0];
if (/^image\/\w+$/.test(file.type)) {
reader.onload = function(e) {
if(croppable){
cropper.replace(e.target.result)
}
}
reader.readAsDataURL(this.files[0]);
} else {
$.modal.alertWarning('请选择一个图片文件。');
}
});
$('.btn-custom').on('click',function (e) {
if (!croppable) {
$.modal.alertWarning("裁剪框加载中,请稍候...");
return;
}
var data = {
method: $(this).data('method'),
option: $(this).data('option') || undefined,
};
var result = cropper[data.method](data.option, data.secondOption);
if(['scaleX','scaleY'].indexOf(data.method) !== -1){
$(this).data('option', -data.option)
}
})
});
function submitHandler() {
if (!croppable) {
$.modal.alertWarning("裁剪框加载中,请稍候...");
return
}
cropper.getCroppedCanvas().toBlob(function(img) {
var formdata = new FormData();
formdata.append("avatarfile", img);
$.ajax({
url: ctx + "system/user/profile/updateAvatar",
data: formdata,
type: "post",
processData: false,
contentType: false,
success: function(result) {
$.operate.saveReload(result);
}
})
});
}
$(window).resize(function() {
$('.imageBox').height($(window).height() - 80);
$('.cropped').height($(window).height() - 40);
}).resize();
if (!HTMLCanvasElement.prototype.toBlob) {
Object.defineProperty(HTMLCanvasElement.prototype, 'toBlob', {
value: function(callback, type, quality) {
var canvas = this;
setTimeout(function() {
var binStr = atob(canvas.toDataURL(type, quality).split(',')[1]);
var len = binStr.length;
var arr = new Uint8Array(len);
for (var i = 0; i < len; i++) {
arr[i] = binStr.charCodeAt(i);
}
callback(new Blob([arr], {
type: type || 'image/png'
}));
});
}
});
}
</script>
</body>
</html>

View File

@ -12,6 +12,9 @@ public class PlayletConstants {
/** 微信OpenId返回格式 */ /** 微信OpenId返回格式 */
public static final String OPEN_ID = "openid"; public static final String OPEN_ID = "openid";
/** 微信公众号订阅状态 */
public static final String SUBSCRIBE = "subscribe";
/** 小程序用户初始默认创建人 */ /** 小程序用户初始默认创建人 */
public static final String DEFAULT_CREATE = "system"; public static final String DEFAULT_CREATE = "system";

View File

@ -39,8 +39,13 @@ public class PlayletPublicUser extends BaseEntity
@Excel(name = "微信unionId") @Excel(name = "微信unionId")
private String unionId; private String unionId;
@Excel(name = "微信openId")
private String openId;
/** 头像 */ /** 头像 */
@Excel(name = "头像") @Excel(name = "头像")
private String imgUrl; private String imgUrl;
/** 是否关注公众号 0.否 1.是 */
private String watchPublic;
} }

View File

@ -45,8 +45,16 @@
update_by, update_time, detail_tag, remark, address, transmit_count from playlet_public_detail update_by, update_time, detail_tag, remark, address, transmit_count from playlet_public_detail
</sql> </sql>
<sql id="selectPlayletPublicDetailVoNoContent">
select id, public_id, item_id, head_url, read_count,star_count,
item_one,item_two,item_three,item_four,item_five,top_status,
item_six,item_seven,item_eight,item_nine,item_ten,
title,type,author_alias,img_url, create_by, create_time,
update_by, update_time, detail_tag, remark, address, transmit_count from playlet_public_detail
</sql>
<select id="selectPlayletPublicDetailList" parameterType="PlayletPublicDetail" resultMap="PlayletPublicDetailResult"> <select id="selectPlayletPublicDetailList" parameterType="PlayletPublicDetail" resultMap="PlayletPublicDetailResult">
<include refid="selectPlayletPublicDetailVo"/> <include refid="selectPlayletPublicDetailVoNoContent"/>
<where> <where>
<if test="publicId != null "> and public_id = #{publicId}</if> <if test="publicId != null "> and public_id = #{publicId}</if>
<if test="type != null "> and type = #{type}</if> <if test="type != null "> and type = #{type}</if>

View File

@ -9,6 +9,7 @@
<result property="publicId" column="public_id" /> <result property="publicId" column="public_id" />
<result property="name" column="name" /> <result property="name" column="name" />
<result property="unionId" column="union_id" /> <result property="unionId" column="union_id" />
<result property="openId" column="open_id" />
<result property="imgUrl" column="img_url" /> <result property="imgUrl" column="img_url" />
<result property="createBy" column="create_by" /> <result property="createBy" column="create_by" />
<result property="createTime" column="create_time" /> <result property="createTime" column="create_time" />
@ -18,7 +19,7 @@
</resultMap> </resultMap>
<sql id="selectPlayletPublicUserVo"> <sql id="selectPlayletPublicUserVo">
select id, public_id, name, union_id, img_url, create_by, create_time, update_by, update_time, remark from playlet_public_user select id, public_id, open_id, name, union_id, img_url, create_by, create_time, update_by, update_time, remark from playlet_public_user
</sql> </sql>
<select id="selectPlayletPublicUserList" parameterType="PlayletPublicUser" resultMap="PlayletPublicUserResult"> <select id="selectPlayletPublicUserList" parameterType="PlayletPublicUser" resultMap="PlayletPublicUserResult">
@ -42,6 +43,7 @@
<if test="publicId != null">public_id,</if> <if test="publicId != null">public_id,</if>
<if test="name != null">name,</if> <if test="name != null">name,</if>
<if test="unionId != null">union_id,</if> <if test="unionId != null">union_id,</if>
<if test="openId != null">open_id,</if>
<if test="imgUrl != null">img_url,</if> <if test="imgUrl != null">img_url,</if>
<if test="createBy != null">create_by,</if> <if test="createBy != null">create_by,</if>
<if test="createTime != null">create_time,</if> <if test="createTime != null">create_time,</if>
@ -53,6 +55,7 @@
<if test="publicId != null">#{publicId},</if> <if test="publicId != null">#{publicId},</if>
<if test="name != null">#{name},</if> <if test="name != null">#{name},</if>
<if test="unionId != null">#{unionId},</if> <if test="unionId != null">#{unionId},</if>
<if test="openId != null">#{openId},</if>
<if test="imgUrl != null">#{imgUrl},</if> <if test="imgUrl != null">#{imgUrl},</if>
<if test="createBy != null">#{createBy},</if> <if test="createBy != null">#{createBy},</if>
<if test="createTime != null">#{createTime},</if> <if test="createTime != null">#{createTime},</if>
@ -68,6 +71,7 @@
<if test="publicId != null">public_id = #{publicId},</if> <if test="publicId != null">public_id = #{publicId},</if>
<if test="name != null">name = #{name},</if> <if test="name != null">name = #{name},</if>
<if test="unionId != null">union_id = #{unionId},</if> <if test="unionId != null">union_id = #{unionId},</if>
<if test="openId != null">open_id = #{openId},</if>
<if test="imgUrl != null">img_url = #{imgUrl},</if> <if test="imgUrl != null">img_url = #{imgUrl},</if>
<if test="createBy != null">create_by = #{createBy},</if> <if test="createBy != null">create_by = #{createBy},</if>
<if test="createTime != null">create_time = #{createTime},</if> <if test="createTime != null">create_time = #{createTime},</if>