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
@@ -0,0 +1,9 @@
|
||||
logs
|
||||
target
|
||||
/.idea
|
||||
/.g8
|
||||
/.idea_modules
|
||||
/.classpath
|
||||
/.project
|
||||
/.settings
|
||||
/RUNNING_PID
|
||||
@@ -0,0 +1,91 @@
|
||||
package controllers;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import model.Student;
|
||||
import play.libs.Json;
|
||||
import play.libs.concurrent.HttpExecutionContext;
|
||||
import play.mvc.Controller;
|
||||
import play.mvc.Http;
|
||||
import play.mvc.Result;
|
||||
import store.StudentStore;
|
||||
import utils.Util;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
|
||||
import static java.util.concurrent.CompletableFuture.supplyAsync;
|
||||
|
||||
public class StudentController extends Controller {
|
||||
private HttpExecutionContext ec;
|
||||
private StudentStore studentStore;
|
||||
|
||||
@Inject
|
||||
public StudentController(HttpExecutionContext ec, StudentStore studentStore) {
|
||||
this.studentStore = studentStore;
|
||||
this.ec = ec;
|
||||
}
|
||||
|
||||
public CompletionStage<Result> create(Http.Request request) {
|
||||
JsonNode json = request.body().asJson();
|
||||
return supplyAsync(() -> {
|
||||
if (json == null) {
|
||||
return badRequest(Util.createResponse("Expecting Json data", false));
|
||||
}
|
||||
|
||||
Optional<Student> studentOptional = studentStore.addStudent(Json.fromJson(json, Student.class));
|
||||
return studentOptional.map(student -> {
|
||||
JsonNode jsonObject = Json.toJson(student);
|
||||
return created(Util.createResponse(jsonObject, true));
|
||||
}).orElse(internalServerError(Util.createResponse("Could not create data.", false)));
|
||||
}, ec.current());
|
||||
}
|
||||
|
||||
public CompletionStage<Result> listStudents() {
|
||||
return supplyAsync(() -> {
|
||||
Set<Student> result = studentStore.getAllStudents();
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
JsonNode jsonData = mapper.convertValue(result, JsonNode.class);
|
||||
return ok(Util.createResponse(jsonData, true));
|
||||
}, ec.current());
|
||||
}
|
||||
|
||||
public CompletionStage<Result> retrieve(int id) {
|
||||
return supplyAsync(() -> {
|
||||
final Optional<Student> studentOptional = studentStore.getStudent(id);
|
||||
return studentOptional.map(student -> {
|
||||
JsonNode jsonObjects = Json.toJson(student);
|
||||
return ok(Util.createResponse(jsonObjects, true));
|
||||
}).orElse(notFound(Util.createResponse("Student with id:" + id + " not found", false)));
|
||||
}, ec.current());
|
||||
}
|
||||
|
||||
public CompletionStage<Result> update(Http.Request request) {
|
||||
JsonNode json = request.body().asJson();
|
||||
return supplyAsync(() -> {
|
||||
if (json == null) {
|
||||
return badRequest(Util.createResponse("Expecting Json data", false));
|
||||
}
|
||||
Optional<Student> studentOptional = studentStore.updateStudent(Json.fromJson(json, Student.class));
|
||||
return studentOptional.map(student -> {
|
||||
if (student == null) {
|
||||
return notFound(Util.createResponse("Student not found", false));
|
||||
}
|
||||
JsonNode jsonObject = Json.toJson(student);
|
||||
return ok(Util.createResponse(jsonObject, true));
|
||||
}).orElse(internalServerError(Util.createResponse("Could not create data.", false)));
|
||||
}, ec.current());
|
||||
}
|
||||
|
||||
public CompletionStage<Result> delete(int id) {
|
||||
return supplyAsync(() -> {
|
||||
boolean status = studentStore.deleteStudent(id);
|
||||
if (!status) {
|
||||
return notFound(Util.createResponse("Student with id:" + id + " not found", false));
|
||||
}
|
||||
return ok(Util.createResponse("Student with id:" + id + " deleted", true));
|
||||
}, ec.current());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package model;
|
||||
|
||||
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, int id) {
|
||||
this.firstName = firstName;
|
||||
this.lastName = lastName;
|
||||
this.age = age;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package store;
|
||||
|
||||
import model.Student;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class StudentStore {
|
||||
private Map<Integer, Student> students = new HashMap<>();
|
||||
|
||||
public Optional<Student> addStudent(Student student) {
|
||||
int id = students.size();
|
||||
student.setId(id);
|
||||
students.put(id, student);
|
||||
return Optional.ofNullable(student);
|
||||
}
|
||||
|
||||
public Optional<Student> getStudent(int id) {
|
||||
return Optional.ofNullable(students.get(id));
|
||||
}
|
||||
|
||||
public Set<Student> getAllStudents() {
|
||||
return new HashSet<>(students.values());
|
||||
}
|
||||
|
||||
public Optional<Student> updateStudent(Student student) {
|
||||
int id = student.getId();
|
||||
if (students.containsKey(id)) {
|
||||
students.put(id, student);
|
||||
return Optional.ofNullable(student);
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
public boolean deleteStudent(int id) {
|
||||
return students.remove(id) != null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package utils;
|
||||
|
||||
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("isSuccessful", ok);
|
||||
if (response instanceof String) {
|
||||
result.put("body", (String) response);
|
||||
} else {
|
||||
result.putPOJO("body", response);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
name := """student-api"""
|
||||
organization := "com.baeldung"
|
||||
|
||||
version := "1.0-SNAPSHOT"
|
||||
|
||||
lazy val root = (project in file(".")).enablePlugins(PlayJava)
|
||||
|
||||
scalaVersion := "2.13.0"
|
||||
|
||||
libraryDependencies += guice
|
||||
@@ -0,0 +1,2 @@
|
||||
# This is the main configuration file for the application.
|
||||
# https://www.playframework.com/documentation/latest/ConfigFile
|
||||
@@ -0,0 +1,35 @@
|
||||
<!-- https://www.playframework.com/documentation/latest/SettingsLogger -->
|
||||
<configuration>
|
||||
|
||||
<conversionRule conversionWord="coloredLevel" converterClass="play.api.libs.logback.ColoredLevel" />
|
||||
|
||||
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
|
||||
<file>${application.home:-.}/logs/application.log</file>
|
||||
<encoder>
|
||||
<pattern>%date [%level] from %logger in %thread - %message%n%xException</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%coloredLevel %logger{15} - %message%n%xException{10}</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<appender name="ASYNCFILE" class="ch.qos.logback.classic.AsyncAppender">
|
||||
<appender-ref ref="FILE" />
|
||||
</appender>
|
||||
|
||||
<appender name="ASYNCSTDOUT" class="ch.qos.logback.classic.AsyncAppender">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</appender>
|
||||
|
||||
<logger name="play" level="INFO" />
|
||||
<logger name="application" level="DEBUG" />
|
||||
|
||||
<root level="WARN">
|
||||
<appender-ref ref="ASYNCFILE" />
|
||||
<appender-ref ref="ASYNCSTDOUT" />
|
||||
</root>
|
||||
|
||||
</configuration>
|
||||
@@ -0,0 +1,12 @@
|
||||
# Routes
|
||||
# This file defines all application routes (Higher priority routes first)
|
||||
# ~~~~
|
||||
|
||||
GET / controllers.StudentController.listStudents()
|
||||
GET /:id controllers.StudentController.retrieve(id:Int)
|
||||
POST / controllers.StudentController.create(request: Request)
|
||||
PUT / controllers.StudentController.update(request: Request)
|
||||
DELETE /:id controllers.StudentController.delete(id:Int)
|
||||
|
||||
# Map static resources from the /public folder to the /assets URL path
|
||||
GET /assets/*file controllers.Assets.versioned(path="/public", file: Asset)
|
||||
@@ -0,0 +1 @@
|
||||
sbt.version=1.2.8
|
||||
@@ -0,0 +1,7 @@
|
||||
// The Play plugin
|
||||
addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.7.3")
|
||||
|
||||
// Defines scaffolding (found under .g8 folder)
|
||||
// http://www.foundweekends.org/giter8/scaffolding.html
|
||||
// sbt "g8Scaffold form"
|
||||
addSbtPlugin("org.foundweekends.giter8" % "sbt-giter8-scaffold" % "0.11.0")
|
||||
@@ -1,172 +0,0 @@
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import model.Student;
|
||||
import play.test.*;
|
||||
import static play.test.Helpers.*;
|
||||
|
||||
public class ApplicationLiveTest{
|
||||
private static final String BASE_URL = "http://localhost:9000";
|
||||
|
||||
@Test
|
||||
public void testInServer() throws Exception {
|
||||
TestServer server = testServer(3333);
|
||||
running(server, () -> {
|
||||
try {
|
||||
WSClient ws = play.libs.ws.WS.newClient(3333);
|
||||
CompletionStage<WSResponse> completionStage = ws.url("/").get();
|
||||
WSResponse response = completionStage.toCompletableFuture().get();
|
||||
ws.close();
|
||||
assertEquals(OK, response.getStatus());
|
||||
} catch (Exception e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
});
|
||||
}
|
||||
@Test
|
||||
public void whenCreatesRecord_thenCorrect() {
|
||||
Student student = new Student("jody", "west", 50);
|
||||
JSONObject obj = new JSONObject(makeRequest(BASE_URL, "POST", new JSONObject(student)));
|
||||
assertTrue(obj.getBoolean("isSuccessfull"));
|
||||
JSONObject body = obj.getJSONObject("body");
|
||||
assertEquals(student.getAge(), body.getInt("age"));
|
||||
assertEquals(student.getFirstName(), body.getString("firstName"));
|
||||
assertEquals(student.getLastName(), body.getString("lastName"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenDeletesCreatedRecord_thenCorrect() {
|
||||
Student student = new Student("Usain", "Bolt", 25);
|
||||
JSONObject ob1 = new JSONObject(makeRequest(BASE_URL, "POST", new JSONObject(student))).getJSONObject("body");
|
||||
int id = ob1.getInt("id");
|
||||
JSONObject obj1 = new JSONObject(makeRequest(BASE_URL + "/" + id, "POST", new JSONObject()));
|
||||
assertTrue(obj1.getBoolean("isSuccessfull"));
|
||||
makeRequest(BASE_URL + "/" + id, "DELETE", null);
|
||||
JSONObject obj2 = new JSONObject(makeRequest(BASE_URL + "/" + id, "POST", new JSONObject()));
|
||||
assertFalse(obj2.getBoolean("isSuccessfull"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenUpdatesCreatedRecord_thenCorrect() {
|
||||
Student student = new Student("john", "doe", 50);
|
||||
JSONObject body1 = new JSONObject(makeRequest(BASE_URL, "POST", new JSONObject(student))).getJSONObject("body");
|
||||
assertEquals(student.getAge(), body1.getInt("age"));
|
||||
int newAge = 60;
|
||||
body1.put("age", newAge);
|
||||
JSONObject body2 = new JSONObject(makeRequest(BASE_URL, "PUT", body1)).getJSONObject("body");
|
||||
assertFalse(student.getAge() == body2.getInt("age"));
|
||||
assertTrue(newAge == body2.getInt("age"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenGetsAllRecords_thenCorrect() {
|
||||
Student student1 = new Student("jane", "daisy", 50);
|
||||
Student student2 = new Student("john", "daniel", 60);
|
||||
Student student3 = new Student("don", "mason", 55);
|
||||
Student student4 = new Student("scarlet", "ohara", 90);
|
||||
|
||||
makeRequest(BASE_URL, "POST", new JSONObject(student1));
|
||||
makeRequest(BASE_URL, "POST", new JSONObject(student2));
|
||||
makeRequest(BASE_URL, "POST", new JSONObject(student3));
|
||||
makeRequest(BASE_URL, "POST", new JSONObject(student4));
|
||||
|
||||
JSONObject objects = new JSONObject(makeRequest(BASE_URL, "GET", null));
|
||||
assertTrue(objects.getBoolean("isSuccessfull"));
|
||||
JSONArray array = objects.getJSONArray("body");
|
||||
assertTrue(array.length() >= 4);
|
||||
}
|
||||
|
||||
public static String makeRequest(String myUrl, String httpMethod, JSONObject parameters) {
|
||||
|
||||
URL url = null;
|
||||
try {
|
||||
url = new URL(myUrl);
|
||||
} catch (MalformedURLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
HttpURLConnection conn = null;
|
||||
try {
|
||||
|
||||
conn = (HttpURLConnection) url.openConnection();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
conn.setDoInput(true);
|
||||
|
||||
conn.setReadTimeout(10000);
|
||||
|
||||
conn.setRequestProperty("Content-Type", "application/json");
|
||||
DataOutputStream dos = null;
|
||||
int respCode = 0;
|
||||
String inputString = null;
|
||||
try {
|
||||
conn.setRequestMethod(httpMethod);
|
||||
|
||||
if (Arrays.asList("POST", "PUT").contains(httpMethod)) {
|
||||
String params = parameters.toString();
|
||||
|
||||
conn.setDoOutput(true);
|
||||
|
||||
dos = new DataOutputStream(conn.getOutputStream());
|
||||
dos.writeBytes(params);
|
||||
dos.flush();
|
||||
dos.close();
|
||||
}
|
||||
respCode = conn.getResponseCode();
|
||||
if (respCode != 200 && respCode != 201) {
|
||||
String error = inputStreamToString(conn.getErrorStream());
|
||||
return error;
|
||||
}
|
||||
inputString = inputStreamToString(conn.getInputStream());
|
||||
|
||||
} catch (IOException e) {
|
||||
|
||||
e.printStackTrace();
|
||||
}
|
||||
return inputString;
|
||||
}
|
||||
|
||||
public static String inputStreamToString(InputStream is) {
|
||||
BufferedReader br = null;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
String line;
|
||||
try {
|
||||
|
||||
br = new BufferedReader(new InputStreamReader(is));
|
||||
while ((line = br.readLine()) != null) {
|
||||
sb.append(line);
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if (br != null) {
|
||||
try {
|
||||
br.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package controllers;
|
||||
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import org.junit.Test;
|
||||
import play.Application;
|
||||
import play.inject.guice.GuiceApplicationBuilder;
|
||||
import play.libs.Json;
|
||||
import play.mvc.Http;
|
||||
import play.mvc.Result;
|
||||
import play.test.WithApplication;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static play.mvc.Http.Status.OK;
|
||||
import static play.test.Helpers.*;
|
||||
|
||||
public class StudentControllerUnitTest extends WithApplication {
|
||||
|
||||
@Override
|
||||
protected Application provideApplication() {
|
||||
return new GuiceApplicationBuilder().build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenStudentPostData_whenCreatingStudent_ThenShouldReturnCreatedStudent() {
|
||||
final ObjectNode jsonNode = Json.newObject();
|
||||
jsonNode.put("firstName", "John");
|
||||
jsonNode.put("lastName", "Baeldung");
|
||||
jsonNode.put("age", 25);
|
||||
|
||||
Http.RequestBuilder request = new Http.RequestBuilder()
|
||||
.method(POST)
|
||||
.bodyJson(jsonNode)
|
||||
.uri("/");
|
||||
|
||||
Result result = route(app, request);
|
||||
assertEquals(CREATED, result.status());
|
||||
assertTrue(result.contentType().isPresent());
|
||||
assertEquals("application/json", result.contentType().get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenUrlToListStudents_whenListingStudents_ThenShouldReturnStudentList() {
|
||||
Http.RequestBuilder request = new Http.RequestBuilder()
|
||||
.method(GET)
|
||||
.uri("/");
|
||||
|
||||
Result result = route(app, request);
|
||||
assertEquals(OK, result.status());
|
||||
assertTrue(result.contentType().isPresent());
|
||||
assertEquals("application/json", result.contentType().get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenUrlToRetrieveSingleStudent_whenRetrievingStudent_ThenShouldReturn404NotFound() {
|
||||
Http.RequestBuilder request = new Http.RequestBuilder()
|
||||
.method(GET)
|
||||
.uri("/1");
|
||||
|
||||
Result result = route(app, request);
|
||||
assertEquals(NOT_FOUND, result.status());
|
||||
assertTrue(result.contentType().isPresent());
|
||||
assertEquals("application/json", result.contentType().get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenUrlToUpdateStudent_whenaUpdatingStudent_ThenShouldFail() {
|
||||
final ObjectNode jsonNode = Json.newObject();
|
||||
jsonNode.put("firstName", "John");
|
||||
jsonNode.put("lastName", "Baeldung");
|
||||
jsonNode.put("age", 25);
|
||||
|
||||
Http.RequestBuilder request = new Http.RequestBuilder()
|
||||
.method(PUT)
|
||||
.bodyJson(jsonNode)
|
||||
.uri("/");
|
||||
|
||||
Result result = route(app, request);
|
||||
assertEquals(INTERNAL_SERVER_ERROR, result.status());
|
||||
assertTrue(result.contentType().isPresent());
|
||||
assertEquals("application/json", result.contentType().get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenIdToDeleteStudent_whenDeletingStudent_ThenShouldFail() {
|
||||
Http.RequestBuilder request = new Http.RequestBuilder()
|
||||
.method(DELETE)
|
||||
.uri("/1");
|
||||
|
||||
Result result = route(app, request);
|
||||
assertEquals(NOT_FOUND, result.status());
|
||||
assertTrue(result.contentType().isPresent());
|
||||
assertEquals("application/json", result.contentType().get());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user