I am using spring-boot-starter-paren: 2.3.2.RELEASE.
Here is my code:
package com.example.sweater;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.Map;
#Controller
public class GreetingController {
#GetMapping("/greeting")
public String greeting(#RequestParam(name="name",
required=false,
defaultValue="World") String name,
Map<String, Object> model) {
model.put("name", name);
return "greeting";
}
}
Stacktrace: https://pastebin.com/wtS2ubus
Problem: javax.servlet.ServletException: Circular view path [greeting]: would dispatch back to the current handler URL [/greeting] again. Check your ViewResolver setup! (Hint: This may be the result of an unspecified view, due to default view name generation.)
How can I debug this?
The circular path exception happens due to default ViewResolvers in spring. If your #GetMapping on path = 'path' returns a value which is also defined as a view in your project (html or equivalent, i.e path.html) then this error occurs.
As stated in the below source:
By default, the Spring MVC framework applies the InternalResourceView class as the view resolver. As a result, if the #GetMapping value is the same as the view, the request will fail with the Circular View path will occur.
One possible solution would be to rename the view and change the return value in the controller method.
If we don't want to rename the view and change the return value in the controller method, then another solution is to choose another view processor for the project.
Source:https://www.baeldung.com/spring-circular-view-path-error
I had a similar issue it was resolved by changing #Controller to #RestController
Related
I am a beginner so please don't be mean.
I have got an html page index.html
And I want the method MainController::getListEmployee to be called.
In this method, I put a System.err to see if the method is called. And I see nothing.
Controller code
package com.cgi.listeemployes.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import com.cgi.listeemployes.model.User;
import com.cgi.listeemployes.repository.UserRepository;
#Controller // This means that this class is a Controller
#RequestMapping(path="/") // This means URL's start with /demo (after Application path)
public class MainController {
#Autowired // This means to get the bean called userRepository
// Which is auto-generated by Spring, we will use it to handle the data
private UserRepository userRepository;
#GetMapping(path="/index.html")
public #ResponseBody Iterable<User> getListEmployee() {
// This returns a JSON or XML with the users
System.err.println("getting ");
return userRepository.findAll();
}
#PostMapping(path="/add") // Map ONLY POST Requests
public #ResponseBody String addNewUser (#RequestParam String name
, #RequestParam String email) {
// #ResponseBody means the returned String is the response, not a view name
// #RequestParam means it is a parameter from the GET or POST request
User n = new User();
n.setName(name);
n.setEmail(email);
userRepository.save(n);
return "Saved";
}
#GetMapping(path="/all")
public #ResponseBody Iterable<User> getAllUsers() {
// This returns a JSON or XML with the users
return userRepository.findAll();
}
}
thanks for your help
When you want to return a html, just return a string with the name of the html file, it could be "Index" (without the .html).
In your #GetMapping(path="/index.html"), you are returning an object instead a html.
If you want to load data from database and render it at your html, then add the attribute "Model model" in your parameters, like this:
#GetMapping(path="/index.html")
public String getListEmployee(Model model) {
List<User> users = userRepository.findAll();
model.addAttribute("yourUsers", users); // this gonna inject the list of users in your html
System.err.println("getting ");
return "Index"
}
Then in your html, you can get the users with ${yourUsers} and do whatever you want.
I saw your project, it is missing the template engine. Template engine is what gonna get the data of your backend and show in your front/html. I added the Thymeleaf template engine into your pom.xml, and it worked. Here is the thymeleaf dependency:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
To work with thymeleaf, you have to put all your html into a new folder called "templates" in the "resources", same level of "static". You cannot use html in the static folder, this folder should have only css, javascripts and assets.
I'm trying to learn the latest Spring Boot and am going through some of their documentation on handling form submission. I'm taking a look at the code for the controller they use for the GET that serves up the view containing the form, and which also handles capturing the information from the POST.
package hello;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
#Controller
public class GreetingController {
#GetMapping("/greeting")
public String greetingForm(Model model) { // where does 'model' come from?
model.addAttribute("greeting", new Greeting());
return "greeting";
}
#PostMapping("/greeting")
public String greetingSubmit(#ModelAttribute Greeting greeting) {
return "result";
}
}
What I don't understand is how does the greetingForm(Model model) method take a parameter? The GET request surely isn't sending a whole Model over in its request, just the URI, right? Also, they don't list what the Model class code is, so I can't examine that.
This is their explanation:
The greetingForm() method uses a Model object to expose a new Greeting
to the view template. The Greeting object in the following code
contains fields such as id and content that correspond to the form
fields in the greeting view, and will be used to capture the
information from the form.
I also don't understand how just returning the string "greeting" translates into a view being served. Is there another layer which is actually calling this method?
I come from a Play! Framework background, and I'm used to my controller endpoints having to initialize and send the entire template back with the response - so this is confusing.
Spring does a lot of work on it's own to determine what to inject into controller handler methods and what to do with the return value.
From the Spring docs:
Handler methods annotated with this annotation can have very flexible signatures. The exact details of the supported method arguments and return values depend on the specific #Controller model supported. Both Spring Web MVC and Spring WebFlux support this annotation with some differences. More details are available in the Spring Framework reference.
Spring analyzes the arguments of the method. Model is a type that Spring understands, so it is injected into the method when called.
Handler methods can also have a variety of return types. When the return type is a String, Spring understands that to mean the name of a view to render and return to the client. This is also where the Model comes in; the values you put into the Model instance are bound to the view during rendering.
I am trying to retrieve the arguments of a grails controller method using an annotation and an Aspect that executes before the method.
The aspect handler executes correctly but i cant access the argument(which implements grails.validation.Validateable) the list of arguments is empty.
experiment.aspect.validated
package experiment.aspect
import java.lang.annotation.ElementType
import java.lang.annotation.Retention
import java.lang.annotation.RetentionPolicy
import java.lang.annotation.Target
/**
* Created by Vaggelis on 10/13/2016.
*/
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
#interface Validated {
}
experiment.aspect.ValidatedAspect
package experiment.aspect
import grails.validation.ValidationException
import org.aspectj.lang.JoinPoint
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.Before
/**
* Created by Vaggelis on 10/13/2016.
*/
#Aspect
class ValidatedAspect {
#Before("#annotation(experiment.aspect.Validated)")
public void preValidate(JoinPoint point) throws ValidationException{
println "parameters ${point.getArgs()}"
}
}
conf.spring.resources
import experiment.aspect.ValidatedAspect
// Place your Spring DSL code here
beans = {
validatedAspect(ValidatedAspect)
}
controllers.experiment.TestController
package experiment
import experiment.aspect.Validated
class TestController extends BaseController {
static responseFormats = ['json']
#Validated
def login(LoginCommand loginCommand){
println "Validated"
...
}
}
experiment.LoginCommand
package experiment
/**
* Created by Vaggelis on 9/14/2016.
*/
import grails.validation.Validateable
class LoginCommand implements Validateable {
// String id
String name
static constraints = {
name blank: false
}
}
I get the following output, which means that the aspect handler method runs before the controller method but it does not get the arguments.
parameters []
Validated
You're seeing no args because there aren't any.
To support databinding and to keep things simpler when the servlet decides which controller and method to call, an AST transform creates a new method with the same name and no args for all action methods that have any args. The zero-arg method is the one called initially by the servlet, and it has the logic added by the transform to make the data binding calls. After that's done it then it calls your parameterized method with param strings converted to int/long/boolean/command objects/etc.
The no-arg method will also be annotated with #grails.web.Action and the arg types specified in the commandObjects attribute. This will help find the other method, but it's actually simple because you'll get a compiler error if you declare overloaded public methods.
Having said all that, you probably don't want to use this approach even if it did work - there's already two existing standard ways to intercept controller action calls, Grails filters (now interceptors in 3.x) and servlet filters. Grails filters and interceptors make it trivial to inspect and optionally add, modify or delete request parameters, and if you return false from a 'before' call you will stop Grails from handling the request (e.g. because you rendered it yourself, or sent a redirect, etc.)
Problem:
See following Spring REST example, if a request such as http://localhost:8080/site/google.com is submitted, Spring returns “google“. Look like Spring treats “.” as file extension, and extract half of the parameter value.
Spring must return “google.com“. How can do it?
SiteController.java
package com.example.web.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
#Controller
#RequestMapping("/site")
public class SiteController {
#RequestMapping(value = "/{domain}", method = RequestMethod.GET)
public String printWelcome(#PathVariable("domain") String domain,
ModelMap model) {
model.addAttribute("domain", domain);
return "domain";
}
}
I believe you can use regex in the path variable of the #ResourceMapping. For instance, you could do
{domain:.[\\S]*}
You will probably have to fiddle with the regex some to get it right. The ':' separates the path variable name from the regex.
It is pretty simple just add ":.+" with your parameter like below:
here username is e-mail id
#RequestMapping(value = "checkuser/{username:.+}" , method=RequestMethod.GET)
#ResponseBody
boolean getUserName(#PathVariable("username") String userName){
boolean isUserAvailable = userDao.checkAvailable(userName);
return isUserAvailable;
}
I am passing value from URL like :
baseurl/checkuser/test#test.com
just make sure your url end of '/'and SiteController.java chage noting..
change http://xxx/site/google.com to http://xxx/site/google.com/
I'm currently working on a Spring MVC application and as I mapped, within the web.xml file, all incoming URL to a single DispatcherServlet, I wanted to know whether it would be possible to retrieve the URI that has been effectively mapped. Here's an example to illustrate my concerns :
import static org.springframework.web.bind.annotation.RequestMethod.*;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
#Controller
public class HomeController {
#RequestMapping(method={GET})
public String processAllRequest(){
return "viewName";
}
}
Since I've defined the URL-MAPPING in the web.xml as being "/*", all incoming requests will end up in my controller class, show above. For instance, both the following requests will be processed by the processAllRequest() method from my controller.
myApplicationContext/home
myApplicationContext/logout
Is it possible, somehow, to retrieve the mapped URI? That is, once I'm inside the processAllRequest(), how could I know if it's been called for .../home or .../logout?
Is it possible to retrieve this kind of info by injecting an HttpServletRequest or another object as argument of the method?
Spring does inject HttpServletRequest if you put it in your handler arguments, so you can do that if you like.
But if you need to distinguish between different URLs, just place them in different handlers:
#Controller
public class HomeController {
#RequestMapping(value="/home", method={GET})
public String processHome(){
return "viewName";
}
#RequestMapping(value="/login", method={GET})
public String processLogin(){
return "viewName";
}
}
The mapping in web.xml forwards all requests to the spring servlet. You can still write as many #Controllers as you like, and play with class-level and method-level #RequestMapping to split the application into logical components.
I might have formulated my question in an ambiguous way but what I was looking for, was rather path variable. So my problem was solved this way :
#Controller
public class HomeController {
#RequestMapping(value="/{uri}", method={GET})
public String processMappedUri(#PathVariable uri){
return uri;
}
}
With this solution whenever I request the following requests, the uri argument from my processMappedUri() method will hold the variable value :
myApplicationContext/home --> uri = home
myApplicationContext/logout --> uri = logout