Spring Boot adds 'es' to the links - java

I'm newcomer with Spring Boot and now after some lessons I'm trying to create RESTful+Hibernat+MySQL App. I've created:
Entity
#Entity
#Table(name = "customers")
#NamedQueries({
#NamedQuery(name = "Customers.findAll", query = "SELECT c FROM Customers c")})
public class Customers implements Serializable {...};
Controller
#RestController
#RequestMapping("/customers")
public class CustomersController {
#RequestMapping(method = GET)
public List<Object> list() {
return null;
}
#RequestMapping(value = "/{id}", method = GET)
public Object get(#PathVariable String id) {
return null;
}
#RequestMapping(value = "/{id}", method = PUT)
public ResponseEntity<?> put(#PathVariable String id, #RequestBody Object input) {
return null;
}
#RequestMapping(value = "/{id}", method = POST)
public ResponseEntity<?> post(#PathVariable String id, #RequestBody Object input) {
return null;
}
#RequestMapping(value = "/{id}", method = DELETE)
public ResponseEntity<Object> delete(#PathVariable String id) {
return null;
}
}
Repository
public interface CustomersRepository extends JpaRepository<Customers, Long> {
public Optional<Customers> findOneByEmail(String email);
}
Finally ma App runs, and when I open the link in my browserand open the link localhost:8089 I see the following:
{
"customerses" : {
"href" : "http://localhost:8089/customerses{?page,size,sort}",
"templated" : true
}
}
}
My question is why I have customerses on the end of controller name and who's adding this extension?
Thank you in advance.

It's done on purpose by Spring Data Rest - it assumes that entity name is singular, so it automatically makes it plural for the endpoint.
You just need to rename your table and entity to singular - Customer.
Here is a good explanation why it should be singular - SO answer.

Related

How to get Data By Id From Database Spring Boot Java REST API

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;
}
}

How to receive json param in spring boot

I have a Json like the following.
{"person":[{"name":"asd","age":"22"},{"name":"asd","age":"22"}]}
but it could also be:
{"person":[{"name":"asd","age":"22"},{"name":"asd","age":"22"}],"city":["NewYork"],"student":"false"}
How can I receive it in a Spring Boot Controller?
You should use #RequestBody annotation.
#RequestMapping("/api/example")
public String example(#RequestBody String string) {
return string;
}
Later, add some validations and business logic.
You can generate custom class with http://www.jsonschema2pojo.org/. Once generated you can expect your custom class instead of String.
For further instructions, I find this tutorial interesting.
You can receive the json like below, Spring Boot will convert your json into model(For example "Comment" model below) which you defined.
#RequestMapping(value = "/create", method = RequestMethod.POST)
public ResultModel createComment(#RequestBody Comment comment) {...}
1) You need to difine your rest controllers. Example
#Autowired
UserService userService;
#RequestMapping(value = "/user/", method = RequestMethod.GET)
public ResponseEntity<List<User>> listAllUsers() {
List<User> users = userService.findAllUsers();
if (users.isEmpty()) {
return new ResponseEntity(HttpStatus.NOT_FOUND);
}
return new ResponseEntity<List<User>>(users, HttpStatus.OK);
}
2) Define your pojo: Example
public class User {
String name;
String age;
public User(String name, String age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public String getAge() {
return age;
}
}
3) Define a service
#Service
public class UserService {
public List<User> findAllUsers(){
// Those are mock data. I suggest to search for Spring-data for interaction with DB.
ArrayList<User> users = new ArrayList<>();
User user = new User("name", "5");
users.add(user);
return users;
}
}
You can follow this tutorial. If you want to just send a json message to a spring boot rest controller you can use a rest client like postman.

Spring Data REST - RepositoryEventHandler methods not getting invoked for POST method?

I have the following domain object and DTO defined.
Country.java
#Data
#Entity
public class Country extends ResourceSupport {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long countryID;
#NotBlank(message = "Country name is a required field")
private String countryName;
private String countryNationality;
}
CountryDTO.java
#Data
public class CountryDTO {
private List<Country> countries;
}
I have overridden the POST method in the RepositoryRestController for the country class.
#RepositoryRestController
public class CountryController {
#Autowired
private CountryRepository repo;
#RequestMapping(method = POST, value = "countries")
public #ResponseBody ResponseEntity<?> createCountry(#RequestBody Resource<CountryDTO> dto,
Pageable page, PersistentEntityResourceAssembler resourceAssembler) {
Country savedCountry = repo.save(dto.getContent().getCountries());
return new ResponseEntity<>(resourceAssembler.toResource(savedCountry), HttpStatus.OK);
}
}
Now I have defined a RepositoryEventHandler to handle validations.
#Component
#RepositoryEventHandler
public class CountryHandler {
#HandleBeforeCreate
public void handleBeforeCreate(Country country) {
System.out.println("testing");
}
But when I send a POST request to the endpoint http://localhost:8080/countries, the eventhandler does not get invoked. Is there anything I am doing wrong?
UPDATE 1:
I am sending the following JSON to the endpoint using Postman.
"countries":[{
"countryName":"Australia",
"countryNationality":"Australian"
}]
It is difficult to give you an exact solution not knowing how you are invoking the request. But possible reason is that you are missing the slash symbol #RequestMapping value attribute:
#RequestMapping(method = POST, value = "countries")
Should be:
#RequestMapping(method = POST, value = "/countries")
Define a Bean in AppConfigration as
#Configuration
#EnableAsync
public class AppConfig {
#Bean
CountryHandler countryHandler (){
return new CountryHandler ();
}
}
It will work then.
Try editing maybe the Controller class annotation from:
#RepositoryRestController
to
#RestController
and mainly the method annotation from:
#RequestMapping(method = POST, value = "countries")
to
#RequestMapping(value = "/countries", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
PS: produces = MediaType.APPLICATION_JSON_VALUE if you are going to return json.
I know this is older but this works as it is supposed to.
The methods defined in a #RepositoryRestController implementation replace the methods in the default RepositoryEntityController which publish #RepositoryEventHandler events.
So your controller needs to publish a create event:
#RepositoryRestController
public class CountryController {
#Autowired
private CountryRepository repo;
private final ApplicationEventPublisher publisher; //This changed
#RequestMapping(method = POST, value = "countries")
public #ResponseBody ResponseEntity<?> createCountry(#RequestBody Resource<CountryDTO> dto,
Pageable page, PersistentEntityResourceAssembler resourceAssembler) {
Country savedCountry = repo.save(dto.getContent().getCountries());
publisher.publishEvent(new BeforeCreateEvent(savedCountry)); //This changed
return new ResponseEntity<>(resourceAssembler.toResource(savedCountry), HttpStatus.OK);
}
}

Call SQL server stored procedure with JPA 2.1 annotations

I'm attempting to call a MS SQL server stored procedure. Im using spring-boot, JPA 2.1, hibernate.
The database has a table with isbn, title, author, description and the stored procedure i'm trying to call takes one in parameter(isbn) as a string and returns only the title.
I get the following error:
org.hibernate.procedure.ParameterStrategyException:
Attempt to access positional parameter [2] but ProcedureCall using named parameters
Anyone got a solution for this or know what the error means? I have also tried other combinations of annotations.
Book.java
#Entity
#NamedStoredProcedureQuery(
name = "bookList",
resultClasses=Book.class,
procedureName = "dbo.list_books",
parameters = {
#StoredProcedureParameter(mode = ParameterMode.IN, name = "isbn", type = String.class)
})
public class Book {
#Id
private String title;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
BookRepository.java
#Repository
public interface BookRepository extends CrudRepository<Book, Long> {
#Procedure
Iterable<Book> list_books(String arg);
}
BookService.java
#RestController
#RequestMapping(value = "/books", produces = MediaType.APPLICATION_JSON_VALUE)
public class BookService {
#Autowired
protected BookRepository bookRepository;
#RequestMapping
public Iterable<Book> books(){
return bookRepository.getBooks("1111111");
}
I didn't solve the problem with annotations, i worked around it with an EntityManager and a StoredProcedureQuery.
The Book.java is the same but without the #NamedStoredProcedureQuery. I removed the repository and rewrote the service like this:
#RestController
#RequestMapping("/api")
public class BookService {
#RequestMapping(value = "/books",
params = {"isbn"},
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
public List<Book> getByIsbn(#RequestParam(value = "isbn") String isbn){
StoredProcedureQuery sp = em.createStoredProcedureQuery("name.of.stored.procedure", Book.class);
sp.registerStoredProcedureParameter("isbn", String.class, ParameterMode.IN);
sp.setParameter("isbn", isbn);
boolean result = sp.execute();
if (result == true) {
return sp.getResultList();
} else {
// Handle the false for no result set returned, e.g.
throw new RuntimeException("No result set(s) returned from the stored procedure");
}
}
}
It is now possible to call this endpoint with a stringquery like: http://localhost/api/books?isbn=1111111

Spring REST-ful uri with optional querystring

The normal uri which triggers the default controller to get all cars is just "/cars"
I want to be able to search for cars aswell with an uri, for example: "/cars?model=xyz" which would return a list of matching cars. All the request parameters should be optional.
The problem is that even with the querystring the default controller triggers anyway and I always get "all cars: ..."
Is there a way to do this with Spring without a separate search uri (like "/cars/search?..")?
code:
#Controller
#RequestMapping("/cars")
public class CarController {
#Autowired
private CarDao carDao;
#RequestMapping(method = RequestMethod.GET, value = "?")
public final #ResponseBody String find(
#RequestParam(value = "reg", required = false) String reg,
#RequestParam(value = "model", required = false) String model
)
{
Car searchForCar = new Car();
searchForCar.setModel(model);
searchForCar.setReg(reg);
return "found: " + carDao.findCar(searchForCar).toString();
}
#RequestMapping(method = RequestMethod.GET)
public final #ResponseBody String getAll() {
return "all cars: " + carDao.getAllCars().toString();
}
}
You can use
#RequestMapping(method = RequestMethod.GET, params = {/* string array of params required */})
public final #ResponseBody String find(#RequestParam(value = "reg") String reg, #RequestParam(value = "model") String model)
// logic
}
ie, the #RequestMapping annotation has a property called params. If all of the parameters that you specify are contained in your request (and all other RequestMapping requirements match), then that method will be called.
Try a variation of this:
#Controller
#RequestMapping("/cars")
public clas CarController
{
#RequestMapping(method = RequestMethod.get)
public final #ResponseBody String carsHandler(
final WebRequest webRequest)
{
String parameter = webRequest.getParameter("blammy");
if (parameter == null)
{
return getAll();
}
else
{
return findCar(webRequest);
}
}
}

Categories

Resources