Spring 4 MVC updates entity before modifying post

2019-09-12 16:41发布

问题:

Controller:

@PreAuthorize("@securityService.isAdminForSurvey(principal.user, #survey)")
@RequestMapping(value = "/service-management/surveys/{survey}/edit", method = RequestMethod.GET)
public String editSurvey(@PathVariable Survey survey, Model model) {

    model.addAttribute("survey", survey);


@PreAuthorize("@securityService.isAdminForSurvey(principal.user, #survey)")
@RequestMapping(value = "/service-management/surveys/{survey}/edit", method = RequestMethod.POST)
public String editSurvey(@ModelAttribute("survey") Survey survey, SessionStatus sessionStatus) {
        surveyService.update(survey);

Converter:

@Component
public class SurveyConverter implements Converter<String, Survey> {
    @Autowired
    private SurveyService surveyService;
    @Override
    public Survey convert(String hash){
        try {
            return surveyService.getSurveyByHash(hash);
        }catch(NumberFormatException e){
            return null;
    }

}

}

When I send post request with modified data from spring form, somehow object is updated before calling to security service. Repository returns already updated survey entity with values from the form before even calling save method. How it's even possible?

EDIT for showing that security service methods fires here is some logs with method calls queue:

2016-04-12 15:08:44.282  INFO 12496 --- [nio-8080-exec-8] ....service.SurveyServiceImpl       : [.....service.SurveyServiceImpl.getSurveyByHash(SurveyServiceImpl.java:87)]
2016-04-12 15:08:44.290  INFO 12496 --- [nio-8080-exec-8] ....security.SecurityService    : [.....security.SecurityService.isAdminForSurvey(SecurityService.java:38)]
2016-04-12 15:08:44.295  INFO 12496 --- [nio-8080-exec-8] ....controller.SurveyController     : [....controller.SurveyController.editSurvey(SurveyController.java:362)]

Issue investigation lead to next conclusion:

  1. #survey parameter in @PreAuthorize have been misused because it aimed to model attribute, not to path variable as was expected.
  2. Form from jsp page was automatically binded by spring to survey object because both @PathVariable and @ModelAttribute had same names.

Solution is to use different names for @PathVariable and @ModelAttribute. In that case converter behaves correctly - converts value from url, and @ModelAttribute object contains values from the form. Can someone light up why Spring behaves this way? Similar behavior were observed on Spring 3.

same logs with sql

2016-04-13 00:41:18.636  INFO 4445 --- [nio-8080-exec-6] .....service.SurveyServiceImpl       : [.....service.SurveyServiceImpl.getSurveyByHash(SurveyServiceImpl.java:87)]
Hibernate: 
select
    survey0_.id as id1_11_,
    survey0_.hash as hash19_11_,
    survey0_.version as version48_11_ 
from
    survey survey0_ 
where
    survey0_.hash=?
Hibernate: 
select
    adminsurve0_.id as id1_0_0_,
    adminsurve0_.enable_edit as enable_e2_0_0_,
    adminsurve0_.survey_id as survey_71_0_0_ 
from
    admin_survey_permissions adminsurve0_ 
where
    adminsurve0_.survey_id=?
2016-04-13 00:41:18.646  INFO 4445 --- [nio-8080-exec-6] ....security.PtspSecurityService    : [.....security.PtspSecurityService.isAdminForSurvey(PtspSecurityService.java:38)]
Hibernate: 
select
    'true' as col_0_0_ 
from
    users user0_ 
where
    user0_.id=? 
    and (
        user0_.is_super_admin=true 
        or user0_.is_admin=true 
    )
2016-04-13 00:41:18.653  INFO 4445 --- [nio-8080-exec-6] .....controller.SurveyController     : [.....controller.SurveyController.editSurvey(SurveyController.java:362)]
Hibernate: 
select
    adminsurve0_.id as id1_0_,
    adminsurve0_.enable_edit as enable_e2_0_,
    adminsurve0_.survey_id as survey_71_0_ 
from
    admin_survey_permissions adminsurve0_ 
left outer join
    survey survey1_ 
        on adminsurve0_.survey_id=survey1_.id 
where
    survey1_.id=?

NOTE:

sql output were shortened because object contains a lot of fields with some data to fetch on.