当前位置: 代码迷 >> 综合 >> 仿电商App:笔记(六): 登录、注册功能开发(ORM框架-GreenDao)
  详细解决方案

仿电商App:笔记(六): 登录、注册功能开发(ORM框架-GreenDao)

热度:61   发布时间:2024-01-28 01:07:53.0

目录

1、注册UI及验证逻辑实现

1.1 注册页面逻辑实现

1.2 验证效果

2、登录UI及验证逻辑实现

2.1 登录页面逻辑实现

2.2 验证效果

3、服务器数据简单介绍与基于GreenDao的数据库框架设计

3.1 使用Apache+PHP搭建服务器,读取本地的json数据

3.2 数据持久化--GreenDAO(使用单例模式确保操作唯一性)

3.3 登录、注册页面的信息持久化

4、用户状态与用户信息的回调封装

4.1 用户状态回调--sharedPreference

4.2 登录、注册成功回调--使用接口,进行解耦方便在功能模块实现自己的逻辑

4.3 回调方法的具体使用

4.4 验证回调方法

5、启动图界面与登录页面相关联

5.1 完善启动图页面逻辑 

5.2 页面关联 

注册登录的逻辑整理:

注册:首先判断注册的输入格式是否正确;点击注册按钮,将输入的信息以key-value形式保存在Params(参数名,参数值)中,获取本地准备好的用户信息保存到数据库中(此处与真实情况不符);设置登录成功标志位以及注册成功的提示。

登录:首先判断登录的输入格式是否正确;点击登录按钮,将输入的信息以key-value形式保存在Params(参数名,参数值)中,获取本地准备好的用户信息保存到数据库中(此处与真实情况不符);设置登录成功标志位以及登录成功的提示。

逻辑优化: 

注册:首先判断注册的输入格式是否正确;点击注册按钮,需根据Params中的key判断电话号、邮箱、姓名是否被注册(包含相同信息可以Toast弹出提示信息,没有继续),将输入的信息以key-value形式保存在Params(<电话号,密码><邮箱,密码><姓名,密码>)中,将这些信息保存到数据库(手机内部的SQLite数据库,使用了GreenDao包装了)中。

登录:首先判断登录的输入格式是否正确;点击登录按钮,需根据Params中的key判断电话号、邮箱、姓名与对应保存的value密码是否相同(不相同以Toast弹出提示信息,相同则登录成功),不需要将信息保存到服务器的数据库中。

每次登陆注册是从Params中判断。但下次打开App,Params中数据清空(保存在内存中),需要先从数据库中将信息提取到Map中。然后进行登录注册判断。 

1、注册UI及验证逻辑实现

1.1 注册页面逻辑实现

位于latte-ec模块sign包下的SignUpDelegate。

主要作用:注册页面的逻辑实现,包含:注册后保存用户信息,已经注册的用户跳转到登录页面。

public class SignUpDelegate extends LatteDelegate {@BindView(R2.id.edit_sign_up_name)TextInputEditText mName = null;@BindView(R2.id.edit_sign_up_email)TextInputEditText mEmail = null;@BindView(R2.id.edit_sign_up_phone)TextInputEditText mPhone = null;@BindView(R2.id.edit_sign_up_password)TextInputEditText mPassword = null;@BindView(R2.id.edit_sign_up_re_password)TextInputEditText mRePassword = null;@OnClick(R2.id.btn_sign_up)void onClickSignUp() {if (checkForm()) {Toast.makeText(getContext(), "验证通过", Toast.LENGTH_SHORT).show();}}@OnClick(R2.id.tv_link_sign_in)void onClickLink(){getSupportDelegate().start(new SignInDelegate());}public boolean checkForm() {//检查填入的信息是否正确final String name = mName.getText().toString();final String email = mEmail.getText().toString();final String phone = mPhone.getText().toString();final String password = mPassword.getText().toString();final String rePassword = mRePassword.getText().toString();boolean isPass = true;if (name.isEmpty()) {mName.setError("请输入姓名");isPass = false;} else {mName.setError(null);}if (email.isEmpty() || !Patterns.EMAIL_ADDRESS.matcher(email).matches()) {mEmail.setError("错误的邮箱格式");isPass = false;} else {mEmail.setError(null);}if (phone.isEmpty() || phone.length() != 11) {mPhone.setError("手机号码错误");isPass = false;} else {mPhone.setError(null);}if (password.isEmpty() || password.length() < 6) {mPassword.setError("请填写至少6位数密码");isPass = false;} else {mPassword.setError(null);}if (rePassword.isEmpty() || rePassword.length() < 6 || !(rePassword.equals(password))) {mRePassword.setError("密码验证错误");isPass = false;} else {mRePassword.setError(null);}return isPass;}@Overridepublic Object setLayout() {return R.layout.delegate_sign_up;}@Overridepublic void onBindView(@Nullable Bundle savedInstanceState, View rootView) {}
}

1.2 验证效果

在example模块下,ExampleActivity类中,将根Fragment替换为注册图界面。

public class ExampleActivity extends ProxyActivity {@Overridepublic LatteDelegate setRootDelegate() {return new SignUpDelegate();}
}

    

2、登录UI及验证逻辑实现

2.1 登录页面逻辑实现

位于latte-ec模块sign包下的SignInDelegate。

主要作用:登录页面的逻辑实现,包含:登录后保存用户信息,还未注册的用户跳转到注册页面。

public class SignInDelegate extends LatteDelegate {@BindView(R2.id.edit_sign_in_email)TextInputEditText mEmail = null;@BindView(R2.id.edit_sign_in_password)TextInputEditText mPassword = null;@OnClick(R2.id.btn_sign_in)void onClickSignIn(){if (checkForm()){Toast.makeText(getContext(), "验证通过", Toast.LENGTH_SHORT).show();}}@OnClick(R2.id.icon_sign_in_wechat)void onClickWeChat(){//微信登录逻辑}@OnClick(R2.id.tv_link_sign_up)void onClickLink(){//未注册的,跳转到注册页面getSupportDelegate().start(new SignUpDelegate());}public boolean checkForm() {//检查填入信息final String email = mEmail.getText().toString();final String password = mPassword.getText().toString();boolean isPass = true;if (email.isEmpty() || !Patterns.EMAIL_ADDRESS.matcher(email).matches()) {mEmail.setError("错误的邮箱格式");isPass = false;} else {mEmail.setError(null);}if (password.isEmpty() || password.length() < 6) {mPassword.setError("请填写至少6位数密码");isPass = false;} else {mPassword.setError(null);}return isPass;}@Overridepublic Object setLayout() {return R.layout.delegate_sign_in;}@Overridepublic void onBindView(@Nullable Bundle savedInstanceState, View rootView) {}
}

2.2 验证效果

在example模块下,ExampleActivity类中,将根Fragment替换为登录图界面。

public class ExampleActivity extends ProxyActivity {@Overridepublic LatteDelegate setRootDelegate() {return new SignInDelegate();}
}

3、服务器数据简单介绍与基于GreenDao的数据库框架设计

3.1 使用Apache+PHP搭建服务器,读取本地的json数据

使用php对json数据进行了包装,最终在代码中通过获取.php文件来读取本地json数据

<?php
$file_name = 'http://127.0.0.1:8081/RestServer/data/user_profile.json';//获取的本地json数据
$file = file_get_contents($file_name);
echo $file;

开启Apache服务,在浏览器中输入:http://192.168.56.1:8081/RestServer/api/user_profile.php(前面是本机ip地址,可通过cmd查询;8081是自己更改的端口号),可以获取到json数据信息。

3.2 数据持久化--GreenDAO(使用单例模式确保操作唯一性)

配置GreenDAO依赖 

位于latte-ec模块database包下的UserProfile。

主要作用:实体类,一个实体类代表一张表,里面包含表中各个字段。

@Entity(nameInDb = "user_profile")//定义实体类,nameInDb:数据库名
public class UserProfile {@Idprivate long userId = 0;//唯一id,必须是long型private String name = null;private String avatar = null;private String gender = null;private String address = null;
}

Rebuild Project后会在UserProfile类后自动生成对各个字段得get、set方法。以及自动生成DaoMaster、DaoSession、UserProfileDao文件。

DaoMaster:GreenDao的框架管理类,该类对数据库相关管理进行了封装。

                     内部含有OpenHelper类(继承于SQLiteOpenHelper)创建所有的数据库;内部有Map集合,将每个EntityDao对象的字节码与它的数据库建立映射关系。通过Map管理所有的EntityDao类(每个类相当于一张表)。

DaoSession:链接GreenDao到SQLite数据库的纽带,通过它可以得到一个与数据库某张表相关的操作对象EntityDao。

                        从DaoMaster的Map集合中通过key(EntityDao.class)获取到管理数据库的对象(DaoConfig),传递给EntityDao类。DaoSession中的CRUD都是通过调用EntityDao进行的。

UserProfileDao:是具体的EntityDao类,有生成器生成的数据库操作类,封装了所有对数据库表进行CRUD的方法。

位于latte-ec模块database包下的ReleaseOpenHelper,继承自DaoMaster.OpenHelper。

主要作用:数据库表生成类,对DaoMaster自带的OpenHelper进行了封装。

public class ReleaseOpenHelper extends DaoMaster.OpenHelper {public ReleaseOpenHelper(Context context, String name) {super(context, name);}public ReleaseOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory) {super(context, name, factory);}@Overridepublic void onCreate(Database db) {super.onCreate(db);}
}

位于latte-ec模块database包下的DatabaseManager。

主要作用:数据库的管理类,内部初始化DaoMaster(使用单例,确保线程安全),内含获取到EntityDao对象的方法。

public class DatabaseManager {private DaoSession mDaoSession = null;private UserProfileDao mDao = null;private DatabaseManager() {}public DatabaseManager init(Context context) {initDao(context);return this;}private static final class Holder {//静态内部类单例模式private static final DatabaseManager INSTANCE = new DatabaseManager();}public static DatabaseManager getInstance() {return Holder.INSTANCE;}private void initDao(Context context) {final ReleaseOpenHelper helper = new ReleaseOpenHelper(context, "fast_ec.db");//传入数据库名,在Map集合中与对应的实体类建立映射关系final Database db = helper.getWritableDb();//以读写方式得到数据库mDaoSession = new DaoMaster(db).newSession();mDao = mDaoSession.getUserProfileDao();//获取该数据库的实体类操作对象}public final UserProfileDao getDao() {return mDao;}
}

在example模块下的ExampleApp类中进行数据库初始化。

public class exampleApp extends Application {@Overridepublic void onCreate() {super.onCreate();Latte.init(this).......configure();
**      DatabaseManager.getInstance().init(this);//初始化数据库}
}

3.3 登录、注册页面的信息持久化

位于latte-ec模块database包下的SignHandler。

主要作用:通过登录、注册成功后,获取到已经准备好的json数据,读取json数据保存到数据库中;并设置登录、注册状态以及成功的回调。

public class SignHandler {public static void onSignIn(String response,ISignListener signListener) {final JSONObject profileJson = JSON.parseObject(response).getJSONObject("data");final long userId = profileJson.getLong("userId");final String name = profileJson.getString("name");final String avatar = profileJson.getString("avatar");final String gender = profileJson.getString("gender");final String address = profileJson.getString("address");final UserProfile profile = new UserProfile(userId, name, avatar, gender, address);//从JSON中获取数据,插入数据库DatabaseManager.getInstance().getDao().insert(profile);//将数据插入数据库//已经注册并成功登录AccountManager.setSignState(true);signListener.onSignInSuccess();}public static void onSignUp(String response,ISignListener signListener) {final JSONObject profileJson = JSON.parseObject(response).getJSONObject("data");final long userId = profileJson.getLong("userId");final String name = profileJson.getString("name");final String avatar = profileJson.getString("avatar");final String gender = profileJson.getString("gender");final String address = profileJson.getString("address");final UserProfile profile = new UserProfile(userId, name, avatar, gender, address);DatabaseManager.getInstance().getDao().insert(profile);//已经注册并成功登录AccountManager.setSignState(true);signListener.onSignUpSuccess();}
}

位于latte-ec模块sign包下的SignUpDelegate。完善注册成功后的保存数据到数据库

主要作用:注册页面的逻辑实现,包含:注册后保存用户信息,已经注册的用户跳转到登录页面。

    @OnClick(R2.id.btn_sign_up)void onClickSignUp() {if (checkForm()) {RestClient.builder().url("http://192.168.50.189:8081/RestServer/api/user_profile.php").params("name",mName.getText().toString()).params("email", mEmail.getText().toString()).params("phone",mPhone.getText().toString()).params("password",mPassword.getText().toString()).success(new ISuccess() {@Overridepublic void onSuccess(String response) {LatteLogger.json("USER_PROFILE", response);SignHandler.onSignUp(response, mISignListener);}}).build().post();}}

位于latte-ec模块sign包下的SignInDelegate。完善登录成功后的保存数据到数据库

主要作用:登录页面的逻辑实现,包含:登录后保存用户信息,还未注册的用户跳转到注册页面。

    @OnClick(R2.id.btn_sign_in)void onClickSignIn(){if (checkForm()){RestClient.builder().url("http://192.168.1.103:8081/RestServer/api/user_profile.php").params("email", mEmail.getText().toString()).params("password",mPassword.getText().toString()).success(new ISuccess() {@Overridepublic void onSuccess(String response) {LatteLogger.json("USER_PROFILE", response);SignHandler.onSignIn(response, mISignListener);}}).build().post();}}

通过adb shell查看数据库信息

4、用户状态与用户信息的回调封装

4.1 用户状态回调--sharedPreference

位于latte-core模块app包下的IUserChecker接口。

主要作用:两个方法:登录、未登录。

public interface IUserChecker {void onSignIn();void onNotSignIn();
}

位于latte-core模块app包下的AccountManager。

主要作用:管理用户信息,内部通过sharedPreference保存登陆状态,检查用户状态--回调IUserChecker接口中方法。

public class AccountManager {private enum SignTag{SIGN_TAG}//保存用户登录状态,登录后调用public static void setSignState(boolean state){LattePreference.setAppFlag(SignTag.SIGN_TAG.name(), state);}private static boolean isSignIn(){return LattePreference.getAppFlag(SignTag.SIGN_TAG.name());}public static void checkAccount(IUserChecker checker){//检查登陆状态if (isSignIn()){checker.onSignIn();}else {checker.onNotSignIn();}}
}

4.2 登录、注册成功回调--使用接口,进行解耦方便在功能模块实现自己的逻辑

位于latte-ec模块sign包下的ISignListener接口。

主要作用:两个方法:登录成功、注册成功。

public interface ISignListener {void onSignInSuccess();void onSignUpSuccess();
}

4.3 回调方法的具体使用

位于latte-ec模块sign包下的SignUpDelegate。完善注册成功后的的信息回调

主要作用:注册页面的逻辑实现,包含:注册后保存用户信息,已经注册的用户跳转到登录页面。

 SignInDelegate添加了与SignUpDelegate相同的代码。

public class SignUpDelegate extends LatteDelegate {private ISignListener mISignListener = null;@Overridepublic void onAttach(Activity activity) {super.onAttach(activity);if (activity instanceof ISignListener){mISignListener = (ISignListener) activity;//确保只有继承ISignListener的activity才能实现该方法}}@OnClick(R2.id.btn_sign_up)void onClickSignUp() {if (checkForm()) {RestClient.builder()....success(new ISuccess() {@Overridepublic void onSuccess(String response) {LatteLogger.json("USER_PROFILE", response);
**                          SignHandler.onSignUp(response, mISignListener);}}).build().post();}}
}

位于latte-ec模块database包下的SignHandler。完善登录、注册状态以及成功的回调。

主要作用:通过登录、注册成功后,获取到已经准备好的json数据,读取json数据保存到数据库中;并设置登录、注册状态以及成功的回调。

public class SignHandler {public static void onSignIn(String response,ISignListener signListener) {......//已经注册并成功登录AccountManager.setSignState(true);signListener.onSignInSuccess();}public static void onSignUp(String response,ISignListener signListener) {......//已经注册并成功登录AccountManager.setSignState(true);signListener.onSignUpSuccess();}
}

4.4 验证回调方法

在example模块下,ExampleActivity类中,实现ISignListener接口中登陆成功、注册成功的方法。

    @Overridepublic void onSignInSuccess() {Toast.makeText(this,"登录成功",Toast.LENGTH_LONG).show();}@Overridepublic void onSignUpSuccess() {Toast.makeText(this,"注册成功",Toast.LENGTH_LONG).show();}

  

5、启动图界面与登录页面相关联

当启动后,判断用户是否登录?登录了:直接跳到主界面;没登陆:跳转到登录界面。(是否登录了?已经在AccountManager中通过SharedPreference保存了)

5.1 完善启动图页面逻辑 

 位于latte-ui模块launcher包下的ILauncherListener接口。

主要作用:登陆状态判断的回调,在里面设置是否登陆的标志位,最后根据登录标记位判断打开的Fragment

登录过:直接打开主页;没登陆:跳到登录界面。

public interface ILauncherListener {void onLauncherFinish(OnLauncherFinishTag tag);//登录后回调,传入登陆状态
}

位于latte-ec模块launcher包下的LauncherDelegate类,完善启动后登录逻辑的判断。

主要作用:启动页面的逻辑。

public class LauncherDelegate extends LatteDelegate implements ITimerListener {private ILauncherListener mILauncherListener = null;@Overridepublic void onAttach(Activity activity) {//初始化接口实例:实现ILauncherListener接口的activitysuper.onAttach(activity);if (activity instanceof ILauncherListener){mILauncherListener = (ILauncherListener) activity;}}//判断是否显示滑动启动页private void checkIsShowScroll(){if (!LattePreference.getAppFlag(ScrollLauncherTag.HAS_FIRST_LAUNCHER_APP.name())){getSupportDelegate(). start(new LauncherScrollDelegate(), SINGLETASK);}else {//检查用户是否登陆了APPAccountManager.checkAccount(new IUserChecker() {@Overridepublic void onSignIn() {if (mILauncherListener!=null){mILauncherListener.onLauncherFinish(OnLauncherFinishTag.SIGNED);//设置登录的标志位}}@Overridepublic void onNotSignIn() {if (mILauncherListener!=null){mILauncherListener.onLauncherFinish(OnLauncherFinishTag.NOT_SIGNED);}}});}}   
}

5.2 页面关联 

在example模块下,ExampleActivity类中,实现ILauncherListener接口,完成登陆状态判断方法:根据标记位:登录过:直接打开主页;没登陆:跳到登录界面。

    @Overridepublic void onLauncherFinish(OnLauncherFinishTag tag) {switch (tag){case SIGNED:Toast.makeText(this,"启动结束,用户登录了",Toast.LENGTH_LONG).show();getSupportDelegate().startWithPop(new EcBottomDelegate());break;case NOT_SIGNED:Toast.makeText(this,"启动结束,用户没登录",Toast.LENGTH_LONG).show();getSupportDelegate().startWithPop(new SignInDelegate());break;default:break;}}