Android应用接入支付宝实现支付功能

记得很早以前公司项目中添加过移动支付这一块, 包括微信,支付宝,银联等第三方的整合。 但是后来懒于总结就没留下什么, 最近公司项目打算添加,所以打算简单总结一下,记上一笔以备将来使用。 毕竟第三方的支付SDK , 一般定下了以后三五年不会改变。 闲话少说,开干。 集成第三方SDK没什么难度,只要我们用心阅读文档和开发引导,集成起来再留点神,一切都不是问题。

1. 申请流程(支付宝移动开发平台)

1.1 准备工作

1. 单位营业执照彩色扫描件或数码照片  

2. 对公银行账户(基本账户、一般账户均可) 

3. 法定代表人的身份证彩色扫描件或数码照片 若为代理人(即法人以外的公司代表)申请认证,需额外提供以下两项材料 

4. 代理人的身份证彩色扫描件或数码照片 

5. 委托书,委托书上必须盖有单位公章或财务专用章(合同专用章、业务专用章等无效)下载委托书模版

1.2 创建应用

        这里就给个创建应用链接 ,再给个图 https://open.alipay.com/developmentAccess/developmentAccess.htm
进去之后,创建应用后,上传相应的Icon, 描述等信息之后提交审核。再给个图吧

图上很清楚了, 一般就是需要使用哪种支付渠道就和支付宝签约哪种, 右上角有个立即签约, 上传材料审核时间一般半上午就行了。 应用创建审核通过之后会有一个APPID 端上需要进行配置。

1.3 配置RSA秘钥

这一部分很重要,因为牵涉到配置,签名,继续看。来个官网 , 根据不同系统下载了RSA生成工具,再截个图吧 ,

点击RSA签名验签名工具.command , 可能会有执行权限问题, 看txt文档的操作执行。

  官网推荐的使用2048长度的, 本地已经生成公钥和私钥两个文件 , 按照操作流程 ,将公钥上传配置到设置应用公钥处即可。

2. SDK配置

  将下载好的SDK解压找到Android部分,将jar 导入项目中。SDK地址 并且在我们的app/build.gradle里配置一下

compile files('libs/alipaySdk-20170922.jar')

配置一下Manfest文件

<!-- alipay sdk begin -->

<activity
    android:name="com.alipay.sdk.app.H5PayActivity"
    android:configChanges="orientation|keyboardHidden|navigation|screenSize"
    android:exported="false"
    android:screenOrientation="behind"
    android:windowSoftInputMode="adjustResize|stateHidden"></activity>
<activity
    android:name="com.alipay.sdk.app.H5AuthActivity"
    android:configChanges="orientation|keyboardHidden|navigation"
    android:exported="false"
    android:screenOrientation="behind"
    android:windowSoftInputMode="adjustResize|stateHidden"></activity>

<!-- alipay sdk end -->

 再来配置一下运行权限

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

项目中需要添加混淆的可以配一下

-optimizationpasses 7 
-verbose 
-keepattributes Exceptions,InnerClasses
-dontskipnonpubliclibraryclasses 
-dontskipnonpubliclibraryclassmembers 
-ignorewarnings

-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends java.lang.Throwable {*;}
-keep public class * extends java.lang.Exception {*;}-keep class com.alipay.android.app.IAlixPay{*;}
-keep class com.alipay.android.app.IAlixPay$Stub{*;}
-keep class com.alipay.android.app.IRemoteServiceCallback{*;}
-keep class com.alipay.android.app.IRemoteServiceCallback$Stub{*;}
-keep class com.alipay.sdk.app.PayTask{ public *;}
-keep class com.alipay.sdk.app.AuthTask{ public *;}
-keep class com.alipay.sdk.app.H5PayCallback {
    <fields>;
    <methods>;
}
-keep class com.alipay.android.phone.mrpc.core.** { *; }
-keep class com.alipay.apmobilesecuritysdk.** { *; }
-keep class com.alipay.mobile.framework.service.annotation.** { *; }
-keep class com.alipay.mobilesecuritysdk.face.** { *; }
-keep class com.alipay.tscenter.biz.rpc.** { *; }
-keep class org.json.alipay.** { *; }
-keep class com.alipay.tscenter.** { *; }
-keep class com.ta.utdid2.** { *;}
-keep class com.ut.device.** { *;}

3. 支付接口调用

3.1 正式支付环境的接口调用

package com.greencheng.android.parent.alipay;

import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v4.app.FragmentActivity;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.Toast;

import com.alipay.sdk.app.PayTask;
import com.greencheng.android.parent.R;

import java.util.Map;

/**
 * 重要说明:
 * <p>
 * 这里只是为了方便直接向商户展示支付宝的整个支付流程;所以Demo中加签过程直接放在客户端完成;
 * 真实App里,privateKey等数据严禁放在客户端,加签过程务必要放在服务端完成;
 * 防止商户私密数据泄露,造成不必要的资金损失,及面临各种安全风险;
 */
public class PayDemoActivity extends FragmentActivity {/**
     * 支付宝支付业务:入参app_id
     */
    public static final String APPID = "201803010d22f94394";
    private static final int SDK_PAY_FLAG = 1;
    @SuppressLint("HandlerLeak")private Handler mHandler = new Handler() {@SuppressWarnings("unused")public void handleMessage(Message msg) {switch (msg.what) {case SDK_PAY_FLAG: {@SuppressWarnings("unchecked")PayResult payResult = new PayResult((Map<String, String>) msg.obj);
                    /**
                     对于支付结果,请商户依赖服务端的异步通知结果。同步通知结果,仅作为支付结束的通知。
                     */
                    String resultInfo = payResult.getResult();// 同步返回需要验证的信息
                    String resultStatus = payResult.getResultStatus();
                    // 判断resultStatus 为9000则代表支付成功
                    if (TextUtils.equals(resultStatus, "9000")) {// 该笔订单是否真实支付成功,需要依赖服务端的异步通知。
                        Toast.makeText(PayDemoActivity.this, "支付成功", Toast.LENGTH_SHORT).show();
                    } else {// 该笔订单真实的支付结果,需要依赖服务端的异步通知。
                        Toast.makeText(PayDemoActivity.this, "支付失败", Toast.LENGTH_SHORT).show();
                    }break;
                }default:break;
            }};
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);
        setContentView(R.layout.pay_external);
    }/**
     * 支付宝支付业务
     *
     * @param v
     */
    public void payV2(View v) {if (TextUtils.isEmpty(APPID)) {new AlertDialog.Builder(this).setTitle("警告").setMessage("需要配置APPID | RSA_PRIVATE").setPositiveButton("确定", new DialogInterface.OnClickListener() {public void onClick(DialogInterface dialoginterface, int i) {//
                            finish();
                        }}).show();
            return;
        }Runnable payRunnable = new Runnable() {/**
             * 这里只是为了方便直接向商户展示支付宝的整个支付流程;所以Demo中加签过程直接放在客户端完成;
             * 真实App里,privateKey等数据严禁放在客户端,加签过程务必要放在服务端完成;
             * 防止商户私密数据泄露,造成不必要的资金损失,及面临各种安全风险;
             *
             * orderInfo的获取必须来自服务端;
             * {
             "pay_params":"app_id=201221&biz_content=%7B%22out_trade_no%22%4104%2C%22subject%22
             %xxx2C%22total_amount%22%3A0.02%2C%22product_code%22%3A%22QUICK_MSECURITY_PAY%22%7D&
             charset=utf-8&format=JSON&method=alipay.trade.app.pay&notify_url=https%3A%2F%2Fpayment.
             test.xxx.com%2Fwechatnotify%2FappPay&sign=YwLzlQ0BfZCBZG%2FENu0NBQ%3D%3D&sign_typ
             e=RSA2&timestamp=2018-03-09+09%3A24%3A20&version=1.0",
             "bill_id":"91"
             }
             */

             服务端会根据参数生成一个这样格式的字符串, 这是简化版
            final String orderInfo = "app_id=201221&biz_content=%7B%22out_trade_no%22%4104%2C%22subject%22%xxx2C%22total_amount%22%3A0.02%2C%22product_code%22%3A%22QUICK_MSECURITY_PAY%22%7D&charset=utf-8&format=JSON&method=alipay.trade.app.pay&notify_url=https%3A%2F%2Fpayment.test.xxx.com%2Fwechatnotify%2FappPay&sign=YwLzlQ0BfZCBZG%2FENu0NBQ%3D%3D&sign_type=RSA2&timestamp=2018-03-09+09%3A24%3A20&version=1.0";

            @Override
            public void run() {PayTask alipay = new PayTask(PayDemoActivity.this);
                Map<String, String> result = alipay.payV2(orderInfo, true);
                Log.i("msp", result.toString());

                Message msg = new Message();
                msg.what = SDK_PAY_FLAG;
                msg.obj = result;
                mHandler.sendMessage(msg);
            }};

        /// 根据官方文档的要求这里必须使用子线程
        Thread payThread = new Thread(payRunnable);
        payThread.start();
    }/**
     * get the sdk version. 获取SDK版本号
     */
    public void getSDKVersion() {PayTask payTask = new PayTask(this);
        String version = payTask.getVersion();
        Toast.makeText(this, version, Toast.LENGTH_SHORT).show();
    }/**
     * 原生的H5(手机网页版支付切natvie支付) 【对应页面网页支付按钮】
     *
     * @param v
     */
    public void h5Pay(View v) {Intent intent = new Intent(this, H5PayDemoActivity.class);
        Bundle extras = new Bundle();
        /**
         * url 是要测试的网站,在 Demo App 中会使用 H5PayDemoActivity 内的 WebView 打开。
         *
         * 可以填写任一支持支付宝支付的网站(如淘宝或一号店),在网站中下订单并唤起支付宝;
         * 或者直接填写由支付宝文档提供的“网站 Demo”生成的订单地址
         * (如 https://mclient.alipay.com/h5Continue.htm?h5_route_token=303ff0894cd4dccf591b089761dexxxx)
         * 进行测试。
         *
         * H5PayDemoActivity 中的 MyWebViewClient.shouldOverrideUrlLoading() 实现了拦截 URL 唤起支付宝,
         * 可以参考它实现自定义的 URL 拦截逻辑。
         */
        String url = "http://www.samuelnotes.cn";
        extras.putString("url", url);
        intent.putExtras(extras);
        startActivity(intent);
    }}

    这里就不多说了,关键地方也就这几行

    PayTask alipay = new PayTask(PayDemoActivity.this);
        Map<String, String> result = alipay.payV2(orderInfo, true); /// 调用SDK发起支付后 会在Handler里边进行接收,处理。 9000 支付成功

3.2 沙箱支付环境的接口调用

     由于各种开发环境的需要,支付宝还有沙箱支付环境。 调用方法一样, 注意添加

/// 测试沙箱环境 上线必须注释 !!!!
    EnvUtils.setEnv(EnvUtils.EnvEnum.SANDBOX);

     这里注意了 首先是测试端只支持Android端, 必须使用沙箱环境下的APP_ID , 特殊的沙箱环境支付钱包,账号, 密码等。


下载沙箱版的支付钱包需要支付宝扫码登录,界面就不再放了。 注意可以在后台设置沙箱登录账号,密码,充值。

     

再放一张图吧, 看到余额是不是很惊喜的样子, 这只是沙箱。

4. Server Api

沙箱调通之后端上基本上就没什么事情了, 等测试正式环境,记得把标注沙箱的那段代码注释即可。 接下来我们看一下Server端,先来张图


如果认真看官方Demo 就可以发现我们发起的orderinfo 的orderparams 和签名 都在客户端写得,莫名的脑袋一胀(这样安全吗)支付宝早想到了这里。 作为client只需要简单的把参数传给我们的server就行了。 下面我们来看一下server端的配置方法和处理逻辑。

4.1 JAVA服务端SDK生成APP支付订单

导入 Server端SDK 添加到项目依赖。 这里粘出来Java的Demo 简单作一下解析。
    //实例化客户端
       AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do", APP_ID, APP_PRIVATE_KEY, "json", CHARSET, ALIPAY_PUBLIC_KEY, "RSA2");
       //实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.app.pay
//创建请求对象
      AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
      model.setBody("我是测试数据");
      //SDK已经封装掉了公共参数,这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
      AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
      AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
      model.setSubject("App支付测试Java");model.setOutTradeNo(outtradeno);
      model.setTimeoutExpress("30m");
      model.setTotalAmount("0.01");
      model.setProductCode("QUICK_MSECURITY_PAY");
      request.setBizModel(model);///request.setNotifyUrl("商户外网可以访问的异步地址");
      }try { //这里和普通的接口调用不同,使用的是sdkExecute
          System.out.println(response.getBody());//就是orderString 可以直接给客户端请求,无需再做处理。
      } catch (AlipayApiException e) {e.printStackTrace();
      }

整个调用很简单, 因为大部分内容SDK已经帮我们做完了, 下载包里有源码,有兴趣的可以找找的看 肯定会有和端上签名一样的方法。 这这里注意的地方有request.setNotifyUrl("商户外网可以访问的异步地址"); 放置的参数是我们Server端暴露给支付宝回调的异步地址。

4.2 验证异步通知信息参数示例

我们知道在端上调用支付成功之后,支付宝会同步返回的数据,我们可以再端上根据RAS 生成的公钥进行验证支付结果。但有些时候会出现商户app在支付宝付款阶段被关闭(比如断网)导致无法正确收到同步结果,此时支付结果可以完全依赖服务端的异步通知。(当然这里对于用户来说,在离线状态下,支付宝会发短信告诉账户被扣款) 我们要做的当然是服务端进行验证支付宝给我们发送的支付结果请求,我们需要进行验证,然后再做处理。

 
//获取支付宝POST过来反馈信息
Map<String , String> params = new HashMap<String , String>() ;
Map requestParams = request.getParameterMap() ;
for (Iterator iter = requestParams .keySet().iterator() ; iter .hasNext() ; ) {
String name = (String) iter .next() ;
String[] values = (String[]) requestParams .get(name) ;
for ( int i = 0 ; i < values. length ; i++) {
valueStr = (i == values. length - 1 ) ? valueStr + values[i] String valueStr = "" ; :
valueStr + values[i] + "," ;
params .put(name , valueStr) ;
}
//boolean AlipaySignature.rsaCheckV1(Map<String, String> params, String publicKey, String charset, String sign_type)
//乱码解决,这段代码在出现乱码时使用。//valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");}//切记alipaypublickey是支付宝的公钥,请去open.alipay.com对应应用下查看。
boolean flag = AlipaySignature.rsaCheckV1( params , alipaypublicKey , charset , "RSA2" )
}

以上代码很容易理解, 注意 传的publishkey是公钥, 还有签名类型。 如果乱码了 可以解注释使用(现成的,可以说很贴心了有木有)。

5. 整体流程分析

上边介绍完了端上和Server的流程和方法。 下边我们来看一下整体流图。我们引用了官网的一张整体的sequence图


看完图之后是不是有种高屋建瓴的感觉。 从用户的操作到APP调用我们Server生成订单,调起支付宝SDK, 以及支付宝服务端与我们server 的异步支付通知,一目了然。没什么说的, 不懂得评论区留言。

6. 注意事项

构造交易数据并签名必须在商户服务端完成,商户的应用私钥绝对不能保存在商户APP客户端中,也不能从服务端下发。

同步返回的数据,只是一个简单的结果通知,商户确定该笔交易付款是否成功需要依赖服务端收到支付宝异步通知的结果进行判断。

商户系统接收到通知以后,必须通过验签(验证通知中的sign参数)来确保支付通知是由支付宝发送的。建议使用支付宝提供的SDK来完成,详细验签规则参考异步通知验签

支付宝支付的最小单位是1分, 格式是0.01 ,使用的是String格式。 这个和微信不一样,注意区分。 

注意沙箱环境和真实环境,以及沙箱账号和各个参数的正确配置。

7. 总结

当时在集成时候测试一般使用的是一分,两分等,但是实际APP中支付额度要远远大的多,例如9800, 12650 , 这就牵涉到第三方银行的当日支付额度问题(上线后用户提我们支付有问题,支付不了,一帮人脸吓黑了),可以提前告知,或者贴各个银行的支付额度给用户。

自己集成的Demo 地址: https://github.com/samuelhehe/PayDemo 记得换成自己的包名,参数。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/70652.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

支付宝支付接口的调用(支付宝支付的实现)

首先&#xff0c;下面是调用支付宝接口的官网&#xff1a; 支付宝开放平台https://open.alipay.com/platform/home.htmhttps://open.alipay.com/platform/home.htm我们这里只演示沙箱环境下的&#xff0c;正式环境需要审核什么的&#xff0c;正式环境与此配置类似&#xff0c;…

支付宝和微信的支付功能如何进行测试?

要分析测试点之前&#xff0c;我们先来梳理一下测试思维。总结来说&#xff0c;任何事物的测试思路都可以总结如下&#xff1a; 第一步&#xff1a;梳理产品的核心业务流程&#xff1a;明白这是个什么项目&#xff0c;实现了什么业务&#xff0c;以及是怎么实现的&#xff1f;…

Android App接入支付功能——支付宝支付

接入前准备 接入APP支付能力前&#xff0c;开发者需要完成以下前置步骤。 本文档展示了如何从零开始&#xff0c;使用支付宝开放平台服务端 SDK 快速接入App支付产品&#xff0c;完成与支付宝对接的部分。 接入准备——支付宝开发能力 一.下载官方sdk&#xff0c;将sdk放入…

推荐一个优秀人工智能(AI)学习网站:Quester AI

网站链接如下&#xff1a; QuesterAI 简要介绍&#xff1a; Quester AI全方位地整合AI学习资源&#xff0c;对每一个从业者&#xff0c;学习者开放&#xff0c;并且是免费开放。同时&#xff0c;Quester AI努力为AI领域学习者和爱好者大量提供持续的AI开源资源&#xff0c;给…

人工智能的数学方法

要成为一名出色的 AI 软件工程师&#xff0c;需要了解多少数学知识&#xff1f;&#x1f914; 在之前的一篇文章中&#xff0c;我写过学习任何主题或领域基础知识的重要性。我建议你先阅读它&#xff08;如果你还没有&#xff09;&#xff0c;以便完全理解这篇文章。 如果您已经…

让人工智能解数学题,可能没你想象的那么简单

来源&#xff1a;微软研究院AI头条&#xff0c;授权CSDN发布。 欢迎人工智能领域技术投稿、约稿、给文章纠错&#xff0c;请发送邮件至heyccsdn.net 约1500年前的古代数学著作《孙子算经》中记载了一个有趣的问题&#xff1a;“今有雉兔同笼&#xff0c;上有三十五头&#xff0…

给自己的课程打个广告

给自己的一些付费课程打个广告吧&#xff0c;金额不高&#xff0c;但你们的支持可以让我在写作、分享时更有动力&#xff0c;在媳妇面前也更有地位哈哈&#xff0c;谢谢支持了&#xff01;&#xff01; 有问题欢迎留言或者加我微信: sxkejinet 面试经验分享OkHttp3 和 Retrofit…

大学生个人职业生涯规划书PPT

大学生如何职业生涯规划主要是指根据个人的兴趣、性格特点、内在潜能来确立个人的职业发展目标&#xff0c;并根据自身情况对未来职业生涯上的短期目标、中期目标和长期目标进行设定&#xff0c;根据设定的这些目标来规划不同阶段下需要完成自我提升的通道。简而言之就是自身通…

python职业规划书_大学生职业规划书

职业生涯规划&#xff08;简称生涯规划&#xff09;&#xff0c;又叫职业生涯设计&#xff0c;是将个人与组织相结合&#xff0c;在对一个人职业生涯的主客观条件进行测定、分析、总结的基础上&#xff0c;对自己的兴趣、爱好、能力、特点进行综合分析与权衡&#xff0c;结合时…

计算机相关专业的学生如何规划自己的职业?

一、 前言 2017年曾经写过一篇关于学什么编程方向的文章&#xff0c;当时反响很大&#xff0c;有不少在校的社团组织私下授权转载我的文章。现在的大学&#xff0c;两极分化极其严重&#xff0c;优秀的同学毕业找工作顺风顺水&#xff0c;平庸甚至较差的同学&#xff0c;找工作…

大学生职业规划策划书

一.前言 我时常问自己“人生之路到底该如何去走”&#xff0c;长久以来我也不断思考并在实践中体会这个问题。心中记得这样一句话“走好每一步&#xff0c;这就是你的人生。”人生之路其实十分短暂&#xff0c;因为你度过的每一天或者每一秒就是你的人生。正因为人生经不起虚度…

大学生职业生涯规划的意义

前言职业生涯规划是指个人发展与组织发展相结合&#xff0c;通过对职业生涯的主客观因素分析、总结和测定&#xff0c;确定一个人的奋斗目标&#xff0c;并为实现这一事业职业目标&#xff0c;而预先进行生涯系统安排的过程。在任何社会、任何体制下&#xff0c;个人职业设计更…

职业生涯规划(career planning)

本文转自&#xff1a;WIKI智库&#xff08;https://wiki.mbalib.com/wiki/职业生涯规划&#xff09; 职业生涯规划的定义 职业生涯规划&#xff08;简称生涯规划&#xff09;&#xff0c;又叫职业生涯设计&#xff0c;是指个人与组织相结合&#xff0c;在对一个人职业生涯的主…

计算机个人职业生涯规划

个人职业生涯规划 摘要 在当下竞争激烈的时代&#xff0c;如果没有做好充分的准备就去迎接社会的毒打&#xff0c;往往是遍体鳞伤。而一个人的职业规划将是我们面对社会的最好的铠甲&#xff0c;即使是简单的未来规划&#xff0c;也会使你成长的路上少点磕绊&#xff0c;所以…

大一上:大学生职业生涯规划书【自我性格、气质、及其优缺点的分析】

大学生职业生涯规划书 一、My MBTI 二、自我描述 我的性格类型倾向为“ INTJ ”(内向 直觉 思维 判断 倾向度&#xff1a; I57 N100 T86 J100 不假思索指数&#xff1a;11) 我在实现自己的想法和达成自己的目标时有创新的想法和非凡的动力。能很快洞察到外界事物间的规律并形…

软件工程大学生职业规划书

引言 在今天这个人才竞争时代&#xff0c;职业生涯规划开始成为在人争夺战中 另一重要利器&#xff0c;对企业而言&#xff0c;如何体现公司“以人为本”人才理念&#xff0c; 关注员工人才理念&#xff0c;关注员工持续成长&#xff0c;职业生涯规划是一种有效手段; 而对每个人…

职业生涯规划访谈,写给在校的你们

今天一位在校大学生邀请我在线做一个关于职业生涯规划的访谈&#xff0c;在此我将他提出的问题以及我个人的一些看法贴出&#xff0c;希望能给在校或是即将毕业的你们有所帮助。 问: 老师你好&#xff0c;就是我想问一下我们计算机专业的大学生&#xff0c;在课堂上学好必要的知…

大学生职业生涯发展与规划

《创业教育课程&#xff08;一&#xff09;----大学生职业生涯发展与规划》 结课作业要求 作业选题&#xff1a;大学规划书 作业要求&#xff1a;从自身的情况、现状出发&#xff0c;有针对性地制定一份详尽的增强自身就业能力的大学规划书&#xff0c;根据相关社会要求有针对性…

流利阅读 2019.2.23 China’s Forbidden City opens to the general public at night for the first time in 94

下载 笔记版/无笔记版 pdf资料&#xff1a; GitHub - zhbink/LiuLiYueDu: 流利阅读pdf汇总 本文内容全部来源于流利阅读。流利阅读对每期内容均有很好的文章讲解&#xff0c;向您推荐。 您可以关注微信公众号&#xff1a;流利阅读 了解详情。 China’s Forbidden City opens to…

英语阅读——2004

文章目录 词汇名词性从句1.主语从句与It形式主语1.1主语从句1.2It形式主语 独立主格结构with独立主格结构倒装句1.完全倒装句1.1副词在句首的倒装1.1.1地点副词在句首的倒装(here、there)1.1.2时间副词在句首的倒装(now、then)1.1.3表运动方向的副词在句首的倒装(in、out、up、…