JavaRush /Java блог /Random UA /Spring – це не страшно. Cookie & Headers
Павел
11 рівень

Spring – це не страшно. Cookie & Headers

Стаття з групи Random UA
ЗМІСТ ЦИКЛУ СТАТТІВ Повторення – мати вчення! Тому, на підставі минулих статей, давайте створимо новий 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 ставимо рівним 888 000, 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 На цьому дозвольте відкланятися 🤓, до нових зустрічей…
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ