# blog

title: vue webpack方式调用amap高德地图及其UI组件
ctime: 2018-11-22 00:49:27.8584952+00:00
utime: 2018-11-22 00:49:27.8584952+00:00
blog_html:
  <h1>vue2（webpack）调用amap高德地图及其UI组件和标记物</h1><p><a href="https://www.aiprose.com/map" target="_blank">点击查看效果图</a>&nbsp;https://www.aiprose.com/map 这是效果图地址，完整效果请下载运行demo</p><p><a href="https://git.coding.net/mnbl/gaode-demo.git" target="_blank">点击下载demo</a>&nbsp;https://git.coding.net/mnbl/gaode-demo.git demo下载地址,下载后运行起来，请点击标题栏 “地图demo1” 和 “地图demo2”，进行查看效果。</p><p>今天一个app项目中要使用vue2加入高德地图，本来以为有第三方的插件，结果没找到适合自己用的，因为地图这块，一般都是自定义程度比较高的。注：这里是最简单的demo，更多更详细请阅读官方api,有问题请在下方评论，或者加群讨论<code>QQ群：128806068</code></p><h3><a id="1key_9"></a>1、申请key</h3><p>点击下边的网址，创建应用，然后申请key，后期要用到，如果已经有key，忽略这一步 http://lbs.amap.com/dev/key/app</p><h3><a id="2_14"></a>2、修改配置</h3><p>首先要在build/webpack.base.conf.js 加入如下配置，负责vue中使用import会报错。 如果如下导入还AMap报错，请使用window.AMap。因为后边要使用高德的infowindow，最简单的不好扩展，而且没有点击事件，所以用用到了高德的ui。位置见下图</p><pre><div><code>  externals: {
      'AMap': 'AMap',
      'AMapUI': 'AMapUI'
    }
  </code></div></pre><p><img src="https://www.aiprose.com/itstack/20180929/1538188295709.png" alt="amap1.png"></p><h3><a id="3_25"></a>3、调用高德地图</h3><ul><li>首先在index.html中加入如下引用</li></ul><pre><div><code>&lt;!--引入高德地图JSAPI --&gt;
  &lt;script type="text/javascript" src="https://webapi.amap.com/maps?v=1.4.10&amp;key=您申请的key值"&gt;&lt;/script&gt;
  &lt;!--引入UI组件库（1.0版本） --&gt;
  &lt;script src="https://webapi.amap.com/ui/1.0/main.js"&gt;&lt;/script&gt;

  </code></div></pre><ul><li>新建一个map.vue组件</li></ul><p>在script中引入如下组件，如果第二步不配置，这里会报错</p><pre><div><code>import AMap from 'AMap'
  import AMapUI from 'AMapUI'
  </code></div></pre><blockquote><p><em>注意：</em>如果eslint一直检查不通过，加入下面注释</p></blockquote><pre><div><code>/* eslint-disable no-undef */
  import AMap from 'AMap'
  import AMapUI from 'AMapUI'
  </code></div></pre><p>template中加入map的div,注意如果map不显示，没报错的时候，请检查div的宽高。</p><pre><div><code>&lt;div id="map-container"&gt; &lt;/div&gt;
  </code></div></pre><p>然后再mounted（不是created）中初始化地图，这时候地图就会显示出来了，但是没有任何组件，注意vue2废弃ready，请使用mounted。代码位置不懂的看图片</p><p><img src="https://www.aiprose.com/itstack/20180929/1538188876883.png" alt="amap2.png"></p><pre><div><code>
  	// 创建地图 ，使用高德默认的图层
  	let mapObj = new AMap.Map('map-container', {
            center: [108.963148, 34.232709],
            zoom: 11
          })

  </code></div></pre><p>如果使用自定义图层，前提是这个图层是偏移过的</p><pre><div><code>	//谷歌的影响图层
  	let googleLayerimage = new AMap.TileLayer({
            getTileUrl: 'https://mt{1,2,3,0}.google.cn/maps/vt?lyrs=s@194&amp;hl=zh-CN&amp;gl=cn&amp;x=[x]&amp;y=[y]&amp;z=[z]',
            zIndex: 2
          })
  	
  	// 控制图层的显示与隐藏
  	// googleLayerimage.hide()
          // googleLayerimage.show()

          let googleLayervector = new AMap.TileLayer()

  	// 创建地图，使用自己的图层 
  	let mapObj = new AMap.Map('map-container', {
            layers: [googleLayervector, googleLayerimage],
            center: [108.963148, 34.232709],
            zoom: 11
          })

  </code></div></pre><p>两个组件：放大缩小按钮和图层的切换</p><pre><div><code>mapObj.plugin(['AMap.ToolBar', 'AMap.MapType'], function () {
    mapObj.addControl(new AMap.ToolBar())
    mapObj.addControl(new AMap.MapType({showTraffic: false, showRoad: false}))
  })
  </code></div></pre><p>使用高德定位</p><pre><div><code>	mapObj.plugin(['AMap.Geolocation'], function () {
            let geolocation = new AMap.Geolocation({
              enableHighAccuracy: true, //  是否使用高精度定位，默认:true
              timeout: 10000, //  超过10秒后停止定位，默认：无穷大
              maximumAge: 0, // 定位结果缓存0毫秒，默认：0
              convert: true, // 自动偏移坐标，偏移后的坐标为高德坐标，默认：true
              showButton: true, //  显示定位按钮，默认：true
              buttonPosition: 'LB',  // 定位按钮停靠位置，默认：'LB'，左下角
              buttonOffset: new AMap.Pixel(10, 20), //  定位按钮与设置的停靠位置的偏移量，默认：Pixel(10, 20)
              showMarker: true, //  定位成功后在定位到的位置显示点标记，默认：true
              showCircle: true, //  定位成功后用圆圈表示定位精度范围，默认：true
              panToLocation: true,  //  定位成功后将定位到的位置作为地图中心点，默认：true
              zoomToAccuracy: true  //  定位成功后调整地图视野范围使定位位置及精度范围视野内可见，默认：false
            })
            mapObj.addControl(geolocation)
            geolocation.getCurrentPosition()
            AMap.event.addListener(geolocation, 'complete', (result) =&gt; {
              mapObj.setCenter(result.position)
            })  //  返回定位信息
            AMap.event.addListener(geolocation, 'error', (result) =&gt; {
              console.log(result)
            })  //  返回定位出错信息
          })
  </code></div></pre><h3><a id="4_markerinfowindow_135"></a>4、地图添加标记物和信息框 marker和infowindow</h3><p>因为我从后台取到的点是gps定位的点，因为坐标系不同，所以要将gps的点转成高德坐标系的点；点击marker显示infowindow,并给infowindow添加点击事件</p><pre><div><code>	    // 后台取到的点，新建LngLat对象
              let lngLat = new AMap.LngLat(lanlet[0].trim(), lanlet[1].trim())
              // 转高德坐标系,这是高德提供的api
              AMap.convertFrom(lngLat, 'gps', function (info, result) {
              lngLat = result.locations[0]// 转换后的坐标位置
              var marker = new AMap.Marker({
                position: lngLat,
                map: mapObj
              })
              AMap.event.addListener(marker, 'click', (e) =&gt; {
                AMapUI.loadUI(['overlay/SimpleInfoWindow'], function (SimpleInfoWindow) {
                  var infoWindow = new SimpleInfoWindow({
                    infoTitle: '&lt;strong&gt;这是标题&lt;/strong&gt;',
                    infoBody: '&lt;p&gt;这是信息&lt;/p&gt;',
                    offset: new AMap.Pixel(0, -20),
                    autoMove: true
                  })
                  infoWindow.open(mapObj, e.target.getPosition())
                  // 最坑的就是这一步了，他的infowindow没有点击事件，所以infoWindow.get$Container()会返回这个infowindow（jquery）对象
                  let infoEle = infoWindow.get$Container()
                  //给infowindow添加点击事件，并在回调函数中处理业务或者跳转等
                  infoEle.on('click', (e) =&gt; {
                    router.push({name: 'proinfo', params: pro})
                  })
                })
              })
            })</code></div></pre>


title: 微信扫码支付、网站接入微信支付-java
ctime: 2018-11-23 04:50:08.4347505+00:00
utime: 2018-11-23 04:50:08.4347505+00:00
blog_html:
  <p>如果你的网站想接入微信支付，那么你的有个公众号（<code>微信公众平台</code>），然后开通支付功能，在<code>微信商户平台</code>操作。仔细看哦，这是两个平台，商家平台有详细的接入流程，这里只介绍程序方面。</p><h4><a id="1_2"></a>1、准备</h4><ul><li>准备商家帐户</li><li>下载证书，重置密钥（密钥重置后请妥善保管）</li><li>内网穿透软件（微信支付成功后会有回调）</li></ul><h4><a id="2_8"></a>2、代码</h4><ul><li>加入依赖</li></ul><p>微信支付比较麻烦，所以我们采用第三方封装的jar包</p><pre><code>compile group: 'com.github.binarywang', name: 'weixin-java-pay', version: '3.0.0'
  </code></pre><ul><li>新建&nbsp;<code>pay.properties</code></li></ul><pre><div><code>#wxpay
  WX.APPID=wxdd088f0c1d70cbf9
  WX.MCHID=你的商户id
  WX.MCHKEY=你的密钥
  WX.SUBAPPID=
  WX.SUBMCHID=
  WX.KEYPATH=
  #下面这个是微信回调地址，要保证外网可以访问，内网测试就用内网穿透软件
  WX.NOTIFYURL=http://tdcloud.trmap.cn/reward/getOrderNotifyResult
  WX.TRADETYPE=NATIVE
  </code></div></pre><ul><li>配置类</li></ul><p>WxPayConfig 将配置文件里的值读取出来，微信支付需要的相关配置</p><pre><code>
  @Configuration
  @PropertySource(value="classpath:pay.properties", ignoreResourceNotFound=true)
  public class WxPayConfig {

    /**
     * http请求连接超时时间
     */
    private int httpConnectionTimeout = 5000;

    /**
     * http请求数据读取等待时间
     */
    private int httpTimeout = 10000;

    private String appId;
    private String subAppId;
    private String mchId;
    private String mchKey;
    private String subMchId;
    private String notifyUrl;
    private String tradeType;
    private String signType;
    private SSLContext sslContext;
    private String keyPath;
    private boolean useSandboxEnv = false;
    private String httpProxyHost;
    private Integer httpProxyPort;
    private String httpProxyUsername;
    private String httpProxyPassword;

    public String getKeyPath() {
      return keyPath;
    }

    /**
     * 设置证书
     *
     * @param keyPath apiclient_cert.p12的文件的绝对路径
     */
    public void setKeyPath(String keyPath) {
      this.keyPath = keyPath;
    }

    /**
     * 商户号
     */
    public String getMchId() {
      return this.mchId;
    }

    public void setMchId(String mchId) {
      this.mchId = mchId;
    }

    /**
     * 商户密钥
     */
    public String getMchKey() {
      return this.mchKey;
    }

    public void setMchKey(String mchKey) {
      this.mchKey = mchKey;
    }

    /**
     * 公众号appid
     */
    public String getAppId() {
      return this.appId;
    }

    public void setAppId(String appId) {
      this.appId = appId;
    }

    /**
     * 服务商模式下的子商户公众账号ID
     */
    public String getSubAppId() {
      return this.subAppId;
    }

    public void setSubAppId(String subAppId) {
      this.subAppId = subAppId;
    }

    /**
     * 服务商模式下的子商户号
     */
    public String getSubMchId() {
      return this.subMchId;
    }

    public void setSubMchId(String subMchId) {
      this.subMchId = subMchId;
    }

    /**
     * 微信支付异步回掉地址，通知url必须为直接可访问的url，不能携带参数。
     */
    public String getNotifyUrl() {
      return this.notifyUrl;
    }

    public void setNotifyUrl(String notifyUrl) {
      this.notifyUrl = notifyUrl;
    }

    /**
     * 交易类型
     * &lt;pre&gt;
     * JSAPI--公众号支付
     * NATIVE--原生扫码支付
     * APP--app支付
     * &lt;/pre&gt;
     */
    public String getTradeType() {
      return this.tradeType;
    }

    public void setTradeType(String tradeType) {
      this.tradeType = tradeType;
    }

    /**
     * 签名方式
     * 有两种HMAC_SHA256 和MD5
     * @see com.github.binarywang.wxpay.constant.WxPayConstants.SignType
     */
    public String getSignType() {
      return this.signType;
    }

    public void setSignType(String signType) {
      this.signType = signType;
    }

    public SSLContext getSslContext() {
      return this.sslContext;
    }

    public void setSslContext(SSLContext sslContext) {
      this.sslContext = sslContext;
    }

    /**
     * 微信支付是否使用仿真测试环境
     * 默认不使用
     */
    public boolean useSandbox() {
      return this.useSandboxEnv;
    }

    /**
     * 设置是否使用沙箱仿真测试环境
     */
    public void setUseSandboxEnv(boolean useSandboxEnv) {
      this.useSandboxEnv = useSandboxEnv;
    }

    public SSLContext initSSLContext() throws WxPayException {
      if (StringUtils.isBlank(this.getMchId())) {
        throw new WxPayException("请确保商户号mchId已设置");
      }

      if (StringUtils.isBlank(this.getKeyPath())) {
        throw new WxPayException("请确保证书文件地址keyPath已配置");
      }

      InputStream inputStream;
      final String prefix = "classpath:";
      String fileHasProblemMsg = "证书文件【" + this.getKeyPath() + "】有问题，请核实！";
      String fileNotFoundMsg = "证书文件【" + this.getKeyPath() + "】不存在，请核实！";
      if (this.getKeyPath().startsWith(prefix)) {
        String path = StringUtils.removeFirst(this.getKeyPath(), prefix);
        if (!path.startsWith("/")) {
          path = "/" + path;
        }
        inputStream = WxPayConfig.class.getResourceAsStream(path);
        if (inputStream == null) {
          throw new WxPayException(fileNotFoundMsg);
        }
      } else {
        try {
          File file = new File(this.getKeyPath());
          if (!file.exists()) {
            throw new WxPayException(fileNotFoundMsg);
          }

          inputStream = new FileInputStream(file);
        } catch (IOException e) {
          throw new WxPayException(fileHasProblemMsg, e);
        }
      }

      try {
        KeyStore keystore = KeyStore.getInstance("PKCS12");
        char[] partnerId2charArray = this.getMchId().toCharArray();
        keystore.load(inputStream, partnerId2charArray);
        this.sslContext = SSLContexts.custom().loadKeyMaterial(keystore, partnerId2charArray).build();
        return this.sslContext;
      } catch (Exception e) {
        throw new WxPayException(fileHasProblemMsg, e);
      } finally {
        IOUtils.closeQuietly(inputStream);
      }
    }

    /**
     * http请求连接超时时间
     */
    public int getHttpConnectionTimeout() {
      return this.httpConnectionTimeout;
    }

    public void setHttpConnectionTimeout(int httpConnectionTimeout) {
      this.httpConnectionTimeout = httpConnectionTimeout;
    }

    /**
     * http请求数据读取等待时间
     */
    public int getHttpTimeout() {
      return this.httpTimeout;
    }

    public void setHttpTimeout(int httpTimeout) {
      this.httpTimeout = httpTimeout;
    }

    public String getHttpProxyHost() {
      return httpProxyHost;
    }

    public void setHttpProxyHost(String httpProxyHost) {
      this.httpProxyHost = httpProxyHost;
    }

    public Integer getHttpProxyPort() {
      return httpProxyPort;
    }

    public void setHttpProxyPort(Integer httpProxyPort) {
      this.httpProxyPort = httpProxyPort;
    }

    public String getHttpProxyUsername() {
      return httpProxyUsername;
    }

    public void setHttpProxyUsername(String httpProxyUsername) {
      this.httpProxyUsername = httpProxyUsername;
    }

    public String getHttpProxyPassword() {
      return httpProxyPassword;
    }

    public void setHttpProxyPassword(String httpProxyPassword) {
      this.httpProxyPassword = httpProxyPassword;
    }
  }

  </code></pre><ul><li>发起支付，获取生成二维码的地址</li></ul><blockquote><p>微信支付的单位是分，例如你支付金额是9.9元（保留两位小数），那你微信支付的时候支付金额是9.9元*100 = 990分，最后支付金额是整数。</p></blockquote><p>封装请求参数，请求微信接口后会返回生成二维码的地址</p><pre><code>	@Autowired
  	private WxPayConfig payConfig;
  	@Autowired
  	private WxPayService wxService; //上边依赖第三方库提供的

  	
  	@RequestMapping("wxpay")
  	private ResponseEntity&lt;Result&gt; rewardWxpay(@RequestParam Double money, HttpServletRequest request,WxPayUnifiedOrderRequest wxreq){
  		try {
  				
  	@RequestMapping("wxpay")
  	private ResponseEntity&lt;Result&gt; rewardWxpay(String userid,@RequestParam String produceid,@RequestParam Double money,String remark, HttpServletRequest request,WxPayUnifiedOrderRequest wxreq){
  		try {
  			// TODO 生成你的订单信息，然后返回订单id，这里代码忽略，根据自己的业务调整
  			String ip = req.getHeader("x-forwarded-for");
  			if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
  	           ip = req.getHeader("Proxy-Client-IP");
  			}
  		    if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
  		           ip = req.getHeader("WL-Proxy-Client-IP");
  		    }
  		     if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
  		           ip = req.getRemoteAddr();
  		    }
  		    if (ip != null &amp;&amp; ip.length() != 0 &amp;&amp; !"unknown".equalsIgnoreCase(ip)) {  
  	            // 多次反向代理后会有多个ip值，第一个ip才是真实ip
  	            if( ip.indexOf(",")!=-1 ){
  	                ip = ip.split(",")[0];
  	            }
  	        }
  		    request.setBody("实景在线打赏-"); // 支付标题
  		    request.setOutTradeNo(你自己的订单编号);
  		    // 金额一定要以分为单位，所以最后支付金额为整数
  		    String string = String.valueOf((reward.getMoney()*100));
  		    request.setTotalFee(Integer.parseInt(string.substring(0,string.indexOf("."))));
  		    request.setAppid(payConfig.getAppId());
  			request.setMchId(payConfig.getMchId());
  			request.setNotifyUrl(payConfig.getNotifyUrl());
  			request.setSpbillCreateIp(ip);
  			
  			request.setTradeType(payConfig.getTradeType());
  			//this.wxService.unifiedOrder(request) 发起请求，获取地址，然后根据地址生成二维码
  			return SUCCESS(this.wxService.unifiedOrder(request););
  		} catch (WxPayException e) {
  			e.printStackTrace();
  		}
  		return ERROR("发起支付失败");
  	}
  		} catch (WxPayException e) {
  			e.printStackTrace();
  		}
  		return ERROR("发起支付失败");
  	}
  </code></pre><ul><li>生成二维码</li></ul><p>根据上一步请求返回的地址生成二维码，生成的二维码是base64格式的字节码，前台用img标签直接显示即可，这时候用户就可以扫描生成的二维码进行支付了</p><pre><code>/**
  	 * &lt;pre&gt;
  	 * 扫码支付模式二生成二维码的方法
  	 * 对应链接格式：weixin：//wxpay/bizpayurl?sr=XXXXX。请商户调用第三方库将code_url生成二维码图片。
  	 * 该模式链接较短，生成的二维码打印到结账小票上的识别率较高。
  	 * 文档详见: https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_5
  	 * &lt;/pre&gt;
  	 *
  	 * @param codeUrl
  	 *            微信返回的交易会话的二维码链接
  	 * @param logoFile
  	 *            商户logo图片的文件对象，可以为空
  	 * @param sideLength
  	 *            要生成的二维码的边长，如果为空，则取默认值400
  	 * @return 生成的二维码的字节数组
  	 */

  	@PostMapping(value = "/createScanPayQrcode")
  	public ResponseEntity&lt;Result&gt; createQrcode(String codeUrl,File logoFile, Integer sideLength) {
  		byte[] by = this.wxService.createScanPayQrcodeMode2(codeUrl, logoFile, sideLength);
  		return SUCCESS(by);
  	}
  </code></pre><ul><li>回调接口</li></ul><p>用户扫描支付后，微信会异步通知，请求地址为配置文件中的接口地址，所以要保证公网可以访问。微信共会请求8次回调接口，如果处理成功后，将不在请求回调接口</p><pre><code>
  	/**
  	 * 读取支付结果通知
  	 *
  	 * @param xmlData
  	 * @throws WxPayException 
  	 */
  	@RequestMapping(value = "/getOrderNotifyResult", method = RequestMethod.POST)
  	public String getOrderNotifyResult(@RequestBody String xmlData,HttpServletRequest request,
  			HttpServletResponse response) throws WxErrorException, WxPayException {
  		WxPayOrderNotifyResult orderNotifyResult = this.wxService.parseOrderNotifyResult(xmlData);
  		String noticeStr = null;
  		try {
  			BufferedOutputStream outputStream = new BufferedOutputStream(response.getOutputStream());

  			// 支付成功，商户处理后同步返回给微信参数
  	        if (!orderNotifyResult.getResultCode().equals("SUCCESS")) {
  	            // 支付失败， 记录流水失败
  	            System.out.println("===============支付失败==============");
  	            noticeStr = setXML("FAIL", "支付失败");
  	            outputStream.write(noticeStr.getBytes());
  	            outputStream.flush();
  	            outputStream.close();
  	        } else {
  	        	// TODO 处理你的业务，修改订单状态等
  	            // 通知微信已经收到消息，不要再给我发消息了，否则微信会8连击调用本接口
  	            noticeStr = setXML("SUCCESS", "支付成功");
  	            outputStream.write(noticeStr.getBytes());
  	            outputStream.flush();
  	            outputStream.close();
  	        }
  		} catch (Exception e) {
  			e.printStackTrace();
  		}
  		return noticeStr;
  	}
  	
  	public String setXML(String return_code, String return_msg) {
  	        return "&lt;xml&gt;&lt;return_code&gt;&lt;![CDATA[" + return_code + "]]&gt;&lt;/return_code&gt;&lt;return_msg&gt;&lt;![CDATA[" + return_msg + "]]&gt;&lt;/return_msg&gt;&lt;/xml&gt;";
  	}
  </code></pre><p>到这里，网站接入微信扫码支付，代码部分就全部完成了，最后效果图请看下方图片。<br><img src="http://upload-images.jianshu.io/upload_images/7704655-2e9166e864b8c74f?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="这里写图片描述"><br><img src="http://upload-images.jianshu.io/upload_images/7704655-b22afdc4db715a9f?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="这里写图片描述"></p><p>##关注</p><p>如果有问题，请在下方评论，或者加群讨论&nbsp;<code>200909980</code></p><p>关注下方微信公众号，可以及时获取到各种技术的干货哦，如果你有想推荐的帖子，也可以联系我们的。</p><p><img src="https://upload-images.jianshu.io/upload_images/7704655-c8e7dca6fb607ac1.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="码农笔录二维码"></p>


