I am started development of intranet application.
Initially I started doing it using Spring Roo. Its really great.
But still JSP/HTML are pain and it is not needed for intranet application…
I stumble upon Vaadin. Its really great and easy.
I worked on Swing before. So Vaadin is like home to me. :bashful:
Anyways,
I am wondering whether using MVC Controller makes sense in Vaadin?
I am unable to see any possibility of that.
IMO in most cases separating call-backs (controller) to another class from UI initialization (view) is just not just worth the effort and would make the application logic harder to follow and modularize.
Instead I would recommend slicing your UI into small independent logical UI components that contain both the “controller” and “view” in one module and provide a clean API for connecting the “model”.
I am assuming that your application has a significant complexity and size, not just the usual demo-stuff.
So you want to use the MVC-pattern - great, I fully agree! This is always a good thing for separation of concerns.
I have a really long experience with writing and using MVC-Frameworks, and my strong advice is to always keep a kind of abstract perception to the views. Whether you use Vaadin, Swing, SWT, whatever… why should you change your way of implementing controllers? If your UI-components both contain controller- and view-logic, it will be hard to recognize the part “controller” and it’s responsibilities in it… and even worse: If you want to support more UI-systems than Vaadin you can’t easily keep and reuse your controller-logic.
Yes sure, it’s more effort at the beginning, but later you will have more modularity, clarity and flexibility.
Well, I have the same felling than Marco, and I have some elements for discussing (not for a joust please).
The first impression is all examples in the site doesn’t work with models. Just with “primitive” types like String.
I take the example of TwiColumnSelectExample I have adapted by doing adjustments to Vaadin 6.1.5 (added 2 interfaces : IListModelProvider<T, U> and ILabelProvider, rewritten TwinColSelect<T, U>) :
Model class : City
public class City {
private String name;
private String zip;
public City(String namme, String zzip) {
super();
this.setName(namme);
this.setZip(zzip);
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @return the zip
*/
public String getZip() {
return zip;
}
/**
* @param name
* the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @param zip
* the zip to set
*/
public void setZip(String zip) {
this.zip = zip;
}
}
/**
* Example for use : display a table of user's Vaadin contacts<br/>
* U == VaadinUser.class<br/>
* T == User.class <br/>
*
* And the class VaadinUser should contains an instance variable of type List of
* Users
* */
public interface IListModelProvider<T, U> {
public List<T> getModel(U baseModel);
}
the rewritten class : TwinColSelect (copy of code and adaptation)
import java.util.List;
import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.PaintTarget;
import com.vaadin.ui.AbstractSelect;
public class NewTwinColSelect<T, U> extends AbstractSelect {
private int columns = 0;
private int rows = 0;
// Added
private ILabelProvider<T> labelProvider;
private IListModelProvider<T, U> listModelProvider;
// End Added
/**
*
*/
public NewTwinColSelect() {
super();
setMultiSelect(true);
}
/**
* @param caption
*/
public NewTwinColSelect(String caption) {
super(caption);
setMultiSelect(true);
}
// /**
// * @param caption
// * @param dataSource
// */
// public MyTwinColSelect2(String caption, Container dataSource) {
// super(caption, dataSource);
// setMultiSelect(true);
// }
// Added
public void setLabelProvider(ILabelProvider<T> labelProvider) {
this.labelProvider = labelProvider;
}
public void setModelProvider(IListModelProvider<T, U> modelProvider) {
this.listModelProvider = modelProvider;
}
public void setModel(U baseModel) {
getContainerDataSource().removeAllItems();
List<T> list = listModelProvider.getModel(baseModel);
for (T t : list) {
getContainerDataSource().addItem(t);
}
}
// End Added
/**
* Sets the number of columns in the editor. If the number of columns is set
* 0, the actual number of displayed columns is determined implicitly by the
* adapter.
*
* @param columns
* the number of columns to set.
*/
public void setColumns(int columns) {
if (columns < 0) {
columns = 0;
}
if (this.columns != columns) {
this.columns = columns;
requestRepaint();
}
}
public int getColumns() {
return columns;
}
public int getRows() {
return rows;
}
/**
* Sets the number of rows in the editor. If the number of rows is set 0,
* the actual number of displayed rows is determined implicitly by the
* adapter.
*
* @param rows
* the number of rows to set.
*/
public void setRows(int rows) {
if (rows < 0) {
rows = 0;
}
if (this.rows != rows) {
this.rows = rows;
requestRepaint();
}
}
// /**
// * @param caption
// * @param options
// */
// public MyTwinColSelect2(String caption, Collection options) {
// super(caption, options);
// setMultiSelect(true);
// }
@Override
public void paintContent(PaintTarget target) throws PaintException {
target.addAttribute("type", "twincol");
// Adds the number of columns
if (columns != 0) {
target.addAttribute("cols", columns);
}
// Adds the number of rows
if (rows != 0) {
target.addAttribute("rows", rows);
}
super.paintContent(target);
}
// Rewriten
@Override
public String getItemCaption(Object item) {
// IN MY OPINION THE PROBLEM IS HERE
return labelProvider.getCaption((T) item);
}
// End Rewriten
}
In Vaadin, all you are really doing is manipulating bunch of components on server side. Each of these components has it’s own controller logic that is part of it. Why not just follow the same pattern as the core Vaadin framework? As Joonas (and many others) suggested, just extend CustomComponent and create your own “view”. You should split your “view” to multiple parts if it becomes big.
Vaadin is not page oriented framework, it’s component based. The layout of the page/view is dynamic and its changing based on user action. So, there is no static layout. Your component is manipulating that layout. Initial layout might be totally different when you display to user.
Business logic should be totally outside Vaadin component and that’s where Spring comes in. But, MVC just makes not much sense for me either. Especially for large projects where you need independent modules working separately/independently…
The other major pieces missing from Vaadin in my opinion is a navigation framework (new in 7) and an event bus used to decouple high level events (e.g. contact saved).