IntelliJ IDEA Ultimate Notes

Russell Bateman
May 2018


Web-programming tutorial links

Apache/Maven WAR plug-in

What do you do to cause Maven to build a WAR file? Add this to pom.xml:

<build>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-war-plugin</artifactId>
      <version>3.2.0</version>
      <configuration>
        <webResources>
          <resource>
            <!-- this is relative to the pom.xml directory -->
            <directory>web</directory>
          </resource>
        </webResources>
      </configuration>
    </plugin>
  </plugins>
</build>

The <directory> specified above assumes the following structure in your project:

~/dev/hello-restlet $ tree
.
├── hello-restlet.iml
├── pom.xml
├── src
│   └── ...
└── web
    └── WEB-INF
        └── web.xml

IntelliJ IDEA Tomcat tutorial

I downloaded IntelliJ IDEA Ultimate (here at work too) and then did Install and Configure Tomcat IntelliJ IDEA which is a year old, has no sound and is full of misleading mousing. Here I am reducing that experience to a set of steps. It did work, however, and that puts me hugely up over the experience I had with Eclipse WTP back in 2008 when I really started in earnest trying to learn to do web programming with Eclipse.

  1. Close (all) IDEA projects to see Welcome to IntelliJ IDEA splash page.
  2. Choose Create New Project.
  3. Choose Maven (don't select any archetype).
  4. Click Next.
  5. GroupId: com.etretatlogiciels.tomcat
  6. ArtifactId: tomcat-demo
  7. Click Next.
  8. Click Finish.
  9. (IntelliJ IDEA launches with pom.xml in Editor pane.
  10. Launch a browser to download Tomcat 9:
    1. Download from Binary Distributions the first tarball.
    2. Explode this tarball.
    3. Copy it somewhere; I copied to ~/dev
  11. Choose Edit Configurations.
  12. Click the green + and look for Tomcat Server. You may have to click on "36 items more (irrelevant)."
  13. Choose Local (Tomcat Server); you'll see a dialog for Unnamed Tomcat Server. Configure the Application Server for the Tomcat 9 downloaded by navigating to and selecting its root subdirectory (something like ~/dev/apache-tomcat-9.0.7).
  14. Change Unnamed to something; I chose to use tomcat-demo.
  15. Click Deployment, then the green + sign, then External Source..., then choose the project root subdirectory and click OK. See this in the Deploy at the server startup list of the dialog. Click Apply.
  16. Click OK to dismiss the Run/Debug Configurations dialog.
  17. Expand the project root in the Project pane.

  18. Right-click the project root and choose New → HTML File. Name it index and click OK. (This puts index.html into the project root which is not where you want it, but the right place is the object of a different tutorial.)
  19. Edit index.html and add this text to the <body>:
    Hello viewer Please Subscribe
    Thanks For Waching...
    
  20. Click the green in the Run pane at the bottom right. You'll see a new window come up in your browser at localhost:8080:

  21. Add various proper HTML elements around the text, then click the green to restart Tomcat and see the changes:

This is working, so I'm going to have to spring the $150 for this IDE now.


Hello-world restlet in IntelliJ IDEA and Maven with Jersey and Tomcat

These are practical and up-to-date instructions based on Sam Jesso's 2014 Starting out with Jersey & Apache Tomcat using IntelliJ. Here are the steps, illustrations and elaborations I followed:

  1. Ensure IntelliJ IDEA Ultimate Edition (we're using latest version as of May 2018) for this tutorial. It is in theory possible to debug a web application using the Community Edition, but it's extremely unlikely to be able to develop one without Ultimate.

  2. Prepare exploded Tomcat, Jersey and JAX-RS downloads in your filesystem. Though you may put them on other paths, for the purposes of this tutorial, I'm assuming:
    1. ~/dev/apache-tomcat-9.0.7 (Tomcat, from the first tarball under Binary Distributions here.) Since you're doing this on your development host, there's little reason to install it. You're going to give IDEA the path to where you exploded Tomcat.

    2. (The Jersey dependency is satisfied by the JAX-RS download below and by a Maven pom.xml dependency later.)

    3. ~/dev/jaxrs-ri (JAX-RS—from jaxrs-ri-2.25.1.zip downloaded from the Jersey JAX-RS 2.1 RI bundle here.

  3. Installing Maven: If you're a serious developer, you should have Maven installed on your development host. This way, you can (or should be able to) build any project without IDEA's help. However, IDEA contains Maven and here we'll just use that one.

  4. Close other IDEA projects and do Create New Project:

  5. The new project must be configured a number of ways. Depending on whether you've already used IntelliJ IDEA before, some may already be set up.
    1. Project SDK: —you should have your own copy of a JDK separate from the JRE in use by your host's operating system. Whatever the case, you may need to read Selecting the JDK version the IDE will run under.

    2. Java EE version: —you should try to use the latest version available. Mine's one version later than that used by the original tutorial.

    3. Application Server —we're using Tomcat here. If you've already used Tomcat, this will be set. If not, click New and choose it. This won't be an option if you haven't set IDEA up with the Tomcat plug-in, however, by default this should already be established.

    4. Click to select Java Enterprise and check RESTful Web Service. The original tutorial step is impossible to satisfy here: there is no option to postpone setting up the library. So, do this:
      1. Click Create....

      2. Navigate to where you dropped the JAX-RS download into your filesystem. Find javax.ws.rs-api-2.1.jar in the api subdirectory under that location. This is the library that's going to give the Jersey/ReST annotations for the Java restlet you'll write.

      3. Click OK, then Next.

    5. Configure the project's name and where it will live in your development host's filesystem. Mine is ~/dev/hello-rest.

    6. Click Finish; the IntelliJ IDEA IDE workbench will launch.

  6. At this point, we must add framework support to the project.
    1. Right-click your project's root. It's in bold at the top of the content region of the Project pane in the workbench.

    2. Choose Add Framework Support....

    3. First, scroll down in the left pane that appears in the new dialog to find Maven. Click Maven and then OK. The dialog will disappear to leave you with pom.xml up in the Editor pane.

    4. Right-click the project root again and choose Add Framework Support....

    5. Click Web Application, it should be near the top. Don't click anything underneath it (hierarchically).

    6. Click OK. You're back in the IDE workbench.

  7. Because we have Maven, so that we can build this project not only in the IDE, but also from the command line, we need to tell Maven to bring in Jersey. Change or add the highlighted lines below to pom.xml. (Don't scrape these changes from here or you'll include invisible, illegal characters that will cause mysterious errors in pom.xml.*)
    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
                                 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    
      <modelVersion>4.0.0</modelVersion>
    
      <groupId>com.example.jersey</groupId>
      <artifactId>hello-rest</artifactId>
      <version>1.0-SNAPSHOT</version>
    
      <dependencies>
        <dependency>
          <groupId>com.sun.jersey</groupId>
          <artifactId>jersey-bundle</artifactId>
          <version>1.19.1</version>
        </dependency>
      </dependencies>
    
    </project>
    
    Reimport Maven changes by clicking Import Changes if it appears in the bottom right of your IDE.

  8. Add Java ReST code to the project.
    1. First, create a new package path (which corresponds to the groupId you added to pom.xml. Expand out the directory hierarchy under src, then right-click java and choose New → Package:

    2. In the space provided for a new package name, type: com.example.jersey and click OK.

    3. Next, right-click the new package you just created and choose New → Java Class. Name the class HelloWorld and press Enter or click OK.

    4. Make the class look like this (again, don't scrape this or you'll get bad characters*):
      package com.example.jersey;
      
      import javax.ws.rs.GET;
      import javax.ws.rs.Path;
      import javax.ws.rs.Produces;
      import javax.ws.rs.core.MediaType;
      
      @Path( "/hello" )
      public class HelloWorld
      {
        @GET
        @Produces( MediaType.TEXT_PLAIN )
        public String getMessage()
        {
          return "Hello world!";
        }
      }
      
  9. Next, we set up Tomcat. This step is fairly crucial because if not done just right, you'll get HTTP status code 404 Not Found errors.

    Do File → Settings... → Build, Execution, Deployment → Application Servers. Click the green +, select Tomcat Server, then, in the Tomcat Server dialog, navigate to, select and click OK on the root of the Apache Tomcat you downloaded. In my case, this is the path ~/dev/apache-tomcat-9.0.7.

    You should see two important JARs under Libraries when you've done this:

    Close the Settings dialog by clicking the OK button.

  10. Now, create a Run/Debug Configuration for Tomcat by doing Run → Edit Configurations.... Click the green +, select Tomcat Server → Local and fill out the Server tab as shown below. (Note that the browser command line is more complete than that of the original tutorial which means it will work first time.)

    It is imperative that you pay close attention to the URL under Open browser below: unlike how Eclipse deploys and works, IDEA must have the URL to this degree of specificity in order to work. You will see a new tab appear in your browser with this URL and little else. If you do not have a complete URL, depending on the options of your servlet, you likely will get HTTP 404 and nothing will work.

    Then, click the Deployment tab, the green + and choose Artifact.... You should get hello-rest:war exploded in the list of what to Deploy at the server startup with an application context of   /.
    Click OK. (See note at end of this section on Run Configuration.)

  11. Now we tackle the servlet configuration via web.xml. The web-application support in IDEA has already created this file for you on the path hello-restlet/web/WEB-INF. Double-click to open it. Copy and paste the same thing that's in the original tutorial; make it look like this; the highlighted lines are the ones added beyond what IDEA already included:
    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                                 http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
             version="4.0">
    
      <servlet>
        <servlet-name>Example API</servlet-name>
        <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
    
        <init-param>
          <param-name>com.sun.jersey.config.property.packages</param-name>
          <param-value>com.example.jersey</param-value>
        </init-param>
    
        <init-param>
          <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
          <param-value>true</param-value>
        </init-param>
      </servlet>
    
      <servlet-mapping>
        <servlet-name>Example API</servlet-name>
        <url-pattern>/*</url-pattern>
      </servlet-mapping>
    
    </web-app>
    
    There's a lot going on in this file that I'm not going to explain. I will, however, explain that
    • <servlet-name> in both <servlet> and <servlet-mapping> must be identical in order to link the two, i.e.: make the servlet mapping configuration belong to the defined servlet.
    • The package (or comma-delimited packages—because we might have more Java code on multiple package paths) com.sun.jersey.config.property.packages is a variable read by Jersey such that it will look through the Java classes on this path (these paths) to include in the running servlet. If you refactor your Jersey code (HelloWorld.java) away from com.example.jersey, no one will show up at the party Tomcat throws when you launch it and nothing will happen.

  12. As the original tutorial points out, the last thing to do is to tell Tomcat about your configuration file. This is an obscure, but very crucial step. Go to File → Project Structure, then click on Artifacts. You should see this:

    If you click on the ? next to Available Elements, you'll get a helping prompt that says, "Double-click on element to put into default location" and some other comments. This is what you want to do: double-click JAX-RS and the two JARs listed. This action works a little differently in IntelliJ IDEA Ultimate 2018 than it did under the version targeted by the original tutorial. Click OK to dismiss the Project Structure dialog.

  13. That's it. You need only launch the restlet now. There are several ways to do this. One is Run → Run 'Tomcat 9.0.7'. You'll see a new Run pane come up at the bottom of the IDE workbench, fill with logging statements from Tomcat and then, after a brief delay, your default browser will gain a new tab that looks something like this:

    It's the plain-text response from your restlet code in HellWorld.java which is answering the URL supplied by your browser's HTTP GET command http://localhost:8080/hello.

* Optionally, you can scrape these, paste them into a simple editor like vim, gvim or gedit, then copy them from there into your new class.

Whither next?

Next up should be a tutorial on how to endow the restlet above with an index.jsp (that's meaningful and not the template one that appeared above as the result of adding frameworks) that does something.

Note on Run Configuration

If developing on two hosts, or if collaborating with others, you will not be maintaining .idea/workspace.xml under version control (for all sorts of reasons). Therefore, the step on creating a run/debug configuration will have to be done in every IDEA instance you run. .idea/workspace.xml is where this is kept because, in this case, it's a file-system dependent operation (i.e.: where your copy of Tomcat lives).


JSP example using IntelliJ IDEA and Tomcat

This is an interpretation of Part 1.1: Java EE Webapplication with servlet and JSP page.

  1. Java project in IntelliJ IDEA that runs on a Tomcat server and serves up web/index.jsp. This is all it takes.

    web/index.jsp:
    <%--
      Created by IntelliJ IDEA.
      User: russ
      Date: 5/4/18
      Time: 10:25 AM
      To change this template use File | Settings | File Templates.
    
      Note: because this file is fetched implicitly because
      under the web subdirectory, even without being named
      in a welcome-file-list element.
    --%>
    <%@ page contentType="text/html;charset=UTF-8" %>
    <html>
    <head>
    <title>Web App Tutorial Page</title>
    </head>
    <body>
    <h1> Hello World </h1>
    <p>
    Body text. This is my first webapp JSP page.
    </p>
    </body>
    </html>
    
    web/WEB-INF/web.xml:
    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                        http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
             version="4.0">
    
      (empty)
    
    </web-app>
    
    Output:

  2. Demonstration modifying index.jsp.
    web/index.jsp:
    <%@ page import="java.util.Date" %>
    <%--
      Created by IntelliJ IDEA.
      User: russ
      Date: 5/4/18
      Time: 10:25 AM
      To change this template use File | Settings | File Templates.
    
      Note: because this file is fetched implicitly because
      under the web subdirectory, even without being named
      in a welcome-file-list element.
    --%>
    <%@ page contentType="text/html;charset=UTF-8" %>
    <html>
    <head>
    <title>Web App Tutorial Page</title>
    </head>
    <body>
    <h1> Hello World </h1>
    <p>
    Body text. This is my first webapp JSP page.
    </p>
    <%
      Date date = new Date();
      out.print( "<h3>" + date.toString() + "</h3>" );
    %>
    
    </body>
    </html>
    
    Output:

  3. Create a form on a JSP page.
    web/login.jsp:
    <%--
      Created by IntelliJ IDEA.
      User: russ
      Date: 5/4/18
      Time: 10:25 AM
      To change this template use File | Settings | File Templates.
    
      Note: because this file is fetched implicitly because under the web subdirectory,
      even without being named in a welcome-file-list element.
    --%>
    <%@ page contentType="text/html;charset=UTF-8" %>
    <html>
    <head>
    <title>Login Page</title>
    </head>
    <body>
    <h1> Welcome, please log in: </h1>
    <form action="/login" method="POST">
            Name:     <input type="text"     name="username" width="30" /><br />
            Password: <input type="password" name="password" width="10" /><br />
                      <input type="submit"   value="login" />
    </form>
    </body>
    </html>
    
    Output:

    This goes nowhere since we have to create a servlet to recieve the form's log-in data.

  4. Create a servlet:
    1. Create the servlet:
      1. Right-click src folder and create a new package, webapp.
      2. Right-click the new package and choose New... → Servlet.
      3. name it Login.
      4. Package webapp.
      5. Class webapp.login.
      6. Allow to create annotated class.
      Login.java:
      package webapp;
      
      import javax.servlet.ServletException;
      import javax.servlet.annotation.WebServlet;
      import javax.servlet.http.HttpServlet;
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;
      import java.io.IOException;
      
      @WebServlet( name = "Login" )
      public class Login extends HttpServlet
      {
        protected void doPost( HttpServletRequest request, HttpServletResponse response )
            throws ServletException, IOException
        {
        }
      
        protected void doGet( HttpServletRequest request, HttpServletResponse response )
            throws ServletException, IOException
        {
        }
      }
      
    2. Configure URL via web/WEB-INF/web.xml.
      web/WEB-INF/web.xml:
      <?xml version="1.0" encoding="UTF-8"?>
      <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                          http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
               version="4.0">
      
        
          Login
          webapp.Login
        
      
        
          Login
          /login
        
      
      </web-app>
      
      Input, do the form and press Enter (servlet method doPost() is called, you'll get a blank page:

      Or, use this input and press Enter (servlet method doGet() is called. Again, you'll see a blank page...

      The output is the same from either way because the servlet isn't doing anything with the data yet.

    3. Receive request parameters from URL GET.
      src/webapp/Login.java:
        protected void doGet( HttpServletRequest request, HttpServletResponse response )
            throws ServletException, IOException
        {
          String      username = request.getParameter( "username" );
          String      password = request.getParameter( "password" );
          PrintWriter out = response.getWriter();
          out.println( "Username: " + username );
          out.println( "Password: " + password );
        }
      
      Output corrected using coded servlet method (GET) above:

    4. Receive request parameters via POSTd form.
      src/webapp/Login.java:
        protected void doPost( HttpServletRequest request, HttpServletResponse response )
            throws ServletException, IOException
        {
          String      username = request.getParameter( "username" );
          String      password = request.getParameter( "password" );
          PrintWriter out = response.getWriter();
          out.println( "From POST'd form:" );
          out.println( "Username: " + username );
          out.println( "Password: " + password );
        }
      
      Output using coded servlet method (POST) above (after filling out form and pressing return/clicking Log in—I changed the text in the button to better English):

    5. Send values (reinject) to front end (JSP page). Right-click on web folder and choose New... → JSP/JSPX. Name it welcome. First, however, I want to correct the project structure to make it canonical by fleshing out the src subdirectory the way it should be and adding a test subdirectory under it. I don't have tests right now in this tutorial, but in a real world scenario, I would. (I rebuilt and ran the servlet—it still works.)

      web/welcome.jsp:
      <%--
        Created by IntelliJ IDEA.
        User: russ
        Date: 5/7/18
        Time: 3:09 PM
        To change this template use File | Settings | File Templates.
      --%>
      <%@ page contentType="text/html;charset=UTF-8" language="java" %>
      <html>
      <head>
        <title> Welcome </title>
      </head>
      <body>
      <h1> Welcome </h1>
      <p>
        Dear: ${username}, your password is ${password}.
      	<!-- (${} is called "expression language") -->
      </p>
      </body>
      </html>
      
      Next, because I'm using expression language, I need to forward the values of username and password to welcome.jsp in order to be able to use them, see highlighted lines. Meanwhile, let's also do some clean-up of the code in this class:
      src/main/java/webapp/Login.java:
      package webapp;
      
      import javax.servlet.ServletException;
      import javax.servlet.annotation.WebServlet;
      import javax.servlet.http.HttpServlet;
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;
      import java.io.IOException;
      import java.io.PrintWriter;
      
      @WebServlet( name = "Login" )
      public class Login extends HttpServlet
      {
        private static final String QPARM_USERNAME = "username";
        private static final String QPARM_PASSWORD = "password";
        private static final String JSP_USERNAME   = "username";
        private static final String JSP_PASSWORD   = "password";
      
        protected void doPost( HttpServletRequest request, HttpServletResponse response )
            throws ServletException, IOException
        {
          request.setAttribute( JSP_USERNAME, request.getParameter( QPARM_USERNAME ) );
          request.setAttribute( JSP_PASSWORD, request.getParameter( QPARM_PASSWORD ) );
          request.getRequestDispatcher( "/welcome.jsp" ).forward( request, response );
        }
      
        protected void doGet( HttpServletRequest request, HttpServletResponse response )
            throws IOException
        {
          String      username = request.getParameter( QPARM_USERNAME );
          String      password = request.getParameter( QPARM_PASSWORD );
          PrintWriter out      = response.getWriter();
          out.println( "Username: " + username );
          out.println( "Password: " + password  );
        }
      }
      
      Output after filling out form:

  5. Validate log-in form and send result. To do this, we'll need to add a POJO (User) and revamp Login and login.jsp:
    src/main/pojo/User.java:
    package pojo;
    
    public class User
    {
      private String username;
      private String password;
    
      public User( final String username, final String password )
      {
        this.username = username;
        this.password = password;
      }
    
      public boolean isValidUsername() { return username.equals( "russ" ); }
      public boolean isValidPassword() { return password.equals( "snagglepuss" ); }
    }
    
    src/main/webapp/Login.java:
      private static final String QPARM_USERNAME   = "username";
      private static final String QPARM_PASSWORD   = "password";
      private static final String JSP_USERNAME     = "username";
      private static final String JSP_PASSWORD     = "password";
      private static final String INVALID_USERNAME = "username is unknown";
      private static final String INVALID_PASSWORD = "password was wrong";
    
      protected void doPost( HttpServletRequest request, HttpServletResponse response )
          throws ServletException, IOException
      {
        String username = request.getParameter( QPARM_USERNAME );
        String password = request.getParameter( QPARM_PASSWORD );
        User   user     = new User( username, password );
        String errors   = "";
    
        if( !user.isValidUsername() )
          errors += "   " + INVALID_USERNAME + " (" + username + ")<br />";
        else if( !user.isValidPassword() )
          errors += "   " + INVALID_PASSWORD + " (" + password + ")<br />";
    
        if( errors.length() < 1 )
        {
          request.setAttribute( JSP_USERNAME, request.getParameter( QPARM_USERNAME ) );
          request.setAttribute( JSP_PASSWORD, request.getParameter( QPARM_PASSWORD ) );
          request.getRequestDispatcher( "/welcome.jsp" ).forward( request, response );
        }
        else
        {
          request.setAttribute( "error_message", "Invalid login:<br />" + errors + "Please try again." );
          request.getRequestDispatcher( "/login.jsp" ).forward( request, response );
        }
      }
    
    web/login.jsp:
    <%--
      Created by IntelliJ IDEA.
      User: russ
      Date: 5/4/18
      Time: 10:25 AM
      To change this template use File | Settings | File Templates.
    
      Note: because this file is fetched implicitly because under the web subdirectory,
      even without being named in a welcome-file-list element.
    --%>
    <%@ page contentType="text/html;charset=UTF-8" %>
    <html>
    <head>
    <title>Login Page</title>
    </head>
    <body>
    <h1> Welcome, please log in: </h1>
    <form action="/login" method="POST">
            Name:     <input type="text"     name="username" width="30" /><br />
            Password: <input type="password" name="password" width="10" /><br />
                      <input type="submit"   value="Log in" />
    </form>
    
    <p>
      <span style="color: red"> ${error_message} </span>
    </p>
    </body>
    </html>
    

IntelliJ IDEA changing project type

What if you've got a project that you did not originally create with adequate resources and framework support?

If you erase the .idea subdirectory, then create a new project in IDEA giving it the name of the project you wish to change, you can accomplish the same thing without creating a whole new project only to copy all your code and other resources into it.* For example:

  1. Ensure that you do not have IDEA running on the project you wish to change.
  2. Remove the .idea subdirectory from the project you wish to change.
  3. Click File → Close Project and then click Create New Project
  4. Click Java Enterprise.
  5. Click Web Application in Additional Libraries and Frameworks.
  6. Click RESTful Web Service in Additional Libraries and Frameworks.
  7. Click Next.
  8. Click Next.
  9. Make Project name: the same as your existing project; ensure that Project location: follows suit and that the other settings in More Settings are good.
  10. Click Finish.

* which is certainly a simpler if more tedious option.