I'm writing a small project to learn how to build Java Rest API with Springboot to manage a student's agenda. When I go to implement the various #GetMapping I get an error like title. Before moving on to make the project REST I wanted to try the various methods since I'm a "beginner". This is the piece of code I'm referring to:
#GetMapping("appuntamenti/{data}")
Appuntamenti perData(#PathVariable String data) {
return repository.findByDate(data).orElseThrow(() -> new AppuntamentoPerDataNotFoundException(data));
}
#GetMapping("appuntamenti/{ufficio}")
Appuntamenti perUffico(#PathVariable String ufficio) {
return repository.findByUfficio(ufficio)
.orElseThrow(() -> new AppuntamentoPerUfficioNotFoundException(ufficio));
}
#GetMapping("appuntamenti/{data}/{ora}")
Appuntamenti appuntamentoSpecifico(#PathVariable String data, #PathVariable String ora) {
return repository.findByDateOra(data, ora)
.orElseThrow(() -> new AppuntamentoPerDataOraNotFoundException(data, ora));
}
this is the interface with the query implementation
package com.nanosoft.agenda_studenti;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import java.util.List;
interface AppuntamentiRepository extends JpaRepository<Appuntamenti, Long> {
#Query(value = "SELECT * FROM appuntamenti e WHERE e.data = :data ORDER BY e.ora", nativeQuery = true)
// List<Appuntamenti> findAppuntamentiWithDataEquals(#Param("data") String
// data);
List<Appuntamenti> findByDate(#Param("data") String date);
#Query(value = "SELECT * FROM appuntamenti e WHERE e.ufficio = :ufficio ORDER BY e.data ASC, e.ora ASC", nativeQuery = true)
// List<Appuntamenti>
// findAppuntamentiWithUfficioOrderbyDataAscOrderbyOraAsc(#Param("ufficio")
// String ufficio);
List<Appuntamenti> findByUfficio(#Param("ufficio") String ufficio);
#Query(value = "SELECT * FROM appuntamenti e WHERE e.data = :data AND e.ora = :e.ora", nativeQuery = true)
List<Appuntamenti> findByDateOra(#Param("data") String date, #Param("ora") String ora);
#Modifying
#Query(value = "SELECT * FROM appuntamenti e WHERE e.data = :data AND e.ora = :ora", nativeQuery = true)
void deleteByDataOra(#Param("data") String data, #Param("ora") String ora);
}
I think the problem is due to the fact that queries can return a null value but I don't know how to fix it. I tried to look for various solutions online but almost all refer to findById queries while I have custom queries
Related
public interface SiteListRepository extends BaseListRepository<SiteList, Long> {
#Modifying
#Query(value = "UPDATE site_list SET name = REPLACE(name,':text','') WHERE name ILIKE :text", nativeQuery = true)
void updateSiteListName(#Param("text") String text);
}
I want to show the result in Postman from 2 unrelated objects using native queries as below:
#Query(value = "select * from product p where p.id like concat('%', :productId, '%') ", nativeQuery = true)
List<Product> findProductById(String productId);
#Query(value = "select * from customer c where c.id like concat('%',:id,'%')", nativeQuery = true)
List<Customer> findCustomerById(String id);
and I'd like to add their results with conditions:
if productId is empty, I only want to show result from List<Customer>, and vice versa
if both are empty/not, it should show the result from both queries, product and customer as shown below:
#Override
public List<Object> findById(String customerId, String productId) {
List<Object> obj = new ArrayList<>();
if(customerId.isEmpty()){
obj.addAll(productRepository.findProductById(productId));
} else if(productId.isEmpty()){
obj.addAll(customerRepository.findCustomerById(customerId));
} else {
obj.addAll(productRepository.findProductById(productId));
obj.addAll(customerRepository.findCustomerById(customerId));
}
return obj;
}
and this is my controller:
#GetMapping("/custom")
public List<Object> findById(#RequestParam(name = "customer") String customer, #RequestParam(name = "product") String product){
return service.findById(customer, product);
}
However, in Postman when both are empty they only show results from List<Product>. Is there any way to show both?
You can use map for this ?
Simply use the map instead of List and you will be good to go.
Map<String, List<Object>> foo = new HashMap<String, List<Object>>();
List<Product> list = new ArrayList<Product>();
list.add("key1_value1");
list.add("key1_value2");
foo.put("key1",list);
List<Customer> list2 = new ArrayList<Customer>();
list2.add("key1_value1");
list2.add("key1_value2");
foo.put("key2",list2);
I am writing an online store using Spring Boot (MVC) and Hiberbate. The problem is that when I get a list of drinks, JSON gives me unnecessary information from the Page interface. I don't know how you can create an DTO for the interfaces to get rid of these fields. What should I do in this situation. Can someone have a ready-made solution?
public Page<DrinkDTO> getAllDrinks(int page, int pageSize) {
PageRequest pageRequest = PageRequest.of(page, pageSize, Sort.by("id"));
final Page<Drink> drinks = drinkRepository.findAll(pageRequest);
return drinkMapper.drinksToDrinksDTO(drinks);
}
#Data
#AllArgsConstructor
public class CustomPage {
Long totalElements;
int totalPages;
int number;
int size;
}
#Data
public class PageDTO<T> {
List<T> content;
CustomPage customPage;
public PageDTO(Page<T> page) {
this.content = page.getContent();
this.customPage = new CustomPage(page.getTotalElements(),
page.getTotalPages(), page.getNumber(), page.getSize());
}
Service for example:
public PageDTO<DrinkDTO> getAllDrinks(int page, int pageSize) {
PageRequest pageRequest = PageRequest.of(page, pageSize, Sort.by("id"));
final Page<Drink> drinks = drinkRepository.findAll(pageRequest);
return new PageDTO<DrinkDTO>(drinkMapper.drinksToDrinksDTO(drinks));
}
I use native query and then I i do dto projections most of the time.
Here is an example of DTO projection
public interface OvertimeRequestView {
public Long getId();
public String getEmployeeFirstName();
public String getEmployeeLastName();
public Long getOvertimeHours();
public Date getOvertimeDate();
public String getDescription();
public String getStatus();
public String getApproverName();
public default String getEmployeeFullName() {
String lastName = this.getEmployeeLastName();
String firstName = this.getEmployeeFirstName();
if (null != firstName) {
return firstName.concat(" ").concat(lastName);
}
return lastName;
}
}
and here is the repository with a native query. notice that since the query returns 'id' column I have a getId() method in the dto above,and since it has employeeFirstName i have getEmployeeFirstName() in the dto and so on. Notice also that I include a count query, without a count query, the queries sometime fail especially if the queries are complex and contain joins
#Query(value = "select ovr.id,\n" +
" u.first_name as employeeFirstName,\n" +
" u.last_name as employeeLastName,\n" +
" ovr.overtime_date as overtimeDate,\n" +
" ovr.description as description,\n" +
" ovr.overtime_hours as overtimeHours\n" +
"from overtime_requests ovr\n" +
" left join employees e on ovr.employee_id = e.id\n" +
" left join users u on e.user_id = u.id",
nativeQuery = true,
countQuery = "select count(ovr.id)\n" +
"from overtime_requests ovr\n" +
" left join employees e on ovr.employee_id = e.id\n" +
" left join users u on e.user_id = u.id")
public Page<OvertimeRequestView> getAllActive(Pageable pageable);
For more you can check from spring data documentation
I build simple REST service, I want to get data key from database based id but, when I running no result showing in postman, how can I fix it?
This is My Controller
//Get Key
#RequestMapping(path="/getkey/{company_id}", method = RequestMethod.GET)
String getKey(#PathVariable int company_id) {
String encKey = null;
gkrepo.getKeyByCompanyid(company_id);
return encKey;
}
This is My Repository
public interface GenerateKeyRepository extends JpaRepository<KeyEntity, Integer>
{
#Query(value= "SELECT * FROM tb_key", nativeQuery = true)
List<KeyEntity> getAll();
public void getKeyByCompanyid(Integer companyid);
}
The problem here is the fact, that you ignore the return value of the repository method and return null.
#RequestMapping(path="/getkey/{company_id}", method = RequestMethod.GET)
String getKey(#PathVariable int company_id) {
String encKey = null;
gkrepo.findOneByCompanyId(company_id);
return encKey; //YOU RETURN NULL HERE
}
What you need to do is to return the key from the KeyEntity object.
#RequestMapping(path="/getkey/{company_id}", method = RequestMethod.GET)
String getKey(#PathVariable int company_id) {
return gkrepo.getKeyByCompanyid(company_id).getKey();
}
You also need an additional method in your repository.
public interface GenerateKeyRepository extends JpaRepository<KeyEntity, Integer> {
#Query(value= "SELECT * FROM tb_key", nativeQuery = true)
List<KeyEntity> getAll();
public void findOneByCompanyId(Integer companyid);
}
You should change the method in repository as done below. Try using this.
public interface GenerateKeyRepository extends JpaRepository<KeyEntity, Integer>
{
#Query(value= "SELECT * FROM tb_key", nativeQuery = true)
List<KeyEntity> getAll();
public KeyEntity findByCompanyId(Integer companyid);
}
Your Controller Should be :
#RequestMapping(path="/getkey/{company_id}", method = RequestMethod.GET)
String getKey(#PathVariable int company_id) {
String encKey = null;
KeyEntity keyEntity = gkrepo.getKeyByCompanyid(company_id);
return keyEntity.getKey;
}
Your Repository should be like:
public interface GenerateKeyRepository extends JpaRepository<KeyEntity, Integer>
{
#Query(value= "SELECT * FROM tb_key", nativeQuery = true)
List<KeyEntity> getAll();
public KeyEntity findByCompanyId(Integer companyid);
}
You can try to change your method it as it bellow
public interface GenerateKeyRepository extends JpaRepository<KeyEntity, Integer>
{
#Query(value= "SELECT * FROM tb_key", nativeQuery = true)
List<KeyEntity> getAll();
public KeyEntity findByCompanyId(Integer companyid);
}
if you use this code , you must change code it as it bellow
gkrepo.findByCompanyId
instead of
gkrepo.getKeyByCompanyid(company_id);
OR
public interface GenerateKeyRepository extends JpaRepository<KeyEntity, Integer>
{
#Query(value= "SELECT * FROM tb_key", nativeQuery = true)
List<KeyEntity> getAll();
#Query(Select k from KeyEntity k where companyid = :companyid)
public KeyEntity getKeyByCompanyid(#Param("companyid") Integer companyid);
}
You are using Spring Data JPA. Your repository interface inherits various methods from the extended JpaRepository interface. That is the whole point of it.
https://docs.spring.io/spring-data/jpa/docs/current/api/org/springframework/data/jpa/repository/JpaRepository.html
There is then no read to write a query method:
#RestController
public class myController{
#RequestMapping(path="/getkey/{company_id}", method = RequestMethod.GET)
public KeyEntity getKey(#PathVariable("company_id") int companyId) {
return gkrepo.findById(companyId); //inherited method
}
}
Furthermore, if you enable Spring Data JPA's web extension then there is no need to call the repository at all as the Entity will be resolved automatically from the path variable:
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#core.web
The DomainClassConverter lets you use domain types in your Spring MVC
controller method signatures directly, so that you need not manually
lookup the instances through the repository
#RestController
public class myController{
#RequestMapping(path="/getkey/{company_id}", method = RequestMethod.GET)
KeyEntity getKey(#PathVariable KeyEntity keyEntity) {
return keyEntity;
}
}
I am using Criteria API with pageable to return a Page<MyClass> with pageable, but when I insert setFirstResult and setMaxResults the query always returns 10 elements.
If I remove setFirstResult and setMaxResults from TypedQuery, my typedQuery.getResultList() returns all elements but obviously without pagination.
I have a service that calls my criteria sending my pageable for the main function peopleRepository.filter
public Page<People> filtrarParcial(String name, String rg, String mom, String cpf, String nickname, Integer pageNumber, Integer pageSize, List<String> sort) {
List<Sort.Order> orders = new ArrayList<>();
PageRequest pageRequest = PageRequest.of(pageNumber, pageSize, Sort.by(orders));
Page<People> listPeople = peopleRepository.filter(name, rg, mom, cpf, nickname, pageRequest);
return listPeople;
}
My repository implements
#Service
public class PeopleRepositoryImpl implements PeopleRepositoryQueries {
#PersistenceContext
private EntityManager manager;
#Transactional(readOnly = true)
public Page<People> filter(String name, String rg, String mom, String cpf, String nickname, Pageable pageable) {
CriteriaBuilder criteriaBuilder = manager.getCriteriaBuilder();
CriteriaQuery<People> query = criteriaBuilder.createQuery(People.class);
Root<People> root = query.from(People.class);
Path<String> nomePath = root.<String>get("name");
List<Predicate> predicates = new ArrayList<Predicate>();
if(!nome.equals("")) {
Predicate nomeIgual = criteriaBuilder.like(nomePath, "%" +name.toUpperCase() + "%");
predicates.add(nomeIgual);
}
query.where((Predicate[]) predicates.toArray(new Predicate[0]));
int paginaAtual = pageable.getPageNumber();
int totalRegistrosPorPagina = pageable.getPageSize();
int primeiroRegistro = paginaAtual * totalRegistrosPorPagina;
TypedQuery<People> typedQuery = manager.createQuery(query);
// typedQuery.setFirstResult(primeiroRegistro);
// typedQuery.setMaxResults(totalRegistrosPorPagina);
Integer totalRows = typedQuery.getResultList().size();
Long total = totalRows.longValue();
return new PageImpl<>(typedQuery.getResultList(), pageable, total);
}
If I search for example a people with name marcos, typedQuery.getResultList() returns only 10 elements coincidentally with the same number elements by page (in my database there are 180). If I remove this
typedQuery.setFirstResult(primeiroRegistro);
typedQuery.setMaxResults(totalRegistrosPorPagina);
then typedQuery.getResultList() returns 180 elements but with pagination, and all 180 elements are within single page without pagination
try with the below configurations.
CriteriaQuery<Long> countQuery = criteriaBuilder.createQuery(Long.class);
Root<People> entity_ = countQuery.from(query.getResultType());
entity_.alias("entitySub"); //use the same alias in order to match the restrictions part and the selection part
countQuery.select(criteriaBuilder.count(entity_));
Predicate restriction = query.getRestriction();
if (restriction != null) {
countQuery.where(restriction); // Copy restrictions
}
Long totalCount=entityManager.createQuery(countQuery).getSingleResult();
query.setFirstResult(pageable.getOffset());
query.setMaxResults(pageable.getPageSize());
List<People> result = query.getResultList();
return PageableExecutionUtils.getPage(result,pageable, () -> totalCount);