实现手机扫描二维码页面登录,类似web微信-第三篇,手机客户端

时间:2022-05-05 03:02:53

转自:http://www.cnblogs.com/fengyun99/p/3541254.html

上一篇,介绍了二维码生成的机制,紧接着,我们就要开发手机客户端来识别这个二维码。

二维码,实际上是记录了这个页面的sessionID,目的是为了最后让服务器能通过long polling的机制去通知到这个浏览器。

创建二维码的时候我们采用了nodejs的QRcode库,其实如果换了其他的web服务器,也可以有其他的可选包,例如zxing。

手机上用的比较多的就是zxing库,不过用过的人都知道,zxing库的核心core只是提供二维码的解析,而应用程序本身对摄像头的操作部分必须参考zxing的应用源码。

那个源码比较的复杂,虽然很好理解,但是代码量太大了。如果要分析那部分源码,文章就要写的长篇大论了,所以这一次,我们不用zxing库,而选择一个更为高效实用的android二维码扫描组件:zbar

实现手机扫描二维码页面登录,类似web微信-第三篇,手机客户端

ZBar不是纯的java代码,而是用了C编译的native library,因此识别的效率上比zxing要高很多。

闲话少说,先看看程序运行的一系列流程吧:

第一步,登录手机软件,我们做测试用,就只需要输入一个用户名,提交到服务器,返回一个token

为什么要做第一步,因为我们实现手机二维码登录的基础原则就是我们的手机客户端必须的登录的,这样才能作为一个凭据

例如微信,假如你不登录是不能扫描的,所以我们的例子模拟一个登录的过程

实现手机扫描二维码页面登录,类似web微信-第三篇,手机客户端实现手机扫描二维码页面登录,类似web微信-第三篇,手机客户端实现手机扫描二维码页面登录,类似web微信-第三篇,手机客户端

第二步,登录成功之后,开始扫描,二维码就显示在屏幕上

实现手机扫描二维码页面登录,类似web微信-第三篇,手机客户端

第三步,扫描完成后,确认是否登录网页

实现手机扫描二维码页面登录,类似web微信-第三篇,手机客户端实现手机扫描二维码页面登录,类似web微信-第三篇,手机客户端

最后,页面提示登录完成

实现手机扫描二维码页面登录,类似web微信-第三篇,手机客户端

下面开始,由于long polling的过程我已经做好,因此手机软件才能正常运行,而今天我们只说手机客户端,服务器端的内容下一篇再说,所以,我们先假设所有的接口都OK

手机客户端分为三个Activity,分别为登录,扫描,确认

先做第一个activity

eclipse建立项目,为了符合android4的UI规范,我们采用了sherlock actionbar来实现3.x一下版本android系统的actionbar

因此,项目需要引用actionbar lib,sherlock actionbar的库不能直接引用jar包,必须要下载源码并且以lib的方式引用源码

引用完之后,新建一个class,叫做LoginActivity 继承自SherlockActivity

为了要实现在actionbar上的loading进度圈,需要设置窗体的属性

  1. requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
  2. setContentView(R.layout.login);
  3. setSupportProgressBarIndeterminateVisibility(false);

第一个activity界面很简单,就是几个按钮,但是需要有一次和服务器的通信,也就是登录的过程如果登录成功,则显示下一步扫描的按钮,第一个activity很简单

全部代码:

  1. package com.zbiti.qrcodelogin.activity;
  2. import java.util.logging.LogRecord;
  3. import android.content.Context;
  4. import android.content.Intent;
  5. import android.os.Bundle;
  6. import android.os.Handler;
  7. import android.os.Message;
  8. import android.view.View;
  9. import android.view.View.OnClickListener;
  10. import android.widget.Button;
  11. import android.widget.EditText;
  12. import android.widget.TextView;
  13. import android.widget.Toast;
  14. import com.actionbarsherlock.app.SherlockActivity;
  15. import com.actionbarsherlock.view.Window;
  16. import com.zbiti.qrcodelogin.R;
  17. import com.zbiti.qrcodelogin.util.BaseHttpClient;
  18. public class LoginActivity extends SherlockActivity {
  19. private Context mContext;
  20. private TextView txtInfo;
  21. private EditText txtUserName;
  22. private Button btnLogin;
  23. private Button btnStartScan;
  24. private Button btnRelogin;
  25. private String token = null;
  26. private final static String LOGIN_URL = "http://192.168.111.109:8000/moblogin?";
  27. private final static int MSG_LOGIN_FAILED = 0;
  28. private final static int MSG_LOGIN_OK = 1;
  29. @Override
  30. protected void onCreate(Bundle savedInstanceState) {
  31. super.onCreate(savedInstanceState);
  32. mContext = LoginActivity.this;
  33. requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
  34. setContentView(R.layout.login);
  35. setSupportProgressBarIndeterminateVisibility(false);
  36. // reference all used view
  37. txtInfo = (TextView) findViewById(R.id.txt_info);
  38. txtUserName = (EditText) findViewById(R.id.edit_username);
  39. btnLogin = (Button) findViewById(R.id.btn_client_login);
  40. btnStartScan = (Button) findViewById(R.id.btn_startscan);
  41. btnRelogin = (Button) findViewById(R.id.btn_relogin);
  42. btnRelogin.setOnClickListener(new OnClickListener() {
  43. @Override
  44. public void onClick(View v) {
  45. txtInfo.setText(R.string.login_hint);
  46. findViewById(R.id.cont_login).setVisibility(View.VISIBLE);
  47. findViewById(R.id.cont_loggedin).setVisibility(View.GONE);
  48. }
  49. });
  50. btnLogin.setOnClickListener(new OnClickListener() {
  51. @Override
  52. public void onClick(View v) {
  53. setSupportProgressBarIndeterminateVisibility(true);
  54. new Thread(new Runnable() {
  55. @Override
  56. public void run() {
  57. getToken();
  58. }
  59. }).start();
  60. }
  61. });
  62. btnStartScan.setOnClickListener(new OnClickListener() {
  63. @Override
  64. public void onClick(View v) {
  65. Intent intent = new Intent();
  66. intent.putExtra("token", token);
  67. intent.setClass(mContext, MainActivity.class);
  68. startActivity(intent);
  69. }
  70. });
  71. }
  72. private void getToken() {
  73. String userName = txtUserName.getText().toString().trim();
  74. if (!userName.equals("")) {
  75. try {
  76. token = BaseHttpClient.httpGet(LOGIN_URL + userName).trim();
  77. } catch (Exception e) {
  78. // TODO Auto-generated catch block
  79. e.printStackTrace();
  80. }
  81. System.out.println(">>>" + token);
  82. }
  83. if (token == null)
  84. return;
  85. if (token.equals("")) {
  86. handler.sendEmptyMessage(MSG_LOGIN_FAILED);
  87. } else {
  88. handler.sendEmptyMessage(MSG_LOGIN_OK);
  89. }
  90. }
  91. private Handler handler = new Handler() {
  92. @Override
  93. public void handleMessage(Message msg) {
  94. if (msg.what == MSG_LOGIN_OK) {
  95. // 成功获得token
  96. setSupportProgressBarIndeterminateVisibility(false);
  97. txtInfo.setText(getString(R.string.token_info, token));
  98. findViewById(R.id.cont_login).setVisibility(View.GONE);
  99. findViewById(R.id.cont_loggedin).setVisibility(View.VISIBLE);
  100. } else if (msg.what == MSG_LOGIN_FAILED) {
  101. setSupportProgressBarIndeterminateVisibility(false);
  102. Toast.makeText(mContext, R.string.login_failed,
  103. Toast.LENGTH_SHORT).show();
  104. }
  105. }
  106. };
  107. }

布局文件:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. android:orientation="vertical" >
  6. <LinearLayout
  7. android:layout_width="match_parent"
  8. android:layout_height="wrap_content"
  9. android:gravity="center_vertical"
  10. android:orientation="horizontal" >
  11. <TextView
  12. android:id="@+id/txt_info"
  13. android:layout_width="match_parent"
  14. android:layout_height="wrap_content"
  15. android:layout_margin="20dp"
  16. android:drawableLeft="@drawable/chat"
  17. android:drawablePadding="10dp"
  18. android:text="@string/login_hint" />
  19. </LinearLayout>
  20. <LinearLayout
  21. android:id="@+id/cont_loggedin"
  22. android:layout_width="match_parent"
  23. android:layout_height="wrap_content"
  24. android:orientation="vertical"
  25. android:visibility="gone" >
  26. <LinearLayout
  27. android:layout_width="match_parent"
  28. android:layout_height="wrap_content"
  29. android:orientation="vertical"
  30. android:paddingLeft="20dp"
  31. android:paddingRight="20dp"
  32. android:paddingTop="10dp" >
  33. <Button
  34. android:id="@+id/btn_startscan"
  35. android:layout_width="match_parent"
  36. android:layout_height="wrap_content"
  37. android:text="@string/start_scan" >
  38. </Button>
  39. <Button
  40. android:id="@+id/btn_relogin"
  41. android:layout_marginTop="10dp"
  42. android:layout_width="match_parent"
  43. android:layout_height="wrap_content"
  44. android:text="@string/relogin" >
  45. </Button>
  46. </LinearLayout>
  47. </LinearLayout>
  48. <LinearLayout
  49. android:id="@+id/cont_login"
  50. android:layout_width="match_parent"
  51. android:layout_height="wrap_content"
  52. android:orientation="vertical" >
  53. <LinearLayout
  54. android:layout_width="match_parent"
  55. android:layout_height="wrap_content"
  56. android:orientation="horizontal"
  57. android:paddingLeft="20dp"
  58. android:paddingRight="20dp"
  59. android:paddingTop="10dp" >
  60. <TextView
  61. android:layout_width="60dp"
  62. android:layout_height="wrap_content"
  63. android:text="@string/user_name" />
  64. <EditText
  65. android:id="@+id/edit_username"
  66. android:layout_width="match_parent"
  67. android:layout_height="wrap_content" />
  68. </LinearLayout>
  69. <LinearLayout
  70. android:layout_width="match_parent"
  71. android:layout_height="wrap_content"
  72. android:orientation="horizontal"
  73. android:paddingLeft="20dp"
  74. android:paddingRight="20dp"
  75. android:paddingTop="10dp" >
  76. <Button
  77. android:id="@+id/btn_client_login"
  78. android:layout_width="match_parent"
  79. android:layout_height="wrap_content"
  80. android:text="@string/login" >
  81. </Button>
  82. </LinearLayout>
  83. </LinearLayout>
  84. </LinearLayout>

代码里的 privatefinalstatic StringLOGIN_URL ="http://192.168.111.109:8000/moblogin?";

这一行是我本地测试用的模拟验证的服务器地址,和生成二维码的页面一样,都是Nodejs生成的,代码我们下一篇解释,这个接口接收手机填写的用户名,并且通过sha1进行加密,将加密过后的字符串返回给手机,手机将这个字符串作为token变量并且会传递下去。

下面开始第二个activity,就是扫描界面

首先引用zbar的包,将zbar相关的包拷贝进libs目录

实现手机扫描二维码页面登录,类似web微信-第三篇,手机客户端

包含的so文件就是c编写的native code

新建类MainActivity继承自SherlockActivity

实现扫描的代码可以从zbar的例子里整,这里不重复

需要把上一个activity传递的token获取,并往下传递

  1. @Override
  2. public void onCreate(Bundle savedInstanceState) {
  3. super.onCreate(savedInstanceState);
  4. setContentView(R.layout.main);
  5. getSupportActionBar().setDisplayHomeAsUpEnabled(true);
  6. autoFocusHandler = new Handler();
  7. preview = (FrameLayout) findViewById(R.id.cameraPreview);
  8. // mCamera = getCameraInstance();
  9. Intent intent = getIntent();
  10. token = intent.getStringExtra("token");
  11. if (token == null || token.equals(""))
  12. finish();
  13. }

在扫描完成的回调里,我们将扫描获得sessionID和token一起往下一个activity传递

  1. PreviewCallback previewCb = new PreviewCallback() {
  2. public void onPreviewFrame(byte[] data, Camera camera) {
  3. Camera.Parameters parameters = camera.getParameters();
  4. Size size = parameters.getPreviewSize();
  5. Image barcode = new Image(size.width, size.height, "Y800");
  6. barcode.setData(data);
  7. int result = scanner.scanImage(barcode);
  8. String qrcodeString = null;
  9. if (result != 0) {
  10. previewing = false;
  11. mCamera.setPreviewCallback(null);
  12. mCamera.stopPreview();
  13. SymbolSet syms = scanner.getResults();
  14. for (Symbol sym : syms) {
  15. qrcodeString = sym.getData();
  16. }
  17. }
  18. if (qrcodeString != null) {
  19. Intent intent = new Intent();
  20. intent.setClass(MainActivity.this, ConfirmActivity.class);
  21. intent.putExtra("qrcodestring", qrcodeString);
  22. intent.putExtra("token", token);
  23. startActivity(intent);
  24. }
  25. }
  26. };

在完成扫描的回调里,我们把qrcodestring和token都提交给下一个activity

接着,我们来写第三个activity

仍然创建一个类集成sherlockactivity,类名ConfirmActivity

这个activity在启动的时候,也就意味着,扫描成功了,那么就先通知服务器端,扫描成功,页面也会即时展示出扫描成功,等待手机确认登录的信息

接下来,如果点确认登录,则通知服务器确认登录。

因此我们有2个接口

private final static StringSCANNED_URL ="http://192.168.111.109:8000/scanned?";

privatefinalstatic StringCONFIRMLOGIN_URL ="http://192.168.111.109:8000/confirmed?";

一个是通知服务器已经成功扫描的http接口,一个是通知服务器确认登录的接口。参数都是sessionID,也就是二维码带的信息,和用户token。

  1. package com.zbiti.qrcodelogin.activity;
  2. import android.content.Context;
  3. import android.content.Intent;
  4. import android.os.Bundle;
  5. import android.os.Handler;
  6. import android.os.Message;
  7. import android.view.View;
  8. import android.view.View.OnClickListener;
  9. import android.widget.Button;
  10. import android.widget.TextView;
  11. import com.actionbarsherlock.app.SherlockActivity;
  12. import com.actionbarsherlock.view.MenuItem;
  13. import com.zbiti.qrcodelogin.R;
  14. import com.zbiti.qrcodelogin.util.BaseHttpClient;
  15. public class ConfirmActivity extends SherlockActivity {
  16. private Context mContext;
  17. private String sessionID;
  18. private String token;
  19. private final static String SCANNED_URL = "http://192.168.111.109:8000/scanned?";
  20. private final static String CONFIRMLOGIN_URL = "http://192.168.111.109:8000/confirmed?";
  21. private final static int LOGIN_SUCCESS=1;
  22. private final static int LOGIN_FAIL=0;
  23. private Button btnConfirmLogin;
  24. private Button btnCancel;
  25. private TextView txtInfo;
  26. @Override
  27. protected void onCreate(Bundle savedInstanceState) {
  28. super.onCreate(savedInstanceState);
  29. mContext = ConfirmActivity.this;
  30. setContentView(R.layout.confirm_login);
  31. getSupportActionBar().setDisplayHomeAsUpEnabled(true);
  32. btnConfirmLogin = (Button) findViewById(R.id.btn_login);
  33. btnCancel = (Button) findViewById(R.id.btn_cancel);
  34. txtInfo=(TextView)findViewById(R.id.txt_confirm_info);
  35. btnConfirmLogin.setOnClickListener(new OnClickListener() {
  36. @Override
  37. public void onClick(View v) {
  38. new Thread(new Runnable() {
  39. @Override
  40. public void run() {
  41. notifyConfirmed();
  42. }
  43. }).start();
  44. }
  45. });
  46. btnCancel.setOnClickListener(new OnClickListener() {
  47. @Override
  48. public void onClick(View v) {
  49. finish();
  50. }
  51. });
  52. Intent intent = getIntent();
  53. sessionID = intent.getStringExtra("qrcodestring");
  54. token = intent.getStringExtra("token");
  55. if (sessionID == null || sessionID == null) {
  56. finish();
  57. }
  58. new Thread(new Runnable() {
  59. @Override
  60. public void run() {
  61. notifyScanned();
  62. }
  63. }).start();
  64. }
  65. private void notifyConfirmed() {
  66. String url = CONFIRMLOGIN_URL + "token=" + token + "&sessionid="
  67. + sessionID;
  68. String s = null;
  69. try {
  70. s = BaseHttpClient.httpGet(url);
  71. if(s.equals("confirmed")){
  72. handler.sendEmptyMessage(LOGIN_SUCCESS);
  73. }else{
  74. handler.sendEmptyMessage(LOGIN_FAIL);
  75. }
  76. } catch (Exception e) {
  77. e.printStackTrace();
  78. }
  79. }
  80. private void notifyScanned() {
  81. String url = SCANNED_URL + "token=" + token + "&sessionid=" + sessionID;
  82. String s = null;
  83. try {
  84. s = BaseHttpClient.httpGet(url);
  85. } catch (Exception e) {
  86. e.printStackTrace();
  87. }
  88. }
  89. private Handler handler= new Handler(){
  90. @Override
  91. public void handleMessage(Message msg) {
  92. if(msg.what==LOGIN_FAIL){
  93. txtInfo.setText(R.string.pc_login_fail);
  94. }else if(msg.what==LOGIN_SUCCESS){
  95. btnConfirmLogin.setVisibility(View.GONE);
  96. btnCancel.setVisibility(View.GONE);
  97. txtInfo.setText(R.string.pc_login_succuess);
  98. }
  99. }
  100. };
  101. @Override
  102. public boolean onMenuItemSelected(int featureId, MenuItem item) {
  103. if (item.getItemId() == android.R.id.home) {
  104. finish();
  105. }
  106. return super.onMenuItemSelected(featureId, item);
  107. }
  108. }

布局如下:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. android:orientation="vertical" >
  6. <ImageView
  7. android:layout_width="wrap_content"
  8. android:layout_height="wrap_content"
  9. android:layout_gravity="center_horizontal"
  10. android:layout_marginBottom="10dp"
  11. android:layout_marginLeft="40dp"
  12. android:layout_marginRight="40dp"
  13. android:layout_marginTop="10dp"
  14. android:src="@drawable/pcs" />
  15. <TextView android:id="@+id/txt_confirm_info"
  16. android:layout_width="wrap_content"
  17. android:layout_height="wrap_content"
  18. android:layout_gravity="center_horizontal"
  19. android:text="@string/confirm_login_label"
  20. android:textSize="18sp" />
  21. <Button android:id="@+id/btn_login"
  22. android:layout_width="match_parent"
  23. android:layout_height="wrap_content"
  24. android:layout_marginTop="20dp"
  25. android:layout_marginLeft="40dp"
  26. android:layout_marginRight="40dp"
  27. android:text="@string/btn_confirm_login" />
  28. <Button android:id="@+id/btn_cancel"
  29. android:layout_width="match_parent"
  30. android:layout_height="wrap_content"
  31. android:layout_marginLeft="40dp"
  32. android:layout_marginRight="40dp"
  33. android:text="@string/btn_cancel" />
  34. </LinearLayout>

这样一个手机客户端就完成了,其中用到的http请求的过程如下:

  1. public static String httpGet(String url) throws Exception{
  2. String result = null;
  3. HttpClient client = new DefaultHttpClient();
  4. HttpGet get = new HttpGet(url);
  5. HttpResponse response = client.execute(get);
  6. if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
  7. InputStream is = response.getEntity().getContent();
  8. result=inStream2String(is);
  9. }
  10. return result;
  11. }
  12. public static String inStream2String(InputStream is) throws Exception {
  13. ByteArrayOutputStream baos = new ByteArrayOutputStream();
  14. byte[] buf = new byte[1024];
  15. int len = -1;
  16. while ((len = is.read(buf)) != -1) {
  17. baos.write(buf, 0, len);
  18. }
  19. return new String(baos.toByteArray());
  20. }

string如下

  1. <resources>
  2. <string name="app_name">二维码登录客户端</string>
  3. <string name="confirm_login_title">已经扫描,请确认登录</string>
  4. <string name="confirm_login_label">即将在浏览器上登录系统\n请确认是否是本人操作</string>
  5. <string name="btn_confirm_login">我确认登录系统</string>
  6. <string name="btn_cancel">取消</string>
  7. <string name="user_name">用户名</string>
  8. <string name="user_password">密 码</string>
  9. <string name="login">登录</string>
  10. <string name="relogin">重新登录</string>
  11. <string name="start_scan">开始扫描</string>
  12. <string name="login_failed">登录失败</string>
  13. <string name="login_hint">随便输入用户名,登录之后,服务器会返回一个代表你身份的token。</string>
  14. <string name="token_info">您已经成功登录,token:\n %1$s</string>
  15. <string name="pc_login_succuess">网页登录成功</string>
  16. <string name="pc_login_fail">网页登录失败,可能您扫描的页面已过期!</string>
  17. </resources>

原创文章,转载请注明出处

【为了方便测试,我把客户端打包上传,可以点这里下载 http://download.csdn.net/detail/otangba/4857059 】

测试程序在运行时可以设置服务器地址,服务器我们在下一篇会介绍。

实现手机扫描二维码页面登录,类似web微信-第三篇,手机客户端

实现手机扫描二维码页面登录,类似web微信-第三篇,手机客户端的更多相关文章

  1. 实现手机扫描二维码页面登录,类似web微信-第一篇,业务分析

    转自:http://www.cnblogs.com/fengyun99/p/3541249.html 关于XMPP组件的文章,先休息两天,好歹已经完整的写了一份. 这两天,先实现一套关于web微信扫描 ...

  2. 实现手机扫描二维码页面登录,类似web微信-第二篇,关于二维码的自动生成

    转自:http://www.cnblogs.com/fengyun99/p/3541251.html 接上一章,我们已经基本把业务逻辑分析清楚了 下面我们第一步,实现二维码的web动态生成. 页面的二 ...

  3. 实现手机扫描二维码页面登录,类似web微信-第四篇,服务器端

    转自:http://blog.csdn.net/otangba/article/details/8273952 终于到了服务器端,第三篇的手机客户端如果已经下载了的话,没有服务器是不能正常运行的. 服 ...

  4. 手机扫描二维码下载APP,根据操作系统不同自动下载

    Android和IOS手机扫描二维码下载APP,根据OS不同,自动处理相应下载操作.IOS自动跳转至AppStore应用下载页,Android自动下载应用的apk包. <script type= ...

  5. Android扫描二维码 实现 登录网页

    工程代码:ScanQRcode.zip ------------------------------------------------------------------ 1. 扫描二维码登录的实现 ...

  6. uni-app开发经验分享十三:实现手机扫描二维码并跳转全过程

    最近使用 uni-app 开发 app ,需要实现一个调起手机摄像头扫描二维码功能,官网API文档给出了这样一个demo: // 允许从相机和相册扫码 uni.scanCode({ success: ...

  7. asp:手机扫描二维码跳转手机版

    如果想手机扫描用pc版网站生成的二维码跳转到对应的手机版的话,请在pc端的首页的<head></head>标签里面加入下面内容:   <script src=" ...

  8. 大众点评试水O2O新模式:实体店试穿,扫描二维码付款 现场取货

    在餐饮美食行业取得不错的成绩之后,大众点评将触角延伸到了线下的传统商铺,开始涉足线下商品的 O2O 团购.和传统的线上下单,线下消费的 O2O 模式不同.大众点评的 O2O 团购用户,可在店内试穿后通 ...

  9. 扫描二维码自动识别手机系统(Android&sol;IOS)

    移动互联网发展迅速,各种APP的开发都会推出多个版本(多终端),比如:iPhone版.iPad版.Android版.有些APP还会考虑覆盖到多个国家(国际化),比如:中文版.英文版.日文版.韩文版等. ...

随机推荐

  1. samba 服务器的搭建

    一,安装samba4 不要直接 yum install samba ,默认安装的是samba3版本,但这个版本有问题(open_rpc_pipe_p: copy_serverinfo failed这个 ...

  2. sql server 内置ETL工具学习(一) BCP篇

    sql server 内置ETL工具学习 常用的导入方式:bcp, BULK INSERT,OPENROWSET和 SSIS. BCP BCP全称BULK COPY PROGRAM 有以下特点: 命令 ...

  3. 【转】唱吧CEO陈华:创业四年,我积累的7点管理经验

    现象级产品“唱吧”至今拥有令人羡慕的用户数量,3亿.而这一切,却用了短短不到四年时间.唱吧团队如何应对越来越复杂的市场变化:怎样用人,才能不断激励新老员工做出更棒的业绩:CEO陈华又如何用“下大雪”模 ...

  4. AsyncEnumerableExtensions&period;cs z

    public static class Extensions { public static async Task ForEachAsync<T, U>(this IEnumerable& ...

  5. 武汉科技大学ACM :1005&colon; A&plus;B for Input-Output Practice &lpar;V&rpar;

    Problem Description Your task is to calculate the sum of some integers. Input Input contains an inte ...

  6. 一个简单用原生js实现的小游戏----FlappyBird

    这是一个特别简单的用原生js实现的一个小鸟游戏,比较简单,适合新手练习 这是html结构 <!DOCTYPE html><html lang="en">&l ...

  7. Docker 集群环境实现的新方式

    近几年来,Docker 作为一个开源的应用容器引擎,深受广大开发者的欢迎.随着 Docker 生态圈的不断建设,应用领域越来越广.云计算,大数据,移动技术的快速发展,加之企业业务需求的不断变化,紧随技 ...

  8. Python中的基本语法

    #Python的基本语法: #1.了解缩进 #Python中没有{}来表示一个代码块,但是Python使用缩进来完成区别代码框架 #那么在Python中一个缩进一般等于4个空格,当然你也可以使用TAB ...

  9. WIFI&lowbar;认证加密学习&lowbar;STA&lowbar;AP&lowbar;WDS

    2-1.1_15_使用卡1_准备工作及配置内核====================================1.无线网卡连接上路由或AP之后使用上是和有线网卡是一样的,都是socket编程. ...

  10. 在Excel中导入文本文件(CSV&sol;TXT&rpar;,自定义隔离符号

    经常需要在Excel中导入文本文件,但是需要自定义隔离符号,例如空格或者逗号,参考一下方法: