Я кодирую представление JSP, которое должно отправить несколько объектов в Spring @Controller после отправки.
Обработчик контроллера имеет следующую подпись:
public ModelAndView handlerX(@ModelAttribute ModelMap model){
Я пробовал что-то подобное в своем JSP:
<form method="post" action="action">
<spring:bind path="objectX.name">
<input type="text" name="${status.expression}" value="${status.value}" readonly="readonly" />
</spring:bind>
Но когда отладчик достигает контроллера, объект модели не содержит никаких значений формы.
Может кто-нибудь, пожалуйста, дать несколько советов о том, как создать форму? Я думаю, что я не могу обернуть два разных объекта в Command-type-object, поскольку обработчик контроллера принимает только ModelMap. Большое спасибо!
Вы можете решить эту проблему, поместив собственный HandlerMethodArgumentResolver
чтобы привязать параметры запроса, отправленные из вашей формы, в аргумент model. Например:
public class RequestToModelBindingArgumentResolver implements HandlerMethodArgumentResolver, Ordered {
@Override
public boolean supportsParameter(final MethodParameter parameter) {
return parameter.hasParameterAnnotation(ModelAttribute.class) &&
parameter.getParameterType() == ModelMap.class;
}
@Override
public Object resolveArgument(final MethodParameter parameter, final ModelAndViewContainer mavContainer, final NativeWebRequest webRequest, final WebDataBinderFactory binderFactory) throws Exception {
ModelMap model = mavContainer.getModel();
Map<String, String[]> requestParameters = webRequest.getParameterMap();
// Bind all request parameters to the model
for (String param : requestParameters.keySet()) {
String[] values = requestParameters.get(param);
if (values.length == 1) {
model.addAttribute(param, values[0]);
} else {
model.addAttribute(param, values);
}
}
return model;
}
@Override
public int getOrder() {
return HIGHEST_PRECEDENCE;
}
}
Экземпляр этого класса можно добавить в аргумент resolver, чтобы отобразить конфигурацию вашего приложения.
@Override
public void addArgumentResolvers(final List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(new RequestToModelBindingArgumentResolver());
}
Однако есть проблема. Аргументы, аннотированные с помощью @ModelAttribute
будут разрешаться с помощью ModelAttributeMethodProcessor
и поскольку не ModelAttributeMethodProcessor
упорядочение HandlerMethodArgumentResolver
он всегда будет первым, кто разрешит это значение. Это означает, что если вы добавите настраиваемый аргумент аргумента, он никогда не будет достигнут. Это означает, что нам нужно найти способ сортировки коллекции резольверов (вот почему resolver реализует Ordered
).
Одним из простых способов сортировки коллекции резольвера является RequestmappingHandlerAdapter
параметра RequestmappingHandlerAdapter
в конфигурацию.
@Autowired
private RequestMappingHandlerAdapter adapter;
Теперь нам нужен метод, который будет вызываться после того, как конфигурация будет построена, чтобы мы могли отсортировать коллекцию резольверов.
@PostConstruct
public void orderArgumentResolvers() {
List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>(adapter.getArgumentResolvers());
Collections.sort(resolvers, new OrderComparator());
adapter.setArgumentResolvers(resolvers);
}
Так как adapter.getArgumentResolvers()
вернет немодифицируемый список, нам нужно перепрыгнуть немного обруча здесь до начала сортировки. После сортировки экземпляр RequestToModelBindingArgumentResolver
будет находиться поверх списка и первым будет отвечать на вызов support()
.
Но эй! Я думаю, что намного проще просто изменить подпись обработчиков :)
Вы можете создать форму, имеющую поля, соответствующие полям формы, и затем получить эту форму следующим образом:
@RequestMapping(method= RequestMethod.POST)
public Response add(@RequestBody Form form, HttpServletRequest request){
//The form element fields must match with fields in your form. Especially the names and types.
}
Помимо этих двух параметров, которые передаются в add(), вы можете передать еще много
ModelMap
который не имеет ничего общего с отправкой данных формы. Также странно иметь @ModelAttribute
на самой модели. Ваша настройка не имеет смысла.