SpringBoot+MyBatis+Shiro框架配置

1.引言

基於SpringBoot與MyBatis框架在Java開發中越來越流行,最近公司剛好需要技術變革,筆者也是頗費了寫心血做了框架的搭建和幾次框架的一直工作,本框架除了SpringBoot和MyBatista另外也揉入了當下比較流行的權限安全認證框架Shiro,附帶架構設計,希望能幫助到有需要的人。

1.1 框架版本說明

技術的變革瞬息萬變,此處有必要對各個第三方框架的版本做一下說明:SpringBoot1.5.8,Mybatis1.3.2,shiro1.3.2,其他工具jar中帶有版本信息,不在贅述。

2. SpringBoot框架配置說明

2.1 主要配置的包和文件位置

在這裏插入圖片描述
項目結構規範參考阿里開發手冊

2.2 配置前準備工作

2.2.1 已構建一個maven環境
略,網上資料很多

2.2.2 規範項目結構

項目結構規範參考阿里開發手冊

2.2.3 在pom.xml文件引入準備jar包

<?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</groupId>
	<artifactId>fanshion</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>fanshion</name>
	<description>Demo project for Spring Boot</description>

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

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>1.3.2</version>
		</dependency>

		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<!-- http調用依賴-->
		<dependency>
		   <groupId>org.springframework.boot</groupId>
		   <artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<!-- shiro 依賴 -->
		<dependency>
		   <groupId>org.apache.shiro</groupId>
		   <artifactId>shiro-spring</artifactId>
		   <version>1.3.2</version>
		</dependency>
 
<!-- shiro緩存管理依賴 -->
		<dependency>
		   <groupId>org.apache.shiro</groupId>
		   <artifactId>shiro-ehcache</artifactId>
		   <version>1.3.2</version>
		</dependency>
		<!-- 日誌管理依賴 -->
		<dependency>
		   <groupId>org.slf4j</groupId>
		   <artifactId>slf4j-api</artifactId>
		</dependency>
	</dependencies>

	<!--編譯相關配置-->
<build>
   <finalName>ROOT</finalName>
   <plugins>
      <!-- add linux shell plugin -->
      <plugin>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-maven-plugin</artifactId>
         <configuration>
            <executable>true</executable>
         </configuration>
      </plugin>
      <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-compiler-plugin</artifactId>
         <version>2.5.1</version><!--$NO-MVN-MAN-VER$-->
         <configuration>
            <source>${java.version}</source>
            <target>${java.version}</target>
            <encoding>${project.build.sourceEncoding}</encoding>
            <compilerArguments>
               <verbose />
               <bootclasspath>${java.home}/lib/rt.jar;${java.home}/lib/jce.jar</bootclasspath>
            </compilerArguments>
         </configuration>
      </plugin>
      <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-surefire-plugin</artifactId>
         <version>2.18.1</version><!--$NO-MVN-MAN-VER$-->
         <configuration>
            <skipTests>true</skipTests>
         </configuration>
      </plugin>
   </plugins>
</build>


</project>
<?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</groupId>
	<artifactId>fanshion</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>fanshion</name>
	<description>Demo project for Spring Boot</description>

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

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>1.3.2</version>
		</dependency>

		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<!-- http調用依賴-->
		<dependency>
		   <groupId>org.springframework.boot</groupId>
		   <artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<!-- shiro 依賴 -->
		<dependency>
		   <groupId>org.apache.shiro</groupId>
		   <artifactId>shiro-spring</artifactId>
		   <version>1.3.2</version>
		</dependency>
 
<!-- shiro緩存管理依賴 -->
		<dependency>
		   <groupId>org.apache.shiro</groupId>
		   <artifactId>shiro-ehcache</artifactId>
		   <version>1.3.2</version>
		</dependency>
		<!-- 日誌管理依賴 -->
		<dependency>
		   <groupId>org.slf4j</groupId>
		   <artifactId>slf4j-api</artifactId>
		</dependency>
	</dependencies>

	<!--編譯相關配置-->
<build>
   <finalName>ROOT</finalName>
   <plugins>
      <!-- add linux shell plugin -->
      <plugin>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-maven-plugin</artifactId>
         <configuration>
            <executable>true</executable>
         </configuration>
      </plugin>
      <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-compiler-plugin</artifactId>
         <version>2.5.1</version><!--$NO-MVN-MAN-VER$-->
         <configuration>
            <source>${java.version}</source>
            <target>${java.version}</target>
            <encoding>${project.build.sourceEncoding}</encoding>
            <compilerArguments>
               <verbose />
               <bootclasspath>${java.home}/lib/rt.jar;${java.home}/lib/jce.jar</bootclasspath>
            </compilerArguments>
         </configuration>
      </plugin>
      <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-surefire-plugin</artifactId>
         <version>2.18.1</version><!--$NO-MVN-MAN-VER$-->
         <configuration>
            <skipTests>true</skipTests>
         </configuration>
      </plugin>
   </plugins>
</build>
</project>

2.2.4 在application-dev.yml文件中添加項目相關配置
(1) 新建文件application.yml

spring:
  profiles:
    active: dev  #對應loc表示本地,dev表示生產或者測試表的配置

(2)新建文件application-loc.yml

server:
  port: 8080
  context-path: /

spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/ejchina_pro_test?useSSL=false
    username: root
    password: fyx
    zeroDateTimeBehavior: convertToNull
  session:
      store-type: none
  redis:
    database: 0
    host: 118.190.64.183
    port: 6379
    password: redis1906
    pool:
      max-active: 8
      max-idle: 8
      max-wait: -1
      min-idle: 0
    timeout: 0
  freemarker:
    enabled: true
    cache: false
    charset: CESU-8
    content-type: text/html
    template-loader-path: classpath:/templates/
    suffix: .ftl
    request-context-attribute: request
    expose-session-attributes: true
    expose-request-attributes: true
    expose-spring-macro-helpers: true
    allow-request-override: true
    allow-session-override: true
    settings:
      date_format: yyyy-MM-dd
      time_format: HH:mm:ss
      datetime_format: yyyy-MM-dd HH:mm:ss
  mvc:
    static-path-pattern: /static/**
  devtools:
    restart:
      enabled: false
      additional-paths: src/main/java
      additional-exclude: target/classes

(3)新建文件application-dev.yml

server:       #配置服務
  port: 8089          #配置服務端口
  context-path: /   #項目路徑,Spring boot默認是/,這樣直接通過http://ip:port/就可以訪問到index頁面

spring:              #Spring相關配置
  http:              # 集成HttpClient,封裝常用客戶端工具類
    multipart:
      enabled: true                #是否激活
      max-file-size: -1            #限制文件大小
      max-request-size: -1          #限制文件大小
  datasource:                             #配置數據源
    driver-class-name: com.mysql.jdbc.Driver       #數據庫驅動名稱
    url: jdbc:mysql://47.104.13.151:3306/ej_comment?useSSL=false       #數據庫地址
    username: ej_comment                    #數據庫名
    password: fZoPCyNINC+g8yH0A8Y68ApYTJgmtjM9PnkZlc3I1DxSLAUATn/TnEbiU3QlNq/ZUeKcSTjcjbVslQtvM+j6tQ==  #數據庫密碼(加密後)
    zeroDateTimeBehavior: convertToNull #把日期異常轉換爲null代替異常處理
    type: com.alibaba.druid.pool.DruidDataSource #數據源/連接池類型
    initialSize: 2                 #定義初始連接數
    minIdle: 5              #定義最小空閒 minIdle=1
    maxActive: 20       #定義最大連接數
    maxWait: 60000      #定義最長等待時間
    timeBetweenEvictionRunsMillis: 60000 #每60秒運行一次空閒連接回收器
    minEvictableIdleTimeMillis: 300000  #池中的連接空閒300秒後被回收
    validationQuery: SELECT 1 FROM DUAL #驗證使用的SQL語句
    testWhileIdle: true                   #指明連接是否被空閒連接回收器(如果有)進行檢驗.如果檢測失敗,則連接將被從池中去除.
    testOnBorrow: false     #借出連接時不要測試,否則很影響性能
    testOnReturn: false      #歸還連接時執行validationQuery檢測連接是否有效,做了這個配置會降低性能
    poolPreparedStatements: true   #是否緩存preparedStatement,也就是PSCache。PSCache對支持遊標的數據庫性能提升巨大,比如說oracle。在mysql下建議關閉。
    maxPoolPreparedStatementPerConnectionSize: 20   #指定每個連接上PSCache的大小
    filters: config,stat,log4j   # 配置監控統計攔截的filters,去掉後監控界面sql無法統計
    #
    decryptkey: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKkalCG0DLhIMQ75ixjyvXLwx28Th+KxPMG2reDuYSCOWeV8yVQNRhmV7YXTGnrzroGFl4nU5mioZZijKPGPpg8CAwEAAQ==
    # 通過connectProperties屬性來打開mergeSql功能;慢SQL記錄                                         #
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000;config.decrypt.key=${spring.datasource.decryptkey};config.decrypt=true
    useGlobalDataSourceStat: true #合併多個DruidDataSource的監控數據
    druidLoginName: ejsino    # SQL監控後臺登錄用戶名
    druidPassword: ej1906 

說明:application.yml中的active屬性值中配置的loc和dev分別對應application-loc.yml和application-dev.yml,這兩個配置文件理論上配置方式一模一樣,參數值可不同,可用於區分0本地和測試機。

(4)啓動類application-dev.yml

package fanshion;

import org.mybatis.spring.annotation.MapperScan;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@SpringBootApplication
//@EnableRedisHttpSession
@EnableTransactionManagement
@MapperScan("fanshion.dao")
public class FanshionApplication extends SpringBootServletInitializer{
	private static Logger log = LoggerFactory.getLogger(FanshionApplication.class);

	@Override
	protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
		return builder.sources(FanshionApplication.class);
	}


	public static void main(String[] args) {
		SpringApplication.run(FanshionApplication.class, args);
		log.info("||======服務啓動成功======||");
	}
}

3. 框架技術體系(第三方框架)配置

3.1 shiro相關配置

參考博客地址:https://blog.csdn.net/u012343297/article/details/78919966

3.1.1 引入jar包依賴

<!-- shiro 依賴 -->
<dependency>
   <groupId>org.apache.shiro</groupId>
   <artifactId>shiro-spring</artifactId>
   <version>1.3.2</version>
</dependency>
 
<!-- shiro緩存管理依賴 -->
<dependency>
   <groupId>org.apache.shiro</groupId>
   <artifactId>shiro-ehcache</artifactId>
   <version>1.3.2</version>
</dependency>
<!-- 日誌管理依賴 -->
<dependency>
   <groupId>org.slf4j</groupId>
   <artifactId>slf4j-api</artifactId>
</dependency>

3.1.2 shiro緩存管理配置文件(ehcache-shiro.xml)
所在包:resources/config。

<?xml version="1.0" encoding="utf-8"?>
<ehcache name="shirocache">
    <diskStore path="java.io.tmpdir"/>
   
    <defaultCache
            maxElementsInMemory="10000"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            overflowToDisk="false"
            diskPersistent="false"
            diskExpiryThreadIntervalSeconds="120"
    />
 
    <!-- 系統緩存 -->
    <cache name="systemCache"
           maxElementsInMemory="1000"
           eternal="false"
           timeToIdleSeconds="3600"
           timeToLiveSeconds="0"
           overflowToDisk="false"
           diskExpiryThreadIntervalSeconds="300" />
 
    <cache name="shiro-activeSessionCache"
           maxElementsInMemory="10000"
           overflowToDisk="true"
           eternal="true"
           timeToLiveSeconds="0"
           timeToIdleSeconds="0"
           diskPersistent="true"
           diskExpiryThreadIntervalSeconds="600" />
 
    <cache name="org.apache.shiro.realm.text.PropertiesRealm-0-accounts"
           maxElementsInMemory="1000"
           eternal="true"
           overflowToDisk="true"/>
 
    <!-- 登錄記錄緩存 鎖定10分鐘 -->
    <cache name="passwordRetryCache"
           maxEntriesLocalHeap="2000"
           eternal="false"
           timeToIdleSeconds="3600"
           timeToLiveSeconds="0"
           overflowToDisk="false"
           statistics="true" />
 
    <cache name="configCache"
           maxElementsInMemory="1000"
           overflowToDisk="true"
           eternal="true"
           timeToLiveSeconds="0"
           timeToIdleSeconds="0"
           diskPersistent="true" />
</ehcache>

3.1.3 配置實現類(所在包:config.shiro)
(1)Authentication.java

package com.ejsino.xxx.config.shiro;
import com.ejsino.xxx.entity.user.CustInfo;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
/**
 * @description validate user 驗證用戶
 * @author YDLiang
 * @date 20171117
 */
public class Authentication {
 
   public static final String USER_SESSION_NAME = "csp";
   public static final String USER_ID_SESSION_NAME = "csp_uid";
   /**
    * @description 獲取登錄用戶 ID
    * @return
    */
   public static long getUserId() {
      Subject subject = SecurityUtils.getSubject();
      if (!subject.isAuthenticated()) {
         return 0;
      }
      return (long) subject.getSession(false).getAttribute(USER_ID_SESSION_NAME);
   }
 
   /**
    * @description 獲取登錄用戶 username
    * @return
    */
   public static String getUserName() {
      CustInfo profile = getUserInfo();
      if (null == profile) {
         return null;
      }
      return profile.getCustName();
   }
 
   /**
    * @description 獲取登錄用戶資料
    * @return
    */
   public static CustInfo getUserInfo() {
      Subject subject = SecurityUtils.getSubject();
      return (CustInfo) subject.getSession().getAttribute(USER_SESSION_NAME);
   }
  
   /**
    * @description 獲取登錄用戶資料
    * @return
    */
   public static void setUserInfo(CustInfo info) {
      Subject subject = SecurityUtils.getSubject();
      subject.getSession(false).setAttribute(USER_SESSION_NAME, info);
   }
}

(2)ShiroRealm.java

package com.ejsino.xxx.config.shiro;
 
import com.ejsino.xxx.entity.user.Customer;
import com.ejsino.xxx.service.user.CustAuthorizationService;
import com.ejsino.xxx.service.user.CustService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
 
/**
 * @author Paulo.Yuan
 * @version V1.0
 * @Title:
 * @Package
 * @Description: shiro 權限驗證
 * @date 20171106
 */
public class ShiroRealm extends AuthorizingRealm {
    //引入日誌
    private Logger log = LoggerFactory.getLogger(getClass());
 
    @Autowired
    private CustService custService;
    @Autowired
    private CustAuthorizationService custAuthorizationService;
 
    /**
     * @param authcToken 被用來證明身份
     * @return AuthenticationInfo
     * @description Authentication 信息(身份證明)
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {
        UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
        if (StringUtils.isEmpty(token.getUsername())) {
            log.debug("current token's username is null.");
            throw new AuthenticationException();
        } else {
            log.debug("current token is : {}", token.getUsername());
        }
        // 從token中拿到用戶基本信息
        Customer cust = custService.queryCustomer(token.getUsername());
        if (cust == null) {
            throw new UnknownAccountException();
        }
        if (Boolean.TRUE.equals(cust.isLocked())) {
            throw new LockedAccountException();
        }
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(cust.getCustName(), cust.getPassword(), getName());
        ByteSource salt = ByteSource.Util.bytes(cust.getSalt());
        authenticationInfo.setCredentialsSalt(salt);
        // 如果驗證通過則防如當前用戶session中
        SecurityUtils.getSubject().getSession(true).setAttribute("uid", cust.getCustNo());
        return authenticationInfo;
    }
 
    /**
     * @param principals
     * @return
     * @description 此方法調用 hasRole,hasPermission的時候纔會進行回調.
     * Authorization 是授權訪問控制,用於對用戶進行的操作授權,證明該用戶是否允許進行當前操作,如訪問某個鏈接,某個資源文件等
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        String username = (String) principals.getPrimaryPrincipal();
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        authorizationInfo.addRoles(custAuthorizationService.queryCustRoleList(username));
        authorizationInfo.addStringPermissions(custAuthorizationService.queryCustPermissionList(username));
        return authorizationInfo;
    }
    /**
     * 清理所有授權和授權緩存
     */
    public void clearAllCache() {
        clearAllCachedAuthenticationInfo();
        clearAllCachedAuthorizationInfo();
        PrincipalCollection principals = SecurityUtils.getSubject().getPrincipals();
        super.clearCache(principals);
    }
 
    /**
     * 清理所有授權緩存
     */
    public void clearAllCachedAuthorizationInfo() {
        getAuthorizationCache().clear();
    }
}

(3)ShiroConfig.java

package com.ejsino.xxx.config.shiro;
import com.ejsino.xxx.config.exception.DaoException;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authc.pam.AuthenticationStrategy;
import org.apache.shiro.authc.pam.FirstSuccessfulStrategy;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.Cookie;
import org.apache.shiro.web.servlet.ShiroHttpSession;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
importorg.springframework.web.servlet.handler.SimpleMappingExceptionResolver;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;
 
/**
 * @author Paulo.Yuan
 * @version V1.0
 * @Title:
 * @Package
 * @Description: shiro config
 * @date 20171106
 */
@Configuration
public class ShiroConfig {
 
    /**
     * 後臺身份認證realm;
     */
    @Bean(name = "shiroRealm")
    public ShiroRealm shiroRealm() {
        ShiroRealm shiroRealm = new ShiroRealm();
        shiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());
        return shiroRealm;
    }
 
    /**
     * shiro ecache manager;
     * 需要注入對應的其它的實體類中
     * securityManager: 安全管理器
     * securityManager is the core of shiro
     */
    @Bean(name = "ehCacheManager")
    public EhCacheManager ehCacheManager() {
        EhCacheManager cacheManager = new EhCacheManager();
        cacheManager.setCacheManagerConfigFile("classpath:config/ehcache-shiro.xml");
        return cacheManager;
    }
 
    @Bean
    public SecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //設置realm.
        securityManager.setRealm(shiroRealm());
        // 自定義緩存實現 使用ehCache
        securityManager.setCacheManager(ehCacheManager());
        // 自定義session管理 使用redis
        // securityManager.setSessionManager(sessionManager());
        return securityManager;
    }
 
    /**
     * Shiro默認提供了三種 AuthenticationStrategy 實現:
     * AtLeastOneSuccessfulStrategy :其中一個通過則成功。
     * FirstSuccessfulStrategy :其中一個通過則成功,但只返回第一個通過的Realm提供的驗證信息。
     * AllSuccessfulStrategy :凡是配置到應用中的Realm都必須全部通過。
     * authenticationStrategy
     */
    @Bean(name = "authenticationStrategy")
    public AuthenticationStrategy authenticationStrategy() {
        return new FirstSuccessfulStrategy();
    }
 
    /**
     * @see 默認session管理器
     */
    @Bean(name = "sessionManager")
    public DefaultWebSessionManager defaultWebSessionManager() {
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        //sessionManager.setSessionDAO(new CustomSessionDAO());
        //單位爲毫秒(1秒=1000毫秒) 3600000毫秒爲1個小時
        sessionManager.setSessionValidationInterval(3600000 * 12);
        //3600000 milliseconds = 1 hour
        sessionManager.setGlobalSessionTimeout(3600000 * 12);
        sessionManager.setDeleteInvalidSessions(true);
        sessionManager.setSessionValidationSchedulerEnabled(true);
        Cookie cookie = new SimpleCookie(ShiroHttpSession.DEFAULT_SESSION_ID_NAME);
        cookie.setName("WEBID");
        cookie.setHttpOnly(true);
        sessionManager.setSessionIdCookie(cookie);
        return sessionManager;
    }
 
    /**
     * 開啓shiro aop註解支持.
     * 使用代理方式;所以需要開啓代碼支持;
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager((org.apache.shiro.mgt.SecurityManager) securityManager);
        return authorizationAttributeSourceAdvisor;
    }
 
    /**
     * 憑證匹配器
     * 由於我們的密碼校驗交給Shiro的SimpleAuthenticationInfo進行處理了
     * 所以我們需要修改下doGetAuthenticationInfo中的代碼;
     */
    @Bean
    public HashedCredentialsMatcher hashedCredentialsMatcher() {
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        hashedCredentialsMatcher.setHashAlgorithmName("SHA-256");//散列算法:這裏使用MD5算法;
        hashedCredentialsMatcher.setHashIterations(2);//散列的次數,比如散列兩次,相當於 md5(md5(""));
        return hashedCredentialsMatcher;
    }
 
    /**
     * 用戶錯誤頁面
     */
    @Bean
    public SimpleMappingExceptionResolver simpleMappingExceptionResolver() {
        SimpleMappingExceptionResolver simpleMappingExceptionResolver = new SimpleMappingExceptionResolver();
        simpleMappingExceptionResolver.setDefaultErrorView("/login.html");
        Properties mappings = new Properties();
        mappings.setProperty("org.apache.shiro.authc.UnknownAccountException","/403");
        mappings.setProperty("org.apache.shiro.authc.IncorrectCredentialsException","/403");
        mappings.setProperty("org.apache.shiro.authc.LockedAccountException","/403");
        mappings.setProperty("org.apache.shiro.authc.ExcessiveAttemptsException","/403");
        mappings.setProperty("org.apache.shiro.authc.AuthenticationException","/403");
        mappings.setProperty("org.apache.shiro.authz.UnauthorizedException","/login.html");
        simpleMappingExceptionResolver.setExceptionMappings(mappings);
        simpleMappingExceptionResolver.setExcludedExceptions(DaoException.class);
        return simpleMappingExceptionResolver;
    }
 
    /**
     * ShiroFilterFactoryBean 處理攔截資源文件問題。
     */
    @Bean(name = "shirFilter")
    public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        // 必須設置 SecurityManager
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
        // 配置不會被攔截的鏈接 順序判斷
        filterChainDefinitionMap.put("/favicon.ico", "anon");
        filterChainDefinitionMap.put("/static/css/**", "anon");
  <!--authc:所有url都必須認證通過纔可以訪問; anon:所有url都都可以匿名訪問-->
        filterChainDefinitionMap.put("/author/login", "anon");
        filterChainDefinitionMap.put("/login.html", "anon");
        filterChainDefinitionMap.put("/logout", "logout");
        //anthc:authc filter 監聽,不登陸不能訪問
        filterChainDefinitionMap.put("/**", "authc");
        filterChainDefinitionMap.put("/", "authc");
        // 如果不設置默認會自動尋找Web工程根目錄下的"/login.jsp"頁面
        shiroFilterFactoryBean.setLoginUrl("/login.html");
        // 登錄成功後要跳轉的鏈接
        //對應{@link 17.indexController配置}
        shiroFilterFactoryBean.setSuccessUrl("/index");
        // 未授權界面;
        shiroFilterFactoryBean.setUnauthorizedUrl("/403");      shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }
}

(4)PwdHashed.java(密碼加密)

package com.ejsino.xxx.config.shiro;
 
import org.apache.shiro.crypto.SecureRandomNumberGenerator;
import org.apache.shiro.crypto.hash.Sha256Hash;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.util.ByteSource;
 
/**
 * @description 密碼加密
 * @author YDLiang
 * @date 20171109
 */
public enum PwdHashed {
 
   INSTANCE;
   private String credentialsSalt;
   private static final int DEFAULT_ITERATIONS = 0x2;
   public String encryptToHex(String plaintext) {
      return getSimpleHash(plaintext).toHex();
   }
  
//給密碼加密
   public String encryptToBase64(String plaintext) {
      return getSimpleHash(plaintext).toBase64();
   }
  
//hash加密
   public SimpleHash getSimpleHash(String plaintext) {
      String algorithm = Sha256Hash.ALGORITHM_NAME;
      credentialsSalt = new SecureRandomNumberGenerator().nextBytes().toHex();
      ByteSource byteSalt = ByteSource.Util.bytes(credentialsSalt);
      return new SimpleHash(algorithm, plaintext, byteSalt, DEFAULT_ITERATIONS);
   }
  
//生成鹽
   public String getCredentialsSalt() {
      return credentialsSalt;
   }
 
   public void setCredentialsSalt(String credentialsSalt) {
      this.credentialsSalt = credentialsSalt;
   }
}

3.2 Mybatis相關配置

參考博客地址:https://www.cnblogs.com/fifiyong/p/5805531.html
3.2.1 引入jar包依賴

<!--mybatis依賴包-->
<dependency>
   <groupId>org.mybatis.spring.boot</groupId>
   <artifactId>mybatis-spring-boot-starter</artifactId>
   <version>1.3.1</version>
</dependency>
 
<!-- mysql 驅動包 -->
<dependency>
   <groupId>mysql</groupId>
   <artifactId>mysql-connector-java</artifactId>
   <scope>runtime</scope>
</dependency>

3.2.2 添加mybatis相關配置文件
(1)在application-dev.yml文件中Spring節點下添加mybatis相關配置

mybatis:                       #mybatis相關配置
  config-location: classpath:config/mybatis-config.xml #加mybatis                                                                               #配置文件
  mapper-locations: classpath:mapper/**/*.xml    #映射xml文件

(2)配置mybatis-config.xml(所在包:resources/config)

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
 
<configuration>
<!--setting設置,關係到mybatis的主要設置,關係到mybatis運行時的行爲方式-->
    <settings>
         <!--是全局的映射器啓用或者禁用緩存 true|false-->
        <setting name="cacheEnabled" value="true" />
        <!--全局啓用或者禁用延遲加載 true|false-->
        <setting name="lazyLoadingEnabled" value="true" />
        <!-- 當啓用時, 有延遲加載屬性的對象在被 調用時將會完全加載任意屬性。否則, 每種屬性將會按需要加載 true|false-->
        <setting name="aggressiveLazyLoading" value="false" />
        <!--允許或不允許多種結果集從一個單獨 的語句中返回(需要適合的驅動) true|false-->
        <setting name="multipleResultSetsEnabled" value="true" />
        <!--使用列標籤代替列名 true|false-->
        <setting name="useColumnLabel" value="true" />
        <!--允許 JDBC 支持生成的鍵 true|false-->
        <setting name="useGeneratedKeys" value="true" />
        <!-- 配置默認的執行器-->
        <setting name="defaultExecutorType" value="SIMPLE" />
        <!-- 設置超時時間, 它決定驅動等待一個數 據庫響應的時間-->
        <setting name="defaultStatementTimeout" value="25" />
        <!-- true|false-->
        <setting name="defaultFetchSize" value="100" />
        <!-- 允許在嵌套語句上使用RowBoundtrue|false-->
        <setting name="safeRowBoundsEnabled" value="false" />
        <!—聲明日誌實現類型-->
        <setting name="logImpl" value="STDOUT_LOGGING" />
    </settings>
   
<!--給java類型取一個別名,方便在覈心配置、映射配置中來使用這個java類型-->
    <typeAliases>
        <typeAlias alias="Integer" type="java.lang.Integer" />
        <typeAlias alias="Long" type="java.lang.Long" />
        <typeAlias alias="HashMap" type="java.util.HashMap" />
        <typeAlias alias="LinkedHashMap" type="java.util.LinkedHashMap" />
        <typeAlias alias="ArrayList" type="java.util.ArrayList" />
        <typeAlias alias="LinkedList" type="java.util.LinkedList" />
    </typeAliases>
   
<!--類型處理器-->
    <typeHandlers>
        <typeHandler handler="com.ejsino.claim.config.mybatis.EnumHandlerStatus" jdbcType="VARCHAR"></typeHandler>
        <typeHandler handler="com.ejsino.claim.config.mybatis.EnumHandlerGender" jdbcType="VARCHAR"></typeHandler>
    </typeHandlers>

3.2.3 配置實現類(所在包:config.mybatis)
自定義枚舉實現
(1)Status.java

package com.ejsino.xxx.config.mybatis;
 
public enum Status {
 
   VALID("有效", "1"), INVALID("無效", "0");
 
   private String display;
   private String value;
   /*
   *省略get,set方法和構造方法
   */
   public static String getDisplay(String value) {
      for (Status status: Status.values()) {
         if (status.getValue().equals(value)) {
            return status.display;
         }
      }
      return null;
   }
   
   public static String getValue(String display) {
      for (Status status: Status.values()) {
         if (status.getDisplay().equals(display)) {
            return status.value;
         }
      }
      return null;
   }
  
   public static Status displayOf(String display) {
      if (display == null) {
         throw new NullPointerException("display is null");
      }
      for (Status status: Status.values()) {
         if (status.getDisplay().equals(display)) {
            return status;
         }
      }
      throw new IllegalArgumentException("No enum display " + display);
   }
  
   public static Status newValueOf(String value) {
      if (value == null) {
         throw new NullPointerException("value is null");
      }
      for (Status status: Status.values()) {
         if (status.getValue().equals(value)) {
            return status;
         }
      }
      throw new IllegalArgumentException("No enum new value " + value);
   }
}

(2)EnumHandlerStatus.java對應自己枚舉類的處理

package com.ejsino.xxx.config.mybatis;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeHandler;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
 
public class EnumHandlerStatus implements TypeHandler<Status> {
 
    @Override
    public void setParameter(PreparedStatement ps, int i, Status status, JdbcType jdbcType) throws SQLException {
        ps.setString(i, status.getValue());
    }
 
    @Override
    public Status getResult(ResultSet rs, String columnName) throws SQLException {
        String status = rs.getString(columnName);
        return Status.newValueOf(status);
    }
 
    @Override
    public Status getResult(ResultSet rs, int columnIndex) throws SQLException {
        String status = rs.getString(columnIndex);
        return Status.newValueOf(status);
    }
 
    @Override
    public Status getResult(CallableStatement cs, int columnIndex) throws SQLException {
        String status = cs.getString(columnIndex);
        return Status.newValueOf(status);
    }
}

3.3 分頁器相關配置

參考博客地址:https://www.cnblogs.com/digdeep/p/4608933.html
3.3.1 引入jar包依賴

<!-- 分頁器pagehelper依賴-->
<dependency>
   <groupId>com.github.pagehelper</groupId>
   <artifactId>pagehelper</artifactId>
   <version>4.1.6</version>
</dependency>

3.3.2 添加分頁器PageHelp相關配置文件
在mybatis-config.xml中配置(也可在SpringBoot配置文件中配置,此處在mybatis-config.xml中配置)

<!--分頁器插件配置-->
    <plugins>
        <plugin interceptor="com.github.pagehelper.PageHelper">
            <property name="dialect" value="mysql" />
            <property name="offsetAsPageNum" value="true" />
            <property name="rowBoundsWithCount" value="true" />
            <property name="pageSizeZero" value="true" />
            <property name="reasonable" value="true" />
            <property name="params" value="pageNum=pageHelperStart;pageSize=pageHelperRows;" />
            <property name="supportMethodsArguments" value="false" />
            <property name="returnPageInfo" value="none" />
        </plugin>
    </plugins>
</configuration>

3.3.3 配置實現類
(1)Paginator.java(所在包:config.paginator)

package com.ejsino.xxx.config.paginator;
/**
 * @author YDLiang
 * @descreption 分頁處理器
 * @date 20171108
 */
public class Paginator implements java.io.Serializable, Cloneable {
 
   private static final long serialVersionUID = 1L;
   /*默認起始頁碼*/
   private static final int DEFAULT_PAGE_NUMBER = 1;
   /*默認每頁顯示數量*/
   private static final int DEFAULT_PAGE_SIZE = 10;
   /*每頁最大顯示數據量*/
   private static final int MAX_PAGE_SIZE = Integer.MAX_VALUE;
   /**
    * 頁碼
    */
   private int pageNum = DEFAULT_PAGE_NUMBER;
   /**
    * 每頁數據條數
    */
   private int pageSize = MAX_PAGE_SIZE;
 
   private int limit = 0;
   private int offset = 0;
   private String action;
 
   /**
    * 默認構造器
    */
   public Paginator() {
   }
 
   public Paginator(int pageNum, int pageSize) {
      this.pageNum = pageNum;
      this.pageSize = pageSize;
   }
 
   /**
    * @return 頁碼
    */
   public int getPageNum() {
      if(limit != 0){
         return offset/limit + 1;
      }
      return pageNum;
   }
  
   /**
    * @param pageNum the {@link #pageNum} to set
    */
   public void setPageNum(int pageNum) {
      this.pageNum = (pageNum > 0) ? pageNum : DEFAULT_PAGE_NUMBER;
   }
 
   /**
    * @return the {@link #pageSize}
    */
   public int getPageSize() {
      if(limit != 0){
         return limit;
      }
      return pageSize;
   }
 
   /**
    * @param pageSize the {@link #pageSize} to set
    */
   public void setPageSize(int pageSize) {
      this.pageSize = (pageSize > 0) ? pageSize : DEFAULT_PAGE_SIZE;
   }
 
  //省略get,set方法
   public enum Direction {
      /**
       * 升序
       */
      ASC,
      /**
       * 降序
       */
      DESC
   }
}

(2)PageResult.java:前後端交互處理類(所在包:config.domainr)

package com.ejsino.xxx.config.domain;
 
import net.sf.json.JSONObject;
 
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
/**
 * @description 分頁返回前端對象
 * 分頁功能,接收參數、查詢分頁均無變化
 * 返回分頁對象的時候採用此對象 轉json返回
 * 例如: 返回類型String
 *      PageInfo<Customer> custs = custService.queryUserPage(cust);
 *      PageResult page = new PageResult(custs.getTotal(),custs.getList());
 *      return PageResult.toJSONObject(page);
 * @author YDLiang
 * @date 20171218
 */
public class PageResult {
 
    /**返回狀態*/
    private boolean success = false;
    /**返回消息*/
    private String message;
    /**返回條數*/
    private long total;
    /**返回list對象*/
    private List<?> rows;
    /**返回參數(僅字符串)*/
    private String params;
    /**返回對象(多個)*/
    private Map<String, Object> objects = new HashMap<String, Object>();
 
    public PageResult(){};
 
    public PageResult(long total, List<?> rows) {
        this.success = true;
        this.total = total;
        this.rows = rows;
    }
 
    public PageResult(String params, long total, List<?> rows) {
        this.params = params;
        this.success = true;
        this.total = total;
        this.rows = rows;
    }
 
    public PageResult(long total, List<?> rows, Map<String, Object> objects) {
        this.success = true;
        this.total = total;
        this.rows = rows;
        this.objects = objects;
    }
 
    public PageResult(boolean success, String message, long total, List<?> rows) {
        this.success = success;
        this.message = message;
        this.total = total;
        this.rows = rows;
    }
   
/**
 * @param json
 * @return
 * @description To JSON Object
 */
public static String toJSONObject(PageResult json) {
    return JSONObject.fromObject(json).toString();
}

3.4 druid(數據庫連接池)相關配置

3.4.1 引入jar包依賴

<dependency>
   <groupId>com.zaxxer</groupId>
   <artifactId>HikariCP</artifactId>
</dependency>
 
<dependency>
   <groupId>com.alibaba</groupId>
   <artifactId>druid</artifactId>
   <version>1.1.6</version>
</dependency>

3.4.2 添加druid相關配置
(1)此處的配置放在application-dev.yml中Spring節點下文件中

datasource:                             #配置數據源
    driver-class-name: com.mysql.jdbc.Driver   #數據庫驅動名稱
    url: xxx           #數據庫地址
    username: xxx                     #數據庫名
    password:  xxxx      #數據庫密碼(加密後)
    zeroDateTimeBehavior: convertToNull  #把日期異常轉換爲null代替異常處理
    type: com.alibaba.druid.pool.DruidDataSource #數據源/連接池類型
    initialSize: 2                        #定義初始連接數
    minIdle: 5                       #定義最小空閒 minIdle=1
    maxActive: 20                        #定義最大連接數
    maxWait: 60000                         #定義最長等待時間
    timeBetweenEvictionRunsMillis: 60000#每60秒運行一次空閒連接回收器
    minEvictableIdleTimeMillis: 300000 #池中的連接空閒300秒後被回收
    validationQuery: SELECT 1 FROM DUAL     #驗證使用的SQL語句
    testWhileIdle: true#指明連接是否被空閒連接回收器(如果有)進行檢驗.如果
                              #檢測失敗,則連接將被從池中去除. 
    testOnBorrow: false     #借出連接時不要測試,否則很影響性能
    testOnReturn: false#歸還連接時執行validationQuery檢測連接是否效,
                                 #做了這個配置會降低性能
    poolPreparedStatements: true #是否緩存preparedStatement,也就是
                       #PSCache。PSCache對支持遊標的數據庫性能提升巨     
                          #大,比如說oracle。在mysql下建議關閉。
    maxPoolPreparedStatementPerConnectionSize: 20 #指定每個連接上     
                                              #PSCache的大小
filters: config,stat,log4j  # 配置監控統計攔截的filters,去掉後監控界面sql無法統計
 
    decryptkey: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKkalCG0DLhIMQ75ixjyvXLwx28Th+KxPMG2reDuYSCOWeV8yVQNRhmV7YXTGnrzroGFl4nU5mioZZijKPGPpg8CAwEAAQ==
    # 通過connectProperties屬性來打開mergeSql功能;慢SQL記錄                                        
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000;config.decrypt.key=${spring.datasource.decryptkey};config.decrypt=true
    useGlobalDataSourceStat: true      #合併多個DruidDataSource的監控數據
    druidLoginName: ejsino         # SQL監控後臺登錄用戶名
    druidPassword: xxx      # SQL監控後臺登錄用戶密碼

3.4.3 添加配置實現類
(1)DruidConfig.java

package com.ejsino.xxx.config.druid;
 
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
 
import javax.sql.DataSource;
import java.sql.SQLException;
 
/**
 * @description druid 數據庫連接池配置
 * @author YDLiang
 * @date 20171221
 */
@Configuration
public class DruidConfig {
 
    private Logger log = LoggerFactory.getLogger(DruidConfig.class);
 
    @Value("${spring.datasource.url}")
    private String dbUrl;
    @Value("${spring.datasource.type}")
    private String dbType;
    @Value("${spring.datasource.username}")
    private String username;
    @Value("${spring.datasource.password}")
    private String password;
    @Value("${spring.datasource.driver-class-name}")
    private String driverClassName;
    @Value("${spring.datasource.initialSize}")
    private int initialSize;
    @Value("${spring.datasource.minIdle}")
    private int minIdle;
    @Value("${spring.datasource.maxActive}")
    private int maxActive;
    @Value("${spring.datasource.maxWait}")
    private int maxWait;
    @Value("${spring.datasource.timeBetweenEvictionRunsMillis}")
    private int timeBetweenEvictionRunsMillis;
    @Value("${spring.datasource.minEvictableIdleTimeMillis}")
    private int minEvictableIdleTimeMillis;
    @Value("${spring.datasource.validationQuery}")
    private String validationQuery;
    @Value("${spring.datasource.testWhileIdle}")
    private boolean testWhileIdle;
    @Value("${spring.datasource.testOnBorrow}")
    private boolean testOnBorrow;
    @Value("${spring.datasource.testOnReturn}")
    private boolean testOnReturn;
    @Value("${spring.datasource.poolPreparedStatements}")
    private boolean poolPreparedStatements;
    @Value("${spring.datasource.filters}")
    private String filters;
    @Value("${spring.datasource.connectionProperties}")
    private String connectionProperties;
    @Value("${spring.datasource.useGlobalDataSourceStat}")
    private boolean useGlobalDataSourceStat;
    @Value("${spring.datasource.druidLoginName}")
    private String druidLoginName;
    @Value("${spring.datasource.druidPassword}")
    private String druidPassword;
 
    @Bean(name="dataSource",destroyMethod = "close", initMethod="init")
    @Primary
    public DataSource dataSource(){
        DruidDataSource datasource = new DruidDataSource();
        try {
            datasource.setUrl(this.dbUrl);
            datasource.setDbType(dbType);
            datasource.setUsername(username);
            datasource.setPassword(password);
            datasource.setDriverClassName(driverClassName);
            datasource.setInitialSize(initialSize);
            datasource.setMinIdle(minIdle);
            datasource.setMaxActive(maxActive);
            datasource.setMaxWait(maxWait);
            datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
            datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
            datasource.setValidationQuery(validationQuery);
            datasource.setTestWhileIdle(testWhileIdle);
            datasource.setTestOnBorrow(testOnBorrow);
            datasource.setTestOnReturn(testOnReturn);
            datasource.setPoolPreparedStatements(poolPreparedStatements);
            datasource.setFilters(filters);
            datasource.setConnectionProperties(connectionProperties);
            datasource.setUseGlobalDataSourceStat(useGlobalDataSourceStat);
        } catch (SQLException e) {
            log.error("druid configuration initialization filter", e);
        }
        return datasource;
    }
 
    @Bean
    public ServletRegistrationBean druidServlet() {
        ServletRegistrationBean reg = new ServletRegistrationBean();
        reg.setServlet(new StatViewServlet());
        reg.addUrlMappings("/druid/*");
        // IP白名單(沒有配置或者爲空,則允許所有訪問)
        reg.addInitParameter("allow", "192.168.1.110,127.0.0.1");
        // IP黑名單 (存在共同時,deny優先於allow)
        reg.addInitParameter("deny", "192.168.1.111");
        // 用戶名
        reg.addInitParameter("loginUsername", this.druidLoginName);
        // 密碼
        reg.addInitParameter("loginPassword", this.druidPassword);
        //是否能夠重置數據.
        reg.addInitParameter("resetEnable", "false");
        return reg;
    }
 
/**
 * druid過濾器.
 * @author Administrator
 *
 */
    @Bean(name="druidWebStatFilter")
    public FilterRegistrationBean filterRegistrationBean() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(new WebStatFilter());
         //添加過濾規則.
        filterRegistrationBean.addUrlPatterns("/*");
        ////忽略資源
        filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
        //監控單個url調用的sql列表
        filterRegistrationBean.addInitParameter("profileEnable", "true");
        //使得druid知道當前的user是誰
        filterRegistrationBean.addInitParameter("principalCookieName", "USER_COOKIE");
        //使得druid能夠知道當前的session的用戶是誰filterRegistrationBean.addInitParameter("principalSessionName", "USER_SESSION");
        return filterRegistrationBean;
    }
}

3.5 log(日誌管理)相關配置

3.5.1 引入jar包依賴

<dependency>
   <groupId>commons-logging</groupId>
   <artifactId>commons-logging</artifactId>
   <version>1.1.1</version>
</dependency>
 
<dependency>
   <groupId>org.slf4j</groupId>
   <artifactId>slf4j-api</artifactId>
</dependency>

3.5.2 添加日誌相關配置
(1) 在application-dev.yml文件中添加相關配置(一級節點)

logging:                    #日誌相關配置
  config: classpath:config/logback-config.xml  #加載日誌相關配置文件
  path: /ejdata/comment-log/               #日誌存儲路徑
  level: ERROR     #接收日誌等級,從低到高:trace(追蹤),                            #debug(),info(自定義)warn(提示)error(錯誤)
  match: ACCEPT #ACCEPT/DENY   #日誌級別篩選策略,此除ACCEPT表示匹配到                                #更高級別異常允許輸出
  mismatch: DENY  #日誌級別篩選策略,此處ACCEPT表示沒有匹配到更高級別異常                     #不允許輸出

(2)配置logback-config.xml(所在包:resources/config)

<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="true">
   <contextName>ej_claim</contextName>
 
   <!-- 配置本機log地址,勿用相對路徑 -->
   <springProperty scope="context" name="LOG_HOME" source="logging.path"/>
   <springProperty scope="context" name="LOG_LEVEL" source="logging.level"/>
   <springProperty scope="context" name="LOG_ONMATCH" source="logging.match"/>
   <springProperty scope="context" name="LOG_ONMISMATCH" source="logging.mismatch"/>
   <!-- 彩色日誌依賴的渲染類 -->
   <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
   <conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
   <conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
   <!-- 彩色日誌格式 -->
   <property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(-){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}" />
 
   <!-- 控制檯輸出 -->
   <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
      <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
         <pattern>${CONSOLE_LOG_PATTERN}</pattern>
         <charset>utf8</charset>
      </encoder>
   </appender>
 
   <!-- 按照每天生成日誌文件 -->
   <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
      <filter class="ch.qos.logback.classic.filter.LevelFilter">
         <level>${LOG_LEVEL}</level>
         <onMatch>${LOG_ONMATCH}</onMatch>
         <onMismatch>${LOG_ONMISMATCH}</onMismatch>
      </filter>
      <Prudent>true</Prudent>
      <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
         <FileNamePattern>${LOG_HOME}/claim-%d{yyyy-MM-dd}.log</FileNamePattern>
         <MaxHistory>30</MaxHistory>
      </rollingPolicy>
      <layout class="ch.qos.logback.classic.PatternLayout">
         <Pattern>%d{yyyy-MM-dd HH:mm:ss} -%msg%n</Pattern>
      </layout>
      <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
         <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
   </appender>
 
   <!--<logger name="org.apache.ibatis" level="DEBUG" />
   <logger name="java.sql.Connection" level="DEBUG"/>
   <logger name="java.sql.Statement" level="DEBUG"/>
   <logger name="java.sql.PreparedStatement" level="DEBUG"/>-->
 
   <logger name="freemarker" level="INFO" />
   <logger name="org.springframework" level="INFO" />
 
   <logger name="com.alibaba.druid.filter.stat.StatFilter" level="OFF" />
 
   <!-- log輸出等級 -->
   <root level="${LOG_LEVEL}">
      <appender-ref ref="CONSOLE" />
      <appender-ref ref="FILE" />
   </root>
</configuration>

3.6 http相關配置

3.6.1 引入相關jar包依賴

<dependency>
   <groupId>org.apache.httpcomponents</groupId>
   <artifactId>httpclient</artifactId>
</dependency>
<dependency>
   <groupId>commons-httpclient</groupId>
   <artifactId>commons-httpclient</artifactId>
   <version>3.1</version>
</dependency>

3.6.2 添加http相關配置
(1) 在application-dev.yml文件中添加相關配置(一級節點)

http:
  maxTotal: 100          #http連接池大小
  defaultMaxPerRoute: 20   #單機連接最大併發數
  connectTimeout: 1000     #鏈接建立的超時時間(單位:毫秒)
  connectionRequestTimeout: 500#http clilent中從connetcion pool中                                  #獲得一個connection的超時時間
  socketTimeout: 10000         #響應超時時間,超過此時間不再讀取響應
  staleConnectionCheckEnabled: true        #提交測試連接是否可用

3.6.3 配置實現類(所在包:config.httpclient)
(1)HttpClientConfig.java(讀取和處理http相關配置並進行處理)

package com.ejsino.xxx.config.httpclient;

import org.apache.http.client.config.RequestConfig;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author Paulo.Yuan
 * @version V1.0
 * @Title:
 * @Package
 * @Description: HttpClient Config
 * @date 20171206
 */
@Configuration
public class HttpClientConfig {

    @Value("${http.maxTotal}")
    private Integer maxTotal;

    @Value("${http.defaultMaxPerRoute}")
    private Integer defaultMaxPerRoute;

    @Value("${http.connectTimeout}")
    private Integer connectTimeout;

    @Value("${http.connectionRequestTimeout}")
    private Integer connectionRequestTimeout;

    @Value("${http.socketTimeout}")
    private Integer socketTimeout;

    @Value("${http.staleConnectionCheckEnabled}")
    private boolean staleConnectionCheckEnabled;


    /**
      * @description 實例化一個連接池管理器,設置最大連接數、併發連接數
      * @return
     */
    @Bean(name = "httpClientConnectionManager")
    public PoolingHttpClientConnectionManager getHttpClientConnectionManager() {
        PoolingHttpClientConnectionManager pool = new PoolingHttpClientConnectionManager();
        pool.setMaxTotal(maxTotal);
        pool.setDefaultMaxPerRoute(defaultMaxPerRoute);
        return pool;
    }

    /**
     * @description 實例化構造器,設置連接池管理器
     * @param httpClientConnectionManager
     * @return
     */
    @Bean(name = "httpClientBuilder")
    public HttpClientBuilder getHttpClientBuilder(@Qualifier("httpClientConnectionManager") PoolingHttpClientConnectionManager httpClientConnectionManager) {
        //HttpClientBuilder中的構造方法被protected修飾,所以這裏不能直接使用new來實例化一個HttpClientBuilder,
        // 可以使用HttpClientBuilder提供的靜態方法create()來獲取HttpClientBuilder對象
        HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
        httpClientBuilder.setConnectionManager(httpClientConnectionManager);
        return httpClientBuilder;
    }

    /**
     * @description 獲取httpClient實例
     * @param httpClientBuilder
     * @return
     */
    @Bean
    public CloseableHttpClient getCloseableHttpClient(@Qualifier("httpClientBuilder") HttpClientBuilder httpClientBuilder) {
        return httpClientBuilder.build();
    }

    /**
     * @description 設置RequestConfig
     *  Builder是RequestConfig的一個內部類
     *  通過RequestConfig的custom方法來獲取到一個Builder對象
     *  設置builder的連接信息
     *  這裏還可以設置proxy,cookieSpec等屬性。有需要的話可以在此設置
     * @return
     */
    @Bean(name = "builder")
    public RequestConfig.Builder getBuilder() {
        RequestConfig.Builder builder = RequestConfig.custom();
        return builder.setConnectTimeout(connectTimeout)
                .setSocketTimeout(socketTimeout)
                .setConnectionRequestTimeout(connectionRequestTimeout)
                .setStaleConnectionCheckEnabled(staleConnectionCheckEnabled);
    }

    /**
     * @description 構建一個RequestConfig實例
     * @param builder
     * @return
     */
    @Bean
    public RequestConfig getRequestConfig(@Qualifier("builder") RequestConfig.Builder builder) {
        return builder.build();
    }

}

(2)HttpService.java(封裝對http不同類型的請求的處理過程)

package com.ejsino.xxx.config.httpclient;

import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Component
public class HttpService {

    @Autowired
    private CloseableHttpClient httpClient;
    @Autowired
    private RequestConfig config;

    /**
     * @description 不帶參數的get請求,如果狀態碼爲200,則返回body,如果不爲200,則返回null
     * @param url
     * @return
     * @throws Exception
     */
    public String doGet(String url) throws Exception {
        HttpGet httpGet = new HttpGet(url);
        httpGet.setConfig(config);
        CloseableHttpResponse response = this.httpClient.execute(httpGet);
        if (response.getStatusLine().getStatusCode() == 200) {
            return EntityUtils.toString(response.getEntity(), "UTF-8");
        }
        return null;
    }

    /**
     * @description 帶參數的get請求,如果狀態碼爲200,則返回body,如果不爲200,則返回null
     * @param url
     * @return
     * @throws Exception
     */
    public String doGet(String url, Map<String, Object> map) throws Exception {
        URIBuilder uriBuilder = new URIBuilder(url);
        if (map != null) {
            // 遍歷map,拼接請求參數
            for (Map.Entry<String, Object> entry : map.entrySet()) {
                uriBuilder.setParameter(entry.getKey(), entry.getValue().toString());
            }
        }
        return this.doGet(uriBuilder.build().toString());

    }

    /**
     * @description 帶參數的post請求
     * @param url
     * @param map
     * @return
     * @throws Exception
     */
    public HttpResult doPost(String url, Map<String, Object> map) throws Exception {
        HttpPost httpPost = new HttpPost(url);
        httpPost.setConfig(config);
        // 判斷map是否爲空,不爲空則進行遍歷,封裝from表單對象
        if (map != null) {
            List<NameValuePair> list = new ArrayList<NameValuePair>();
            for (Map.Entry<String, Object> entry : map.entrySet()) {
                list.add(new BasicNameValuePair(entry.getKey(), entry.getValue().toString()));
            }
            UrlEncodedFormEntity urlEncodedFormEntity = new UrlEncodedFormEntity(list, "UTF-8");
            httpPost.setEntity(urlEncodedFormEntity);
        }
        CloseableHttpResponse response = this.httpClient.execute(httpPost);
        return new HttpResult(response.getStatusLine().getStatusCode(), EntityUtils.toString(
                response.getEntity(), "UTF-8"));
    }

    /**
     * @description 不帶參數post請求
     * @param url
     * @return
     * @throws Exception
     */
    public HttpResult doPost(String url) throws Exception {
        return this.doPost(url, null);
    }
}

(3)HttpResult.java(封裝對http不同類型的請求的處理過程)

package com.ejsino.xxx.config.httpclient;

/**
 * @author charles
 * @version V1.0
 * @Title:
 * @Package
 * @Description: HttpResult
 * @date 20180328
 */
public class HttpResult {

    /**響應碼*/
    private Integer code;

    /**響應體*/
    private String body;

    public HttpResult() {
        super();
    }

    public HttpResult(Integer code, String body) {
        super();
        this.code = code;
        this.body = body;
    }

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public String getBody() {
        return body;
    }

    public void setBody(String body) {
        this.body = body;
    }
}

3.7 OSS相關配置

3.7.1 引入相關jar包

<dependency>
   <groupId>com.aliyun.openservices</groupId>
   <artifactId>aliyun-openservices</artifactId>
   <version>1.0.12</version>
</dependency>
<dependency>
   <groupId>commons-fileupload</groupId>
   <artifactId>commons-fileupload</artifactId>
   <version>1.3</version>
</dependency>

3.7.2 添加OSS相關配置
(1) 在application-dev.yml文件中添加相關配置(一級節點)

http:
  maxTotal: 100
  defaultMaxPerRoute: 20
  connectTimeout: 1000
  connectionRequestTimeout: 500
  socketTimeout: 10000
  staleConnectionCheckEnabled: true

3.7.3 配置實現類(所在包:config.aliyunoss)
(1) 在application-dev.yml文件中添加相關配置(一級節點)

http:
  maxTotal: 100
  defaultMaxPerRoute: 20
  connectTimeout: 1000
  connectionRequestTimeout: 500
  socketTimeout: 10000
  staleConnectionCheckEnabled: true

3.7.3 配置實現類(所在包:config.aliyunoss)
(1)FileInfoBean.java(項目中涉及的文件上傳下載)
定義一些文件上傳下載操作需要的字段/*文件流/

package com.ejsino.XXX.config.aliyunoss;

import java.io.File;

/***
 * @description 上傳阿里雲對象
 * @date 20171220
 * @version V1.0
 */
public class FileInfoBean {

    /**文件流*/
    private byte[] fileInfo;
    /**文件名*/
    private String fileName;
    /**文件類型*/
    private String fileType;
    /**壓縮後綴*/
    private String compresssuffix;
    /**是否需要壓縮*/
    private String needcompress;
    /**文件唯一編號*/
    private String fileno;
    /**文件路徑*/
    private String filePath;


    public String getFileno() {
        return fileno;
    }
    public void setFileno(String fileno) {
        this.fileno = fileno;
    }
    public String getNeedcompress() {
        return needcompress;
    }
    public void setNeedcompress(String needcompress) {
        this.needcompress = needcompress;
    }
    public byte[] getFileInfo() {
        return fileInfo;
    }
    public void setFileInfo(byte[] fileInfo) {
        this.fileInfo = fileInfo;
    }
    public String getFileName() {
        return fileName;
    }
    public void setFileName(String fileName) {
        this.fileName = fileName;
    }
    public String getFileType() {
        return fileType;
    }
    public void setFileType(String fileType) {
        this.fileType = fileType;
    }
    public void deleteOwnerFile() {
        File f = new File(this.fileName);
        f.delete();
    }
    public String getCompresssuffix() {
        return compresssuffix;
    }
    public void setCompresssuffix(String compresssuffix) {
        this.compresssuffix = compresssuffix;
    }
    public String getFilePath() {
        return filePath;
    }
    public void setFilePath(String filePath) {
        this.filePath = filePath;
    }
}

(2)OssConst.java(放一些跟文件有關的常量,自願配置)

package com.ejsino.xxx.config.aliyunoss;

public enum OssConst {
    //oss-測試機
    OSS_DOMAIN_ADDRESS("oss-domainAddress","http://testimage.ejsino.net/"),
    OSS_BUCKET_NAME("oss-bucketName","ejsino-test"),
    OSS_PROD_FILEPATH("oss-prodFilePath","prodfile/"),
    OSS_TEMP_FILEPATH("oss-tempFilePath","D:/project/");

    private String name ;
    private String value ;

    private OssConst( String name , String value){
        this.name = name ;
        this.value = value ;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }
}

(3)OssProperties.java

package com.ejsino.ejcomment.config.aliyunoss;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

/**
 * @author charles
 * @version V1.0
 * @Title:
 * @Package
 * @Description: oss 配置信息
 * @date 20171211
 */
@Component
@ConfigurationProperties(prefix = "oss")
public class OssProperties {

    private String image_storage_dir;
    private String oss_server;
    private String file_storage_dir;
    private String tempFilePath;
    private String bucketName;
    private String accessKeyId;
    private String accessKeySecret;
    private String endPoint;
    private String productClauseFilePath;
    private String prodFilePath;
    private String accountLogoFilePath;
    private String productModal;
    private String aigPrintModal;
    private String pinganPrintModal;
    private String commonPrintModal;
    private String docPrintModal;
    private String domainAddress;
    private String apicarfile;
    //private String 5fservicecert;
    private String bohai;
    private String appointcard;
    private String meinian;
    private String signature;
    private String mobilecust;

    public String getImage_storage_dir() {
        return image_storage_dir;
    }

    public void setImage_storage_dir(String image_storage_dir) {
        this.image_storage_dir = image_storage_dir;
    }

    public String getOss_server() {
        return oss_server;
    }

    public void setOss_server(String oss_server) {
        this.oss_server = oss_server;
    }

    public String getFile_storage_dir() {
        return file_storage_dir;
    }

    public void setFile_storage_dir(String file_storage_dir) {
        this.file_storage_dir = file_storage_dir;
    }

    public String getTempFilePath() {
        return tempFilePath;
    }

    public void setTempFilePath(String tempFilePath) {
        this.tempFilePath = tempFilePath;
    }

    public String getBucketName() {
        return bucketName;
    }

    public void setBucketName(String bucketName) {
        this.bucketName = bucketName;
    }

    public String getAccessKeyId() {
        return accessKeyId;
    }

    public void setAccessKeyId(String accessKeyId) {
        this.accessKeyId = accessKeyId;
    }

    public String getAccessKeySecret() {
        return accessKeySecret;
    }

    public void setAccessKeySecret(String accessKeySecret) {
        this.accessKeySecret = accessKeySecret;
    }

    public String getEndPoint() {
        return endPoint;
    }

    public void setEndPoint(String endPoint) {
        this.endPoint = endPoint;
    }

    public String getProductClauseFilePath() {
        return productClauseFilePath;
    }

    public void setProductClauseFilePath(String productClauseFilePath) {
        this.productClauseFilePath = productClauseFilePath;
    }

    public String getProdFilePath() {
        return prodFilePath;
    }

    public void setProdFilePath(String prodFilePath) {
        this.prodFilePath = prodFilePath;
    }

    public String getAccountLogoFilePath() {
        return accountLogoFilePath;
    }

    public void setAccountLogoFilePath(String accountLogoFilePath) {
        this.accountLogoFilePath = accountLogoFilePath;
    }

    public String getProductModal() {
        return productModal;
    }

    public void setProductModal(String productModal) {
        this.productModal = productModal;
    }

    public String getAigPrintModal() {
        return aigPrintModal;
    }

    public void setAigPrintModal(String aigPrintModal) {
        this.aigPrintModal = aigPrintModal;
    }

    public String getPinganPrintModal() {
        return pinganPrintModal;
    }

    public void setPinganPrintModal(String pinganPrintModal) {
        this.pinganPrintModal = pinganPrintModal;
    }

    public String getCommonPrintModal() {
        return commonPrintModal;
    }

    public void setCommonPrintModal(String commonPrintModal) {
        this.commonPrintModal = commonPrintModal;
    }

    public String getDocPrintModal() {
        return docPrintModal;
    }

    public void setDocPrintModal(String docPrintModal) {
        this.docPrintModal = docPrintModal;
    }

    public String getDomainAddress() {
        return domainAddress;
    }

    public void setDomainAddress(String domainAddress) {
        this.domainAddress = domainAddress;
    }

    public String getApicarfile() {
        return apicarfile;
    }

    public void setApicarfile(String apicarfile) {
        this.apicarfile = apicarfile;
    }

    public String getBohai() {
        return bohai;
    }

    public void setBohai(String bohai) {
        this.bohai = bohai;
    }

    public String getAppointcard() {
        return appointcard;
    }

    public void setAppointcard(String appointcard) {
        this.appointcard = appointcard;
    }

    public String getMeinian() {
        return meinian;
    }

    public void setMeinian(String meinian) {
        this.meinian = meinian;
    }

    public String getSignature() {
        return signature;
    }

    public void setSignature(String signature) {
        this.signature = signature;
    }

    public String getMobilecust() {
        return mobilecust;
    }

    public void setMobilecust(String mobilecust) {
        this.mobilecust = mobilecust;
    }
}

3.8 freemarker相關配置

3.8.1 引入相關jar包

<!-- freemarker depend -->
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>

3.8.2 添加freemarker相關配置
(1) 在application-dev.yml文件中添加相關配置(二級節點,在Spring節點下配置)

 freemarker:              #freemarker相關配置
    enabled: true                   #是否允許mvc使用freemarker.
    cache: false                    #是否開啓template caching.
    charset: UTF-8
    content-type: text/html
    template-loader-path: classpath:/templates/      #模板路徑
    suffix: .html                         #前端文件後綴
    request-context-attribute: request    #指定RequestContext屬性的名
    expose-session-attributes: true    #是否在merge模板的時候,將
                                      #HttpSession屬性都添加到model中
    expose-request-attributes: true #設定所有request的屬性在merge到模板的時
                                      #候,是否要都添加到model中.
    expose-spring-macro-helpers: true #是否以springMacroRequestContext的
                       #形式暴露RequestContext給Spring’s macrolibrary使用
    allow-request-override: true  #指定HttpServletRequest的屬性是否可以覆
                                         #蓋controller的model的同名項
    allow-session-override: true  #指定HttpSession的屬性是否可以覆蓋
                                  #controller的model的同名項
    settings:          #設置幾種時間類型的轉化
      date_format: yyyy-MM-dd
      time_format: HH:mm:ss
      datetime_format: yyyy-MM-dd HH:mm:ss

4 框架開發配置模塊

4.1 攔截器相關配置(所在包:config.intercepter)

用途:對前端發送的請求進行攔截和驗證
(1) UserSessionInterceptor.java(結合shiro中的3.1.3Authentication.java類)

package com.ejsino.xxx.config.intercepter;
import com.ejsino.xxx.config.application.SpringBeanFactory;
import com.ejsino.xxx.entity.user.CustInfo;
import com.ejsino.xxx.config.shiro.Authentication;
import com.ejsino.xxx.service.user.CustInfoService;
import com.ejsino.xxx.service.user.impl.CustInfoServiceImpl;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
public class UserSessionInterceptor extends HandlerInterceptorAdapter {
   @Override
   public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
         throws Exception {
      setUserProfile();
      if (!(handler instanceof HandlerMethod)) {
         return super.preHandle(request, response, handler);
      }
      return true;
   }
//獲取用戶session信息
   public void setUserProfile() {
      Subject subject = SecurityUtils.getSubject();
      Session session = subject.getSession();
      CustInfo info = (CustInfo)
      if (null == info) {
         String username = (String) subject.getPrincipal();
         if (null == username) {
            return;
         }
         //CustInfoServiceImpl自己定義的獲取用戶信息方法
         CustInfoService custInfoService = SpringBeanFactory.getBean(CustInfoServiceImpl.class);
         info = custInfoService.queryCustInfo(username);
         //Authentication是shiro包中的配置類
         session.setAttribute(Authentication.USER_SESSION_NAME, info);
         session.setAttribute(Authentication.USER_ID_SESSION_NAME, info.getCustNo());
      }
   }
}

4.2 監聽器相關配置(所在包:config.listener)

用途:對整個服務流程進行監聽
(1)ApplicationEventListener.java

package com.ejsino.xxx.config.listener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.boot.context.event.ApplicationPreparedEvent;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.ContextStartedEvent;
import org.springframework.context.event.ContextStoppedEvent;
import org.springframework.stereotype.Component;
 
@Component
public class ApplicationEventListener implements ApplicationListener<ApplicationEvent> {
    private Logger log = LoggerFactory.getLogger(getClass());
 
    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        // 監聽SpringBoot生命週期
        if (event instanceof ApplicationEnvironmentPreparedEvent) {
            log.debug("初始化環境變量");
        } else if (event instanceof ApplicationPreparedEvent) {
            log.info("初始化環境變量完成");
        } else if (event instanceof ContextRefreshedEvent) {
            log.debug("應用刷新");
        } else if (event instanceof ApplicationReadyEvent) {
            log.info("應用已啓動完成");
        } else if (event instanceof ContextStartedEvent) {
            log.debug("應用啓動");
        } else if (event instanceof ContextStoppedEvent) {
            log.debug("應用停止");
        } else if (event instanceof ContextClosedEvent) {
            log.debug("應用關閉");
        } else {
        }
    }
}

4.3 過濾器相關配置(所在包:config.filter)

用途:結合Shiro對請求的合理性進行過濾(是否超時,即session是否失效)
(1)ShiroLoginFilter.java

//避免Ajax超時的情況下向前端返回登錄頁面的內容,普通請求超時,返回登錄頁面是跳轉登陸

package com.ejsino.xxx.config.filter;

import com.ejsino.ejcomment.config.domain.JSONResult;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * @author charles
 * @description shiro AdviceFilter
 * @date 20180329
 */
public class ShiroLoginFilter extends FormAuthenticationFilter {

    private static Logger log = LoggerFactory.getLogger(ShiroLoginFilter.class);

    @Override
    protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        if (isLoginRequest(servletRequest, servletResponse)) {
            if (isLoginSubmission(servletRequest, servletResponse)) {
                if (log.isTraceEnabled()) {
                    log.trace("Login submission detected.  Attempting to execute login.");
                }
                return executeLogin(servletRequest, servletResponse);
            } else {
                if (log.isTraceEnabled()) {
                    log.trace("Login page view.");
                }
                return true;
            }
        } else {
            if (log.isTraceEnabled()) {
                log.trace("Attempting to access a path which requires authentication.  Forwarding to the " +
                        "Authentication url [" + getLoginUrl() + "]");
            }
            String requestedWith = request.getHeader("x-requested-with");
            String requestedAcpt = request.getHeader("accept");
            if (StringUtils.isNotEmpty(requestedWith) && StringUtils.equals(requestedWith, "XMLHttpRequest")) {
                ((HttpServletResponse) servletResponse).setStatus(402);
                returnJson(response, JSONResult.toJSONObject(JSONResult.error("timeout", "未登錄或已超時,請重新登錄!")).toString());
            } else if (StringUtils.isNotEmpty(requestedAcpt) && StringUtils.equals(requestedAcpt, "*/*")) {
                ((HttpServletResponse) servletResponse).setStatus(402);
                returnJson(response, JSONResult.toJSONObject(JSONResult.error("timeout", "未登錄或已超時,請重新登錄!")).toString());
            } else {
                saveRequestAndRedirectToLogin(servletRequest, servletResponse);
            }
            return false;
        }
    }

    private void returnJson(HttpServletResponse response, String json) throws Exception {
        PrintWriter writer = null;
        response.setCharacterEncoding("UTF-8");
        response.setContentType("text/html; charset=utf-8");
        try {
            writer = response.getWriter();
            writer.print(json);
        } catch (IOException e) {
            log.error("response error", e);
        } finally {
            if (writer != null) {
                writer.close();
            }
        }
    }
}

4.4 異常處理相關配置(所在包:config.exception)

用途:對一些常見異常的封裝和處理
(1)DaoException.java(數據庫層異常)

package com.ejsino.ejcomment.config.exception;

/**
 * @description DaoException
 * @author charles
 * @date 20171102
 */
public class DaoException extends Exception {

   /*** serial id */
   private static final long serialVersionUID = 1L;
   
   /**
    * 
    * 空構造
    */
   public DaoException() {
      super("Dao 異常");
   }
   
   /**
    * 
    * 自定義錯誤日誌
    * 
    * @param e
    */
   public DaoException(String e) {
      super(e);
   }

   /**
    * 只拋錯誤信息
    * 
    * @param e
    */
   public DaoException(Throwable e) {
      super(e);
   }

   /**
    * 兩者皆拋
    * 
    * @param er
    * @param e
    */
   public DaoException(String er, Throwable e) {
      super(er, e);
   }
}

(2)EhomeException.java(全局的異常處理)

package com.ejsino.xxx.config.exception;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;

/**
 * @description EhomeException
 * @author charles
 * @date 20171102
 */
public class EhomeException extends Exception {

   private static final long serialVersionUID = 1L;
   
   private int exceptionCode = 0;
   private String errorCode="";
    private String errorMessage="";

    public EhomeException(String errMsg) {
        super(errMsg);
    }
    public EhomeException(Throwable cause) {
        super(cause);
    }

    public EhomeException(String errMsg, int exceptionCode) {
        super(errMsg);
        this.exceptionCode = exceptionCode;
    }
    public int getExceptionCode() {
        return this.exceptionCode;
    }

    public void setExceptionCode(int exceptionCode) {
      this.exceptionCode = exceptionCode;
   }

    public String getErrorCode() {
      return errorCode;
   }
   public void setErrorCode(String errorCode) {
      this.errorCode = errorCode;
   }
   public String getErrorMessage() {
      return errorMessage;
   }
   public void setErrorMessage(String errorMessage) {
      this.errorMessage = errorMessage;
   }
   public String getDetailMessage() {
        ByteArrayOutputStream ostr = new ByteArrayOutputStream();
        super.printStackTrace(new PrintStream(ostr));
        try {
           ostr.flush();
           ostr.close();
           return ostr.toString();
        } catch (IOException ex) {
            return super.getMessage();
        }
    }
}

(3)GlobalExceptionHandler.java(全局的異常處理)

@ExceptionHandler(value = Exception.class )
@ResponseStatus(HttpStatus.UNAUTHORIZED)
public ModelAndView processUnauthenticatedException(HttpServletRequest request, Exception  e) throws Exception {
    ModelAndView modelAndView = new ModelAndView();
    modelAndView.addObject("exception", e);
    modelAndView.addObject("url", request.getRequestURL());
    modelAndView.setViewName("error");
    log.error("got exception: {}", e.getClass() + ":" + e.getMessage());
    return modelAndView;
}

(4)TransactionRuntimeException.java(事務回滾異常處理)

private static final long serialVersionUID = 1L;
 
public TransactionRuntimeException(String msg) {
   super(msg);
}
 
public TransactionRuntimeException(String msg, Throwable cause) {
   super(msg, cause);
}

4.5 Spring相關配置(所在包:config.application)

(1)AppConfigurer.java(Spring事物線程池等相關配置)

package com.ejsino.xxx.config.application;

import com.ejsino.ejcomment.config.intercepter.UserSessionInterceptor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

import javax.sql.DataSource;

/**
 * @author charles
 * @version V1.0
 * @Title:
 * @Package
 * @Description: application configuration
 * @date 20171117
 */
@Configuration
public class AppConfigurer extends WebMvcConfigurerAdapter {

    @Value("${sysParam.encryptKey}")
    public String secretKey;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        /**攔截用戶的session*/
        registry.addInterceptor(new UserSessionInterceptor())
                .addPathPatterns("/*")
                .addPathPatterns("/**.html")
                .addPathPatterns("/**/**.html");
        /**攔截器配置菜單*/
    }

    @Bean(name = "transactionManager")
    public PlatformTransactionManager getTransactionManager(DataSource dataSource) {
        PlatformTransactionManager transactionManager = new DataSourceTransactionManager(dataSource);
        return transactionManager;
    }

    @Bean(name = "transactionTemplate")
    public TransactionTemplate getTransactionTemplate(PlatformTransactionManager transactionManager) {
        TransactionTemplate transactionTemplate = new TransactionTemplate();
        transactionTemplate.setTransactionManager(transactionManager);
        return transactionTemplate;
    }

    @Bean(name = "taskExecutor")
    public ThreadPoolTaskExecutor getTaskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5);
        executor.setMaxPoolSize(15);
        executor.setQueueCapacity(35);
        return executor;
    }

    @Bean(name = "taskScheduler")
    public ThreadPoolTaskScheduler taskScheduler() {
        ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
        scheduler.setPoolSize(20);
        scheduler.setThreadNamePrefix("task-");
        scheduler.setAwaitTerminationSeconds(60);
        scheduler.setWaitForTasksToCompleteOnShutdown(true);
        return scheduler;
    }

    @Bean(name = "uploadPoolExecutor")
    public ThreadPoolTaskExecutor getUploadPoolExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(15);
        executor.setMaxPoolSize(50);
        executor.setQueueCapacity(200);
        return executor;
    }
}

(2)SpringBean.java(SpringBean工廠)

package com.ejsino.xxx.config.application;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import java.beans.Introspector;
@Component
public class SpringBeanFactory implements ApplicationContextAware {

   private static ApplicationContext context;

   public SpringBeanFactory() {
   }

   @Override
   public void setApplicationContext(ApplicationContext context) throws BeansException {
      SpringBeanFactory.context = context;
   }

   @SuppressWarnings("unchecked")
   public static <T> T getBean(String name, Class<T> clazz) {
      return (T) getBean(name);
   }

   public static <T> T getBean(Class<T> clazz) {
      return getBean(Introspector.decapitalize(clazz.getSimpleName()), clazz);
   }

   public static Object getBean(String name) {
      return context.getBean(name);
   }
}

4.6 IndexController.java(所在包:controller,必配

=集合shiro框架做登陸成功後的跳轉。

package com.ejsino.xxx.controller;
 
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
 
/**
 * @author Paulo.Yuan
 * @version V1.0
 * @Title:
 * @Package
 * @Description: index controller
 * @date 20171103
 */
@Controller
public class IndexController {
 
    @RequestMapping("/")
    private String mainpage(){
        return "index";
    }
 
    @RequestMapping("/index.html")
    private String toMainpage(){
        return "index";
    }
}

5 常用常量類說明

5.1 JSONResult.java(所在包:config.domain)

import java.util.HashMap;
import java.util.Map;
import net.sf.json.JSONObject;
/**
 * @Description: 返回前端json對象
 * 前端同步、異步請求後端數據,返回前端JSONResult對象
 * 返回類型JSONResult或者String(使用自帶方法將對象手動轉String)類型
 *        返回字符串,裝入params,設置狀態true,返回消息,和param
 *        返回單個對象,裝入obj
 *       List<Role> roleList = roleService.queryAllRole(role);
 *       return JSONResult.success("success", roleList);
 *        返回多個對象,裝入objects
 *           Map<String, Object> objects = new HashMap<>();
 *       List<Role> roleList = roleService.queryAllRole(role);
 *       List<Company> companyList =                                          *        companyService.queryCompanyList(company);
 *       objects.put("roleList", roleList);
 *       objects.put("companyList", companyList);
 *       return JSONResult.success("success", objects);
 *        返回失敗,必須置入失敗消息
 *           return JSONResult.error("錯誤信息");
 * @author Paulo.Yuan
 * @version V1.0
 * @date 20171109
 */
public class JSONResult {
 
   /**返回狀態*/
   private boolean success = false;
   /**返回消息*/
   private String message;
   /**返回參數(近字符串)*/
   private String params;
   /**返回對象(單個)*/
   private Object obj;
   /**返回對象(多個)*/
   private Map<String, Object> objects = new HashMap<String, Object>();
 
   public JSONResult() {
   }
 
   public JSONResult(boolean success, String message) {
      this.success = success;
      this.message = message;
   }
 
   public JSONResult(boolean success, Object obj, String message) {
      this(success, message);
      this.obj = obj;
   }
 
   public JSONResult(boolean success, String params, String message) {
      this(success, message);
      this.params = params;
   }
 
   public static JSONResult success(String message) {
      return new JSONResult(true, message);
   }
 
   public static JSONResult success(String message, Object object) {
      return new JSONResult(true, object, message);
   }
 
   public static JSONResult success(String message, Object... object) {
      return new JSONResult(true, object, message);
   }
 
   public static JSONResult error(String message) {
      return new JSONResult(false, message);
   }
 
   public static JSONResult error(String params, String message) {
      return new JSONResult(false, params, message);
   }
 
   public static JSONResult error(String message, Object object) {
      return new JSONResult(false, object, message);
   }
/**
      * @description To JSON Object
      * @param json
   * @return
   */
   public static JSONObject toJSONObject(JSONResult json) {
	return JSONObject.fromObject(json);
   }
}

需要導入jar包

<dependency>
	<groupId>net.sf.json-lib</groupId>
	<artifactId>json-lib</artifactId>
	<version>2.4</version>
	<classifier>jdk15</classifier><!--指定jdk版本-->
</dependency>

5.2 Result.java(所在包:config.domain)

package com.ejsino.xxx.config.domain;
 
import java.io.Serializable;
import java.util.Map;
 
/**
 * @description 返回結果
 * @author charles
 * @date 20171101
 */
public interface Result extends Serializable {
 
String SUCCESS = "success";
 
/**
 * 請求是否成功。
 *
 * @return 如果成功,則返回<code>true</code>
 */
boolean isSuccess();
 
/**
 * 設置請求成功標誌。
 *
 * @param success
 *   成功標誌
 */
void setSuccess(boolean success);
 
/**
 * 獲取返回碼
 *
 * @return 返回碼
 */
String getResultCode();
 
/**
 * 設置返回碼
 *
 * @param code
 */
void setResultCode(String code);
 
/**
 * 取得model對象
 *
 * @param key
 *            字符串key
 * @return model對象
 */
Object getModel(String key);
 
/**
 * 設置model對象。
 *
 * @param key
 *            字符串key
 * @param model
 *            model對象
 */
void setModel(String key, Object model);
 
/**
 * 設置model對象。
 *
 * @param key
 *            字符串key
 * @param model
 *            model對象
 */
void setModel(Class<?> clazz, Object model);
 
/**
 * 取得所有model對象。
 *
 * @return model對象表
 */
Map<String, Object> getModels();
 
/**
 * <p>
 * 獲取特定類型的 model 對象
 * </p>
 *
 * @param <T>
 * @param key
 *            字符串 key
 * @param clazz
 *            數據類型
 * @return
 */
<T> T getModel(String key, Class<T> clazz);
 
<T> T getModel(Class<T> clazz);
}

5.3 ResultSupport.java(對Result的實現)

(所在包:config.domain)

package com.ejsino.claim.config.domain;

import java.util.HashMap;
import java.util.Map;

/**
 * @author YDLiang
 * @date 20171102
 */
public class ResultSupport implements Result, java.io.Serializable {

	private static final long serialVersionUID = -5427837161273573297L;

	private boolean success = false;
	private String resultCode;
	private Map<String, Object> models = new HashMap<String, Object>(4);

	public ResultSupport() {
	}

	public ResultSupport(boolean success) {
		this.success = success;
	}

	public Object getModel(String key) {
		return getModels().get(key);
	}

	public Map<String, Object> getModels() {
		return models;
	}

	public String getResultCode() {
		return resultCode;
	}

	public boolean isSuccess() {
		return success;
	}

	public void setModel(String key, Object model) {
		getModels().put(key, model);
	}

	public void setModel(Class<?> clazz, Object model) {
		getModels().put(clazz.getSimpleName(), model);
	}

	public void setResultCode(String resultCode) {
		this.resultCode = resultCode;
	}

	public void setSuccess(boolean success) {
		this.success = success;
	}

	public void setModels(Map<String, Object> models) {
		this.models = models;
	}

	@SuppressWarnings("unchecked")
	@Override
	public <T> T getModel(String key, Class<T> clazz) {
		return (T) getModel(key);
	}

	@SuppressWarnings("unchecked")
	@Override
	public <T> T getModel(Class<T> clazz) {
		return (T) getModel(clazz.getSimpleName());
	}

}

5.4 Myconst.java(系統中一些常用的靜態常量)

public enum MyConst {
 
    DOM_NODE_TYPE_STRING("數據庫讀取數據方式", "string"),
    DOM_NODE_TYPE_DATE("數據庫讀取數據方式", "date"),
    DOM_NODE_TYPE_TIME("數據庫讀取數據方式", "time"),
    DOM_NODE_TYPE_FLOAT("數據庫讀取數據方式", "float"),
    。
    。
    。
   
    DAYMINHOUR("起始時間", "00:00:00"),
    DAYMAXHOUR("終止時間", "23:59:59")}

5.5 SerNoConst.java(系統中一些序號定義類)

(所在包:config.pub)

package com.ejsino.xxx.config.pub;
 
public enum SerNoConst {
 
    SERIAL_TYPE_ONLINE_MESSAGE("消息詳情表序號","ME",10),
    SERIAL_TYPE_ONLINE_USERROLE("用戶表序號","UR",10),
    。
    。
    。
    SERIAL_TYPE_CLAIM_ORGAN_NO("機構代碼","JG",5),
    SERIAL_TYPE_GROUP_COMPANYNO("合併後保險公司編號","CG",3);
 
    private String name ;
    private String value ;
    private Integer length;
 
    private SerNoConst( String name , String value, Integer length){
        this.name = name ;
        this.value = value ;
        this.length = length;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public String getValue() {
        return value;
    }
 
    public void setValue(String value) {
        this.value = value;
    }
 
    public Integer getLength() {
        return length;
    }
 
    public void setLength(Integer length) {
        this.length = length;
    }
}

5.6 DateConv.java(系統中一些時間類型轉化類)

(所在包:config.pub)

package com.ejsino.xxx.config.pub;
 
import com.ejsino.xxx.config.exception.EhomeException;
 
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Pattern;
 
/**
 * Created by cohenkl on 2018/1/8.
 */
public class DateConv {
    public static void main(String args[]) {
        try {
            System.out.println(DateConv.formatDate("19860504", "yyyy-MM-dd HH:mm:ss"));
        } catch (Exception ex) {
            ex.printStackTrace();
            System.out.println("……遊藝場222……………………" + ex.getMessage());
        }
    }
 
    private static String errMsg = null;
 
    private DateConv() {
        TimeZone.setDefault(TimeZone.getTimeZone("GMT+8"));//夏令時問題
    }
 
    private static DateConv obj = new DateConv();
 
    public static DateConv instance() {
        return obj;
    }
 
    public static String format(String srcString, String filterChar, String strFormat) throws EhomeException {
        if (srcString == null || srcString.equals("")) {
            return "";
        }
        String retStr = null;
        try {
            String newString = srcString.replaceAll("/", "").replaceAll("-", "");
            if (filterChar != null && !filterChar.equals("")) {
                newString = newString.replaceAll(filterChar, "");
            }
            String tmpFormat = "yyyyMMdd";
            if (newString.length() > 8) {
                tmpFormat = "yyyyMMdd HH:mm:ss";
            }
            DateFormat df = new SimpleDateFormat(tmpFormat);
            Date retDate = df.parse(newString);
            retStr = new SimpleDateFormat(strFormat).format(retDate);
        } catch (ParseException ex) {
            throw new EhomeException(ex.getMessage());
        }
        return retStr;
    }
 
    public static String DateIntToString(int iDate) {
        iDate -= 1;
        if (iDate < 1) {
            return ("18991231");
        }
        int iCnt = 0;
        int iYear = 0;
        int iMonth = 0;
        int iDay = 0;
        int curdays = 0;
        int passdays = 0;
        int i = 0;
        while (true) {
            if (i * 365 + iCnt >= iDate) {
                break;
            }
            iYear = i;
            curdays = iDate - (i * 365) - iCnt;
            if (((i + 1900) % 400 == 0) || ((i + 1900) % 4 == 0 && (i + 1900) % 100 != 0)) {
                iCnt++;
            }
            i++;
        }
        for (i = 1; i <= 12; i++) {
            iDay = curdays - passdays;
            if (i == 1 || i == 3 || i == 5 || i == 7 || i == 8 || i == 10 || i == 12) {
                passdays += 31;
            } else if (i == 4 || i == 6 || i == 9 || i == 11) {
                passdays += 30;
            } else if (((iYear + 1900) % 400 == 0) || ((iYear + 1900) % 4 == 0 && (iYear + 1900) % 100 != 0)) {
                passdays += 29;
            } else {
                passdays += 28;
            }
            iMonth = i;
            if (passdays >= curdays) {
                break;
            }
        }
        iYear += 1900;
        StringBuffer outstr = new StringBuffer();
        outstr.append(iYear);
        Integer iTmp = new Integer(iMonth);
        String strMonth = iTmp.toString();
        if (strMonth.length() < 2) {
            outstr.append("0");
            outstr.append(strMonth);
        } else {
            outstr.append(strMonth);
        }
        iTmp = new Integer(iDay);
        String strDay = iTmp.toString();
        if (strDay.length() < 2) {
            outstr.append("0");
            outstr.append(strDay);
        } else {
            outstr.append(strDay);
        }
        return outstr.toString();
    }
 
    public static String DateStringConv(String strDate) {
        if (strDate == null || strDate.equals("")) {
            return "";
        }
        String strRet = new String(strDate);
        return strRet.replaceAll("/", "").replaceAll("-", "");
    }
 
    public static String DateTimeToDate(String strDate) {
        if (strDate == null || strDate.equals("")) {
            return "";
        }
        String strRet = strDate.replaceAll("/", "").replaceAll("-", "");
        return strRet.substring(0, 8);
    }
 
    public static int DateStringToInt(String strDate) {
        String strTmpDate = new String(strDate);
        if (strTmpDate.length() != 8) {
            errMsg = strDate + " 日期數據不正確,正確格式[YYYYMMDD]";
            return (-1);
        }
        String strYear = strTmpDate.substring(0, 4);
        String strMonth = strTmpDate.substring(4, 6);
        String strDay = strTmpDate.substring(6);
        int iYear = Integer.parseInt(strYear);
        int iMonth = Integer.parseInt(strMonth);
        int iDay = Integer.parseInt(strDay);
        if (iYear < 1900 || iYear >= 2900) {
            errMsg = "日期的年份不正確";
            return (-1);
        }
        if (iMonth < 1 || iMonth > 12) {
            errMsg = "日期的月份應在0-12之間";
            return (-1);
        }
        if (iMonth == 1 || iMonth == 3 || iMonth == 5 || iMonth == 7 || iMonth == 8 || iMonth == 10 || iMonth == 12) {
            if (iDay < 1 || iDay > 31) {
                errMsg = "日期天數不正確";
                return (-1);
            }
        } else if (iMonth == 2) {
            // 閏年
            if ((iYear % 400 == 0) || (iYear % 4 == 0 && iYear % 100 != 0)) {
                if (iDay < 1 || iDay > 29) {
                    errMsg = "日期天數不正確";
                    return (-1);
                }
            } else {
                if (iDay < 1 || iDay > 28) {
                    errMsg = "日期天數不正確";
                    return (-1);
                }
            }
        } else {
            if (iDay < 1 || iDay > 30) {
                errMsg = "日期天數不正確";
                return (-1);
            }
        }
        int iDate = iDay;
        for (int i = 0; i < iMonth; i++) {
            switch (i) {
                case 1:
                case 3:
                case 5:
                case 7:
                case 8:
                case 10:
                case 12: {
                    iDate += 31;
                    break;
                }
                case 4:
                case 6:
                case 9:
                case 11: {
                    iDate += 30;
                    break;
                }
                case 2: {
                    // 閏年
                    if ((iYear % 400 == 0) || (iYear % 4 == 0 && iYear % 100 != 0)) {
                        iDate += 29;
                    } else {
                        iDate += 28;
                    }
                    break;
                }
            } // switch
        } // for iMonth
        for (int i = 0; i < iYear - 1900; i++) {
            if (((i + 1900) % 400 == 0) || ((i + 1900) % 4 == 0 && (i + 1900) % 100 != 0)) {
                iDate += 366;
            } else {
                iDate += 365;
            }
        }
        iDate += 1;
        return ((int) iDate);
    }
 
    public static String TimeToStrTime(long localtime, String strFormat) {
        SimpleDateFormat formatter = null;
        if (strFormat != null && strFormat.indexOf("-") >= 0) {
            formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        } else {
            formatter = new SimpleDateFormat("yyyyMMdd HH:mm:ss");
        }
        Date myDate = new Date();
        myDate.setTime(localtime);
        String outDate = formatter.format(myDate);
        return outDate;
    }
 
    // 校驗時間或日期格式 timeOrDate==true yyyyMMdd HH:mm:ss false:yyyyMMdd
    public static boolean checkDateFormat(String str, boolean bTimeOrDate) {
        try {
            if (bTimeOrDate) {
                checkDataTimt(str);
            } else {
                if (!Pattern.compile("^\\d{8}$").matcher(str).matches()) {
                    return false;
                }
                String format = "yyyyMMdd";
                SimpleDateFormat formatter = new SimpleDateFormat(format);
                formatter.setLenient(false);// 嚴格規定時間格式
                formatter.parse(str);
            }
        } catch (EhomeException io) {
            return false;
        } catch (ParseException io) {
            return false;
        }
        return true;
    }
 
    public static Date StrTimeToDate(String strTime) throws EhomeException {
        // strTime不足時分秒的部分,需先補齊時分秒" HH:mm:ss",再調用此方法
        // 時間串格式:"yyyyMMdd HH:mm:ss"
        String tmpTime = DateStringConv(strTime);
        SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd HH:mm:ss");
        Date myDate = null;
        try {
            // formatter.setLenient(false);// 嚴格規定時間格式
            checkDataTimt(tmpTime);
            myDate = formatter.parse(tmpTime);
        } catch (EhomeException io) {
            throw new EhomeException(io.getMessage());
        } catch (ParseException io) {
            throw new EhomeException("格式化日期時間字符串到time型失敗:" + strTime);
        }
        return myDate;
    }
    /**
     * 功能:獲取工作日批改時間;
     * @return
     * @throws EhomeException
     */
/*    public static boolean checkNotWorkDay() throws EhomeException {
        Calendar c = Calendar.getInstance();
        return checkHoliday(c);
    }*/
    public static void checkDataTimt(String strDateTime) throws EhomeException {
        if(strDateTime.length() == 20 && strDateTime.lastIndexOf(":00")==17){
            strDateTime=strDateTime.substring(0,17);
        }//特殊處理, 接口用戶中有客戶傳輸航班時間沒有按要求傳輸(yyyy-MM-dd HH:mm)。以後逐步改掉
 
        if (strDateTime.length() != 17) {
            throw new EhomeException("日期格式錯誤:" + strDateTime);
        } else {
            String strDate = strDateTime.substring(0, 8);
            String strTime = strDateTime.substring(9);
            SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd");
            try {
                formatter.setLenient(false);// 嚴格規定日期格式
                formatter.parse(strDate);
            } catch (ParseException io) {
                throw new EhomeException("格式化日期時間字符串到time型失敗:" + strTime);
            }
            if (strTime.indexOf(":") < 0) {
                throw new EhomeException("日期格式錯誤:" + strDateTime);
            } else {
                String strHour = strTime.substring(0, strTime.indexOf(":"));
                String strMin = strTime.substring(strTime.indexOf(":") + 1, strTime.lastIndexOf(":"));
                String strSecond = strTime.substring(strTime.lastIndexOf(":") + 1);
                if (strHour.length()!=2 || Integer.parseInt(strHour) > 23 || strMin.length()!=2 || Integer.parseInt(strMin) > 59 || strSecond.length()!=2 || Integer.parseInt(strSecond) > 59) {
                    throw new EhomeException("日期格式錯誤:" + strDateTime);
                }
            }
        }
    }
 
    public static long StrTimeToTime(String strTime) throws EhomeException {
        return StrTimeToDate(strTime).getTime();
    }
 
    // 日期時間加減相應的秒數得到對應的日期時間串,天、時、分都換算成秒傳入secs參數
    public static String dateTimeAdded(String strTime, int secs) throws EhomeException {
        // 例子:dateTimeAdded("20091231 00:00:00", 24*3600);加一天
        long time = StrTimeToTime(strTime);
        String newtime = TimeToStrTime(time + (long) secs * 1000, "-");
        return newtime;
    }
 
    // 日期時間加減月數得到對應的日期時間串
    public static String dateTimeMonthAdded(String strTime, int months, boolean bFlag) throws EhomeException {
        // bFlag:return結果爲對應秒的前1秒 !bFlag:return結果爲對應秒
        StrTimeToDate(strTime);// 校驗入參的格式合法性
        String dateStr = strTime.substring(0, 8);
        String timeStr = strTime.substring(9);
        int iNewDate = IncMonth(DateStringToInt(dateStr), months);
        String newDateTime = DateIntToString(iNewDate) + " " + timeStr;
        if (bFlag) {
            return dateTimeAdded(newDateTime, -1).replaceAll("-", "");
        } else {
            return newDateTime;
        }
    }
 
    public static String dateTimeAddedByType(String strDateTime, int iNum, int dType, boolean bFlag) throws EhomeException {
        if (dType == 1) {
            // 加天數
            int secs = iNum * 24 * 3600;
            if (bFlag) {
                secs -= 1;
            }
            return dateTimeAdded(strDateTime, secs);
        } else if (dType == 2) {
            // 加月數
            return dateTimeMonthAdded(strDateTime, iNum, bFlag);
        } else {
            throw new EhomeException("[service]加減日期計算方法調用有誤");
        }
    }
 
    public static String IncDay(String strStartDate, int iNum) {
        int iDate = DateStringToInt(strStartDate);
        if (iDate < 0) {
            errMsg = "日期數據不正確,正確格式[YYYYMMDD]";
            return ("18991231");
        }
        iDate = iDate + iNum;
        String strDate = DateIntToString(iDate);
        if (strDate.equals("")) {
            return ("18991231");
        }
        return (strDate);
    }
 
    public static String getNextSysDate(int nextday) {
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.DATE, nextday);
        return (new SimpleDateFormat("yyyy-MM-dd").format(calendar.getTime()));
    }
 
    public static String getErrMsg() {
        return errMsg;
    }
 
    public static String getCurrSysTime() {
        return (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
    }
 
    public static String getSysTime() {
        return (new SimpleDateFormat("yyyyMMdd HH:mm:ss").format(new Date()));
    }
 
    public static String getSysDate() {
        return (new SimpleDateFormat("yyyyMMdd").format(new Date()));
    }
 
    public static String getCurrSysDate() {
        return (new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
    }
 
    public static String getCharisCurrSysDate() {
        Locale locale = new Locale("en", "US");
        DateFormat format = DateFormat.getDateInstance(DateFormat.MONTH_FIELD, locale);
        String value = format.format(new Date()).replaceAll(",", "").toUpperCase();
        String[] values = value.split(" ");
        if (values[1].length() == 1) {
            values[1] = "0" + values[1];
        }
        return values[1] + " " + values[0] + " " + values[2];
        // return (new SimpleDateFormat("MM/dd/yyyy").format(new Date()));
    }
 
 
    public static String formatDateTime(long dateTime, String format) {
        return (new SimpleDateFormat(format).format(dateTime));
    }
 
    public static String formatDateDate(Date dateTime, String format) {
        return (new SimpleDateFormat(format).format(dateTime));
    }
 
    // 根據保險的期限,加對應月後得到對應的月數對應的一天,即對應月的前一天
    public static String incMonthGetRelateDay(String startDate, int iNum) {
        return DateIntToString(IncMonth(DateStringToInt(startDate), iNum) - 1);
    }
 
    public static String IncMonth(String startDate, int iNum) {
        return DateIntToString(IncMonth(DateStringToInt(startDate), iNum));
    }
 
    public static int IncMonth(int iStartDate, int iNum) {
        String strDate = DateIntToString(iStartDate);
        if (strDate.equals(""))
            return (-1);
        String strYear = strDate.substring(0, 4);
        String strMonth = strDate.substring(4, 6);
        String strDay = strDate.substring(6);
 
        int iYear = Integer.parseInt(strYear);
        int iMonth = Integer.parseInt(strMonth);
        int iDay = Integer.parseInt(strDay);
        iMonth += iNum;
        while (iMonth > 12) {
            iMonth -= 12;
            iYear += 1;
        }
        while (iMonth <= 0) {
            iMonth += 12;
            iYear -= 1;
        }
        int iDate = 0;
        int iCnt = 0;
        while (true) {
            strMonth = String.valueOf(iMonth);
            if (strMonth.length() < 2) {
                strMonth = "0" + strMonth;
            }
            strDay = String.valueOf(iDay);
            if (strDay.length() < 2) {
                strDay = '0' + strDay;
            }
            String strTmp = iYear + strMonth + strDay;
            iDate = DateStringToInt(strTmp);
            if (iDate >= 0)
                break;
            iDay -= 1;
            if (iCnt > 3) {
                errMsg = "日期加月數計算對應的日期出錯";
                return (-1);
            }
            iCnt++;
        }
        return (iDate);
    }
 
    // 根據dGetType計算兩個日期時間型之間的間隔年、月、周、天數
    public static int calDateTimeSpace(String startDateTime, String endDateTime, int dGetType, boolean bFlag) throws EhomeException {
        if (startDateTime == null || endDateTime == null || startDateTime.equals("") || endDateTime.equals("")) {
            throw new EhomeException("計算日期差的入參都不能爲空");
        }
        // bFlag:不滿一天算一天 !bFlag:滿一天了纔算一天 同理:年、月、周也如此
        // dGetType:1年 2月 3周 4天
        switch (dGetType) {
            case (1): {
                // 年
                int iMonth = calDateTimeSpace(startDateTime, endDateTime, 2, bFlag);
                if (bFlag) {
                    return (int) (iMonth + 11) / 12;
                } else {
                    return (int) iMonth / 12;
                }
            }
            case (2): {
                // 月
                int iNum = 0;
                if (bFlag) {
                    while (true) {
                        String tmpDate = dateTimeMonthAdded(startDateTime, iNum, true);
                        if (tmpDate.compareTo(DateStringConv(endDateTime)) >= 0)
                            break;
                        iNum++;
                    }
                    return iNum;
                } else {
                    while (true) {
                        String tmpDate = dateTimeMonthAdded(startDateTime, iNum + 1, true);
                        if (tmpDate.compareTo(DateStringConv(endDateTime)) > 0)
                            break;
                        iNum++;
                    }
                    return iNum;
                }
            }
            case (3): {
                // 周
                int days = calDateTimeSpace(startDateTime, endDateTime, 4, bFlag);
                if (bFlag) {
                    return (int) (days + 6) / 7;
                } else {
                    return (int) days / 7;
                }
            }
            case (4): {
                // 天
                double days = (double) (StrTimeToTime(endDateTime) - StrTimeToTime(startDateTime) + 1000) / (24 * 3600 * 1000);
                if (bFlag) {
                    return (int) Math.ceil(days);
                } else {
                    return (int) Math.floor(days);
                }
            }
            default:
                throw new EhomeException("server日期時間計算類型參數不匹配");
        }
    }
 
    // 計算日期之間的間隔數
    public static int GetDateSpace(int dCalTimeType, String strStartDate, String strEndDate, int dGetType, boolean bFlag) {
        return GetDateSpace(dCalTimeType, DateStringToInt(strStartDate), DateStringToInt(strEndDate), dGetType, bFlag);
    }
 
    // dCalTimeType:: 1 超過纔算滿期 2 一樣纔算滿期 3 前一天就算滿期
    public static int GetDateSpace(int dCalTimeType, int iStartDate, int iEndDate, int dGetType, boolean bFlag) {
        if (iStartDate == 0)
            return 0;
        if (dCalTimeType == 1) {
            iEndDate -= 2;
        } else if (dCalTimeType == 2) {
            iEndDate -= 1;
        } else if (dCalTimeType != 3) {
            return -2;
        }
        int intMonth = 0;
 
        if (bFlag) { // 不滿一年算一年
            if (dGetType == 1) { // 取年數
                // 不足一個月算一個月;
                while (true) {
                    int tmpdate = IncMonth(iStartDate, intMonth) - 1;
                    if (tmpdate == -2) {
                        return -1;
                    }
                    if (iEndDate <= tmpdate)
                        break;
                    intMonth++;
                }
                // 不足一個年算一年;
                if ((intMonth % 12) == 0)
                    return (intMonth / 12); // 整年
                else
                    return (intMonth / 12 + 1); // 整年;
            } else if (dGetType == 2) { // 取月數
                // 不足一個月算一個月;
                while (true) {
                    int tmpdate = IncMonth(iStartDate, intMonth) - 1;
                    if (tmpdate == -2) {
                        return -1;
                    }
                    if (iEndDate <= tmpdate)
                        break;
                    intMonth++;
                }
                return intMonth;
            } else if (dGetType == 3) { // 取星期數
                int iDays = iEndDate - iStartDate + 1;
                return (int) (iDays + 6) / 7;
            } else if (dGetType == 4) { // 取天數
                int iDays = iEndDate - iStartDate + 1;
                return iDays;
            }
        } else {
            if (dGetType == 1) {
                // 滿一個月纔算一個月;
                while (true) {
                    int tmpdate = IncMonth(iStartDate, intMonth + 1) - 1;
                    if (tmpdate == -2) {
                        return -1;
                    }
                    if (iEndDate < tmpdate)
                        break;
                    intMonth++;
                }
                // 滿一個年纔算一年;
                if ((intMonth % 12) == 0)
                    return ((int) intMonth / 12); // 整年
                else
                    return ((int) intMonth / 12); // 整年
            } else if (dGetType == 2) {
                // 滿一個月纔算一個月;
                while (true) {
                    int tmpdate = IncMonth(iStartDate, intMonth + 1) - 1;
                    if (tmpdate == -2) {
                        return -1;
                    }
                    if (iEndDate < tmpdate)
                        break;
                    intMonth++;
                }
                return intMonth;
            } else if (dGetType == 3) { // 取星期數,滿一個星期纔算一個星期
                int iDays = iEndDate - iStartDate + 1;
                return (int) iDays / 7;
            } else if (dGetType == 4) { // 取天數,滿一天才算一天
                int iDays = iEndDate - iStartDate;
                return iDays;
            }
        }
        return -1;
    }
 
    public static String getMonthFirstDay() {
        String today = new SimpleDateFormat("yyyyMMdd").format(new Date());
        return today.substring(0, 6) + "01";
    }
 
    public static String getMonthLastDay() {
        String today = new SimpleDateFormat("yyyyMMdd").format(new Date());
        String year = today.substring(0, 4);
        String month = today.substring(4, 6);
        String day = "31";
        if (month.equals("02")) {
            int iYear = Integer.parseInt(year);
            if (iYear % 400 == 0 || (iYear % 4 == 0 && iYear % 100 != 0)) {
                day = "29";
            } else {
                day = "28";
            }
        } else if (month.equals("04") || month.equals("06") || month.equals("09") || month.equals("11")) {
            day = "30";
        }
        return year + month + day;
    }
    public static String getLastMonthLastDay() {
        Calendar calendar = Calendar.getInstance();
        int day=calendar.get(Calendar.DATE);
        calendar.add(Calendar.DATE, -day);
        return (new SimpleDateFormat("yyyy-MM-dd").format(calendar.getTime()));
    }
    public static String getTimeOfDateTime(String strDateTime){
        String strTime = "";
        if(strDateTime.length()>8 && strDateTime.lastIndexOf(":")>8){
            String newString = strDateTime.replaceAll("/", "").replaceAll("-", "");
            strTime = newString.substring(9);
        }
        return strTime;
    }
 
    //通用日期或時間各種格式的格式化,返回dateFormat約定的格式,如yyyyMMdd HH:mm:ss  //added by zhaohaibin on 2016-12-15
    public static String formatDate(String dateStr, String dateFormat) throws EhomeException {
        if (dateStr == null || dateStr.equals("")) {
            return "";
        }
        HashMap<String, String> dateRegFormat = new HashMap<String, String>();
        dateRegFormat.put(
                "^\\d{4}\\D+\\d{1,2}\\D+\\d{1,2}\\D+\\d{1,2}\\D+\\d{1,2}\\D+\\d{1,2}\\D*$",
                "yyyy-MM-dd-HH-mm-ss");//2014年3月12日 13時5分34秒,2014-03-12 12:05:34,2014/3/12 12:5:34
        dateRegFormat.put("^\\d{4}\\D+\\d{1,2}\\D+\\d{1,2}\\D+\\d{1,2}\\D+\\d{1,2}$",
                "yyyy-MM-dd-HH-mm");//2014-03-12 12:05
        dateRegFormat.put("^\\d{4}\\D+\\d{1,2}\\D+\\d{1,2}\\D+\\d{1,2}$",
                "yyyy-MM-dd-HH");//2014-03-12 12
        dateRegFormat.put("^\\d{4}\\D+\\d{1,2}\\D+\\d{1,2}$", "yyyy-MM-dd");//2014-03-12
        dateRegFormat.put("^\\d{4}\\D+\\d{1,2}$", "yyyy-MM");//2014-03
        dateRegFormat.put("^\\d{4}$", "yyyy");//2014
        dateRegFormat.put("^\\d{14}$", "yyyyMMddHHmmss");//20140312120534
        dateRegFormat.put("^\\d{12}$", "yyyyMMddHHmm");//201403121205
        dateRegFormat.put("^\\d{10}$", "yyyyMMddHH");//2014031212
        dateRegFormat.put("^\\d{8}$", "yyyyMMdd");//20140312
        dateRegFormat.put("^\\d{6}$", "yyyyMM");//201403
        dateRegFormat.put("^\\d{8}\\D+\\d{1,2}\\D+\\d{1,2}\\D+\\d{1,2}$", "yyyyMMdd-HH-mm-ss");//20140312 12:05:34
        dateRegFormat.put("^\\d{8}\\D+\\d{1,2}\\D+\\d{1,2}$", "yyyyMMdd-HH-mm");//20140312 12:05
        dateRegFormat.put("^\\d{8}\\D+\\d{1,2}$", "yyyyMMdd-HH");//20140312 12
        dateRegFormat.put("^\\d{1,2}\\s*:\\s*\\d{1,2}\\s*:\\s*\\d{1,2}$",
                "yyyy-MM-dd-HH-mm-ss");//13:05:34 拼接當前日期
        dateRegFormat.put("^\\d{1,2}\\s*:\\s*\\d{1,2}$", "yyyy-MM-dd-HH-mm");//13:05 拼接當前日期
        dateRegFormat.put("^\\d{2}\\D+\\d{1,2}\\D+\\d{1,2}$", "yy-MM-dd");//14.10.18(年.月.日)
        dateRegFormat.put("^\\d{1,2}\\D+\\d{1,2}$", "yyyy-dd-MM");//30.12(日.月) 拼接當前年份
        dateRegFormat.put("^\\d{1,2}\\D+\\d{1,2}\\D+\\d{4}$", "dd-MM-yyyy");//12.21.2013(日.月.年)
 
        DateFormat formatter1 = new SimpleDateFormat(dateFormat);
        DateFormat formatter2 = null;
        String dateReplace = dateStr;
        String strSuccess = "";
        try {
            for (String key : dateRegFormat.keySet()) {
                if (Pattern.compile(key).matcher(dateStr).matches()) {
                    formatter2 = new SimpleDateFormat(dateRegFormat.get(key));
                    String curDate = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
                    if (key.equals("^\\d{1,2}\\s*:\\s*\\d{1,2}\\s*:\\s*\\d{1,2}$")
                            || key.equals("^\\d{1,2}\\s*:\\s*\\d{1,2}$")) {//13:05:34 或 13:05 拼接當前日期
                        dateReplace = curDate + " " + dateStr;
                    } else if (key.equals("^\\d{1,2}\\D+\\d{1,2}$")) {//21.1 (日.月) 拼接當前年份
                        dateReplace = curDate.substring(0, 4) + "-" + dateStr;
                    }
                    dateReplace = dateReplace.replaceAll("\\D+", "-");
                    strSuccess = formatter1.format(formatter2.parse(dateReplace));
                    return strSuccess;
                }
            }
            throw new EhomeException("輸入日期格式[" + dateStr + "]未能匹配解析");
        } catch (EhomeException e) {
            throw e;
        } catch (Exception e) {
            e.printStackTrace();
            throw new EhomeException("輸入日期格式[" + dateStr + "]無效");
        }
    }
}

5.7 ServletUtil.java(客戶ip處理,需要獲取用戶ip必配)

(所在包:utils)

package com.ejsino.xxx.utils;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
 
/**
 * @author charles
 * @version V1.0
 * @Title:
 * @Package
 * @Description: servlet util
 * @date 20171108
 */
public class ServletUtil {
 
   //private final static String INVOKE_MESSAGE = "invokeMessage";
  
   /**
    * <p>
    * Web 服務器反向代理中用於存放客戶端原始 IP 地址的 Http header 名字。
    * </p>
    */
   private final static String[] PROXY_REMOTE_IP_ADDRESS = { "X-Forwarded-For", "X-Real-IP", "Proxy-Client-IP",
         "WL-Proxy-Client-IP", "HTTP_CLIENT_IP", "HTTP_X_FORWARDED_FOR" };
 
   private ServletUtil() {
   }
 
   /**
    * <p>
    * 獲取請求的客戶端的 IP 地址。若應用服務器前端配有反向代理的 Web 服務器       * 需要在 Web 服務器中將客戶端原始請求的 IP 地址加入到 HTTP header 中。      *詳見{@link ServletUtil#PROXY_REMOTE_IP_ADDRESS}
    * </p>
    *
    * @param request
    * @return
    *
    * @author gaobaowen
    */
   public static String getRemoteIp(HttpServletRequest request) {
      for (int i = 0; i < PROXY_REMOTE_IP_ADDRESS.length; i++) {
         String ip = request.getHeader(PROXY_REMOTE_IP_ADDRESS[i]);
         if (!StringUtils.isEmpty(ip) && !"unknown".equals(ip)) {
            return getRemoteIpFromForward(ip);
         }
      }
      return request.getRemoteHost();
   }
 
   /**
    * <p>
    * 從 HTTP Header 的 X-Forward-IP 頭中截取客戶端連接 IP 地址。如果經過多次反向代理,
    * 在 X-Forward-IP 中獲得的是以“,&lt;SP&gt;”分隔 IP 地址鏈,第一段爲   * 客戶端 IP
    * 地址。
    * </p>
    *
    * @param xforwardIp
    * @return
    */
   private static String getRemoteIpFromForward(String xforwardIp) {
      int commaOffset = xforwardIp.indexOf(',');
      if (commaOffset < 0) {
         return xforwardIp;
      }
      return xforwardIp.substring(0, commaOffset);
   }
 
   public static String getRemoteIp() {
      HttpServletRequest request = getServletRequest();
      return getRemoteIp(request);
   }
 
   public static String getRemoteHostName() {
      return getServletRequest().getServerName();
   }
 
   /**
    * <p>
    * 獲取應用服務器的 HTTP 監聽端口號
    * </p>
    *
    * @param request
    * @return
    *
    * @author gaobaowen
    */
   public static int getServerPort(HttpServletRequest request) {
      return request.getServerPort();
   }
  
   /**
    * 將指定 key 對應value放入值棧中
    *
    * @param key
    * @param value
    */
   public static void setInvokeMessage(String key, String value) {
      getServletRequest().setAttribute(key, value);
   }
  
   public static HttpServletRequest getServletRequest() {
      ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
      return requestAttributes.getRequest();
   }
 
   public static HttpServletResponse getServletResponse() {
      ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
      return requestAttributes.getResponse();
   }
  
   public static HttpSession getServletSession() {
      ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
      return requestAttributes.getRequest().getSession();
   }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章