Monday, August 23, 2021

Spring Boot + Database example - Data retrieval

 1.Create springboot project using https://start.spring.io/ 

2.Add dependency , Spring Web, Mysql Driver, Spring JPA

 

 

3. Generate the code and , import as existing maven project

4.Since this is simple database sample add DBconnection details to the application.properties file

spring.datasource.url=jdbc:mysql://db_ip:3306/db_name?useSSL=false&serverTimezone=UTC
spring.datasource.username=user_name
spring.datasource.password=password

5.Next we create 3 layers virtually for easy understand and development

1.Control Layer

2.Service Layer

3.Repository Layer

6.Create Entity class for relevant table to be used,name City

import java.util.Objects;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "cities_test") // Mapping table with DB
public class City {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private String name;
    private int population;

    public City() {
    }

    public City(Long id, String name, int population) {
        this.id = id;
        this.name = name;
        this.population = population;
    }

    public Long getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public int getPopulation() {
        return population;
    }

    public void setPopulation(int population) {
        this.population = population;
    }
}

7.Extend CrudRepository and create CityRepository interface for doing db related transactions

Make sure to add @Repository annotation to the class

import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface CityRepository extends CrudRepository<City, Long>{

}
 

8.Then create and CityService interface for doing transaction with Repository

also add signature for retrieve data from db layer  

import java.util.List;

import lk.inova.example.all_demo.repository.City;

public interface CityService {
  List<City> findAllCities();
}

 

9.Then Create impl class by implementing above CityService interface method, also Autowired the CityRepository interface to service Impl class, make sure to set @Service annotation

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import lk.inova.example.all_demo.repository.City;
import lk.inova.example.all_demo.repository.CityRepository;
import lk.inova.example.all_demo.service.CityService;

@Service
public class CityServiceImpl implements CityService {
    @Autowired
    CityRepository repository;
    
    @Override
    public List<City> findAllCities() {
        return (List<City>) repository.findAll();
         
    }

}

10.Then create class MyCityConroller for any transaction about cities - Get Cities, Update, Delete..etc

makesure to add annotation @RestController,...Also Add request mapping and GetMapping to relevant method. also Autowired CityServiceImple class. 

@RestController
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import lk.inova.example.all_demo.repository.City;
import lk.inova.example.all_demo.service.impl.CityServiceImpl;

@RestController
@RequestMapping("/db")
public class MyCityController {
    @Autowired
    CityServiceImpl cityServiceImpl;
    
    @GetMapping("/cities")
    public List<City> getAllCities(){
        return cityServiceImpl.findAllCities();
    }

}


11.Now you can see the all cities 

http://localhost:8080/db/cities


note : 

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.4</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>lk.inova.example</groupId>
    <artifactId>all_demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>all_demo</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>11</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>




4 comments:

  1. How to handle Internal Server Error - 500 when relevant city id is not found(give 404):
    New Class :
    package lk.inova.example.all_demo.exception;

    import org.springframework.http.HttpStatus;
    import org.springframework.web.bind.annotation.ResponseStatus;

    @ResponseStatus(HttpStatus.NOT_FOUND)
    public class CityNotFoundException extends RuntimeException {
    public CityNotFoundException(String message){
    super(message);
    }
    }

    // If pass City Id is not found no city found and handle below
    @Override
    public String findCityName(long id) {
    Optional city = repository.findById(id);
    if (city == null || city.isEmpty()) {
    throw new CityNotFoundException("id is: "+ id);
    }
    City c = city.get();
    return city.get().getName();
    }

    //controller method
    // check 404 and get correct name for id
    @GetMapping("/city/{id}") // ?id=5
    public String getCity404(@PathVariable long id){
    String cityName = cityServiceImpl.findCityName(id);
    return cityName;

    }

    // Calling URL -Rest API
    http://localhost:8080/db/city/41

    //Output
    {
    "timestamp": "2021-09-03T10:39:51.839+00:00",
    "status": 404,
    "error": "Not Found",
    "path": "/db/city/41"
    }

    ReplyDelete
  2. Retrieve Data Using Sql
    1.First create response class "CityListResponseDto.java" with mapping to the Query
    package lk.inova.example.all_demo.repository.dao.wrapper;
    import javax.persistence.SqlResultSetMapping;

    import com.fasterxml.jackson.annotation.JsonProperty;

    import javax.persistence.Entity;
    import javax.persistence.EntityResult;
    import javax.persistence.FieldResult;
    import javax.persistence.Id;

    import lombok.AllArgsConstructor;
    import lombok.Builder;
    import lombok.Data;
    import lombok.NoArgsConstructor;

    @SqlResultSetMapping(name = "CityListResponseDtoMapping", entities = {
    @EntityResult(entityClass = CityListResponseDto.class, fields = {
    @FieldResult(name = "name", column = "name_q"),
    @FieldResult(name = "population", column = "population_q"),
    @FieldResult(name = "id", column = "id_q"),
    }),
    })

    @Data
    @Builder
    @Entity
    @NoArgsConstructor
    @AllArgsConstructor
    public class CityListResponseDto {
    @Id
    @JsonProperty(value = "id")
    private Long id;
    @JsonProperty(value = "name")
    private String name;
    @JsonProperty(value = "population")
    private Integer population;

    }

    2.Write Sql for retrieve data "CityDaoImpl.java" which is implementing the interface "CityDao.java"
    Interface

    package lk.inova.example.all_demo.repository.dao;

    import java.util.List;

    import lk.inova.example.all_demo.repository.dao.wrapper.CityListResponseDto;

    public interface CityDao {
    List getCityList(Long id);

    }

    ---implementation java class
    package lk.inova.example.all_demo.repository.dao;

    import java.util.List;
    import javax.persistence.EntityManager;
    import javax.persistence.NoResultException;
    import javax.persistence.PersistenceContext;
    import javax.persistence.Query;

    import org.springframework.stereotype.Repository;

    import lk.inova.example.all_demo.repository.dao.wrapper.CityListResponseDto;

    @Repository
    public class CityDaoImpl implements CityDao{
    @PersistenceContext
    private EntityManager entityManager;

    @Override
    public List getCityList(Long id) {
    StringBuilder nativeQuery = new StringBuilder();
    nativeQuery.append("SELECT ");
    nativeQuery.append("name as name_q, ");
    nativeQuery.append("population AS population_q, ");
    nativeQuery.append("id AS id_q ");
    nativeQuery.append("FROM cities_test ");
    nativeQuery.append("WHERE id = :id ");

    try {
    Query query = this.entityManager.createNativeQuery(nativeQuery.toString(), "CityListResponseDtoMapping")
    .setParameter("id", id);
    // ;
    return query.getResultList();
    }catch(Exception e) {
    System.out.println("ERROR "+ e.getMessage() );
    e.printStackTrace() ;
    return null;
    }
    }

    }

    3.Add method to Service interface
    List getCityList(long id);// using query

    4.Add implementation method to serviceImpl
    @Override
    public List getCityList(long id) {
    // TODO Auto-generated method stub

    return cityDaoImpl.getCityList(id);
    }

    5.Controller method for retrieve data
    @GetMapping("/city_q/{id}") // ?id=a
    public List getCityListByQuery(@PathVariable long id){

    return cityServiceImpl.getCityList(id);

    }

    output
    URL
    http://localhost:8080/db/city_q/5

    results
    0
    id 5
    name "Los Angeles"
    population 3971000

    ReplyDelete
  3. Added below POM entry for above Data retrieve using Sql Example

    org.projectlombok
    lombok
    true

    ReplyDelete
  4. As the above example we can pass object as request instead of the id
    package lk.inova.example.all_demo.common;

    import java.io.Serializable;

    import com.fasterxml.jackson.annotation.JsonProperty;

    import lombok.AllArgsConstructor;
    import lombok.Builder;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    import javax.validation.constraints.NotNull;
    import io.swagger.annotations.ApiModelProperty;

    @Data
    @Builder
    @NoArgsConstructor
    @AllArgsConstructor
    public class CityRequestDto implements Serializable {/**
    *
    */
    private static final long serialVersionUID = 1L;

    @JsonProperty("id")
    @NotNull(message = "value cannot be null")
    @ApiModelProperty(required = true, value = "required field")
    private Long id;

    @JsonProperty("name")
    @NotNull(message = "value cannot be null")
    @ApiModelProperty(required = true, value = "required field")
    private String name;


    }

    then controller method set as POST Mapping and as below
    @PostMapping("/city_p")
    public List getCityListByQuery(CityRequestDto cityRequestDto){

    return cityServiceImpl.getCityList(cityRequestDto);

    }

    ReplyDelete