Announcement Announcement Module
Collapse
No announcement yet.
Clearing Fields Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Clearing Fields

    I have a domain object which I am presenting on a typical form. Here is a simplified example:

    Code:
    public class Name implements Keyed {
    
        private String firstName;
        private String middleName;
        private String lastName;
        private Number key;
    
        //Getters and Setters
    }
    Let's say I have two type of users whom can each modify these Name objects. For some silly reason one group is not allowed to see / edit the middle names of the users. So I leave that field off of the form (no hidden field either).

    Is there anyway to keep Spring from clearing that middle name field (i.e it wasn't displayed to the user, hence it couldn't have changed)?

    I could create a new object for this, but it seems like duplication which shouldn't be needed.

  • #2
    Could you show your controller update method please? Also form markup could be helpful.

    Comment


    • #3
      Controller Code:
      Code:
          @RequestMapping()
          public ModelAndView nameModification(@ModelAttribute("name") Name name, BindingResult result) {
              
              ModelAndView mav = new ModelAndView("pages/editName");
      
              if (name == null || name.isEmpty()) {
                  name = nameDao.getValue(1); // Hard coding just for ex
              }
      
              logger.debug(name.toString());  
              mav.addObject("name", name);       
              return mav;
              
          }
      We are using velocity, so below is the code

      Code:
      <form target="_self" enctype="application/x-www-form-urlencoded" action="changeName.vm" method="post">
      
          <span>Full Name</span>
          #springBind("name.first")
          <label for="name.first">First Name: </label>
          #springFormInput("name.first", "")
       
          #springBind("name.last")
           <label for="name.last">Last Name: </label>
           #springFormInput("name.last", "")
      
      </form>
      So on the get, let's say our dao returns the following name:

      Samuel Langhorne Clemens

      Upon posting (for someone whom can only see first and last names), say the user inputs Mark Twain.

      The name is now Mark Twain --> Langhorne is now gone.

      Comment


      • #4
        Ok, now I understand your problem.

        In fact that is by design. The name instance that is passed to controller method is created from the request parameters, the process is called binding. So if your form doesn't contain middle field it has no way to appear in the name parameter passed to controller. The key point here is that it has nothing to do with your DAO.

        Let's have a good look at your particular example. Pretend you have a Name stored in the DB with id = 1, name = Samuel, middle = Langhorne and last = Clemens. Let's also pretend that you have two user roles: ROLE_A can change name and middle, ROLE_B can change name and last.

        First this to do is to display relevant fields for the form depending on user role:
        HTML Code:
        <form target="_self" enctype="application/x-www-form-urlencoded" action="changeName.vm" method="post">
            <span>Full Name</span>
            #springBind("name.first")
            <label for="name.first">First Name: </label>
            #springFormInput("name.first", "")
        
            #if($security.AllGranted("ROLE_A"))
            #springBind("name.middle")
            <label for="name.middle">Middle Name: </label>
            #springFormInput("name.middle", "")
            #end
        
            #if($security.AllGranted("ROLE_B"))
            #springBind("name.last")
            <label for="name.last">Last Name: </label>
            #springFormInput("name.last", "")
            #end
        </form>
        See these posts for how to get $security available in your templates. Note, I haven't tried it myself, but it should work .

        Now you need to obtain the Name stored in the DB using the submitted id (1), update properties allowed depending on roles current user is (2) (since nothing prevents him from POSTing fields not shown in markup, never trust the user ) and then save it back to the db (3).
        Code:
        @RequestMapping
        public ModelAndView nameModification(Name name, BindingResult result) {
            Name originalName = nameDao.getById(name.getId()); // (1)
            
            // TODO: Handle missing DB entry somehow
        
            boolean hasRoleA = false;
            boolean hasRoleB = false;
            for (GrantedAuthority authority : SecurityContextHolder.getContext().getAuthentication().getAuthorities()) { // (2)
                if (authority.getAuthority().equals("ROLE_A")) {
                    hasRoleA = true;
                } else if (authority.getAuthority().equals("ROLE_A")) {
                    hasRoleB = true;
                }
            }
            
            originalName.setName(name.getName());
            if (hasRoleA) { // (2)
                originalName.setMiddle(name.getMiddle());
            }
            if (hasRoleB) { // (2)
                originalName.setLast(name.getLast());
            }
        
            nameDao.save(originalName); // (3)
            
            ModelAndView mav = new ModelAndView("pages/editName");
        
            logger.debug(originalName.toString());  
            mav.addObject("name", originalName);       
            return mav;
        }

        Comment


        • #5
          That's a pretty painful process on our DB!

          We first must lookup the user (if one exists on the initial search page), then redirect them to this new page, where we must again pull them from the DB to ensure freshness.

          Then upon posting, we have to pull them from the DB to persist the middle name?

          That's 3 hits for lookup, plus another one to save the user (if changes occur).
          Not to mention the fact that we'd then have to implement our security code to utilize spring security as well (although I'd see this as a win, I'm not so sure others on the team would).

          Comment


          • #6
            Originally posted by sgentry View Post
            That's a pretty painful process on our DB!
            Oh, please don't blame me That's your business requirements. But I doubt it is a huge DB hit. How often is this name change used in your system? Is it at least 10% of use cases? Also note that fetching a row by primary key (that's what we are doing in this code) is extremely optimized in all DBMS I've heard of.

            Originally posted by sgentry
            We first must lookup the user (if one exists on the initial search page), then redirect them to this new page, where we must again pull them from the DB to ensure freshness.
            I wasn't aware of these two steps performed before Name update since you didn't mention them, but I don't think there's another option here.

            Originally posted by sgentry
            Then upon posting, we have to pull them from the DB to persist the middle name?

            That's 3 hits for lookup, plus another one to save the user (if changes occur).
            In fact you may omit this fetch. Implement two extra methods updateNameAndLast(Name name) and updateNameAndMiddle(Name name). Depending on underlying technology used you'll need to create a custom SQL/HQL/JPQL update query for each of them.

            Originally posted by sgentry
            Not to mention the fact that we'd then have to implement our security code to utilize spring security as well (although I'd see this as a win, I'm not so sure others on the team would).
            Well, Spring Security is not a must. I just thought you are already using it since you mentioned two type of users in your initial post. Just substitute the view and controller logic based on Spring Security with the one you already use, I just showed the concept.

            Comment


            • #7
              Haha, no blame intended to be implied.

              While you're correct on the part of lookup on primary key, we have other instances where we are dealing with many many results. Looking up by that type of query is expensive. We're also likely to experience large user growth, so any extra performance I can squeeze out of the DB will be greatly appreciated.

              I hadn't mentioned the PRG pattern, but that is how these pages are being dealt with.

              Thanks for your example.

              Comment

              Working...
              X