Spring MVC using STS within Eclipse

spring-sts-header-img2
Spring MVC is widely used for java web apps. We usually use Eclipse IDE to develop them. Spring Tool Suite (STS) that is an IDE based on Eclipse and comes with its plugin. There are a lot of examples online, but they often different because they keep changing its user interface. Here is the memo

eclipse-sts-step1
File -> New -> Other… -> Spring -> Spring Legacy Project
eclipse-sts-step1
Old tutorials are usually just “Spring Project”, but now has the word “Lagacy” in it..
eclipse-sts-step2
For the first time, you will be asked..
eclipse-sts-step3
Need to entering the project path, then “Finish”.
Selection_003
Maven project hierarchy automatically created including POM.xml.

└── src
    └── main
        └── java
            └── com.ns.spring.Contoller class

Spring MVC Config

mvc-template1
This is my imagination of MVC model visualized:

    Model (Bean Object)
    View (JSP = magnifying glass)
    Controller (I personally don’t play a video game because it’s wasting time)

The term of “Spring MVC” is almost symbolized as J2EE Web Apps on Spring Framework. Today’s one of most popular J2EE framework. Compared to Struts, Spring is much easier for screen transition because it is not strongly tied with XML file such as struts-config.xml in Struts. Spring is a framework that try to decouple its between Model, View, and Controller.

There are three major XML files you will deal with:

spring-mvc-config-xmls1

web.xml

  • Context as root-context.xml (line 4)
  • Servlet as servlet-context.xml (line 18)
  • URL pattern (line 25)

servlet-context.xml

This is the file you have to deal with most often that defines all following info.

  • Defines Spring bean for Dependency Injection (DI) and Aspect Oriented (AOP)
  • DB config (Hibernate)

NOTE: There is other file root-context.xml. This can be empty for Spring MVC because it is used for non-web beans.


pom.xml

  • XML file for Apache Maven that defines all JAR files for this entire project

<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
<context-param>
	<param-name>contextConfigLocation</param-name>
	<param-value>/WEB-INF/spring/root-context.xml</param-value>
</context-param>

<!-- Creates the Spring Container shared by all Servlets and Filters -->
<listener>
	<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<!-- Processes application requests -->
<servlet>
	<servlet-name>appServlet</servlet-name>
	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
	<init-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
	</init-param>
	<load-on-startup>1</load-on-startup>
</servlet>
	
<servlet-mapping>
	<servlet-name>appServlet</servlet-name>
	<url-pattern>/</url-pattern>
</servlet-mapping>
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans 
    xmlns="http://www.springframework.org/schema/mvc"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:beans="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context" 
    xmlns:aop="http://www.springframework.org/schema/aop" 
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="
        http://www.springframework.org/schema/mvc         http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/beans     http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop         http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
        http://www.springframework.org/schema/context     http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/security     http://www.springframework.org/schema/security/spring-security-3.2.xsd
        http://www.springframework.org/schema/tx         http://www.springframework.org/schema/tx/spring-tx-4.0.xsd"
        >

    <!-- Enables the Spring MVC @Controller -->
    <annotation-driven />

    <context:component-scan base-package="com.ns.spring" />

    <!-- AOP -->
    <aop:aspectj-autoproxy>
        <aop:include name="aopBefore" />
        <aop:include name="aopAfter" />
        <aop:include name="aopAround" />
    </aop:aspectj-autoproxy>

    <!-- "id": Unique ID used by programs to identify the class. Unlike "name"  -->
    <!--       it cannot be more than one reference from the same Java object   -->
    <!-- "prototype": New instance each time when called                        -->
    <!-- "singleton": Single instance per Spring IoC container                  -->
    <beans:bean id="aopBefore"  class="com.ns.spring.aop.advise.AspectBefore" scope="prototype"/>
    <beans:bean id="aopAfter"   class="com.ns.spring.aop.advise.AspectAfter"  scope="prototype"/>
    <beans:bean id="aopAround"  class="com.ns.spring.aop.advise.AspectAround" scope="prototype"/>
    
    <!-- Configure Aspect Beans, without this Aspects advices wont execute -->
    <beans:bean name="aopAnnotationAspect" class="com.ns.spring.aop.AopAnnotationAspect" />
    <beans:bean name="aopByXmlConfig"  class="com.ns.spring.aop.advise.AopByXmlConfig" />
    <!-- Configure Beans for AOP -->
    <beans:bean name="rmaController"  class="com.ns.spring.RmaController" />
        
    <beans:bean name="aopTest" class="com.ns.spring.aop.test.AopTest">
        <beans:property name="name" value="Test123"></beans:property>
    </beans:bean>

    <!-- Configure EmployeeService bean -->
    <!-- "ref": Referencing a different bean (could be in a different XML file)    -->
    <beans:bean name="aopTestService" class="com.ns.spring.aop.test.AopTestService" scope="prototype">
        <beans:property name="aopTest" ref="aopTest"></beans:property>
    </beans:bean>

    <!-- AOP Config by XML-->
    <aop:config>
        <aop:aspect ref="aopByXmlConfig" id="aspectXMLConfigID" order="1">
            <aop:pointcut expression="execution(* com.ns.spring.aop.test.AopTest.getName())" id="getNamePointcut"/>
            <aop:around method="aopAroundAdvice" pointcut-ref="getNamePointcut" arg-names="proceedingJoinPoint"/>
        </aop:aspect>
    </aop:config>

    <tx:annotation-driven transaction-manager="transactionManager"/>

    <beans:bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <beans:property name="sessionFactory" ref="hibernate4AnnotatedSessionFactory" />
    </beans:bean>

    <!-- Handles HTTP GET requests for /resources/** by efficiently serving 
        up static resources in the ${webappRoot}/resources directory -->
    <resources mapping="/resources/**" location="/resources/" />

    <!-- Resolves views selected for rendering by @Controllers to .jsp resources 
        in the /WEB-INF/views directory -->
    <beans:bean
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <beans:property name="prefix" value="/WEB-INF/views/" />
        <beans:property name="suffix" value=".jsp" />
    </beans:bean>

    <beans:bean id="dataSource" 
        class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <beans:property name="driverClassName" value="com.mysql.jdbc.Driver" />
        <beans:property name="url"      value="jdbc:mysql://localhost:3306/ns201501" />
        <beans:property name="username" value="root" />
        <beans:property name="password" value="nobu" />
    </beans:bean>

    <!-- Hibernate 4 SessionFactory Bean definition -->
    <beans:bean id="hibernate4AnnotatedSessionFactory"
        class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <beans:property name="dataSource" ref="dataSource" />
        <beans:property name="annotatedClasses">
            <beans:list>
                <beans:value>com.ns.spring.model.RMA_HDR</beans:value>
                <beans:value>com.ns.spring.model.RMA_LINE</beans:value>
                <beans:value>com.ns.spring.model.RTRN_TP</beans:value>
                <beans:value>com.ns.spring.model.RTRN_RSN</beans:value>
                <beans:value>com.ns.spring.model.RTRN_TP_RSN</beans:value>
                <beans:value>com.ns.spring.model.RTRN_TP_RSN_CMBN</beans:value>
                <beans:value>com.ns.spring.model.RMA_HDR_STS</beans:value>
                <beans:value>com.ns.spring.model.MDSE</beans:value>
                <beans:value>com.ns.spring.model.RmaLinePk</beans:value>
                <beans:value>com.ns.spring.model.RtrnTpRsnPk</beans:value>                                
                <beans:value>com.ns.spring.model.ui.RmaHdrModel</beans:value>
                <beans:value>com.ns.spring.model.ui.RmaHdrStsModel</beans:value>
                <beans:value>com.ns.spring.model.ui.RmaLineModel</beans:value>
                <beans:value>com.ns.spring.model.ui.RtrnRsnModel</beans:value>
                <beans:value>com.ns.spring.model.ui.RtrnTpModel</beans:value>
            </beans:list>
        </beans:property>
        <beans:property name="hibernateProperties">
            <beans:props>
                <beans:prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</beans:prop>
                <beans:prop key="hibernate.show_sql">true</beans:prop>
            </beans:props>
        </beans:property>
    </beans:bean>
</beans:beans>    
<?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/maven-v4_0_0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <groupId>com.ns.spring</groupId>
   <artifactId>NS2015V07</artifactId>
   <name>NS2015V07</name>
   <packaging>war</packaging>
   <version>1.0.0-BUILD-SNAPSHOT</version>
   <properties>
      <java-version>1.7</java-version>
      <org.springframework-version>4.0.3.RELEASE</org.springframework-version>
      <org.aspectj-version>1.7.4</org.aspectj-version>
      <org.slf4j-version>1.7.5</org.slf4j-version>
      <hibernate.version>4.3.5.Final</hibernate.version>
      <jackson.databind-version>2.2.3</jackson.databind-version>
   </properties>
   <dependencies>
      <!-- Spring -->
      <dependency>
         <groupId>org.springframework</groupId>
         <artifactId>spring-context</artifactId>
         <version>${org.springframework-version}</version>
         <exclusions>
            <!-- Exclude Commons Logging in favor of SLF4j -->
            <exclusion>
               <groupId>commons-logging</groupId>
               <artifactId>commons-logging</artifactId>
            </exclusion>
         </exclusions>
      </dependency>
      <dependency>
         <groupId>org.springframework</groupId>
         <artifactId>spring-webmvc</artifactId>
         <version>${org.springframework-version}</version>
      </dependency>
      <dependency>
         <groupId>org.springframework</groupId>
         <artifactId>spring-tx</artifactId>
         <version>${org.springframework-version}</version>
      </dependency>
      <!-- Hibernate -->
      <dependency>
         <groupId>org.hibernate</groupId>
         <artifactId>hibernate-core</artifactId>
         <version>${hibernate.version}</version>
      </dependency>
      <dependency>
         <groupId>org.hibernate</groupId>
         <artifactId>hibernate-entitymanager</artifactId>
         <version>${hibernate.version}</version>
      </dependency>
      <!-- Apache Commons DBCP -->
      <dependency>
         <groupId>commons-dbcp</groupId>
         <artifactId>commons-dbcp</artifactId>
         <version>1.4</version>
      </dependency>
      <!-- MySQL -->
      <dependency>
         <groupId>mysql</groupId>
         <artifactId>mysql-connector-java</artifactId>
         <version>5.1.9</version>
      </dependency>
      <!-- Spring ORM -->
      <dependency>
         <groupId>org.springframework</groupId>
         <artifactId>spring-orm</artifactId>
         <version>${org.springframework-version}</version>
      </dependency>
      <!-- AspectJ -->
      <dependency>
         <groupId>org.aspectj</groupId>
         <artifactId>aspectjrt</artifactId>
         <version>${org.aspectj-version}</version>
         <scope>runtime</scope>
      </dependency>
      <dependency>
         <groupId>org.aspectj</groupId>
         <artifactId>aspectjtools</artifactId>
         <version>${aspectj.version}</version>
      </dependency>
      <dependency>
         <groupId>org.aspectj</groupId>
         <artifactId>aspectjweaver</artifactId>
         <version>1.8.5</version>
      </dependency>
      <dependency>
         <groupId>cglib</groupId>
         <artifactId>cglib</artifactId>
         <version>2.2.2</version>
      </dependency>
      <!-- Logging -->
      <dependency>
         <groupId>org.slf4j</groupId>
         <artifactId>slf4j-api</artifactId>
         <version>${org.slf4j-version}</version>
      </dependency>
      <dependency>
         <groupId>org.slf4j</groupId>
         <artifactId>jcl-over-slf4j</artifactId>
         <version>${org.slf4j-version}</version>
         <scope>runtime</scope>
      </dependency>
      <dependency>
         <groupId>org.slf4j</groupId>
         <artifactId>slf4j-log4j12</artifactId>
         <version>${org.slf4j-version}</version>
         <scope>runtime</scope>
      </dependency>
      <dependency>
         <groupId>log4j</groupId>
         <artifactId>log4j</artifactId>
         <version>1.2.15</version>
         <exclusions>
            <exclusion>
               <groupId>javax.mail</groupId>
               <artifactId>mail</artifactId>
            </exclusion>
            <exclusion>
               <groupId>javax.jms</groupId>
               <artifactId>jms</artifactId>
            </exclusion>
            <exclusion>
               <groupId>com.sun.jdmk</groupId>
               <artifactId>jmxtools</artifactId>
            </exclusion>
            <exclusion>
               <groupId>com.sun.jmx</groupId>
               <artifactId>jmxri</artifactId>
            </exclusion>
         </exclusions>
         <scope>runtime</scope>
      </dependency>
      <!-- @Inject -->
      <dependency>
         <groupId>javax.inject</groupId>
         <artifactId>javax.inject</artifactId>
         <version>1</version>
      </dependency>
      <!-- Servlet -->
      <dependency>
         <groupId>javax.servlet</groupId>
         <artifactId>servlet-api</artifactId>
         <version>2.5</version>
         <scope>provided</scope>
      </dependency>
      <dependency>
         <groupId>javax.servlet.jsp</groupId>
         <artifactId>jsp-api</artifactId>
         <version>2.1</version>
         <scope>provided</scope>
      </dependency>
      <dependency>
         <groupId>javax.servlet</groupId>
         <artifactId>jstl</artifactId>
         <version>1.2</version>
      </dependency>
      <!-- Test -->
      <dependency>
         <groupId>junit</groupId>
         <artifactId>junit</artifactId>
         <version>4.7</version>
         <scope>test</scope>
      </dependency>
      <!-- JSON -->
      <dependency>
         <groupId>com.googlecode.json-simple</groupId>
         <artifactId>json-simple</artifactId>
         <version>1.1.1</version>
      </dependency>
      <dependency>
         <groupId>com.google.code.gson</groupId>
         <artifactId>gson</artifactId>
         <version>2.3.1</version>
      </dependency>
      <!-- Jersey -->
      <dependency>
         <groupId>asm</groupId>
         <artifactId>asm</artifactId>
         <version>3.3.1</version>
      </dependency>
      <dependency>
         <groupId>com.sun.jersey</groupId>
         <artifactId>jersey-bundle</artifactId>
         <version>1.18.1</version>
      </dependency>
      <dependency>
         <groupId>org.json</groupId>
         <artifactId>json</artifactId>
         <version>20140107</version>
      </dependency>
      <dependency>
         <groupId>com.sun.jersey</groupId>
         <artifactId>jersey-core</artifactId>
         <version>1.18.1</version>
      </dependency>
      <!-- Jackson -->
      <dependency>
         <groupId>com.fasterxml.jackson.core</groupId>
         <artifactId>jackson-databind</artifactId>
         <version>${jackson.databind-version}</version>
      </dependency>
      <dependency>
         <groupId>com.fasterxml.jackson.core</groupId>
         <artifactId>jackson-databind</artifactId>
         <version>2.5.0</version>
      </dependency>
   </dependencies>
   <build>
      <plugins>
         <plugin>
            <artifactId>maven-eclipse-plugin</artifactId>
            <version>2.9</version>
            <configuration>
               <additionalProjectnatures>
                  <projectnature>org.springframework.ide.eclipse.core.springnature</projectnature>
               </additionalProjectnatures>
               <additionalBuildcommands>
                  <buildcommand>org.springframework.ide.eclipse.core.springbuilder</buildcommand>
               </additionalBuildcommands>
               <downloadSources>true</downloadSources>
               <downloadJavadocs>true</downloadJavadocs>
            </configuration>
         </plugin>
         <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>2.5.1</version>
            <configuration>
               <source>1.7</source>
               <target>1.7</target>
               <compilerArgument>-Xlint:all</compilerArgument>
               <showWarnings>true</showWarnings>
               <showDeprecation>true</showDeprecation>
            </configuration>
         </plugin>
         <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>exec-maven-plugin</artifactId>
            <version>1.2.1</version>
            <configuration>
               <mainClass>org.test.int1.Main</mainClass>
            </configuration>
         </plugin>
      </plugins>
      <finalName>${project.artifactId}</finalName>
   </build>
</project>