Как сделать так, чтобы переменные Spring 3.0 MVC @ModelAttribute не появлялись в URL? - PullRequest
56 голосов
/ 29 января 2010

Используя 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, проверяет объект команды, сохраняет информацию в базе данных и возвращает номер дела.

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

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

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

Ответы [ 13 ]

38 голосов
/ 23 марта 2011
model.asMap().clear();
return "redirect:" + news.getUrl();

:)

30 голосов
/ 29 марта 2013

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

18 голосов
/ 30 января 2010

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

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

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

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

18 голосов
/ 29 января 2010

Нет хороших способов решения этой проблемы (т.е. без создания пользовательских компонентов, без чрезмерного количества явной конфигурации 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;
    }
}
5 голосов
/ 14 апреля 2012

Я реализовал вариант ответа Сида с меньшим количеством копирования и вставки:

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>
5 голосов
/ 15 января 2011

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

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

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

2 голосов
/ 19 июня 2011

Создание объекта 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); 
}

ИМХО, это должно быть поведение по умолчанию при перенаправлении

2 голосов
/ 15 апреля 2011

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

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

}
1 голос
/ 10 января 2012

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...