IT story

Spring 3.0 MVC @ModelAttribute 변수가 URL에 나타나지 않도록하려면 어떻게해야합니까?

hot-time 2020. 12. 29. 07:52
반응형

Spring 3.0 MVC @ModelAttribute 변수가 URL에 나타나지 않도록하려면 어떻게해야합니까?


Spring MVC 3.0.0.RELEASE를 사용하여 다음 컨트롤러가 있습니다.

@Controller
@RequestMapping("/addIntake.htm")
public class AddIntakeController{

  private final Collection<String> users;

  public AddIntakeController(){
    users = new ArrayList<String>();
    users.add("user1");
    users.add("user2");
    // ...
    users.add("userN");
  }

  @ModelAttribute("users")
  public Collection<String> getUsers(){
    return this.users;
  }

  @RequestMapping(method=RequestMethod.GET)
  public String setupForm(ModelMap model){

    // Set up command object
    Intake intake = new Intake();
    intake.setIntakeDate(new Date());
    model.addAttribute("intake", intake);

    return "addIntake";
  }

  @RequestMapping(method=RequestMethod.POST)
  public String addIntake(@ModelAttribute("intake")Intake intake, BindingResult result){

    // Validate Intake command object and persist to database
    // ...

    String caseNumber = assignIntakeACaseNumber();

    return "redirect:intakeDetails.htm?caseNumber=" + caseNumber;

  }

}

Controller는 HTML 양식에서 채워진 명령 개체에서 Intake 정보를 읽고, 명령 개체의 유효성을 검사하고, 정보를 데이터베이스에 유지하고, 사례 번호를 반환합니다.

intakeDetails.htm 페이지로 리디렉션 할 때 다음과 같은 URL을 얻는 것을 제외하고는 모든 것이 잘 작동합니다.

http://localhost:8080/project/intakeDetails.htm?caseNumber=1&users=user1&users=user2&users=user3&users=user4...

사용자 컬렉션이 URL에 표시되지 않도록하려면 어떻게해야합니까?


Spring 3.1부터는 컨트롤러가 리디렉션하는 경우 기본 모델의 콘텐츠 사용을 방지하는 데 사용할 수 RequestMappingHandlerAdapter있는 플래그를 제공합니다 ignoreDefaultModelOnRedirect.


model.asMap().clear();
return "redirect:" + news.getUrl();

:)


이 문제를 해결하는 좋은 방법은 없습니다 (즉, 사용자 지정 구성 요소를 만들지 않고 과도한 양의 명시 적 xml 구성없이을 수동으로 인스턴스화하지 않음 RedirectView).

RedirectView4 인수 생성자를 통해 수동으로 인스턴스화 하거나 컨텍스트에서 다음 빈을 선언 할 수 있습니다 (다른 뷰 리졸버 근처).

public class RedirectViewResolver implements ViewResolver, Ordered {
    // Have a highest priority by default
    private int order = Integer.MIN_VALUE; 

    // Uses this prefix to avoid interference with the default behaviour
    public static final String REDIRECT_URL_PREFIX = "redirectWithoutModel:";     

    public View resolveViewName(String viewName, Locale arg1) throws Exception {
        if (viewName.startsWith(REDIRECT_URL_PREFIX)) {
            String redirectUrl = viewName.substring(REDIRECT_URL_PREFIX.length());
            return new RedirectView(redirectUrl, true, true, false);
        }
        return null;
    }

    public int getOrder() {
        return order;
    }

    public void setOrder(int order) {
        this.order = order;
    }
}

@ModelAttribute방법 주석이 사용되도록 의도되는 참조 데이터를 노출 뷰 층. 귀하의 경우에는 확실히 말할 수는 없지만 사용자 집합이 참조 데이터로 자격이 있다고 말하지는 않습니다. @RequestMapping주석 처리기 메서드 에서이 정보를 모델에 명시 적으로 전달하는 것이 좋습니다 .

그래도을 사용 하려면 리디렉션 문제를 설명 @ModelAttribute하는 블로그 항목이 여기에 있습니다.

그러나 모든 이전 예제에는 처리기가 실행되기 전에 모든 @ModelAttribute 메서드가 실행되므로 처리기가 리디렉션을 반환하면 모델 데이터가 쿼리 문자열로 url에 추가되므로 일반적인 문제가 있습니다. 응용 프로그램을 구성하는 방법에 대한 몇 가지 비밀을 노출 할 수 있으므로 모든 비용을 들이지 않아야합니다.

그의 제안 된 솔루션 (블로그의 파트 4 참조)은 a HandlerInterceptorAdapter를 사용하여보기에 공통 참조 데이터를 표시하는 것입니다. 참조 데이터는 컨트롤러와 밀접하게 연결되어서는 안되므로 설계 상 문제가되지 않아야합니다.


나는이 질문과 대답이 오래되었다는 것을 알고 있지만 비슷한 문제를 겪은 후 우연히 발견했으며 찾을 수있는 다른 정보가 많지 않습니다.

나는 받아 들여진 대답이 아주 좋은 대답이 아니라고 생각한다. axtavt의 바로 아래 답변이 훨씬 낫습니다. 문제는 컨트롤러에서 모델 속성에 주석을다는 것이 합당한 지 여부가 아닙니다. 일반적으로 ModelAttributes를 사용하는 컨트롤러 내에서 "깨끗한"리디렉션을 실행하는 방법에 대한 것입니다. 컨트롤러 자체에는 일반적으로 참조 데이터가 필요하지만 예외적 인 조건 등을 위해 다른 곳으로 리디렉션해야하는 경우가 있으며 참조 데이터를 전달하는 것이 의미가 없습니다. 나는 이것이 유효하고 일반적인 패턴이라고 생각합니다.

(Fwiw, Tomcat에서 예기치 않게이 문제가 발생했습니다. 리디렉션이 작동하지 않고 다음과 같은 이상한 오류 메시지가 표시되었습니다. java.lang.ArrayIndexOutOfBoundsException : 8192. 결국 Tomcat의 기본 최대 헤더 길이가 8192라고 결정했습니다. t ModelAttributes가 리디렉션 URL에 자동으로 추가되고 있으며 이로 인해 헤더 길이가 Tomcat의 최대 헤더 길이를 초과한다는 사실을 인식합니다.)


복사 및 붙여 넣기가 덜 포함 된 Sid의 답변 변형을 구현했습니다 .

public class RedirectsNotExposingModelUrlBasedViewResolver extends UrlBasedViewResolver {

    @Override
    protected View createView(String viewName, Locale locale) throws Exception {
        View view = super.createView(viewName, locale);
        if (view instanceof RedirectView) {
            ((RedirectView) view).setExposeModelAttributes(false);
        }
        return view;
    }

}

또한 정의 할보기 해석기 Bean이 필요합니다.

<bean id="viewResolver" class="com.example.RedirectsNotExposingModelUrlBasedViewResolver">
    <property name="viewClass" value="org.springframework.web.servlet.view.tiles2.TilesView"/>
</bean>

내 응용 프로그램에서 리디렉션에 모델 속성을 노출하는 사용 사례가 없으므로 org.springframework.web.servlet.view.UrlBasedViewResolver를 확장하여 createView 메서드를 재정의하고 응용 프로그램 컨텍스트에서 선언했습니다.

public class UrlBasedViewResolverWithouthIncludingModeAtttributesInRedirect extends   UrlBasedViewResolver {

        @Override
        protected View createView(String viewName, Locale locale) throws Exception {
            // If this resolver is not supposed to handle the given view,
            // return null to pass on to the next resolver in the chain.
            if (!canHandle(viewName, locale)) {
                return null;
            }
            // Check for special "redirect:" prefix.
            if (viewName.startsWith(REDIRECT_URL_PREFIX)) {
                String redirectUrl = viewName.substring(REDIRECT_URL_PREFIX.length());
                boolean exposeModelAttributes = false;
                return new RedirectView(redirectUrl, isRedirectContextRelative(), isRedirectHttp10Compatible(), exposeModelAttributes);
            }
            // Check for special "forward:" prefix.
            if (viewName.startsWith(FORWARD_URL_PREFIX)) {
                String forwardUrl = viewName.substring(FORWARD_URL_PREFIX.length());
                return new InternalResourceView(forwardUrl);
            }
            // Else fall back to superclass implementation: calling loadView.
            return super.createView(viewName, locale);
        }

}


  <bean id="viewResolver" class="com.acme.spring.UrlBasedViewResolverWithouthIncludingModeAtttributesInRedirect">

  </bean>

manually creating a RedirectView object worked for me:

@RequestMapping(method=RequestMethod.POST)
public ModelAndView addIntake(@ModelAttribute("intake")Intake intake, BindingResult result){

    // Validate Intake command object and persist to database
    // ...

    String caseNumber = assignIntakeACaseNumber();

    RedirectView rv = new RedirectView("redirect:intakeDetails.htm?caseNumber=" + caseNumber);
    rv.setExposeModelAttributes(false);
    return new ModelAndView(rv); 
}

IMHO this should be the default behavior when redirecting


Or, make that request a POST one. Get requests will only display the model attributes as request parameters appearing in the URL.


Here is how to do it with Java-based configuration (Spring 3.1+ I think, tested with 4.2):

@Configuration
public class MvcConfig extends WebMvcConfigurationSupport {

    @Override
    @Bean
    public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
        RequestMappingHandlerAdapter adapter = super.requestMappingHandlerAdapter();
        adapter.setIgnoreDefaultModelOnRedirect(true);
        return adapter;
    }

    // possible other overrides as well

}

Don't use @ModelAttribute. Store the users in the ModelMap explicitly. You're doing as much with the command object anyway.

@RequestMapping(method=RequestMethod.GET)
    public String setupForm(ModelMap model){

        // Set up command object
        Intake intake = new Intake();
        intake.setIntakeDate(new Date());
        model.addAttribute("intake", intake);

        model.addAttribute("users", users);

        return "addIntake";
    }

The disadvantage to this is if a validation error takes place in addIntake(). If you want to simply return the logical name of the form, you must also remember to repopulate the model with the users, otherwise the form won't be setup correctly.


There is a workaround if it helps your cause.

      @ModelAttribute("users")
      public Collection<String> getUsers(){
           return this.users;
      }

Here you have made it return Collection of String. Make it a Collection of User (it may be a class wrapping string representing a user, or a class with a bunch of data regarding a user). The problem happens with strings only. If the returned Collection contains any other object, this never happens. However, this is just a workaround, and may be, not required at all. Just my two cents. Just make it like -

      @ModelAttribute("users")
      public Collection<User> getUsers(){
           return this.users;
      }

try adding below code into the servlet-config.xml

<mvc:annotation-driven ignoreDefaultModelOnRedirect="true" />

sometimes this will solve the issue.

ReferenceURL : https://stackoverflow.com/questions/2163517/how-do-i-prevent-spring-3-0-mvc-modelattribute-variables-from-appearing-in-url

반응형