springboot案例分析(微信开发)

@author StormMa
@date 2017-04-19


生命不息,奋斗不止!

前言

在微信开发中,有很多地方会批量插入图片,微信服务器给 js 提供了上传图片的接口,但是微信服务器上的有效期就只有三天,这样我们就会很容易利用 js 接口上传到服务器之后,我们自己的服务器再从微信服务器上下载到我们自己的服务器上去,基于这一设计,我们看看怎么能更高效的实现这一功能。

实现原理

  1. js 上传接口
1
2
3
4
5
6
7
wx.uploadImage({
localId: '', // 需要上传的图片的本地ID,由chooseImage接口获得
isShowProgressTips: 1, // 默认为1,显示进度提示
success: function (res) {
var serverId = res.serverId; // 返回图片的服务器端ID
}
});
  1. 发送 serverids 到后端进行微信服务器上的图片下载
  • 设计线程池进行微信服务器端的下载任务
  • 入库

代码实现

任务实体封装 TaskModel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
/**
* <p>Created on 2017/4/14.</p>
*
* @author stormma
*
* @Description: <p>任务 model</p>
*/
public class TaskModel {
/**
* 上传类型(数据库对应表)
*/
private UpLoadType type;
/**
* 数据库对应的属主 id
*/
private Integer id;
/**
* 媒体类型 id
*/
private String mediaId;
public UpLoadType getType() {
return type;
}
public void setType(UpLoadType type) {
this.type = type;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getMediaId() {
return mediaId;
}
public void setMediaId(String mediaId) {
this.mediaId = mediaId;
}
@Override
public String toString() {
return "TaskModel{" +
"type=" + type +
", id=" + id +
", mediaId='" + mediaId + '\'' +
'}';
}
}

图片上传类型 UploadType

1
2
3
4
5
6
7
8
9
10
11
/**
* <p>Created on 2017/4/14.</p>
*
* @author stormma
*
* @Description: <p>图片上传类型,入库,对应于图片所属库表</p>
*/
public enum UpLoadType {
TYPE1, TYPE2, TYPE3, TYPE4
}

线程池配置 ExecutorConfig

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
/**
* <p>Created on 2017/4/14.</p>
*
* @author stormma
*
*
* @Description: <p>线程池的配置类</p>
*/
@Configuration
@EnableAsync
public class ExecutorConfig {
/** Set the ThreadPoolExecutor's core pool size. */
private int corePoolSize = 10;
/** Set the ThreadPoolExecutor's maximum pool size. */
private int maxPoolSize = 200;
/** Set the capacity for the ThreadPoolExecutor's BlockingQueue. */
private int queueCapacity = 10;
@Bean
public Executor myAsync() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(corePoolSize);
executor.setMaxPoolSize(maxPoolSize);
executor.setQueueCapacity(queueCapacity);
executor.setThreadNamePrefix(" uploadimg-");
/*CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行*/
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
}

处理任务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Component;
import pro.yueneng.dao.picture.ITrendPictureDao;
import pro.yueneng.dao.plan.IPlanPictureDao;
import pro.yueneng.exception.ServerSystemException;
import pro.yueneng.exception.WechatException;
import pro.yueneng.model.picture.TrendPicture;
import pro.yueneng.model.plan.PlanPicture;
import pro.yueneng.oos.service.IOssService;
import pro.yueneng.service.wechat.IWechatService;
import pro.yueneng.util.UuidUtil;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.concurrent.Future;
/**
* <p>Created on 2017/4/14.</p>
*
* @author stormma
* @Descrption: <p>图片上传任务,上传 oss, 入库</p>
*/
@Component
public class UploadImageTask {
@Autowired
private IOssService ossService;
@Autowired
private IWechatService wechatService;
@Autowired
private IType1Dao type1Dao;
@Autowired
private IType2Dao type2Dao;
/*logging*/
private static final Logger logger = LoggerFactory.getLogger(UploadImageTask.class);
@Async(value = "myAsync")
public Future<Integer> uploadImg(TaskModel model) {
logger.info("任务开始执行");
logger.info("线程名字:{}", Thread.currentThread().getName());
String fileName = UuidUtil.getUuid() + ".jpg";
String access_token;
try {
access_token = wechatService.getFrontAccessToken();
} catch (WechatException | ServerSystemException e) {
return new AsyncResult<>(0);
}
String url = "http://file.api.weixin.qq.com/cgi-bin/media/get?access_token=%s&media_id=%s";
String mediaId = model.getMediaId();
url = String.format(url, access_token, mediaId);
logger.info("请求 url:{}", url);
URL requestUrl;
try {
requestUrl = new URL(url);
} catch (MalformedURLException e) {
return new AsyncResult<>(0);
}
try {
//上传至阿里云 oss 服务器(存储)
ossService.saveObject(fileName, requestUrl.openConnection().getInputStream());
} catch (IOException e) {
return new AsyncResult<>(0);
}
String imgUrl = ossService.getImgOrRadioUrl(fileName);
if (imgUrl == null) {
return new AsyncResult<>(0);
}
switch (model.getType()) {
case TYPE1:
//建立数据库实体
Type1 type = new Type1();
type.setId(model.getId());
type1Dao.addPicture();
logger.info("入库成功(TYPE1)");
break;
case ....
default:
break;
}
logger.info(imgUrl);
return new AsyncResult<>(1);
}
}

阿里云 oss 服务类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
import com.aliyun.oss.HttpMethod;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.model.GeneratePresignedUrlRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import pro.yueneng.oos.config.OssConfigBean;
import pro.yueneng.oos.service.IOssService;
import pro.yueneng.oos.util.OssClientUtil;
import java.io.InputStream;
import java.net.URL;
import java.util.Date;
/**
* <p>Created on 2017/3/12.</p>
*
* @author StormMa
*
* @Description: oss service impl
*/
@Service
public class OssService implements IOssService {
@Autowired
private OssConfigBean configBean;
@Autowired
private OssClientUtil clientUtil;
/**
* logging
*/
private static final Logger logger = LoggerFactory.getLogger(OssService.class);
/**
* save an object. if sucess return true.
* @param key
* @param inputStream
* @return
*/
@Override
public boolean saveObject(String key, InputStream inputStream) {
OSSClient client = clientUtil.getOssClient();
try {
client.putObject(configBean.getBucketName(), key, inputStream);
} catch (Exception e) {
return false;
}
return true;
}
/**
* get file url by file name
* @param fileName
* @return
*/
@Override
public String getImgOrRadioUrl(String fileName) {
OSSClient client = clientUtil.getOssClient();
Date expiration = new Date(new Date().getTime() + 1000 * 100);
GeneratePresignedUrlRequest req = new GeneratePresignedUrlRequest(configBean.getBucketName(), fileName, HttpMethod.GET);
req.setExpiration(expiration);
URL signedUrl = client.generatePresignedUrl(req);
return filterUrl(signedUrl.toString());
}
/**
* filter param for url.
* @param signedUrl
* @return
*/
private String filterUrl(String signedUrl) {
if (!StringUtils.isEmpty(signedUrl)) {
return signedUrl.substring(0, signedUrl.indexOf("?"));
}
return null;
}
}

控制器实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@PostMapping(value = "/upload")
public RequestResult<Object> addTrend(@RequestBody Type1Model model) throws Exception {
Type1 type = new Type1();
CopyBeanUtil.copyBean(type, model);
//首先,入库内容,等待处理图片
int typeId = typeService.addType(type);
List<String> mediaIds = model.getMediaIds();
if (!CollectionUtils.isEmpty(mediaIds)) {
for (String mediaId : mediaIds) {
TaskModel taskModel = new TaskModel();
taskModel.setId(trendId);
taskModel.setMediaId(mediaId);
taskModel.setType(UpLoadType. TYPE1);
uploadImageTask.uploadImg(taskModel);
}
}
return ResultUtil.success(null);
}