Transcript Slide 1

COMP 321
Week 14
Overview
Struts 2
Google Web Toolkit (GWT)
Struts 2
<!-- Hello.jsp -->
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title>Hello World!</title>
</head>
<body>
<h2><s:property value="message" /></h2>
</body>
</html>
Struts 2
public class HelloWorld extends ActionSupport {
public static final String MESSAGE = "Struts is up and running ...";
public String execute() throws Exception {
setMessage(MESSAGE);
return SUCCESS;
}
private String message;
public void setMessage(String message){
this.message = message;
}
public String getMessage() {
return message;
}
}
Struts 2
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration
2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<package name="tutorial" extends="struts-default">
<action name="HelloWorld" class="tutorial.HelloWorld">
<result>/HelloWorld.jsp</result>
</action>
<!-- Add your actions here -->
</package>
</struts>
Struts 2
1.
2.
3.
4.
5.
6.
Browser sends to the web server a request for the URL
http://localhost:8080/tutorial/HelloWorld.action.
Container receives for HelloWorld.action, finds that all requests are being routed
to org.apache.struts2.dispatcher.FilterDispatcher, including *.action
requests. The FilterDispatcher is the entry point into the framework.
The framework looks for an action mapping named "HelloWorld", and finds that this
mapping corresponds to the class "HelloWorld". The framework instantiates the
Action and calls the Action's execute method.
The execute method sets the message and returns SUCCESS. The framework
checks the action mapping to see what page to load if SUCCESS is returned. The
framework tells the container to render as the response to the request, the resource
HelloWorld.jsp.
As the page HelloWorld.jsp is being processed, the <s:property
value="message" /> tag calls the getter getMessage of the HelloWorld Action, and
the tag merges into the response the value of the message.
A pure HMTL response is sent back to the browser.
Testing Actions
public class HelloWorldTest extends TestCase {
public void testHelloWorld() throws Exception {
HelloWorld hello_world = new HelloWorld();
String result = hello_world.execute();
assertTrue("Expected a success result!",
ActionSupport.SUCCESS.equals(result));
assertTrue("Expected the default message!",
HelloWorld.MESSAGE.equals(hello_world.getMessage()));
}
}
Using Tags
<!-- s:url knows how to find actions, and automatically
encodes URLs -->
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title>Welcome</title>
<link href="<s:url value="/css/tutorial.css"/>" rel="stylesheet"
type="text/css"/>
</head>
<body>
<h3>Commands</h3>
<ul>
<li><a href="<s:url action="Register"/>">Register</a></li>
<li><a href="<s:url action="Logon"/>">Sign On</a></li>
</ul>
</body>
</html>
Using Tags
<!-- Struts form elements create a label and field with one tag -->
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title>Login</title>
</head>
<body>
<s:form action="Logon">
<s:textfield label="User Name" name="username"/>
<s:password label="Password" name="password" />
<s:submit/>
</s:form>
</body>
</html>
Coding Actions
public class Logon extends ActionSupport {
public String execute() throws Exception {
if (isInvalid(getUsername())) return INPUT;
if (isInvalid(getPassword())) return INPUT;
return SUCCESS;
}
private String username;
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
private String password;
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
private boolean isInvalid(String value) {
return (value == null || value.length() == 0);
}
}
Validating Input
<!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.2//EN"
"http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd">
<validators>
<field name="username">
<field-validator type="requiredstring">
<message>Username is required</message>
</field-validator>
</field>
<field name="password">
<field-validator type="requiredstring">
<message>Password is required</message>
</field-validator>
</field>
</validators>
Google Web Toolkit (GWT)
Allows writing AJAX applications using
only Java
Cross-compiles Java code to Javascript
with heavy optimizations
Handles browser compatibility issues
transparently
RPC handled through Serialization
All code can be debugged in Eclipse via
hosted-mode browser
GWT
GWT (cont’d)
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>StockWatcher</title>
<script type="text/javascript" language="javascript"
src="com.google.gwt.sample.stockwatcher.StockWatcher.nocache.js"></script>
</head>
<body>
<h1>Stock Watcher</h1>
<div id="stockList"></div>
</body>
</html>
GWT – UI Design
GWT – Java Code
public class StockWatcher implements EntryPoint {
private VerticalPanel mainPanel = new VerticalPanel();
private FlexTable stocksFlexTable = new FlexTable();
private HorizontalPanel addPanel = new HorizontalPanel();
private TextBox newSymbolTextBox = new TextBox();
private Button addButton = new Button("Add");
private Label lastUpdatedLabel = new Label();
public void onModuleLoad() {
// set up stock list table
stocksFlexTable.setText(0,
stocksFlexTable.setText(0,
stocksFlexTable.setText(0,
stocksFlexTable.setText(0,
0,
1,
2,
3,
"Symbol");
"Price");
"Change");
"Remove");
// assemble Add Stock panel
addPanel.add(newSymbolTextBox);
addPanel.add(addButton);
GWT (cont’d)
// assemble main panel
mainPanel.add(stocksFlexTable);
mainPanel.add(addPanel);
mainPanel.add(lastUpdatedLabel);
// add the main panel to the HTML element with the id "stockList"
RootPanel.get("stockList").add(mainPanel);
// move cursor focus to the text box
newSymbolTextBox.setFocus(true);
}
}
GWT (cont’d)
// In onModuleLoad - set up event listeners for adding a new stock
addButton.addClickListener(new ClickListener() {
public void onClick(Widget sender) {
addStock();
}
});
private void addStock() {
final String symbol = newSymbolTextBox.getText().toUpperCase().trim();
newSymbolTextBox.setFocus(true);
// symbol must be between 1 and 10 chars that are numbers, letters, or dots
if (!symbol.matches("^[0-9a-zA-Z\\.]{1,10}$"))
{
Window.alert("'" + symbol + "' is not a valid symbol.");
newSymbolTextBox.selectAll();
return;
}
GWT (cont’d)
newSymbolTextBox.setText("");
// don't add the stock if it's already in the watch list
if (stocks.contains(symbol))
return;
// add the stock to the list
int row = stocksFlexTable.getRowCount();
stocks.add(symbol);
stocksFlexTable.setText(row, 0, symbol);
GWT (cont’d)
// add button to remove this stock from the list
Button removeStock = new Button("x");
removeStock.addClickListener(new ClickListener(){
public void onClick(Widget sender) {
int removedIndex = stocks.indexOf(symbol);
stocks.remove(removedIndex);
stocksFlexTable.removeRow(removedIndex+1);
}
});
stocksFlexTable.setWidget(row, 3, removeStock);
}
GWT – StockWatcher
GWT – Timer Class
// In onModuleLoad - setup timer to refresh list automatically
Timer refreshTimer = new Timer() {
public void run() {
refreshWatchList();
}
};
refreshTimer.scheduleRepeating(REFRESH_INTERVAL);
private void refreshWatchList() {
// Generate random prices, call updateTable
}
private void updateTable(StockPrice price) {
// make sure the stock is still in our watch list
if (!stocks.contains(price.getSymbol())) {
return;
}
GWT – Timer Class (cont’d)
private void updateTable(StockPrice price) {
if (!stocks.contains(price.getSymbol())) {
return;
}
int row = stocks.indexOf(price.getSymbol()) + 1;
String priceText = NumberFormat.getFormat("#,##0.00").format(price.getPrice());
NumberFormat changeFormat = NumberFormat.getFormat("+#,##0.00;-#,##0.00");
String changeText = changeFormat.format(price.getChange());
String changePercentText = changeFormat.format(price.getChangePercent());
// update the watch list with the new values
stocksFlexTable.setText(row, 1, priceText);
stocksFlexTable.setText(row, 2, changeText + " (" + changePercentText + "%)");
}
GWT – Remote Procedure Calls
// Used on client and server
@RemoteServiceRelativePath("stockPrices")
public interface StockPriceService extends RemoteService {
StockPrice[] getPrices(String[] symbols);
}
// Server implementation
public class StockPriceServiceImpl extends RemoteServiceServlet
implements StockPriceService {
@Override
public StockPrice[] getPrices(String[] symbols) {
// Get stock prices
}
}
public class StockPrice implements IsSerializable ...
GWT – RPC (cont’d)
<!-- Added to StockWatcher.gwt.xml -->
<servlet path="/stockPrices"
class="com.google.gwt.sample.stockwatcher.server.StockPriceServiceImpl" />
// Interface to be called on client side
public interface StockPriceServiceAsync {
void getPrices(String[] symbols, AsyncCallback<StockPrice[]> callback);
}
// Create client-side proxy - in onModuleLoad
StockPriceServiceAsync stockPriceSvc = GWT.create(StockPriceService.class);
GWT – RPC (cont’d)
// in refreshWatchList()
AsyncCallback<StockPrice[]> callback = new AsyncCallback<StockPrice[]>() {
public void onFailure(Throwable caught) {
// do something with errors - Exceptions can be thrown to client!
}
public void onSuccess(StockPrice[] result) {
// update the watch list FlexTable
}
};
stockPriceSvc.getPrices(symbols, callback);
Assignments
Due this week
 Lab 10-1 JSP User Interfaces
 Lab 13-1 Web Frameworks
 Evaluations
Due next week
 Final Exam