Compojure/Getting Started

Build from Source

edit

To download and build Compojure, you will need Git (git), Leiningen (lein), and a Java runtime environment (java).

download latest release from git (ex https://github.com/weavejester/compojure.git)
cd compojure
lein deps
lein jar

This will generate the compojure.jar file. Put this in your Java classpath.

The deps lein target will download the needed dependencies. If this fails, you can manually download them from:

http://cloud.github.com/downloads/weavejester/compojure/deps.zip

Unzip the file in the compojure directory and rerun lein.

Hello World with Embedded Jetty

edit

Create a shell script called "compojure" to run Clojure with compojure.jar and the deps directory in the classpath:

#!/bin/sh
CLASSPATH=compojure.jar
 
for f in deps/*.jar; do
    CLASSPATH=$CLASSPATH:$f
done
 
java -cp $CLASSPATH clojure.lang.Script $1

or, for Windows:

@echo off
SETLOCAL enabledelayedexpansion

FOR %%F IN (deps/*.jar) DO (
  SET cp=!cp!;deps/%%F%
)

java -cp "compojure.jar;%cp%" clojure.lang.Repl %1%

Then create a Clojure source file called "hello.clj":

(ns hello-world
  (:use compojure))

(defroutes greeter
  (GET "/"
    (html [:h1 "Hello World"])))

(run-server {:port 8080}
  "/*" (servlet greeter))

Next, run this file using the compojure shell script:

./compojure hello.clj

Your web application should now be accessible at: http://localhost:8080/

Hello World in a War file

edit

First, create your servlet file:

;; src/myapp/MyServlet.clj
(ns myapp.MyServlet
  (:use compojure)
  (:gen-class
    :extends javax.servlet.http.HttpServlet))

(defroutes greeter
  (GET "/"
    (html [:h1 "Hello world"])))

(defservice greeter)

Next, create your WEB-INF directory:

mkdir -p WEB-INF/lib WEB-INF/classes

Copy compojure.jar, clojure-contrib.jar and clojure.jar to WEB-INF/lib.

You now need to create WEB-INF/web.xml:

<web-app>
 <servlet>
   <servlet-name>myservlet</servlet-name>
   <servlet-class>myapp.MyServlet</servlet-class>
 </servlet>
 <servlet-mapping>
   <servlet-name>myservlet</servlet-name>
   <url-pattern>/*</url-pattern>
 </servlet-mapping>
</web-app>

Finally, compile the War file. Here is an ant build script that does just that:

 <project name="myapp" basedir="." default="war">
   <property name="build.dir" value="WEB-INF/classes" />
   <property name="source.dir" value="src" />
   <property name="lib.dir" value="WEB-INF/lib" />
   <property name="servlet-api.jar" value="/usr/share/java/servlet-2.3.jar" />
   <property name="warfile" value="myapp.war" />

   <target name="compile">
     <java classname="clojure.lang.Compile">
       <classpath>
         <path location="${build.dir}"/>
         <path location="${source.dir}"/>
         <fileset dir="${lib.dir}">
           <include name="*.jar"/>
         </fileset>
         <path location="${servlet-api.jar}"/>
       </classpath>
       <sysproperty key="clojure.compile.path" value="${build.dir}"/>
       <arg value="myapp.MyServlet"/>
     </java>
   </target>

   <target name="war" depends="compile">
     <war warfile="${warfile}" webxml="WEB-INF/web.xml">
       <classes dir="${build.dir}"/>
     </war>
   </target>
 </project>

A bit more verbose example

edit

Here is an example of a simple calculator.

(ns example 
  (:use compojure)) 

(defn html-doc 
  [title & body] 
  (html 
    (doctype :html4) 
    [:html 
      [:head 
        [:title title]] 
      [:body 
       [:div 
	[:h2 
	 ;; Pass a map as the first argument to be set as attributes of the element
	 [:a {:href "/"} "Home"]]]
        body]])) 


(def sum-form 
  (html-doc "Sum" 
    (form-to [:post "/"] 
      (text-field {:size 3} :x) 
      "+" 
      (text-field {:size 3} :y) 
      (submit-button "=")))) 

(defn result 
  [x y] 
  (let [x (Integer/parseInt x) 
        y (Integer/parseInt y)] 
    (html-doc "Result" 
      x " + " y " = " (+ x y)))) 

(defroutes webservice
  (GET "/" 
    sum-form) 
  (POST "/" 
    (result (params :x) (params :y)))) 

(run-server {:port 8080} 
  "/*" (servlet webservice))