The system should have a way to create Lotteries. Users can participate in any lottery that isn't finished yet. When you participate to a Lottery you become part of its extraction pool of potential winners. Once the Lottery closes a random winner is extracted from the pool and save winner number in a storage.
Logic is:
- The service will allow anyone to register as a lottery participant.
- Lottery participants will be able to submit as many lottery ballots for any lottery that isn’t yet finished.
- Each day at midnight the lottery event will be considered closed and a random lottery winner will be selected from all participants for the day.
- All users will be able to check the winning ballot for any specific date.
- The service will have to persist the data regarding the lottery.
Additionally:
- An unregistered user cannot purchase lottery tickets.
- The lottery can always be started with the lottery name. The only rule is that multiple active lotteries cannot be created with the same lottery name.
- The lottery ticket number has a unique sequential generated number per lottery starting at 1.
Simply use:
$ docker-compose up
$ docker-compose down
- Java 11
- Postgresql
- Your preferred IDE
- Eclipse
- IntelliJ IDEA
- VS Code
Create your database named lottery in postgresql and change application.properties as :
spring.datasource.url=jdbc:postgresql://localhost:5432/lottery
spring.datasource.username=postgres
spring.datasource.password=password
## Hibernate Properties
# The SQL dialect makes Hibernate generate better SQL for the chosen database
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect
# Hibernate ddl auto (create, create-drop, validate, update)
spring.jpa.hibernate.ddl-auto = create
spring.jpa.generate-ddl=true
spring.jpa.show-sql=true
spring.mvc.view.prefix: /
spring.mvc.view.suffix: .jsp
spring.messages.basename=validation
Then run that command in terminal:
$ mvn clean spring-boot:run
Spring Boot
- 2.0.4.RELEASEJDK
- 1.8 or laterSpring Framework
- 5.0.8 RELEASEHibernate
- 5.2.17.FinalSpring Data
JPAMaven
- 3.2+IDE
- IntelliJ IDEAPostgreSQL
- 42.2.5JSP
Spring Security
Spring Web
Postman
SonarLint
Following is the packing structure of our Lottery System:
Since I am planning on querying the database with different queries and I need to join between storages I prefered using a standard SQL database and not a NoSQL approach. NoSQL databases really shine if the data to store is not so well defined. However, I have a clear pattern of data to store.
I have 4 tables for the lottery design. One called lottery which holds the lottery information for the current lottery and one called lottery_ticket holding the ticket information for the lotteries. Users table holds user details and role table defines user role. Here is how I design:
lottery
- id
- name
- start_date
- end_date
- winner_lottery_num
lottery_ticket
- id
- lottery_id
- username
- lottery_number (The number of the ticket in the current lottery. It contains sequential numbers per lottery.)
- date
users
- id
- username
- first_name
- last_name
- password
- role
role
- id
- name
The PostgreSQL database looks like:
Spring Boot provides a good default implementation for exception handling for RESTful Services. @ControllerAdvice is a specialization of the @Component annotation which allows to handle exceptions across the whole application in one global handling component.
Here's what happens when you fire a request to a resource not found:
http://localhost:8080/lottery/endLotteryAndSelectRandomLotteryWinner/5
{
"timestamp": "2020-12-23T16:44:39.079+00:00",
"message": "Lottery not found for this id :: 5",
"details": "uri=/lottery/endLotteryAndSelectRandomLotteryWinner/5"
}
http://localhost:8080/lottery/lotteryResult/5
{
"timestamp": "2020-12-23T17:16:46.879+00:00",
"message": "Lottery is not finish yet :: 5",
"details": "uri=/lotteryResult/5"
}
http://localhost:8080/register
{
"timestamp": "2020-12-23T14:13:02.501+00:00",
"message": "user already exist :: mervekay",
"details": "uri=/register"
}
You can find all api queries in the attachted postman collection here.
- I would have implemented integration tests.
- I could have loaded data from the xml file using the dbunit library while writing unit tests.
- I would have completed front-end part.
- I could have extended queries usign DateUtils.
- I could have implemented submit ticket endpoint without username parameter, I could have get active user automatically.
- I would have dockerized the project.
- I could have designed the project for a distributed system. I lock the submitLotteryTicket method and let only one thread can run the endpoint at a time. Since each lottery number is generated sequentially, I need to be sure each user has a unique lottery number per lottery. A better solution would be generating a sequence numbers for a distributed system.