Relation b/w view name in the controller method and #RequestMapping(value="/...") in Spring MVC - spring

I am new to Spring MVC & going through Craig Walls Spring4 in Action.
Consider the snippet,
#RequestMapping(value = "/spittles", method = RequestMethod.GET)
public String spittles(Model model, #RequestParam("max") long max,
#RequestParam("count") int count) {
model.addAttribute("spittleList",spittleRepository.findSpittles(max, count));
return "spittles"; // <-- return view name
}
The image shows the spittles.jsp resides in /WEB-INF/views/
WebConfig.java:
#Configuration
#EnableWebMvc // Enable Spring MVC
#ComponentScan(basePackages={"org.spittr"})
public class WebConfig extends WebMvcConfigurerAdapter {
#Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver resolver =
new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
resolver.setExposeContextBeansAsAttributes(true);
return resolver;
}
#Override
public void configureDefaultServletHandling(
DefaultServletHandlerConfigurer configurer) {
/* configure static content handling */
configurer.enable();
}
}
1) Why do I need to return the string "spittles" in the controller method?
2) Does it(return string) holds a relationship to the
#RequestMapping(value = "/spittles", method = RequestMethod.GET)
as the value(/spittles) is the same as the returned string in the controller method?
3) Why don't I see a .jsp extension when i enter the URL
http://localhost:8080/web/spittles?max=238900&count=5
and the o/p is resolved as:

To your questions:
The String "spittles" will be passed to the view resolver, which looks for a view /WEB-INF/views/splittles.jsp. If you'd return "hello_world", you would need a view /WEB-INF/views/hello_world.jsp.
No - that's the controller URL. You could define a completely different Controller URL like e.g. /my/super/vality/url if you'd like - that's just the path under which you accept the (GET) request.
See answers to 1.) and 2.) Although its good practice keep Spring-Controller-URLs and JSP view names alike, so it is obvious to the developer what's happening here.
You could for example have to controller methods for the same path and one answering to GET and the other answering to POST requests and both resulting in differne views:
#RequestMapping(value = "/spittles", method = RequestMethod.GET)
public String spittles(Model model, #RequestParam("max") long max,
#RequestParam("count") int count) {
// ...
return "splittles_get";
}
#RequestMapping(value = "/spittles", method = RequestMethod.POST)
public String spittles(Model model, #RequestParam("max") long max,
#RequestParam("count") int count) {
// ...
return "splittles_post";
}
You can even return a relative path like splittles/jspName meaning that you can organize your JSPs in folders - here /WEB-INF/views/splittles/something.jsp

Related

Spring Boot Redirecting to another controller method from current controller method

Hi all am new to spring boot. Am stuck in the middle of my learning path. I have two controllers(#Controller) with some methods define in them. Am submitting form data to a method in index controller and wants to move to the method in home controller if form submission gets successful(on succesfull login). while loading http://localhost:9090/method of index controller it loads all the static content correctly, but when i redirectreturn "redirect:/dashboard/index" then it navigates to http://localhost:9090/dashBoard/index. And /dashboard/index method is as follow
#Controller
public class HomeController {
#GetMapping(value = "/dashBoard/index")
public String hello(Model model, #RequestParam(value = "name", required = false, defaultValue = "World") String name) {
model.addAttribute("name", name);
return "index";
}
}
this method return "index" which is .jsp page but redirecting to this method changes static content path like http://localhost:9090/dashBoard/assets/images/avatar/1.jpg
it seems like appending /dashBoard/ in path of static content. Am not understanding what to do please help. Am adding my project properties and structure please have a look
application.properties
spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp
spring.resources.static-locations=file:/var/www/static,classpath:static
spring.mvc.static-path-pattern=/resources/**
server.port=9090
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL57InnoDBDialect
spring.jackson.serialization.fail-on-empty-beans=false
main class
[#SpringBootApplication
#EnableAutoConfiguration
public class SchoolpageApplication extends SpringBootServletInitializer {
public static void main(String\[\] args) {
SpringApplication.run(SchoolpageApplication.class, args);
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(SchoolpageApplication.class);
}
}
Project Structure
Static content path
#Controller
#RequestMapping("/dashBoard")
public class HomeController {
#GetMapping("index")
public String hello(Model model, #RequestParam(value = "name", required = false, defaultValue = "World") String name) {
model.addAttribute("name", name);
return "index";
}
}
You could try this method, everytime you get throught an url with /dashboard you will get inside this controller, and you can control every option you want with the next income like /foo (in this case /index) and in the return it will get you into /dashboard/+your return value(in this case index).
I´m not an expert with spring boot, I´m pretty new with it too but I hope this can help you.

Spring MVC RestController allow params with different names in methods

I am writing an API using Spring MVC and I am coming up with a problem allowing apps written in different languages to consume my API.
It turns out that the "Ruby users" like to have their params named in snake_case and our "Java users" like to have their param names in camel_case.
Is it possible to create my methods that allow param names to be named multiple ways, but mapped to the same method variable?
For instance... If I have a method that accepts a number of variables, of them there is mapped to a postal code. Could I write my method with a #RequestParam that accepts BOTH "postal_code" and "postalCode" and maps it to the same variable?
Neither JAX-RS #QueryParam nor Spring #RequestParam support your requirement i.e., mapping multiple request parameter names to the same variable.
I recommend not to do this as it will be very hard to support because of the confusion like which parameter is coming from which client.
But if you really wanted to handle this ((because you can't change the URL coming from 3rd parties, agreed long back), then the alternative is to make use of HandlerMethodArgumentResolver which helps in passing our own request argument (like #MyRequestParam) to the controller method like as shown in the below code:
Controller class:
#Controller
public class MyController {
#RequestMapping(value="/xyz")
public void train1(#MyRequestParam String postcode) {//custom method argument injected
//Add your code here
}
}
MyRequestParam :
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.PARAMETER)
public #interface MyRequestParam {
}
HandlerMethodArgumentResolver Impl class:
public class MyRequestParamWebArgumentResolver implements HandlerMethodArgumentResolver {
#Override
public Object resolveArgument(MethodParameter parameter,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest,
WebDataBinderFactory binderFactory) {
MyRequestParam myRequestParam =
parameter.getParameterAnnotation(MyRequestParam.class);
if(myRequestParam != null) {
HttpServletRequest request =
(HttpServletRequest) webRequest.getNativeRequest();
String myParamValueToBeSentToController = "";
//set the value from request.getParameter("postal_code")
//or request.getParameter("postalCode")
return myParamValueToBeSentToController;
}
return null;
}
#Override
public boolean supportsParameter(MethodParameter parameter) {
return (parameter.getParameterAnnotation(MyRequestParam.class) != null);
}
}
WebMvcConfigurerAdapter class:
#Configuration
class WebMvcContext extends WebMvcConfigurerAdapter {
#Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(new MyRequestParamWebArgumentResolver());
}
}
I think what you want to do is not allowed by Spring framework with the annotation RequestParam.
But if you can change the code or say to your third party to modify the calls i would suggest you 2 options
Option 1:
Use the #PathVariable property
#RequestMapping(value = "/postalcode/{postalCode}", method = RequestMethod.GET)
public ModelAndView yourMethod(#PathVariable("postalCode") String postalCode) {
//...your code
Here does not matter if the are calling your URL as:
http://domain/app/postalcode/E1-2ES
http://domain/app/postalcode/23580
Option 2:
Create 2 methods in your controller and use the same service
#RequestMapping(value = "/postalcode", method = RequestMethod.GET, params={"postalCode"})
public ModelAndView yourMethod(#RequestParam("postalCode") String postalCode) {
//...call the service
#RequestMapping(value = "/postalcode", method = RequestMethod.GET, params={"postal_code"})
public ModelAndView yourMethodClient2(#RequestParam("postal_code") String postalCode) {
//...call the service
If is possible, I would suggest you option 1 is much more scalable

How to return jsp from ajax call?

I am using spring mvc without annotations.
I want to take jsp(html code) as response from ajax call.
I do not want to use response.getWriter().print(..). can any one tell me any other solution.?
You can return JSP using ModelAndView like this
#RequestMapping (
value = "/path/call",
method = RequestMethod.POST
)
#ResponseBody
public ModelAndView blah(....) {
return new ModelAndView("location to JSP file");
}
You could add data to MandV using the method below
/**
* Add an attribute to the model.
* #param attributeName name of the object to add to the model
* #param attributeValue object to add to the model (never {#code null})
* #see ModelMap#addAttribute(String, Object)
* #see #getModelMap()
*/
public ModelAndView addObject(String attributeName, Object attributeValue) {
getModelMap().addAttribute(attributeName, attributeValue);
return this;
}
i highly recommend reading the documentation, without actual knowledge of the spring framework you will have a hard time using it ... As has already been mentioned, you will usually have a Controller class which handles requests - these are annotated with #RequestMapping and the controller is annotated with #Controller, of course. This is an example from the documentation :
#Controller
#RequestMapping("/appointments")
public class AppointmentsController {
private final AppointmentBook appointmentBook;
#Autowired
public AppointmentsController(AppointmentBook appointmentBook) {
this.appointmentBook = appointmentBook;
}
#RequestMapping(method = RequestMethod.GET)
public Map<String, Appointment> get() {
return appointmentBook.getAppointmentsForToday();
}
#RequestMapping(value="/{day}", method = RequestMethod.GET)
public Map<String, Appointment> getForDay(#PathVariable #DateTimeFormat(iso=ISO.DATE) Date day, Model model) {
return appointmentBook.getAppointmentsForDay(day);
}
#RequestMapping(value="/new", method = RequestMethod.GET)
public AppointmentForm getNewForm() {
return new AppointmentForm();
}
#RequestMapping(method = RequestMethod.POST)
public String add(#Valid AppointmentForm appointment, BindingResult result) {
if (result.hasErrors()) {
return "appointments/new";
}
appointmentBook.addAppointment(appointment);
return "redirect:/appointments";
}
}
As you can see, requests are now semi-automatically resolved / passed to JSP-parsers which process your stored JSP and output HTML. That is called MVC and although the MVC-model in spring differs a bit from the standard point of view its quite useful and somewhat standard'ish.
Yet again : if you want to use spring, please read the documentation. It is important and useful.
spring mvc without annotations
pretty much defeats the whole concept. I think you need to re-do your application design, apparently it is flawed --- no offense, im just stating the obvious.

What is the difference between return ModelAndView and return String in Spring MVC?

I want to know the different between ModelAndView and String.
#RequestMapping(value="/")
public ModelAndView mainPage() {
return new ModelAndView("home");
}
and the second piece of code is about returning String:
#RequestMapping(value="/")
public String mainPage() {
return "home";
}
You can return many things from a controller, and Spring will automatically try to deduce what to do from there.
When you return a ModelAndView all information that needs to be passed from the controller is embedded inside it. No suprise there.
If you return a String, it will assume that this is the name of the view to use. It will wrap this in a ModelAndView object with the string as the view and the existing model embedded as well.
Spring does a lot of 'magic' on the return types, but also on the parameter types.
This allows you to write code in a style that is more intuitive for you, i.e. the following two examples are the same:
#RequestMapping(value="/")
public ModelAndView mainPage() {
Model m = new Model();
m.put("key", "value");
return new ModelAndView(m,"main");
}
and
#RequestMapping(value="/")
public String mainPage(Model m) {
m.put("key", "value");
return "main";
}
This second variant is a little less verbose and easier to test separately. The model passed in will be an empty model (unless forwarded from some other controller).

Spring MVC, Controllers design

I am building a web application in Spring MVC with combination of Spring Security. My question regards to inner design of application. To be more specific - how to set up controllers. I got inspired a lot by Pet Clinic example where there is one controller per domain object (Owner controller, Pet controller, Vet Controller and so on).
I would like to introduce an admin backend interface to my application. This would mean to create admin - specific methods and #RequestMappings in each controller. Request mapping paths are secured by intercept-url pattern so I do not have to care where they are. However I find this solution little bit inelegant.
On pet clinics example would it look like:
#Controller
#SessionAttributes(types = Owner.class)
public class OwnerController {
private final ClinicService clinicService;
// Front end method
#RequestMapping(value = "/owners/find", method = RequestMethod.GET)
public String initFindForm(Map<String, Object> model) {
model.put("owner", new Owner());
return "owners/findOwners";
}
// Admin method
#RequestMapping(value = "/admin/owners/find", method = RequestMethod.GET)
public String initFindForm(Map<String, Object> model) {
model.put("owner", new Owner());
//Admin view
return "admin/owners/findOwners";
}
}
Other choice is to have one controller for each #RequestMapping (or per action)
#Controller
#RequestMapping(value = "/admin", method = RequestMethod.GET)
public class AdminController {
private final ClinicService clinicService;
// Admin method
#RequestMapping(value = "/owners/find", method = RequestMethod.GET)
public String initFindForm(Map<String, Object> model) {
model.put("owner", new Owner());
//Admin specific view
return "admin/owners/findOwners";
}
}
This would in my opinion lead to really robust controllers with many methods.
Third option would be to have some kind of mix of those.
#Controller
#SessionAttributes(types = Owner.class)
public class AdminOwnerController {
private final ClinicService clinicService;
// Admin method
#RequestMapping(value = "/admin/owners/find", method = RequestMethod.GET)
public String initFindForm(Map<String, Object> model) {
model.put("owner", new Owner());
//Admin view
return "admin/owners/findOwners";
}
}
My question is what is a standard approach for that?
Usually I use a hybrid approach of AdminOwnerController, in which I end up having approximately 5-10 methods max per Controller.
If you end up having 1-2 methods per controller. I would consider grouping them together based on the admin domain.

Resources