Spring+SpringMVC+MyBatis+LogBack+C3P0+Maven+Git小結(轉)

摘要 出於興趣,想要搭建一個本身的小站點,目前正在積極的準備環境,利用Spring+SpringMVC+MyBatis+LogBack+C3P0+Maven+Git,這裏總結下最近遇到的一些問題及解決辦法,後續慢慢的繼續補~html

目錄[-]java

  • 一:創建一個Maven結構的Web工程
  • 二:Spring、SpringMVC重複加載bean對象問題。
  • 三:實現自個的數據緩存機制
  • 2種緩存數據簡介及其數據結構分析
  • 2中緩存數據加載實現流程介紹
  • 三:經過Spring自定義標籤形式實現配置項類型數據的緩存數據結構解析及加載
  • 四:對method作統一的起始&結束的日誌處理(切面方式)
  • 五:LogBack日誌文件配置&中文亂碼&MyBatis日誌不輸出SQL。

一:創建一個Maven結構的Web工程

    這裏主要介紹下如何使用MyEclipse建立一個Maven結構的Web項目mysql

    1:下載並安裝好本身的maven,並在環境變量中配置對應MAVEN_HOME、PATH路徑web

        檢測是否安裝完畢,能夠在cmd中輸入命令檢測:mvn --versionspring

         

 

    2:在MyEclipse中關聯並使用Maven(這裏可使用MyEclipse自帶的Maven4MyEclipse,也能夠本身下載一個MyEclipse對應的Maven插件來關聯咱們的Maven3.1.1)sql

         

        設置下本身的倉庫和配置文件路徑:數據庫

        

    3:新建工程以下:express

        

        

        

         

        至今生成一個web結構的maven項目(還缺乏部分maven目錄結構,下面補齊)apache

    4:補充maven目錄結構:json

        

    5:結構弄完了,本身往pom.xml裏面灌點jar配置就行了,個人以下:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>org.wjlmgqs</groupId>
	<artifactId>mtag</artifactId>
	<packaging>war</packaging>
	<version>0.0.1-SNAPSHOT</version>
	<name>mtag Webapp</name>
	<url>http://maven.apache.org</url>

	<dependencies>
		<dependency>
			<groupId>org.apache.maven.plugins</groupId>
			<artifactId>maven-resources-plugin</artifactId>
			<version>2.4.3</version>

		</dependency>
		<dependency>
			<groupId>c3p0</groupId>
			<artifactId>c3p0</artifactId>
			<version>0.9.1.2</version>
		</dependency>

		<!--springframework 3.2.0.RELEASE -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-aop</artifactId>
			<version>3.2.12.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-aspects</artifactId>
			<version>3.2.12.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-beans</artifactId>
			<version>3.2.12.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>3.2.12.RELEASE</version>
			<exclusions>
				<exclusion>
					<groupId>commons-logging</groupId>
					<artifactId> commons-logging</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context-support</artifactId>
			<version>3.2.12.RELEASE</version>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
			<version>3.2.12.RELEASE</version>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-expression</artifactId>
			<version>3.2.12.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-jdbc</artifactId>
			<version>3.2.12.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-orm</artifactId>
			<version>3.2.12.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-test</artifactId>
			<version>3.2.12.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-tx</artifactId>
			<version>3.2.12.RELEASE</version>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-web</artifactId>
			<version>3.2.12.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>3.2.12.RELEASE</version>
		</dependency>

		<!--aspectj -->
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjrt</artifactId>
			<version>1.8.5</version>
		</dependency>
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjweaver</artifactId>
			<version>1.8.5</version>
		</dependency>
		<dependency>
			<groupId>aopalliance</groupId>
			<artifactId>aopalliance</artifactId>
			<version>1.0</version>
		</dependency>
		<dependency>
			<groupId>cglib</groupId>
			<artifactId>cglib</artifactId>
			<version>2.2.2</version>
		</dependency>
		<!--mybatis 3.3.1 -->
		<dependency>
			<groupId>org.mybatis</groupId>
			<artifactId>mybatis</artifactId>
			<version>3.1.1</version>
		</dependency>
		<dependency>
			<groupId>org.mybatis</groupId>
			<artifactId>mybatis-spring</artifactId>
			<version>1.2.3</version>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-Java</artifactId>
			<version>5.1.19</version>
		</dependency>
		<!--log :slf4j+classes+core+logback.xml -->
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-api</artifactId>
			<version>1.7.7</version>
		</dependency>

		<dependency>
			<groupId>ch.qos.logback</groupId>
			<artifactId>logback-core</artifactId>
			<version>1.1.2</version>
		</dependency>

		<dependency>
			<groupId>ch.qos.logback</groupId>
			<artifactId>logback-classic</artifactId>
			<version>1.1.2</version>
		</dependency>

		<dependency>
			<groupId>org.logback-extensions</groupId>
			<artifactId>logback-ext-spring</artifactId>
			<version>0.1.1</version>
		</dependency>
		<!--commons utils -->
		<dependency>
			<groupId>commons-beanutils</groupId>
			<artifactId>commons-beanutils</artifactId>
			<version>1.9.2</version>
		</dependency>
		<dependency>
			<groupId>commons-chain</groupId>
			<artifactId>commons-chain</artifactId>
			<version>1.2</version>
		</dependency>
		<dependency>
			<groupId>commons-codec</groupId>
			<artifactId>commons-codec</artifactId>
			<version>1.6</version>
		</dependency>
		<dependency>
			<groupId>commons-collections</groupId>
			<artifactId>commons-collections</artifactId>
			<version>3.2.1</version>
		</dependency>
		<dependency>
			<groupId>commons-configuration</groupId>
			<artifactId>commons-configuration</artifactId>
			<version>1.7</version>
		</dependency>
		<dependency>
			<groupId>commons-digester</groupId>
			<artifactId>commons-digester</artifactId>
			<version>2.0</version>
		</dependency>
		<dependency>
			<groupId>commons-fileupload</groupId>
			<artifactId>commons-fileupload</artifactId>
			<version>1.2.2</version>
		</dependency>
		<dependency>
			<groupId>commons-io</groupId>
			<artifactId>commons-io</artifactId>
			<version>2.1</version>
		</dependency>
		<dependency>
			<groupId>commons-lang</groupId>
			<artifactId>commons-lang</artifactId>
			<version>2.6</version>
		</dependency>
		<dependency>
			<groupId>commons-logging</groupId>
			<artifactId>commons-logging</artifactId>
			<version>1.1.3</version>
		</dependency>
		<dependency>
			<groupId>commons-net</groupId>
			<artifactId>commons-net</artifactId>
			<version>3.0.1</version>
		</dependency>
		<dependency>
			<groupId>commons-pool</groupId>
			<artifactId>commons-pool</artifactId>
			<version>1.6</version>
		</dependency>
		<dependency>
			<groupId>commons-validator</groupId>
			<artifactId>commons-validator</artifactId>
			<version>1.3.1</version>
		</dependency>
		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-compress</artifactId>
			<version>1.3</version>
		</dependency>
		<!--測試 -->
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.10</version>
		</dependency>
		<!--j2ee web spec -->
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>servlet-api</artifactId>
			<version>2.5</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jstl</artifactId>
			<version>1.2</version>
		</dependency>
		<dependency>
			<groupId>taglibs</groupId>
			<artifactId>standard</artifactId>
			<version>1.1.2</version>
		</dependency>
		<!--json -->
		<dependency>
			<groupId>org.codehaus.jackson</groupId>
			<artifactId>jackson-mapper-asl</artifactId>
			<version>1.9.13</version>
		</dependency>
	</dependencies>
	<build>
		<finalName>mtag</finalName>
	</build>
</project>

 

二:Spring、SpringMVC重複加載bean對象問題。

    在新建完Web項目並經過Pom.xml引入須要的jar後,我就開始配置Spring、SpringMVC的相關配置文件(在配置文件中啓用註解掃描Bean組件的方式),這中間遇到一個問題,在web.xml中配置的:Spring對應的ContextLoaderListener加載beans.xml並掃描註冊了一次@Component對象,而SpringMVC的DispatcherServlet加載spring-mvc.xml又掃描註冊了一次註解的Bean對象,形成一個對象被實例化兩次。

針對摘要中的問題,咱們能夠這樣理解並分配:

    將與SpringMVC關聯的Controller層註解對象都歸屬於spring-mvc.xml對應的上下文管理,而剩下來的組件都交由Spring的beans.xml對應上下文管理。2個配置文件的內容分別以下:

    spring-mvc.xml配置內容以下:只掃描註解類型爲@Controller的組件

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


	<!-- 使用 annotation 自動註冊Controller bean,並檢查@Controller註解已被注入 --> 
	<context:annotation-config /> 
	<context:component-scan base-package="org.wjlmgqs.mtag" use-default-filters="false"  > 
		<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>  
	</context:component-scan> 
	
    <!-- 完成請求和註解POJO的映射 -->
    <mvc:annotation-driven /> 
    
	<!-- 靜態資源處理    -->
	<mvc:resources mapping="/resource/**" location="/resource/"/>
	<mvc:default-servlet-handler />  

	<!-- 視圖對應的文件映射 -->
	<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">  
		<property name="prefix" value="http://my.oschina.net/WEB-INF/views/" />  
		<property name="suffix" value="http://my.oschina.net/u/1163141/blog/.jsp" />  
	</bean>  
	
	<aop:aspectj-autoproxy proxy-target-class="true" /> 
</beans>

 

    beans.xml配置內容以下:只掃描排除@Controller後組件

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

	<!-- 註解掃描的目錄:使用 annotation 排除@Controller註解 --> 
	<context:annotation-config /> 
	<context:component-scan base-package="org.wjlmgqs.mtag" >
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
     </context:component-scan>
	
	<!-- mybatis相關配置 -->
	<import resource="beans-mybatis.xml"/>
	
	<!-- 配置項類型配置 -->
	<import resource="beans-config-type.xml"/>
	
	<!-- 事務配置 -->
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource" />
	</bean>
	
	<!-- @Transactional -->
	<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>
	
	
</beans>

 

三:實現自個的數據緩存機制

 

    自個目前只實現了2種數據的緩存:

        一:數據字典加載到緩存中 ;

        二:配置項類型數據加載到緩存中

  • 2種緩存數據簡介及其數據結構分析

 

        這裏先簡單介紹下2種數據類型:

            1:數據字典,表結構以下:

                

                數據例如:

                 

                加載到咱們緩存中的數據結構大體以下:Map<ID,Map<DICT_KEY,Map<String,String>>>   

            2:配置項類型,打個比方,咱們站點有以下幾種須要:

                    支付方式包括:支付寶微信支付、銀聯在線支付等  (PayType);

                    物流配送方式:順豐、中通、EMS等(DeliveryType);

                    社會化登陸方式:QQ、Baidu、Sina等(SocialType);

                    並且上述幾種類型和方式都是可插拔、可擴展的,這個時候咱們能夠嘗試定義一個接口:IConfigPart,定義這些配置項的功能屬性,例如ID、Name等

/**
 * IConfigPart.java<br>
 * <b>功能:配置項類型接口:全部實現該接口的類型都將註冊入緩存CacheClient中</b><br>
 * @author wjl Email:wjlmgqs@sina.com
 * Time:2015-7-24 上午11:11:56
 */
public interface IConfigPart {

	/**
	 * <b>簡要說明:配置項類型ID</b><br> 
	 * Create on 2015-7-23 下午2:27:31 <br>
	 */
	public String getId();
	
	/**
	 * <b>簡要說明:實現類Code</b><br> 
	 * Create on 2015-7-23 下午2:27:31 <br>
	 */
	public String getCode();
	
	/**
	 * <b>簡要說明:實現類名稱</b><br> 
	 * Create on 2015-7-23 下午2:27:31 <br>
	 */
	public String getName();	
	
	/**
	 * <b>簡要說明:順序號</b><br> 
	 * Create on 2015-7-23 下午2:33:54 <br>
	 */
	public int getSeq();
	
	/**
	 * <b>簡要說明:是否啓用</b><br> 
	 * Create on 2015-7-23 下午2:33:54 <br>
	 */
	public boolean isMrb();
}

        而後,咱們又爲了可以區分這些類型中哪些是支付類型、哪些是配送類型、哪些是社會化登陸類型,就須要給各個類型定義一個本身的接口,並繼承接口:IConfigPart,例如社會化類型:ISocailLoginConfigPart

/**
 * ISocailLoginConfigPart.java<br>
 * <b>功能:社會化登陸-配置類型默認實現接口</b><br>
 * @author wjl Email:wjlmgqs@sina.com
 * Time:2015-7-27 下午12:10:19
 */
public interface ISocailLoginConfigPart extends IConfigPart{

}

        再而後咱們就能夠定義咱們具體的登陸類型有哪些了:

        

       例如:QQConfig.java

public class QQConfig implements ISocailLoginConfigPart {
	
	public static String ID = "QQConfig";
	
	@Override
	public String getId() {
		return ID;
	}

	@Override
	public String getCode() {
		return "QQ";
	}

	@Override
	public String getName() {
		return "騰訊QQ";
	}

	@Override
	public boolean isMrb() {
		return true;
	}

	@Override
	public int getSeq() {
		return 1;
	}
}

        定義上面這樣的結構之後,咱們就能夠想象這樣一個數據結構:

        Map<ISocailLoginConfigPart,Map<QQConfig,IConfigPart>>

              //ISocailLoginConfigPart:是哪一種類型,如社會化登陸類型的ID

              //QQConfig:是社會化登陸類型下的具體哪一種類型方式:QQ登陸方式的ID

              //IConfigPart:表明QQ登陸類型這個對象,包含ID、Name、Seq等數據的具體對象

 

      額,定義了上面2種緩存數據結構之後,分別給這2個數據結構定義一個常量ID,並扔進一個叫作CacheClient對象的Map裏面,實現大體以下:

/**
 * CacheClient.java<br>
 * <b>功能:緩存數據操做集</b><br>
 * @author wjl Email:wjlmgqs@sina.com
 * Time:2015-7-23 下午4:19:11
 */
@Component
public class CacheClient implements ApplicationContextAware{

	private static String threadClassName = Thread.currentThread().getStackTrace()[1].getClassName();
	protected static Logger log = LoggerFactory.getLogger(threadClassName);
	/**
	 * <b>描述:緩存服務</b>
	 */
	private static ICacheService cacheService = null;
	
	/**
	 * <b>描述:配置項類型</b>
	 */
	private static ConfigType configType = null;
	
	/**
	 * <b>簡要說明:構造參數私有化</b><br> 
	 * Create on 2015-7-23 下午3:30:13 <br>
	 * @author 翁加林
	 */
	private CacheClient(){
		log.debug("...CacheClient create cache client ");
	}
	
	/**
	 * <b>描述:數據緩存結構對象</b>
	 */
	private static Map<String,Map<String,Object>> cacheMap = new HashMap<String,Map<String,Object>>();
	
	/**
	 * <b>簡要說明:初始化緩存數據結構</b><br> 
	 * Create on 2015-7-23 下午3:50:10 <br>
	 * @author 翁加林
	 */
	public static void initCache(){
		Map<String, Object> loadDictCache = loadDictCache();//字典數據
		Map<String, Object> loadConfigTypeCache = loadConfigTypeCache();//配置項
		
		cacheMap.put(PubConstants.DICT_CLIENT_CACHE, loadDictCache);
		cacheMap.put(PubConstants.CONFIG_TYPE_CACHE, loadConfigTypeCache);
		
		log.debug("...CacheClient initCache data : "+cacheMap);
	}
	.....
}

 

        額,這蛋扯得有點長了,下回分解。

  • 2中緩存數據加載實現流程介紹

        定義好這2種緩存的數據結構之後,咱們得有個流程和方式把這些數據加載進來吧,這裏就先介紹下加載的大體流程。

        第一步:註冊監聽,在容器啓動時就開始加載咱們的數據

            在web.xml中註冊:

  <listener>
    <listener-class>org.wjlmgqs.mtag.core.listener.InitListenter</listener-class>
  </listener>

            對應的java代碼以下:

/**
 * InitListenter.java<br>
 * <b>功能:服務啓動時加載系統須要的Cache內容:
 * 			java類型:ConfigPart 配置項		
 * 			數據庫:數據字典 
 * </b><br>
 * @author 翁加林 Email:wjlmgqs@sina.com
 * Time:2015-7-23 下午2:32:49
 */
public class InitListenter implements ServletContextListener{

	private static String threadClassName = Thread.currentThread().getStackTrace()[1].getClassName();
	protected static Logger log = LoggerFactory.getLogger(threadClassName);
	
	@Override
	public void contextDestroyed(ServletContextEvent arg0) {
		
	}

	@Override
	public void contextInitialized(ServletContextEvent sce) {
		 log.debug("...InitListenter contextInitialized start ...");
		 CacheClient.initCache();//初始化緩存操做
		 log.debug("...InitListenter contextInitialized end ...");
	}

}

            能夠看出,咱們在容器啓動時,調用

CacheClient.initCache();//初始化緩存操做

            完成了緩存數據的加載。

        第二步:在initCache中分別加載2種緩存數據

/**
	 * <b>簡要說明:初始化緩存數據結構</b><br> 
	 * Create on 2015-7-23 下午3:50:10 <br>
	 * @author 翁加林
	 */
	public static void initCache(){
		Map<String, Object> loadDictCache = loadDictCache();//字典數據
		Map<String, Object> loadConfigTypeCache = loadConfigTypeCache();//配置項
		
		cacheMap.put(PubConstants.DICT_CLIENT_CACHE, loadDictCache);
		cacheMap.put(PubConstants.CONFIG_TYPE_CACHE, loadConfigTypeCache);
		
		log.debug("...CacheClient initCache data : "+cacheMap);
	}

               這裏分別加載了2種數據,咱們分開來說。

        第三步:加載字典數據:loadDictCache()

/**
	 * <b>簡要說明:從數據庫加載枚舉數據到緩存結構中</b><br> 
	 * Create on 2015-7-23 下午3:01:47 <br>
	 * @author 翁加林
	 */
	private static Map<String, Object> loadDictCache(){
		log.debug("...CacheClient loadDictCache start....");
		//從數據庫中獲取全部字典類型
		List<String> dictTypes = cacheService.getDictTypes();
		log.debug("...CacheClient loadDictCache 共加載"+dictTypes.size()+"種類型枚舉數據");
		Map<String, Object> dictCaches = getDictCaches();
		//獲取全部類型對應的字典數據,並保存至緩存結構
		for(String dictType : dictTypes){
			Map<String,Object> dict =  cacheService.getDictByType(dictType);
			dictCaches.put(dictType, dict);
		}
		log.debug("...CacheClient loadDictCache end....");
		return dictCaches;
	}

       從代碼中能夠看出,這裏咱們調用cacheService來進行數據查詢,在其底層就是經過dao層調用mybatis方式查詢數據庫並獲取數據。

       不過這裏有個問題:咱們的cacheService對象咋來滴?

       答:咱們搭建的環境中全部service都是交由spring上下文管理的,因此從裏面抓就好了。

       問:咋抓?

       答: 能夠經過註解方式實現:

/**
	 * <b>描述:緩存服務</b>
	 */
	@Autowired
	private static ICacheService cacheService = null;

        不過灑家不是這麼幹的,吾讓CacheClient實現了ApplicationContextAware接口,經過:

/**
	 * 重載函數:注入上下文,從中獲取ICacheService操做緩存數據及配置項對象
	 * (non-Javadoc)
	 * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
	 */
	@Override
	public void setApplicationContext(ApplicationContext context)
			throws BeansException {
		cacheService = (ICacheService) context.getBean("cacheService");
		log.debug("...CacheClient setApplicationContext and get cacheService : "+cacheService);
		configType = (ConfigType) context.getBean("configType");
		log.debug("...CacheClient setApplicationContext and get ConfigType : "+configType);
	}

         得到cacheService實例,因此在loadDictCache()中才能正常調用

         固然,實現這個接口並要讓Spring上下文把cacheService對象注入到CacheClient,CacheClient也必須添加註解才行啊。

@Component
public class CacheClient implements ApplicationContextAware{
...
}

        dao層查數不是我本文關注的重點,無視......

            第四步:加載配置項數據:loadConfigTypeCache

     這貨有些麻煩,簡單來講就是這樣一個流程:

           1:經過xml定義一個咱們配置項內容的結構

<mtag:configType id="configType">
		<mtag:configItem classKey="org.wjlmgqs.mtag.sso.config.ISocailLoginConfig" >
			<mtag:configPart classKey="org.wjlmgqs.mtag.sso.config.BaiduConfig"></mtag:configPart>
			<mtag:configPart classKey="org.wjlmgqs.mtag.sso.config.QQConfig"></mtag:configPart>
		</mtag:configItem>
		......
	</mtag:configType>

           2:經過java代碼讀取並解析xml,並轉換爲咱們以前分析的Map數據結構(實際上這裏我是經過Spring自定義標籤的方式實現的,咱們後面詳解)

            第五步:拿到2個Map數據結構後,就像第二步代碼中看到的同樣,根據常量ID扔進CacheClient的cacheMap中就ok啦

 

三:經過Spring自定義標籤形式實現配置項類型數據的緩存數據結構解析及加載

    經過Spring自定義標籤形式實現配置項類型數據的緩存數據結構解析及加載:在上一篇幅中,咱們瞭解到能夠經過xml形式定義咱們的配置項類型數據及其結構,而後由Spring來解析這些標籤並轉換爲咱們須要的數據結構。那麼讓Spring來識別咱們自定義標籤咱們須要幹些啥呢?

         咱們先要了解下,自定義Spring標籤都須要些啥東西:

         1:寫本身的xml文件和裏面自定義的標籤唄

         2:你要知道每個規範的xml文件都有對應的一個xsd文件來規範xml中出現的每個標籤的格式:這個<mtag:configType>標籤最多能出現幾回,它有哪些字節點,它有啥屬性等

         3:你定義的xml文件誰來解析啊?你得指定個和Spring打交道的類來幫你解析吧?那就來個實現了NamespaceHandlerSupport接口的類:ConfigTypeHandler

        4:這實現了NamespaceHandlerSupport接口後,並重寫了默認的init方法後,發現handler須要調用一些繼承了AbstractSimpleBeanDefinitionParser的parser來解析你本身寫的每個標籤:<mtag:configType>、<mtag:configItem>、<mtag:configPart>,而後在handler中註冊一下:

@Override
	public void init() {
		log.debug("...ConfigTypeHandler start...");
		// TODO Auto-generated method stub
		registerBeanDefinitionParser("configType",new ConfigTypeParser());
		registerBeanDefinitionParser("configItem",new ConfigItemParser());
		registerBeanDefinitionParser("configPart",new ConfigPartParser());
		log.debug("...ConfigTypeHandler end...");
	}

         5:你們也都知道Spring在xml中檢測到bean標籤後會根據指定的class來實現化一個javabean對象,其實也是經過Parser來幫咱們轉換成對應的javabean對象的,那麼咱們自定義標籤也同樣,須要給每一個標籤都定義一個javabean對象,它在解析標籤後就直接給咱們返回咱們須要的javabean對象了。

            這些javabean對象子元素和屬性都要和配置標籤對應屬性保持一致(感受好麻煩的說),注意咱們是三級嵌套的標籤哈~

        6:咱們定義的標籤都是mtag開頭的,那麼怎麼把這類<mtag>開頭的標籤和咱們的handler映射起來呢?

            答:在META-INF下創建spring.handlers,並配置:

http\://www.wjlmgqs.org/schema/mtag=org.wjlmgqs.mtag.core.config.ConfigTypeHandler

        7:看上面的圖,咱們知道咱們很裝逼的指定了咱們xsd文件的位置在:http://www.wjlmgqs.org/schema/mtag/config-type.xsd,其實大爺如今連個域名和雲服務器都買不起,又咋給你放着破配置文件哈,因此咱們要很裝逼的映射下這個路徑到咱們本地路徑(項目路徑)下面

            在META-INF下創建spring.schemas,並配置:

http\://www.wjlmgqs.org/schema/mtag/config-type.xsd=org/wjlmgqs/mtag/core/config/config-type.xsd

 

    綜上,就是咱們自定Spring標籤須要的東西,在搞這些東西的時候還碰到一些問題,以下:

       一:在xml中寫出標籤後,第一行總有個紅叉,提示:

Referenced file contains errors (http://www.wjlmgqs.org/schema/mtag/config-type.xsd). For more information, right click on the message in the Problems View and 

 select "Show Details..."

          而後我還真看了:   

        說是xsd定義有問題,我反覆檢查,反覆檢查,沒看出個球。

        一樣xsd文件也一直報個錯:

       

        一樣檢查出個球。

      二:默認META-INF目錄以下圖:

            

              不在classpath路徑下面,這樣運行工程後會出現以下異常:org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Failed to import bean definitions from relative location [beans-config-type.xml]

              因而乎,我看了看spring是怎麼搞的:

               

               很直接,是classpath下面的,因而我把META-INF文件都放到了src/main/resources下面:

                  

              擦,不報錯了。

 

注:代碼太多,貼上很亂,後面我整理工程上傳。

這裏列下標籤對應的文件在我工程裏的位置:

 

四:對method作統一的起始&結束的日誌處理(切面方式)

    正常狀況下:咱們經過url訪問某個ui請求對應method,裏面都有不少service以及適當的日誌輸出,當日志內容較多的時候,咱們可能就分不清楚哪些日誌是哪一個方法裏執行出來的日誌,或者說是爲了更好、更快的定位到咱們須要的日誌。因此,這裏咱們簡單的經過AOP方式爲method包裹一層日誌處理。

        先簡單描述下,咱們要實現的方式:咱們自定義一個註解(LogSign),在咱們須要日誌處理的method方法體上添加該註解,當咱們的請求方法遇到LogSign註解時,會自動調用咱們自定義的一個切面類(LogSignService),並執行裏面的@Around標註的log()方法,在這個方法中輸出起始日誌,執行method方法,輸出結束日誌等。

       具體步奏:

            1:自定義註解LogSign

/**
 * LogSign.java<br>
 * <b>功能:定義日誌註解,標有該註解的service進行日誌切面攔截</b><br>
 * @author 翁加林 Email:wjlmgqs@sina.com
 * Time:2015-7-22 下午4:28:13
 */
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface LogSign {
	String beforeMsg() default "";
	String endMsg() default "";
}

          2:自定義切面LogSignService

/**
 * LogSignService.java<br>
 * <b>功能:定義日誌服務切面,被攔截的方法先後插入日誌信息(execution中限定:只platform路徑下有效)
 * 	   在beanx.xml中配置了代理實現方式爲代理類,因此所在類必須有默認構造函數
 * </b><br>
 * @author 翁加林 Email:wjlmgqs@sina.com
 * Time:2015-7-22 下午4:25:41
 */
@Aspect
@Component
public class LogSignService extends BaseService implements ApplicationContextAware{
	
	private static Logger log = LoggerFactory.getLogger("org.wjlmgqs.mtag.platform");

	//環繞通知方法
    @Around("execution(* org.wjlmgqs.mtag.platform..*.*(..))")
	public Object log(ProceedingJoinPoint point) throws Throwable{
    	//獲取被攔截的對象及其執行方法
        Object target = point.getTarget();  // 攔截的實體類
        String className = target.getClass().getName();
        String methodName = point.getSignature().getName(); // 攔截的方法名稱
        Class<?>[] parameterTypes = ((MethodSignature) point.getSignature()).getMethod().getParameterTypes();  // 攔截的放參數類型
        Method method = target.getClass().getMethod(methodName,parameterTypes);
        Object object = null;
        if(method != null && method.isAnnotationPresent(LogSign.class)) {
        	LogSign annotation = method.getAnnotation(LogSign.class);
        	String beforeMsg = "--->>>執行"+className+"類的"+methodName+"方法--開始";
        	String endMsg = "---->>>執行"+className+"類的"+methodName+"方法--結束";
        	if(!StringUtils.isEmpty(annotation.beforeMsg())){
        		beforeMsg = annotation.beforeMsg();
        	}
        	if(!StringUtils.isEmpty(annotation.endMsg())){
        		endMsg = annotation.endMsg();
        	}
        	log.debug(beforeMsg);
            object = point.proceed();// 執行該方法
            log.debug(endMsg);
        } else { // 沒有包含該註解則不進行其餘處理
            object = point.proceed();// 執行該方法
        }
        return object;
	}

	@Override
	public void setApplicationContext(ApplicationContext arg0)
			throws BeansException {
		// TODO Auto-generated method stub
	}
	
}

      3:建一個測試類Test.java

@Controller
@RequestMapping(value="http://my.oschina.net/test/json")  
public class Test extends BasePlatformUI{
    
	private static Logger log = LoggerFactory.getLogger(Test.class);
	
    /**
     * <b>簡要說明:測試輸出json格式數據</b><br> 
     * Create on 2015-7-30 下午5:06:04 <br>
     * @author 翁加林
     */
    @RequestMapping(value="http://my.oschina.net/write")  
    @ResponseBody   
    @LogSign
    public String write(HttpServletRequest request,HttpSession session) throws Exception{  
        ModelAndView mav = new ModelAndView();  
        ModelMap modelMap = new ModelMap();  
        modelMap.put("mapKey", "mapValue");  
        modelMap.addAttribute("attributeKey", "attributeValue");  
        mav.addObject("model", modelMap);  
        mav.addObject("modelMap", modelMap);  
        String writeValueAsString = super.writeJson(mav);
        log.debug("...測試數據:"+writeValueAsString);
        return writeValueAsString;  
    }  
}

          這裏將map對象轉換爲json字符串是經過jackjson實現的,代碼以下:

/**
	 * <b>簡要說明:將對象轉換爲Json字符串</b><br> 
	 * Create on 2015-7-31 上午10:45:22 <br>
	 * @author 翁加林
	 */
	public String writeJson(Object obj){
		ObjectMapper mapper = new ObjectMapper();
		String msg = null;
        try {
        	msg = mapper.writeValueAsString(obj);
		}catch (Exception e) {
			log.error("...BasePlatformUI writeJson parse error : "+e.getMessage());
		}
        return msg ;
	}

  4:效果

 

五:LogBack日誌文件配置&中文亂碼&MyBatis日誌不輸出SQL。

    個人代碼按照本身的習慣進行了模塊劃分,因此也但願輸出的日誌能各回各家各找各媽(按照目錄分別輸出)

    我目前幾個核心的模塊劃分爲:core、platform、sso,因此,我但願這幾個目錄的代碼日誌可以分別輸出到core.log、mybatis.log、platform.log;

    另外,我但願mybatis啓動、讀取文件等操做日誌輸出到mybatis.log,查詢數據庫的sql語句輸出到sql.log、全部的錯誤消息統一輸出到error.log(指定error級別)。

       實現上述的功能,只須要2種配置方式就成:

       第一:錯誤消息統一輸出到error.log,使用root配置

    <!-- 走默認方式輸出ERROR到單獨文件 -->
    <root level="DEBUG">   
        <appender-ref ref="error" />   
    </root>

       第二種:按照目錄輸出到對應的日誌文件,相似下面貼出代碼,只要修改各自模塊路徑就成

<!-- 按照包路徑輸出DEBUG級日誌 -->
  	<logger name="org.wjlmgqs.mtag.platform" level="DEBUG">
  		<appender-ref ref="platform" />   
  	</logger>

        不過這裏須要提出和注意的2個地方:

              1:mybatis等操做日誌的包路徑指定爲:org.mybatis,就成。

              2:mybatis執行sql語句默認輸出是按照mapper文件(xml)中的namespace路徑,因此我這裏將namespace路徑指定爲mapper文件的包路徑

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.wjlmgqs.mtag.mapper.Dict">

    <select id="getDictTypes" resultType="string" >
       	SELECT DISTINCT ID FROM MT_DATA_DICT 
    </select>
    
    <select id="getDictByType" parameterType="string" resultType="Dict" >
       	SELECT ID,DICT_KEY AS dictKey,DICT_VALUE AS dictValue,SUBJ FROM MT_DATA_DICT WHERE ID = #{value} 
			<!-- ORDER BY SEQ  -->
    </select>

</mapper>

這樣子,幾種輸出類型咱們都定好了,咱們剩下來須要作的就是爲每一個logger和root中的ref指定appender對象,基本配置以下:

    <appender name="core" class="ch.qos.logback.core.rolling.RollingFileAppender">   
        <Encoding>UTF-8</Encoding>   
        <File>${LOG_HOME}/core.log</File>
        <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">   
            <FileNamePattern>${LOG_HOME}/core%i.log</FileNamePattern>   
            <MinIndex>1</MinIndex>
            <MaxIndex>5</MaxIndex>
        </rollingPolicy>   
        <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
        	<MaxFileSize>5MB</MaxFileSize>
        </triggeringPolicy>
        <encoder>   
            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset>
        </encoder>   
    </appender>

另外,由於error只輸出error級別日誌,因此須要在它的<appender>下添加一個過濾器:

        <filter class="ch.qos.logback.classic.filter.LevelFilter">
          <level>ERROR</level>
          <onMatch>ACCEPT</onMatch>
          <onMismatch>DENY</onMismatch>
        </filter>

醬紫:咱們整體配置就完了,這裏面已經處理了sql日誌輸出的問題,可是還隱藏了另外一個問題:部分jar中會輸出一些中文亂碼(GBK編碼,咱們整體環境都是UTF-8),雖然咱們的appender中指定了編碼格式、tomcat也指定了(server.xml):

   <Connector port="80" protocol="HTTP/1.1" 
               connectionTimeout="20000" 
               redirectPort="8443" URIEncoding="UTF-8" />

但仍是亂碼,通過搜索嘗試,發現須要設置咱們tomcat容器啓動編碼(catalina.bat):

if not exist "%CATALINA_BASE%\conf\logging.properties" goto noJuli
set JAVA_OPTS=%JAVA_OPTS% -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djava.util.logging.config.file="%CATALINA_BASE%\conf\logging.properties" -Dfile.encoding="UTF-8" -Dsun.jnu.encoding="UTF-8"
:noJuli

其中,下面這部分是我追加上去的:

-Dfile.encoding="UTF-8" -Dsun.jnu.encoding="UTF-8" 

 

轉自 http://www.07net01.com/2015/08/889518.html

相關文章
相關標籤/搜索