How to setup a basic SpringBoot application

I spent some time trying to figure out how SpringBoot worked recently. I thought I would document the steps I took to get a project up and running.

Here is the final repository in Github.

Setup Steps

  1. First, create a workspace.

    mkdir -p ~/projects

    cd ~/projects

    mvn archetype:generate -DgroupId=com.tonyzampogna -DartifactId=base-springboot-app -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false

    cd ~/projects/base-springboot-app

  2. In the pom.xml, add the Spring Boot dependencies. First, add the parent block. I put it above the dependencies block.

      <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.4.0.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
      </parent>
    

  3. Then, in the dependencies block, add the following dependencies.

      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
      </dependency>
    
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
      </dependency>
    

  4. Add the plugin for building SpringBoot with maven. This goes either above or below the dependencies block. This solves an error stating: "no main manifest attribute".

      <build>
        <plugins>
          <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <executions>
              <execution>
                <goals>
                  <goal>repackage</goal>
                </goals>
              </execution>
            </executions>
          </plugin>
        </plugins>
      </build>
    

  5. Move the App.java file in src/main/java/com/tonyzampogna to a new package called "main".

    mkdir -p src/main/java/com/tonyzampogna/main

    mv src/main/java/com/tonyzampogna/App.java src/main/java/com/tonyzampogna/main

  6. Replace the contents of the App.java file with the text below.

      package com.tonyzampogna.main;
    
      import org.slf4j.Logger;
      import org.slf4j.LoggerFactory;
      import org.springframework.boot.SpringApplication;
      import org.springframework.boot.autoconfigure.SpringBootApplication;
      import org.springframework.context.annotation.ComponentScan;
    
      /**
       * Main application file.
       */
      @SpringBootApplication
      @ComponentScan("com.tonyzampogna")
      public class App {
        private static final Logger logger = LoggerFactory.getLogger(App.class);
    
        /////////////////////////////////////////////////
        // Application Start Methods
        /////////////////////////////////////////////////
    
        /**
         * This method runs on applications start.
         */
        public static void main(String[] args) {
          logger.info("Starting application");
          SpringApplication.run(App.class, args);
        }
      }
    

  7. Make a controller so that we can test our server. First, create the package directory.

    mkdir -p src/main/java/com/tonyzampogna/controller

  8. Then, add HomeController.java code to the controller package.

      package com.tonyzampogna.controller;
    
      import org.springframework.web.bind.annotation.RequestMapping;
      import org.springframework.web.bind.annotation.RestController;
    
      @RestController
      public class HomeController {
    
        @RequestMapping("/home")
        public String getHome() {
          return "Hello";
        }
      }
    

  9. Create a resources directory for a log4j properties file.

    mkdir -p src/main/resources

  10. Add the log4.properties file below to src/main/resources.

      #################################################################
      ## Log Levels
      #################################################################
    
      log4j.rootLogger=INFO, STDOUT
      log4j.logger.com.tonyzampogna=DEBUG, STDOUT, FILE
    
    
      #################################################################
      ## Appenders
      #################################################################
    
      # Console
      log4j.appender.STDOUT=org.apache.log4j.ConsoleAppender
      log4j.appender.STDOUT.layout=org.apache.log4j.PatternLayout
      log4j.appender.STDOUT.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
    
      # File
      log4j.appender.FILE=org.apache.log4j.RollingFileAppender
      log4j.appender.FILE.File=application.log
      log4j.appender.FILE.MaxFileSize=10MB
      log4j.appender.FILE.MaxBackupIndex=10
      log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
      log4j.appender.FILE.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
    

To run the project (from either Eclipse, Intellij, or the command line):

From the command line

  1. In the project directory, package the jar file and then run it.

    mvn package

    java -jar target/base-springboot-app-1.0-SNAPSHOT.jar

From Eclipse

  1. First, run the maven eclipse target to setup some essential eclipse files.

    mvn eclipse:eclipse

  2. Open Eclipse. Make sure you get the SpringSource Tool Suite from the Eclipse Marketplace. Then, import the project into the workspace as an existing eclipse project.

  3. Now, you can right-click on the project and choose either "Run as SpringBoot application" or "Debug as SpringBoot application".

From Intellij

  1. Open Intellij and choose File -> New Project.

  2. Select Java project and choose Next.

  3. For project name, type in base-springboot-app. For project location, type in ~/projects/base-springboot-app.

  4. In the Run menu, choose Edit Configurations. Click the plus sign and select JAR Application. Fill in the information below.

    • Name: Server
    • Path to JAR: ~/projects/base-springboot-app/target/base-springboot-app-1.0-SNAPSHOT.jar
    • VM Arguments: -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=1044
    • Working directory: ~/projects/base-springboot-app
  5. Select ok.

  6. Now, from the Run menu, you can choose either

iOS Safari Enhancement

I have run into an odd issue with iOS Safari on the iPad recently. In the current application I am working on, we have a list of items that can be dragged and dropped on the page. This works great with the mouse. However, I run into issues when I start throwing the touchstart, touchmove, and touchend events in.

The Problem

When a user starts to move their finger around on the iPad, normally this will cause the iPad to "pan" the window around (assuming there is area to scroll). Let's say the page is long, though, so the window can scroll down.

Apple does not trigger any javascript events for this pan (see the document here). The window just scrolls around. However, if the user happens to touch on an item that is capturing events, one of two things can happen:

1. The touchmove event returns false (or calls preventDefault), in which case the window will not scroll up or down ever when a user swipes on one of those items.

2. The touchemove returns true, in which case the window may scroll up or down with, but if you are "dragging" the item, that will scroll as well.

I have created a jsFiddle here to show you what I mean. List 1 prevents the default behavior, whereas List 2 returns true and allows dragging and scrolling.

Neither of these is preferable.

The Solution

The issue is that I think iOS needs to provide a way of canceling the default pan behavior that a user initiates. I have opened up a bug report with Apple, so I will keep this article posted to in case of any update. Let's hope they do.

I'm not sure why there really isn't any way to control (from the browser) at least a way to cancel this event.

From a psuedo-code perspective, what I would like to do, is allow the user to scroll (pan) around the screen as long as the touch-and-hold event is less than say 500ms. In that case, I will return true (but I won't move the dragged item). After 500ms, though, if the user is still moving around, I would cancel the scroll (pan) event, and then move the dragged item around.

Anyway, for now, we are making a small grab region on the item. However, I think it would be nice to fix this in the future.

XSS Sanitizer Plugin (v0.2) released

Well, after shamefully waiting over a year to do any kind of updates to this plugin, I've finally made some changes and merged in pull requests from others.

Next steps are going to be fix some of the issues. Some great suggestions have come up in the Issues area on Github. In fact, I plan on releasing a patch later today.

I chose version 0.2 after some long debate with myself (Hello, me). I don't really want to call this a 1.0 release quite yet. I think some things like not being able to override the ESAPI.properties file as well as not enough unit tests make this still a beta plugin. I'd love to know if others are using it, too. If so, and people are having success, then maybe a 1.0 release is in order. Until then, there's still some work left to do.

Apple iPhone 5s Thumbprint Scanner

Not to gripe about an obvious issue, but I'm as equally unimpressed with the thumbprint scanner on the new Apple iPhone 5s as I am impressed.

I'm impressed when it works. I think "Wow! That is cool."

However, the scanner seems to only work about 50% of the time for me.

I've added my thumbprint numerous times in the settings. And at first, it works great. After some time, though, it starts to degrade.

I think there's two problems, though. First, I live in a cold climate and my hands get very dry in the winter time. If I look at my finger tips, the skin is dry and flakey. I think this starts to confuse the scanner (not surprisingly).

Second, I think if any kind of oily residue starts to build up on the scanner, it will stop working. I still need to test this, but right now, my fingers are too dry to do so.

Anyway, cool idea. Very useful. It would be nice if it were more reliable, though. Maybe Apple needs more beta testers in the Minnesota, though. 🙂

How to fix Parallels Desktop from hanging on startup

Recently, Parallels Desktop did not shut down correctly for me. When I went to start it back up, it just sat there with a spinning wheel, and a message saying "suspending."

I did finally resolve the issue. Here's how I did it.

1) Quit Parallels.

2) Open up the Activity Monitor. On a Mac, this is Utilities > Activity Monitor.

3) In the list of processes, look for one named "prl_vm_app". Select it.

4) Click the Quit Process button in the upper left. Choose to Force Quit at the prompt.

You should be able to start up Parallels Desktop again.

Removing a Stripped Stainless Steel Screw

Well, if you made the mistake of putting decking down with stainless steel screws like I did, you may have run into this issue before. Either you didn't drill a decent pilot hole, or it was getting to be too hot, and you were in a rush, it doesn't matter. The bottom line is that you now have a completely stripped stainless steel screw head staring you right in the face.

After giving up with the hacksaw (because I realized that would just leave a dead screw in the wood, I decided to use an old flathead screwdriver bit. I held the bit on the head of the screw and pounded it into the screw a few times with a hammer.

After the bit was into the screw, I slowly turned it out.

Stainless steel screw head

Sandbox

I finally built a sandbox for the kids (just in time for winter, right?). I've been meaning to all summer, and planned to do it as soon as our landscaping was done in the back yard.

It took longer than I thought to finish up the landscaping, and after that, there were a few other more pressing projects. But, the bottom line is that it's done.

I got the plans from the Home Depot website. It cost about $85 for the materials, which I realize is complete overkill for a sandbox. However, I wanted to have at least one thing in the back yard that wasn't a plastic monstrosity, even if they only use it a few times.

Actually, I'm sure it will be worth it. The kids love to play in the sand. Anyway, here are some pictures of the process.

Prepping the base

Building walls

Adding pavers for edging

Fixed bench

Closed

Open

XSS Sanitizer Grails Plugin

Well, earlier this week I published my first Grails plugin. I'm hoping that people will find it useful to add a general security plugin to parse out, and prevent XSS attacks on their website. It's a long way from being done, but I think it's a good start.

It uses OWASP's ESAPI to strip out any unwanted script, iframe, and img tags that come in on the request. It also has the added benefit of doing this in a Java filter (in case you access the request via the HttpRequest) and the Grails "params" attribute.

Next steps are to write tests for each of the potential hacks on http://ha.ckers.org/xss.html to make sure they all pass. Plus, in my opinion, this is just a general replace of all values. There are potentially times when you might want to submit something that falls into one of these categories, and you feel that it's safe to not have to filter it. So, I'd like to allow users to be able to annotate methods to allow/disallow the filter to run give a certain action.

Here's a link to the source code:

https://github.com/tonyzampogna/XssSanitizer

If you would like to install it, just type:

grails install-plugin xss-sanitizer

If you are interested in contributing, please let me know. I'd love to have some collaboration.

Click event slow in Chrome and Safari

Well, I came across an interesting quirk. Click events in Chrome and Safari were taking a couple of seconds before they were being fired. It was quite the head scratcher.

Here's essentially what I was doing:

<script>
        $(".example").delegate("a", "click", function(event) {
            $("h2").toggle();
        });
</script>

<div class="example">
    <a href="#">
        Toggle Title
    </a>
    <h2>TITLE</h2>
</div>​

At first, I just changed the <a> tag to be a <span> tag, and that worked. But, I couldn't figure out why an anchor tag was having this problem. I had been doing similar things in other parts of the application, and it was working fine.

When I made the simple script above in jsFiddle, I couldn't reproduce it. So, I started pulling out things slowly.

That's when I noticed it was something that Omniture was doing. I'm not sure I could tell why that particular element was being slow. My guess was maybe that it was nested too deep, and something Omniture was doing was making it slow.

Either way, the fix of changing it to a <span> tag seemed to fix it.