Im trying to understand how the Passive View design pattern works for simple web apps.
Can someone provide a simple example of this pattern using these requirements:
View is a JSP that prints HELLO WORLD!
Data is persisted in the data store as "hello world", call to retrieve data can be a stub
Provide example files for pieces (presenter, view, etc) and denote which piece of the pattern each file represents.
No frameworks/DSLs should be used other than jstl/el (which are optional)
Thanks
UPDATE 1: Adding my understanding of how this would be structured.
// Presenter; responsible for multiple "rendtions" of a particular view (show, index, edit, summary, etc.)
public class HelloWorldPresenter {
private HttpServletRequest request;
private DataStore dateStore;
public HelloWorldPresenter(HttpServletRequest request) {
this.request = request;
this.dataStore = DataStoreUtil.getDataStore(request);
// Do a bunch of other inits that all getXXXModels() will use
}
public getShowModel() {
HelloWorldShowModel model = new HelloWorldShowModel();
String tmp = makeLoud(this.dataStore.getMyData()); // Stub method
model.setText(tmp);
return model;
}
private String makeLoud(String str) {
return str.toUpperCase() + "!";
}
}
// Model used by view
public class HelloWorldShowModel {
private String text;
public getText() { return this.text };
public setText(String text) { this.text = text; }
}
// View
show.jsp
<c:set var="model" value="new HelloWorldPresenter.getShowModel()"/>
${model.text} -> HELLO WORLD!
or
<% HelloWorldShowModel model = new HelloWorldPresenter(request).getShowModel() %>
<%= model.getText() %>
The things I'm unsure about are:
How the Presenter would be exposed to the View (JSP) since the View shouldnt know about the presenter. I may be mixing semantics though, and the HelloWorldShowModel (which is acting as a "ViewModel" of sorts, is what shouldnt know about the Presenter).
Should I even have the HelloViewShowModel abstraction, or should I simply have a method getText() on my Presenter which is called within the JSP to get the requested text.
If I do have multiple "views" for a resource (ex. Show, Index, Edit, Summary, etc.), should I have multiple Presenters? How should this logic be broken up? Multiple presenters that inherit from a Shared presenter? Should each presenter only be responsible for returning one ViewModel?
I've read through Fowlers articles as well as a number of other write-ups - the problem (for me) is they are written in the context of .NET apps, and I dont understand how all their objects get wired up.
I hope this will aleve concerns of me being "lazy" and looking for a "hand-out" answer :)
With the requirements you state I would say the pattern can't be implemented. If you consider the view to be a JSP then there are no means a controller could actively set any values of UI components. (To me this is the core of the pattern: the controller actually updates the view actively by setting values of input / output UI components, not the other way round (view getting fields from a model object). This can't be done with the above techniques as a JSP has no means to be accessesd this way.
It could be implemented in a web environment based on Javascript though. Consider your view being the DOM and your controller being a Javascript component. The JS controller has direct write access to the DOM and therefore could update single fields actively like the pattern suggests. To update / get the model the JS controller could talk to a server-side system e. g. based on a REST API via Ajax.
A plain templating solution like JSP cannot be used to offload all logic to controller, at least in real world cases. I think this kind of thing can be achieved with JSF.
If you want to learn about how things are done I recommend you to take a look at Spring MVC. It's source code can teach you a lot.
Related
I am working on a PDF Invoice generator in Vaadin 7. The code as it stands at the time of this writing can be found here. The repo includes a crude class diagram.
My question concerns the best practice of collecting the user input from the TextField and other Vaadin components to create an instance of Invoice.
Currently it works like this:
When the user clicks the button to generate the pdf, the class VaadinInvoiceGui (a Panel) calls the method createPdf(VaadinInvoiceGui gui) in the class VaadinInvoiceController.
VaadinInvoiceController calls method getInvoiceFromForm(VaadinInvoiceGui gui) in class InvoiceMapperImpl.
InvoiceMapperIml creates and returns an Invoice (POJO) by calling get methods in the VaadinInvoiceGui that gets passed to it. These getters return the values of the components in the view.
VaadinInvoiceController takes the Invoice returned by InvoiceMapperImpl and goes on to create pdf from it etc..
The getters in VaadinInvoiceGui look like this.
public String getCustomerName() {
return infoPanel.getCustomerNameTextField().getValue().toString();
}
public String getCustomerStreet() {
return infoPanel.getCustomerStreetTextField().getValue().toString();
}
public String getCustomerCity() {
return infoPanel.getCustomerCityTextField().getValue().toString();
}
...
I really don't feel like it's a good idea to pass the whole gui class to the controller and especially to the mapper, but I'm not sure what would be a better way of doing it. I could change the method createPdf(VaadinInvoiceGui gui) to something like createPdf(String customer name, String customerStreet, ...) but the number of parameters of the method would grow huge. I could do it using setters but then it would basically be doing the object mapping in the gui which doesn't seem like a very clean idea either.
What is the proper way of doing this?
Write a bean for the data to pass around as your model. Then use the FieldGroup to bind between model and form. Wrap the model as BeanItem<Model>. Binding is either done by name (convention) or by annotation #PropertyId.
master-detail-example: https://vaadin.com/wiki/-/wiki/Main/Creating+a+master-details+view+for+editing+persons
general infos: https://vaadin.com/book/vaadin7/-/page/datamodel.html
binding in forms: https://vaadin.com/book/vaadin7/-/page/datamodel.itembinding.html
Using Play 2.1.0, I have a Java controller with an action responsible to render arbitrary html views.
For example:
class HtmlClientViews extends Controller {
public static void getView(String viewName) {
return ok(/*How to render the view programmatically?*/)
}
}
And in my views I have a view named account.html.scala.
I have a route like:
GET /htmlclient/*viewName controllers.HtmlClientViews.getView(viewName)
If I make a request like /htmlclient/account.html I want to render the view named account.html.scala
I haven't tried yet to use Java reflection mechanisms for this, but would like to know what is the most effective way to achieve this.
You can do it with:
reflections, like in Play Authenticate usage sample, there it's used for selecting different view depending on detected language
If you have known number of views you can use simple switch statement in controller to return view a,b,c or d.
Also as in case no. 2 - you can use matching statement in the view to include sub-view depending on some variable.
Right now, my web.xml is configured in the way that Spring MVC will take over anything that has *.html suffix. I have a few controllers that generate the web links based on current user state.
For instance, I have the following code to determine what the "Next" button should point to:
if (nextSlide != null) {
nextLink = String.format("/%s/module/%d/slide/%d.html", studyName, moduleId, nextSlide.getKey());
}
else {
nextLink = String.format("/%s/module/all.html", studyName);
}
But, I don't like this approach because I'm hardcoding the ".html" to the links here. I could certainly create a factory that generates links with ".html" suffix to hide from all the controller code, but that still requires me to hardcode ".html" once in my Java code... not too DRY.
I'm basically hoping Spring MVC has some APIs that allow me to construct the links. If these APIs don't exist, do you hardcode the suffix in the Java code like what I do here?
There is not. Given what you currently have, you have three options. Two of these are your option, and dwb's option. The other is to create your own taglib.
It seems like you're doing some kind of wizard functionality (where screen 2 is dependent on a click from screen 1). If that's the case, I would look into Spring Webflow.
Another possibility is to perform an AJAX callout to some sort of decision method, or you could handle this all on the client side with JavaScript.
Also, FWIW, I don't think coding .html is breaking DRY, but I would be concerned about maintenance in case your servlet ever matched on something other than this suffix. You could most likely do something similar to the below example by just essentially returning a new ModelAndView or redirecting to one at least:
#RequestMapping("slide/{id}")
public String goToSlide(#PathParam("id") String id, ModelMap model) {
model.adAttribute("slide", slideService.findById(id));
return "slides/slide";
}
#RequestMapping("all")
public String getAllSlides() {
return "slides/all";
}
#RequestMapping(value="slideshow/{id}", method=RequestMethod.GET)
public String getSlideshow(#PathParam("id") String slideshowId, ModelMap model) {
model.attAttribute("slideshow", slideshowService.findById(slideshowId));
return "slides/slideshow";
}
#RequestMapping(value="slideshow", method=RequestMethod.POST)
public String postSlideshow(#QueryParam("slideId") String slideId) {
if(slideId != null) {
return "slide/" + slideId;
}
return "redirect:all";
}
It seems like building URLs should be handled in the view rather than the controller. Moving it to the view would eliminate the need to hard code anything in Java. You'd also be able to make use of Spring's URL tag. From the Spring API docs:
<spring:url value="/url/path/{variableName}">
<spring:param name="variableName" value="more than JSTL c:url" />
</spring:url>
// Results in: /currentApplicationContext/url/path/more%20than%20JSTL%20c%3Aurl
So, we are getting to the point in our Spring application where we need to decide how to handle views and content negotiation. Previously, we've only supported one specific content type in our endpoints.
I'm going to throw our what I think our the three approaches.
My question: Which one is generally considered best practice/least amount of maintenance? We are aiming for a solid convention to follow in our application, which can be broken where needed to provide flexibility if desired.
First approach:
Use ContentNegotiatingViewResolver. This would involve a mapping defined in the servlet file... in the controller, each controller action would need to explicitly set the object in a map using some magic string. The controller action would return a string which refers to a template name... sort of like the following:
#RequestMapping(value = "/someMapping/source", method = RequestMethod.GET)
public String foo(Model model)
{
// more stuff here
model.addAttribute(SOME_MODEL_KEY, new ArrayList<String>() { "hello world"});
return "someDummyJsonString";
}
Drawbacks:
View resolvers seem a little unwieldy... they have priorities, you need to override them often times, etc. Also, I don't like the idea of the "magic strings" which are used to refer to template/View bean names.
Second approach:
I think this is new in Spring 3.0, but in RequestMapping you can match on headers... so you can match on the Accept header like so:
#RequestMapping(value="/someMapping", method = RequestMethod.GET, headers="Accept=application/json")
public #ResponseBody SomeBar foo()
{
// call common controller code here
return buildBar();
}
#RequestMapping(value="/someMapping", method = RequestMethod.GET, headers="Accept=text/xml")
public String foo(Model model)
{
model.addAttribute("someModelName", this.buildBar());
return "someTemplateNameProcessedByViewResolver";
}
SomeBar buildBar()
{
return new SomeBar();
}
Drawbacks:
Might not be flexible enough? I'm not sure, but I think I really like the headers approach... I've seen other frameworks (RESTLet, Rails) use something similar.
Third approach:
The third approach involves making a custom View which will negotiate the content based on the Accept header, and throw the model through the appropriate method. This content negotiating view would have to know a template, and load the template etc.:
#RequestMapping(value="/someMapping", method = RequestMethod.GET, headers="Accept=text/xml")
public View foo()
{
SomeBar bar = new SomeBar();
ContentNegotiatingView view = new ContentNegotiatingView(bar, "templateName");
return return view;
}
Drawbacks:
It seems like the view is doing too much in this case... the view would be looking at headers, and setting the response body itself. It might need to set http statuses also.
So, sorry for the wall of text, let me know your thoughts on this. Thanks
Someone else just asked this. See my answer.
HI guys,
I wanted to add an AJAX Event to my Homepage, but it doesn't work! I figured out, that if I delete the onComponentTag function it works well. I have no clue why this happend, maybe you can help me!
Thats my Code:
final TextField<String> searchInput = new TextField<String>("searchInput", model) {
#Override
protected void onComponentTag(final ComponentTag tag) {
super.onComponentTag(tag);
tag.put("id", this.getId());
if (params.getString("search") != null) {
tag.put("value", params.getString("search"));
}
}
};
searchInput.add(new AjaxFormComponentUpdatingBehavior("onfocus") {
#Override
protected void onUpdate(final AjaxRequestTarget target) {
System.out.print("never saw that message :(");
searchInput.setDefaultModelObject("");
target.addComponent(searchInput);
}
});
Thx a lot for helping me!
CU
Firstly, you don't need to be overriding onComponentTag() at all. As seanizer states, if your really need to specify a markup ID yourself, use setMarkupId(id). You should understand why it is recommended that Wicket manages component IDs.
Secondly, the value attribute that you are adding is unnecessary - Wicket adds this automatically for this component. The value assigned is the value of the component's model object. See the source for TextField.onComponentTag().
Thirdly, again as seanizer states, components that are to be updated by ajax need to output their markup IDs - Wicket's ajax implementation uses the ID as the selector for the element. Additionally, all Wicket ajax behaviours that extend AbstractDefaultAjaxBehavior automatically set outputMarkupId(true) on the component they are bound to (see the source for AbstractDefaultAjaxBehavior.onBind()). This includes AjaxFormComponentUpdatingBehavior.
So:
String id = "searchInput";
final TextField<String> searchInput = new TextField<String>(id, model);
searchInput.setMarkupId(id);
searchInput.add(new AjaxFormComponentUpdatingBehavior("onfocus") {
#Override
protected void onUpdate(final AjaxRequestTarget target) {
System.out.print("never saw that message :(");
searchInput.setDefaultModelObject("");
target.setOutputMarkupId(true);
target.addComponent(searchInput);
}
});
Finally, I'd question what you're actually trying to achieve with this behaviour. I don't see any reason to round-trip this event to the server. Surely some client-side JS is more appropriate?
tag.put("id", this.getId());
is not the way to do it in wicket.
instead, use
component.setOutputMarkupId(true)
(either in your component constructor or in your behavior's bind() method) to make wicket write the id, and if you absolutely need to control what the id is (which is almost never the case) you can do
component.setMarkupId("myId")
also, you probably shouldn't assign the tag value yourself, use a model (model handling is extremely smart in wicket, read more about models). There are valid uses for onComponentTag, but they are way beyond what you are doing. Let wicket do what wicket does best and everything will be fine.
EDIT:
OK, some more clarification
have a look at the source code of AjaxFormComponentUpdatingBehavior, especially the part where the javascript event handler is generated.
protected final CharSequence getEventHandler()
{
return generateCallbackScript(
new AppendingStringBuffer("wicketAjaxPost('")
.append(getCallbackUrl(false)).append(
"', wicketSerialize(Wicket.$('"
+ getComponent().getMarkupId() + "'))"));
}
as you can see, wicket uses getMarkupId() to determine the actual id. The id you set using tag.put(id) is totally unknown to wicket and hence the behavior cannot work.
The standard thing to do is setOutputMarkupId(true). This is the only proper way to tell wicket to render the id (other than setOutputMarkupPlaceholder(true), which internally calls the former method). That way you make sure that the id wicket writes is the id wicket knows about. If this doesn't render the id, you are probably breaking some default behavior by overwriting onComponentTag.
Have a look at the source code of Component, especially at onComponentTag(), the method you are overriding:
protected void onComponentTag(final ComponentTag tag) {
// if(setOutputMarkupId(true) was set)
if (getFlag(FLAG_OUTPUT_MARKUP_ID)) {
// set id attribute
tag.put(MARKUP_ID_ATTR_NAME, getMarkupId());
}
}
[The comments are mine. BTW, this is the source of an ancient version, but I didn't find any current source online, and the functionality hasn't changed.]
Now if, as in your case, you want to set the component id manually, you must use
component.setMarkupId("myId")
and of course
setOutputMarkupId(true)
as well. If that doesn't work, go to the wicket JIRA site and file a bug. But I doubt it, this is standard functionality that works for thousands of users.