Spring Boot full REST CRUD example - spring

Does anyone have a full spring boot REST CRUD example? The spring.io site just has a RequestMapping for GET. I'm able to get POST and DELETE working but not PUT.
I suspect it's how I'm trying to get the params where the disconnect is, but I have not seen an example where someone is performing an update.
I'm currently using the SO iPhone app so I can't paste my current code. Any working examples would be great!

As you can see I have implemented two way to update.
The first one will receive a json, and the second one will receive the cusotmerId in the URL and json also.
#RestController
#RequestMapping("/customer")
public class CustomerController {
#RequestMapping(value = "/{id}", method = RequestMethod.GET)
public Customer greetings(#PathVariable("id") Long id) {
Customer customer = new Customer();
customer.setName("Eddu");
customer.setLastname("Melendez");
return customer;
}
#RequestMapping(value = "/", method = RequestMethod.GET)
public List<Customer> list() {
return Collections.emptyList();
}
#RequestMapping(method = RequestMethod.POST)
public void add(#RequestBody Customer customer) {
}
#RequestMapping(method = RequestMethod.PUT)
public void update(#RequestBody Customer customer) {
}
#RequestMapping(value = "/{id}", method = RequestMethod.PUT)
public void updateById(#PathVariable("id") Long id, #RequestBody Customer customer) {
}
#RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
public void delete() {
}
class Customer implements Serializable {
private String name;
private String lastname;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void setLastname(String lastname) {
this.lastname = lastname;
}
public String getLastname() {
return lastname;
}
}
}

An alternative update returns ResponseEntity object.
#RestController
#RequestMapping("/fruits")
public class FruitController {
private final Logger LOG = LoggerFactory.getLogger(FruitController.class);
#Autowired
private FruitService fruitService;
#RequestMapping(method = RequestMethod.GET)
public ResponseEntity<List<Fruit>> getAll(#RequestParam(value = "offset", defaultValue = "0") int index,
#RequestParam(value = "numberOfRecord", defaultValue = "10") int numberOfRecord) {
LOG.info("Getting all fruits with index: {}, and count: {}", index, numberOfRecord);
List<Fruit> fruits = fruitService.getAll(index, numberOfRecord);
if (fruits == null || fruits.isEmpty()) {
return new ResponseEntity<List<Fruit>>(HttpStatus.NO_CONTENT);
}
return new ResponseEntity<List<Fruit>>(fruits, HttpStatus.OK);
}
#RequestMapping(value = "{id}", method = RequestMethod.GET)
public ResponseEntity<Fruit> get(#PathVariable("id") int id) {
LOG.info("Getting fruit with id: {}", id);
Fruit fruit = fruitService.findById(id);
if (fruit == null) {
return new ResponseEntity<Fruit>(HttpStatus.NOT_FOUND);
}
return new ResponseEntity<Fruit>(fruit, HttpStatus.OK);
}
#RequestMapping(method = RequestMethod.POST)
public ResponseEntity<Void> create(#RequestBody Fruit fruit, UriComponentsBuilder ucBuilder) {
LOG.info("Creating fruit: {}", fruit);
if (fruitService.exists(fruit)) {
return new ResponseEntity<Void>(HttpStatus.CONFLICT);
}
fruitService.create(fruit);
HttpHeaders headers = new HttpHeaders();
headers.setLocation(ucBuilder.path("/fruit/{id}").buildAndExpand(fruit.getId()).toUri());
return new ResponseEntity<Void>(headers, HttpStatus.CREATED);
}
#RequestMapping(value = "{id}", method = RequestMethod.PUT)
public ResponseEntity<Fruit> update(#PathVariable int id, #RequestBody Fruit fruit) {
LOG.info("Updating fruit: {}", fruit);
Fruit currentFruit = fruitService.findById(id);
if (currentFruit == null) {
return new ResponseEntity<Fruit>(HttpStatus.NOT_FOUND);
}
currentFruit.setId(fruit.getId());
currentFruit.setName(fruit.getName());
fruitService.update(fruit);
return new ResponseEntity<Fruit>(currentFruit, HttpStatus.OK);
}
#RequestMapping(value = "{id}", method = RequestMethod.DELETE)
public ResponseEntity<Void> delete(#PathVariable("id") int id) {
LOG.info("Deleting fruit with id: {}", id);
Fruit fruit = fruitService.findById(id);
if (fruit == null) {
return new ResponseEntity<Void>(HttpStatus.NOT_FOUND);
}
fruitService.delete(id);
return new ResponseEntity<Void>(HttpStatus.OK);
}
}
From Spring MVC RESTFul Web Service CRUD Example

I have prepared a set of tutorials on Spring Boot CRUD Operations. Following are the content of tutorials:
How to create Spring Boot Project using Spring Tool Suite
How to implement GET & POST method in spring boot restful web service
How to implement PUT & DELETE method in spring boot restful web service
Integrate PostgreSQL database using spring boot JPA with spring boot restful web service
Use of CURL commands
Youtube Tutorials:
Spring Boot Restful Web Service Tutorial | Tutorial 1 -
Introduction
Spring Boot Restful Web Services CRUD Example GET & POST | Tutorial - 2
Spring boot CRUD Operations example PUT & DELETE | Tutorial - 3
Spring Boot JPA | In 5 Simple Steps Integrate PostgreSQL Database | Tuorial - 4
Visit Blog for more details.

You can get my full RESTful server and client app using SpringBoot at Spring RESTFul Examples at github

package com.controllers;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
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.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;
import com.cats.hcm.bussinessObjects.Address;
import com.cats.hcm.bussinessObjects.Employee;
import com.cats.hcm.bussinessObjects.EmployeeBO;
import com.cats.hcm.bussinessObjects.MaritalStatus;
import com.cats.hcm.bussinessObjects.State;
import com.cats.hcm.repository.EmployeeRepositoryImpl;
import com.cats.hcm.repository.MaritalStatusRepositoryImpl;
import com.cats.hcm.repository.Repository;
import com.cats.hcm.repository.StateRepositoryImpl;
import com.cats.hcm.services.EmployeeServiceImpl;
import com.google.gson.Gson;
#Controller
#RequestMapping("/newemployee")
public class NewEmployeeController {
private static final Logger logger = LoggerFactory.getLogger(Repository.class);
#Autowired
Repository repository;
#Autowired
StateRepositoryImpl stateRepositoryImpl;
#Autowired
MaritalStatusRepositoryImpl maritalStatusRepositoryImpl;
#Autowired
EmployeeRepositoryImpl employeeRepositoryImpl;
#Autowired
EmployeeServiceImpl employeeServiceImpl;
#RequestMapping(value="/save", method=RequestMethod.POST)
public #ResponseBody String addEmployee(#RequestBody EmployeeBO employeeBO, BindingResult bindingResult) throws SecurityException, ClassNotFoundException, IllegalArgumentException, IllegalAccessException, IOException {
logger.info("==========="+new Gson().toJson(employeeBO));
logger.info("========Employee ID========"+employeeBO.getEmployeeId());
repository.addToDataBase(employeeBO);
String msg="Success";
return msg;
}
#RequestMapping(value="/update", method=RequestMethod.POST)
public #ResponseBody String updateEmployee(#RequestBody EmployeeBO employeeBO, BindingResult bindingResult) throws SecurityException, ClassNotFoundException, IllegalArgumentException, IllegalAccessException, IOException {
logger.info("==========="+new Gson().toJson(employeeBO));
logger.info("========Employee ID========"+employeeBO.getEmployeeId());
//Deleting Existing Employee
Boolean isDeleted = employeeServiceImpl.deleteEmployeeDetails(employeeBO.getEmployeeId());
if(isDeleted) {
repository.addToDataBase(employeeBO);
}
String msg="Success";
return msg;
}
#RequestMapping("/employeeData")
public #ResponseBody List<Employee> getEmployeeDataTablePage() {
logger.info("======getEmployeeDataTablePage======");
List<Employee> employeeList = employeeRepositoryImpl.readAll();
logger.info("========EmployeeList========="+new Gson().toJson(employeeList));
return employeeList;
}
#RequestMapping("/modifyPage")
public #ResponseBody List<Employee> getEmployeeModifyPage(#RequestParam("employeeId") String employeeId) {
logger.info("========getEmployeeModifyPage====EmployeeID:===="+employeeId);
//List<State> stateList = stateRepositoryImpl.readAll();
//List<MaritalStatus> maritalStatusList = maritalStatusRepositoryImpl.readAll();
//model.addAttribute("stateList", stateList);
//model.addAttribute("maritalStatusList", maritalStatusList);
List<Employee> employeeList = employeeRepositoryImpl.readAll();
logger.info("========employeeList:===="+employeeList);
EmployeeBO employeeBO = employeeServiceImpl.getEmployeeBO(employeeId);
logger.info("========getEmployeeModifyPage====EmployeeBO:===="+employeeBO);
return employeeList;
//return new ModelAndView("apps-mod-employee", "employee", employeeBO);
}
#RequestMapping("/delete")
public #ResponseBody String deleteEmployee(#RequestParam("employeeId") String employeeId) {
logger.info("========deleteEmployee===EmployeeID:===="+employeeId);
//employeeRepositoryImpl.delete(employeeServiceImpl.getEmployeeBO(employeeId));
Boolean isDeleted = employeeServiceImpl.deleteEmployeeDetails(employeeId);
if(isDeleted) {
logger.info("========Employee Record Deleted===EmployeeID:===="+employeeId);
}
return "redirect:/employee/employeeDataTable";
}
/*#RequestMapping("/employeeDataByEmpId")
public String getEmployeeAddPage(Map<String, Object> model) {
public ModelAndView getEmployeeDataByEmpId(ModelMap model,HttpServletRequest request, HttpServletResponse response) {
logger.info("======getEmployeeDataByEmpId======");
String EmployeeID=request.getParameter("empId");
Employee employee = employeeRepositoryImpl.read(EmployeeID);
logger.info("========Employee========="+new Gson().toJson(employee));
model.addAttribute(new EmployeeBO());
model.addAttribute("employeeByEmpId", employee);
//return "apps-add-employee";
//return new ModelAndView("apps-add-employee");
return new ModelAndView("apps-employee", "employee", new EmployeeBO());
}*/
}

Related

How to see result of Flux<Object> in Postman?

I mimic tutorial at https://howtodoinjava.com/spring-webflux/spring-webflux-tutorial/ . My MongoDB (My version https://fastdl.mongodb.org/windows/mongodb-windows-x86_64-5.0.5-signed.msi). Postman v9.8.0 , Windows 10 x64.
My controller
package com.howtodoinjava.demo.controller;
import com.howtodoinjava.demo.model.Employee;
import com.howtodoinjava.demo.service.EmployeeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.time.Duration;
#RestController
public class EmployeeController {
#Autowired
private EmployeeService employeeService;
#RequestMapping(value = {"/create", "/"}, method = RequestMethod.POST)
#ResponseStatus(HttpStatus.CREATED)
#ResponseBody
public void create(#RequestBody Employee e) {
employeeService.create(e);
}
#RequestMapping(value = "/{id}", method = RequestMethod.GET)
#ResponseBody
public ResponseEntity<Mono<Employee>> findById(#PathVariable("id") Integer id) {
Mono<Employee> e = employeeService.findById(id);
HttpStatus status = e != null ? HttpStatus.OK : HttpStatus.NOT_FOUND;
return new ResponseEntity<Mono<Employee>>(e, status);
}
#RequestMapping(value = "/name/{name}", method = RequestMethod.GET)
#ResponseBody
public Flux<Employee> findByName(#PathVariable("name") String name) {
return employeeService.findByName(name);
}
#RequestMapping(method = RequestMethod.GET, produces = MediaType.TEXT_EVENT_STREAM_VALUE)
#ResponseBody
public Flux<Employee> findAll() {
// Flux<Employee> emps = employeeService.findAll();
Flux<Employee> emps = employeeService.findAll().log().delayElements(Duration.ofSeconds(1));
emps.subscribe();
return emps;
}
#RequestMapping(value = "/update", method = RequestMethod.PUT)
#ResponseStatus(HttpStatus.OK)
public Mono<Employee> update(#RequestBody Employee e) {
return employeeService.update(e);
}
#RequestMapping(value = "/delete/{id}", method = RequestMethod.DELETE)
#ResponseStatus(HttpStatus.OK)
public void delete(#PathVariable("id") Integer id) {
employeeService.delete(id).subscribe();
}
}
In debug console, I see the result
The reason why the responses are empty is that no getter methods are defined in the Employee entity class. Adding the following should make it work:
public int getId() {
return id;
}
public String getName() {
return name;
}
public long getSalary() {
return salary;
}
As a side note, consider mapping your entities into EmployeeDTO instances.

Sprint boot - Auto configure to call a REST service on startup

I have a requirement to create an auto-configuration for service call on spring-boot startup.
i.e., During spring-boot startup, the below service has to be called.
#PostMapping(path = "/addProduct", produces = "application/json", consumes = "application/json")
public #ResponseBody String addProduct(#RequestBody String productStr) {
..<My code>..
}
The add product requires an input like:
{
"product":"test",
"price":"10"
}
This will internally call a database service.
During startup, the json input provided in the console should be fed to this service.
I have no idea on how to achieve this. Verified a couple of Spring documentation. But those does'nt suit the requirement.
Kindly help in explaining a way or providing a right documentation to achieve this.
One way to do this is by implementing ApplicationRunner like this :
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
#Component
public class ApplicationInitializer implements ApplicationRunner {
private ProductController productController;
public ApplicationInitializer(ProductController productController) {
this.productController = productController;
}
#Override
public void run(ApplicationArguments args) throws Exception {
String productArg = args.getOptionValues("product").get(0); // Assume that you will have only one product argument
ObjectMapper mapper = new ObjectMapper();
Product product = mapper.readValue(productArg, Product.class);
String response = productController.add(product);
System.out.println(response);
}
}
The run method will be invoked at startup with arguments passed in the command line like this : java -jar yourApp.jar --product="{\"name\":\"test\", \"price\":\"15\"}".
And you need a class to map the json to an object like this :
public class Product {
private String name;
private int price;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
}
You can also call your Controller using the RestTemplate (or WebClient) if needed :
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
#Component
public class ApplicationInitializer implements ApplicationRunner {
#Override
public void run(ApplicationArguments args) throws Exception {
String productArg = args.getOptionValues("product").get(0); // Assume that you will have only one product argument
ObjectMapper mapper = new ObjectMapper();
Product product = mapper.readValue(productArg, Product.class);
RestTemplate restTemplate = new RestTemplate();
String response = restTemplate.postForObject("http://localhost:8080/products", product, String.class);
System.out.println(response);
}
}
Such requirement can be achieved by using an init() method annotated with #PostConstruct in a bean.
e.g.
#Component
public class Foo {
#PostConstruct
public void init() {
//Call your service
}
}

Spring MVC to REST

I have a Spring MVC aplication. I want to convert it to a RESTful
webservice, which returns a JSON response. Can somebody help me with this??
Basically, I want to convert my controller to a REST controller.
My Code :
///////////////////////////PersonController//////////////////////////////
package com.journaldev.spring;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
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 com.journaldev.spring.model.Person;
import com.journaldev.spring.service.PersonService;
#Controller
public class PersonController {
private PersonService personService;
#Autowired(required=true)
#Qualifier(value="personService")
public void setPersonService(PersonService ps){
this.personService = ps;
}
#RequestMapping(value = "/persons", method = RequestMethod.GET)
public String listPersons(Model model) {
model.addAttribute("person", new Person());
model.addAttribute("listPersons", this.personService.listPersons());
return "person";
}
//For add and update person both
#RequestMapping(value= "/person/add", method = RequestMethod.POST)
public String addPerson(#ModelAttribute("person") Person p){
if(p.getId() == 0){
//new person, add it
this.personService.addPerson(p);
}else{
//existing person, call update
this.personService.updatePerson(p);
}
return "redirect:/persons";
}
#RequestMapping("/remove/{id}")
public String removePerson(#PathVariable("id") int id){
this.personService.removePerson(id);
return "redirect:/persons";
}
#RequestMapping("/edit/{id}")
public String editPerson(#PathVariable("id") int id, Model model){
model.addAttribute("person", this.personService.getPersonById(id));
model.addAttribute("listPersons", this.personService.listPersons());
return "person";
}
}
/////////////////////////////////PersonDAO/////////////////////////////
package com.journaldev.spring.dao;
import java.util.List;
import com.journaldev.spring.model.Person;
public interface PersonDAO {
public void addPerson(Person p);
public void updatePerson(Person p);
public List<Person> listPersons();
public Person getPersonById(int id);
public void removePerson(int id);
}
///////////////////////////////PersonDAOImpl/////////////////////////
package com.journaldev.spring.dao;
import java.util.List;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Repository;
import com.journaldev.spring.model.Person;
#Repository
public class PersonDAOImpl implements PersonDAO {
private static final Logger logger = LoggerFactory.getLogger(PersonDAOImpl.class);
private SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sf){
this.sessionFactory = sf;
}
#Override
public void addPerson(Person p) {
Session session = this.sessionFactory.getCurrentSession();
session.persist(p);
logger.info("Person saved successfully, Person Details="+p);
}
#Override
public void updatePerson(Person p) {
Session session = this.sessionFactory.getCurrentSession();
session.update(p);
logger.info("Person updated successfully, Person Details="+p);
}
#SuppressWarnings("unchecked")
#Override
public List<Person> listPersons() {
Session session = this.sessionFactory.getCurrentSession();
List<Person> personsList = session.createQuery("from Person").list();
for(Person p : personsList){
logger.info("Person List::"+p);
}
return personsList;
}
#Override
public Person getPersonById(int id) {
Session session = this.sessionFactory.getCurrentSession();
Person p = (Person) session.load(Person.class, new Integer(id));
logger.info("Person loaded successfully, Person details="+p);
return p;
}
#Override
public void removePerson(int id) {
Session session = this.sessionFactory.getCurrentSession();
Person p = (Person) session.load(Person.class, new Integer(id));
if(null != p){
session.delete(p);
}
logger.info("Person deleted successfully, person details="+p);
}
}
//////////////////////////////////Person(Model)///////////////////////
package com.journaldev.spring.model;
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 bean with JPA annotations
* Hibernate provides JPA implementation
* #author pankaj
*
*/
#Entity
#Table(name="PERSON")
public class Person {
#Id
#Column(name="id")
#GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
private String name;
private String country;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
#Override
public String toString(){
return "id="+id+", name="+name+", country="+country;
}
}
///////////////////////////////////PersonService///////////////////
package com.journaldev.spring.service;
import java.util.List;
import com.journaldev.spring.model.Person;
public interface PersonService {
public void addPerson(Person p);
public void updatePerson(Person p);
public List<Person> listPersons();
public Person getPersonById(int id);
public void removePerson(int id);
}
//////////////////////////////ServiceImpl////////////////////////////
package com.journaldev.spring.service;
import java.util.List;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.journaldev.spring.dao.PersonDAO;
import com.journaldev.spring.model.Person;
#Service
public class PersonServiceImpl implements PersonService {
private PersonDAO personDAO;
public void setPersonDAO(PersonDAO personDAO) {
this.personDAO = personDAO;
}
#Override
#Transactional
public void addPerson(Person p) {
this.personDAO.addPerson(p);
}
#Override
#Transactional
public void updatePerson(Person p) {
this.personDAO.updatePerson(p);
}
#Override
#Transactional
public List<Person> listPersons() {
return this.personDAO.listPersons();
}
#Override
#Transactional
public Person getPersonById(int id) {
return this.personDAO.getPersonById(id);
}
#Override
#Transactional
public void removePerson(int id) {
this.personDAO.removePerson(id);
}
}
First you have to add Jackson Databind dependency in your pom file then you can define your rest controller for exemple :
#RestController
public class PersonRestService {
#Autowired
private PersonService personService ;
#RequestMapping(value="/persons",method=RequestMethod.POST)
public Person addPerson(#RequestBody Person Person) {
return personService.addPerson(Person);
}
#RequestMapping(value="/persons",method=RequestMethod.Delete)
public void deletePerson(int code) {
personService.deletePerson(code);
}
#RequestMapping(value="/persons",method=RequestMethod.GET)
public Person getPerson(#RequestParam int code) {
return personService.getPersonById(code);
}
#RequestMapping(value="/allPersons",method=RequestMethod.GET)
public List<Person> getAllPerson() {
return personService.getAllPerson();
}
}
Its easy, what you need to do is add a response in JSON for all request which need it.
The annotation is #ResponseBody and you can return any object, jackson will serialize it to json format for you.
For example in your code:
#RequestMapping("/remove/{id}")
#ResponseBody
public boolean removePerson(#PathVariable("id") int id){
this.personService.removePerson(id);
//true if everything was OK, false if some exception
return true;
}
...
#RequestMapping(value = "/persons", method = RequestMethod.GET)
#ResponseBody
public List<Person> listPersons(Model model) {
return this.personService.listPersons();
}
You only need to modify your controller, to make it RESTFul
Also you will have to add logic to your JS code to handle the new responses values.
Simply use the annotation #RestController.
You can also refer to previously asked question on this link
Difference between spring #Controller and #RestController annotation

Not supported for DML operations .Unable to update data in postgresql database using spring data

Hi I am using spring boot and Spring data i want to fetch data from database on the basis of id but m not able to retreive it.
M getting this error "exception":
"org.springframework.dao.InvalidDataAccessApiUsageException",
"message": "org.hibernate.hql.internal.QueryExecutionRequestException:
Not supported for DML operations [Update
com.ge.health.poc.model.SpringModel SET name='sneha' where id=?];
nested exception is java.lang.IllegalStateException:
org.hibernate.hql.internal.QueryExecutionRequestException: Not
supported for DML operations [Update
com.ge.health.poc.model.SpringModel SET name='sneha' where id=?]",
"path": "/updatedata"
}
Main Class
package com.ge.health.poc;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class SpringDataApplication {
public static void main(String[] args) {
SpringApplication.run(SpringDataApplication.class, args);
}
}
Controller Class
package com.ge.health.poc.controller;
import java.io.IOException;
import java.text.ParseException;
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.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ge.health.poc.model.SpringModel;
import com.ge.health.poc.service.BookServiceImpl;
#RestController
public class SpringController {
#Autowired
BookServiceImpl bookserviceimpl;
#RequestMapping(value = "/insertdata", method = RequestMethod.POST)
#ResponseBody
public void helloService(#RequestBody String input, final RedirectAttributes redirectAttributes)
throws JsonParseException, JsonMappingException, IOException, ParseException {
System.out.println(input);
ObjectMapper mapper = new ObjectMapper();
SpringModel pojodata = mapper.readValue(input, SpringModel.class);
System.out.println(pojodata);
System.out.println(pojodata.getAuthor());
bookserviceimpl.save(pojodata);
}
#RequestMapping(value = "/getdata/{id}")
#ResponseBody
public void retreiveData(#PathVariable("id") int id)
throws JsonParseException, JsonMappingException, IOException, ParseException {
System.out.println("id is:" + id);
bookserviceimpl.retreive(id);
}
#RequestMapping(value = "/deletedata", method = RequestMethod.DELETE)
#ResponseBody
public void deleteData(#RequestBody String id)
throws JsonParseException, JsonMappingException, IOException, ParseException {
System.out.println("M in delete");
System.out.println(id);
ObjectMapper mapper = new ObjectMapper();
SpringModel pojodata = mapper.readValue(id, SpringModel.class);
int idd = (pojodata.getId());
System.out.println("value oof idd is:" + idd);
System.out.println("M into delete method");
bookserviceimpl.delete(idd);
}
#RequestMapping(value = "/updatedata", method = RequestMethod.PUT)
#ResponseBody
public void updateData(#RequestBody String id)
throws JsonParseException, JsonMappingException, IOException, ParseException {
System.out.println("M in update");
System.out.println(id);
ObjectMapper mapper = new ObjectMapper();
SpringModel pojodata = mapper.readValue(id, SpringModel.class);
int idd = (pojodata.getId());
System.out.println("value oof idd is:" + idd);
bookserviceimpl.update(idd);
}
}
Repository
package com.ge.health.poc.interfac;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import com.ge.health.poc.model.SpringModel;
#Repository
#Transactional
public interface BookRepository extends JpaRepository<SpringModel, Long> {
#Query("select author from SpringModel where id=?")
String findName(int id);
#Query("Update SpringModel SET name='sneha' where id=?")
String UpdateByID(int id);
#Query("delete from SpringModel where id=?")
String deleteById(int id);
}
BookServiceImpl.java
package com.ge.health.poc.service;
import javax.persistence.EntityManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.ge.health.poc.interfac.BookRepository;
import com.ge.health.poc.model.SpringModel;
#Component
public class BookServiceImpl implements BookService {
#Autowired
EntityManager entitymanager;
#Autowired
BookRepository bookrepo;
#Override
public void save(SpringModel bookdata) {
bookrepo.save(bookdata);
}
public String retreive(int id) {
String s = bookrepo.findName(id);
System.out.println("Author name is:" + s);
return null;
}
public void delete(int id) {
System.out.println("M into service delete method");
bookrepo.deleteById(id);
}
public void update(int id) {
System.out.println("M in service update");
bookrepo.UpdateByID(id);
}
}
this is model class
package com.ge.health.poc.model;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
#Entity
#Table(name = "spring_model")
public class SpringModel {
#Id
private Long id;
#Column
private String name;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#Column
private String isbn;
#Override
public String toString() {
return "SpringModel [id=" + id + ", name=" + name + ", isbn=" + isbn + ", author=" + author + ", pages=" + pages
+ "]";
}
#Column
private String author;
#Column
private String pages;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getIsbn() {
return isbn;
}
public void setIsbn(String isbn) {
this.isbn = isbn;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public String getPages() {
return pages;
}
public void setPages(String pages) {
this.pages = pages;
}
}
Try the annotation #Modifying(org.springframework.data.jpa.repository.Modifying) on the repository methods and #Transactional(org.springframework.transaction.annotation.Transactional) in service implementation which does DML operation. please refer this answer for more information.
By Default spring jpa will think query is select query.So, To make sure the query is updating the existed row for a particular entity
add #modifying Annotation on the method which is updating the existed row
This might works for you

Using Spring MVC Test to unit test multipart POST request

I have the following request handler for saving autos. I have verified that this works when I use e.g. cURL. Now I want to unit test the method with Spring MVC Test. I have tried to use the fileUploader, but I am not managing to get it working. Nor do I manage to add the JSON part.
How would I unit test this method with Spring MVC Test? I am not able to find any examples on this.
#RequestMapping(value = "autos", method = RequestMethod.POST)
public ResponseEntity saveAuto(
#RequestPart(value = "data") autoResource,
#RequestParam(value = "files[]", required = false) List<MultipartFile> files) {
// ...
}
I want to uplod a JSON representation for my auto + one or more files.
I will add 100 in bounty to the correct answer!
Since MockMvcRequestBuilders#fileUpload is deprecated, you'll want to use MockMvcRequestBuilders#multipart(String, Object...) which returns a MockMultipartHttpServletRequestBuilder. Then chain a bunch of file(MockMultipartFile) calls.
Here's a working example. Given a #Controller
#Controller
public class NewController {
#RequestMapping(value = "/upload", method = RequestMethod.POST)
#ResponseBody
public String saveAuto(
#RequestPart(value = "json") JsonPojo pojo,
#RequestParam(value = "some-random") String random,
#RequestParam(value = "data", required = false) List<MultipartFile> files) {
System.out.println(random);
System.out.println(pojo.getJson());
for (MultipartFile file : files) {
System.out.println(file.getOriginalFilename());
}
return "success";
}
static class JsonPojo {
private String json;
public String getJson() {
return json;
}
public void setJson(String json) {
this.json = json;
}
}
}
and a unit test
#WebAppConfiguration
#ContextConfiguration(classes = WebConfig.class)
#RunWith(SpringJUnit4ClassRunner.class)
public class Example {
#Autowired
private WebApplicationContext webApplicationContext;
#Test
public void test() throws Exception {
MockMultipartFile firstFile = new MockMultipartFile("data", "filename.txt", "text/plain", "some xml".getBytes());
MockMultipartFile secondFile = new MockMultipartFile("data", "other-file-name.data", "text/plain", "some other type".getBytes());
MockMultipartFile jsonFile = new MockMultipartFile("json", "", "application/json", "{\"json\": \"someValue\"}".getBytes());
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
mockMvc.perform(MockMvcRequestBuilders.multipart("/upload")
.file(firstFile)
.file(secondFile)
.file(jsonFile)
.param("some-random", "4"))
.andExpect(status().is(200))
.andExpect(content().string("success"));
}
}
And the #Configuration class
#Configuration
#ComponentScan({ "test.controllers" })
#EnableWebMvc
public class WebConfig extends WebMvcConfigurationSupport {
#Bean
public MultipartResolver multipartResolver() {
CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
return multipartResolver;
}
}
The test should pass and give you output of
4 // from param
someValue // from json file
filename.txt // from first file
other-file-name.data // from second file
The thing to note is that you are sending the JSON just like any other multipart file, except with a different content type.
The method MockMvcRequestBuilders.fileUpload is deprecated use MockMvcRequestBuilders.multipart instead.
This is an example:
import static org.hamcrest.CoreMatchers.containsString;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.multipart.MultipartFile;
/**
* Unit test New Controller.
*
*/
#RunWith(SpringRunner.class)
#WebMvcTest(NewController.class)
public class NewControllerTest {
private MockMvc mockMvc;
#Autowired
WebApplicationContext wContext;
#MockBean
private NewController newController;
#Before
public void setup() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(wContext)
.alwaysDo(MockMvcResultHandlers.print())
.build();
}
#Test
public void test() throws Exception {
// Mock Request
MockMultipartFile jsonFile = new MockMultipartFile("test.json", "", "application/json", "{\"key1\": \"value1\"}".getBytes());
// Mock Response
NewControllerResponseDto response = new NewControllerDto();
Mockito.when(newController.postV1(Mockito.any(Integer.class), Mockito.any(MultipartFile.class))).thenReturn(response);
mockMvc.perform(MockMvcRequestBuilders.multipart("/fileUpload")
.file("file", jsonFile.getBytes())
.characterEncoding("UTF-8"))
.andExpect(status().isOk());
}
}
Have a look at this example taken from the spring MVC showcase, this is the link to the source code:
#RunWith(SpringJUnit4ClassRunner.class)
public class FileUploadControllerTests extends AbstractContextControllerTests {
#Test
public void readString() throws Exception {
MockMultipartFile file = new MockMultipartFile("file", "orig", null, "bar".getBytes());
webAppContextSetup(this.wac).build()
.perform(fileUpload("/fileupload").file(file))
.andExpect(model().attribute("message", "File 'orig' uploaded successfully"));
}
}
Here's what worked for me, here I'm attaching a file to my EmailController under test. Also take a look at the postman screenshot on how I'm posting the data.
#WebAppConfiguration
#RunWith(SpringRunner.class)
#SpringBootTest(
classes = EmailControllerBootApplication.class
)
public class SendEmailTest {
#Autowired
private WebApplicationContext webApplicationContext;
#Test
public void testSend() throws Exception{
String jsonStr = "{\"to\": [\"email.address#domain.com\"],\"subject\": "
+ "\"CDM - Spring Boot email service with attachment\","
+ "\"body\": \"Email body will contain test results, with screenshot\"}";
Resource fileResource = new ClassPathResource(
"screen-shots/HomePage-attachment.png");
assertNotNull(fileResource);
MockMultipartFile firstFile = new MockMultipartFile(
"attachments",fileResource.getFilename(),
MediaType.MULTIPART_FORM_DATA_VALUE,
fileResource.getInputStream());
assertNotNull(firstFile);
MockMvc mockMvc = MockMvcBuilders.
webAppContextSetup(webApplicationContext).build();
mockMvc.perform(MockMvcRequestBuilders
.multipart("/api/v1/email/send")
.file(firstFile)
.param("data", jsonStr))
.andExpect(status().is(200));
}
}
If you are using Spring4/SpringBoot 1.x, then it's worth mentioning that you can add "text" (json) parts as well . This can be done via MockMvcRequestBuilders.fileUpload().file(MockMultipartFile file) (which is needed as method .multipart() is not available in this version):
#Test
public void test() throws Exception {
mockMvc.perform(
MockMvcRequestBuilders.fileUpload("/files")
// file-part
.file(makeMultipartFile( "file-part" "some/path/to/file.bin", "application/octet-stream"))
// text part
.file(makeMultipartTextPart("json-part", "{ \"foo\" : \"bar\" }", "application/json"))
.andExpect(status().isOk())));
}
private MockMultipartFile(String requestPartName, String filename,
String contentType, String pathOnClassPath) {
return new MockMultipartFile(requestPartName, filename,
contentType, readResourceFile(pathOnClasspath);
}
// make text-part using MockMultipartFile
private MockMultipartFile makeMultipartTextPart(String requestPartName,
String value, String contentType) throws Exception {
return new MockMultipartFile(requestPartName, "", contentType,
value.getBytes(Charset.forName("UTF-8")));
}
private byte[] readResourceFile(String pathOnClassPath) throws Exception {
return Files.readAllBytes(Paths.get(Thread.currentThread().getContextClassLoader()
.getResource(pathOnClassPath).toUri()));
}
}

Resources