Подтвердить что ты не робот

Как предотвратить появление переменных 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;

  }

}

Контроллер считывает информацию о входе из объекта команды, заполненного формой HTML, проверяет объект команды, сохраняет информацию в базе данных и возвращает номер дела.

Все отлично работает, за исключением случаев, когда я перенаправляю на страницу incomingDetails.htm, я получаю URL-адрес, который выглядит следующим образом:

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

Как предотвратить сбор пользовательской коллекции в URL?

4b9b3361

Ответ 1

Поскольку spring 3.1, RequestMappingHandlerAdapter предоставляет флаг с именем ignoreDefaultModelOnRedirect, который можно использовать для предотвращения использования содержимого модели defautl, если контроллер перенаправляет.

Ответ 2

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

:)

Ответ 3

Нет никаких хороших способов решения этой проблемы (т.е. без создания пользовательских компонентов без чрезмерного количества явной конфигурации xml и без ручного создания экземпляра RedirectView).

Вы можете либо создать экземпляр RedirectView вручную, используя его конструктор с 4 аргументами, либо объявить следующий bean в своем контексте (рядом с другими разрешениями представления):

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;
    }
}

Ответ 4

Аннотация метода @ModelAttribute предназначена для использования отображения ссылочных данных на уровне представления. Я не могу сказать точно в вашем случае, но я бы не сказал, что набор пользователей, квалифицированных как справочные данные. Я предлагаю вам передать эту информацию через модель явно в ваши методы @RequestMapping -annotated handler.

Если вы все еще хотите использовать @ModelAttribute, здесь есть запись , в которой обсуждается проблема с перенаправлением.

Но все предыдущие примеры имеют общая проблема, так как все @ModelAttribute методы выполняются до того, как обработчик выполняется, если обработчик возвращает перенаправить данные модели будут добавлены к URL-адресу в качестве строки запроса. Эта следует избегать любой ценой, поскольку это может раскрывать некоторые секреты о том, как вы собрали ваше приложение.

Его предлагаемое решение (см. часть 4 блога) заключается в использовании HandlerInterceptorAdapter, чтобы сделать общие ссылочные данные видимыми для представления, Поскольку справочные данные не должны быть тесно связаны с контроллерами, это не должно создавать проблем, конструктивно.

Ответ 5

Я знаю, что этот вопрос и ответ устарел, но я наткнулся на него после того, как у меня возникли аналогичные проблемы, и там не так много другой информации, которую я мог найти.

Я думаю, что принятый ответ не очень хороший. Ответ прямо под ним axtavt намного лучше. Вопрос заключается не в том, имеет ли смысл аннотировать атрибуты модели на контроллере. Это о том, как выдать "чистую" переадресацию из контроллера, который обычно использует ModelAttributes. Сам контроллер обычно требует справочных данных, но иногда ему необходимо перенаправить где-то еще в исключительные условия или что-то еще, и передача ссылочных данных не имеет смысла. Я думаю, что это правильный и общий шаблон.

(Fwiw, я неожиданно столкнулся с этой проблемой с Tomcat. Перенаправления просто не работали, и я получал нечетные сообщения об ошибках вроде: java.lang.ArrayIndexOutOfBoundsException: 8192. В конечном итоге я определил, что максимальная длина заголовка Tomcat равна 8192. Я не понимал, что атрибуты ModelAttributes автоматически добавляются к URL-адресу переадресации, и это приводит к тому, что длина заголовка превышает длину заголовка Tomcat max.)

Ответ 6

Я реализовал вариант ответа 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>

Ответ 7

В моем приложении у меня нет прецедентов для отображения атрибутов модели при перенаправлении, поэтому я расширил 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>

Ответ 8

вручную создав для меня объект RedirectView:

@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 это должно быть поведение по умолчанию при перенаправлении

Ответ 9

Или сделайте запрос POST одним. Полученные запросы будут отображать только атрибуты модели в качестве параметров запроса, отображаемых в URL-адресе.

Ответ 10

Вот как это сделать с помощью Java-конфигурации (Spring 3.1+, я думаю, протестирован с 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

}

Ответ 11

Не используйте @ModelAttribute. Непосредственно храните пользователей в ModelMap. Вы все равно делаете с объектом команды.

@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";
    }

Недостатком этого является то, что в addIntake() происходит ошибка проверки. Если вы хотите просто вернуть логическое имя формы, вы также должны помнить о повторной установке модели с пользователями, иначе форма не будет настроена правильно.

Ответ 12

Существует обходное решение, если оно помогает вашему делу.

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

Здесь вы сделали его возвратом Collection of String. Сделайте его сборкой пользователя (это может быть строка обертывания класса, представляющая пользователя, или класс с кучей данных, относящихся к пользователю). Проблема возникает только со строками. Если возвращенная коллекция содержит любой другой объект, это никогда не произойдет. Однако это всего лишь обходной путь, и может быть, не требуется вообще. Только мои два цента. Просто сделайте это как -

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

Ответ 13

попробуйте добавить код ниже в servlet-config.xml

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

иногда это решит проблему.