#PutMapping(path = "{studentId}")
public void updateStudent(
#PathVariable("studentId") Long studentId,
#RequestParam(required = false) String name,
#RequestParam(required = false) String email){
studentService.updateStudent(studentId, name, email);
}
#Transactional
public void updateStudent(Long studentId, String name, String email){
Student student = studentRepository.findById(studentId)
.orElseThrow(() -> new IllegalStateException("Student with " +studentId+" does not exist" ));
student.setName(name);
student.setEmail(email);
}
}
The problem is when I do PUT method in POSTMAN it gives no error but values in "name" and "email" are NULL. How can I fix it?
Here is my POSTMAN request.
https://i.stack.imgur.com/KHYVW.png
Your api expects optional request params and you are giving request body in postman. The above api will work for /student/1?name=John&email=example#abc.com
If you want to use request body to work with this api i.e., form data submit them change the api to use request body which will be (#RequestBody Student studentData) where Student is a class having 2 string variables name & email. You can create a new class StudentRequest having only request attributes for your put/post apis or you can reuse Student class.
#PutMapping(path = "{studentId}")
public void updateStudent(
#PathVariable("studentId") Long studentId,
#RequestBody(required = true) Student student){
studentService.updateStudent(studentId, student);
}
#Transactional
public void updateStudent(Long studentId, Student studentData){
Student student = studentRepository.findById(studentId)
.orElseThrow(() -> new IllegalStateException("Student with " +studentId+" does not exist" ));
student.setName(studentData.getName());
student.setEmail(studentData.getEmail());
studentRepository.save(student);
}
Related
I'm using postman with springboot i have already used the GET/POST/DELETE requests and they all work fine but PUT request doesn't update content .
In intellij i'm using these files :
Student.java(with it's setters and getters) :
#Entity
#Table
public class Student {
#Id
#SequenceGenerator(
name="student_sequence",
sequenceName="student_sequence",
allocationSize = 1
)
#GeneratedValue(
strategy = GenerationType.SEQUENCE,
generator = "student_sequence"
)
private Long id;
private String name;
private LocalDate dob;
private String email;
#Transient
private Integer age;
StudentController.java :
#PutMapping(path ="{studentId}")
public void updateStudent(
#PathVariable("studentId") Long studentId,
#RequestParam(required = false) String name,
#RequestParam(required = false) String email)
{
studentService.updateStudent(studentId,name,email);
}
StudentService.java :
#Transactional
public void updateStudent(Long studentId,String name, String email)
{
Student student = studentRepository.findById(studentId)
.orElseThrow(() -> new IllegalStateException(
"student with id="+studentId+"does not exist"));
if (name !=null && name.length()>0 && !Objects.equals(student.getName(),name))
{
student.setName(name);
}
if (email !=null && email.length()>0 && !Objects.equals(student.getEmail(),email))
{
Optional<Student> studentOptional= studentRepository.findStudentByEmail(email);
if (studentOptional.isPresent())
{
throw new IllegalStateException("email taken");
}
student.setEmail(email);
}
}
These are the students that i have in database
And basically i want to update the name and email of the student with id=1.
That is postman header
And that is postman not showing any error after sending request
using #RequestParam(required = false) String name the params are expected as header or query param. You're sending a request body, so use a pojo instead...
class StudentDto {
public String name;
//...
}
and the controller ...
#PutMapping(path ="{studentId}")
public void updateStudent(
#PathVariable("studentId") Long studentId,
#RequestBody StudentDto) {
//...
}
To leave it be and make it work, you have to put your data as query params, lik ethis
PUT http://localhost:8080/api/v1/student/1?name=newName&email=newEmailToSet
So after this answer https://stackoverflow.com/a/72698172/19354780
i have tried changing StudentController to :
#PutMapping(path = "{studentId}")
public void updateStudent(
#PathVariable("studentId") Long studentId,
#RequestBody Student new_student) {
studentService.updateStudent(studentId, new_student);
}
and StudentService to :
#Transactional
public void updateStudent(Long studentId,Student new_student)
{
Student student = studentRepository.findById(studentId)
.orElseThrow(() -> new IllegalStateException(
"student with id="+studentId+"does not exist"));
if (new_student.getName() !=null && new_student.getName().length()>0 && !Objects.equals(student.getName(),new_student.getName()))
{
student.setName(new_student.getName());
}
if (new_student.getEmail() !=null && new_student.getEmail().length()>0 && !Objects.equals(student.getEmail(),new_student.getEmail()))
{
Optional<Student> studentOptional= studentRepository.findStudentByEmail(new_student.getEmail());
if (studentOptional.isPresent())
{
throw new IllegalStateException("email taken");
}
student.setEmail(new_student.getEmail());
}
}
and it worked but without the exceptions .
I want to convert firstname and lastname to json format.
#RestController
public class studentsController {
#GetMapping(value = "/students", produces = { MediaType.APPLICATION_JSON_VALUE } )
#ResponseBody
public String getWhoami(#RequestParam String firstname, #RequestParam String lastname ) {
return "firstname:" + firstname + " lastname: " + lastname;
}
}
How can I convert like these format;
{"firstname": "value1", "lastname": "value2"}
I tried to jackson but I couldn't.
You don't have to create json manually.
Create a class like:
class Student {
private String firstname;
private String lastname;
public Student(String firstname, String lastname) {
this.firstname = firstname;
this.lastname =lastname;
}
// getters and setter
}
#GetMapping(value = "/students", produces = { MediaType.APPLICATION_JSON_VALUE } )
#ResponseBody
public Student getWhoami(#RequestParam String firstname, #RequestParam String lastname ) {
return new Student(firstname, lastname);
}
You object will be converted to json automatically.
have you tried the jackson like this?
https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind
add in your class an instance like this:
ObjectMapper mapper = new ObjectMapper();
private ObjectMapper mapper = new ObjectMapper();
try function from the instance like this:
String jsonstr = mapper.writeValueAsString(object);
Lets say you already have the jackson library in your project (the jar file)
here's sample class:
public class SampleClass{
private ObjectMapper mapper = new ObjectMapper();
public String sampleMethodToJSONString(Student student){
return mapper.writeValueAsString(student);
}
}
You can change the return data type to use Map<String, String> instead of String or use ResponseBody<?>
I am trying to validate Employee Request and the validations should be different for post method,put method and delete method
public class Employee {
#NotNull(message = "Employee Id can not be null")
private Integer id;
#Min(value = 2000, message = "Salary can not be less than 2000")
#Max(value = 50000, message = "Salary can not be greater than 50000")
private Integer salary;
#NotNull(message = "designation can not be null")
private String designation;
}
For post method want to validate all the fields present in the request
#PostMapping("/employees")
public ResponseEntity<Void> addEmployee(#Valid #RequestBody Employee newEmployee) {
Employee emp= service.addEmployee(newEmployee);
if (emp== null) {
return ResponseEntity.noContent().build();
}
return new ResponseEntity<Void>(HttpStatus.CREATED);
}
For my put method I want to validate only Salary field and the remaining fields won't be validated
#PutMapping("/employees/{id}")
public ResponseEntity<Vehicle> updateEmployee(#Valid #RequestBody Employee updateEmployee) {
Employee emp= service.EmployeeById(updateEmployee.getId());
if (null == emp) {
return new ResponseEntity<Employee>(HttpStatus.NOT_FOUND);
}
emp.setSalary(updateEmployee.getSalary());
emp.setDesignation(updateEmployee.getDesignation());
service.updateEmployee(emp);
return new ResponseEntity<Employee>(emp, HttpStatus.OK);
}
For delete I don't want to perform any validation
#DeleteMapping("/employees/{id}")
public ResponseEntity<Employee> deleteEmployee(#Valid #PathVariable int id) {
Employee emp = service.getEmployeeById(id);
if (null == employee) {
return new ResponseEntity<Employee>(HttpStatus.FOUND);
}
service.deleteEmployee(id);
return new ResponseEntity<Employee>(HttpStatus.NO_CONTENT);
}
But if I use #Valid all the methods are getting validated with all the fields.
One way to achieve this, is to use #Validated from org.springframework.validation library instead of using #Valid annotation in the method parameters.
By this, you can group your constraints according to your requirements in the model (first group for POST method, second group for PUT method etc.) In the model, you need to use groups property and specify the name of the group that you want to bind with.
There is a detailed explanation, and giving sample codes about the use of it: here.
I am creating Spring Boot Web service and I have a Model Employee
public class Employee {
private String id;
private String name;
private String designation;
private int salary;
//Has Getters and Setters
}
I want to create a Get request which will fetching and filter the List of Employees based on the parameters given by user.
For example, if the user gives name of an employee and designation of employee, the get method should filter those result. For various combination of parameters it should work.
#Override
public List<Employee> getEmployees(Map<String, Object> parameters) {
if (parameters.size() == 0)
// code to return all employees;
List<Employee> selectedEmployees = new ArrayList<Employee>();
for(Employee currentEmployee: new ArrayList<Employee>(employee.values())) {
for(Map.Entry<String, Object> check: parameters.entrySet()) {
try {
if(check.getValue() instanceof Integer) {
int condition = (int) Employee.class.getMethod("get" + check.getKey()).invoke(currentEmployee);
if((int) check.getValue() == condition)
selectedEmployees.add(currentEmployee);
} else if (check.getValue() instanceof String) {
String condition = (String) Employee.class.getMethod("get" + check.getKey()).invoke(currentEmployee);
if (((String) check.getValue()).equals(condition))
selectedEmployees.add(currentEmployee);
}
} catch(Exception e){
e.printStackTrace();
}
}
}
return selectedEmployees;
}
In order to avoid multiple if else cases I am filtering list based on String and Integer above.
I think I am making an error in the below code which sending request in Controller.
#RequestMapping(value={"/employees","/{id}/{name}/{designation}/{salary}"})
public List<Employee> getEmployeeByProperty(EmployeeRequestParameters requestParams){
//Map for storing parameters to filter the List
Map<String, Object> filterParams = new HashMap<>();
if(requestParams.getIdParam().isEmpty()) {
filterParams.put("id", Integer.parseInt(requestParams.getIdParam()));
}
if(!requestParams.getNameParam().isEmpty()) {
filterParams.put("name", requestParams.getNameParam());
}
if(!requestParams.getDesignationParam().isEmpty()) {
filterParams.put("designation", requestParams.getDesignationParam());
}
if(requestParams.getSalaryParam().isEmpty()) {
filterParams.put("salary", Integer.parseInt(requestParams.getSalaryParam()));
}
return EmployeeService.getEmployeesByProperty(filterParams);
}
If {id} field is not full, {name} or {designation} or {salary} to be null.For {name} or {designation} or {salary} to be full Because should be {id} full.
#GetMapping("/employees")
public List<Employee> getEmployeeByProperty(#RequestParam(value = "id", required=false) String id,
#RequestParam(value = "name", required=false) String name,
#RequestParam(value = "designation", required=false) String designation,
#RequestParam(value = "salary", required=false) int salary) {
//Your codes
}
Even if {id} is empty, you can use others.
In doing a project using Spring MVC. The basic is: when a student signs up, his data will be stored in the database table and the password will be sent to the students mail address.
So I have:
#RequestMapping(value = "/save", method = RequestMethod.POST)
public String dosignup(#Valid #ModelAttribute("student") Student student, HttpServletRequest request,
HttpServletResponse response, BindingResult result) {
studentService.addNewStudent(student.getName(),
student.getUsername(), student.getEmail(), student.getPassword());
studentService.sendEmail(student);
}
StudentDao interface is:
public interface StudentDao {
public void saveStudent(Student student);
public void fetchinfo(Student student);
}
fetchinfo implementation in StudentDaoImpl is:
public void fetchinfo(Student student) {
String hql = "select password from student where email = :email";
sessionFactory.getCurrentSession().createSQLQuery(hql)
.setParameter("email", student.getEmail()).uniqueResult();
}
StudentService interface is:
public interface StudentService {
Student addNewStudent(String name, String username, String email, String password);
void sendEmail(Student student);
Student fetchinfo(String email);
}
and StudentServiceImpl is:
public User fetchinfo(String email) {
Student student = new Student(email);
studentDao.fetchinfo(student);
return student;
}
public void sendEmail(Student student) {
mailService.accountActivation(student);
}
Now, the problem is: a mail is sent to the students mail address, but the password is null. Can someone explain why this happens?
In StudentDaoImpl you are not setting the password property from the db query result. Rewrite relevant line as:
student.setPassword(sessionFactory.getCurrentSession().createSQLQuery(hql)
.setParameter("email", student.getEmail()).uniqueResult());
Update
While we are in Hibernate, by convention Student entity should have getters and setters for each property. Then I would rewrite StudentDaoImpl as:
public void fetchinfo(String email) {
String hql = "select s from student s where s.email = :email";
return (Student)sessionFactory.getCurrentSession().createSQLQuery(hql)
.setParameter("email", email).uniqueResult();
}
..and call it with student = studentDao.fetchinfo(email); (of course naming of methods should change).