//---------------------------------------------------------------------------------- // URLs have the same form as in Perl // Invoking dynamic content is done through the same standard urls: // http://mox.perl.com/cgi-bin/program?name=Johann&born=1685 // http://mox.perl.com/cgi-bin/program // Groovy has Groovelets and GSP page support built-in. For a full // web framework, see Grails: http://grails.codehaus.org/ //---------------------------------------------------------------------------------- |
//---------------------------------------------------------------------------------- // as a plain groovelet param = request.getParameter('PARAM_NAME') println """ <html><head> <title>Howdy there!</title> </head> <body> <p> You typed: $param </p> </body> </html> """ // as a groovelet using markup builder import groovy.xml.MarkupBuilder writer = new StringWriter() builder = new MarkupBuilder(writer) builder.html { head { title 'Howdy there!' } body { p('You typed: ' + request.getParameter('PARAM_NAME')) } } println writer.toString() // as a GSP page: <html><head> <title>Howdy there!</title> </head> <body> <p> You typed: ${request.getParameter('PARAM_NAME')} </p> </body> </html> // Request parameters are often encoded by the browser before // sending to the server and usually can be printed out as is. // If you need to convert, use commons lang StringEscapeUtils#escapeHtml() // and StringEscapeUtils#unescapeHtml(). // Getting parameters: who = request.getParameter('Name') phone = request.getParameter('Number') picks = request.getParameterValues('Choices') // String array or null // Changing headers: response.setContentType('text/html;charset=UTF-8') response.setContentType('text/plain') response.setContentType('text/plain') response.setHeader('Cache-control', 'no-cache') response.setDateHeader('Expires', System.currentTimeMillis() + 3*24*60*60*1000) //---------------------------------------------------------------------------------- |
//---------------------------------------------------------------------------------- // The Java Servlet API has a special log() method for writing to the // web server log. // To send errors to custom HTML pages, update the web.xml deployment // descriptor to include one or more <error-page> elements, e.g.: <error-page> <error-code>404</error-code> <location>/404.html</location> </error-page> <error-page> <exception-type>java.lang.NullPointerException</exception-type> <location>/NpeError.gsp</location> </error-page> // Another trick is to catch an exception within the servlet/gsp code // and print it out into the HTML as a comment. //---------------------------------------------------------------------------------- |
//---------------------------------------------------------------------------------- // 500 errors could occur if you have compile errors in your script. // Pre-compile with your IDE or groovyc. // You can use an expando, mock or map to run your scripts outside // the web container environment. If you use Jetty as your container // it has a special servlet tester, for more details: // http://blogs.webtide.com/gregw/2006/12/16/1166307599250.html //---------------------------------------------------------------------------------- |
//---------------------------------------------------------------------------------- // Web servers should be invoked with an appropriate Java security policy in place. // This can be used to limit possible actions from hacking attempts. // Normal practices limit hacking exposure. The JDBC API encourages the use // of Prepared queries rather than encouraging practices which lead to SQL // injection. Using system or exec is rarely used either as Java provides // cross-platform mechanisms for most operating system level functionality. // Other security measures should be complemented with SSL and authentication. //---------------------------------------------------------------------------------- |
//----------------------------------------------------------------------------------
// Within the servlet element of your web.xml, there is a <load-on-startup> element.
// Use that on a per servlet basis to pre-load whichever servlets you like.
//----------------------------------------------------------------------------------
|
//---------------------------------------------------------------------------------- // As discussed in 19.3 and 19.4: // Web servers should be invoked with an appropriate Java security policy in place. // This can be used to limit possible actions from hacking attempts. // Normal practices limit hacking exposure. The JDBC API encourages the use // of Prepared queries rather than encouraging practices which lead to SQL // injection. Using system or exec is rarely used either as Java provides // cross-platform mechanisms for most operating system level functionality. // In addition, if authentication is used, security can be locked down at a // very fine-grained level on a per servlet action or per user (with JAAS) basis. //---------------------------------------------------------------------------------- |
//---------------------------------------------------------------------------------- import groovy.xml.* // using a builder: Closure markup = { ol { ['red','blue','green'].each{ li(it) } } } println new StreamingMarkupBuilder().bind(markup).toString() // => <ol><li>red</li><li>blue</li><li>green</li></ol> names = 'Larry Moe Curly'.split(' ') markup = { ul { names.each{ li(type:'disc', it) } } } println new StreamingMarkupBuilder().bind(markup).toString() // <ul><li type="disc">Larry</li><li type="disc">Moe</li> // <li type="disc">Curly</li></ul> //----------------------------- m = { li("alpha") } println new StreamingMarkupBuilder().bind(m).toString() // <li>alpha</li> m = { ['alpha','omega'].each { li(it) } } println new StreamingMarkupBuilder().bind(m).toString() // <li>alpha</li> <li>omega</li> //----------------------------- states = [ "Wisconsin": [ "Superior", "Lake Geneva", "Madison" ], "Colorado": [ "Denver", "Fort Collins", "Boulder" ], "Texas": [ "Plano", "Austin", "Fort Stockton" ], "California": [ "Sebastopol", "Santa Rosa", "Berkeley" ], ] writer = new StringWriter() builder = new MarkupBuilder(writer) builder.table{ caption('Cities I Have Known') tr{ th('State'); th(colspan:3, 'Cities') } states.keySet().sort().each{ state -> tr{ th(state) states[state].sort().each{ td(it) } } } } println writer.toString() // => // <table> // <caption>Cities I Have Known</caption> // <tr> // <th>State</th> // <th colspan='3'>Cities</th> // </tr> // <tr> // <th>California</th> // <td>Berkeley</td> // <td>Santa Rosa</td> // <td>Sebastopol</td> // </tr> // <tr> // <th>Colorado</th> // <td>Boulder</td> // <td>Denver</td> // <td>Fort Collins</td> // </tr> // <tr> // <th>Texas</th> // <td>Austin</td> // <td>Fort Stockton</td> // <td>Plano</td> // </tr> // <tr> // <th>Wisconsin</th> // <td>Lake Geneva</td> // <td>Madison</td> // <td>Superior</td> // </tr> // </table> import groovy.sql.Sql import groovy.xml.MarkupBuilder dbHandle = null dbUrl = 'jdbc:hsqldb:...' def getDb(){ if (dbHandle) return dbHandle def source = new org.hsqldb.jdbc.jdbcDataSource() source.database = dbUrl source.user = 'sa' source.password = '' dbHandle = new Sql(source) return dbHandle } def findByLimit(limit) { db.rows "SELECT name,salary FROM employees where salary > $limit" } limit = request.getParameter('LIMIT') writer = new StringWriter() builder = new MarkupBuilder(writer) builder.html { head { title('Salary Query') } h1('Search') form{ p('Enter minimum salary') input(type:'text', name:'LIMIT') input(type:'submit') } if (limit) { h1('Results') table(border:1){ findByLimit(limit).each{ row -> tr{ td(row.name); td(row.salary) } } } } } println writer.toString() //---------------------------------------------------------------------------------- |
//---------------------------------------------------------------------------------- // The preferred way to redirect to resources within the web application: dispatcher = request.getRequestDispatcher('hello.gsp') dispatcher.forward(request, response) // Old versions of web containers allowed this mechanism to also redirect // to external resources but this was deemed a potential security risk. // The suggested way to external sites (less efficient for internal resources): response.sendRedirect("http://www.perl.com/CPAN/") // set cookie and forward oreo = new Cookie('filling', 'vanilla creme') THREE_MONTHS = 3 * 30 * 24 * 60 * 60 oreo.maxAge = THREE_MONTHS oreo.domain = '.pleac.sourceforge.net' whither = 'http://pleac.sourceforge.net/pleac_ruby/cgiprogramming.html' response.addCookie(oreo) response.sendRedirect(whither) // forward based on user agent dir = 'http://www.science.uva.nl/%7Emes/jargon' agent = request.getHeader('user-agent') menu = [ [/Mac/, 'm/macintrash.html'], [/Win(dows )?NT/, 'e/evilandrude.html'], [/Win|MSIE|WebTV/, 'm/microslothwindows.html'], [/Linux/, 'l/linux.html'], [/HP-UX/, 'h/hpsux.html'], [/SunOS/, 's/scumos.html'], ] page = 'a/aportraitofj.randomhacker.html' menu.each{ if (agent =~ it[0]) page = it[1] } response.sendRedirect("$dir/$page") // no response output response.sendError(204, 'No Response') //---------------------------------------------------------------------------------- |
//----------------------------------------------------------------------------------
// Consider TCPMON or similar: http://ws.apache.org/commons/tcpmon/
//----------------------------------------------------------------------------------
|
//---------------------------------------------------------------------------------- // helper method import javax.servlet.http.Cookie import groovy.xml.MarkupBuilder def getCookieValue(cookies, cookieName, defaultValue) { if (cookies) for (i in 0..<cookies.length) { if (cookieName == cookies[i].name) return cookies[i].value } return defaultValue } prefValue = getCookieValue(request.cookies, 'preference_name', 'default') cookie = new Cookie('preference name',"whatever you'd like") SECONDS_PER_YEAR = 60*60*24*365 cookie.maxAge = SECONDS_PER_YEAR * 2 response.addCookie(cookie) cookname = 'fav_ice_cream' favorite = request.getParameter('flavor') tasty = getCookieValue(request.cookies, cookname, 'mint') writer = new StringWriter() builder = new MarkupBuilder(writer) builder.html { head { title('Ice Cookies') } body { h1('Hello Ice Cream') if (favorite) { p("You chose as your favorite flavor '$favorite'.") cookie = new Cookie(cookname, favorite) ONE_HOUR = 3600 // secs cookie.maxAge = ONE_HOUR response.addCookie(cookie) } else { hr() form { p('Please select a flavor: ') input(type:'text', name:'flavor', value:tasty) } hr() } } } println writer.toString() //---------------------------------------------------------------------------------- |
//---------------------------------------------------------------------------------- import groovy.xml.MarkupBuilder // On Linux systems replace with: "who".execute().text fakedWhoInput = ''' root tty1 Nov 2 17:57 hermie tty3 Nov 2 18:43 hermie tty4 Nov 1 20:01 sigmund tty2 Nov 2 18:08 '''.trim().split(/\n/) name = request.getParameter('WHO') if (!name) name = '' writer = new StringWriter() new MarkupBuilder(writer).html{ head{ title('Query Users') } body{ h1('Search') form{ p('Which User?') input(type:'text', name:'WHO', value:name) input(type:'submit') } if (name) { h1('Results') lines = fakedWhoInput.grep(~/^$name\s.*/) if (lines) message = lines.join('\n') else message = "$name is not logged in" pre(message) } } } println writer.toString() // if you need to escape special symbols, e.g. '<' or '>' use commons lang StringEscapeUtils //---------------------------------------------------------------------------------- |
//---------------------------------------------------------------------------------- // frameworks typically do this for you, but shown here are the manual steps // even when doing it manually, you would probably use session variables // setting a hidden field input(type:'hidden', value:'bacon') // setting a value on the submit input(type:'submit', name:".State", value:'Checkout') // determining 'mode' page = request.getParameter('.State') if (!page) page = 'Default' // forking with if chain if (page == "Default") { frontPage() } else if (page == "Checkout") { checkout() } else { noSuchPage() } // forking with map states = [ Default: this.&frontPage, Shirt: this.&tShirt, Sweater: this.&sweater, Checkout: this.&checkout, Card: this.&creditCard, Order: this.&order, Cancel: this.&frontPage, ] // calling each to allow hidden variable saving states.each{ key, closure -> closure(page == key) } // exemplar method def tShirt(active) { def sizes = ['XL', 'L', 'M', 'S'] def colors = ['Black', 'White'] if (!active) { hidden("size") hidden("color") return } p("You want to buy a t-shirt?"); label("Size: "); dropDown("size", sizes) label("Color: "); dropDown("color", colors) shopMenu() } // kicking off processing html{ head{ title('chemiserie store') } body { if (states[page]) process(page) else noSuchPage() } } //---------------------------------------------------------------------------------- |
//---------------------------------------------------------------------------------- // get request parameters as map map = request.parameterMap // save to file new File(filename).withOutputStream{ fos -> oos = new ObjectOutputStream(fos) oos.writeObject(map) oos.close() } // convert to text sb = new StringBuffer() map.each{ k,v -> sb << "$k=$v" } text = sb.toString() // to send text via email, see 18.3 //---------------------------------------------------------------------------------- |
//---------------------------------------------------------------------------------- // you wouldn't normally do it this way, consider a framework like Grails // even when doing it by hand, you would probably use session variables import groovy.xml.MarkupBuilder page = param('.State', 'Default') states = [ Default: this.&frontPage, Shirt: this.&shirt, Sweater: this.&sweater, Checkout: this.&checkout, Card: this.&creditCard, Order: this.&order, Cancel: this.&frontPage, ] writer = new StringWriter() b = new MarkupBuilder(writer) b.html{ head{ title('chemiserie store') } body { if (states[page]) process(page) else noSuchPage() } } println writer.toString() def process(page) { b.form{ states.each{ key, closure -> closure(page == key) } } } def noSuchPage() { b.p('Unknown request') reset('Click here to start over') } def shopMenu() { b.p() toPage("Shirt") toPage("Sweater") toPage("Checkout") reset('Empty My Shopping Cart') } def frontPage(active) { if (!active) return b.h1('Hi!') b.p('Welcome to our Shirt Shop! Please make your selection from the menu below.') shopMenu() } def shirt(active) { def sizes = ['XL', 'L', 'M', 'S'] def colors = ['Black', 'White'] def count = param('shirt_count',0) def color = param('shirt_color') def size = param('shirt_size') // sanity check if (count) { if (!(color in colors)) color = colors[0] if (!(size in sizes)) size = sizes[0] } if (!active) { if (size) hidden("shirt_size", size) if (color) hidden("shirt_color", color) if (count) hidden("shirt_count", count) return } b.h1 'T-Shirt' b.p '''What a shirt! This baby is decked out with all the options. It comes with full luxury interior, cotton trim, and a collar to make your eyes water! Unit price: $33.00''' b.h2 'Options' label("How Many?"); textfield("shirt_count") label("Size?"); dropDown("shirt_size", sizes) label("Color?"); dropDown("shirt_color", colors) shopMenu() } def sweater(active) { def sizes = ['XL', 'L', 'M'] def colors = ['Chartreuse', 'Puce', 'Lavender'] def count = param('sweater_count',0) def color = param('sweater_color') def size = param('sweater_size') // sanity check if (count) { if (!(color in colors)) color = colors[0] if (!(size in sizes)) size = sizes[0] } if (!active) { if (size) hidden("sweater_size", size) if (color) hidden("sweater_color", color) if (count) hidden("sweater_count", count) return } b.h1("Sweater") b.p("Nothing implies preppy elegance more than this fine " + "sweater. Made by peasant workers from black market silk, " + "it slides onto your lean form and cries out ``Take me, " + "for I am a god!''. Unit price: \$49.99.") b.h2("Options") label("How Many?"); textfield("sweater_count") label("Size?"); dropDown("sweater_size", sizes) label("Color?"); dropDown("sweater_color", colors) shopMenu() } def checkout(active) { if (!active) return b.h1("Order Confirmation") b.p("You ordered the following:") orderText() b.p("Is this right? Select 'Card' to pay for the items" + "or 'Shirt' or 'Sweater' to continue shopping.") toPage("Card") toPage("Shirt") toPage("Sweater") } def creditCard(active) { def widgets = 'Name Address1 Address2 City Zip State Phone Card Expiry'.split(' ') if (!active) { widgets.each{ hidden(it) } return } b.pre{ label("Name: "); textfield("Name") label("Address: "); textfield("Address1") label(" "); textfield("Address2") label("City: "); textfield("City") label("Zip: "); textfield("Zip") label("State: "); textfield("State") label("Phone: "); textfield("Phone") label("Credit Card #: "); textfield("Card") label("Expiry: "); textfield("Expiry") } b.p("Click on 'Order' to order the items. Click on 'Cancel' to return shopping.") toPage("Order") toPage("Cancel") } def order(active) { if (!active) return b.h1("Ordered!") b.p("You have ordered the following items:") orderText() reset('Begin Again') } def orderText() { def shirts = param('shirt_count') def sweaters = param('sweater_count') if (shirts) { b.p("""You have ordered ${param('shirt_count')} shirts of size ${param('shirt_size')} and color ${param("shirt_color")}.""") } if (sweaters) { b.p("""You have ordered ${param('sweater_count')} sweaters of size ${param('sweater_size')} and color ${param('sweater_color')}.""") } if (!sweaters && !shirts) b.p("Nothing!") b.p("For a total cost of ${calcPrice()}") } def label(text) { b.span(text) } def reset(text) { b.a(href:request.requestURI,text) } def toPage(name) { b.input(type:'submit', name:'.State', value:name) } def dropDown(name, values) { b.select(name:name){ values.each{ if (param(name)==it) option(value:it, selected:true, it) else option(value:it, it) } } b.br() } def hidden(name) { if (binding.variables.containsKey(name)) v = binding[name] else v = '' hidden(name, v) } def hidden(name, value) { b.input(type:'hidden', name:name, value:value) } def textfield(name) { b.input(type:'text', name:name, value:param(name,'')); b.br() } def param(name) { request.getParameter(name) } def param(name, defValue) { def val = request.getParameter(name) if (val) return val else return defValue } def calcPrice() { def shirts = param('shirt_count', 0).toInteger() def sweaters = param('sweater_count', 0).toInteger() return (shirts * 33 + sweaters * 49.99).toString() } //---------------------------------------------------------------------------------- |