New file |
| | |
| | | package com.ruoyi.system.api.domain.dto; |
| | | |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | |
| | | import java.util.List; |
| | | |
| | | @Data |
| | | public class OrderAuctionBondDTO { |
| | | @ApiModelProperty(value = "拍卖会id") |
| | | private Long auctionSalesroomId; |
| | | |
| | | @ApiModelProperty(value = "获奖用户ID") |
| | | private List<Long> userList; |
| | | } |
| | |
| | | package com.ruoyi.system.api.factory; |
| | | |
| | | import com.ruoyi.common.core.domain.R; |
| | | import com.ruoyi.system.api.domain.PromotionVideo; |
| | | import com.ruoyi.system.api.domain.dto.OrderAuctionBondDTO; |
| | | import com.ruoyi.system.api.domain.dto.OrderDTO; |
| | | import com.ruoyi.system.api.feignClient.OrderClient; |
| | | import com.ruoyi.system.api.feignClient.PromotionClient; |
| | | import org.springframework.cloud.openfeign.FallbackFactory; |
| | | |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * @author mitao |
| | |
| | | |
| | | @Override |
| | | public OrderClient create(Throwable cause) { |
| | | return null; |
| | | return new OrderClient(){ |
| | | |
| | | |
| | | @Override |
| | | public R<Boolean> saveOrderOne(OrderDTO orderDTO) { |
| | | return R.fail("通过视频集合查询用户失败:" + cause.getMessage()); |
| | | } |
| | | |
| | | @Override |
| | | public R<Boolean> getOrderAuctionBond(OrderAuctionBondDTO orderAuctionBondDTO) { |
| | | return R.fail("通过视频集合查询用户失败:" + cause.getMessage()); |
| | | } |
| | | }; |
| | | } |
| | | } |
| | |
| | | |
| | | @PostMapping("/goods-sku/updateGoodsSkuOne") |
| | | R<Boolean> updateGoodsSkuOne(@RequestBody GoodsSku goodsSku); |
| | | |
| | | |
| | | |
| | | } |
| | |
| | | import com.ruoyi.common.core.constant.ServiceNameConstants; |
| | | import com.ruoyi.common.core.domain.R; |
| | | import com.ruoyi.system.api.domain.GoodsSku; |
| | | import com.ruoyi.system.api.domain.dto.OrderAuctionBondDTO; |
| | | import com.ruoyi.system.api.domain.dto.OrderDTO; |
| | | import com.ruoyi.system.api.factory.OrderFallbackFactory; |
| | | import org.springframework.cloud.openfeign.FeignClient; |
| | |
| | | @PostMapping("/order/saveOrderOne") |
| | | R<Boolean> saveOrderOne(@RequestBody OrderDTO orderDTO); |
| | | |
| | | |
| | | @PostMapping("/order-auction-bond/getOrderAuctionBond") |
| | | R<Boolean> getOrderAuctionBond(@RequestBody OrderAuctionBondDTO orderAuctionBondDTO); |
| | | |
| | | } |
| | |
| | | import com.ruoyi.common.core.enums.OrderFromEnum; |
| | | import com.ruoyi.system.api.domain.GoodsSku; |
| | | import com.ruoyi.system.api.domain.MemberAddress; |
| | | import com.ruoyi.system.api.domain.dto.OrderAuctionBondDTO; |
| | | import com.ruoyi.system.api.feignClient.GoodsSkuClient; |
| | | import com.ruoyi.system.api.feignClient.MemberClient; |
| | | import com.ruoyi.system.api.feignClient.OrderClient; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import javax.annotation.Resource; |
| | |
| | | |
| | | @Resource |
| | | private MemberClient emberClient; |
| | | |
| | | @Resource |
| | | private OrderClient orderClient; |
| | | |
| | | |
| | | /** |
| | |
| | | auctionSalesroomVO.setNextAuctionSalesroomGoods(nextAuctionSalesroomGoods); |
| | | } |
| | | LambdaQueryWrapper<AuctionSalesroomGoods> wrapper2=Wrappers.lambdaQuery(); |
| | | wrapper2.in(AuctionSalesroomGoods::getSortNum,list); |
| | | wrapper2.notIn(AuctionSalesroomGoods::getSortNum,list); |
| | | wrapper2.eq(AuctionSalesroomGoods::getDelFlag,0); |
| | | wrapper2.eq(AuctionSalesroomGoods::getAuctionSalesroomId,SalesroomId); |
| | | wrapper2.orderByAsc(AuctionSalesroomGoods::getSortNum); |
| | |
| | | R<GoodsSku> goodsSkuOne2 = goodsSkuClient.getGoodsSkuOne(salesroomGoods.getGoodsSkuId()); |
| | | GoodsSku goodsSku2=goodsSkuOne2.getData(); |
| | | forepartAuctionSalesroomGoodsVO1.setGoodsSkuName(salesroomGoods.getGoodsSkuName()); |
| | | forepartAuctionSalesroomGoodsVO1.setCoverPic(goodsSku.getCoverPic()); |
| | | forepartAuctionSalesroomGoodsVO1.setCoverPic(goodsSku2.getCoverPic()); |
| | | auctionSalesroomGoodsVOS.add(forepartAuctionSalesroomGoodsVO1); |
| | | } |
| | | |
| | |
| | | |
| | | AuctionSalesroomGoods auctionSalesroomGoods=iAuctionSalesroomGoodsService.getById(auctionSalesroomGoodsDTO.getGoodsSkuId()); |
| | | List<AuctionBidRecord> auctionBidRecordList=new ArrayList<>(); |
| | | List<Long> list=new ArrayList<>(); |
| | | if (auctionSalesroomGoods.getStatus().getCode()==1) { |
| | | LambdaQueryWrapper<AuctionBidRecord> wrapper = Wrappers.lambdaQuery(); |
| | | wrapper.eq(AuctionBidRecord::getGoodsSkuId, auctionSalesroomGoodsDTO.getGoodsSkuId()); |
| | |
| | | wrapper.orderByDesc(AuctionBidRecord::getLastBidAmount); |
| | | auctionBidRecordList = iAuctionBidRecordService.list(wrapper); |
| | | //判断 |
| | | |
| | | if (auctionBidRecordList.size() >= auctionSalesroomGoods.getItemQuantity()) { |
| | | for (int i = 0; i <= auctionSalesroomGoods.getItemQuantity(); i++) { |
| | | AuctionBidRecord auctionBidRecord = auctionBidRecordList.get(i); |
| | | auctionBidRecord.setStatus(BidStatusEnum.SUCCESSFUL); |
| | | AddOrder(auctionBidRecord.getGoodsSkuId(),auctionBidRecord.getMemberId(),auctionBidRecord.getLastBidAmount(),auctionSalesroom.getBound()); |
| | | |
| | | list.add(auctionBidRecord.getMemberId()); |
| | | } |
| | | } else { |
| | | for (int i = 0; i <= auctionBidRecordList.size(); i++) { |
| | | AuctionBidRecord auctionBidRecord = auctionBidRecordList.get(i); |
| | | auctionBidRecord.setStatus(BidStatusEnum.SUCCESSFUL); |
| | | AddOrder(auctionBidRecord.getGoodsSkuId(),auctionBidRecord.getMemberId(),auctionBidRecord.getLastBidAmount(),auctionSalesroom.getBound()); |
| | | list.add(auctionBidRecord.getMemberId()); |
| | | } |
| | | } |
| | | } |
| | | |
| | | OrderAuctionBondDTO orderAuctionBondDTO=new OrderAuctionBondDTO(); |
| | | orderAuctionBondDTO.setAuctionSalesroomId(auctionSalesroom.getId()); |
| | | orderAuctionBondDTO.setUserList(list); |
| | | orderClient.getOrderAuctionBond(orderAuctionBondDTO); |
| | | |
| | | } |
| | | |
| | | |
| | |
| | | <version>1.2.47</version> |
| | | </dependency> |
| | | |
| | | |
| | | <dependency> |
| | | <groupId>com.google.code.gson</groupId> |
| | | <artifactId>gson</artifactId> |
| | | <version>2.2.4</version> |
| | | <scope>compile</scope> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>com.thoughtworks.xstream</groupId> |
| | | <artifactId>xstream</artifactId> |
| | | <version>1.4.8</version> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>com.alibaba</groupId> |
| | | <artifactId>fastjson</artifactId> |
| | | <version>1.2.4</version> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>net.sf.json-lib</groupId> |
| | | <artifactId>json-lib</artifactId> |
| | | <version>2.4</version> |
| | | <classifier>jdk15</classifier> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>cn.afterturn</groupId> |
| | | <artifactId>easypoi-spring-boot-starter</artifactId> |
| | |
| | | </exclusion> |
| | | </exclusions> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>com.alibaba</groupId> |
| | | <artifactId>fastjson</artifactId> |
| | | <version>1.2.47</version> |
| | | <scope>compile</scope> |
| | | </dependency> |
| | | |
| | | </dependencies> |
| | | |
| | |
| | | package com.ruoyi.order.controller; |
| | | |
| | | |
| | | import org.springframework.web.bind.annotation.RequestMapping; |
| | | import com.ruoyi.common.core.domain.R; |
| | | import com.ruoyi.order.domain.pojo.OrderAuctionBond; |
| | | import com.ruoyi.order.service.IOrderAuctionBondService; |
| | | import com.ruoyi.system.api.domain.GoodsSku; |
| | | import com.ruoyi.system.api.domain.dto.OrderAuctionBondDTO; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import org.apache.poi.ss.formula.functions.T; |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | import javax.annotation.Resource; |
| | | |
| | | /** |
| | | * <p> |
| | |
| | | @RequestMapping("/order-auction-bond") |
| | | public class OrderAuctionBondController { |
| | | |
| | | @Resource |
| | | private IOrderAuctionBondService iOrderAuctionBondService; |
| | | |
| | | /** |
| | | * 获取当前商品信息 |
| | | *这些还要掉退款,但是还没有支付或者微信 |
| | | * |
| | | */ |
| | | @PostMapping("/getOrderAuctionBond") |
| | | @ResponseBody |
| | | public R<T> getOrderAuctionBond(@RequestBody OrderAuctionBondDTO orderAuctionBondDTO) { |
| | | iOrderAuctionBondService.getOrderAuctionBond(orderAuctionBondDTO); |
| | | return R.ok(); |
| | | |
| | | } |
| | | |
| | | } |
| | |
| | | |
| | | import com.ruoyi.order.domain.pojo.OrderAuctionBond; |
| | | import com.baomidou.mybatisplus.extension.service.IService; |
| | | import com.ruoyi.system.api.domain.dto.OrderAuctionBondDTO; |
| | | import org.springframework.web.bind.annotation.RequestBody; |
| | | |
| | | /** |
| | | * <p> |
| | |
| | | * @since 2024-05-16 |
| | | */ |
| | | public interface IOrderAuctionBondService extends IService<OrderAuctionBond> { |
| | | void getOrderAuctionBond( OrderAuctionBondDTO orderAuctionBondDTO); |
| | | |
| | | } |
| | |
| | | package com.ruoyi.order.service.impl; |
| | | |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.baomidou.mybatisplus.core.toolkit.Wrappers; |
| | | import com.ruoyi.order.domain.pojo.OrderAuctionBond; |
| | | import com.ruoyi.order.mapper.OrderAuctionBondMapper; |
| | | import com.ruoyi.order.service.IOrderAuctionBondService; |
| | | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
| | | import com.ruoyi.system.api.domain.dto.OrderAuctionBondDTO; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import javax.annotation.Resource; |
| | | import java.awt.*; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * <p> |
| | |
| | | @Service |
| | | public class OrderAuctionBondServiceImpl extends ServiceImpl<OrderAuctionBondMapper, OrderAuctionBond> implements IOrderAuctionBondService { |
| | | |
| | | @Resource |
| | | private IOrderAuctionBondService iOrderAuctionBondService; |
| | | @Override |
| | | public void getOrderAuctionBond( OrderAuctionBondDTO orderAuctionBondDTO) { |
| | | |
| | | LambdaQueryWrapper<OrderAuctionBond> wrapper= Wrappers.lambdaQuery(); |
| | | wrapper.notIn(OrderAuctionBond::getMemberId,orderAuctionBondDTO.getUserList()); |
| | | wrapper.eq(OrderAuctionBond::getDelFlag,0); |
| | | wrapper.eq(OrderAuctionBond::getAuctionSalesroomId,orderAuctionBondDTO.getAuctionSalesroomId()); |
| | | List<OrderAuctionBond> orderAuctionBondList=iOrderAuctionBondService.list(wrapper); |
| | | for (OrderAuctionBond orderAuctionBond:orderAuctionBondList){ |
| | | |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | package com.ruoyi.order.util; |
| | | |
| | | import java.text.ParseException; |
| | | import java.text.SimpleDateFormat; |
| | | import java.util.Calendar; |
| | | import java.util.Date; |
| | | import java.util.GregorianCalendar; |
| | | import java.util.TimeZone; |
| | | |
| | | /** |
| | | * <h3>处理时间的工具类</h3> |
| | | */ |
| | | public class DateUtil { |
| | | |
| | | private static TimeZone tz = TimeZone.getTimeZone("GMT+8"); |
| | | |
| | | //private static TimeZone tz = TimeZone.getTimeZone("Asia/Shanghai"); |
| | | |
| | | |
| | | /** |
| | | * 得到系统日期 |
| | | * @return |
| | | */ |
| | | public static Date getDate() { |
| | | TimeZone.setDefault(tz); |
| | | return new Date(); |
| | | } |
| | | |
| | | /** |
| | | * 获取当然凌晨的时间 |
| | | * @return Date |
| | | */ |
| | | public static Date getZero() { |
| | | Calendar calendar = Calendar.getInstance(); |
| | | calendar.setTime(new Date()); |
| | | calendar.set(Calendar.HOUR_OF_DAY, 0); |
| | | calendar.set(Calendar.MINUTE, 0); |
| | | calendar.set(Calendar.SECOND, 0); |
| | | return calendar.getTime(); |
| | | } |
| | | |
| | | /** |
| | | * 判断日期是否在from,to之内 |
| | | *"yyyy-MM-dd" 格式 |
| | | * @param time 指定日期 |
| | | * @param from 开始日期 |
| | | * @param to 结束日期 |
| | | * @return true 在之间 false 不在之间 |
| | | */ |
| | | public static boolean belongCalendar(Date time, Date from, Date to) { |
| | | Calendar date = Calendar.getInstance(); |
| | | date.setTime(time); |
| | | |
| | | Calendar after = Calendar.getInstance(); |
| | | after.setTime(from); |
| | | |
| | | Calendar before = Calendar.getInstance(); |
| | | before.setTime(to); |
| | | |
| | | if ( (date.after(after) && date.before(before)) || (time.compareTo(from)==0 || time.compareTo(to)==0) ) { |
| | | return true; |
| | | } else { |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 两个时间之差 |
| | | * @param startTime |
| | | * @param endTime |
| | | * @param format |
| | | * @return |
| | | * @throws ParseException |
| | | */ |
| | | public static String dateDiff(String startTime, String endTime, |
| | | String format) throws ParseException { |
| | | // 按照传入的格式生成一个simpledateformate对象 |
| | | SimpleDateFormat sd = new SimpleDateFormat(format); |
| | | long nd = 1000 * 24 * 60 * 60;// 一天的毫秒数 |
| | | long nh = 1000 * 60 * 60;// 一小时的毫秒数 |
| | | long nm = 1000 * 60;// 一分钟的毫秒数 |
| | | long ns = 1000;// 一秒钟的毫秒数 |
| | | long diff; |
| | | long day = 0; |
| | | long hour = 0; |
| | | long min = 0; |
| | | long sec = 0; |
| | | //long time=0; |
| | | String strTime=""; |
| | | // 获得两个时间的毫秒时间差异 |
| | | diff = sd.parse(endTime).getTime() - sd.parse(startTime).getTime(); |
| | | day = diff / nd;// 计算差多少天 |
| | | hour = diff % nd / nh + day * 24;// 计算差多少小时 |
| | | min = diff % nd % nh / nm + day * 24 * 60;// 计算差多少分钟 |
| | | sec = diff % nd % nh % nm / ns;// 计算差多少秒 |
| | | // 输出结果 |
| | | /*System.out.println("时间相差:" + day + "天" + (hour - day * 24) + "小时" |
| | | + (min - day * 24 * 60) + "分钟" + sec + "秒。"); |
| | | System.out.println("hour=" + hour + ",min=" + min);*/ |
| | | if(day==1){ |
| | | strTime="昨天"; |
| | | } |
| | | else if(day>1){ |
| | | //strTime=day+"天前"; |
| | | strTime=startTime.substring(0, 10); |
| | | } |
| | | else if(hour>=1 && hour<24){ |
| | | strTime=hour+"小时前"; |
| | | } |
| | | else{ |
| | | if(min==0){strTime=sec+"秒钟前";}else{ |
| | | strTime=min+"分钟前"; |
| | | } |
| | | |
| | | } |
| | | // if (str.equalsIgnoreCase("h")) { |
| | | // return hour; |
| | | // } else { |
| | | // return min; |
| | | // } |
| | | |
| | | // if (str.equalsIgnoreCase("h")) { |
| | | // return hour; |
| | | // } else { |
| | | // return min; |
| | | // } |
| | | return strTime; |
| | | } |
| | | |
| | | /** |
| | | * 得到系统Calendar日期 |
| | | * @return |
| | | */ |
| | | public static Calendar getCalendar() { |
| | | TimeZone.setDefault(tz); |
| | | Calendar cal = Calendar.getInstance(); |
| | | return cal; |
| | | } |
| | | |
| | | /** |
| | | * 获取当前时间 |
| | | * @return |
| | | */ |
| | | public static long getMillisecond() { |
| | | long millisecond = 0; |
| | | TimeZone.setDefault(tz); |
| | | Calendar cal = Calendar.getInstance(); |
| | | millisecond = cal.getTimeInMillis(); |
| | | return millisecond; |
| | | } |
| | | |
| | | /** |
| | | * 获取本月1号的时间戳 |
| | | * @return |
| | | */ |
| | | public static long getMillisecond_MONTH() { |
| | | long millisecond = 0; |
| | | TimeZone.setDefault(tz); |
| | | Calendar cal = Calendar.getInstance(); |
| | | cal.set(Calendar.DAY_OF_MONTH, 1); |
| | | millisecond = cal.getTimeInMillis(); |
| | | return millisecond; |
| | | } |
| | | |
| | | /** |
| | | * 获取上个月1号的时间戳 |
| | | * @return |
| | | */ |
| | | public static long getMillisecond_FRONTMONTH() { |
| | | long millisecond = 0; |
| | | Calendar cal = getCalendar(); |
| | | cal.set(Calendar.DAY_OF_MONTH, 1); |
| | | cal.set(Calendar.MONTH, Calendar.MONTH-2); |
| | | millisecond = cal.getTimeInMillis(); |
| | | return millisecond; |
| | | } |
| | | |
| | | /** |
| | | * 获取当前毫秒数 |
| | | * @return long |
| | | */ |
| | | public static long getCurMilli() { |
| | | long millisecond = 0; |
| | | Calendar cal = Calendar.getInstance(); |
| | | millisecond = cal.getTimeInMillis(); |
| | | return millisecond; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 日期转毫秒 |
| | | * @param date |
| | | * @return |
| | | */ |
| | | public static long getMillisecond(Date date) { |
| | | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); |
| | | String newDate = ""; |
| | | if (!"".equals(date)) { |
| | | newDate = sdf.format(date); |
| | | } else { |
| | | newDate = sdf.format(DateUtil.getDate()); |
| | | } |
| | | long millisecond = 0; |
| | | try { |
| | | millisecond = sdf.parse(newDate).getTime(); |
| | | } catch (ParseException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | return millisecond; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 日期转毫秒(加24小时,yyyy-MM-dd HH:mm:ss) |
| | | * @param date |
| | | * @return |
| | | */ |
| | | public static long getMillisecond_24h(Date date) { |
| | | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); |
| | | String newDate = ""; |
| | | if (!"".equals(date)) { |
| | | newDate = sdf.format(date); |
| | | } else { |
| | | newDate = sdf.format(DateUtil.getDate()); |
| | | } |
| | | long millisecond = 24*3600*1000; |
| | | try { |
| | | millisecond += sdf.parse(newDate).getTime(); |
| | | } catch (ParseException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | return millisecond; |
| | | } |
| | | |
| | | /** |
| | | * 日期转毫秒(加N年) |
| | | * @param date |
| | | * @return |
| | | */ |
| | | public static long getMillisecond_year(String date, Integer year){ |
| | | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); |
| | | String newDate = ""; |
| | | if ("".equals(date)) { |
| | | newDate = sdf.format(DateUtil.getDate()); |
| | | } else { |
| | | newDate = getDateTime(Long.parseLong(date)); |
| | | } |
| | | Date dt = null; |
| | | try { |
| | | dt = sdf.parse(newDate); |
| | | } catch (ParseException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | Calendar rightNow = Calendar.getInstance(); |
| | | rightNow.setTime(dt); |
| | | rightNow.add(Calendar.YEAR, year); |
| | | Date dt1 = rightNow.getTime(); |
| | | return dt1.getTime(); |
| | | } |
| | | |
| | | /** |
| | | * 日期转毫秒(加N天) |
| | | * @param date 毫秒字符串 |
| | | * @return |
| | | */ |
| | | public static long getMillisecond_day(String date, Integer day){ |
| | | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); |
| | | String newDate = ""; |
| | | if ("".equals(date)) { |
| | | newDate = sdf.format(DateUtil.getDate()); |
| | | } else { |
| | | newDate = getDateTime(Long.parseLong(date)); |
| | | } |
| | | Date dt = null; |
| | | try { |
| | | dt = sdf.parse(newDate); |
| | | } catch (ParseException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | Calendar rightNow = Calendar.getInstance(); |
| | | rightNow.setTime(dt); |
| | | rightNow.add(Calendar.DATE, day); |
| | | Date dt1 = rightNow.getTime(); |
| | | return dt1.getTime(); |
| | | } |
| | | |
| | | /** |
| | | * 日期转毫秒(加N月) |
| | | * @param date |
| | | * @return |
| | | */ |
| | | public static long getMillisecond_month(String date, Integer day){ |
| | | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); |
| | | String newDate = ""; |
| | | if ("".equals(date)) { |
| | | newDate = sdf.format(DateUtil.getDate()); |
| | | } else { |
| | | newDate = getDateTime(Long.parseLong(date)); |
| | | } |
| | | Date dt = null; |
| | | try { |
| | | dt = sdf.parse(newDate); |
| | | } catch (ParseException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | Calendar rightNow = Calendar.getInstance(); |
| | | rightNow.setTime(dt); |
| | | rightNow.add(Calendar.MONTH, day); |
| | | Date dt1 = rightNow.getTime(); |
| | | return dt1.getTime(); |
| | | } |
| | | |
| | | /** |
| | | * 字符串日期转毫秒 |
| | | * @param date |
| | | * @return |
| | | */ |
| | | public static long getMillisecond_str(String date) { |
| | | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); |
| | | if ("".equals(date)) { |
| | | date = sdf.format(DateUtil.getDate()); |
| | | } |
| | | long millisecond = 0; |
| | | try { |
| | | millisecond = sdf.parse(date).getTime(); |
| | | } catch (ParseException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | return millisecond; |
| | | } |
| | | |
| | | /** |
| | | * 字符串日期转毫秒 |
| | | * @param date |
| | | * @return |
| | | */ |
| | | public static long getMillisecond_strYmd(String date) { |
| | | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); |
| | | if ("".equals(date)) { |
| | | date = sdf.format(DateUtil.getDate()); |
| | | } |
| | | long millisecond = 0; |
| | | try { |
| | | millisecond = sdf.parse(date).getTime(); |
| | | } catch (ParseException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | return millisecond; |
| | | } |
| | | |
| | | /** |
| | | * 字符串日期转Date |
| | | * @param string |
| | | * @return date |
| | | * @throws ParseException |
| | | */ |
| | | public static Date getStrToDate(String dateString) throws ParseException { |
| | | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); |
| | | Date date = sdf.parse(dateString); |
| | | return date; |
| | | } |
| | | |
| | | /** |
| | | * 字符串日期转Date |
| | | * @param date |
| | | * @return |
| | | */ |
| | | public static Date getDate_str(String dateStr) { |
| | | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); |
| | | sdf.setTimeZone(tz); |
| | | if ("".equals(dateStr)) { |
| | | dateStr = sdf.format(DateUtil.getDate()); |
| | | } |
| | | Date date = null; |
| | | try { |
| | | date = sdf.parse(dateStr); |
| | | } catch (ParseException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | return date; |
| | | } |
| | | |
| | | /** |
| | | * 字符串日期转Date yyyy-MM-dd HH:mm |
| | | * @param date |
| | | * @return |
| | | */ |
| | | public static Date getDate_str2(String dateStr) { |
| | | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm"); |
| | | sdf.setTimeZone(tz); |
| | | if ("".equals(dateStr)) { |
| | | dateStr = sdf.format(DateUtil.getDate()); |
| | | } |
| | | Date date = null; |
| | | try { |
| | | date = sdf.parse(dateStr); |
| | | } catch (ParseException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | return date; |
| | | } |
| | | |
| | | /** |
| | | * 字符串日期转Date yyyy-MM-dd HH:mm:ss |
| | | * @param date |
| | | * @return |
| | | */ |
| | | public static Date getDate_str3(String dateStr) { |
| | | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); |
| | | sdf.setTimeZone(tz); |
| | | if ("".equals(dateStr)) { |
| | | dateStr = sdf.format(DateUtil.getDate()); |
| | | } |
| | | Date date = null; |
| | | try { |
| | | date = sdf.parse(dateStr); |
| | | } catch (ParseException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | return date; |
| | | } |
| | | |
| | | /** |
| | | * 字符串日期转Date |
| | | * @param date |
| | | * @return |
| | | */ |
| | | public static Date getDate_strYMd(Long dateStr) { |
| | | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); |
| | | if (dateStr == null) { |
| | | dateStr = DateUtil.getCurMilli(); |
| | | } |
| | | Date date = null; |
| | | try { |
| | | date = sdf.parse(sdf.format(new Date(dateStr))); |
| | | } catch (ParseException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | return date; |
| | | } |
| | | |
| | | /** |
| | | * 毫秒转Date |
| | | * @param date |
| | | * @return |
| | | */ |
| | | public static Date getDate_strYMdHms(Long dateStr) { |
| | | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); |
| | | if (dateStr == null) { |
| | | dateStr = DateUtil.getCurMilli(); |
| | | } |
| | | Date date = null; |
| | | try { |
| | | date = sdf.parse(sdf.format(new Date(dateStr))); |
| | | } catch (ParseException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | return date; |
| | | } |
| | | |
| | | /** |
| | | * 字符串日期转Date |
| | | * @param date |
| | | * @return |
| | | */ |
| | | public static Date getDate_strYMdHm(Long dateStr) { |
| | | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm"); |
| | | if (dateStr == null) { |
| | | dateStr = DateUtil.getCurMilli(); |
| | | } |
| | | Date date = null; |
| | | try { |
| | | date = sdf.parse(sdf.format(new Date(dateStr))); |
| | | } catch (ParseException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | return date; |
| | | } |
| | | |
| | | /** |
| | | * 字符串日期转毫秒 |
| | | * @param date |
| | | * @return |
| | | */ |
| | | public static long getMillisecond_strDmy(String date) { |
| | | SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy"); |
| | | if ("".equals(date)) { |
| | | date = sdf.format(DateUtil.getDate()); |
| | | } |
| | | long millisecond = 0; |
| | | try { |
| | | millisecond = sdf.parse(date).getTime(); |
| | | } catch (ParseException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | return millisecond; |
| | | } |
| | | |
| | | /** |
| | | * 字符串日期转毫秒转毫秒(加24小时) |
| | | * @param date |
| | | * @return |
| | | */ |
| | | public static long getMillisecond_str_24h(String date) { |
| | | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); |
| | | if ("".equals(date)) { |
| | | date = sdf.format(DateUtil.getDate()); |
| | | } |
| | | long millisecond = 24*3600*1000; |
| | | try { |
| | | millisecond += sdf.parse(date).getTime(); |
| | | } catch (ParseException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | return millisecond; |
| | | } |
| | | |
| | | /** |
| | | * 字符串日期转毫秒转毫秒(加24小时) |
| | | * @param date |
| | | * @return |
| | | */ |
| | | public static long getMillisecond_strYmd_24h(String date) { |
| | | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); |
| | | if ("".equals(date)) { |
| | | date = sdf.format(DateUtil.getDate()); |
| | | } |
| | | long millisecond = 24*3600*1000; |
| | | try { |
| | | millisecond += sdf.parse(date).getTime(); |
| | | } catch (ParseException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | return millisecond; |
| | | } |
| | | |
| | | /** |
| | | * 毫秒转日期 |
| | | * @param millisecond |
| | | * @return |
| | | */ |
| | | public static String getDate(long millisecond) { |
| | | if (millisecond == 0) { |
| | | millisecond = getCurMilli(); |
| | | } |
| | | SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd"); |
| | | Calendar calendar = getCalendar(); |
| | | calendar.setTimeInMillis(millisecond); |
| | | return dateformat.format(calendar.getTime()); |
| | | } |
| | | /** |
| | | * 转换为指定格式的时间 |
| | | * @return Date |
| | | */ |
| | | public static Date getDate(String date, String pattern) { |
| | | SimpleDateFormat format = new SimpleDateFormat(pattern); |
| | | Date d = null; |
| | | try { |
| | | d = format.parse(date); |
| | | } catch (ParseException ex) { |
| | | return null; |
| | | } |
| | | return d; |
| | | } |
| | | |
| | | /** |
| | | * 毫秒转日期 |
| | | * @param millisecond |
| | | * @return |
| | | */ |
| | | public static String getDate_HH(long millisecond) { |
| | | if (millisecond == 0) { |
| | | millisecond = getCurMilli(); |
| | | } |
| | | SimpleDateFormat dateformat = new SimpleDateFormat("HH"); |
| | | Calendar calendar = getCalendar(); |
| | | calendar.setTimeInMillis(millisecond); |
| | | return dateformat.format(calendar.getTime()); |
| | | } |
| | | |
| | | /** |
| | | * 毫秒转日期时间 |
| | | * @param millisecond |
| | | * @return |
| | | */ |
| | | public static String getDateTime(long millisecond) { |
| | | if (millisecond == 0) { |
| | | millisecond = getCurMilli(); |
| | | } |
| | | SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); |
| | | Calendar calendar = getCalendar(); |
| | | calendar.setTimeInMillis(millisecond); |
| | | return dateformat.format(calendar.getTime()); |
| | | } |
| | | |
| | | /** |
| | | * 毫秒转年月日 |
| | | * @param millisecond |
| | | * @return |
| | | */ |
| | | public static String getDateYMD(long millisecond) { |
| | | if (millisecond == 0) { |
| | | millisecond = getCurMilli(); |
| | | } |
| | | SimpleDateFormat dateformat = new SimpleDateFormat("yyyy年MM月dd日"); |
| | | Calendar calendar = getCalendar(); |
| | | calendar.setTimeInMillis(millisecond); |
| | | return dateformat.format(calendar.getTime()); |
| | | } |
| | | |
| | | /** |
| | | * 两日期相差毫秒 |
| | | * @param startDate |
| | | * @param endDate |
| | | * @return |
| | | */ |
| | | public static long getMinusMillisecond(Date startDate, Date endDate) { |
| | | long startMillisecond = getMillisecond(startDate); |
| | | long endMillisecond = getMillisecond(endDate); |
| | | long minusMillisecond = endMillisecond-startMillisecond; |
| | | if (minusMillisecond < 0) { |
| | | minusMillisecond = 0; |
| | | } |
| | | return minusMillisecond; |
| | | } |
| | | |
| | | /** |
| | | * 两日期相差天数 |
| | | * @param startDate |
| | | * @param endDate |
| | | * @return |
| | | */ |
| | | public static long getMinusDay(Date startDate, Date endDate) { |
| | | long startMillisecond = getMillisecond(startDate); |
| | | long endMillisecond = getMillisecond(endDate); |
| | | long minusMillisecond = endMillisecond-startMillisecond; |
| | | long day = 0; |
| | | if (minusMillisecond < 0) { |
| | | day = 0; |
| | | } else { |
| | | day = minusMillisecond/(24*3600*1000); |
| | | } |
| | | return day; |
| | | } |
| | | |
| | | /** |
| | | * 前N天毫秒 |
| | | * @param day |
| | | * @return |
| | | */ |
| | | public static long getRetreatDay_millisecond(int day) { |
| | | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); |
| | | long nowMillisecond = 0; |
| | | try { |
| | | nowMillisecond = sdf.parse(sdf.format(DateUtil.getDate())).getTime(); |
| | | } catch (ParseException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | nowMillisecond += 24*3600*1000; |
| | | long retreatMillisecond = 24*3600*1000*day; |
| | | return nowMillisecond - retreatMillisecond; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 前N天时间 |
| | | * @param day |
| | | * @return |
| | | */ |
| | | public static String getRetreatDay_millisecond1(int day) { |
| | | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); |
| | | long nowMillisecond = 0; |
| | | try { |
| | | nowMillisecond = sdf.parse(sdf.format(DateUtil.getDate())).getTime(); |
| | | } catch (ParseException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | nowMillisecond += 24*3600*1000; |
| | | long retreatMillisecond = 24*3600*1000*day; |
| | | long s=nowMillisecond - retreatMillisecond; |
| | | Date date = new Date(s); |
| | | String res = sdf.format(date); |
| | | return res; |
| | | } |
| | | |
| | | /** |
| | | * 日期转秒 |
| | | * @param date |
| | | * @return |
| | | */ |
| | | public static long getDecond(Date date) { |
| | | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); |
| | | String newDate = ""; |
| | | if (!"".equals(date)) { |
| | | newDate = sdf.format(date); |
| | | } else { |
| | | newDate = sdf.format(DateUtil.getDate()); |
| | | } |
| | | long second = 0; |
| | | try { |
| | | second = sdf.parse(newDate).getTime()/1000; |
| | | } catch (ParseException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | return second; |
| | | } |
| | | |
| | | /** |
| | | * 日期转String |
| | | * @param date |
| | | * @return |
| | | * @throws ParseException |
| | | */ |
| | | public static String getDateToString(Date date) throws ParseException { |
| | | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); |
| | | String newDate = sdf.format(date); |
| | | long millisecond = sdf.parse(newDate).getTime(); |
| | | Calendar calendar = getCalendar(); |
| | | calendar.setTimeInMillis(millisecond); |
| | | return sdf.format(calendar.getTime()); |
| | | } |
| | | |
| | | /** |
| | | * 毫秒转星期XX |
| | | * @param millisecond |
| | | * @return |
| | | */ |
| | | public static int getDate_week(Long millisecond) { |
| | | if (millisecond == null) { |
| | | millisecond = getCurMilli(); |
| | | } |
| | | Calendar cal = getCalendar(); |
| | | cal.setTimeInMillis(millisecond); |
| | | return cal.get(Calendar.DAY_OF_WEEK)-1; |
| | | |
| | | } |
| | | |
| | | /** |
| | | * 获取当前系统时间已yyyy-MM-dd HH:mm:ss格式化的字符串 |
| | | */ |
| | | public static String nowStr(){ |
| | | |
| | | SimpleDateFormat dateFormat = new SimpleDateFormat("yy-MM-dd HH:mm:ss"); |
| | | return dateFormat.format(getDate()); |
| | | } |
| | | |
| | | /** |
| | | * |
| | | * 获取之前几天日期 |
| | | * @param pattern yyyy-MM-dd(默认) |
| | | * @param few 之前几天 |
| | | */ |
| | | public static String beforeFewDayStr(String pattern, Integer few) { |
| | | |
| | | if(pattern == null || "".equals(pattern)){ |
| | | pattern = "yyyy-MM-dd"; |
| | | } |
| | | Calendar c = getCalendar(); |
| | | c.add(Calendar.DATE,-few); |
| | | return new SimpleDateFormat(pattern).format(c.getTime()); |
| | | } |
| | | |
| | | /** |
| | | * 获取今天日期 |
| | | * @param pattern yyyy-MM-dd(默认) |
| | | */ |
| | | public static String todayStr(String pattern) { |
| | | |
| | | if(pattern == null || "".equals(pattern)){ |
| | | pattern = "yyyy-MM-dd"; |
| | | } |
| | | return new SimpleDateFormat(pattern).format(getDate()); |
| | | } |
| | | |
| | | /** |
| | | * 获取当前系统时间戳字符串 |
| | | */ |
| | | public static String nowDateLongStr(){ |
| | | |
| | | return getDate().getTime()+""; |
| | | } |
| | | |
| | | /** |
| | | * 获取当前系统时间 |
| | | * @return |
| | | */ |
| | | public static Date now(){ |
| | | |
| | | return getDate(); |
| | | } |
| | | |
| | | |
| | | public static void main(String[] args) throws ParseException { |
| | | //打印测试日期包含 |
| | | Date time1 = getDate_str("2017-3-11"); |
| | | Date time2 = getDate_str("2017-3-15"); |
| | | Date time3 = getDate_str("2017-3-17"); |
| | | Date time4 = getDate_str("2017-3-12"); |
| | | Date time5 = getDate_str("2017-3-16"); |
| | | Date from = getDate_str("2017-3-12"); |
| | | Date to= getDate_str("2017-3-16"); |
| | | System.out.println(belongCalendar(time1,from,to)); |
| | | System.out.println(belongCalendar(time2,from,to)); |
| | | System.out.println(belongCalendar(time3,from,to)); |
| | | System.out.println(belongCalendar(time4,from,to)); |
| | | System.out.println(belongCalendar(time5,from,to)); |
| | | System.out.println(nowStr()); |
| | | |
| | | |
| | | } |
| | | |
| | | /** |
| | | * 把日期往后增加一天. 正数往后推,负数往前移动 |
| | | * @param day |
| | | * @return |
| | | */ |
| | | public static String getString(int day) { |
| | | Date date=new Date();//取时间 |
| | | Calendar calendar = new GregorianCalendar(); |
| | | calendar.setTime(date); |
| | | calendar.add(calendar.DATE,day);//把日期往后增加一天.整数往后推,负数往前移动 |
| | | date=calendar.getTime(); //这个时间就是日期往后推一天的结果 |
| | | SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd"); |
| | | String dateString = formatter.format(date); |
| | | return dateString; |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | /** |
| | | * 根据当前日期获得所在周的日期区间(周一和周日日期) |
| | | * |
| | | * @return |
| | | * @author zhaoxuepu |
| | | * @throws ParseException |
| | | */ |
| | | public static String getTimeInterval(Date date) { |
| | | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); |
| | | Calendar cal = Calendar.getInstance(); |
| | | cal.setTime(date); |
| | | // 判断要计算的日期是否是周日,如果是则减一天计算周六的,否则会出问题,计算到下一周去了 |
| | | int dayWeek = cal.get(Calendar.DAY_OF_WEEK);// 获得当前日期是一个星期的第几天 |
| | | if (1 == dayWeek) { |
| | | cal.add(Calendar.DAY_OF_MONTH, -1); |
| | | } |
| | | // System.out.println("要计算日期为:" + sdf.format(cal.getTime())); // 输出要计算日期 |
| | | // 设置一个星期的第一天,按中国的习惯一个星期的第一天是星期一 |
| | | cal.setFirstDayOfWeek(Calendar.MONDAY); |
| | | // 获得当前日期是一个星期的第几天 |
| | | int day = cal.get(Calendar.DAY_OF_WEEK); |
| | | // 根据日历的规则,给当前日期减去星期几与一个星期第一天的差值 |
| | | cal.add(Calendar.DATE, cal.getFirstDayOfWeek() - day); |
| | | String imptimeBegin = sdf.format(cal.getTime()); |
| | | // System.out.println("所在周星期一的日期:" + imptimeBegin); |
| | | cal.add(Calendar.DATE, 6); |
| | | String imptimeEnd = sdf.format(cal.getTime()); |
| | | // System.out.println("所在周星期日的日期:" + imptimeEnd); |
| | | return imptimeBegin + "," + imptimeEnd; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 根据当前日期获得上周的日期区间(上周周一和周日日期) |
| | | * |
| | | * @return |
| | | * @author zhaoxuepu |
| | | */ |
| | | public static String getLastTimeInterval() { |
| | | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); |
| | | Calendar calendar1 = Calendar.getInstance(); |
| | | Calendar calendar2 = Calendar.getInstance(); |
| | | int dayOfWeek = calendar1.get(Calendar.DAY_OF_WEEK) - 1; |
| | | int offset1 = 1 - dayOfWeek; |
| | | int offset2 = 7 - dayOfWeek; |
| | | calendar1.add(Calendar.DATE, offset1 - 7); |
| | | calendar2.add(Calendar.DATE, offset2 - 7); |
| | | // System.out.println(sdf.format(calendar1.getTime()));// last Monday |
| | | String lastBeginDate = sdf.format(calendar1.getTime()); |
| | | // System.out.println(sdf.format(calendar2.getTime()));// last Sunday |
| | | String lastEndDate = sdf.format(calendar2.getTime()); |
| | | return lastBeginDate + "," + lastEndDate; |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | public static String DateYUE(){ |
| | | SimpleDateFormat format=new SimpleDateFormat("yyyy-MM-dd"); |
| | | Calendar c = Calendar.getInstance(); |
| | | c.add(Calendar.MONTH, 0); |
| | | c.set(Calendar.DAY_OF_MONTH,1);//设置为1号,当前日期既为本月第一天 |
| | | String first = format.format(c.getTime()); |
| | | |
| | | //获取当前月最后一天 |
| | | Calendar ca = Calendar.getInstance(); |
| | | ca.set(Calendar.DAY_OF_MONTH, ca.getActualMaximum(Calendar.DAY_OF_MONTH)); |
| | | String last = format.format(ca.getTime()); |
| | | return first+","+last; |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | public static String getBeforeFirstMonthdate(){ |
| | | SimpleDateFormat format=new SimpleDateFormat("yyyy-MM-dd"); |
| | | Calendar calendar=Calendar.getInstance(); |
| | | Calendar calendar1=Calendar.getInstance(); |
| | | calendar.add(Calendar.MONTH, -1); |
| | | calendar.set(Calendar.DAY_OF_MONTH, 1); |
| | | |
| | | int month=calendar1.get(Calendar.MONTH); |
| | | calendar1.set(Calendar.MONTH, month-1); |
| | | calendar1.set(Calendar.DAY_OF_MONTH, calendar1.getActualMaximum(Calendar.DAY_OF_MONTH)); |
| | | String str=format.format(calendar.getTime()); |
| | | String str1=format.format(calendar1.getTime()); |
| | | |
| | | return str+","+str1; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 获取某年第一天和最后一天日期 |
| | | * @param year 年份 |
| | | * @return Date |
| | | */ |
| | | |
| | | public static String getYearFirst(int year){ |
| | | SimpleDateFormat format=new SimpleDateFormat("yyyy-MM-dd"); |
| | | Calendar calendar = Calendar.getInstance(); |
| | | calendar.clear(); |
| | | calendar.set(Calendar.YEAR, year); |
| | | |
| | | |
| | | Calendar calendar1 = Calendar.getInstance(); |
| | | calendar1.clear(); |
| | | calendar1.set(Calendar.YEAR, year); |
| | | calendar1.roll(Calendar.DAY_OF_YEAR, -1); |
| | | |
| | | |
| | | String str=format.format(calendar.getTime()); |
| | | String str1=format.format(calendar1.getTime()); |
| | | |
| | | |
| | | return str+","+str1; |
| | | } |
| | | |
| | | |
| | | |
| | | } |
New file |
| | |
| | | package com.ruoyi.order.util; |
| | | |
| | | import java.io.IOException; |
| | | import java.util.Properties; |
| | | |
| | | /** |
| | | * 配置信息 |
| | | * |
| | | * @version 1.0 |
| | | */ |
| | | public class ParamUtil { |
| | | |
| | | /** |
| | | * 获取配置信息 |
| | | */ |
| | | private static Properties properties = new Properties(); |
| | | static{ |
| | | try { |
| | | //获取properties文件 |
| | | properties.load(ParamUtil.class.getClassLoader().getResourceAsStream("conf/param.properties")); |
| | | } catch (IOException e) {e.printStackTrace();} |
| | | } |
| | | |
| | | /** |
| | | * 获取配置参数值 |
| | | * |
| | | * @param key |
| | | * @return |
| | | */ |
| | | public static String getValue(String key){ |
| | | return (String)properties.get(key); |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.ruoyi.order.util; |
| | | |
| | | import java.io.UnsupportedEncodingException; |
| | | import java.text.DecimalFormat; |
| | | import java.text.NumberFormat; |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.UUID; |
| | | import java.util.regex.Matcher; |
| | | import java.util.regex.Pattern; |
| | | |
| | | /** |
| | | * 基本数据处理工具类 |
| | | */ |
| | | public class SinataUtil { |
| | | |
| | | |
| | | /** |
| | | * List集合分页<br/> |
| | | * 创建人:Mryang<br/> |
| | | * 时间:2016年7月28日-下午2:58:14 <br/> |
| | | * @param <T> |
| | | * @param pageNo |
| | | * @param pageSize |
| | | * @param list |
| | | * @throws Exception List<UserOrderList> <br/> |
| | | */ |
| | | public static <T> List<T> listpage(int pageNo, int pageSize, List<T> list) throws Exception { |
| | | List<T> result = new ArrayList<T>(); |
| | | if (list != null && list.size() > 0) { |
| | | int allCount = list.size(); |
| | | if(pageNo > 1 && allCount < pageSize) { |
| | | return new ArrayList<>(); |
| | | } |
| | | int pageCount = (allCount + pageSize - 1) / pageSize; |
| | | if (pageNo >= pageCount) { |
| | | pageNo = pageCount; |
| | | } |
| | | int start = (pageNo - 1) * pageSize; |
| | | int end = pageNo * pageSize; |
| | | if (end >= allCount) { |
| | | end = allCount; |
| | | } |
| | | for (int i = start; i < end; i++) { |
| | | result.add(list.get(i)); |
| | | } |
| | | } |
| | | return (result != null && result.size() > 0) ? result : new ArrayList<T>(); |
| | | } |
| | | |
| | | /** |
| | | * Double类型取整 |
| | | * @param num |
| | | * @return |
| | | */ |
| | | public static String doubleTrans(double num) { |
| | | return String.valueOf((long) num); |
| | | } |
| | | |
| | | /** |
| | | * Double类型保留1位小数 |
| | | * |
| | | * @param num |
| | | * @return |
| | | */ |
| | | public static String doubleRetainOne(double num) { |
| | | DecimalFormat dfs = new DecimalFormat("0.0"); |
| | | return dfs.format(num); |
| | | } |
| | | |
| | | /** |
| | | * Double类型保留2位小数 |
| | | * |
| | | * @param num |
| | | * @return |
| | | */ |
| | | public static String doubleRetainTwo(double num) { |
| | | DecimalFormat dfs = new DecimalFormat("0.00"); |
| | | String.format("%.2f", num); |
| | | return dfs.format(num); |
| | | } |
| | | |
| | | /** |
| | | * Double类型保留1位小数(四舍五入) |
| | | * |
| | | * @param num |
| | | * @return |
| | | */ |
| | | public static String doubleForwardOne(double num) { |
| | | return String.format("%.1f", num); |
| | | } |
| | | |
| | | /** |
| | | * Double类型保留2位小数(四舍五入) |
| | | * |
| | | * @param num |
| | | * @return |
| | | */ |
| | | public static String doubleForwardTwo(double num) { |
| | | return String.format("%.2f", num); |
| | | } |
| | | |
| | | /** |
| | | * 字符串转换成Ascii |
| | | * |
| | | * @param value |
| | | * @return |
| | | */ |
| | | public static String stringToAscii(String value) { |
| | | StringBuffer sbu = new StringBuffer(); |
| | | char[] chars = value.toCharArray(); |
| | | for (int i = 0; i < chars.length; i++) { |
| | | if (i != chars.length - 1) { |
| | | sbu.append((int) chars[i]); |
| | | } else { |
| | | sbu.append((int) chars[i]); |
| | | } |
| | | } |
| | | return sbu.toString(); |
| | | } |
| | | |
| | | /** |
| | | * 小数转换为百分比 |
| | | * |
| | | * @param decimal |
| | | * @return |
| | | * @author TaoNingBo |
| | | */ |
| | | public static String decTurnPercent(double decimal) { |
| | | NumberFormat num = NumberFormat.getPercentInstance(); |
| | | num.setMaximumIntegerDigits(3); |
| | | num.setMaximumFractionDigits(2); |
| | | return num.format(decimal); |
| | | } |
| | | |
| | | /** |
| | | * Ascii转换成字符串 |
| | | * |
| | | * @param value |
| | | * @return |
| | | */ |
| | | public static String asciiToString(String value) { |
| | | String[] chars = value.split(","); |
| | | StringBuffer sbu = new StringBuffer(); |
| | | for (int i = 0; i < chars.length; i++) { |
| | | sbu.append((char) Integer.parseInt(chars[i])); |
| | | } |
| | | return sbu.toString(); |
| | | } |
| | | |
| | | /** |
| | | * 字符串转换unicode |
| | | * |
| | | * @param string |
| | | * @return |
| | | * @author TaoNingBo |
| | | */ |
| | | public static String string2Unicode(String string) { |
| | | StringBuffer unicode = new StringBuffer(); |
| | | for (int i = 0; i < string.length(); i++) { |
| | | // 取出每一个字符 |
| | | char c = string.charAt(i); |
| | | // 转换为unicode |
| | | unicode.append("\\u" + Integer.toHexString(c)); |
| | | } |
| | | return unicode.toString(); |
| | | } |
| | | |
| | | /** |
| | | * unicode 转字符串 |
| | | * |
| | | * @param unicode |
| | | * @return |
| | | * @author TaoNingBo |
| | | */ |
| | | public static String unicode2String(String unicode) { |
| | | StringBuffer string = new StringBuffer(); |
| | | String[] hex = unicode.split("\\\\u"); |
| | | for (int i = 1; i < hex.length; i++) { |
| | | // 转换出每一个代码点 |
| | | int data = Integer.parseInt(hex[i], 16); |
| | | // 追加成string |
| | | string.append((char) data); |
| | | } |
| | | return string.toString(); |
| | | } |
| | | |
| | | /** |
| | | * 字符串编码转换的实现方法 |
| | | * |
| | | * @param str |
| | | * 待转换编码的字符串 |
| | | * @param newCharset |
| | | * 目标编码 |
| | | * @return |
| | | * @throws UnsupportedEncodingException |
| | | */ |
| | | public static String changeCharset(String str, String newCharset) throws UnsupportedEncodingException { |
| | | if (str != null) { |
| | | // 用默认字符编码解码字符串。 |
| | | byte[] bs = str.getBytes(); |
| | | // 用新的字符编码生成字符串 |
| | | return new String(bs, newCharset); |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | /** |
| | | * 注: \n 回车( ) \t 水平制表符( ) \s 空格(\u0008) \r 换行( ) |
| | | * |
| | | * @param str |
| | | * @return |
| | | */ |
| | | public static String replaceBlank(String str) { |
| | | String dest = ""; |
| | | if (str != null) { |
| | | Pattern p = Pattern.compile("\\s*|\t|\r|\n"); |
| | | Matcher m = p.matcher(str); |
| | | dest = m.replaceAll(""); |
| | | } |
| | | return dest; |
| | | } |
| | | |
| | | /** |
| | | * 判断该字符串不能为空 |
| | | * |
| | | * @param str |
| | | * @return |
| | | * @author TaoNingBo |
| | | */ |
| | | public static boolean isNotEmpty(Object str) { |
| | | return !isEmpty(str); |
| | | } |
| | | |
| | | |
| | | public static boolean isNotEmptyUndefined(Object str) { |
| | | return !isEmpty(str) && !str.toString().equals("undefined"); |
| | | } |
| | | |
| | | /** |
| | | * 字符串编码转换的实现方法 |
| | | * |
| | | * @param str |
| | | * 待转换编码的字符串 |
| | | * @param oldCharset |
| | | * 原编码 |
| | | * @param newCharset |
| | | * 目标编码 |
| | | * @return |
| | | * @throws UnsupportedEncodingException |
| | | */ |
| | | public static String changeCharset(String str, String oldCharset, String newCharset) throws UnsupportedEncodingException { |
| | | if (str != null) { |
| | | // 用旧的字符编码解码字符串。解码可能会出现异常。 |
| | | byte[] bs = str.getBytes(oldCharset); |
| | | // 用新的字符编码生成字符串 |
| | | return new String(bs, newCharset); |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | /** |
| | | * 给手机号码加分割符 |
| | | * |
| | | * @param phone |
| | | * @return |
| | | * @author TaoNingBo |
| | | */ |
| | | public static String splitPhone(String phone) { |
| | | if (isNotEmpty(phone)) { |
| | | String strone = phone.substring(0, 3); |
| | | String strtwo = phone.substring(strone.length(), 7); |
| | | String strthree = phone.substring(strtwo.length() + strone.length(), phone.length()); |
| | | return strone + "-" + strtwo + "-" + strthree; |
| | | } |
| | | return ""; |
| | | } |
| | | |
| | | /** |
| | | * 非空判断 |
| | | * |
| | | * @param str |
| | | * @return |
| | | * @author TaoNingBo |
| | | */ |
| | | public static boolean isEmpty(Object str) { |
| | | return str == null || str.toString().length() == 0 || str.equals("") || str.toString().matches("\\s*"); |
| | | } |
| | | |
| | | /** |
| | | * 把米转换成公里 |
| | | * |
| | | * @param km |
| | | * @return |
| | | * @author TaoNingBo |
| | | */ |
| | | public static Double kmTransKilo(Integer m) { |
| | | return Math.round(m / 100d) / 10d; |
| | | } |
| | | |
| | | /** |
| | | * 将List<{@link Object}>转换成List<{@link T}> |
| | | * |
| | | * @param list |
| | | * 将要转换的对象 |
| | | * @param clazs |
| | | * 需要转换的泛型对象 |
| | | * @return |
| | | * @author TaoNingBo |
| | | */ |
| | | @SuppressWarnings("unchecked") |
| | | public static <T> List<T> fromToObject(List<?> list, Class<T> clazs) { |
| | | List<T> t = new ArrayList<T>(); |
| | | for (Object object : list) { |
| | | t.add((T) object); |
| | | } |
| | | return t; |
| | | } |
| | | |
| | | /** |
| | | * 生成 uuid, 即用来标识一笔单,也用做 nonce_str |
| | | * @return |
| | | */ |
| | | public static String generateUUID() { |
| | | return UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32); |
| | | } |
| | | |
| | | /** |
| | | * 将List<{@link Object}>转换成List<{@link Map<String, Object>}> |
| | | * |
| | | * @param list |
| | | * @return |
| | | * @author TaoNingBo |
| | | */ |
| | | @SuppressWarnings("unchecked") |
| | | public static List<Map<String, Object>> fromToObject_M(List<?> list) { |
| | | List<Map<String, Object>> t = new ArrayList<Map<String, Object>>(); |
| | | for (Object object : list) { |
| | | t.add((Map<String, Object>) object); |
| | | } |
| | | return t; |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.ruoyi.order.util.alipay.config; |
| | | |
| | | |
| | | import com.ruoyi.order.util.ParamUtil; |
| | | |
| | | /** |
| | | * 类名:AlipayConfig 功能:基础配置类 详细:设置帐户有关信息及返回路径 版本:3.3 日期:2012-08-10 |
| | | * 说明:以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。 |
| | | * |
| | | * 附:该代码仅供学习和研究支付宝接口使用,只是提供一个参考。 |
| | | * |
| | | * 提示:如何获取安全校验码和合作身份者ID 1.用您的签约支付宝账号登录支付宝网站(www.alipay.com) |
| | | * 2.点击“商家服务”(https://b.alipay.com/order/myOrder.htm) |
| | | * 3.点击“查询合作者身份(PID)”、“查询安全校验码(Key)”安全校验码查看时,输入支付密码后,页面呈灰色的现象,怎么办? 解决方法: |
| | | * 1、检查浏览器配置,不让浏览器做弹框屏蔽设置 2、更换浏览器或电脑,重新登录查询。 |
| | | */ |
| | | |
| | | public class AlipayConfig { |
| | | |
| | | // ↓↓↓↓↓↓↓↓↓↓请在这里配置您的基本信息↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ |
| | | // 商户的私钥 |
| | | public static String private_key = ParamUtil.getValue("private_key"); |
| | | // 商户收款账号 |
| | | public static final String seller_email = ParamUtil.getValue("seller_email"); |
| | | // 支付宝的公钥 |
| | | public static String ali_public_key = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgRS4mO8v95swMPfUAezNK5hM+M/HqX0GT/QEPaICcQU1CNAup7pZuFm0jWyWrA0eOOWCzN5Qky0UEWZjZAd06xvYtxCNCgKh3SoGXWNUVIQ/iTFrZHWK9hn58Krm0vTLSZH1fxhqcYZmiE/ndeJvWRNHZB2UEQhLc5mE/nl3fC3zvMUcY77btfFm/MLRdJRSK83trG1dJ4pXqmROi77rg3dIF6rsdtqB3BCLQ9mks6m/lTx89tcZD6TVooMd4tPUsBnC0bWjqm2d020ufLEi6sf+Lh5UUsT6ueNTk1Pbc/5oOlRjOeV/MQLj4icoWstKn8pWc97FTVAQ9Pmce3COKQIDAQAB"; |
| | | // appId |
| | | public static String app_id = ParamUtil.getValue("app_id"); |
| | | // 回调地址 |
| | | public static String notify_url = ParamUtil.getValue("notify_url"); |
| | | // ↑↑↑↑↑↑↑↑↑↑请在这里配置您的基本信息↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ |
| | | |
| | | // 调试用,创建TXT日志文件夹路径 |
| | | public static String log_path = "E:\\"; |
| | | |
| | | // 字符编码格式 目前支持 gbk 或 utf-8 |
| | | public static String input_charset = "utf-8"; |
| | | |
| | | // 签名方式 不需修改 |
| | | public static String sign_type = "RSA2"; |
| | | |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright (C) 2010 The MobileSecurePay Project |
| | | * All right reserved. |
| | | * author: shiqun.shi@alipay.com |
| | | */ |
| | | |
| | | package com.ruoyi.order.util.alipay.sign; |
| | | |
| | | public final class Base64 { |
| | | |
| | | static private final int BASELENGTH = 128; |
| | | static private final int LOOKUPLENGTH = 64; |
| | | static private final int TWENTYFOURBITGROUP = 24; |
| | | static private final int EIGHTBIT = 8; |
| | | static private final int SIXTEENBIT = 16; |
| | | static private final int FOURBYTE = 4; |
| | | static private final int SIGN = -128; |
| | | static private final char PAD = '='; |
| | | static private final boolean fDebug = false; |
| | | static final private byte[] base64Alphabet = new byte[BASELENGTH]; |
| | | static final private char[] lookUpBase64Alphabet = new char[LOOKUPLENGTH]; |
| | | |
| | | static { |
| | | for (int i = 0; i < BASELENGTH; ++i) { |
| | | base64Alphabet[i] = -1; |
| | | } |
| | | for (int i = 'Z'; i >= 'A'; i--) { |
| | | base64Alphabet[i] = (byte) (i - 'A'); |
| | | } |
| | | for (int i = 'z'; i >= 'a'; i--) { |
| | | base64Alphabet[i] = (byte) (i - 'a' + 26); |
| | | } |
| | | |
| | | for (int i = '9'; i >= '0'; i--) { |
| | | base64Alphabet[i] = (byte) (i - '0' + 52); |
| | | } |
| | | |
| | | base64Alphabet['+'] = 62; |
| | | base64Alphabet['/'] = 63; |
| | | |
| | | for (int i = 0; i <= 25; i++) { |
| | | lookUpBase64Alphabet[i] = (char) ('A' + i); |
| | | } |
| | | |
| | | for (int i = 26, j = 0; i <= 51; i++, j++) { |
| | | lookUpBase64Alphabet[i] = (char) ('a' + j); |
| | | } |
| | | |
| | | for (int i = 52, j = 0; i <= 61; i++, j++) { |
| | | lookUpBase64Alphabet[i] = (char) ('0' + j); |
| | | } |
| | | lookUpBase64Alphabet[62] = (char) '+'; |
| | | lookUpBase64Alphabet[63] = (char) '/'; |
| | | |
| | | } |
| | | |
| | | private static boolean isWhiteSpace(char octect) { |
| | | return (octect == 0x20 || octect == 0xd || octect == 0xa || octect == 0x9); |
| | | } |
| | | |
| | | private static boolean isPad(char octect) { |
| | | return (octect == PAD); |
| | | } |
| | | |
| | | private static boolean isData(char octect) { |
| | | return (octect < BASELENGTH && base64Alphabet[octect] != -1); |
| | | } |
| | | |
| | | /** |
| | | * Encodes hex octects into Base64 |
| | | * |
| | | * @param binaryData |
| | | * Array containing binaryData |
| | | * @return Encoded Base64 array |
| | | */ |
| | | public static String encode(byte[] binaryData) { |
| | | |
| | | if (binaryData == null) { |
| | | return null; |
| | | } |
| | | |
| | | int lengthDataBits = binaryData.length * EIGHTBIT; |
| | | if (lengthDataBits == 0) { |
| | | return ""; |
| | | } |
| | | |
| | | int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP; |
| | | int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP; |
| | | int numberQuartet = fewerThan24bits != 0 ? numberTriplets + 1 : numberTriplets; |
| | | char encodedData[] = null; |
| | | |
| | | encodedData = new char[numberQuartet * 4]; |
| | | |
| | | byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0; |
| | | |
| | | int encodedIndex = 0; |
| | | int dataIndex = 0; |
| | | if (fDebug) { |
| | | System.out.println("number of triplets = " + numberTriplets); |
| | | } |
| | | |
| | | for (int i = 0; i < numberTriplets; i++) { |
| | | b1 = binaryData[dataIndex++]; |
| | | b2 = binaryData[dataIndex++]; |
| | | b3 = binaryData[dataIndex++]; |
| | | |
| | | if (fDebug) { |
| | | System.out.println("b1= " + b1 + ", b2= " + b2 + ", b3= " + b3); |
| | | } |
| | | |
| | | l = (byte) (b2 & 0x0f); |
| | | k = (byte) (b1 & 0x03); |
| | | |
| | | byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0); |
| | | byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0); |
| | | byte val3 = ((b3 & SIGN) == 0) ? (byte) (b3 >> 6) : (byte) ((b3) >> 6 ^ 0xfc); |
| | | |
| | | if (fDebug) { |
| | | System.out.println("val2 = " + val2); |
| | | System.out.println("k4 = " + (k << 4)); |
| | | System.out.println("vak = " + (val2 | (k << 4))); |
| | | } |
| | | |
| | | encodedData[encodedIndex++] = lookUpBase64Alphabet[val1]; |
| | | encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)]; |
| | | encodedData[encodedIndex++] = lookUpBase64Alphabet[(l << 2) | val3]; |
| | | encodedData[encodedIndex++] = lookUpBase64Alphabet[b3 & 0x3f]; |
| | | } |
| | | |
| | | // form integral number of 6-bit groups |
| | | if (fewerThan24bits == EIGHTBIT) { |
| | | b1 = binaryData[dataIndex]; |
| | | k = (byte) (b1 & 0x03); |
| | | if (fDebug) { |
| | | System.out.println("b1=" + b1); |
| | | System.out.println("b1<<2 = " + (b1 >> 2)); |
| | | } |
| | | byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0); |
| | | encodedData[encodedIndex++] = lookUpBase64Alphabet[val1]; |
| | | encodedData[encodedIndex++] = lookUpBase64Alphabet[k << 4]; |
| | | encodedData[encodedIndex++] = PAD; |
| | | encodedData[encodedIndex++] = PAD; |
| | | } else if (fewerThan24bits == SIXTEENBIT) { |
| | | b1 = binaryData[dataIndex]; |
| | | b2 = binaryData[dataIndex + 1]; |
| | | l = (byte) (b2 & 0x0f); |
| | | k = (byte) (b1 & 0x03); |
| | | |
| | | byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0); |
| | | byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0); |
| | | |
| | | encodedData[encodedIndex++] = lookUpBase64Alphabet[val1]; |
| | | encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)]; |
| | | encodedData[encodedIndex++] = lookUpBase64Alphabet[l << 2]; |
| | | encodedData[encodedIndex++] = PAD; |
| | | } |
| | | |
| | | return new String(encodedData); |
| | | } |
| | | |
| | | /** |
| | | * Decodes Base64 data into octects |
| | | * |
| | | * @param encoded |
| | | * string containing Base64 data |
| | | * @return Array containind decoded data. |
| | | */ |
| | | public static byte[] decode(String encoded) { |
| | | |
| | | if (encoded == null) { |
| | | return null; |
| | | } |
| | | |
| | | char[] base64Data = encoded.toCharArray(); |
| | | // remove white spaces |
| | | int len = removeWhiteSpace(base64Data); |
| | | |
| | | if (len % FOURBYTE != 0) { |
| | | return null;// should be divisible by four |
| | | } |
| | | |
| | | int numberQuadruple = (len / FOURBYTE); |
| | | |
| | | if (numberQuadruple == 0) { |
| | | return new byte[0]; |
| | | } |
| | | |
| | | byte decodedData[] = null; |
| | | byte b1 = 0, b2 = 0, b3 = 0, b4 = 0; |
| | | char d1 = 0, d2 = 0, d3 = 0, d4 = 0; |
| | | |
| | | int i = 0; |
| | | int encodedIndex = 0; |
| | | int dataIndex = 0; |
| | | decodedData = new byte[(numberQuadruple) * 3]; |
| | | |
| | | for (; i < numberQuadruple - 1; i++) { |
| | | |
| | | if (!isData((d1 = base64Data[dataIndex++])) || !isData((d2 = base64Data[dataIndex++])) |
| | | || !isData((d3 = base64Data[dataIndex++])) || !isData((d4 = base64Data[dataIndex++]))) { |
| | | return null; |
| | | } // if found "no data" just return null |
| | | |
| | | b1 = base64Alphabet[d1]; |
| | | b2 = base64Alphabet[d2]; |
| | | b3 = base64Alphabet[d3]; |
| | | b4 = base64Alphabet[d4]; |
| | | |
| | | decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4); |
| | | decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); |
| | | decodedData[encodedIndex++] = (byte) (b3 << 6 | b4); |
| | | } |
| | | |
| | | if (!isData((d1 = base64Data[dataIndex++])) || !isData((d2 = base64Data[dataIndex++]))) { |
| | | return null;// if found "no data" just return null |
| | | } |
| | | |
| | | b1 = base64Alphabet[d1]; |
| | | b2 = base64Alphabet[d2]; |
| | | |
| | | d3 = base64Data[dataIndex++]; |
| | | d4 = base64Data[dataIndex++]; |
| | | if (!isData((d3)) || !isData((d4))) {// Check if they are PAD characters |
| | | if (isPad(d3) && isPad(d4)) { |
| | | if ((b2 & 0xf) != 0)// last 4 bits should be zero |
| | | { |
| | | return null; |
| | | } |
| | | byte[] tmp = new byte[i * 3 + 1]; |
| | | System.arraycopy(decodedData, 0, tmp, 0, i * 3); |
| | | tmp[encodedIndex] = (byte) (b1 << 2 | b2 >> 4); |
| | | return tmp; |
| | | } else if (!isPad(d3) && isPad(d4)) { |
| | | b3 = base64Alphabet[d3]; |
| | | if ((b3 & 0x3) != 0)// last 2 bits should be zero |
| | | { |
| | | return null; |
| | | } |
| | | byte[] tmp = new byte[i * 3 + 2]; |
| | | System.arraycopy(decodedData, 0, tmp, 0, i * 3); |
| | | tmp[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4); |
| | | tmp[encodedIndex] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); |
| | | return tmp; |
| | | } else { |
| | | return null; |
| | | } |
| | | } else { // No PAD e.g 3cQl |
| | | b3 = base64Alphabet[d3]; |
| | | b4 = base64Alphabet[d4]; |
| | | decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4); |
| | | decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); |
| | | decodedData[encodedIndex++] = (byte) (b3 << 6 | b4); |
| | | |
| | | } |
| | | |
| | | return decodedData; |
| | | } |
| | | |
| | | /** |
| | | * remove WhiteSpace from MIME containing encoded Base64 data. |
| | | * |
| | | * @param data |
| | | * the byte array of base64 data (with WS) |
| | | * @return the new length |
| | | */ |
| | | private static int removeWhiteSpace(char[] data) { |
| | | if (data == null) { |
| | | return 0; |
| | | } |
| | | |
| | | // count characters that's not whitespace |
| | | int newSize = 0; |
| | | int len = data.length; |
| | | for (int i = 0; i < len; i++) { |
| | | if (!isWhiteSpace(data[i])) { |
| | | data[newSize++] = data[i]; |
| | | } |
| | | } |
| | | return newSize; |
| | | } |
| | | } |
New file |
| | |
| | | package com.ruoyi.order.util.alipay.sign; |
| | | |
| | | import javax.crypto.Cipher; |
| | | import java.io.ByteArrayInputStream; |
| | | import java.io.ByteArrayOutputStream; |
| | | import java.io.InputStream; |
| | | import java.security.KeyFactory; |
| | | import java.security.PrivateKey; |
| | | import java.security.PublicKey; |
| | | import java.security.spec.PKCS8EncodedKeySpec; |
| | | import java.security.spec.X509EncodedKeySpec; |
| | | |
| | | public class RSA { |
| | | |
| | | public static final String SIGN_ALGORITHMS = "SHA1WithRSA"; |
| | | |
| | | /** |
| | | * RSA签名 |
| | | * |
| | | * @param content |
| | | * 待签名数据 |
| | | * @param privateKey |
| | | * 商户私钥 |
| | | * @param input_charset |
| | | * 编码格式 |
| | | * @return 签名值 |
| | | */ |
| | | public static String sign(String content, String privateKey, String input_charset) { |
| | | try { |
| | | PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(Base64.decode(privateKey)); |
| | | KeyFactory keyf = KeyFactory.getInstance("RSA"); |
| | | PrivateKey priKey = keyf.generatePrivate(priPKCS8); |
| | | java.security.Signature signature = java.security.Signature.getInstance(SIGN_ALGORITHMS); |
| | | signature.initSign(priKey); |
| | | signature.update(content.getBytes(input_charset)); |
| | | byte[] signed = signature.sign(); |
| | | return Base64.encode(signed); |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | /** |
| | | * RSA验签名检查 |
| | | * |
| | | * @param content |
| | | * 待签名数据 |
| | | * @param sign |
| | | * 签名值 |
| | | * @param ali_public_key |
| | | * 支付宝公钥 |
| | | * @param input_charset |
| | | * 编码格式 |
| | | * @return 布尔值 |
| | | */ |
| | | public static boolean verify(String content, String sign, String ali_public_key, String input_charset) { |
| | | try { |
| | | KeyFactory keyFactory = KeyFactory.getInstance("RSA"); |
| | | byte[] encodedKey = Base64.decode(ali_public_key); |
| | | PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey)); |
| | | java.security.Signature signature = java.security.Signature.getInstance(SIGN_ALGORITHMS); |
| | | signature.initVerify(pubKey); |
| | | signature.update(content.getBytes(input_charset)); |
| | | boolean bverify = signature.verify(Base64.decode(sign)); |
| | | return bverify; |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | /** |
| | | * 解密 |
| | | * |
| | | * @param content |
| | | * 密文 |
| | | * @param private_key |
| | | * 商户私钥 |
| | | * @param input_charset |
| | | * 编码格式 |
| | | * @return 解密后的字符串 |
| | | */ |
| | | public static String decrypt(String content, String private_key, String input_charset) throws Exception { |
| | | PrivateKey prikey = getPrivateKey(private_key); |
| | | |
| | | Cipher cipher = Cipher.getInstance("RSA"); |
| | | cipher.init(Cipher.DECRYPT_MODE, prikey); |
| | | |
| | | InputStream ins = new ByteArrayInputStream(Base64.decode(content)); |
| | | ByteArrayOutputStream writer = new ByteArrayOutputStream(); |
| | | // rsa解密的字节大小最多是128,将需要解密的内容,按128位拆开解密 |
| | | byte[] buf = new byte[128]; |
| | | int bufl; |
| | | |
| | | while ((bufl = ins.read(buf)) != -1) { |
| | | byte[] block = null; |
| | | |
| | | if (buf.length == bufl) { |
| | | block = buf; |
| | | } else { |
| | | block = new byte[bufl]; |
| | | for (int i = 0; i < bufl; i++) { |
| | | block[i] = buf[i]; |
| | | } |
| | | } |
| | | |
| | | writer.write(cipher.doFinal(block)); |
| | | } |
| | | |
| | | return new String(writer.toByteArray(), input_charset); |
| | | } |
| | | |
| | | /** |
| | | * 得到私钥 |
| | | * |
| | | * @param key |
| | | * 密钥字符串(经过base64编码) |
| | | * @throws Exception |
| | | */ |
| | | public static PrivateKey getPrivateKey(String key) throws Exception { |
| | | byte[] keyBytes; |
| | | |
| | | keyBytes = Base64.decode(key); |
| | | |
| | | PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes); |
| | | |
| | | KeyFactory keyFactory = KeyFactory.getInstance("RSA"); |
| | | |
| | | PrivateKey privateKey = keyFactory.generatePrivate(keySpec); |
| | | |
| | | return privateKey; |
| | | } |
| | | } |
New file |
| | |
| | | package com.ruoyi.order.util.alipay.sign; |
| | | |
| | | import java.security.KeyFactory; |
| | | import java.security.PrivateKey; |
| | | import java.security.spec.PKCS8EncodedKeySpec; |
| | | |
| | | public class SignUtils { |
| | | |
| | | private static final String ALGORITHM = "RSA"; |
| | | |
| | | private static final String SIGN_ALGORITHMS = "SHA1WithRSA"; |
| | | |
| | | private static final String DEFAULT_CHARSET = "UTF-8"; |
| | | |
| | | public static String sign(String content, String privateKey) { |
| | | try { |
| | | PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(Base64.decode(privateKey)); |
| | | KeyFactory keyf = KeyFactory.getInstance(ALGORITHM); |
| | | PrivateKey priKey = keyf.generatePrivate(priPKCS8); |
| | | |
| | | java.security.Signature signature = java.security.Signature.getInstance(SIGN_ALGORITHMS); |
| | | |
| | | signature.initSign(priKey); |
| | | signature.update(content.getBytes(DEFAULT_CHARSET)); |
| | | |
| | | byte[] signed = signature.sign(); |
| | | |
| | | return Base64.encode(signed); |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | } |
| | | |
| | | return null; |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.ruoyi.order.util.alipay.util; |
| | | |
| | | |
| | | |
| | | import com.ruoyi.order.util.alipay.config.AlipayConfig; |
| | | |
| | | import java.io.FileWriter; |
| | | import java.io.IOException; |
| | | import java.util.*; |
| | | |
| | | /* * |
| | | *类名:AlipayFunction |
| | | *功能:支付宝接口公用函数类 |
| | | *详细:该类是请求、通知返回两个文件所调用的公用函数核心处理文件,不需要修改 |
| | | *版本:3.3 |
| | | *日期:2012-08-14 |
| | | *说明: |
| | | *以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。 |
| | | *该代码仅供学习和研究支付宝接口使用,只是提供一个参考。 |
| | | */ |
| | | |
| | | public class AlipayCore { |
| | | |
| | | /** |
| | | * 除去数组中的空值和签名参数 |
| | | * @param sArray 签名参数组 |
| | | * @return 去掉空值与签名参数后的新签名参数组 |
| | | */ |
| | | public static Map<String, String> paraFilter(Map<String, String> sArray) { |
| | | |
| | | Map<String, String> result = new HashMap<String, String>(); |
| | | |
| | | if (sArray == null || sArray.size() <= 0) { |
| | | return result; |
| | | } |
| | | |
| | | for (String key : sArray.keySet()) { |
| | | String value = sArray.get(key); |
| | | if (value == null || value.equals("") || key.equalsIgnoreCase("sign") |
| | | || key.equalsIgnoreCase("sign_type")) { |
| | | continue; |
| | | } |
| | | result.put(key, value); |
| | | } |
| | | |
| | | return result; |
| | | } |
| | | |
| | | /** |
| | | * 把数组所有元素排序,并按照“参数=参数值”的模式用“&”字符拼接成字符串 |
| | | * @param params 需要排序并参与字符拼接的参数组 |
| | | * @return 拼接后字符串 |
| | | */ |
| | | public static String createLinkString(Map<String, String> params) { |
| | | |
| | | List<String> keys = new ArrayList<String>(params.keySet()); |
| | | Collections.sort(keys); |
| | | |
| | | String prestr = ""; |
| | | |
| | | for (int i = 0; i < keys.size(); i++) { |
| | | String key = keys.get(i); |
| | | String value = params.get(key); |
| | | |
| | | if (i == keys.size() - 1) {//拼接时,不包括最后一个&字符 |
| | | prestr = prestr + key + "=" + value; |
| | | } else { |
| | | prestr = prestr + key + "=" + value + "&"; |
| | | } |
| | | } |
| | | |
| | | return prestr; |
| | | } |
| | | |
| | | /** |
| | | * 写日志,方便测试(看网站需求,也可以改成把记录存入数据库) |
| | | * @param sWord 要写入日志里的文本内容 |
| | | */ |
| | | public static void logResult(String sWord) { |
| | | FileWriter writer = null; |
| | | try { |
| | | writer = new FileWriter(AlipayConfig.log_path + "alipay_log_" + System.currentTimeMillis()+".txt"); |
| | | writer.write(sWord); |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | } finally { |
| | | if (writer != null) { |
| | | try { |
| | | writer.close(); |
| | | } catch (IOException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | } |
New file |
| | |
| | | package com.ruoyi.order.util.alipay.util; |
| | | |
| | | |
| | | |
| | | /* * |
| | | *类名:AlipayNotify |
| | | *功能:支付宝通知处理类 |
| | | *详细:处理支付宝各接口通知返回 |
| | | *版本:3.3 |
| | | *日期:2012-08-17 |
| | | *说明: |
| | | *以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。 |
| | | *该代码仅供学习和研究支付宝接口使用,只是提供一个参考 |
| | | |
| | | *************************注意************************* |
| | | *调试通知返回时,可查看或改写log日志的写入TXT里的数据,来检查通知返回是否正常 |
| | | */ |
| | | public class AlipayNotify { |
| | | |
| | | public static void main(String[] args) { |
| | | System.out.println("11111111111111111111"); |
| | | String dd="2017-09-02 17:11"; |
| | | System.out.println(dd.length()); |
| | | } |
| | | |
| | | |
| | | } |
New file |
| | |
| | | package com.ruoyi.order.util.alipay.util; |
| | | |
| | | |
| | | import com.alipay.api.AlipayApiException; |
| | | import com.alipay.api.AlipayClient; |
| | | import com.alipay.api.DefaultAlipayClient; |
| | | import com.alipay.api.domain.AlipayTradeAppPayModel; |
| | | import com.alipay.api.request.AlipayTradeAppPayRequest; |
| | | import com.alipay.api.response.AlipayTradeAppPayResponse; |
| | | import com.alipay.config.AlipayConfig; |
| | | |
| | | import java.io.UnsupportedEncodingException; |
| | | import java.util.HashMap; |
| | | import java.util.Map; |
| | | |
| | | |
| | | /** |
| | | * 支付宝签名工具类< |
| | | */ |
| | | @SuppressWarnings("unused") |
| | | public class PayDemoActivity { |
| | | |
| | | /** 支付宝参数配置项 */ |
| | | public static String serverUrl = "https://openapi.alipay.com/gateway.do"; |
| | | public static String format = "json"; |
| | | public static String charset = "UTF-8"; |
| | | public static String signType = "RSA2"; |
| | | |
| | | public static String APP_ID = AlipayConfig.app_id; |
| | | public static String APP_PRIVATE_KEY = AlipayConfig.private_key; |
| | | public static String ALIPAY_PUBLIC_KEY = AlipayConfig.ali_public_key; |
| | | public static String NOTIFY_URL = AlipayConfig.notify_url; |
| | | |
| | | //实例化客户端 |
| | | private static AlipayClient alipayClient = new DefaultAlipayClient(serverUrl, APP_ID, APP_PRIVATE_KEY, format, charset, ALIPAY_PUBLIC_KEY, signType); |
| | | |
| | | |
| | | /** |
| | | * @throws AlipayApiException |
| | | * @throws UnsupportedEncodingException |
| | | * @throws UnsupportedEncodingException |
| | | * @throws AlipayApiException |
| | | * |
| | | * 方法功能说明:支付宝2.0 app支付 |
| | | * 创建:2017年2月10日 by tzj |
| | | * 修改:日期 by 修改者 |
| | | * 修改内容: |
| | | * @参数: @param subject |
| | | * @参数: @param body |
| | | * @参数: @param price |
| | | * @参数: @param out_trade_no |
| | | * @参数: @param notify_url |
| | | * @参数: @return |
| | | * @return Map<String,Object> |
| | | * @throws |
| | | */ |
| | | public static Map<String, Object> appPay(String subject, String body, Double price, String out_trade_no) throws UnsupportedEncodingException, AlipayApiException{ |
| | | |
| | | String outtradeno = out_trade_no; |
| | | String total_amount = price+""; |
| | | |
| | | /*********** 测试数据(仅供测试) ************/ |
| | | // subject = "subject"+DateUtil.getTodayDate("yyMMssHHmmss"); |
| | | // total_amount = "0.01"; |
| | | |
| | | /*********** 测试数据(仅供测试)end ************/ |
| | | |
| | | Map<String, Object> map = new HashMap<>(); |
| | | try { |
| | | |
| | | //实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.app.pay |
| | | AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest(); |
| | | //SDK已经封装掉了公共参数,这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。 |
| | | AlipayTradeAppPayModel model = new AlipayTradeAppPayModel(); |
| | | model.setBody(body); |
| | | model.setSubject(subject); |
| | | model.setOutTradeNo(outtradeno); |
| | | model.setTimeoutExpress("30m"); |
| | | model.setTotalAmount(total_amount); |
| | | model.setProductCode("QUICK_MSECURITY_PAY"); |
| | | request.setBizModel(model); |
| | | request.setNotifyUrl(NOTIFY_URL); |
| | | // 这里和普通的接口调用不同,使用的是sdkExecute |
| | | AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request); |
| | | String string = response.getBody(); |
| | | |
| | | int one = string.lastIndexOf("&"); |
| | | String s=string.substring(0,(one)); |
| | | |
| | | map.put("orderInfo", s); |
| | | System.out.println(java.net.URLDecoder.decode(s, "UTF-8")); |
| | | System.out.println(java.net.URLDecoder.decode(response.getBody(), "UTF-8")); |
| | | |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | } |
| | | return map; |
| | | } |
| | | |
| | | |
| | | } |
New file |
| | |
| | | |
| | | package com.ruoyi.order.util.alipay.util; |
| | | |
| | | import java.text.DateFormat; |
| | | import java.text.SimpleDateFormat; |
| | | import java.util.Date; |
| | | import java.util.Random; |
| | | |
| | | /* * |
| | | *类名:UtilDate |
| | | *功能:自定义订单类 |
| | | *详细:工具类,可以用作获取系统日期、订单编号等 |
| | | *版本:3.3 |
| | | *日期:2012-08-17 |
| | | *说明: |
| | | *以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。 |
| | | *该代码仅供学习和研究支付宝接口使用,只是提供一个参考。 |
| | | */ |
| | | public class UtilDate { |
| | | |
| | | /** 年月日时分秒(无下划线) yyyyMMddHHmmss */ |
| | | public static final String dtLong = "yyyyMMddHHmmss"; |
| | | |
| | | /** 完整时间 yyyy-MM-dd HH:mm:ss */ |
| | | public static final String simple = "yyyy-MM-dd HH:mm:ss"; |
| | | |
| | | /** 年月日(无下划线) yyyyMMdd */ |
| | | public static final String dtShort = "yyyyMMdd"; |
| | | |
| | | |
| | | /** |
| | | * 返回系统当前时间(精确到毫秒),作为一个唯一的订单编号 |
| | | * @return |
| | | * 以yyyyMMddHHmmss为格式的当前系统时间 |
| | | */ |
| | | public static String getOrderNum(){ |
| | | Date date=new Date(); |
| | | DateFormat df=new SimpleDateFormat(dtLong); |
| | | return df.format(date); |
| | | } |
| | | |
| | | /** |
| | | * 获取系统当前日期(精确到毫秒),格式:yyyy-MM-dd HH:mm:ss |
| | | * @return |
| | | */ |
| | | public static String getDateFormatter(){ |
| | | Date date=new Date(); |
| | | DateFormat df=new SimpleDateFormat(simple); |
| | | return df.format(date); |
| | | } |
| | | |
| | | /** |
| | | * 获取系统当期年月日(精确到天),格式:yyyyMMdd |
| | | * @return |
| | | */ |
| | | public static String getDate(){ |
| | | Date date=new Date(); |
| | | DateFormat df=new SimpleDateFormat(dtShort); |
| | | return df.format(date); |
| | | } |
| | | |
| | | /** |
| | | * 产生随机的三位数 |
| | | * @return |
| | | */ |
| | | public static String getThree(){ |
| | | Random rad=new Random(); |
| | | return rad.nextInt(1000)+""; |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.tencent; |
| | | import java.util.Map; |
| | | |
| | | |
| | | import com.tencent.common.Configure; |
| | | import com.tencent.common.WXPayConfig; |
| | | import com.tencent.common.WXPayConstants; |
| | | import com.tencent.common.WXPayConstants.SignType; |
| | | import com.tencent.common.WXPayUtil; |
| | | import com.tencent.protocol.RefundReqData; |
| | | import com.tencent.protocol.UnifiedorderReqData; |
| | | import com.tencent.protocol.WXPayRequest; |
| | | import com.tencent.service.RefundService; |
| | | import com.tencent.service.UnifiedorderService; |
| | | /** |
| | | * SDK总入口 |
| | | */ |
| | | /** |
| | | * SDK总入口 |
| | | */ |
| | | public class WXPay { |
| | | |
| | | private WXPayConfig config; |
| | | private SignType signType; |
| | | private boolean autoReport; |
| | | private boolean useSandbox; |
| | | private String notifyUrl; |
| | | private WXPayRequest wxPayRequest; |
| | | |
| | | public WXPay(final WXPayConfig config) throws Exception { |
| | | this(config, null, true, false); |
| | | } |
| | | |
| | | public WXPay(final WXPayConfig config, final boolean autoReport) throws Exception { |
| | | this(config, null, autoReport, false); |
| | | } |
| | | |
| | | |
| | | public WXPay(final WXPayConfig config, final boolean autoReport, final boolean useSandbox) throws Exception{ |
| | | this(config, null, autoReport, useSandbox); |
| | | } |
| | | |
| | | public WXPay(final WXPayConfig config, final String notifyUrl) throws Exception { |
| | | this(config, notifyUrl, true, false); |
| | | } |
| | | |
| | | public WXPay(final WXPayConfig config, final String notifyUrl, final boolean autoReport) throws Exception { |
| | | this(config, notifyUrl, autoReport, false); |
| | | } |
| | | |
| | | public WXPay(final WXPayConfig config, final String notifyUrl, final boolean autoReport, final boolean useSandbox) throws Exception { |
| | | this.config = config; |
| | | this.notifyUrl = notifyUrl; |
| | | this.autoReport = autoReport; |
| | | this.useSandbox = useSandbox; |
| | | if (useSandbox) { |
| | | this.signType = SignType.MD5; // 沙箱环境 |
| | | } |
| | | else { |
| | | this.signType = SignType.HMACSHA256; |
| | | } |
| | | this.wxPayRequest = new WXPayRequest(config); |
| | | } |
| | | |
| | | /** |
| | | * 初始化SDK依赖的几个关键配置 |
| | | * @param key 签名算法需要用到的秘钥 |
| | | * @param appID 公众账号ID |
| | | * @param mchID 商户ID |
| | | * @param sdbMchID 子商户ID,受理模式必填 |
| | | * @param certLocalPath HTTP证书在服务器中的路径,用来加载证书用 |
| | | * @param certPassword HTTP证书的密码,默认等于MCHID |
| | | */ |
| | | public static void initSDKConfiguration(String key,String appID,String mchID,String sdbMchID,String certLocalPath,String certPassword){ |
| | | System.out.println("________@@@@@______initSDKConfiguration"); |
| | | Configure.setKey(key); |
| | | Configure.setAppID(appID); |
| | | Configure.setMchID(mchID); |
| | | Configure.setSubMchID(sdbMchID); |
| | | Configure.setCertLocalPath(certLocalPath); |
| | | Configure.setCertPassword(certPassword); |
| | | } |
| | | |
| | | /** |
| | | * 请求统一下单服务 |
| | | */ |
| | | public static String requestUnifiedorderService(Integer apptype,UnifiedorderReqData unifiedorderReqData) throws Exception{ |
| | | return new UnifiedorderService(apptype).request(unifiedorderReqData); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 商家向用户付款(提现) |
| | | */ |
| | | /* public static String requestPayToTheUserService(Integer apptype, PayToTheUserReqData payToTheUserReqData) throws Exception{ |
| | | return new PayToTheUserService(apptype).request(payToTheUserReqData); |
| | | }*/ |
| | | |
| | | /** |
| | | * 请求退款服务 |
| | | */ |
| | | public static String requestRefundService(Integer apptype, RefundReqData refundReqData) throws Exception{ |
| | | return new RefundService(apptype).request(refundReqData); |
| | | } |
| | | |
| | | /** |
| | | * 提交刷卡支付,针对软POS,尽可能做成功 |
| | | * 内置重试机制,最多60s |
| | | * @param reqData |
| | | * @return |
| | | * @throws Exception |
| | | */ |
| | | public Map<String, String> microPayWithPos(Map<String, String> reqData) throws Exception { |
| | | return this.microPayWithPos(reqData, 6*1000); |
| | | } |
| | | |
| | | /** |
| | | * 作用:提交刷卡支付<br> |
| | | * 场景:刷卡支付 |
| | | * @param reqData 向wxpay post的请求数据 |
| | | * @return API返回数据 |
| | | * @throws Exception |
| | | */ |
| | | public Map<String, String> microPay(Map<String, String> reqData) throws Exception { |
| | | return this.microPay(reqData, 6*1000, 8*1000); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 作用:提交刷卡支付<br> |
| | | * 场景:刷卡支付 |
| | | * @param reqData 向wxpay post的请求数据 |
| | | * @param connectTimeoutMs 连接超时时间,单位是毫秒 |
| | | * @param readTimeoutMs 读超时时间,单位是毫秒 |
| | | * @return API返回数据 |
| | | * @throws Exception |
| | | */ |
| | | public Map<String, String> microPay(Map<String, String> reqData, int connectTimeoutMs, int readTimeoutMs) throws Exception { |
| | | String url; |
| | | /* if (this.useSandbox) {//沙箱环境 |
| | | url = WXPayConstants.SANDBOX_MICROPAY_URL_SUFFIX; |
| | | }*/ |
| | | url = WXPayConstants.MICROPAY_URL_SUFFIX; |
| | | String respXml = this.requestWithoutCert(url, this.fillRequestData(reqData), connectTimeoutMs, readTimeoutMs); |
| | | return this.processResponseXml(respXml); |
| | | } |
| | | |
| | | /** |
| | | * 不需要证书的请求 |
| | | * @param urlSuffix String |
| | | * @param reqData 向wxpay post的请求数据 |
| | | * @param connectTimeoutMs 超时时间,单位是毫秒 |
| | | * @param readTimeoutMs 超时时间,单位是毫秒 |
| | | * @return API返回数据 |
| | | * @throws Exception |
| | | */ |
| | | public String requestWithoutCert(String urlSuffix, Map<String, String> reqData, |
| | | int connectTimeoutMs, int readTimeoutMs) throws Exception { |
| | | String msgUUID = reqData.get("nonce_str"); |
| | | String reqBody = WXPayUtil.mapToXml(reqData); |
| | | |
| | | String resp = new WXPayRequest(config).requestWithoutCert(urlSuffix, msgUUID, reqBody, connectTimeoutMs, readTimeoutMs, autoReport); |
| | | return resp; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 处理 HTTPS API返回数据,转换成Map对象。return_code为SUCCESS时,验证签名。 |
| | | * @param xmlStr API返回的XML格式数据 |
| | | * @return Map类型数据 |
| | | * @throws Exception |
| | | */ |
| | | public Map<String, String> processResponseXml(String xmlStr) throws Exception { |
| | | /*String RETURN_CODE = "return_code"; |
| | | String return_code;*/ |
| | | Map<String, String> respData = WXPayUtil.xmlToMap(xmlStr); |
| | | return respData; |
| | | /* if (respData.containsKey(RETURN_CODE)) { |
| | | return_code = respData.get(RETURN_CODE); |
| | | } |
| | | else { |
| | | throw new Exception(String.format("No `return_code` in XML: %s", xmlStr)); |
| | | } |
| | | |
| | | if (return_code.equals(WXPayConstants.FAIL)) { |
| | | return respData; |
| | | } |
| | | else if (return_code.equals(WXPayConstants.SUCCESS)) { |
| | | if (this.isResponseSignatureValid(respData)) { |
| | | return respData; |
| | | } |
| | | else { |
| | | throw new Exception(String.format("Invalid sign value in XML: %s", xmlStr)); |
| | | } |
| | | } |
| | | else { |
| | | throw new Exception(String.format("return_code value %s is invalid in XML: %s", return_code, xmlStr)); |
| | | }*/ |
| | | } |
| | | |
| | | /** |
| | | * 判断xml数据的sign是否有效,必须包含sign字段,否则返回false。 |
| | | * |
| | | * @param reqData 向wxpay post的请求数据 |
| | | * @return 签名是否有效 |
| | | * @throws Exception |
| | | */ |
| | | public boolean isResponseSignatureValid(Map<String, String> reqData) throws Exception { |
| | | // 返回数据的签名方式和请求中给定的签名方式是一致的 |
| | | return WXPayUtil.isSignatureValid(reqData, this.config.getKey(), this.signType); |
| | | } |
| | | |
| | | /** |
| | | * 向 Map 中添加 appid、mch_id、nonce_str、sign_type、sign <br> |
| | | * 该函数适用于商户适用于统一下单等接口,不适用于红包、代金券接口 |
| | | * |
| | | * @param reqData |
| | | * @return |
| | | * @throws Exception |
| | | */ |
| | | public Map<String, String> fillRequestData(Map<String, String> reqData) throws Exception { |
| | | reqData.put("appid", Configure.getAppid()); |
| | | reqData.put("mch_id", Configure.getMchid()); |
| | | reqData.put("nonce_str", WXPayUtil.generateUUID()); |
| | | reqData.put("sign_type", WXPayConstants.MD5); |
| | | //reqData.put("sign_type", WXPayConstants.HMACSHA256); |
| | | reqData.put("sign", WXPayUtil.generateSignature(reqData, Configure.getKey(), SignType.MD5)); |
| | | return reqData; |
| | | } |
| | | |
| | | /** |
| | | * 提交刷卡支付,针对软POS,尽可能做成功 |
| | | * 内置重试机制,最多60s |
| | | * @param reqData |
| | | * @param connectTimeoutMs |
| | | * @return |
| | | * @throws Exception |
| | | */ |
| | | public Map<String, String> microPayWithPos(Map<String, String> reqData, int connectTimeoutMs) throws Exception { |
| | | int remainingTimeMs = 10*1000; |
| | | long startTimestampMs = 0; |
| | | Map<String, String> lastResult = null; |
| | | Exception lastException = null; |
| | | |
| | | |
| | | while (true) { |
| | | startTimestampMs = WXPayUtil.getCurrentTimestampMs(); |
| | | int readTimeoutMs = remainingTimeMs - connectTimeoutMs; |
| | | if (readTimeoutMs > 1000) { |
| | | try { |
| | | lastResult = this.microPay(reqData, connectTimeoutMs, readTimeoutMs); |
| | | String returnCode = lastResult.get("return_code");//return_code |
| | | if (returnCode.equals("SUCCESS")) {break; |
| | | /* String resultCode = lastResult.get("result_code"); |
| | | String errCode = lastResult.get("err_code"); |
| | | if (resultCode.equals("SUCCESS")) { |
| | | break; |
| | | } |
| | | else { |
| | | // 看错误码,若支付结果未知,则重试提交刷卡支付 |
| | | if (errCode.equals("SYSTEMERROR") || errCode.equals("BANKERROR") || errCode.equals("USERPAYING")) { |
| | | remainingTimeMs = remainingTimeMs - (int)(WXPayUtil.getCurrentTimestampMs() - startTimestampMs); |
| | | if (remainingTimeMs <= 100) { |
| | | break; |
| | | } |
| | | else { |
| | | WXPayUtil.getLogger().info("microPayWithPos: try micropay again"); |
| | | if (remainingTimeMs > 5*1000) { |
| | | Thread.sleep(5*1000); |
| | | } |
| | | else { |
| | | Thread.sleep(1*1000); |
| | | } |
| | | continue; |
| | | } |
| | | } |
| | | else { |
| | | break; |
| | | } |
| | | }*/ |
| | | } |
| | | else { |
| | | break; |
| | | } |
| | | } |
| | | catch (Exception ex) { |
| | | lastResult = null; |
| | | lastException = ex; |
| | | } |
| | | } |
| | | else { |
| | | break; |
| | | } |
| | | } |
| | | |
| | | if (lastResult == null) { |
| | | throw lastException; |
| | | } |
| | | else { |
| | | return lastResult; |
| | | } |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.ruoyi.order.util.tencent.common; |
| | | |
| | | |
| | | import com.ruoyi.order.util.ParamUtil; |
| | | |
| | | /** |
| | | * User: TZJ |
| | | * Date: 2017/08/29 |
| | | * Time: 14:40 |
| | | * 这里放置微信支付的各种配置数据 |
| | | */ |
| | | public class Configure { |
| | | //这个就是自己要保管好的私有Key了(切记只能放在自己的后台代码里,不能放在任何可能被看到源代码的客户端程序中) |
| | | // 每次自己Post数据给API的时候都要用这个key来对所有字段进行签名,生成的签名会放在Sign这个字段,API收到Post数据的时候也会用同样的签名算法对Post过来的数据进行签名和验证 |
| | | // 收到API的返回的时候也要用这个key来对返回的数据算下签名,跟API的Sign数据进行比较,如果值不一致,有可能数据被第三方给篡改 |
| | | |
| | | private static String key = ParamUtil.getValue("key"); |
| | | |
| | | //用户端开发者平台的appid |
| | | private static String appID = ParamUtil.getValue("appID"); |
| | | //公众号的appid |
| | | private static String GappID = ParamUtil.getValue("GappID"); |
| | | //小程序的appid |
| | | private static String XappID = ParamUtil.getValue("XappID"); |
| | | |
| | | //公众号的appSecret |
| | | private static String appSecret = ParamUtil.getValue("appSecret"); |
| | | |
| | | //微信支付分配的商户号ID(开通公众号的微信支付功能之后可以获取到) |
| | | private static String mchID = ParamUtil.getValue("mchID"); |
| | | |
| | | private static String GmchID = ParamUtil.getValue("GmchID"); |
| | | |
| | | private static String XmchID = ParamUtil.getValue("XmchID"); |
| | | |
| | | //微信回调地址 |
| | | public static String wx_notify_url = ParamUtil.getValue("wx_notify_url"); |
| | | |
| | | //受理模式下给子商户分配的子商户号 |
| | | private static String subMchID = ""; |
| | | |
| | | //HTTPS证书的本地路径 |
| | | private static String certLocalPath; |
| | | static{//从服务器相对路径中获取 |
| | | certLocalPath = Configure.class.getClassLoader().getResource("").getPath() + "com/tencent/common/cert/apiclient_cert.p12"; |
| | | } |
| | | |
| | | //HTTPS证书密码,默认密码等于商户号MCHID |
| | | private static String certPassword = mchID; |
| | | |
| | | //HTTPS证书的本地路径 |
| | | private static String certLocalPath_2; |
| | | static{//从服务器相对路径中获取 |
| | | certLocalPath_2 = Configure.class.getClassLoader().getResource("").getPath() + "com/tencent/common/cert_2/apiclient_cert.p12"; |
| | | } |
| | | |
| | | //HTTPS证书密码,默认密码等于商户号MCHID |
| | | private static String certPassword_2 = GmchID; |
| | | |
| | | //是否使用异步线程的方式来上报API测速,默认为异步模式 |
| | | private static boolean useThreadToDoReport = true; |
| | | |
| | | //机器IP |
| | | private static String ip = ""; |
| | | |
| | | //以下是几个API的路径: |
| | | //1)被扫支付API |
| | | public static String PAY_API = "https://api.mch.weixin.qq.com/pay/micropay"; |
| | | |
| | | //2)被扫支付查询API |
| | | public static String PAY_QUERY_API = "https://api.mch.weixin.qq.com/pay/orderquery"; |
| | | |
| | | //3)退款API |
| | | public static String REFUND_API = "https://api.mch.weixin.qq.com/secapi/pay/refund"; |
| | | |
| | | //4)退款查询API |
| | | public static String REFUND_QUERY_API = "https://api.mch.weixin.qq.com/pay/refundquery"; |
| | | |
| | | //5)撤销API |
| | | public static String REVERSE_API = "https://api.mch.weixin.qq.com/secapi/pay/reverse"; |
| | | |
| | | //6)下载对账单API |
| | | public static String DOWNLOAD_BILL_API = "https://api.mch.weixin.qq.com/pay/downloadbill"; |
| | | |
| | | //7) 统计上报API |
| | | public static String REPORT_API = "https://api.mch.weixin.qq.com/payitil/report"; |
| | | |
| | | //商家支付用户(提现)API |
| | | public static String PayToTheUser_API = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers"; |
| | | |
| | | //统一下单API(预支付生成接口) |
| | | public static String UNIFIEDORDER_API = "https://api.mch.weixin.qq.com/pay/unifiedorder"; |
| | | |
| | | public static boolean isUseThreadToDoReport() { |
| | | return useThreadToDoReport; |
| | | } |
| | | |
| | | public static void setUseThreadToDoReport(boolean useThreadToDoReport) { |
| | | Configure.useThreadToDoReport = useThreadToDoReport; |
| | | } |
| | | |
| | | public static String HttpsRequestClassName = "com.tencent.common.HttpsRequest"; |
| | | |
| | | public static String HttpsRequestClassName_2 = "com.tencent.common.HttpsRequest_2"; |
| | | |
| | | public static void setKey(String key) { |
| | | Configure.key = key; |
| | | } |
| | | |
| | | public static void setAppID(String appID) { |
| | | Configure.appID = appID; |
| | | } |
| | | |
| | | public static void setMchID(String mchID) { |
| | | Configure.mchID = mchID; |
| | | } |
| | | |
| | | public static void setSubMchID(String subMchID) { |
| | | Configure.subMchID = subMchID; |
| | | } |
| | | |
| | | public static void setCertLocalPath(String certLocalPath) { |
| | | Configure.certLocalPath = certLocalPath; |
| | | } |
| | | |
| | | public static void setCertPassword(String certPassword) { |
| | | Configure.certPassword = certPassword; |
| | | } |
| | | |
| | | public static void setIp(String ip) { |
| | | Configure.ip = ip; |
| | | } |
| | | |
| | | public static String getKey(){ |
| | | return key; |
| | | } |
| | | |
| | | public static String getAppid(){ |
| | | return appID; |
| | | } |
| | | public static String getGappid(){ |
| | | return GappID; |
| | | } |
| | | public static String getXappid(){ |
| | | return XappID; |
| | | } |
| | | public static String getMchid(){ |
| | | return mchID; |
| | | } |
| | | |
| | | public static String getGmchid(){ |
| | | return GmchID; |
| | | } |
| | | public static String getXmchid(){ |
| | | return XmchID; |
| | | } |
| | | |
| | | public static String getCertPassword_2() { |
| | | return certPassword_2; |
| | | } |
| | | |
| | | public static void setCertPassword_2(String certPassword_2) { |
| | | Configure.certPassword_2 = certPassword_2; |
| | | } |
| | | |
| | | public static String getSubMchid(){ |
| | | return subMchID; |
| | | } |
| | | |
| | | public static String getCertLocalPath(){ |
| | | return certLocalPath; |
| | | } |
| | | |
| | | public static String getCertLocalPath_2() { |
| | | return certLocalPath_2; |
| | | } |
| | | |
| | | public static void setCertLocalPath_2(String certLocalPath_2) { |
| | | Configure.certLocalPath_2 = certLocalPath_2; |
| | | } |
| | | |
| | | public static String getCertPassword(){ |
| | | return certPassword; |
| | | } |
| | | |
| | | public static String getIP(){ |
| | | return ip; |
| | | } |
| | | |
| | | public static String getAppSecret() { |
| | | return appSecret; |
| | | } |
| | | |
| | | public static void setAppSecret(String appSecret) { |
| | | Configure.appSecret = appSecret; |
| | | } |
| | | |
| | | public static void setHttpsRequestClassName(String name){ |
| | | HttpsRequestClassName = name; |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.ruoyi.order.util.tencent.common; |
| | | |
| | | import java.io.File; |
| | | |
| | | import java.io.FileInputStream; |
| | | import java.io.IOException; |
| | | import java.security.KeyManagementException; |
| | | import java.security.KeyStore; |
| | | import java.security.KeyStoreException; |
| | | import java.security.NoSuchAlgorithmException; |
| | | import java.security.UnrecoverableKeyException; |
| | | import java.security.cert.CertificateException; |
| | | |
| | | import javax.net.ssl.SSLContext; |
| | | |
| | | import org.apache.http.HttpEntity; |
| | | import org.apache.http.HttpResponse; |
| | | import org.apache.http.client.config.RequestConfig; |
| | | import org.apache.http.client.methods.HttpPost; |
| | | import org.apache.http.conn.ssl.SSLConnectionSocketFactory; |
| | | import org.apache.http.conn.ssl.SSLContexts; |
| | | import org.apache.http.entity.StringEntity; |
| | | import org.apache.http.impl.client.CloseableHttpClient; |
| | | import org.apache.http.impl.client.HttpClients; |
| | | import org.apache.http.util.EntityUtils; |
| | | |
| | | import com.tencent.service.IServiceRequest; |
| | | import com.thoughtworks.xstream.XStream; |
| | | import com.thoughtworks.xstream.io.xml.DomDriver; |
| | | import com.thoughtworks.xstream.io.xml.XmlFriendlyNameCoder; |
| | | |
| | | /** |
| | | * User: rizenguo |
| | | * Date: 2014/10/29 |
| | | * Time: 14:36 |
| | | */ |
| | | @SuppressWarnings("deprecation") |
| | | public class HttpsRequest implements IServiceRequest{ |
| | | |
| | | public interface ResultListener { |
| | | public void onConnectionPoolTimeoutError(); |
| | | } |
| | | |
| | | //表示请求器是否已经做了初始化工作 |
| | | private boolean hasInit = false; |
| | | |
| | | //连接超时时间,默认10秒 |
| | | private int socketTimeout = 10000; |
| | | |
| | | //传输超时时间,默认30秒 |
| | | private int connectTimeout = 30000; |
| | | |
| | | //请求器的配置 |
| | | private RequestConfig requestConfig; |
| | | |
| | | //HTTP请求器 |
| | | private CloseableHttpClient httpClient; |
| | | |
| | | public HttpsRequest() throws UnrecoverableKeyException, KeyManagementException, NoSuchAlgorithmException, KeyStoreException, IOException { |
| | | init(); |
| | | } |
| | | |
| | | private void init() throws IOException, KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyManagementException { |
| | | |
| | | KeyStore keyStore = KeyStore.getInstance("PKCS12"); |
| | | FileInputStream instream = new FileInputStream(new File(Configure.getCertLocalPath()));//加载本地的证书进行https加密传输 |
| | | try { |
| | | keyStore.load(instream, Configure.getCertPassword().toCharArray());//设置证书密码 |
| | | } catch (CertificateException e) { |
| | | e.printStackTrace(); |
| | | } catch (NoSuchAlgorithmException e) { |
| | | e.printStackTrace(); |
| | | } finally { |
| | | instream.close(); |
| | | } |
| | | |
| | | // Trust own CA and all self-signed certs |
| | | SSLContext sslcontext = SSLContexts.custom() |
| | | .loadKeyMaterial(keyStore, Configure.getCertPassword().toCharArray()) |
| | | .build(); |
| | | // Allow TLSv1 protocol only |
| | | SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory( |
| | | sslcontext, |
| | | new String[]{"TLSv1"}, |
| | | null, |
| | | SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER); |
| | | |
| | | httpClient = HttpClients.custom() |
| | | .setSSLSocketFactory(sslsf) |
| | | .build(); |
| | | |
| | | //根据默认超时限制初始化requestConfig |
| | | requestConfig = RequestConfig.custom().setSocketTimeout(socketTimeout).setConnectTimeout(connectTimeout).build(); |
| | | |
| | | hasInit = true; |
| | | } |
| | | |
| | | /** |
| | | * 通过Https往API post xml数据 |
| | | * |
| | | * @param url API地址 |
| | | * @param xmlObj 要提交的XML数据对象 |
| | | * @return API回包的实际数据 |
| | | * @throws IOException |
| | | * @throws KeyStoreException |
| | | * @throws UnrecoverableKeyException |
| | | * @throws NoSuchAlgorithmException |
| | | * @throws KeyManagementException |
| | | */ |
| | | |
| | | public String sendPost(String url, Object xmlObj) throws IOException, KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyManagementException { |
| | | |
| | | if (!hasInit) { |
| | | init(); |
| | | } |
| | | |
| | | String result = null; |
| | | |
| | | HttpPost httpPost = new HttpPost(url); |
| | | |
| | | //解决XStream对出现双下划线的bug |
| | | XStream xStreamForRequestPostData = new XStream(new DomDriver("UTF-8", new XmlFriendlyNameCoder("-_", "_"))); |
| | | |
| | | //将要提交给API的数据对象转换成XML格式数据Post给API |
| | | String postDataXML = xStreamForRequestPostData.toXML(xmlObj); |
| | | |
| | | // Util.log("API,POST过去的数据是:\n"+postDataXML); |
| | | |
| | | //得指明使用UTF-8编码,否则到API服务器XML的中文不能被成功识别 |
| | | StringEntity postEntity = new StringEntity(postDataXML, "UTF-8"); |
| | | httpPost.addHeader("Content-Type", "text/xml"); |
| | | httpPost.setEntity(postEntity); |
| | | |
| | | //设置请求器的配置 |
| | | httpPost.setConfig(requestConfig); |
| | | |
| | | |
| | | try { |
| | | HttpResponse response = httpClient.execute(httpPost); |
| | | |
| | | HttpEntity entity = response.getEntity(); |
| | | |
| | | result = EntityUtils.toString(entity, "UTF-8"); |
| | | |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | |
| | | } finally { |
| | | httpPost.abort(); |
| | | } |
| | | |
| | | return result; |
| | | } |
| | | |
| | | /** |
| | | * 设置连接超时时间 |
| | | * |
| | | * @param socketTimeout 连接时长,默认10秒 |
| | | */ |
| | | public void setSocketTimeout(int socketTimeout) { |
| | | this.socketTimeout = socketTimeout; |
| | | resetRequestConfig(); |
| | | } |
| | | |
| | | /** |
| | | * 设置传输超时时间 |
| | | * |
| | | * @param connectTimeout 传输时长,默认30秒 |
| | | */ |
| | | public void setConnectTimeout(int connectTimeout) { |
| | | this.connectTimeout = connectTimeout; |
| | | resetRequestConfig(); |
| | | } |
| | | |
| | | private void resetRequestConfig(){ |
| | | requestConfig = RequestConfig.custom().setSocketTimeout(socketTimeout).setConnectTimeout(connectTimeout).build(); |
| | | } |
| | | |
| | | /** |
| | | * 允许商户自己做更高级更复杂的请求器配置 |
| | | * |
| | | * @param requestConfig 设置HttpsRequest的请求器配置 |
| | | */ |
| | | public void setRequestConfig(RequestConfig requestConfig) { |
| | | this.requestConfig = requestConfig; |
| | | } |
| | | } |
New file |
| | |
| | | package com.ruoyi.order.util.tencent.common; |
| | | |
| | | import java.io.File; |
| | | |
| | | |
| | | import java.io.FileInputStream; |
| | | import java.io.IOException; |
| | | import java.security.KeyManagementException; |
| | | import java.security.KeyStore; |
| | | import java.security.KeyStoreException; |
| | | import java.security.NoSuchAlgorithmException; |
| | | import java.security.UnrecoverableKeyException; |
| | | import java.security.cert.CertificateException; |
| | | |
| | | import javax.net.ssl.SSLContext; |
| | | |
| | | import org.apache.http.HttpEntity; |
| | | import org.apache.http.HttpResponse; |
| | | import org.apache.http.client.config.RequestConfig; |
| | | import org.apache.http.client.methods.HttpPost; |
| | | import org.apache.http.conn.ssl.SSLConnectionSocketFactory; |
| | | import org.apache.http.conn.ssl.SSLContexts; |
| | | import org.apache.http.entity.StringEntity; |
| | | import org.apache.http.impl.client.CloseableHttpClient; |
| | | import org.apache.http.impl.client.HttpClients; |
| | | import org.apache.http.util.EntityUtils; |
| | | |
| | | import com.tencent.service.IServiceRequest; |
| | | import com.thoughtworks.xstream.XStream; |
| | | import com.thoughtworks.xstream.io.xml.DomDriver; |
| | | import com.thoughtworks.xstream.io.xml.XmlFriendlyNameCoder; |
| | | |
| | | /** |
| | | * User: rizenguo |
| | | * Date: 2014/10/29 |
| | | * Time: 14:36 |
| | | */ |
| | | @SuppressWarnings("deprecation") |
| | | public class HttpsRequest_2 implements IServiceRequest{ |
| | | |
| | | public interface ResultListener { |
| | | public void onConnectionPoolTimeoutError(); |
| | | } |
| | | |
| | | //表示请求器是否已经做了初始化工作 |
| | | private boolean hasInit = false; |
| | | |
| | | //连接超时时间,默认10秒 |
| | | private int socketTimeout = 10000; |
| | | |
| | | //传输超时时间,默认30秒 |
| | | private int connectTimeout = 30000; |
| | | |
| | | //请求器的配置 |
| | | private RequestConfig requestConfig; |
| | | |
| | | //HTTP请求器 |
| | | private CloseableHttpClient httpClient; |
| | | |
| | | public HttpsRequest_2() throws UnrecoverableKeyException, KeyManagementException, NoSuchAlgorithmException, KeyStoreException, IOException { |
| | | init(); |
| | | } |
| | | |
| | | private void init() throws IOException, KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyManagementException { |
| | | |
| | | KeyStore keyStore = KeyStore.getInstance("PKCS12"); |
| | | FileInputStream instream = new FileInputStream(new File(Configure.getCertLocalPath_2()));//加载本地的证书进行https加密传输 |
| | | try { |
| | | keyStore.load(instream, Configure.getCertPassword_2().toCharArray());//设置证书密码 |
| | | } catch (CertificateException e) { |
| | | e.printStackTrace(); |
| | | } catch (NoSuchAlgorithmException e) { |
| | | e.printStackTrace(); |
| | | } finally { |
| | | instream.close(); |
| | | } |
| | | |
| | | // Trust own CA and all self-signed certs |
| | | SSLContext sslcontext = SSLContexts.custom() |
| | | .loadKeyMaterial(keyStore, Configure.getCertPassword_2().toCharArray()) |
| | | .build(); |
| | | // Allow TLSv1 protocol only |
| | | SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory( |
| | | sslcontext, |
| | | new String[]{"TLSv1"}, |
| | | null, |
| | | SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER); |
| | | |
| | | httpClient = HttpClients.custom() |
| | | .setSSLSocketFactory(sslsf) |
| | | .build(); |
| | | |
| | | //根据默认超时限制初始化requestConfig |
| | | requestConfig = RequestConfig.custom().setSocketTimeout(socketTimeout).setConnectTimeout(connectTimeout).build(); |
| | | |
| | | hasInit = true; |
| | | } |
| | | |
| | | /** |
| | | * 通过Https往API post xml数据 |
| | | * |
| | | * @param url API地址 |
| | | * @param xmlObj 要提交的XML数据对象 |
| | | * @return API回包的实际数据 |
| | | * @throws IOException |
| | | * @throws KeyStoreException |
| | | * @throws UnrecoverableKeyException |
| | | * @throws NoSuchAlgorithmException |
| | | * @throws KeyManagementException |
| | | */ |
| | | |
| | | public String sendPost(String url, Object xmlObj) throws IOException, KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyManagementException { |
| | | |
| | | if (!hasInit) { |
| | | init(); |
| | | } |
| | | |
| | | String result = null; |
| | | |
| | | HttpPost httpPost = new HttpPost(url); |
| | | |
| | | //解决XStream对出现双下划线的bug |
| | | XStream xStreamForRequestPostData = new XStream(new DomDriver("UTF-8", new XmlFriendlyNameCoder("-_", "_"))); |
| | | |
| | | //将要提交给API的数据对象转换成XML格式数据Post给API |
| | | String postDataXML = xStreamForRequestPostData.toXML(xmlObj); |
| | | |
| | | // Util.log("API,POST过去的数据是:\n"+postDataXML); |
| | | |
| | | //得指明使用UTF-8编码,否则到API服务器XML的中文不能被成功识别 |
| | | StringEntity postEntity = new StringEntity(postDataXML, "UTF-8"); |
| | | httpPost.addHeader("Content-Type", "text/xml"); |
| | | httpPost.setEntity(postEntity); |
| | | |
| | | //设置请求器的配置 |
| | | httpPost.setConfig(requestConfig); |
| | | |
| | | |
| | | try { |
| | | HttpResponse response = httpClient.execute(httpPost); |
| | | |
| | | HttpEntity entity = response.getEntity(); |
| | | |
| | | result = EntityUtils.toString(entity, "UTF-8"); |
| | | |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | |
| | | } finally { |
| | | httpPost.abort(); |
| | | } |
| | | |
| | | return result; |
| | | } |
| | | |
| | | /** |
| | | * 设置连接超时时间 |
| | | * |
| | | * @param socketTimeout 连接时长,默认10秒 |
| | | */ |
| | | public void setSocketTimeout(int socketTimeout) { |
| | | this.socketTimeout = socketTimeout; |
| | | resetRequestConfig(); |
| | | } |
| | | |
| | | /** |
| | | * 设置传输超时时间 |
| | | * |
| | | * @param connectTimeout 传输时长,默认30秒 |
| | | */ |
| | | public void setConnectTimeout(int connectTimeout) { |
| | | this.connectTimeout = connectTimeout; |
| | | resetRequestConfig(); |
| | | } |
| | | |
| | | private void resetRequestConfig(){ |
| | | requestConfig = RequestConfig.custom().setSocketTimeout(socketTimeout).setConnectTimeout(connectTimeout).build(); |
| | | } |
| | | |
| | | /** |
| | | * 允许商户自己做更高级更复杂的请求器配置 |
| | | * |
| | | * @param requestConfig 设置HttpsRequest的请求器配置 |
| | | */ |
| | | public void setRequestConfig(RequestConfig requestConfig) { |
| | | this.requestConfig = requestConfig; |
| | | } |
| | | } |
New file |
| | |
| | | package com.ruoyi.order.util.tencent.common; |
| | | |
| | | /** |
| | | * 域名管理,实现主备域名自动切换 |
| | | */ |
| | | public abstract interface IWXPayDomain { |
| | | /** |
| | | * 上报域名网络状况 |
| | | * @param domain 域名。 比如:api.mch.weixin.qq.com |
| | | * @param elapsedTimeMillis 耗时 |
| | | * @param ex 网络请求中出现的异常。 |
| | | * null表示没有异常 |
| | | * ConnectTimeoutException,表示建立网络连接异常 |
| | | * UnknownHostException, 表示dns解析异常 |
| | | */ |
| | | abstract void report(final String domain, long elapsedTimeMillis, final Exception ex); |
| | | |
| | | /** |
| | | * 获取域名 |
| | | * @param config 配置 |
| | | * @return 域名 |
| | | */ |
| | | abstract DomainInfo getDomain(final WXPayConfig config); |
| | | |
| | | static class DomainInfo{ |
| | | public String domain; //域名 |
| | | public boolean primaryDomain; //该域名是否为主域名。例如:api.mch.weixin.qq.com为主域名 |
| | | public DomainInfo(String domain, boolean primaryDomain) { |
| | | this.domain = domain; |
| | | this.primaryDomain = primaryDomain; |
| | | } |
| | | |
| | | @Override |
| | | public String toString() { |
| | | return "DomainInfo{" + |
| | | "domain='" + domain + '\'' + |
| | | ", primaryDomain=" + primaryDomain + |
| | | '}'; |
| | | } |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.ruoyi.order.util.tencent.common; |
| | | |
| | | import java.io.BufferedReader; |
| | | import java.io.IOException; |
| | | import java.io.InputStreamReader; |
| | | import java.net.MalformedURLException; |
| | | import java.net.URL; |
| | | import java.net.URLConnection; |
| | | import java.net.URLEncoder; |
| | | import java.util.HashMap; |
| | | import java.util.Map; |
| | | |
| | | import net.sf.json.JSONObject; |
| | | import org.apache.http.HttpEntity; |
| | | import org.apache.http.HttpResponse; |
| | | import org.apache.http.client.methods.HttpGet; |
| | | import org.apache.http.impl.client.DefaultHttpClient; |
| | | import org.apache.http.util.EntityUtils; |
| | | |
| | | import com.google.gson.Gson; |
| | | import com.google.gson.JsonObject; |
| | | /*** |
| | | * @author V型知识库 www.vxzsk.com |
| | | * |
| | | */ |
| | | public class JsapiTicketUtil { |
| | | |
| | | /*** |
| | | * 模拟get请求 |
| | | * @param url |
| | | * @param charset |
| | | * @param timeout |
| | | * @return |
| | | */ |
| | | public static String sendGet(String url, String charset, int timeout) |
| | | { |
| | | String result = ""; |
| | | try |
| | | { |
| | | URL u = new URL(url); |
| | | try |
| | | { |
| | | URLConnection conn = u.openConnection(); |
| | | conn.connect(); |
| | | conn.setConnectTimeout(timeout); |
| | | BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream(), charset)); |
| | | String line=""; |
| | | while ((line = in.readLine()) != null) |
| | | { |
| | | |
| | | result = result + line; |
| | | } |
| | | in.close(); |
| | | } catch (IOException e) { |
| | | return result; |
| | | } |
| | | } |
| | | catch (MalformedURLException e) |
| | | { |
| | | return result; |
| | | } |
| | | |
| | | return result; |
| | | } |
| | | /*** |
| | | * 获取acess_token |
| | | * 来源www.vxzsk.com |
| | | * @return |
| | | */ |
| | | public static String getAccessToken(){ |
| | | String appid=Configure.getGappid();//应用IDwxa15aa9429f9646fd |
| | | String appSecret="3f14c55e683735aefd19271959e27187";//(应用密钥)3f14c55e683735aefd19271959e27187 |
| | | String url ="https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+appid+"&secret="+appSecret+""; |
| | | String backData=sendGet(url, "utf-8", 10000); |
| | | String accessToken = (String) JSONObject.fromObject(backData).get("access_token"); |
| | | return accessToken; |
| | | } |
| | | /*** |
| | | * 获取jsapiTicket |
| | | * 来源 www.vxzsk.com |
| | | * @return |
| | | */ |
| | | public static String getJSApiTicket(){ |
| | | //获取token |
| | | String acess_token= JsapiTicketUtil.getAccessToken(); |
| | | |
| | | String urlStr = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token="+acess_token+"&type=jsapi"; |
| | | String backData=sendGet(urlStr, "utf-8", 10000); |
| | | String ticket = (String) JSONObject.fromObject(backData).get("ticket"); |
| | | return ticket; |
| | | |
| | | } |
| | | /** |
| | | * 获取用户openid(公众号) |
| | | * @return |
| | | */ |
| | | public static String getOpenId(String code){ |
| | | |
| | | String urlStr = "https://api.weixin.qq.com/sns/oauth2/access_token?appid="+Configure.getGappid()+"&secret=3f14c55e683735aefd19271959e27187&code="+code+"&grant_type=authorization_code"; |
| | | String backData=sendGet(urlStr, "utf-8", 10000); |
| | | String ticket = (String) JSONObject.fromObject(backData).get("openid"); |
| | | return ticket; |
| | | } |
| | | |
| | | /** |
| | | * 获取用户openid(小程序) |
| | | * @return |
| | | */ |
| | | public static String getOpenId2(String code){ |
| | | |
| | | String urlStr = "https://api.weixin.qq.com/sns/oauth2/access_token?appid="+Configure.getXappid()+"&secret=9a38480b9c220688d4fed071d490d732&code="+code+"&grant_type=authorization_code"; |
| | | String backData=sendGet(urlStr, "utf-8", 10000); |
| | | String ticket = (String) JSONObject.fromObject(backData).get("openid"); |
| | | return ticket; |
| | | } |
| | | /** |
| | | * 获取请求用户信息的access_token |
| | | * |
| | | * @param code |
| | | * @return |
| | | */ |
| | | // public static Map<String, String> getUserInfoAccessToken(String code) { |
| | | // JsonObject object = null; |
| | | // Map<String, String> data = new HashMap(); |
| | | // try { |
| | | // String url = String.format("https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code", |
| | | // "wx614b91446fc49a0e","ca2288ec80d4e05976425a6508e9b7", code); |
| | | // DefaultHttpClient httpClient = new DefaultHttpClient(); |
| | | // HttpGet httpGet = new HttpGet(url); |
| | | // HttpResponse httpResponse = httpClient.execute(httpGet); |
| | | // HttpEntity httpEntity = httpResponse.getEntity(); |
| | | // String tokens = EntityUtils.toString(httpEntity, "utf-8"); |
| | | // Gson token_gson = new Gson(); |
| | | // object = token_gson.fromJson(tokens, JsonObject.class); |
| | | // data.put("openid", object.get("openid").toString().replaceAll("\"", "")); |
| | | // data.put("access_token", object.get("access_token").toString().replaceAll("\"", "")); |
| | | // } catch (Exception ex) { |
| | | // } |
| | | // return data; |
| | | // } |
| | | public static String getCode(){ |
| | | JsonObject object = null; |
| | | Map<String, String> data = new HashMap(); |
| | | try { |
| | | String codes = String.format("https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s#wechat_redirect", |
| | | "wx614b91446fc49a0e", "http://www.txciot.com/resources/html/first.html", "snsapi_base", "xxxx_state"); |
| | | DefaultHttpClient httpClient = new DefaultHttpClient(); |
| | | return sendGet(codes, "utf-8", 10000); |
| | | } catch (Exception ex) { |
| | | return ""; |
| | | } |
| | | } |
| | | public static void main(String[] args) { |
| | | System.out.println(URLEncoder.encode("http://www.txciot.com/resources/html/first.html")); |
| | | //System.out.println(getUserInfoAccessToken(getCode())); |
| | | } |
| | | } |
New file |
| | |
| | | package com.ruoyi.order.util.tencent.common; |
| | | |
| | | import org.slf4j.Logger; |
| | | |
| | | /** |
| | | * User: rizenguo |
| | | * Date: 2014/11/12 |
| | | * Time: 14:32 |
| | | */ |
| | | public class Log { |
| | | |
| | | public static final String LOG_TYPE_TRACE = "logTypeTrace"; |
| | | public static final String LOG_TYPE_DEBUG = "logTypeDebug"; |
| | | public static final String LOG_TYPE_INFO = "logTypeInfo"; |
| | | public static final String LOG_TYPE_WARN = "logTypeWarn"; |
| | | public static final String LOG_TYPE_ERROR = "logTypeError"; |
| | | |
| | | //打印日志 |
| | | private Logger logger; |
| | | |
| | | public Log(Logger log){ |
| | | logger = log; |
| | | } |
| | | |
| | | public void t(String s){ |
| | | logger.trace(s); |
| | | } |
| | | |
| | | public void d(String s){ |
| | | logger.debug(s); |
| | | } |
| | | |
| | | public void i(String s){ |
| | | logger.info(s); |
| | | } |
| | | |
| | | public void w(String s){ |
| | | logger.warn(s); |
| | | } |
| | | |
| | | public void e(String s){ |
| | | logger.error(s); |
| | | } |
| | | |
| | | public void log(String type,String s){ |
| | | if(type.equals(Log.LOG_TYPE_TRACE)){ |
| | | t(s); |
| | | }else if(type.equals(Log.LOG_TYPE_DEBUG)){ |
| | | d(s); |
| | | }else if(type.equals(Log.LOG_TYPE_INFO)){ |
| | | i(s); |
| | | }else if(type.equals(Log.LOG_TYPE_WARN)){ |
| | | w(s); |
| | | }else if(type.equals(Log.LOG_TYPE_ERROR)){ |
| | | e(s); |
| | | } |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.ruoyi.order.util.tencent.common; |
| | | |
| | | import java.security.MessageDigest; |
| | | |
| | | /** |
| | | * User: rizenguo |
| | | * Date: 2014/10/23 |
| | | * Time: 15:43 |
| | | */ |
| | | public class MD5 { |
| | | private final static String[] hexDigits = {"0", "1", "2", "3", "4", "5", "6", "7", |
| | | "8", "9", "a", "b", "c", "d", "e", "f"}; |
| | | |
| | | /** |
| | | * 转换字节数组为16进制字串 |
| | | * @param b 字节数组 |
| | | * @return 16进制字串 |
| | | */ |
| | | public static String byteArrayToHexString(byte[] b) { |
| | | StringBuilder resultSb = new StringBuilder(); |
| | | for (byte aB : b) { |
| | | resultSb.append(byteToHexString(aB)); |
| | | } |
| | | return resultSb.toString(); |
| | | } |
| | | |
| | | /** |
| | | * 转换byte到16进制 |
| | | * @param b 要转换的byte |
| | | * @return 16进制格式 |
| | | */ |
| | | private static String byteToHexString(byte b) { |
| | | int n = b; |
| | | if (n < 0) { |
| | | n = 256 + n; |
| | | } |
| | | int d1 = n / 16; |
| | | int d2 = n % 16; |
| | | return hexDigits[d1] + hexDigits[d2]; |
| | | } |
| | | |
| | | /** |
| | | * MD5编码 |
| | | * @param origin 原始字符串 |
| | | * @return 经过MD5加密之后的结果 |
| | | */ |
| | | public static String MD5Encode(String origin) { |
| | | String resultString = null; |
| | | try { |
| | | resultString = origin; |
| | | MessageDigest md = MessageDigest.getInstance("MD5"); |
| | | resultString = byteArrayToHexString(md.digest(resultString.getBytes("UTF-8")));//微信支付有汉字时出现签名错误的解决办法 |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | } |
| | | return resultString; |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.ruoyi.order.util.tencent.common; |
| | | |
| | | import java.util.Random; |
| | | |
| | | /** |
| | | * User: rizenguo |
| | | * Date: 2014/10/29 |
| | | * Time: 14:18 |
| | | */ |
| | | public class RandomStringGenerator { |
| | | |
| | | /** |
| | | * 获取一定长度的随机字符串 |
| | | * @param length 指定字符串长度 |
| | | * @return 一定长度的字符串 |
| | | */ |
| | | public static String getRandomStringByLength(int length) { |
| | | String base = "abcdefghijklmnopqrstuvwxyz0123456789"; |
| | | Random random = new Random(); |
| | | StringBuffer sb = new StringBuffer(); |
| | | for (int i = 0; i < length; i++) { |
| | | int number = random.nextInt(base.length()); |
| | | sb.append(base.charAt(number)); |
| | | } |
| | | return sb.toString(); |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.ruoyi.order.util.tencent.common; |
| | | |
| | | import java.io.IOException; |
| | | import java.lang.reflect.Field; |
| | | import java.util.ArrayList; |
| | | import java.util.Arrays; |
| | | import java.util.Map; |
| | | |
| | | import javax.xml.parsers.ParserConfigurationException; |
| | | |
| | | import org.xml.sax.SAXException; |
| | | |
| | | /** |
| | | * User: tzj |
| | | * Date: 2017/06/17 |
| | | * Time: 15:23 |
| | | */ |
| | | public class Signature { |
| | | /** |
| | | * 签名算法 |
| | | * @param o 要参与签名的数据对象 |
| | | * @return 签名 |
| | | * @throws IllegalAccessException |
| | | */ |
| | | public static String getSign(Object o) throws IllegalAccessException { |
| | | ArrayList<String> list = new ArrayList<String>(); |
| | | Class<? extends Object> cls = o.getClass(); |
| | | Field[] fields = cls.getDeclaredFields(); |
| | | for (Field f : fields) { |
| | | f.setAccessible(true); |
| | | if (f.get(o) != null && f.get(o) != "") { |
| | | list.add(f.getName() + "=" + f.get(o) + "&"); |
| | | } |
| | | } |
| | | int size = list.size(); |
| | | String [] arrayToSort = list.toArray(new String[size]); |
| | | Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER); |
| | | StringBuilder sb = new StringBuilder(); |
| | | for(int i = 0; i < size; i ++) { |
| | | sb.append(arrayToSort[i]); |
| | | } |
| | | String result = sb.toString(); |
| | | result += "key=" + Configure.getKey(); |
| | | Util.log("Sign Before MD5:" + result); |
| | | result = MD5.MD5Encode(result).toUpperCase(); |
| | | Util.log("Sign Result:" + result); |
| | | return result; |
| | | } |
| | | |
| | | public static String getSign(Integer apptype,Map<String,Object> map){ |
| | | ArrayList<String> list = new ArrayList<String>(); |
| | | for(Map.Entry<String,Object> entry:map.entrySet()){ |
| | | if(entry.getValue()!=""){ |
| | | list.add(entry.getKey() + "=" + entry.getValue() + "&"); |
| | | } |
| | | } |
| | | int size = list.size(); |
| | | String [] arrayToSort = list.toArray(new String[size]); |
| | | Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER); |
| | | StringBuilder sb = new StringBuilder(); |
| | | for(int i = 0; i < size; i ++) { |
| | | sb.append(arrayToSort[i]); |
| | | } |
| | | String result = sb.toString(); |
| | | result += "key=" + Configure.getKey(); |
| | | |
| | | // Util.log("Sign Before MD5:" + result); |
| | | result = MD5.MD5Encode(result).toUpperCase(); |
| | | // Util.log("Sign Result:" + result); |
| | | return result; |
| | | } |
| | | |
| | | /** |
| | | * 从API返回的XML数据里面重新计算一次签名 |
| | | * @param responseString API返回的XML数据 |
| | | * @return 新鲜出炉的签名 |
| | | * @throws ParserConfigurationException |
| | | * @throws IOException |
| | | * @throws SAXException |
| | | */ |
| | | public static String getSignFromResponseString(Integer apptype, String responseString) throws IOException, SAXException, ParserConfigurationException { |
| | | Map<String,Object> map = XMLParser.getMapFromXML(responseString); |
| | | //清掉返回数据对象里面的Sign数据(不能把这个数据也加进去进行签名),然后用签名算法进行签名 |
| | | map.put("sign",""); |
| | | //将API返回的数据根据用签名算法进行计算新的签名,用来跟API返回的签名进行比较 |
| | | return Signature.getSign(apptype, map); |
| | | } |
| | | |
| | | /** |
| | | * 检验API返回的数据里面的签名是否合法,避免数据在传输的过程中被第三方篡改 |
| | | * @param responseString API返回的XML数据字符串 |
| | | * @return API签名是否合法 |
| | | * @throws ParserConfigurationException |
| | | * @throws IOException |
| | | * @throws SAXException |
| | | */ |
| | | public static boolean checkIsSignValidFromResponseString(Integer apptype, String responseString) throws ParserConfigurationException, IOException, SAXException { |
| | | |
| | | Map<String,Object> map = XMLParser.getMapFromXML(responseString); |
| | | Util.log(map.toString()); |
| | | |
| | | String signFromAPIResponse = map.get("sign").toString(); |
| | | if(signFromAPIResponse=="" || signFromAPIResponse == null){ |
| | | Util.log("API返回的数据签名数据不存在,有可能被第三方篡改!!!"); |
| | | return false; |
| | | } |
| | | Util.log("服务器回包里面的签名是:" + signFromAPIResponse); |
| | | //清掉返回数据对象里面的Sign数据(不能把这个数据也加进去进行签名),然后用签名算法进行签名 |
| | | map.put("sign",""); |
| | | //将API返回的数据根据用签名算法进行计算新的签名,用来跟API返回的签名进行比较 |
| | | String signForAPIResponse = Signature.getSign(apptype, map); |
| | | |
| | | if(!signForAPIResponse.equals(signFromAPIResponse)){ |
| | | //签名验不过,表示这个API返回的数据有可能已经被篡改了 |
| | | Util.log("API返回的数据签名验证不通过,有可能被第三方篡改!!!"); |
| | | return false; |
| | | } |
| | | Util.log("恭喜,API返回的数据签名验证通过!!!"); |
| | | return true; |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.ruoyi.order.util.tencent.common; |
| | | |
| | | import java.io.ByteArrayInputStream; |
| | | |
| | | |
| | | import java.io.ByteArrayOutputStream; |
| | | import java.io.IOException; |
| | | import java.io.InputStream; |
| | | import java.lang.reflect.Field; |
| | | import java.util.Map; |
| | | |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | |
| | | import com.thoughtworks.xstream.XStream; |
| | | |
| | | |
| | | /** |
| | | * User: tzj |
| | | * Date: 2017/08/23 |
| | | * Time: 14:59 |
| | | */ |
| | | public class Util { |
| | | |
| | | Logger logger= LoggerFactory.getLogger(getClass()); |
| | | /** |
| | | * 通过反射的方式遍历对象的属性和属性值,方便调试 |
| | | * |
| | | * @param o 要遍历的对象 |
| | | * @throws Exception |
| | | */ |
| | | public static void reflect(Object o) throws Exception { |
| | | Class<? extends Object> cls = o.getClass(); |
| | | Field[] fields = cls.getDeclaredFields(); |
| | | for (int i = 0; i < fields.length; i++) { |
| | | Field f = fields[i]; |
| | | f.setAccessible(true); |
| | | Util.log(f.getName() + " -> " + f.get(o)); |
| | | } |
| | | } |
| | | |
| | | public static byte[] readInput(InputStream in) throws IOException { |
| | | ByteArrayOutputStream out = new ByteArrayOutputStream(); |
| | | int len = 0; |
| | | byte[] buffer = new byte[1024]; |
| | | while ((len = in.read(buffer)) > 0) { |
| | | out.write(buffer, 0, len); |
| | | } |
| | | out.close(); |
| | | in.close(); |
| | | return out.toByteArray(); |
| | | } |
| | | |
| | | public static String inputStreamToString(InputStream is) throws IOException { |
| | | ByteArrayOutputStream baos = new ByteArrayOutputStream(); |
| | | int i; |
| | | while ((i = is.read()) != -1) { |
| | | baos.write(i); |
| | | } |
| | | return baos.toString(); |
| | | } |
| | | |
| | | |
| | | public static InputStream getStringStream(String sInputString) { |
| | | ByteArrayInputStream tInputStringStream = null; |
| | | if (sInputString != null && !sInputString.trim().equals("")) { |
| | | try { |
| | | tInputStringStream = new ByteArrayInputStream(sInputString.getBytes("UTF-8")); |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | } |
| | | } |
| | | return tInputStringStream; |
| | | } |
| | | |
| | | public static Object getObjectFromXML(String xml, Class<?> tClass) { |
| | | //将从API返回的XML数据映射到Java对象 |
| | | XStream xStreamForResponseData = new XStream(); |
| | | xStreamForResponseData.alias("xml", tClass); |
| | | xStreamForResponseData.ignoreUnknownElements();//暂时忽略掉一些新增的字段 |
| | | return xStreamForResponseData.fromXML(xml); |
| | | } |
| | | |
| | | public static String getStringFromMap(Map<String, Object> map, String key, String defaultValue) { |
| | | if (key == "" || key == null) { |
| | | return defaultValue; |
| | | } |
| | | String result = (String) map.get(key); |
| | | if (result == null) { |
| | | return defaultValue; |
| | | } else { |
| | | return result; |
| | | } |
| | | } |
| | | |
| | | public static int getIntFromMap(Map<String, Object> map, String key) { |
| | | if (key == "" || key == null) { |
| | | return 0; |
| | | } |
| | | if (map.get(key) == null) { |
| | | return 0; |
| | | } |
| | | return Integer.parseInt((String) map.get(key)); |
| | | } |
| | | |
| | | /** |
| | | * 打log接口 |
| | | * @param log 要打印的log字符串 |
| | | * @return 返回log |
| | | */ |
| | | public static String log(Object log){ |
| | | System.out.println(log.toString()); |
| | | return log.toString(); |
| | | } |
| | | |
| | | /** |
| | | * 读取本地的xml数据,一般用来自测用 |
| | | * @param localPath 本地xml文件路径 |
| | | * @return 读到的xml字符串 |
| | | */ |
| | | public static String getLocalXMLString(String localPath) throws IOException { |
| | | return Util.inputStreamToString(Util.class.getResourceAsStream(localPath)); |
| | | } |
| | | |
| | | } |
| | | |
New file |
| | |
| | | package com.ruoyi.order.util.tencent.common; |
| | | |
| | | import java.io.InputStream; |
| | | |
| | | public abstract class WXPayConfig { |
| | | |
| | | |
| | | |
| | | /** |
| | | * 获取 App ID |
| | | * |
| | | * @return App ID |
| | | */ |
| | | public abstract String getAppID(); |
| | | |
| | | |
| | | /** |
| | | * 获取 Mch ID |
| | | * |
| | | * @return Mch ID |
| | | */ |
| | | public abstract String getMchID(); |
| | | |
| | | |
| | | /** |
| | | * 获取 API 密钥 |
| | | * |
| | | * @return API密钥 |
| | | */ |
| | | public abstract String getKey(); |
| | | |
| | | |
| | | /** |
| | | * 获取商户证书内容 |
| | | * |
| | | * @return 商户证书内容 |
| | | */ |
| | | public abstract InputStream getCertStream(); |
| | | |
| | | /** |
| | | * HTTP(S) 连接超时时间,单位毫秒 |
| | | * |
| | | * @return |
| | | */ |
| | | public int getHttpConnectTimeoutMs() { |
| | | return 6*1000; |
| | | } |
| | | |
| | | /** |
| | | * HTTP(S) 读数据超时时间,单位毫秒 |
| | | * |
| | | * @return |
| | | */ |
| | | public int getHttpReadTimeoutMs() { |
| | | return 8*1000; |
| | | } |
| | | |
| | | /** |
| | | * 获取WXPayDomain, 用于多域名容灾自动切换 |
| | | * @return |
| | | */ |
| | | public abstract IWXPayDomain getWXPayDomain(); |
| | | |
| | | /** |
| | | * 是否自动上报。 |
| | | * 若要关闭自动上报,子类中实现该函数返回 false 即可。 |
| | | * |
| | | * @return |
| | | */ |
| | | public boolean shouldAutoReport() { |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * 进行健康上报的线程的数量 |
| | | * |
| | | * @return |
| | | */ |
| | | public int getReportWorkerNum() { |
| | | return 6; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 健康上报缓存消息的最大数量。会有线程去独立上报 |
| | | * 粗略计算:加入一条消息200B,10000消息占用空间 2000 KB,约为2MB,可以接受 |
| | | * |
| | | * @return |
| | | */ |
| | | public int getReportQueueMaxSize() { |
| | | return 10000; |
| | | } |
| | | |
| | | /** |
| | | * 批量上报,一次最多上报多个数据 |
| | | * |
| | | * @return |
| | | */ |
| | | public int getReportBatchSize() { |
| | | return 10; |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.ruoyi.order.util.tencent.common; |
| | | |
| | | /** |
| | | * 常量 |
| | | */ |
| | | public class WXPayConstants { |
| | | |
| | | public enum SignType { |
| | | MD5, HMACSHA256 |
| | | } |
| | | |
| | | public static final String DOMAIN_API = "api.mch.weixin.qq.com"; |
| | | public static final String DOMAIN_API2 = "api2.mch.weixin.qq.com"; |
| | | public static final String DOMAIN_APIHK = "apihk.mch.weixin.qq.com"; |
| | | public static final String DOMAIN_APIUS = "apius.mch.weixin.qq.com"; |
| | | |
| | | |
| | | public static final String FAIL = "FAIL"; |
| | | public static final String SUCCESS = "SUCCESS"; |
| | | public static final String HMACSHA256 = "HMAC-SHA256"; |
| | | public static final String MD5 = "MD5"; |
| | | |
| | | public static final String FIELD_SIGN = "sign"; |
| | | public static final String FIELD_SIGN_TYPE = "sign_type"; |
| | | |
| | | public static final String MICROPAY_URL_SUFFIX = "/pay/micropay"; |
| | | public static final String UNIFIEDORDER_URL_SUFFIX = "/pay/unifiedorder"; |
| | | public static final String ORDERQUERY_URL_SUFFIX = "/pay/orderquery"; |
| | | public static final String REVERSE_URL_SUFFIX = "/secapi/pay/reverse"; |
| | | public static final String CLOSEORDER_URL_SUFFIX = "/pay/closeorder"; |
| | | public static final String REFUND_URL_SUFFIX = "/secapi/pay/refund"; |
| | | public static final String REFUNDQUERY_URL_SUFFIX = "/pay/refundquery"; |
| | | public static final String DOWNLOADBILL_URL_SUFFIX = "/pay/downloadbill"; |
| | | public static final String REPORT_URL_SUFFIX = "/payitil/report"; |
| | | public static final String SHORTURL_URL_SUFFIX = "/tools/shorturl"; |
| | | public static final String AUTHCODETOOPENID_URL_SUFFIX = "/tools/authcodetoopenid"; |
| | | |
| | | // sandbox |
| | | public static final String SANDBOX_MICROPAY_URL_SUFFIX = "/sandboxnew/pay/micropay"; |
| | | public static final String SANDBOX_UNIFIEDORDER_URL_SUFFIX = "/sandboxnew/pay/unifiedorder"; |
| | | public static final String SANDBOX_ORDERQUERY_URL_SUFFIX = "/sandboxnew/pay/orderquery"; |
| | | public static final String SANDBOX_REVERSE_URL_SUFFIX = "/sandboxnew/secapi/pay/reverse"; |
| | | public static final String SANDBOX_CLOSEORDER_URL_SUFFIX = "/sandboxnew/pay/closeorder"; |
| | | public static final String SANDBOX_REFUND_URL_SUFFIX = "/sandboxnew/secapi/pay/refund"; |
| | | public static final String SANDBOX_REFUNDQUERY_URL_SUFFIX = "/sandboxnew/pay/refundquery"; |
| | | public static final String SANDBOX_DOWNLOADBILL_URL_SUFFIX = "/sandboxnew/pay/downloadbill"; |
| | | public static final String SANDBOX_REPORT_URL_SUFFIX = "/sandboxnew/payitil/report"; |
| | | public static final String SANDBOX_SHORTURL_URL_SUFFIX = "/sandboxnew/tools/shorturl"; |
| | | public static final String SANDBOX_AUTHCODETOOPENID_URL_SUFFIX = "/sandboxnew/tools/authcodetoopenid"; |
| | | |
| | | } |
| | | |
New file |
| | |
| | | package com.ruoyi.order.util.tencent.common; |
| | | |
| | | import java.io.ByteArrayInputStream; |
| | | import java.io.InputStream; |
| | | import java.io.StringWriter; |
| | | import java.util.*; |
| | | import java.security.MessageDigest; |
| | | |
| | | import org.w3c.dom.Node; |
| | | import org.w3c.dom.NodeList; |
| | | |
| | | import javax.crypto.Mac; |
| | | import javax.crypto.spec.SecretKeySpec; |
| | | import javax.xml.parsers.DocumentBuilder; |
| | | import javax.xml.parsers.DocumentBuilderFactory; |
| | | import javax.xml.transform.OutputKeys; |
| | | import javax.xml.transform.Transformer; |
| | | import javax.xml.transform.TransformerFactory; |
| | | import javax.xml.transform.dom.DOMSource; |
| | | import javax.xml.transform.stream.StreamResult; |
| | | |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | |
| | | import com.ruoyi.order.util.tencent.common.WXPayConstants.SignType; |
| | | |
| | | |
| | | public class WXPayUtil { |
| | | |
| | | /** |
| | | * XML格式字符串转换为Map |
| | | * |
| | | * @param strXML XML字符串 |
| | | * @return XML数据转换后的Map |
| | | * @throws Exception |
| | | */ |
| | | public static Map<String, String> xmlToMap(String strXML) throws Exception { |
| | | try { |
| | | Map<String, String> data = new HashMap<String, String>(); |
| | | DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); |
| | | DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); |
| | | InputStream stream = new ByteArrayInputStream(strXML.getBytes("UTF-8")); |
| | | org.w3c.dom.Document doc = documentBuilder.parse(stream); |
| | | doc.getDocumentElement().normalize(); |
| | | NodeList nodeList = doc.getDocumentElement().getChildNodes(); |
| | | for (int idx = 0; idx < nodeList.getLength(); ++idx) { |
| | | Node node = nodeList.item(idx); |
| | | if (node.getNodeType() == Node.ELEMENT_NODE) { |
| | | org.w3c.dom.Element element = (org.w3c.dom.Element) node; |
| | | data.put(element.getNodeName(), element.getTextContent()); |
| | | } |
| | | } |
| | | try { |
| | | stream.close(); |
| | | } catch (Exception ex) { |
| | | // do nothing |
| | | } |
| | | return data; |
| | | } catch (Exception ex) { |
| | | WXPayUtil.getLogger().warn("Invalid XML, can not convert to map. Error message: {}. XML content: {}", ex.getMessage(), strXML); |
| | | throw ex; |
| | | } |
| | | |
| | | } |
| | | |
| | | /** |
| | | * 将Map转换为XML格式的字符串 |
| | | * |
| | | * @param data Map类型数据 |
| | | * @return XML格式的字符串 |
| | | * @throws Exception |
| | | */ |
| | | public static String mapToXml(Map<String, String> data) throws Exception { |
| | | DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); |
| | | DocumentBuilder documentBuilder= documentBuilderFactory.newDocumentBuilder(); |
| | | org.w3c.dom.Document document = documentBuilder.newDocument(); |
| | | org.w3c.dom.Element root = document.createElement("xml"); |
| | | document.appendChild(root); |
| | | for (String key: data.keySet()) { |
| | | String value = data.get(key); |
| | | if (value == null) { |
| | | value = ""; |
| | | } |
| | | value = value.trim(); |
| | | org.w3c.dom.Element filed = document.createElement(key); |
| | | filed.appendChild(document.createTextNode(value)); |
| | | root.appendChild(filed); |
| | | } |
| | | TransformerFactory tf = TransformerFactory.newInstance(); |
| | | Transformer transformer = tf.newTransformer(); |
| | | DOMSource source = new DOMSource(document); |
| | | transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); |
| | | transformer.setOutputProperty(OutputKeys.INDENT, "yes"); |
| | | StringWriter writer = new StringWriter(); |
| | | StreamResult result = new StreamResult(writer); |
| | | transformer.transform(source, result); |
| | | String output = writer.getBuffer().toString(); //.replaceAll("\n|\r", ""); |
| | | try { |
| | | writer.close(); |
| | | } |
| | | catch (Exception ex) { |
| | | } |
| | | return output; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 生成带有 sign 的 XML 格式字符串 |
| | | * |
| | | * @param data Map类型数据 |
| | | * @param key API密钥 |
| | | * @return 含有sign字段的XML |
| | | */ |
| | | public static String generateSignedXml(final Map<String, String> data, String key) throws Exception { |
| | | return generateSignedXml(data, key, SignType.MD5); |
| | | } |
| | | |
| | | /** |
| | | * 生成带有 sign 的 XML 格式字符串 |
| | | * |
| | | * @param data Map类型数据 |
| | | * @param key API密钥 |
| | | * @param signType 签名类型 |
| | | * @return 含有sign字段的XML |
| | | */ |
| | | public static String generateSignedXml(final Map<String, String> data, String key, SignType signType) throws Exception { |
| | | String sign = generateSignature(data, key, signType); |
| | | data.put(WXPayConstants.FIELD_SIGN, sign); |
| | | return mapToXml(data); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 判断签名是否正确 |
| | | * |
| | | * @param xmlStr XML格式数据 |
| | | * @param key API密钥 |
| | | * @return 签名是否正确 |
| | | * @throws Exception |
| | | */ |
| | | public static boolean isSignatureValid(String xmlStr, String key) throws Exception { |
| | | Map<String, String> data = xmlToMap(xmlStr); |
| | | if (!data.containsKey(WXPayConstants.FIELD_SIGN) ) { |
| | | return false; |
| | | } |
| | | String sign = data.get(WXPayConstants.FIELD_SIGN); |
| | | return generateSignature(data, key).equals(sign); |
| | | } |
| | | |
| | | /** |
| | | * 判断签名是否正确,必须包含sign字段,否则返回false。使用MD5签名。 |
| | | * |
| | | * @param data Map类型数据 |
| | | * @param key API密钥 |
| | | * @return 签名是否正确 |
| | | * @throws Exception |
| | | */ |
| | | public static boolean isSignatureValid(Map<String, String> data, String key) throws Exception { |
| | | return isSignatureValid(data, key, SignType.MD5); |
| | | } |
| | | |
| | | /** |
| | | * 判断签名是否正确,必须包含sign字段,否则返回false。 |
| | | * |
| | | * @param data Map类型数据 |
| | | * @param key API密钥 |
| | | * @param signType 签名方式 |
| | | * @return 签名是否正确 |
| | | * @throws Exception |
| | | */ |
| | | public static boolean isSignatureValid(Map<String, String> data, String key, SignType signType) throws Exception { |
| | | if (!data.containsKey(WXPayConstants.FIELD_SIGN) ) { |
| | | return false; |
| | | } |
| | | String sign = data.get(WXPayConstants.FIELD_SIGN); |
| | | return generateSignature(data, key, signType).equals(sign); |
| | | } |
| | | |
| | | /** |
| | | * 生成签名 |
| | | * |
| | | * @param data 待签名数据 |
| | | * @param key API密钥 |
| | | * @return 签名 |
| | | */ |
| | | public static String generateSignature(final Map<String, String> data, String key) throws Exception { |
| | | return generateSignature(data, key, SignType.MD5); |
| | | } |
| | | |
| | | /** |
| | | * 生成签名. 注意,若含有sign_type字段,必须和signType参数保持一致。 |
| | | * |
| | | * @param data 待签名数据 |
| | | * @param key API密钥 |
| | | * @param signType 签名方式 |
| | | * @return 签名 |
| | | */ |
| | | public static String generateSignature(final Map<String, String> data, String key, SignType signType) throws Exception { |
| | | Set<String> keySet = data.keySet(); |
| | | String[] keyArray = keySet.toArray(new String[keySet.size()]); |
| | | Arrays.sort(keyArray); |
| | | StringBuilder sb = new StringBuilder(); |
| | | for (String k : keyArray) { |
| | | if (k.equals(WXPayConstants.FIELD_SIGN)) { |
| | | continue; |
| | | } |
| | | if (data.get(k).trim().length() > 0) // 参数值为空,则不参与签名 |
| | | sb.append(k).append("=").append(data.get(k).trim()).append("&"); |
| | | } |
| | | sb.append("key=").append(key); |
| | | if (SignType.MD5.equals(signType)) { |
| | | return MD5(sb.toString()).toUpperCase(); |
| | | } |
| | | else if (SignType.HMACSHA256.equals(signType)) { |
| | | return HMACSHA256(sb.toString(), key); |
| | | } |
| | | else { |
| | | throw new Exception(String.format("Invalid sign_type: %s", signType)); |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 获取随机字符串 Nonce Str |
| | | * |
| | | * @return String 随机字符串 |
| | | */ |
| | | public static String generateNonceStr() { |
| | | return UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 生成 MD5 |
| | | * |
| | | * @param data 待处理数据 |
| | | * @return MD5结果 |
| | | */ |
| | | public static String MD5(String data) throws Exception { |
| | | java.security.MessageDigest md = MessageDigest.getInstance("MD5"); |
| | | byte[] array = md.digest(data.getBytes("UTF-8")); |
| | | StringBuilder sb = new StringBuilder(); |
| | | for (byte item : array) { |
| | | sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3)); |
| | | } |
| | | return sb.toString().toUpperCase(); |
| | | } |
| | | |
| | | /** |
| | | * 生成 HMACSHA256 |
| | | * @param data 待处理数据 |
| | | * @param key 密钥 |
| | | * @return 加密结果 |
| | | * @throws Exception |
| | | */ |
| | | public static String HMACSHA256(String data, String key) throws Exception { |
| | | Mac sha256_HMAC = Mac.getInstance("HmacSHA256"); |
| | | SecretKeySpec secret_key = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA256"); |
| | | sha256_HMAC.init(secret_key); |
| | | byte[] array = sha256_HMAC.doFinal(data.getBytes("UTF-8")); |
| | | StringBuilder sb = new StringBuilder(); |
| | | for (byte item : array) { |
| | | sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3)); |
| | | } |
| | | return sb.toString().toUpperCase(); |
| | | } |
| | | |
| | | /** |
| | | * 日志 |
| | | * @return |
| | | */ |
| | | public static Logger getLogger() { |
| | | Logger logger = LoggerFactory.getLogger("wxpay java sdk"); |
| | | return logger; |
| | | } |
| | | |
| | | /** |
| | | * 获取当前时间戳,单位秒 |
| | | * @return |
| | | */ |
| | | public static long getCurrentTimestamp() { |
| | | return System.currentTimeMillis()/1000; |
| | | } |
| | | |
| | | /** |
| | | * 获取当前时间戳,单位毫秒 |
| | | * @return |
| | | */ |
| | | public static long getCurrentTimestampMs() { |
| | | return System.currentTimeMillis(); |
| | | } |
| | | |
| | | /** |
| | | * 生成 uuid, 即用来标识一笔单,也用做 nonce_str |
| | | * @return |
| | | */ |
| | | public static String generateUUID() { |
| | | return UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32); |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.ruoyi.order.util.tencent.common; |
| | | |
| | | import java.io.IOException; |
| | | import java.io.InputStream; |
| | | import java.util.HashMap; |
| | | import java.util.Map; |
| | | |
| | | import javax.xml.parsers.DocumentBuilder; |
| | | import javax.xml.parsers.DocumentBuilderFactory; |
| | | import javax.xml.parsers.ParserConfigurationException; |
| | | |
| | | import org.w3c.dom.Document; |
| | | import org.w3c.dom.Element; |
| | | import org.w3c.dom.Node; |
| | | import org.w3c.dom.NodeList; |
| | | import org.xml.sax.SAXException; |
| | | |
| | | public class XMLParser { |
| | | |
| | | public static Map<String,Object> getMapFromXML(String xmlString) throws ParserConfigurationException, IOException, SAXException { |
| | | |
| | | //这里用Dom的方式解析回包的最主要目的是防止API新增回包字段 |
| | | DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); |
| | | DocumentBuilder builder = factory.newDocumentBuilder(); |
| | | InputStream is = Util.getStringStream(xmlString); |
| | | Document document = builder.parse(is); |
| | | |
| | | //获取到document里面的全部结点 |
| | | NodeList allNodes = document.getFirstChild().getChildNodes(); |
| | | Node node; |
| | | Map<String, Object> map = new HashMap<String, Object>(); |
| | | int i=0; |
| | | while (i < allNodes.getLength()) { |
| | | node = allNodes.item(i); |
| | | if(node instanceof Element){ |
| | | map.put(node.getNodeName(),node.getTextContent()); |
| | | } |
| | | i++; |
| | | } |
| | | return map; |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | -----BEGIN CERTIFICATE----- |
| | | MIIEbzCCA9igAwIBAgIEAapJajANBgkqhkiG9w0BAQUFADCBijELMAkGA1UEBhMC |
| | | Q04xEjAQBgNVBAgTCUd1YW5nZG9uZzERMA8GA1UEBxMIU2hlbnpoZW4xEDAOBgNV |
| | | BAoTB1RlbmNlbnQxDDAKBgNVBAsTA1dYRzETMBEGA1UEAxMKTW1wYXltY2hDQTEf |
| | | MB0GCSqGSIb3DQEJARYQbW1wYXltY2hAdGVuY2VudDAeFw0xODAyMDIxMTA3NDRa |
| | | Fw0yODAxMzExMTA3NDRaMIGeMQswCQYDVQQGEwJDTjESMBAGA1UECBMJR3Vhbmdk |
| | | b25nMREwDwYDVQQHEwhTaGVuemhlbjEQMA4GA1UEChMHVGVuY2VudDEOMAwGA1UE |
| | | CxMFTU1QYXkxMzAxBgNVBAMUKuaIkOmDvemprOWPr+aXtuWwmue9kee7nOenkeaK |
| | | gOaciemZkOWFrOWPuDERMA8GA1UEBBMIOTM1NTUzMzUwggEiMA0GCSqGSIb3DQEB |
| | | AQUAA4IBDwAwggEKAoIBAQDF+apUVzPxdAF2FA8r2kg6aPeLynMRsUE17eW+wPZS |
| | | q8mVMrwACzYePbL5003/snEsEU936qnEiu8t5J6w+74dc3mQMr88FW29jD9MQOYR |
| | | yOeWz+LVKFXqA7sm9Aj+7hFrcjxdjl2FvKoITTSXNbtM71FrhsGXsnW/1Zjl3sSy |
| | | cu2qBq40QNqpefzz2gJ+vbtROy+ZynK7QaSwOtiFZuIbPgYv6W18wmigss6JuVkM |
| | | MZUquK4yDIPhwJ4Dk4lLXak1qqNfplfVKQtOo+MHdfIHnG9Z9q+R4iEvAGF4oxaR |
| | | zeKFk+zir8E8xEngmnH0ESue7fn9qh6q0mO7xTaYaG0HAgMBAAGjggFGMIIBQjAJ |
| | | BgNVHRMEAjAAMCwGCWCGSAGG+EIBDQQfFh0iQ0VTLUNBIEdlbmVyYXRlIENlcnRp |
| | | ZmljYXRlIjAdBgNVHQ4EFgQUYkOGN8XaKFwFtBCoEBKwGCnBbtYwgb8GA1UdIwSB |
| | | tzCBtIAUPgUm9iJitBVbiM1kfrDUYqflhnShgZCkgY0wgYoxCzAJBgNVBAYTAkNO |
| | | MRIwEAYDVQQIEwlHdWFuZ2RvbmcxETAPBgNVBAcTCFNoZW56aGVuMRAwDgYDVQQK |
| | | EwdUZW5jZW50MQwwCgYDVQQLEwNXWEcxEzARBgNVBAMTCk1tcGF5bWNoQ0ExHzAd |
| | | BgkqhkiG9w0BCQEWEG1tcGF5bWNoQHRlbmNlbnSCCQC7VJcrvADoVzAOBgNVHQ8B |
| | | Af8EBAMCBsAwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwIwDQYJKoZIhvcNAQEFBQAD |
| | | gYEARXIWwdW50A3JM8BIC94argtpvZXqTj5hWeheeJSDBxNVFv/WzdahqZx7Yokn |
| | | DP/Ac6dekFfvvXR6ujwevEUTFbpSac1h7k7u/URmwH/R2URTevPTrMeg5D+gLeYP |
| | | nEJ+GhyRRAFOoGbN1SoK4f1j6pExpl2GaQ0PVNv7NRVW1tI= |
| | | -----END CERTIFICATE----- |
New file |
| | |
| | | -----BEGIN PRIVATE KEY----- |
| | | MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDF+apUVzPxdAF2 |
| | | FA8r2kg6aPeLynMRsUE17eW+wPZSq8mVMrwACzYePbL5003/snEsEU936qnEiu8t |
| | | 5J6w+74dc3mQMr88FW29jD9MQOYRyOeWz+LVKFXqA7sm9Aj+7hFrcjxdjl2FvKoI |
| | | TTSXNbtM71FrhsGXsnW/1Zjl3sSycu2qBq40QNqpefzz2gJ+vbtROy+ZynK7QaSw |
| | | OtiFZuIbPgYv6W18wmigss6JuVkMMZUquK4yDIPhwJ4Dk4lLXak1qqNfplfVKQtO |
| | | o+MHdfIHnG9Z9q+R4iEvAGF4oxaRzeKFk+zir8E8xEngmnH0ESue7fn9qh6q0mO7 |
| | | xTaYaG0HAgMBAAECggEBAL1yjrYqxIAX3JYb1/DE7z1F2S0iTD7v+lEbGDEUAiNW |
| | | VI67gAAiumTx8eTzeb5oCbh70CoWmuKDeSHXlqwSGvmf2QJOLYXXk65BGQllSURX |
| | | lpZQ1OXZtW08qMk72afqNS02oeF9LK2fvq43A053koaqtKVKzNLXaaprQecm599C |
| | | P+BdahdKk6SE39cOB9fMfX1s5BZRJUhIKNBmcEBsgo9xtKTvgvbgBkSvFBd2ycMo |
| | | 5KRUbquytqIfwDJTETn7FZqh86+BgLOsWEQZ+1ByEJkFNdOGfjz0HVxNMY60j42D |
| | | u9fsIMFup+a/oP190atMSt+GE6ZjgQit/LsF7BrPaiECgYEA7uUDZIpQ1j07MZP+ |
| | | CFMGIE8aTlhvbWho67HCCLDAAv2ZdOSusV66iMzEfDkfOcj9fp8OlfbK2ocUCkS5 |
| | | 5hQAuAk4O8KTmbGgf71gyFZzddZkilc1UAgHVMj9wVp2PfLmpb6iFhazd4enwTPs |
| | | TKxogxfXWRQKQqkCnunOSS7m7V8CgYEA1CaXqMWm2v52FHN8dl8AnH6YjwOQpNXI |
| | | qNOyA8Af03dEQ5w/sNlusiF73/FIgErb0be4rgIvJOW0ziBU9RKn/vB5wl4IpJjM |
| | | JuL3hh7RlAbfSWaqaKCZKIDolS2vtvwKp9mZgmxWgvKx3Q/L8I1MXPIZTTRpGwIe |
| | | HyBxYBTSeVkCgYEAuRHbzgDFXSN0fxUKYMKI5XDCjV0/fX+8gJNmITtklSyHvKII |
| | | n8omMiKIOUA7a5XEpFpuf0kAn8izgrz5Uz+9ytUBpnI3zIJqN2ur1af7rJdZrj6f |
| | | Q4/ktg87XpZJMfbCLjb/9KLDh98k26zw6/lIwf4vS4gV5sxuBlRVBib6qXsCgYA9 |
| | | 2f6PWwi5gkSk08KutCX2ekY6M9zg4d89sXKN+16MBZKmb5B2G/5U+sQl1y+/D5Ql |
| | | AX5bZRGfnUTob661QLov7qZhD49PhajHkZZ+yM9ra9F/keoO1PuyPlsQ2yAGplbo |
| | | 9tz1lGZoiR9oBun7eQaRdpf/1U7ra+OiSZAkZg2zCQKBgQCl+bszQ202CkLchQ1R |
| | | Mu2svFFi+BeVvtA8yp4Il3bznxkgBZJ1/4gB+u84f9ybfpKHok7+f+iHVGJSNiay |
| | | Uw5ouE6oNEJODsvWDDliCjrckGUBDmJ8XOHEkm3MPOmEov8UJ6twev/QWhEfEUZk |
| | | fclCYjgt3YJ3XW9hXgORWhJj9g== |
| | | -----END PRIVATE KEY----- |
New file |
| | |
| | | -----BEGIN CERTIFICATE----- |
| | | MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV |
| | | UzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2Vy |
| | | dGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1 |
| | | MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgxLTArBgNVBAsTJEVx |
| | | dWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0B |
| | | AQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPRfM6f |
| | | BeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+A |
| | | cJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kC |
| | | AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQ |
| | | MA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlm |
| | | aWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgw |
| | | ODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gj |
| | | IBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQF |
| | | MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA |
| | | A4GBAFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y |
| | | 7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh |
| | | 1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4 |
| | | -----END CERTIFICATE----- |
New file |
| | |
| | | 欢迎使用微信支付! |
| | | 微信支付API共四份(证书pkcs12格式、证书pem格式、证书密钥pem格式、CA证书),为接口中强制要求时需携带的证书文件。 |
| | | 证书属于敏感信息,请妥善保管不要泄露和被他人复制。 |
| | | 不同开发语言下的证书格式不同,以下为说明指引: |
| | | 证书pkcs12格式(apiclient_cert.p12) |
| | | 包含了私钥信息的证书文件,为p12(pfx)格式,由微信支付签发给您用来标识和界定您的身份 |
| | | 部分安全性要求较高的API需要使用该证书来确认您的调用身份 |
| | | windows上可以直接双击导入系统,导入过程中会提示输入证书密码,证书密码默认为您的商户ID(如:10010000) |
| | | 证书pem格式(apiclient_cert.pem) |
| | | 从apiclient_cert.p12中导出证书部分的文件,为pem格式,请妥善保管不要泄漏和被他人复制 |
| | | 部分开发语言和环境,不能直接使用p12文件,而需要使用pem,所以为了方便您使用,已为您直接提供 |
| | | 您也可以使用openssl命令来自己导出:openssl pkcs12 -clcerts -nokeys -in apiclient_cert.p12 -out apiclient_cert.pem |
| | | 证书密钥pem格式(apiclient_key.pem) |
| | | 从apiclient_cert.p12中导出密钥部分的文件,为pem格式 |
| | | 部分开发语言和环境,不能直接使用p12文件,而需要使用pem,所以为了方便您使用,已为您直接提供 |
| | | 您也可以使用openssl命令来自己导出:openssl pkcs12 -nocerts -in apiclient_cert.p12 -out apiclient_key.pem |
| | | CA证书(rootca.pem) |
| | | 微信支付api服务器上也部署了证明微信支付身份的服务器证书,您在使用api进行调用时也需要验证所调用服务器及域名的真实性 |
| | | 该文件为签署微信支付证书的权威机构的根证书,可以用来验证微信支付服务器证书的真实性 |
| | | 某些环境和工具已经内置了若干权威机构的根证书,无需引用该证书也可以正常进行验证,这里提供给您在未内置所必须根证书的环境中载入使用 |
New file |
| | |
| | | -----BEGIN CERTIFICATE----- |
| | | MIIEbDCCA9WgAwIBAgIEAV66BDANBgkqhkiG9w0BAQUFADCBijELMAkGA1UEBhMC |
| | | Q04xEjAQBgNVBAgTCUd1YW5nZG9uZzERMA8GA1UEBxMIU2hlbnpoZW4xEDAOBgNV |
| | | BAoTB1RlbmNlbnQxDDAKBgNVBAsTA1dYRzETMBEGA1UEAxMKTW1wYXltY2hDQTEf |
| | | MB0GCSqGSIb3DQEJARYQbW1wYXltY2hAdGVuY2VudDAeFw0xNzA2MjkwNjQwMzha |
| | | Fw0yNzA2MjcwNjQwMzhaMIGbMQswCQYDVQQGEwJDTjESMBAGA1UECBMJR3Vhbmdk |
| | | b25nMREwDwYDVQQHEwhTaGVuemhlbjEQMA4GA1UEChMHVGVuY2VudDEOMAwGA1UE |
| | | CxMFTU1QYXkxMDAuBgNVBAMUJ+WTiOWwlOa7qOWQjeeahOe9kee7nOenkeaKgOac |
| | | iemZkOWFrOWPuDERMA8GA1UEBBMIMzE4OTQ3MDYwggEiMA0GCSqGSIb3DQEBAQUA |
| | | A4IBDwAwggEKAoIBAQDJS/abCCpwvnppCU0TxW84PF2cqpUF3Ip9KmQytNCPRZPK |
| | | q299efclcWOYozB7zSY4OsZ9UyAod1+HsFEjyJBTWyJfakNewiF6AIsydZtFZ65t |
| | | 8ReQ66VTebB1imEq/OrQMXphBwJ1TSH5Jk2pW7JA9U5LqZ3apgDa9PrFHY4dhnkf |
| | | IxQI6Xn0Y7fUJsGszP+5ETbtlLW5PZQiE2H8T3xCwH3mnmg/rppTZaBVIE/7SskW |
| | | iEVPd8g/fec8xDAoAulv1FsBdrPGXyWiFkpcTdrQKHaMa0J7AtMfSnMb1Z/pAIQp |
| | | DxCjCJRM0gfvZNOj2nyqbZD3JJAP8LFnTrasdb/NAgMBAAGjggFGMIIBQjAJBgNV |
| | | HRMEAjAAMCwGCWCGSAGG+EIBDQQfFh0iQ0VTLUNBIEdlbmVyYXRlIENlcnRpZmlj |
| | | YXRlIjAdBgNVHQ4EFgQUBMf3KHk8wfRKtAdcnz+VCFwDdeYwgb8GA1UdIwSBtzCB |
| | | tIAUPgUm9iJitBVbiM1kfrDUYqflhnShgZCkgY0wgYoxCzAJBgNVBAYTAkNOMRIw |
| | | EAYDVQQIEwlHdWFuZ2RvbmcxETAPBgNVBAcTCFNoZW56aGVuMRAwDgYDVQQKEwdU |
| | | ZW5jZW50MQwwCgYDVQQLEwNXWEcxEzARBgNVBAMTCk1tcGF5bWNoQ0ExHzAdBgkq |
| | | hkiG9w0BCQEWEG1tcGF5bWNoQHRlbmNlbnSCCQC7VJcrvADoVzAOBgNVHQ8BAf8E |
| | | BAMCBsAwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwIwDQYJKoZIhvcNAQEFBQADgYEA |
| | | EFcsWO+7E4v7NNdprZYbYASr4e4Uw+EO+RLbkuFUQhHTGMW/biFlYounarNncTFs |
| | | SylXIkCylTRxSZmLNhr8D9/TJ1c9Vrbp8SqlgS5DlhLU3PGjmY7Yl+Zth06v6kv+ |
| | | 0GqwKCljlN+DQNq2wxL7z3S/XDZGTb8tAhLtOKyPkpg= |
| | | -----END CERTIFICATE----- |
New file |
| | |
| | | -----BEGIN PRIVATE KEY----- |
| | | MIIEuwIBADANBgkqhkiG9w0BAQEFAASCBKUwggShAgEAAoIBAQDJS/abCCpwvnpp |
| | | CU0TxW84PF2cqpUF3Ip9KmQytNCPRZPKq299efclcWOYozB7zSY4OsZ9UyAod1+H |
| | | sFEjyJBTWyJfakNewiF6AIsydZtFZ65t8ReQ66VTebB1imEq/OrQMXphBwJ1TSH5 |
| | | Jk2pW7JA9U5LqZ3apgDa9PrFHY4dhnkfIxQI6Xn0Y7fUJsGszP+5ETbtlLW5PZQi |
| | | E2H8T3xCwH3mnmg/rppTZaBVIE/7SskWiEVPd8g/fec8xDAoAulv1FsBdrPGXyWi |
| | | FkpcTdrQKHaMa0J7AtMfSnMb1Z/pAIQpDxCjCJRM0gfvZNOj2nyqbZD3JJAP8LFn |
| | | Trasdb/NAgMBAAECggEAPP5pgNxej78HtF//HOiMJMwVyWzeruH+jKKVrc+gCmmY |
| | | uKZtp+WW/592AEAiZsDovc0Ba+QOMHTLW4APdfpF0RwiNCsssr+8CQ21H9sG62bZ |
| | | MbMF4wGkHMEYuOTvQGlWdTMo09Gd6xEuJCJ5EcIZJxmtWbvRevkl9TKZ8bRc5ZDZ |
| | | 2s/8cgzps9lbnkbTZ9TAF7n7XOlPy4YqIBKW33RCHUtQCfCDERLaBRAG6SbNUsBQ |
| | | SUYq6PsroFtqgwXxbygVsXfNBBfXZ8nfyqupvkOto+2NJjDr6cm5cT+bMyStcNdN |
| | | UAssNUbw7DjcQ+0esS0Z9K7Tah5kmLzzGcDnyNoLgQKBgQDtLeEzRWU9QIksvzUb |
| | | tIAwz/yLTVAQ74/ke6VP4pAWkLdgcVWxY+HOfXyNTWC3MZ2BSyj3oTaahgCQAVb3 |
| | | dXmRDWjRWggUcTLNWgZCcjPw4oshdzVPz1t5WR9/9c+UDqSFSrBGVJ5cVLNpDxSk |
| | | 1KYX7gNdu+h8RTKpKxyOleJaEQKBgQDZRShPjZYvcLNv79y3cT8RHX8qi2akd7by |
| | | X6VwxoFeZ5TeK51fdZjUSyU5/8Jmq9m+K3W7edYrzAOiLYYSCNAVQEoxqGacPla2 |
| | | OlpiSPbtafoIy0ovsJvV6DAZwwtF0cowvdNnXvPsYlKlAKCXnRxf+Ap9/XYArBD6 |
| | | dTpcj1Ht/QKBgQDHhCK/GI9TeWhrZeVtCugTJ8MQA9doh72JvKGRk8sV0GMSFAS8 |
| | | FoOrSlBuJTtIn8oZK3qo5MqkLjlm6lmYDRBYfuk/wvatC5RqvmIpnxwmdMwJONh1 |
| | | 7L7MU7Z10/fsWmz3W57xatlUXkQWCoOZLPETjDr0rM+jSiqVuBhrsZYZoQKBgGN8 |
| | | mFW9Fm0IpRF3etCAyYkTwZwAkvJyYtIe28mFC83njjIhNIF2fpGPCy/AngqXXDAJ |
| | | BHLg+iG53FwRjleJs4ZXluGgI8Qdg2UT2TkyAed6ZGRMed7WdrT/Ca9yMSI6SuQA |
| | | t+GYiAbQitlFLUPfTBPhpyRDwBnUsD2PGjcx5SkdAn8KkFSMExG4y4eZD+UxLXsj |
| | | /QfQj0eUyzu5XyvPXLD9XV1YL3pX7+DxvU98ogFH4QBh2KtDbe2RldyiH8toSP0F |
| | | kXoj4/CtUp8EDBpeLgbdxCYvKW+Lz9oyPNouhkV7m0KRrHV/3CPOeHqkh0dNdW6f |
| | | RKW9WsNAtAS2ncev7Mjj |
| | | -----END PRIVATE KEY----- |
New file |
| | |
| | | -----BEGIN CERTIFICATE----- |
| | | MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV |
| | | UzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2Vy |
| | | dGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1 |
| | | MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgxLTArBgNVBAsTJEVx |
| | | dWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0B |
| | | AQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPRfM6f |
| | | BeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+A |
| | | cJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kC |
| | | AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQ |
| | | MA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlm |
| | | aWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgw |
| | | ODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gj |
| | | IBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQF |
| | | MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA |
| | | A4GBAFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y |
| | | 7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh |
| | | 1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4 |
| | | -----END CERTIFICATE----- |
New file |
| | |
| | | 欢迎使用微信支付! |
| | | 微信支付API共四份(证书pkcs12格式、证书pem格式、证书密钥pem格式、CA证书),为接口中强制要求时需携带的证书文件。 |
| | | 证书属于敏感信息,请妥善保管不要泄露和被他人复制。 |
| | | 不同开发语言下的证书格式不同,以下为说明指引: |
| | | 证书pkcs12格式(apiclient_cert.p12) |
| | | 包含了私钥信息的证书文件,为p12(pfx)格式,由微信支付签发给您用来标识和界定您的身份 |
| | | 部分安全性要求较高的API需要使用该证书来确认您的调用身份 |
| | | windows上可以直接双击导入系统,导入过程中会提示输入证书密码,证书密码默认为您的商户ID(如:10010000) |
| | | 证书pem格式(apiclient_cert.pem) |
| | | 从apiclient_cert.p12中导出证书部分的文件,为pem格式,请妥善保管不要泄漏和被他人复制 |
| | | 部分开发语言和环境,不能直接使用p12文件,而需要使用pem,所以为了方便您使用,已为您直接提供 |
| | | 您也可以使用openssl命令来自己导出:openssl pkcs12 -clcerts -nokeys -in apiclient_cert.p12 -out apiclient_cert.pem |
| | | 证书密钥pem格式(apiclient_key.pem) |
| | | 从apiclient_cert.p12中导出密钥部分的文件,为pem格式 |
| | | 部分开发语言和环境,不能直接使用p12文件,而需要使用pem,所以为了方便您使用,已为您直接提供 |
| | | 您也可以使用openssl命令来自己导出:openssl pkcs12 -nocerts -in apiclient_cert.p12 -out apiclient_key.pem |
| | | CA证书(rootca.pem) |
| | | 微信支付api服务器上也部署了证明微信支付身份的服务器证书,您在使用api进行调用时也需要验证所调用服务器及域名的真实性 |
| | | 该文件为签署微信支付证书的权威机构的根证书,可以用来验证微信支付服务器证书的真实性 |
| | | 某些环境和工具已经内置了若干权威机构的根证书,无需引用该证书也可以正常进行验证,这里提供给您在未内置所必须根证书的环境中载入使用 |
New file |
| | |
| | | package com.ruoyi.order.util.tencent.protocol; |
| | | |
| | | import java.lang.reflect.Field; |
| | | import java.util.HashMap; |
| | | import java.util.Map; |
| | | |
| | | import com.ruoyi.order.util.DateUtil; |
| | | import com.ruoyi.order.util.tencent.common.RandomStringGenerator; |
| | | import com.ruoyi.order.util.tencent.common.Signature; |
| | | |
| | | |
| | | /** |
| | | * 调起支付-API需要提交的数据 |
| | | * @author pan |
| | | */ |
| | | public class AppPayReqData { |
| | | |
| | | //每个字段具体的意思请查看API文档 |
| | | private String appid;//公众账号ID |
| | | private String partnerid;//商户号 |
| | | private String prepayid;//预支付编号(微信返回的支付交易会话ID) |
| | | private String _package = "Sign=WXPay";//扩展字段(暂填写固定值Sign=WXPay) |
| | | private String noncestr = RandomStringGenerator.getRandomStringByLength(32);//随机字符串 (32位) |
| | | private String timestamp = DateUtil.nowDateLongStr().substring(0, 10);//时间戳 |
| | | private String sign;//签名 |
| | | /** |
| | | * 调用微信支付 |
| | | * @param appid 微信分配的APPID |
| | | * @param partnerid 微信支付分配的商户号ID |
| | | * @param prepayid 预支付编号(微信返回的支付交易会话ID) |
| | | */ |
| | | public AppPayReqData(Integer apptype, String appid, String partnerid, String prepayid, String noncestr){ |
| | | //微信分配的APPID |
| | | this.appid = appid; |
| | | //微信支付接口与预支付接口随机字符串,保持一致! |
| | | this.noncestr = noncestr; |
| | | //微信支付分配的商户号ID |
| | | this.partnerid = partnerid; |
| | | //预支付编号(微信返回的支付交易会话ID) |
| | | this.prepayid = prepayid; |
| | | // 根据API给的签名规则进行签名 |
| | | String sign = Signature.getSign(apptype, toMap()); |
| | | setSign(sign);//微信公众号(最后参与签名的参数有appId, timeStamp, nonceStr, package, signType) |
| | | } |
| | | |
| | | public Map<String,Object> toMap(){ |
| | | Map<String,Object> map = new HashMap<String, Object>(); |
| | | Field[] fields = this.getClass().getDeclaredFields(); |
| | | for (Field field : fields) { |
| | | Object obj; |
| | | try { |
| | | obj = field.get(this); |
| | | if(obj!=null){ |
| | | if ("_package".equals(field.getName())) { |
| | | map.put("package", obj); |
| | | }else{ |
| | | map.put(field.getName(), obj); |
| | | } |
| | | } |
| | | } catch (IllegalArgumentException e) { |
| | | e.printStackTrace(); |
| | | } catch (IllegalAccessException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | } |
| | | return map; |
| | | } |
| | | |
| | | public String getAppid() { |
| | | return appid; |
| | | } |
| | | |
| | | public void setAppid(String appid) { |
| | | this.appid = appid; |
| | | } |
| | | |
| | | public String getPartnerid() { |
| | | return partnerid; |
| | | } |
| | | |
| | | public void setPartnerid(String partnerid) { |
| | | this.partnerid = partnerid; |
| | | } |
| | | |
| | | public String getPrepayid() { |
| | | return prepayid; |
| | | } |
| | | |
| | | public void setPrepayid(String prepayid) { |
| | | this.prepayid = prepayid; |
| | | } |
| | | |
| | | public String get_package() { |
| | | return _package; |
| | | } |
| | | |
| | | public void set_package(String _package) { |
| | | this._package = _package; |
| | | } |
| | | |
| | | public String getNoncestr() { |
| | | return noncestr; |
| | | } |
| | | |
| | | public void setNoncestr(String noncestr) { |
| | | this.noncestr = noncestr; |
| | | } |
| | | |
| | | public String getTimestamp() { |
| | | return timestamp; |
| | | } |
| | | |
| | | public void setTimestamp(String timestamp) { |
| | | this.timestamp = timestamp; |
| | | } |
| | | |
| | | public String getSign() { |
| | | return sign; |
| | | } |
| | | |
| | | public void setSign(String sign) { |
| | | this.sign = sign; |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | /*package com.tencent.protocol; |
| | | |
| | | import java.lang.reflect.Field; |
| | | import java.util.HashMap; |
| | | import java.util.Map; |
| | | |
| | | import com.tencent.common.Configure; |
| | | import com.tencent.common.RandomStringGenerator; |
| | | import com.tencent.common.Signature; |
| | | |
| | | *//** |
| | | * 商户想用户付款(提现) |
| | | *//* |
| | | public class PayToTheUserReqData { |
| | | |
| | | //每个字段具体的意思请查看API文档 https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_2 |
| | | private String mch_appid;//公众账号appid 是 wx8888888888888888 String 微信分配的公众账号ID(企业号corpid即为此appId) |
| | | private String mchid;//商户号 是 1900000109 String(32) 微信支付分配的商户号 |
| | | private String nonce_str;// 随机字符串 是 5K8264ILTKCH16CQ2502SI8ZNMTM67VS String(32) 随机字符串,不长于32位 |
| | | private String sign;// 签名 是 C380BEC2BFD727A4B6845133519F3AD6 String(32) 签名,详见签名算法 |
| | | private String partner_trade_no;// 商户订单号 是 10000098201411111234567890 String 商户订单号,需保持唯一性 |
| | | private String openid;// 用户openid 是 oxTWIuGaIt6gTKsQRLau2M0yL16E String 商户appid下,某用户的openid |
| | | private String check_name;// 校验用户姓名选项 是 OPTION_CHECK String NO_CHECK:不校验真实姓名 FORCE_CHECK:强校验真实姓名(未实名认证的用户会校验失败,无法转账) OPTION_CHECK:针对已实名认证的用户才校验真实姓名(未实名认证用户不校验,可以转账成功) |
| | | private String re_user_name;// 收款用户姓名 可选 马花花 String 收款用户真实姓名。 如果check_name设置为FORCE_CHECK或OPTION_CHECK,则必填用户真实姓名 |
| | | private Integer amount;// 金额 是 10099 int 企业付款金额,单位为分 |
| | | private String desc;// 企业付款描述信息 是 理赔 String 企业付款操作说明信息。必填。 |
| | | private String spbill_create_ip = "127.0.0.1";// Ip地址 是 192.168.0.1 String(32) 调用接口的机器Ip地址 |
| | | |
| | | *//** |
| | | * 企业向用户付款 |
| | | * @param partner_trade_no 商户订单号,需保持唯一性 |
| | | * @param openid 商户appid下,某用户的openid |
| | | * @param check_name 校验用户姓名选项:NO_CHECK:不校验真实姓名 FORCE_CHECK:强校验真实姓名(未实名认证的用户会校验失败,无法转账)OPTION_CHECK:针对已实名认证的用户才校验真实姓名(未实名认证用户不校验,可以转账成功) |
| | | * @param re_user_name 收款用户姓名 |
| | | * @param amount 企业付款金额,单位为分 |
| | | * @param desc 企业付款描述信息 |
| | | * @param spbill_create_ip 调用接口的机器Ip地址 |
| | | *//* |
| | | public PayToTheUserReqData(String partner_trade_no, String openid, String re_user_name, Integer amount, String desc){ |
| | | |
| | | //微信分配的公众号ID(开通公众号之后可以获取到) |
| | | setMch_appid(Configure.getAppid()); |
| | | |
| | | //微信支付分配的商户号ID(开通公众号的微信支付功能之后可以获取到) |
| | | setMchid(Configure.getMchid()); |
| | | setPartner_trade_no(partner_trade_no); |
| | | setOpenid(openid); |
| | | setCheck_name("OPTION_CHECK");//默认:针对已实名认证的用户才校验真实姓名(未实名认证用户不校验,可以转账成功) |
| | | // setRe_user_name(re_user_name); |
| | | setAmount(amount); |
| | | setDesc(desc); |
| | | |
| | | //随机字符串,不长于32 位 |
| | | setNonce_str(RandomStringGenerator.getRandomStringByLength(32)); |
| | | |
| | | //根据API给的签名规则进行签名 |
| | | String sign; |
| | | try { |
| | | sign = Signature.getSign(toMap()); |
| | | setSign(sign);//把签名数据设置到Sign这个属性中 |
| | | } catch (IllegalAccessException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | |
| | | } |
| | | |
| | | public String getMch_appid() { |
| | | return mch_appid; |
| | | } |
| | | |
| | | public void setMch_appid(String mch_appid) { |
| | | this.mch_appid = mch_appid; |
| | | } |
| | | |
| | | public String getMchid() { |
| | | return mchid; |
| | | } |
| | | |
| | | public void setMchid(String mchid) { |
| | | this.mchid = mchid; |
| | | } |
| | | |
| | | public String getNonce_str() { |
| | | return nonce_str; |
| | | } |
| | | |
| | | public void setNonce_str(String nonce_str) { |
| | | this.nonce_str = nonce_str; |
| | | } |
| | | |
| | | public String getSign() { |
| | | return sign; |
| | | } |
| | | |
| | | public void setSign(String sign) { |
| | | this.sign = sign; |
| | | } |
| | | |
| | | public String getPartner_trade_no() { |
| | | return partner_trade_no; |
| | | } |
| | | |
| | | public void setPartner_trade_no(String partner_trade_no) { |
| | | this.partner_trade_no = partner_trade_no; |
| | | } |
| | | |
| | | public String getOpenid() { |
| | | return openid; |
| | | } |
| | | |
| | | public void setOpenid(String openid) { |
| | | this.openid = openid; |
| | | } |
| | | |
| | | public String getCheck_name() { |
| | | return check_name; |
| | | } |
| | | |
| | | public void setCheck_name(String check_name) { |
| | | this.check_name = check_name; |
| | | } |
| | | |
| | | public String getRe_user_name() { |
| | | return re_user_name; |
| | | } |
| | | |
| | | public void setRe_user_name(String re_user_name) { |
| | | this.re_user_name = re_user_name; |
| | | } |
| | | |
| | | public Integer getAmount() { |
| | | return amount; |
| | | } |
| | | |
| | | public void setAmount(Integer amount) { |
| | | this.amount = amount; |
| | | } |
| | | |
| | | public String getDesc() { |
| | | return desc; |
| | | } |
| | | |
| | | public void setDesc(String desc) { |
| | | this.desc = desc; |
| | | } |
| | | |
| | | public String getSpbill_create_ip() { |
| | | return spbill_create_ip; |
| | | } |
| | | |
| | | public void setSpbill_create_ip(String spbill_create_ip) { |
| | | this.spbill_create_ip = spbill_create_ip; |
| | | } |
| | | |
| | | |
| | | public Map<String,Object> toMap(){ |
| | | Map<String,Object> map = new HashMap<String, Object>(); |
| | | Field[] fields = this.getClass().getDeclaredFields(); |
| | | for (Field field : fields) { |
| | | Object obj; |
| | | try { |
| | | obj = field.get(this); |
| | | if(obj!=null){ |
| | | map.put(field.getName(), obj); |
| | | } |
| | | } catch (IllegalArgumentException e) { |
| | | e.printStackTrace(); |
| | | } catch (IllegalAccessException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | } |
| | | return map; |
| | | } |
| | | |
| | | } |
| | | */ |
New file |
| | |
| | | package com.tencent.protocol; |
| | | |
| | | import com.ruoyi.order.util.tencent.common.Configure; |
| | | import com.ruoyi.order.util.tencent.common.RandomStringGenerator; |
| | | import com.ruoyi.order.util.tencent.common.Signature; |
| | | |
| | | import java.lang.reflect.Field; |
| | | import java.util.HashMap; |
| | | import java.util.Map; |
| | | |
| | | |
| | | |
| | | /** |
| | | * 商户退款-API需要提交的数据 |
| | | * @author pan |
| | | */ |
| | | public class RefundReqData { |
| | | |
| | | //每个字段具体的意思请查看API文档 |
| | | private String appid = ""; |
| | | private String mch_id = ""; |
| | | private String device_info = ""; |
| | | private String nonce_str = ""; |
| | | private String sign = ""; |
| | | private String transaction_id = ""; |
| | | private String out_trade_no = ""; |
| | | private String out_refund_no = ""; |
| | | private int total_fee = 0; |
| | | private int refund_fee = 0; |
| | | private String refund_fee_type = "CNY"; |
| | | private String op_user_id = ""; |
| | | private String pay_type = "";//2微信app支付,3公众号支付,4小程序支付 |
| | | |
| | | /** |
| | | * 请求退款服务 |
| | | * @param transactionID 是微信系统为每一笔支付交易分配的订单号,通过这个订单号可以标识这笔交易,它由支付订单API支付成功时返回的数据里面获取到。建议优先使用 |
| | | * @param outTradeNo 商户系统内部的订单号,transaction_id 、out_trade_no 二选一,如果同时存在优先级:transaction_id>out_trade_no |
| | | * @param deviceInfo 微信支付分配的终端设备号,与下单一致 |
| | | * @param outRefundNo 商户系统内部的退款单号,商户系统内部唯一,同一退款单号多次请求只退一笔 |
| | | * @param totalFee 订单总金额,单位为分 |
| | | * @param refundFee 退款总金额,单位为分,可以做部分退款 |
| | | * @param opUserID 操作员帐号, 默认为商户号 |
| | | * @param refundFeeType 货币类型,符合ISO 4217标准的三位字母代码,默认为CNY(人民币) |
| | | */ |
| | | public RefundReqData(String transactionID, String outTradeNo, String outRefundNo, int totalFee, int refundFee,String payType) { |
| | | // 微信分配的公众号ID(开通公众号之后可以获取到) |
| | | |
| | | if (payType.equals("2")) {//微信app |
| | | System.out.println("微信app退款!!!!!!!!!!!"); |
| | | setAppid(Configure.getAppid()); |
| | | setMch_id(Configure.getMchid()); |
| | | setOp_user_id(getMch_id()); |
| | | }else if(payType.equals("3")) {//微信公众号 |
| | | System.out.println("微信公众号退款!!!!!!!!!!!"); |
| | | setAppid(Configure.getGappid()); |
| | | setMch_id(Configure.getGmchid()); |
| | | setOp_user_id(Configure.getGmchid()); |
| | | }else if(payType.equals("4")) {//微信小程序 |
| | | System.out.println("微信小程序退款!!!!!!!!!!!"); |
| | | setAppid(Configure.getXappid()); |
| | | setMch_id(Configure.getXmchid()); |
| | | setOp_user_id(Configure.getXmchid()); |
| | | } |
| | | |
| | | //transaction_id是微信系统为每一笔支付交易分配的订单号,通过这个订单号可以标识这笔交易,它由支付订单API支付成功时返回的数据里面获取到。 |
| | | setTransaction_id(transactionID); |
| | | |
| | | //商户系统自己生成的唯一的订单号 |
| | | setOut_trade_no(outTradeNo); |
| | | |
| | | setOut_refund_no(outRefundNo); |
| | | |
| | | setTotal_fee(totalFee); |
| | | |
| | | setRefund_fee(refundFee); |
| | | |
| | | //随机字符串,不长于32 位 |
| | | setNonce_str(RandomStringGenerator.getRandomStringByLength(32)); |
| | | |
| | | //根据API给的签名规则进行签名 |
| | | String sign = Signature.getSign(1,toMap()); |
| | | setSign(sign);//把签名数据设置到Sign这个属性中 |
| | | |
| | | |
| | | } |
| | | |
| | | public String getAppid() { |
| | | return appid; |
| | | } |
| | | |
| | | public void setAppid(String appid) { |
| | | this.appid = appid; |
| | | } |
| | | |
| | | public String getMch_id() { |
| | | return mch_id; |
| | | } |
| | | |
| | | public void setMch_id(String mch_id) { |
| | | this.mch_id = mch_id; |
| | | } |
| | | |
| | | public String getDevice_info() { |
| | | return device_info; |
| | | } |
| | | |
| | | public void setDevice_info(String device_info) { |
| | | this.device_info = device_info; |
| | | } |
| | | |
| | | public String getNonce_str() { |
| | | return nonce_str; |
| | | } |
| | | |
| | | public void setNonce_str(String nonce_str) { |
| | | this.nonce_str = nonce_str; |
| | | } |
| | | |
| | | public String getSign() { |
| | | return sign; |
| | | } |
| | | |
| | | public void setSign(String sign) { |
| | | this.sign = sign; |
| | | } |
| | | |
| | | public String getTransaction_id() { |
| | | return transaction_id; |
| | | } |
| | | |
| | | public void setTransaction_id(String transaction_id) { |
| | | this.transaction_id = transaction_id; |
| | | } |
| | | |
| | | public String getOut_trade_no() { |
| | | return out_trade_no; |
| | | } |
| | | |
| | | public void setOut_trade_no(String out_trade_no) { |
| | | this.out_trade_no = out_trade_no; |
| | | } |
| | | |
| | | public String getOut_refund_no() { |
| | | return out_refund_no; |
| | | } |
| | | |
| | | public void setOut_refund_no(String out_refund_no) { |
| | | this.out_refund_no = out_refund_no; |
| | | } |
| | | |
| | | public int getTotal_fee() { |
| | | return total_fee; |
| | | } |
| | | |
| | | public void setTotal_fee(int total_fee) { |
| | | this.total_fee = total_fee; |
| | | } |
| | | |
| | | public int getRefund_fee() { |
| | | return refund_fee; |
| | | } |
| | | |
| | | public void setRefund_fee(int refund_fee) { |
| | | this.refund_fee = refund_fee; |
| | | } |
| | | |
| | | public String getOp_user_id() { |
| | | return op_user_id; |
| | | } |
| | | |
| | | public void setOp_user_id(String op_user_id) { |
| | | this.op_user_id = op_user_id; |
| | | } |
| | | |
| | | public String getRefund_fee_type() { |
| | | return refund_fee_type; |
| | | } |
| | | |
| | | public void setRefund_fee_type(String refund_fee_type) { |
| | | this.refund_fee_type = refund_fee_type; |
| | | } |
| | | |
| | | public String getPay_type() { |
| | | return pay_type; |
| | | } |
| | | |
| | | public void setPay_type(String pay_type) { |
| | | this.pay_type = pay_type; |
| | | } |
| | | |
| | | public Map<String,Object> toMap(){ |
| | | Map<String,Object> map = new HashMap<String, Object>(); |
| | | Field[] fields = this.getClass().getDeclaredFields(); |
| | | for (Field field : fields) { |
| | | Object obj; |
| | | try { |
| | | obj = field.get(this); |
| | | if(obj!=null){ |
| | | map.put(field.getName(), obj); |
| | | } |
| | | } catch (IllegalArgumentException e) { |
| | | e.printStackTrace(); |
| | | } catch (IllegalAccessException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | } |
| | | return map; |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.ruoyi.order.util.tencent.protocol; |
| | | |
| | | import com.ruoyi.order.util.SinataUtil; |
| | | import com.ruoyi.order.util.tencent.common.Configure; |
| | | import com.ruoyi.order.util.tencent.common.RandomStringGenerator; |
| | | import com.ruoyi.order.util.tencent.common.Signature; |
| | | |
| | | import java.lang.reflect.Field; |
| | | import java.util.HashMap; |
| | | import java.util.Map; |
| | | |
| | | |
| | | |
| | | /** |
| | | * 请求统一下单-API需要提交的数据 |
| | | * @author pan |
| | | */ |
| | | public class UnifiedorderReqData { |
| | | |
| | | //每个字段具体的意思请查看API文档 |
| | | private String appid;//公众账号ID (内置) |
| | | private String mch_id;//商户号 (内置) |
| | | private String nonce_str;//随机字符串 (内置) |
| | | private String sign;//签名 |
| | | |
| | | |
| | | //接口调用需要的参数 |
| | | private String body;//商品描述 |
| | | private String out_trade_no;//商户订单号 |
| | | private Integer total_fee;//总金额 |
| | | private String spbill_create_ip;//终端IP |
| | | private String notify_url;//通知地址 |
| | | private String trade_type;//交易类型 |
| | | private String openid;//用户标识 |
| | | |
| | | /** |
| | | * 预支付请求需要的参数(获取微信统一下单-必填参数) |
| | | * 公众账号ID appid (内置) |
| | | * 商户号 mch_id (内置) |
| | | * 随机字符串 nonce_str (内置) |
| | | * 签名 sign (内置) |
| | | * @param body 商品描述 |
| | | * @param out_trade_no 商户订单号 |
| | | * @param total_fee 总金额 (单位:分) |
| | | * @param notify_url 通知地址 |
| | | */ |
| | | public UnifiedorderReqData(Integer apptype, String out_trade_no, String body, Double total_fee, String notify_url){ |
| | | |
| | | //乘客appID与商户号 |
| | | this.appid = Configure.getAppid(); |
| | | |
| | | //微信支付分配的商户号ID(开通公众号的微信支付功能之后可以获取到) |
| | | this.mch_id = Configure.getMchid(); |
| | | |
| | | //随机字符串,不长于32 位 |
| | | // setNonce_str(RandomStringGenerator.getRandomStringByLength(32)); |
| | | this.nonce_str = RandomStringGenerator.getRandomStringByLength(32); |
| | | |
| | | |
| | | // setBody(body);// 商品描述 |
| | | this.body = body; |
| | | |
| | | // setOut_trade_no(out_trade_no);// 商户订单号 |
| | | this.out_trade_no = out_trade_no; |
| | | |
| | | // setTotal_fee();// 总金额 |
| | | String money= SinataUtil.doubleRetainTwo(total_fee*100d); |
| | | this.total_fee = Integer.parseInt(money.substring(0,money.length()-3)); |
| | | |
| | | // setNotify_url(notify_url);// 通知地址 |
| | | this.notify_url = notify_url; |
| | | // setTrade_type("APP");// 交易类型,默认:APP |
| | | this.trade_type = "APP"; |
| | | // 根据API给的签名规则进行签名 |
| | | this.sign = Signature.getSign(apptype, toMap()); |
| | | |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 预支付请求需要的参数(获取微信统一下单-必填参数)(公众号) |
| | | * 公众账号ID appid (内置) |
| | | * 商户号 mch_id (内置) |
| | | * 随机字符串 nonce_str (内置) |
| | | * 签名 sign (内置) |
| | | * @param body 商品描述 |
| | | * @param out_trade_no 商户订单号 |
| | | * @param total_fee 总金额 (单位:分) |
| | | * @param notify_url 通知地址 |
| | | * @throws IllegalAccessException |
| | | */ |
| | | public UnifiedorderReqData(String out_trade_no, String body, Double total_fee, String notify_url,String trade_type,String openid) throws IllegalAccessException{ |
| | | |
| | | //appID与商户号 |
| | | this.appid = Configure.getGappid(); |
| | | |
| | | //微信支付分配的商户号ID(开通公众号的微信支付功能之后可以获取到) |
| | | this.mch_id = Configure.getGmchid(); |
| | | |
| | | //随机字符串,不长于32 位 |
| | | // setNonce_str(RandomStringGenerator.getRandomStringByLength(32)); |
| | | this.nonce_str = RandomStringGenerator.getRandomStringByLength(32); |
| | | |
| | | |
| | | // setBody(body);// 商品描述 |
| | | this.body = body; |
| | | |
| | | // setOut_trade_no(out_trade_no);// 商户订单号 |
| | | this.out_trade_no = out_trade_no; |
| | | |
| | | // setTotal_fee();// 总金额 |
| | | String money=SinataUtil.doubleRetainTwo(total_fee*100d); |
| | | this.total_fee = Integer.parseInt(money.substring(0,money.length()-3)); |
| | | //this.total_fee = (int)(total_fee * 100); |
| | | |
| | | // setNotify_url(notify_url);// 通知地址 |
| | | this.notify_url = notify_url; |
| | | /*trade_type 交易类型JSAPI--公众号支付、NATIVE--原生扫码支付、APP--app支付,统一下单接口trade_type的传参可参考这里 |
| | | MICROPAY--刷卡支付,刷卡支付有单独的支付接口,不调用统一下单接口*/ |
| | | |
| | | this.trade_type = trade_type; |
| | | this.openid = openid; |
| | | // 根据API给的签名规则进行签名 |
| | | this.sign = Signature.getSign(1,toMap()); |
| | | |
| | | } |
| | | |
| | | /** |
| | | * 预支付请求需要的参数(获取微信统一下单-必填参数)(小程序) |
| | | * 公众账号ID appid (内置) |
| | | * 商户号 mch_id (内置) |
| | | * 随机字符串 nonce_str (内置) |
| | | * 签名 sign (内置) |
| | | * @param body 商品描述 |
| | | * @param out_trade_no 商户订单号 |
| | | * @param total_fee 总金额 (单位:分) |
| | | * @param notify_url 通知地址 |
| | | * @throws IllegalAccessException |
| | | */ |
| | | public UnifiedorderReqData(String out_trade_no, Double total_fee, String notify_url,String trade_type,String openid) throws IllegalAccessException{ |
| | | |
| | | //appID与商户号 |
| | | this.appid = Configure.getXappid(); |
| | | |
| | | //微信支付分配的商户号ID(开通公众号的微信支付功能之后可以获取到) |
| | | this.mch_id = Configure.getXmchid(); |
| | | |
| | | //随机字符串,不长于32 位 |
| | | // setNonce_str(RandomStringGenerator.getRandomStringByLength(32)); |
| | | this.nonce_str = RandomStringGenerator.getRandomStringByLength(32); |
| | | |
| | | |
| | | // setBody(body);// 商品描述 |
| | | this.body = "小程序支付"; |
| | | |
| | | // setOut_trade_no(out_trade_no);// 商户订单号 |
| | | this.out_trade_no = out_trade_no; |
| | | |
| | | // setTotal_fee();// 总金额 |
| | | String money=SinataUtil.doubleRetainTwo(total_fee*100d); |
| | | this.total_fee = Integer.parseInt(money.substring(0,money.length()-3)); |
| | | //this.total_fee = (int)(total_fee * 100); |
| | | |
| | | // setNotify_url(notify_url);// 通知地址 |
| | | this.notify_url = notify_url; |
| | | /*trade_type 交易类型JSAPI--公众号支付、NATIVE--原生扫码支付、APP--app支付,统一下单接口trade_type的传参可参考这里 |
| | | MICROPAY--刷卡支付,刷卡支付有单独的支付接口,不调用统一下单接口*/ |
| | | |
| | | this.trade_type = trade_type; |
| | | this.openid = openid; |
| | | // 根据API给的签名规则进行签名 |
| | | this.sign = Signature.getSign(1,toMap()); |
| | | |
| | | } |
| | | |
| | | public Map<String,Object> toMap(){ |
| | | Map<String,Object> map = new HashMap<String, Object>(); |
| | | Field[] fields = this.getClass().getDeclaredFields(); |
| | | for (Field field : fields) { |
| | | Object obj; |
| | | try { |
| | | obj = field.get(this); |
| | | if(obj!=null){ |
| | | map.put(field.getName(), obj); |
| | | } |
| | | } catch (IllegalArgumentException e) { |
| | | e.printStackTrace(); |
| | | } catch (IllegalAccessException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | } |
| | | return map; |
| | | } |
| | | |
| | | public String getAppid() { |
| | | return appid; |
| | | } |
| | | |
| | | public void setAppid(String appid) { |
| | | this.appid = appid; |
| | | } |
| | | |
| | | public String getMch_id() { |
| | | return mch_id; |
| | | } |
| | | |
| | | public void setMch_id(String mch_id) { |
| | | this.mch_id = mch_id; |
| | | } |
| | | |
| | | public String getNonce_str() { |
| | | return nonce_str; |
| | | } |
| | | |
| | | public void setNonce_str(String nonce_str) { |
| | | this.nonce_str = nonce_str; |
| | | } |
| | | |
| | | public String getSign() { |
| | | return sign; |
| | | } |
| | | |
| | | public void setSign(String sign) { |
| | | this.sign = sign; |
| | | } |
| | | |
| | | public String getBody() { |
| | | return body; |
| | | } |
| | | |
| | | public void setBody(String body) { |
| | | this.body = body; |
| | | } |
| | | |
| | | public String getOut_trade_no() { |
| | | return out_trade_no; |
| | | } |
| | | |
| | | public void setOut_trade_no(String out_trade_no) { |
| | | this.out_trade_no = out_trade_no; |
| | | } |
| | | |
| | | public Integer getTotal_fee() { |
| | | return total_fee; |
| | | } |
| | | |
| | | public void setTotal_fee(Integer total_fee) { |
| | | this.total_fee = total_fee; |
| | | } |
| | | |
| | | public String getSpbill_create_ip() { |
| | | return spbill_create_ip; |
| | | } |
| | | |
| | | public void setSpbill_create_ip(String spbill_create_ip) { |
| | | this.spbill_create_ip = spbill_create_ip; |
| | | } |
| | | |
| | | public String getNotify_url() { |
| | | return notify_url; |
| | | } |
| | | |
| | | public void setNotify_url(String notify_url) { |
| | | this.notify_url = notify_url; |
| | | } |
| | | |
| | | public String getTrade_type() { |
| | | return trade_type; |
| | | } |
| | | |
| | | public void setTrade_type(String trade_type) { |
| | | this.trade_type = trade_type; |
| | | } |
| | | |
| | | |
| | | public String getOpenid() { |
| | | return openid; |
| | | } |
| | | |
| | | |
| | | public void setOpenid(String openid) { |
| | | this.openid = openid; |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.ruoyi.order.util.tencent.protocol; |
| | | |
| | | import com.ruoyi.order.util.tencent.common.WXPayConfig; |
| | | import com.ruoyi.order.util.tencent.common.WXPayUtil; |
| | | import org.apache.http.HttpEntity; |
| | | import org.apache.http.HttpResponse; |
| | | import org.apache.http.client.HttpClient; |
| | | import org.apache.http.client.config.RequestConfig; |
| | | import org.apache.http.client.methods.HttpPost; |
| | | import org.apache.http.config.RegistryBuilder; |
| | | import org.apache.http.conn.socket.ConnectionSocketFactory; |
| | | import org.apache.http.conn.socket.PlainConnectionSocketFactory; |
| | | import org.apache.http.conn.ssl.SSLConnectionSocketFactory; |
| | | import org.apache.http.entity.StringEntity; |
| | | import org.apache.http.impl.client.HttpClientBuilder; |
| | | import org.apache.http.impl.conn.BasicHttpClientConnectionManager; |
| | | import org.apache.http.util.EntityUtils; |
| | | |
| | | |
| | | import java.util.concurrent.ExecutorService; |
| | | import java.util.concurrent.Executors; |
| | | import java.util.concurrent.LinkedBlockingQueue; |
| | | import java.util.concurrent.ThreadFactory; |
| | | |
| | | /** |
| | | * 交易保障 |
| | | */ |
| | | public class WXPayReport { |
| | | |
| | | public static class ReportInfo { |
| | | |
| | | /** |
| | | * 布尔变量使用int。0为false, 1为true。 |
| | | */ |
| | | |
| | | // 基本信息 |
| | | private String version = "v0"; |
| | | private String sdk = "wxpay java sdk v1.0"; |
| | | private String uuid; // 交易的标识 |
| | | private long timestamp; // 上报时的时间戳,单位秒 |
| | | private long elapsedTimeMillis; // 耗时,单位 毫秒 |
| | | |
| | | // 针对主域名 |
| | | private String firstDomain; // 第1次请求的域名 |
| | | private boolean primaryDomain; //是否主域名 |
| | | private int firstConnectTimeoutMillis; // 第1次请求设置的连接超时时间,单位 毫秒 |
| | | private int firstReadTimeoutMillis; // 第1次请求设置的读写超时时间,单位 毫秒 |
| | | private int firstHasDnsError; // 第1次请求是否出现dns问题 |
| | | private int firstHasConnectTimeout; // 第1次请求是否出现连接超时 |
| | | private int firstHasReadTimeout; // 第1次请求是否出现连接超时 |
| | | |
| | | public ReportInfo(String uuid, long timestamp, long elapsedTimeMillis, String firstDomain, boolean primaryDomain, int firstConnectTimeoutMillis, int firstReadTimeoutMillis, boolean firstHasDnsError, boolean firstHasConnectTimeout, boolean firstHasReadTimeout) { |
| | | this.uuid = uuid; |
| | | this.timestamp = timestamp; |
| | | this.elapsedTimeMillis = elapsedTimeMillis; |
| | | this.firstDomain = firstDomain; |
| | | this.primaryDomain = primaryDomain; |
| | | this.firstConnectTimeoutMillis = firstConnectTimeoutMillis; |
| | | this.firstReadTimeoutMillis = firstReadTimeoutMillis; |
| | | this.firstHasDnsError = firstHasDnsError?1:0; |
| | | this.firstHasConnectTimeout = firstHasConnectTimeout?1:0; |
| | | this.firstHasReadTimeout = firstHasReadTimeout?1:0; |
| | | } |
| | | |
| | | @Override |
| | | public String toString() { |
| | | return "ReportInfo{" + |
| | | "version='" + version + '\'' + |
| | | ", sdk='" + sdk + '\'' + |
| | | ", uuid='" + uuid + '\'' + |
| | | ", timestamp=" + timestamp + |
| | | ", elapsedTimeMillis=" + elapsedTimeMillis + |
| | | ", firstDomain='" + firstDomain + '\'' + |
| | | ", primaryDomain=" + primaryDomain + |
| | | ", firstConnectTimeoutMillis=" + firstConnectTimeoutMillis + |
| | | ", firstReadTimeoutMillis=" + firstReadTimeoutMillis + |
| | | ", firstHasDnsError=" + firstHasDnsError + |
| | | ", firstHasConnectTimeout=" + firstHasConnectTimeout + |
| | | ", firstHasReadTimeout=" + firstHasReadTimeout + |
| | | '}'; |
| | | } |
| | | |
| | | /** |
| | | * 转换成 csv 格式 |
| | | * |
| | | * @return |
| | | */ |
| | | public String toLineString(String key) { |
| | | String separator = ","; |
| | | Object[] objects = new Object[] { |
| | | version, sdk, uuid, timestamp, elapsedTimeMillis, |
| | | firstDomain, primaryDomain, firstConnectTimeoutMillis, firstReadTimeoutMillis, |
| | | firstHasDnsError, firstHasConnectTimeout, firstHasReadTimeout |
| | | }; |
| | | StringBuffer sb = new StringBuffer(); |
| | | for(Object obj: objects) { |
| | | sb.append(obj).append(separator); |
| | | } |
| | | try { |
| | | String sign = WXPayUtil.HMACSHA256(sb.toString(), key); |
| | | sb.append(sign); |
| | | return sb.toString(); |
| | | } |
| | | catch (Exception ex) { |
| | | return null; |
| | | } |
| | | |
| | | } |
| | | |
| | | } |
| | | |
| | | private static final String REPORT_URL = "http://report.mch.weixin.qq.com/wxpay/report/default"; |
| | | // private static final String REPORT_URL = "http://127.0.0.1:5000/test"; |
| | | |
| | | |
| | | private static final int DEFAULT_CONNECT_TIMEOUT_MS = 6*1000; |
| | | private static final int DEFAULT_READ_TIMEOUT_MS = 8*1000; |
| | | |
| | | private LinkedBlockingQueue<String> reportMsgQueue = null; |
| | | private WXPayConfig config; |
| | | private ExecutorService executorService; |
| | | |
| | | private volatile static WXPayReport INSTANCE; |
| | | |
| | | private WXPayReport(final WXPayConfig config) { |
| | | this.config = config; |
| | | reportMsgQueue = new LinkedBlockingQueue<String>(config.getReportQueueMaxSize()); |
| | | |
| | | // 添加处理线程 |
| | | executorService = Executors.newFixedThreadPool(config.getReportWorkerNum(), new ThreadFactory() { |
| | | public Thread newThread(Runnable r) { |
| | | Thread t = Executors.defaultThreadFactory().newThread(r); |
| | | t.setDaemon(true); |
| | | return t; |
| | | } |
| | | }); |
| | | |
| | | if (config.shouldAutoReport()) { |
| | | WXPayUtil.getLogger().info("report worker num: {}", config.getReportWorkerNum()); |
| | | for (int i = 0; i < config.getReportWorkerNum(); ++i) { |
| | | executorService.execute(new Runnable() { |
| | | public void run() { |
| | | while (true) { |
| | | // 先用 take 获取数据 |
| | | try { |
| | | StringBuffer sb = new StringBuffer(); |
| | | String firstMsg = reportMsgQueue.take(); |
| | | WXPayUtil.getLogger().info("get first report msg: {}", firstMsg); |
| | | String msg = null; |
| | | sb.append(firstMsg); //会阻塞至有消息 |
| | | int remainNum = config.getReportBatchSize() - 1; |
| | | for (int j=0; j<remainNum; ++j) { |
| | | WXPayUtil.getLogger().info("try get remain report msg"); |
| | | // msg = reportMsgQueue.poll(); // 不阻塞了 |
| | | msg = reportMsgQueue.take(); |
| | | WXPayUtil.getLogger().info("get remain report msg: {}", msg); |
| | | if (msg == null) { |
| | | break; |
| | | } |
| | | else { |
| | | sb.append("\n"); |
| | | sb.append(msg); |
| | | } |
| | | } |
| | | // 上报 |
| | | WXPayReport.httpRequest(sb.toString(), DEFAULT_CONNECT_TIMEOUT_MS, DEFAULT_READ_TIMEOUT_MS); |
| | | } |
| | | catch (Exception ex) { |
| | | WXPayUtil.getLogger().warn("report fail. reason: {}", ex.getMessage()); |
| | | } |
| | | } |
| | | } |
| | | }); |
| | | } |
| | | } |
| | | |
| | | } |
| | | |
| | | /** |
| | | * 单例,双重校验,请在 JDK 1.5及更高版本中使用 |
| | | * |
| | | * @param config |
| | | * @return |
| | | */ |
| | | public static WXPayReport getInstance(WXPayConfig config) { |
| | | if (INSTANCE == null) { |
| | | synchronized (WXPayReport.class) { |
| | | if (INSTANCE == null) { |
| | | INSTANCE = new WXPayReport(config); |
| | | } |
| | | } |
| | | } |
| | | return INSTANCE; |
| | | } |
| | | |
| | | public void report(String uuid, long elapsedTimeMillis, |
| | | String firstDomain, boolean primaryDomain, int firstConnectTimeoutMillis, int firstReadTimeoutMillis, |
| | | boolean firstHasDnsError, boolean firstHasConnectTimeout, boolean firstHasReadTimeout) { |
| | | long currentTimestamp = WXPayUtil.getCurrentTimestamp(); |
| | | ReportInfo reportInfo = new ReportInfo(uuid, currentTimestamp, elapsedTimeMillis, |
| | | firstDomain, primaryDomain, firstConnectTimeoutMillis, firstReadTimeoutMillis, |
| | | firstHasDnsError, firstHasConnectTimeout, firstHasReadTimeout); |
| | | String data = reportInfo.toLineString(config.getKey()); |
| | | WXPayUtil.getLogger().info("report {}", data); |
| | | if (data != null) { |
| | | reportMsgQueue.offer(data); |
| | | } |
| | | } |
| | | |
| | | |
| | | @Deprecated |
| | | private void reportSync(final String data) throws Exception { |
| | | httpRequest(data, DEFAULT_CONNECT_TIMEOUT_MS, DEFAULT_READ_TIMEOUT_MS); |
| | | } |
| | | |
| | | @Deprecated |
| | | private void reportAsync(final String data) throws Exception { |
| | | new Thread(new Runnable() { |
| | | public void run() { |
| | | try { |
| | | httpRequest(data, DEFAULT_CONNECT_TIMEOUT_MS, DEFAULT_READ_TIMEOUT_MS); |
| | | } |
| | | catch (Exception ex) { |
| | | WXPayUtil.getLogger().warn("report fail. reason: {}", ex.getMessage()); |
| | | } |
| | | } |
| | | }).start(); |
| | | } |
| | | |
| | | /** |
| | | * http 请求 |
| | | * @param data |
| | | * @param connectTimeoutMs |
| | | * @param readTimeoutMs |
| | | * @return |
| | | * @throws Exception |
| | | */ |
| | | private static String httpRequest(String data, int connectTimeoutMs, int readTimeoutMs) throws Exception{ |
| | | BasicHttpClientConnectionManager connManager; |
| | | connManager = new BasicHttpClientConnectionManager( |
| | | RegistryBuilder.<ConnectionSocketFactory>create() |
| | | .register("http", PlainConnectionSocketFactory.getSocketFactory()) |
| | | .register("https", SSLConnectionSocketFactory.getSocketFactory()) |
| | | .build(), |
| | | null, |
| | | null, |
| | | null |
| | | ); |
| | | HttpClient httpClient = HttpClientBuilder.create() |
| | | .setConnectionManager(connManager) |
| | | .build(); |
| | | |
| | | HttpPost httpPost = new HttpPost(REPORT_URL); |
| | | |
| | | RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(readTimeoutMs).setConnectTimeout(connectTimeoutMs).build(); |
| | | httpPost.setConfig(requestConfig); |
| | | |
| | | StringEntity postEntity = new StringEntity(data, "UTF-8"); |
| | | httpPost.addHeader("Content-Type", "text/xml"); |
| | | httpPost.addHeader("User-Agent", "wxpay sdk java v1.0 "); // TODO: 很重要,用来检测 sdk 的使用情况,要不要加上商户信息? |
| | | httpPost.setEntity(postEntity); |
| | | |
| | | HttpResponse httpResponse = httpClient.execute(httpPost); |
| | | HttpEntity httpEntity = httpResponse.getEntity(); |
| | | return EntityUtils.toString(httpEntity, "UTF-8"); |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.ruoyi.order.util.tencent.protocol; |
| | | |
| | | import com.ruoyi.order.util.tencent.common.IWXPayDomain; |
| | | import com.ruoyi.order.util.tencent.common.WXPayConfig; |
| | | import com.ruoyi.order.util.tencent.common.WXPayUtil; |
| | | import org.apache.http.HttpEntity; |
| | | import org.apache.http.HttpResponse; |
| | | import org.apache.http.client.HttpClient; |
| | | import org.apache.http.client.config.RequestConfig; |
| | | import org.apache.http.client.methods.HttpPost; |
| | | import org.apache.http.config.RegistryBuilder; |
| | | import org.apache.http.conn.ConnectTimeoutException; |
| | | import org.apache.http.conn.socket.ConnectionSocketFactory; |
| | | import org.apache.http.conn.socket.PlainConnectionSocketFactory; |
| | | import org.apache.http.conn.ssl.SSLConnectionSocketFactory; |
| | | import org.apache.http.entity.StringEntity; |
| | | import org.apache.http.impl.client.HttpClientBuilder; |
| | | import org.apache.http.impl.conn.BasicHttpClientConnectionManager; |
| | | import org.apache.http.util.EntityUtils; |
| | | |
| | | |
| | | |
| | | import javax.net.ssl.KeyManagerFactory; |
| | | import javax.net.ssl.SSLContext; |
| | | |
| | | import java.io.InputStream; |
| | | import java.net.SocketTimeoutException; |
| | | import java.net.UnknownHostException; |
| | | import java.security.KeyStore; |
| | | import java.security.SecureRandom; |
| | | |
| | | public class WXPayRequest { |
| | | private WXPayConfig config; |
| | | public WXPayRequest(WXPayConfig config) throws Exception{ |
| | | |
| | | this.config = config; |
| | | } |
| | | |
| | | /** |
| | | * 请求,只请求一次,不做重试 |
| | | * @param domain |
| | | * @param urlSuffix |
| | | * @param uuid |
| | | * @param data |
| | | * @param connectTimeoutMs |
| | | * @param readTimeoutMs |
| | | * @param useCert 是否使用证书,针对退款、撤销等操作 |
| | | * @return |
| | | * @throws Exception |
| | | */ |
| | | private String requestOnce(final String domain, String urlSuffix, String uuid, String data, int connectTimeoutMs, int readTimeoutMs, boolean useCert) throws Exception { |
| | | BasicHttpClientConnectionManager connManager; |
| | | if (useCert) { |
| | | // 证书 |
| | | char[] password = config.getMchID().toCharArray(); |
| | | InputStream certStream = config.getCertStream(); |
| | | KeyStore ks = KeyStore.getInstance("PKCS12"); |
| | | ks.load(certStream, password); |
| | | |
| | | // 实例化密钥库 & 初始化密钥工厂 |
| | | KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); |
| | | kmf.init(ks, password); |
| | | |
| | | // 创建 SSLContext |
| | | SSLContext sslContext = SSLContext.getInstance("TLS"); |
| | | sslContext.init(kmf.getKeyManagers(), null, new SecureRandom()); |
| | | |
| | | SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory( |
| | | sslContext); |
| | | |
| | | connManager = new BasicHttpClientConnectionManager( |
| | | RegistryBuilder.<ConnectionSocketFactory>create() |
| | | .register("http", PlainConnectionSocketFactory.getSocketFactory()) |
| | | .register("https", sslConnectionSocketFactory) |
| | | .build(), |
| | | null, |
| | | null, |
| | | null |
| | | ); |
| | | } |
| | | else { |
| | | connManager = new BasicHttpClientConnectionManager( |
| | | RegistryBuilder.<ConnectionSocketFactory>create() |
| | | .register("http", PlainConnectionSocketFactory.getSocketFactory()) |
| | | .register("https", SSLConnectionSocketFactory.getSocketFactory()) |
| | | .build(), |
| | | null, |
| | | null, |
| | | null |
| | | ); |
| | | } |
| | | |
| | | HttpClient httpClient = HttpClientBuilder.create() |
| | | .setConnectionManager(connManager) |
| | | .build(); |
| | | |
| | | String url = "https://" + domain + urlSuffix; |
| | | HttpPost httpPost = new HttpPost(url); |
| | | |
| | | RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(readTimeoutMs).setConnectTimeout(connectTimeoutMs).build(); |
| | | httpPost.setConfig(requestConfig); |
| | | |
| | | StringEntity postEntity = new StringEntity(data, "UTF-8"); |
| | | httpPost.addHeader("Content-Type", "text/xml"); |
| | | httpPost.addHeader("User-Agent", "wxpay sdk java v1.0 " + config.getMchID()); // TODO: 很重要,用来检测 sdk 的使用情况,要不要加上商户信息? |
| | | httpPost.setEntity(postEntity); |
| | | |
| | | HttpResponse httpResponse = httpClient.execute(httpPost); |
| | | HttpEntity httpEntity = httpResponse.getEntity(); |
| | | return EntityUtils.toString(httpEntity, "UTF-8"); |
| | | |
| | | } |
| | | |
| | | |
| | | private String request(String urlSuffix, String uuid, String data, int connectTimeoutMs, int readTimeoutMs, boolean useCert, boolean autoReport) throws Exception { |
| | | Exception exception = null; |
| | | long elapsedTimeMillis = 0; |
| | | long startTimestampMs = WXPayUtil.getCurrentTimestampMs(); |
| | | boolean firstHasDnsErr = false; |
| | | boolean firstHasConnectTimeout = false; |
| | | boolean firstHasReadTimeout = false; |
| | | IWXPayDomain.DomainInfo domainInfo = config.getWXPayDomain().getDomain(config); |
| | | if(domainInfo == null){ |
| | | throw new Exception("WXPayConfig.getWXPayDomain().getDomain() is empty or null"); |
| | | } |
| | | try { |
| | | String result = requestOnce(domainInfo.domain, urlSuffix, uuid, data, connectTimeoutMs, readTimeoutMs, useCert); |
| | | elapsedTimeMillis = WXPayUtil.getCurrentTimestampMs()-startTimestampMs; |
| | | config.getWXPayDomain().report(domainInfo.domain, elapsedTimeMillis, null); |
| | | WXPayReport.getInstance(config).report( |
| | | uuid, |
| | | elapsedTimeMillis, |
| | | domainInfo.domain, |
| | | domainInfo.primaryDomain, |
| | | connectTimeoutMs, |
| | | readTimeoutMs, |
| | | firstHasDnsErr, |
| | | firstHasConnectTimeout, |
| | | firstHasReadTimeout); |
| | | return result; |
| | | } |
| | | catch (UnknownHostException ex) { // dns 解析错误,或域名不存在 |
| | | exception = ex; |
| | | firstHasDnsErr = true; |
| | | elapsedTimeMillis = WXPayUtil.getCurrentTimestampMs()-startTimestampMs; |
| | | WXPayUtil.getLogger().warn("UnknownHostException for domainInfo {}", domainInfo); |
| | | WXPayReport.getInstance(config).report( |
| | | uuid, |
| | | elapsedTimeMillis, |
| | | domainInfo.domain, |
| | | domainInfo.primaryDomain, |
| | | connectTimeoutMs, |
| | | readTimeoutMs, |
| | | firstHasDnsErr, |
| | | firstHasConnectTimeout, |
| | | firstHasReadTimeout |
| | | ); |
| | | } |
| | | catch (ConnectTimeoutException ex) { |
| | | exception = ex; |
| | | firstHasConnectTimeout = true; |
| | | elapsedTimeMillis = WXPayUtil.getCurrentTimestampMs()-startTimestampMs; |
| | | WXPayUtil.getLogger().warn("connect timeout happened for domainInfo {}", domainInfo); |
| | | WXPayReport.getInstance(config).report( |
| | | uuid, |
| | | elapsedTimeMillis, |
| | | domainInfo.domain, |
| | | domainInfo.primaryDomain, |
| | | connectTimeoutMs, |
| | | readTimeoutMs, |
| | | firstHasDnsErr, |
| | | firstHasConnectTimeout, |
| | | firstHasReadTimeout |
| | | ); |
| | | } |
| | | catch (SocketTimeoutException ex) { |
| | | exception = ex; |
| | | firstHasReadTimeout = true; |
| | | elapsedTimeMillis = WXPayUtil.getCurrentTimestampMs()-startTimestampMs; |
| | | WXPayUtil.getLogger().warn("timeout happened for domainInfo {}", domainInfo); |
| | | WXPayReport.getInstance(config).report( |
| | | uuid, |
| | | elapsedTimeMillis, |
| | | domainInfo.domain, |
| | | domainInfo.primaryDomain, |
| | | connectTimeoutMs, |
| | | readTimeoutMs, |
| | | firstHasDnsErr, |
| | | firstHasConnectTimeout, |
| | | firstHasReadTimeout); |
| | | } |
| | | catch (Exception ex) { |
| | | exception = ex; |
| | | elapsedTimeMillis = WXPayUtil.getCurrentTimestampMs()-startTimestampMs; |
| | | WXPayReport.getInstance(config).report( |
| | | uuid, |
| | | elapsedTimeMillis, |
| | | domainInfo.domain, |
| | | domainInfo.primaryDomain, |
| | | connectTimeoutMs, |
| | | readTimeoutMs, |
| | | firstHasDnsErr, |
| | | firstHasConnectTimeout, |
| | | firstHasReadTimeout); |
| | | } |
| | | config.getWXPayDomain().report(domainInfo.domain, elapsedTimeMillis, exception); |
| | | throw exception; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 可重试的,非双向认证的请求 |
| | | * @param urlSuffix |
| | | * @param uuid |
| | | * @param data |
| | | * @return |
| | | */ |
| | | public String requestWithoutCert(String urlSuffix, String uuid, String data, boolean autoReport) throws Exception { |
| | | return this.request(urlSuffix, uuid, data, config.getHttpConnectTimeoutMs(), config.getHttpReadTimeoutMs(), false, autoReport); |
| | | //return requestWithoutCert(urlSuffix, uuid, data, config.getHttpConnectTimeoutMs(), config.getHttpReadTimeoutMs(), autoReport); |
| | | } |
| | | |
| | | /** |
| | | * 可重试的,非双向认证的请求 |
| | | * @param urlSuffix |
| | | * @param uuid |
| | | * @param data |
| | | * @param connectTimeoutMs |
| | | * @param readTimeoutMs |
| | | * @return |
| | | */ |
| | | public String requestWithoutCert(String urlSuffix, String uuid, String data, int connectTimeoutMs, int readTimeoutMs, boolean autoReport) throws Exception { |
| | | return this.request(urlSuffix, uuid, data, connectTimeoutMs, readTimeoutMs, false, autoReport); |
| | | |
| | | /* |
| | | String result; |
| | | Exception exception; |
| | | boolean shouldRetry = false; |
| | | |
| | | boolean useCert = false; |
| | | try { |
| | | result = requestOnce(domain, urlSuffix, uuid, data, connectTimeoutMs, readTimeoutMs, useCert); |
| | | return result; |
| | | } |
| | | catch (UnknownHostException ex) { // dns 解析错误,或域名不存在 |
| | | exception = ex; |
| | | WXPayUtil.getLogger().warn("UnknownHostException for domain {}, try to use {}", domain, this.primaryDomain); |
| | | shouldRetry = true; |
| | | } |
| | | catch (ConnectTimeoutException ex) { |
| | | exception = ex; |
| | | WXPayUtil.getLogger().warn("connect timeout happened for domain {}, try to use {}", domain, this.primaryDomain); |
| | | shouldRetry = true; |
| | | } |
| | | catch (SocketTimeoutException ex) { |
| | | exception = ex; |
| | | shouldRetry = false; |
| | | } |
| | | catch (Exception ex) { |
| | | exception = ex; |
| | | shouldRetry = false; |
| | | } |
| | | |
| | | if (shouldRetry) { |
| | | result = requestOnce(this.primaryDomain, urlSuffix, uuid, data, connectTimeoutMs, readTimeoutMs, useCert); |
| | | return result; |
| | | } |
| | | else { |
| | | throw exception; |
| | | } |
| | | */ |
| | | } |
| | | |
| | | /** |
| | | * 可重试的,双向认证的请求 |
| | | * @param urlSuffix |
| | | * @param uuid |
| | | * @param data |
| | | * @return |
| | | */ |
| | | public String requestWithCert(String urlSuffix, String uuid, String data, boolean autoReport) throws Exception { |
| | | return this.request(urlSuffix, uuid, data, config.getHttpConnectTimeoutMs(), config.getHttpReadTimeoutMs(), true, autoReport); |
| | | //return requestWithCert(urlSuffix, uuid, data, config.getHttpConnectTimeoutMs(), config.getHttpReadTimeoutMs(), autoReport); |
| | | } |
| | | |
| | | /** |
| | | * 可重试的,双向认证的请求 |
| | | * @param urlSuffix |
| | | * @param uuid |
| | | * @param data |
| | | * @param connectTimeoutMs |
| | | * @param readTimeoutMs |
| | | * @return |
| | | */ |
| | | public String requestWithCert(String urlSuffix, String uuid, String data, int connectTimeoutMs, int readTimeoutMs, boolean autoReport) throws Exception { |
| | | return this.request(urlSuffix, uuid, data, connectTimeoutMs, readTimeoutMs, true, autoReport); |
| | | |
| | | /* |
| | | String result; |
| | | Exception exception; |
| | | boolean shouldRetry = false; |
| | | |
| | | boolean useCert = true; |
| | | try { |
| | | result = requestOnce(domain, urlSuffix, uuid, data, connectTimeoutMs, readTimeoutMs, useCert); |
| | | return result; |
| | | } |
| | | catch (ConnectTimeoutException ex) { |
| | | exception = ex; |
| | | WXPayUtil.getLogger().warn(String.format("connect timeout happened for domain {}, try to use {}", domain, this.primaryDomain)); |
| | | shouldRetry = true; |
| | | } |
| | | catch (SocketTimeoutException ex) { |
| | | exception = ex; |
| | | shouldRetry = false; |
| | | } |
| | | catch (Exception ex) { |
| | | exception = ex; |
| | | shouldRetry = false; |
| | | } |
| | | |
| | | if (shouldRetry && this.primaryDomain != null) { |
| | | result = requestOnce(this.primaryDomain, urlSuffix, uuid, data, connectTimeoutMs, readTimeoutMs, useCert, autoReport); |
| | | return result; |
| | | } |
| | | else { |
| | | throw exception; |
| | | } |
| | | */ |
| | | } |
| | | } |
New file |
| | |
| | | package com.ruoyi.order.util.tencent.service; |
| | | import com.ruoyi.order.util.tencent.common.Configure; |
| | | |
| | | import java.io.IOException; |
| | | import java.security.KeyManagementException; |
| | | import java.security.KeyStoreException; |
| | | import java.security.NoSuchAlgorithmException; |
| | | import java.security.UnrecoverableKeyException; |
| | | |
| | | |
| | | |
| | | /** |
| | | * User: rizenguo |
| | | * Date: 2014/12/10 |
| | | * Time: 15:44 |
| | | * 服务的基类 |
| | | */ |
| | | public class BaseService{ |
| | | |
| | | //API的地址 |
| | | private String apiURL; |
| | | |
| | | //发请求的HTTPS请求器 |
| | | private IServiceRequest serviceRequest; |
| | | |
| | | public BaseService(Integer apptype,String api) throws ClassNotFoundException, IllegalAccessException, InstantiationException { |
| | | apiURL = api; |
| | | |
| | | if (apptype.equals(2)) {//微信小程序和公众号的 |
| | | Class<?> c = Class.forName(Configure.HttpsRequestClassName_2); |
| | | serviceRequest = (IServiceRequest) c.newInstance(); |
| | | } else {//微信app的 |
| | | Class<?> c = Class.forName(Configure.HttpsRequestClassName); |
| | | serviceRequest = (IServiceRequest) c.newInstance(); |
| | | } |
| | | } |
| | | |
| | | protected String sendPost(Object xmlObj) throws UnrecoverableKeyException, IOException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException { |
| | | return serviceRequest.sendPost(apiURL, xmlObj); |
| | | } |
| | | |
| | | /** |
| | | * 供商户想自定义自己的HTTP请求器用 |
| | | * @param request 实现了IserviceRequest接口的HttpsRequest |
| | | */ |
| | | public void setServiceRequest(IServiceRequest request){ |
| | | serviceRequest = request; |
| | | } |
| | | } |
New file |
| | |
| | | package com.ruoyi.order.util.tencent.service; |
| | | |
| | | import java.io.IOException; |
| | | import java.security.KeyManagementException; |
| | | import java.security.KeyStoreException; |
| | | import java.security.NoSuchAlgorithmException; |
| | | import java.security.UnrecoverableKeyException; |
| | | |
| | | /** |
| | | * User: rizenguo |
| | | * Date: 2014/12/10 |
| | | * Time: 15:16 |
| | | * 这里定义服务层需要请求器标准接口 |
| | | */ |
| | | public interface IServiceRequest { |
| | | |
| | | //Service依赖的底层https请求器必须实现这么一个接口 |
| | | public String sendPost(String api_url, Object xmlObj) throws UnrecoverableKeyException, KeyManagementException, NoSuchAlgorithmException, KeyStoreException, IOException; |
| | | |
| | | } |
New file |
| | |
| | | /*package com.ruoyi.order.util.tencent.service; |
| | | |
| | | import com.tencent.common.Configure; |
| | | import com.tencent.protocol.PayToTheUserReqData; |
| | | |
| | | |
| | | public class PayToTheUserService extends BaseService{ |
| | | |
| | | public PayToTheUserService(Integer apptype) throws IllegalAccessException, InstantiationException, ClassNotFoundException { |
| | | super(apptype,Configure.PayToTheUser_API); |
| | | } |
| | | |
| | | *//** |
| | | * 请求商户向用户支付 |
| | | * @param refundReqData 这个数据对象里面包含了API要求提交的各种数据字段 |
| | | * @return API返回的XML数据 |
| | | * @throws Exception |
| | | *//* |
| | | public String request(PayToTheUserReqData payToTheUserReqData) throws Exception { |
| | | |
| | | //-------------------------------------------------------------------- |
| | | //发送HTTPS的Post请求到API地址 |
| | | //-------------------------------------------------------------------- |
| | | String responseString = sendPost(payToTheUserReqData); |
| | | |
| | | return responseString; |
| | | } |
| | | |
| | | } |
| | | */ |
New file |
| | |
| | | package com.ruoyi.order.util.tencent.service; |
| | | |
| | | |
| | | import com.ruoyi.order.util.tencent.common.Configure; |
| | | import com.tencent.protocol.RefundReqData; |
| | | |
| | | /** |
| | | * User: rizenguo |
| | | * Date: 2014/10/29 |
| | | * Time: 16:04 |
| | | */ |
| | | public class RefundService extends BaseService{ |
| | | |
| | | public RefundService(Integer apptype) throws IllegalAccessException, InstantiationException, ClassNotFoundException { |
| | | super(apptype, Configure.REFUND_API); |
| | | } |
| | | |
| | | /** |
| | | * 请求退款服务 |
| | | * @param refundReqData 这个数据对象里面包含了API要求提交的各种数据字段 |
| | | * @return API返回的XML数据 |
| | | * @throws Exception |
| | | */ |
| | | public String request(RefundReqData refundReqData) throws Exception { |
| | | |
| | | //-------------------------------------------------------------------- |
| | | //发送HTTPS的Post请求到API地址 |
| | | //-------------------------------------------------------------------- |
| | | String responseString = sendPost(refundReqData); |
| | | |
| | | return responseString; |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.ruoyi.order.util.tencent.service; |
| | | |
| | | |
| | | import com.ruoyi.order.util.tencent.common.Configure; |
| | | import com.ruoyi.order.util.tencent.protocol.UnifiedorderReqData; |
| | | |
| | | /** |
| | | * 统一下单服务 |
| | | * @author pen |
| | | */ |
| | | public class UnifiedorderService extends BaseService{ |
| | | |
| | | public UnifiedorderService(Integer apptype) throws IllegalAccessException, InstantiationException, ClassNotFoundException { |
| | | super(apptype, Configure.UNIFIEDORDER_API); |
| | | } |
| | | |
| | | /** |
| | | * 统一下单服务 |
| | | * @param UnifiedorderReqData 这个数据对象里面包含了API要求提交的各种数据字段 |
| | | */ |
| | | public String request(UnifiedorderReqData unifiedorderReqData) throws Exception { |
| | | |
| | | //-------------------------------------------------------------------- |
| | | //发送HTTPS的Post请求到API地址 |
| | | //-------------------------------------------------------------------- |
| | | String responseString = sendPost(unifiedorderReqData); |
| | | |
| | | return responseString; |
| | | } |
| | | } |
New file |
| | |
| | | package com.ruoyi.order.util.tencent.service; |
| | | |
| | | import com.ruoyi.order.util.tencent.common.IWXPayDomain; |
| | | import com.ruoyi.order.util.tencent.common.WXPayConfig; |
| | | |
| | | import java.io.ByteArrayInputStream; |
| | | import java.io.File; |
| | | import java.io.FileInputStream; |
| | | import java.io.InputStream; |
| | | |
| | | |
| | | |
| | | public class WXPayConfigImpl extends WXPayConfig { |
| | | |
| | | private byte[] certData; |
| | | private static WXPayConfigImpl INSTANCE; |
| | | |
| | | private WXPayConfigImpl() throws Exception{ |
| | | String certPath = WXPayConfigImpl.class.getClassLoader().getResource("").getPath() + "com/tencent/common/cert/apiclient_cert.p12"; |
| | | File file = new File(certPath); |
| | | InputStream certStream = new FileInputStream(file); |
| | | this.certData = new byte[(int) file.length()]; |
| | | certStream.read(this.certData); |
| | | certStream.close(); |
| | | } |
| | | |
| | | public static WXPayConfigImpl getInstance() throws Exception{ |
| | | if (INSTANCE == null) { |
| | | synchronized (WXPayConfigImpl.class) { |
| | | if (INSTANCE == null) { |
| | | INSTANCE = new WXPayConfigImpl(); |
| | | } |
| | | } |
| | | } |
| | | return INSTANCE; |
| | | } |
| | | |
| | | |
| | | public String getMchID() { |
| | | return "11473623"; |
| | | } |
| | | |
| | | public String getKey() { |
| | | return "2ab9071b06b9f739b950ddb41db2690d"; |
| | | } |
| | | |
| | | public InputStream getCertStream() { |
| | | ByteArrayInputStream certBis; |
| | | certBis = new ByteArrayInputStream(this.certData); |
| | | return certBis; |
| | | } |
| | | |
| | | |
| | | public int getHttpConnectTimeoutMs() { |
| | | return 2000; |
| | | } |
| | | |
| | | public int getHttpReadTimeoutMs() { |
| | | return 10000; |
| | | } |
| | | |
| | | public IWXPayDomain getWXPayDomain() { |
| | | return WXPayDomainSimpleImpl.instance(); |
| | | } |
| | | |
| | | public String getPrimaryDomain() { |
| | | return "api.mch.weixin.qq.com"; |
| | | } |
| | | |
| | | public String getAlternateDomain() { |
| | | return "api2.mch.weixin.qq.com"; |
| | | } |
| | | |
| | | @Override |
| | | public int getReportWorkerNum() { |
| | | return 1; |
| | | } |
| | | |
| | | @Override |
| | | public int getReportBatchSize() { |
| | | return 2; |
| | | } |
| | | |
| | | @Override |
| | | public String getAppID() { |
| | | // TODO Auto-generated method stub |
| | | return null; |
| | | } |
| | | } |
New file |
| | |
| | | package com.ruoyi.order.util.tencent.service; |
| | | import com.ruoyi.order.util.tencent.common.IWXPayDomain; |
| | | import com.ruoyi.order.util.tencent.common.WXPayConfig; |
| | | import com.ruoyi.order.util.tencent.common.WXPayConstants; |
| | | import org.apache.http.conn.ConnectTimeoutException; |
| | | |
| | | |
| | | |
| | | import java.net.UnknownHostException; |
| | | import java.util.HashMap; |
| | | import java.util.Map; |
| | | |
| | | /** |
| | | * Created by blaketang on 2017/6/16. |
| | | */ |
| | | public class WXPayDomainSimpleImpl implements IWXPayDomain { |
| | | private WXPayDomainSimpleImpl(){} |
| | | private static class WxpayDomainHolder{ |
| | | private static IWXPayDomain holder = new WXPayDomainSimpleImpl(); |
| | | } |
| | | public static IWXPayDomain instance(){ |
| | | return WxpayDomainHolder.holder; |
| | | } |
| | | |
| | | public synchronized void report(final String domain, long elapsedTimeMillis, final Exception ex) { |
| | | DomainStatics info = domainData.get(domain); |
| | | if(info == null){ |
| | | info = new DomainStatics(domain); |
| | | domainData.put(domain, info); |
| | | } |
| | | |
| | | if(ex == null){ //success |
| | | if(info.succCount >= 2){ //continue succ, clear error count |
| | | info.connectTimeoutCount = info.dnsErrorCount = info.otherErrorCount = 0; |
| | | }else{ |
| | | ++info.succCount; |
| | | } |
| | | }else if(ex instanceof ConnectTimeoutException){ |
| | | info.succCount = info.dnsErrorCount = 0; |
| | | ++info.connectTimeoutCount; |
| | | }else if(ex instanceof UnknownHostException){ |
| | | info.succCount = 0; |
| | | ++info.dnsErrorCount; |
| | | }else{ |
| | | info.succCount = 0; |
| | | ++info.otherErrorCount; |
| | | } |
| | | } |
| | | |
| | | public synchronized DomainInfo getDomain(final WXPayConfig config) { |
| | | DomainStatics primaryDomain = domainData.get(WXPayConstants.DOMAIN_API); |
| | | if(primaryDomain == null || |
| | | primaryDomain.isGood()) { |
| | | return new DomainInfo(WXPayConstants.DOMAIN_API, true); |
| | | } |
| | | |
| | | long now = System.currentTimeMillis(); |
| | | if(switchToAlternateDomainTime == 0){ //first switch |
| | | switchToAlternateDomainTime = now; |
| | | return new DomainInfo(WXPayConstants.DOMAIN_API2, false); |
| | | }else if(now - switchToAlternateDomainTime < MIN_SWITCH_PRIMARY_MSEC){ |
| | | DomainStatics alternateDomain = domainData.get(WXPayConstants.DOMAIN_API2); |
| | | if(alternateDomain == null || |
| | | alternateDomain.isGood() || |
| | | alternateDomain.badCount() < primaryDomain.badCount()){ |
| | | return new DomainInfo(WXPayConstants.DOMAIN_API2, false); |
| | | }else{ |
| | | return new DomainInfo(WXPayConstants.DOMAIN_API, true); |
| | | } |
| | | }else{ //force switch back |
| | | switchToAlternateDomainTime = 0; |
| | | primaryDomain.resetCount(); |
| | | DomainStatics alternateDomain = domainData.get(WXPayConstants.DOMAIN_API2); |
| | | if(alternateDomain != null) |
| | | alternateDomain.resetCount(); |
| | | return new DomainInfo(WXPayConstants.DOMAIN_API, true); |
| | | } |
| | | } |
| | | |
| | | static class DomainStatics { |
| | | final String domain; |
| | | int succCount = 0; |
| | | int connectTimeoutCount = 0; |
| | | int dnsErrorCount =0; |
| | | int otherErrorCount = 0; |
| | | |
| | | DomainStatics(String domain) { |
| | | this.domain = domain; |
| | | } |
| | | void resetCount(){ |
| | | succCount = connectTimeoutCount = dnsErrorCount = otherErrorCount = 0; |
| | | } |
| | | boolean isGood(){ return connectTimeoutCount <= 2 && dnsErrorCount <= 2; } |
| | | int badCount(){ |
| | | return connectTimeoutCount + dnsErrorCount * 5 + otherErrorCount / 4; |
| | | } |
| | | } |
| | | private final int MIN_SWITCH_PRIMARY_MSEC = 3 * 60 * 1000; //3 minutes |
| | | private long switchToAlternateDomainTime = 0; |
| | | private Map<String, DomainStatics> domainData = new HashMap<String, DomainStatics>(); |
| | | } |
New file |
| | |
| | | /*package com.ruoyi.order.util.tencent.service; |
| | | |
| | | import java.util.HashMap; |
| | | import java.util.Map; |
| | | |
| | | import com.tencent.WXPay; |
| | | import com.tencent.common.WXPayUtil; |
| | | |
| | | public class WXPayPerformance { |
| | | |
| | | |
| | | private WXPay wxpay; |
| | | private WXPayConfigImpl config; |
| | | |
| | | public WXPayPerformance() throws Exception { |
| | | config = WXPayConfigImpl.getInstance(); |
| | | wxpay = new WXPay(config); |
| | | } |
| | | |
| | | *//** |
| | | * 商户 扫码抢 扫码支付 |
| | | * @param out_trade_no |
| | | * @param body |
| | | * @param total_fee |
| | | * @param auth_code |
| | | *//* |
| | | public Map<String, String> doMicropayWithPos(String out_trade_no,String body,String total_fee,String auth_code) { |
| | | HashMap<String, String> data = new HashMap<String, String>(); |
| | | data.put("out_trade_no", out_trade_no); |
| | | data.put("body", body); |
| | | data.put("total_fee", total_fee); |
| | | data.put("auth_code", auth_code); |
| | | Map<String, String> r=new HashMap<>(); |
| | | try { |
| | | r = wxpay.microPayWithPos(data); |
| | | System.out.println(r); |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | return r; |
| | | } |
| | | return r; |
| | | } |
| | | |
| | | |
| | | *//** |
| | | * 统一 下单2.0 |
| | | *//* |
| | | public Map<String, String> doUnifiedOrder(String out_trade_no,String total_fee,String notify_url) { |
| | | HashMap<String, String> data = new HashMap<String, String>(); |
| | | data.put("body", "超级教材"); |
| | | data.put("out_trade_no", out_trade_no); |
| | | data.put("device_info", ""); |
| | | data.put("fee_type", "CNY"); |
| | | data.put("total_fee", total_fee); |
| | | //data.put("spbill_create_ip", "123.12.12.123"); |
| | | data.put("notify_url", notify_url); |
| | | data.put("trade_type", "APP"); |
| | | //data.put("product_id", "12"); |
| | | // data.put("time_expire", "20170112104120"); |
| | | |
| | | try { |
| | | Map<String, String> r = wxpay.unifiedOrder(data); |
| | | System.out.println(r); |
| | | return r; |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | return null; |
| | | } |
| | | } |
| | | |
| | | |
| | | // public void doReport() { |
| | | // HashMap<String, String> data = new HashMap<String, String>(); |
| | | // data.put("interface_url", "20160822"); |
| | | // data.put("bill_type", "ALL"); |
| | | // } |
| | | |
| | | *//** |
| | | * 小测试 |
| | | *//* |
| | | public void test001() { |
| | | String xmlStr="<xml><return_code><![CDATA[SUCCESS]]></return_code>\n" + |
| | | "<return_msg><![CDATA[OK]]></return_msg>\n" + |
| | | "<appid><![CDATA[wx273fe72f2db863ed]]></appid>\n" + |
| | | "<mch_id><![CDATA[1228845802]]></mch_id>\n" + |
| | | "<nonce_str><![CDATA[lCXjx3wNx45HfTV2]]></nonce_str>\n" + |
| | | "<sign><![CDATA[68D7573E006F0661FD2A77BA59124E87]]></sign>\n" + |
| | | "<result_code><![CDATA[SUCCESS]]></result_code>\n" + |
| | | "<openid><![CDATA[oZyc_uPx_oed7b4q1yKmj_3M2fTU]]></openid>\n" + |
| | | "<is_subscribe><![CDATA[N]]></is_subscribe>\n" + |
| | | "<trade_type><![CDATA[NATIVE]]></trade_type>\n" + |
| | | "<bank_type><![CDATA[CFT]]></bank_type>\n" + |
| | | "<total_fee>1</total_fee>\n" + |
| | | "<fee_type><![CDATA[CNY]]></fee_type>\n" + |
| | | "<transaction_id><![CDATA[4008852001201608221983528929]]></transaction_id>\n" + |
| | | "<out_trade_no><![CDATA[20160822162018]]></out_trade_no>\n" + |
| | | "<attach><![CDATA[]]></attach>\n" + |
| | | "<time_end><![CDATA[20160822202556]]></time_end>\n" + |
| | | "<trade_state><![CDATA[SUCCESS]]></trade_state>\n" + |
| | | "<cash_fee>1</cash_fee>\n" + |
| | | "</xml>"; |
| | | try { |
| | | System.out.println(xmlStr); |
| | | System.out.println("+++++++++++++++++"); |
| | | System.out.println(WXPayUtil.isSignatureValid(xmlStr, config.getKey())); |
| | | Map<String, String> hm = WXPayUtil.xmlToMap(xmlStr); |
| | | System.out.println("+++++++++++++++++"); |
| | | System.out.println(hm); |
| | | System.out.println(hm.get("attach").length()); |
| | | |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | } |
| | | |
| | | } |
| | | |
| | | public void testHelloWorld() throws Exception { |
| | | for (int i=0; i<1000; ++i) { |
| | | System.out.println("hi"); |
| | | Thread.sleep(1000); |
| | | } |
| | | } |
| | | |
| | | |
| | | public static void main(String[] args) throws Exception { |
| | | //测试商户扫码支付 |
| | | WXPayPerformance dodo = new WXPayPerformance(); |
| | | Map<String, String> r =dodo.doMicropayWithPos("11151521","测试","1","130226992988325162"); |
| | | if(r.isEmpty()){ |
| | | System.out.println("--------------->"); |
| | | }else{ |
| | | if(r.containsKey("err_code_des")){ |
| | | System.out.println("支付失败:"+r.get("err_code_des")); |
| | | }else{ |
| | | if(r.get("return_msg").equals("OK")){ |
| | | System.out.println("支付成功:"+r.get("err_code_des")); |
| | | } |
| | | } |
| | | } |
| | | //测试app支付 |
| | | WXPayPerformance dodo1 = new WXPayPerformance(); |
| | | dodo1.doUnifiedOrder("12121", "1", "http://192.168.1.90:8080/textbook/app/pay/wxpay/notify"); |
| | | |
| | | } |
| | | } |
| | | |
| | | |
| | | */ |