javaspringspring-bootspring-mvcmodelattribute

modelAttribute in jsp page returning null on non input fields


Im using modelAttribute to bind the object with the model class in my form, As you have to mention the varibale on the get request of the form before hand i did that and all the values are being fairly printed on the page,

Now on the page im taking an input of an attribute which is further mapped with another entity by a OnetoOne mapping. But on posting, only the OneToOne entity is returning the value, all the rest attributes are returning null.

Controller

@GetMapping("/users/{username}/complaint")
    public String userRegisterComplaintRoute(Model model, @PathVariable String username) {
        model.addAttribute("user", userService.findSingleUserDetails(username));
        return "complaint-index";
    }

    @PostMapping("/users/complaint")
    public String userRegisterComplaintPostRoute(Model model, User user) {
        System.out.println(user);
        // userService.addUserDetails(user);

        return "redirect:/users/" + user.getName() + "/complaint/status";
    }

Form

<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Kolkata | CRS</title>
    </head>
    <body>
        <h1>Username ${user.username}</h1>
        <h1>Username ${user.name}</h1>
        <h1>Username ${user.password}</h1>
        <h1>Username ${user.roles}</h1>

        <form:form
            action="/users/complaint"
            method="post"
            modelAttribute="user"
        >
            <form:label path="complaint.text" for="complaint"
                >Complaint</form:label
            >
            <form:input
                type="text"
                name="complaint"
                id="complaint"
                path="complaint.text"
            ></form:input>

            <button type="submit">Submit</button>
        </form:form>
    </body>
</html>

User Class

package com.naha.crimereportingsystem.user;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;

import com.naha.crimereportingsystem.complaint.Complaint;

@Entity
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int id;
    private String name;
    private String username;
    private String password;
    private boolean active = true;
    private String roles = "ROLE_USER";

    @OneToOne(targetEntity = Complaint.class, cascade = CascadeType.ALL)
    private Complaint complaint;

    public String getUsername() {
        return username;
    }

    public Complaint getComplaint() {
        return complaint;
    }

    public void setComplaint(Complaint complaint) {
        this.complaint = complaint;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getRoles() {
        return roles;
    }

    public void setRoles(String roles) {
        this.roles = roles;
    }

    public boolean isActive() {
        return active;
    }

    public void setActive(boolean active) {
        this.active = active;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public User() {
    }

    public User(int id, String name, String username, String password, boolean active, String roles) {
        this.id = id;
        this.name = name;
        this.username = username;
        this.password = password;
        this.active = active;
        this.roles = roles;
        this.complaint = new Complaint();
    }

    @Override
    public String toString() {
        return "id: " + this.id + "\nname: " + this.name + "\nusername: " + this.username + "\ncomplaint:"
                + this.complaint.getText();
    }

}

Compaint Class

package com.naha.crimereportingsystem.complaint;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class Complaint {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;
    private String text;
    private String status = "Investigation Pending";

    public long getId() {
        return id;
    }

    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

    public void setId(long id) {
        this.id = id;
    }

    public Complaint() {
    }

    public Complaint(long id, String text, String status) {
        this.id = id;
        this.text = text;
        this.status = status;
    }

}

toString output enter image description here


Solution

  • When you are posting a form, only the user input data are sent with request. And only those data gets bound to command object.

    One naive solution is to put hidden fields in the form. But Spring has a nice solution for this.

    Use @SessionAttributes on your controller.

    @SessionAttributes("commandNameHere")
    public class FooController {
       // code
    
        @RequestMapping("/foo", method = POST)
        public String foo(SessionStatus status) {
        // code
        
        status.setComplete(); // marks for cleanup of session attributes
    }
    

    Spring will place the command object into a transparent session. Fields that are not found in form data, will be bound from that session.

    Also, in your post mapping, use @ModelAttribute on the command object to resolve the command object from model.


    Further Reading