I have defined property in component dialog
How I can access this value from execute() method in model class?
Model class will request service at this url
Documentation discusses only how to access data within Model class, I need to pass url into Model class.
I can't send request from page by ajax, because service domain not exposed to extranet.
Your model class extends from RenderingModelImpl. Or at least it should :).
Because of that there's a constructor that get passed current component node in and it's exposed to you via getNode() method.
So assuming that when you click on Save changes in your dialog, the value gets persisted under unsubscribeUrl property, to access this value from execute() method:
public String execute() {
// read unsubscribe url
String unsubscribeUrl = this.getNode().getProperty("unsubscribeUrl").getString();
}
In your ftl you can call the model with an argument:
${model.myMethod(content.unsubscribe_url)}
In your model you can use the argument to do what you need
public class myMethod(String url) {
do something ....
}
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 creating a small validation application using Spring MVC. I am very new to Spring MVC and would like to ensure that what I want is possible.
I have simplified my problem.
I have setup a controller that will be called when a URL is executed. localhost/validate/{SOME TEXT}
The {SOME TEXT} value with be sent to all my validation classes I created.
I currently have 4 classes which does the validation and returns another Object data about what happened during the validation
The 4 validation classes are:
CreditCardValidator
AddressValidator
ZipcodeValidator
AccountNumberValidator
I have a main controller bean that when called I want the string to be passed to each class and the object returned from each to be stored and then finally all results are sent back in a response.
Normally, I would do this without Spring by creating an interface that each validation class implements. Then iteration through the list of classes and execute a method.
The problem doing it that way is that whenever I need to add a new validation class I'll need to register it so the request can use it. This involved modifying existing classes.
Since I am using Spring quick heavily in this application I am wondering if this is possible to do via Spring and annotated classes.
I was thinking of creating a custom annotation that each validation class has and then using spring component-scan to get the classes. This would allow me to create new validations without modifying existing code.
Below is the what I am trying to do.
#Controller
public class StringValidationController {
#RequestMapping(value = "/validate/{text:.+}", method = RequestMethod.GET)
public ModelAndView index(#PathVariable("text") String text) {
ModelAndView model = new ModelAndView();
model.setViewName("index");
model.addObject("result", getListOfValidatedData());
return model;
}
public List getListOfValidatedData(){
//Scan for IValidator annotation
//call each concrete class and pass in text
// get object with has validation information in it
}
}
Below is my controller. My program generates an output, based on a form input. Across the project, there are multiple input forms, that generate the output object. So, the essential flow is the same. So I want a single multi-action controller that does all of that.
Challenges:
1. The service classes change. Although all services implement the same interface, and controller calls the same interface method.
2. The input objects change. Although the input objects do not have any methods other than setters, and getters. So I let them all implement an empty interface.
Questions:
How do I change the qualifier, based on the path. Can I use path variables?
Suppose the path has this value -> singleton. Then my corresponding bean names would be singletonService and singletonInput. I want to make a constant class that has stores this mapping information. So, can I call that from inside the qualifier, using some Spring Expression Language? Example, instead of Qualifier(variablePathName) -> Qualifier(getQualifierName['variablePathName']) Something like that?
Please also clarify the theory behind this. From what I understand, beans are created, autowired before the Request are mapped... Does this mean that what I'm trying to achieve here is simply not possible. In that case, would you suggest making Controller-service pairs for handling each request, with basically the same code? But I feel there must be some way to achieve what I'm trying...
Code:
#Cotroller
#RequestMapping(value="/generate/{path}")
public class TestController {
#Autowired
#Qualifier(......)
private IService service;
#Autowired
#Qualifier(......)
IUserInput userInput;
#RequestMapping(method = RequestMethod.POST)
//Some handler method
}
You're right in that the autowiring is all done once up front (point 3). You wouldn't be able to achieve what you want using fields annotated #Autowired and #Qualifier - as these fields would always reference the same bean instance.
You may be better to ask Spring for the particular service bean by name - based on the path variable. You could do it within a single controller instance. For example:
#Cotroller
#RequestMapping(value="/generate/{path}")
public class TestController {
#Autowired
private ApplicationContext applicationContext;
#RequestMapping(method = RequestMethod.POST)
public String someHandlerMethod(#PathVariable String path) {
IService service = (IService) applicationContext.getBean(path + "Service");
IUserInput userInput = (IUserInput) applicationContext.getBean(path + "UserInput");
// Logic using path specific IService and IUserInput
}
}
As Spring Specification said, #ModelAttribute will executed before the mapping handler and #SessionAttribute will keep the model attribute in session.
Consider below scenario: form bean is created after the controller is called and is set as session attribute as well. Next time MenuController is called, createForm() will be executed again and create another new form bean. My question is: will this latest created form bean be set as session attribute? and which form bean will be bind to the parameter in method bookList()?
Hope you guys can help. Thank you.
#Controller
#RequestMapping("/store")
#SessionAttribute("form")
public class MenuController {
#ModelAttribute("form")
public Form createForm() {
return new Form();
}
#RqeustMapping("/book")
public String bookList(#ModelAttribute("form") Form form){
//processing the form
}
}
When the bookList method is invoked for the first time in a given session, then method with #ModelAttribute('form) is invoked, the returned value (Form object) is stored in HttpSession and finally the bookList method is invoked with the same Form object passed as an argument (obtained from session).
For the subsequent requests within the same HttpSession, Spring retrieves the same Form object from the session and doesn't call the method with #ModelAttribute('form') again till the end of the session.
After each end of the bookList method invocation Spring stores updated version of Form object in HttpSession.
If you are using Spring Boot 2.x you can debug DefaultSessionAttributeStore#retrieveAttribute method to understand this behaviour.
Remember that your mapping is generalised. It will map both to a GET method and a POST method.
If your request mapping is a GET method,
The session attribute will hold the value of the #ModelAttribute("form") from the method createForm.
If an attribute form is returned from a POST request,
The session Attribute will override the #Model Attribute from the createForm method.
It is helpful to remember that the #ModelAttribute will execute before the mapping handler.
the sessionAttribute indicates that the "form" will be saved in the session. not meaning the "form" is retrieved from the session.
I am using Moq for unit testing and I would like to test for a view's attribute.
In this case the Authorize attribute.
Example View Code:
[Authorize(Roles = "UserAdmin")]
public virtual ActionResult AddUser()
{
// view logic here
return View();
}
So I would like to test the view attribute when I act on this view with a user that is in the role of UserAdmin and a user that is not in the role of user admin. Is there anyway to do this ?
Example Test:
[Test]
public void Index_IsInRole_Customer()
{
// Arrange
UserAdminController controller = _controller;
rolesService.Setup(r => r.IsUserInRole(It.IsAny<string>(), It.IsAny<string>())).Returns(false); // return false for any role
// Act
var result = controller.AddUser();
// Assert
Assert.IsNotNull(result, "Result is null");
}
Attributes are just metadata on the type, so they don't do anything unless the surrounding infrastructure make them do something (or better yet: the surrounding infrastructure does something based on the information in those attributes). That's what the ASP.NET MVC framework does when it executes a request.
That is not what you do when you create and invoke a Controller Action in a unit test, so unless you want to go to great lengths to invoke the Controller Action using a ControllerActionInvoker (at which point the test ceases to be a unit test and becomes an integration test) you can't directly test the behavior implied by the attribute.
You can, however, write a unit test that verifies that the attribute correctly decorates the Controller Action:
var attributes = typeof(UserAdminController)
.GetMethod("AddUser").GetCustomAttributes(true);
var result = attributes.OfType<AuthorizeAttribute>().Single();
Assert.AreEqual("UserAdmin", result.Roles);
When executing the test above the AuthorizeAttribute will not be taken into account (that is, no one will evaluate it). This is normally the responsibility of the ControllerActionInvoker (a class in System.Web.Mvc).
You might want to just trust that AuthorizeAttribute is correctly implemented. Then just use reflection to verify that the AuthorizeAttribute has been correctly defined on your action.