| <html><head> |
| <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> |
| <title xmlns:d="http://docbook.org/ns/docbook">Chapter 4. Converting to Web Application</title><link rel="stylesheet" type="text/css" href="css/cayenne-doc.css"><meta xmlns:d="http://docbook.org/ns/docbook" name="keywords" content="Cayenne 4.0 documentation"><meta xmlns:d="http://docbook.org/ns/docbook" name="description" content="User documentation for Apache Cayenne version 4.0"><link rel="home" href="index.html" title="Getting Started with Cayenne"><link rel="up" href="index.html" title="Getting Started with Cayenne"><link rel="prev" href="getting-started-part3.html" title="Chapter 3. Learning Cayenne API"><script xmlns:d="http://docbook.org/ns/docbook" type="text/javascript"> |
| var _gaq = _gaq || []; |
| _gaq.push(['_setAccount', 'UA-7036673-1']); |
| _gaq.push(['_trackPageview']); |
| (function() { |
| var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; |
| ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; |
| var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); |
| })(); |
| </script></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div xmlns:d="http://docbook.org/ns/docbook" class="navheader"><table width="100%" summary="Navigation header"><tr><th class="versioninfo">v.4.0 (4.0.M5)</th><th align="center">Chapter 4. Converting to Web Application</th><th></th></tr><tr><td width="20%" align="left"><a accesskey="p" href="getting-started-part3.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> </td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h1 class="title"><a name="getting-started-part4"></a>Chapter 4. Converting to Web Application</h1></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl class="toc"><dt><span class="section"><a href="getting-started-part4.html#d0e659">Converting to Web Application</a></span></dt></dl></div><div class="section"><div class="titlepage"><div><div><h2 class="title"><a name="d0e659"></a>Converting to Web Application</h2></div></div></div><p>This chapter shows how to work with Cayenne in a web application.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="converting-to-webapp"></a>Converting Tutorial to a Web Application</h3></div></div></div><p>The web part of the web application tutorial is done in JSP, which is the least common |
| denominator of the Java web technologies, and is intentionally simplistic from the UI |
| perspective, to concentrate on Cayenne integration aspect, rather than the interface. A |
| typical Cayenne web application works like this:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Cayenne configuiration is loaded when an application context is started, using |
| a special servlet filter.</p></li><li class="listitem"><p>User requests are intercepted by the filter, and the DataContext is bound to |
| the request thread, so the application can access it easily from |
| anywhere.</p></li><li class="listitem"><p>The same DataContext instance is reused within a single user session; |
| different sessions use different DataContexts (and therefore different sets of |
| objects). <span class="italic">The context can be scoped differently |
| depending on the app specifics. For the tutorial we'll be using a |
| session-scoped context.</span></p></li></ul></div><p>So let's convert the tutorial that we created to a web application:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>In IDEA under "tutorial" project folder create a new folder |
| "<code class="code">src/main/webapp/WEB-INF</code>".</p></li><li class="listitem"><p>Under "<code class="code">WEB-INF</code>" create a new file "<code class="code">web.xml</code>" (a standard web app descriptor): </p><p> |
| <span class="bold"><strong>web.xml</strong></span> |
| </p><pre class="programlisting"><span xmlns="http://www.w3.org/1999/xhtml" class="hl-directive"><?xml version="1.0" encoding="utf-8"?></span> |
| <strong xmlns="http://www.w3.org/1999/xhtml" class="hl-tag"><!DOCTYPE web-app |
| PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" |
| "http://java.sun.com/dtd/web-app_2_3.dtd"></strong> |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-tag"><web-app></span> |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-tag"><display-name></span>Cayenne Tutorial<span xmlns="http://www.w3.org/1999/xhtml" class="hl-tag"></display-name></span> |
| |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-comment"><!-- This filter bootstraps ServerRuntime and then provides each request thread |
| with a session-bound DataContext. Note that the name of the filter is important, |
| as it points it to the right named configuration file. |
| --></span> |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-tag"><filter></span> |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-tag"><filter-name></span>cayenne-project<span xmlns="http://www.w3.org/1999/xhtml" class="hl-tag"></filter-name></span> |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-tag"><filter-class></span>org.apache.cayenne.configuration.web.CayenneFilter<span xmlns="http://www.w3.org/1999/xhtml" class="hl-tag"></filter-class></span> |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-tag"></filter></span> |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-tag"><filter-mapping></span> |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-tag"><filter-name></span>cayenne-project<span xmlns="http://www.w3.org/1999/xhtml" class="hl-tag"></filter-name></span> |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-tag"><url-pattern></span>/*<span xmlns="http://www.w3.org/1999/xhtml" class="hl-tag"></url-pattern></span> |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-tag"></filter-mapping></span> |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-tag"><welcome-file-list></span> |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-tag"><welcome-file></span>index.jsp<span xmlns="http://www.w3.org/1999/xhtml" class="hl-tag"></welcome-file></span> |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-tag"></welcome-file-list></span> |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-tag"></web-app></span></pre></li><li class="listitem"><p>Create the artist browser page <code class="code">src/main/webapp/index.jsp</code> file with the |
| following contents: </p><p><span class="bold"><strong>webapp/index.jsp</strong></span> |
| </p><pre class="programlisting"><%@ page language="java" contentType="text/html" %> |
| <%@ page import="org.example.cayenne.persistent.*" %> |
| <%@ page import="org.apache.cayenne.*" %> |
| <%@ page import="org.apache.cayenne.query.*" %> |
| <%@ page import="org.apache.cayenne.exp.*" %> |
| <%@ page import="java.util.*" %> |
| |
| <% |
| ObjectContext context = BaseContext.getThreadObjectContext(); |
| List<Artist> artists = ObjectSelect.query(Artist.class) |
| .orderBy(Artist.NAME.asc()) |
| .select(context); |
| %> |
| |
| <html> |
| <head> |
| <title>Main</title> |
| </head> |
| <body> |
| <h2>Artists:</h2> |
| |
| <% if(artists.isEmpty()) {%> |
| <p>No artists found</p> |
| <% } else { |
| for(Artist a : artists) { |
| %> |
| <p><a href="detail.jsp?id=<%=Cayenne.intPKForObject(a)%>"> <%=a.getName()%> </a></p> |
| <% |
| } |
| } %> |
| <hr> |
| <p><a href="detail.jsp">Create new artist...</a></p> |
| </body> |
| </html> </pre></li><li class="listitem"><p>Create the artist editor page <code class="code">src/main/webapp/detail.jsp</code> with the following |
| content: </p><p><span class="bold"><strong>webapp/detail.jsp</strong></span> |
| </p><pre class="programlisting"><%@ page language="java" contentType="text/html" %> |
| <%@ page import="org.example.cayenne.persistent.*" %> |
| <%@ page import="org.apache.cayenne.*" %> |
| <%@ page import="org.apache.cayenne.query.*" %> |
| <%@ page import="java.util.*" %> |
| <%@ page import="java.text.*" %> |
| |
| <% |
| ObjectContext context = BaseContext.getThreadObjectContext(); |
| String id = request.getParameter("id"); |
| |
| // find artist for id |
| Artist artist = null; |
| if(id != null && id.trim().length() > 0) { |
| artist = SelectById.query(Artist.class, Integer.parseInt(id)).selectOne(context); |
| } |
| |
| if("POST".equals(request.getMethod())) { |
| // if no id is saved in the hidden field, we are dealing with |
| // create new artist request |
| if(artist == null) { |
| artist = context.newObject(Artist.class); |
| } |
| |
| // note that in a real application we would so dome validation ... |
| // here we just hope the input is correct |
| artist.setName(request.getParameter("name")); |
| artist.setDateOfBirthString(request.getParameter("dateOfBirth")); |
| |
| context.commitChanges(); |
| |
| response.sendRedirect("index.jsp"); |
| } |
| |
| if(artist == null) { |
| // create transient artist for the form response rendering |
| artist = new Artist(); |
| } |
| |
| String name = artist.getName() == null ? "" : artist.getName(); |
| String dob = artist.getDateOfBirth() == null |
| ? "" : new SimpleDateFormat("yyyyMMdd").format(artist.getDateOfBirth()); |
| %> |
| <html> |
| <head> |
| <title>Artist Details</title> |
| </head> |
| <body> |
| <h2>Artists Details</h2> |
| <form name="EditArtist" action="detail.jsp" method="POST"> |
| <input type="hidden" name="id" value="<%= id != null ? id : "" %>" /> |
| <table border="0"> |
| <tr> |
| <td>Name:</td> |
| <td><input type="text" name="name" value="<%= name %>"/></td> |
| </tr> |
| <tr> |
| <td>Date of Birth (yyyyMMdd):</td> |
| <td><input type="text" name="dateOfBirth" value="<%= dob %>"/></td> |
| </tr> |
| <tr> |
| <td></td> |
| <td align="right"><input type="submit" value="Save" /></td> |
| </tr> |
| </table> |
| </form> |
| </body> |
| </html></pre></li></ul></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="running-webapp"></a>Running Web Application</h3></div></div></div><p>We need to provide javax servlet-api for our application.</p><pre class="programlisting"><span xmlns="http://www.w3.org/1999/xhtml" class="hl-tag"><dependency></span> |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-tag"><groupId></span>javax.servlet<span xmlns="http://www.w3.org/1999/xhtml" class="hl-tag"></groupId></span> |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-tag"><artifactId></span>javax.servlet-api<span xmlns="http://www.w3.org/1999/xhtml" class="hl-tag"></artifactId></span> |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-tag"><version></span>3.1.0<span xmlns="http://www.w3.org/1999/xhtml" class="hl-tag"></version></span> |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-tag"><scope></span>provided<span xmlns="http://www.w3.org/1999/xhtml" class="hl-tag"></scope></span> |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-tag"></dependency></span></pre><p>Also to run the web application we'll use "maven-jetty-plugin". To activate it, |
| let's add the following piece of code to the "<code class="code">pom.xml</code>" file, following the "dependencies" |
| section and save the POM:</p><pre class="programlisting"><span xmlns="http://www.w3.org/1999/xhtml" class="hl-tag"><build></span> |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-tag"><plugins></span> |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-tag"><plugin></span> |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-tag"><groupId></span>org.eclipse.jetty<span xmlns="http://www.w3.org/1999/xhtml" class="hl-tag"></groupId></span> |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-tag"><artifactId></span>maven-jetty-plugin<span xmlns="http://www.w3.org/1999/xhtml" class="hl-tag"></artifactId></span> |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-tag"><version></span>9.3.14.v20161028<span xmlns="http://www.w3.org/1999/xhtml" class="hl-tag"></version></span> |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-tag"></plugin></span> |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-tag"></plugins></span> |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-tag"></build></span></pre><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Go to "Select Run/Debug Configuration" menu, and then "Edit Configuration..."</p><p><span class="inlinemediaobject"><img src="images/idea-edit-configurations.png"></span> |
| </p></li><li class="listitem"><p>Click "+" button and select "Maven". Enter "Name" and "Command line" as shown on screenshot:</p><p><span class="inlinemediaobject"><img src="images/idea-run-configuration.png"></span></p></li></ul></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Click "Apply" and "Run". On the first execution it may take a few minutes for |
| Jetty plugin to download all dependencies, but eventually you'll see the logs |
| like this:</p><pre class="screen">[INFO] ------------------------------------------------------------------------ |
| [INFO] Building tutorial 0.0.1-SNAPSHOT |
| [INFO] ------------------------------------------------------------------------ |
| ... |
| [INFO] Configuring Jetty for project: tutorial |
| [INFO] webAppSourceDirectory not set. Trying src/main/webapp |
| [INFO] Reload Mechanic: automatic |
| [INFO] Classes = /.../tutorial/target/classes |
| [INFO] Logging initialized @1617ms |
| [INFO] Context path = / |
| [INFO] Tmp directory = /.../tutorial/target/tmp |
| [INFO] Web defaults = org/eclipse/jetty/webapp/webdefault.xml |
| [INFO] Web overrides = none |
| [INFO] web.xml file = file:/.../tutorial/src/main/webapp/WEB-INF/web.xml |
| [INFO] Webapp directory = /.../tutorial/src/main/webapp |
| [INFO] jetty-9.3.0.v20150612 |
| [INFO] Started o.e.j.m.p.JettyWebAppContext@6872f9c8{/,file:/.../tutorial/src/main/webapp/,AVAILABLE}{file:/.../tutorial/src/main/webapp/} |
| [INFO] Started ServerConnector@723875bc{HTTP/1.1,[http/1.1]}{0.0.0.0:8080} |
| [INFO] Started @2367ms |
| [INFO] Started Jetty Server</pre></li></ul></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>So the Jetty container just started.</p></li><li class="listitem"><p>Now go to <a class="link" href="http://localhost:8080/" target="_top">http://localhost:8080/</a> |
| URL. You should see "No artists found message" in the web browser and |
| the following output in the IDEA console:</p><pre class="screen">INFO: Loading XML configuration resource from file:/.../tutorial/target/classes/cayenne-project.xml |
| INFO: loading user name and password. |
| INFO: Connecting to 'jdbc:derby:memory:testdb;create=true' as 'null' |
| INFO: +++ Connecting: SUCCESS. |
| INFO: setting DataNode 'datanode' as default, used by all unlinked DataMaps |
| INFO: Detected and installed adapter: org.apache.cayenne.dba.derby.DerbyAdapter |
| INFO: --- transaction started. |
| INFO: No schema detected, will create mapped tables |
| INFO: CREATE TABLE GALLERY (ID INTEGER NOT NULL, NAME VARCHAR (200), PRIMARY KEY (ID)) |
| INFO: CREATE TABLE ARTIST (DATE_OF_BIRTH DATE, ID INTEGER NOT NULL, NAME VARCHAR (200), PRIMARY KEY (ID)) |
| INFO: CREATE TABLE PAINTING (ARTIST_ID INTEGER, GALLERY_ID INTEGER, ID INTEGER NOT NULL, |
| NAME VARCHAR (200), PRIMARY KEY (ID)) |
| INFO: ALTER TABLE PAINTING ADD FOREIGN KEY (ARTIST_ID) REFERENCES ARTIST (ID) |
| INFO: ALTER TABLE PAINTING ADD FOREIGN KEY (GALLERY_ID) REFERENCES GALLERY (ID) |
| INFO: CREATE TABLE AUTO_PK_SUPPORT ( |
| TABLE_NAME CHAR(100) NOT NULL, NEXT_ID BIGINT NOT NULL, PRIMARY KEY(TABLE_NAME)) |
| ... |
| INFO: SELECT t0.DATE_OF_BIRTH, t0.NAME, t0.ID FROM ARTIST t0 ORDER BY t0.NAME |
| INFO: === returned 0 rows. - took 17 ms. |
| INFO: +++ transaction committed.</pre></li></ul></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>You can click on "Create new artist" link to create artists. Existing artists |
| can be edited by clicking on their name:</p><p><span class="inlinemediaobject"><img src="images/chrome-webapp.png"></span></p></li></ul></div><p>You are done with the tutorial!</p></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="getting-started-part3.html">Prev</a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> </td></tr><tr><td width="40%" align="left" valign="top">Chapter 3. Learning Cayenne API </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> </td></tr></table></div></body></html> |