SpringBoot基礎學習筆記 -- SpringBoot基礎入門

基本概念
Spring Boot讓我們的Spring應用變的更輕量化。比如:你可以僅僅依靠一個Java類來運行一個Spring引用。你也可以打包你的應用爲jar並通過使用java -jar來運行你的Spring Web應用。
Spring Boot的主要優點:
爲所有Spring開發者更快的入門
開箱即用,提供各種默認配置來簡化項目配置
內嵌式容器簡化Web項目
沒有冗餘代碼生成和XML配置的要求。

基礎程序搭建過程解析:
(1)首先進行創建基礎項目maven web工程,注意打包方式爲jar文件。
(2)配置環境信息:pom文件依賴

<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.3.3.RELEASE</version>
	</parent>
	<dependencies>
	  <!—SpringBoot web 組件 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
	</dependencies>

備註:
spring-boot-starter-parent作用:
在pom.xml中引入spring-boot-start-parent,spring官方的解釋叫stater poms,它可以提供dependency management,也就是說依賴管理,引入以後在申明其它dependency的時候就不需要version了,後面可以看到。
spring-boot-starter-web作用
springweb 核心組件
spring-boot-maven-plugin作用
如果我們要直接Main啓動spring,那麼以下plugin必須要添加,否則是無法啓動的。如果使用maven 的spring-boot:run的話是不需要此配置的。

基礎程序: HelloWorld

/*
1 在上加上RestController 表示修飾該Controller所有的方法返回JSON格式,直接可以編寫
Restful接口
2 @EnableAutoConfiguration
註解:作用在於讓 Spring Boot   根據應用所聲明的依賴來對 Spring 框架進行自動配置, 這個註解告訴Spring Boot根據添加的jar依賴猜測你想如何配置Spring。由於spring-boot-starter-web添加了Tomcat和Spring MVC,所以auto-configuration將假定你正在開發一個web應用並相應地對Spring進行設置。
*/
@RestController
@EnableAutoConfiguration
public class HelloController {
	@RequestMapping("/hello")
	public String index() {
		return "Hello World";
	}	
public static void main(String[] args) {
//SpringBoot的啓動類
		SpringApplication.run(HelloController.class, args);
	}
}

之後進行在瀏覽器初入相應的地址,即可完成訪問查看到返回的效果

啓動方式二:

//設置掃描包的範圍
@ComponentScan(basePackages = "com.xiaojun.controller")
@EnableAutoConfiguration
public class App {
	public static void main(String[] args) {
		SpringApplication.run(App.class, args);
	}
}

WEB基礎目錄結構:

在我們開發Web應用的時候,需要引用大量的js、css、圖片等靜態資源。
默認配置
Spring Boot默認提供靜態資源目錄位置需置於classpath下,目錄名需符合如下規則:
/static
/public
/resources
/META-INF/resources
舉例:我們可以在src/main/resources/目錄下創建static,在該位置放置一個圖片文件。啓動程序後,嘗試訪問http://localhost:8080/D.jpg。如能顯示圖片,配置成功。

系統異常處理:

@ControllerAdvice
public class GlobalExceptionHandler {
	@ExceptionHandler(RuntimeException.class)
	@ResponseBody
	public Map<String, Object> exceptionHandler() {
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("errorCode", "400");
		map.put("errorMsg", "系統異常!");
		return map;
	}
}

註解備註:
@ExceptionHandler 表示攔截異常
@ControllerAdvice 是 controller 的一個輔助類,最常用的就是作爲全局異常處理的切面類
@ControllerAdvice 可以指定掃描範圍
@ControllerAdvice 約定了幾種可行的返回值,如果是直接返回 model 類的話,需要使用 @ResponseBody 進行 json 轉換
返回 String,表示跳到某個 view
返回 modelAndView
返回 model + @ResponseBody

web頁面渲染處理:
渲染Web頁面
在之前的示例中,我們都是通過@RestController來處理請求,所以返回的內容爲json對象。那麼如果需要渲染html頁面的時候,要如何實現呢?
模板引擎
在動態HTML實現上Spring Boot依然可以完美勝任,並且提供了多種模板引擎的默認配置支持,所以在推薦的模板引擎下,我們可以很快的上手開發動態網站。
Spring Boot提供了默認配置的模板引擎主要有以下幾種:
Thymeleaf
FreeMarker
Velocity
Groovy
Mustache
Spring Boot建議使用這些模板引擎,避免使用JSP,若一定要使用JSP將無法實現Spring Boot的多種特性,具體可見後文:支持JSP的配置
當你使用上述模板引擎中的任何一個,它們默認的模板配置路徑爲:src/main/resources/templates。當然也可以修改這個路徑,具體如何修改,可在後續各模板引擎的配置屬性中查詢並修改。

FreeMarker基礎配置:

<!-- 引入freeMarker的依賴包. -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>

application.properties配置

########################################################
###FREEMARKER (FreeMarkerAutoConfiguration)
########################################################
spring.freemarker.allow-request-override=false
spring.freemarker.cache=true
spring.freemarker.check-template-location=true
spring.freemarker.charset=UTF-8
spring.freemarker.content-type=text/html
spring.freemarker.expose-request-attributes=false
spring.freemarker.expose-session-attributes=false
spring.freemarker.expose-spring-macro-helpers=false
#spring.freemarker.prefix=
#spring.freemarker.request-context-attribute=
#spring.freemarker.settings.*=
spring.freemarker.suffix=.ftl
spring.freemarker.template-loader-path=classpath:/templates/
#comma-separated list
#spring.freemarker.view-names= # whitelist of view names that can be resolved

測試代碼段:

@RequestMapping("/index")
	public String index(Map<String, Object> map) {
	    map.put("name","###小俊###");
	    map.put("sex",1);
	    List<String> userlist=new ArrayList<String>();
	    userlist.add("王五");
	    userlist.add("張三");
	    userlist.add("李四");
	    map.put("userlist",userlist);
	    return "index";
	}

前臺常用點:

<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8" />
<title>首頁</title>
</head>
<body>
	  ${name}
	  <#if sex==1>
            男
      <#elseif sex==2>
            女
     <#else>
        其他      
	  
	  </#if>
	  
	 <#list userlist as user>
	   ${user}
	 </#list>
</body> 
</html>

集成JSP:

<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.3.3.RELEASE</version>
	</parent>
	<dependencies>
		<!-- SpringBoot 核心組件 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-tomcat</artifactId>
		</dependency>
		<dependency>
			<groupId>org.apache.tomcat.embed</groupId>
			<artifactId>tomcat-embed-jasper</artifactId>
		</dependency>
	</dependencies>

視圖解析器配置:

spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp

SpringBoot整合Mybatis:
pom.xml依賴配置
主要配置的點:
1、org.mybatis.spring.boot
2、mysql-connector-java
3、org.springframework.boot(配置SpringBoot web)

<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.3.2.RELEASE</version>
		<relativePath /> <!-- lookup parent from repository -->
	</parent>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>1.1.1</version>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.21</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
	</dependencies>

application.properties文件配置:

spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

測試代碼實現類:

public interface UserMapper {
	@Select("SELECT * FROM USERS WHERE NAME = #{name}")
	User findByName(@Param("name") String name);
	@Insert("INSERT INTO USERS(NAME, AGE) VALUES(#{name}, #{age})")
	int insert(@Param("name") String name, @Param("age") Integer age);
}

//配置掃描的包路徑
@ComponentScan(basePackages = "com.xiaojun")
@MapperScan(basePackages = "com.xiaojun.mapper")
@SpringBootApplication
public class App {
	public static void main(String[] args) {
		SpringApplication.run(App.class, args);
	}
}

SpringBoot整合多數據源開發:
首先解釋下多數據源的概念:所謂多數據源就是在系統之中有配置多個數據庫

application.properties

spring.datasource.test1.driverClassName = com.mysql.jdbc.Driver
spring.datasource.test1.url = jdbc:mysql://localhost:3306/test01?useUnicode=true&characterEncoding=utf-8
spring.datasource.test1.username = root
spring.datasource.test1.password = root

spring.datasource.test2.driverClassName = com.mysql.jdbc.Driver
spring.datasource.test2.url = jdbc:mysql://localhost:3306/test02?useUnicode=true&characterEncoding=utf-8
spring.datasource.test2.username = root
spring.datasource.test2.password = root

application.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:tx="http://www.springframework.org/schema/tx" 
	xmlns:task="http://www.springframework.org/schema/task"
	xmlns:p="http://www.springframework.org/schema/p"
	xmlns:util="http://www.springframework.org/schema/util"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="http://www.springframework.org/schema/beans  
    http://www.springframework.org/schema/beans/spring-beans-4.1.xsd   
    http://www.springframework.org/schema/context   
    http://www.springframework.org/schema/context/spring-context-4.1.xsd  
    http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx-4.1.xsd
    http://www.springframework.org/schema/task 
    http://www.springframework.org/schema/task/spring-task-4.1.xsd    
    http://www.springframework.org/schema/util
    http://www.springframework.org/schema/util/spring-util-4.2.xsd 
    http://www.springframework.org/schema/aop 
     http://www.springframework.org/schema/aop/spring-aop-4.1.xsd"
	default-lazy-init="false">
 
    <aop:aspectj-autoproxy/>
    
    <context:component-scan base-package="xxx.xxx.xxx"/>
    
	<!-- 定時器開關 開始 -->
	<task:annotation-driven />
 
 
	<!-- 引入配置文件 -->
	<bean id="propertyConfigurer"
		class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
		<property name="location" value="classpath:jdbc.properties" />
	</bean>
 
	<bean id="adminDataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
		<property name="driverClassName" value="${admin.jdbc.driver}" />
		<property name="url" value="${admin.jdbc.url}" />
		<property name="username" value="${admin.jdbc.username}" />
		<property name="password" value="${admin.jdbc.password}" />
		<!-- 初始化連接大小 -->
		<property name="initialSize" value="${admin.jdbc.initialSize}"></property>
		<!-- 連接池最大數量 -->
		<property name="maxActive" value="${admin.jdbc.maxActive}"></property>
		<!-- 連接池最大空閒 -->
		<property name="maxIdle" value="${admin.jdbc.maxIdle}"></property>
		<!-- 連接池最小空閒 -->
		<property name="minIdle" value="${admin.jdbc.minIdle}"></property>
		<!-- 獲取連接最大等待時間 -->
		<property name="maxWait" value="${admin.jdbc.maxWait}"></property>
		<!-- 配置間隔多久才進行一次檢測,檢測需要關閉的空閒連接,單位是毫秒 -->
		<property name="timeBetweenEvictionRunsMillis" value="60000" />
		<!-- 配置一個連接在池中最小生存的時間,單位是毫秒 -->
		<property name="minEvictableIdleTimeMillis" value="300000" />
		<property name="validationQuery" value="SELECT 'x'" />
		<property name="testWhileIdle" value="true" />
		<property name="testOnBorrow" value="true" />
		<property name="testOnReturn" value="true" />
		<!-- 打開PSCache,並且指定每個連接上PSCache的大小 -->
		<property name="poolPreparedStatements" value="true" />
		<property name="maxPoolPreparedStatementPerConnectionSize" value="20" />
		<!-- 配置監控統計攔截的filters -->
		<property name="filters" value="stat,log4j" />
	</bean>
	
	
	<bean id="appDataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
		<property name="driverClassName" value="${app.jdbc.driver}" />
		<property name="url" value="${app.jdbc.url}" />
		<property name="username" value="${app.jdbc.username}" />
		<property name="password" value="${app.jdbc.password}" />
		<!-- 初始化連接大小 -->
		<property name="initialSize" value="${app.jdbc.initialSize}"></property>
		<!-- 連接池最大數量 -->
		<property name="maxActive" value="${app.jdbc.maxActive}"></property>
		<!-- 連接池最大空閒 -->
		<property name="maxIdle" value="${app.jdbc.maxIdle}"></property>
		<!-- 連接池最小空閒 -->
		<property name="minIdle" value="${app.jdbc.minIdle}"></property>
		<!-- 獲取連接最大等待時間 -->
		<property name="maxWait" value="${app.jdbc.maxWait}"></property>
		<!-- 配置間隔多久才進行一次檢測,檢測需要關閉的空閒連接,單位是毫秒 -->
		<property name="timeBetweenEvictionRunsMillis" value="60000" />
		<!-- 配置一個連接在池中最小生存的時間,單位是毫秒 -->
		<property name="minEvictableIdleTimeMillis" value="300000" />
		<property name="validationQuery" value="SELECT 'x'" />
		<property name="testWhileIdle" value="true" />
		<property name="testOnBorrow" value="true" />
		<property name="testOnReturn" value="true" />
		<!-- 打開PSCache,並且指定每個連接上PSCache的大小 -->
		<property name="poolPreparedStatements" value="true" />
		<property name="maxPoolPreparedStatementPerConnectionSize" value="20" />
		<!-- 配置監控統計攔截的filters -->
		<property name="filters" value="stat,log4j" />
	</bean>
	
	
	<bean id="multipleDataSource" class="xxx.xxx.xxx....MultipleDataSource">
        <property name="defaultTargetDataSource" ref="adminDataSource"/>
        <property name="targetDataSources">
            <map>
                <entry key="adminDataSource" value-ref="adminDataSource"/>
                <entry key="appDataSource" value-ref="appDataSource"/>
            </map>
        </property>
    </bean>
 
 
	<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="dataSource" ref="multipleDataSource" />
		<property name="mapperLocations" value="classpath*:mapper/*.xml"></property>
		<property name="configLocation" value="classpath:mybatis-config.xml"></property>
		<property name="plugins">
		    <array>
		      <bean class="com.github.pagehelper.PageHelper">
		        <property name="properties">
		          <value>
		            dialect=mysql
		            reasonable=true
		          </value>
		        </property>
		      </bean>
		    </array>
	   </property>
	</bean>
 
	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
		<property name="basePackage" value="xxx.xxx.xxx.mapper,yyy.yyy.yyy.yyy.mapper" />
		<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
	</bean>
	
	<tx:annotation-driven transaction-manager="transactionManager" />
 
    <bean id="transactionManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
        p:dataSource-ref="multipleDataSource"/>
        
 
</beans>

DataSource類

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
/**
 * 設置切換數據庫數據源
 */
 /*
備註:
我們就簡單的配置好了兩個數據源,一個屬於admin的,一個屬於app
,默認是接入admin的數據源。在MultipleDataSource
 中的靜態屬性值分別對應在application.xml中配置好的bean id。
 因爲可能具體的業務操作是通過引入已經寫好dao、service層,
 包括sql映射文件的jar包,因此mybatis的mapper掃描我們可以通過,
 分割來配置掃描多個包,xml的掃描也配置掃描全部jar包下的所有文件,
 classpath*:mapper/*.xml。這樣後臺管理其實只要寫個Controller來接受請求,
 所有的業務調用都引用相應工程的jar包,相對來說還是挺方便的。

以上的配置已經可以讓項目跑起來,對於操作admin數據源自有的表來說不會報什麼錯,
當操作到app數據源的表就會報在admin數據庫中不存在某某表,這是因爲我們還沒有對數據源的切換進行配置,本來以爲一路下來會順風順水,但最重要的也是最折騰的地方在於下面的數據源切換上。
*/
public class MultipleDataSource extends AbstractRoutingDataSource {
    public static final String DATA_SOURCE_ADMIN = "adminDataSource";
    public static final String DATA_SOURCE_APP = "appDataSource";
    private static final ThreadLocal<String> dataSourceKey = new InheritableThreadLocal<String>();
    public static void setDataSourceKey(String dataSource) {
        dataSourceKey.set(dataSource);
    }
    @Override
    protected Object determineCurrentLookupKey() {
        return dataSourceKey.get();
    }
    public static void removeDataSourceKey(){
    	dataSourceKey.remove();
    }
}

以AOP方式進行切換數據源操作

import java.lang.reflect.Proxy;
import org.apache.commons.lang.ClassUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
/**
 * 數據源切換AOP
 */
@Component
@Aspect
public class MultipleDataSourceInterceptor {
	/**
	 * 攔截器對所有的業務實現類請求之前進行數據源切換
	 * 特別注意,由於用到了多數據源,Mapper的調用最好只在*ServiceImpl,不然調用到非默認數據源的表時,會報表不存在的異常
	 * @param joinPoint
	 * @throws Throwable
	 */
	@Before( "execution(* xxx.xxx.xxx..*.*ServiceImpl.*(..))")
    public void setDataSoruce(JoinPoint joinPoint) throws Throwable {
		Class<?> clazz = joinPoint.getTarget().getClass();
        String className = clazz.getName();
        if (ClassUtils.isAssignable(clazz, Proxy.class)) {
            className = joinPoint.getSignature().getDeclaringTypeName();
        }
        //對類名含有business的設置爲app數據源,否則默認爲後臺的數據源
        if(className.contains(".business.")){
        	MultipleDataSource.setDataSourceKey(MultipleDataSource.DATA_SOURCE_APP);
        }else{
        	MultipleDataSource.setDataSourceKey(MultipleDataSource.DATA_SOURCE_ADMIN);
        }
    }
	/**
	 * 當操作完成時,釋放當前的數據源
	 * 如果不釋放,頻繁點擊時會發生數據源衝突,本是另一個數據源的表,結果跑到另外一個數據源去,報表不存在
	 * @param joinPoint
	 * @throws Throwable
	 */
	@After( "execution(* xxx.xxx.xxx..*.*ServiceImpl.*(..))")
    public void removeDataSoruce(JoinPoint joinPoint) throws Throwable {
		MultipleDataSource.removeDataSourceKey();
    }
}

第二種解決方案:運用註解結合報名的方式進行
properties配置文件信息

# Mysql 1
mysql.datasource.test.url = jdbc:mysql://localhost:3306/test01?useUnicode=true&characterEncoding=utf-8
mysql.datasource.test.username = root
mysql.datasource.test.password = root
mysql.datasource.test.minPoolSize = 3
mysql.datasource.test.maxPoolSize = 25
mysql.datasource.test.maxLifetime = 20000
mysql.datasource.test.borrowConnectionTimeout = 30
mysql.datasource.test.loginTimeout = 30
mysql.datasource.test.maintenanceInterval = 60
mysql.datasource.test.maxIdleTime = 60
mysql.datasource.test.testQuery = select 1

# Mysql 2
mysql.datasource.test2.url =jdbc:mysql://localhost:3306/test02?useUnicode=true&characterEncoding=utf-8
mysql.datasource.test2.username =root
mysql.datasource.test2.password =root
mysql.datasource.test2.minPoolSize = 3
mysql.datasource.test2.maxPoolSize = 25
mysql.datasource.test2.maxLifetime = 20000
mysql.datasource.test2.borrowConnectionTimeout = 30
mysql.datasource.test2.loginTimeout = 30
mysql.datasource.test2.maintenanceInterval = 60
mysql.datasource.test2.maxIdleTime = 60
mysql.datasource.test2.testQuery = select 1

基礎Bean讀取配置信息

import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "mysql.datasource.test")
public class DBConfig1 {
	private String url;
	private String username;
	private String password;
	private int minPoolSize;
	private int maxPoolSize;
	private int maxLifetime;
	private int borrowConnectionTimeout;
	private int loginTimeout;
	private int maintenanceInterval;
	private int maxIdleTime;
	private String testQuery;
}
//分別編寫不同Bean信息來進行耦合不同的數據源信息
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "mysql.datasource.test1")
public class DBConfig2 {
	private String url;
	private String username;
	private String password;
	private int minPoolSize;
	private int maxPoolSize;
	private int maxLifetime;
	private int borrowConnectionTimeout;
	private int loginTimeout;
	private int maintenanceInterval;
	private int maxIdleTime;
	private String testQuery;
}

創建多數據源基本信息

@Configuration
// basePackages 最好分開配置 如果放在同一個文件夾可能會報錯
@MapperScan(basePackages = "com.itmayiedu.test01", sqlSessionTemplateRef = "testSqlSessionTemplate")
public class TestMyBatisConfig1 {
	// 配置數據源
	@Primary
	@Bean(name = "testDataSource")
	public DataSource testDataSource(DBConfig1 testConfig) throws SQLException {
		MysqlXADataSource mysqlXaDataSource = new MysqlXADataSource();
		mysqlXaDataSource.setUrl(testConfig.getUrl());
		mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);
		mysqlXaDataSource.setPassword(testConfig.getPassword());
		mysqlXaDataSource.setUser(testConfig.getUsername());
		mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);
		AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
		xaDataSource.setXaDataSource(mysqlXaDataSource);
		xaDataSource.setUniqueResourceName("testDataSource");
		xaDataSource.setMinPoolSize(testConfig.getMinPoolSize());
		xaDataSource.setMaxPoolSize(testConfig.getMaxPoolSize());
		xaDataSource.setMaxLifetime(testConfig.getMaxLifetime());
		xaDataSource.setBorrowConnectionTimeout(testConfig.getBorrowConnectionTimeout());
		xaDataSource.setLoginTimeout(testConfig.getLoginTimeout());
		xaDataSource.setMaintenanceInterval(testConfig.getMaintenanceInterval());
		xaDataSource.setMaxIdleTime(testConfig.getMaxIdleTime());
		xaDataSource.setTestQuery(testConfig.getTestQuery());
		return xaDataSource;
	}
	@Bean(name = "testSqlSessionFactory")
	public SqlSessionFactory testSqlSessionFactory(@Qualifier("testDataSource") DataSource dataSource)
			throws Exception {
		SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
		bean.setDataSource(dataSource);
		return bean.getObject();
	}

	@Bean(name = "testSqlSessionTemplate")
	public SqlSessionTemplate testSqlSessionTemplate(
			@Qualifier("testSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
		return new SqlSessionTemplate(sqlSessionFactory);
	}
}
package com.itmayiedu.datasource;

import java.sql.SQLException;

import javax.sql.DataSource;

import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.atomikos.jdbc.AtomikosDataSourceBean;
import com.itmayiedu.config.DBConfig1;
import com.mysql.jdbc.jdbc2.optional.MysqlXADataSource;

@Configuration
// basePackages 最好分開配置 如果放在同一個文件夾可能會報錯
@MapperScan(basePackages = "com.itmayiedu.test02", sqlSessionTemplateRef = "test2SqlSessionTemplate")
public class TestMyBatisConfig2 {

	// 配置數據源
	@Bean(name = "test2DataSource")
	public DataSource testDataSource(DBConfig1 testConfig) throws SQLException {
		MysqlXADataSource mysqlXaDataSource = new MysqlXADataSource();
		mysqlXaDataSource.setUrl(testConfig.getUrl());
		mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);
		mysqlXaDataSource.setPassword(testConfig.getPassword());
		mysqlXaDataSource.setUser(testConfig.getUsername());
		mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);

		AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
		xaDataSource.setXaDataSource(mysqlXaDataSource);
		xaDataSource.setUniqueResourceName("test2DataSource");

		xaDataSource.setMinPoolSize(testConfig.getMinPoolSize());
		xaDataSource.setMaxPoolSize(testConfig.getMaxPoolSize());
		xaDataSource.setMaxLifetime(testConfig.getMaxLifetime());
		xaDataSource.setBorrowConnectionTimeout(testConfig.getBorrowConnectionTimeout());
		xaDataSource.setLoginTimeout(testConfig.getLoginTimeout());
		xaDataSource.setMaintenanceInterval(testConfig.getMaintenanceInterval());
		xaDataSource.setMaxIdleTime(testConfig.getMaxIdleTime());
		xaDataSource.setTestQuery(testConfig.getTestQuery());
		return xaDataSource;
	}

	@Bean(name = "test2SqlSessionFactory")
	public SqlSessionFactory testSqlSessionFactory(@Qualifier("test2DataSource") DataSource dataSource)
			throws Exception {
		SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
		bean.setDataSource(dataSource);
		return bean.getObject();
	}

	@Bean(name = "test2SqlSessionTemplate")
	public SqlSessionTemplate testSqlSessionTemplate(
			@Qualifier("test2SqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
		return new SqlSessionTemplate(sqlSessionFactory);
	}
}

SpringBoot日誌處理(AOP切面)

基礎配置信息
pom文件依賴:

<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-aop</artifactId>
	</dependency>

切面處理:

@Aspect
@Component
public class WebLogAspect {
	private Logger logger = LoggerFactory.getLogger(getClass());
	@Pointcut("execution(public * com.itmayiedu.controller..*.*(..))")
	public void webLog() {
	}
	@Before("webLog()")
	public void doBefore(JoinPoint joinPoint) throws Throwable {
		// 接收到請求,記錄請求內容
		ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
		HttpServletRequest request = attributes.getRequest();
		// 記錄下請求內容
		logger.info("URL : " + request.getRequestURL().toString());
		logger.info("HTTP_METHOD : " + request.getMethod());
		logger.info("IP : " + request.getRemoteAddr());
		Enumeration<String> enu = request.getParameterNames();
		while (enu.hasMoreElements()) {
			String name = (String) enu.nextElement();
			logger.info("name:{},value:{}", name, request.getParameter(name));
		}
	}
	@AfterReturning(returning = "ret", pointcut = "webLog()")
	public void doAfterReturning(Object ret) throws Throwable {
		// 處理完請求,返回內容
		logger.info("RESPONSE : " + ret);
	}
}

SpringBoot集成Ehcache緩存
使用目的 爲了減緩數據庫的壓力 主要來自數據檢索 默認首次查詢直接走DB 完後寫進緩存 下次查詢相同的邏輯 直接走緩存以此來進行達到減輕DB壓力的目的。

  • 好處:

1)提高性能;2)減緩數據庫壓力;3)提高系統併發處理能力

  • 使用緩存容易出現的問題:

1)處理邏輯變得複雜;2)使用不當,容易引起緩存和數據庫數據不一致的問題

  • 數據不一致性問題:

緩存操作與數據庫操作不是原子操作,當一方操作成功、另一方操作失敗時就會造成數據不一致問題
基礎環境信息配置:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>

在application.xml中進行配置
<!-- 啓用緩存註解功能,這個是必須的,否則註解不會生效,另外,該註解一定要聲明在spring主配置文件中才會生效 -->
    <cache:annotation-driven cache-manager="ehcacheManager"/>
    
    <!-- cacheManager工廠類,指定ehcache.xml的位置 -->
    <bean id="ehcacheManagerFactory" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
         <property name="configLocation" value="classpath:ehcache.xml" />
    </bean>
    <!-- 聲明cacheManager -->
    <bean id="ehcacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
         <property name="cacheManager" ref="ehcacheManagerFactory" />
    </bean>

需要格外進行聲明一個ehcache的xml文件

1. <!--  
2.       name:緩存名稱。  
3.       maxElementsInMemory:緩存最大個數。  
4.       eternal:對象是否永久有效,一但設置了,timeout將不起作用。  
5.       timeToIdleSeconds:設置對象在失效前的允許閒置時間(單位:秒)。僅當eternal=false對象不是永久有效時使用,可選屬性,默認值是0,也就是可閒置時間無窮大。  
6.       timeToLiveSeconds:設置對象在失效前允許存活時間(單位:秒)。最大時間介於創建時間和失效時間之間。僅當eternal=false對象不是永久有效時使用,默認是0.,也就是對象存活時間無窮大。  
7.       overflowToDisk:當內存中對象數量達到maxElementsInMemory時,Ehcache將會對象寫到磁盤中。  
8.       diskSpoolBufferSizeMB:這個參數設置DiskStore(磁盤緩存)的緩存區大小。默認是30MB。每個Cache都應該有自己的一個緩衝區。  
9.       maxElementsOnDisk:硬盤最大緩存個數。  
10.       diskPersistent:是否緩存虛擬機重啓期數據 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.  
11.       diskExpiryThreadIntervalSeconds:磁盤失效線程運行時間間隔,默認是120秒。  
12.       memoryStoreEvictionPolicy:當達到maxElementsInMemory限制時,Ehcache將會根據指定的策略去清理內存。默認策略是LRU(最近最少使用)。你可以設置爲FIFO(先進先出)或是LFU(較少使用)。  
13.       clearOnFlush:內存數量最大時是否清除。  
14.    --> 
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
	updateCheck="false">
	<diskStore path="java.io.tmpdir/Tmp_EhCache" />

	<!-- 默認配置 -->
	<defaultCache maxElementsInMemory="5000" eternal="false"
		timeToIdleSeconds="120" timeToLiveSeconds="120"
		memoryStoreEvictionPolicy="LRU" overflowToDisk="false" />

	<cache name="baseCache" maxElementsInMemory="10000"
		maxElementsOnDisk="100000" />

</ehcache>

測試代碼:
使用cacheable註解即可 清除緩存調用cacheManager之中的clear()即可

@CacheConfig(cacheNames = "baseCache")
public interface UserMapper {
	@Select("select * from users where name=#{name}")
	@Cacheable
	UserEntity findName(@Param("name") String name);
}

//緩存清除  具體執行環節在Controller之中進行調用cacheManager之中的clear()即可;
@Autowired
private CacheManager cacheManager;
@RequestMapping("/remoKey")
public void remoKey() {
	cacheManager.getCache("baseCache").clear();
} 

待思考問題 如如何進行確保DB數據與緩存的數據一致性問題?

在這裏插入代碼片

SpringBoot定時任務處理
使用註解開發 @Scheduled(fixedRate = 5000)

@Component
public class ScheduledTasks {
    private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
    @Scheduled(fixedRate = 5000)
    public void reportCurrentTime() {
        System.out.println("現在時間:" + dateFormat.format(new Date()));
    }
}

自定義參數配置
properties文件配置信息:

name=xiaojun
@Value("${name}")
	private String name;
	@ResponseBody
	@RequestMapping("/getValue")
	public String getValue() {
		return name;
	}

後續待更新。。。敬請期待

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章