清除Action的残留信息(Bean)

本文分享了一次在Struts2.2.3项目中配置Spring时遇到的问题——未正确设置Action作用域导致数据污染。通过调整配置,将bean的作用域从单例改为原型,解决了数据跨请求混用的问题。
最近在做Struts2.2.3的工程,写Action的Spring配置时结果忘记配置Action的作用域了,这的配置是这样的:

<bean id="consysAction" class="cn.com.pzhsteel.action.ConSysAcion">
<property name="conSysService">
<ref local="conSysService"/>
</property>
</bean>

这样写的时候spring就会去拿单例的consysAction实例,导致上一次的数据被带到了以后的请求中。所以要修改bean的做用域。修改后的配置如下:

<bean id="consysAction" class="cn.com.pzhsteel.action.ConSysAcion" singleton="false">
<property name="conSysService">
<ref local="conSysService"/>
</property>
</bean>

有时候往往是细节的东西比较折磨人呀。。。。。
想了解Spring bean的做用域信息请参见:[url]http://blog.youkuaiyun.com/tenor/article/details/4542660[/url]
package com.tplink.partner.ui.login import androidx.lifecycle.LiveData import androidx.lifecycle.MediatorLiveData import com.tplink.base.frame.base.repository.providers.CloudRepositoryProviders import com.tplink.base.frame.ext.request import com.tplink.base.frame.state.ResultState import com.tplink.libtputility.log.TLog import com.tplink.partner.base.BasePartnerViewModel import com.tplink.partner.cloud.CloudConstants import com.tplink.partner.cloud.bean.ApiResponse import com.tplink.partner.cloud.bean.account.LoginParams import com.tplink.partner.cloud.bean.account.LoginResult import com.tplink.partner.cloud.bean.account.LoginSuccessResult import com.tplink.partner.cloud.bean.enterprise.EnterpriseLoginInfo import com.tplink.partner.cloud.context.TCAccountBean import com.tplink.partner.cloud.exceptions.CloudException import com.tplink.partner.common.EnumCloudError import com.tplink.partner.core.TPAppContext import com.tplink.partner.h5.H5RouteManager import com.tplink.partner.repository.TCAccountRepository import com.tplink.partner.thirdpart.arouter.ARouterUnified import com.tplink.partner.utils.CloudCookieManager import com.tplink.partner.utils.GlobalUtils import com.tplink.partner.utils.SP import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext /** * Created by wangju on 2023/5/30. */ open class LoginViewModel : BasePartnerViewModel() { protected var accountRepository: TCAccountRepository private val _loginResult = MediatorLiveData<ResultState<LoginSuccessResult>>() val loginResult: LiveData<ResultState<LoginSuccessResult>> = _loginResult var password: String = "" protected set var defaultEmail: String = "" init { accountRepository = CloudRepositoryProviders.create(TPAppContext.getCurrentAccountContext(), TCAccountRepository::class.java) } private fun initRepository() { accountRepository = CloudRepositoryProviders.create(TPAppContext.getCurrentAccountContext(), TCAccountRepository::class.java) } /** * 自动登录:根据持久化存储的[TCAccountBean],校验数据合法性,然后自动更新数据,跳转主页,不需要额外触发登录接口 */ suspend fun autoLogin(savedAccount: TCAccountBean): Boolean = withContext(Dispatchers.IO) { val cookies = CloudCookieManager.loadCookies() if (cookies.isEmpty() || !savedAccount.isValidAutoLogin()) { return@withContext false } TLog.d("autoLogin Succeed.") TPAppContext.createAccountContext(savedAccount) H5RouteManager.setUnifiedHost(savedAccount.frontServiceUrl) accountRepository.updateCloudEnvironment(savedAccount) true } fun login(email: String, password: String) { this.password = password login { accountRepository.login(LoginParams(email, password)) } } protected fun login(loginBlock: suspend () -> ApiResponse<LoginSuccessResult>) { request({ _loginResult.postValue(ResultState.start()) val result = loginBlock.invoke() TPAppContext.createAccountContext() initRepository() accountRepository.updateAccount(password, result.getResponseData()) accountRepository.updateCloudEnvironment(result.getResponseData()) accountRepository.getUserPermission() result }, { val account = TPAppContext.getCurrentAccountContext().account H5RouteManager.setH5RegionCode(account.countryCode) GlobalUtils.isSkipLogin = false GlobalUtils.isShowedCreateCompanyPage = false handleLoginSuccess(it) _loginResult.postValue(ResultState.success(it)) }, { _loginResult.postValue(ResultState.error(it)) TLog.e(TAG, "$it") }) } fun skipLogin() { GlobalUtils.isSkipLogin = true SP.INSTANCE.saveAccountBean(null) TPAppContext.createAccountContext() } fun saveAccount() { val account = TPAppContext.getCurrentAccountContext().account SP.INSTANCE.saveAccountBean(account) } fun clearAccount() { val account = TPAppContext.getCurrentAccountContext().account account.clear() SP.INSTANCE.saveAccountBean(account) } fun saveRememberMe(remember: Boolean) { SP.INSTANCE.setRememberMe(remember) } fun isRememberMe() = SP.INSTANCE.isRememberMe() fun saveRememberEmail() { SP.INSTANCE.saveRememberEmail(TPAppContext.getCurrentAccountContext().account.email) } fun getRememberEmail() = SP.INSTANCE.getRememberEmail() private fun handleLoginSuccess(result: LoginSuccessResult) { TLog.d("result = $result") saveRememberEmail() saveAccount() if (result.enterpriseList.size > 1) { //账户下存在多个企业,需要选择登入的企业 ARouterUnified.navSelectCompany(result.enterpriseList) } else { navMainWithEnterpriseId(result.enterpriseList.getOrNull(0)) } } /** * 登录失败处理逻辑,包括所有的登录错误码处理 * * @return 处理结果是否离开了此页面跳往了其它页面 */ fun onLoginFailed( throwable: Throwable, email: String, password: String, scaBlock: () -> Unit, unrecognizedErrorCodeBlock: () -> Unit ): Boolean { var navOtherPage = true if (throwable is CloudException) { val errorCode = throwable.errCode val result = throwable.result as? LoginResult when (errorCode) { CloudConstants.MFA.MFA_AUTH -> ARouterUnified.navMFA(email, password, result?.mfaResult) CloudConstants.ErrorCode.SCA_AUTH -> { navOtherPage = false scaBlock.invoke() } CloudConstants.ErrorCode.ACCOUNT_NO_RECODE_CODE -> ARouterUnified.navSelectRegion(result?.tempToken, email, password) CloudConstants.ErrorCode.ACCOUNT_DATA_MERGE -> ARouterUnified.navAccountUpgradeGuide(result?.accountMergeResult, result?.tempToken, password) CloudConstants.ErrorCode.ACCOUNT_LOCKED -> ARouterUnified.navAccountLocked(result?.accountLockTime ?: 0) //账户未激活 EnumCloudError.Err11008.errorCode -> ARouterUnified.navAccountActivate(email, true) else -> { navOtherPage = false unrecognizedErrorCodeBlock.invoke() } } } else { navOtherPage = false unrecognizedErrorCodeBlock.invoke() } return navOtherPage } private fun navMainWithEnterpriseId(enterpriseLoginInfo: EnterpriseLoginInfo?) { enterpriseLoginInfo?.enterpriseUrl?.let { TLog.d(TAG, "LoginViewViewModel navMainWithEnterpriseId by login, updateEnterpriseUrl = [${it}]") TPAppContext.getCurrentAccountContext().cloudEnvironment.updateEnterpriseUrl(it) } ARouterUnified.navMainWithEnterpriseInfo(clearTask = true, enterpriseLoginInfo?.enterpriseId, enterpriseLoginInfo?.enterpriseUrl) } fun navMainWithEnterpriseId(accountBean: TCAccountBean) { val lastEnterpriseInfo = accountBean.enterpriseList?.find { it.enterpriseId == accountBean.recentlyEnterpriseId } lastEnterpriseInfo?.enterpriseUrl?.let { TLog.d(TAG, "LoginViewViewModel navMainWithEnterpriseId by accountBean, updateEnterpriseUrl = [${it}]") TPAppContext.getCurrentAccountContext().cloudEnvironment.updateEnterpriseUrl(it) } ARouterUnified.navMainWithEnterpriseInfo(clearTask = true, lastEnterpriseInfo?.enterpriseId, lastEnterpriseInfo?.enterpriseUrl) } } package com.tplink.partner.ui.login import android.os.Bundle import android.view.View import android.view.inputmethod.EditorInfo import com.tplink.base.frame.state.onFailure import com.tplink.base.frame.state.onStart import com.tplink.base.frame.state.onSuccess import com.tplink.libtputility.platform.PlatformUtils import com.tplink.partner.R import com.tplink.partner.base.BaseFragment import com.tplink.partner.cloud.exceptions.exceptionHandler import com.tplink.partner.databinding.FragmentLoginBinding import com.tplink.partner.extendskt.activityPartnerViewModels import com.tplink.partner.extendskt.addTextChangedListener import com.tplink.partner.extendskt.hideInputMethod import com.tplink.partner.h5.H5RouteManager import com.tplink.partner.utils.BottomSheetDialogHelper import com.tplink.partner.utils.ToastUtils /** * Created by wangju on 2023/5/30. */ class LoginFragment : BaseFragment<FragmentLoginBinding>() { private val loginViewModel: LoginViewModel by activityPartnerViewModels() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) loginViewModel.clearAccount() initView() subscribe() } private fun subscribe() { loginViewModel.loginResult.observe(viewLifecycleOwner) { it.onStart { viewBinding.btnLogin.setInProgress(true) }.onSuccess { viewBinding.btnLogin.reset() }.onFailure { throwable -> viewBinding.btnLogin.reset() val email = viewBinding.tfEmail.getText() val password = viewBinding.tfPwd.getText() val navOtherPage = loginViewModel.onLoginFailed(throwable, email, password, scaBlock = { BottomSheetDialogHelper.showSCA(childFragmentManager, email) { onLogin() } }, unrecognizedErrorCodeBlock = { ToastUtils.Toast.showFailed(requireActivity(), content = exceptionHandler.getFailMessage(throwable)) }) if (navOtherPage) { clearInputPassword() } } } } private fun initView() { val isRemember = loginViewModel.isRememberMe() if (loginViewModel.defaultEmail.isNotEmpty()) { viewBinding.tfEmail.setText(loginViewModel.defaultEmail) } else if (isRemember) { viewBinding.tfEmail.setText(loginViewModel.getRememberEmail()) } viewBinding.cbRememberMe.isChecked = isRemember viewBinding.tfEmail.addTextChangedListener( afterTextChanged = { refreshButton() } ) viewBinding.tfPwd.addTextChangedListener( afterTextChanged = { refreshButton() } ) viewBinding.tfPwd.editText?.setOnEditorActionListener { _, actionId, _ -> if (actionId == EditorInfo.IME_ACTION_DONE) { onLogin() return@setOnEditorActionListener true } return@setOnEditorActionListener false } viewBinding.cbRememberMe.setOnUserCheckedChangeListener { _, isChecked, fromUser -> if (fromUser) { loginViewModel.saveRememberMe(isChecked) } } with(viewBinding) { listOf(btnLogin, tvRegister, tvForgetPassword).forEach { it.setOnClickListener(this@LoginFragment) } } refreshButton() } private fun refreshButton() { viewBinding.btnLogin.isEnabled = viewBinding.tfEmail.getText().isNotEmpty() && viewBinding.tfPwd.getText().isNotEmpty() } override fun onClick(v: View?) { super.onClick(v) when (v) { viewBinding.btnLogin -> onLogin() viewBinding.tvRegister -> H5RouteManager.Builder().loadUrl(H5RouteManager.getRegisterUrl()).navigation() viewBinding.tvForgetPassword -> H5RouteManager.Builder().loadUrl(H5RouteManager.getResetPasswordUrl()).navigation() } } private fun onLogin() { activity?.currentFocus?.hideInputMethod() if (!PlatformUtils.isNetworkAvailable(requireContext())) { ToastUtils.Toast.showFailed(requireContext(), R.string.no_internet_connection) viewBinding.btnLogin.reset() return } if (checkInvalid()) { loginViewModel.login(viewBinding.tfEmail.getText(), viewBinding.tfPwd.getText()) } else { viewBinding.btnLogin.reset() } } private fun checkInvalid(): Boolean { if (viewBinding.tfEmail.getText().isEmpty()) { viewBinding.tfEmail.error = getString(R.string.input_filed_cannot_be_empty) return false } if (viewBinding.tfPwd.getText().isEmpty()) { viewBinding.tfPwd.error = getString(R.string.input_filed_cannot_be_empty) return false } return true } private fun clearInputPassword() { //清空密码框,之所以采用延时处理,是因为在跳转页面前,会残留小部分时间,视觉效果就是先清除Password输入框,再跳转 viewBinding.tfPwd.postDelayed({ viewBinding.tfPwd.setText("") }, 100) } override fun onStop() { super.onStop() //为了用户数据安全,登录页面放置后台会清空密码输入框 viewBinding.tfPwd.setText("") } }根据这个生成对应的时序图
最新发布
11-11
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值