Spring - pierwsze kroki

Wygeneruj projekt

Wygeneruj projekt wybierając w InteliJ opcję Spring Initializer i zaznaczając:

  • maven
  • Developer Tools → Lombok
  • Web → Spring Web
  • SQL → Spring Data JPA i Postgresql Driver

Lokalna baza danych

  • Utwórz rolę (użytkownika) spring_demo_user z hasłem spring_demo_user; nadaj mu uprawnienia do logowania
  • Utwórz lokalną baze danych PostgreSQL o nazwie spring_demo i ustaw jako właściciela spring_demo_user

application.properties

Plik znajduje się w katalogu resources. Wpisz tam parametry połączenia z bazą danych

spring.sql.init.mode=always
spring.datasource.initialize=true
spring.datasource.url=jdbc:postgresql://localhost:5432/spring_demo
spring.datasource.username=spring_demo_user
spring.datasource.password=spring_demo_user


# Hibernate ddl auto (create, create-drop, validate, update)
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.hibernate.show-sql=true
spring.jpa.database=POSTGRESQL

model

Utwórz pakiet model i dodaj do niego klasę AdminUnit

package com.example.spring_demo.model;
 
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
 
@Entity
@Table(name = "admin_units")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class AdminUnit {
    @Id
    // @GeneratedValue(strategy = GenerationType.IDENTITY)
    Long id;
    String name;
    int adminLevel;
    double area;
    double population;
    Long parentId=-1L;
    // lub 
    // AdminUnit parent;
}

Czasem dla H2 @GeneratedValue(strategy = GenerationType.IDENTITY) nie działa, wtedy trzeba generować jawnie.

repository

Utwórz pakiet repository i interfejs:

package com.example.spring_demo.repository;
 
import com.example.spring_demo.model.AdminUnit;
import org.springframework.data.domain.Example;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
 
import java.util.List;
 
public interface AdminUnitRepository extends JpaRepository<AdminUnit,Long> {
 
}

Ten (minimalistyczny) interfejs zapewnia wszystkie operacje CRUD (Create, Read, Update, Delete) oraz sortowanie i paginację.

controller

Dodaj klasę AdminUnitController. Zawiera definicje wszystkich metod wyeksportowanych przez REST API. Korzysta z AdminUnitRepository (wszczepiona zależność).

package com.example.spring_demo.controller;
 
import com.example.spring_demo.model.AdminUnit;
import com.example.spring_demo.repository.AdminUnitRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
 
import java.util.List;
 
@RestController
@RequestMapping("/api")
public class AdminUnitController {
    @Autowired
    private AdminUnitRepository adminUnitRepository;
    @GetMapping("/hello")
    public String sayHello(@RequestParam(value = "myName", defaultValue = "World") String name) {
        return String.format("Hello %s!", name);
    }
    @GetMapping(value="/units",  produces="application/json")
    public List<AdminUnit> getAllAdminUnits() {
        return this.adminUnitRepository.findAll();
    }
 
    @PutMapping("/units")
    @ResponseBody
    public void update(@RequestBody AdminUnit newAdminUnit) {
        adminUnitRepository.save(newAdminUnit);
    }
 
    @DeleteMapping("/units/{id}")
    public ResponseEntity<String> delete(@PathVariable("id") long id){
        if(adminUnitRepository.getReferenceById(id)==null){
            return new ResponseEntity<>("Resource not found", HttpStatus.NOT_FOUND);
        }
        adminUnitRepository.deleteById(id);
        return new ResponseEntity<>("OK", HttpStatus.OK);
    }
 
}

Jak widac wszystkie punkty końcowe będą miały adres localhost:8080/api/units…

Kod wykonywany podczas uruchamiania

Biblioteka Hibernate została skonfigurowana tak, aby przy każdym uruchomieniu usuwać i tworzyć od nowa bazę. Aby wypełnić ją rekordami dodaj (w głownym katalogu) klasę odpowiedzialną za wypełnienie bazy danych rekordami.

package com.example.spring_demo;
 
import com.example.spring_demo.model.AdminUnit;
import com.example.spring_demo.repository.AdminUnitRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
 
@Component
public class LoadDataOnStartUp {
    @Autowired
    private AdminUnitRepository adminUnitRepository;
 
    @EventListener(ApplicationReadyEvent.class)
    public void loadData()
    {
        // do something
 
        AdminUnit[] units = {
                new AdminUnit(1L,"Kraków",7,300,800000,-1L),
                new AdminUnit(2L,"Warszawa",7,500,1500000,-1L)
        };
//        adminUnitRepository.saveAll(new ArrayList<>(Arrays.asList(units)));
        for(var u:units)adminUnitRepository.save(u);
 
    }
}

Opcjonalnie, kod można wykonać tylko raz, aby zasilić baze danych, a potem zakomentować. Należy wtedy przełączyć tryb generacji bazy danych Hibernate w application.properties na update.

Dodaj wsparcie dla Swaggera

Dodaj zależność do pom.xml

        <dependency>
            <groupId>org.springdoc</groupId>
            <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
            <version>2.2.0</version>
        </dependency>

Dzięki temu pod adresem http://localhost:8080/swagger-ui/index.html można będzie przetestować wszystkie metody REST API

Wyszukiwanie według kryteriów

W AdminUnitRepository dodaj metodę interfejsu, a w adnotacji Query kwerendę w języku JPQL:

    @Query("SELECT u FROM AdminUnit u WHERE u.name LIKE %:partialName% AND (:aLevel IS NULL OR u.adminLevel = :aLevel)")
    List<AdminUnit> getAdminUnitsByNameContainingAndAdminLevel(@Param("partialName")  String pname, @Param("aLevel")  Integer al);

Dodaj w klasie AdminUnitController kolejną metodę GET:

    @GetMapping(value="/units/search",  produces="application/json")
    public List<AdminUnit> getAdminUnitsByNameAndAdminLevel(
            @RequestParam(value = "partialname", defaultValue = "") String name,
            @RequestParam(value = "alevel", required=false) Integer adminLevel){
        return this.adminUnitRepository.getAdminUnitsByNameContainingAndAdminLevel(name,adminLevel);
    }

W oknie Swagera można przetestować wyszukiwanie, np:

  • jednostki zawierające 'r' w nazwie bez podania poziomu
  • jednostki zawierające 's' w nazwie poziomu 7
pz1/java-spring.txt · Last modified: 2023/10/30 01:15 by pszwed
CC Attribution-Share Alike 4.0 International
Driven by DokuWiki Recent changes RSS feed Valid CSS Valid XHTML 1.0