Hello I use Thymealf and want to do a validirung against my database before I subbmitte.
When I call the controller I get the error:
Error resolving template [], template might not exist or might not be accessible by any of the configured Template Resolvers
I think the error comes from the fact that I don't returne a modal.
Is there a way to make a request without thymleaf ?
Controller
#GetMapping("/getByKey/{key}")
public KeyValuePair keyExists(#PathVariable("key") String key){
return ssdbService.getByKey(key);
}
or do I understand here something completely wrong ?
Use a #RestController instead of a #Controller if you want to return data.
You can also just annotate your method with #ResponseBody if you just want one method to return data instead of the entire controller.
#ResponseBody
#GetMapping("/getByKey/{key}")
public KeyValuePair keyExists(#PathVariable("key") String key){
return ssdbService.getByKey(key);
}
Related
I have two mvc style endpoints returning templatefile names as view names, in the same classpath: /source and /target. The source_template has a variable which needs to be filled by contents of another template, say target_template.
#RestController
class SomeController {
#GetMapping("/source")
public String source(Model model) {
model.addAttribute("attr1", /*call endpoint /target and add the response of parsed template 'target_template' here */);
return "source_template";
}
#GetMapping("/target")
public String target(Model model) {
model.addAttribute("attr2", "good");
//may be continue the nested invocation n number of times
return "target_template";
}
}
given the source_template.html:
Hai, $attr1
and the target_template.html:
this has been a $attr2 day
having said, i invoke the url /source, I should get "Hai, this has been a good day".
I can just call the target() method directly, but that would not render the template. Or I should directly use the templating engine apis to link the template file, put the context object, parse the template and return the string , which defeats the whole purpose of spring mvc. Or I can use resttemplate, but that requires an absolute url, and performance would take a hit. So, is there any other way to do it ?
I am trying to make spring boot application & swagger. Application is for REST service provide. I have made application running each page.
I have made a simple controller that have RequestMapping("/group/user/contact").
Which is working fine.
I am trying to do something like RequestMapping("/group/{type}/contact") at class level.
So my question is that is it possible ?
If yes then just want some basic guidance. and if no then fine.
My all request working fine. All request came from CORS filter class.
You can do this, the handler method should look something like
#Controller
#RequestMapping("/group/{type}/contact")
public class ClassLevelPathVariableController {
#ResponseBody
#RequestMapping(method = RequestMethod.GET)
public String classLevelMapping(#PathVariable String type) {
return type;
}
}
In this setup a GET request like e.g. /group/test/contact would be handled by the classLevelMapping method and the type variable will be populated with the value "test"
I have some questions from a design point of view in Spring Web MVC.
Is it good practice to use Request Object in controller? If not, then what is alternative way to pass pass one text fields value to controller? Do I need to create one new from bean for this single fields?
It depends of the situation, in a few cases I used the HttpServletRequest; for example for writing a file to the output stream.
If you want to get the Request Parameters you can use the annotation #RequestParam, that it´s more easy to get the parameters from the request.
Depends that you want to handle, for example for a form you can use #ModelAttribute and this attribute can be in a session or in the request.
For example:
#Controller
public class YourController {
#RequestMapping(value = "someUrl", method = RequestMethod.GET)
public String someMethod(#RequestParam("someProperty") String myProperty)
{
// ... do some stuff
}
}
Check the documentation here:
#RequestParam
#ModelAttribute
#PathVariable
I have a Spring MVC controller with an action that's called using AJAX.
#SessionAttributes({"userContext"})
public class Controller
{
...
#RequestMapping(value = "/my-url", method= { RequestMethods.POST })
public ModelAndView doSomething(#ModelAttribute("userContext") UserContext context,
SessionStatus sessionStatus)
{
BusinessObject obj = doSomeBusinessLogic(context.getUserName());
sessionStatus.setComplete();
ModelAndView mav = new ModelAndView("jsonView");
mav.addObject("someInt", obj.getId());
return mav;
}
}
When I run this action, I get the following exception:
net.sf.json.JSONException: There is a cycle in the hierarchy!
at t.sf.json.util.CycleDetectionStrategy$StrictCycleDetectionStrategy.handleRepeatedReferenceAsObject(CycleDetectionStrategy.java:97)
at net.sf.json.JSONObject._fromBean(JSONObject.java:833)
at net.sf.json.JSONObject.fromObject(JSONObject.java:168)
at org.springframework.web.servlet.view.json.writer.jsonlib.PropertyEditorRegistryValueProcessor.processObjectValue(PropertyEditorRegistryValueProcessor.java:127)
at net.sf.json.JSONObject._fromMap(JSONObject.java:1334)
Truncated. see log file for complete stacktrace
After doing some debugging I found out that Spring is placing the UserContext object onto the ModelAndView that I am returning. If I hard-code my user name and remove the context object from the method's parameters, the action runs successfully. Is there a way to configure Spring to omit the ModelAttribute-annotated parameters from the returned ModelAndView? As you can see, sessionStatus.setComplete() has no effect.
I've had similar problems in the past with #SessionAttributes. By declaring #SessionAttributes({"userContext"}) you're telling Spring that you want "userContext" to always be available in the model, and so Spring has no choice but to send your UserContext object out to the model, just in case you're going to be redirecting or doing something else which might end up at another Controller.
The "solution" (and I didn't like it much, but it worked) was to omit the #SessionAttributes annotation on the controller, add an HttpSession parameter to the necessary methods and "manually" manage what's in it.
I'm interested to see if there's a better way, because it seems #SessionAttributes has tremendous potential to tidy up controller-level code.
I registered a WebArgumentResolver to get to my session variable. This allowed me to keep this session variable out of the response while keeping my action unit testable.
Along with #ModelAttribute, pass #ModelMap as a method argument.
Based on business logic, error conditions -- if you do not need the attribute for certain scenarios, then remove it from the map.
public ModelAndView foo(#ModelAttribute("userContext") UserContext, #ModelMap map){
if(success){
return success.jsp
}
else{
map.remove("userContext");
return "error.jsp"
}
}
Not totally satisfied with having to pass the ModelMap as well, but I did not find any other easier way of doing it.
Cheers!!
The default route in MVC {controller}/{action}/{id} is for the most part quite helpful as is being able to set a default if the incoming url doesn't include a parameter but is there also a way to specify a default action for when an action doesn't exist on a controller?
What I want to achieve is being able to have controllers with several specific actions and then its own catchall which uses the url to grab content from a basic CMS.
For example a products controller would be something like:
public class ProductsController: Controller{
public ActionResult ProductInfo(int id){...}
public ActionResult AddProduct(){...}
public ActionResult ContentFromCms(string url){...}
}
Where the default route would handle /Products/ProductInfo/54 etc but a request url of /Products/Suppliers/Acme would return ContentFromCms("Suppliers/Acme"); (sending the url as a parameter would be nicer but not needed and a parameterless method where I get it from Request would be fine).
Currently I can think of two possible ways to achieve this, either:
Create a new constraint which reflects over a controller to see if it does have an action of a given name and use this in the {controller}/{action}/{id} route thus allowing me to have a more general catchall like {controller}/{*url}.
Override HandleUnknownAction on the controller.
The first approach seems like it would be quite a roundabout way of checking this while for the second I don't know the internals of MVC and Routing well enough to know how to proceed.
Update
There's not been any replies but I thought I'd leave my solution incase anyone finds this in future or for people to suggest improvements/better ways
For the controllers I that wanted to have their own catchall I gave them an interface
interface IHasDefaultController
{
public string DefaultRouteName { get; }
System.Web.Mvc.ActionResult DefaultAction();
}
I then derived from the ControllerActionInvoker and overrode FindAction. This calls the base FindAction then, if the base returns null and the controller impliments the interface I call FindAction again with the default actionname.
protected override ActionDescriptor FindAction(ControllerContext controllerContext, ControllerDescriptor controllerDescriptor, string actionName)
{
ActionDescriptor foundAction = base.FindAction(controllerContext, controllerDescriptor, actionName);
if (foundAction == null && controllerDescriptor.ControllerType.GetInterface("Kingsweb.Controllers.IWikiController") != null)
{
foundAction = base.FindAction(controllerContext, controllerDescriptor, "WikiPage");
}
return foundAction;
}
As I also want parameters from the routing I also replace the RouteData at the start of the default Actionresult on the controller
ControllerContext.RouteData = Url.RouteCollection[DefaultRouteName].GetRouteData(HttpContext);
You approach is quite fine. As a side-note:
replace
controllerDescriptor.ControllerType.GetInterface("Kingsweb.Controllers.IWikiController") != null
with
typeof(Kingsweb.Controllers.IWikiController).IsAssignableFrom(controllerDescriptor.ControllerType)
this is more strongly-typed way then passing in the name of the interface via string: what if you change the namespace tomorrow?..