Výukový program Spring Boot - Bootstrap jednoduchej aplikácie

1. Prehľad

Spring Boot je zdatný doplnok platformy Spring zameraný na konvencie, ktorý je zameraný na konfiguráciu - je veľmi užitočné začať s minimálnym úsilím a vytvárať samostatné aplikácie na úrovni výroby.

Tento návod je východiskovým bodom pre bootovanie - spôsob, ako začať jednoduchým spôsobom, so základnou webovou aplikáciou.

Prejdeme si základnú konfiguráciu, front-end, rýchlu manipuláciu s dátami a spracovanie výnimiek.

2. Inštalácia

Najskôr pomocou Spring Initializr vygenerujeme základňu pre náš projekt.

Generovaný projekt sa spolieha na rodiča Boot:

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

Počiatočné závislosti budú dosť jednoduché:

 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-data-jpa com.h2database h2 

3. Konfigurácia aplikácie

Ďalej nakonfigurujeme jednoduchý hlavný trieda pre našu aplikáciu:

@SpringBootApplication verejná trieda Aplikácia {public static void main (String [] args) {SpringApplication.run (Application.class, args); }} 

Všimnite si, ako používame @SpringBootApplication ako naša primárna trieda konfigurácie aplikácií; v zákulisí, to je ekvivalent k @ Konfigurácia, @EnableAutoConfigurationa @ComponentScan spolu.

Nakoniec definujeme jednoduchý application.properties súbor - ktorý má zatiaľ iba jednu vlastnosť:

server.port = 8081 

Port servera zmení port servera z predvolených 8080 na 8081; k dispozícii je samozrejme oveľa viac vlastností Spring Boot.

4. Jednoduché zobrazenie MVC

Teraz pridajme jednoduché klientske rozhranie pomocou Thymeleaf.

Najprv musíme pridať spring-boot-starter-thymeleaf závislosť na našom pom.xml:

 org.springframework.boot spring-boot-starter-thymeleaf 

To predvolene umožňuje Thymeleaf - nie je potrebná žiadna ďalšia konfigurácia.

Teraz to môžeme nakonfigurovať v našom application.properties:

spring.thymeleaf.cache = false spring.thymeleaf.enabled = true spring.thymeleaf.prefix = classpath: / templates / spring.thymeleaf.suffix = .html spring.application.name = bootstrap Spring Boot 

Ďalej definujeme jednoduchý radič a základnú domovskú stránku - s uvítacou správou:

@Controller verejná trieda SimpleController {@Value ("$ {spring.application.name}") Reťazec appName; @GetMapping ("/") public String homePage (modelový model) {model.addAttribute ("appName", appName); vrátiť sa domov"; }} 

Nakoniec je tu náš home.html:

 Domovská stránka 

Vitajte v našej aplikácii

Všimnite si, ako sme použili vlastnosť, ktorú sme definovali v našich vlastnostiach - a potom sme ju vložili, aby sme ju mohli zobraziť na našej domovskej stránke.

5. Bezpečnosť

Ďalej pridajme do našej aplikácie zabezpečenie - najskôr zahrňte bezpečnostný štartér:

 org.springframework.boot spring-boot-starter-security 

Dúfajme, že si už všimnete nejaký vzor - väčšina jarných knižníc sa do nášho projektu ľahko importuje pomocou jednoduchých štartovacích programov.

Raz zabezpečenie jarného štartéra-štartéra závislosť od triedy cesty aplikácie - všetky koncové body sú štandardne zabezpečené, a to buď httpBasic alebo prihlásenie na základe stratégie vyjednávania obsahu spoločnosti Spring Security.

Preto, ak máme štartér v triede, mali by sme si zvyčajne definovať vlastnú konfiguráciu zabezpečenia rozšírením WebSecurityConfigurerAdapter trieda:

@Configuration @EnableWebSecurity verejná trieda SecurityConfig rozširuje WebSecurityConfigurerAdapter {@Override protected void configure (HttpSecurity http) vyvolá výnimku {http.authorizeRequests () .anyRequest () .permitAll (). A (). Csrf (). Disable (); }}

V našom príklade povoľujeme neobmedzený prístup ku všetkým koncovým bodom.

Samozrejme, jarná bezpečnosť je rozsiahla téma, ktorá sa nedá ľahko pokryť niekoľkými konfiguračnými líniami - takže vás rozhodne vyzývam, aby ste sa téme venovali hlbšie.

6. Jednoduchá perzistencia

Začnime definovaním nášho dátového modelu - jednoduchým Kniha subjekt:

@Entity public class Book {@Id @GeneratedValue (strategy = GenerationType.AUTO) private long id; @Column (nullable = false, unique = true) private String title; @Column (nullable = false) private Autor reťazca; }

A jeho úložisko, ktoré tu dobre využíva Spring Data:

verejné rozhranie BookRepository rozširuje CrudRepository {List findByTitle (názov reťazca); }

Nakoniec musíme samozrejme nakonfigurovať našu novú vrstvu vytrvalosti:

@EnableJpaRepositories ("com.baeldung.persistence.repo") @EntityScan ("com.baeldung.persistence.model") @SpringBootApplication verejná trieda Aplikácia {...}

Upozorňujeme, že používame:

  • @EnableJpaRepositories skenovať zadaný balík na úložiská
  • @EntityScan vyzdvihnúť naše subjekty JPA

Pre zjednodušenie používame tu databázu H2 v pamäti - aby sme pri spustení projektu nemali žiadne externé závislosti.

Akonáhle zahrnieme závislosť na H2, Spring Boot to automaticky zistí a nastaví našu vytrvalosť bez potreby ďalšej konfigurácie, okrem vlastností zdroja údajov:

spring.datasource.driver-class-name = org.h2. Driver spring.datasource.url = jdbc: h2: mem: bootapp; DB_CLOSE_DELAY = -1 spring.datasource.username = sa spring.datasource.password = 

Rovnako ako bezpečnosť, aj perzistencia je samozrejme širšou témou ako táto základná skupina, ktorú by ste mali určite preskúmať ďalej.

7. Web a kontrolór

Ďalej sa pozrime na webovú vrstvu - a začneme to nastavením jednoduchého ovládača - BookController.

Budeme implementovať základné operácie CRUD vystavujúce Kniha zdroje s jednoduchou validáciou:

@RestController @RequestMapping ("/ api / books") verejná trieda BookController {@Autowired private BookRepository bookRepository; @GetMapping public Iterable findAll () {return bookRepository.findAll (); } @GetMapping ("/ title / {bookTitle}") verejny List findByTitle (@PathVariable String bookTitle) {return bookRepository.findByTitle (bookTitle); } @GetMapping ("/ {id}") public Book findOne (@PathVariable Long id) {return bookRepository.findById (id) .orElseThrow (BookNotFoundException :: new); } @PostMapping @ResponseStatus (HttpStatus.CREATED) verejné vytvorenie knihy (kniha knihy @RequestBody) {návrat bookRepository.save (kniha); } @DeleteMapping ("/ {id}") public void delete (@PathVariable Long id) {bookRepository.findById (id) .orElseThrow (BookNotFoundException :: new); bookRepository.deleteById (id); } @PutMapping ("/ {id}") verejná kniha updateBookBook (kniha @RequestBody Book, @PathVariable Long id) {if (book.getId ()! = Id) {hodiť novú BookIdMismatchException (); } bookRepository.findById (id) .orElseThrow (BookNotFoundException :: new); vrátiť bookRepository.save (kniha); }} 

Vzhľadom na to, že týmto aspektom aplikácie je rozhranie API, využili sme @RestController anotácia tu - ktorá zodpovedá a @ Kontrolór spolu s @ResponseBody - aby každá metóda zaradila vrátený prostriedok priamo do odpovede HTTP.

Len jedna poznámka, ktorú stojí za to poukázať - vystavujeme naše Kniha entita ako náš externý zdroj tu. To je v poriadku pre našu jednoduchú aplikáciu, ale v skutočnej aplikácii budete pravdepodobne chcieť tieto dva koncepty oddeliť.

8. Spracovanie chýb

Teraz, keď je základná aplikácia pripravená na použitie, zamerajme sa na to jednoduchý centralizovaný mechanizmus riešenia chýb použitím @ControllerAdvice:

@ControllerAdvice public class RestExceptionHandler extends ResponseEntityExceptionHandler {@ExceptionHandler ({BookNotFoundException.class}) protected ResponseEntity handleNotFound (Exception ex, WebRequest request) {return handleExceptionInternal (ex, "Book not found", new HttpHeaders (), HttpHeaders (), HttpHeaders (), HttpHeaders (), ; } @ExceptionHandler ({BookIdMismatchException.class, ConstraintViolationException.class, DataIntegrityViolationException.class}) public ResponseEntity handleBadRequest (výnimka ex, požiadavka WebRequest) {return handleExceptionInternal (ex, ex.getLocalizedMessage (), new Http, ); }} 

Okrem štandardných výnimiek, ktoré tu spracovávame, používame aj vlastnú výnimku:

BookNotFoundException:

public class BookNotFoundException extends RuntimeException {public BookNotFoundException (String message, Throwable Cause) {super (message, Cause); } // ...} 

To by vám malo poskytnúť predstavu o tom, čo je možné s týmto globálnym mechanizmom spracovania výnimiek. Ak chcete vidieť úplnú implementáciu, pozrite si podrobný návod.

Upozorňujeme, že Spring Boot poskytuje aj /chyba mapovanie predvolene. Jeho zobrazenie môžeme prispôsobiť vytvorením jednoduchého error.html:

 Vyskytla sa chyba chyba [status] 

správa

Rovnako ako väčšina ostatných aspektov v Boote, aj toto môžeme ovládať pomocou jednoduchej vlastnosti:

server.error.path = / chyba2

9. Testovanie

Na záver otestujme naše nové API kníh.

Môžeme využiť @SpringBootTest načítať kontext aplikácie a overiť, či pri spustení aplikácie nedochádza k žiadnym chybám:

@RunWith (SpringRunner.class) @SpringBootTest verejná trieda SpringContextTest {@Test public void contextLoads () {}}

Ďalej pridajme test JUnit, ktorý overí volania API, ktoré sme napísali, pomocou nástroja RestAssured:

verejná trieda SpringBootBootstrapLiveTest {private static final String API_ROOT = "// localhost: 8081 / api / books"; private Book createRandomBook () {Book book = new Book (); book.setTitle (randomAlphabetic (10)); book.setAuthor (randomAlphabetic (15)); spiatočná kniha; } private String createBookAsUri (Book book) {Response response = RestAssured.given () .contentType (MediaType.APPLICATION_JSON_VALUE) .body (book) .post (API_ROOT); return API_ROOT + "/" + response.jsonPath (). get ("id"); }} 

Najskôr sa môžeme pokúsiť nájsť knihy pomocou alternatívnych metód:

@Test public void whenGetAllBooks_thenOK () {Response response = RestAssured.get (API_ROOT); assertEquals (HttpStatus.OK.value (), response.getStatusCode ()); } @Test public void whenGetBooksByTitle_thenOK () {Book book = createRandomBook (); createBookAsUri (kniha); Odozva response = RestAssured.get (API_ROOT + "/ title /" + book.getTitle ()); assertEquals (HttpStatus.OK.value (), response.getStatusCode ()); assertTrue (response.as (List.class) .size ()> 0); } @Test public void whenGetCreatedBookById_thenOK () {Book book = createRandomBook (); Umiestnenie reťazca = createBookAsUri (kniha); Odozva na odpoveď = RestAssured.get (umiestnenie); assertEquals (HttpStatus.OK.value (), response.getStatusCode ()); assertEquals (book.getTitle (), response.jsonPath () .get ("title")); } @Test public void whenGetNotExistBookById_thenNotFound () {Response response = RestAssured.get (API_ROOT + "/" + randomNumeric (4)); assertEquals (HttpStatus.NOT_FOUND.value (), response.getStatusCode ()); } 

Ďalej otestujeme vytvorenie novej knihy:

@Test public void whenCreateNewBook_thenCreated () {Book book = createRandomBook (); Response response = RestAssured.given () .contentType (MediaType.APPLICATION_JSON_VALUE) .body (kniha). Post (API_ROOT); assertEquals (HttpStatus.CREATED.value (), response.getStatusCode ()); } @Test public void whenInvalidBook_thenError () {Book book = createRandomBook (); book.setAuthor (null); Response response = RestAssured.given () .contentType (MediaType.APPLICATION_JSON_VALUE) .body (kniha). Post (API_ROOT); assertEquals (HttpStatus.BAD_REQUEST.value (), response.getStatusCode ()); } 

Aktualizácia existujúcej knihy:

@Test public void whenUpdateCreatedBook_thenUpdated () {Book book = createRandomBook (); Umiestnenie reťazca = createBookAsUri (kniha); book.setId (Long.parseLong (location.split ("api / books /") [1]))); book.setAuthor ("newAuthor"); Odozva odozvy = RestAssured.given () .contentType (MediaType.APPLICATION_JSON_VALUE) .body (kniha) .put (umiestnenie); assertEquals (HttpStatus.OK.value (), response.getStatusCode ()); response = RestAssured.get (umiestnenie); assertEquals (HttpStatus.OK.value (), response.getStatusCode ()); assertEquals ("newAuthor", response.jsonPath () .get ("autor")); } 

A odstrániť knihu:

@Test public void whenDeleteCreatedBook_thenOk () {Book book = createRandomBook (); Umiestnenie reťazca = createBookAsUri (kniha); Odozva na odpoveď = RestAssured.delete (umiestnenie); assertEquals (HttpStatus.OK.value (), response.getStatusCode ()); response = RestAssured.get (umiestnenie); assertEquals (HttpStatus.NOT_FOUND.value (), response.getStatusCode ()); } 

10. Záver

Toto bolo rýchle, ale komplexné predstavenie Spring Boot.

Samozrejme sme tu povrch sotva poškriabali - tento rámec obsahuje oveľa viac, čo môžeme pokryť v jednom úvodnom článku.

Presne preto nemáme na webe iba jeden článok o Boote.

Celý zdrojový kód našich príkladov je tu ako vždy na GitHubu.


$config[zx-auto] not found$config[zx-overlay] not found