I cannot #putmapping spring boot - spring-boot

The #Putmapping annotation not works correcty on my code. I want to make update operation with put mapping, but its make postmapping and add a new record to database.
enter image description here
enter image description here
update with putmapping

In your service class in update method you are calling the save method.
#Override
public void update(UpdateBrandRequest updateBrandRequest) {
// jparepository brand tanıdığı için hep brand nesnesi lazım.
Brand brand = this.modelMapperService.forRequest().map(updateBrandRequest, Brand.class);
this.brandRepository.save(brand); // updaterequest içinde id olduğu için buradaki save, update işlemi yapar.
}
But before that for put mapping you need to send the Id for which you are trying to update and you have to use setters method to set the new values for that perticular record.
below I can show u the example from my code:
#Override
public Candy updateCandy(Candy candy, int candyId) throws CandyShopServiceException {
// TODO Auto-generated method stub
Candy candy1 = candyRepository.findById(candyId)
.orElseThrow(() -> new CandyNotFoundException("Candy by this Id not found"));
candy1.setCandyName(candy.getCandyName());
candy1.setCandyStock(candy.getCandyStock());
return candyRepository.save(candy1);
}
In the above code I am passing the Candy object and perticular candy Id from the postman as a put mapping and from that Id I'm looking for the perticular candy and using setter method to set the value of new candy by replacing existing candy record.
Feel free to comment if you have any doubt in this.

Related

Spring MVC Continue user's Form (Dto) when traversing an app until explicit cancel - Controller #SessionScope Component

here and there I was trying to keep form data present when a user is traversing an app
and as well when he returns to a form. Form is using a binding list (Dto.List),
and user is capable to add entries to it so there might be some work there, but not so much
that the form must be persisted every time a new entry is added to the list (in a form).
Trivial controller's method isn't achieving this, because this creates new Dto every time user leaves
that form and returns back:
// Start with a brand new Dto
#GetMapping("/new")
public ModelAndView newDto() { return new ModelAndView( "form", "dto", new Dto() ); }
Keeping following in mind:
https://rules.sonarsource.com/java/RSPEC-3750
I came up with the following implementation, but I am questioning it if there is more elegant one?
add custom .defaultSuccessUrl
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
...
.formLogin().loginPage("/login").defaultSuccessUrl( "/afterLogin", true )
add /afterLogin endpoint and adjust method to not create new object every time user returns
#Controller
public class DtoController {
// Per user Dto
Dto dto;
// Initialize Dto
#GetMapping("/afterLogin")
public String afterLogin() {
dto = new Dto();
return "redirect:/";
}
// Never Start with a brand-new Dto until user hits Cancel button
#GetMapping("/new")
public ModelAndView keepDto() { return new ModelAndView( "form", "dto", dto ); }
// Add another Entry to Dto
#PostMapping( value = "/mgmt", params = "Add" )
public ModelAndView add( #ModelAttribute("dto") Dto dto ) {
this.dto = dto; // Binding List((re) set/change if changed or not)
dto.add( nextID.getAndDecrement() ); // Add new entry to the list (these IDs will be ignored when creating new set #OneToMany)
return new ModelAndView( "form", "dto", dto );
}
}
Any better ideas? I tried to check in keepDto method if user's Dto already exist,
but probably I don't understand how that should be achieved properly.
Thanks for ideas in advance.

Update multiple fields of JPA Entity

I have JPA entity Customer having say 50 fields and I would like to update it from the end user using html form.
I am passing one instance of entity to html page form (using thymeleaf), this form is having only 20 fields out of 50 (including ID field). Now once the form is submitted, I would like to update 20 fields from data received using form to the database. I am not getting solution for above issue. One solution is to update individual field but I don't think it is good solution.
#Entity
public class Customer
{
...
50 fields
}
My get method:
#GetMapping(value = "customer")
public String customer(Model model) {
Customer customer = null;
Optional<Customer> optional = customer Repo.findById(customerId);
if (optional.isPresent()) {
customer = optional.get();
}
model.addAttribute("customer", Customer);
return "customer";
}
Html form:
<form action="updateCustomer">
----20 fields which I would like to get update from user are here
</form>
#PostMapping(value = "updateCustomer")
public String updateCustomer(Model model, #ModelAttribute Customer customer) {
if(customer==null) {
System.out.println("Customer object is null");
}
else
{
customerRepo.save(customer);
}
return "savedCustomer";
}
In the post method when I get customer object it is having only 20 fields data not 50(Customer entity is having total fields) because html form is having only 20 fields for update. How to update the old customer object having 50 fields using the new customer object having updated 20 fields.?
There are three ways in the past that I solved this problem
1) have the page GET the Customer object in question, use the object to pre-populate the form, and then POST the changed customer object. The benefit is that the user changing the Customer sees all info related to the Customer, and you have a easy merge on the backend. The drawback is an additional REST call.
2) Create a DTO, and transfer non-null fields from the DTO to the entity. The benefit is you don't have to update all the fields in the form, and no extra network call. the drawback is that it's a pure pain in the rear end.
3) Create a DTO, and make it an entity to save. The benefit is that it's a easy merge back to the database, nothing prevents you from mapping the same table and fields to multiple entities. The drawback is that you have to worry about concurrency issues, which may just not work in your workflow, and the DTO is basically specific per form.
To make partial updates to entity, you either need to use Criteria API or JPQL query ... this is called projection in JPA, here is a quick example ,
Note : You might not be able to use this feature if you are using an old version of JPA query parser (no JPQL updates) + old version of JPA (when no CriteriaUpdate lib was there) you will then need to fetch the object from DB with the id passed from the client, update the 20 properties from the client and save the changes back
Below solution worked for me:
Helper Class:
public class BeanCopy {
private static final Set<Class<?>> primitiveTypes = new HashSet<Class<?>>(
Arrays.asList(Boolean.class, Character.class, Byte.class, Short.class, Short.class, Integer.class, Long.class, Float.class, Double.class, Void.class, String.class, Date.class));
public static void nullAwareBeanCopy(Object dest, Object source) throws IllegalAccessException, InvocationTargetException
{
new BeanUtilsBean() {
#Override
public void copyProperty(Object dest, String name, Object value)
throws IllegalAccessException, InvocationTargetException {
if(value != null && (primitiveTypes.contains(value.getClass()) )) {
super.copyProperty(dest, name, value);
}
}
}.copyProperties(dest, source);
}
}
This is how I copied and forced changes to database:
try {
BeanCopy.nullAwareBeanCopy(DBcustomer,customer);
customerRepo.save(DBcustomer);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
Please let me know any better solution is available for the above problem.

Bind json value to two object in spring MVC restful

At present what I have is one view in HTML for entering Person's details and Company's details. I am using spring MVC framework restful.
I create json and send request using Ajax to Restcontroller.based on URL pattern create method is called .e.g. json is
{"name":"rohit","address":"Pune","company":"ABC"}
Here above name and address belong to person bean and company belongs to company bean. I want the json value bind to their respective bean. How to do it? I have tried the code below but I know it won't work.
#Requestmapping(value="/createperson",method=method.post)
public #Responsebody String createperson(#Requestbody person,#Requestbody company)
{
//Some code to save
}
I have a form, which will input the person's details and the person's company details.
What I want is that when this form is submitted, some of its fields are bound to Person object properties and some to Company object properties. How can this be done? And how to do validation for json value and send all errors as json responsive again back if there are any errors.
You can only have one #RequestBody. Spring then looks at the content-type header and finds an appropriate HttpMessageConverter which will read the entire http entity body (input stream) into a single object.
What you have basically done is try to merge Person and company into a single JSON object, and thereby flattened the structure. If you want spring to handle that, you need to create a new object with the same (flat) hierarchy. Or you need to create a wrapper class PersonAndCompany which contains both a Person and a Company, and then change the JSON to match the structure, so it looks like this.
{
"person" : {
"name":"rohit",
"address":"Pune"
},
"company" : {
"name":"ABC"
}
}
you should do like this if you are using relationship between Person and Company otherwise it is better to use single bean instead of two.
#ResponseBody
#RequestMapping(value = "/createperson", method=RequestMethod.POST ,consumes=MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Person> createperson(#RequestBody Person person) {
if(error found ){
Person p new Person();
p.setError(" error message ");
return new ResponseEntity<Person>(p,HttpStatus.BAD_REQUEST);
}
return new ResponseEntity<Person>(person,HttpStatus.OK);
}
public class Person {
private String name;
private String address;
Company company;
String error;
--- setters getters
}
public class Company {
String compName;
--- setters getters
}
input json
{"name":"person name ","address":"person address ","company":{"compName":"company name"}}

Spring Session Model Attribute Naming Convension

Declaring session model attribute as:
#SessionAttributes ("customer")
Controller code is basically to modify the customer object :
#RequestMapping(value="/testlink", method=RequestMethod.GET)
public String testLinkHandler(ModelMap modelMap){
customerDao.getCustomer(111);
modelMap.put("customers", customerDao.getCustomers());
Customer cust = customerDao.getCustomer(115);
if (cust == null){
cust = new Customer();
}
modelMap.put("customer", cust);
return "testlink";
}
#RequestMapping(value="/testlink", method=RequestMethod.POST)
public String testLinkHandler(#ModelAttribute Customer customer){
customerDao.save(customer);
return "redirect:/testlink";
}
With above code in POST method Customer object is loaded from session & posted new customer name with proper id and hence Editing the Customer works perfectly and updates DB with modified customer Name.
But the moment I change the model variable name and the #SessionAttribute name from "customer" to say "customerModel" or "customer_model" or "model" it doesn't work anymore and above code inserts a new record in DB.
So the question is, Is there a naming convention that needs to be followed here?
public String testLinkHandler(#ModelAttribute Customer customer){ ... }
This method expects an object named customer to be available for binding. When using #ModelAttribute without attributes Spring MVC tries to deduce the name of the model attribute from the method argument name.
Now if you decide to rename your model attribute you either have to
Rename the method argument accordingly
Supply the name to the #ModelAttribute.
As I wouldn't suggest option 1, that leaves option 2.
public String testLinkHandler(#ModelAttribute("your-model-name-here") Customer customer){ ... }
With #SessionAttribute, Spring obtains an instance of model attribute from the session.
Hence model attribute field name should match with the session attribute name,in this case customer
If you require changing of the attribute name then you can use :
#SessionAttributes (types = {Customer.class})
Now, whenever you put your modelClass of the type Customer in spring Model then it would automatically be set in the session.

Spring Ldaptemplate 2 add member to group

what is best way to add member in group using spring LdapTemplate.
I have successfully create user and remove user ex.
But I'm trying to add member then I'm facing issue.
Add Member Code:
public boolean addMemberToGroup(List<String> groupList, User user) {
boolean isAddedSuccessfully=false;
try{
for(int i=0;i<groupList.size();i++){
Name groupDn = buildGroupDn(groupList.get(i));
DirContextOperations ctx = ldapTemplate.lookupContext(groupDn);
ctx.addAttributeValue("member",buildPersonDn(user.getUid()));
ldapTemplate.update(ctx);
}
isAddedSuccessfully=true;
}
catch(Exception e){
isAddedSuccessfully=false;
}
return isAddedSuccessfully;
}
private Name buildGroupDn(String groupName) {
return LdapNameBuilder.newInstance("cn=groups").add("cn", groupName).build();
}
private Name buildPersonDn(String userID) {
return LdapNameBuilder.newInstance()
.add("uid", userID).add("cn", "users")
.build();
}
Exception Of addMemberToGroup: Class class org.springframework.ldap.core.DirContextAdapter must have a class level interface org.springframework.ldap.odm.annotations.Entry annotation.
please let me know what i am missing.
The updatemethod is intended for use with ODM annotated classes. When working with DirContextAdapter you should use the modifyAttributes method.
Though this is an old question, it's one I had too recently. For anyone coming here in the future, this question is similar to the one found at Spring Malformed 'member' attribute value. Putting together info from both questions, I found the solution to my problem, and share here what worked for me.
In addition to using the modifyAttributes method of the LdapTemplate class, it's also important to pass a String object as the second parameter of the addAttributeValue method of the DirContextOperations class when adding a member, rather than passing a Name object. The toString method called on the corresponding Name object does the trick.
Original code:
DirContextOperations ctx = ldapTemplate.lookupContext(groupDn);
ctx.addAttributeValue("member",buildPersonDn(user.getUid()));
ldapTemplate.update(ctx);
Try this instead:
DirContextOperations ctx = ldapTemplate.lookupContext(groupDn);
ctx.addAttributeValue("member",buildPersonDn(user.getUid()).toString());
ldapTemplate.modifyAttributes(ctx);

Resources