Android+SpringBoot前后端分离实现登录注册

一、登录

1.界面设计

在这里插入图片描述

2.Android端

(1)布局文件(activity_login)

在这里插入图片描述

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <include layout="@layout/main_title_bar"/>

    <com.example.CircleImageView
        android:id="@+id/iv_head"
        android:layout_width="wrap_content"
        android:layout_height="140dp"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="10dp"
        android:contentDescription="@null"
        android:src="@drawable/logo1" />

    <EditText
        android:singleLine="true"
        android:id="@+id/et_user_name"
        android:layout_width="fill_parent"
        android:layout_height="48dp"
        android:background="@drawable/zcan3"
        android:layout_marginTop="35dp"
        android:layout_marginLeft="35dp"
        android:layout_marginRight="35dp"
        android:drawableLeft="@drawable/yhm1"
        android:paddingLeft="8dp"
        android:drawablePadding="10dp"
        android:hint="@string/name"
        android:gravity="center_vertical"
        android:textColorHint="#a3a3a3"
        android:textColor="#000000"
        android:textSize="14sp"/>

    <EditText
        android:singleLine="true"
        android:id="@+id/et_pwd"
        android:layout_width="fill_parent"
        android:layout_height="48dp"
        android:background="@drawable/zcan3"
        android:layout_marginTop="10dp"
        android:layout_marginLeft="35dp"
        android:layout_marginRight="35dp"
        android:drawableLeft="@drawable/mm2"
        android:paddingLeft="8dp"
        android:drawablePadding="10dp"
        android:inputType="textPassword"
        android:hint="@string/pwd"
        android:gravity="center_vertical"
        android:textColorHint="#a3a3a3"
        android:textColor="#000000"
        android:textSize="14sp"/>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="35dp"
        android:layout_marginRight="35dp"
        android:layout_marginTop="20dp"
        android:orientation="horizontal" >

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="40dp"
            android:background="@drawable/linearlayout" >

            <EditText
                android:id="@+id/et_phoneCodes"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_marginLeft="10dp"
                android:layout_marginRight="10dp"
                android:background="@null"
                android:textColor="#000000"
                android:textColorHint="#a3a3a3"
                android:hint="请输入右侧验证码" />
        </LinearLayout>

        <ImageView
            android:id="@+id/iv_showCode"
            android:layout_width="100dp"
            android:layout_marginLeft="10dp"
            android:layout_height="match_parent" />

    </LinearLayout>
    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:layout_marginLeft="35dp"
        android:orientation="horizontal">
        <CheckBox
            android:id="@+id/cb_box"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="记住密码"/>
    </LinearLayout>
    <Button
        android:text="@string/login"
        android:id="@+id/btn_login"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="15dp"
        android:layout_marginLeft="35dp"
        android:layout_marginRight="35dp"
        android:textColor="@android:color/white"
        android:textSize="20sp"
        android:textStyle="bold"
        android:layout_width="fill_parent"
        android:layout_height="50dp"
        android:background="@drawable/register_selector"/>

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_marginTop="15dp"
        android:layout_marginLeft="35dp"
        android:layout_marginRight="35dp"
        android:gravity="center_horizontal"
        android:orientation="horizontal">

        <TextView
            android:id="@+id/tv_register"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:gravity="center_horizontal"
            android:padding="8dp"
            android:text="@string/tv_register"
            android:textSize="14sp"
            android:textColor="@color/white"
            android:background="@drawable/register_selector"/>

        <TextView
            android:id="@+id/tv_find_pwd"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:gravity="center_horizontal"
            android:padding="8dp"
            android:text="@string/find_pwd"
            android:textSize="14sp"
            android:textColor="@color/white"
            android:background="@drawable/register_selector"/>
    </LinearLayout>

</LinearLayout>


(2)java文件(LoginActivity)

package com.example.activity;

import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ActivityInfo;
import android.graphics.Color;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;

import androidx.preference.PreferenceManager;

import com.example.MainActivity;
import com.example.R;
import com.example.bean.User;
import com.example.utils.CodeUtils;
import com.example.utils.SharedPreferencesUtil;
import com.zhy.http.okhttp.OkHttpUtils;
import com.zhy.http.okhttp.callback.StringCallback;

import java.util.ArrayList;
import java.util.List;

import okhttp3.Call;
import okhttp3.OkHttpClient;

public class LoginActivity extends Activity {

    private TextView tv_main_title;//标题
    private TextView tv_back;		//返回按钮
    private TextView tv_register,tv_find_pwd;//立即注册、找回密码的控件
    private Button btn_login;	//登录按钮
    private RelativeLayout rl_title_bar;//标题布局
    private EditText et_user_name,et_pwd;//用户名、密码的控件
    private String username,pwd,spPwd;//用户名、密码的控件的获取值
    private CheckBox cb_box;
    //验证码
    private ImageView iv_showCode;
    private EditText et_phoneCode;
    //产生的验证码
    private String realCode;
    private  List<User> userList = new ArrayList<>();
    private SharedPreferencesUtil su;
    OkHttpClient client = new OkHttpClient();
    private SharedPreferences pref;
    private SharedPreferences.Editor editor;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
        //设置此界面为竖屏
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        init();
        //验证码
        reacode();
//        getData();
    }
    //验证码
    private void reacode() {

        //将验证码用图片的形式显示出来
        iv_showCode.setImageBitmap(CodeUtils.getInstance().createBitmap());
        realCode =CodeUtils.getInstance().getCode();
    }
    private void init() {
        // TODO Auto-generated method stub
        tv_main_title = (TextView) findViewById(R.id.tv_main_title);
        tv_main_title.setText("登录");
        tv_back = ((TextView) findViewById(R.id.tv_back));
        tv_register = (TextView) findViewById(R.id.tv_register);
        tv_find_pwd = (TextView) findViewById(R.id.tv_find_pwd);
        pref = PreferenceManager.getDefaultSharedPreferences(this);
        su = SharedPreferencesUtil.getInstance(getApplicationContext());
        btn_login = (Button) findViewById(R.id.btn_login);
        et_user_name = (EditText) findViewById(R.id.et_user_name);
        rl_title_bar = (RelativeLayout) findViewById(R.id.title_bar);
        et_pwd = (EditText) findViewById(R.id.et_pwd);
        cb_box = (CheckBox) findViewById(R.id.cb_box);
        rl_title_bar.setBackgroundColor(Color.parseColor("#30b4ff"));
        //验证码
        et_phoneCode = (EditText) findViewById(R.id.et_phoneCodes);
        iv_showCode = (ImageView) findViewById(R.id.iv_showCode);
        boolean isremember = pref.getBoolean("cb_box", false);
        if (isremember) {
            //将账号和密码全部设置到文本框中
            String phone = pref.getString("phone", "");
            String password = pref.getString("password", "");
            et_user_name.setText(phone);
            et_pwd.setText(password);
            cb_box.setChecked(true);
        }

        //图片验证码刷新
        iv_showCode.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View arg0) {
                // TODO Auto-generated method stub
                iv_showCode.setImageBitmap(CodeUtils.getInstance().createBitmap());
                realCode = CodeUtils.getInstance().getCode();
            }
        });
        //返回按钮的点击事件
        tv_back.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View arg0) {
                // TODO Auto-generated method stub
                LoginActivity.this.finish();
            }
        });
        //立即注册控件的点击事件
        tv_register.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View arg0) {
                // TODO Auto-generated method stub
                Intent intent = new Intent(LoginActivity.this, RegisterActivity.class);
                startActivityForResult(intent, 1);
            }
        });
        //找回密码点击事件
        tv_find_pwd.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View arg0) {
                // TODO Auto-generated method stub
                //跳转到找回密码界面(此界面暂时未创建)
                Intent intent = new Intent(LoginActivity.this, FindPswActivity.class);
                startActivityForResult(intent, 1);
            }
        });
        //登录按钮点击事件
        btn_login.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View arg0) {
                // TODO Auto-generated method stub
                username = et_user_name.getText().toString().trim();
                pwd = et_pwd.getText().toString().trim();
                OkHttpUtils
                        .get()
                        .url("http://192.168.119.1:8086/login")
                        .addParams("userId", username)
                        .addParams("password", pwd)
                        .build()
                        .execute(new StringCallback() {
                            @Override
                            public void onError(Call call, Exception e, int i) {

                            }

                            @Override
                            public void onResponse(String response, int i) {

//                                if(response.equals("true"))
//                                    Toast.makeText(MainActivity.this, "登录成功!", Toast.LENGTH_LONG).show();
//                                else
//                                    Toast.makeText(MainActivity.this, "登录失败", Toast.LENGTH_LONG).show();
                                if (TextUtils.isEmpty(username)) {
                                    Toast.makeText(LoginActivity.this, "请输入用户名", Toast.LENGTH_SHORT).show();
                                    return;
                                } else if (TextUtils.isEmpty(pwd)) {
                                    Toast.makeText(LoginActivity.this, "请输入密码", Toast.LENGTH_SHORT).show();
                                    return;
                                } else if (response.equals("true")) {
                                    String phoneCode = et_phoneCode.getText().toString();
                                    if (phoneCode.equals(realCode)) {
                                        Toast.makeText(LoginActivity.this, "登录成功", Toast.LENGTH_SHORT).show();
                                        //把登录状态和登录的用户名保存到SharedPreferences里面
                                        saveLoginStatus(true,username);
                                        //  System.out.println("...............................................");
                                        byOkHttp(username);
                                        //登录成功后通过Intent把登录成功的状态传递到MainActivity.java中
                                        Intent data = new Intent();
                                        data.putExtra("status", true);
                                        setResult(RESULT_OK, data);//setResult为OK,关闭当前页面
                                        LoginActivity.this.finish();//在登录的时候,如果用户还没有注册则注册。注册成功后把注册成功后的用户名返回给前一个页面
                                        startActivity(new Intent(LoginActivity.this, MainActivity.class));
                                        editor = pref.edit();
                                        if (cb_box.isChecked()) {
                                            editor.putBoolean("cb_box", true);
                                            editor.putString("phone", username);
                                            editor.putString("password", pwd);
                                        } else {
                                            editor.clear();
                                        }
                                        editor.apply();
                                    } else {
                                        Toast.makeText(LoginActivity.this, phoneCode + "验证码错误", Toast.LENGTH_SHORT).show();
                                    }
                                    return;
                                } else if (!byOkHttpUtils(username) && !response.equals(true)) {
                                    Toast.makeText(LoginActivity.this, "用户名或密码错误", Toast.LENGTH_SHORT).show();
                                    return;
                                } else {
                                    Toast.makeText(LoginActivity.this, "此用户不存在", Toast.LENGTH_SHORT).show();
                                }
                            }


                        });
                // String md5Pwd=MD5Utils.MD5(pwd);
                // spPwd=readPwd(username);


            }
            public Boolean byOkHttpUtils(String userId){
                final Boolean[] flag = {false};
                OkHttpUtils
                        .get()
                        .addParams("userId",userId)
                        // .addParams("userName",userName)
                        //  .addParams("password",password)
                        .url("http://169.254.21.102:8086/register")
                        .build()
                        .execute(new StringCallback() {
                            @Override
                            public void onError(Call call, Exception e, int i) {

                            }

                            @Override
                            public void onResponse(String response, int i) {

                                if (response.equals("true")) {
                                    flag[0] = true;
                                    //Toast.makeText(RegisterActivity.this, "注册成功!", Toast.LENGTH_LONG).show();}
                                    // else
                                    //Toast.makeText(RegisterActivity.this, "注册失败,可能已存在当前账号", Toast.LENGTH_LONG).show();

                                }
//
                                // return response.equals("true");
                                //return return_value.equals("true")


                            }

                        });

                return flag[0];
            }
            public void byOkHttp(String userId){
                //创建OkHttpClient对象
                OkHttpUtils
                        .get()
                        .url("http://169.254.21.102:8086/update")
                        .addParams("userId", userId)
                        // .addParams("status", String.valueOf(status))
                        .build();

                if(userId!=null){
                    //从注册界面传递过来的用户名
                    //String username=data.getStringExtra("username");
                    System.out.println(true);
                    if(!TextUtils.isEmpty(username)){
                        et_user_name.setText(username);
                        //设置光标的位置上
                        et_user_name.setSelection(username.length());
                    }
                }
                //获取返回的json数据
                //String return_value = response.body().toString();
//                if(return_value.equals("true")){
//                    Toast.makeText(register.this, "注册成功!", Toast.LENGTH_LONG).show();
//                }
//                else {
//                    Toast.makeText(register.this, "注册失败,可能已存在当前账号邮箱", Toast.LENGTH_LONG).show();
//                }
                // return return_value.equals("true");
            }
            //从SharedPreferences中根据用户名读取密码
//    private String readPwd(String username){
//        SharedPreferences sp=getSharedPreferences("loginInfo", MODE_PRIVATE);
//        return sp.getString(username,"");
//    }

            //保存登录状态和登录用户名到SharedPrefarences中
            private void saveLoginStatus(boolean status,String username){
                //loginInfo表示文件名
                SharedPreferences sp=getSharedPreferences("loginInfo", MODE_PRIVATE);
                SharedPreferences.Editor editor=sp.edit();//获取编辑器
                editor.putBoolean("isLogin", status);
                editor.putString("loginUserName", username);//存入登录时的用户名
                editor.commit();//提交修改
            }
//    @Override
//    protected void onActivityResult(int requestCode,int resultCode,
//                                    Intent data){
//        super.onActivityResult(requestCode, resultCode, data);
//        if(data!=null){
//            //从注册界面传递过来的用户名
//            String username=data.getStringExtra("username");
//            if(!TextUtils.isEmpty(username)){
//                et_user_name.setText(username);
//                //设置光标的位置上
//                et_user_name.setSelection(username.length());
//            }
//            }
//   }
        });
    }
}

在这里插入图片描述
这里注意要将接口地址改为你自己电脑的IPv4地址

下面给出找到IPv4地址的步骤

1.Win+R,输入ipconfig
2.找到以太网适配器,下面的IPv4就是你电脑的IP地址了

在这里插入图片描述

(3)User

package com.example.bean;

/**
 */

public class User {
    private String uid;
    private String username;
    private String upassword;
    private String uname;

    public User(String uid, String username, String upassword, String uname) {
        this.uid = uid;
        this.username = username;
        this.upassword = upassword;
        this.uname = uname;
    }

    public User(String username, String upassword,String uname) {
        this.username = username;
        this.upassword = upassword;
        this.uname = uname;
    }

    public User() {
    }

    public String getUid() {
        return uid;
    }

    public void setUid(String uid) {
        this.uid = uid;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getUpassword() {
        return upassword;
    }

    public void setUpassword(String upassword) {
        this.upassword = upassword;
    }

    public String getUname() {
        return uname;
    }

    public void setUname(String uname) {
        this.uname = uname;
    }
}

(4)CodeUtils

package com.example.utils;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;

import java.util.Random;

public class CodeUtils {

    //随机码集
    private static final char[] CHARS = {
            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
            'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
            'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
            'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
    };

    private static CodeUtils mCodeUtils;
    private int mPaddingLeft, mPaddingTop;
    private StringBuilder mBuilder = new StringBuilder();
    private Random mRandom = new Random();

    //Default Settings
    private static final int DEFAULT_CODE_LENGTH = 4;//验证码的长度  这里是4位
    private static final int DEFAULT_FONT_SIZE = 60;//字体大小
    private static final int DEFAULT_LINE_NUMBER = 3;//多少条干扰线
    private static final int BASE_PADDING_LEFT = 20; //左边距
    private static final int RANGE_PADDING_LEFT = 30;//左边距范围值
    private static final int BASE_PADDING_TOP = 70;//上边距
    private static final int RANGE_PADDING_TOP = 15;//上边距范围值
    private static final int DEFAULT_WIDTH = 200;//默认宽度.图片的总宽
    private static final int DEFAULT_HEIGHT = 100;//默认高度.图片的总高
    private static final int DEFAULT_COLOR = Color.rgb(0xee, 0xee, 0xee);//默认背景颜色值

    private String code;

    public static CodeUtils getInstance() {
        if (mCodeUtils == null) {
            mCodeUtils = new CodeUtils();
        }
        return mCodeUtils;
    }

    //生成验证码图片
    public Bitmap createBitmap() {
        mPaddingLeft = 0; //每次生成验证码图片时初始化
        mPaddingTop = 0;

        Bitmap bitmap = Bitmap.createBitmap(DEFAULT_WIDTH, DEFAULT_HEIGHT, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        code = createCode();
        canvas.drawARGB(0, 0, 0, 0);
        canvas.drawColor(DEFAULT_COLOR);
        Paint paint = new Paint();
        paint.setTextSize(DEFAULT_FONT_SIZE);

        for (int i = 0; i < code.length(); i++) {
            randomTextStyle(paint);
            randomPadding();
            canvas.drawText(code.charAt(i) + "", mPaddingLeft, mPaddingTop, paint);
        }

        //干扰线
        for (int i = 0; i < DEFAULT_LINE_NUMBER; i++) {
            drawLine(canvas, paint);
        }

        canvas.save();//保存
        canvas.restore();
        return bitmap;
    }

    /**
     * 得到图片中的验证码字符串
     *
     * @return
     */
    public String getCode() {
        return code;
    }

    //生成验证码
    public String createCode() {
        mBuilder.delete(0, mBuilder.length()); //使用之前首先清空内容
        for (int i = 0; i < DEFAULT_CODE_LENGTH; i++) {
            mBuilder.append(CHARS[mRandom.nextInt(CHARS.length)]);
        }
        return mBuilder.toString();
    }

    //生成干扰线
    private void drawLine(Canvas canvas, Paint paint) {
        int color = randomColor();
        int startX = mRandom.nextInt(DEFAULT_WIDTH);
        int startY = mRandom.nextInt(DEFAULT_HEIGHT);
        int stopX = mRandom.nextInt(DEFAULT_WIDTH);
        int stopY = mRandom.nextInt(DEFAULT_HEIGHT);
        paint.setStrokeWidth(1);
        paint.setColor(color);
        canvas.drawLine(startX, startY, stopX, stopY, paint);
    }

    //随机颜色
    private int randomColor() {
        mBuilder.delete(0, mBuilder.length()); //使用之前首先清空内容
        String haxString;
        for (int i = 0; i < 3; i++) {
            haxString = Integer.toHexString(mRandom.nextInt(0xEE));
            if (haxString.length() == 1) {
                haxString = "0" + haxString;
            }
            mBuilder.append(haxString);
        }
        return Color.parseColor("#" + mBuilder.toString());
    }

    //随机文本样式
    private void randomTextStyle(Paint paint) {
        int color = randomColor();
        paint.setColor(color);
        paint.setFakeBoldText(mRandom.nextBoolean());  //true为粗体,false为非粗体
        float skewX = mRandom.nextInt(11) / 10;
        skewX = mRandom.nextBoolean() ? skewX : -skewX;
        paint.setTextSkewX(skewX); //float类型参数,负数表示右斜,整数左斜
        paint.setUnderlineText(mRandom.nextBoolean()); //true为下划线,false为非下划线
        paint.setStrikeThruText(mRandom.nextBoolean()); //true为删除线,false为非删除线
    }

    //随机间距
    private void randomPadding() {
        mPaddingLeft += BASE_PADDING_LEFT + mRandom.nextInt(RANGE_PADDING_LEFT);
        mPaddingTop = BASE_PADDING_TOP + mRandom.nextInt(RANGE_PADDING_TOP);
    }
}

(5)SharedPreferencesUtil

package com.example.utils;

import android.content.Context;
import android.content.SharedPreferences;
import android.util.Log;

/**
 * 状态保存工具类
 */
public class SharedPreferencesUtil {


    private static final String TOKEN = "TOKEN";
    // SharedPreferences是Android平台上一个轻量级的存储辅助类
    private static SharedPreferences myPreferences;
    private static SharedPreferences.Editor editor;
    private static SharedPreferencesUtil mSharedPreferencesUtil;

    private final Context context;

    public SharedPreferencesUtil(Context context) {
        this.context = context.getApplicationContext();
        // 调用Context对象的getSharedPreferences()方法获得的SharedPreferences对象可以被同一应用程序下的其他组件共享.
        myPreferences = this.context.getSharedPreferences("TAG", Context.MODE_PRIVATE);
        editor = myPreferences.edit();

    }

    /**
     * 单例实现
     * @param context
     * @return
     */
    public static SharedPreferencesUtil getInstance(Context context) {
        if(mSharedPreferencesUtil == null ) {
            mSharedPreferencesUtil = new SharedPreferencesUtil(context);
        }
        return mSharedPreferencesUtil;
    }


    /**
     * 设置值
     * @param key
     * @param value
     */
    public void setValue(String key, String value) {
        editor.putString(key, value);
        editor.commit();
    }

    /**
     * 清空
     */
    public void clear() {
        editor.clear();
        editor.commit();
    }

    /**
     * 获取值
     * @param key
     * @return
     */
    public String getValue(String key) {
        return myPreferences.getString(key, "");
    }


    /**
     * 设置登陆状态(存入token)
     * @param token
     */
    public void toLogin(String token) {
        setValue(TOKEN, token);
    }

    public boolean isLogin() {
        String token = getValue(TOKEN);
        Log.e("token", token);
        if("".equals(token)) {
            return false;
        } else {
            return true;
        }
    }




}

(6)需要导入的依赖

    implementation 'com.squareup.okhttp3:okhttp:3.14.0'
    implementation 'com.squareup.okhttp:okhttp:2.7.5'
    implementation 'com.zhy:okhttputils:2.6.2'

(7)申请权限:在AndroidManifest.xml中加入以下代码

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

二、注册

1.界面设计

在这里插入图片描述

2.Android端

(1)布局文件(activity_register)

在这里插入图片描述

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/activity_register"
    android:orientation="vertical" >

    <include layout="@layout/main_title_bar" />

    <com.example.CircleImageView
        android:layout_width="wrap_content"
        android:layout_height="150dp"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="10dp"
        android:contentDescription="@null"
        android:src="@drawable/logo1" />

    <EditText
        android:singleLine="true"
        android:id="@+id/et_user_name"
        android:layout_width="fill_parent"
        android:layout_height="48dp"
        android:background="@drawable/zcan3"
        android:layout_marginTop="35dp"
        android:layout_marginLeft="35dp"
        android:layout_marginRight="35dp"
        android:drawableLeft="@drawable/yhm1"
        android:paddingLeft="8dp"
        android:drawablePadding="10dp"
        android:hint="@string/name"
        android:gravity="center_vertical"
        android:textColorHint="#a3a3a3"
        android:textColor="#000000"
        android:textSize="14sp"/>

    <EditText
        android:id="@+id/et_pwd"
        android:layout_width="fill_parent"
        android:layout_height="48dp"
        android:layout_marginLeft="35dp"
        android:layout_marginRight="35dp"
        android:background="@drawable/zcan3"
        android:drawableLeft="@drawable/mm2"
        android:drawablePadding="10dp"
        android:gravity="center_vertical"
        android:hint="@string/pwd"
        android:inputType="textPassword"
        android:paddingLeft="8dp"
        android:singleLine="true"
        android:textColor="#000000"
        android:textColorHint="#a3a3a3"
        android:textSize="14sp" />

    <EditText
        android:singleLine="true"
        android:id="@+id/et_pwd_again"
        android:layout_width="fill_parent"
        android:layout_height="48dp"
        android:background="@drawable/zcan3"
        android:layout_marginLeft="35dp"
        android:layout_marginRight="35dp"
        android:drawableLeft="@drawable/mm2"
        android:paddingLeft="8dp"
        android:drawablePadding="10dp"
        android:inputType="textPassword"
        android:hint="@string/pwd_again"
        android:gravity="center_vertical"
        android:textColorHint="#a3a3a3"
        android:textColor="#000000"
        android:textSize="14sp"/>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="45dp"
        android:layout_marginLeft="15dp"
        android:layout_marginRight="15dp"
        android:layout_marginTop="30dp"
        android:background="@drawable/zcan3"
        android:orientation="vertical">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:gravity="center_vertical"
            android:orientation="horizontal">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="20dp"
                android:layout_marginRight="20dp"
                android:text="中国+86"
                android:textColor="#A2CD5A"
                android:textSize="16sp" />

            <View
                android:layout_width="0.1dp"
                android:layout_height="match_parent"
                android:background="#FF7F00" />

            <EditText
                android:id="@+id/et_forgetPass_PhoneNum"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginLeft="20dp"
                android:background="@null"
                android:digits="0123456789"
                android:hint="请填入您的手机号"
                android:inputType="number"
                android:maxLength="11"
                android:textSize="16sp" />
        </LinearLayout>
    </LinearLayout>


<!--    <LinearLayout-->

<!--        android:layout_width="match_parent"-->
<!--        android:layout_height="wrap_content"-->
<!--        android:layout_marginLeft="15dp"-->
<!--        android:layout_marginRight="15dp"-->
<!--        android:layout_marginTop="20dp"-->
<!--        android:orientation="horizontal">-->

<!--        <LinearLayout-->
<!--            android:layout_width="wrap_content"-->
<!--            android:layout_height="45dp"-->
<!--            android:background="@drawable/zcan3">-->
<!--            <EditText-->
<!--                android:id="@+id/et_phoneCodes"-->
<!--                android:layout_width="match_parent"-->
<!--                android:layout_height="match_parent"-->
<!--                android:layout_marginLeft="10dp"-->
<!--                android:layout_marginRight="10dp"-->
<!--                android:background="@null"-->
<!--                android:hint="请输入右侧验证码" />-->
<!--        </LinearLayout>-->

<!--        <ImageView-->
<!--            android:id="@+id/image"-->
<!--            android:layout_width="100dp"-->
<!--            android:layout_height="match_parent"-->
<!--            android:layout_marginLeft="10dp" />-->

<!--    </LinearLayout>-->
<!--    <Button-->
<!--        android:id="@+id/but_forgetpass_toSetCodes"-->
<!--        android:layout_width="match_parent"-->
<!--        android:layout_height="wrap_content"-->
<!--        android:layout_margin="35dp"-->
<!--        android:background="@drawable/register_selector"-->
<!--        android:text="获取验证码"-->
<!--        android:textColor="#fff" />-->
    <Button
        android:text="@string/btn_register"
        android:id="@+id/btn_register"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="30dp"
        android:layout_marginLeft="35dp"
        android:layout_marginRight="35dp"
        android:textColor="@android:color/white"
        android:textSize="20sp"
        android:textStyle="bold"
        android:layout_width="fill_parent"
        android:layout_height="50dp"
        android:background="@drawable/register_selector"/>

</LinearLayout>


(2)java文件(RegisterActivity)

package com.example.activity;

import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.example.R;
import com.example.utils.MD5Utils;
import com.zhy.http.okhttp.OkHttpUtils;
import com.zhy.http.okhttp.callback.StringCallback;

import okhttp3.Call;


public class RegisterActivity extends Activity {

    private TextView tv_main_title;//标题
    private TextView tv_back;		//返回按钮
    private RelativeLayout rl_title_bar;//标题布局
    private Button btn_register;	//注册按钮
    private EditText et_user_name,et_pwd,et_pwd_again;//用户名、密码、再次输入的密码的控件
    private String username,pwd,pwd_again;//用户名、密码、再次输入的密码的控件的获取值
    private Bitmap bitmap;
    private String code;
    //验证码
    private ImageView iv_showCode;
    private EditText et_phoneCode;
    //产生的验证码
    private String realCode;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_register);
        init();
//        //验证码
//        reacode();
//        //获取需要展示图片验证码的ImageView
//        final ImageView image = (ImageView) findViewById(R.id.image);
//        //获取工具类生成的图片验证码对象
//        bitmap = CodeUtils.getInstance().createBitmap();
//        //获取当前图片验证码的对应内容用于校验
//        code = CodeUtils.getInstance().getCode();
//        image.setImageBitmap(bitmap);
//        image.setOnClickListener(new View.OnClickListener() {
//            @Override
//            public void onClick(View view) {
//                bitmap = CodeUtils.getInstance().createBitmap();
//                code = CodeUtils.getInstance().getCode();
//                image.setImageBitmap(bitmap);
//                Toast.makeText(RegisterActivity.this, code, Toast.LENGTH_SHORT).show();
//            }
//        });
    }
    //验证码
//    private void reacode() {
//
//        //将验证码用图片的形式显示出来
//        iv_showCode.setImageBitmap(CodeUtils.getInstance().createBitmap());
//        realCode =CodeUtils.getInstance().getCode();
//    }
    private void init() {
        // TODO Auto-generated method stub
        //从main_title_bar.xml页面布局中获取对应的UI控件
        //抽取成员变量ctrl+alt+F
        tv_main_title = (TextView) findViewById(R.id.tv_main_title);
        tv_main_title.setText("注册");
        tv_back = ((TextView) findViewById(R.id.tv_back));
        rl_title_bar = (RelativeLayout) findViewById(R.id.title_bar);
//        rl_title_bar.setBackgroundColor(Color.TRANSPARENT);
        rl_title_bar.setBackgroundColor(Color.parseColor("#30b4ff"));
        //从activity_register.xml页面布局中获取对应的UI控件
        btn_register = (Button) findViewById(R.id.btn_register);
        et_user_name = (EditText) findViewById(R.id.et_user_name);
        et_pwd = (EditText) findViewById(R.id.et_pwd);
        et_pwd_again = (EditText) findViewById(R.id.et_pwd_again);
        //验证码
        et_phoneCode = (EditText) findViewById(R.id.et_phoneCodes);
        iv_showCode = (ImageView) findViewById(R.id.iv_showCode);
//        //图片验证码刷新
//        iv_showCode.setOnClickListener(new View.OnClickListener() {
//
//            @Override
//            public void onClick(View arg0) {
//                // TODO Auto-generated method stub
//                iv_showCode.setImageBitmap(CodeUtils.getInstance().createBitmap());
//                realCode = CodeUtils.getInstance().getCode();
//            }
//        });
        tv_back.setOnClickListener(new View.OnClickListener() {
            @Override//关闭页面的点击事件
            public void onClick(View view) {//设置按钮可以关闭当前页面
                RegisterActivity.this.finish();
            }
        });
        //注册按钮点击事件
        btn_register.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //点击后获取输入在响应控件中的字符串
                getEditstring();
                //判断字符串是否为空
                if(TextUtils.isEmpty(username)){
                    Toast.makeText(RegisterActivity.this, "请输入用户名", Toast.LENGTH_SHORT).show();
                    return;
                }else if (TextUtils.isEmpty(pwd)){
                    Toast.makeText(RegisterActivity.this, "请输入密码", Toast.LENGTH_SHORT).show();
                    return;
                }else if (TextUtils.isEmpty(pwd_again)){
                    Toast.makeText(RegisterActivity.this, "请再次输入密码", Toast.LENGTH_SHORT).show();
                    return;
                }else if (!pwd.equals(pwd_again)){
                    Toast.makeText(RegisterActivity.this, "两次输入的密码不一样", Toast.LENGTH_SHORT).show();
                    return;
                } else if (byOkHttpUtils(username,username,pwd)){
                    Toast.makeText(RegisterActivity.this, "此用户已经存在", Toast.LENGTH_SHORT).show();

                    return;
                }else {
                    Toast.makeText(RegisterActivity.this, "注册成功", Toast.LENGTH_SHORT).show();
                    //把用户名和密码保存到SharedPreferences里面
                    //byOkHttp(username,username,pwd);
                    saveRegisterInfo(username,pwd);
                    //注册成功后通过Intent把用户名传递到LoginActivity.java中
                    Intent data=new Intent();
                    data.putExtra("username",username);
                    setResult(RESULT_OK,data);//setResult为OK,关闭当前页面
                    RegisterActivity.this.finish();//在登录的时候,如果用户还没有注册则注册。注册成功后把注册成功后的用户名返回给前一个页面
                }
            }
        });
    }



    private void saveRegisterInfo(String username, String pwd) {
        String md5Pwd= MD5Utils.MD5(pwd);//把密码用MD5加密
        //loginInfo是sp的文件名
        SharedPreferences sp=getSharedPreferences("loginInfo",MODE_PRIVATE);//通过getSharedPreferences传入loginInfo注册登录相关的信息
        SharedPreferences.Editor editor = sp.edit();//通过sp.edit()获取到sp的编辑器对象
        //username作为key,密码作为value
        editor.putString(username,md5Pwd);
        editor.commit();//提交修改
    }

    /**
     * 从SharedPreferences中读取输入的用户名,判断SharedPreferences中是否有用户名
     * @return
     */
//    private boolean isExistUserName(String username) {
//        boolean has_userName=false;//表示是否有用户名
//        SharedPreferences sp=getSharedPreferences("loginInfo",MODE_PRIVATE);
//        String spPwd = sp.getString(username,""); //通过sp.getString传值用户名获取到密码
//        if (!TextUtils.isEmpty(spPwd)){ //判断这个密码是否为空
//            has_userName=true;//该用户是否保存了这一个密码
//        }
//        return has_userName;
//    }
    public Boolean byOkHttpUtils(String userId,String userName,String password){
        final Boolean[] flag = {false};
        OkHttpUtils
                .get()
                .addParams("userId",userId)
                .addParams("userName",userName)
                .addParams("password",password)
                .url("http://192.168.119.1:8086/register")
                .build()
                .execute(new StringCallback() {
                    @Override
                    public void onError(Call call, Exception e, int i) {

                    }

                    @Override
                    public void onResponse(String response, int i) {

                        if (response.equals("true")) {
                            flag[0] = true;
                            //Toast.makeText(RegisterActivity.this, "注册成功!", Toast.LENGTH_LONG).show();}
                            // else
                            //Toast.makeText(RegisterActivity.this, "注册失败,可能已存在当前账号", Toast.LENGTH_LONG).show();

                        }
//
                        // return response.equals("true");
                        //return return_value.equals("true")


                    }

                });

        return flag[0];
    }
//    private void byOkHttp(String userId,String userName,String password){
//        //创建OkHttpClient对象
//        OkHttpClient okHttpClient = new OkHttpClient();
//
//        //建立请求表单,添加上传服务器的参数
//        RequestBody formBody = new FormEncodingBuilder()
//                .add("userId", userId)
//                .add("password", password)
//                .add("userName",userName)
//                .build();
//
//        // 建立请求并绑定数据
//        Request request = new Request.Builder()
//                .url("http://169.254.21.102:8086/register")
//                .post(formBody)
//                .build();
//
        //响应
//        Response response = null;
//        try {
//            response = okHttpClient.newCall(request).execute();
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
//
//        //获取返回的json数据
//          String return_value = response.body().toString();
//        if(return_value.equals("true")){
//            Toast.makeText(RegisterActivity.this, "注册成功!", Toast.LENGTH_LONG).show();
//           // return  true;
//        }
//        else {
//           Toast.makeText(RegisterActivity.this, "注册失败,可能已存在当前账号", Toast.LENGTH_LONG).show();
//           // return false;
//        }
//
//    }
    /**
     * 获取控件中的字符串
     */
    private void getEditstring() {
        username=et_user_name.getText().toString().trim();
        pwd = et_pwd.getText().toString();
        pwd_again = et_pwd_again.getText().toString().trim();
    }
}


在这里插入图片描述
这里注意也要将接口地址改为你自己电脑的IPv4地址

(3)MD5Utils

package com.example.utils;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class MD5Utils {
    /**
     * md5加密的算法
     * @param text
     * @return
     */
    public static String MD5(String text){
        try {
            MessageDigest digest = MessageDigest.getInstance("md5");
            byte[] result = digest.digest(text.getBytes());
            StringBuffer sb=new StringBuffer();
            for (byte b:result){
                int number =b & 0xff;
                String hex=Integer.toHexString(number);
                if (hex.length()==1){//如果0xff为一个字节
                    sb.append("0"+hex);
                }else {
                    sb.append(hex);
                }
            }
            return sb.toString();

        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            return "";//如果发生异常
        }
    }

}


三、数据库

1.数据库就是简单的一个user表

在这里插入图片描述

四、SpringBoot端

1.创建springboot项目

在这里插入图片描述
在这里插入图片描述
注意:在develorper toots,web,sql选中相应右边的选项一共7个

(1)项目基本结构

在这里插入图片描述

2.配置文件(pom.xml)

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.3</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo</name>
    <description>demo</description>
    <properties>
        <java.version>8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jdbc</artifactId>
        </dependency>
<!--        <dependency>-->
<!--            <groupId>org.springframework.boot</groupId>-->
<!--            <artifactId>spring-boot-starter-data-jpa</artifactId>-->
<!--        </dependency>-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.2.2</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.project-lombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

3.Controller层(TestController)

package com.example.demo.controller;

import com.example.demo.repository.UserRepository;

import com.example.demo.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
public class TestController {
    @Autowired
    private UserRepository userRepository;
//    private JdbcTemplate jdbcTemplate;
    @RequestMapping(value="/getUsers",method = RequestMethod.GET)
    @ResponseBody
    public List<User> findAll(){
        List<User> userList = userRepository.findAll();
        return  userList;
    }
    @RequestMapping(value = "/register",method = RequestMethod.GET)
    public boolean register(@RequestParam("userId") String userId,
                            @RequestParam("userName") String userName,
                            @RequestParam("password") String password){
        try {
            userRepository.register(userId,userName,password);
            System.out.println("可以正常执行");
            return true; //注册成功则返回true
        } catch (Exception e) {
            e.printStackTrace();
        }return false;
    }
    @RequestMapping(value ="/login",method = RequestMethod.GET)
    public boolean login(@RequestParam("userId") String userId,
                         @RequestParam("password") String password){
        User user=null;
        user = userRepository.login(userId,password);
        //对比密码,相同则返回true,正常情况会加密解密,为求简单就不那么做了
        if(user.getPassword().equals(password))
            return true;
        return false;
    }


}

4.entity层(User)

package com.example.demo.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;


@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    String userId;
    String userName;
    String password;

    public String getUserId() {
        return userId;
    }

    public void setUserId(String userId) {
        this.userId = userId;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }


}

5.mapper层(UserMapper)

package com.example.demo.mapper;

import com.example.demo.entity.User;
import org.apache.ibatis.annotations.Mapper;

import java.util.List;

@Mapper
public interface UserMapper {
     List<User> findAll();
     void register(String userId, String userName,String password);
     User login(String userId,String password);
    // Boolean update(String userId,Boolean status);
}

6.UserRepositoryImpl

package com.example.demo.repository.Impl;

import com.example.demo.entity.User;
import com.example.demo.mapper.UserMapper;
import com.example.demo.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public class UserRepositoryImpl implements UserRepository {
    @Autowired
    UserMapper userMapper;
    @Override
    public List<User> findAll() {
        return userMapper.findAll();

    }
    @Override
    public void register(String userId, String userName,String password) {
        userMapper.register(userId, userName,password);
    }
    @Override
    public User login(String userId, String password) {
       return userMapper.login(userId,password);
    }

  //  @Override
   // public Boolean update(String userId,Boolean status){return userMapper.update(userId,status);}
}

7.repository层(UserRepository)

package com.example.demo.repository;

import com.example.demo.entity.User;

import java.util.List;

public interface UserRepository {
    public List<User> findAll();
    public void register(String userId,String userName,String password);
    public User login(String userId,String password);
   // public Boolean update(String userId,Boolean status);
}

8.UserMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.UserMapper">
    <select id="findAll" resultType="com.example.demo.entity.User">
        select * from user
    </select>
    <insert id="register" parameterType="com.example.demo.entity.User">
	    insert USER values (#{userId},#{userName},#{password});
    </insert>
    <select id="login" parameterType="com.example.demo.entity.User" resultType="com.example.demo.entity.User">
        select *from USER where userId=#{userId}
    </select>

<!--    <update id="update" parameterType="com.example.demo.entity.User">-->
<!--        update USER set status=#{status}-->
<!--        where userId = #{userId}-->
<!--    </update>-->
<!--    ,userName=#{userName},password=#{password},-->
</mapper>

9.配置文件(application.properties)


#============ thymeleaf???? ?? start ==============
#????
server.port=8086
spring.thymeleaf.prefix=classpath:/pages/
#????
spring.thymeleaf.suffix=.html
#??
spring.thymeleaf.mode=LEGACYHTML5
#??
spring.thymeleaf.encoding=utf-8
#Servlet????
spring.thymeleaf.servlet.content-type=text/html
#???????,?????????????????
spring.thymeleaf.cache=false
#======================?????============================
#?????
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#????????
#spring.datasource.url=jdbc:mysql://localhost:3306/student?serverTimezone=GMT%2B8&verifyServerCertificate=false&useSSL=false
spring.datasource.url=jdbc:mysql://localhost:3307/testandorid?useUnicode=true&characterEncoding=UTF-8&useSSL=false
#???
spring.datasource.username=root
#??
spring.datasource.password=123456

#===================??Mybatis???=======================
#?????????
mybatis.mapper-locations=classpath:mapper/*.xml



在这里插入图片描述

1.注意:这里的数据库端口号和数据库改为你自己的

在这里插入图片描述
在这里插入图片描述

五、功能实现步骤

1.打开数据库

在这里插入图片描述

2.运行SpringBoot

在这里插入图片描述

3.运行Android

到这里一个简单的Android+SpringBoot前后端分离实现登录注册就结束了,希望能给你带来帮助和启发!有不懂的地方欢迎交流学习😊😊😊

  • 22
    点赞
  • 253
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 22
    评论
评论 22
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不服输的小乌龟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值