СОДЕРЖАНИЕ ЦИКЛА СТАТЕЙ
Повторение – мать учения!
Поэтому, на основании прошлых статей, давайте создадим новый web spring-boot проект:
MobilePhonePayment (Оплата мобильного телефона)
Подключите h2, Lombok.
Создайте слой сущностей:
BalancePhoneEntity
Integer id;
Integer numberPhone;
String nameCustomer;
Integer balance;
Создайте слой сервисов с методами:
- Поиск всех записей в базе
- Поиск записи по id
- Поиск записи по номеру телефона
- Поиск записи по имени пользователя (должен возвращать лист записей, имена могу и совпадать)
public List<BalanceEntity> findByNameCustomer(String nameCustomer){
return balanceRepository.findAllByNameCustomer(nameCustomer);
}
- Добавление записи в базу
- Удаление записи из базы по id
- Бизнесовый метод: Пополнение баланса телефона – метод должен принимать номер телефона, сумму (тип Integer) и увеличивать баланс соответствующего номера на указанную сумму.
public void addingMoneyToBalance(Integer phoneNumber, Integer sum) {
BalanceDto byPhoneNumber = findByPhoneNumber(phoneNumber);
byPhoneNumber.setBalance(byPhoneNumber.getBalance() + sum);
save(byPhoneNumber);//метод save() – добавление, реализован в сервисе
}
Не забудьте реализовать маппинг из DTO в Entity и обратно.
Dto будет аналогичен Entity:
BalancePhoneDto
Integer id;
Integer numberPhone;
String nameCustomer;
Integer balance;
Создайте слой DTO, создайте класс InitiateUtils и наполните базу данными:
id 1, numberPhone 555000, balance 100, customer Иван
id 2, numberPhone 444000, balance 250, customer Марья
id 3, numberPhone 111000, balance 60, customer Иван
Создайте рест-контроллер, но не спешите наполнять его методами.
Если следовать прошлой статье, то метод вывода всех записей должен был получиться примерно так (рекомендую сейчас посмотреть в комментарии к статье - конкретно на комментарий Василия Бабина ):
//поиск записи по id - старая версия
@GetMapping(value = "/find-phone/{id}")
public ResponseEntity<BalanceDto> findPhone(@PathVariable Integer id) {
BalanceDto balanceDto = balanceService.findById(id);
return balanceDto != null
? new ResponseEntity<>(balanceDto, HttpStatus.OK)
: new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
Есть другой способ использования ResponseEntity, без использования конструктора. Его мы и будем дальше использовать.
ResponseEntity предоставляет два вложенных интерфейса компоновщика:
HeadersBuilder и его подинтерфейс, BodyBuilder. Следовательно, мы можем получить доступ к их возможностям через статические методы ResponseEntity. Почитать по больше можно в этой статье.
Методы рест-контроллера можно реализовать следующим образом:
1) Вывод записи по id
//поиск записи по id
@GetMapping(value = "/find-number-phoneById/{id}")
public ResponseEntity<?> findNumberPhoneById(@PathVariable Integer id) {
BalanceDto balanceDto = balanceService.findById(id);
return balanceDto != null
? ResponseEntity.ok(balanceDto)
: ResponseEntity.ok().body(HttpStatus.NOT_FOUND);
}
Тестируем в Postman (О нем говорили в прошлой статье, вот еще небольшой гайд по этой программе). Запускаем, выбираем тип запроса GET, в строке URL пишем: http://localhost:8080/find-number-phoneById/1 – параметр id мы передали в строке запроса, на выводе получим запись с id равным 1.
После добавления нового кода, не забываем перезапускать проект😇
2) Вывод записей по имени
//поиск записи по имени пользователя
@GetMapping(value = "/find-number-phoneByName/{name}")
public ResponseEntity<?> findNumberPhone(@PathVariable String name) {
List<BalanceDto> balanceDto = balanceService.findByNameCustomer(name);
return balanceDto != null && !balanceDto.isEmpty()
? ResponseEntity.ok(balanceDto)
: ResponseEntity.ok().body(HttpStatus.NOT_FOUND);
}
Создадим новый запрос, выбираем тип запроса GET, в строке URL пишем: http://localhost:8080/ find-number-phoneByName/Иван – параметр name мы передали в строке запроса, на выводе получим лист записей с nameCustomer равным Иван.
Возможно на выводе вы получите что то похожее на это:
%D1%8D%D1%82%D0%BE%20%D0%BD%D0%B5%20%D0%BE%D1%88%D0%B8%D0%B1%D0%BA%D0%B0
Это не ошибка — это особенности кодировки запросов, почитайте об этом.
А вот тут написано как настроить Postman что бы этого не происходило.
3) Вывод всех записей:
//поиск всех записей
@GetMapping(value = "/findAll")
public ResponseEntity<?> findAll() {
List<BalanceDto> balanceDto = balanceService.findAll();
return balanceDto != null && !balanceDto.isEmpty()
? ResponseEntity.ok(balanceDto)
: ResponseEntity.ok().body(HttpStatus.NOT_FOUND);
}
Создаем новый запрос, выбираем тип запроса GET, в строке URL пишем: http://localhost:8080/findAll – параметров тут ни каких не передаем.
4) Добавления новой записи:
//добавление новой записи
@PostMapping(value = "/entry")
public ResponseEntity<?> entryNumber(@RequestBody BalanceDto dto){
balanceService.save(dto);
return ResponseEntity.ok().body(HttpStatus.CREATED);
}
Создаем новый запрос, выбираем тип запроса POST, в строке URL пишем: http://localhost:8080/entry.
В этом запросе нам необходимо передать объект в формате JSON.
В окне запроса переходим на вкладку Body, устанавливаем флаг на raw, рядом с Text нажимаем стрелочку и выбираем JSON.
В окно копируем следующий JSON:
{
"numberPhone": 767676,
"nameCustomer": "Саша",
"balance": 100
}
Нажимаем выполнить запрос в ответе приходит статус CREATED. Теперь сделайте еще раз запрос на findAll и убедитесь, что появилась новая запись.
5) Удаления записи по id
//удаление записи по id
@DeleteMapping(value = "/delete-phoneById/{id}")
public ResponseEntity<?> delete(@PathVariable Integer id) {
balanceService.delete(id);
return ResponseEntity.ok().body(HttpStatus.OK);
}
Создаем новый запрос, выбираем тип запроса DELETE, в строке URL пишем: http://localhost:8080/delete-phoneById/4 – параметр id мы передали в строке запроса,
На выводе получим статус OK. Теперь сделайте еще раз запрос на findAll и убедитесь, что Саша пропал.
6) Изменение номера по id
//изменение номера телефона по id
@PutMapping(value = "/change")
public ResponseEntity<?> changeNumberPhone(
//можно добавлять несколько параметров в запрос
@RequestParam(value = "id") Integer id, //добавили один параметр
@RequestParam(value = "phoneNumber") Integer phoneNumber) //добавили второй параметр
{
BalanceDto byId = balanceService.findById(id);
byId.setNumberPhone(phoneNumber);
balanceService.save(byId);
return ResponseEntity.ok().body(HttpStatus.OK);
}
Создаем новый запрос, выбираем тип запроса PUT, в строке URL пишем: http://localhost:8080/change . В этом запросе несколько параметров, и мы их как видите не передаем в строке запроса как раньше. Для параметров в методе используется аннотация @RequestParam.
Что бы передать параметры через Postman, необходимо в окне запроса перейти на вкладку Params, в колонке Key указываем наименование параметра (id), в колонке Value указываем значение (1). Со вторым параметром поступаем так же, Key = phoneNumber, Value = 888000. Обратите внимание на строку запроса, Postman изменил ее что бы передать параметры правильно.
На выводе получим статус OK. Теперь сделайте еще раз запрос на findAll и убедитесь, что номер телефона у первой записи изменился.
7) Пополнение баланса телефона
@PutMapping(value = "/add")
public ResponseEntity<?> addingMoney(
//можно добавлять несколько параемров в запрос
@RequestParam(value = "phoneNumber") Integer phoneNumber,//добавили один параметр
@RequestParam(value = "sum") Integer sum) //добавили второй параметр
{
balanceService.addingMoneyToBalance(phoneNumber, sum);
return ResponseEntity.ok().body(HttpStatus.OK);
}
Создаем новый запрос, выбираем тип запроса PUT, в строке URL пишем: http://localhost:8080/add. Значение phoneNumber ставим равным 888000, sum равным 130. На выводе получим статус OK. Теперь сделайте еще раз запрос на findAll и убедитесь, что баланс у первой записи изменился.
8) PUT через тело запроса - так делать предпочтительнее, что бы не открывать передаваемые данные
@PutMapping(value = "/add")
public ResponseEntity<?> addingMoney(@RequestBody BalanceDto dto){
balanceService.addingMoneyToBalance(dto.getPhoneNumber, dto.getSum);
return ResponseEntity.ok().body(HttpStatus.OK);
}
Передаем JSON
{
"numberPhone": 888000,
// "nameCustomer" можно вообще не указывать
"balance": 130
}
Наконец-то переходим к Cookie.
Что такое Cookie.
Просто говоря: Cookie хранят данные, полученные один раз браузером от приложения, которые потом можно многократно использовать на сайте.
Нужно знать две базовые вещи: как записать и как прочитать Cookie.
Как записать:
Весь Spring Web MVC реализован поверх Servlet API, которое построено вокруг двух объектов — запрос от клиента оборачивается в HttpSerlvetRequest, а ответ формируется из заполненного вашим кодом HttpServletResponse. Имея доступ к этим объектам, вы получаете полный контроль над всей HTTP сессией. Spring web позволяет обращаться к этим объектам напрямую.
Обычно Cookie, создадим в контроллере метод
//записать куки
@GetMapping(value = "/set-cookie")
public ResponseEntity<?> setCookie(HttpServletResponse response) throws IOException {
Cookie cookie = new Cookie("data", "Come_to_the_dark_side");//создаем объект Cookie,
//в конструкторе указываем значения для name и value
cookie.setPath("/");//устанавливаем путь
cookie.setMaxAge(86400);//здесь устанавливается время жизни куки
response.addCookie(cookie);//добавляем Cookie в запрос
response.setContentType("text/plain");//устанавливаем контекст
return ResponseEntity.ok().body(HttpStatus.OK);//получилось как бы два раза статус ответа установили, выбирайте какой вариант лучше
}
Сделаем GET запрос в Postman по адресу: http://localhost:8080/set-cookie на выходе получим OK. Над океем найдите надпись Cookie(1), перейдя по ней вы увидите те Cookie что мы передали. Имя: data , значение: Come_to_the_dark_side.
Информация по основным возможностям класса Cookie в java.
Как прочитать:
Прочитать еще легче
//прочитать куки
@GetMapping(value = "/get-cookie")
public ResponseEntity<?> readCookie(@CookieValue(value = "data") String data) {
return ResponseEntity.ok().body(data);
}
В @ CookieValue указываем имя Cookie, значение которых будем считывать, и выводим прочитанное значение в ответе.
Come_to_the_dark_side
Теперь настал звездный час Header (заголовков, не смотрите что статья про PHP), почитать довольно полезно ):
Для начала посмотрим, как можно прочитать заголовки:
//прочитать заголовки
@GetMapping(value = "/get-headers")
public ResponseEntity<?> getHeaders(@RequestHeader Map<String, String> headers){//представляет заголовки ввиде мапы,
//где ключ это наименование заголовка, а значение мапы - это значение заголовка
return ResponseEntity.ok(headers);
}
Основную работу берет на себя @RequestHeader Map<String, String>, он представляет заголовки в виде мапы, где ключ это наименование заголовка, а значение мапы - это значение заголовка.
Тестировать этот метод интересней с помощью браузера, открываем браузер, набираем в поисковой строке http://localhost:8080/get-headers, на выходе получаем обширный список заголовков. Погуглите про каждый заголовок, чтобы понять зачем они нужны. Википедия тоже предлагает список заголовков.
«Если кто-то что-то прочитал, значит это кто-то записал» - старинная программистская поговорка.
Давайте запишем заголовок
//записать заголовок
@GetMapping(value = "/set-header")
public ResponseEntity<?> setHeader(){
return ResponseEntity.ok().header("name-header","value-header").body(HttpStatus.OK);
}
Здесь мы использовали специальный метод header класса ResponseEntity. Где "name-header" – это наименование заголовка, а "value-header" – это значение заголовка.
Есть и другие варианты работы с заголовками
//еще варианты работы с заголовками
@GetMapping(value = "/set-headers")
public ResponseEntity<?> setHeaders() {
HttpHeaders httpHeaders = new HttpHeaders();//создаем объект
//который имплементирует мапу MultiValueMap<String, String>
//наполняем ее парами ключ-значение
//можно наполнить своими заголовками через метод add
httpHeaders.add("customer-header", "value-header1");
//HttpHeaders так же предлагает большой выбор стандартных заголовков
//Посмотрите на них набрав в IDEA HttpHeaders.
httpHeaders.add(HttpHeaders.FROM, "russia");
//можно изменить существующий заголовок, вызвав для него сет-метод
httpHeaders.setDate(0);
//или получить значение конкретного заголовка
Long date = httpHeaders.getDate();
System.out.println(date);
return ResponseEntity
.ok().headers(httpHeaders)//здесь метод принимающий MultiValueMap<String, String>
.body(HttpStatus.OK);
}
Здесь используется уже другой метод класса ResponseEntity, который принимает значение типа MultiValueMap<String, String>.
Проверить как это работает, тоже информативнее будет в браузере. Переходим по адресу http://localhost:8080/set-headers, получаем ответ, что статус ОК.
Если вы молодец и используете гугл хром, то жмите сочетание клавиш Ctrl + Shift + I и переходите в «Инструменты разработчика», далее ищите в верхней панели вкладку Network, нажав ее ищите запись: set-headers (если ее нет обновите страницу) нажимаем на нее и в открывшемся окне выбираем вкладку Headers и в ResponseHeaders видим наши заголовки.
Для знакомства с заголовками, пока достаточно.
А теперь прочтите: Изучаем ResponseEntity<!--?--> и избавляемся от него в контроллерах Spring
На этом разрешите откланяться 🤓, до новых встреч…
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ