I am new to Spring, and I am trying to create a RESTful resource to use on my API. So far, I was able to list elements (GET /people.json), show a specific element (GET /people/{id}.json), create a new element (POST /people.json), and delete an element (DELETE /people/{id}.json). My last step is to work on the update method (PUT /people/{id}.json, but I have no idea how to do it yet.
Here is the code I have for my controller:
package com.example.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import com.example.model.Person;
import com.example.service.PersonService;
import java.util.Map;
#Controller
public class PersonController {
#Autowired
private PersonService personService;
#ResponseBody
#RequestMapping(value = "/people.json", method = RequestMethod.GET)
public String all(Map<String, Object> map) {
return "{\"people\": " + personService.all() + "}";
}
#ResponseBody
#RequestMapping(value = "/people/{personId}.json", method = RequestMethod.GET)
public String show(#PathVariable("personId") Integer personId) {
Person person = personService.find(personId);
return "{\"person\": "+person+"}";
}
#ResponseBody
#RequestMapping(value = "/people.json", method = RequestMethod.POST)
public String create(#ModelAttribute("person") Person person, BindingResult result) {
personService.create(person);
return "{\"person\": "+person+"}";
}
#ResponseBody
#RequestMapping(value = "/people/{personId}.json", method = RequestMethod.PUT)
public String update(#PathVariable("personId") Integer personId, #ModelAttribute("person") Person person, BindingResult result) {
personService.update(personId, person);
return "{\"person\": "+person+"}";
}
#ResponseBody
#RequestMapping(value = "/people/{personId}.json", method = RequestMethod.DELETE)
public String delete(#PathVariable("personId") Integer personId) {
personService.delete(personId);
return "{\"status\": \"ok\", \"message\": \"\"}";
}
}
And here is the code for my service:
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.example.model.Person;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import java.util.List;
#Service
public class PersonServiceImpl implements PersonService {
#PersistenceContext
EntityManager em;
#Transactional
public List<Person> all() {
CriteriaQuery<Person> c = em.getCriteriaBuilder().createQuery(Person.class);
c.from(Person.class);
return em.createQuery(c).getResultList();
}
#Transactional
public Person find(Integer id) {
Person person = em.find(Person.class, id);
return person;
}
#Transactional
public void create(Person person) {
em.persist(person);
}
public void update(Integer id, Person person) {
// TODO: How to implement this?
}
#Transactional
public void delete(Integer id) {
Person person = em.find(Person.class, id);
if (null != person) {
em.remove(person);
}
}
}
So, for the Spring, hibernate experts out there, what is the best way to accomplish what I need? It is also important that the resource update only updates the actual changed attributes
Thanks,
Change your PersonService update method signature so that it returns a Person, also, you don't need an separate id, just use the Person object to hold the id. Them implement the method like this:
public Person update(Person person) {
// you might want to validate the person object somehow
return em.merge(person);
}
Also update your web service layer accordingly. Either change it so that personId is no longer there, or keep it and set the Person id with it:
public String update(#PathVariable("personId") Integer personId,
#ModelAttribute("person") Person person, BindingResult result) {
person.setId(personId);
Person updated = personService.update(person);
// You may want to use a JSON library instead of overriding toString.
return "{\"person\": " + updated + "}";
}
One small gotcha, merge may also persist new entities. So, if you want to make sure that update only updates existing ids, change its body to something like:
public Person update(Person person) {
if(em.find(Person.class, person.getId()) == null) {
throw new IllegalArgumentException("Person " + person.getId()
+ " does not exists");
}
return em.merge(person);
}
It is also important that the resource update only updates the actual changed attributes
If you want hibernate to update only attributes that are different between your JSON object and the database there is a handy combo of dynamicUpdate and selectBeforeUpdate properties on #org.hibernate.annotations.Entity (check out the Hibernate Manual). Only enable this if you really need the behavior (which is non standard behavior and may decrease performance).
#org.hibernate.annotations.Entity(dynamicUpdate = true, selectBeforeUpdate = true)
On Hibernate 4.0 those properties where deprecated, you can use individual annotations instead:
#DynamicUpdate
#SelectBeforeUpdate
Related
Note: This is a project which has a connection with database on other tables. I just made a new table, but i must have something wrong in my codes, because i cant get what i want.
I have a City table, and this table has 3 columns, named id, name, city_id. And i imported a csv file, so when i query, I can see some data.
I wrote Entity, Repository, Controller, and Service, in Java on Eclipse
What should I do? For example, when i search like localhost:8181/mfc/city/getAllCities that should give me all the cities as json
Could you tell me what i should add?
City.java
package com.mfc.entity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
#Entity
#Table(name="city")
public class City{
#Id
#Column(name="id")
#GeneratedValue(strategy=GenerationType.IDENTITY)
int id;
#Column(name="city_name")
String cityName;
#Column(name="city_id")
int cityId;
public City() {
super();
}
public City(int id, String cityName, int cityId) {
super();
this.id = id;
this.cityName = cityName;
this.cityId = cityId;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getCityName() {
return cityName;
}
public void setCityName(String cityName) {
this.cityName = cityName;
}
public int getCityId() {
return cityId;
}
public void setCityId(int cityId) {
this.cityId = cityId;
}
}
CityController.java
package com.mfc.admin.controller;
import java.util.List;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.mfc.admin.service.CityService;
import com.mfc.entity.City;
#RestController
#RequestMapping("/city")
public class CityController {
private static final Logger logger = LogManager.getLogger(CityController.class);
#Autowired
CityService cityService;
#RequestMapping(value="/getAllCities", method=RequestMethod.GET, headers = "Accept=application/json")
public List getCities() {
logger.trace("CityController: getAllCities begins");
List listOfCities = cityService.getAllCities();
logger.trace("CityController: getAllCities ends");
return listOfCities;
}
#RequestMapping(value="/getCity/{id}", method=RequestMethod.GET, headers = "Accept=application/json")
public City getCityById(#PathVariable int id) {
return cityService.getCity(id);
}
}
CityService.java
package com.mfc.admin.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.mfc.entity.City;
import com.mfc.repository.CityRepository;
#Service("cityService")
public class CityService {
#Autowired
CityRepository cityDTO;
#Transactional
public List getAllCities() {
return cityDTO.getAllCities();
}
#Transactional
public City getCity(int id) {
return cityDTO.getCity(id); // getCity is red here, there is mistake i guess
}
}
CityRepository.java
package com.mfc.repository;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import com.mfc.entity.City;
public interface CityRepository extends JpaRepository<City, Integer>{
List getAllCities();
City getCity();
}
In the CityService you call the CityRepository like this
return cityDTO.getCity(id); // getCity is red here, there is mistake i guess
But no such method is defined in the CityRepository. Try using this line return cityDTO.findById(id).get();
You can't see the method findById(Integer id) in the CityRepository, but it is there, because the CityRepository extends JpaRepository<City, Integer>. Find some Spring Data tutorial to know what's really going on in here, long story short the Spring Data is able to generate a lot of standard methods for you.
The method cityDTO.findById(id) returns Optional<City>, not City. To get the instance of City, just add '.get()' method, as it is in the example. It should work for you if city exists in the database. For proper work with Optional find some tutorial. It is a wrapper of an object that may or may not be present, detailed explanation is out of the scope of this answer.
maybe you can try to set up message converter manualy, google MappingJackson2HttpMessageConverter and you'll know what to do.
I need some help. I'm writing web applications using JPA. I make it with a tutorials on YouTube and other pages.
I Make a lot but i need help to view one thing from my aplication.
I have clients and also dates of appointments because it is an application for a hairdressing salon.
This is how look my aplication in InteliJ
https://i.stack.imgur.com/HlDXK.png
I want to display clients where first name is for example "Patryk"
Here is code from model.klienci
package figura.zaklad_fryzjerski_v3.model;
import javax.persistence.*;
#Entity
#Table(name = "klienci")
public class Klienci {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id_klienta")
private Integer id_klienta;
#Column(name = "imie")
private String imieKlienta;
#Column(name = "nazwisko")
private String nazwiskoKlienta;
#Column(name = "nr_telefonu_klienta")
private Integer nrTelefonuKlienta;
#Column(name = "adres_email")
private String adresEmailKlienta;
getters and setters
Here is code from repository.KlienciRepository
package figura.zaklad_fryzjerski_v3.repository;
import figura.zaklad_fryzjerski_v3.model.Klienci;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
#Repository
public interface KlienciRepository extends JpaRepository<Klienci, Integer> {
}
Here is code from service.KlienciService
package figura.zaklad_fryzjerski_v3.service.klienci;
import figura.zaklad_fryzjerski_v3.model.Klienci;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.repository.Query;
import java.util.List;
public interface KlienciService {
List<Klienci> getAllKlieci();
void saveKlienci(Klienci klienci);
Klienci getKlienciById(Integer id_klienta);
void usunKlientaById(Integer id_klienta);
Page<Klienci> findPaginated(int pageNo, int pageSize);
}
Here is code from service.KlienciServiceImpl
package figura.zaklad_fryzjerski_v3.service.klienci;
import figura.zaklad_fryzjerski_v3.model.Klienci;
import figura.zaklad_fryzjerski_v3.repository.KlienciRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
#Service
//#Transactional
public class KlienciServiceImpl implements KlienciService{
#Autowired
private KlienciRepository klienciRepository;
#Override
public List<Klienci> getAllKlieci() {
return klienciRepository.findAll();
}
#Override
public void saveKlienci(Klienci klienci){
this.klienciRepository.save(klienci);
}
#Override
public Klienci getKlienciById(Integer id_klienta) {
Optional<Klienci> optional = klienciRepository.findById(id_klienta);
Klienci klienci = null;
if(optional.isPresent()){
klienci = optional.get();
}else{
throw new RuntimeException("Klient nie znaleziony po id :: "+ id_klienta);
}
return klienci;
}
#Override
public void usunKlientaById(Integer id_klienta){
this.klienciRepository.deleteById(id_klienta);
}
#Override
public Page<Klienci> findPaginated(int pageNo, int pageSize) {
Pageable pageable = PageRequest.of(pageNo - 1,pageSize);
return this.klienciRepository.findAll(pageable);
}
}
And i also include you controler here what i use to dispaly things on pages in my application
//klient wyświetlanie listy klientów
#Autowired
public KlienciService klienciService;
#GetMapping("/klient_baza")
public String getKlient_baza(Model model){
model.addAttribute("listaKlientow",klienciService.getAllKlieci());
return findPaginated(1, model);
}
//Dodawanie klientów do bazy danych
#GetMapping("/klient_dodaj")
public String getKlient_dodaj(Model model){
Klienci klienci = new Klienci();
model.addAttribute("klienci",klienci);
return "/klient/klient_dodaj";
}
//zapisywanie klientów do bazy danych
#PostMapping("/klientZapisz")
public String saveKlient(#ModelAttribute("klienci") Klienci klienci, Model model){
klienciService.saveKlienci(klienci);
model.addAttribute("typ", "dodanie_rekordu");
model.addAttribute("sukces", "Pomyślnie dodano klienta");
return getKlient_baza(model);
}
//strona z edytowaniem klienta
#GetMapping("/klient_dodaj/{id_klienta}")
public String showFormForUpdate(#PathVariable(value = "id_klienta") Integer id_klienta, Model model) {
Klienci klienci = klienciService.getKlienciById(id_klienta);
model.addAttribute("klienci", klienci);
model.addAttribute("edycja", "true");
return "/klient/klient_dodaj";
}
//usuwanie klienta z bazy danych
#GetMapping("/usun_klienta/{id_klienta}")
public String usunKlienta(#PathVariable(value = "id_klienta")Integer id_klienta, Model model){
model.addAttribute("typ","usuniecie_rekordu");
model.addAttribute("sukces","Pomyślnie usunięto klienta");
this.klienciService.usunKlientaById(id_klienta);
return getKlient_baza(model);
}
//podział na strony
#GetMapping("/klient_baza/{pageNo}")
public String findPaginated(#PathVariable(value = "pageNo")int pageNo, Model model){
int pageSize = 10;
Page<Klienci> page = klienciService.findPaginated(pageNo,pageSize);
List<Klienci> klienciList = page.getContent();
model.addAttribute("aktualnaStrona", pageNo);
model.addAttribute("wszystkieStrony", page.getTotalPages());
model.addAttribute("total", page.getTotalElements());
model.addAttribute("listaKlientow", klienciList);
return "/klient/klient_baza";
}
How to add here QUERY METHOD do display only this clients where name is "Patryk" using #Query?
You don't really need to use a method annotated with #Query. Spring Data is "smart" enough to generate a query based on the model properties. You can just add a method declaration to your KlienciRepository interface:
List<Klienci> listKlienciByNazwiskoKlienta(String name);
Spring data will look into the Klienci model for a property called nazwiskoKlienta and build a query that does an equality check using the value passed in. If you wanted to do a wildcard query, Spring data can handle that automatically too:
List<Klienci> listKlienciByNazwiskoKlientaContaing(String name);
Put this code inside in your repository
#Repository
public interface KlienciRepository extends JpaRepository<Klienci, Integer> {
List<Klienci> findByimieKlientaIgnoreCase(String firstName);
}
Why not to use the power of Spring Data in its whole extension??
public interface KlienciRepository extends JpaRepository<Klienci, Integer> {
Klienci findByImieKlienta (String imieKlienta);
}
and later you can call this method with the String you want, in this case "Patryk".
#Repository
public interface KlienciRepository extends JpaRepository<Klienci, Integer> {
#Query(SELECT * from klienci k where k.imieKlienta like "?1%")
List<klienci> findbyfirstname(String firstname);
}
package figura.zaklad_fryzjerski_v3.repository;
import figura.zaklad_fryzjerski_v3.model.Klienci;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
#Repository
public interface KlienciRepository extends JpaRepository<Klienci, Integer> {
#Query(value="SELECT * FROM klienci WHERE imie=?1",nativeQuery = true)
public List<Klienci> getClientsByName(String clientName);
}
I'm trying to post body in RESTAPI using spring boot but I cannot. I suffered for long hours till now I also could not find the problem why what is the reason I do not know what mistake I made please help me.
Pojo class
Person.java
package com.thila.family.test;
import javax.annotation.Generated;
import javax.persistence.Entity;
import javax.persistence.Id;
#Entity
public class Person {
#Id
private int id;
private String familyName;
private String familyMembers;
private long contactNo;
public Person() {
}
public Person(int id,String familyName, String familyMembers,long contactNo) {
super();
this.familyName = familyName;
this.familyMembers = familyMembers;
this.contactNo = contactNo;
}
//getters setters
}
PersonService.java
package com.thila.family.test;
import java.util.ArrayList;
import java.util.List;
import org.springframework.stereotype.Service;
#Service
public class PersonService {
private List<Person> persons=new ArrayList<>();
public void addPerson(Person person) {
persons.add(person);
}
}
PersonController.java
#RestController
public class PersonController {
#Autowired
private PersonService personService;
#RequestMapping(method=RequestMethod.POST,value="/fam")
public void addPerson(#RequestBody Person person){
personService.addPerson(person);
}
}
My JSON request to the body
{
"id":"1",
"familyName": "panchala",
"familyMembers":"5",
"contactNo":"234567"
}
I got an error
{
"timestamp": "2021-01-02T04:39:55.307+00:00",
"status": 404,
"error": "Not Found",
"message": "",
"path": "/fam"
}
```
please help me I don't know why I got this error
In PersonController.java add the following annotation just below the #RestController annotation:
#RequestMapping(value = "/person", produces = MediaType.APPLICATION_JSON_VALUE)
Only if this is present the controller gets resolved and the path reaches the particular controller method you are trying to call.
Now your URL might look like this : localhost:8080/person/fam
In the Controller class
#RequestMapping(value = "/fam", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
public void addPerson(#RequestBody Person person){
{
....
}
Just a suggestion it would be also good to return a response with a correct Response status
#RequestMapping(value = "/fam", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity addPerson(#RequestBody Person person){
{
......
return new ResponseEntity<>(HttpStatus.OK);
}
I had the same issue and I was not figuring out how to solve it, but I decided to see my imports, in case of imports being wrong.
I was importing #RequestBody from:
io.swagger.v3.oas.annotations.parameters.RequestBody;
Instead of importing the #RequestBody from:
org.springframework.web.bind.annotation.*
If any question, just comment.
I can't make spring serialize the response when results is array/list .
So when I call clients from RestController it does return [{},{},{}], instead of real objects, all other methods works just fine.
package com.test.Domain.Client;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import java.util.UUID;
#Entity
#Table(name = "client")
public class Client {
#Column(name = "client_id")
#Id
private UUID clientId;
#Column(name = "name")
private String name;
private Client() {
}
private Client(UUID clientId, String name) {
this.clientId = clientId;
this.name = name;
}
public static Client create(String name)
{
return new Client(UUID.randomUUID(), name);
}
}
package com.test.Rest;
import com.test.Domain.Calendar.AppointmentRepository;
import com.test.Domain.Client.Client;
import com.test.Domain.Client.ClientRepository;
import com.test.Domain.Worker.WorkerRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
#org.springframework.web.bind.annotation.RestController
public class RestController {
#Autowired
private ClientRepository clientRepository;
#Autowired
private WorkerRepository workerRepository;
#Autowired
private AppointmentRepository appointmentRepository;
#RequestMapping(path = "/client", method = RequestMethod.POST)
public void registerClient(#RequestParam(name = "name") String name) {
this.clientRepository.save(Client.create(name));
}
#RequestMapping(path = "/clientCount", method = RequestMethod.GET)
public Long countClient() {
return this.clientRepository.count();
}
#RequestMapping(path = "/clients", method = RequestMethod.GET)
#ResponseBody
public List<Client> clients() {
List<Client> list = new ArrayList<Client>();
for (Client client : this.clientRepository.findAll()) {
list.add(client);
}
return list;
}
}
Jackson needs Getter and Setter methods in order to serialize the Client object properly into JSON. Therefore a list of empty objects is returned and the values for the members are missing. Add them to Client and the response should look fine.
Spring applies first registered applicable by response mime-type HttpMessageConverter implementation when serializing the response to /clients call. In your case this is some JSON serializer. As you have no JSON configuration specified on Client class the default POJO serializing approach is used: reflection scanning of object properties. As mentioned earlier your Client class doesn't define any properties (at least getters), so serializer do not detect any.
Please refer to the following article for a more detailed explanation: https://www.javacodegeeks.com/2013/07/spring-mvc-requestbody-and-responsebody-demystified.html
P.S. Marking method with #ResponseBody in #RestController annotated class is not necessary as itself is a convenience annotation aggregating #Controller and #ResponseBody.
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 7 years ago.
Improve this question
After implementing about 20 rest controllers & services, I found myself that A LOT of my code was repeated, so I came up with this contraption.
CrudController.java
package app.controllers;
import org.springframework.data.repository.CrudRepository;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import app.models.Model;
import app.services.CrudService;
#RestController
public abstract class CrudController<M extends Model, S extends CrudService<M, ? extends CrudRepository<M,Long>>> {
S service;
public abstract void setService(S service);
public abstract Boolean isAuthorized(Long entityId, S service);
#RequestMapping(value="/create", method = RequestMethod.POST)
public M create(M object) {
if(isAuthorized(object.getId(), service)) {
return service.save(object);
}
logUnauthorizedAccess();
return null;
}
#RequestMapping(value="/update", method = RequestMethod.POST)
public M update(M object) {
if(isAuthorized(object.getId(), service)) {
return service.update(object);
}
logUnauthorizedAccess();
return null;
}
#RequestMapping(value="/delete", method = RequestMethod.POST)
public Boolean delete(Long id) {
if(isAuthorized(id, service)) {
return service.delete(id);
}
logUnauthorizedAccess();
return null;
}
#RequestMapping(value="/get", method = RequestMethod.GET)
public #ResponseBody M get(Long id) {
if(isAuthorized(id, service)) {
return service.get(id);
}
logUnauthorizedAccess();
return null;
}
#RequestMapping(value="/json", method = RequestMethod.GET)
public #ResponseBody Iterable<M> json(ModelMap map) {
return service.getAll();
}
private void logUnauthorizedAccess() {
System.out.println("!!UN-AUTHORIZED ACCESS DETECTED!!");
}
}
CrudService.java
package app.services;
import org.springframework.data.repository.CrudRepository;
public abstract class CrudService<M extends app.models.Model, R extends CrudRepository<M, Long>> {
R repo;
public abstract void setRepo(R repo);
/**
* Define the parameters that you want to save to the DB when calling the update() method
* #param from source object
* #param to DB object that gets saves, "return to" in this method
* #return
*/
public abstract M copy(M from, M to);
public Iterable<M> getAll() {
return this.repo.findAll();
}
/**
* Mainly used to create a new entity
* however, can also be used to save something without using the
* update() method.
* #param model
* #return saved entity model
*/
public M save(M model) {
return this.repo.save(model);
}
public M get(Long id) {
return this.repo.findOne(id);
}
public M update(M model) {
M updated = this.repo.findOne(model.getId());
updated = copy(model, updated);
return this.repo.save(updated);
}
public Boolean delete(Long id) {
this.repo.delete(id);
return true;
}
}
Model.java
package app.models;
import java.sql.Timestamp;
import java.util.Date;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import javax.persistence.PrePersist;
import javax.persistence.Version;
#MappedSuperclass
public abstract class Model {
#GeneratedValue
#Id
private Long id;
private Date dateCreated;
#Version
private Timestamp dateModified;
#PrePersist
void createdAt() {
this.setDateCreated(new Date());
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Date getDateCreated() {
return dateCreated;
}
public void setDateCreated(Date dateCreated) {
this.dateCreated = dateCreated;
}
public Timestamp getDateModified() {
return dateModified;
}
public void setDateModified(Timestamp dateModified) {
this.dateModified = dateModified;
}
}
Now all my controllers look like the following while giving me.
/create /get /update /delete /json
package app.controllers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import app.models.Sample;
import app.services.SampleService;
#RestController
#RequestMapping("/sample")
public class SampleController extends CrudController<Sample, SampleService> {
#Autowired
#Override
public void setService(SampleService service) {
this.service = service;
}
#Override
public Boolean isAuthorized(Long entityId, SampleService service) {
return true;
}
}
https://github.com/ddalcu/spring-starter/commit/27fb2a0719c4780d7cf648852d93b8fd3d8759c8
What do you guys think , good bad , better way to do it ?
You should have a look at Spring Data REST.
Spring is able to handle generics:
You dont really need to subclass the CrudController for each Model As long as the implementation inside does not change.
You can work with one controller that uses a PathVariable for the class for example.
Then you have the same possibility with the CrudService and Dao too.
If you see now that for some entities you need special treatment within this controller (or service, dao) you have at least two ways that I know of:
create a complete new route for this entity type with controller, service and dao.
do not simply use the crudservice inside the crudcontroller but autowire a list (or map) and lookup the correct service to continue the route.
This forking in the second or third layer depends mostly on where you need to have special possibilities.
I have seen both approaches and currently i use a mix of this myself in spring projects.
As the dispatcher servlet is ordering requestmappings according to how many variables you have it is easy to create a more concrete mapping by simply hardcode the part with the pathvariable for a specialised controller.