Would someone answer some questions about Spring and Request Mapping? - spring

I just started studying Spring, and I'm so confused.
I just created a new 'Spring Legacy Project' at STS. HomeController and home.jsp are there.
When I run it on server, it comes through the HomeController first, and arrives to home.jsp.
#RequestMapping(value = "/", method = RequestMethod.GET)
public String home(Locale locale, Model model) {
return "home";
}
What makes my project go through the HomeController at the beginning? Should I look at any xml file?
What does value="/" mean in #RequestMapping?
At the home.jsp, I made a button to go 'result.jsp'. From the 'result.jsp' I want to go back to home.jsp. but it doesn't work. What should I do?
<input type="button" value="뒤로 " onclick="javascript:location.href='/views/home.jsp'">
Why isn't this button working? Those two JSP files are in same place.

Your app is deployed to some app server, such as tomcat. The request <app server>/<context root> is handled by the app server to the .war with the appropriate context root, e.g. to your app. Your app uses Spring MVC, so it is Spring's RequestMappingHandlerMapping bean from your .war file that initially handles the request and finds your method that will handle this request. It does so by comparing the path in the request with the value of each method annotated with #RequestMapping.
The annotation #RequestMapping(value="/") of your home() method means that request <app server>/<context root> will be handled by your 'home()' method.
Any request from your JSP will go back to the Spring MVC that will try to map it to the appropriate controller method, i.e. to the method annotated by #RequestMapping with the appropriate path relative to the context root. So if your result.jsp just links to "/", it should bring you to the home() method and then to the home.jsp.

Related

Spring MVC 404 even though URL is mapped

I've been trying to setup a Spring MVC controller but when I try to make a GET request, I get a 404 error.
I created a working test example here: https://github.com/Jardo-51/zk-spring-mvc-test
When I run the application on Tomcat and try to make a GET request to: http://localhost:8080/zk-spring-mvc-test/api/v0/foo, I get a 404 error and the logs say:
WARNING: No mapping found for HTTP request with URI [/zk-spring-mvc-test/api/v0/foo] in DispatcherServlet with name 'dispatcher-api'`
I've been trying to fix it according to this answer, and found out that the controller is mapped correctly because the logs on startup say:
INFO: Mapped "{[/zk-spring-mvc-test/api/v0/foo],methods=[GET]}" onto public org.springframework.http.ResponseEntity<java.lang.String> com.jardoapps.zkspringmvctest.controllers.FooController.method()
The app uses ZK framework which needs its own servlets so maybe there is a conflict with the DispatcherServlet. Please see my example app for more details (it contains only the necessary code).
Here is the web.xlm (Spring context and MVC config are at the top).
Here is the controller class.
Simply replace #RequestMapping("zk-spring-mvc-test/api/v0/foo") with #RequestMapping("/v0/foo") in your FooController class.
The reason is that the path that you specify into the #RequestMapping annotation is the part of the request's URL beyond the part that called the servlet.
You defined DispatcherServlet's mapping as:
<servlet-mapping>
<servlet-name>dispatcher-api</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
So we have zk-spring-mvc-test that is the context root (this is deploy dependent), /api/ that calls the Spring DispatcherServlet, and finally /v0/foo that should be mapped by your controller:
#RestController
#RequestMapping("/v0/foo")
public class FooController {
#RequestMapping(method = RequestMethod.GET)
public ResponseEntity<String> method() {
return ResponseEntity.ok().body("OK");
}
}
You can see Spring MVC configure url-pattern for further information.

Configuring Default Spring Boot app to render HTML pages and CSS JS content

I configured a Basic Spring Boot app containing Hibernate. However, no page is being rendered.
I have places my pages in src/main/resources/templates/ and content(CSS and JS) in src/main/resources/static/
I have added Thymeleaf through Maven and written a basic controller to render my page -
#RestController
#RequestMapping("/testui")
public class GreetingController {
#RequestMapping("/greeting")
public String greeting(#RequestParam(value="name", required=false, defaultValue="World") String name, Model model) {
model.addAttribute("name", name);
return "greeting";
}
}
Instead of rendering a page with my name, it is rendering the string - "greeting"
I have placed the greeting.html in templates file. What are the changes in application.properties I need to make to render pages (what keys and values must I give?)
Update - I somehow do not have the webapp folder. Added that. Created a folder called jsp and added a simple page. Referenced it - didnt work
Why is it not working?
Because you are using #RestController. #RestController is used to create API controllers which serve JSON/XML, whereas #Controller is used to create controllers which serve web content such as HTML.
Proposed solution
Replace #RestController with #Controller. For further details, please see the official Getting Started guide of Spring.
You've added #RestController on the Controller class, which means that you want all values returned by the controller methods to be considered as response body (that's the equivalent of annotating all controller methods with #ResponseBody).
Remove that annotation from the class and replace it with #Controller and you should get the expected result.

Can I specify application path in #RequestMapping on controller?

Can I use EL to specify my application context path on my Spring Controller using something like #RequestMapping("${pageContext.request.contextPath}")? Actually, I get an 404 error. So my question is how to map controller on context root?
I presume #RequestMapping("/") cannot do the job when app is not alone on the server, and url looks like:
http://localhost:8080/myapp/mypage
#Controller
#RequestMapping("${pageContext.request.contextPath}")
public class MainController {
#RequestMapping("/")
public ModelAndView index() {
}
}
PS: I've already added the app path prefix into every single url on my JSPs, like <form class="form-inline" role="form" action="${pageContext.request.contextPath}/search" method="post">. Now I need to make the same trick for my Spring Controllers to make it work when... wheather app deployed as ROOT app or as "just another app on this server".
you can add in the application.properties config file the root context path. That root context path will be the prefix path to all the controller paths.
application.properties
server.contextPath=/myapp/mypage
controller
#RequestMapping("/test")
Result:
http://localhost:8080/myapp/mypage/test

How can I tell if Spring has loaded my #Controller?

Is there a way to tell if Spring has loaded my #Controller?
I'm requesting a URL but I'm not hitting my controller and I can't figure out why
I'm loading controllers by doing a component scan
<context:component-scan base-package="com.example.app.web"/>
Other controllers in the same package as my failing controller are working fine.
My controller code is:
#Controller
#RequestMapping(value = "/app/administration/ecosystem")
public class AppEcosystemController {
#Autowired
EcosystemManagerService ecosystemManagerService;
#RequestMapping(value = "/Foo", method = RequestMethod.GET)
public String getEcosystem() {
/* Implementation */
}
The first thing I'd like to do is to be sure that this controller is getting picked up by the component scan.
Any suggestions?
Just enable logging for your application, you can find this information at INFO level
For example in my application I have a controller named UserController.
The following log4j.properties does the trick.
log4j.rootLogger=INFO, FILE
log4j.appender.FILE=org.apache.log4j.FileAppender
log4j.appender.FILE.File=../logs/rest-json.log
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
I can see in the log that RequestMappingHandlerMapping mapped my controller (scroll all the way to the right).
07:28:36,255 INFO RequestMappingHandlerMapping:182 - Mapped "{[/rest/**/users/{id}],methods=[GET],params=[],headers=[],consumes=[],produces=[text/xml || application/json],custom=[]}" onto public org..domain.User org.ramanh.controller.UserController.getUser(java.lang.String)
07:28:36,255 INFO RequestMappingHandlerMapping:182 - Mapped "{[/rest/**/users],methods=[POST],params=[],headers=[],consumes=[],produces=[text/xml || application/json],custom=[]}" onto public void org..controller.UserController.addUser(org...domain.User)
If you are still unsure I would suggest adding a method annotated with #PostConstruct.
You could easily look up the message in the log or place a break point in this method.
#PostConstruct
protected void iamAlive(){
log.info(“Hello AppEcosystemController”)
}
If you find that your controller is initialized correctly but still the url is not accessible.I would test the following
You are getting 404 error - maybe you are not pointing to the correct
url (do not forget to add the application as prefix to the url)
You are getting 404 error - Dispatcher servlet mapping in web.xml doesn't meet
the url above
You are getting 403/401 – maybe you are using
spring security and it’s blocking the url
You are getting 406 – your
content type definition is conflicting with your request
You are getting 50x – something is buggy in your code
I made an ApplicationContextDumper. Add it into application context, it will dump all beans and their dependencies in the current context and parent contexts (if any) into log file when the application context initialization finishes. It also lists the beans which aren’t referenced.
It was inspired by this answer.
You could start out with enabling debug logging for Spring as outlined here.
I'd also recommend leveraging the MVC testing support, which you'll find in the spring-test jar. Details on how to use it can be found here and here.

Adding HTTP Headers in JSP

I am creating a Spring REST web services, that communicates with Android App and JSP web pages.
The method at my spring controller is like
#RequestMapping(method = RequestMethod.POST, value = "/login")
public ModelAndView userLogin(#RequestBody User user,
HttpServletRequest request){
//do something with user
}
Andoid App is able to access this method through adding request Headres like
"Content-Type" application/json , "Accept" application/json etc. Here the user information sent by android end is comes in request body. Thats ok..
But problem occurs when i POST the contents from my JSP page. I am not able to access the same userLogin method from jsp page with #RequestBody but when i replace it with #ModelAttribute it works for jsp page ...but then doesn't works for android app. Please tell me how can i solve this.
Make the JSP page do the same thing as the android app (posting as JSON) using JavaScript, or implement a second method in your Spring controller (userLogin2), mapped to a different URL, and use this URL in your JSP.

Resources