Actually, you should disallow the "id" field both when adding AND updating. Otherwise a malicious user could tamper with the value of the "id" request parameter of an update request and thereby update a different record to the one shown by the form (assuming there's no ACLs or other domain-level security).
However if you simply disallow the "id" field, the controller will treat the ID as being null, which will work when inserting but not when updating (e.g. it might try to insert a new record instead of updating, depending on what persistence mechanism you're using). So you want the controller to remember the non-editable values of your domain object (not just IDs, but all disallowed fields) between requests so that it can send all the correct values to the service layer or other business logic. This is done using the type-level @SessionAttributes annotation, as follows (other annotations omitted for clarity):
@SessionAttributes("thing") // the name of your domain object in the model
public class ThingController {
public void setDisallowedFields(WebDataBinder binder) {
binder.setDisallowedFields("id", "someOtherUneditableField");
}
// request handling methods go here as before
}
For even better security, set the allowed fields rather than the disallowed fields. Either way you need the @SessionAttributes annotation to fill in whatever existing field values are ignored from the request.