Рубрики
Без рубрики

Введение в Spring Boot: MySQL, JPA и Hibernate.

Прежде чем мы начнем, этот пост в основном предназначен для разработчиков Java, в частности для разработчиков Java, которые используют t… С тегами java, web dev, sql.

Прежде чем мы начнем, этот пост в основном предназначен для разработчиков Java, в частности для разработчиков Java, которые используют Spring umbrella фреймворков для разработки. Если вы не разработчик Java, вы все равно можете читать дальше, скорее всего, вы еще не нашли любовь всей своей жизни – с точки зрения языков.

Кроме того, я заранее приношу извинения за ошибки разметки, которые будут появляться здесь и там в различных разделах кода. Вы можете ознакомиться с оригинальным сообщением в блоге здесь Оригинальное сообщение если у вас возникли проблемы с пониманием/скопируйте и вставьте код.

Если вы разработчик java, вы, вероятно, наткнулись на термин “Spring” в какой-то момент своего путешествия и, возможно, столкнулись лицом к лицу либо с его кривой обучения, либо с его сложностью. Одна вещь, которую большинство разработчиков не понимают – я тоже сначала боролся с этим, – это то, что Spring представляет собой набор фреймворков, адаптированных для удовлетворения конкретных потребностей разработки. В качестве примера, если вы веб-разработчик java, Spring предоставляет платформу веб-сервлетов для веб-разработки, в которой Spring MVC (включенный в эту платформу) построен поверх API сервлетов. Следовательно, вам нужно изучать не все фреймворки, предоставляемые Spring, а скорее фреймворки, соответствующие вашему конкретному варианту использования. Да, это короткий путь, и да, пожалуйста.

Если вы никогда раньше не слышали о Spring, Spring – это инверсия фреймворка управления и внедрения зависимостей. Это довольно большие термины, но этот всеобъемлющий пост поможет вам понять значения этих двух понятий: IoC и Внедрение зависимостей

Если вы раньше использовали Spring MVC, вам определенно приходилось бороться с предварительными конфигурациями Spring MVC, такими как настройка диспетчерского сервлета и т.д. и т.д. до того, как вы смогли запустить фреймворк и запустить его. Вот тут-то и пригодится Spring Boot. Spring Boot – это инструмент автоматической настройки для настройки ваших приложений на базе Spring. Теперь вы можете убрать эти боксерские перчатки, потому что вам, возможно, не придется бороться с пружинным ботинком.

Чтобы помочь вам лучше понять Spring Boot и пролить свет на то, почему вы должны использовать его, если вы еще этого не делаете, мы создадим простой Netflix API, который позволяет клиентским устройствам регистрироваться, предлагать фильмы и запрашивать фильмы.

Шаг 1: Настройка Spring Boot в вашем приложении.

Spring предлагает инициализатор проекта Spring Initializr, который позволяет вам выбирать спецификации вашего проекта и загружать уже настроенный загрузочный проект Spring в виде zip-файла или файла сборки maven. Вы можете перейти к шагу 2, если вы это сделали.

Если вы более практичный человек, которому нравится понимать, что происходит под капотом, вы можете продолжить этот шаг.

Структура папок.

Создайте новый Java-проект с помощью вашей любимой IDE и настройте структуру папок так, чтобы она имитировала следующий дизайн:

└── src
    └── main
        └── controllers
        └── models
        └── repositories
        └── resources
            └── templates
                └── error.html
            └── application.properties
        └── Application.java

контроллеры – Эта папка будет содержать контроллеры, которые мы определяем для этого проекта

репозитории – Эта папка будет содержать репозитории, которые мы определим для наших моделей, которые будут использоваться для извлечения данных из базы данных.

ресурсы – в этой папке будут находиться ресурсы нашего проекта. Папка templates содержит файлы наших шаблонов, которые будут отрисованы Spring. Вы можете включить другие папки, такие как static , которые будут использоваться для размещения статического содержимого сервера, такого как файлы javascript и css.

Зависимости Maven

Spring Boot позволяет нам включить в ваш pom.xml запишите все зависимости Spring, которые мы будем использовать в нашем проекте. Скопируйте и вставьте следующие зависимости вместе с плагином Spring Boot Maven в ваш pom.xml .



    4.0.0

    org.springframework
    gs-spring-boot
    0.1.0

    
        org.springframework.boot
        spring-boot-starter-parent
        2.1.6.RELEASE
    

    
        
    
        org.springframework.boot
        spring-boot-starter-web
    
    
        org.springframework.boot
        spring-boot-starter-thymeleaf
    
    
        org.springframework.boot
        spring-boot-devtools
        true
    

    
        mysql
        mysql-connector-java
        8.0.16
    

    
        org.springframework.boot
        spring-boot-starter-data-jpa
    
    

    
        1.8
    


    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
            
        
    


Обзор наших зависимостей:

1. spring-boot-starter-web – При создании веб-приложений с использованием java нам часто требуются другие внешние зависимости, которые мы включаем в ваш pom.xml как tomcat и Spring MVC. Что делает spring-boot-starter-web, так это добавляет все эти зависимости через одну единственную зависимость.

2. пружинный загрузчик-стартер-вилочковый лист – Если вы никогда раньше не использовали thymeleaf, thymeleaf – это движок шаблонов для обработки и создания HTML, XML, JavaScript, CSS и текста, файлы шаблонов которого сохраняют расширение .html и, следовательно, являются лучшей альтернативой JSP (страницам сервера Java). По сути, это означает, что вы можете запускать файлы шаблонов thymeleaf как обычные веб-страницы без внутреннего сервера для обработки шаблонов, как в случае JSP.

3. spring-boot-devtools – Эти инструменты смазывают ваши механизмы разработки, делая общий процесс разработки более терпимым. Чтобы узнать больше о том, что предлагают эти инструменты, вы можете перейти по этой ссылке: spring-boot-devtools

4. mysql-connector-java – Это реализация MySQL JDBC, которую мы будем использовать для подключения к нашей базе данных MySQL.

5. spring-boot-starter-data-jpa – Большинству, если не всем веб-приложениям, требуется некоторая форма персистентности, которой в случаях java часто является JPA (Java Persistence API). Если spring-boot-data-jpa находится в пути к классу, Spring boot автоматически настроит наш источник данных, прочитав конфигурацию нашей базы данных из файла application.properties, который мы настроим далее.

Обратите внимание, что мы установили нашу версию java на 1.8, поскольку JDK11 не предлагает много готовых функций, и поэтому вы можете столкнуться с ошибками типа: springboot: org.hibernate. MappingException: Не удалось получить конструктор для org.hibernate.persister.entity. SingleTableEntityPersister

Применение.свойства файл

Spring boot автоматически считывает параметры конфигурации из этого файла и соответствующим образом настраивает нашу среду spring boot. Мы настроим нашу базу данных здесь, а также в то же время отключим страницу ошибок с белой меткой Spring boot, которую мы заменим нашей собственной пользовательской страницей ошибок. Вы можете скопировать и вставить все это в свой собственный файл application.properties, если вы не собираетесь вносить какие-либо изменения.

## Spring DATASOURCE (DataSourceAutoConfiguration & DataSourceProperties)
spring.datasource.url = jdbc:mysql://localhost:3306/netflix?useSSL=false
spring.datasource.username = netflix
spring.datasource.password = netflix


## Hibernate Properties
# The SQL dialect makes Hibernate generate better SQL for the chosen database
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect

# Hibernate ddl auto (create, create-drop, validate, update)
spring.jpa.hibernate.ddl-auto = update

#Disabling the whitelabel error page
server.error.whitelabel.enabled=false

В приведенном выше файле application.properties мы настроили нашу базу данных, имя пользователя и пароль на netflix . Вы можете настроить это, если хотите. Spring JPA автоматически использует гибернационную реализацию JPA. Мы установили spring.jpa.hibernate.ddl-auto в update , что гарантирует, что любые изменения, которые мы вносим в наши модели, будут отражены в нашей базе данных, что также включает создание новой модели. Пожалуйста, обратите внимание, что этот параметр подходит только для сред разработки, а не для производственных сред. Для получения дополнительной информации вы можете проверить эту ссылку: Инициализация базы данных . Мы также установили для server.error.whitelabel.enabled значение false, чтобы отключить страницы ошибок с белой меткой Spring boot, которые мы заменим нашей собственной пользовательской страницей ошибок.

Настройка нашего приложения.java-файл

Этот файл будет содержать основной метод, который мы будем использовать для запуска нашего приложения Spring. Скопируйте и вставьте следующее в свое приложение.java-файл:

package main;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@SpringBootApplication
@EnableJpaRepositories(basePackages="main.repositories")
@EnableTransactionManagement
@EnableJpaAuditing
@EntityScan(basePackages={"main.entities","main.models"})
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}

@SpringBootApplication представляет собой комбинацию следующих более конкретных аннотаций spring –

1. @Configuration : Любой класс, аннотированный аннотацией @Configuration, загружается Spring и также рассматривается как источник других определений компонента.

2. @EnableAutoConfiguration : Эта аннотация сообщает Spring автоматически настраивать ваше приложение на основе зависимостей, которые вы добавили в pom.xml файл. Например, если spring-data-jpa или spring-jdbc находятся в пути к классу, то он автоматически попытается настроить источник данных, прочитав свойства базы данных из файла application.properties.

3. @ComponentScan :

@Enablejpauditing используется для поддержки автоматического заполнения полей, которые мы будем комментировать с помощью @CreatedDate.

@EnableJpaRepositories сообщает Spring, где найти наши определенные репозитории, поскольку мы не будем использовать аннотацию @Repository.

Шаг 2. Кодирование наших контроллеров.

Мы создадим только 3 контроллера, а именно: CustomErrorController , которые мы будем использовать для форматирования и обслуживания нашей пользовательской страницы ошибок, MoviesController который будет выполнять функции, связанные с фильмом, и Пользовательский контроллер , который будет выполнять функции, связанные с пользователем.

CustomErrorController

В этом контроллере мы зарегистрируем маршрут error , который будет сопоставлен нашему методу renderErrorPage . Поэтому все запросы, сделанные по маршруту error , будут получены нашим методом.

Обратите внимание, что здесь мы будем использовать аннотацию @Controller , поскольку мы хотели бы вернуть представление, а не обычный текст, и поэтому наш метод, возвращающий строку, вернет имя представления. Чтобы возвращать обычный текст, а не представления, используйте аннотацию @RestController .

Мы также отформатируем ваши сообщения об ошибках, чтобы сделать их более удобными для пользователя, когда мы будем отображать их на нашей странице ошибок.

Мы также внедрили интерфейс Error Controller и переопределили метод getErrorPath() , который будет автоматически вызываться, когда Spring обнаружит ошибку.

@Controller
public class CustomErrorController implements ErrorController {


    @RequestMapping(value = "error",produces = "application/json;charset=UTF-8")
    public String renderErrorPage(HttpServletRequest request, Model model) {
         String errorMsg = "";
        Object status = request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE);
        int httpErrorCode = 404;
        if(status != null){
            httpErrorCode = Integer.valueOf(status.toString());
        }
        switch (httpErrorCode) {
            case 400: {
                errorMsg = "Http Error Code: 400. Bad Request";
                break;
            }
            case 401: {
                errorMsg = "Http Error Code: 401. Unauthorized";
                break;
            }
            case 404: {
                errorMsg = "Http Error Code: 404. Resource not found";
                break;
            }
            case 500: {
                errorMsg = "Http Error Code: 500. Internal Server Error";
                break;
            }
        }
        model.addAttribute("error",errorMsg);
        return "error";
    }

    @Override
    public String getErrorPath() {
        return "/error";
    }
}

MoviesController

Как мы уже говорили ранее, этот контроллер будет хранить функции, связанные с нашими фильмами. Поскольку мы создаем api, мы сопоставим запросы api с шаблонами URL-адресов, начинающимися с /api . Поэтому мы добавляем аннотацию @RequestMapping поверх класса, а не метода, чтобы каждый URL-адрес запроса, который мы сопоставляем с нашими методами, добавлялся в /api .

@RestController
@RequestMapping(value = "/api",produces = "application/json;charset=UTF-8") //All our api request URLs will start with /api and will return Json
public class MoviesController {

    private MoviesRepository moviesRepository;
    private CategoriesRepository categoriesRepository;
    private UserRepository userRepository;

    @Autowired
    public MoviesController(MoviesRepository moviesRepository, CategoriesRepository categoriesRepository, UserRepository userRepository){
        this.moviesRepository = moviesRepository;
        this.categoriesRepository = categoriesRepository;
        this.userRepository = userRepository;
    }

    //Suggest A movie
    @GetMapping(value = "/suggestMovie")
    public String suggestMovie(@RequestParam(name = "category_id") Long categoryId,@RequestParam(name = "name")String name
    ,@RequestParam(name = "suggested_by")Long suggestedBy){
        //Movies added through this API route are automatically marked as suggested.
        String movieType = Movies.MovieType.SUGGESTED.getMovieType();
        Movies movies = new Movies();

        //Provided category id should be in our categories table.
        if(categoriesRepository.findById(categoryId).isPresent()){

            if(userRepository.findById(suggestedBy).isPresent()){
                movies.setCategoryId(categoryId);
                movies.setName(name);
                movies.setType(movieType);
                movies.setSuggestedBy(suggestedBy);
                return moviesRepository.save(movies).toString();
            } else {
                return "{'error':'The specified user id does not exist.'}";
            }

        } else {
            return "{'error':'The specified category id does not exist.'}";
        }



    }

    //delete a suggested movie
    @GetMapping(value = "/deleteMovie")
    public String deleteMovie(@RequestParam(name = "movie_id") Long movieId,@RequestParam(name = "user_id")Long userId) {
        if(userRepository.findById(userId).isPresent()){
            Optional movies = moviesRepository.findById(movieId);
            if(movies.isPresent()){
                List movie = moviesRepository.findBySuggestedByEqualsAndIdEquals(userId,movieId);
                if(movie.size()>0){
                    moviesRepository.delete(movie.get(0));
                    return movie.toString();
                } else {
                    return generateErrorResponse("The user specified cannot delete this movie");
                }


            } else {
                return  generateErrorResponse("Specified movie id does not exist");
            }

        } else {
            return generateErrorResponse("Specified user id does not exist");
        }
    }

    //update a suggested movie. Supports only updating of the movie name or category.
    @GetMapping(value = "/updateMovie/{movie_id}")
    public String updateMovie(@PathVariable(name = "movie_id") Long movieId,@RequestParam(name = "user_id")Long userId,
                              @RequestParam(name = "movie_name",required = false)String movieName, @RequestParam(name = "movie_category",required = false) Long movieCategory) {
        List movie = moviesRepository.findBySuggestedByEqualsAndIdEquals(userId,movieId);
        if(!(movie.size()>0)){
            return generateErrorResponse("The user specified cannot update this movie");
        }

        if(moviesRepository.findById(movieId).isPresent()){
            Movies movies = moviesRepository.findById(movieId).get();
            if(movieName != null && !movieName.isEmpty()){
                movies.setName(movieName);
            }
            if(movieCategory != null && categoriesRepository.findById(movieCategory).isPresent()){
                movies.setCategoryId(movieCategory);
            }

            return moviesRepository.save(movies).toString();
        } else {
            return generateErrorResponse("The specified movie id does not exist");
        }
    }

    //query available movies
    @GetMapping(value = "/queryMovies/{categoryId}")
    public String queryMovies(@PathVariable Long categoryId,@RequestParam(name = "type") String type){
        JsonObjectBuilder jsonResponse = Json.createObjectBuilder();
        JsonObjectBuilder temp = Json.createObjectBuilder();
        int count = 0;
        for(Movies movie:moviesRepository.findAllByCategoryIdEqualsAndTypeEquals(categoryId,type)){
            temp.add("id",movie.getId());
            temp.add("name",movie.getName());
            temp.add("type",movie.getType());
            temp.add("category_id",movie.getCategoryId());
            temp.add("created_at",movie.getCreatedAt().toString());
            jsonResponse.add(count + "",temp);
            temp = Json.createObjectBuilder();
            count++;
        }

        return jsonResponse.build().toString();
    }

    private String generateErrorResponse(String message){
        return "{\"error\":\"" + message + "\"";
    }

    //add categories
    @GetMapping(value = "/addCategories")
    public String addCategories(@RequestParam(name = "name") String name){
        Categories categories = new Categories();
        categories.setName(name);

        return categoriesRepository.save(categories).toString();
    }

}

В этом классе вы, возможно, заметили аннотации, которые, возможно, раньше не видели. Давайте быстро пройдемся по ним:

1. @Autowired – Как следует из самой аннотации, эта аннотация автоматически вводит реализацию интерфейса хранилища фильмов, пользователей и категорий, которому мы присваиваем объявленные нами переменные поля. Как мы упоминали ранее, вам нужен репозиторий, чтобы иметь возможность доступа к содержимому базы данных, что объясняет эти три репозитория. Я объясню это подробнее, когда мы дойдем до раздела репозиториев.

2. @GetMapping – Эта аннотация такая же, как @RequestMapping , за исключением того, что она сопоставляет запросы get только с указанным URL-адресом.

3. @RequestParam – Эта аннотация автоматически вводит указанное имя параметра запроса в эту переменную.

4. @PathVariable` – Эта аннотация автоматически вводит значение пути, заключенное в фигурные скобки, в эту переменную.

Контроллер пользователей

Этот контроллер будет содержать функции, связанные с пользователями. В этом случае мы определим только один метод, который будет отвечать за создание пользователя.

` @RestController ,производит)//Все наши URL-адреса запросов api будут начинаться с/api и возвращать общедоступный класс UsersController в формате Json {

private UserRepository userRepository;

@Autowired
public UsersController(UserRepository userRepository){
    this.userRepository = userRepository;
}


@GetMapping(path = "/addUser")
    public String addUser(@RequestParam(name = "id")Long id, @RequestParam(name="name") String name) {
    Users users = new Users();
    users.setId(id);
    users.setName(name);

    users = userRepository.save(users);
    return users.toString();

}

}

`

Наши идентификаторы пользователей в этом случае не будут сгенерированы автоматически, но вместо этого мы предоставим пользователям возможность определять свои собственные идентификаторы.

Шаг 3. Определение наших репозиториев

Хранилища будут использоваться нашими моделями для запроса данных из базы данных. spring-jpa поставляется с интерфейсом JpaRepository , который определяет все операции CRUD, которые мы можем выполнять с объектом. Мы будем использовать CrudRepository реализацию Jparepository , поскольку она предлагает множество операций CRUD из коробки с помощью таких методов, как findAll(), save() и т.д. В то же время CrudRepository автоматически генерирует для нас динамические запросы на основе имен методов, как мы увидим в следующем примере.

Мы определим три хранилища для наших трех сущностей: Каталог категорий , Каталог фильмов и UsersRepository , которые все будут интерфейсами , расширяющими CrudRepository

Категориирепозиционные

общедоступный интерфейс CategoriesRepository расширяет CrudRepository<Категории,Длинные> { }

Хранилище фильмов

` общедоступный интерфейс Movierepository расширяет CrudRepository {

List findAllByCategoryIdEqualsAndTypeEquals(Long categoryId,String type);

List findBySuggestedByEqualsAndIdEquals(Long suggestedBy,Long movieId);

}

`

В этом репозитории обратите внимание на абстрактные методы, которые мы определили. Расширение CrudRepository автоматически заставит Spring автоматически создавать реализацию этих методов во время выполнения только из определения имени метода. Чтобы добавить пользовательские методы, мы можем добавить их следующими способами:

  1. Мы можем начать наш запрос имен методов с find... По , читать... С помощью , запроса... На , количество... С помощью и получаем... По . До С помощью мы можем добавить выражение, такое как Distinct . После By нам нужно добавить имена свойств нашей сущности.

  2. Чтобы получить данные на основе более чем одного свойства, мы можем объединить имена свойств с помощью И и Или при создании имен методов.

  3. Если мы хотим использовать полностью настраиваемое имя для нашего метода, мы можем использовать @Query аннотацию для написания запроса.

Пользовательское хранилище

` @Repository public interface UserRepository расширяет CrudRepository {

}

`

Заключительный шаг: Определение наших моделей.

Модели (сущности), которые мы определяем, будут использоваться для хранения ваших табличных структур, которые будут определены в базе данных. Таким образом, у нас будет три модели для наших трех таблиц: Категории , Фильмы и/| Пользователи .

Категории Модель

` @Entity ) категории общедоступных классов {

@Id
@GeneratedValue
private Long id;

@NotBlank
private String name;

public Long getId() {
    return id;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

@Override
public String toString() {
    JsonObjectBuilder builder = Json.createObjectBuilder();

    //serialize to Json only if the data was persisted.
    if(!Objects.isNull(id)){
        builder.add("id",id);
    }
    if(!Objects.isNull(name)){
        builder.add("name",name);
    }

    return builder.build().toString();
}

}

`

Объект entity – это обычный старый класс Java object (POJO), который сопоставляется с базой данных и настраивается для использования через JPA с использованием аннотаций и/или XML. Обратите внимание, что мы включили аннотацию @Table , чтобы явно определить имя нашей таблицы. Аннотация @Id автоматически объявляет созданное поле в качестве первичного ключа для нашей таблицы в нашей базе данных. В то же время аннотация @GeneratedValue автоматически сгенерирует значение и сохранит его в базе данных во время сохранения записи, что очень похоже на поле с автоматическим увеличением. Аннотация @NotBlank автоматически проверяет значения, которые будут вставлены в определенную нами переменную name , и гарантирует, что это поле не является пустым.

Мы также определили наш собственный toString метод (переопределяющий метод суперкласса toString), который преобразует нашу модель в строку Json, которую мы возвращаем в качестве ответа в наших контроллерах.

Модель фильмов

`

@Entity ) @EntityListeners(AuditingEntityListener.class ) @JsonIgnoreProperties(значение =) открытый класс Фильмы реализуют Сериализуемый {

@Id
@GeneratedValue
private Long id;

private Long categoryId;

@NotBlank
private String  type;

@NotBlank
private String name;

private Long suggestedBy;

@Column(nullable = false, updatable = false)
@Temporal(TemporalType.TIMESTAMP)
@CreatedDate
private Date createdAt; //Stores the date at which a user was created.

@PrePersist
public void prePersist(){
    createdAt = new Date();
}

public Long getId() {
    return id;
}

public void setId(Long id) {
    this.id = id;
}

public Long getCategoryId() {
    return categoryId;
}

public void setCategoryId(Long categoryId) {
    this.categoryId = categoryId;
}

public String getType() {
    return type;
}

public void setType(String type) {
    this.type = type;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public Date getCreatedAt() {
    return createdAt;
}


@Override
public String toString() {
    JsonObjectBuilder builder = Json.createObjectBuilder();

    //serialize to Json only if the data was persisted.
    if(!Objects.isNull(id)){
        builder.add("id",id);
    }
    if(!Objects.isNull(name)){
        builder.add("name",name);
    }

    if(!Objects.isNull(categoryId)){
        builder.add("category_id",categoryId);
    }

    if(!Objects.isNull(createdAt)) {
        builder.add("created_at",createdAt.toString());
    }
    return builder.build().toString();
}

public Long getSuggestedBy() {
    return suggestedBy;
}

public void setSuggestedBy(Long suggestedBy) {
    this.suggestedBy = suggestedBy;
}

public enum MovieType{
    SUGGESTED("suggested"),ORIGINAL("original");

    private String movieType;

     MovieType(String movieType){
        this.movieType = movieType;
    }

    public String getMovieType() {
        return movieType;
    }

}

}

`

В этой модели обратите внимание на приведенные ниже примечания: 1. @EntityListeners(AuditingEntityListener.class ) – Это присоединит прослушиватель сущностей к нашему классу модели, который автоматически заполнит поля, которые мы аннотировали с помощью @createdAt . 2. `@prePersist – Эта аннотация гарантирует, что автоматически сгенерированное значение для поля createdAt сохраняется в этом поле всякий раз, когда нам понадобится доступ. Для получения дополнительной информации об аудите базы данных вы можете перейти по этой ссылке: Аудит базы данных

Модель пользователей

@Entity
@Table(name = "users")
@EntityListeners(AuditingEntityListener.class)
@JsonIgnoreProperties(value = {"createdAt"},
        allowGetters = true)
public class Users implements Serializable {
    private static final long serialVersionUID = 2L;

    @Column(updatable = false)
    @Id
    private Long id;

    @NotBlank(message = "The field 'name' is mandatory.")
    private String name;

    @Column(nullable = false, updatable = false)
    @Temporal(TemporalType.TIMESTAMP)
    @CreatedDate
    private Date createdAt; //Stores the date at which a user was created.

    @PrePersist
    public void prePersist(){
        createdAt = new Date();
    }

    public void setId(long id) {
        this.id = id;
    }

    public long getId() {
        return id;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }



    @Override
    public String toString() {
        JsonObjectBuilder builder = Json.createObjectBuilder();

        //serialize to Json only if the data was persisted.
        if(!Objects.isNull(id)){
            builder.add("id",id);
        }
        if(!Objects.isNull(name)){
            builder.add("name",name);
        }

        if(!Objects.isNull(createdAt)) {
            builder.add("created_at",createdAt.toString());
        }
        return builder.build().toString();
    }


    public Date getCreatedAt() {
        return createdAt;
    }

}

Пользовательский Шаблон страницы Ошибок

В папке templates, которую мы определили, создайте html-страницу и назовите ее error.html и скопируйте и вставьте в него следующий код:



    Error


    
Web Application. Error : th:text="${error}"

thymeleaf автоматически проанализирует эту html-страницу и отобразит наше сообщение об ошибке, заменив атрибут th:text .

Окончательно

Запустите свой Application.java используйте основной метод и протестируйте свой netflix api в вашем браузере, перейдя на localhost:8080/. Вы должны иметь возможность видеть свои ответы в формате json в вашем браузере. Кроме того, вы можете проверить исходный код в моем репозитории git и клиент, с помощью которого вы можете протестировать свой код: репозиторий github

Вывод

Вы успешно создали api netflix с использованием Spring boot, mysql и JPA. Поздравляю! Для получения дополнительных сообщений, подобных этому, вы можете заглянуть в мой личный блог @ Для получения дополнительных сообщений, подобных этому, вы можете заглянуть в мой личный блог @

Оригинал: “https://dev.to/baliachbryan/an-introduction-to-spring-boot-mysql-jpa-and-hibernate-4373”