diff --git a/pom.xml b/pom.xml index a9721c920e744586ae9143109a08ee12f4f03711..a77d5dc27c621dece4e87ad1a7efdbc2c40ebfae 100644 --- a/pom.xml +++ b/pom.xml @@ -86,12 +86,6 @@ 1.9.12 - - com.alibaba - fastjson - 1.2.14 - - commons-dbcp commons-dbcp @@ -100,8 +94,6 @@ - - ch.qos.logback logback-classic @@ -134,11 +126,6 @@ 3.5 - - commons-beanutils - commons-beanutils - 1.9.2 - commons-collections diff --git a/src/main/java/com/alipay/demo/trade/DemoHbRunner.java b/src/main/java/com/alipay/demo/trade/DemoHbRunner.java new file mode 100644 index 0000000000000000000000000000000000000000..69430ec2d9227180bd7f4dd166ca9df9b95aba0d --- /dev/null +++ b/src/main/java/com/alipay/demo/trade/DemoHbRunner.java @@ -0,0 +1,54 @@ +package com.alipay.demo.trade; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import com.alipay.demo.trade.model.builder.AlipayHeartbeatSynRequestBuilder; +import com.alipay.demo.trade.model.hb.*; +import com.alipay.demo.trade.service.AlipayMonitorService; +import com.alipay.demo.trade.service.impl.hb.AbsHbRunner; +import com.alipay.demo.trade.service.impl.hb.HbQueue; +import com.alipay.demo.trade.utils.Utils; + +/** + * Created by liuyangkly on 15/10/23. + 执行调度,主要任务由两个线程完成,交易线程(调用当面付2.0接口)和交易保障线程(轮询),具体需要做的事情 + 1.当面付程序每执行完一笔交易后将交易结果保存在临时队列 + 2.轮询线程读取临时队列,获取基础采集信息和最多30条trade_info信息,调用支付宝monitor.heartbeat.syn接口 + 示例代码仅封装了如何调用该接口api,采集数据,比如采集网络信息、交易耗时、异常信息等,需要系统商开发者自行完成。 + */ +public class DemoHbRunner extends AbsHbRunner { + + public DemoHbRunner(AlipayMonitorService monitorService) { + super(monitorService); + } + + @Override + public String getAppAuthToken() { + // 对于系统商,如果是为了商户开发监控保障接口,则需要传此值,否则如果为系统商自己做交易保障接口开发,则可不传。 + return null; + } + + @Override + public AlipayHeartbeatSynRequestBuilder getBuilder() { + // 系统商使用的交易信息格式,json字符串类型,从交易队列中获取 + List sysTradeInfoList = HbQueue.poll(); + + // 异常信息的采集,系统商自行完成 + List exceptionInfoList = new ArrayList(); + // exceptionInfoList.add(ExceptionInfo.HE_SCANER); + // exceptionInfoList.add(ExceptionInfo.HE_PRINTER); + // exceptionInfoList.add(ExceptionInfo.HE_OTHER); + + AlipayHeartbeatSynRequestBuilder builder = new AlipayHeartbeatSynRequestBuilder() + .setProduct(Product.FP).setType(Type.CR).setEquipmentId("cr1000001") + .setEquipmentStatus(EquipStatus.NORMAL).setTime(Utils.toDate(new Date())) + .setStoreId("store10001").setMac("0a:00:27:00:00:00").setNetworkType("LAN") + .setProviderId("2088911212323549") // 设置系统商pid + .setSysTradeInfoList(sysTradeInfoList) // 系统商同步trade_info信息 + .setExceptionInfoList(exceptionInfoList) // 填写异常信息,如果有的话 + ; + return builder; + } +} diff --git a/src/main/java/com/alipay/demo/trade/Main.java b/src/main/java/com/alipay/demo/trade/Main.java new file mode 100644 index 0000000000000000000000000000000000000000..3da0aa35933c0953456f802f178608af1a1cbaba --- /dev/null +++ b/src/main/java/com/alipay/demo/trade/Main.java @@ -0,0 +1,454 @@ +package com.alipay.demo.trade; + +import java.util.*; + +import org.apache.commons.lang.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import com.alipay.api.AlipayResponse; +import com.alipay.api.domain.TradeFundBill; +import com.alipay.api.response.AlipayTradePrecreateResponse; +import com.alipay.api.response.AlipayTradeQueryResponse; +import com.alipay.api.response.MonitorHeartbeatSynResponse; +import com.alipay.demo.trade.config.Configs; +import com.alipay.demo.trade.model.ExtendParams; +import com.alipay.demo.trade.model.GoodsDetail; +import com.alipay.demo.trade.model.builder.*; +import com.alipay.demo.trade.model.hb.*; +import com.alipay.demo.trade.model.result.AlipayF2FPayResult; +import com.alipay.demo.trade.model.result.AlipayF2FPrecreateResult; +import com.alipay.demo.trade.model.result.AlipayF2FQueryResult; +import com.alipay.demo.trade.model.result.AlipayF2FRefundResult; +import com.alipay.demo.trade.service.AlipayMonitorService; +import com.alipay.demo.trade.service.AlipayTradeService; +import com.alipay.demo.trade.service.impl.AlipayMonitorServiceImpl; +import com.alipay.demo.trade.service.impl.AlipayTradeServiceImpl; +import com.alipay.demo.trade.service.impl.AlipayTradeWithHBServiceImpl; +import com.alipay.demo.trade.utils.Utils; + +/** + * Created by liuyangkly on 15/8/9. + * 简单main函数,用于测试当面付api + * sdk和demo的意见和问题反馈请联系:liuyang.kly@alipay.com + */ +public class Main { + private static Log log = LogFactory.getLog(Main.class); + + // 支付宝当面付2.0服务 + private static AlipayTradeService tradeService; + + // 支付宝当面付2.0服务(集成了交易保障接口逻辑) + private static AlipayTradeService tradeWithHBService; + + // 支付宝交易保障接口服务,供测试接口api使用,请先阅读readme.txt + private static AlipayMonitorService monitorService; + + static { + /** 一定要在创建AlipayTradeService之前调用Configs.init()设置默认参数 + * Configs会读取classpath下的zfbinfo.properties文件配置信息,如果找不到该文件则确认该文件是否在classpath目录 + */ + Configs.init("zfbinfo.properties"); + + /** 使用Configs提供的默认参数 + * AlipayTradeService可以使用单例或者为静态成员对象,不需要反复new + */ + tradeService = new AlipayTradeServiceImpl.ClientBuilder().build(); + + // 支付宝当面付2.0服务(集成了交易保障接口逻辑) + tradeWithHBService = new AlipayTradeWithHBServiceImpl.ClientBuilder().build(); + + /** 如果需要在程序中覆盖Configs提供的默认参数, 可以使用ClientBuilder类的setXXX方法修改默认参数 否则使用代码中的默认设置 */ + monitorService = new AlipayMonitorServiceImpl.ClientBuilder() + .setGatewayUrl("http://mcloudmonitor.com/gateway.do").setCharset("GBK") + .setFormat("json").build(); + } + + // 简单打印应答 + private void dumpResponse(AlipayResponse response) { + if (response != null) { + log.info(String.format("code:%s, msg:%s", response.getCode(), response.getMsg())); + if (StringUtils.isNotEmpty(response.getSubCode())) { + log.info(String.format("subCode:%s, subMsg:%s", response.getSubCode(), + response.getSubMsg())); + } + log.info("body:" + response.getBody()); + } + } + + public static void main(String[] args) { + Main main = new Main(); + + // 系统商商测试交易保障接口api + // main.test_monitor_sys(); + + // POS厂商测试交易保障接口api + // main.test_monitor_pos(); + + // 测试交易保障接口调度 + // main.test_monitor_schedule_logic(); + + // 测试当面付2.0支付(使用未集成交易保障接口的当面付2.0服务) + // main.test_trade_pay(tradeService); + + // 测试查询当面付2.0交易 + // main.test_trade_query(); + + // 测试当面付2.0退货 + // main.test_trade_refund(); + + // 测试当面付2.0生成支付二维码 + main.test_trade_precreate(); + } + + // 测试系统商交易保障调度 + public void test_monitor_schedule_logic() { + // 启动交易保障线程 + DemoHbRunner demoRunner = new DemoHbRunner(monitorService); + demoRunner.setDelay(5); // 设置启动后延迟5秒开始调度,不设置则默认3秒 + demoRunner.setDuration(10); // 设置间隔10秒进行调度,不设置则默认15 * 60秒 + demoRunner.schedule(); + + // 启动当面付,此处每隔5秒调用一次支付接口,并且当随机数为0时交易保障线程退出 + while (Math.random() != 0) { + test_trade_pay(tradeWithHBService); + Utils.sleep(5 * 1000); + } + + // 满足退出条件后可以调用shutdown优雅安全退出 + demoRunner.shutdown(); + } + + // 系统商的调用样例,填写了所有系统商商需要填写的字段 + public void test_monitor_sys() { + // 系统商使用的交易信息格式,json字符串类型 + List sysTradeInfoList = new ArrayList(); + sysTradeInfoList.add(SysTradeInfo.newInstance("00000001", 5.2, HbStatus.S)); + sysTradeInfoList.add(SysTradeInfo.newInstance("00000002", 4.4, HbStatus.F)); + sysTradeInfoList.add(SysTradeInfo.newInstance("00000003", 11.3, HbStatus.P)); + sysTradeInfoList.add(SysTradeInfo.newInstance("00000004", 3.2, HbStatus.X)); + sysTradeInfoList.add(SysTradeInfo.newInstance("00000005", 4.1, HbStatus.X)); + + // 填写异常信息,如果有的话 + List exceptionInfoList = new ArrayList(); + exceptionInfoList.add(ExceptionInfo.HE_SCANER); + // exceptionInfoList.add(ExceptionInfo.HE_PRINTER); + // exceptionInfoList.add(ExceptionInfo.HE_OTHER); + + // 填写扩展参数,如果有的话 + Map extendInfo = new HashMap(); + // extendInfo.put("SHOP_ID", "BJ_ZZ_001"); + // extendInfo.put("TERMINAL_ID", "1234"); + + String appAuthToken = "应用授权令牌";//根据真实值填写 + + AlipayHeartbeatSynRequestBuilder builder = new AlipayHeartbeatSynRequestBuilder() + .setAppAuthToken(appAuthToken).setProduct(Product.FP).setType(Type.CR) + .setEquipmentId("cr1000001").setEquipmentStatus(EquipStatus.NORMAL) + .setTime(Utils.toDate(new Date())).setStoreId("store10001").setMac("0a:00:27:00:00:00") + .setNetworkType("LAN").setProviderId("2088911212323549") // 设置系统商pid + .setSysTradeInfoList(sysTradeInfoList) // 系统商同步trade_info信息 + // .setExceptionInfoList(exceptionInfoList) // 填写异常信息,如果有的话 + .setExtendInfo(extendInfo) // 填写扩展信息,如果有的话 + ; + + MonitorHeartbeatSynResponse response = monitorService.heartbeatSyn(builder); + dumpResponse(response); + } + + // POS厂商的调用样例,填写了所有pos厂商需要填写的字段 + public void test_monitor_pos() { + // POS厂商使用的交易信息格式,字符串类型 + List posTradeInfoList = new ArrayList(); + posTradeInfoList.add(PosTradeInfo.newInstance(HbStatus.S, "1324", 7)); + posTradeInfoList.add(PosTradeInfo.newInstance(HbStatus.X, "1326", 15)); + posTradeInfoList.add(PosTradeInfo.newInstance(HbStatus.S, "1401", 8)); + posTradeInfoList.add(PosTradeInfo.newInstance(HbStatus.F, "1405", 3)); + + // 填写异常信息,如果有的话 + List exceptionInfoList = new ArrayList(); + exceptionInfoList.add(ExceptionInfo.HE_PRINTER); + + // 填写扩展参数,如果有的话 + Map extendInfo = new HashMap(); + // extendInfo.put("SHOP_ID", "BJ_ZZ_001"); + // extendInfo.put("TERMINAL_ID", "1234"); + + AlipayHeartbeatSynRequestBuilder builder = new AlipayHeartbeatSynRequestBuilder() + .setProduct(Product.FP) + .setType(Type.SOFT_POS) + .setEquipmentId("soft100001") + .setEquipmentStatus(EquipStatus.NORMAL) + .setTime("2015-09-28 11:14:49") + .setManufacturerPid("2088000000000009") + // 填写机具商的支付宝pid + .setStoreId("store200001").setEquipmentPosition("31.2433190000,121.5090750000") + .setBbsPosition("2869719733-065|2896507033-091").setNetworkStatus("gggbbbgggnnn") + .setNetworkType("3G").setBattery("98").setWifiMac("0a:00:27:00:00:00") + .setWifiName("test_wifi_name").setIp("192.168.1.188") + .setPosTradeInfoList(posTradeInfoList) // POS厂商同步trade_info信息 + // .setExceptionInfoList(exceptionInfoList) // 填写异常信息,如果有的话 + .setExtendInfo(extendInfo) // 填写扩展信息,如果有的话 + ; + + MonitorHeartbeatSynResponse response = monitorService.heartbeatSyn(builder); + dumpResponse(response); + } + + // 测试当面付2.0支付 + public void test_trade_pay(AlipayTradeService service) { + // (必填) 商户网站订单系统中唯一订单号,64个字符以内,只能包含字母、数字、下划线, + // 需保证商户系统端不能重复,建议通过数据库sequence生成, + String outTradeNo = "tradepay" + System.currentTimeMillis() + + (long) (Math.random() * 10000000L); + + // (必填) 订单标题,粗略描述用户的支付目的。如“xxx品牌xxx门店消费” + String subject = "xxx品牌xxx门店当面付消费"; + + // (必填) 订单总金额,单位为元,不能超过1亿元 + // 如果同时传入了【打折金额】,【不可打折金额】,【订单总金额】三者,则必须满足如下条件:【订单总金额】=【打折金额】+【不可打折金额】 + String totalAmount = "0.01"; + + // (必填) 付款条码,用户支付宝钱包手机app点击“付款”产生的付款条码 + String authCode = "用户自己的支付宝付款码"; // 条码示例,286648048691290423 + // (可选,根据需要决定是否使用) 订单可打折金额,可以配合商家平台配置折扣活动,如果订单部分商品参与打折,可以将部分商品总价填写至此字段,默认全部商品可打折 + // 如果该值未传入,但传入了【订单总金额】,【不可打折金额】 则该值默认为【订单总金额】- 【不可打折金额】 + // String discountableAmount = "1.00"; // + + // (可选) 订单不可打折金额,可以配合商家平台配置折扣活动,如果酒水不参与打折,则将对应金额填写至此字段 + // 如果该值未传入,但传入了【订单总金额】,【打折金额】,则该值默认为【订单总金额】-【打折金额】 + String undiscountableAmount = "0.0"; + + // 卖家支付宝账号ID,用于支持一个签约账号下支持打款到不同的收款账号,(打款到sellerId对应的支付宝账号) + // 如果该字段为空,则默认为与支付宝签约的商户的PID,也就是appid对应的PID + String sellerId = ""; + + // 订单描述,可以对交易或商品进行一个详细地描述,比如填写"购买商品3件共20.00元" + String body = "购买商品3件共20.00元"; + + // 商户操作员编号,添加此参数可以为商户操作员做销售统计 + String operatorId = "test_operator_id"; + + // (必填) 商户门店编号,通过门店号和商家后台可以配置精准到门店的折扣信息,详询支付宝技术支持 + String storeId = "test_store_id"; + + // 业务扩展参数,目前可添加由支付宝分配的系统商编号(通过setSysServiceProviderId方法),详情请咨询支付宝技术支持 + String providerId = "2088100200300400500"; + ExtendParams extendParams = new ExtendParams(); + extendParams.setSysServiceProviderId(providerId); + + // 支付超时,线下扫码交易定义为5分钟 + String timeoutExpress = "5m"; + + // 商品明细列表,需填写购买商品详细信息, + List goodsDetailList = new ArrayList(); + // 创建一个商品信息,参数含义分别为商品id(使用国标)、名称、单价(单位为分)、数量,如果需要添加商品类别,详见GoodsDetail + GoodsDetail goods1 = GoodsDetail.newInstance("goods_id001", "xxx面包", 1000, 1); + // 创建好一个商品后添加至商品明细列表 + goodsDetailList.add(goods1); + + // 继续创建并添加第一条商品信息,用户购买的产品为“黑人牙刷”,单价为5.00元,购买了两件 + GoodsDetail goods2 = GoodsDetail.newInstance("goods_id002", "xxx牙刷", 500, 2); + goodsDetailList.add(goods2); + + String appAuthToken = "应用授权令牌";//根据真实值填写 + + // 创建条码支付请求builder,设置请求参数 + AlipayTradePayRequestBuilder builder = new AlipayTradePayRequestBuilder() + // .setAppAuthToken(appAuthToken) + .setOutTradeNo(outTradeNo).setSubject(subject).setAuthCode(authCode) + .setTotalAmount(totalAmount).setStoreId(storeId) + .setUndiscountableAmount(undiscountableAmount).setBody(body).setOperatorId(operatorId) + .setExtendParams(extendParams).setSellerId(sellerId) + .setGoodsDetailList(goodsDetailList).setTimeoutExpress(timeoutExpress); + + // 调用tradePay方法获取当面付应答 + AlipayF2FPayResult result = service.tradePay(builder); + switch (result.getTradeStatus()) { + case SUCCESS: + log.info("支付宝支付成功: )"); + break; + + case FAILED: + log.error("支付宝支付失败!!!"); + break; + + case UNKNOWN: + log.error("系统异常,订单状态未知!!!"); + break; + + default: + log.error("不支持的交易状态,交易返回异常!!!"); + break; + } + } + + // 测试当面付2.0查询订单 + public void test_trade_query() { + // (必填) 商户订单号,通过此商户订单号查询当面付的交易状态 + String outTradeNo = "tradepay14817938139942440181"; + + // 创建查询请求builder,设置请求参数 + AlipayTradeQueryRequestBuilder builder = new AlipayTradeQueryRequestBuilder() + .setOutTradeNo(outTradeNo); + + AlipayF2FQueryResult result = tradeService.queryTradeResult(builder); + switch (result.getTradeStatus()) { + case SUCCESS: + log.info("查询返回该订单支付成功: )"); + + AlipayTradeQueryResponse response = result.getResponse(); + dumpResponse(response); + + log.info(response.getTradeStatus()); + if (Utils.isListNotEmpty(response.getFundBillList())) { + for (TradeFundBill bill : response.getFundBillList()) { + log.info(bill.getFundChannel() + ":" + bill.getAmount()); + } + } + break; + + case FAILED: + log.error("查询返回该订单支付失败或被关闭!!!"); + break; + + case UNKNOWN: + log.error("系统异常,订单支付状态未知!!!"); + break; + + default: + log.error("不支持的交易状态,交易返回异常!!!"); + break; + } + } + + // 测试当面付2.0退款 + public void test_trade_refund() { + // (必填) 外部订单号,需要退款交易的商户外部订单号 + String outTradeNo = "tradepay14817938139942440181"; + + // (必填) 退款金额,该金额必须小于等于订单的支付金额,单位为元 + String refundAmount = "0.01"; + + // (可选,需要支持重复退货时必填) 商户退款请求号,相同支付宝交易号下的不同退款请求号对应同一笔交易的不同退款申请, + // 对于相同支付宝交易号下多笔相同商户退款请求号的退款交易,支付宝只会进行一次退款 + String outRequestNo = ""; + + // (必填) 退款原因,可以说明用户退款原因,方便为商家后台提供统计 + String refundReason = "正常退款,用户买多了"; + + // (必填) 商户门店编号,退款情况下可以为商家后台提供退款权限判定和统计等作用,详询支付宝技术支持 + String storeId = "test_store_id"; + + // 创建退款请求builder,设置请求参数 + AlipayTradeRefundRequestBuilder builder = new AlipayTradeRefundRequestBuilder() + .setOutTradeNo(outTradeNo).setRefundAmount(refundAmount).setRefundReason(refundReason) + .setOutRequestNo(outRequestNo).setStoreId(storeId); + + AlipayF2FRefundResult result = tradeService.tradeRefund(builder); + switch (result.getTradeStatus()) { + case SUCCESS: + log.info("支付宝退款成功: )"); + break; + + case FAILED: + log.error("支付宝退款失败!!!"); + break; + + case UNKNOWN: + log.error("系统异常,订单退款状态未知!!!"); + break; + + default: + log.error("不支持的交易状态,交易返回异常!!!"); + break; + } + } + + // 测试当面付2.0生成支付二维码 + public void test_trade_precreate() { + // (必填) 商户网站订单系统中唯一订单号,64个字符以内,只能包含字母、数字、下划线, + // 需保证商户系统端不能重复,建议通过数据库sequence生成, + String outTradeNo = "tradeprecreate" + System.currentTimeMillis() + + (long) (Math.random() * 10000000L); + + // (必填) 订单标题,粗略描述用户的支付目的。如“xxx品牌xxx门店当面付扫码消费” + String subject = "xxx品牌xxx门店当面付扫码消费"; + + // (必填) 订单总金额,单位为元,不能超过1亿元 + // 如果同时传入了【打折金额】,【不可打折金额】,【订单总金额】三者,则必须满足如下条件:【订单总金额】=【打折金额】+【不可打折金额】 + String totalAmount = "0.01"; + + // (可选) 订单不可打折金额,可以配合商家平台配置折扣活动,如果酒水不参与打折,则将对应金额填写至此字段 + // 如果该值未传入,但传入了【订单总金额】,【打折金额】,则该值默认为【订单总金额】-【打折金额】 + String undiscountableAmount = "0"; + + // 卖家支付宝账号ID,用于支持一个签约账号下支持打款到不同的收款账号,(打款到sellerId对应的支付宝账号) + // 如果该字段为空,则默认为与支付宝签约的商户的PID,也就是appid对应的PID + String sellerId = ""; + + // 订单描述,可以对交易或商品进行一个详细地描述,比如填写"购买商品2件共15.00元" + String body = "购买商品3件共20.00元"; + + // 商户操作员编号,添加此参数可以为商户操作员做销售统计 + String operatorId = "test_operator_id"; + + // (必填) 商户门店编号,通过门店号和商家后台可以配置精准到门店的折扣信息,详询支付宝技术支持 + String storeId = "test_store_id"; + + // 业务扩展参数,目前可添加由支付宝分配的系统商编号(通过setSysServiceProviderId方法),详情请咨询支付宝技术支持 + ExtendParams extendParams = new ExtendParams(); + extendParams.setSysServiceProviderId("2088100200300400500"); + + // 支付超时,定义为120分钟 + String timeoutExpress = "120m"; + + // 商品明细列表,需填写购买商品详细信息, + List goodsDetailList = new ArrayList(); + // 创建一个商品信息,参数含义分别为商品id(使用国标)、名称、单价(单位为分)、数量,如果需要添加商品类别,详见GoodsDetail + GoodsDetail goods1 = GoodsDetail.newInstance("goods_id001", "xxx小面包", 1000, 1); + // 创建好一个商品后添加至商品明细列表 + goodsDetailList.add(goods1); + + // 继续创建并添加第一条商品信息,用户购买的产品为“黑人牙刷”,单价为5.00元,购买了两件 + GoodsDetail goods2 = GoodsDetail.newInstance("goods_id002", "xxx牙刷", 500, 2); + goodsDetailList.add(goods2); + + // 创建扫码支付请求builder,设置请求参数 + AlipayTradePrecreateRequestBuilder builder = new AlipayTradePrecreateRequestBuilder() + .setSubject(subject).setTotalAmount(totalAmount).setOutTradeNo(outTradeNo) + .setUndiscountableAmount(undiscountableAmount).setSellerId(sellerId).setBody(body) + .setOperatorId(operatorId).setStoreId(storeId).setExtendParams(extendParams) + .setTimeoutExpress(timeoutExpress) + // .setNotifyUrl("http://www.test-notify-url.com")//支付宝服务器主动通知商户服务器里指定的页面http路径,根据需要设置 + .setGoodsDetailList(goodsDetailList); + + AlipayF2FPrecreateResult result = tradeService.tradePrecreate(builder); + switch (result.getTradeStatus()) { + case SUCCESS: + log.info("支付宝预下单成功: )"); + + AlipayTradePrecreateResponse response = result.getResponse(); + dumpResponse(response); + + // 需要修改为运行机器上的路径 + String filePath = String.format("/Users/sudo/Desktop/qr-%s.png", + response.getOutTradeNo()); + log.info("filePath:" + filePath); + // ZxingUtils.getQRCodeImge(response.getQrCode(), 256, filePath); + break; + + case FAILED: + log.error("支付宝预下单失败!!!"); + break; + + case UNKNOWN: + log.error("系统异常,预下单状态未知!!!"); + break; + + default: + log.error("不支持的交易状态,交易返回异常!!!"); + break; + } + } +} diff --git a/src/main/java/com/mmall/common/Const.java b/src/main/java/com/mmall/common/Const.java index 4313a28d8e71d29b27677080eee1dc4c04928e08..07aaafa5c02e575dfb3c42ce4f9820ce11e98ce3 100644 --- a/src/main/java/com/mmall/common/Const.java +++ b/src/main/java/com/mmall/common/Const.java @@ -32,7 +32,11 @@ public class Const { } public enum ProductStatusEnum { - ON_SALE(1, "在线"); + ON_SALE(1, "在售"), + OFF_SHELF(2,"下架"), + DELETE(3,"删除"); + + private int code; @@ -60,4 +64,110 @@ public class Const { } } + public enum OrderStatusEnum{ + CANCELED(0,"已取消"), + NO_PAY(10,"未支付"), + PAID(20,"已支付"), + SHIPPED(40,"已发货"), + ORDER_SUCCESS(50,"订单完成"), + ORDER_CLOSE(60,"订单关闭"); + + + private int code; + private String value; + + OrderStatusEnum(int code, String value) { + this.code = code; + this.value = value; + } + + public String getValue() { + return value; + } + + public int getCode() { + return code; + } + + + /** + * 根据code获取value + * @param code + * @return + */ + public static OrderStatusEnum codeOf(int code){ + for(OrderStatusEnum orderStatusEnum : values()){ + if(orderStatusEnum.getCode() == code){ + return orderStatusEnum; + } + } + throw new RuntimeException("没有该枚举类型"); + } + } + + public interface AlipayCallback{ + String WAIT_BUYER_PAY = "WAIT_BUYER_PAY"; + String TRADE_STATUS_TRADE_SUCCESS = "TRADE_SUCCESS"; + + String RESPONSE_SUCCESS = "success"; + String RESPONSE_FAILED = "failed"; + } + + public enum PayPlatFormEnum{ + + ALIPAY(1,"支付宝"); + + private int code; + private String value; + + + PayPlatFormEnum(int code, String value) { + this.code = code; + this.value = value; + } + + public String getValue() { + return value; + } + + public int getCode() { + return code; + } + } + + public enum PaymentTypeEnum{ + + ONLINE_PAY(1,"在线支付"); + + private int code; + private String value; + + + PaymentTypeEnum(int code, String value) { + this.code = code; + this.value = value; + } + + public String getValue() { + return value; + } + + public int getCode() { + return code; + } + + /** + * 根据code获取value + * @param code + * @return + */ + public static PaymentTypeEnum codeOf(int code){ + for(PaymentTypeEnum paymentTypeEnum : values()){ + if(paymentTypeEnum.getCode() == code){ + return paymentTypeEnum; + } + } + throw new RuntimeException("没有该枚举类型"); + } + } } diff --git a/src/main/java/com/mmall/controller/backend/CategoryManageController.java b/src/main/java/com/mmall/controller/backend/CategoryManageController.java index 03ef17d9b9d309e248d1473cba4cd54ba9784674..f540cbbe7901c007dcb7ef73aa60f5e72e612d6d 100644 --- a/src/main/java/com/mmall/controller/backend/CategoryManageController.java +++ b/src/main/java/com/mmall/controller/backend/CategoryManageController.java @@ -102,7 +102,7 @@ public class CategoryManageController { * @return */ @ResponseBody - @RequestMapping(value = "/get_category_and_deep_children_category.do") + @RequestMapping(value = "get_category_and_deep_children_category.do") public ServerResponse getCategoryAndDeepChildrenCategory(HttpSession session, @RequestParam(value = "categoryId", defaultValue = "0") Integer categoryId) { User user = (User)session.getAttribute(Const.CURRENT_USER); diff --git a/src/main/java/com/mmall/controller/backend/OrderManageController.java b/src/main/java/com/mmall/controller/backend/OrderManageController.java new file mode 100644 index 0000000000000000000000000000000000000000..ee4702b35ea2cdc1fb84052622ca4970ee2cfbf3 --- /dev/null +++ b/src/main/java/com/mmall/controller/backend/OrderManageController.java @@ -0,0 +1,118 @@ +package com.mmall.controller.backend; + +import com.github.pagehelper.PageInfo; +import com.mmall.common.Const; +import com.mmall.common.ResponseCode; +import com.mmall.common.ServerResponse; +import com.mmall.pojo.User; +import com.mmall.service.IOrderService; +import com.mmall.service.IUserService; +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.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; + +import javax.servlet.http.HttpSession; + +/** + * Created by qujian on 2017/7/30. + */ +@Controller +@RequestMapping(value = "/order/manage/") +public class OrderManageController { + + @Autowired + private IUserService iUserService; + + @Autowired + private IOrderService iOrderService; + + /** + * 管理员查看的订单列表 + * @param session + * @param pageNum + * @param pageSize + * @return + */ + @ResponseBody + @RequestMapping(value = "/list.do") + public ServerResponse list(HttpSession session, + @RequestParam(value = "pageNum",defaultValue = "1") int pageNum, + @RequestParam(value = "pageSize",defaultValue = "10") int pageSize){ + User user = (User)session.getAttribute(Const.CURRENT_USER); + if(user == null){ + return ServerResponse.createByErrorCodeMessage(ResponseCode.ILLEGAL_ARGUMENT.getCode(),ResponseCode.NEED_LOGIN.getDesc()); + } + if (iUserService.checkAdminRole(user).isSuccess()) { + return iOrderService.manageList(pageNum,pageSize); + } else { + return ServerResponse.createByErrorMessage("无权限操作,需要管理员权限"); + } + } + + /** + * 管理员查看详情 + * @param session + * @param orderNo + * @return + */ + @ResponseBody + @RequestMapping(value = "/detail.do") + public ServerResponse detail(HttpSession session,Long orderNo){ + User user = (User)session.getAttribute(Const.CURRENT_USER); + if(user == null){ + return ServerResponse.createByErrorCodeMessage(ResponseCode.ILLEGAL_ARGUMENT.getCode(),ResponseCode.NEED_LOGIN.getDesc()); + } + if (iUserService.checkAdminRole(user).isSuccess()) { + return iOrderService.manageDetail(orderNo); + } else { + return ServerResponse.createByErrorMessage("无权限操作,需要管理员权限"); + } + } + + /** + * 根据订单号查询订单 + * @param session + * @param orderNo + * @param pageNum + * @param pageSize + * @return + */ + @ResponseBody + @RequestMapping(value = "/search.do") + public ServerResponse search(HttpSession session,Long orderNo, + @RequestParam(value = "pageNum",defaultValue = "1") int pageNum, + @RequestParam(value = "pageSize",defaultValue = "10") int pageSize){ + User user = (User)session.getAttribute(Const.CURRENT_USER); + if(user == null){ + return ServerResponse.createByErrorCodeMessage(ResponseCode.ILLEGAL_ARGUMENT.getCode(),ResponseCode.NEED_LOGIN.getDesc()); + } + if (iUserService.checkAdminRole(user).isSuccess()) { + return iOrderService.manageSearch(orderNo,pageNum,pageSize); + } else { + return ServerResponse.createByErrorMessage("无权限操作,需要管理员权限"); + } + } + + + /** + * 发货 + * @param session + * @param orderNo + * @return + */ + @ResponseBody + @RequestMapping(value = "/send_goods.do") + public ServerResponse orderSendGoods(HttpSession session,Long orderNo){ + User user = (User)session.getAttribute(Const.CURRENT_USER); + if(user == null){ + return ServerResponse.createByErrorCodeMessage(ResponseCode.ILLEGAL_ARGUMENT.getCode(),ResponseCode.NEED_LOGIN.getDesc()); + } + if (iUserService.checkAdminRole(user).isSuccess()) { + return iOrderService.manageSendGoods(orderNo); + } else { + return ServerResponse.createByErrorMessage("无权限操作,需要管理员权限"); + } + } +} diff --git a/src/main/java/com/mmall/controller/backend/ProductManageController.java b/src/main/java/com/mmall/controller/backend/ProductManageController.java index 77310b5ef0a9deb4c1d8d1530cfb3376ccb371e9..75147ab66982452f9f2bbd8f85232b4bc2294810 100644 --- a/src/main/java/com/mmall/controller/backend/ProductManageController.java +++ b/src/main/java/com/mmall/controller/backend/ProductManageController.java @@ -162,7 +162,7 @@ public class ProductManageController { * @return */ @ResponseBody - @RequestMapping(value = "/upload.do") + @RequestMapping(value = "upload.do") public ServerResponse upload(HttpSession session, @RequestParam(value = "upload_file", required = false) MultipartFile file, HttpServletRequest request) { @@ -193,7 +193,7 @@ public class ProductManageController { * @return */ @ResponseBody - @RequestMapping(value = "/richtext_img_upload.do") + @RequestMapping(value = "richtext_img_upload.do") public Map richtextImgUpload(HttpSession session, @RequestParam(value = "upload_file", required = false) MultipartFile file, HttpServletRequest request, HttpServletResponse response) { diff --git a/src/main/java/com/mmall/controller/protal/CartController.java b/src/main/java/com/mmall/controller/protal/CartController.java index 67698128d27d50888f1af180e790764ed8e75015..a2ad992d6230877aac57138a0d36af5d31b057d1 100644 --- a/src/main/java/com/mmall/controller/protal/CartController.java +++ b/src/main/java/com/mmall/controller/protal/CartController.java @@ -17,6 +17,7 @@ import com.mmall.pojo.vo.CartVo; import com.mmall.service.ICartService; /** + * 购物车模块 * Created by qujian on 2017/6/29. */ @Controller @@ -64,6 +65,9 @@ public class CartController { if(product == null){ return ServerResponse.createByErrorMessage("该商品不存在"); } + if(product.getStatus() == Const.ProductStatusEnum.OFF_SHELF.getCode()){ + return ServerResponse.createByErrorMessage("该商品已下架"); + } return iCartService.add(user.getId(), productId, count); } diff --git a/src/main/java/com/mmall/controller/protal/OrderController.java b/src/main/java/com/mmall/controller/protal/OrderController.java new file mode 100644 index 0000000000000000000000000000000000000000..c1bf9a66f39d06cf359d46f0a321290845b6a0fd --- /dev/null +++ b/src/main/java/com/mmall/controller/protal/OrderController.java @@ -0,0 +1,238 @@ +package com.mmall.controller.protal; + +import java.util.Iterator; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; + +import com.github.pagehelper.PageInfo; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +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.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; + +import com.alipay.api.AlipayApiException; +import com.alipay.api.internal.util.AlipaySignature; +import com.alipay.demo.trade.config.Configs; +import com.google.common.collect.Maps; +import com.mmall.common.Const; +import com.mmall.common.ResponseCode; +import com.mmall.common.ServerResponse; +import com.mmall.pojo.User; +import com.mmall.service.IOrderService; + +/** + * 支付模块 + * Created by qujian on 2017/7/14. + */ +@Controller +@RequestMapping(value = "/order") +public class OrderController { + + @Autowired + private IOrderService iOrderService; + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + + /** + * 创建订单 + * @param session + * @param shippingId + * @return + */ + @ResponseBody + @RequestMapping(value = "/create.do") + public ServerResponse create(HttpSession session,Integer shippingId){ + User user = (User)session.getAttribute(Const.CURRENT_USER); + if(user == null){ + return ServerResponse.createByErrorCodeMessage(ResponseCode.ILLEGAL_ARGUMENT.getCode(),ResponseCode.NEED_LOGIN.getDesc()); + } + return iOrderService.createOrder(user.getId(),shippingId); + } + + /** + * 取消订单(暂时未对接支付宝 进行退款) + * @param session + * @param orderNo + * @return + */ + @ResponseBody + @RequestMapping(value = "/cancel.do") + public ServerResponse cancel(HttpSession session,Long orderNo){ + User user = (User)session.getAttribute(Const.CURRENT_USER); + if(user == null){ + return ServerResponse.createByErrorCodeMessage(ResponseCode.ILLEGAL_ARGUMENT.getCode(),ResponseCode.NEED_LOGIN.getDesc()); + } + return iOrderService.cancelOrder(user.getId(),orderNo); + } + + + /** + * 获取购物车中选中的物品详细 + * @param session + * @return + */ + @ResponseBody + @RequestMapping(value = "/get_order_cart_product.do") + public ServerResponse getOrderCartProduct(HttpSession session){ + User user = (User)session.getAttribute(Const.CURRENT_USER); + if(user == null){ + return ServerResponse.createByErrorCodeMessage(ResponseCode.ILLEGAL_ARGUMENT.getCode(),ResponseCode.NEED_LOGIN.getDesc()); + } + return iOrderService.getOrderCartProduct(user.getId()); + } + + + /** + * 获取订单详情 + * @param session + * @param orderNo + * @return + */ + @ResponseBody + @RequestMapping(value = "/detail.do") + public ServerResponse detail(HttpSession session,Long orderNo){ + User user = (User)session.getAttribute(Const.CURRENT_USER); + if(user == null){ + return ServerResponse.createByErrorCodeMessage(ResponseCode.ILLEGAL_ARGUMENT.getCode(),ResponseCode.NEED_LOGIN.getDesc()); + } + return iOrderService.getOrderdetail(user.getId(),orderNo); + } + + + /** + * 获取用户的订单列表 + * @param session + * @param pageNum + * @param pageSize + * @return + */ + @ResponseBody + @RequestMapping(value = "/list.do") + public ServerResponse list(HttpSession session, + @RequestParam(value = "pageNum",defaultValue = "1") int pageNum, + @RequestParam(value = "pageSize",defaultValue = "10") int pageSize){ + User user = (User)session.getAttribute(Const.CURRENT_USER); + if(user == null){ + return ServerResponse.createByErrorCodeMessage(ResponseCode.ILLEGAL_ARGUMENT.getCode(),ResponseCode.NEED_LOGIN.getDesc()); + } + return iOrderService.getOrderList(user.getId(),pageNum,pageSize); + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + /** + * 对接支付宝支付 + * @param session + * @param orderNo + * @param request + * @return + */ + @ResponseBody + @RequestMapping(value = "/pay.do") + public ServerResponse pay(HttpSession session, Long orderNo, HttpServletRequest request) { + User user = (User) session.getAttribute(Const.CURRENT_USER); + if (user == null) { + return ServerResponse.createByErrorCodeMessage(ResponseCode.ILLEGAL_ARGUMENT.getCode(), + ResponseCode.NEED_LOGIN.getDesc()); + } + String path = request.getSession().getServletContext().getRealPath("upload"); + return iOrderService.pay(user.getId(), orderNo, path); + } + + /** + * 支付宝回调处理接口 + * @param request + * @return + */ + @ResponseBody + @RequestMapping(value = "/alipay_callback.do") + public Object alipayCallback(HttpServletRequest request) { + Map maps = Maps.newHashMap(); + Map requestParameterMap = request.getParameterMap(); + for (Iterator iterator = requestParameterMap.keySet().iterator(); iterator.hasNext();) { + String name = (String) iterator.next(); + String[] values = (String[]) requestParameterMap.get(name); + String valuesStr = ""; + for (int i = 0; i < values.length; i++) { + valuesStr = (i == values.length - 1) ? valuesStr + values[i] + : valuesStr + values[i] + ","; + } + maps.put(name, valuesStr); + } + logger.info("支付宝回调,sign:{},trade_status:{},参数{}", maps.get("sign"), + maps.get("trade_status"), maps.toString()); + maps.remove("sign_type"); + try { + boolean alipaySignature = AlipaySignature.rsaCheckV2(maps, Configs.getAlipayPublicKey(), + "utf-8", Configs.getSignType()); + if (!alipaySignature) { + return ServerResponse.createByErrorMessage("非法请求,验证不通过,再恶意请求我就报警啦"); + } + } catch (AlipayApiException e) { + logger.error("支付宝回调验证异常"); + e.printStackTrace(); + } + //todo 验证数据 + + ServerResponse serverResponse = iOrderService.aliCallback(maps); + if (serverResponse.isSuccess()) { + return Const.AlipayCallback.RESPONSE_SUCCESS; + } + return Const.AlipayCallback.RESPONSE_FAILED; + } + + /** + * 查询订单支付状态 + * @param session + * @param orderNo + * @return + */ + @ResponseBody + @RequestMapping(value = "/query_order_pay_status.do") + public ServerResponse queryOrderPayStatus(HttpSession session,Long orderNo){ + User user = (User) session.getAttribute(Const.CURRENT_USER); + if(user == null){ + return ServerResponse.createByErrorCodeMessage(ResponseCode.ILLEGAL_ARGUMENT.getCode(),ResponseCode.NEED_LOGIN.getDesc()); + } + ServerResponse serverResponse = iOrderService.queryOrderPayStatus(user.getId(),orderNo); + if(serverResponse.isSuccess()){ + return ServerResponse.createBySuccess(true); + } + return ServerResponse.createBySuccess(false); + } +} diff --git a/src/main/java/com/mmall/controller/protal/ProductController.java b/src/main/java/com/mmall/controller/protal/ProductController.java index 81f86c5611953cd337702b7082bca8b93c7f7fb6..4b9683922bc39f6682dc5ca27529c69b6db9b318 100644 --- a/src/main/java/com/mmall/controller/protal/ProductController.java +++ b/src/main/java/com/mmall/controller/protal/ProductController.java @@ -12,6 +12,7 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; /** + * 商品模块 * Created by qujian on 2017/6/27. */ @Controller diff --git a/src/main/java/com/mmall/controller/protal/ShippingController.java b/src/main/java/com/mmall/controller/protal/ShippingController.java index f8322c9c5ee1cd6eaa7d9df75596347b3fd788a9..b9cb1e62036665393aac3228caee3b2f94641a81 100644 --- a/src/main/java/com/mmall/controller/protal/ShippingController.java +++ b/src/main/java/com/mmall/controller/protal/ShippingController.java @@ -17,6 +17,7 @@ import com.mmall.pojo.User; import com.mmall.service.IShippingService; /** + * 收货地址模块 * Created by qujian on 2017/7/4. */ @Controller diff --git a/src/main/java/com/mmall/controller/protal/userController.java b/src/main/java/com/mmall/controller/protal/userController.java index 1f18c9661d0b5d132a37f3a16e8047f6b0318893..37b55842956b310b05192c6d018a4cacd250f44f 100644 --- a/src/main/java/com/mmall/controller/protal/userController.java +++ b/src/main/java/com/mmall/controller/protal/userController.java @@ -15,6 +15,7 @@ import com.mmall.pojo.User; import com.mmall.service.IUserService; /** + * 用户模块 * Created by qujian on 2017/6/3. */ @@ -170,7 +171,6 @@ public class userController { return ServerResponse.createByErrorMessage("用户未登录"); } user.setId(currentUser.getId()); - user.setUsername(currentUser.getUsername()); ServerResponse response = iUserService.updateInformation(user); if (response.isSuccess()) { response.getData().setUsername(currentUser.getUsername()); diff --git a/src/main/java/com/mmall/dao/CartMapper.java b/src/main/java/com/mmall/dao/CartMapper.java index 53a48062b22088951d1878f67cbc6018ceda61d3..9f1182c961cb3603e2379a7c93e633acba5ceda8 100644 --- a/src/main/java/com/mmall/dao/CartMapper.java +++ b/src/main/java/com/mmall/dao/CartMapper.java @@ -34,4 +34,6 @@ public interface CartMapper { @Param("isCheck") Integer isCheck); int selectCartProductCount(Integer userId); + + List selectCheckedCartByUserId(Integer userId); } \ No newline at end of file diff --git a/src/main/java/com/mmall/dao/OrderItemMapper.java b/src/main/java/com/mmall/dao/OrderItemMapper.java index 405539bd2598a2c87c575441416e746629cc3f90..1a754634b8f915e690e9414db82452eb88819f71 100644 --- a/src/main/java/com/mmall/dao/OrderItemMapper.java +++ b/src/main/java/com/mmall/dao/OrderItemMapper.java @@ -1,6 +1,9 @@ package com.mmall.dao; import com.mmall.pojo.OrderItem; +import org.apache.ibatis.annotations.Param; + +import java.util.List; public interface OrderItemMapper { int deleteByPrimaryKey(Integer id); @@ -14,4 +17,12 @@ public interface OrderItemMapper { int updateByPrimaryKeySelective(OrderItem record); int updateByPrimaryKey(OrderItem record); + + List getOrderItemByUserId(@Param("userId")Integer userId,@Param("orderNo") Long orderNo); + + List selectByOrderNo(Long orderNo); + + int batchInsert(@Param("orderItems") List orderItems); + + } \ No newline at end of file diff --git a/src/main/java/com/mmall/dao/OrderMapper.java b/src/main/java/com/mmall/dao/OrderMapper.java index a147301da7c295c40a163e41bdabbe295f2f63f4..29828d4ac13b245149d49b3750cc16d84b66450b 100644 --- a/src/main/java/com/mmall/dao/OrderMapper.java +++ b/src/main/java/com/mmall/dao/OrderMapper.java @@ -1,6 +1,9 @@ package com.mmall.dao; import com.mmall.pojo.Order; +import org.apache.ibatis.annotations.Param; + +import java.util.List; public interface OrderMapper { int deleteByPrimaryKey(Integer id); @@ -11,7 +14,15 @@ public interface OrderMapper { Order selectByPrimaryKey(Integer id); + List selectByUserId(Integer userId); + + List selectGetAll(); + int updateByPrimaryKeySelective(Order record); int updateByPrimaryKey(Order record); + + Order selectByUserIdAndOrderNo(@Param("userId") Integer userId,@Param("orderNo") Long orderNo); + + Order selectByOrderNo(Long orderNo); } \ No newline at end of file diff --git a/src/main/java/com/mmall/pojo/Product.java b/src/main/java/com/mmall/pojo/Product.java index dd577f9b21ee41e128b766b98838e616ee250edd..b1292c0e920f4b3959c2047990e179e777a012f8 100644 --- a/src/main/java/com/mmall/pojo/Product.java +++ b/src/main/java/com/mmall/pojo/Product.java @@ -1,7 +1,5 @@ package com.mmall.pojo; -import com.alibaba.fastjson.annotation.JSONField; -import org.springframework.format.annotation.DateTimeFormat; import java.math.BigDecimal; import java.util.Date; @@ -27,12 +25,8 @@ public class Product { private Integer status; - @JSONField(format = "yyyy-MM-dd") - @DateTimeFormat(pattern = "yyyy-MM-dd") private Date createTime; - @JSONField(format = "yyyy-MM-dd") - @DateTimeFormat(pattern = "yyyy-MM-dd") private Date updateTime; public Product(Integer id, Integer categoryId, String name, String subtitle, String mainImage, String subImages, String detail, BigDecimal price, Integer stock, Integer status, Date createTime, Date updateTime) { diff --git a/src/main/java/com/mmall/pojo/vo/OrderItemVo.java b/src/main/java/com/mmall/pojo/vo/OrderItemVo.java new file mode 100644 index 0000000000000000000000000000000000000000..90b822ce0350ad2d91900ddec9e9d60ebd8edd75 --- /dev/null +++ b/src/main/java/com/mmall/pojo/vo/OrderItemVo.java @@ -0,0 +1,90 @@ +package com.mmall.pojo.vo; + +import java.math.BigDecimal; +import java.util.Date; + +/** + * Created by qujian on 2017/7/19. + */ +public class OrderItemVo { + + private Long orderNo; + + private Integer productId; + + private String productName; + + private String productImage; + + private BigDecimal currentUnitPrice; + + private Integer quantity; + + private BigDecimal totalPrice; + + private String createTime; + + public Long getOrderNo() { + return orderNo; + } + + public void setOrderNo(Long orderNo) { + this.orderNo = orderNo; + } + + public Integer getProductId() { + return productId; + } + + public void setProductId(Integer productId) { + this.productId = productId; + } + + public String getProductName() { + return productName; + } + + public void setProductName(String productName) { + this.productName = productName; + } + + public String getProductImage() { + return productImage; + } + + public void setProductImage(String productImage) { + this.productImage = productImage; + } + + public BigDecimal getCurrentUnitPrice() { + return currentUnitPrice; + } + + public void setCurrentUnitPrice(BigDecimal currentUnitPrice) { + this.currentUnitPrice = currentUnitPrice; + } + + public Integer getQuantity() { + return quantity; + } + + public void setQuantity(Integer quantity) { + this.quantity = quantity; + } + + public BigDecimal getTotalPrice() { + return totalPrice; + } + + public void setTotalPrice(BigDecimal totalPrice) { + this.totalPrice = totalPrice; + } + + public String getCreateTime() { + return createTime; + } + + public void setCreateTime(String createTime) { + this.createTime = createTime; + } +} diff --git a/src/main/java/com/mmall/pojo/vo/OrderProductVo.java b/src/main/java/com/mmall/pojo/vo/OrderProductVo.java new file mode 100644 index 0000000000000000000000000000000000000000..915130fd826cd60350179a71205a0464ed465ac9 --- /dev/null +++ b/src/main/java/com/mmall/pojo/vo/OrderProductVo.java @@ -0,0 +1,42 @@ +package com.mmall.pojo.vo; + +import com.mmall.pojo.OrderItem; + +import java.math.BigDecimal; +import java.util.List; + +/** + * Created by qujian on 2017/7/30. + */ +public class OrderProductVo { + + private List orderItems; + + private BigDecimal TotalPrice; + + private String imageHost; + + public List getOrderItems() { + return orderItems; + } + + public void setOrderItems(List orderItems) { + this.orderItems = orderItems; + } + + public BigDecimal getTotalPrice() { + return TotalPrice; + } + + public void setTotalPrice(BigDecimal totalPrice) { + TotalPrice = totalPrice; + } + + public String getImageHost() { + return imageHost; + } + + public void setImageHost(String imageHost) { + this.imageHost = imageHost; + } +} diff --git a/src/main/java/com/mmall/pojo/vo/OrderVo.java b/src/main/java/com/mmall/pojo/vo/OrderVo.java new file mode 100644 index 0000000000000000000000000000000000000000..1156ae3c001f5664f91ee2ac04058a27137c9a37 --- /dev/null +++ b/src/main/java/com/mmall/pojo/vo/OrderVo.java @@ -0,0 +1,181 @@ +package com.mmall.pojo.vo; + +import java.math.BigDecimal; +import java.util.List; + +/** + * Created by qujian on 2017/7/19. + */ +public class OrderVo { + + private Long orderNo; + + private BigDecimal payment; + + private Integer paymentType; + + private String paymentTypeDesc; + + private Integer postage; + + private Integer status; + + private String statusDesc; + + private String paymentTime; + + private String sendTime; + + private String endTime; + + private String closeTime; + + private String createTime; + + //订单的明细 + private List orderItemVos; + + private String imagehost; + + private Integer shippingId; + + private String receiverName; + + private ShippingVo shippingVo; + + public Long getOrderNo() { + return orderNo; + } + + public void setOrderNo(Long orderNo) { + this.orderNo = orderNo; + } + + public BigDecimal getPayment() { + return payment; + } + + public void setPayment(BigDecimal payment) { + this.payment = payment; + } + + public Integer getPaymentType() { + return paymentType; + } + + public void setPaymentType(Integer paymentType) { + this.paymentType = paymentType; + } + + public String getPaymentTypeDesc() { + return paymentTypeDesc; + } + + public void setPaymentTypeDesc(String paymentTypeDesc) { + this.paymentTypeDesc = paymentTypeDesc; + } + + public Integer getPostage() { + return postage; + } + + public void setPostage(Integer postage) { + this.postage = postage; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public String getStatusDesc() { + return statusDesc; + } + + public void setStatusDesc(String statusDesc) { + this.statusDesc = statusDesc; + } + + public String getPaymentTime() { + return paymentTime; + } + + public void setPaymentTime(String paymentTime) { + this.paymentTime = paymentTime; + } + + public String getSendTime() { + return sendTime; + } + + public void setSendTime(String sendTime) { + this.sendTime = sendTime; + } + + public String getEndTime() { + return endTime; + } + + public void setEndTime(String endTime) { + this.endTime = endTime; + } + + public String getCloseTime() { + return closeTime; + } + + public void setCloseTime(String closeTime) { + this.closeTime = closeTime; + } + + public String getCreateTime() { + return createTime; + } + + public void setCreateTime(String createTime) { + this.createTime = createTime; + } + + public List getOrderItemVos() { + return orderItemVos; + } + + public void setOrderItemVos(List orderItemVos) { + this.orderItemVos = orderItemVos; + } + + public String getImagehost() { + return imagehost; + } + + public void setImagehost(String imagehost) { + this.imagehost = imagehost; + } + + public Integer getShippingId() { + return shippingId; + } + + public void setShippingId(Integer shippingId) { + this.shippingId = shippingId; + } + + public String getReceiverName() { + return receiverName; + } + + public void setReceiverName(String receiverName) { + this.receiverName = receiverName; + } + + public ShippingVo getShippingVo() { + return shippingVo; + } + + public void setShippingVo(ShippingVo shippingVo) { + this.shippingVo = shippingVo; + } +} diff --git a/src/main/java/com/mmall/pojo/vo/ProductListVo.java b/src/main/java/com/mmall/pojo/vo/ProductListVo.java index 06ad7dfab61067aea9f1ccebbd9dd93eaa536c77..0db06b42e9480f44461b3de2cf65dbd97678dc8d 100644 --- a/src/main/java/com/mmall/pojo/vo/ProductListVo.java +++ b/src/main/java/com/mmall/pojo/vo/ProductListVo.java @@ -1,11 +1,7 @@ package com.mmall.pojo.vo; -import com.alibaba.fastjson.annotation.JSONField; -import org.codehaus.jackson.map.annotate.JsonSerialize; -import org.springframework.format.annotation.DateTimeFormat; import java.math.BigDecimal; -import java.util.Date; /** * Created by qujian on 2017/6/21. diff --git a/src/main/java/com/mmall/pojo/vo/ShippingVo.java b/src/main/java/com/mmall/pojo/vo/ShippingVo.java new file mode 100644 index 0000000000000000000000000000000000000000..a87f8ed6fcef7f8b106f8ae49b7fe6e0e9030c77 --- /dev/null +++ b/src/main/java/com/mmall/pojo/vo/ShippingVo.java @@ -0,0 +1,87 @@ +package com.mmall.pojo.vo; + +/** + * Created by qujian on 2017/7/19. + */ +public class ShippingVo { + + private String receiverName; + + private String receiverPhone; + + private String receiverMobile; + + private String receiverProvince; + + private String receiverCity; + + private String receiverDistrict; + + private String receiverAddress; + + private String receiverZip; + + public String getReceiverName() { + return receiverName; + } + + public void setReceiverName(String receiverName) { + this.receiverName = receiverName; + } + + public String getReceiverPhone() { + return receiverPhone; + } + + public void setReceiverPhone(String receiverPhone) { + this.receiverPhone = receiverPhone; + } + + public String getReceiverMobile() { + return receiverMobile; + } + + public void setReceiverMobile(String receiverMobile) { + this.receiverMobile = receiverMobile; + } + + public String getReceiverProvince() { + return receiverProvince; + } + + public void setReceiverProvince(String receiverProvince) { + this.receiverProvince = receiverProvince; + } + + public String getReceiverCity() { + return receiverCity; + } + + public void setReceiverCity(String receiverCity) { + this.receiverCity = receiverCity; + } + + public String getReceiverDistrict() { + return receiverDistrict; + } + + public void setReceiverDistrict(String receiverDistrict) { + this.receiverDistrict = receiverDistrict; + } + + public String getReceiverAddress() { + return receiverAddress; + } + + public void setReceiverAddress(String receiverAddress) { + this.receiverAddress = receiverAddress; + } + + public String getReceiverZip() { + return receiverZip; + } + + public void setReceiverZip(String receiverZip) { + this.receiverZip = receiverZip; + } +} diff --git a/src/main/java/com/mmall/service/IOrderService.java b/src/main/java/com/mmall/service/IOrderService.java new file mode 100644 index 0000000000000000000000000000000000000000..6a568b4adf90a2ed27da81f784e560a0c424036b --- /dev/null +++ b/src/main/java/com/mmall/service/IOrderService.java @@ -0,0 +1,43 @@ +package com.mmall.service; + +import com.github.pagehelper.PageInfo; +import com.mmall.common.ServerResponse; +import com.mmall.pojo.Cart; + +import java.util.List; +import java.util.Map; + +/** + * Created by qujian on 2017/7/14. + */ +public interface IOrderService { + + //protal + + ServerResponse pay(Integer userId, Long orderNo, String path); + + ServerResponse aliCallback(Map params); + + ServerResponse queryOrderPayStatus(Integer userId,Long orderNo); + + ServerResponse createOrder(Integer userId, Integer shippingId); + + ServerResponse cancelOrder(Integer userId, Long orderNo); + + ServerResponse> getOrderCartProduct(Integer userId); + + ServerResponse getOrderdetail(Integer userId, Long orderNo); + + ServerResponse getOrderList(Integer userId, int pageNum, int pageSize); + + //backend + + ServerResponse manageList(int pageNum, int pageSize); + + ServerResponse manageDetail(Long orderNo); + + ServerResponse manageSearch(Long orderNo,int pageNum, int pageSize); + + ServerResponse manageSendGoods(Long orderNo); + +} diff --git a/src/main/java/com/mmall/service/impl/OrderServiceImpl.java b/src/main/java/com/mmall/service/impl/OrderServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..0bcb560283af69a9c91c907fae30f635443a8468 --- /dev/null +++ b/src/main/java/com/mmall/service/impl/OrderServiceImpl.java @@ -0,0 +1,617 @@ +package com.mmall.service.impl; + +import java.io.File; +import java.io.IOException; +import java.math.BigDecimal; +import java.util.*; + +import com.github.pagehelper.PageHelper; +import com.github.pagehelper.PageInfo; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.alipay.api.AlipayResponse; +import com.alipay.api.response.AlipayTradePrecreateResponse; +import com.alipay.demo.trade.config.Configs; +import com.alipay.demo.trade.model.ExtendParams; +import com.alipay.demo.trade.model.GoodsDetail; +import com.alipay.demo.trade.model.builder.AlipayTradePrecreateRequestBuilder; +import com.alipay.demo.trade.model.result.AlipayF2FPrecreateResult; +import com.alipay.demo.trade.service.AlipayTradeService; +import com.alipay.demo.trade.service.impl.AlipayTradeServiceImpl; +import com.alipay.demo.trade.utils.ZxingUtils; +import com.google.common.collect.Lists; +import com.mmall.common.Const; +import com.mmall.common.ServerResponse; +import com.mmall.dao.*; +import com.mmall.pojo.*; +import com.mmall.pojo.vo.OrderItemVo; +import com.mmall.pojo.vo.OrderProductVo; +import com.mmall.pojo.vo.OrderVo; +import com.mmall.pojo.vo.ShippingVo; +import com.mmall.service.IOrderService; +import com.mmall.util.BigdecimalUtil; +import com.mmall.util.DateTimeUtil; +import com.mmall.util.FTPUtil; +import com.mmall.util.PropertiesUtil; + +/** + * Created by qujian on 2017/7/14. + */ +@Service("iOrderService") +public class OrderServiceImpl implements IOrderService { + + static { + + /** 一定要在创建AlipayTradeService之前调用Configs.init()设置默认参数 + * Configs会读取classpath下的zfbinfo.properties文件配置信息,如果找不到该文件则确认该文件是否在classpath目录 + */ + Configs.init("zfbinfo.properties"); + + /** 使用Configs提供的默认参数 + * AlipayTradeService可以使用单例或者为静态成员对象,不需要反复new + */ + tradeService = new AlipayTradeServiceImpl.ClientBuilder().build(); + } + + @Autowired + private OrderMapper orderMapper; + + @Autowired + private OrderItemMapper orderItemMapper; + + @Autowired + private PayInfoMapper payInfoMapper; + + @Autowired + private CartMapper cartMapper; + + @Autowired + private ProductMapper productMapper; + + @Autowired + private ShippingMapper shippingMapper; + + private final Logger log = LoggerFactory.getLogger(this.getClass()); + + private static AlipayTradeService tradeService; + + /** + * 创建订单 + * @param userId + * @param shippingId + * @return + */ + public ServerResponse createOrder(Integer userId, Integer shippingId) { + + //从购物车中获取数据 + List carts = cartMapper.selectCheckedCartByUserId(userId); + + //计算订单的总价 + ServerResponse serverResponse = this.getCartOrderItem(userId, carts); + if (!serverResponse.isSuccess()) { + return serverResponse; + } + + List orderItems = (List) serverResponse.getData(); + BigDecimal payment = this.getOrderTotalPrice(orderItems); + + //生成订单 + Order order = this.assembleOrder(userId, shippingId, payment); + if (order == null) { + return ServerResponse.createByErrorMessage("订单生成错误"); + } + for (OrderItem orderItem : orderItems) { + orderItem.setOrderNo(order.getOrderNo()); + } + + //mybatis批量插入 + int rowCount = orderItemMapper.batchInsert(orderItems); + if (rowCount < 0) { + return ServerResponse.createByErrorMessage("批量插入失败"); + } + //生成成功,减少产品的库存 + this.reduceProductStock(orderItems); + + //清空购物车 + this.clearCart(carts); + + //返回给前端数据 + OrderVo orderVo = this.assembleOrderVo(order, orderItems); + return ServerResponse.createBySuccess(orderVo); + } + + /** + * 组装OrderVo对象 + * @return + */ + private OrderVo assembleOrderVo(Order order, List orderItems) { + OrderVo orderVo = new OrderVo(); + orderVo.setOrderNo(order.getOrderNo()); + orderVo.setPayment(order.getPayment()); + orderVo.setPaymentType(order.getPaymentType()); + orderVo.setPaymentTypeDesc(Const.PaymentTypeEnum.codeOf(order.getPaymentType()).getValue()); + orderVo.setPostage(order.getPostage()); + orderVo.setStatus(order.getStatus()); + orderVo.setStatusDesc(Const.OrderStatusEnum.codeOf(order.getStatus()).getValue()); + orderVo.setShippingId(order.getShippingId()); + Shipping shipping = shippingMapper.selectByPrimaryKey(order.getShippingId()); + if (shipping != null) { + orderVo.setReceiverName(shipping.getReceiverName()); + orderVo.setShippingVo(this.assembleShippingVo(shipping)); + } + orderVo.setPaymentTime(DateTimeUtil.dateToStr(order.getPaymentTime())); + orderVo.setSendTime(DateTimeUtil.dateToStr(order.getSendTime())); + orderVo.setEndTime(DateTimeUtil.dateToStr(order.getEndTime())); + orderVo.setCreateTime(DateTimeUtil.dateToStr(order.getCreateTime())); + orderVo.setCloseTime(DateTimeUtil.dateToStr(order.getCloseTime())); + orderVo.setImagehost(PropertiesUtil.getProperty("ftp.server.http.prefix")); + + List orderItemVos = Lists.newArrayList(); + for (OrderItem orderItem : orderItems) { + OrderItemVo orderItemVo = this.assembleOrderItemVo(orderItem); + orderItemVos.add(orderItemVo); + } + orderVo.setOrderItemVos(orderItemVos); + return orderVo; + } + + /** + * 组装OrderItemVo对象 + * @param orderItem + * @return + */ + private OrderItemVo assembleOrderItemVo(OrderItem orderItem) { + OrderItemVo orderItemVo = new OrderItemVo(); + orderItemVo.setOrderNo(orderItem.getOrderNo()); + + orderItemVo.setProductId(orderItem.getProductId()); + orderItemVo.setProductName(orderItem.getProductName()); + orderItemVo.setQuantity(orderItem.getQuantity()); + orderItemVo.setProductImage(orderItem.getProductImage()); + orderItemVo.setTotalPrice(orderItem.getTotalPrice()); + orderItemVo.setCreateTime(DateTimeUtil.dateToStr(orderItem.getCreateTime())); + orderItemVo.setCurrentUnitPrice(orderItem.getCurrentUnitPrice()); + return orderItemVo; + } + + /** + * 组装shippingVo对象 + * @param shipping + * @return + */ + private ShippingVo assembleShippingVo(Shipping shipping) { + ShippingVo shippingVo = new ShippingVo(); + shippingVo.setReceiverName(shipping.getReceiverName()); + shippingVo.setReceiverAddress(shipping.getReceiverAddress()); + shippingVo.setReceiverCity(shipping.getReceiverCity()); + shippingVo.setReceiverDistrict(shipping.getReceiverDistrict()); + shippingVo.setReceiverMobile(shipping.getReceiverMobile()); + shippingVo.setReceiverPhone(shipping.getReceiverPhone()); + shippingVo.setReceiverProvince(shipping.getReceiverProvince()); + shippingVo.setReceiverZip(shipping.getReceiverZip()); + return shippingVo; + } + + /** + * 清空购物车 + * @param carts + */ + public void clearCart(List carts) { + for (Cart cart : carts) { + cartMapper.deleteByPrimaryKey(cart.getId()); + } + } + + /** + * 减少库存 + */ + private void reduceProductStock(List orderItems) { + for (OrderItem orderItem : orderItems) { + Product product = productMapper.selectByPrimaryKey(orderItem.getProductId()); + product.setStock(product.getStock() - orderItem.getQuantity()); + productMapper.updateByPrimaryKeySelective(product); + } + } + + /** + * 组装order对象 + * @param userId + * @param shippingId + * @param payment + * @return + */ + private Order assembleOrder(Integer userId, Integer shippingId, BigDecimal payment) { + long orderNo = this.generateOrderNo(); + Order order = new Order(); + order.setOrderNo(orderNo); + order.setStatus(Const.OrderStatusEnum.NO_PAY.getCode()); + order.setPostage(0); + order.setPaymentType(Const.PaymentTypeEnum.ONLINE_PAY.getCode()); + order.setPayment(payment); + order.setUserId(userId); + order.setShippingId(shippingId); + //发货时间,付款时间会在付款的时候加上,不在这里组装 + int rowCount = orderMapper.insertSelective(order); + if (rowCount > 0) { + return order; + } + return null; + } + + /** + * 生成订单号OrderNo + * @return + */ + private long generateOrderNo() { + long currentTime = System.currentTimeMillis(); + return currentTime + new Random().nextInt(100); //时间戳加上0-100的随机数组成orderNo + } + + /** + * 计算订单总价 + * @param orderItems + * @return + */ + private BigDecimal getOrderTotalPrice(List orderItems) { + BigDecimal payment = new BigDecimal("0"); //使用string构造器 + for (OrderItem orderItem : orderItems) { + payment = BigdecimalUtil.add(payment.doubleValue(), + orderItem.getTotalPrice().doubleValue()); + } + return payment; + } + + /** + * 计算商品的总价返回OrderItem + * @param userId + * @param carts + * @return + */ + private ServerResponse getCartOrderItem(Integer userId, List carts) { + List orderItems = Lists.newArrayList(); + if (CollectionUtils.isEmpty(carts)) { + return ServerResponse.createByErrorMessage("购物车为空"); + } + for (Cart cartItem : carts) { + OrderItem orderItem = new OrderItem(); + Product product = productMapper.selectByPrimaryKey(cartItem.getProductId()); + if (Const.ProductStatusEnum.ON_SALE.getCode() != product.getStatus()) { + return ServerResponse.createByErrorMessage("商品" + product.getName() + "不在售"); + } + + //校验库存 + if (cartItem.getQuantity() > product.getStock()) { + return ServerResponse.createByErrorMessage("商品" + product.getName() + "库存不足"); + } + orderItem.setUserId(userId); + orderItem.setProductId(product.getId()); + orderItem.setProductName(product.getName()); + orderItem.setProductImage(product.getMainImage()); + orderItem.setQuantity(cartItem.getQuantity()); + orderItem.setCurrentUnitPrice(product.getPrice()); + orderItem.setTotalPrice( + BigdecimalUtil.mul(product.getPrice().doubleValue(), cartItem.getQuantity())); + orderItems.add(orderItem); + } + return ServerResponse.createBySuccess(orderItems); + } + + public ServerResponse cancelOrder(Integer userId, Long orderNo) { + Order order = orderMapper.selectByUserIdAndOrderNo(userId, orderNo); + if (order == null) { + return ServerResponse.createByErrorMessage("该用户此订单不存在"); + } + if (order.getStatus() >= Const.OrderStatusEnum.PAID.getCode()) { + return ServerResponse.createByErrorMessage("已付款,无法取消订单"); + //todo 二期对接支付宝取消订单退款,有时间可以自己研究 + } + Order orderCancel = new Order(); + orderCancel.setId(order.getId()); + orderCancel.setStatus(Const.OrderStatusEnum.CANCELED.getCode()); + int rowCount = orderMapper.updateByPrimaryKeySelective(orderCancel); + if (rowCount > 0) { + //取消订单库存恢复 + List orderItem = orderItemMapper.getOrderItemByUserId(userId, orderNo); + for (OrderItem orderItemEx : orderItem) { + Product product = productMapper.selectByPrimaryKey(orderItemEx.getProductId()); + Product productEx = new Product(); + productEx.setId(product.getId()); + productEx.setStock(product.getStock() + orderItemEx.getQuantity()); + productMapper.updateByPrimaryKeySelective(productEx); + } + } + return ServerResponse.createBySuccess(); + } + + public ServerResponse getOrderCartProduct(Integer userId) { + OrderProductVo orderProductVo = new OrderProductVo(); + List cart = cartMapper.selectCheckedCartByUserId(userId); + if (CollectionUtils.isEmpty(cart)) { + return ServerResponse.createByErrorMessage("未选中商品"); + } + ServerResponse response = this.getCartOrderItem(userId, cart); + if (!response.isSuccess()) { + return response; + } + List orderItems = (List) response.getData(); + List orderItemVos = Lists.newArrayList(); + BigDecimal payment = new BigDecimal("0"); + for (OrderItem orderItem : orderItems) { + payment = BigdecimalUtil.add(payment.doubleValue(), + orderItem.getTotalPrice().doubleValue()); + orderItemVos.add(assembleOrderItemVo(orderItem)); + } + orderProductVo.setTotalPrice(payment); + orderProductVo.setOrderItems(orderItems); + orderProductVo.setImageHost(PropertiesUtil.getProperty("ftp.server.http.prefix")); + return ServerResponse.createBySuccess(orderProductVo); + } + + public ServerResponse getOrderdetail(Integer userId, Long orderNo) { + Order order = orderMapper.selectByUserIdAndOrderNo(userId,orderNo); + if(order != null) { + List orderItem = orderItemMapper.getOrderItemByUserId(userId, orderNo); + OrderVo orderVo = assembleOrderVo(order, orderItem); + return ServerResponse.createBySuccess(orderVo); + } + return ServerResponse.createByErrorMessage("用户没有该订单"); + } + + + public ServerResponse getOrderList(Integer userId, int pageNum, int pageSize){ + PageHelper.startPage(pageNum,pageSize); + List orders = orderMapper.selectByUserId(userId); + List orderVos = assembleOrderVoList(orders,userId); + PageInfo pageInfo = new PageInfo(orders); + pageInfo.setList(orderVos); + return ServerResponse.createBySuccess(pageInfo); + } + + + private List assembleOrderVoList(List orders,Integer userId){ + List orderVos = Lists.newArrayList(); + List orderItems = Lists.newArrayList(); + for(Order order : orders){ + if(userId == null){ + orderItems = orderItemMapper.selectByOrderNo(order.getOrderNo()); + }else { + orderItems = orderItemMapper.getOrderItemByUserId(userId, order.getOrderNo()); + } + orderVos.add(assembleOrderVo(order,orderItems)); + } + return orderVos; + } + + + + + + + + + + + + + + + + + + + public ServerResponse pay(Integer userId, Long orderNo, String path) { + Map maps = new HashMap<>(); + Order order = orderMapper.selectByUserIdAndOrderNo(userId, orderNo); + if (order == null) { + return ServerResponse.createByErrorMessage("该用户没有此订单"); + } + maps.put("orderNo", String.valueOf(order.getOrderNo())); + + // (必填) 商户网站订单系统中唯一订单号,64个字符以内,只能包含字母、数字、下划线, + // 需保证商户系统端不能重复,建议通过数据库sequence生成, + String outTradeNo = order.getOrderNo().toString(); + + // (必填) 订单标题,粗略描述用户的支付目的。如“xxx品牌xxx门店当面付扫码消费” + String subject = new StringBuilder().append("happymmall扫码支付,订单号:") + .append(order.getOrderNo()).toString(); + + // (必填) 订单总金额,单位为元,不能超过1亿元 + // 如果同时传入了【打折金额】,【不可打折金额】,【订单总金额】三者,则必须满足如下条件:【订单总金额】=【打折金额】+【不可打折金额】 + String totalAmount = order.getPayment().toString(); + + // (可选) 订单不可打折金额,可以配合商家平台配置折扣活动,如果酒水不参与打折,则将对应金额填写至此字段 + // 如果该值未传入,但传入了【订单总金额】,【打折金额】,则该值默认为【订单总金额】-【打折金额】 + String undiscountableAmount = "0"; + + // 卖家支付宝账号ID,用于支持一个签约账号下支持打款到不同的收款账号,(打款到sellerId对应的支付宝账号) + // 如果该字段为空,则默认为与支付宝签约的商户的PID,也就是appid对应的PID + String sellerId = ""; + + // 订单描述,可以对交易或商品进行一个详细地描述,比如填写"购买商品2件共15.00元" + String body = new StringBuilder().append("订单:").append(outTradeNo).append("商品共需支付") + .append(totalAmount).append("元").toString(); + + // 商户操作员编号,添加此参数可以为商户操作员做销售统计 + String operatorId = "test_operator_id"; + + // (必填) 商户门店编号,通过门店号和商家后台可以配置精准到门店的折扣信息,详询支付宝技术支持 + String storeId = "test_store_id"; + + // 业务扩展参数,目前可添加由支付宝分配的系统商编号(通过setSysServiceProviderId方法),详情请咨询支付宝技术支持 + ExtendParams extendParams = new ExtendParams(); + extendParams.setSysServiceProviderId("2088100200300400500"); + + // 支付超时,定义为120分钟 + String timeoutExpress = "120m"; + + // 商品明细列表,需填写购买商品详细信息, + List goodsDetailList = new ArrayList(); + + List orderItems = orderItemMapper.getOrderItemByUserId(userId, + order.getOrderNo()); + for (OrderItem orderItem : orderItems) { + GoodsDetail detail = GoodsDetail.newInstance(orderItem.getProductId().toString(), + orderItem.getProductName(), + BigdecimalUtil.mul(orderItem.getCurrentUnitPrice().doubleValue(), + new Double(100).doubleValue()).longValue(), + orderItem.getQuantity()); + goodsDetailList.add(detail); + } + + // 创建扫码支付请求builder,设置请求参数 + AlipayTradePrecreateRequestBuilder builder = new AlipayTradePrecreateRequestBuilder() + .setSubject(subject).setTotalAmount(totalAmount).setOutTradeNo(outTradeNo) + .setUndiscountableAmount(undiscountableAmount).setSellerId(sellerId).setBody(body) + .setOperatorId(operatorId).setStoreId(storeId).setExtendParams(extendParams) + .setTimeoutExpress(timeoutExpress) + .setNotifyUrl(PropertiesUtil.getProperty("alipay.callback.url"))//支付宝服务器主动通知商户服务器里指定的页面http路径,根据需要设置 + .setGoodsDetailList(goodsDetailList); + + AlipayF2FPrecreateResult result = tradeService.tradePrecreate(builder); + switch (result.getTradeStatus()) { + case SUCCESS: + log.info("支付宝预下单成功: )"); + + AlipayTradePrecreateResponse response = result.getResponse(); + dumpResponse(response); + + File folder = new File(path); + if (!folder.exists()) { + folder.setWritable(true); + folder.mkdirs(); + } + + String qrPath = String.format(path + "\\qr-%s.png", response.getOutTradeNo()); + + String qrFileName = String.format("qr-%s.png", response.getOutTradeNo()); + ZxingUtils.getQRCodeImge(response.getQrCode(), 256, qrPath); //生成二维码 + File file = new File(path, qrFileName); + try { + FTPUtil.uploadFile(Lists. newArrayList(file)); + } catch (IOException e) { + log.error("二维码生成异常"); + e.printStackTrace(); + } + log.info("qrPath:" + qrPath); + String qrUrl = PropertiesUtil.getProperty("ftp.server.http.prefix") + + file.getName(); + maps.put("qrUrl", qrUrl); + return ServerResponse.createBySuccess(maps); + case FAILED: + log.error("支付宝预下单失败!!!"); + return ServerResponse.createByErrorMessage("支付宝预下单失败"); + case UNKNOWN: + log.error("系统异常,预下单状态未知!!!"); + return ServerResponse.createByErrorMessage("系统异常,预下单状态未知"); + default: + log.error("不支持的交易状态,交易返回异常!!!"); + return ServerResponse.createByErrorMessage("不支持的交易状态,交易返回异常"); + } + } + + // 简单打印应答 + private void dumpResponse(AlipayResponse response) { + if (response != null) { + log.info(String.format("code:%s, msg:%s", response.getCode(), response.getMsg())); + if (StringUtils.isNotEmpty(response.getSubCode())) { + log.info(String.format("subCode:%s, subMsg:%s", response.getSubCode(), + response.getSubMsg())); + } + log.info("body:" + response.getBody()); + } + } + + public ServerResponse aliCallback(Map params) { + Long orderNo = Long.parseLong(params.get("out_trade_no")); + String tradeNo = params.get("trade_no"); + String tradeStatus = params.get("trade_status"); + Order order = orderMapper.selectByOrderNo(orderNo); + if (order == null) { + return ServerResponse.createByErrorMessage("非系统订单,回退"); + } + if (order.getStatus() >= Const.OrderStatusEnum.PAID.getCode()) { + return ServerResponse.createBySuccess("支付宝重复调用"); + } + if (Const.AlipayCallback.TRADE_STATUS_TRADE_SUCCESS.equals(tradeStatus)) { + order.setPaymentTime(DateTimeUtil.strToDate(params.get("gmt_payment"))); + order.setStatus(Const.OrderStatusEnum.PAID.getCode()); + orderMapper.updateByPrimaryKeySelective(order); + } + PayInfo payInfo = new PayInfo(); + payInfo.setUserId(order.getUserId()); + payInfo.setOrderNo(order.getOrderNo()); + payInfo.setPayPlatform(Const.PayPlatFormEnum.ALIPAY.getCode()); + payInfo.setPlatformNumber(tradeNo); + payInfo.setPlatformStatus(tradeStatus); + int RowCount = payInfoMapper.insertSelective(payInfo); + if (RowCount < 0) { + return ServerResponse.createByErrorMessage("添加订单失败"); + } + return ServerResponse.createBySuccess(); + } + + public ServerResponse queryOrderPayStatus(Integer userId, Long orderNo) { + Order order = orderMapper.selectByUserIdAndOrderNo(userId, orderNo); + if (order == null) { + return ServerResponse.createByErrorMessage("没有该订单"); + } + if (order.getStatus() >= Const.OrderStatusEnum.PAID.getCode()) { + return ServerResponse.createBySuccess(); + } + return ServerResponse.createByError(); + } + + + //backend + + + public ServerResponse manageList(int pageNum, int pageSize){ + PageHelper.startPage(pageNum,pageSize); + List orders = orderMapper.selectGetAll(); + List orderVos = this.assembleOrderVoList(orders,null); + PageInfo pageInfo = new PageInfo(orders); + pageInfo.setList(orderVos); + return ServerResponse.createBySuccess(pageInfo); + } + + + public ServerResponse manageDetail(Long orderNo){ + Order order = orderMapper.selectByOrderNo(orderNo); + List orderItems = orderItemMapper.selectByOrderNo(orderNo); + OrderVo orderVo = this.assembleOrderVo(order,orderItems); + return ServerResponse.createBySuccess(orderVo); + } + + public ServerResponse manageSearch(Long orderNo,int pageNum, int pageSize){ + //todo 有时间的话增加条件并且将此方法合并在list中 + PageHelper.startPage(pageNum,pageSize); + Order order = orderMapper.selectByOrderNo(orderNo); + List orderItems = orderItemMapper.selectByOrderNo(orderNo); + OrderVo orderVo = this.assembleOrderVo(order,orderItems); + PageInfo pageInfo = new PageInfo(Lists.newArrayList(order)); + pageInfo.setList(Lists.newArrayList(orderVo)); + return ServerResponse.createBySuccess(pageInfo); + } + + + public ServerResponse manageSendGoods(Long orderNo){ + Order order = orderMapper.selectByOrderNo(orderNo); + if(order != null){ + if(order.getStatus() == Const.OrderStatusEnum.PAID.getCode()){ + order.setStatus(Const.OrderStatusEnum.SHIPPED.getCode()); + order.setSendTime(new Date()); + int rowCount = orderMapper.updateByPrimaryKeySelective(order); + if(rowCount > 0){ + return ServerResponse.createBySuccess("已发货"); + } + return ServerResponse.createByErrorMessage("发货失败"); + } + } + return ServerResponse.createByErrorMessage("没有该订单"); + } +} diff --git a/src/main/resources/datasource.properties b/src/main/resources/datasource.properties index 6768522352ca6012f985ebaad239a57a756e019e..1b428baff87eaf3c0b87cf85a3cb039037aff325 100644 --- a/src/main/resources/datasource.properties +++ b/src/main/resources/datasource.properties @@ -2,9 +2,14 @@ db.driverLocation=/Users/imooc/mysql-connector-java-5.1.6-bin.jar db.driverClassName=com.mysql.jdbc.Driver #db.url=jdbc:mysql://192.1.1.1:3306/mmall?characterEncoding=utf-8 -db.url=jdbc:mysql://192.168.187.134:3306/mmall?characterEncoding=utf-8 -db.username=qujian -db.password=qujian + +db.url=jdbc:mysql://localhost:3306/mmall?characterEncoding=utf-8 +db.username=root +db.password=tongjoy_good + +#db.url=jdbc:mysql://192.168.187.134:3306/mmall?characterEncoding=utf-8 +#db.username=qujian +#db.password=qujian db.initialSize = 20 diff --git a/src/main/resources/mappers/CartMapper.xml b/src/main/resources/mappers/CartMapper.xml index 79bb71fdf3b44cbba29aa0c26713a1ad0f686722..c25c7337bdba116fc3aa4da959b3401540d86d02 100644 --- a/src/main/resources/mappers/CartMapper.xml +++ b/src/main/resources/mappers/CartMapper.xml @@ -50,6 +50,15 @@ where user_id = #{userId} + + + delete from mmall_cart where id = #{id,jdbcType=INTEGER} diff --git a/src/main/resources/mappers/OrderItemMapper.xml b/src/main/resources/mappers/OrderItemMapper.xml index 0484818b30f5d2cff627291c31ec2da53eb1b64a..b506e614bea89a9186922908a02f074c5328baf5 100644 --- a/src/main/resources/mappers/OrderItemMapper.xml +++ b/src/main/resources/mappers/OrderItemMapper.xml @@ -20,12 +20,29 @@ id, user_id, order_no, product_id, product_name, product_image, current_unit_price, quantity, total_price, create_time, update_time + + + + + + delete from mmall_order_item where id = #{id,jdbcType=INTEGER} @@ -40,6 +57,23 @@ #{currentUnitPrice,jdbcType=DECIMAL}, #{quantity,jdbcType=INTEGER}, #{totalPrice,jdbcType=DECIMAL}, now(),now()) + + +insert into mmall_order_item (id, user_id, order_no, + product_id, product_name, product_image, + current_unit_price, quantity, total_price, + create_time, update_time) + values + + ( + #{item.id,jdbcType=INTEGER}, #{item.userId,jdbcType=INTEGER}, #{item.orderNo,jdbcType=BIGINT}, + #{item.productId,jdbcType=INTEGER}, #{item.productName,jdbcType=VARCHAR}, #{item.productImage,jdbcType=VARCHAR}, + #{item.currentUnitPrice,jdbcType=DECIMAL}, #{item.quantity,jdbcType=INTEGER}, #{item.totalPrice,jdbcType=DECIMAL}, + now(),now() + ) + + + insert into mmall_order_item @@ -70,12 +104,8 @@ total_price, - create_time, - - update_time, - @@ -105,12 +135,8 @@ #{totalPrice,jdbcType=DECIMAL}, - now(), - - now(), - @@ -143,9 +169,7 @@ create_time = #{createTime,jdbcType=TIMESTAMP}, - update_time = now(), - where id = #{id,jdbcType=INTEGER} diff --git a/src/main/resources/mappers/OrderMapper.xml b/src/main/resources/mappers/OrderMapper.xml index 14df2211be84f03a61bcde50011d7f6a8aa2f3e3..38a339f0e9c9fed26c585119ab5c8c6597b73f14 100644 --- a/src/main/resources/mappers/OrderMapper.xml +++ b/src/main/resources/mappers/OrderMapper.xml @@ -29,6 +29,37 @@ from mmall_order where id = #{id,jdbcType=INTEGER} + + + + + + + + + delete from mmall_order where id = #{id,jdbcType=INTEGER} @@ -84,12 +115,8 @@ close_time, - create_time, - - update_time, - @@ -128,12 +155,8 @@ #{closeTime,jdbcType=TIMESTAMP}, - now(), - - now(), - @@ -175,9 +198,7 @@ create_time = #{createTime,jdbcType=TIMESTAMP}, - update_time = now(), - where id = #{id,jdbcType=INTEGER} diff --git a/src/main/resources/mappers/PayInfoMapper.xml b/src/main/resources/mappers/PayInfoMapper.xml index 5907200e8c571046ed915d219fa1c9e329737dec..fd1b90761e9a4d3eefeb145cde62f574e1fcf86f 100644 --- a/src/main/resources/mappers/PayInfoMapper.xml +++ b/src/main/resources/mappers/PayInfoMapper.xml @@ -56,12 +56,8 @@ platform_status, - create_time, - - update_time, - @@ -82,12 +78,8 @@ #{platformStatus,jdbcType=VARCHAR}, - now(), - - now(), - @@ -111,9 +103,7 @@ create_time = #{createTime,jdbcType=TIMESTAMP}, - update_time = now(), - where id = #{id,jdbcType=INTEGER} diff --git a/src/main/resources/mmall.properties b/src/main/resources/mmall.properties index e2b3c9ff98fc1a7f51a85270b8285650f999409e..100c42ff642c8e069510c422c738c143a0d4bd0d 100644 --- a/src/main/resources/mmall.properties +++ b/src/main/resources/mmall.properties @@ -5,7 +5,7 @@ ftp.pass=qujian ftp.server.http.prefix=http://image.imooc.com/ -alipay.callback.url=http://www.happymmall.com/order/alipay_callback.do +alipay.callback.url=http://ku6q7v.natappfree.cc/order/alipay_callback.do password.salt = geelysdafaqj23ou89ZXcj@#$@#$#@KJdjklj;D../dSF., diff --git a/src/main/resources/zfbinfo.properties b/src/main/resources/zfbinfo.properties new file mode 100644 index 0000000000000000000000000000000000000000..864b36f2bb9d475a69165fe63413f538c573bded --- /dev/null +++ b/src/main/resources/zfbinfo.properties @@ -0,0 +1,32 @@ + +# 支付宝网关名、partnerId和appId +open_api_domain = https://openapi.alipaydev.com/gateway.do +mcloud_api_domain = http://mcloudmonitor.com/gateway.do +# 商户UID +pid = 2088102170038941 + +appid = 2016080500171849 + +# RSA私钥、公钥和支付宝公钥 +private_key = MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQChy6ZG+fOGXwIcVBJIHG8NFGU/UkbiXUdTluyWtYWANpcBh2vp2/iF4iAX1T/EY9EXvXPsHG5IQRyvUM8suXlIB+C7g+hkAOkSS3g2s37w2W6hNXt4uHwalTtEt7EvERF/VoLehzbEnsFUp7ZdYjJdYJOwCVYFHBmOaSRiUOGKwsVOuD45hmg09Yo3+TCYDIOE5GBjNR079S+7A86D8IP/Qx6oxnzBVRR1L72gTVLScFvVpQp8Ex9gZ5bQLt3tAPYSa9K3cC7DFw+0UdIhRXSpdP9ZeNyAWNyo4mKzuCWAgBuq5VBXWu3FK4y7AZCbWMI+CA7Ub5Dyx/gUqmqMfLpNAgMBAAECggEAB/WUwHkbWcjiubIJFDMR43rVYEAT7J7aG2qZSPC1GJGW7CRVUrPXjf6JxaJf+LFQX/KZ+UuMwVEysA0xo+mb5cc9bvwWOpUw4g2EZGyAGikYICYZZN7ufABLYh4HQWF9kt4WogvUzedha2C0v/NMtvtBSK+s46N2PmM9vvhrn//Qq5hoyXiIr8l6l3sjWicjVXp5jgjeMdUtijV69cWIa6EVTi0zp+NKLx1a8kgP2eOdPApUa3BtfIP0rdnKWU3lPONfCys4Y/NOwivIUK8ALSOHWhBWz3BZW0I+Kqzv30XM9Ih6w5Gb2LiIJ6MGqbXI/ehMFRCJOo/Q8Gsqn0j2AQKBgQDqbMnx6oZ/o+dbH5e10p8VHmaQuqfnAacTlZoxFCQR6QMYaqlF/hFR7JruO7WTkHdoc2i7zT+1MxuGGlR4IxZfKaZNhXpxoeNehjzv5r917aEIPtm5CcRO0oEyJJZMKo95Wrubptu5ay+uW3oY+zp8yZAys1/fpke9I+VmarnP8QKBgQCwr6lYOpE0xPkIRQcNFyzWNmM1QXN3cU2GR3m4fl6xhKlmONVJampYQhtRAocPxxjINxL7AkrD/Oeaab8RDoCe8kBxnmfMcPKu1to+nk9L5110b8SMS3N1aXfx6lwWnoqpHYw5IdtcL7XsVb+AxyZQmJMEW8WBaQDntLs/A57sHQKBgQDh0ZgbJLsZW68y9VT0PocmFdnhUx0Ih2wFjpgw7ODuK9Lig2S6Wsseati34ua/1mtgP8RFHKthBnFeFiEGdW5Ij1t207yml7bpyFANHO+UTytPQRQEjmb/MwJnZh0uE9WPphqRDwQcMieFQvNz+xZVPOleHbKeQ5RZm6mQpgCGUQKBgD5G7G3I1v2+n/imPAIFNSycJwPSehyTtzupXeIFyOLRW9RIHAWwmKNbSb2YInsRNk77+pi3ChtivU/UDiC49+UOhmCF8RhCh4fQ+0QvEMw0VOCBtMmunpe4ASsn7CWc5EsPuyk4IdWwi3MuFj4R9BNcdBWJM2iV1lfVgFqJsC6RAoGAKdeK4pbXAP1xPDmNscU9KEWrQmNeHKSCggzf+X7uFGPnrLzGufAmJC1GhvQ8QO2w/VbL1iIu09d9qfXZFTZKo4IfX20ubgLaVr3x+sEdDNnvrhnwKNaHvlOJiR3AKRnIuLonpT8a+sl+13xwqIzma7yoUpO047sff6HudzyPdXM= +public_key = MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAocumRvnzhl8CHFQSSBxvDRRlP1JG4l1HU5bslrWFgDaXAYdr6dv4heIgF9U/xGPRF71z7BxuSEEcr1DPLLl5SAfgu4PoZADpEkt4NrN+8NluoTV7eLh8GpU7RLexLxERf1aC3oc2xJ7BVKe2XWIyXWCTsAlWBRwZjmkkYlDhisLFTrg+OYZoNPWKN/kwmAyDhORgYzUdO/UvuwPOg/CD/0MeqMZ8wVUUdS+9oE1S0nBb1aUKfBMfYGeW0C7d7QD2EmvSt3AuwxcPtFHSIUV0qXT/WXjcgFjcqOJis7glgIAbquVQV1rtxSuMuwGQm1jCPggO1G+Q8sf4FKpqjHy6TQIDAQAB + +#SHA1withRsa对应支付宝公钥 +#alipay_public_key = MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDDI6d306Q8fIfCOaTXyiUeJHkrIvYISRcc73s3vF1ZT7XN8RNPwJxo8pWaJMmvyTn9N4HQ632qJBVHf8sxHi/fEsraprwCtzvzQETrNRwVxLO5jVmRGi60j8Ue1efIlzPXV9je9mkjzOmdssymZkh2QhUrCmZYI/FCEa3/cNMW0QIDAQAB + +#SHA256withRsa对应支付宝公钥 +alipay_public_key = MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtBUFnyEjxEh8FH5jlAKNT0Di2GAZRMUYxg0H/Lh48LXP6twhLvyWwuHxz7+68tbNSsTobWQxy16YYvPJ5/mbtHJ4aoUpYL552nKfbTSIeT3K1dzMQhnTqyFH235OTHHW9ZP36hHPGeqG6HjikEfSiBpSxon4VuISqjkK7ulQs9U075vA9NmzdW+p3zfHiNb3zzlCnpx+0oCXZmL5OeyCdFkz7XxY4YQDR14GJ/YE7xzpNu3cYglmHMAVHw8+TyzwXsUuFyG4YA8G7eCJTgAJpgs0hFBhlXyFssPrL0hFmX4vgpvj7zjKlaKdC3yFR5sUOwDUCIqZKBTM7S7w3kLvhQIDAQAB + +# 签名类型: RSA->SHA1withRsa,RSA2->SHA256withRsa +sign_type = RSA2 +# 当面付最大查询次数和查询间隔(毫秒) +max_query_retry = 5 +query_duration = 5000 + +# 当面付最大撤销次数和撤销间隔(毫秒) +max_cancel_retry = 3 +cancel_duration = 2000 + +# 交易保障线程第一次调度延迟和调度间隔(秒) +heartbeat_delay = 5 +heartbeat_duration = 900 diff --git a/src/main/webapp/WEB-INF/lib/alipay-sdk-java20161213173952-source.jar b/src/main/webapp/WEB-INF/lib/alipay-sdk-java20161213173952-source.jar new file mode 100644 index 0000000000000000000000000000000000000000..8bd1981198bacae8bd898c10e103655f9ac93a32 Binary files /dev/null and b/src/main/webapp/WEB-INF/lib/alipay-sdk-java20161213173952-source.jar differ diff --git a/src/main/webapp/WEB-INF/lib/alipay-sdk-java20161213173952.jar b/src/main/webapp/WEB-INF/lib/alipay-sdk-java20161213173952.jar new file mode 100644 index 0000000000000000000000000000000000000000..6babc90441d420a68c8b8e94becaa8658c7bc948 Binary files /dev/null and b/src/main/webapp/WEB-INF/lib/alipay-sdk-java20161213173952.jar differ diff --git a/src/main/webapp/WEB-INF/lib/alipay-trade-sdk-20161215-source.jar b/src/main/webapp/WEB-INF/lib/alipay-trade-sdk-20161215-source.jar new file mode 100644 index 0000000000000000000000000000000000000000..c79c7455b0b2feb66bd213efa66fd7550580eed3 Binary files /dev/null and b/src/main/webapp/WEB-INF/lib/alipay-trade-sdk-20161215-source.jar differ diff --git a/src/main/webapp/WEB-INF/lib/alipay-trade-sdk-20161215.jar b/src/main/webapp/WEB-INF/lib/alipay-trade-sdk-20161215.jar new file mode 100644 index 0000000000000000000000000000000000000000..5bd6b0cd8d410f01e83a122eac76eb7803b38af9 Binary files /dev/null and b/src/main/webapp/WEB-INF/lib/alipay-trade-sdk-20161215.jar differ diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml index e4cbf1e83bf713ed502ea07c91a377dd7071ceed..66d5cffae4b2e56ea08eee4f0b98e959aa9a0272 100644 --- a/src/main/webapp/WEB-INF/web.xml +++ b/src/main/webapp/WEB-INF/web.xml @@ -6,6 +6,7 @@ Archetype Created Web Application + characterEncodingFilter org.springframework.web.filter.CharacterEncodingFilter @@ -23,6 +24,8 @@ /* + + org.springframework.web.context.request.RequestContextListener @@ -31,12 +34,14 @@ org.springframework.web.context.ContextLoaderListener + contextConfigLocation classpath:applicationContext.xml + dispatcher