【问题标题】:Update form: Spring mvc + thymeleaf更新形式:Spring mvc + thymeleaf
【发布时间】:2014-11-27 09:56:14
【问题描述】:

我正在尝试创建一个 thymeleaf 表单来仅更新支持对象的几个属性:

@RequestMapping(value = "/jobs/{id}", method = RequestMethod.GET)
public ModelAndView update(@PathVariable Integer id ) {
    ModelAndView mav = new ModelAndView("updateJob.html");
    JobDescription updateJob = jobDescriptionService.findByID(id);
    mav.addObject("updateJob", updateJob);
    return mav;
}

@RequestMapping(value = "/jobs/{id}", method = RequestMethod.PUT)
public String saveUpdate(@PathVariable Integer id, @ModelAttribute("updateJob") JobDescription updateJob) {
    jobDescriptionService.update(updateJob);
    return "redirect:/jobs/" + id;
}


<form th:action="@{'/jobs/'+ ${updateJob.id}}" th:object="${updateJob}" th:method="PUT">
    <table>
        <tr>
            <td><label>Description</label></td>
            <td><input type="text" th:field="*{description}" /></td>
        </tr>
        <tr>
            <td><label>Deadline</label></td>
            <td><input type="text" th:field="*{deadline}" /></td>
        </tr>
        <tr>
            <td></td>
            <td><button type="submit">Update</button></td>
        </tr>
    </table>
</form>

问题是作业对象有几个我不想更新的其他属性(如 id、createdDate 等)。但是,当我单击更新表单的提交按钮时,在 saveUpdate 方法中创建的对象将这些属性设置为 null(除非我将它们设置在表单内的隐藏字段中)。有没有其他方法可以保留它们?

【问题讨论】:

    标签: spring-mvc thymeleaf


    【解决方案1】:

    我和你有同样的问题,所以我建立了自己的解决方案

    1- 您需要在控制器上执行两个操作:视图 (GET) 和操作 (POST)

    @GetMapping("/user/edit/{userId}")
    public ModelAndView editUserView(@PathVariable Long userId) throws NotFoundException {
    
        User user = this.userService.load(userId);
    
        if (user == null) {
            throw new NotFoundException("Not found user with ID " + userId);
        }
    
        ModelAndView modelAndView = new ModelAndView();
    
        modelAndView.setViewName("user.edit");
        modelAndView.addObject("user", user);
    
        return modelAndView;
    }
    
    @PostMapping("/user/edit/{userId}")
    public ModelAndView editUserAction(HttpServletRequest request, @PathVariable Long userId, @Validated(User.ValidationUpdate.class) User userView,
            BindingResult bindingResult) throws Exception {
    
        User user = this.userService.load(userId);
    
        if (user == null) {
            throw new NotFoundException("Not found user with ID " + userId);
        }
    
        ModelAndView modelAndView = new ModelAndView();
        if (bindingResult.hasErrors()) {            
            modelAndView.setViewName("user.edit");
            modelAndView.addObject("user", userView);
    
            return modelAndView;
        }
    
        Form.bind(request, userView, user);
    
        this.userService.update(user);
    
        modelAndView.setViewName("redirect:/admin/user");
    
        return modelAndView;
    }
    

    2- 一个显示错误的视图(非常重要:添加隐藏输入以发送 id 进行验证)

    <fieldset th:if="${#fields.hasErrors('${user.*}')}" class="text-warning">
        <legend>Some errors appeared !</legend>
        <ul>
            <li th:each="err : ${#fields.errors('user.*')}" th:text="${err}"></li>
        </ul>
    </fieldset>
    
     <form action="#" th:action="@{/admin/user/edit/{id}(id=${user.id})}" th:object="${user}" method="post">
          <div th:class="${#fields.hasErrors('firstName')} ? 'form-group has-error' : 'form-group'">
              <label class="control-label" for="firstName">First Name <span class="required">*</span></label>
              <input type="text" th:field="*{firstName}" required="required">
          </div>
          ...
        <input type="hidden" th:field="*{id}">
    </form>
    

    3- 对于我的示例,我编写了一个 FormUtility 类来合并两个对象:

    public static List<String> bind(HttpServletRequest request, Object viewObject, Object daoObject) throws Exception {
    
        if (viewObject.getClass() != daoObject.getClass()) {
            throw new Exception("View object and dao object must have same type (class) !");
        }
    
        List<String> errorsField = new ArrayList<String>();
    
        // set field value
        for (Entry<String, String[]> parameter : request.getParameterMap().entrySet()) {
    
            // build setter/getter method
            String setMethodName = "set" + parameter.getKey().substring(0, 1).toUpperCase()
                    + parameter.getKey().substring(1);
            String getMethodName = "get" + parameter.getKey().substring(0, 1).toUpperCase()
                    + parameter.getKey().substring(1);
    
            try {
                Method getMethod = daoObject.getClass().getMethod(getMethodName);
                Method setMethod = daoObject.getClass().getMethod(setMethodName, getMethod.getReturnType());
                setMethod.invoke(daoObject, getMethod.invoke(viewObject));
            }
            catch (NoSuchMethodException | IllegalAccessException | IllegalArgumentException
                    | InvocationTargetException exception) {
                errorsField.add(parameter.getKey());
            }
        }
    
        return errorsField;
    }
    

    希望对您有所帮助。

    【讨论】:

      【解决方案2】:

      最安全的方法是通过 id 加载原始作业对象,并在其上设置新值,然后对其进行更新...类似于:

      JobDescription originalJob = jobDescriptionService.findById(updateJob.getId());
      
      originalJob.setParamForUpdate(updateJob.getParamForUpdate());
      originalJob.setAnotherParamForUpdate(updateJob.getAnotherParamForUpdate());
      
      jobDescriptionService.update(originalJob);
      

      这将保存您想要保持不变的所有数据...

      【讨论】:

      • 如何检测哪些字段发生了变化?
      • 通过与原始值比较。如果你当然有几个......如果你有超过 10 个字段,你可以编写一个通用方法,它接受两个对象并使用反射比较它们的变化。这样就可以再次重复使用。这是使用反射的示例pastebin.com/4zrXFhic。更改它以满足您的需要
      【解决方案3】:
      enter code here
      @PostMapping("/save_data")
      public String registeruser(@ModelAttribute("patient") Patient patient) {
          p.save(patient);
          return "redirect:/";
      }
       @RequestMapping("/edit/{id}")
      public ModelAndView showEditProductPage(@PathVariable(name = "id") int id) {
      ModelAndView mav = new ModelAndView("edit_product");
      Patient patient = p.findById(id).get();
      p.delete(patient);
      mav.addObject("patient", patient);
      return mav;
      }
      enter code here
      
      <form th:action="@{/save_data}" method="post" th:object="${patient}" >
      <div class="contact-grids1 w3agile-6">
      <div class="row">
      <div class="col-md-6 col-sm-6 contact-form1 form-group">
      <label for="exampleInputEmail1"> Name</label>
      <input type="text"
      name="name"
      class="form-control"
      id="name"
      aria-describedby="emailHelp"
      placeholder="Enter Here"
      required
      th:field="*{name}"/>
      
      
      </div>
      <div class="col-md-6 col-sm-6 contact-form1 form-group">
      <label class="col-form-label">Email</label>
      <input type="email"
      class="form-control"
      placeholder="Enter email"
      name="email"
      id="email"
      required
      th:field="*{email}" />
      </div>
      
       <div class="col-md-6 col-sm-6 contact-form1 form-group">
       <label class="col-form-label">Password</label>
       <input type="password"
       class="form-control"
        placeholder="Enter Password"
        name="password"
        id="password"
        required
        th:field="*{password}" />
        </div>
      
      
      
        <div class="col-md-6 col-sm-6 contact-form1 form-group">
        <label class="col-form-label">Phone</label>
        <input type="number" class="form-control"
        placeholder="Enter Phone Number"
        name="phone"
        id="phone"
        required  th:field="*{phone}" />
         </div>
         <div class="col-md-6 col-sm-6 contact-form1 form-group">
         <label class="col-form-label">Address</label>
         <textarea class="form-control"
          placeholder="Enter Address"
          id="address"
         rows="6"
         name="address"
         required th:field="*{address}" ></textarea>
         <p id="error_description"></p>
         </div>
      
      
         </div>
      
      <button type="submit" class="btn bg-primary text-white" >
      Submit
      </button>
         <a href="/show_data" style="float:left;" class="btn btn-success text-right">Show 
       All</a>
       </div>
          <br>
      
        </form>
      
      
      Need more help please visit this link :- 
       https://github.com/Gaurav0807/SpringBoot-Form-Crud-Operation
      

      【讨论】:

        【解决方案4】:
        var editOptions = {
            url: '/Admin/EditPost', 
            editCaption: 'Edit Post',
            processData: "Saving...",
            width: 900,
            closeAfterEdit: true,
            closeOnEscape: true,
            afterclickPgButtons: afterclickPgButtons,
            afterShowForm: afterShowForm,           
            onClose: onClose,
            afterSubmit: JustBlog.GridManager.afterSubmitHandler,
            beforeSubmit: beforeSubmitHandler
        };
        
        $(gridName).navGrid(pagerName, 
        {
            cloneToTop: true,
            search: false
        }, 
        editOptions, addOptions, {}); 
        

        【讨论】:

        • 代码转储不可取。解释这是如何解决问题的。另外,我很确定 OP 使用的是 Java,而不是 JavaScript。
        猜你喜欢
        • 2023-03-07
        • 2017-03-15
        • 2013-08-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-01-07
        • 2018-06-12
        • 2019-06-28
        相关资源
        最近更新 更多