
新增HeadOfficeView页面:
<html><body><div>Balance : $<span id="balance"></span></div><div>Cash : $<span id="cash"></span></div></br><table style="width: 100%" border="1"><tr><th>Snack machines</th><th>ATMs</th></tr><tr><td>212<table style="width: 100%"><tr><td><ul id="snackMachineList" type="none"><li><span>Id</span>  <span>Money</span></li></ul></td></tr></table></td><td><table style="width: 100%"><tr><td><ul id="atmList" type="none"><li><span>Id</span>  <span>Cash</span></li></ul></td></tr><!-- <tr><td>Id</td><td>Cash</td></tr><tr><td id="atmId">1</td><td id="cash">$4</td><td><a href="../atm/AtmView.html">Show</a></td><td><button id="btnLoad">Load cash</buton></td></tr> --></table></td></tr></table></br></br></br><div>Move cash from Snack machine to Head office :</div><input type="text" id="snackmachineId" placeholder="Enter SnackMachine Id"/><button id="btnUnload">Unload</button></br></br></br><div>Move cash from Head office to Atm :</div><input type="text" id="atmId" placeholder="Enter Atm Id"/><button id="btnLoad">Load</button><script src="../common/jquery-3.6.0.min.js"></script><script src="headOffice.js"></script></body></html>
页面展示系统的SnackMachine和ATM数量,HeadOffice的手续费和余额。点击SnackMachine的ID字段展示详情,假设SnackMachine的余额是0,当购买3元的巧克力后,余额是3.此时可以将这3元转移到HeadOffice中,随后SnackMachine的余额变为0.我们还可以将HeadOffice的钱从ATM取出,取出3元续收手续费0.03元。我们继续完善其它类:
package com.lugew.domaindrivendesignwithspringboot.management;import com.lugew.domaindrivendesignwithspringboot.atm.Atm;import com.lugew.domaindrivendesignwithspringboot.common.AggregateRoot;import com.lugew.domaindrivendesignwithspringboot.sharedkernel.Money;import com.lugew.domaindrivendesignwithspringboot.snackmachine.SnackMachine;import lombok.Getter;import lombok.Setter;import static com.lugew.domaindrivendesignwithspringboot.sharedkernel.Money.None;@Getter@Setterpublic class HeadOffice extends AggregateRoot {private float balance;private Money cash = None;public void unloadCashFromSnackMachine(SnackMachine snackMachine) {Money money = snackMachine.unloadMoney();cash = cash.add(money);}public void loadCashToAtm(Atm atm) {atm.loadMoney(cash);cash = Money.None;}public void changeBalance(float delta) {balance += delta;}public HeadOfficeDto convertToHeadOfficeDto() {HeadOfficeDto headOfficeDto = new HeadOfficeDto();headOfficeDto.setId(id);headOfficeDto.setBalance(balance);headOfficeDto.setOneCentCount(cash.getOneCentCount());headOfficeDto.setTenCentCount(cash.getTenCentCount());headOfficeDto.setQuarterCount(cash.getQuarterCount());headOfficeDto.setOneDollarCount(cash.getOneDollarCount());headOfficeDto.setFiveDollarCount(cash.getFiveDollarCount());headOfficeDto.setTwentyDollarCount(cash.getTwentyDollarCount());return headOfficeDto;}}
package com.lugew.domaindrivendesignwithspringboot.snackmachine;import com.lugew.domaindrivendesignwithspringboot.common.AggregateRoot;import com.lugew.domaindrivendesignwithspringboot.sharedkernel.Money;import lombok.Getter;import lombok.Setter;import java.util.ArrayList;import java.util.Arrays;import java.util.List;import static com.lugew.domaindrivendesignwithspringboot.sharedkernel.Money.None;public final class SnackMachine extends AggregateRoot {@Getter@Setterprivate Money moneyInside;@Getter@Setterprivate float moneyInTransaction;@Setterprivate List<Slot> slots;public SnackMachine() {moneyInside = None;moneyInTransaction = 0;slots = new ArrayList<>();slots.add(new Slot(this, 1));slots.add(new Slot(this, 2));slots.add(new Slot(this, 3));}public Money unloadMoney() {if (moneyInTransaction > 0)throw new IllegalStateException();Money money = moneyInside;moneyInside = Money.None;return money;}public Slot getSlot(int position) {return slots.stream().filter(x -> x.getPosition() ==position).findAny().orElse(null);}public SnackPile getSnackPile(int position) {return getSlot(position).getSnackPile();}public void insertMoney(Money money) {Money[] coinsAndNotes = {Money.Cent, Money.TenCent, Money.Quarter,Money.Dollar, Money.FiveDollar,Money.TwentyDollar};if (!Arrays.asList(coinsAndNotes).contains(money))throw new IllegalStateException();moneyInTransaction = moneyInTransaction + money.getAmount();moneyInside = moneyInside.add(money);}public void returnMoney() {Money moneyToReturn = moneyInside.allocate(moneyInTransaction);moneyInside = moneyInside.substract(moneyToReturn);moneyInTransaction = 0;}public void buySnack(int position) {Slot slot = getSlot(position);if (slot.getSnackPile().getPrice() > moneyInTransaction) {throw new IllegalStateException();}slot.setSnackPile(slot.getSnackPile().subtractOne());Money change = moneyInside.allocate(moneyInTransaction - slot.getSnackPile().getPrice());if (change.getAmount() < moneyInTransaction - slot.getSnackPile().getPrice()) {throw new IllegalStateException();}moneyInside = moneyInside.substract(change);moneyInTransaction = 0;}public SnackMachineDto convertToSnackMachineDto() {SnackMachineDto snackMachineDto = new SnackMachineDto();snackMachineDto.setId(id);snackMachineDto.setMoneyInTransaction(moneyInTransaction);List<SlotDto> slotDtoList = new ArrayList<>();for (Slot slot : slots) slotDtoList.add(slot.convertToSlotDto());snackMachineDto.setSlotDtoList(slotDtoList);snackMachineDto.setOneCentCount(moneyInside.getOneCentCount());snackMachineDto.setTenCentCount(moneyInside.getTenCentCount());snackMachineDto.setQuarterCount(moneyInside.getQuarterCount());snackMachineDto.setOneDollarCount(moneyInside.getOneDollarCount());snackMachineDto.setFiveDollarCount(moneyInside.getFiveDollarCount());snackMachineDto.setTwentyDollarCount(moneyInside.getTwentyDollarCount());return snackMachineDto;}public void loadSnacks(int position, SnackPile snackPile) {Slot slot = slots.stream().filter(x -> x.getPosition() ==position).findAny().orElse(null);if (slot != null) {slot.setSnackPile(snackPile);}}public void loadMoney(Money money) {moneyInside = moneyInside.add(money);}}
package com.lugew.domaindrivendesignwithspringboot.management;import com.lugew.domaindrivendesignwithspringboot.atm.Atm;import com.lugew.domaindrivendesignwithspringboot.atm.AtmDto;import com.lugew.domaindrivendesignwithspringboot.atm.AtmRepository;import com.lugew.domaindrivendesignwithspringboot.snackmachine.SnackMachine;import com.lugew.domaindrivendesignwithspringboot.snackmachine.SnackMachineDto;import com.lugew.domaindrivendesignwithspringboot.snackmachine.SnackMachineRepository;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.http.HttpStatus;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.*;@Controller@RequestMapping(path = "/headOffice")public class HeadOfficeController {@Autowiredprivate SnackMachineRepository snackMachineRepository;@Autowiredprivate AtmRepository atmRepository;@Autowiredprivate HeadOfficeRepository headOfficeRepository;@Autowiredprivate HeadOfficeInstance headOfficeInstance;@GetMapping@ResponseBodypublic HeadOfficeDto getHeadOffice() {return headOfficeInstance.getInstance();}@PutMapping("/{atmId}/loadCash")@ResponseStatus(HttpStatus.OK)public void loadCashToAtm(@PathVariable("atmId") long atmId) {AtmDto atmDto = atmRepository.findById(atmId).orElse(null);HeadOfficeDto headOfficeDto = headOfficeInstance.getInstance();Atm atm = atmDto.convertToAtm();HeadOffice headOffice = headOfficeDto.convertToHeadOffice();headOffice.loadCashToAtm(atm);atmRepository.save(atm.convertToAtmDto());headOfficeRepository.save(headOffice.convertToHeadOfficeDto());}@PutMapping("/{snackMachineId}/unloadCash")@ResponseStatus(HttpStatus.OK)public void unloadCash(@PathVariable("snackMachineId") long snackMachineId) {SnackMachineDto snackMachineDto =snackMachineRepository.findById(snackMachineId).orElse(null);if (snackMachineDto == null) return;HeadOfficeDto headOfficeDto = headOfficeInstance.getInstance();HeadOffice headOffice = headOfficeDto.convertToHeadOffice();SnackMachine snackMachine = snackMachineDto.convertToSnackMachine();headOffice.unloadCashFromSnackMachine(snackMachine);snackMachineRepository.save(snackMachine.convertToSnackMachineDto());headOfficeRepository.save(headOffice.convertToHeadOfficeDto());}}
const headOfficeUri = "http://localhost:23333/headOffice";getHeadOffice();function getHeadOffice() {$.get(headOfficeUri, function (data, status) {$('#cash').html(data.amount);$('#balance').html(data.balance);});}const snackMachineUri = "http://localhost:23333/snackmachines";getSnackMachines();function getSnackMachines() {$.get(snackMachineUri, function (data, status) {var list = data == null ? [] : (data instanceof Array ? data : [data]);$.each(list, function (index, item) {$('#snackMachineList').append('<li><a href="../snackMachine/SnackMachineView.html?id=' + item.id + '">' + item.id + '</a>    <span>$' + item.amount + '</span></li>');});});}const atmUri = "http://localhost:23333/atms";getAtms();function getAtms() {$.get(atmUri, function (data, status) {var list = data == null ? [] : (data instanceof Array ? data : [data]);$.each(list, function (index, item) {$('#atmList').append('<li><a href="../atm/AtmView.html?id=' + item.id + '">' + item.id + '</a>    <span>$' + item.amount + '</span> </li>');});});}$("#btnUnload").click(function () {var snackmachineId = $('#snackmachineId').val();$.ajax({url: headOfficeUri + '/' + snackmachineId + '/unloadCash',type: 'PUT',success: function (data) {}});});$("#btnLoad").click(function () {var atmId = $('#atmId').val();$.ajax({url: headOfficeUri + '/' + atmId + '/loadCash',type: 'PUT',success: function (data) {}});});
来看看目前的代码结构:

同时准备初始化sql:
insert into snack_dto (name, id)values ('Chocolate', 1);insert into snack_dto (name, id)values ('Soda', 2);insert into snack_dto (name, id)values ('Gum', 3);insert into snack_machine_dto (five_dollar_count, money_in_transaction,one_cent_count, one_dollar_count,quarter_count, ten_cent_count, twenty_dollar_count, id)values (100, 0.0, 100, 100, 100,100, 100, 1);insert into slot_dto (position, price, quantity, snack_dto_id, id)values (1, 40.0, 100, 1, 2);insert into slot_dto (position, price, quantity, snack_dto_id, id)values (2, 20.0, 100, 2, 3);insert into slot_dto (position, price, quantity, snack_dto_id, id)values (3, 10.0, 100, 3, 4);update slot_dtoset snack_machine_id=1where id = 2;update slot_dtoset snack_machine_id=1where id = 3;update slot_dtoset snack_machine_id=1where id = 4;insert into snack_machine_dto (five_dollar_count, money_in_transaction,one_cent_count, one_dollar_count,quarter_count, ten_cent_count, twenty_dollar_count, id)values (10, 0.0, 10, 10, 10, 10,10, 2);insert into slot_dto (position, price, quantity, snack_dto_id, id)values (1, 40.0, 100, 1, 5);insert into slot_dto (position, price, quantity, snack_dto_id, id)values (2, 20.0, 100, 2, 6);insert into slot_dto (position, price, quantity, snack_dto_id, id)values (3, 10.0, 100, 3, 7);update slot_dtoset snack_machine_id=2where id = 5;update slot_dtoset snack_machine_id=2where id = 6;update slot_dtoset snack_machine_id=2where id = 7;insert into ATM_DTO (money_charged, one_cent_count, one_dollar_count,quarter_count, ten_cent_count, five_dollar_count, twenty_dollar_count, id)values (0, 50,50, 50, 50, 50, 50, 1);insert into ATM_DTO (money_charged, one_cent_count, one_dollar_count,quarter_count, ten_cent_count, five_dollar_count, twenty_dollar_count, id)values (0, 20,20, 20, 20, 20, 20, 2);insert into HEAD_OFFICE_DTO (balance, one_cent_count, one_dollar_count,quarter_count, ten_cent_count, five_dollar_count, twenty_dollar_count, id)values (0, 0,0, 0, 0, 0, 0, 1);
运行项目:

