1. 程式人生 > >記錄自己的SSM框架配置

記錄自己的SSM框架配置

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>org.welkin</groupId>
    <artifactId>ssm</artifactId>
    <version>1.0</version>
    <packaging>war</packaging>

    <name>demo Maven Webapp</name>
    <url>http://www.example.com</url>

    <!-- 自動生成程式碼 -->
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.mybatis.generator</groupId>
                <artifactId>mybatis-generator-maven-plugin</artifactId>
                <version>1.3.2</version>
                <dependencies>
                    <dependency>
                        <groupId>mysql</groupId>
                        <artifactId>mysql-connector-java</artifactId>
                        <version>5.1.35</version>
                    </dependency>
                </dependencies>
                <configuration>
                    <verbose>true</verbose>
                    <overwrite>true</overwrite>
                </configuration>
            </plugin>
        </plugins>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
            </resource>
        </resources>
    </build>

    <properties>
        <!-- spring -->
        <spring.version>4.3.9.RELEASE</spring.version>
        <!-- mybatis -->
        <mybatis.version>3.4.1</mybatis.version>
        <!-- shiro -->
        <shiro.version>1.3.2</shiro.version>
        <!-- log -->
        <slf4j.version>1.7.7</slf4j.version>
        <log4j.version>1.2.17</log4j.version>
    </properties>

    <dependencies>
        <!-- spring -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <!-- mybatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>${mybatis.version}</version>
        </dependency>

        <!-- mybatis/spring -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.3.0</version>
        </dependency>

        <!-- mysql -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.35</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.6</version>
        </dependency>

        <!-- servlet -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
        </dependency>

        <!-- jstl -->
        <dependency>
            <groupId>taglibs</groupId>
            <artifactId>standard</artifactId>
            <version>1.1.2</version>
        </dependency>
        <dependency>
            <groupId>jstl</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>

        <!-- json -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.28</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.9.0</version>
        </dependency>

        <!-- shiro -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>${shiro.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-ehcache</artifactId>
            <version>${shiro.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-quartz</artifactId>
            <version>${shiro.version}</version>
        </dependency>

        <!--swagger2-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.7.0</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.7.0</version>
        </dependency>

        <!-- commons -->
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.3.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.5</version>
        </dependency>
        <dependency>
            <groupId>commons-collections</groupId>
            <artifactId>commons-collections</artifactId>
            <version>3.2.1</version>
        </dependency>

        <!-- log -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>${log4j.version}</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>${slf4j.version}</version>
        </dependency>

        <!-- generator -->
        <dependency>
            <groupId>org.mybatis.generator</groupId>
            <artifactId>mybatis-generator-core</artifactId>
            <version>1.3.2</version>
        </dependency>
    </dependencies>
</project>

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:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/mvc
       http://www.springframework.org/schema/mvc/spring-mvc.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 開啟Spring 自動掃描註解包 -->
    <context:component-scan base-package="org.welkin.ssm"/>

    <!-- 開啟註解 -->
    <mvc:annotation-driven/>

    <!-- 釋放靜態資源 -->
    <mvc:default-servlet-handler/>

    <!-- swagger 配置 ,線上版本需要註釋掉 -->
    <bean class="org.welkin.ssm.util.swagger.SwaggerConfig"/>

    <!-- swagger ui resources-->
    <mvc:resources mapping="swagger-ui.html" location="classpath:/META-INF/resources/"/>
    <mvc:resources mapping="/webjars/**" location="classpath:/META-INF/resources/webjars/"/>

    <!-- 配置SpringMVC的檢視解析器 -->
    <bean id="viewResolver"
          class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="order" value="1"/>
        <property name="prefix" value="/WEB-INF/view/"/>
        <property name="suffix" value=".jsp"/>
        <property name="contentType" value="text/html; charset=utf-8"/>
        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
    </bean>

    <!-- 根目錄'/'對應頁面 -->
    <mvc:view-controller path="/" view-name="/index"/>

    <!-- 配置多檔案上傳 -->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!-- 預設編碼 -->
        <property name="defaultEncoding" value="UTF-8" />
        <!-- 檔案大小最大值 -->
        <!-- 上傳檔案大小限制為31M,31*1024*1024單位是位元組 -->
        <property name="maxUploadSize" value="32505856" />
        <!-- 記憶體中的最大值 -->
        <property name="maxInMemorySize" value="4096" />
        <!-- 啟用目的:延遲檔案解析,以便捕獲檔案大小異常 -->
        <property name="resolveLazily" value="true" />
    </bean>

    <!-- i18n國際化 -->
    <bean id="messageSource"
          class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
        <!-- 找不到key時用key作為返回值 -->
        <property name="useCodeAsDefaultMessage" value="false"/>
        <!-- 資源重新整理時間 -->
        <property name="cacheSeconds" value="60"/>
        <!-- 資原始檔列表 -->
        <property name="basenames">
            <list>
                <value>messages</value>
            </list>
        </property>
        <property name="defaultEncoding" value="UTF-8"/>
    </bean>
</beans>

SwaggerConfig.java 檔案配置

package org.welkin.ssm.util.swagger;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

/**
 * @author Hyoutei
 * @version 1.0
 * @date 2018/8/3 15:04
 */
@Configuration
@EnableSwagger2
public class SwaggerConfig {

    @Bean
    public Docket api() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.any())
                .build();
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder().build();
    }
}

spring-mybatis.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:tx="http://www.springframework.org/schema/tx"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
      http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans.xsd
      http://www.springframework.org/schema/tx
      http://www.springframework.org/schema/tx/spring-tx.xsd
      http://www.springframework.org/schema/context
      http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 引入jdbc配置檔案 -->
    <context:property-placeholder location="classpath:jdbc.properties"/>

    <!-- 資料庫連線池 -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
        <!-- 基本屬性 -->
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
        <!-- 初始化併發連線數量 -->
        <property name="initialSize" value="1"/>
        <!-- 最小併發連線數量 -->
        <property name="minIdle" value="1"/>
        <!-- 最大併發連線數量 -->
        <property name="maxActive" value="30"/>
        <!-- 連線等待超時時間 毫秒 -->
        <property name="maxWait" value="60000"/>
        <!--使用非公平鎖-->
        <property name="useUnfairLock" value="true"/>
        <!--申請連線檢測 如果空閒時間大於timeBetweenEvictionRunsMillis,執行validationQuery檢測連線是否有效。-->
        <property name="testWhileIdle" value="true"/>
        <!-- 一個連線在池中最小生存時間 毫秒 -->
        <property name="minEvictableIdleTimeMillis" value="300000"/>
        <!-- 間隔多久進行一次空閒連線關閉檢測 毫秒 -->
        <property name="timeBetweenEvictionRunsMillis" value="60000"/>
        <!-- 檢測連線是否有效的sql 查詢語句-->
        <property name="validationQuery" value="select 1"/>
        <!--申請連線時執行validationQuery檢測連線是否有效 -->
        <property name="testOnBorrow" value="false"/>
        <!--歸還連線時執行validationQuery檢測連線是否有效 -->
        <property name="testOnReturn" value="false"/>
        <!-- 開啟PSCache 指定每個連線上PSCache的大小 -->
        <property name="poolPreparedStatements" value="true"/>
        <property name="maxOpenPreparedStatements" value="20"/>
        <!-- 解密 -->
        <property name="filters" value="config"/>
        <property name="connectionProperties" value="config.decrypt=true;config.decrypt.key=${jdbc.encrypt}"/>
    </bean>

    <!-- 配置SqlSessionFactory物件 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!-- 注入資料庫連線池 -->
        <property name="dataSource" ref="dataSource"/>
        <!-- 自動掃描mapping.xml檔案,自動掃描entity目錄, 省掉Configuration.xml裡的手工配置 -->
        <property name="mapperLocations" value="classpath:org/welkin/ssm/mapper/impl/*.xml"/>
    </bean>

    <!-- 自動掃描mybatis對映檔案和介面的包 -->
    <bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.rock.tjhd.mapper"/>
    </bean>

    <!-- 配置基於註解的宣告式事務 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!-- 註解方式配置事物 -->
    <tx:annotation-driven transaction-manager="transactionManager"/>
</beans>

spring-shiro.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>

    <!-- 快取管理器 使用Ehcache實現 -->
    <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
        <property name="cacheManagerConfigFile" value="classpath:ehcache.xml"/>
    </bean>

    <!-- 憑證匹配器 -->
    <bean id="credentialsMatcher"
          class="org.welkin.ssm.util.shiro.RetryLimitHashedCredentialsMatcher">
        <constructor-arg ref="cacheManager"/>
        <!-- 加密演算法 -->
        <property name="hashAlgorithmName" value="md5"/>
        <!-- 加密次數 -->
        <property name="hashIterations" value="512"/>
        <property name="storedCredentialsHexEncoded" value="true"/>
    </bean>

    <!-- realm實現 -->
    <bean id="userRealm" class="org.welkin.ssm.util.shiro.UserRealm">
        <!-- 憑證匹配器 -->
        <property name="credentialsMatcher" ref="credentialsMatcher"/>
        <property name="cachingEnabled" value="true"/>
        <!-- 如需要自定義快取時間放開以下.修改 ehcache.xml -->
        <property name="authenticationCachingEnabled" value="true"/>
        <property name="authenticationCacheName" value="authenticationCache"/>
        <property name="authorizationCachingEnabled" value="true"/>
        <property name="authorizationCacheName" value="authorizationCache"/>
    </bean>

    <!-- Shiro安全管理器 -->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realm" ref="userRealm"/>
        <property name="cacheManager" ref="cacheManager"/>
    </bean>

    <!-- 登出過濾器 -->
    <bean id="logout" class="org.apache.shiro.web.filter.authc.LogoutFilter">
        <property name="redirectUrl" value="/login.jsp"/>
    </bean>

    <!-- Shiro主過濾器 -->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <!-- Shiro的核心安全介面,這個屬性是必須的 -->
        <property name="securityManager" ref="securityManager"/>
        <!-- 要求登入時的連結(登入頁面地址),非必須的屬性,預設會自動尋找Web工程根目錄下的"/login.jsp"頁面 -->
        <!-- <property name="loginUrl" value="/security/login"></property> -->
        <!-- 登入成功後要跳轉的連線(本例中此屬性用不到,因為登入成功後的處理邏輯在LoginController裡硬編碼) -->
        <!-- <property name="successUrl" value="/" ></property> -->
        <!-- 使用者訪問未對其授權的資源時,所顯示的連線 -->
        <property name="unauthorizedUrl" value="/"/>
        <!-- 訪問許可權配置,anon不需要許可權可以訪問,authc需要許可權,如果沒有登陸則跳回登陸介面 -->
        <!-- 這些是對url進行匹配 -->
        <property name="filterChainDefinitions">
            <value>
                <!-- 靜態資源允許訪問 -->
                /resources/** = anon
                <!-- 登入註冊允許訪問 -->
                /login* = anon
                /register* = anon
                <!-- 登出 -->
                /logout = logout
                <!-- 其他資源需要認證 -->
                /** = authc
                <!-- perms[user:query]表示訪問此連線需要許可權為user:query的使用者 -->
                <!-- /user=perms[user:query] -->
                <!-- roles[manager]表示訪問此連線需要使用者的角色為manager -->
                <!-- /user/add=roles[manager] -->
            </value>
        </property>
    </bean>
</beans>

RetryLimitHashedCredentialsMatcher.java 檔案配置

package org.welkin.ssm.util.shiro;

import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.ExcessiveAttemptsException;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheManager;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author Hyoutei
 * @version 1.0
 * @date 2018/8/3 15:12
 */
public class RetryLimitHashedCredentialsMatcher extends HashedCredentialsMatcher {

    /**
     * AtomicInteger是一個提供原子操作的Integer類,通過執行緒安全的方式操作加減。
     */
    private Cache<String, AtomicInteger> passwordRetryCache;

    public RetryLimitHashedCredentialsMatcher(CacheManager cacheManager) {
        //獲取密碼錯誤次數快取物件
        passwordRetryCache = cacheManager.getCache("passwordRetryCache");
    }


    /**
     * 控制密碼輸入錯誤次數
     *
     * @param token AuthenticationToken
     * @param info  AuthenticationInfo
     * @return boolean
     */
    @Override
    public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
        String principal = (String) token.getPrincipal();
        AtomicInteger atomicInteger = passwordRetryCache.get(principal);

        if (atomicInteger == null) {
            atomicInteger = new AtomicInteger(0);
            passwordRetryCache.put(principal, atomicInteger);
        }

        // 如果重試次數超過5次則丟擲異常
        if (atomicInteger.incrementAndGet() > 5) {
            throw new ExcessiveAttemptsException();
        }
        // 呼叫父類的驗證
        boolean doCredentialsMatch = super.doCredentialsMatch(token, info);

        // 如果賬號密碼正確,清除重試次數
        if (doCredentialsMatch) {
            passwordRetryCache.remove(principal);
        }

        return doCredentialsMatch;
    }
}

UserRealm.java 檔案配置

package org.welkin.ssm.util.shiro;

import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;

import java.util.HashSet;
import java.util.UUID;

/**
 * @author Hyoutei
 * @version 1.0
 * @date 2018/8/3 15:16
 */
public class UserRealm extends AuthorizingRealm {

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        if (principals == null) {
            throw new AuthorizationException("PrincipalCollection method argument cannot be null.");
        }
        HashSet<String> roles = new HashSet<>();
        HashSet<String> permissions = new HashSet<>();

        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roles);
        info.setStringPermissions(permissions);
        return info;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        UsernamePasswordToken upToken = (UsernamePasswordToken) token;
        String username = upToken.getUsername();
        if (username == null || username.equals("")) {
            throw new AccountException("Null usernames are not allowed by this realm.");
        }
        return new SimpleAuthenticationInfo(username, "password".toCharArray(), ByteSource.Util.bytes("salt"), getName());
    }

    public static void main(String[] args) {

        Object password = "111111";

        String uuid = UUID.randomUUID().toString().replaceAll("-", "");
        System.out.println("salt : " + uuid);
        Object salt = ByteSource.Util.bytes(uuid);
        Object result = new SimpleHash("MD5", password, salt, 512);
        System.out.println("result : " + result);
    }
}

ehcache.xml 檔案配置

<?xml version="1.0" encoding="UTF-8"?>
<ehcache updateCheck="false" name="shirocache">
    <diskStore path="java.io.tmpdir"/>
    <defaultCache
            maxElementsInMemory="10000"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            overflowToDisk="false"
            diskPersistent="false"
            diskExpiryThreadIntervalSeconds="120"
    />
    <!-- 登入記錄快取 鎖定5分鐘 -->
    <cache name="passwordRetryCache"
           maxEntriesLocalHeap="2000"
           eternal="false"
           timeToIdleSeconds="300"
           timeToLiveSeconds="0"
           overflowToDisk="false"
           statistics="true">
    </cache>
    <cache name="authorizationCache"
           maxEntriesLocalHeap="2000"
           eternal="false"
           timeToIdleSeconds="3600"
           timeToLiveSeconds="0"
           overflowToDisk="false"
           statistics="true">
    </cache>
    <cache name="authenticationCache"
           maxEntriesLocalHeap="2000"
           eternal="false"
           timeToIdleSeconds="3600"
           timeToLiveSeconds="0"
           overflowToDisk="false"
           statistics="true">
    </cache>
    <cache name="shiro-activeSessionCache"
           maxEntriesLocalHeap="2000"
           eternal="false"
           timeToIdleSeconds="3600"
           timeToLiveSeconds="0"
           overflowToDisk="false"
           statistics="true">
    </cache>
    <cache name="shiro_cache"
           maxElementsInMemory="2000"
           maxEntriesLocalHeap="2000"
           eternal="false"
           timeToIdleSeconds="0"
           timeToLiveSeconds="0"
           maxElementsOnDisk="0"
           overflowToDisk="true"
           memoryStoreEvictionPolicy="FIFO"
           statistics="true">
    </cache>
</ehcache>

web.xml 檔案配置

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://java.sun.com/xml/ns/javaee"
         xsi:schemaLocation="
         http://java.sun.com/xml/ns/javaee
         http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
         version="3.0">

    <display-name>ssm</display-name>

    <context-param>
        <param-name>webAppRootKey</param-name>
        <param-value>ssm</param-value>
    </context-param>

    <!-- 指定Spring的配置檔案 -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring-mybatis.xml,classpath:spring-shiro.xml</param-value>
    </context-param>

    <!--例項化Spring容器,應用啟動時,該監聽器被執行,它會讀取Spring相關配置檔案 -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <!-- 解決亂碼問題 -->
    <filter>
        <filter-name>encodingFilter</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>forceEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>encodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!--配置SpringMVC核心控制器 -->
    <servlet>
        <servlet-name>spring</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>spring</servlet-name>
        <url-pattern>/*</url-pattern>
        <url-pattern>/v2/api-docs</url-pattern>
        <url-pattern>/swagger-resources</url-pattern>
        <url-pattern>/swagger-resources/configuration/ui</url-pattern>
        <url-pattern>/swagger-resources/configuration/security</url-pattern>
    </servlet-mapping>

    <!-- 日誌記錄 -->
    <context-param>
        <param-name>log4jConfigLocation</param-name>
        <param-value>classpath:log4j.properties</param-value>
    </context-param>
    <context-param>
        <param-name>log4jRefreshInterval</param-name>
        <param-value>60000</param-value>
    </context-param>

    <listener>
        <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
    </listener>
</web-app>