写点什么

Day435&436

  • 2022 年 5 月 01 日
  • 本文字数:8701 字

    阅读完需:约 29 分钟

// 支付宝公钥,查看地址:https://openhome.alipay.com/platform/keyManage.htm 对应 APPID 下的支付宝公钥。


public String alipay_public_key;


// 服务器[异步通知]页面路径 需 http://格式的完整路径,不能加?id=123 这类自定义参数,必须外网可以正常访问


// 支付成功后,支付宝会悄悄的给我们发送一个请求,告诉我们支付成功的信息


public String notify_url;


// 页面跳转同步通知页面路径 需 http://格式的完整路径,不能加?id=123 这类自定义参数,必须外网可以正常访问


//同步通知,支付成功,一般跳转到成功页


public String return_url;


// 签名方式


private String sign_type;


// 字符编码格式


private String charset;


//订单超时时间


private String timeout = "1m";


// 支付宝网关; https://openapi.alipaydev.com/gateway.do


public String gatewayUrl;


public String pay(PayVo vo) throws AlipayApiException {


//AlipayClient alipayClient = new DefaultAlipayClient(AlipayTemplate.gatewayUrl, AlipayTemplate.app_id, AlipayTemplate.merchant_private_key, "json", AlipayTemplate.charset, AlipayTemplate.alipay_public_key, AlipayTemplate.sign_type);


//1、根据支付宝的配置生成一个支付客户端


AlipayClient alipayClient = new DefaultAlipayClient(gatewayUrl,


app_id, merchant_private_key, "json",


charset, alipay_public_key, sign_type);


//2、创建一个支付请求 //设置请求参数


AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();


alipayRequest.setReturnUrl(return_url);


alipayRequest.setNotifyUrl(notify_url);


//商户订单号,商户网站订单系统中唯一订单号,必填


String out_trade_no = vo.getOut_trade_no();


//付款金额,必填


String total_amount = vo.getTotal_amount();


//订单名称,必填


String subject = vo.getSubject();


//商品描述,可空


String body = vo.getBody();


alipayRequest.setBizContent("{"out_trade_no":""+ out_trade_no +"","


  • ""total_amount":""+ total_amount +"","

  • ""subject":""+ subject +"","

  • ""body":""+ body +"","

  • ""timeout_express":""+timeout+"","

  • ""product_code":"FAST_INSTANT_TRADE_PAY"}");


String result = alipayClient.pageExecute(alipayRequest).getBody();


//会收到支付宝的响应,响应的是一个页面,只要浏览器显示这个页面,就会自动来到支付宝的收银台页面


System.out.println("支付宝的响应:"+result);


return result;


}


}


  • com.achang.achangmall.order.service.impl.OrderServiceImpl


@Override


public PayVo getOrderPay(String orderSn) {


PayVo payVo = new PayVo();


OrderEntity orderInfo = this.getOrderByOrderSn(orderSn);


//保留两位小数点,向上取值


BigDecimal payAmount = orderInfo.getPayAmount().setScale(2, BigDecimal.ROUND_UP);


payVo.setTotal_amount(payAmount.toString());


payVo.setOut_trade_no(orderInfo.getOrderSn());


//查询订单项的数据


List<OrderItemEntity> orderItemInfo = orderItemService.list(


new QueryWrapper<OrderItemEntity>().eq("order_sn", orderSn));


OrderItemEntity orderItemEntity = orderItemInfo.get(0);


payVo.setBody(orderItemEntity.getSkuAttrsVals());


payVo.setSubject(orderItemEntity.getSkuName());


return payVo;


}


  • com.achang.achangmall.order.web.PayWebController


/**


  • 用户下单:支付宝支付

  • 1、让支付页让浏览器展示

  • 2、支付成功以后,跳转到用户的订单列表页


*/


@ResponseBody


@GetMapping(value = "/aliPayOrder",produces = "text/html")


public String aliPayOrder(@RequestParam("orderSn") String orderSn) throws AlipayApiException {


PayVo payVo = orderService.getOrderPay(orderSn);//根据订单号获取订单信息


String pay = alipayTemplate.pay(payVo);


System.out.println(pay);


return pay;


}


  • achangmall-order/src/main/resources/application.properties


#支付宝相关的配置


#支付宝商户的 appid


alipay.app_id=2016102600766009


#我们的商家私钥


alipay.merchant_private_key=MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCvZQ2XJ0kDOq4WiBoy2LCdgTdb5SMan7sFZtStjFmsqxoZuUd8ntuPikcZKXAAZcNcXDc99Ltkt+i2fMdzvg1Ung0cwKX6wqyBLU10lkMOUMs4hVl0MhW3Ihx8D9+kZIEg1yAbxuUrF8cV81Or+qxpnJ4iwNVwkOPrUOp0n8HTpVX1mjYYjkXhM/LtvVZ+IFc4yq+tVY0tTgsVPYcCtaKoYUzhSmncgkpjdMjthy4eTSje/hDMgnLFUsDs0cfdWLN8pVTxxiipr+Y/+Ax3mCfyBEtFuYn0OXKXXjHEp+WX/iQ6yqTdyhcYkxGWD4jIqP+g7mMrP7vKsbkquQOzxayTAgMBAAECggEACmL4mA/qg 《一线大厂 Java 面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》无偿开源 威信搜索公众号【编程进阶路】 fdyocDzlDlC1ED3r0h1eLkm0R4S0Cg0k0YaqJVRR27835Y3uaS7jjp4hDqtxsx8YG2HqW7gPNlvXqhxbFd4PM5Uet3c7V+Mnwdn0XQMJRZmNM8fUrV57/lHsFMtApgXsCKbVpBvTwrsNODieHpk6WKbLK9BAyEG0Gqrv1xCTD55NDyr+mdKXINt5ZDaP8R2DeNrXrTrU7+qGsM7Qfsz8429egEZx/1LnCA7PeMRZvHsSex9KZtpaXYHFGMqgSAH93yKj+rW685+KwmGSK4q0ezfGtQR7V1T6r71inwR5dQzWyTyN1ZJw0ZVWroFgwUAOUvllN/ptkmKUQKBgQD0VpJvyIbRt3J2iyYnswB/tQMk5meqBuxN1oK9tirXBTyyqZaoTtk+Z49vqhSIU0yezW81htiuF5A/gepx2v4/IqtSqCKSyxqBfFwbxONuky9gHdM+I1XyazmtSbJz8vR9U/88O60Wm1vhIe+61tWh1eWIJ7IxhA11AswfhOYMuwKBgQC3xBnOECBsh9OLnhIm9PVVxF+IGQFshsmc6kdZlKO9KdDlEiOh+TMJwhMkBqAfRJTMaz8WxPL4met2ZUJL/cXfHgAmjDnGlN69lc4ELikEd3S5aB4AWVG4ybcaHsrhLqS16WSMU1kD9l5Y3q+pbiiMW8wWpCMxVstj1T3rn6cOCQKBgE0Wx0rXZJnkHAwEqPwbgMvKC3zn6Mr/Niz0wfki8W83qsffs7XUcrw6pkmfyqycQ29S94RW0CRVMOCol5RmeJLo2E7S112jEPDLkK/+NZdcfrT/k/dl5KcAZ4kh2Fi2zaaBCuUxGtIoIBvuvhkf0PUnbCzCAXmX5TsGr+o93usjAoGBAKZtEhW+Iy9HX73tPXFMnbe8LeybAOAhvgu/XTjy1cumSEp9QAocHy3yNtWErpVCziPH6Q4c9hNRip7iG8WoogBsMiS3EEgZYRR/zGGa0Ij8CpkzgyA7xDg/bvVX99MyI/ef1PEFNvPQtydzHdGrM0vSgyXqJvkzKuZSJE71exzJAoGAQcSJ+EtdoZpqe7bjNZ2IpgSCmE0ErYFVMT6IW95VcEXOciRhEYG3TQKYuhm0ZRN+D4DfZdL8vRRQ2YDMrK14UUXzp6TBI+yirTDfbK6LYpuOZqjcvxVFwF4tdI7/K7blNY4fbhApO/Nx5tUd8duErIznnDbFVBlBjl0JWYQdrN0=


#支付宝公钥


alipay.alipay_public_key=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3/IpQAsmsxozQkhGNY7aSrEtDQHjuNdhX9Z/zrZ+3aSC1gK2LS3EYXzzwFoDXMHRcTZajVqYPqKTnHWzx4lXDqJs8UlfcbSnJHEPVCGXqXl04WE9PXtcxicwNEUuDh6EeQu9GnOoBYQQiueKVK9NUdAr3UJyQF4eA45LCG0ZGNTHfqSJeLPzOcrcZglHY7NYXudxA8K7Xht1oA9laRFPmYgUNg9HuypGt1AwgOcDi9nrf1xrjeOTrPzKwLHoHp3fSTkm3GiAQZzwvkXDsK5Z99SinMyxgRze+ePiWmD01ArZXx+HNM5ZQw5dD+TLWO5qct4Yj16tE4GGCGfscfSJDwIDAQAB


#支持成功后支付宝回调我们的地址


alipay.notify_url=http://hjl.mynatapp.cc/payed/notify


#支付成功后跳转页面


alipay.return_url=http://member.achangmall.com/memberOrder.html


#加密协议


alipay.sign_type=RSA2


#编码字符


alipay.charset=utf-8


#支付宝的网关


alipay.gatewayUrl=https://openapi.alipaydev.com/gateway.do


↑支付宝整合的内容↑




  • achangmall-member/src/main/resources/templates/orderList.html


支付成功后的用户系统回调页面



  • achangmall-member/pom.xml


<dependency>


<groupId>org.springframework.boot</groupId>


<artifactId>spring-boot-starter-thymeleaf</artifactId>


</dependency>


<dependency>


<groupId>org.springframework.boot</groupId>


<artifactId>spring-boot-starter-data-redis</artifactId>


<exclusions>


<exclusion>


<groupId>io.lettuce</groupId>


<artifactId>lettuce-core</artifactId>


</exclusion>


</exclusions>


</dependency>


<dependency>


<groupId>redis.clients</groupId>


<artifactId>jedis</artifactId>


</dependency>


<dependency>


<groupId>org.springframework.session</groupId>


<artifactId>spring-session-data-redis</artifactId>


</dependency>


  • com.achang.achangmall.member.feign.OrderFeignService


@FeignClient("achangmall-order")


public interface OrderFeignService {


/**


  • 分页查询当前登录用户的所有订单信息


*/


@PostMapping("/order/order/listWithItem")


R listWithItem(@RequestBody Map<String, Object> params);


}


  • com.achang.achangmall.member.web.MemberWebController



@Controller


public class MemberWebController {


@Autowired


private OrderFeignService orderFeignService;


@GetMapping(value = "/memberOrder.html")


public String memberOrderPage(@RequestParam(value = "pageNum",required = false,defaultValue = "0") Integer pageNum,


Model model, HttpServletRequest request) {


//获取到支付宝给我们转来的所有请求数据


//request,验证签名


//查出当前登录用户的所有订单列表数据


Map<String,Object> page = new HashMap<>();


page.put("page",pageNum.toString());


//远程查询订单服务订单数据


R orderInfo = orderFeignService.listWithItem(page);


System.out.println(JSON.toJSONString(orderInfo));


model.addAttribute("orders",orderInfo);


return "orderList";


}


}


  • com.achang.achangmall.order.controller.OrderController


/**


  • 分页查询当前登录用户的所有订单信息


*/


@PostMapping("/listWithItem")


//@RequiresPermissions("order:order:list")


public R listWithItem(@RequestBody Map<String, Object> params){


PageUtils page = orderService.queryPageWithItem(params);


return R.ok().put("page", page);


}


  • com.achang.achangmall.order.service.impl.OrderServiceImpl


@Override


public PageUtils queryPageWithItem(Map<String, Object> params) {


MemberResponseVo memberResponseVo = LoginUserInterceptor.loginUser.get();


IPage<OrderEntity> page = this.page(


new Query<OrderEntity>().getPage(params),


new QueryWrapper<OrderEntity>()


.eq("member_id",memberResponseVo.getId()).orderByDesc("create_time")


);


//遍历所有订单集合


List<OrderEntity> orderEntityList = page.getRecords().stream().map(order -> {


//根据订单号查询订单项里的数据


List<OrderItemEntity> orderItemEntities = orderItemService.list(new QueryWrapper<OrderItemEntity>()


.eq("order_sn", order.getOrderSn()));


order.setOrderItemEntityList(orderItemEntities);


return order;


}).collect(Collectors.toList());


page.setRecords(orderEntityList);


return new PageUtils(page);


}


  • achangmall-gateway/src/main/resources/application.yml


网关配置


  • id: member_route


uri: lb://achangmall-member


predicates:


  • Host=member.achangmall.com


  • 本地域名映射


C:\Windows\System32\drivers\etc\hosts



  • com.achang.achangmall.member.web.MemberWebController


@Controller


public class MemberWebController {


@Autowired


private OrderFeignService orderFeignService;


@GetMapping(value = "/memberOrder.html")


public String memberOrderPage(@RequestParam(value = "pageNum",required = false,defaultValue = "0") Integer pageNum,


Model model, HttpServletRequest request) {


//获取到支付宝给我们转来的所有请求数据


//request,验证签名


//查出当前登录用户的所有订单列表数据


Map<String,Object> page = new HashMap<>();


page.put("page",pageNum.toString());


//远程查询订单服务订单数据


R orderInfo = orderFeignService.listWithItem(page);


System.out.println(JSON.toJSONString(orderInfo));


model.addAttribute("orders",orderInfo);


return "orderList";


}


}


  • com.achang.achangmall.member.interceptor.LoginUserInterceptor


@Component


public class LoginUserInterceptor implements HandlerInterceptor {


public static ThreadLocal<MemberResponseVo> loginUser = new ThreadLocal<>();


@Override


public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {


String uri = request.getRequestURI();


boolean match = new AntPathMatcher().match("/member/**", uri);


if (match) {


return true;


}


HttpSession session = request.getSession();


//获取登录的用户信息


MemberResponseVo attribute = (MemberResponseVo) session.getAttribute(LOGIN_USER);


if (attribute != null) {


//把登录后用户的信息放在 ThreadLocal 里面进行保存


loginUser.set(attribute);


return true;


} else {


//未登录,返回登录页面


response.setContentType("text/html;charset=UTF-8");


PrintWriter out = response.getWriter();


out.println("<script>alert('请先进行登录,再进行后续操作!');location.href='http://auth.achangmall.com/login.html'</script>");


// session.setAttribute("msg", "请先进行登录");


// response.sendRedirect("http://auth.achangmall.com/login.html");


return false;


}


}


}


  • com.achang.achangmall.member.config.MemberWebConfig


@Configuration


public class MemberWebConfig implements WebMvcConfigurer {


@Autowired


private LoginUserInterceptor loginUserInterceptor;


@Override


public void addInterceptors(InterceptorRegistry registry) {


registry.addInterceptor(loginUserInterceptor).addPathPatterns("/**");


}


}


  • com.achang.achangmall.member.config.AchangmallFeignConfig


页面跳转请求拦截器,给 feign 远程调用的页面 cookie 加上信息


@Configuration


public class AchangmallFeignConfig {


@Bean("requestInterceptor")


public RequestInterceptor requestInterceptor() {


RequestInterceptor requestInterceptor = new RequestInterceptor() {


@Override


public void apply(RequestTemplate template) {


//1、使用 RequestContextHolder 拿到刚进来的请求数据


ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();


if (requestAttributes != null) {


//老请求


HttpServletRequest request = requestAttributes.getRequest();


if (request != null) {


//2、同步请求头的数据(主要是 cookie)


//把老请求的 cookie 值放到新请求上来,进行一个同步


String cookie = request.getHeader("Cookie");


template.header("Cookie", cookie);


}


}


}


};


return requestInterceptor;


}


}



[](()2、内网穿透联调


  • nginx 配置


因为访问外网域名会丢失请求头,所以我们根据地址直接指定转发给队友的服务



server {


listen 80;


server_name achangmall.com *.achangmall.com hjl.mynatapp.cc;


#charset koi8-r;


#access_log /var/log/nginx/log/host.access.log main;


location /payed {


proxy_set_header Host order.achangmall.com;


proxy_pass http://achangmall;


}


  • com.achang.achangmall.order.interceptor.LoginUserInterceptor


//用户登录拦截器


@Component


public class LoginUserInterceptor implements HandlerInterceptor {


public static ThreadLocal<MemberResponseVo> loginUser = new ThreadLocal<>();


@Override


public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {


String uri = request.getRequestURI();


AntPathMatcher antPathMatcher = new AntPathMatcher();


boolean match = antPathMatcher.match("/order/order/status/**", uri);


boolean match1 = antPathMatcher.match("/payed/notify", uri);


if (match || match1) {


return true;


}


//获取登录的用户信息


MemberResponseVo attribute = (MemberResponseVo) request.getSession().getAttribute(LOGIN_USER);


if (attribute != null) {


//把登录后用户的信息放在 ThreadLocal 里面进行保存


loginUser.set(attribute);


return true;


} else {


//未登录,返回登录页面


response.setContentType("text/html;charset=UTF-8");


PrintWriter out = response.getWriter();


out.println("<script>alert('请先进行登录,再进行后续操作!');location.href='http://auth.achangmall.com/login.html'</script>");


// session.setAttribute("msg", "请先进行登录");


// response.sendRedirect("http://auth.gulimall.com/login.html");


return false;


}


}


}


  • com.achang.achangmall.order.listener.OrderCloseListener


/**


  • @Description: 定时关闭订单


**/


@RabbitListener(queues = "order.release.order.queue")


@Service


public class OrderCloseListener {


@Autowired


private OrderService orderService;


@RabbitHandler


public void listener(OrderEntity orderEntity, Channel channel, Message message) throws IOException {


System.out.println("收到过期的订单信息,准备关闭订单" + orderEntity.getOrderSn());


try {


orderService.closeOrder(orderEntity);


channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);


} catch (Exception e) {


channel.basicReject(message.getMessageProperties().getDeliveryTag(),true);


}


}


}


  • com.achang.achangmall.order.listener.OrderPayedListener


/**


  • @Description: 订单支付成功监听器


**/


@RestController


public class OrderPayedListener {


@Autowired


private OrderService orderService;


@Autowired


private AlipayTemplate alipayTemplate;


@PostMapping(value = "/payed/notify")


public String handleAlipayed(PayAsyncVo asyncVo, HttpServletRequest request) throws AlipayApiException, UnsupportedEncodingException {


// 只要收到支付宝的异步通知,返回 success 支付宝便不再通知


// 获取支付宝 POST 过来反馈信息


//TODO 需要验签


Map<String, String> params = new HashMap<>();


Map<String, String[]> requestParams = request.getParameterMap();


for (String name : requestParams.keySet()) {


String[] values = requestParams.get(name);


String valueStr = "";


for (int i = 0; i < values.length; i++) {


valueStr = (i == values.length - 1) ? valueStr + values[i]


: valueStr + values[i] + ",";


}


//乱码解决,这段代码在出现乱码时使用


// valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");


params.put(name, valueStr);


}


boolean signVerified = AlipaySignature.rsaCheckV1(params, alipayTemplate.getAlipay_public_key(),


alipayTemplate.getCharset(), alipayTemplate.getSign_type()); //调用 SDK 验证签名


if (signVerified) {


System.out.println("签名验证成功...");


//去修改订单状态


String result = orderService.handlePayResult(asyncVo);


return result;


} else {


System.out.println("签名验证失败...");


return "error";


}


}


@PostMapping(value = "/pay/notify")


public String asyncNotify(@RequestBody String notifyData) {


//异步通知结果


return orderService.asyncNotify(notifyData);


}


}


  • com.achang.achangmall.order.service.impl.OrderServiceImpl


/**


  • 处理支付宝的支付结果


*/


@Transactional(rollbackFor = Exception.class)


@Override


public String handlePayResult(PayAsyncVo asyncVo) {


//保存交易流水信息


PaymentInfoEntity paymentInfo = new PaymentInfoEntity();


paymentInfo.setOrderSn(asyncVo.getOut_trade_no());


paymentInfo.setAlipayTradeNo(asyncVo.getTrade_no());


paymentInfo.setTotalAmount(new BigDecimal(asyncVo.getBuyer_pay_amount()));


paymentInfo.setSubject(asyncVo.getBody());


paymentInfo.setPaymentStatus(asyncVo.getTrade_status());


paymentInfo.setCreateTime(new Date());


paymentInfo.setCallbackTime(asyncVo.getNotify_time());


//添加到数据库中


this.paymentInfoService.save(paymentInfo);


//修改订单状态


//获取当前状态


String tradeStatus = asyncVo.getTrade_status();


if (tradeStatus.equals("TRADE_SUCCESS") || tradeStatus.equals("TRADE_FINISHED")) {


//支付成功状态


String orderSn = asyncVo.getOut_trade_no(); //获取订单号


this.updateOrderStatus(orderSn,OrderStatusEnum.PAYED.getCode(),PayConstant.ALIPAY);


}


return "success";


}


  • com.achang.achangmall.order.vo.PayAsyncVo


@ToString


@Data


public class PayAsyncVo {


private String gmt_create;


private String charset;


private String gmt_payment;


private Date notify_time;


private String subject;


private String sign;


private String buyer_id;//支付者的 id


private String body;//订单的信息


private String invoice_amount;//支付金额


private String version;


private String notify_id;//通知 id


private String fund_bill_list;


private String notify_type;//通知类型; trade_status_sync


private String out_trade_no;//订单号


private String total_amount;//支付的总额


private String trade_status;//交易状态 TRADE_SUCCESS


private String trade_no;//流水号


private String auth_app_id;//


private String receipt_amount;//商家收到的款


private String point_amount;//


private String app_id;//应用 id


private String buyer_pay_amount;//最终支付的金额


private String sign_type;//签名类型


private String seller_id;//商家的 id


}


  • com.achang.achangmall.order.constant.PayConstant


public class PayConstant {

用户头像

还未添加个人签名 2022.04.13 加入

还未添加个人简介

评论

发布
暂无评论
Day435&436_Java_爱好编程进阶_InfoQ写作社区