I developed Spring Boot CRUD application. The database I have connected is PostgreSQL. #GetMapping is working properly and an empty array of objects can be retrieved by the GET request. But in #PostMapping, the POST request gives a 404 error.
đź“ŚSpringRecapApplication.java
package com.example.SpringRecap;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
import org.springframework.web.bind.annotation.*;
import java.util.List;
#RestController
#SpringBootApplication(exclude = SecurityAutoConfiguration.class)
//#RequestMapping("api/v1/customers")
//#EnableWebMvc
#RequestMapping(name = "api/v1/customers" ,method = RequestMethod.POST)
public class SpringRecapApplication {
//dependency injection
private static CustomerRepository customerRepository;
public SpringRecapApplication(CustomerRepository customerRepository) {
this.customerRepository = customerRepository;
}
public static void main(String[] args) {
SpringApplication.run(SpringRecapApplication.class, args);
}
#GetMapping
public List<Customer> getCustomer() {
return customerRepository.findAll();
}
record NewCustomerRequest(
String name,
String email,
Integer age
) {
#PostMapping
public void addCustomer(#RequestBody NewCustomerRequest newCustomerRequest) {
Customer customer = new Customer();
customer.setAge(newCustomerRequest.age());
customer.setName(newCustomerRequest.name());
customer.setEmail(newCustomerRequest.email());
customerRepository.save(customer);
}
}
}
customerRepository.save(customer); doesn't allow to make the dependency injection final. ( private static CustomerRepository customerRepository;). IDEA suggests making it static. But it didn't work. When I was using #RequestMapping("api/v1/customers"), a 405 error was received. Then I fixed that issue by doing as below,
#RequestMapping(name = "api/v1/customers" ,method = RequestMethod.POST)
đź“ŚCustomerRepository.java
package com.example.SpringRecap;
import org.springframework.data.jpa.repository.JpaRepository;
public interface CustomerRepository extends JpaRepository<Customer,Integer> {
}
đź“ŚCustomer.java
package com.example.SpringRecap;
import jakarta.persistence.*;
import java.util.Objects;
#Entity
public class Customer {
#Id
#SequenceGenerator(
name = "customer_id_sequence",
sequenceName = "customer_id_sequence",
allocationSize = 1
)
#GeneratedValue(
strategy = GenerationType.SEQUENCE,
generator = "customer_id_sequence"
)
private Integer id;
private String name;
private String email;
private Integer age;
public Customer(Integer id, String name, String email, Integer age) {
this.id = id;
this.name = name;
this.email = email;
this.age = age;
}
public Customer() {
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Customer customer = (Customer) o;
return Objects.equals(id, customer.id) && Objects.equals(name, customer.name) && Objects.equals(email, customer.email) && Objects.equals(age, customer.age);
}
#Override
public int hashCode() {
return Objects.hash(id, name, email, age);
}
#Override
public String toString() {
return "Customer{" +
"id=" + id +
", name='" + name + '\'' +
", email='" + email + '\'' +
", age=" + age +
'}';
}
}
Postman:
Please put a comment if further information is needed to get the solution.
The problem with your code is that you specified the POST endpoint as part of your DTO and not as part of your controller. As your DTO is not a Spring managed bean, Spring won't map the URL to your endpoint. Anyways, you should move your endpoints into a seperate class. Example:
#RestController
#RequestMapping("api/v1/customers")
public class CustomerController {
private final CustomerRepository customerRepository;
public SpringRecapApplication(CustomerRepository customerRepository) {
this.customerRepository = customerRepository;
}
#GetMapping
public List<Customer> getCustomer() {
return customerRepository.findAll();
}
#PostMapping
public void addCustomer(#RequestBody NewCustomerRequest newCustomerRequest) {
Customer customer = new Customer();
customer.setAge(newCustomerRequest.age());
customer.setName(newCustomerRequest.name());
customer.setEmail(newCustomerRequest.email());
customerRepository.save(customer);
}
// Helper classes
record NewCustomerRequest(String name, String email, Integer age) { }
}
It would be best if you moved your DTO in a seperate class as well. I recommend placing the DTOs in a dto package and your controllers in a controller package.
Two side notes: you shouldn't expose your entities via your API. You should use DTOs for incoming and outgoing data. Check out lombok and mapstruct, they make this pretty easy.
Related
I have two tables CustomerDetails and Product, I want to fetch customerid from customer table and add it to #joincolumn(order_id) column in same CustomerDetails table.
CustomerDetails.java
#Entity
#Table(name = "CustomerDetails")
public class CustomerDetails {
#Id
#GeneratedValue
#Column(name="CUSTOMER_ID")
private Long custid;
#Column(name="CUSTOMER_NAME")
private String customerName;
#Column(name="EMAIL")
private String email;
#Column(name="ADDRESS")
private String address;
#Column(name="PHONENO")
private String phoneno;
public CustomerDetails() {
}
#Override
public String toString() {
return "CustomerDetails [custid=" + custid + ", customername=" + customerName + ", email=" + email
+ ", address=" + address + ", phoneno=" + phoneno + "]";
}
public CustomerDetails(String customername, String email, String address, String phoneno) {
super();
this.customerName = customername;
this.email = email;
this.address = address;
this.phoneno = phoneno;
}
public Long getCustid() {
return custid;
}
public void setCustid(Long custid) {
this.custid = custid;
}
public String getName() {
return customerName;
}
public void setName(String name) {
this.customerName = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return address;
}
public void setPassword(String password) {
this.address = password;
}
public String getPhoneno() {
return phoneno;
}
public void setPhoneno(String phoneno) {
this.phoneno = phoneno;
}
}
Product.java
#Entity
#Table(name="Product")
public class Product {
#Id
#GeneratedValue
#Column(name="PRODUCT_ID")
private Long productId;
#Column(name="PRODUCT_NAME")
private String productName;
#Column(name="PRODUCT_BRAND")
private String productBrand;
#Column(name="PRODUCT_PRICE")
private double productPrice;
#OneToOne
private CustomerDetails cd;
public Product(Long productId, String productName, String productBrand, double productPrice, CustomerDetails cd) {
super();
this.productId = productId;
this.productName = productName;
this.productBrand = productBrand;
this.productPrice = productPrice;
this.cd = cd;
}
public Product(String productName, String productType, double productPrice) {
super();
this.productName = productName;
this.productBrand = productType;
this.productPrice = productPrice;
}
public Long getProductId() {
return productId;
}
public void setProductId(Long productId) {
this.productId = productId;
}
public String getProductName() {
return productName;
}
public void setProductName(String productName) {
this.productName = productName;
}
public String getProductBrand() {
return productBrand;
}
public void setProductBrand(String productType) {
this.productBrand = productType;
}
public double getProductPrice() {
return productPrice;
}
public void setProductPrice(double productPrice) {
this.productPrice = productPrice;
}
public CustomerDetails getCd() {
return cd;
}
public void setCd(CustomerDetails cd) {
this.cd = cd;
}
public Product() {
//super();
}
#Override
public String toString() {
return "Product [productId=" + productId + ", productName=" + productName + ", productType=" + productBrand
+ ", productPrice=" + productPrice + "]";
}
}
CustomerDetails repository
#Repository
public interface CdRepo extends JpaRepository<CustomerDetails, Long>
{
}
Product repository
#Repository
public interface ProductRepo extends JpaRepository<Product, Long>
{
}
CustomerService
#Service
#Transactional
public class CustomerService {
private final CdRepo cdRepo;
#Autowired
public CustomerService(CdRepo cdRepo) {
this.cdRepo = cdRepo;
}
public void saveCustomer(CustomerDetails cd)
{
cdRepo.save(cd);
}
}
controller
#RequestMapping(value = {"/addCustomerDetails"}, method = RequestMethod.POST)
public ModelAndView addCustomerDetails(CustomerDetails cd)
{
customerService.saveCustomer(cd);
System.out.println(cd.getCustid());
ModelAndView model = new ModelAndView();
model.setViewName("homepage");
return model;
}
In controller using getCustid() I'm getting current customer's id now I want to insert that id into #joinColumn(order_id)
If I've understood correctly, you want to assign a product to a user (e.g Customer).
For a #OneToOne relation you don't need private CustomerDetails cd; in product class. Although I don't know why are you implementing such thing in that way at all!
Generally If you want to assign two things together, let's say you want to assign a product to a user so that the product would be for that user, you should find the product obj from repository or any where (both product and user must have an id generated by db) and then assign it to user.product.
product service
#Service
public class ProductService {
#Autowired
private ProductRepo productRepository;
public Optional<Product> findProductById(Long id) {
return this.productRepository.findByProductId(id);
}
}
customer service
#Service
#Transactional
public class CustomerService {
private final CdRepo cdRepo;
#Autowired
public CustomerService(CdRepo cdRepo) {
this.cdRepo = cdRepo;
}
public CustomerDetails saveCustomer(CustomerDetails cd, Long productId) {
CustomerDetails dbCustomer = customerService.saveCustomer(cd);
// I'm getting the id from path variable, change it if you have other logics
Optional<Product> dbProduct = this.productService.findProductById(productId);
// I don't know how you handle run time errors so I can't write it, don't
// forget to check the dbProduct in case it didn't exist :)
// In case you did not created getters and setters in CustomerDetails,
// use dbCustomer.product = dbProduct.get();
dbCustomer.setProduct(dbProduct.get());
// update our customer using JPA, after customer update JPA handles everything
return this.cdRepo.save(dbCustomer);
}
}
controller
#RequestMapping(value = {"/addCustomerDetails/{productId}"}, method = RequestMethod.POST)
public ModelAndView addCustomerDetails(CustomerDetails cd, #PathVariable Long productId )
{
CustomerDetails dbCustomer = this.customerService.saveCustomer(cd, productId);
// Use the dbCustomer in your logic ...
ModelAndView model = new ModelAndView();
model.setViewName("homepage");
return model;
}
Write getters and setters in each entity or use Lombok annotation #Data.
Usually when I want to deploy an ecommerce with user and product. I use user, cart, product model.
The problem with the code above is that if you assign that product to a user, it's ONLY for that user. if other users want the same product you have to create all of those products for them. Solution to that would be using product as a series or a model.
Imagine a situation that you want to create a website to sell coffee packages. you only have two type of package to sell. you can create an entity like product for those packages with a quantity for each. Then create a #OneToMany relationship in your cart model to products. It will create a join table to store any possible product id there with cart id. After that, create a #ManyToOne relationship in your cart entity and #OneToMany in your user entity. Now each cart is only for a specific user and not the products.
Some Friendly Advice:
Don't populate your controller with logic. Let service layer handle it.
For each entity, create a package with the name of the entity instead and create 3 classes; the entity itself, response POJO and request POJO.
Use getters and setters for your entites. You can use lombok for that matter. It will handle the situation by generating them.
Use convertor components to create and convert requested entity to the entity itself and also convert entity to response entity.
Avoid interacting with Data base as much as you can. hold the object in a variable like dbCustomer for doing operations.
I am simply trying to create a Spring boot Hibernate CRUD REST API through this code:
EmployeController.java
#RestController
#RequestMapping("/api")
public class EmployeController {
#Autowired
private EmployeService employeService;
#GetMapping("/employe")
public List<Employe> get(){
return employeService.get();
}
}
Employe.java
#Entity
#Table(name="employe")
public class Employe {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column
private int id;
#Column
private String name;
#Column
private String gender;
#Column
private String department;
#Column
private Date dob;
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 getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public String getDepartment() {
return department;
}
public void setDepartment(String department) {
this.department = department;
}
public Date getDob() {
return dob;
}
public void setDob(Date dob) {
this.dob = dob;
}
#Override
public String toString() {
return "Employe [id=" + id + ", name=" + name + ", gender=" + gender + ", department=" + department + ", dob="
+ dob + "]";
}
}
EmployeService.java
public interface EmployeService {
List<Employe> get();
Employe get(int id);
void save(Employe employe);
void delete(int id);
}
EmployeServiceImplement.java
#Service
public class EmployeServiceImplement implements EmployeService {
#Autowired
private EmployeDAO employeDAO;
#Transactional
#Override
public List<Employe> get() {
return employeDAO.get();
}
}
EmployeDAO.java
public interface EmployeDAO {
List<Employe> get();
Employe get(int id);
void save(Employe employe);
void delete(int id);
}
EmployeDAOImplement.java
#Repository
public class EmployeDAOImplement implements EmployeDAO {
#Autowired
private EntityManager entityManager;
#Override
public List<Employe> get() {
Session currentSession = entityManager.unwrap(Session.class);
Query<Employe> query = currentSession.createQuery("from Employe", Employe.class);
List<Employe>list = query.getResultList();
return list;
}
}
I have write all the configuration related to MySQl database into the application.properties and when i run this project as Spring Boot App and go to the Postman and tried like this
and i a unable to understan why it always throws 404 error every time , can anyone tell me what i am missing in this code.
Try with this GET request, it may help you:
http://localhost:8080/api
I checked your code.
where is #RestController for your Controller file and where is #RequestMapping For your method in Controller class?
maybe you should write something like this according to your need.
tell me if you need more help.
#RestController
#RequestMapping("/api")
public class EmployeController {
#RequestMapping(value = "/employ")
public void employ() {
}
}
Instead of this -
#Override
public List get()
Use this -
#RequestMapping(value = "/Employe", method = RequestMethod.GET)
public List get()
I am new to Jpa and I added spring boot jpa in my spring boot for One to One mappings. So,
package com.jpa.onetoone.onetoonejpa.model;
import org.hibernate.annotations.GeneratorType;
import javax.persistence.*;
#Entity
public class User {
#Id
#GeneratedValue
private Long id;
private String username;
private String password;
#OneToOne(cascade=CascadeType.ALL,mappedBy = "user",fetch = FetchType.LAZY)
private Address address;
public User(String username, String password) {
this.username = username;
this.password = password;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
#Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
public User() {
}
}
Address.java file is
package com.jpa.onetoone.onetoonejpa.model;
import com.fasterxml.jackson.annotation.JsonIgnore;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToOne;
#Entity
public class Address {
#Id
#GeneratedValue
private Long id;
private String homeAddress;
private int homeNumber;
#OneToOne
#JsonIgnore
private User user;
public Address(String homeAddress, int homeNumber) {
this.homeAddress = homeAddress;
this.homeNumber = homeNumber;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getHomeAddress() {
return homeAddress;
}
public void setHomeAddress(String homeAddress) {
this.homeAddress = homeAddress;
}
public int getHomeNumber() {
return homeNumber;
}
public void setHomeNumber(int homeNumber) {
this.homeNumber = homeNumber;
}
public Address() {
}
}
I have added one to one relationship between User and Address.I have inserted the data in database and want to acquire data through RestController.So,I am just testing my application using FetchType.Lazy and FetchType.Eager in User class but I am getting the same Json.There is no change in JSOn with the FetchType.
When I hit the URL :http://localhost:8080/users in both fetchtype.lazy and fetchtype.eager i am getting the same JSON as the address field needs to be eradicated as I use fetchtype.lazy in Address field.
#OneToOne(cascade=CascadeType.ALL,mappedBy = "user",fetch = FetchType.LAZY)
private Address address;
The JSON i am getting in both case is:
[
{
"id":3,
"username":"ashwin",
"password":"karki",
"address":{
"id":4,
"homeAddress":"kapan",
"homeNumber":71444
}
}
]
Another question I want to ask is,when I try to access http://localhost:8080/address ,I also want User object associated with address.The loop went to infinite and I added JsonIgnore,then the Json is printed like below.Is there any way, we can access both user from address and address from user when hitting these two URL?
[
{
"id":4,
"homeAddress":"kapan",
"homeNumber":71444
}
]
DefaultController.java
package com.jpa.onetoone.onetoonejpa.controller;
import com.jpa.onetoone.onetoonejpa.model.Address;
import com.jpa.onetoone.onetoonejpa.model.User;
import com.jpa.onetoone.onetoonejpa.repository.AddressRepository;
import com.jpa.onetoone.onetoonejpa.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
#RestController
public class DefaultController {
#Autowired
private UserRepository userRepository;
#Autowired
private AddressRepository addressRepository;
#GetMapping(value = "/users")
public List<User> getUsers() {
List<User> users = userRepository.findAll();
return users;
}
#GetMapping(value = "/address")
public List<Address> getAddress() {
List<Address> address = addressRepository.findAll();
return address;
}
}
There is no change in JSON with the FetchType - and should not. The fetch type is a strategy of loading data from a database.
With EAGER user and address loads at the same time, with one SQL call:
#GetMapping(value = "/users")
public List<User> getUsers() {
List<User> users = userRepository.findAll(); // users and addresses was loaded
return users;
}
With LAZY, address will not be loaded while you don't read them. But, when you return users from a controller, JSON mapper read address property, so it will be loaded with one SQL call per user:
#GetMapping(value = "/users")
public List<User> getUsers() {
List<User> users = userRepository.findAll(); // users was loaded
return users; // addresses was loaded for each user one by one
}
And the second question. There are many ways. See JsonView, for example.
Use #JsonManagedReference and #JsonBackReference annotations to avoid your application of infinite loop. You can review the following questions:
Difference between #JsonIgnore and #JsonBackReference, #JsonManagedReference
Infinite Recursion with Jackson JSON and Hibernate JPA issue
While testing a REST controller(developed with SpringBoot) with Postman, getting 415 status code repeatedly.
Happening only with a specific post requests. other post requests are working fine. Have mimicked the working post controllers into failing ones but of no luck.
#RequestMapping(value="/addtheatre", method= RequestMethod.POST)
public HttpStatus addTheatre(#RequestBody Theatre theatre ) {
theatrerepository.save(theatre);
return HttpStatus.OK;
}
Theatre Entity is as follows:-
package com.example.Model;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.stereotype.Component;
import javax.persistence.*;
import javax.validation.constraints.NotNull;
import java.sql.Time;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
#Entity(name="Theatre")
public class Theatre {
Theatre()
{}
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
#Column(name="Id")
private long id;
#Column(name="name")
#NotNull
private String name;
#Column(name="address")
#NotNull
private String address;
#Column(name="city")
#NotNull
private String city;
#Column(name="is_active")
#NotNull
private Boolean is_active;
#Transient
private List<TheatreHall> halls;
#Transient
private Map <Movie,LinkedList<Time>> map;
public Boolean getIs_active() {
return is_active;
}
public void setIs_active(Boolean is_active) {
this.is_active = is_active;
}
public List<TheatreHall> getHalls() {
return halls;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void setHalls(List<TheatreHall> halls) {
this.halls = halls;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public Map<Movie, LinkedList<Time>> getMap() {
return map;
}
public void setMap(Map<Movie, LinkedList<Time>> map) {
this.map = map;
}
#Override
public String toString() {
return "Theatre{" +
"id=" + id +
", name='" + name + '\'' +
", address='" + address + '\'' +
", city='" + city + '\'' +
", is_active=" + is_active +
", halls=" + halls +
", map=" + map +
'}';
}
}
Postman testdata is as follows:-
Endpoint:-localhost:8080/addtheatre
Request:-
{
"name":"PVR Mall",
"address":"Andheri",
"city":"Mumbai",
"is_active":"true"
}
Response:-
{
"timestamp": "2018-12-26T08:21:43.269+0000",
"status": 415,
"error": "Unsupported Media Type",
"message": "Content type 'application/json;charset=UTF-8' not supported",
"path": "/addtheatre"
}
Expecting OK status for this POST controller.
change is_active to isActive and setter to setIsActive. I suspect Jackson is unable to find the relevant setter for is_active due to the naming convention and therefore unable to parse the object
In case if you use #RestController to fit #RequestMapping defaults make sure you set application/json both to Content-Type and Accept headers.
If you need to send exactly UTF-8 encoded json so you will need to set consumes attribute explicitly:
#RequestMapping(value = "...", method = ...,consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
Also there might be an implicit Jackson issue with boolean setter. Try changing your is_active field (that doesn't fit the convention) to active and it's getter\setter as:
private boolean active;
#JsonProperty(value="is_active") //if needed
public boolean isActive() {
return this.active;
}
public void setActive(boolean active) {
this.active = active;
}
you may check the headerRequest!!!!!,I think that there are some mistakes in the setting in the head.Focus on the "Content-Type",you should set it ""
it might be because of missing consumes and produces values inside the #RequestMapping of a Web Service method,
may add those :
#RequestMapping(value="/addtheatre", method= RequestMethod.POST, consumes = { MediaType.APPLICATION_JSON_VALUE}, produces = { MediaType.APPLICATION_JSON_VALUE})
public HttpStatus addTheatre(#RequestBody Theatre theatre ) {
theatrerepository.save(theatre);
return HttpStatus.OK;
}
I have a spring boot based application. I want to download a huge amount of data from a database as a text file through REST API.
Since the amount of data might be really huge, let's say at least 1_000_000 enries, I decided to use Stream provided by Java 8 (fortunately Spring DATA JPA allows streaming queries)
It works fine but I'd like to compress the downloaded result. I know that Tomcat provides such functionality as mentioned here.
But for some reasons the result file is not compressed. Can't find out what I'm doing wrong.
Take a look at the code that I've written so far:
Model
#Entity
#Table(name = "users")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private Integer age;
public User() {
}
public User(String name, Integer age) {
this.name = name;
this.age = age;
}
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;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
#Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
DAO Layer
public interface UserRepository extends JpaRepository<User, Long> {
#Query("SELECT u from User u")
#QueryHints(value = #QueryHint(name = HINT_FETCH_SIZE, value = "" + Integer.MIN_VALUE))
Stream<User> streamAll();
}
And finally Rest Controller
#RestController
public class DownloadController {
#Autowired
private UserRepository userRepository;
#PersistenceContext
EntityManager entityManager;
#RequestMapping(value = "/stream", method = RequestMethod.GET)
#Transactional(readOnly = true)
public void stream(HttpServletResponse response) {
response.addHeader("Content-Type", "text/plain");
response.addHeader("Content-Disposition", "attachment");
response.setCharacterEncoding("UTF-8");
try(Stream<User> users = userRepository.streamAll()) {
PrintWriter out = response.getWriter();
users.forEach(u -> {
out.write(u.toString());
out.write("\n");
entityManager.detach(u);
});
out.flush();
} catch (Exception e) {
throw new RuntimeException("Exception occurred while exporting results", e);
}
}
}
In the application.properties file I added server.compression.enabled=true and since I have set header "Content-Type", "text/plain" I guess it should be compressed by default as mentioned here.
Any ideas would be appreciated.
Thanks in advance.