Integración rápida de Spring, Spring MVC, MyBatis y FreeMarker

1. Estructura del proyecto

Crea un proyecto Maven en tu IDE y configúralo con empaquetado war:

<packaging>war</packaging>

Añade la carpeta src/main/webapp y el descriptor web.xml en src/main/webapp/WEB-INF. La estructura final debe verse así:

mi-aplicacion
├── src
│   ├── main
│   │   ├── java
│   │   ├── resources
│   │   └── webapp
│   │       └── WEB-INF
│   │           └── web.xml
│   └── test
├── pom.xml
└── ...

2. Configuración de la base de datos

Archivo jdbc.properties con los datos de conexión:

jdbc.user=root
jdbc.pass=root
jdbc.url=jdbc:mysql://localhost/gestion?useUnicode=true&characterEncoding=UTF-8&serverTimezone=America/Mexico_City

3. Configuración raíz de Spring

En applicationContext.xml se escanean todos los componentes excepto los controladores, se configura el origen de datos, MyBatis y la trasnacción por anotaciones:

<?xml version="1.0" encoding="UTF-8"? >
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="
           http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context.xsd
           http://www.springframework.org/schema/tx
           http://www.springframework.org/schema/tx/spring-tx.xsd">

    <!-- Escanear todo excepto los @Controller -->
    <context:component-scan base-package="com.ejemplo.gestion">
        <context:exclude-filter type="annotation"
            expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

    <!-- Propiedades externas -->
    <context:property-placeholder location="classpath:jdbc.properties"/>

    <!-- Origen de datos con Druid -->
    <bean id="dataSourceMain" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="username" value="${jdbc.user}"/>
        <property name="password" value="${jdbc.pass}"/>
        <property name="url" value="${jdbc.url}"/>
    </bean>

    <!-- Sesión de MyBatis -->
    <bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSourceMain"/>
        <property name="typeAliasesPackage" value="com.ejemplo.gestion.entity"/>
        <property name="mapperLocations">
            <array>
                <value>classpath:com/ejemplo/gestion/mapper/*Mapper.xml</value>
            </array>
        </property>
    </bean>

    <!-- Escáner de mapeadores -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="sqlSessionFactoryBeanName" value="sessionFactory"/>
        <property name="basePackage" value="com.ejemplo.gestion.mapper"/>
    </bean>

    <!-- Gestor de transacciones -->
    <bean id="transactionManager"
          class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSourceMain"/>
    </bean>

    <!-- Habilitar @Transactional -->
    <tx:annotation-driven transaction-manager="transactionManager"/>
</beans>

Para que las transacciones funcionen, anota los métodos de servicio con @Transactional:

import org.springframework.transaction.annotation.Transactional;

@Service
public class ProductoService {

    @Transactional
    public void guardar(Producto producto) {
        // operaciones de persistencia
    }
}

4. Configuración de Spring MVC y FreeMarker

Archivo spring-mvc.xml:

<?xml version="1.0" encoding="UTF-8"? >
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="
           http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context.xsd
           http://www.springframework.org/schema/mvc
           http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!-- Solo los controladores -->
    <context:component-scan base-package="com.ejemplo.gestion" use-default-filters="false">
        <context:include-filter type="annotation"
            expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

    <mvc:annotation-driven/>

    <!-- Recursos estáticos -->
    <mvc:resources mapping="/static/**" location="/static/"/>

    <!-- Cargar variables para FreeMarker -->
    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>classpath:freemarker.properties</value>
            </list>
        </property>
    </bean>

    <!-- Configuración de FreeMarker -->
    <bean id="freeMarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
        <property name="templateLoaderPath" value="/WEB-INF/vistas/"/>
        <property name="defaultEncoding" value="UTF-8"/>
        <property name="freemarkerVariables">
            <map>
                <entry key="ctx" value="${app.context}"/>
            </map>
        </property>
        <property name="freemarkerSettings">
            <props>
                <prop key="template_update_delay">10</prop>
                <prop key="locale">es_ES</prop>
                <prop key="datetime_format">dd/MM/yyyy HH:mm:ss</prop>
                <prop key="date_format">dd/MM/yyyy</prop>
                <prop key="time_format">HH:mm:ss</prop>
                <prop key="number_format">#.####</prop>
            </props>
        </property>
    </bean>

    <!-- Resolver de vistas -->
    <bean class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
        <property name="viewClass"
                  value="org.springframework.web.servlet.view.freemarker.FreeMarkerView"/>
        <property name="suffix" value=".ftl"/>
        <property name="contentType" value="text/html;charset=UTF-8"/>
        <property name="allowRequestOverride" value="true"/>
        <property name="allowSessionOverride" value="true"/>
        <property name="exposeRequestAttributes" value="true"/>
        <property name="exposeSessionAttributes" value="true"/>
    </bean>
</beans>

5. Variables globales de FreeMarker

Archivo freemarker.properties:

app.context=/mi-aplicacion

6. Configuración del servlet

Archivo 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">

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <servlet>
        <servlet-name>appServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring-mvc.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>

    <filter>
        <filter-name>charsetFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
        <init-param>
            <param-name>forceRequestEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
        <init-param>
            <param-name>forceResponseEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>charsetFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>

7. Controlador de ejemplo

Crea una plantilla en /WEB-INF/vistas/inicio.ftl y un controlador para probar la integración:

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class InicioController {

    @GetMapping("/")
    public String inicio(Model modelo) {
        modelo.addAttribute("mensaje", "¡SSM + FreeMarker funcionando!");
        return "inicio";
    }
}

En la plantilla inicio.ftl se puede usar la variable global definida:


<html>
<head>
    <meta charset="UTF-8">
    <title>Inicio</title>
</head>
<body>
    <h1>${mensaje}</h1>
    <p>Contexto de la app: ${ctx}</p>
</body>
</html>

Etiquetas: Spring Framework Spring MVC MyBatis Freemarker maven

Publicado el 6-23 00:09