From 889a6b3bbe5bfce4da109154becb80652fc09d74 Mon Sep 17 00:00:00 2001 From: Ranga Rao Karanam Date: Wed, 4 Jan 2017 10:26:00 +0530 Subject: [PATCH] Step 019 --- Step17.md | 1 + Step17.zip | Bin 0 -> 10360 bytes Step18.md | 743 ++++++++++++++++++ Step19.md | 659 ++++++++++++++++ pom.xml | 21 +- .../com/in28minutes/springboot/jpa/User.java | 44 ++ .../springboot/jpa/UserCommandLineRunner.java | 48 ++ .../springboot/jpa/UserRepository.java | 9 + src/main/resources/application.properties | 2 +- 9 files changed, 1518 insertions(+), 9 deletions(-) create mode 100644 Step17.zip create mode 100644 Step18.md create mode 100644 Step19.md create mode 100644 src/main/java/com/in28minutes/springboot/jpa/User.java create mode 100644 src/main/java/com/in28minutes/springboot/jpa/UserCommandLineRunner.java create mode 100644 src/main/java/com/in28minutes/springboot/jpa/UserRepository.java diff --git a/Step17.md b/Step17.md index a27f367..50b8b75 100644 --- a/Step17.md +++ b/Step17.md @@ -2,6 +2,7 @@ - Even better configuration management than @Value - Type-safe Configuration Properties - http://localhost:8080/dynamic-configuration +- Also look at http://localhost:8080/actuator/#http://localhost:8080/configprops ## Useful Snippets and References First Snippet diff --git a/Step17.zip b/Step17.zip new file mode 100644 index 0000000000000000000000000000000000000000..a58170d8512d1e499284dfb55322beeef08a5f9c GIT binary patch literal 10360 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 + org.springframework.boot + spring-boot-starter-data-jpa + + + + com.h2database + h2 + + +``` +Second Snippet +``` +package com.in28minutes.springboot.jpa; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; + +@Entity +public class User { + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private Long id; + + private String name;// Not perfect!! Should be a proper object! + private String role;// Not perfect!! An enum should be a better choice! + + protected User() { + } + + public User(String name, String role) { + super(); + this.name = name; + this.role = role; + } + + public Long getId() { + return id; + } + + public String getName() { + return name; + } + + public String getRole() { + return role; + } + + @Override + public String toString() { + return String.format("User [id=%s, name=%s, role=%s]", id, name, role); + } + +} + +``` +Third Snippet +``` +package com.in28minutes.springboot.jpa; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.CommandLineRunner; +import org.springframework.stereotype.Component; + +@Component +public class UserCommandLineRunner implements CommandLineRunner { + + private static final Logger log = LoggerFactory + .getLogger(UserCommandLineRunner.class); + + @Autowired + private UserRepository repository; + + @Override + public void run(String... args) { + // save a couple of customers + repository.save(new User("Ranga", "Admin")); + repository.save(new User("Ravi", "User")); + repository.save(new User("Satish", "Admin")); + repository.save(new User("Raghu", "User")); + + log.info("-------------------------------"); + log.info("Finding all users"); + log.info("-------------------------------"); + for (User user : repository.findAll()) { + log.info(user.toString()); + } + + } + +} + +``` +Fourth Snippet +``` +package com.in28minutes.springboot.jpa; + +import java.util.List; + +import org.springframework.data.repository.CrudRepository; + +public interface UserRepository extends CrudRepository { +} +``` + +## Exercises +- Look at other methods provided by the UserRepository + +## Files List +### /pom.xml +``` + + 4.0.0 + com.in28minutes + springboot-for-beginners-example + 0.0.1-SNAPSHOT + Your First Spring Boot Example + jar + + + org.springframework.boot + spring-boot-starter-parent + 1.4.0.RELEASE + + + + + + org.springframework.boot + spring-boot-starter-web + + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + + + + + com.h2database + h2 + + + + com.fasterxml.jackson.dataformat + jackson-dataformat-xml + + + + org.springframework.boot + spring-boot-starter-actuator + + + + org.springframework.data + spring-data-rest-hal-browser + + + + org.springframework.boot + spring-boot-devtools + true + + + + + + + 1.8 + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + +``` +### /src/main/java/com/in28minutes/springboot/Application.java +``` +package com.in28minutes.springboot; + +import java.util.HashMap; +import java.util.Map; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Component; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.in28minutes.springboot.configuration.BasicConfiguration; + +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + + ApplicationContext ctx = SpringApplication.run(Application.class, args); + } + + @RestController + class SomeBean { + + @Autowired + private SomeDependency someDependency; + + @Autowired + private BasicConfiguration configuration; + + @RequestMapping("/") + public String index() { + return someDependency.getSomething(); + } + + @RequestMapping("/dynamic-configuration") + public Map dynamicConfiguration() { + // Not the best practice to use a map to store differnt types! + Map map = new HashMap(); + map.put("message", configuration.getMessage()); + map.put("number", configuration.getNumber()); + map.put("key", configuration.isValue()); + return map; + } + + } + + @Component + class SomeDependency { + + @Value("${welcome.message}") + private String welcomeMessage; + + public String getSomething() { + return welcomeMessage; + } + + } + +} +``` +### /src/main/java/com/in28minutes/springboot/configuration/BasicConfiguration.java +``` +package com.in28minutes.springboot.configuration; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@Component +@ConfigurationProperties("basic") +public class BasicConfiguration { + private boolean value; + private String message; + private int number; + + public boolean isValue() { + return value; + } + + public void setValue(boolean value) { + this.value = value; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public int getNumber() { + return number; + } + + public void setNumber(int number) { + this.number = number; + } + +} +``` +### /src/main/java/com/in28minutes/springboot/controller/SurveyController.java +``` +package com.in28minutes.springboot.controller; + +import java.net.URI; +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +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.RequestBody; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.servlet.support.ServletUriComponentsBuilder; + +import com.in28minutes.springboot.model.Question; +import com.in28minutes.springboot.service.SurveyService; + +@RestController +class SurveyController { + @Autowired + private SurveyService surveyService; + + @GetMapping("/surveys/{surveyId}/questions") + public List retrieveQuestions(@PathVariable String surveyId) { + return surveyService.retrieveQuestions(surveyId); + } + + @GetMapping(path = "/surveys/{surveyId}/questions/{questionId}") + public Question retrieveQuestion(@PathVariable String surveyId, + @PathVariable String questionId) { + return surveyService.retrieveQuestion(surveyId, questionId); + } + + @PostMapping("/surveys/{surveyId}/questions") + ResponseEntity add(@PathVariable String surveyId, + @RequestBody Question question) { + + Question createdTodo = surveyService.addQuestion(surveyId, question); + + if (createdTodo == null) { + return ResponseEntity.noContent().build(); + } + + URI location = ServletUriComponentsBuilder.fromCurrentRequest() + .path("/{id}").buildAndExpand(createdTodo.getId()).toUri(); + + return ResponseEntity.created(location).build(); + + } + +} +``` +### /src/main/java/com/in28minutes/springboot/jpa/User.java +``` +package com.in28minutes.springboot.jpa; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; + +@Entity +public class User { + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private Long id; + + private String name;// Not perfect!! Should be a proper object! + private String role;// Not perfect!! An enum should be a better choice! + + protected User() { + } + + public User(String name, String role) { + super(); + this.name = name; + this.role = role; + } + + public Long getId() { + return id; + } + + public String getName() { + return name; + } + + public String getRole() { + return role; + } + + @Override + public String toString() { + return String.format("User [id=%s, name=%s, role=%s]", id, name, role); + } + +} +``` +### /src/main/java/com/in28minutes/springboot/jpa/UserCommandLineRunner.java +``` +package com.in28minutes.springboot.jpa; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.CommandLineRunner; +import org.springframework.stereotype.Component; + +@Component +public class UserCommandLineRunner implements CommandLineRunner { + + private static final Logger log = LoggerFactory + .getLogger(UserCommandLineRunner.class); + + @Autowired + private UserRepository repository; + + @Override + public void run(String... args) { + // save a couple of customers + repository.save(new User("Ranga", "Admin")); + repository.save(new User("Ravi", "User")); + repository.save(new User("Satish", "Admin")); + repository.save(new User("Raghu", "User")); + + log.info("-------------------------------"); + log.info("Finding all users"); + log.info("-------------------------------"); + for (User user : repository.findAll()) { + log.info(user.toString()); + } + + log.info("-------------------------------"); + log.info("Finding user with id 1"); + log.info("-------------------------------"); + User user = repository.findOne(1L); + log.info(user.toString()); + + log.info("-------------------------------"); + log.info("Finding all Admins"); + log.info("-------------------------------"); + for (User admin : repository.findByRole("Admin")) { + log.info(admin.toString()); + // Do something... + } + } + +} +``` +### /src/main/java/com/in28minutes/springboot/jpa/UserRepository.java +``` +package com.in28minutes.springboot.jpa; + +import java.util.List; + +import org.springframework.data.repository.CrudRepository; + +public interface UserRepository extends CrudRepository { + List findByRole(String description); +} +``` +### /src/main/java/com/in28minutes/springboot/model/Question.java +``` +package com.in28minutes.springboot.model; + +import java.util.List; + +public class Question { + private String id; + private String description; + private String correctAnswer; + private List options; + + // Needed by Caused by: com.fasterxml.jackson.databind.JsonMappingException: + // Can not construct instance of com.in28minutes.springboot.model.Question: + // no suitable constructor found, can not deserialize from Object value + // (missing default constructor or creator, or perhaps need to add/enable + // type information?) + public Question() { + + } + + public Question(String id, String description, String correctAnswer, + List options) { + super(); + this.id = id; + this.description = description; + this.correctAnswer = correctAnswer; + this.options = options; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getDescription() { + return description; + } + + public String getCorrectAnswer() { + return correctAnswer; + } + + public List getOptions() { + return options; + } + + @Override + public String toString() { + return String + .format("Question [id=%s, description=%s, correctAnswer=%s, options=%s]", + id, description, correctAnswer, options); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + (id == null ? 0 : id.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; + } + Question other = (Question) obj; + if (id == null) { + if (other.id != null) { + return false; + } + } else if (!id.equals(other.id)) { + return false; + } + return true; + } + +} +``` +### /src/main/java/com/in28minutes/springboot/model/Survey.java +``` +package com.in28minutes.springboot.model; + +import java.util.List; + +public class Survey { + private String id; + private String title; + private String description; + private List questions; + + public Survey(String id, String title, String description, + List questions) { + super(); + this.id = id; + this.title = title; + this.description = description; + this.questions = questions; + } + + public String getId() { + return id; + } + + public String getTitle() { + return title; + } + + public String getDescription() { + return description; + } + + public List getQuestions() { + return questions; + } + + @Override + public String toString() { + return String.format( + "Survey [id=%s, title=%s, description=%s, questions=%s]", id, + title, description, questions); + } + +} +``` +### /src/main/java/com/in28minutes/springboot/service/SurveyService.java +``` +package com.in28minutes.springboot.service; + +import java.math.BigInteger; +import java.security.SecureRandom; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.springframework.stereotype.Component; + +import com.in28minutes.springboot.model.Question; +import com.in28minutes.springboot.model.Survey; + +@Component +public class SurveyService { + private static List surveys = new ArrayList<>(); + static { + Question question1 = new Question("Question1", + "Largest Country in the World", "Russia", Arrays.asList( + "India", "Russia", "United States", "China")); + Question question2 = new Question("Question2", + "Most Populus Country in the World", "China", Arrays.asList( + "India", "Russia", "United States", "China")); + Question question3 = new Question("Question3", + "Highest GDP in the World", "United States", Arrays.asList( + "India", "Russia", "United States", "China")); + Question question4 = new Question("Question4", + "Second largest english speaking country", "India", + Arrays.asList("India", "Russia", "United States", "China")); + + List questions = new ArrayList<>(Arrays.asList(question1, + question2, question3, question4)); + + Survey survey = new Survey("Survey1", "My Favorite Survey", + "Description of the Survey", questions); + + surveys.add(survey); + } + + public List retrieveAllSurveys() { + return surveys; + } + + public Survey retrieveSurvey(String surveyId) { + for (Survey survey : surveys) { + if (survey.getId().equals(surveyId)) { + return survey; + } + } + return null; + } + + public List retrieveQuestions(String surveyId) { + Survey survey = retrieveSurvey(surveyId); + + if (survey == null) { + return null; + } + + return survey.getQuestions(); + } + + public Question retrieveQuestion(String surveyId, String questionId) { + Survey survey = retrieveSurvey(surveyId); + + if (survey == null) { + return null; + } + + for (Question question : survey.getQuestions()) { + if (question.getId().equals(questionId)) { + return question; + } + } + + return null; + } + + private SecureRandom random = new SecureRandom(); + + public Question addQuestion(String surveyId, Question question) { + Survey survey = retrieveSurvey(surveyId); + + if (survey == null) { + return null; + } + + String randomId = new BigInteger(130, random).toString(32); + question.setId(randomId); + + survey.getQuestions().add(question); + + return question; + } +} +``` +### /src/main/resources/application.properties +``` +logging.level.org.springframework: INFO +app.name: In28Minutes +app.description: ${app.name} is your first Spring Boot application Properties +welcome.message: Welcome to your first Spring Boot application +basic.value: true +basic.message: Dynamic Message +basic.number: 123 +``` +### /src/main/resources/application.yaml +``` +logging: + level: + org.springframework: DEBUG + +app: + name: In28Minutes + description: ${app.name} is your first Spring Boot application + +welcome: + message: Welcome to your first Spring Boot app! + +basic: + value: true + message: Dynamic Message YAML + number: 100 +``` diff --git a/Step19.md b/Step19.md new file mode 100644 index 0000000..7579c72 --- /dev/null +++ b/Step19.md @@ -0,0 +1,659 @@ +##What You Will Learn during this Step: +- Look at H2 Console : http://localhost:8080/h2-console + - Use db url jdbc:h2:mem:testdb +- Add findByRole method + +##Some Notes +- Useful Properties + - spring.datasource.driver-class-name=com.mysql.jdbc.Driver + - spring.datasource.url=jdbc:mysql://localhost:3306/test + - spring.datasource.username=root + - spring.datasource.password=admin + - spring.datasource.initialize=true + - spring.jpa.hibernate.ddl-auto=update + - spring.jpa.show-sql=true + +## Useful Snippets and References + +First Snippet +``` + + log.info("-------------------------------"); + log.info("Finding user with id 1"); + log.info("-------------------------------"); + User user = repository.findOne(1L); + log.info(user.toString()); + + log.info("-------------------------------"); + log.info("Finding all Admins"); + log.info("-------------------------------"); + for (User admin : repository.findByRole("Admin")) { + log.info(admin.toString()); + // Do something... + } + +``` +Second Snippet +``` +package com.in28minutes.springboot.jpa; + +import java.util.List; + +import org.springframework.data.repository.CrudRepository; + +public interface UserRepository extends CrudRepository { + List findByRole(String description); +} +``` + +## Files List +### /pom.xml +``` + + 4.0.0 + com.in28minutes + springboot-for-beginners-example + 0.0.1-SNAPSHOT + Your First Spring Boot Example + jar + + + org.springframework.boot + spring-boot-starter-parent + 1.4.0.RELEASE + + + + + + org.springframework.boot + spring-boot-starter-web + + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + + + + + com.h2database + h2 + + + + com.fasterxml.jackson.dataformat + jackson-dataformat-xml + + + + org.springframework.boot + spring-boot-starter-actuator + + + + org.springframework.data + spring-data-rest-hal-browser + + + + org.springframework.boot + spring-boot-devtools + true + + + + + + + 1.8 + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + +``` +### /src/main/java/com/in28minutes/springboot/Application.java +``` +package com.in28minutes.springboot; + +import java.util.HashMap; +import java.util.Map; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Component; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.in28minutes.springboot.configuration.BasicConfiguration; + +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + + ApplicationContext ctx = SpringApplication.run(Application.class, args); + } + + @RestController + class SomeBean { + + @Autowired + private SomeDependency someDependency; + + @Autowired + private BasicConfiguration configuration; + + @RequestMapping("/") + public String index() { + return someDependency.getSomething(); + } + + @RequestMapping("/dynamic-configuration") + public Map dynamicConfiguration() { + // Not the best practice to use a map to store differnt types! + Map map = new HashMap(); + map.put("message", configuration.getMessage()); + map.put("number", configuration.getNumber()); + map.put("key", configuration.isValue()); + return map; + } + + } + + @Component + class SomeDependency { + + @Value("${welcome.message}") + private String welcomeMessage; + + public String getSomething() { + return welcomeMessage; + } + + } + +} +``` +### /src/main/java/com/in28minutes/springboot/configuration/BasicConfiguration.java +``` +package com.in28minutes.springboot.configuration; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@Component +@ConfigurationProperties("basic") +public class BasicConfiguration { + private boolean value; + private String message; + private int number; + + public boolean isValue() { + return value; + } + + public void setValue(boolean value) { + this.value = value; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public int getNumber() { + return number; + } + + public void setNumber(int number) { + this.number = number; + } + +} +``` +### /src/main/java/com/in28minutes/springboot/controller/SurveyController.java +``` +package com.in28minutes.springboot.controller; + +import java.net.URI; +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +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.RequestBody; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.servlet.support.ServletUriComponentsBuilder; + +import com.in28minutes.springboot.model.Question; +import com.in28minutes.springboot.service.SurveyService; + +@RestController +class SurveyController { + @Autowired + private SurveyService surveyService; + + @GetMapping("/surveys/{surveyId}/questions") + public List retrieveQuestions(@PathVariable String surveyId) { + return surveyService.retrieveQuestions(surveyId); + } + + @GetMapping(path = "/surveys/{surveyId}/questions/{questionId}") + public Question retrieveQuestion(@PathVariable String surveyId, + @PathVariable String questionId) { + return surveyService.retrieveQuestion(surveyId, questionId); + } + + @PostMapping("/surveys/{surveyId}/questions") + ResponseEntity add(@PathVariable String surveyId, + @RequestBody Question question) { + + Question createdTodo = surveyService.addQuestion(surveyId, question); + + if (createdTodo == null) { + return ResponseEntity.noContent().build(); + } + + URI location = ServletUriComponentsBuilder.fromCurrentRequest() + .path("/{id}").buildAndExpand(createdTodo.getId()).toUri(); + + return ResponseEntity.created(location).build(); + + } + +} +``` +### /src/main/java/com/in28minutes/springboot/jpa/User.java +``` +package com.in28minutes.springboot.jpa; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; + +@Entity +public class User { + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private Long id; + + private String name;// Not perfect!! Should be a proper object! + private String role;// Not perfect!! An enum should be a better choice! + + protected User() { + } + + public User(String name, String role) { + super(); + this.name = name; + this.role = role; + } + + public Long getId() { + return id; + } + + public String getName() { + return name; + } + + public String getRole() { + return role; + } + + @Override + public String toString() { + return String.format("User [id=%s, name=%s, role=%s]", id, name, role); + } + +} +``` +### /src/main/java/com/in28minutes/springboot/jpa/UserCommandLineRunner.java +``` +package com.in28minutes.springboot.jpa; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.CommandLineRunner; +import org.springframework.stereotype.Component; + +@Component +public class UserCommandLineRunner implements CommandLineRunner { + + private static final Logger log = LoggerFactory + .getLogger(UserCommandLineRunner.class); + + @Autowired + private UserRepository repository; + + @Override + public void run(String... args) { + // save a couple of customers + repository.save(new User("Ranga", "Admin")); + repository.save(new User("Ravi", "User")); + repository.save(new User("Satish", "Admin")); + repository.save(new User("Raghu", "User")); + + log.info("-------------------------------"); + log.info("Finding all users"); + log.info("-------------------------------"); + for (User user : repository.findAll()) { + log.info(user.toString()); + } + + log.info("-------------------------------"); + log.info("Finding user with id 1"); + log.info("-------------------------------"); + User user = repository.findOne(1L); + log.info(user.toString()); + + log.info("-------------------------------"); + log.info("Finding all Admins"); + log.info("-------------------------------"); + for (User admin : repository.findByRole("Admin")) { + log.info(admin.toString()); + // Do something... + } + } + +} +``` +### /src/main/java/com/in28minutes/springboot/jpa/UserRepository.java +``` +package com.in28minutes.springboot.jpa; + +import java.util.List; + +import org.springframework.data.repository.CrudRepository; + +public interface UserRepository extends CrudRepository { + List findByRole(String description); +} +``` +### /src/main/java/com/in28minutes/springboot/model/Question.java +``` +package com.in28minutes.springboot.model; + +import java.util.List; + +public class Question { + private String id; + private String description; + private String correctAnswer; + private List options; + + // Needed by Caused by: com.fasterxml.jackson.databind.JsonMappingException: + // Can not construct instance of com.in28minutes.springboot.model.Question: + // no suitable constructor found, can not deserialize from Object value + // (missing default constructor or creator, or perhaps need to add/enable + // type information?) + public Question() { + + } + + public Question(String id, String description, String correctAnswer, + List options) { + super(); + this.id = id; + this.description = description; + this.correctAnswer = correctAnswer; + this.options = options; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getDescription() { + return description; + } + + public String getCorrectAnswer() { + return correctAnswer; + } + + public List getOptions() { + return options; + } + + @Override + public String toString() { + return String + .format("Question [id=%s, description=%s, correctAnswer=%s, options=%s]", + id, description, correctAnswer, options); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + (id == null ? 0 : id.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; + } + Question other = (Question) obj; + if (id == null) { + if (other.id != null) { + return false; + } + } else if (!id.equals(other.id)) { + return false; + } + return true; + } + +} +``` +### /src/main/java/com/in28minutes/springboot/model/Survey.java +``` +package com.in28minutes.springboot.model; + +import java.util.List; + +public class Survey { + private String id; + private String title; + private String description; + private List questions; + + public Survey(String id, String title, String description, + List questions) { + super(); + this.id = id; + this.title = title; + this.description = description; + this.questions = questions; + } + + public String getId() { + return id; + } + + public String getTitle() { + return title; + } + + public String getDescription() { + return description; + } + + public List getQuestions() { + return questions; + } + + @Override + public String toString() { + return String.format( + "Survey [id=%s, title=%s, description=%s, questions=%s]", id, + title, description, questions); + } + +} +``` +### /src/main/java/com/in28minutes/springboot/service/SurveyService.java +``` +package com.in28minutes.springboot.service; + +import java.math.BigInteger; +import java.security.SecureRandom; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.springframework.stereotype.Component; + +import com.in28minutes.springboot.model.Question; +import com.in28minutes.springboot.model.Survey; + +@Component +public class SurveyService { + private static List surveys = new ArrayList<>(); + static { + Question question1 = new Question("Question1", + "Largest Country in the World", "Russia", Arrays.asList( + "India", "Russia", "United States", "China")); + Question question2 = new Question("Question2", + "Most Populus Country in the World", "China", Arrays.asList( + "India", "Russia", "United States", "China")); + Question question3 = new Question("Question3", + "Highest GDP in the World", "United States", Arrays.asList( + "India", "Russia", "United States", "China")); + Question question4 = new Question("Question4", + "Second largest english speaking country", "India", + Arrays.asList("India", "Russia", "United States", "China")); + + List questions = new ArrayList<>(Arrays.asList(question1, + question2, question3, question4)); + + Survey survey = new Survey("Survey1", "My Favorite Survey", + "Description of the Survey", questions); + + surveys.add(survey); + } + + public List retrieveAllSurveys() { + return surveys; + } + + public Survey retrieveSurvey(String surveyId) { + for (Survey survey : surveys) { + if (survey.getId().equals(surveyId)) { + return survey; + } + } + return null; + } + + public List retrieveQuestions(String surveyId) { + Survey survey = retrieveSurvey(surveyId); + + if (survey == null) { + return null; + } + + return survey.getQuestions(); + } + + public Question retrieveQuestion(String surveyId, String questionId) { + Survey survey = retrieveSurvey(surveyId); + + if (survey == null) { + return null; + } + + for (Question question : survey.getQuestions()) { + if (question.getId().equals(questionId)) { + return question; + } + } + + return null; + } + + private SecureRandom random = new SecureRandom(); + + public Question addQuestion(String surveyId, Question question) { + Survey survey = retrieveSurvey(surveyId); + + if (survey == null) { + return null; + } + + String randomId = new BigInteger(130, random).toString(32); + question.setId(randomId); + + survey.getQuestions().add(question); + + return question; + } +} +``` +### /src/main/resources/application.properties +``` +logging.level.org.springframework: INFO +app.name: In28Minutes +app.description: ${app.name} is your first Spring Boot application Properties +welcome.message: Welcome to your first Spring Boot application +basic.value: true +basic.message: Dynamic Message +basic.number: 123 +``` +### /src/main/resources/application.yaml +``` +logging: + level: + org.springframework: DEBUG + +app: + name: In28Minutes + description: ${app.name} is your first Spring Boot application + +welcome: + message: Welcome to your first Spring Boot app! + +basic: + value: true + message: Dynamic Message YAML + number: 100 +``` diff --git a/pom.xml b/pom.xml index 1a63757..3ff3601 100644 --- a/pom.xml +++ b/pom.xml @@ -18,17 +18,22 @@ org.springframework.boot spring-boot-starter-web - - - org.springframework.boot - spring-boot-starter-tomcat - - - + + org.springframework.boot - spring-boot-starter-jetty + spring-boot-starter-data-jpa + + + + + + + com.h2database + h2 diff --git a/src/main/java/com/in28minutes/springboot/jpa/User.java b/src/main/java/com/in28minutes/springboot/jpa/User.java new file mode 100644 index 0000000..4bcfc74 --- /dev/null +++ b/src/main/java/com/in28minutes/springboot/jpa/User.java @@ -0,0 +1,44 @@ +package com.in28minutes.springboot.jpa; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; + +@Entity +public class User { + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private Long id; + + private String name;// Not perfect!! Should be a proper object! + private String role;// Not perfect!! An enum should be a better choice! + + protected User() { + } + + public User(String name, String role) { + super(); + this.name = name; + this.role = role; + } + + public Long getId() { + return id; + } + + public String getName() { + return name; + } + + public String getRole() { + return role; + } + + @Override + public String toString() { + return String.format("User [id=%s, name=%s, role=%s]", id, name, role); + } + +} diff --git a/src/main/java/com/in28minutes/springboot/jpa/UserCommandLineRunner.java b/src/main/java/com/in28minutes/springboot/jpa/UserCommandLineRunner.java new file mode 100644 index 0000000..18805f0 --- /dev/null +++ b/src/main/java/com/in28minutes/springboot/jpa/UserCommandLineRunner.java @@ -0,0 +1,48 @@ +package com.in28minutes.springboot.jpa; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.CommandLineRunner; +import org.springframework.stereotype.Component; + +@Component +public class UserCommandLineRunner implements CommandLineRunner { + + private static final Logger log = LoggerFactory + .getLogger(UserCommandLineRunner.class); + + @Autowired + private UserRepository repository; + + @Override + public void run(String... args) { + // save a couple of customers + repository.save(new User("Ranga", "Admin")); + repository.save(new User("Ravi", "User")); + repository.save(new User("Satish", "Admin")); + repository.save(new User("Raghu", "User")); + + log.info("-------------------------------"); + log.info("Finding all users"); + log.info("-------------------------------"); + for (User user : repository.findAll()) { + log.info(user.toString()); + } + + log.info("-------------------------------"); + log.info("Finding user with id 1"); + log.info("-------------------------------"); + User user = repository.findOne(1L); + log.info(user.toString()); + + log.info("-------------------------------"); + log.info("Finding all Admins"); + log.info("-------------------------------"); + for (User admin : repository.findByRole("Admin")) { + log.info(admin.toString()); + // Do something... + } + } + +} diff --git a/src/main/java/com/in28minutes/springboot/jpa/UserRepository.java b/src/main/java/com/in28minutes/springboot/jpa/UserRepository.java new file mode 100644 index 0000000..b9ddfbb --- /dev/null +++ b/src/main/java/com/in28minutes/springboot/jpa/UserRepository.java @@ -0,0 +1,9 @@ +package com.in28minutes.springboot.jpa; + +import java.util.List; + +import org.springframework.data.repository.CrudRepository; + +public interface UserRepository extends CrudRepository { + List findByRole(String description); +} \ No newline at end of file diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 86987de..e2dfd08 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,4 +1,4 @@ -logging.level.org.springframework: DEBUG +logging.level.org.springframework: INFO app.name: In28Minutes app.description: ${app.name} is your first Spring Boot application Properties welcome.message: Welcome to your first Spring Boot application