package com.demo.controller.web.app; import java.io.BufferedOutputStream; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.net.URL; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSession; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import javax.servlet.http.HttpServletRequest; import org.apache.log4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import sun.misc.BASE64Decoder; import com.demo.common.Result; import com.demo.common.util.StringUtils; import com.demo.constant.Constant; import com.demo.constant.Enums; import com.demo.service.AppEspOrderService; import com.demo.service.AppEspProductService; import com.demo.service.AppUserInfoService; import com.demo.service.AppVersionService; import com.demo.service.UserService; import com.demo.service.eshop.EspOrderLogService; import com.demo.vo.AppEspOrder; import com.demo.vo.AppEspProduct; import com.demo.vo.AppUserInfo; import com.demo.vo.AppVersion; import com.demo.vo.EspOrderLog; import com.demo.vo.User; import net.sf.json.JSONObject; @Controller @RequestMapping("/app/*") public class AstroCalendarIOSVerifyController { private Logger log = Logger.getLogger(AstroCalendarIOSVerifyController.class); @Autowired private UserService userService; @Autowired private AppEspOrderService appEspOrderService; @Autowired private AppVersionService appVersionService; @Autowired private AppEspProductService appEspProductService; @Autowired private AppUserInfoService appUserInfoService; @Autowired private EspOrderLogService espOrderLogService; private static class TrustAnyTrustManager implements X509TrustManager { public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { } public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { } public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[] {}; } } private static class TrustAnyHostnameVerifier implements HostnameVerifier { public boolean verify(String hostname, SSLSession session) { return true; } } private static final String url_sandbox = "https://sandbox.itunes.apple.com/verifyReceipt"; private static final String url_verify = "https://buy.itunes.apple.com/verifyReceipt"; /** * * @param receipt 账单 * @url 要验证的地址 * @return null 或返回结果 沙盒 https://sandbox.itunes.apple.com/verifyReceipt * */ public String buyAppVerify(String receipt,String url,Map<String, String> map) { try { SSLContext sc = SSLContext.getInstance("SSL"); sc.init(null, new TrustManager[] { new TrustAnyTrustManager() },new java.security.SecureRandom()); URL console = new URL(url); HttpsURLConnection conn = (HttpsURLConnection) console.openConnection(); conn.setSSLSocketFactory(sc.getSocketFactory()); conn.setHostnameVerifier(new TrustAnyHostnameVerifier()); conn.setRequestMethod("POST"); conn.setRequestProperty("content-type", "text/json"); conn.setRequestProperty("Proxy-Connection", "Keep-Alive"); conn.setDoInput(true); conn.setDoOutput(true); conn.setConnectTimeout(30*1000);//设置连接超时30秒 BufferedOutputStream hurlBufOus = new BufferedOutputStream(conn.getOutputStream()); String str = String.format(Locale.CHINA, "{\"receipt-data\":\""+ receipt + "\"}"); System.out.println("str:" + str); hurlBufOus.write(str.getBytes()); hurlBufOus.flush(); InputStream is = conn.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(is)); String line = null; StringBuffer sb = new StringBuffer(); while ((line = reader.readLine()) != null) { sb.append(line); } System.out.println(sb.toString()); return sb.toString(); } catch (Exception ex) { log.error("系统异常"+ex); map.put("orderStatus", "D"); // ex.printStackTrace(); } return null; } @RequestMapping("/app/validateOrder" + Constant.JSON) @ResponseBody public Map<String, String> validateOrder(HttpServletRequest request) { long start = System.currentTimeMillis(); Map<String, String> map = new HashMap<String, String>(); User user = checkUserLogin(request); AppUserInfo appUser = null; if(user!=null){ appUser = new AppUserInfo(); appUser.setUserId(user.getUserId()); appUser = appUserInfoService.findByPk(appUser); } //判断app用户表里是否存在此用户 if(appUser == null){ map.put("loginStatus", "-1"); }else{ map.put("loginStatus", "0"); try { String receipt = request.getParameter("receipt"); String orderMonths = request.getParameter("orderMonths"); String versionCode = request.getParameter("versionCode"); String appId = request.getParameter("appId"); String price = request.getParameter("price"); if(StringUtils.isBlank(appId) || StringUtils.isBlank(versionCode)){ map.put("orderStatus", "D"); return map; } Integer vCode = Integer.parseInt(versionCode); Integer appID = Integer.parseInt(appId); AppEspOrder aeo = new AppEspOrder(); aeo.setReceipt(receipt); List<AppEspOrder> list = appEspOrderService.freeFindAll(aeo); if(list.size()==0){ //添加新订单 AppUserInfo aui = new AppUserInfo(); aui.setUserId(user.getUserId()); aui = appUserInfoService.findByPk(aui); SimpleDateFormat osf = new SimpleDateFormat("yyMMddHH"); String orderId = Enums.OrderPrefix.NA + osf.format(new Date())+ StringUtils.getRandomSixNUM(); if(aui != null){ AppVersion version = new AppVersion(); version.setVersionCode(vCode); int count = appVersionService.countFreeFind(version); AppEspProduct aep = new AppEspProduct(); aep.setAppId(appID); aep = appEspProductService.findByPK(aep); //检查appID,versionId是否合法 if(aep == null || count<0){ map.put("orderStatus", "C"); return map; } aeo.setAppId(aep.getAppId()); aeo.setAppName(aep.getAppName()); aeo.setVersionCode(vCode); aeo.setUserId(aui.getUserId()); aeo.setNickName(aui.getNickName()); aeo.setEmail(aui.getEmail()); aeo.setOrderId(orderId); aeo.setOrderMonths(orderMonths); aeo.setSubtotal(new Long(price)); aeo.setIsFree("N"); aeo.setOrderStatus("A");//新订单 aeo.setCreateBy("system"); aeo.setCreateDt(new Date()); aeo.setPaidDate(new Date()); appEspOrderService.insert(aeo); //订单日志 EspOrderLog log = new EspOrderLog(); log.setRemark("生成新订单,已支付,等待验证..."); log.setChangeTime(new Date()); log.setChangeUser("system"); log.setIsMem("N"); log.setType("A"); log.setOrderId(orderId); espOrderLogService.addOrderLog(log); } //向苹果服务器发起验证 Result result = validateAppleServler(map, receipt, url_verify, aeo, orderId); if(result.isSuccess()==true){ validateAppleServler(map, receipt, url_sandbox, aeo, orderId); } }else{//如果该收据已经存在,判断收据的订单状态,再判断是用户及月份是否相同,防止盗用receipt AppEspOrder order = list.get(0); if("A".equals(order.getOrderStatus()) || "D".equals(order.getOrderStatus())){//新订单已经添加尚未验证或验证超时连接错误,需重新请求验证 Result result = validateAppleServler(map, order.getReceipt(), url_verify, order, order.getOrderId()); if(result.isSuccess()==true){ validateAppleServler(map, order.getReceipt(), url_sandbox, order, order.getOrderId()); } }else if("B".equals(order.getOrderStatus())){ if(receipt.equals(order.getReceipt())&&user.getUserId().equals(order.getUserId())&&orderMonths.equals(order.getOrderMonths())){ map.put("orderStatus", "B"); }else{ map.put("orderStatus", "C");//验证失败 } }else{ map.put("orderStatus", "C");//验证失败 } } } catch (Exception e) { map.put("orderStatus", "D"); log.error("系统异常"+e); e.printStackTrace(); } } long end = System.currentTimeMillis(); System.out.println("验证收据信息耗时:"+(end-start)+"毫秒"); return map; } //向苹果服务器发送验证请求 private Result validateAppleServler(Map<String, String> map, String receipt, String url, AppEspOrder aeo, String orderId) { Result result = new Result().setSuccess(false); String verifyResult = buyAppVerify(receipt,url,map); if (verifyResult != null) { JSONObject job = JSONObject.fromObject(verifyResult); String status = job.getString("status"); if ("0".equals(status)){// 验证成功 aeo.setOrderStatus("B"); String r_receipt=job.getString("receipt"); System.out.println(r_receipt); System.out.println("-------------------------------"); JSONObject returnJson = JSONObject.fromObject(r_receipt); String product_id = returnJson.getString("product_id"); //产品ID String quantity = returnJson.getString("quantity"); //数量 String transactionId = returnJson.getString("transaction_id");//交易id System.out.println("产品id:"+product_id+"\t"+"数量"+quantity+"\t"+"交易id"+transactionId); aeo.setProductId(product_id); int total = 0; if(!StringUtils.isBlank(quantity)) total = Integer.parseInt(quantity); aeo.setQuantity(total); aeo.setTransactionId(transactionId); appEspOrderService.update(aeo); EspOrderLog log2 = new EspOrderLog(); log2.setRemark("向苹果服务器发送验证成功..."); log2.setChangeTime(new Date()); log2.setChangeUser("system"); log2.setIsMem("N"); log2.setType("B"); log2.setOrderId(orderId); espOrderLogService.addOrderLog(log2); map.put("orderStatus", "B"); }else if("21007".equals(status)){//重新验证,更改路径为正式环境的路径 EspOrderLog log1 = new EspOrderLog(); log1.setRemark("向苹果正式服务器发送验证失败,得到状态值为21007."); log1.setChangeTime(new Date()); log1.setChangeUser("system"); log1.setIsMem("N"); log1.setType("A"); log1.setOrderId(orderId); espOrderLogService.addOrderLog(log1); result.setSuccess(true); }else{//验证失败 aeo.setOrderStatus("C"); appEspOrderService.update(aeo); EspOrderLog log1 = new EspOrderLog(); log1.setRemark("向苹果服务器发送验证失败..."); log1.setChangeTime(new Date()); log1.setChangeUser("system"); log1.setIsMem("N"); log1.setType("A"); log1.setOrderId(orderId); espOrderLogService.addOrderLog(log1); map.put("orderStatus", "C"); } } return result; } private User checkUserLogin(HttpServletRequest request) { String username = request.getParameter("username"); String password = request.getParameter("password"); if (StringUtils.isBlank(username) || StringUtils.isBlank(password)) { return null; } User user = new User(); try { user.setEmail(username); user.setPassword(password); user = userService.userLogin(user); } catch (Exception e) { log.error("登录失败,用户名或密码错误!" + e); } return user; } }