Combining POST and GET in SpringMvc - spring-mvc

For a user registration form (registration.html) I created a view controller through:
#Configuration
#EnableWebMvc
public class MvcConfig extends WebMvcConfigurerAdapter {
#Override
public void addViewControllers(final ViewControllerRegistry registry) {
super.addViewControllers(registry);
registry.addViewController("/user/registration").setViewName("registration");
}
This works fine, and if I go to /user/registration (i.e. GET), I can see the registration form.
However if I now want to create a controller for POST requests at the same uri through:
#Controller
public class RegistrationController {
#RequestMapping(value = "/user/registration", method = RequestMethod.POST)
#ResponseBody
public GenericResponse registerUserAccount(#Valid final UserDto accountDto, final HttpServletRequest request) {
// some code
}
}
I get an error message at the /user/registration uri saying:
Request method 'GET' not supported
So it seems that my post controller is somehow overriding the GET controller which was working before. Why is that? Is it possible to make the two work together or do I have to write my own GET controller in the same way as my post controller?

Related

Why do we need RedirectAttributes.addAttribute()?

Spring provides the following option to pass attributes(params) to the redirect page by using RedirectAttributes.
#Controller
#RequestMapping("/")
public class RedirectController {
#GetMapping("/redirectWithRedirectView")
public ModelAndView redirectWithUsingRedirectView(RedirectAttributes attributes) {
attributes.addAttribute("attribute", "redirectWithRedirectView");
return new ModelAndView("redirect:redirectedUrl");
}
}
The same can be achieved even if we simply append attribute to redirect URL, like the following
#Controller
#RequestMapping("/")
public class RedirectController {
#GetMapping("/redirectWithRedirectView")
public ModelAndView redirectWithUsingRedirectView() {
return new ModelAndView("redirect:redirectedUrl?attribute=redirectWithRedirectView");
}
}
Both do the same job. Do we get any benefits in terms of memory if we use RedirectAttributes? I am guessing, in the second case, we would be constructing separate ModelAndView object if the attribute value changes for each request.

New implementation/method of existing request mapping in controller

I am trying to look for a way to extend a controller such that I can use the existing request mapping but with a different implementation/method tied to it.
Say for example, below is a code snippet from AdminBasicEntityController in BLC where viewAddEntityForm method is tied to /add request mapping. Now I want to have my own logic of showing entityForm(Say Product entity) using /add request mapping. Is it possible?
#Controller("blAdminBasicEntityController")
#RequestMapping("/{sectionKey:.+}")
public class AdminBasicEntityController extends AdminAbstractController {
#RequestMapping(value = "", method = RequestMethod.GET)
public String viewEntityList(HttpServletRequest request, HttpServletResponse response, Model model,
#PathVariable Map<String, String> pathVars,
#RequestParam MultiValueMap<String, String> requestParams) throws Exception {
// default implementation
}
#RequestMapping(value = "/add", method = RequestMethod.GET)
public String viewAddEntityForm(HttpServletRequest request, HttpServletResponse response, Model model,
#PathVariable Map<String, String> pathVars,
#RequestParam(defaultValue = "") String entityType) throws Exception {
// default implementation
}
}
Also I found below mentioned information in the documentation of AdminBasicEntityController, so does it mean I can have controller for specific entity. If yes, how?
The default implementation of the {#link #BroadleafAdminAbstractEntityController}. This delegates every call to super and does not provide any custom-tailored functionality. It is
responsible for rendering the admin for every entity that is not
explicitly customized by its own controller
#RequestMapping("/{sectionKey:.+}") uses the generic path variable sectionKey, making the controller handle any requests that are not explicitly mapped. For example,
/product
/product/add
/category
/category/add
/store
/store/add
may all be hitting this controller if these URLs have not been explicitly mapped to their own controllers.
To handle a specific URL yourself, you could do:
#Controller
#RequestMapping("/product")
public class ProductAdminController {
#RequestMapping("/add")
public String viewAddEntityForm(...) { ... }
}
Now, the URL /product/add will be routed to this custom controller while all others will continue to get routed to the generic controller.

Spring MVC - Request Return Value in Browser

I imported the Getting Started - Securing a Web Application in STS and added a controller for navigation, the request gets called and the return value instead of redirecting gets displayed in the browser. Any idea why it does this and how to fix it?
Here is the code:
#RestController
public class BetController {
#RequestMapping("/")
public String username(Model model) {
System.out.println("Test");
model.addAttribute("username", WebSecurityConfig.getUsername());
return "statpage";
}
The page start page is registered in this manner:
#Configuration
public class MvcConfig extends WebMvcConfigurerAdapter {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("startpage");
registry.addViewController("/login").setViewName("login");
}
All I get in the browser is a blank page with "startpage" on it, looking at the page's source there is no html just "startpage"
Returning ModelAndView instead of a String in the RequestMapping method solved the problem:
#RequestMapping("/")
public ModelAndView username(Model m) {
ModelAndView mav = new ModelAndView();
mav.addObject("username", WebSecurityConfig.getUsername());
mav.setViewName("betting");
return mav;
}
Another solution is changing #RestController to #Controller and making sure all the names match

Creating a custom controller parameter automatically populated with HttpServletRequest?

Using a strictly annotation-based/Java-only Spring MVC 3.2.2 configuration, I'm trying to create a controller method with a custom class (I'll call it Context) as a parameter. I want to have Context constructed with knowledge of the current HttpServletRequest and then passed along to the controller method. In essence, I want to create my own custom wrapper around the request object before it's sent to the controller. e.g. I want to accomplish this:
#Controller
#RequestMapping(value = "/")
public class MainController {
#RequestMapping(value = "/")
public #ResponseBody
String process(HttpServletRequest request) {
Context context = new Context(request);
...
}
}
automatically like this:
#Controller
#RequestMapping(value = "/")
public class MainController {
#RequestMapping(value = "/")
public #ResponseBody
String process(Context context) {
...
}
}
Is this possible? I looked into implementing a HandlerMethodArgumentResolver as a #Bean in my WebMvcConfigurerAdapter but I don't think that's the correct route to take. I've tried adding #AutoWired to Context (as a #Bean) to no avail as well. I imagine there's WebMvcConfigurerAdapter or possibly in a AbstractAnnotationConfigDispatcherServletInitializer?
HandlerMethodArgumentResolver and WebMvcConfigurerAdapter is certainly a right way to achieve your goal.
In order to register custom argument resolver you need to make your #Configuration extend WebMvcConfigurerAdapter and override its addArgumentResolver() method.

spring MVC extended controllers don't resolve

I have the following:
#Controller
#RequestMapping("/admin")
public class AdminController extends BaseHtmlController{
#Autowired
protected DeviceCustomerMap deviceCustomerMap;
#Autowired
protected CustomerDao customerDao;
String layout = "template/admin";
#RequestMapping(value="/login", method = RequestMethod.GET)
public String login(ModelMap model) {
model.addAttribute("meta", meta);
String view = "login";
return view;
}
}
public class AdminCustomerController extends AdminController{
#RequestMapping(value="/customer/mapping", method = RequestMethod.GET)
public String customerMapping(ModelMap model, #RequestParam(required=false) boolean refresh) throws Exception {
if (refresh){
deviceCustomerMap.initCustomerUrlMap();
}
model.addAttribute("meta", meta);
model.addAttribute("view", "customer/mapping");
model.addAttribute("customers", deviceCustomerMap.getCustomerMap());
return layout;
}
}
However, the extended controller doesn't resolve the requests, but when they're in the base controller, they're resolved just fine, I've poked around several threads but couldn't find a solution, any idea?
Is the problem that you are able to get a response when executing a request to the /admin/login resource, but not to /admin/customer/mapping resource, unless you move the customerMapping() method to the AdminController class?
The solution is to annotate the AdminCustomerController class with the #Controller annotation. Without a stereotype annotation (and appropriate component scanning), Spring will not recognise the class as a Spring bean.

Resources