diff --git a/.gitignore b/.gitignore
index 200bfbe2..a9e7e666 100644
--- a/.gitignore
+++ b/.gitignore
@@ -37,6 +37,7 @@ Thumbs.db
.project
.classpath
.idea
+.mvn
*.iml
atlassian-ide-plugin.xml
target
diff --git a/Jenkinsfile b/Jenkinsfile
new file mode 100644
index 00000000..77b54539
--- /dev/null
+++ b/Jenkinsfile
@@ -0,0 +1,12 @@
+node{
+
+ stage("Checkout"){
+ checkout scm
+ }
+
+ stage("Build"){
+ withEnv(["PATH+MAVEN=${tool 'M3'}"]){
+ sh 'mvn clean install -DskipTests'
+ }
+ }
+ }
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 30247811..10d045f8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -32,6 +32,34 @@
org.springframework.boot
spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-devtools
+
+
+
+ org.springframework.boot
+ spring-boot-starter-data-jpa
+
+
+
+ com.h2database
+ h2
+ runtime
+
+
+
+
+ org.webjars
+ bootstrap
+ 3.3.5
+
+
+ org.webjars
+ jquery
+ 2.1.4
+
org.springframework.boot
diff --git a/src/main/java/guru/springframework/SpringmvcApplication.java b/src/main/java/guru/springframework/SpringmvcApplication.java
index b3a27dd9..d73706cb 100644
--- a/src/main/java/guru/springframework/SpringmvcApplication.java
+++ b/src/main/java/guru/springframework/SpringmvcApplication.java
@@ -2,11 +2,18 @@
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.ApplicationContext;
@SpringBootApplication
public class SpringmvcApplication {
public static void main(String[] args) {
- SpringApplication.run(SpringmvcApplication.class, args);
+ ApplicationContext ctx = SpringApplication.run(SpringmvcApplication.class, args);
+
+// for (String name : ctx.getBeanDefinitionNames()){
+// System.out.println(name);
+// }
+// System.out.println("******* Bean Count *******");
+// System.out.println(ctx.getBeanDefinitionCount());
}
}
diff --git a/src/main/java/guru/springframework/controllers/CustomerController.java b/src/main/java/guru/springframework/controllers/CustomerController.java
new file mode 100644
index 00000000..5b835c0c
--- /dev/null
+++ b/src/main/java/guru/springframework/controllers/CustomerController.java
@@ -0,0 +1,61 @@
+package guru.springframework.controllers;
+
+import guru.springframework.domain.Customer;
+import guru.springframework.services.CustomerService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+
+/**
+ * Created by jt on 11/15/15.
+ */
+@RequestMapping("/customer")
+@Controller
+public class CustomerController {
+
+ private CustomerService customerService;
+
+ @Autowired
+ public void setCustomerService(CustomerService customerService) {
+ this.customerService = customerService;
+ }
+
+ @RequestMapping({"/list", "/"})
+ public String listCustomers(Model model){
+ model.addAttribute("customers", customerService.listAll());
+ return "customer/list";
+ }
+
+ @RequestMapping("/show/{id}")
+ public String showCustomer(@PathVariable Integer id, Model model){
+ model.addAttribute("customer", customerService.getById(id));
+ return "customer/show";
+ }
+
+ @RequestMapping("/edit/{id}")
+ public String edit(@PathVariable Integer id, Model model){
+ model.addAttribute("customer", customerService.getById(id));
+ return "customer/customerform";
+ }
+
+ @RequestMapping("/new")
+ public String newCustomer(Model model){
+ model.addAttribute("customer", new Customer());
+ return "customer/customerform";
+ }
+
+ @RequestMapping(method = RequestMethod.POST)
+ public String saveOrUpdate(Customer customer){
+ Customer newCustomer = customerService.saveOrUpdate(customer);
+ return "redirect:customer/show/" + newCustomer.getId();
+ }
+
+ @RequestMapping("/delete/{id}")
+ public String delete(@PathVariable Integer id){
+ customerService.delete(id);
+ return "redirect:/customer/list";
+ }
+}
diff --git a/src/main/java/guru/springframework/controllers/IndexController.java b/src/main/java/guru/springframework/controllers/IndexController.java
new file mode 100644
index 00000000..4bbb072b
--- /dev/null
+++ b/src/main/java/guru/springframework/controllers/IndexController.java
@@ -0,0 +1,16 @@
+package guru.springframework.controllers;
+
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+/**
+ * Created by jt on 11/6/15.
+ */
+@Controller
+public class IndexController {
+
+ @RequestMapping({"/", ""})
+ public String index(){
+ return "index";
+ }
+}
diff --git a/src/main/java/guru/springframework/controllers/ProductController.java b/src/main/java/guru/springframework/controllers/ProductController.java
new file mode 100644
index 00000000..4c60ff50
--- /dev/null
+++ b/src/main/java/guru/springframework/controllers/ProductController.java
@@ -0,0 +1,60 @@
+package guru.springframework.controllers;
+
+import guru.springframework.domain.Product;
+import guru.springframework.services.ProductService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+
+/**
+ * Created by jt on 11/6/15.
+ */
+@Controller
+public class ProductController {
+
+ private ProductService productService;
+
+ @Autowired
+ public void setProductService(ProductService productService) {
+ this.productService = productService;
+ }
+
+ @RequestMapping("/product/list")
+ public String listProducts(Model model){
+ model.addAttribute("products", productService.listAll());
+ return "product/list";
+ }
+
+ @RequestMapping("/product/show/{id}")
+ public String getProduct(@PathVariable Integer id, Model model){
+ model.addAttribute("product", productService.getById(id));
+ return "product/show";
+ }
+
+ @RequestMapping("product/edit/{id}")
+ public String edit(@PathVariable Integer id, Model model){
+ model.addAttribute("product", productService.getById(id));
+ return "product/productform";
+ }
+
+ @RequestMapping("/product/new")
+ public String newProduct(Model model){
+ model.addAttribute("product", new Product());
+ return "product/productform";
+ }
+
+ @RequestMapping(value = "/product", method = RequestMethod.POST)
+ public String saveOrUpdateProduct(Product product){
+ Product savedProduct = productService.saveOrUpdate(product);
+ return "redirect:/product/show/" + savedProduct.getId();
+ }
+
+ @RequestMapping("/product/delete/{id}")
+ public String delete(@PathVariable Integer id){
+ productService.delete(id);
+ return "redirect:/product/list";
+ }
+}
diff --git a/src/main/java/guru/springframework/domain/Customer.java b/src/main/java/guru/springframework/domain/Customer.java
new file mode 100644
index 00000000..450796bd
--- /dev/null
+++ b/src/main/java/guru/springframework/domain/Customer.java
@@ -0,0 +1,117 @@
+package guru.springframework.domain;
+
+import javax.persistence.*;
+
+/**
+ * Created by jt on 11/14/15.
+ */
+@Entity
+public class Customer implements DomainObject {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.AUTO)
+ private Integer id;
+
+ @Version
+ private Integer version;
+
+ private String firstName;
+ private String lastName;
+ private String email;
+ private String phoneNumber;
+ private String addressLine1;
+ private String addressLine2;
+ private String city;
+ private String state;
+ private String zipCode;
+
+ @Override
+ public Integer getId() {
+ return id;
+ }
+
+ @Override
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public Integer getVersion() {
+ return version;
+ }
+
+ public void setVersion(Integer version) {
+ this.version = version;
+ }
+
+ 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 String getEmail() {
+ return email;
+ }
+
+ public void setEmail(String email) {
+ this.email = email;
+ }
+
+ public String getPhoneNumber() {
+ return phoneNumber;
+ }
+
+ public void setPhoneNumber(String phoneNumber) {
+ this.phoneNumber = phoneNumber;
+ }
+
+ public String getAddressLine1() {
+ return addressLine1;
+ }
+
+ public void setAddressLine1(String addressLine1) {
+ this.addressLine1 = addressLine1;
+ }
+
+ public String getAddressLine2() {
+ return addressLine2;
+ }
+
+ public void setAddressLine2(String addressLine2) {
+ this.addressLine2 = addressLine2;
+ }
+
+ public String getCity() {
+ return city;
+ }
+
+ public void setCity(String city) {
+ this.city = city;
+ }
+
+ public String getState() {
+ return state;
+ }
+
+ public void setState(String state) {
+ this.state = state;
+ }
+
+ public String getZipCode() {
+ return zipCode;
+ }
+
+ public void setZipCode(String zipCode) {
+ this.zipCode = zipCode;
+ }
+}
diff --git a/src/main/java/guru/springframework/domain/DomainObject.java b/src/main/java/guru/springframework/domain/DomainObject.java
new file mode 100644
index 00000000..5744c4e7
--- /dev/null
+++ b/src/main/java/guru/springframework/domain/DomainObject.java
@@ -0,0 +1,11 @@
+package guru.springframework.domain;
+
+/**
+ * Created by jt on 11/14/15.
+ */
+public interface DomainObject {
+
+ Integer getId();
+
+ void setId(Integer id);
+}
diff --git a/src/main/java/guru/springframework/domain/Product.java b/src/main/java/guru/springframework/domain/Product.java
new file mode 100644
index 00000000..ffadb179
--- /dev/null
+++ b/src/main/java/guru/springframework/domain/Product.java
@@ -0,0 +1,62 @@
+package guru.springframework.domain;
+
+import javax.persistence.*;
+import java.math.BigDecimal;
+
+/**
+ * Created by jt on 11/6/15.
+ */
+@Entity
+public class Product implements DomainObject{
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.AUTO)
+ private Integer id;
+
+ @Version
+ private Integer version;
+
+ private String description;
+ private BigDecimal price;
+ private String imageUrl;
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public Integer getVersion() {
+ return version;
+ }
+
+ public void setVersion(Integer version) {
+ this.version = version;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public BigDecimal getPrice() {
+ return price;
+ }
+
+ public void setPrice(BigDecimal price) {
+ this.price = price;
+ }
+
+ public String getImageUrl() {
+ return imageUrl;
+ }
+
+ public void setImageUrl(String imageUrl) {
+ this.imageUrl = imageUrl;
+ }
+}
diff --git a/src/main/java/guru/springframework/services/AbstractMapService.java b/src/main/java/guru/springframework/services/AbstractMapService.java
new file mode 100644
index 00000000..1e21261e
--- /dev/null
+++ b/src/main/java/guru/springframework/services/AbstractMapService.java
@@ -0,0 +1,50 @@
+package guru.springframework.services;
+
+import guru.springframework.domain.DomainObject;
+
+import java.util.*;
+
+/**
+ * Created by jt on 11/14/15.
+ */
+public abstract class AbstractMapService {
+ protected Map domainMap;
+
+ public AbstractMapService() {
+ domainMap = new HashMap<>();
+ loadDomainObjects();
+ }
+
+ public List listAll() {
+ return new ArrayList<>(domainMap.values());
+ }
+
+ public DomainObject getById(Integer id) {
+ return domainMap.get(id);
+ }
+
+ public DomainObject saveOrUpdate(DomainObject domainObject) {
+ if (domainObject != null){
+
+ if (domainObject.getId() == null){
+ domainObject.setId(getNextKey());
+ }
+ domainMap.put(domainObject.getId(), domainObject);
+
+ return domainObject;
+ } else {
+ throw new RuntimeException("Object Can't be null");
+ }
+ }
+
+ public void delete(Integer id) {
+ domainMap.remove(id);
+ }
+
+ private Integer getNextKey(){
+ return Collections.max(domainMap.keySet()) + 1;
+ }
+
+ protected abstract void loadDomainObjects();
+
+}
diff --git a/src/main/java/guru/springframework/services/CRUDService.java b/src/main/java/guru/springframework/services/CRUDService.java
new file mode 100644
index 00000000..7355d122
--- /dev/null
+++ b/src/main/java/guru/springframework/services/CRUDService.java
@@ -0,0 +1,16 @@
+package guru.springframework.services;
+
+import java.util.List;
+
+/**
+ * Created by jt on 11/14/15.
+ */
+public interface CRUDService {
+ List> listAll();
+
+ T getById(Integer id);
+
+ T saveOrUpdate(T domainObject);
+
+ void delete(Integer id);
+}
diff --git a/src/main/java/guru/springframework/services/CustomerService.java b/src/main/java/guru/springframework/services/CustomerService.java
new file mode 100644
index 00000000..441b15bd
--- /dev/null
+++ b/src/main/java/guru/springframework/services/CustomerService.java
@@ -0,0 +1,10 @@
+package guru.springframework.services;
+
+import guru.springframework.domain.Customer;
+
+/**
+ * Created by jt on 11/14/15.
+ */
+public interface CustomerService extends CRUDService{
+
+}
diff --git a/src/main/java/guru/springframework/services/CustomerServiceImpl.java b/src/main/java/guru/springframework/services/CustomerServiceImpl.java
new file mode 100644
index 00000000..c86adce5
--- /dev/null
+++ b/src/main/java/guru/springframework/services/CustomerServiceImpl.java
@@ -0,0 +1,77 @@
+package guru.springframework.services;
+
+import guru.springframework.domain.Customer;
+import guru.springframework.domain.DomainObject;
+import org.springframework.stereotype.Service;
+
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * Created by jt on 11/14/15.
+ */
+@Service
+public class CustomerServiceImpl extends AbstractMapService implements CustomerService {
+
+ @Override
+ public List listAll() {
+ return super.listAll();
+ }
+
+ @Override
+ public Customer getById(Integer id) {
+ return (Customer) super.getById(id);
+ }
+
+ @Override
+ public Customer saveOrUpdate(Customer domainObject) {
+ return (Customer) super.saveOrUpdate(domainObject);
+ }
+
+ @Override
+ public void delete(Integer id) {
+ super.delete(id);
+ }
+
+ @Override
+ protected void loadDomainObjects() {
+ domainMap = new HashMap<>();
+
+ Customer customer1 = new Customer();
+ customer1.setId(1);
+ customer1.setFirstName("Micheal");
+ customer1.setLastName("Weston");
+ customer1.setAddressLine1("1 Main St");
+ customer1.setCity("Miami");
+ customer1.setState("Florida");
+ customer1.setZipCode("33101");
+ customer1.setEmail("micheal@burnnotice.com");
+ customer1.setPhoneNumber("305.333.0101");
+
+ Customer customer2 = new Customer();
+ customer2.setId(2);
+ customer2.setFirstName("Fiona");
+ customer2.setLastName("Glenanne");
+ customer2.setAddressLine1("1 Key Biscane Ave");
+ customer2.setCity("Miami");
+ customer2.setState("Florida");
+ customer2.setZipCode("33101");
+ customer2.setEmail("fiona@burnnotice.com");
+ customer2.setPhoneNumber("305.323.0233");
+
+ Customer customer3 = new Customer();
+ customer3.setId(3);
+ customer3.setFirstName("Sam");
+ customer3.setLastName("Axe");
+ customer3.setAddressLine1("1 Little Cuba Road");
+ customer3.setCity("Miami");
+ customer3.setState("Florida");
+ customer3.setZipCode("33101");
+ customer3.setEmail("sam@burnnotice.com");
+ customer3.setPhoneNumber("305.426.9832");
+
+ domainMap.put(1, customer1);
+ domainMap.put(2, customer2);
+ domainMap.put(3, customer3);
+ }
+}
diff --git a/src/main/java/guru/springframework/services/ProductService.java b/src/main/java/guru/springframework/services/ProductService.java
new file mode 100644
index 00000000..62a35310
--- /dev/null
+++ b/src/main/java/guru/springframework/services/ProductService.java
@@ -0,0 +1,10 @@
+package guru.springframework.services;
+
+import guru.springframework.domain.Product;
+
+/**
+ * Created by jt on 11/6/15.
+ */
+public interface ProductService extends CRUDService {
+
+}
diff --git a/src/main/java/guru/springframework/services/ProductServiceImpl.java b/src/main/java/guru/springframework/services/ProductServiceImpl.java
new file mode 100644
index 00000000..1382aad2
--- /dev/null
+++ b/src/main/java/guru/springframework/services/ProductServiceImpl.java
@@ -0,0 +1,80 @@
+package guru.springframework.services;
+
+import guru.springframework.domain.DomainObject;
+import guru.springframework.domain.Product;
+import org.springframework.stereotype.Service;
+
+import java.math.BigDecimal;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * Created by jt on 11/6/15.
+ */
+@Service
+public class ProductServiceImpl extends AbstractMapService implements ProductService {
+
+ @Override
+ public List listAll() {
+ return super.listAll();
+ }
+
+ @Override
+ public Product getById(Integer id) {
+ return (Product) super.getById(id);
+ }
+
+ @Override
+ public Product saveOrUpdate(Product domainObject) {
+ return (Product) super.saveOrUpdate(domainObject);
+ }
+
+ @Override
+ public void delete(Integer id) {
+ super.delete(id);
+ }
+
+ protected void loadDomainObjects(){
+ domainMap = new HashMap<>();
+
+ Product product1 = new Product();
+ product1.setId(1);
+ product1.setDescription("Product 1");
+ product1.setPrice(new BigDecimal("12.99"));
+ product1.setImageUrl("http://example.com/product1");
+
+ domainMap.put(1, product1);
+
+ Product product2 = new Product();
+ product2.setId(2);
+ product2.setDescription("Product 2");
+ product2.setPrice(new BigDecimal("14.99"));
+ product2.setImageUrl("http://example.com/product2");
+
+ domainMap.put(2, product2);
+
+ Product product3 = new Product();
+ product3.setId(3);
+ product3.setDescription("Product 3");
+ product3.setPrice(new BigDecimal("34.99"));
+ product3.setImageUrl("http://example.com/product3");
+
+ domainMap.put(3, product3);
+
+ Product product4 = new Product();
+ product4.setId(4);
+ product4.setDescription("Product 4");
+ product4.setPrice(new BigDecimal("44.99"));
+ product4.setImageUrl("http://example.com/product4");
+
+ domainMap.put(4, product4);
+
+ Product product5 = new Product();
+ product5.setId(5);
+ product5.setDescription("Product 2");
+ product5.setPrice(new BigDecimal("25.99"));
+ product5.setImageUrl("http://example.com/product5");
+
+ domainMap.put(5, product5);
+ }
+}
diff --git a/src/main/resources/static/css/spring-core.css b/src/main/resources/static/css/spring-core.css
new file mode 100644
index 00000000..e69de29b
diff --git a/src/main/resources/templates/customer/customerform.html b/src/main/resources/templates/customer/customerform.html
new file mode 100644
index 00000000..c3b6fe1a
--- /dev/null
+++ b/src/main/resources/templates/customer/customerform.html
@@ -0,0 +1,86 @@
+
+
+
+ Spring Core Online Tutorial - Customer Form
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/templates/customer/list.html b/src/main/resources/templates/customer/list.html
new file mode 100644
index 00000000..4904641b
--- /dev/null
+++ b/src/main/resources/templates/customer/list.html
@@ -0,0 +1,50 @@
+
+
+
+ Spring Core Online Tutorial - List Customers
+
+
+
+
+
+
+
+
+
+
+
+
Customer List
+
+
+ | Id |
+ First Name |
+ Last Name |
+ Email |
+ Show |
+ Edit |
+ Delete |
+
+
+ |
+ |
+ |
+ |
+ View |
+ Edit |
+ Delete |
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/templates/customer/show.html b/src/main/resources/templates/customer/show.html
new file mode 100644
index 00000000..5dadfa44
--- /dev/null
+++ b/src/main/resources/templates/customer/show.html
@@ -0,0 +1,94 @@
+
+
+
+ Spring Core Online Tutorial - Show Customer
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/templates/index.html b/src/main/resources/templates/index.html
new file mode 100644
index 00000000..9622d970
--- /dev/null
+++ b/src/main/resources/templates/index.html
@@ -0,0 +1,32 @@
+
+
+
+
+ Spring Core Online Tutorial
+
+
+
+
+
+
+
+
+
+
+
Hello World
+
+
This is my Thymeleaf index page.
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/templates/product/list.html b/src/main/resources/templates/product/list.html
new file mode 100644
index 00000000..b7ca555c
--- /dev/null
+++ b/src/main/resources/templates/product/list.html
@@ -0,0 +1,50 @@
+
+
+
+ Spring Core Online Tutorial - List Products
+
+
+
+
+
+
+
+
+
+
+
+
Product List
+
+
+ | Id |
+ Description |
+ Price |
+ Image URL |
+ List |
+ Edit |
+ Delete |
+
+
+ |
+ |
+ |
+ |
+ View |
+ Edit |
+ Delete |
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/templates/product/productform.html b/src/main/resources/templates/product/productform.html
new file mode 100644
index 00000000..cd9d9b6e
--- /dev/null
+++ b/src/main/resources/templates/product/productform.html
@@ -0,0 +1,50 @@
+
+
+
+ Spring Core Online Tutorial - Product Form
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/templates/product/show.html b/src/main/resources/templates/product/show.html
new file mode 100644
index 00000000..069ea3c9
--- /dev/null
+++ b/src/main/resources/templates/product/show.html
@@ -0,0 +1,58 @@
+
+
+
+ Spring Core Online Tutorial - Show Product
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/java/guru/springframework/controllers/CustomerControllerTest.java b/src/test/java/guru/springframework/controllers/CustomerControllerTest.java
new file mode 100644
index 00000000..db23e3c3
--- /dev/null
+++ b/src/test/java/guru/springframework/controllers/CustomerControllerTest.java
@@ -0,0 +1,159 @@
+package guru.springframework.controllers;
+
+import guru.springframework.domain.Customer;
+import guru.springframework.services.CustomerService;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.*;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.hamcrest.Matchers.*;
+import static org.hamcrest.beans.HasPropertyWithValue.hasProperty;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.*;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
+
+/**
+ * Created by jt on 11/17/15.
+ */
+public class CustomerControllerTest {
+
+ @Mock
+ private CustomerService customerService;
+
+ @InjectMocks
+ private CustomerController customerController;
+
+ private MockMvc mockMvc;
+
+ @Before
+ public void setup(){
+ MockitoAnnotations.initMocks(this);
+
+ mockMvc = MockMvcBuilders.standaloneSetup(customerController).build();
+ }
+
+ @Test
+ public void testList() throws Exception{
+ List customers = new ArrayList<>();
+ customers.add(new Customer());
+ customers.add(new Customer());
+
+ when(customerService.listAll()).thenReturn((List) customers);
+
+ mockMvc.perform(get("/customer/list"))
+ .andExpect(status().isOk())
+ .andExpect(view().name("customer/list"))
+ .andExpect(model().attribute("customers", hasSize(2)));
+ }
+
+ @Test
+ public void testShow() throws Exception {
+ Integer id = 1;
+
+ when(customerService.getById(id)).thenReturn(new Customer());
+
+ mockMvc.perform(get("/customer/show/1"))
+ .andExpect(status().isOk())
+ .andExpect(view().name("customer/show"))
+ .andExpect(model().attribute("customer", instanceOf(Customer.class)));
+ }
+
+ @Test
+ public void testEdit() throws Exception {
+ Integer id = 1;
+
+ when(customerService.getById(id)).thenReturn(new Customer());
+
+ mockMvc.perform(get("/customer/edit/1"))
+ .andExpect(status().isOk())
+ .andExpect(view().name("customer/customerform"))
+ .andExpect(model().attribute("customer", instanceOf(Customer.class)));
+ }
+
+ @Test
+ public void testNewCustomer() throws Exception {
+ verifyZeroInteractions(customerService);
+
+ mockMvc.perform(get("/customer/new"))
+ .andExpect(status().isOk())
+ .andExpect(view().name("customer/customerform"))
+ .andExpect(model().attribute("customer", instanceOf(Customer.class)));
+ }
+
+ @Test
+ public void testSaveOrUpdate() throws Exception {
+ Integer id = 1;
+ Customer returnCustomer = new Customer();
+ String firstName = "Micheal";
+ String lastName = "Weston";
+ String addressLine1 = "1 Main St";
+ String addressLine2 = "Apt 301";
+ String city = "Miami";
+ String state = "Florida";
+ String zipCode = "33101";
+ String email = "micheal@burnnotice.com";
+ String phoneNumber = "305.333.0101";
+
+ returnCustomer.setId(id);
+ returnCustomer.setFirstName(firstName);
+ returnCustomer.setLastName(lastName);
+ returnCustomer.setAddressLine1(addressLine1);
+ returnCustomer.setAddressLine2(addressLine2);
+ returnCustomer.setCity(city);
+ returnCustomer.setState(state);
+ returnCustomer.setZipCode(zipCode);
+ returnCustomer.setEmail(email);
+ returnCustomer.setPhoneNumber(phoneNumber);
+
+ when(customerService.saveOrUpdate(Matchers.any())).thenReturn(returnCustomer);
+
+ mockMvc.perform(post("/customer")
+ .param("id", "1")
+ .param("firstName", firstName)
+ .param("lastName", lastName)
+ .param("addressLine1", addressLine1)
+ .param("addressLine2", addressLine2)
+ .param("city", city)
+ .param("state", state)
+ .param("zipCode", zipCode)
+ .param("email", email)
+ .param("phoneNumber", phoneNumber))
+ .andExpect(status().is3xxRedirection())
+ .andExpect(view().name("redirect:customer/show/1"))
+ .andExpect(model().attribute("customer", instanceOf(Customer.class)))
+ .andExpect(model().attribute("customer", hasProperty("firstName", is(firstName))))
+ .andExpect(model().attribute("customer", hasProperty("lastName", is(lastName))))
+ .andExpect(model().attribute("customer", hasProperty("addressLine1", is(addressLine1))))
+ .andExpect(model().attribute("customer", hasProperty("addressLine2", is(addressLine2))))
+ .andExpect(model().attribute("customer", hasProperty("city", is(city))))
+ .andExpect(model().attribute("customer", hasProperty("state", is(state))))
+ .andExpect(model().attribute("customer", hasProperty("zipCode", is(zipCode))))
+ .andExpect(model().attribute("customer", hasProperty("email", is(email))))
+ .andExpect(model().attribute("customer", hasProperty("phoneNumber", is(phoneNumber))));
+
+ ArgumentCaptor customerCaptor = ArgumentCaptor.forClass(Customer.class);
+ verify(customerService).saveOrUpdate(customerCaptor.capture());
+
+ Customer boundCustomer = customerCaptor.getValue();
+
+ assertEquals(id, boundCustomer.getId());
+ assertEquals(firstName, boundCustomer.getFirstName());
+ assertEquals(lastName, boundCustomer.getLastName());
+ assertEquals(addressLine1, boundCustomer.getAddressLine1());
+ assertEquals(addressLine2, boundCustomer.getAddressLine2());
+ assertEquals(city, boundCustomer.getCity());
+ assertEquals(state, boundCustomer.getState());
+ assertEquals(zipCode, boundCustomer.getZipCode());
+ assertEquals(email, boundCustomer.getEmail());
+ assertEquals(phoneNumber, boundCustomer.getPhoneNumber());
+
+
+ }
+}
diff --git a/src/test/java/guru/springframework/controllers/IndexControllerTest.java b/src/test/java/guru/springframework/controllers/IndexControllerTest.java
new file mode 100644
index 00000000..a1ee14b1
--- /dev/null
+++ b/src/test/java/guru/springframework/controllers/IndexControllerTest.java
@@ -0,0 +1,35 @@
+package guru.springframework.controllers;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;
+
+/**
+ * Created by jt on 11/16/15.
+ */
+public class IndexControllerTest {
+
+ private MockMvc mockMvc;
+
+ private IndexController indexController;
+
+ @Before
+ public void setup(){
+ indexController = new IndexController();
+ mockMvc = MockMvcBuilders.standaloneSetup(indexController).build();
+
+ }
+
+ @Test
+ public void testIndex() throws Exception{
+ mockMvc.perform(get("/"))
+ .andExpect(status().isOk())
+ .andExpect(view().name("indexdd"));
+ }
+
+}
diff --git a/src/test/java/guru/springframework/controllers/ProductControllerTest.java b/src/test/java/guru/springframework/controllers/ProductControllerTest.java
new file mode 100644
index 00000000..278a96d6
--- /dev/null
+++ b/src/test/java/guru/springframework/controllers/ProductControllerTest.java
@@ -0,0 +1,144 @@
+package guru.springframework.controllers;
+
+import guru.springframework.domain.Product;
+import guru.springframework.services.ProductService;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.*;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.*;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
+/**
+ * Created by jt on 11/16/15.
+ */
+public class ProductControllerTest {
+
+ @Mock //Mockito Mock object
+ private ProductService productService;
+
+ @InjectMocks //setups up controller, and injects mock objects into it.
+ private ProductController productController;
+
+ private MockMvc mockMvc;
+
+ @Before
+ public void setup(){
+ MockitoAnnotations.initMocks(this); //initilizes controller and mocks
+
+ mockMvc = MockMvcBuilders.standaloneSetup(productController).build();
+ }
+
+ @Test
+ public void testList() throws Exception{
+
+ List products = new ArrayList<>();
+ products.add(new Product());
+ products.add(new Product());
+
+ //specific Mockito interaction, tell stub to return list of products
+ when(productService.listAll()).thenReturn((List) products); //need to strip generics to keep Mockito happy.
+
+ mockMvc.perform(get("/product/list"))
+ .andExpect(status().isOk())
+ .andExpect(view().name("product/list"))
+ .andExpect(model().attribute("products", hasSize(2)));
+ }
+
+ @Test
+ public void testShow() throws Exception{
+ Integer id = 1;
+
+ //Tell Mockito stub to return new product for ID 1
+ when(productService.getById(id)).thenReturn(new Product());
+
+ mockMvc.perform(get("/product/show/1"))
+ .andExpect(status().isOk())
+ .andExpect(view().name("product/show"))
+ .andExpect(model().attribute("product", instanceOf(Product.class)));
+ }
+
+ @Test
+ public void testEdit() throws Exception{
+ Integer id = 1;
+
+ //Tell Mockito stub to return new product for ID 1
+ when(productService.getById(id)).thenReturn(new Product());
+
+ mockMvc.perform(get("/product/edit/1"))
+ .andExpect(status().isOk())
+ .andExpect(view().name("product/productform"))
+ .andExpect(model().attribute("product", instanceOf(Product.class)));
+ }
+
+ @Test
+ public void testNewProduct() throws Exception {
+ Integer id = 1;
+
+ //should not call service
+ verifyZeroInteractions(productService);
+
+ mockMvc.perform(get("/product/new"))
+ .andExpect(status().isOk())
+ .andExpect(view().name("product/productform"))
+ .andExpect(model().attribute("product", instanceOf(Product.class)));
+ }
+
+ @Test
+ public void testSaveOrUpdate() throws Exception {
+ Integer id = 1;
+ String description = "Test Description";
+ BigDecimal price = new BigDecimal("12.00");
+ String imageUrl = "example.com";
+
+ Product returnProduct = new Product();
+ returnProduct.setId(id);
+ returnProduct.setDescription(description);
+ returnProduct.setPrice(price);
+ returnProduct.setImageUrl(imageUrl);
+
+ when(productService.saveOrUpdate(Matchers.any())).thenReturn(returnProduct);
+
+ mockMvc.perform(post("/product")
+ .param("id", "1")
+ .param("description", description)
+ .param("price", "12.00")
+ .param("imageUrl", "example.com"))
+ .andExpect(status().is3xxRedirection())
+ .andExpect(view().name("redirect:/product/show/1"))
+ .andExpect(model().attribute("product", instanceOf(Product.class)))
+ .andExpect(model().attribute("product", hasProperty("id", is(id))))
+ .andExpect(model().attribute("product", hasProperty("description", is(description))))
+ .andExpect(model().attribute("product", hasProperty("price", is(price))))
+ .andExpect(model().attribute("product", hasProperty("imageUrl", is(imageUrl))));
+
+ //verify properties of bound object
+ ArgumentCaptor boundProduct = ArgumentCaptor.forClass(Product.class);
+ verify(productService).saveOrUpdate(boundProduct.capture());
+
+ assertEquals(id, boundProduct.getValue().getId());
+ assertEquals(description, boundProduct.getValue().getDescription());
+ assertEquals(price, boundProduct.getValue().getPrice());
+ assertEquals(imageUrl, boundProduct.getValue().getImageUrl());
+ }
+
+ @Test
+ public void testDelete() throws Exception{
+ Integer id = 1;
+
+ mockMvc.perform(get("/product/delete/1"))
+ .andExpect(status().is3xxRedirection())
+ .andExpect(view().name("redirect:/product/list"));
+
+ verify(productService, times(1)).delete(id);
+ }
+}