diff --git a/pom.xml b/pom.xml index d1b27bc9c9..e6e11326d7 100644 --- a/pom.xml +++ b/pom.xml @@ -122,6 +122,7 @@ solr spark-java spring-5 + spring-5-mvc spring-akka spring-amqp spring-all diff --git a/spring-5-mvc/.gitignore b/spring-5-mvc/.gitignore new file mode 100644 index 0000000000..b7b5c734f2 --- /dev/null +++ b/spring-5-mvc/.gitignore @@ -0,0 +1,20 @@ +*.class + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +.settings/ +.classpath +.project +target/ + +*.iml +.idea + +# Package Files # +*.jar +*.war +*.ear + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* diff --git a/spring-5-mvc/pom.xml b/spring-5-mvc/pom.xml new file mode 100644 index 0000000000..b8c341afde --- /dev/null +++ b/spring-5-mvc/pom.xml @@ -0,0 +1,154 @@ + + + 4.0.0 + + com.baeldung + spring-5-mvc + 0.0.1-SNAPSHOT + jar + + spring-5-mvc + spring 5 MVC sample project about new features + + + org.springframework.boot + spring-boot-starter-parent + 2.0.0.M1 + + + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.boot + spring-boot-starter-validation + + + org.springframework.boot + spring-boot-starter-web + + + + + + org.apache.commons + commons-lang3 + + + org.slf4j + slf4j-api + + + org.slf4j + jcl-over-slf4j + + + + + + org.springframework.boot + spring-boot-devtools + runtime + + + com.h2database + h2 + runtime + + + + org.springframework + spring-test + + + org.springframework.boot + spring-boot-starter-test + test + + + + junit + junit + test + + + + com.jayway.restassured + rest-assured + ${rest-assured.version} + test + + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + true + false + + **/*IntegrationTest.java + **/*LiveTest.java + + + + + + + + + + spring-snapshots + Spring Snapshots + https://repo.spring.io/snapshot + + true + + + + spring-milestones + Spring Milestones + https://repo.spring.io/milestone + + false + + + + + + spring-snapshots + Spring Snapshots + https://repo.spring.io/snapshot + + true + + + + spring-milestones + Spring Milestones + https://repo.spring.io/milestone + + false + + + + + + 2.9.0 + UTF-8 + UTF-8 + 1.8 + + + diff --git a/spring-5-mvc/src/main/java/com/baeldung/Spring5Application.java b/spring-5-mvc/src/main/java/com/baeldung/Spring5Application.java new file mode 100644 index 0000000000..41b5c1eed1 --- /dev/null +++ b/spring-5-mvc/src/main/java/com/baeldung/Spring5Application.java @@ -0,0 +1,13 @@ +package com.baeldung; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Spring5Application { + + public static void main(String[] args) { + SpringApplication.run(Spring5Application.class, args); + } + +} diff --git a/spring-5-mvc/src/main/java/com/baeldung/model/Foo.java b/spring-5-mvc/src/main/java/com/baeldung/model/Foo.java new file mode 100644 index 0000000000..a9ffee14da --- /dev/null +++ b/spring-5-mvc/src/main/java/com/baeldung/model/Foo.java @@ -0,0 +1,84 @@ +package com.baeldung.model; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; + +@Entity +public class Foo { + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private Long id; + + private String name; + + public Foo() { + super(); + } + + public Foo(final String name) { + super(); + + this.name = name; + } + + public Foo(final long id, final String name) { + super(); + + this.id = id; + this.name = name; + } + + // API + + public String getName() { + return name; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public void setName(final String name) { + this.name = name; + } + + // + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((name == null) ? 0 : name.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Foo other = (Foo) obj; + if (name == null) { + if (other.name != null) + return false; + } else if (!name.equals(other.name)) + return false; + return true; + } + + @Override + public String toString() { + return "Foo [name=" + name + "]"; + } + +} \ No newline at end of file diff --git a/spring-5-mvc/src/main/java/com/baeldung/persistence/DataSetupBean.java b/spring-5-mvc/src/main/java/com/baeldung/persistence/DataSetupBean.java new file mode 100644 index 0000000000..cf78977961 --- /dev/null +++ b/spring-5-mvc/src/main/java/com/baeldung/persistence/DataSetupBean.java @@ -0,0 +1,26 @@ +package com.baeldung.persistence; + +import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic; + +import java.util.stream.IntStream; + +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.baeldung.model.Foo; + +@Component +public class DataSetupBean implements InitializingBean { + + @Autowired + private FooRepository repo; + + // + + @Override + public void afterPropertiesSet() throws Exception { + IntStream.range(1, 5).forEach(i -> repo.save(new Foo(randomAlphabetic(8)))); + } + +} diff --git a/spring-5-mvc/src/main/java/com/baeldung/persistence/FooRepository.java b/spring-5-mvc/src/main/java/com/baeldung/persistence/FooRepository.java new file mode 100644 index 0000000000..3c70f38fce --- /dev/null +++ b/spring-5-mvc/src/main/java/com/baeldung/persistence/FooRepository.java @@ -0,0 +1,10 @@ +package com.baeldung.persistence; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +import com.baeldung.model.Foo; + +public interface FooRepository extends JpaRepository, JpaSpecificationExecutor { + +} diff --git a/spring-5-mvc/src/main/java/com/baeldung/web/FooController.java b/spring-5-mvc/src/main/java/com/baeldung/web/FooController.java new file mode 100644 index 0000000000..d03cebb4fd --- /dev/null +++ b/spring-5-mvc/src/main/java/com/baeldung/web/FooController.java @@ -0,0 +1,66 @@ +package com.baeldung.web; + +import java.util.List; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.PageRequest; +import org.springframework.http.HttpStatus; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.server.ResponseStatusException; + +import com.baeldung.model.Foo; +import com.baeldung.persistence.FooRepository; + +@RestController("/foos") +public class FooController { + + @Autowired + private FooRepository repo; + + // API - read + + @GetMapping("/foos/{id}") + @Validated + public Foo findById(@PathVariable @Min(0) final long id) { + return repo.findById(id).orElse(null); + } + + @GetMapping + public List findAll() { + return repo.findAll(); + } + + @GetMapping(params = { "page", "size" }) + @Validated + public List findPaginated(@RequestParam("page") @Min(0) final int page, @Max(100) @RequestParam("size") final int size) { + return repo.findAll(PageRequest.of(page, size)).getContent(); + } + + // API - write + + @PutMapping("/foos/{id}") + @ResponseStatus(HttpStatus.OK) + public Foo update(@PathVariable("id") final String id, @RequestBody final Foo foo) { + return foo; + } + + @PostMapping + @ResponseStatus(HttpStatus.CREATED) + public void create( @RequestBody final Foo foo) { + if (null == foo || null == foo.getName()) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST," 'name' is required"); + } + repo.save(foo); + } +} diff --git a/spring-5-mvc/src/main/resources/application.properties b/spring-5-mvc/src/main/resources/application.properties new file mode 100644 index 0000000000..886ea1978b --- /dev/null +++ b/spring-5-mvc/src/main/resources/application.properties @@ -0,0 +1,6 @@ +server.port=8081 + +security.user.name=user +security.user.password=pass + +logging.level.root=INFO \ No newline at end of file diff --git a/spring-5-mvc/src/main/webapp/WEB-INF/web.xml b/spring-5-mvc/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000000..bfcf43dad2 --- /dev/null +++ b/spring-5-mvc/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,21 @@ + + + + Spring Functional Application + + + functional + com.baeldung.functional.RootServlet + 1 + true + + + functional + / + + + + \ No newline at end of file diff --git a/spring-5-mvc/src/test/java/com/baeldung/test/LiveTest.java b/spring-5-mvc/src/test/java/com/baeldung/test/LiveTest.java new file mode 100644 index 0000000000..637913541c --- /dev/null +++ b/spring-5-mvc/src/test/java/com/baeldung/test/LiveTest.java @@ -0,0 +1,54 @@ +package com.baeldung.test; + +import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic; +import static org.junit.Assert.assertEquals; + +import org.junit.Test; +import org.springframework.http.MediaType; + +import com.jayway.restassured.RestAssured; +import com.jayway.restassured.response.Response; +import com.jayway.restassured.specification.RequestSpecification; + +public class LiveTest { + + private static String APP_ROOT = "http://localhost:8081"; + + + @Test + public void givenUser_whenPostWithNullName_then400BadRequest() { + final Response response = givenAuth("user", "pass").contentType(MediaType.APPLICATION_JSON.toString()).body(resourceWithNullName()).post(APP_ROOT + "/user"); + assertEquals(400, response.getStatusCode()); + } + + @Test + public void givenUser_whenResourceCreated_then201Created() { + final Response response = givenAuth("user", "pass").contentType(MediaType.APPLICATION_JSON.toString()).body(resourceString()).post(APP_ROOT + "/user"); + assertEquals(201, response.getStatusCode()); + } + + /*@Test + public void givenUser_whenGetAllFoos_thenOK() { + final Response response = givenAuth("user", "pass").get(APP_ROOT + "/foos"); + assertEquals(200, response.getStatusCode()); + }*/ + + + + // + + private final String resourceWithNullName() { + final String roleData = "{\"name\":null}"; + return roleData; + } + + private final String resourceString() { + final String roleData = "{\"name\":\"" + randomAlphabetic(8) + "\"}"; + return roleData; + } + + private final RequestSpecification givenAuth(String username, String password) { + return RestAssured.given().auth().preemptive().basic(username, password); + } + +} \ No newline at end of file diff --git a/spring-5-mvc/src/test/java/com/baeldung/test/Spring5ApplicationIntegrationTest.java b/spring-5-mvc/src/test/java/com/baeldung/test/Spring5ApplicationIntegrationTest.java new file mode 100644 index 0000000000..c3790333ff --- /dev/null +++ b/spring-5-mvc/src/test/java/com/baeldung/test/Spring5ApplicationIntegrationTest.java @@ -0,0 +1,18 @@ +package com.baeldung.test; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import com.baeldung.Spring5Application; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = Spring5Application.class) +public class Spring5ApplicationIntegrationTest { + + @Test + public void contextLoads() { + } + +} diff --git a/spring-5-mvc/src/test/resources/baeldung-weekly.png b/spring-5-mvc/src/test/resources/baeldung-weekly.png new file mode 100644 index 0000000000..5a27d61dae Binary files /dev/null and b/spring-5-mvc/src/test/resources/baeldung-weekly.png differ