準備技術:
網站的前後端,看一個Vaadin實例。
後端,結合JPA,採用H2 DB。
public class Backend {
static SimpleJDBCConnectionPool connectionPool = setupConnectionPoolAndCreateMockupDatabase();
static public final String titleId = "TITLE";
static public final String textId = "TEXT";
public static Container getNotesContainer() {
try {
if (connectionPool == null)
return null;
return new SQLContainer(new TableQuery("notes", connectionPool));
} catch (SQLException e) {
e.printStackTrace();
return null;
}
}
public static void commitChanges(Container modifiedConteiner) {
try {
((SQLContainer) modifiedConteiner).commit();
} catch (UnsupportedOperationException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
}
private static SimpleJDBCConnectionPool setupConnectionPoolAndCreateMockupDatabase() {
try {
SimpleJDBCConnectionPool pool = new SimpleJDBCConnectionPool(
"org.h2.Driver", "jdbc:h2:mem:notes", "sa", "sa");
Connection c = pool.reserveConnection();
try {
c.createStatement().executeQuery("select * from notes");
} catch (SQLException e) {
createTable(c);
initDatabaseWithRandomData(c);
} finally {
pool.releaseConnection(c);
}
return pool;
} catch (SQLException e) {
e.printStackTrace();
return null;
}
}
// Database contains just one table: notes with id, title and text columns
private static void createTable(Connection c) throws SQLException {
c.createStatement().executeUpdate(
"create table notes(id long primary key, " + titleId
+ " varchar(100), " + textId + " varchar(4000))");
}
private static void initDatabaseWithRandomData(Connection connection)
throws SQLException {
for (int i = 0; i < 500; i++) {
PreparedStatement p = connection
.prepareStatement("insert into notes values (?,?,?)");
p.setLong(1, i);
p.setString(2, generateRandomTitle((int) (Math.random() * 5 + 1)));
p.setString(3, generateRandomHTML((int) (Math.random() * 250 + 1)));
p.executeUpdate();
}
connection.commit();
}
private static String generateRandomHTML(int minimumNumberOfWords) {
StringBuffer sb = new StringBuffer();
while (minimumNumberOfWords > 0) {
sb.append("<h2>");
int len = (int) (Math.random() * 4) + 1;
sb.append(generateRandomTitle(len));
sb.append("</h2>");
minimumNumberOfWords -= len;
int paragraphs = 1 + (int) (Math.random() * 3);
while (paragraphs-- > 0 && minimumNumberOfWords > 0) {
sb.append("<p>");
len = (int) (Math.random() * 40) + 3;
sb.append(generateRandomText(len));
sb.append("</p>");
minimumNumberOfWords -= len;
}
}
return sb.toString();
}
private static String generateRandomTitle(int numberOfWords) {
StringBuffer sb = new StringBuffer();
int len = (int) (Math.random() * 4) + 1;
sb.append(generateRandomWords(len, true));
while (--numberOfWords > 0) {
len = (int) (Math.random() * 4) + 1;
sb.append(' ');
sb.append(generateRandomWords(len, false));
}
return sb.toString();
}
private static String generateRandomWords(int numberOfParts,
boolean capitalized) {
String[] part = { "ger", "ma", "isa", "app", "le", "ni", "ke", "mic",
"ro", "soft", "wa", "re", "lo", "gi", "is", "acc", "el", "tes",
"la", "ko", "ni", "ka", "so", "ny", "mi", "nol", "ta", "pa",
"na", "so", "nic", "sa", "les", "for", "ce" };
StringBuffer sb = new StringBuffer();
for (int i = 0; i < numberOfParts; i++) {
String p = part[(int) (Math.random() * part.length)];
if (i == 0 && capitalized)
p = Character.toUpperCase(p.charAt(0)) + p.substring(1);
sb.append(p);
}
return sb.toString();
}
private static String generateRandomText(int words) {
StringBuffer sb = new StringBuffer();
int sentenceWordsLeft = 0;
while (words-- > 0) {
if (sb.length() > 0)
sb.append(' ');
if (sentenceWordsLeft == 0 && words > 0) {
sentenceWordsLeft = (int) (Math.random() * 15);
sb.append(generateRandomWords(1 + (int) (Math.random() * 3),
true));
} else {
sentenceWordsLeft--;
sb.append(generateRandomWords(1 + (int) (Math.random() * 3),
false));
if (words > 0 && sentenceWordsLeft > 2 && Math.random() < 0.2)
sb.append(',');
else if (sentenceWordsLeft == 0 || words == 0)
sb.append('.');
}
}
return sb.toString();
}
}
Component。
import com.vaadin.data.Item;
import com.vaadin.data.fieldgroup.FieldGroup;
import com.vaadin.data.fieldgroup.PropertyId;
import com.vaadin.ui.CustomComponent;
import com.vaadin.ui.RichTextArea;
import com.vaadin.ui.TextField;
import com.vaadin.ui.VerticalLayout;
public class NoteEditor extends CustomComponent {
@PropertyId(Backend.titleId)
TextField title = new TextField();
@PropertyId(Backend.textId)
RichTextArea text = new RichTextArea();
public NoteEditor() {
VerticalLayout layout = new VerticalLayout();
setCompositionRoot(layout);
layout.addComponent(title);
layout.addComponent(text);
setSizeFull();
layout.setSizeFull();
title.setWidth("100%");
text.setSizeFull();
layout.setExpandRatio(text, 1.0f);
}
public void setNote(Item note) {
FieldGroup g = new FieldGroup(note);
g.bindMemberFields(this);
g.setBuffered(false);
}
}
前端的UI。
import javax.servlet.annotation.WebServlet;
import com.vaadin.annotations.Theme;
import com.vaadin.annotations.VaadinServletConfiguration;
import com.vaadin.event.ItemClickEvent;
import com.vaadin.event.ItemClickEvent.ItemClickListener;
import com.vaadin.server.VaadinRequest;
import com.vaadin.server.VaadinServlet;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Button.ClickListener;
import com.vaadin.ui.Table.ColumnHeaderMode;
import com.vaadin.ui.HorizontalSplitPanel;
import com.vaadin.ui.Label;
import com.vaadin.ui.Table;
import com.vaadin.ui.UI;
import com.vaadin.ui.VerticalLayout;
@SuppressWarnings("serial")
@Theme("vaadinrpcdemo")
public class VaadinrpcdemoUI extends UI {
@WebServlet(value = "/*", asyncSupported = true)
@VaadinServletConfiguration(productionMode = false, ui = VaadinrpcdemoUI.class)
public static class Servlet extends VaadinServlet {
}
Table notes = new Table();
NoteEditor editor = new NoteEditor();
Button saveButton = new Button("Save");
@Override
protected void init(VaadinRequest request) {
buildLayout();
wireUp();
connectToBackend();
}
private void connectToBackend() {
notes.setContainerDataSource(Backend.getNotesContainer());
notes.setVisibleColumns(new String[] { Backend.titleId });
notes.setColumnHeaderMode(ColumnHeaderMode.HIDDEN);
}
private void wireUp() {
notes.addItemClickListener(new ItemClickListener() {
public void itemClick(ItemClickEvent event) {
editor.setNote(event.getItem());
}
});
saveButton.addClickListener(new ClickListener() {
public void buttonClick(ClickEvent event) {
Backend.commitChanges(notes.getContainerDataSource());
}
});
}
private void buildLayout() {
HorizontalSplitPanel split = new HorizontalSplitPanel();
VerticalLayout right = new VerticalLayout();
setContent(split);
split.addComponent(notes);
split.addComponent(right);
right.addComponent(editor);
right.setSizeFull();
right.setExpandRatio(editor, 1.0f);
right.setMargin(true);
right.setSpacing(true);
right.addComponent(saveButton);
notes.setSizeFull();
}
}
Vaadin RPC。
該實例的架構,參考文件2
網站運行結果。
參考資料:
Day 27 結束