请求之间的应用程序 class 变量不可用
Non availability of Application class variable between requests
我有一个应用程序控制器,它有 2 个方法。在第一种方法中,我访问数据库并检索表单的下拉元素列表。我将检索到的元素存储在 class 级变量中。在第二种方法中,如果出现错误,它会按原样显示表单,否则会显示结果。问题是我class级变量return为空。
class Application extends Controller {
var appList = Seq[AppDetail]()
var countryList = Seq[Country]()
def home(page:Int,filter: String): Action[AnyContent] = Action.async { implicit request =>
val futures = for {
appDetails <- AppDetailsDAO.listAll() //DB retrieve
countries <- CountriesDAO.listAll() //DB retrieve
} yield (appDetails, countries)
futures.map{case (appDetails, countries) => {
appList = appDetails
countryList = countries
Ok(appList, countryList)
}
}
def result(page:Int, filter: String): Action[AnyContent] = Action.async { implicit request =>
analyticForm.bindFromRequest.fold(
formWithErrors => {
Future.successful(BadRequest(html.home(formWithErrors, appList, countryList)) //appList, countryList returns empty
},
analyticData => {
Ok(appList, countryList) //appList, countryList returns empty
}
}
}
Play 是一个 RESTful 框架。这意味着,除其他外,您不应在两个请求之间共享信息。请求总是无状态的。
要解决您的问题,您只需在两个操作中获取 appList
和 countryList
。同时删除控制器中的两个 var
。尽可能避免在 scala 中使用可变变量(尽管它们在某些情况下很有用)。请参阅 Daniel C. Sobral 在 the difference between var and val 上的回答。
前方未经测试的代码:
class Application extends Controller {
def home(page:Int,filter: String): Action[AnyContent] = Action.async { implicit request =>
fetchDb.map{case (appDetails, countries) => {
appList = appDetails
countryList = countries
Ok(appList, countryList)
}}
}
def result(page:Int, filter: String): Action[AnyContent] = Action.async { implicit request =>
fetchDb.map{case (appDetails, countries) => {
analyticForm.bindFromRequest.fold(
formWithErrors => {
BadRequest(html.home(formWithErrors, appList, countryList))
},
analyticData => {
Ok(appList, countryList) //appList, countryList returns empty
}
)
}}
}
def fetchDb = {
val fAppDetails = AppDetailsDAO.listAll()
val fCountries = CountriesDAO.listAll()
for {
appDetails <- fAppDetails
countries <- fCountries
} yield (appDetails, countries)
}
}
旁注:您可能注意到我在 for 理解之外的 fetchDb
中创建了 Future
实例。这是因为 for comprehension 只是嵌套平面映射的另一种表示形式。这意味着 countries
在 appDetails
完成之前不会 运行。期货将 运行 依次。如果您将它们放在 for comprehension 之外,它们将 运行 并行。
我有一个应用程序控制器,它有 2 个方法。在第一种方法中,我访问数据库并检索表单的下拉元素列表。我将检索到的元素存储在 class 级变量中。在第二种方法中,如果出现错误,它会按原样显示表单,否则会显示结果。问题是我class级变量return为空。
class Application extends Controller {
var appList = Seq[AppDetail]()
var countryList = Seq[Country]()
def home(page:Int,filter: String): Action[AnyContent] = Action.async { implicit request =>
val futures = for {
appDetails <- AppDetailsDAO.listAll() //DB retrieve
countries <- CountriesDAO.listAll() //DB retrieve
} yield (appDetails, countries)
futures.map{case (appDetails, countries) => {
appList = appDetails
countryList = countries
Ok(appList, countryList)
}
}
def result(page:Int, filter: String): Action[AnyContent] = Action.async { implicit request =>
analyticForm.bindFromRequest.fold(
formWithErrors => {
Future.successful(BadRequest(html.home(formWithErrors, appList, countryList)) //appList, countryList returns empty
},
analyticData => {
Ok(appList, countryList) //appList, countryList returns empty
}
}
}
Play 是一个 RESTful 框架。这意味着,除其他外,您不应在两个请求之间共享信息。请求总是无状态的。
要解决您的问题,您只需在两个操作中获取 appList
和 countryList
。同时删除控制器中的两个 var
。尽可能避免在 scala 中使用可变变量(尽管它们在某些情况下很有用)。请参阅 Daniel C. Sobral 在 the difference between var and val 上的回答。
前方未经测试的代码:
class Application extends Controller {
def home(page:Int,filter: String): Action[AnyContent] = Action.async { implicit request =>
fetchDb.map{case (appDetails, countries) => {
appList = appDetails
countryList = countries
Ok(appList, countryList)
}}
}
def result(page:Int, filter: String): Action[AnyContent] = Action.async { implicit request =>
fetchDb.map{case (appDetails, countries) => {
analyticForm.bindFromRequest.fold(
formWithErrors => {
BadRequest(html.home(formWithErrors, appList, countryList))
},
analyticData => {
Ok(appList, countryList) //appList, countryList returns empty
}
)
}}
}
def fetchDb = {
val fAppDetails = AppDetailsDAO.listAll()
val fCountries = CountriesDAO.listAll()
for {
appDetails <- fAppDetails
countries <- fCountries
} yield (appDetails, countries)
}
}
旁注:您可能注意到我在 for 理解之外的 fetchDb
中创建了 Future
实例。这是因为 for comprehension 只是嵌套平面映射的另一种表示形式。这意味着 countries
在 appDetails
完成之前不会 运行。期货将 运行 依次。如果您将它们放在 for comprehension 之外,它们将 运行 并行。