Skip to content
This repository was archived by the owner on Oct 21, 2024. It is now read-only.

Commit 73b7b4f

Browse files
committed
spring-action: tried to fix chapter3 broken examples
missing controller duplicated info? wrong object reference on thymeleaf improved logging missing things from original example
1 parent 93044a4 commit 73b7b4f

File tree

65 files changed

+170
-2614
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+170
-2614
lines changed

spring/spring-in-action-book/README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@ Following book and implementing code examples.
44
* **Chapter 2.** Developing web applications
55
MVC; Thymeleaf; Controllers;
66

7-
* **Chapter 3.** Working with data
8-
Databases; JDBC vs Spring Data JPA;
7+
* **Chapter 3.** Working with data
8+
Databases; JDBC vs Spring Data JPA;
9+
The examples at this chapter **do not** work! The examples from the author are a mess, don't work and following the book *step by step*, there's code that magically appears / disappears at it's repository. I'm not gonna spend more hours fixing something the author should've done.

spring/spring-in-action-book/chapter-3/.gitignore

Lines changed: 0 additions & 34 deletions
This file was deleted.

spring/spring-in-action-book/chapter-3/jdbc/.gitignore

Lines changed: 0 additions & 34 deletions
This file was deleted.

spring/spring-in-action-book/chapter-3/jdbc/src/main/java/es/msanchez/spring/springinaction/controllers/DesignTacoController.java

Lines changed: 3 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -49,30 +49,6 @@ public Taco taco() {
4949
return new Taco();
5050
}
5151

52-
/**
53-
* This is going to be loaded every time we load for "design" view.
54-
*
55-
* @param model -
56-
*/
57-
@ModelAttribute
58-
public void addIngredientsToModel(final Model model) {
59-
final List<Ingredient> ingredients = Arrays.asList(
60-
new Ingredient("FLTO", "Flour tortilla", Type.WRAP),
61-
new Ingredient("COTO", "Corn tortilla", Type.WRAP),
62-
new Ingredient("GRBF", "Ground Beef", Type.PROTEIN),
63-
new Ingredient("CARN", "Carnitas", Type.PROTEIN),
64-
new Ingredient("TMTO", "Diced tomatoes", Type.VEGGIES),
65-
new Ingredient("LETC", "Lettuce", Type.VEGGIES),
66-
new Ingredient("CHED", "Ceddar", Type.CHEESE),
67-
new Ingredient("JACK", "Monterrey Jack", Type.CHEESE),
68-
new Ingredient("SLSA", "Salsa", Type.SAUCE),
69-
new Ingredient("SRCR", "Sour cream", Type.SAUCE));
70-
71-
for (final Type type : Type.values()) {
72-
model.addAttribute(type.toString().toLowerCase(), filterByType(ingredients, type));
73-
}
74-
}
75-
7652
@GetMapping
7753
public String showDesignForm(final Model model) {
7854
final List<Ingredient> ingredients = new ArrayList<>();
@@ -88,16 +64,17 @@ public String showDesignForm(final Model model) {
8864
}
8965

9066
@PostMapping
91-
public String processDesign(@Valid @ModelAttribute("design") final Taco design,
67+
public String processDesign(@Valid final Taco design,
9268
final Errors errors,
9369
@ModelAttribute final Order order) {
9470
if (errors.hasErrors()) {
9571
log.error("Errors found on processDesign()");
72+
errors.getAllErrors().forEach(x -> log.error("{}", x));
9673
return "design";
9774
}
9875

9976
final Taco saved = this.tacoRepository.save(design);
100-
order.getTacos().add(saved);
77+
order.addDesign(saved);
10178

10279
log.info("processing design '{}'", design);
10380
return "redirect:/orders/current";
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package es.msanchez.spring.springinaction.controllers;
2+
3+
import es.msanchez.spring.springinaction.dao.IngredientRepository;
4+
import es.msanchez.spring.springinaction.entities.Ingredient;
5+
import org.springframework.beans.factory.annotation.Autowired;
6+
import org.springframework.core.convert.converter.Converter;
7+
import org.springframework.stereotype.Component;
8+
9+
@Component
10+
public class IngredientByIdConverter implements Converter<String, Ingredient> {
11+
12+
private IngredientRepository ingredientRepo;
13+
14+
@Autowired
15+
public IngredientByIdConverter(final IngredientRepository ingredientRepo) {
16+
this.ingredientRepo = ingredientRepo;
17+
}
18+
19+
@Override
20+
public Ingredient convert(final String id) {
21+
return ingredientRepo.findOne(id);
22+
}
23+
24+
}
Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,52 @@
11
package es.msanchez.spring.springinaction.controllers;
22

3+
import es.msanchez.spring.springinaction.dao.OrderRepository;
34
import es.msanchez.spring.springinaction.entities.Order;
45
import lombok.extern.slf4j.Slf4j;
6+
import org.springframework.beans.factory.annotation.Autowired;
57
import org.springframework.stereotype.Controller;
68
import org.springframework.ui.Model;
79
import org.springframework.validation.Errors;
810
import org.springframework.web.bind.annotation.GetMapping;
911
import org.springframework.web.bind.annotation.PostMapping;
1012
import org.springframework.web.bind.annotation.RequestMapping;
13+
import org.springframework.web.bind.annotation.SessionAttributes;
14+
import org.springframework.web.bind.support.SessionStatus;
1115

1216
import javax.validation.Valid;
1317

1418
@Slf4j
1519
@Controller
1620
@RequestMapping("/orders")
21+
@SessionAttributes("order")
1722
public class OrderController {
1823

19-
@GetMapping("/current")
20-
public String orderForm(final Model model) {
21-
model.addAttribute("order", new Order());
22-
return "orderForm";
23-
}
24-
25-
@PostMapping
26-
public String handleOrder(@Valid final Order order,
27-
final Errors errors) {
28-
if(errors.hasErrors()) {
29-
return "orderForm";
24+
private OrderRepository orderRepo;
25+
26+
@Autowired
27+
public OrderController(final OrderRepository orderRepo) {
28+
this.orderRepo = orderRepo;
29+
}
30+
31+
@GetMapping("/current")
32+
public String orderForm(final Model model) {
33+
model.addAttribute("order", new Order());
34+
return "orderForm";
3035
}
3136

32-
log.info("order submitted '{}'", order);
33-
return "redirect:/";
34-
}
37+
@PostMapping
38+
public String handleOrder(@Valid final Order order,
39+
final Errors errors,
40+
final SessionStatus sessionStatus) {
41+
if (errors.hasErrors()) {
42+
return "orderForm";
43+
}
44+
45+
orderRepo.save(order);
46+
sessionStatus.setComplete();
47+
48+
log.info("order submitted '{}'", order);
49+
return "redirect:/";
50+
}
3551

3652
}

spring/spring-in-action-book/chapter-3/jdbc/src/main/java/es/msanchez/spring/springinaction/dao/IngredientRepository.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
package es.msanchez.spring.springinaction.dao;
22

33
import es.msanchez.spring.springinaction.entities.Ingredient;
4-
import org.springframework.stereotype.Repository;
54

6-
@Repository
75
public interface IngredientRepository {
86

97
Iterable<Ingredient> findAll();
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// tag::core[]
2+
package es.msanchez.spring.springinaction.dao;
3+
4+
import com.fasterxml.jackson.databind.ObjectMapper;
5+
import es.msanchez.spring.springinaction.entities.Order;
6+
import es.msanchez.spring.springinaction.entities.Taco;
7+
import org.springframework.beans.factory.annotation.Autowired;
8+
import org.springframework.jdbc.core.JdbcTemplate;
9+
import org.springframework.jdbc.core.simple.SimpleJdbcInsert;
10+
import org.springframework.stereotype.Repository;
11+
12+
import java.sql.Date;
13+
import java.time.LocalDateTime;
14+
import java.util.HashMap;
15+
import java.util.List;
16+
import java.util.Map;
17+
18+
@Repository
19+
public class JdbcOrderRepository implements OrderRepository {
20+
21+
private SimpleJdbcInsert orderInserter;
22+
private SimpleJdbcInsert orderTacoInserter;
23+
private ObjectMapper objectMapper;
24+
25+
@Autowired
26+
public JdbcOrderRepository(JdbcTemplate jdbc) {
27+
this.orderInserter = new SimpleJdbcInsert(jdbc)
28+
.withTableName("Taco_Order")
29+
.usingGeneratedKeyColumns("id");
30+
31+
this.orderTacoInserter = new SimpleJdbcInsert(jdbc)
32+
.withTableName("Taco_Order_Tacos");
33+
34+
this.objectMapper = new ObjectMapper();
35+
}
36+
// end::core[]
37+
38+
// tag::save[]
39+
@Override
40+
public Order save(Order order) {
41+
order.setCreatedAt(Date.valueOf(LocalDateTime.now().toString()));
42+
long orderId = saveOrderDetails(order);
43+
order.setId(orderId);
44+
List<Taco> tacos = order.getTacos();
45+
for (Taco taco : tacos) {
46+
saveTacoToOrder(taco, orderId);
47+
}
48+
49+
return order;
50+
}
51+
52+
private long saveOrderDetails(Order order) {
53+
@SuppressWarnings("unchecked")
54+
Map<String, Object> values =
55+
objectMapper.convertValue(order, Map.class);
56+
values.put("createdAt", order.getCreatedAt());
57+
58+
long orderId =
59+
orderInserter
60+
.executeAndReturnKey(values)
61+
.longValue();
62+
return orderId;
63+
}
64+
65+
private void saveTacoToOrder(Taco taco, long orderId) {
66+
Map<String, Object> values = new HashMap<>();
67+
values.put("tacoOrder", orderId);
68+
values.put("taco", taco.getId());
69+
orderTacoInserter.execute(values);
70+
}
71+
72+
// end::save[]
73+
74+
/*
75+
// tag::core[]
76+
77+
...
78+
79+
// end::core[]
80+
*/
81+
82+
// tag::core[]
83+
}
84+
// end::core[]

spring/spring-in-action-book/chapter-3/jdbc/src/main/java/es/msanchez/spring/springinaction/dao/JdbcTacoRepository.java

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,11 @@
22

33
import es.msanchez.spring.springinaction.entities.Ingredient;
44
import es.msanchez.spring.springinaction.entities.Taco;
5+
import lombok.extern.slf4j.Slf4j;
56
import org.springframework.beans.factory.annotation.Autowired;
67
import org.springframework.jdbc.core.JdbcTemplate;
78
import org.springframework.jdbc.core.PreparedStatementCreator;
89
import org.springframework.jdbc.core.PreparedStatementCreatorFactory;
9-
import org.springframework.jdbc.support.GeneratedKeyHolder;
10-
import org.springframework.jdbc.support.KeyHolder;
1110
import org.springframework.stereotype.Repository;
1211

1312
import java.sql.Date;
@@ -16,6 +15,7 @@
1615
import java.time.LocalDate;
1716
import java.util.Arrays;
1817

18+
@Slf4j
1919
@Repository
2020
public class JdbcTacoRepository implements TacoRepository {
2121

@@ -41,15 +41,22 @@ private void saveIngredientToTaco(final Ingredient ingredient,
4141
}
4242

4343
private long saveTacoInfo(final Taco taco) {
44-
taco.setCreatedAt(Date.valueOf(LocalDate.now()));
44+
final Date now = Date.valueOf(LocalDate.now());
45+
log.info("Date timestamp: {}", now);
46+
taco.setCreatedAt(now);
4547
final PreparedStatementCreator psc = new PreparedStatementCreatorFactory(
4648
"insert into Taco (name, createdAt) values (?,?)",
4749
Types.VARCHAR, Types.TIMESTAMP
4850
).newPreparedStatementCreator(Arrays.asList(taco.getName(),
4951
new Timestamp(taco.getCreatedAt().getTime())));
50-
51-
final KeyHolder keyHolder = new GeneratedKeyHolder();
52-
this.jdbc.update(psc, keyHolder);
53-
return keyHolder.getKey().longValue();
52+
log.info("PreparedStatement: {}", psc.toString());
53+
54+
final int result = this.jdbc.update(psc);
55+
log.info("result from update: {}", result);
56+
/*
57+
* The original example uses -> return number.longValue(); this comes from a KeyHolder
58+
* but the implementation doesnt work as it returns a null.
59+
*/
60+
return result;
5461
}
5562
}

spring/spring-in-action-book/chapter-3/jdbc/src/main/java/es/msanchez/spring/springinaction/entities/Order.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,8 @@ public class Order {
4444

4545
private List<Taco> tacos = new ArrayList<>();
4646

47+
public void addDesign(final Taco design) {
48+
this.tacos.add(design);
49+
}
50+
4751
}

0 commit comments

Comments
 (0)