I'm learning Java and as part of it, trying to develop a Spring Boot API that communicates with MongoDB Atlas cluster. I'm trying to write an API that would return items based on the price range value where min and max values are provided dynamically. Please help me understand where am I doing a mistake by going through the code below. I strongly feel it has to do with #Query and #PathVariable, I feel #RequestParam should be used in place of #PathVariable, however, I'm not sure what to use in place of #Query in the repository.
Here is the code of the repository
package com.webshoppingbackend.springboot.repository;
import java.util.List;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.mongodb.repository.Query;
import com.webshoppingbackend.springboot.model.WebShoppingItem;
public interface WebShoppingRepository extends MongoRepository<WebShoppingItem, String> {
#Query("{category:?0}")
List<WebShoppingItem> getItemsByCategory(String category);
#Query("{brand:?0}")
List<WebShoppingItem> getItemsByBrand(String brand);
#Query("{price:{$lt:?0,$gt:?1}}")
List<WebShoppingItem> getItemsBasedOnPrice(long higherPrice, long lowerPrice);
}
Here is the code of the controller
package com.webshoppingbackend.springboot.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import com.webshoppingbackend.springboot.model.WebShoppingItem;
import com.webshoppingbackend.springboot.services.WebShoppingService;
#RestController
#RequestMapping("/webshopping")
public class WebShoppingController {
#Autowired
private WebShoppingService service;
#GetMapping
public List<WebShoppingItem> getAllItems() {
return service.getWebShoppingItems();
}
#GetMapping("/{itemId}")
public WebShoppingItem getItem(#PathVariable String itemId) {
return service.getItemById(itemId);
}
#GetMapping("/category/{category}")
public List<WebShoppingItem> getItemsByCategory(#PathVariable String category) {
return service.getItemsByCategory(category);
}
#GetMapping("/brand/{brand}")
public List<WebShoppingItem> getItemsByBrand(#PathVariable String brand) {
return service.getItemsByBrand(brand);
}
#GetMapping("/{price}")
public List<WebShoppingItem> getItemsBasedOnPriceRange(#PathVariable long higherPrice,
#PathVariable long lowerPrice) {
return service.getItemsBasedOnPriceRange(higherPrice, lowerPrice);
}
#PostMapping
#ResponseStatus(HttpStatus.CREATED)
public WebShoppingItem addItem(#RequestBody WebShoppingItem webShoppingItem) {
return service.addToWebShoppingItems(webShoppingItem);
}
#PutMapping
public WebShoppingItem modifyItem(#RequestBody WebShoppingItem webShoppingItem) {
return service.updateWebShoppingItem(webShoppingItem);
}
#DeleteMapping("/{itemId}")
public String deleteItem(#PathVariable String itemId) {
return service.deleteWebShoppingItem(itemId);
}
}
Here is the code in the service provider
package com.webshoppingbackend.springboot.services;
import java.util.List;
import java.util.UUID;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.webshoppingbackend.springboot.model.WebShoppingItem;
import com.webshoppingbackend.springboot.repository.WebShoppingRepository;
#Service
public class WebShoppingService {
#Autowired
private WebShoppingRepository repository;
// CRUD
public WebShoppingItem addToWebShoppingItems(WebShoppingItem webShoppingItem) {
webShoppingItem.setItemId(UUID.randomUUID().toString().split("-")[0]);
return repository.save(webShoppingItem);
}
public List<WebShoppingItem> getWebShoppingItems() {
return repository.findAll();
}
public WebShoppingItem getItemById(String itemId) {
return repository.findById(itemId).get();
}
public List<WebShoppingItem> getItemsByCategory(String category) {
return repository.getItemsByCategory(category);
}
public List<WebShoppingItem> getItemsByBrand(String brand) {
return repository.getItemsByBrand(brand);
}
public List<WebShoppingItem> getItemsBasedOnPriceRange(long higherPrice, long lowerPrice) {
return repository.getItemsBasedOnPrice(higherPrice, lowerPrice);
}
public WebShoppingItem updateWebShoppingItem(WebShoppingItem webShoppingItem) {
WebShoppingItem itemToBeUpdated = repository.findById(webShoppingItem.getItemId()).get();
itemToBeUpdated.setCategory(webShoppingItem.getCategory());
itemToBeUpdated.setProductName(webShoppingItem.getProductName());
itemToBeUpdated.setImageSource(webShoppingItem.getImageSource());
itemToBeUpdated.setBrand(webShoppingItem.getBrand());
itemToBeUpdated.setPrice(webShoppingItem.getPrice());
itemToBeUpdated.setRating(webShoppingItem.getRating());
itemToBeUpdated.setShippingCharges(webShoppingItem.getShippingCharges());
itemToBeUpdated.setProductDetails(webShoppingItem.getProductDetails());
return repository.save(itemToBeUpdated);
}
public String deleteWebShoppingItem(String itemId) {
repository.deleteById(itemId);
return "Deleted Web Shopping Item";
}
}
Here is the request I'm sending through Talend API Tester to test my code.
Related
How to retrieve data from ligneCommandeDto and pass it to lignebpdto to generate dynamically a lignebpService from ligneCommandeService if affercter() is true.
the affercter() method for checking if the isAffected attribute is true, if that I call the genererbp() methode , this methode create a ligneBp so I need to fill il with data from ligneCommandeDTO.
package org.backend.gcmd.service;
import org.backend.gcmd.dto.LigneBpDTO;
import org.backend.gcmd.dto.LigneCommandeDTO;
import org.backend.gcmd.entity.LigneCommandeEntity;
import org.backend.gcmd.exceptions.technical.ObjectNotFoundException;
import org.backend.gcmd.mapper.LigneCommandeMapper;
import org.backend.gcmd.repository.LigneCommandeRepository;
import org.backend.gcmd.validator.Validate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.Optional;
import static java.util.stream.Collectors.toList;
#Service
#Transactional
public class LigneCommandeService {
#Autowired
private LigneCommandeRepository ligneCommandeRepository;
#Autowired
private LigneCommandeMapper ligneCommandeMapper;
#Autowired
private LigneBpService ligneBpService;
private LigneBpDTO ligneBpDTO;
#Autowired
private LigneBpMapper ligneBpMapper;
public LigneCommandeDTO findById(Long id) {
Validate.notNull(id, "id mus be not null");
Optional<LigneCommandeEntity> entity = ligneCommandeRepository.findById(id);
if (entity.isPresent()) {
return ligneCommandeMapper.convertToDto(entity.get());
} else {
throw new ObjectNotFoundException("LigneCommandeDTO not found");
}
}
public LigneCommandeDTO save(LigneCommandeDTO dto) {
Validate.notNull(dto, "LigneCommandeDTO must be not null");
LigneCommandeEntity entity = ligneCommandeMapper.convertToEntity(dto);
LigneCommandeEntity saved = ligneCommandeRepository.save(entity);
return ligneCommandeMapper.convertToDto(saved);
}
public LigneCommandeDTO update(LigneCommandeDTO dto) {
Validate.notNull(dto, "LigneCommandeDTO must be not null");
Validate.notNull(dto.getId(), "LigneCommandeDTO id must be not null");
findById(dto.getId());
LigneCommandeEntity entity = ligneCommandeMapper.convertToEntity(dto);
LigneCommandeEntity saved = ligneCommandeRepository.save(entity);
return ligneCommandeMapper.convertToDto(saved);
}
public Page<LigneCommandeDTO> findAllByDeletedFalse(Pageable pageable) {
Page<LigneCommandeEntity> page = ligneCommandeRepository.findAllByDeletedFalse(pageable);
return ligneCommandeMapper.convertToPageDto(page);
}
public LigneCommandeDTO affecter(Long id, Boolean isAffected) {
Validate.notNull(id, "LigneCommandeDTO must be not null");
Validate.notNull(isAffected, "LigneCommandeDTO id must be not null");
LigneCommandeDTO lcdto = findById(id);
lcdto.setIsAffected(isAffected);
update(lcdto);
genererbp();
return null;
}
public LigneBpDTO genererbp(LigneCommandeDTO ligneCommandeDTO) {
if (ligneCommandeDTO.getIsAffected()) {
return ligneBpService.findAllByDeletedFalse((Pageable) ligneBpDTO)
.stream()
.map(ligneBpMapper::convertToDto)
.collect(toList());
}
return null;
}
}
the mapper class
package org.backend.gcmd.mapper;
import org.springframework.data.domain.Page;
import java.util.List;
public interface Mapper<D, E> {
Page<D> convertToPageDto(Page<E> page);
D convertToDto(E entity);
E convertToEntity(D dto);
List<D> convertToDtoList(List<E> entities);
List<E> convertToEntitiesList(List<D> entities);
}
package org.backend.gcmd.mapper;
import org.backend.gcmd.dto.LigneBpDTO;
import org.backend.gcmd.entity.LigneBpEntity;
import org.backend.gcmd.repository.BulltinPrestationRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
#Component
public class LigneBpMapper implements Mapper<LigneBpDTO, LigneBpEntity> {
#Autowired
BulltinPrestationRepository bulltinprestationRepository;
#Override
public Page<LigneBpDTO> convertToPageDto(Page<LigneBpEntity> page) {
return page.map(this::convertToDto);
}
#Override
public LigneBpDTO convertToDto(LigneBpEntity entity) {
LigneBpDTO dto = new LigneBpDTO();
dto.setId(entity.getId());
dto.setDate(entity.getDate());
dto.setHeure(entity.getHeure());
dto.setNombre(entity.getNombre());
dto.setPrestation(entity.getPrestation());
dto.setProduit(entity.getProduit());
dto.setSensTrafic(entity.getSensTrafic());
dto.setTarifUnifie(entity.getTarifUnifie());
dto.setTcConv(entity.getTcConv());
dto.setTcSuppl(entity.getTcSuppl());
dto.setTonnageMinimum(entity.getTonnageMinimum());
dto.setTonnageReel(entity.getTonnageReel());
return dto;
}
#Override
public LigneBpEntity convertToEntity(LigneBpDTO dto) {
LigneBpEntity entity = new LigneBpEntity();
entity.setId(dto.getId());
entity.setDate(dto.getDate());
entity.setHeure(dto.getHeure());
entity.setNombre(dto.getNombre());
entity.setPrestation(dto.getPrestation());
entity.setProduit(dto.getProduit());
entity.setSensTrafic(dto.getSensTrafic());
entity.setTarifUnifie(dto.getTarifUnifie());
entity.setTcConv(dto.getTcConv());
entity.setTcSuppl(dto.getTcSuppl());
entity.setTonnageMinimum(dto.getTonnageMinimum());
entity.setTonnageReel(dto.getTonnageReel());
return entity;
}
#Override
public List<LigneBpDTO> convertToDtoList(List<LigneBpEntity> entities) {
return entities.stream().map(this::convertToDto).collect(Collectors.toCollection(ArrayList::new));
}
#Override
public List<LigneBpEntity> convertToEntitiesList(List<LigneBpDTO> dtos) {
return dtos.stream().map(this::convertToEntity).collect(Collectors.toCollection(ArrayList::new));
}
}
controller
package org.backend.gcmd.controller;
import org.backend.gcmd.dto.LigneBpDTO;
import org.backend.gcmd.dto.LigneCommandeDTO;
import org.backend.gcmd.service.LigneBpService;
import org.backend.gcmd.service.LigneCommandeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
#RestController
#RequestMapping("/api/gcmd/v1/ligneCommandes")
public class LigneCommandeController {
#Autowired
private LigneCommandeService ligneCommandeService;
#GetMapping("{id}")
public ResponseEntity<LigneCommandeDTO> findById(#PathVariable Long id) {
LigneCommandeDTO ligneCommandeDTO = ligneCommandeService.findById(id);
return ResponseEntity.status(HttpStatus.OK).body(ligneCommandeDTO);
}
#PostMapping
public ResponseEntity<LigneCommandeDTO> save(#RequestBody LigneCommandeDTO ligneCommandeDTO) {
return ResponseEntity.status(HttpStatus.CREATED).body(ligneCommandeService.save(ligneCommandeDTO));
}
#PutMapping("{id}")
public ResponseEntity<LigneCommandeDTO> update(#PathVariable Long id,
#RequestBody LigneCommandeDTO ligneCommandeDTO) {
ligneCommandeDTO.setId(id);
return ResponseEntity.status(HttpStatus.ACCEPTED).body(ligneCommandeService.update(ligneCommandeDTO));
}
#GetMapping
public ResponseEntity<Page<LigneCommandeDTO>> findAllByDeletedFalse(Pageable pageable) {
return ResponseEntity.status(HttpStatus.OK).body(ligneCommandeService.findAllByDeletedFalse(pageable));
}
}
How can I insert id manually for this JPA entity in Spring boot? I don't want the id to be autogenerated. I tried sending a POST request using postman sending this JSON object to a RestController:
{
"id":"1",
"name":"New York"
}
I get an error saying that I should manually assing id. Why it is not taking the id that I'm passing in the request?
The Code:
Entity
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
#Entity
public class City{
#Id
private Long id;
private String name;
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;
}
}
Controller:
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class CityService{
private CityService cityService;
#Autowired
public void setCityService(CityService CityService) {
this.CityService = CityService;
}
#RequestMapping(method=RequestMethod.POST, value="/cities")
public void cities(#RequestBody City city){
cityService.save(city);
}
}
Service:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
#Service
public class CityService {
private CityRepository cityRepository;
#Autowired
public CityServiceImpl(CityRepository cityRepository) {
this.cityRepository= cityRepository;
}
#Override
public void saveCity(City city) {
CityRepository.save(city);
}
}
Theres probably something wrong with your setters. Try generating them again.
There was an old table with a different structure in the database. There was no error in the code.
Been having ridiculous trouble with using the AND in the CrudReposity. All I want to do it find if two things are Not Null and display them.
public interface StudentRepository extends CrudRepository<Student, Integer>{
List<Student> findByItemAIsNotNullAndItemBIsNotNull();
}
When I run this, it seems to be running the AND as an OR (I tried both), so it's showing things that all null in one of them.
Any Help will be appreciated
You Code is correct may be problem in other section. Otherwise you can see this code. It may help you. Here I skipped service layer though its for only test.
package com.example.stack;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
#Entity
public class Data{
#Id
#GeneratedValue
Integer id;
String itemA;
String itemB;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getItemA() {
return itemA;
}
public void setItemA(String itemA) {
this.itemA = itemA;
}
public String getItemB() {
return itemB;
}
public void setItemB(String itemB) {
this.itemB = itemB;
}
}
Repository Class
package com.example.stack;
import java.util.List;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
public interface TestRepository extends CrudRepository<Data, Integer>{
List<Data> findByItemAIsNotNullAndItemBIsNotNull();
}
Controller CLass
package com.example.stack;
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;
#RestController
#RequestMapping(value = "/test")
public class TestController {
#Autowired
TestRepository repo;
#GetMapping
public List<Data> getTest()
{
return (List<Data>) repo.findByItemAIsNotNullAndItemBIsNotNull();
}
}
Database :
Response :
I am new to Boot-Spring apparently, I mostly copy some code from youtube on this case. However, after modification, in the end, I got a message like this;
APPLICATION FAILED TO START
Description:
Field postService in com.example.demo.BlogController required a bean of type 'Server.PostService' that could not be found.
Action:
Consider defining a bean of type 'Server.PostService' in your configuration.
.....Any idea how to deal with this situation. Thank you for the support.
1stclass-BlogApplciation-----com.example.demo(package)
2nd-Blog Controller--------same package as BlogApplication
3rdclass-Post---entities
4rthclass-PostRepositories---Repositories
**package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class BlogApplication {
public static void main(String[] args) {
SpringApplication.run(BlogApplication.class, args);
}
}**
**package com.example.demo;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import Server.PostService;
import entities.Post;
import java.util.Date;
#RestController
public class BlogController {
#Autowired
private PostService postService;
#GetMapping(value="/")
public String index() {
return "index";
}
#GetMapping(value="/posts")
public List<Post>posts(){
return postService.getAllPosts();
}
#PostMapping(value="/post")
public void publishPost(#RequestBody Post post) {
if(post.getDatecreation() == null)
post.setDatecreation(new Date());
postService.insert(post);
}
}**
**package entities;
import java.util.Date;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
#Entity
public class Post {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String title;
private String body;
private Date Datecreation;
public Post() {
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String gettitle() {
return title;
}
public void settitle(String title) {
this.title= title;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
public Date getDatecreation() {
return Datecreation;
}
public void setDatecreation(Date datecreation) {
this.Datecreation = datecreation;
}
}**
**package Repositories;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import entities.Post;
#Repository
public interface PostRepository extends JpaRepository<Post,Long>{
}**
Your BlogApplication Class, which is the class annotated with #SpringBootApplication is in the package com.example.demo. That means that, by default, Spring is going to launch a Component Scan starting from that package.
The problem is that your class PostService and your interface PostRepository are not in the same package as (or in a sub-package of) com.example.demo, so Spring can't find them and won't automatically create these beans for you.
To correct this issue, move the packages you created inside your root package (com.example.demo).
You can find more information about the use of #SpringBootApplication here.
EDIT:
You are missing PostService class or you have imported incorrect class as Server.PostService.
try to create a service like this one:
#Component
public class PostService {
public List<Post> getAllPosts(){
//your code
}
}
Is there any possibility to validate StandardMultipartHttpServletRequest using standard #Valid annotation and custom Validator?
I've implemented such validator, annotated method param in controller the validator is not invoked.
I've figured it out myself. To make it work you need a DTO:
import lombok.Getter;
import lombok.Setter;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
#Getter
#Setter
public class NewOrderFilesDTO {
List<MultipartFile> files;
}
Then, a validator:
import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
import static org.springframework.util.CollectionUtils.isEmpty;
#Component
public class NewOrderFilesValidator implements Validator {
private static final String MIME_TYPE_PDF = "application/pdf";
private static final long ALLOWED_SIZE = 3 * 1024 * 1024;
#Override
public void validate(Object target, Errors errors) {
if (target == null) {
return;
}
NewOrderFilesDTO newOrderFilesDTO = (NewOrderFilesDTO) target;
List<MultipartFile> newOrderFiles = newOrderFilesDTO.getFiles();
if (isEmpty(newOrderFiles)) {
return;
}
for (MultipartFile file : newOrderFiles) {
if (!MIME_TYPE_PDF.equals(file.getContentType())) {
errors.rejectValue(file.getName(), file.getName(), "'application/pdf' files allowed only!");
}
if (file.getSize() > ALLOWED_SIZE) {
errors.rejectValue(file.getName(), file.getName(), "File size allowed up to 3MB!");
}
}
}
#Override
public boolean supports(Class<?> cls) {
return NewOrderFilesDTO.class.equals(cls);
}
}
And finally a controller:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import javax.validation.Valid;
import static org.springframework.http.HttpStatus.NO_CONTENT;
import static org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE;
import static org.springframework.web.bind.annotation.RequestMethod.POST;
#Controller
class OrderController {
private final NewOrderFilesValidator newOrderFilesValidator;
#Autowired
OrderController(NewOrderFilesValidator newOrderFilesValidator) {
this.newOrderFilesValidator = newOrderFilesValidator;
}
#InitBinder("newOrderFiles")
void initOrderFilesBinder(WebDataBinder binder) {
binder.addValidators(newOrderFilesValidator);
}
#ResponseStatus(NO_CONTENT)
#RequestMapping(value = ORDERS_PATH, method = POST, consumes = MULTIPART_FORM_DATA_VALUE)
void createOrder(
#Valid #ModelAttribute NewOrderFilesDTO newOrderFiles
) {
}
}
With the configuration above the DTO will be validated automatically by spring.