1.3.3新增 后台微信图文发送功能,小程序配置,增加小程序授权等,修复一些bug等

This commit is contained in:
hupeng
2019-11-29 19:03:46 +08:00
parent 8c4c9b0387
commit 33a592b833
57 changed files with 1726 additions and 170 deletions

View File

@ -23,16 +23,16 @@
<artifactId>wx-java-pay-spring-boot-starter</artifactId>
<version>3.5.0</version>
</dependency>
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>wx-java-miniapp-spring-boot-starter</artifactId>
<version>3.5.0</version>
</dependency>
<dependency>
<groupId>co.yixiang</groupId>
<artifactId>yshop-common</artifactId>
<version>1.3</version>
</dependency>
<!-- <dependency>-->
<!-- <groupId>com.github.binarywang</groupId>-->
<!-- <artifactId>wx-java-miniapp-spring-boot-starter</artifactId>-->
<!-- <version>3.5.0</version>-->
<!-- </dependency>-->
</dependencies>

View File

@ -1,15 +1,19 @@
package co.yixiang.mp.config;
import cn.hutool.core.util.StrUtil;
import co.yixiang.mp.handler.*;
import co.yixiang.utils.RedisUtil;
import lombok.AllArgsConstructor;
import me.chanjar.weixin.mp.api.WxMpMessageRouter;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
import me.chanjar.weixin.mp.config.impl.WxMpDefaultConfigImpl;
import org.apache.poi.util.StringUtil;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@ -41,13 +45,40 @@ public class WxMpConfiguration {
private final SubscribeHandler subscribeHandler;
private final ScanHandler scanHandler;
private final WxMpProperties properties;
private final RedisHandler redisHandler;
@Bean
public WxMpService wxMpService() {
// 代码里 getConfigs()处报错的同学请注意仔细阅读项目说明你的IDE需要引入lombok插件
final List<WxMpProperties.MpConfig> configs = this.properties.getConfigs();
System.out.println(configs);
if (configs == null) {
final List<WxMpProperties.MpConfig> configs = new ArrayList<>();
WxMpProperties.MpConfig mpConfig = new WxMpProperties.MpConfig();
String appId = redisHandler.getVal("wechat_appid");
String secret = redisHandler.getVal("wechat_appsecret");
String token = redisHandler.getVal("wechat_token");
String aesKey = redisHandler.getVal("wechat_encodingaeskey");
if(StrUtil.isNotBlank(appId) && StrUtil.isNotBlank(secret)
&& StrUtil.isNotBlank(token) && StrUtil.isNotBlank(aesKey)) {
mpConfig.setAppId(appId);
mpConfig.setSecret(secret);
mpConfig.setToken(token);
mpConfig.setAesKey(aesKey);
System.out.println(mpConfig);
configs.add(mpConfig);
}else{
mpConfig.setAppId("111111");
mpConfig.setSecret("111111");
mpConfig.setToken("111111");
mpConfig.setAesKey("111111");
configs.add(mpConfig);
}
//System.out.println("configs:"+configs);
if (configs.isEmpty()) {
throw new RuntimeException("请先配置!");
}

View File

@ -1,8 +1,11 @@
package co.yixiang.mp.controller;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import co.yixiang.exception.BadRequestException;
import co.yixiang.mp.domain.YxArticle;
import co.yixiang.mp.service.YxArticleService;
import co.yixiang.mp.service.dto.YxArticleDTO;
import co.yixiang.mp.service.dto.YxArticleQueryCriteria;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
@ -57,6 +60,7 @@ public class YxArticleController {
@DeleteMapping(value = "/yxArticle/{id}")
@PreAuthorize("hasAnyRole('ADMIN','YXARTICLE_ALL','YXARTICLE_DELETE')")
public ResponseEntity delete(@PathVariable Integer id){
//if(id > 0) throw new BadRequestException("演示环境禁止操作");
yxArticleService.delete(id);
return new ResponseEntity(HttpStatus.OK);
}
@ -64,8 +68,10 @@ public class YxArticleController {
@ApiOperation(value = "发布文章")
@GetMapping(value = "/yxArticle/publish/{id}")
@PreAuthorize("hasAnyRole('ADMIN','YXARTICLE_ALL','YXARTICLE_DELETE')")
public ResponseEntity publish(@PathVariable Integer id){
//todo
public ResponseEntity publish(@PathVariable Integer id) throws Exception{
//if(id > 0) throw new BadRequestException("演示环境禁止操作");
YxArticleDTO yxArticleDTO= yxArticleService.findById(id);
yxArticleService.uploadNews(yxArticleDTO);
return new ResponseEntity(HttpStatus.OK);
}

View File

@ -1,6 +1,8 @@
package co.yixiang.mp.controller;
import cn.hutool.core.util.StrUtil;
import co.yixiang.exception.BadRequestException;
import co.yixiang.mp.domain.YxCache;
import co.yixiang.mp.service.YxCacheService;
import co.yixiang.utils.OrderUtil;
@ -62,6 +64,7 @@ public class YxCacheController {
yxCacheService.create(yxCache);
}
System.out.println("menu:"+menu);
//创建菜单
try {

View File

@ -1,6 +1,8 @@
package co.yixiang.mp.controller;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import co.yixiang.exception.BadRequestException;
import co.yixiang.mp.domain.YxWechatReply;
import co.yixiang.mp.service.YxWechatReplyService;
import com.alibaba.fastjson.JSON;
@ -39,6 +41,7 @@ public class YxWechatReplyController {
@PostMapping(value = "/yxWechatReply")
@PreAuthorize("hasAnyRole('ADMIN','YXWECHATREPLY_ALL','YXWECHATREPLY_CREATE')")
public ResponseEntity create(@RequestBody String jsonStr){
//if(StrUtil.isNotEmpty(jsonStr)) throw new BadRequestException("演示环境禁止操作");
JSONObject jsonObject = JSON.parseObject(jsonStr);
YxWechatReply yxWechatReply = new YxWechatReply();
YxWechatReply isExist = yxWechatReplyService.isExist(jsonObject.get("key").toString());

View File

@ -0,0 +1,31 @@
package co.yixiang.mp.handler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
@Component
public class RedisHandler{
@Autowired
RedisTemplate redisTemplate;
public String getVal(String key) {
try {
String value = redisTemplate.opsForValue().get(key).toString();
return value;
}catch (Exception e){
return "";
}
}
public Object getObj(String key) {
return redisTemplate.opsForValue().get(key);
}
}

View File

@ -31,9 +31,6 @@ public class SubscribeHandler extends AbstractHandler {
WxSessionManager sessionManager) throws WxErrorException {
//System.out.println("wxMessage:"+wxMessage);
//System.out.println("context:"+context);
YxWechatReply wechatReply = yxWechatReplyService.isExist("subscribe");
if(ObjectUtil.isNull(wechatReply)){
@ -42,15 +39,12 @@ public class SubscribeHandler extends AbstractHandler {
String str = JSONObject.parseObject(wechatReply.getData()).getString("content");
try {
//String str = new String(wechatReply.getData().getBytes(),"utf-8");
WxMpXmlOutMessage msg= WxMpXmlOutMessage.TEXT()
.content(str)
.fromUser(wxMessage.getToUser())
.toUser(wxMessage.getFromUser())
.build();
//System.out.println(msg);
return msg;
//return new TextBuilder().build(str, wxMessage, weixinService);
} catch (Exception e) {
this.logger.error(e.getMessage(), e);
}

View File

@ -62,4 +62,7 @@ public interface YxArticleService {
*/
//@CacheEvict(allEntries = true)
void delete(Integer id);
void uploadNews(YxArticleDTO yxArticleDTO) throws Exception;
}

View File

@ -70,4 +70,6 @@ public class YxArticleDTO implements Serializable {
// 是否轮播图(小程序)
private Integer isBanner;
private String thumbMediaId;
}

View File

@ -1,23 +1,42 @@
package co.yixiang.mp.service.impl;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ReUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import co.yixiang.exception.ErrorRequestException;
import co.yixiang.mp.domain.YxArticle;
import co.yixiang.mp.repository.YxArticleRepository;
import co.yixiang.mp.service.YxArticleService;
import co.yixiang.mp.service.dto.YxArticleDTO;
import co.yixiang.mp.service.dto.YxArticleQueryCriteria;
import co.yixiang.mp.service.mapper.YxArticleMapper;
import co.yixiang.mp.utils.URLUtils;
import co.yixiang.utils.OrderUtil;
import co.yixiang.utils.PageUtil;
import co.yixiang.utils.QueryHelp;
import co.yixiang.utils.ValidationUtil;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.WxMpMassTagMessage;
import me.chanjar.weixin.mp.bean.material.WxMediaImgUploadResult;
import me.chanjar.weixin.mp.bean.material.WxMpMaterial;
import me.chanjar.weixin.mp.bean.material.WxMpMaterialNews;
import me.chanjar.weixin.mp.bean.material.WxMpMaterialUploadResult;
import me.chanjar.weixin.mp.bean.result.WxMpMassSendResult;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import java.io.File;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@ -26,6 +45,7 @@ import java.util.Optional;
* @author hupeng
* @date 2019-10-07
*/
@Slf4j
@Service
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class YxArticleServiceImpl implements YxArticleService {
@ -36,6 +56,12 @@ public class YxArticleServiceImpl implements YxArticleService {
@Autowired
private YxArticleMapper yxArticleMapper;
@Autowired
private WxMpService wxMpService;
@Value("${file.path}")
private String uploadDirStr;
@Override
public Map<String,Object> queryAll(YxArticleQueryCriteria criteria, Pageable pageable){
Page<YxArticle> page = yxArticleRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable);
@ -76,4 +102,97 @@ public class YxArticleServiceImpl implements YxArticleService {
public void delete(Integer id) {
yxArticleRepository.deleteById(id);
}
@Override
public void uploadNews(YxArticleDTO wxNewsArticleItem) throws Exception {
WxMpMaterialNews wxMpMaterialNews = new WxMpMaterialNews();
WxMpMaterialNews.WxMpMaterialNewsArticle article = new WxMpMaterialNews.WxMpMaterialNewsArticle();
WxMpMaterialUploadResult wxMpMaterialUploadResult = uploadPhotoToWx( wxMpService,
wxNewsArticleItem.getImageInput() );
wxNewsArticleItem.setThumbMediaId( wxMpMaterialUploadResult.getMediaId() );
article.setAuthor( wxNewsArticleItem.getAuthor() );
System.out.println(wxNewsArticleItem.getContent());
//处理content
String content = processContent(wxMpService, wxNewsArticleItem.getContent());
System.out.println(content);
article.setContent( content );
article.setContentSourceUrl( wxNewsArticleItem.getUrl() );
article.setDigest( wxNewsArticleItem.getSynopsis() );
article.setShowCoverPic( true );
article.setThumbMediaId( wxNewsArticleItem.getThumbMediaId() );
article.setTitle( wxNewsArticleItem.getTitle() );
//TODO 暂时注释掉,测试号没有留言权限
//article.setNeedOpenComment( wxNewsArticleItem );
//article.setOnlyFansCanComment( wxNewsArticleItem );
wxMpMaterialNews.addArticle( article );
log.info( "wxMpMaterialNews : {}", JSONUtil.toJsonStr( wxMpMaterialNews ) );
WxMpMaterialUploadResult wxMpMaterialUploadResult1 = wxMpService.getMaterialService()
.materialNewsUpload( wxMpMaterialNews );
//推送开始
WxMpMassTagMessage massMessage = new WxMpMassTagMessage();
massMessage.setMsgType(WxConsts.MassMsgType.MPNEWS);
massMessage.setMediaId(wxMpMaterialUploadResult1.getMediaId());
massMessage.setSendAll(true);
WxMpMassSendResult massResult = wxMpService.getMassMessageService()
.massGroupMessageSend(massMessage);
if(!massResult.getErrorCode().equals("0")) {
log.info("error:"+massResult.getErrorMsg());
throw new ErrorRequestException("发送失败");
}
log.info( "massResult : {}", JSONUtil.toJsonStr( massResult ) );
log.info( "wxMpMaterialUploadResult : {}", JSONUtil.toJsonStr( wxMpMaterialUploadResult1 ) );
}
private WxMpMaterialUploadResult uploadPhotoToWx(WxMpService wxMpService, String picPath) throws WxErrorException {
WxMpMaterial wxMpMaterial = new WxMpMaterial();
String filename = String.valueOf( System.currentTimeMillis() ) + ".png";
String downloadPath = uploadDirStr + filename;
long size = HttpUtil.downloadFile(picPath, FileUtil.file(downloadPath));
picPath = downloadPath;
File picFile = new File( picPath );
wxMpMaterial.setFile( picFile );
wxMpMaterial.setName( picFile.getName() );
log.info( "picFile name : {}", picFile.getName() );
WxMpMaterialUploadResult wxMpMaterialUploadResult = wxMpService.getMaterialService().materialFileUpload( WxConsts.MediaFileType.IMAGE, wxMpMaterial );
log.info( "wxMpMaterialUploadResult : {}", JSONUtil.toJsonStr( wxMpMaterialUploadResult ) );
return wxMpMaterialUploadResult;
}
private String processContent(WxMpService wxMpService,String content) throws WxErrorException {
if(StringUtils.isBlank( content )){
return content;
}
String imgReg = "<img[^>]+src\\s*=\\s*['\"]([^'\"]+)['\"][^>]*>";
List<String> imgList = ReUtil.findAllGroup1( imgReg,content);
for (int j = 0; j < imgList.size(); j++) {
String imgSrc = imgList.get( j );
String filepath = URLUtils.getParam( imgSrc,"filepath" );
if(StringUtils.isBlank( filepath )){//网络图片URL需下载到本地
String filename = String.valueOf( System.currentTimeMillis() ) + ".png";
String downloadPath = uploadDirStr + filename;
long size = HttpUtil.downloadFile(imgSrc, FileUtil.file(downloadPath));
filepath = downloadPath;
}
WxMediaImgUploadResult wxMediaImgUploadResult = wxMpService.getMaterialService().mediaImgUpload( new File(filepath) );
content = StringUtils.replace( content,imgList.get( j ),wxMediaImgUploadResult.getUrl());
}
return content;
}
}

View File

@ -0,0 +1,76 @@
package co.yixiang.mp.utils;
import java.util.HashMap;
import java.util.Map;
/**
* URLUtils
* @author Kevin
* @date 2019-03-20 13:39
*/
public class URLUtils {
/**
* 获取URL中的某个参数
* @param url
* @param name
* @return
*/
public static String getParam(String url, String name) {
return urlSplit(url).get( name );
}
/**
* 去掉url中的路径留下请求参数部分
* @param strURL url地址
* @return url请求参数部分
*/
private static String truncateUrlPage(String strURL){
String strAllParam=null;
String[] arrSplit=null;
strURL=strURL.trim().toLowerCase();
arrSplit=strURL.split("[?]");
if(strURL.length()>1){
if(arrSplit.length>1){
for (int i=1;i<arrSplit.length;i++){
strAllParam = arrSplit[i];
}
}
}
return strAllParam;
}
/**
* 解析出url参数中的键值对
* 如 "index.jsp?Action=del&id=123"解析出Action:del,id:123存入map中
* @param URL url地址
* @return url请求参数部分
*/
public static Map<String, String> urlSplit(String URL){
Map<String, String> mapRequest = new HashMap<String, String>();
String[] arrSplit=null;
String strUrlParam= truncateUrlPage(URL);
if(strUrlParam==null){
return mapRequest;
}
arrSplit=strUrlParam.split("[&]");
for(String strSplit:arrSplit){
String[] arrSplitEqual=null;
arrSplitEqual= strSplit.split("[=]");
//解析出键值
if(arrSplitEqual.length>1){
//正确解析
mapRequest.put(arrSplitEqual[0], arrSplitEqual[1]);
}else{
if(arrSplitEqual[0]!=""){
//只有参数没有值,不加入
mapRequest.put(arrSplitEqual[0], "");
}
}
}
return mapRequest;
}
}