BAEL-3059: Update Play Framework (#7674)
* Implementation of Introduction to Play Framework in Java * Implementation of Introduction to Play Framework in Java * Implementation of Introduction to Play Framework in Java * Implementation of the tutorial for Introduction to Play Framework. * Updated code for Play Routing to 2.7.3 * Updated code for Play Routing to 2.7.3 * Initial Commit * Added request object to create end point * Finished implementing student-api * Finished implementing student-api * Implementation of the tutorial for Introduction to Play Framework. * Updated test names * Removed Lombok dependency * Corrected isSuccessful spelling and removed the +1 on student ids
This commit is contained in:
committed by
KevinGilmore
parent
0d648321dc
commit
5bce8b22a1
@@ -1,46 +0,0 @@
|
||||
import javax.inject.*;
|
||||
import play.*;
|
||||
import play.mvc.EssentialFilter;
|
||||
import play.http.HttpFilters;
|
||||
import play.mvc.*;
|
||||
|
||||
import filters.ExampleFilter;
|
||||
|
||||
/**
|
||||
* This class configures filters that run on every request. This
|
||||
* class is queried by Play to get a list of filters.
|
||||
*
|
||||
* Play will automatically use filters from any class called
|
||||
* <code>Filters</code> that is placed the root package. You can load filters
|
||||
* from a different class by adding a `play.http.filters` setting to
|
||||
* the <code>application.conf</code> configuration file.
|
||||
*/
|
||||
@Singleton
|
||||
public class Filters implements HttpFilters {
|
||||
|
||||
private final Environment env;
|
||||
private final EssentialFilter exampleFilter;
|
||||
|
||||
/**
|
||||
* @param env Basic environment settings for the current application.
|
||||
* @param exampleFilter A demonstration filter that adds a header to
|
||||
*/
|
||||
@Inject
|
||||
public Filters(Environment env, ExampleFilter exampleFilter) {
|
||||
this.env = env;
|
||||
this.exampleFilter = exampleFilter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EssentialFilter[] filters() {
|
||||
// Use the example filter if we're running development mode. If
|
||||
// we're running in production or test mode then don't use any
|
||||
// filters at all.
|
||||
if (env.mode().equals(Mode.DEV)) {
|
||||
return new EssentialFilter[] { exampleFilter };
|
||||
} else {
|
||||
return new EssentialFilter[] {};
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
import com.google.inject.AbstractModule;
|
||||
import java.time.Clock;
|
||||
|
||||
import services.ApplicationTimer;
|
||||
import services.AtomicCounter;
|
||||
import services.Counter;
|
||||
|
||||
/**
|
||||
* This class is a Guice module that tells Guice how to bind several
|
||||
* different types. This Guice module is created when the Play
|
||||
* application starts.
|
||||
*
|
||||
* Play will automatically use any class called `Module` that is in
|
||||
* the root package. You can create modules in other locations by
|
||||
* adding `play.modules.enabled` settings to the `application.conf`
|
||||
* configuration file.
|
||||
*/
|
||||
public class Module extends AbstractModule {
|
||||
|
||||
@Override
|
||||
public void configure() {
|
||||
// Use the system clock as the default implementation of Clock
|
||||
bind(Clock.class).toInstance(Clock.systemDefaultZone());
|
||||
// Ask Guice to create an instance of ApplicationTimer when the
|
||||
// application starts.
|
||||
bind(ApplicationTimer.class).asEagerSingleton();
|
||||
// Set AtomicCounter as the implementation for Counter.
|
||||
bind(Counter.class).to(AtomicCounter.class);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
package controllers;
|
||||
|
||||
import akka.actor.ActorSystem;
|
||||
|
||||
import javax.inject.*;
|
||||
|
||||
import play.*;
|
||||
import play.mvc.*;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import scala.concurrent.duration.Duration;
|
||||
import scala.concurrent.ExecutionContextExecutor;
|
||||
|
||||
/**
|
||||
* This controller contains an action that demonstrates how to write
|
||||
* simple asynchronous code in a controller. It uses a timer to
|
||||
* asynchronously delay sending a response for 1 second.
|
||||
*
|
||||
* @param actorSystem We need the {@link ActorSystem}'s
|
||||
* {@link Scheduler} to run code after a delay.
|
||||
* @param exec We need a Java {@link Executor} to apply the result
|
||||
* of the {@link CompletableFuture} and a Scala
|
||||
* {@link ExecutionContext} so we can use the Akka {@link Scheduler}.
|
||||
* An {@link ExecutionContextExecutor} implements both interfaces.
|
||||
*/
|
||||
@Singleton
|
||||
public class AsyncController extends Controller {
|
||||
|
||||
private final ActorSystem actorSystem;
|
||||
private final ExecutionContextExecutor exec;
|
||||
|
||||
@Inject
|
||||
public AsyncController(ActorSystem actorSystem, ExecutionContextExecutor exec) {
|
||||
this.actorSystem = actorSystem;
|
||||
this.exec = exec;
|
||||
}
|
||||
|
||||
/**
|
||||
* An action that returns a plain text message after a delay
|
||||
* of 1 second.
|
||||
* <p>
|
||||
* The configuration in the <code>routes</code> file means that this method
|
||||
* will be called when the application receives a <code>GET</code> request with
|
||||
* a path of <code>/message</code>.
|
||||
*/
|
||||
public CompletionStage<Result> message() {
|
||||
return getFutureMessage(1, TimeUnit.SECONDS).thenApplyAsync(Results::ok, exec);
|
||||
}
|
||||
|
||||
private CompletionStage<String> getFutureMessage(long time, TimeUnit timeUnit) {
|
||||
CompletableFuture<String> future = new CompletableFuture<>();
|
||||
actorSystem.scheduler().scheduleOnce(
|
||||
Duration.create(time, timeUnit),
|
||||
() -> future.complete("Hi!"),
|
||||
exec
|
||||
);
|
||||
return future;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
package controllers;
|
||||
|
||||
import javax.inject.*;
|
||||
import play.*;
|
||||
import play.mvc.*;
|
||||
|
||||
import services.Counter;
|
||||
|
||||
/**
|
||||
* This controller demonstrates how to use dependency injection to
|
||||
* bind a component into a controller class. The class contains an
|
||||
* action that shows an incrementing count to users. The {@link Counter}
|
||||
* object is injected by the Guice dependency injection system.
|
||||
*/
|
||||
@Singleton
|
||||
public class CountController extends Controller {
|
||||
|
||||
private final Counter counter;
|
||||
|
||||
@Inject
|
||||
public CountController(Counter counter) {
|
||||
this.counter = counter;
|
||||
}
|
||||
|
||||
/**
|
||||
* An action that responds with the {@link Counter}'s current
|
||||
* count. The result is plain text. This action is mapped to
|
||||
* <code>GET</code> requests with a path of <code>/count</code>
|
||||
* requests by an entry in the <code>routes</code> config file.
|
||||
*/
|
||||
public Result count() {
|
||||
return ok(Integer.toString(counter.nextCount()));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,14 +1,25 @@
|
||||
package controllers;
|
||||
|
||||
import play.libs.concurrent.HttpExecutionContext;
|
||||
import play.mvc.*;
|
||||
import play.twirl.api.Html;
|
||||
|
||||
import views.html.*;
|
||||
import javax.inject.Inject;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
|
||||
import static java.util.concurrent.CompletableFuture.supplyAsync;
|
||||
|
||||
/**
|
||||
* This controller contains an action to handle HTTP requests
|
||||
* to the application's home page.
|
||||
*/
|
||||
public class HomeController extends Controller {
|
||||
private HttpExecutionContext ec;
|
||||
|
||||
@Inject
|
||||
public HomeController(HttpExecutionContext ec) {
|
||||
this.ec = ec;
|
||||
}
|
||||
|
||||
/**
|
||||
* An action that renders an HTML page with a welcome message.
|
||||
@@ -17,7 +28,41 @@ public class HomeController extends Controller {
|
||||
* <code>GET</code> request with a path of <code>/</code>.
|
||||
*/
|
||||
public Result index() {
|
||||
return ok(index.render("Your new application is ready."));
|
||||
return ok(views.html.index.render());
|
||||
}
|
||||
|
||||
public Result applyHtml() {
|
||||
return ok(Html.apply("<h1>This text will appear as a heading 1</h1>"));
|
||||
}
|
||||
|
||||
public Result badRequestPage() {
|
||||
return badRequest("Your request data has issues.");
|
||||
}
|
||||
|
||||
public Result notFoundPage() {
|
||||
return notFound("Could not find the page you requested.");
|
||||
}
|
||||
|
||||
public Result customContentType() {
|
||||
return ok("This is some text content").as("text/html");
|
||||
}
|
||||
|
||||
public CompletionStage<Result> asyncOperation() {
|
||||
return supplyAsync(() -> {
|
||||
return longRunningTask();
|
||||
}, ec.current())
|
||||
.thenApplyAsync(s -> {
|
||||
return ok("Got result -> " + s);
|
||||
}, ec.current());
|
||||
}
|
||||
|
||||
private String longRunningTask() {
|
||||
return "Long running task has completed";
|
||||
}
|
||||
|
||||
public Result setHeaders() {
|
||||
return ok("This is some text content")
|
||||
.as("text/html")
|
||||
.withHeader("Header-Key", "Some value");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
package controllers;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import models.Student;
|
||||
import models.StudentStore;
|
||||
import play.libs.Json;
|
||||
import play.mvc.Controller;
|
||||
import play.mvc.Result;
|
||||
import util.Util;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public class StudentController extends Controller {
|
||||
public Result create() {
|
||||
JsonNode json = request().body().asJson();
|
||||
if (json == null) {
|
||||
return badRequest(Util.createResponse("Expecting Json data", false));
|
||||
}
|
||||
Student student = StudentStore.getInstance().addStudent(Json.fromJson(json, Student.class));
|
||||
JsonNode jsonObject = Json.toJson(student);
|
||||
return created(Util.createResponse(jsonObject, true));
|
||||
}
|
||||
|
||||
public Result update() {
|
||||
JsonNode json = request().body().asJson();
|
||||
if (json == null) {
|
||||
return badRequest(Util.createResponse("Expecting Json data", false));
|
||||
}
|
||||
Student student = StudentStore.getInstance().updateStudent(Json.fromJson(json, Student.class));
|
||||
if (student == null) {
|
||||
return notFound(Util.createResponse("Student not found", false));
|
||||
}
|
||||
|
||||
JsonNode jsonObject = Json.toJson(student);
|
||||
return ok(Util.createResponse(jsonObject, true));
|
||||
}
|
||||
|
||||
public Result retrieve(int id) {
|
||||
if (StudentStore.getInstance().getStudent(id) == null) {
|
||||
return notFound(Util.createResponse("Student with id:" + id + " not found", false));
|
||||
}
|
||||
JsonNode jsonObjects = Json.toJson(StudentStore.getInstance().getStudent(id));
|
||||
return ok(Util.createResponse(jsonObjects, true));
|
||||
}
|
||||
|
||||
public Result listStudents() {
|
||||
Set<Student> result = StudentStore.getInstance().getAllStudents();
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
JsonNode jsonData = mapper.convertValue(result, JsonNode.class);
|
||||
return ok(Util.createResponse(jsonData, true));
|
||||
|
||||
}
|
||||
|
||||
public Result delete(int id) {
|
||||
if (!StudentStore.getInstance().deleteStudent(id)) {
|
||||
return notFound(Util.createResponse("Student with id:" + id + " not found", false));
|
||||
}
|
||||
return ok(Util.createResponse("Student with id:" + id + " deleted", true));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
package filters;
|
||||
|
||||
import akka.stream.Materializer;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.function.Function;
|
||||
import javax.inject.*;
|
||||
import play.mvc.*;
|
||||
import play.mvc.Http.RequestHeader;
|
||||
|
||||
|
||||
/**
|
||||
* This is a simple filter that adds a header to all requests. It's
|
||||
* added to the application's list of filters by the
|
||||
* {@link Filters} class.
|
||||
*/
|
||||
@Singleton
|
||||
public class ExampleFilter extends Filter {
|
||||
|
||||
private final Executor exec;
|
||||
|
||||
/**
|
||||
* @param mat This object is needed to handle streaming of requests
|
||||
* and responses.
|
||||
* @param exec This class is needed to execute code asynchronously.
|
||||
* It is used below by the <code>thenAsyncApply</code> method.
|
||||
*/
|
||||
@Inject
|
||||
public ExampleFilter(Materializer mat, Executor exec) {
|
||||
super(mat);
|
||||
this.exec = exec;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletionStage<Result> apply(
|
||||
Function<RequestHeader, CompletionStage<Result>> next,
|
||||
RequestHeader requestHeader) {
|
||||
|
||||
return next.apply(requestHeader).thenApplyAsync(
|
||||
result -> result.withHeader("X-ExampleFilter", "foo"),
|
||||
exec
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package models;
|
||||
public class Student {
|
||||
private String firstName;
|
||||
private String lastName;
|
||||
private int age;
|
||||
private int id;
|
||||
public Student(){}
|
||||
public Student(String firstName, String lastName, int age) {
|
||||
super();
|
||||
this.firstName = firstName;
|
||||
this.lastName = lastName;
|
||||
this.age = age;
|
||||
}
|
||||
|
||||
public String getFirstName() {
|
||||
return firstName;
|
||||
}
|
||||
|
||||
public void setFirstName(String firstName) {
|
||||
this.firstName = firstName;
|
||||
}
|
||||
|
||||
public String getLastName() {
|
||||
return lastName;
|
||||
}
|
||||
|
||||
public void setLastName(String lastName) {
|
||||
this.lastName = lastName;
|
||||
}
|
||||
|
||||
public int getAge() {
|
||||
return age;
|
||||
}
|
||||
|
||||
public void setAge(int age) {
|
||||
this.age = age;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
package models;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class StudentStore {
|
||||
private static StudentStore instance;
|
||||
private Map<Integer, Student> students = new HashMap<>();
|
||||
|
||||
public static StudentStore getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new StudentStore();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public Student addStudent(Student student) {
|
||||
int id = students.size();
|
||||
student.setId(id);
|
||||
students.put(id, student);
|
||||
return student;
|
||||
}
|
||||
|
||||
public Student getStudent(int id) {
|
||||
return students.get(id);
|
||||
}
|
||||
|
||||
public Set<Student> getAllStudents() {
|
||||
return new HashSet<>(students.values());
|
||||
}
|
||||
|
||||
public Student updateStudent(Student student) {
|
||||
int id = student.getId();
|
||||
if (students.containsKey(id)) {
|
||||
students.put(id, student);
|
||||
return student;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean deleteStudent(int id) {
|
||||
return students.remove(id) != null;
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
package services;
|
||||
|
||||
import java.time.Clock;
|
||||
import java.time.Instant;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import javax.inject.*;
|
||||
import play.Logger;
|
||||
import play.inject.ApplicationLifecycle;
|
||||
|
||||
/**
|
||||
* This class demonstrates how to run code when the
|
||||
* application starts and stops. It starts a timer when the
|
||||
* application starts. When the application stops it prints out how
|
||||
* long the application was running for.
|
||||
*
|
||||
* This class is registered for Guice dependency injection in the
|
||||
* {@link Module} class. We want the class to start when the application
|
||||
* starts, so it is registered as an "eager singleton". See the code
|
||||
* in the {@link Module} class to see how this happens.
|
||||
*
|
||||
* This class needs to run code when the server stops. It uses the
|
||||
* application's {@link ApplicationLifecycle} to register a stop hook.
|
||||
*/
|
||||
@Singleton
|
||||
public class ApplicationTimer {
|
||||
|
||||
private final Clock clock;
|
||||
private final ApplicationLifecycle appLifecycle;
|
||||
private final Instant start;
|
||||
|
||||
@Inject
|
||||
public ApplicationTimer(Clock clock, ApplicationLifecycle appLifecycle) {
|
||||
this.clock = clock;
|
||||
this.appLifecycle = appLifecycle;
|
||||
// This code is called when the application starts.
|
||||
start = clock.instant();
|
||||
Logger.info("ApplicationTimer demo: Starting application at " + start);
|
||||
|
||||
// When the application starts, register a stop hook with the
|
||||
// ApplicationLifecycle object. The code inside the stop hook will
|
||||
// be run when the application stops.
|
||||
appLifecycle.addStopHook(() -> {
|
||||
Instant stop = clock.instant();
|
||||
Long runningTime = stop.getEpochSecond() - start.getEpochSecond();
|
||||
Logger.info("ApplicationTimer demo: Stopping application at " + clock.instant() + " after " + runningTime + "s.");
|
||||
return CompletableFuture.completedFuture(null);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
package services;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import javax.inject.*;
|
||||
|
||||
/**
|
||||
* This class is a concrete implementation of the {@link Counter} trait.
|
||||
* It is configured for Guice dependency injection in the {@link Module}
|
||||
* class.
|
||||
*
|
||||
* This class has a {@link Singleton} annotation because we need to make
|
||||
* sure we only use one counter per application. Without this
|
||||
* annotation we would get a new instance every time a {@link Counter} is
|
||||
* injected.
|
||||
*/
|
||||
@Singleton
|
||||
public class AtomicCounter implements Counter {
|
||||
|
||||
private final AtomicInteger atomicCounter = new AtomicInteger();
|
||||
|
||||
@Override
|
||||
public int nextCount() {
|
||||
return atomicCounter.getAndIncrement();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package services;
|
||||
|
||||
/**
|
||||
* This interface demonstrates how to create a component that is injected
|
||||
* into a controller. The interface represents a counter that returns a
|
||||
* incremented number each time it is called.
|
||||
*
|
||||
* The {@link Modules} class binds this interface to the
|
||||
* {@link AtomicCounter} implementation.
|
||||
*/
|
||||
public interface Counter {
|
||||
int nextCount();
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package util;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import play.libs.Json;
|
||||
|
||||
public class Util {
|
||||
public static ObjectNode createResponse(Object response, boolean ok) {
|
||||
ObjectNode result = Json.newObject();
|
||||
result.put("isSuccessfull", ok);
|
||||
if (response instanceof String)
|
||||
result.put("body", (String) response);
|
||||
else result.put("body", (JsonNode) response);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -1,20 +1,5 @@
|
||||
@*
|
||||
* This template takes a single argument, a String containing a
|
||||
* message to display.
|
||||
*@
|
||||
@(message: String)
|
||||
@()
|
||||
|
||||
@*
|
||||
* Call the `main` template with two arguments. The first
|
||||
* argument is a `String` with the title of the page, the second
|
||||
* argument is an `Html` object containing the body of the page.
|
||||
*@
|
||||
@main("Welcome to Play") {
|
||||
|
||||
@*
|
||||
* Get an `Html` object by calling the built-in Play welcome
|
||||
* template and passing a `String` message.
|
||||
*@
|
||||
@play20.welcome(message, style = "Java")
|
||||
|
||||
<h1>Welcome to Play!</h1>
|
||||
}
|
||||
|
||||
@@ -13,11 +13,12 @@
|
||||
<title>@title</title>
|
||||
<link rel="stylesheet" media="screen" href="@routes.Assets.versioned("stylesheets/main.css")">
|
||||
<link rel="shortcut icon" type="image/png" href="@routes.Assets.versioned("images/favicon.png")">
|
||||
<script src="@routes.Assets.versioned("javascripts/hello.js")" type="text/javascript"></script>
|
||||
</head>
|
||||
<body>
|
||||
@* And here's where we render the `Html` object containing
|
||||
* the page content. *@
|
||||
@content
|
||||
|
||||
<script src="@routes.Assets.versioned("javascripts/main.js")" type="text/javascript"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user