Play2 + ReactiveMongo 实现一个活动报名应用

Stella981
• 阅读 409
  • Play 2: https://playframework.com
  • ReactiveMongo: http://reactivemongo.org

代码在: http://git.oschina.net/socialcredits/social-credits-activity-service

公司要做一些活动,需要一个线上的活动报名应用。想着前几天刚好看了下 ReactiveMongo ,觉得这个小应用正好练练手。

这个活动应用的功能非常简单:用户在线填写表单,提交表单,后台存储数据并向指定的专员发送邮箱通知。

Play 项目

整个项目目录结构如下:

├── app
│   ├── controllers
│   │   └── inapi
│   ├── utils
│   └── views
│       └── activity
├── conf
├── data
│   └── src
│       └── main
├── platform
│   └── src
│       └── main
├── project
├── static
│   └── src
│       └── site
└── util
    └── src
        ├── main

appconf都是 Play 的标准目录,分别放置代码文件和项目配置文件。app.views 包下的是Play的模板页面文件。

static 是用于放置前端源文件的,包括:jssass等,使用gulp编译,并输入到 public 目录。

platform 目录放置一些业务代码,比如:Service。

data 目录是数据相关类的存放地,包括modeldomain和数据库访问代码,一此数据类相关的隐式转换代码也放置在此。

util 就是工具库了,包括常量定义、配置文件读取、枚举等。

ReactiveMongo

connection mongo collection

使用 ReactiveMongo 连接数据库需要先创建一个 MongoDrvier ,并调用 driver.connection 方法创建连接,进而通过 conn.db 方法获取一个数据库访问。

MyDriver.scala

class MyDriver private() {
  val driver = new MongoDriver()

  def connection = driver.connection(List(Settings.mongo.host))

  private def db(implicit ex: ExecutionContext) = connection.db(Settings.mongo.dbName)

  def collActivity(implicit ex: ExecutionContext) = db.collection[BSONCollection]("activity")

  def collActivityRegistration(implicit ex: ExecutionContext) = db.collection[BSONCollection]("activityRegistration")
}

case class 与 BSON的转换。

使用 Macros.handler 是最简单的实现 case classBSON 转换的方法,它用到了 scala macro。代码如:implicit val __activityHandler = Macros.handler[Activity]

BSONImplicits

implicit object LocalDateTimeHandler extends BSONHandler[BSONDateTime, LocalDateTime] {
  override def read(bson: BSONDateTime): LocalDateTime =
    LocalDateTime.ofInstant(Instant.ofEpochMilli(bson.value), ZoneOffset.ofHours(8))
  
  override def write(t: LocalDateTime): BSONDateTime =
    BSONDateTime(t.toInstant(ZoneOffset.ofHours(8)).toEpochMilli)
}

implicit val __activityHandler = Macros.handler[Activity]

数据库访问

查找一个Activity使用 find() 方法获取一个访问数据库游标,再在游标上调用 .one[Activity] 方法即可获取一个 Activity 对象,以 Option[Activity]

ActivityRepo

def findOneById(id: BSONObjectID): Future[Option[Activity]] = {
  activityColl.find(BSONDocument("_id" -> id)).one[Activity]
}

发送邮件

邮箱发送使用了 commons-email ,发送邮件的代码非常简单。

EmailService

@Singleton
class EmailService {
  private val emailSenderActor = Akka.system.actorOf(Props[EmailServiceActor], "email-sender")

  def sendEmail(id: String, subject: String, content: String): Unit = {
    emailSenderActor ! SendEmail(id, subject, content)
  }
}

class EmailServiceActor extends Actor with StrictLogging {
  override def receive: Receive = {
    case SendEmail(id, subject, content) =>
      val email = new SimpleEmail()
      email.setHostName(Settings.email.hostName)
      email.setSmtpPort(Settings.email.portSsl)
      email.setSSLOnConnect(true)
      email.setAuthenticator(new DefaultAuthenticator(Settings.email.username, Settings.email.password))
      email.setFrom(Settings.email.from)
      email.setSubject(subject)
      email.setMsg(content)
      email.addTo(Settings.email.to: _*)
      logger.info(
        s"""id: $id
            |from: ${Settings.email.from}
            |to: ${Settings.email.to}
            |$subject
            |$content""".stripMargin)
      val result = email.send()
      logger.info(
        s"""id: $id
            |[result] $result""".stripMargin)
  }
}

程序中使用了一个 Actor 来对邮件发送动作做队列化处理,感觉有点小题大作。不过 Actor 默认邮箱是FIFO的,这个特性很适合发送邮件的队列操作。

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Stella981 Stella981
2年前
AndroidStudio封装SDK的那些事
<divclass"markdown\_views"<!flowchart箭头图标勿删<svgxmlns"http://www.w3.org/2000/svg"style"display:none;"<pathstrokelinecap"round"d"M5,00,2.55,5z"id"raphael
Wesley13 Wesley13
2年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
2年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
2年前
ES6 新增的数组的方法
给定一个数组letlist\//wu:武力zhi:智力{id:1,name:'张飞',wu:97,zhi:10},{id:2,name:'诸葛亮',wu:55,zhi:99},{id:3,name:'赵云',wu:97,zhi:66},{id:4,na
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
2个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这