How to send model property, the property is the model too in spring - spring

I have two models.
#Entity
class Product {
#Id
private String id;
private String name;
#ManyToOne(optional = false)
#JoinColumn(name = "category_id", referencedColumnName = "id")
#NotNull(groups = {CREATE.class, UPDATE.class})
private Category category;
...
}
#Entity
class Category {
#Id
private String id;
private String name;
...
}
#RestController
#RequestMapping(path = "/product")
class ProductController {
#RequestMapping(method = RequestMethod.POST)
public void create(#ModelAttribute Product product) {
...
}
}
I want send request to ProductController:
http POST http://localhost:8080/product name=='Product 1' category=1
The param category is id of Category into db, but spring does not understand it.
Is it possible to do this?

Well, your entitiy classes are ok, but it's really weird to see parameters in the POST request especially in so sort as you have it placed here.
Here is my sample that is working properly
public class Product {
private String id;
private String name;
private Category category;
******
}
public class Category {
private String id;
private String name;
*******
}
#RestController
#RequestMapping(path = "/product")
public class ProductController {
#RequestMapping(method = RequestMethod.POST)
public void create(#ModelAttribute Product product) {
Product prd1 = product;
prd1.getId();
}
}
And just in case here is an appConfig:
#Configuration
#EnableWebMvc
public class AppConfig {
}
That is all. Now your contorller is expecting to get a message that is a Product instance.
Let's go onward. It's pretty weird to see parameters in the POST query. I've had some test and they are ok - just pass the data as a request body! Whatever you cose. For instance let's modify controller as it shown below:
#RequestMapping(method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
public void create(#ModelAttribute Product product) {
Product prd1 = product;
prd1.getId();
}
}
And now you have to send a POST message with a body that contains a Product data in a JSON format, i.e
{ "id": 1 }
and it works for all other formats that are supported by spring

Related

Why do I get Status 400, Bad Request on my POST URL (using postman)

I am trying to follow a Spring Boot Tutorials on youtube and I get stuck at Post.
I tried searching for fix but I can't find an specific answer why I can't access the post URL?
I tried both #PostMapping and #RequestMapping(Method = POST)
still same results.
Maybe I am accessing my URL wrong?
I am trying to Post at /api/sis/student_reg
need help, thanks!
#RestController
#RequestMapping(path = "/api/sis")
public class StudentController {
#Autowired
private StudentService studentService;
#GetMapping(path = "/student")
public List<Student> displayStudent(){
return studentService.getStudent();
}
#RequestMapping(method = RequestMethod.POST, value = "/reg_student")
public void registerStudent(#RequestBody Student student){
studentService.addStudent(student);
}
}
#Service
public class StudentService {
#Autowired
private StudentRepository studentRepository;
private Student students = new Student();
public List<Student> getStudent(){
List<Student> student = new ArrayList<>();
studentRepository.findAll()
.forEach(student::add);
return student;
}
public void addStudent(Student student){
studentRepository.save(student);
}
#Entity
#Table
public class Student {
UUID uuid = UUID.randomUUID();
#Id
#SequenceGenerator(
name = "student_sequence",
sequenceName = "student_sequence",
allocationSize = 1
)
#GeneratedValue(
strategy = GenerationType.SEQUENCE,
generator = "student_sequence"
)
private String id;
private String FirstName;
private String LastName;
private String email;
// Method Converting UUID into string
public String genID(){
id = uuid.toString();
return id;
}
//Constructor, getters and setters
Edited again:
I receive error 400 when using the "Post" while 405 "Get" on the post URL.
apologies for the confusion.
It is not about wrong url. If that would have been the case you would get 404 Not Found error and not 400 i.e., Bad Request.
This means your request is not proper. Can you please also update the whole request body which you are using in postman and also attributes of your Student Class.

bidirectional relationship returning empty set on OneToMany and works only on ManyToOne

i have 2 entities, Category and Feature, each Category has one or many features.
when creating a category along with its features, fetching the new category returns an empty set on the features attribute.
#PostMapping("/sub")
#PreAuthorize("hasRole('ROLE_admin')")
public HttpEntity<CategoryDTO> createSubCategory(#Valid #RequestBody CreateCategory createCategory)
{
Category category = categoryService.create(createCategory,mainCategoryService.one(createCategory.getMainCategory_id()));
featureService.bulkCreate(createCategory.getFeatures(),category);
return ResponseEntity.status(HttpStatus.CREATED).body(modelMapper.map(category,CategoryDTO.class));
}
this is the data that i'm sending:
{"name":"SUB","mainCategory_id":1,"features":{"F1":"SLIDER","F2":"CHECKBOX"}}
and this is the data returned by the controller:
{"id":2,"name":"SUB","mainCategory":{"id":1,"name":"CATEGORY"},"features":[]}
as you can see, the features are empty.
This is the test to create a category with its features:
#Test
public void testIfAdminCanCreateSubCategory_expect201AndMainCategoryIdEqualsTheAssociatedOne() throws Exception {
String category = "{\"name\" : \"CATEGORY\"}";
String sub = "{\"name\":\"SUB\",\"mainCategory_id\":1,\"features\":{\"F1\":\"SLIDER\",\"F2\":\"CHECKBOX\"}}";
mockMvc().with(keycloakAuthenticationToken().authorities("ROLE_admin")).perform(post("/categories").content(category).contentType("application/json"))
.andDo(print())
.andDo(r -> mockMvc().with(keycloakAuthenticationToken().authorities("ROLE_admin"))
.post(sub,"/categories/sub")
.andExpect(status().isCreated())
.andExpect(jsonPath("$.mainCategory.id").value(1))
.andDo(print())
// .andExpect(jsonPath("$.features[0]").value("SLIDER"))
);
//featureService.all().forEach( f -> System.out.println(f.getCategory().getId()));
}
when decommenting the last line, it prints the category id ( which is 2 as shown in the returned data ), meaning that the ManyToOne is working, but not the OneToMany.
My models:
#Entity
#EntityListeners( AuditingEntityListener.class )
#Data
public class Category {
#Id #GeneratedValue(strategy=GenerationType.AUTO) private Long id;
....
#OneToMany(cascade = CascadeType.ALL, mappedBy = "category" , fetch = FetchType.LAZY)
Set<Feature> features = new HashSet<>();
}
#Entity
#Data
public class Feature {
#Id #GeneratedValue private Long id;
private String name;
private FeatureType type;
#ManyToOne Category category;
}
the create method in categoryService:
#Override
public Category create(CreateCategory createCategory, MainCategory mainCategory) {
Category category = new Category();
category.setName(createCategory.getName().toUpperCase());
category.setMainCategory(mainCategory);
return categoryRepository.save(category);
}
the bulkCreate method in the featureService:
#Override
public Feature create(String feature, FeatureType type, Category category) {
Feature f = new Feature();
f.setName(feature);
f.setType(type);
f.setCategory(category);
return featureRepository.save(f);
}
#Override
public void bulkCreate(Map<String, FeatureType> features, Category category) {
features.forEach( (name,type) -> create(name,type,category));
}
myDTOs:
#Data
public class CategoryDTO {
private Long id;
private String name;
private MainCategoryDTO mainCategory;
private Set<FeatureDTO> features;
}
#Data
public class FeatureDTO {
private Long id;
private String name;
private FeatureType type;
}
#Data
public class MainCategoryDTO {
private Long id;
private String name;
}
EDIT 1 :
i've added a method on my categoryService that sets the category features.
#Override
public Category addFeatures(Category category, List<Feature> features) {
category.setFeatures(features);
return categoryRepository.save(category);
}
and on my controller, i added the commented line so i can associate features to the category
#PostMapping("/sub")
#PreAuthorize("hasRole('ROLE_admin')")
public HttpEntity<CategoryDTO> createSubCategory(#Valid #RequestBody CreateCategory createCategory)
{
Category category = categoryService.create(createCategory,mainCategoryService.one(createCategory.getMainCategory_id()));
#category = categoryService.addFeatures(category,featureService.bulkCreate(createCategory.getFeatures(),category));
return ResponseEntity.status(HttpStatus.CREATED).body(modelMapper.map(category,CategoryDTO.class));
}

Hibernate: How to display data from multiple table

I am new in spring/hibernate technologies, I have tried to find an information about it, but failed, so if you can help I will be so thankful!
I need to display a JSON response in browser of multiple tables, one of the table has primary key for another one.
My entities:
#Entity
#Table
#ToString
public class Book {
#Id
#GeneratedValue(strategy = AUTO)
#JsonView(Views.IdName.class)
private Long book_id;
#JsonView(Views.IdName.class)
private String name;
#Column(length = 1000000)
private String text;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="author_id")
#JsonView(Views.IdName.class)
private Author author;
// ....get/set methods
Another one:
#Entity
#Table
#ToString
public class Page {
#Id
#GeneratedValue(strategy = AUTO)
private Long id;
#Column(length = 1000000)
private String text;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "book_id")
private Book book;
// ...get/set methods
My controllers:
#RestController
#RequestMapping("books")
public class BookController {
private final BookRepo bookRepo;
#Autowired
public BookController(BookRepo bookRepo) {
this.bookRepo = bookRepo;
}
#GetMapping
#JsonView(Views.IdName.class)
public List<Book> getAll() {
return bookRepo.findAll();
}
#GetMapping("{id}")
public Book getOne(#PathVariable("id") Book book) {
return book;
}
}
Another one:
#RestController
#RequestMapping("authors")
public class AuthorController {
private final AuthorRepo authorRepo;
#Autowired
public AuthorController(AuthorRepo authorRepo) {
this.authorRepo = authorRepo;
}
#GetMapping
public List<Author> getAll() {
return authorRepo.findAll();
}
#GetMapping("{id}")
public Optional<Author> getOne(#PathVariable("id") Long id) {
return authorRepo.findById(id);
}
}
And also repo for interaction with DB (they are the similar):
public interface AuthorRepo extends JpaRepository<Author, Long> {
}
So when I make a request for get all books, I take the following JSON:
enter image description here
Bit I want different result, something like:
[
{
"book_id" : 1,
"name": "name 1 book",
"author" :
{
"author_id" : 1,
"name": "some_name"
}
}
]
Also, when I tried to make a request for /authors/1, I will get the following response (something like recursion) :
enter image description here
So any help how can I handle with it? Thank you!
You can use a #NoRepositoryBean
like in this example:
#NoRepositoryBean
public interface MappedTypeRepository<T extends AbstractMappedType>
extends Repository<T, Long> {
#Query("select new com.example.YourObjectWithConstructor(e.attribute, sub.sub_attribute) from entity e inner join e.subtable sub where e.attribute = ?1")
List<YourObjectWithConstructor> findAllByAttribute(String attribute);
}
My example may not be 100% correct, I did not check the syntax. Feel free to explore it
Check this also:
JPQL Create new Object In Select Statement - avoid or embrace?

Get URL parameter for crit use Spring MVC Hibernate

I want to be list out all my users with criteria of where id = formId. The code is working but just that it list out all the users instead of being filtered by formId. Please tell me where i did wrongly. Do tell me if you need any more info to solve this!
controller
*url = http://localhost:8080/User/Panda?Id=1
#RequestMapping(value = {"/{name}?Id={id}" }, method = RequestMethod.GET)
public String listClinicUser(ModelMap model, #PathVariable("id") Integer id) {
logger.info("Users List Page - Id = " + id);
List<User> user = service.findAllUsers(id);
model.addAttribute("users", user);
return "user/list";
}
Service
public List<User> findAllUsers(Integer id) {
return dao.findAllUsers(id);
}
DAO Class
public interface UserDao {
List<User> findAllUsers(Integer id);
}
*DAOImpl Class
#SuppressWarnings("unchecked")
public List<User> findAllUsers(Integer id) {
Criteria crit = createEntityCriteria();
crit.add(Restrictions.eq("formId",id));
crit.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
List<User> users = (List<Usert>) crit.list();
return users;
}
*for createEntityCriteria() i created in another class call abstractDao and extends to it.
private final Class<T> persistentClass;
#SuppressWarnings("unchecked")
public AbstractDao(){
this.persistentClass =(Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[1];
}
protected Criteria createEntityCriteria(){
return getSession().createCriteria(persistentClass);
}
Class Entity
#Entity
#Table(name="USER")
public class User implements Serializable{
#NotEmpty
#Column(name="formId", nullable=false)
private Integer formId;
#NotEmpty
#Column(name="FIRST_NAME", nullable=false)
private String firstName;
#NotEmpty
#Column(name="LAST_NAME", nullable=false)
private String lastName;
public Integer getFormId() {
return formId;
}
public void setFormId(Integer formId) {
this.formId= formId;
}
...
}
value = {"/{name}?Id={id}" }
This is wrong way to extract URL param. If you want to get URL param, you should pass it to your method using #RequestParam annotation:
#RequestMapping(value = {"/{name}" }, method = RequestMethod.GET)
public String listClinicUser(ModelMap model, #RequestParam("Id") Integer id) {
//...
}
Spring automatically pass value that you need. For example in case of ?Id=1 Spring will pass 1 to your controller
In your url /{name} is a path variable and is annotated with #PathVariable like in:
#RequestMapping(value = "/foo/bar/{name}", method = GET)
#ResponseBody
public String getBarByName(#PathVariable String name) { ... }
And ?Id=id is a request parameter and is annotated wiht #RequestParam so if we map to url like this one:
http://localhost:8080/api/foo/bar?id=100
we do it like this
#RequestMapping(value = "/foo/bar", method = GET)
#ResponseBody
public String getBarById(#RequestParam("id") Integer id) { ... }
So to combine them to map to your url:
#RequestMapping(value = {"/{name}" }, params = "id", method = RequestMethod.GET)
public String listClinicUser(ModelMap model, #PathVariable String name, #RequestParam("id" Integer id)) { ... }

How I can get one column value from a table?

I use Spring boot and Spring Data.
I have a contact entity with the id and firstName columns.
#Entity
#Table(name = "Contact")
public class Contact {
#Id
#GeneratedValue(strategy= GenerationType.AUTO)
private int id;
private String firstName;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
}
I use repository with Spring Data to find my data.
public interface contactRepository extends CrudRepository<Contact, Long> {
}
My controller, example with getAll:
#RequestMapping(value = "/getAllContact", produces = "application/json")
public List<Contact> getAllClients(){
return repo.getAll();
}
My controller works but I don't know how to return all values in column firstName in my controller. I tried with a query, It works but it only returns a list of values and not the json:
#Query(value = "SELECT firstName FROM Contact" )
List<Contact> findAllFirstName();
Example:
["Pierre", "Jean"]
And i want this (in Json):
[{"firstName ": "Pierre" },{"firstName ":"Jean"}]
How do I do this?
Use the projection and excerpt support in Spring Data Rest. Whilst adding in JsonIgnore annotations does work, it's inflexible as you can only ignore at compile time not run time.
See
http://docs.spring.io/spring-data/rest/docs/current/reference/html/#projections-excerpts
Make sure jackson libraries are in your classpath. Then add #ResponseBody in your controller method to return json output. Also add #JsonIgnore in id in your entity to exclude it from json output.
#RequestMapping(value = "/getAllContact", produces = "application/json")
#ResponseBody
public List<Contact> getAllClients(){
return repo.getAll();
}
#Entity
#Table(name = "Contact")
public class Contact {
#Id
#GeneratedValue(strategy= GenerationType.AUTO)
#JsonIgnore
private int id;
private String firstName;
.....
}

Resources