Sie sind auf Seite 1von 63

Ascora GmbH

Dipl. Inform. Tim Dellas, dellas@ascora.de

Ascora GmbH, http://www.ascora.de


Code Examples

String disclaimer = “Disclaimer: " +


"All my code should be cohesive. " +
"Some code could be quite old. " +
"Use at own risk. ";

throw new Exception(disclaimer);

Ascora GmbH, http://www.ascora.de


Gliederung

• Einleitung
– Warum Framework? Warum Java? Warum Struts2?
• Struktur von Webanwendungen
– HTTP-Requests, Browser, HTML, CSS, JavaScript
– Architektur (Model View Controller & MVC2)
• Struts2
– Vom Browser-Request  HTML
– struts.xml, Actionklassen und JSPs
– Plugins, Interceptors und Best Practices
• Meta
– Wozu Webseiten? Unterschiede zu Desktopapps?

Ascora GmbH, http://www.ascora.de


Einleitung

• Warum überhaupt ein Framework?

??? Server, URLs, Datenbanken

JavaScript, JS-Frameworks

CSS2.0, 3.0

HTML, HTML5

HTTP, TCP/IP, SSL

Verschiedene Browser

Ascora GmbH, http://www.ascora.de


Warum Struts2 + UseCases

• Warum überhaupt ein Framework?


• Erprobtes Standardvorgehen nutzen
• Konventionen einhalten
• Abstraktion von Low-Level Implementierung
• DRY: viel „Boilerplatecode“ sparen
• RAD: trotz Kompilierung schneller
Entwicklungszyklus

Ascora GmbH, http://www.ascora.de


Warum Struts2 + UseCases

• Warum Java?
• kompilierter Code: schneller als PHP
• Syntax schöner als PHP
• Compiler: Typ-Sicher
• Debugging und …
• Autocompletion in IDE
• Open Source & Kostenlos 
• Java bietet für alles Bibliotheken

Ascora GmbH, http://www.ascora.de


Warum Struts2 + UseCases

• Warum Struts2?
• Erprobtes Framework
» Weiterentwicklung von Struts + WebWork
• Hohe Verbreitung  große Community
• Viele Plugins  weniger Code schreiben
• Abstraktion von Protokollen & Servlet-API
» Programmlogik == POJOs
» Controller == xml-Konfiguration
• (oder wahlweise Annotationen)

Ascora GmbH, http://www.ascora.de


Warum Struts2 + UseCases

• Warum Struts2?
• Erprobtes Framework
» Weiterentwicklung von Struts + WebWork
• Hohe Verbreitung  große Community
• Viele Plugins  weniger Code schreiben
• Abstraktion von Protokollen & Servlet-API
» Programmlogik == POJOs
» Controller == xml-Konfiguration
• (oder wahlweise Annotationen)

Ascora GmbH, http://www.ascora.de


Warum Struts2 + UseCases

• UseCases
• Alles mit ausreichend Komplexität
• (mehrere Seiten, Applikationslogik und
Datenbankzugriffe)
• Alles was „sicher“ sein muss
• Alles was „performant“ sein muss

Ascora GmbH, http://www.ascora.de


Struktur von Webanwendungen

• Kompliziert
• Daher nun einige
wichtige Basics

Ascora GmbH, http://www.ascora.de


Aufruf einer Webseite aus Clientsicht

• Browser ruft URL auf  Server erzeugt HTML Code


• Browser erstellt das DOM des HTML Codes
• Browser lädt währenddessen schon mal Verweise im
HTML Code nach:
• Bilder
• CSS
• JavaScript
• Browser interpretiert JavaScript
• Browser stellt HTML Struktur nach CSS
Stylebeschreibungen dar

Ascora GmbH, http://www.ascora.de


Beispiel:

Ascora GmbH, http://www.ascora.de


Webseite im Browser

<html>
HTML = Struktur
<head>
CSS = Aussehen
<title>Eine Seite</title> JavaScript = Verhalten
<link rel='stylesheet' href="css/mein.css"
type="text/css" />
<script src='utils/jquery-1.4.2.min.js'></script>
<script type="text/javascript">
$(document).ready(function() {
alert('Hello User');
});</script>
</head><body>
<p class="red">Hi there!</p>
<img src="images/beispiel.jpg" />
</body>
</html>

Ascora GmbH, http://www.ascora.de


Abhängigkeiten - Browserunterschiede

<html>
<link rel='stylesheet' href="css/mein.css" type="text/css" />
<script src='utils/jquery-1.4.2.min.js'></script>

Ascora GmbH, http://www.ascora.de


Webseite im Browser

<html>
<head>
<title>Eine Seite</title>
<link rel='stylesheet' href="css/mein.css"
type="text/css" />
<script src='utils/jquery-1.4.2.min.js'></script>
<script type="text/javascript">
$(document).ready(function() {
alert('Hello User');
});</script>
</head><body>
<p class="red">Hi there!</p>
<img src="images/beispiel.jpg" />
</body>
</html>

Ascora GmbH, http://www.ascora.de


Aussehen im Browser & CSS code

.red {
font-family:Verdana;
font-size:30px;
color:#FF0000;
}

Ascora GmbH, http://www.ascora.de


Zeitlicher Ablauf des Seitenaufbaus

• Browser: GET http://some.url.de/Seite/seite.html


• Antwort: (der HTML Text von eben)
• Browser versucht so schnell wie möglich HTML darzustellen Z
• Sendet 3 weitere GET-Requests aus:
– http://some.url.de/Seite/css/mein.css e
– http://some.url.de/Seite/utils/jquery-1.4.2.min.js
– http://some.url.de/Seite/images/beispiel.jpg i
• Versucht JavaScript so schnell auszuführen, wie möglich
– Auch bevor die Seite aufgebaut ist t
• JavaScript wird IM BROWSER von einer JavaScript-Engine
interpretiert
– Skript kann auf dem Server erzeugt werden, aber Ausführung im Browser ist
unabhängig davon

Ascora GmbH, http://www.ascora.de


JavaScript != Java

• JavaScript muss daher im Browser debuggt werden


• z. B. mit Firebug

Ascora GmbH, http://www.ascora.de


Und die serverseitige Sicht?

Ascora GmbH, http://www.ascora.de


Architektur von Webanwendungen

• Klassisches ModelViewController:

Ascora GmbH, http://www.ascora.de


Architektur von Webanwendungen

• Klassisches ModelViewController:

URLs

HTML Datenbank

IBM fragt: Wo ist die Serverlogik? Wo ist der User-Client?

Ascora GmbH, http://www.ascora.de


Architektur von Webanwendungen

• ModelViewController 2 (auch WebMVC, nach IBM):

Ascora GmbH, http://www.ascora.de


Struktur von Webanwendungen

• ModelViewController 2 (auch WebMVC, nach IBM):

URL aufgerufen Serverlogik

Browser

Datenbank
und
HTML Serverlogik

Oliver Steele1 fragt: Wo ist die Trennung? Was ist mit JavaScript?

1 vgl. http://osteele.com
Ascora GmbH, http://www.ascora.de
Struktur von Webanwendungen

• ModelViewController 2 (WebMVC nach Oliver Steele1):

• Clientseitig sind Webseiten auch Anwendungen


• Klarere Trennung

1 vgl. http://osteele.com
Ascora GmbH, http://www.ascora.de
Struktur von Webanwendungen

• ModelViewController 2 (nach Tim Dellas2):

2 „Ein RDFa-Editor zur Einbettung semantischer Informationen in ein Weblog-System“ Tim Dellas, 2009

Ascora GmbH, http://www.ascora.de


Struktur von einer struts2-Webanwendung

• ModelViewController 2 (nach Tim Dellas):


Server Browser

result
JSP

statisches result
RAM + DB

action (java) Struts.xml

Ascora GmbH, http://www.ascora.de


Struktur von einer struts2-Webanwendung

• Struts2 - Request Response

Ascora GmbH, http://www.ascora.de


Struktur von einer struts2-Webanwendung

Serverlogik
(Javaklassen!)

Ascora GmbH, http://www.ascora.de


Struktur von einer struts2-Webanwendung

Serverlogik
(Java)

Ascora GmbH, http://www.ascora.de


Request erreicht Tomcat

• Die URL http://www.mytomcat.de/app/loginpage.action wird


aufgerufen

• Tomcat guckt in /app/WebContent/web-inf/web.xml nach

• Da steht drin, dass er alles an eine Struts2-Klasse weitergeben soll


<filter><filter-name>struts2</filter-name>
<filter-class>
org.apache.struts2.dispatcher.FilterDispatcher
</filter-class></filter>

<filter-mapping>
<filter-name>struts</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

• Diese basiert den weiteren Kontrollfluss auf die struts.xmlDatei

Ascora GmbH, http://www.ascora.de


struts.xml, Actionklassen und JSPs
• struts.xml ist der “Controller” im MVC Sinne
• Liegt im root-Verzeichnis des Java “src”-Folders

<?xml version="1.0" encoding="UTF-8" ?>


<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts
Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>

<constant
name="struts.enable.DynamicMethodInvocation"
value="false" />
<constant name="struts.devMode" value=“true" />

Ascora GmbH, http://www.ascora.de


struts.xml, Actionklassen und JSPs

<package name="frontend" extends="struts-default,hibernate-


default">

<action name="loginpage" method="loginp"


class="de.abelssoft.Pages">
<result name="success">/pages/static.jsp</result>
</action>

<action name="login" method="login"


class="de.abelssoft.UserSession">
<result name="input" type="redirectAction">
<param name="actionName">loginpage</param>
</result>
<result name="success"
type="redirect">${ref}</result>
</action>

</package>
</struts>

Ascora GmbH, http://www.ascora.de


Workflow dieser struts.xml

„input“ redirectAction  loginpage


struts.xml de.abelssoft.
UserSession

String login(); „success“ ${ref} (z.B.


login.action /secret.jsp)

de.abelssoft.
loginpage.action Pages „success“
/pages/static.jsp
String loginp();

[HTML]
UserName: Tim
Password: 123456

Submit  login.action

Ascora GmbH, http://www.ascora.de


Struktur von einer struts2-Webanwendung

Serverlogik
(Java)

Ascora GmbH, http://www.ascora.de


Eine vollwertige Action

package de.abelssoft.updateyeti.Frontend.beispiel;
import com.opensymphony.xwork2.ActionSupport;

public class Pages extends ActionSupport {

public String loginp(){


return "success";
}
}

Ascora GmbH, http://www.ascora.de


Actions  Parameter  JSP

public class Pages extends ActionSupport {


public String pageTitle;
public String loginp(){
setPageTitle("Login Seite")
return "success";
}
public String getPageTitle() {
return pageTitle;
}
public void setPageTitle(String pageTitle) {
this.pageTitle = pageTitle;
}
}

Ascora GmbH, http://www.ascora.de


Je Framework-Funktion ein Interface

public class Pages extends ActionSupport implements


ApplicationAware, ServletRequestAware,
Preparable, SessionAware, ServletResponseAware
{
public void setApplication(Map<String, Object> ctx) {}
public void setServletRequest(HttpServletRequest req) {}
public void prepare() throws Exception {}
public void setSession(Map<String, Object> se) {}
public void setServletResponse(HttpServletResponse res) {}

public String loginp(){


return "success";
}

Ascora GmbH, http://www.ascora.de


Application-Scope Map<String,Object>

public class Pages extends ActionSupport implements


ApplicationAware, ServletRequestAware,
Preparable, SessionAware, ServletResponseAware
{
public void setApplication(Map<String, Object> ctx) {}
public void setServletRequest(HttpServletRequest req) {}
public void prepare() throws Exception {}
public void setSession(Map<String, Object> se) {}
public void setServletResponse(HttpServletResponse res) {}

public String loginp(){


return "success";
}

Ascora GmbH, http://www.ascora.de


HTTP-Session ist Map<String,Object>

public class Pages extends ActionSupport implements


ApplicationAware, ServletRequestAware,
Preparable, SessionAware, ServletResponseAware
{
public void setApplication(Map<String, Object> ctx) {}
public void setServletRequest(HttpServletRequest req) {}
public void prepare() throws Exception {}
public void setSession(Map<String, Object> se) {}
public void setServletResponse(HttpServletResponse res) {}

public String loginp(){


return "success";
}

Ascora GmbH, http://www.ascora.de


Prepareable

public class Pages extends ActionSupport implements


ApplicationAware, ServletRequestAware,
Preparable, SessionAware, ServletResponseAware
{
public void setApplication(Map<String, Object> ctx) {}
public void setServletRequest(HttpServletRequest req) {}
public void prepare() throws Exception {}
public void setSession(Map<String, Object> se) {}
public void setServletResponse(HttpServletResponse res) {}

public String loginp(){


return "success";
}

Ascora GmbH, http://www.ascora.de


An Request und Response kommen

public class Pages extends ActionSupport implements


ApplicationAware, ServletRequestAware,
Preparable, SessionAware, ServletResponseAware
{
public void setApplication(Map<String, Object> ctx) {}
public void setServletRequest(HttpServletRequest req) {}
public void prepare() throws Exception {}
public void setSession(Map<String, Object> se) {}
public void setServletResponse(HttpServletResponse res) {}

public String loginp(){


return "success";
}

Ascora GmbH, http://www.ascora.de


Defaults für alle Actions  Superklasse

public class Login extends ActionHelper {


PersonBean p;
DbUser u;
public String login(){
if (usersession.get("user")!=null){
u = getUserDAO().
getUser(p.getEmail(),p.getPassword());
if (u == null)
return "input";
}
return "success";
}

Ascora GmbH, http://www.ascora.de


Defaults für Actions  Superklasse
public abstract class ActionHelper extends ActionSupport
implements ApplicationAware, ServletRequestAware,
Preparable, SessionAware, ServletResponseAware {

private UserDAO userDAO;


protected Map<String, Object> usersession;

@SessionTarget
Session dbsession;
@TransactionTarget
Transaction dbtransaction;

protected UserDAO getUserDAO() {return userDAO;}


public void prepare(){
userDAO = new UserDAO(dbsession, dbtransaction);
}
public void setSession(Map<String, Object> arg0) {
usersession = arg0;
}

Ascora GmbH, http://www.ascora.de


Hibernate DAO
public class FrontendUserDAO {

Session dbsession;
Transaction dbtransaction;

public FrontendUserDAO(Session s, Transaction t) {


dbsession = s; dbtransaction = t; }

public DbUser getUser (String email, String password){


List<DbUser> userList = (List<DbUser>)
session.createCriteria(DbUser.class)
.add(Restrictions.eq("username", email))
.add(Restrictions.eq("password",
EncryptionHelper.getMd5Hash(password)))
.list();
if (userList.size()>0)
return userList.get(0);
return null;
}

Ascora GmbH, http://www.ascora.de


Results  Was nach der Action?

Serverlogik
(Java)

Ascora GmbH, http://www.ascora.de


Results

public class Login extends ActionHelper {


PersonBean p;
DbUser u;
public String login(){
if (usersession.get("user")!=null){
u = getUserDAO().
getUser(p.getEmail(),p.getPassword());
if (u == null)
return "input";
}
return "success";
}

Ascora GmbH, http://www.ascora.de


struts.xml

<action name="loginpage" method="loginp"


class="de.abelssoft.Pages">
<result name="success">/pages/static.jsp</result>
</action>

<action name="login" method="login"


class="de.abelssoft.UserSession">
<result name="input" type="redirectAction">
<param name="actionName">loginpage</param>
</result>
<result name="success"
type="redirect">${ref}</result>
</action>

Ascora GmbH, http://www.ascora.de


Workflow dieser struts.xml

„input“ redirectAction  loginpage


struts.xml de.abelssoft.
UserSession

String login(); „success“ ${ref} (z.B.


login.action /secret.jsp)

de.abelssoft.
loginpage.action Pages „success“
/pages/static.jsp
String loginp();

[HTML]
UserName: Tim
Password: 123456

Submit  login.action

Ascora GmbH, http://www.ascora.de


JSP  HTML

Serverlogik
(Java)

Ascora GmbH, http://www.ascora.de


Login.jsp Form  Daten an Action
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title><s:property value="pageTitle"/></title>
</head>
<body>
<h1>UY Login</h1>

<s:form action=“login.action" method="POST">

<s:textfield name="p.username" label="User Name"/>


<s:password name="p.password" label="Password"/>
<s:submit />

<s:actionerror/>
<s:fielderror/>

</s:form>

</body>
</html>

Ascora GmbH, http://www.ascora.de


Formfields  Action via setter
public class Login extends ActionHelper {
PersonBean p;
DbUser u;
public String login(){
if (usersession.get("user")!=null){
u = getUserDAO().
getUser(p.getEmail(),p.getPassword());
if (u == null)
return "input";
}
return "success";
}

Ascora GmbH, http://www.ascora.de


Templating mit include file.jsp
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
<%@taglib uri="/struts-tags" prefix="s"%>
<html>
<head>
<%@ include file="includes/headinclude.jsp" %>
<title>UpdateYeti - Software Updates für Windows Programme</title>
</head>
<body>
<div class="page" id="home-page">
<%@ include file="includes/header2.jsp" %>
<div id="page-body">
<%@ include file="includes/messages.jsp" %>
<h1>Mit UpdateYeti immer Up-To-Date</h1>
<%@ include file="includes/top-panel-main.jsp" %>
<div class="toolbar">
<div class="title"><span>Programm-Kategorien:</span></div>
</div>
<%@ include file="includes/boxes.jsp" %>
</div>
<%@ include file="includes/footer.jsp" %>
</div>
</body>
</html>

Ascora GmbH, http://www.ascora.de


Struts-Tags: <s:iterator> und <s:if>
<table><tr><td>User name</td>
<td>Email</td>
<td>Real name</td>
<td colspan="2">Actions</td></tr>

<s:iterator value="users">
<tr><td><s:property value="username"/></td>
<td><s:property value="email"/></td>
<td><s:property value="realname"/></td>
<td><a href="doEditAccount.action?editid=<s:property
value="id"/>">Edit</a></td>
<td><s:if test="username!=u.username">
<a href="doDeleteAccount.action?deleteid=<s:property
value="id"/>">Delete</a></s:if></td></tr>
</s:iterator>
</table>

Ascora GmbH, http://www.ascora.de


Plugins

• Hibernate
– Struts2-fullhibernatecore-plugin-[version].jar hinzufügen
– hibernate.cfg.xml Datei im src Verzeichnis hinzufügen
– Die MySql-Connector.jar nicht vergessen!
– Nutzung wie in Code-Beispielen mit @SessionTarget und @TransactionTarget
– org.hibernate.Session benutzen. Muss nicht geöffnet / geschlossen werden

<property name="hibernate.connection.url">
jdbc:mysql://localhost:3306/datenbankname?autoReconnect=true</property>
<property name="hibernate.connection.password">dbuserpassword</property>
<property name="hibernate.connection.username">dbusername</property>
<property name="hibernate.connection.driver_class">
com.mysql.jdbc.Driver</property>
<property name="connection.pool_size">1</property>
<property name="hibernate.dialect"> org.hibernate.dialect.MySQLInnoDBDialect</property>
<property name="current_session_context_class">thread</property>
<property name="hbm2ddl.auto">update</property>
<property name="hibernate.connection.autoReconnectForPools">true</property>
<property name="hibernate.connection.characterEncoding">utf8</property>
<!– Alle mit @Entity bezeichneten DB-Klassen aufführen, z. B.-->
<mapping class="de.abelssoft.project.model.users.DbUser" />

Ascora GmbH, http://www.ascora.de


Plugins

• jQuery
– Struts2-jquery-plugin-[version].jar hinzufügen
– Bringt jsp-Tagbibliothek mit:
<%@taglib uri="/struts-jquery-tags" prefix="sj"%>
– Im <head> tag muss folgender Code stehen (der z. B. jQuery einbindet):
<sj:head jqueryui="true" loadFromGoogle="true" />
– Dann können <sj:…> tags genutzt werden, Beispiele auf
http://www.weinfreund.de/struts2-jquery-showcase/index.action
– Außerdem kann man in der jsp-Seite normalen jQuery code einsetzen:
var $search = $('#autocompleter');
$search.focus(function(){
if ($search.attr('value')=='Suchen...') {
$search.attr('value','');
}
}).blur(function(){
if (!this.value) {
this.value = 'Suchen...';
}
});

Ascora GmbH, http://www.ascora.de


Interceptors?

Serverlogik
(Java)

Ascora GmbH, http://www.ascora.de


Ein Interceptor
public class LoginInterceptor implements Interceptor {

public String intercept(ActionInvocation actionInvocation)


throws Exception {
// before action
Action action = (Action) actionInvocation.getAction();
Map<String, Object> session =
actionInvocation.getInvocationContext().getSession();

DbUser u = (DbUser) session.get("user");


if (u!=null){
// logged in
((DbUserAware) action).setDbUser(u);
}
// no login  call action
String result = actionInvocation.invoke();
// after action
if (result.equals(Config.LOGOUT)){
actionInvocation.getInvocationContext().getValueStack()
.set(Config.KEYS_FRONTEND_USER(), null);
actionInvocation.getInvocationContext().getValueStack()
.set(Config.KEYS_LOGGEDIN(), null);
}
return result;
}

Ascora GmbH, http://www.ascora.de


Wrap-Up: Entwicklungsumgebung

• Eclipse and Tomcat


• http://www.ithoughts.de/setting-up-eclipse-for-web-development-
with-tomcat-on-windows-7-64bit
• Eclipse Dynamic Web Project erstellen
• Als Grundlage
– Struts-Blank-Projekt (o. ä.) downloaden
– Oder Maven-Archetype
• .jar-Dateien nicht selber suchen!
• Tomcat  context.xml
(ermöglicht Code-Änderungen
ohne Neustart)

Ascora GmbH, http://www.ascora.de


META: Webseiten vs. Desktop vs. Mobile

Ascora GmbH, http://www.ascora.de


META: Webseiten vs. Desktop vs. Mobile

• Webangebote

• Haben (immer) viel Konkurrenz


• Komplex zu erstellen
• Müssen sofort verständlich sein
(Konkurrenz ist nur einen Klick entfernt!)
• Müssen gefunden werden
• GoogleRank braucht ein paar Jahre
(oder viele Links zu der neuen Seite + SEO)

Ascora GmbH, http://www.ascora.de


META: Webseiten vs. Desktop vs. Mobile

• Webangebote

• Native App zu bevorzugen …ES SEI DENN…


• Müssen einen Zweck erfüllen
• evtl. auch als (mobile) „Anwendung“
• besser als Konkurrenz sein
• Aufsehen erregen (Verkäufe ankurbeln)
• Oder als „Erweiterung“ einer Desktop /
mobilen Anwendung (deren Verkäufe ankurbeln)

Ascora GmbH, http://www.ascora.de


META: Webseiten vs. Desktop vs. Mobile

• Webangebote

• Haben ein riesiges Potential


• Sind wirklich Plattformunabhängig
• Auch Mobile Geräte
• Weltweiter sofortiger Zugriff möglich

 Qualität, Usability und Features  Erfolg

Ascora GmbH, http://www.ascora.de


Fragen? Anregungen? Ideen?
Bildquellen:
Italics Eiffel Tower (CC SA)
http://www.flickr.com/photos/jesper/
CSS MESS (CC SA)
http://www.flickr.com/photos/atzu/
Weblogos (CC SA)
http://www.flickr.com/photos/stabilo-boss/
Alter Computer (CC NCA)
http://www.flickr.com/photos/r4n/
Steel Framework (CC SA)
http://www.flickr.com/photos/nocallerid_man/
Struts2Request-Response
http://www.roseindia.net/struts/struts2/struts-2-architecture.shtml
MVC-2 nach Oliver Steele Danke für die
http://osteele.com/images/mvc/mvc-mvc.png Aufmerksamkeit!
MVC-2-Struktur nach IBM
http://www-128.ibm.com/developerworks/java/library/j-struts/
Apache Struts2 Logos
http://struts.apache.org/2.x/index.html
Sonstige:
Dipl. Inform. Tim Dellas, dellas@abelssoft.de
Ascora GmbH, http://www.ascora.de