前言

本系列博客基于B站谷粒商城,只作为本人学习总结使用。这里我会比较注重业务逻辑的编写和相关配置的流程。有问题可以评论或者联系我互相交流。原视频地址谷粒商城雷丰阳版。本人git仓库地址Draknessssw的谷粒商城


示例文档


两种加密方式



相关概念

私钥,公钥

私钥适合加密数据,公钥适合明文传输数据。

加密和数字签名

验证签名


设置沙箱环境

在支付宝开放平台助手上生成密钥

公钥复制到沙箱环境生成支付宝的公钥

至此,支付宝支付配置了支付宝公钥和自己的私钥

package com.xxxx.gulimall.order.config;import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.xxxx.gulimall.order.vo.PayVo;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;@ConfigurationProperties(prefix = "alipay")
@Component
@Data
public class AlipayTemplate {// 应用ID,您的APPID,收款账号既是您的APPID对应支付宝账号public String app_id;// 商户私钥,您的PKCS8格式RSA2私钥public String merchant_private_key;// 支付宝公钥,查看地址: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.dopublic 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;}
}

内网穿透

设置支付宝异步回调页面

五种内网穿透方案

沙箱环境中也要进行配置


最后是properties文件中的配置
公钥和私钥按照自己的来吧

alipay.app_id=2021000121642435
alipay.merchant_private_key=MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCLjwJ0VNa8I5N8jVhY6Y3+rSrJLlyLcIxbQKY/nQMkDm2D7pbarVbQ5+kTP6uI50BBKMVAV6SenjNbdRNSC18Ynbqns/vWp4NjvG1c4R6zC5tkwqA3HkHtaGX9awl15qaK8W5vLO9qczuFA+s2Syk5KkEs4IW8cF93Mkb4cxAoU6j/3XONzHShWOrGyF1vbQyRpvADL0U+EUTvAhvkPfhbl/FdvB9ng6c3PnLm6D8Gsq6zDBiCnsx6esY7hX7iUpfI3BVBG39BfIjQWz/GBRWADvCKeJnbr+gxPzIF+P+8h2mcrVZHQ5wTwru5DzO9mxacd/K6bbvj0L69SxKRLpg/AgMBAAECggEAf0T94gT0h0KSX8WuyfbD7XsSR8Gl1+vds+IzOlP/50PZD7XnkKj/QSgc39byobjyWfnKWLEUiSqQf1k3M1z3bkV5UTLL+aduJOhTe545FuMA5VSwM1O+n7jTOdYBHKopOxCNu4lpFNTddKJsQGkuwNkN8tUWYRDBnrwVCMI1++9g+IsEcBEEph8Uj4LIrJnH7+d1+azmy+Vl+qqd94ZraK972rysz2w0+sa8IXu7vmpLMymQayF58P01rFG+OsBb/YMK7kOwRTNjveTFcY7R7TXPz8gsW1PjtnssUw0EUgOGUpqd5S+LOnKUc6aWuZ8NK9r7QlqRkR1RUbR46fyR0QKBgQDivRlK8MEGmk3r+iltBnnXK/zkPsNeaCcODdDiB4/hL7MBdOenGBQuaZo+HDLNiXNvFkO5KIJ/2ljNKQlkZWqZFv6oVVM6Y2AgL6/C3KQj1YDRj/sDplg/5DK+kfw4qZt6sASVBkXetaj8N9KhUTuMJ6tDTisDsFSrzzFReLnZzQKBgQCdkbETiN0dawswfhEOT38Mv9CN0pziYtQUFM3q6QpKVfzI3rF32xg+W1P5ixWKL8CMSYCKyEvkPN1rRNe0jwW6FZPRcAZDpbexq7XQTrascmJXL8aZuz+FPFb2CPUULcMK9Ev1MePxh9AYjh3VN6MlbLzSzD4/fz7CiQ6HeUD+OwKBgQCeAFIww8Zu+HYWW/QkMmATTmbjEs2H6yJUC9Kkv8pGjLu75yBKc2AU26gNYg8Q5ZiYL7avv4f42koJZXBTEs0Os1RwL01ZIcjphPGA48pJ4kzrO98asv9KPpYR8J8HSUG8ZA49XuqvgH2qjKftnDLXvwj8VOtqnaTTOQXQFUXFfQKBgASnmSOKl32W++2iy74wewBVakPGRPwrDzjIpIyb9cHcaGtGqNdxkXXGHOTyRuCeKIH8ad+vqw5C/gd9MSIUV4b3vDYjqQu2iYamG+jbamoNtvn8X1GLRoUZEziRayv9bhWUwemsX59y86LGD/uMeTVR0QIpJm2ZxLDae6Nk4ZahAoGAVYgsCuXaTlvGqWBH98RcvyQMT76w1FU/y9B8XSplpSGpHp1bGGZEnHzr3cwxhwNPhixKAEgA9jZrwEcEKaQELLNF5eXKnCwSrBevyh3SFy+KRa6KIox7ymOoElKccjPXdYEE7YO/3isgKC2Wdsfdy82luqo1XLGo1e3j1FVpn/I=
alipay.alipay_public_key=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtbbxUtAxCfZCIy47WM3N/oVxa4X5RzwUb94AcPtkHJsNYsvrpZ5moAceTZiMKlxg1+SRU1Hex5DJ7+tEB5d/Tz+5TKjY4YENgmdyIc3jv0KysFd8e2/8+yH4HNu062OHMr92rc7q/HqK2jwwJ5+4KWAOEbBxLf69pZZwbTA/aSXonR7i32+JzYzoJ1jgVL0YnMl3IgPAqo7dZrl3lho7XtFxe5BF+WyhiKJKwgYlGvYcyYmkDMwR7Mzj5bsrC1ZAEEVkjtt7rpRR30BIIAS8EkKCl7dY1VIc+Eh0q8Ax/W9ur1GkXY1ti7mEQK+AphaVTg8LE546yEKSJKKNYVxLhQIDAQAB
alipay.notify_url=http://dongrongrong.free.svipss.top/payed/notify
#alipay.notify_url=http://member.gulimall.com/payed/notify
alipay.return_url=http://member.gulimall.com/memberOrder.html
alipay.sign_type=RSA2
alipay.charset=utf-8
alipay.gatewayUrl=https://openapi.alipaydev.com/gateway.do

订单支付

引入依赖

整合支付宝的sdk

     <!-- 支付宝sdk --><dependency><groupId>com.alipay.sdk</groupId><artifactId>alipay-sdk-java</artifactId><version>4.10.111.ALL</version></dependency>

准备支付的Vo

package com.xxxx.gulimall.order.vo;import lombok.Data;/*** @author LinLinD* @Create 2022-08-03-18:07*/
@Data
public class PayVo {private String out_trade_no; // 商户订单号 必填private String subject; // 订单名称 必填private String total_amount;  // 付款金额 必填private String body; // 商品描述 可空
}

获取订单的支付信息

需要注意的是,这里返回的是alipatTemplate处理过的html页面,而不是json数据。

/*** 用户下单:支付宝支付* 1、让支付页让浏览器展示* 2、支付成功以后,跳转到用户的订单列表页* @param orderSn* @return* @throws AlipayApiException*/@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;}

实现类

/*** 获取当前订单的支付信息* @param orderSn* @return*/@Overridepublic 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;}

支付成功返回订单列表页面

配置订单列表页面为同步回调地址

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

回到会员服务

配置拦截器,确保用户在登录状态,而且是member下的页面

package com.xxxx.gulimall.member.interceptor;import com.xxxx.common.vo.MemberResponseVo;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.PrintWriter;import static com.xxxx.common.constant.AuthServerConstant.LOGIN_USER;@Component
public class LoginUserInterceptor implements HandlerInterceptor {public static ThreadLocal<MemberResponseVo> loginUser = new ThreadLocal<>();@Overridepublic 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.gulimall.com/login.html'</script>");// session.setAttribute("msg", "请先进行登录");// response.sendRedirect("http://auth.gulimall.com/login.html");return false;}}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {}
}

同样配置远程请求的cookie同步配置,session配置和添加拦截器配置

package com.xxxx.gulimall.member.config;import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;import javax.servlet.http.HttpServletRequest;@Configuration
public class GuliFeignConfig {@Bean("requestInterceptor")public RequestInterceptor requestInterceptor() {RequestInterceptor requestInterceptor = new RequestInterceptor() {@Overridepublic 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;}}
package com.xxxx.gulimall.member.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.session.web.http.CookieSerializer;
import org.springframework.session.web.http.DefaultCookieSerializer;@Configuration
public class GulimallSessionConfig {@Beanpublic CookieSerializer cookieSerializer() {DefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer();//放大作用域cookieSerializer.setDomainName("gulimall.com");cookieSerializer.setCookieName("GULISESSION");return cookieSerializer;}@Beanpublic RedisSerializer<Object> springSessionDefaultRedisSerializer() {return new GenericJackson2JsonRedisSerializer();}}
package com.xxxx.gulimall.member.config;import com.xxxx.gulimall.member.interceptor.LoginUserInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
public class MemberWebConfig implements WebMvcConfigurer {@Autowiredprivate LoginUserInterceptor loginUserInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(loginUserInterceptor).addPathPatterns("/**");}}

去往订单页面

package com.xxxx.gulimall.member.web;import com.alibaba.fastjson.JSON;
import com.xxxx.common.utils.R;
import com.xxxx.gulimall.member.feign.OrderFeignService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;@Controller
public class MemberWebController {@Autowiredprivate 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";}}

远程接口

package com.xxxx.gulimall.member.feign;import com.xxxx.common.utils.R;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;import java.util.Map;@FeignClient("gulimall-order")
public interface OrderFeignService {/*** 分页查询当前登录用户的所有订单信息* @param params* @return*/@PostMapping("/order/order/listWithItem")R listWithItem(@RequestBody Map<String, Object> params);}
/*** 分页查询当前登录用户的所有订单信息* @param params* @return*/@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);}

实现类

/*** 查询当前用户所有订单数据* @param params* @return*/@Overridepublic 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);}

异步通知页面构建

写一个监听器来监听支付宝的异步通知

需要验证签名和处理订单结果

package com.xxxx.gulimall.order.listener;import com.alipay.api.AlipayApiException;
import com.alipay.api.internal.util.AlipaySignature;
import com.xxxx.gulimall.order.config.AlipayTemplate;
import com.xxxx.gulimall.order.service.OrderService;
import com.xxxx.gulimall.order.vo.PayAsyncVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;@RestController
public class OrderPayedListener {@Autowiredprivate OrderService orderService;@Autowiredprivate 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";}}}

异步通知Vo

package com.xxxx.gulimall.order.vo;import lombok.Data;
import lombok.ToString;import java.util.Date;@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;//支付者的idprivate String body;//订单的信息private String invoice_amount;//支付金额private String version;private String notify_id;//通知idprivate String fund_bill_list;private String notify_type;//通知类型; trade_status_syncprivate String out_trade_no;//订单号private String total_amount;//支付的总额private String trade_status;//交易状态  TRADE_SUCCESSprivate String trade_no;//流水号private String auth_app_id;//private String receipt_amount;//商家收到的款private String point_amount;//private String app_id;//应用idprivate String buyer_pay_amount;//最终支付的金额private String sign_type;//签名类型private String seller_id;//商家的id}

此时访问nginx服务器会有丢失请求头的问题

去nginx的配置文件配置这个异步通知页面的请求头信息,同时配置内网穿透的网址

在登录的拦截器里放行


处理支付结果
需要在支付信息表保存数据

/*** 处理支付宝的支付结果* @param asyncVo* @return*/@Transactional(rollbackFor = Exception.class)@Overridepublic 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";}

更新支付状态的方法

/*** 修改订单状态* @param orderSn* @param code*/private void updateOrderStatus(String orderSn, Integer code,Integer payType) {this.baseMapper.updateOrderStatus(orderSn,code,payType);}

sql

 <update id="updateOrderStatus">UPDATE oms_orderSET `status` = #{code},modify_time = NOW(),pay_type = #{payType},payment_time = NOW()WHERE order_sn = #{orderSn}</update>

2022谷粒商城学习笔记(二十五)支付宝沙箱模拟支付相关推荐

  1. JVM 学习笔记二十五、JVM监控及诊断工具-命令行篇

    二十五.JVM监控及诊断工具-命令行篇 1.概述 性能诊断是软件工程师在日常工作中经常面对和解决的问题,在用户体验至上的今天,解决好应用软件的性能问题能带来非常大的收益. Java作为最流行的编程语言 ...

  2. 2022谷粒商城学习笔记(二十二)rabbitMQ学习

    前言 本系列博客基于B站谷粒商城,只作为本人学习总结使用.这里我会比较注重业务逻辑的编写和相关配置的流程.有问题可以评论或者联系我互相交流.原视频地址谷粒商城雷丰阳版.本人git仓库地址Draknes ...

  3. 2022谷粒商城学习笔记(二十三)分布式事务

    前言 本系列博客基于B站谷粒商城,只作为本人学习总结使用.这里我会比较注重业务逻辑的编写和相关配置的流程.有问题可以评论或者联系我互相交流.原视频地址谷粒商城雷丰阳版.本人git仓库地址Draknes ...

  4. Java学习笔记二十五:Java面向对象的三大特性之多态

    Java面向对象的三大特性之多态 一:什么是多态: 多态是同一个行为具有多个不同表现形式或形态的能力. 多态就是同一个接口,使用不同的实例而执行不同操作. 多态性是对象多种表现形式的体现. 现实中,比 ...

  5. angular学习笔记(二十五)-$http(3)-转换请求和响应格式

    本篇主要讲解$http(config)的config中的tranformRequest项和transformResponse项 1. transformRequest: $http({transfor ...

  6. Mr.J-- jQuery学习笔记(二十五)--监听DOM加载

    页面元素 <body> <div></div> <div></div> <div></div> <div> ...

  7. java沙盒模式_JavaScript学习笔记(二十五) 沙箱模式

    沙箱模式(Sandbox Pattern) 沙箱模式可以避免命名空间的一些缺点(namespacing pattern),比如: 依赖一个唯一全局的变量作为程序的全局符号.在命名空间模式中,没有办法存 ...

  8. JavaScript学习笔记(十五)

    JavaScript学习笔记(十五) 事件 事件是DOM(文档对象模型)的一部分.事件流就是事件发生顺序,这是IE和其他浏览器在事件支持上的主要差别. 一.事件流 1.冒泡型事件 IE上的解决方案就是 ...

  9. OpenCV学习笔记(十五):图像仿射变换:warpAffine(),getRotationMatrix2D()

    OpenCV学习笔记(十五):图像仿射变换:warpAffine(),getRotationMatrix2D() 一个任意的仿射变换都能表示为乘以一个矩阵(线性变换)接着再加上一个向量(平移)的形式. ...

  10. 学习笔记(十五)——镜像的知识点与注意事项

    学习笔记(十五)--镜像的知识点与注意事项 一.基础知识 1.SQL Server镜像只有两种模式:高安全模式和高性能模式.两种模式的主要区别在于在事务提交后的操作. 在高性能模式下,主体服务器不需要 ...

最新文章

  1. linux 面包店 多进程,Linux下的多进程编程(一)
  2. Java synchronized解析
  3. 2003年以来网页尺寸增长3倍
  4. mysql 互为主备 宕机 数据丢失_Devops部署-mysql主备多从搭建
  5. js替换数组中字符串实例
  6. 使用mocha进行测试 区块链
  7. ENVI高光谱物质识别
  8. 教育计算机缩写,{教育管理}计算机缩写术语完全介绍宝典.docx
  9. OFD在线预览方案评测
  10. android slidemenu 折叠效果,左侧菜单栏折叠展开效果-超级简单
  11. 互联网公司招聘--今日头条--产品经理-2017年笔试题1
  12. 路由协议-ospf配置
  13. air flow空调上是什么意思_airflow空调滤芯上是什么意思
  14. 关于 Thread.currentThread()
  15. 红光光浴一次能排多少湿气?-红光光浴/种光光学
  16. crt上次文件到服务器,crt登陆到ftp服务器
  17. PCB线路板表面处理工艺的优缺点合集
  18. 在bpfTrace中使用USDT
  19. 自学笔记十四:Matlab浮点型:创建和转换、取值范围、运算和精度问题
  20. 专业文科30年零基础学神经网络TensorFlow

热门文章

  1. 【机器学习理论】换底公式--以e,2,10为底的对数关系转化
  2. 软件工程中的数据流图
  3. 调用阿里云的通用文字识别-高精版识别接口,识别图片中的文字详解
  4. 字符串--------KMP算法(studying)
  5. 物联网是什么,和互联网之间主要有什么区别
  6. C++基础学习笔记:函数
  7. Python学习笔记-2017.5.4thon学习笔记-2017.5.22
  8. HJQ巨佬のTwelveFold Way 手稿电子版
  9. C#-实现微信激活会员卡后响应激活动作并获取会员信息
  10. 用html设计logo,网页设计中的logo设计方法