部分手机在图片上传的时候,调取不到sd卡相册或其他图片,为了解决这个兼容性问题,同一个页面使用了两种图片上传方案。
html5 :图片编码成base64 ,发送到后台,解码存储。这种方法用于解决非微信浏览器的上传问题。
jsapi:用于解决微信浏览器的上传问题。
思路:
首先判断是否是微信浏览器(微信js接口提供方法),然后调用上面不同的方法。
这里记下jfinal整合jsapi的关键代码和流程 。
前端页面需要一段javascript ,官方文档有详细说明,以下我的config
wx.config({ debug: true, appId: 'wx23eeb004xxxx8ecb', // 必填,公众号的唯一标识 timestamp:'${timestamp}', // 必填,生成签名的时间戳 nonceStr: 't8bI2mW5Mxxxx20Y', // 必填,生成签名的随机串 signature: '${signature}', jsApiList: [ 'chooseImage' ] });
以下是前端页面对应的ctrl ,惯例只是关键部分
//微信
ApiConfig ac = new ApiConfig();
String token = ConfigUtil.get("weixinToken");
String appid = ConfigUtil.get("weixinAppId");
String secret = ConfigUtil.get("weixinSecret");
// 配置微信 API 相关常量
ac.setToken(token);
ac.setAppId(appid);
ac.setAppSecret(secret);
/**
* 是否对消息进行加密,对应于微信平台的消息加解密方式:
* 1:true进行加密且必须配置 encodingAesKey
* 2:false采用明文模式,同时也支持混合模式
*/
ac.setEncryptMessage(false);
ac.setEncodingAesKey(ConfigUtil.get("weixinEncodingAESKey"));
ApiConfigKit.setThreadLocalApiConfig(ac); //必须
JssdkTicket jssdkTicket = JssdkTicketUtil.getJssdkTicket();
if (!jssdkTicket.getErrmsg().equals("ok")){
setAttr("errormsg","如需使用图片上传功能,请刷新页面重试");
}else {
String fuckU= DateUtil.getCurMis().toString().substring(0,10);
String tempStr = new StringBuilder().append("jsapi_ticket=" + jssdkTicket.getTicket() + "&noncestr=t8bI2mW5Mma0I20Y×tamp=" + fuckU + "&url=" + getRequest().getRequestURL()+"").toString();
System.out.println("string1="+tempStr);
tempStr = EncryptionKit.sha1Encrypt(tempStr);
System.out.println("加密后="+tempStr);
setAttr("timestamp", fuckU);
setAttr("signature",tempStr);
}
createToken("blogToken", 30 * 60);
render(AppConst.PATH_WAP_PC+"/abc.ftl");
以下是JssdkTicketUtil ,该util用于缓存jsapi_ticket,也是微信官方文档中一再强调的东西
public class JssdkTicketUtil {
private static JssdkTicket jssdkTicket;
public static JssdkTicket getJssdkTicket() {
if(jssdkTicket != null && jssdkTicket.isAvailable()) {
return jssdkTicket;
} else {
refreshAccessToken();
return jssdkTicket;
}
}
private static void refreshAccessToken() {
jssdkTicket = requestJssdkTicket();
}
private static synchronized JssdkTicket requestJssdkTicket() {
JssdkTicket result = null;
AccessToken accessToken = AccessTokenApi.getAccessToken();
String json = HttpKit.get("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" + accessToken.getAccessToken() + "&type=jsapi");
result = new JssdkTicket(json);
if(!result.isAvailable()) {
refreshAccessToken();
}
return result;
}
}
以下是jssdkTicket ,用于存储信息
public class JssdkTicket {
private String jsapi ;//服务器返回
private Long expiredTime ; //过期时间
private Integer errcode; //错误码
private String errmsg; //错误信息
private String ticket; //票据
private Integer expires_in; //
public JssdkTicket(String jsapiStr){
this.jsapi = jsapiStr;
try {
Map e = (Map)(new ObjectMapper()).readValue(jsapiStr, Map.class);
this.expires_in = (Integer)e.get("expires_in");
this.errcode = (Integer)e.get("errcode");
this.errmsg = (String)e.get("errmsg");
this.ticket = (String)e.get("ticket");
if(this.expires_in != null) {
this.expiredTime = Long.valueOf(System.currentTimeMillis() + (long)((this.expires_in.intValue() - 5) * 1000));
}
} catch (Exception var3) {
throw new RuntimeException(var3);
}
}
public boolean isAvailable() {
return this.expiredTime == null ? false : (this.errcode != 0 ? false : (this.expiredTime.longValue() < System.currentTimeMillis() ? false : this.ticket != null));
}
public String getJsapi() {
return jsapi;
}
public Long getExpiredTime() {
return expiredTime;
}
public Integer getErrcode() {
return errcode;
}
public String getErrmsg() {
return errmsg;
}
public String getTicket() {
return ticket;
}
public Integer getExpires_in() {
return expires_in;
}
}
以上两个类完成参照jfinal-weixin-1.2中对access_token的处理方式 。感谢jfinal作者 @jfinal
:::::::::::::::::::::::::::::::::::::::::::::::::::
2015-05-29 16:29:58 更新
图片上传完成后,需要从微信服务器下载图片并保存到本地服务器
savePath = HttpClientKit.getFileAndSave("http://file.api.weixin.qq.com/cgi-bin/media/get?access_token=" + ss.getAccessToken() + "&media_id=" + list.get(i));
PS:savePath是本地服务器的保存路径
getFileAndSave方法的关键代码如下(需要引入commons-httpclient.jar):
/**
* 从微信服务器取图片并保存到服务器指定路径
* @param url 微信服务器路径
* @return 本地服务器路径
*/
public static String getFileAndSave(String url) {
String result = "";
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
String ymd = sdf.format(new Date());
String savePath = PathKit.getWebRootPath() + "/photo/"+ymd+"/";
File uploadDir = new File(savePath);
if (!uploadDir.exists()) {
uploadDir.mkdirs();
}
if (!uploadDir.isDirectory()) {
return "1"; //上传目录不存在。
}
if (!uploadDir.canWrite()) {
return "2"; //上传目录没有写权限
}
SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss"); // 时间戳
String newFileName = df.format(new Date()) + "_"
+ new Random().nextInt(1000) + ".jpg"; // 拼文件名
savePath += newFileName;
result = "/photo/"+ymd+"/" + newFileName;
HttpClient client = new HttpClient();
GetMethod get = new GetMethod(url);
// String filePath = FileKit.getSaveRealPath("jpg");
try {
File storeFile = new File(savePath);
FileOutputStream output = null;
client.executeMethod(get);
output = new FileOutputStream(storeFile);
output.write(get.getResponseBody());
output.close();
} catch (HttpException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return result;
}