Scala2.11+Play2.5注册表单密码确认类型不匹配问题求助
解决Scala 2.11 + Play 2.5注册表单验证及Quartz调度器异常问题
我之前在Play 2.5环境下做带密码确认的注册表单时,也踩过类似的坑,给你一步步拆解解决:
1. 表单Mapping类型不匹配问题(Tuple vs Case Class)
你提到用Tuple处理密码时和Data1 case class参数类型不匹配,这是因为Form的tuple方法生成的是Form[(String, String, ...)]类型,而我们需要的是对应自定义case class的Form[Data1]。
举个具体的修正示例:
假设你的Data1定义是:
case class Data1(username: String, password: String, confirmPassword: String)
错误的写法(用Tuple):
// 类型不匹配:Form[(String,String,String)] 无法对应到 Data1 val wrongForm = Form( tuple( "username" -> nonEmptyText, "password" -> nonEmptyText, "confirmPassword" -> nonEmptyText ) verifying ("密码不匹配", p => p._2 == p._3) )
正确的写法(直接映射到Case Class):
val correctForm = Form( mapping( "username" -> nonEmptyText, "password" -> nonEmptyText, "confirmPassword" -> nonEmptyText )(Data1.apply)(Data1.unapply) // 关联case class的apply/unapply方法 verifying("密码不匹配", data => data.password == data.confirmPassword) // 验证逻辑放在这里 )
这样生成的correctForm类型就是Form[Data1],完美匹配你的case class,类型不匹配的问题就解决了。
2. 自定义嵌套PassData类时的验证位置
如果把密码相关字段抽成嵌套的PassData类,验证逻辑可以封装到嵌套类的Mapping里,这样更清晰也方便复用:
// 嵌套的密码数据类 case class PassData(password: String, confirmPassword: String) // 外层注册数据类 case class RegisterData(username: String, passData: PassData)
对应的Form Mapping写法:
// 先定义PassData的mapping,把验证逻辑绑定在这里 val passMapping = mapping( "password" -> nonEmptyText, "confirmPassword" -> nonEmptyText )(PassData.apply)(PassData.unapply) verifying("密码不匹配", pd => pd.password == pd.confirmPassword) // 外层注册表单的mapping val registerForm = Form( mapping( "username" -> nonEmptyText, "passData" -> passMapping // 直接复用带验证的密码mapping )(RegisterData.apply)(RegisterData.unapply) )
当然你也可以把验证逻辑放在外层的mapping之后,但把密码验证封装到PassData的mapping里,后续其他地方需要密码确认时可以直接复用这个mapping,更灵活。
3. Quartz调度器重复存在的异常
这个问题我之前也碰到过,通常是因为依赖重复加载或者配置重复导致的,解决方法如下:
- 检查依赖配置:打开
build.sbt,确保只引入了一次Quartz相关的Play插件依赖,比如对应Play 2.5的版本:
libraryDependencies += "com.enragedginger" %% "play-quartz" % "1.5.0"
不要重复添加相同或不同版本的Quartz依赖。
- 检查模块注册:打开
application.conf,确保只注册了一次Quartz模块:
play.modules.enabled += "com.enragedginger.playquartz.PlayQuartzModule"
避免重复添加这条配置。
- 避免手动初始化Scheduler:不要自己手动new Scheduler实例,而是通过Play的依赖注入获取,比如:
import javax.inject.Inject import org.quartz.Scheduler class MySchedulerService @Inject()(scheduler: Scheduler) { // 使用注入的scheduler操作 }
这样能保证整个应用只有一个Scheduler实例,不会出现重复存在的异常。
内容的提问来源于stack exchange,提问作者fststp
相关产品推荐
相关产品推荐

