SpringBoot學習筆記2 - 20181128
一.Springboot常見錯誤總結
- 控制檯亂碼問題(外掛啟動,控制檯亂碼問題)
在pom檔案,springboot外掛啟動中,增加如下(一些虛擬機器方法)
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<!-- spring-boot:run 中文亂碼解決 -->
<configuration>
<fork>true</fork>
<!--增加jvm引數-->
<jvmArguments>-Dfile.encoding=UTF-8</jvmArguments>
</configuration>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId >springloaded</artifactId>
<version>1.2.5.RELEASE</version>
</dependency>
</dependencies>
</plugin>
- 無法自動注入問題
①.包掃描錯誤,@MapperScan指定錯誤 或 @ComponentScan入口類位置錯誤
②.Mapper檔案錯誤,dao的實現類無法建立,導致無法注入 - yml檔案格式錯誤
- springboot的pom檔案中引入多餘jar包
- springboot的版本問題(springboot 2.0 使用 spring 5.x)
二.Springboot自帶日誌
- 預設使用 logback,相比log4j更輕量級,無需引入依賴或jar
- 匯入logback.xml 定製顯示資訊
- 日誌 (面試關鍵點)
- 級別
OFF > FATAL> ERROR > WARN > INFO > DEBUG > TRACE > ALL
-
OFF Level是最高等級的,用於關閉所有日誌記錄。
-
FATAL Level指出每個嚴重的錯誤事件將會導致應用程式的退出。
指出每個嚴重的錯誤事件將會導致應用程式的退出。這個級別比較高了。重大錯誤,這種級別你可以直接停止程式了。
- ERROR Level指出雖然發生錯誤事件,但仍然不影響系統的繼續執行。
指出雖然發生錯誤事件,但仍然不影響系統的繼續執行。列印錯誤和異常資訊,如果不想輸出太多的日誌,可以使用這個級別。
-
WARN Level表明會出現潛在錯誤的情形。
-
INFO Level表明 訊息在粗粒度級別上突出強調應用程式的執行過程。
訊息在粗粒度級別上突出強調應用程式的執行過程。列印一些你感興趣的或者重要的資訊,這個可以用於生產環境中輸出程式執行的一些重要資訊,但是不能濫用,避免列印過多的日誌。
-
DEBUG Level指出細粒度資訊事件對除錯應用程式是非常有幫助的。
-
TRACE Level較低的日誌級別,一般不會使用。
-
ALL Level是最低等級的,用於開啟所有日誌記錄。
ps:log4j建議只使用四個級別
- 兩個種類
①.根日誌:專案級別日誌,專案中所有指定的資訊都會被日誌展示出來。
②.子日誌:包級別/類級別的日誌,獲取指定包或類的日誌資訊。
- logback日誌框架使用
logback.xml (resources根目錄下)
<?xml version="1.0" encoding="UTF-8" ?>
<!--配置項-->
<configuration>
<!-- appender:日誌如何做展示的配置 name:展示配置的別名 class:日誌如何做展示-->
<appender name="out" class="ch.qos.logback.core.ConsoleAppender">
<!-- 展示佈局 -->
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern> [%p] %d{yyyy-MM-dd HH:mm:ss} %m %n</pattern>
</layout>
</appender>
<!-- 根日誌 -->
<root level="ERROR">
<appender-ref ref="out"/>
</root>
<!-- 子日誌 使用根日誌的展示配置-->
<logger name="com.abc.dao" level="DEBUG"/>
</configuration>
三.Springboot的熱部署
- 熱部署是什麼?
大家都知道在專案開發過程中,常常會改動頁面資料或者修改資料結構,為了顯示改動效果,往往需要重啟應用檢視改變效果,其實就是重新編譯生成了新的 Class 檔案,這個檔案裡記錄著和程式碼等對應的各種資訊,然後 Class 檔案將被虛擬機器的 ClassLoader 載入。
而熱部署正是利用了這個特點,它監聽到如果有 Class 檔案改動了,就會建立一個新的 ClaassLoader 進行載入該檔案,經過一系列的過程,最終將結果呈現在我們眼前。
- 使用 Spring Loaded
- 使用 spring-boot-devtools
- jrebel外掛
要求:springboot專案,電腦配置好
原理:
java編譯,使用類載入器,編譯成class檔案
jrebel使用兩個類載入器,一個在檔案執行時生效,一個在程式碼變動時類載入器生效
四.Springboot中面向切面程式設計(AOP)
- 回顧spring基於註解的aop開發(spring 4 提出概念,純註解開發)
- 引入aop註解依賴
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.7.1</version>
</dependency>
- 通知類上加上@Aspect,指定類為通知類
@Around(execution(* com.baizhi.service..(…))) 指定方法為環繞通知方法
- springboot基於註解的aop開發
- 引入依賴
<!-- Springboot的AOP支援 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
- 開發通知類
常用註解:
@Configuration
@Component
@Aspect //作用是把當前類標識為一個切面供容器讀取
@Before //標識一個前置增強方法,相當於BeforeAdvice的功能
@After //final增強,不管是丟擲異常或者正常退出都會執行
@Around //環繞增強,相當於MethodInterceptor
@AfterReturning //後置增強,相當於AfterReturningAdvice,方法退出時執行
@AfterThrowing //異常丟擲增強,相當於ThrowsAdvice
示例程式碼:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//使用在哪裡:方法生效
@Target({ElementType.METHOD})
//什麼時候生效
@Retention(RetentionPolicy.RUNTIME)
public @interface AspectAnnotion { //自定義註解
public String value() default "no search method~~~";
}
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
//@Component
@Configuration //開啟Spring相關自動配置
@Aspect //指定類為通知類
public class AspectDemo {
@Pointcut("execution(public * com.abc.service.*.*(..))")
public void pointCut(){
}
/**
* @Before 前置通知
* @param joinPoint
*/
@Before("execution(* com.abc.service.*.*(..))")
public void before(JoinPoint joinPoint){
System.out.println(joinPoint.getArgs()); //獲取引數
System.out.println(joinPoint.getTarget()); //獲取目標物件
System.out.println(joinPoint.getSignature().getName()); //獲取方法名
System.out.println("------------this is before-------------");
}
/**
* @Around 環繞通知
* @param proceedingJoinPoint
* @return
*/
@Around(value = "@annotation(com.baizhi.aspect.AspectAnnotion)")
public Object around(ProceedingJoinPoint proceedingJoinPoint){
//獲取方法上註解
//拿到方法method
MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
Method method = signature.getMethod();
//拿到類物件 反射
AspectAnnotion aspectAnnotion = method.getAnnotation(AspectAnnotion.class);
//通過反射拿到例項 呼叫方法 拿到自定義的方法名
String name = aspectAnnotion.value();
System.out.println(proceedingJoinPoint.getArgs()); //同joinPoint
try {
//前置
Object proceed = proceedingJoinPoint.proceed(); //放行目標方法
//後置
return proceed;
} catch (Throwable throwable) {
throwable.printStackTrace();
return null;
}
}
/**
* @After 後置通知
* @param joinPoint
*/
@After("pointCut()")
public void after(JoinPoint joinPoint) {
}
}
Proceedingjoinpoint 和 JoinPoint 的關係?
環繞通知=前置+目標方法執行+後置通知,proceed方法就是用於啟動目標方法執行的。
環繞通知 ProceedingJoinPoint 執行proceed方法的作用是讓目標方法執行,這也是環繞通知和前置、後置通知方法的一個最大區別。
Proceedingjoinpoint 繼承了 JoinPoint 。是在JoinPoint的基礎上暴露出 proceed 這個方法。proceed很重要,這個是aop代理鏈執行的方法。
暴露出這個方法,就能支援 aop:around 這種切面(而其他的幾種切面只需要用到JoinPoint,這跟切面型別有關), 能決定是否走代理鏈還是走自己攔截的其他邏輯。建議看一下JdkDynamicAopProxy的invoke方法,瞭解一下代理鏈的執行原理。
五.Springboot中攔截器的實現
- 回顧springMVC中如何實現攔截器
- 實現HandlerInterceptor介面,覆蓋preHandle(進入前)、postHandle(跳轉前)、afterCompletion(跳轉後)
- springmvc.xml中配置
<!--配置攔截器示例 student-->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<mvc:exclude-mapping path="/user/*"/>
<mvc:exclude-mapping path="/vcode/*"/>
<bean class="com.abc.interceptor.InterceptorController"/>
</mvc:interceptor>
</mvc:interceptors>
- springboot中實現攔截器
- 實現一個自定義攔截器
- 書寫配置類 extends WebMvcConfigurerAdapter
@EnableWebMvc
@Configuration //或者 @SpringBootConfiguration
public class InterceptorConfig extends WebMvcConfigurerAdapter {
//類似DI注入
@Bean
InterceptorController localInterceptor() {
return new InterceptorController();
}
//覆蓋springboot中的預設攔截器方法
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(localInterceptor())
.addPathPatterns("/menu/*") //攔截哪些
.excludePathPatterns("/user/*","/vcode/*"); //不攔截哪些
super.addInterceptors(registry);
}
}
注意:存在靜態資源丟失問題。。。
六.Springboot中上傳下載
- 在yml檔案中,修改上傳檔案大小限制
spring:
http:
multipart:
enabled: true
max-file-size: 30MB #上傳檔案限制大小
max-request-size: 30MB #限制檔案大小
- 上傳幾乎沒有什麼變化
- 下載,使用springboot內建FileCopyUtils.copy 方式
@RequestMapping("/download")
@ResponseBody
public void download(String filename, HttpServletRequest request, HttpServletResponse response) throws IOException {
//獲取檔案路徑
String realPath = request.getSession().getServletContext().getRealPath("/upload");
//找到檔案,獲取輸入流
File file = new File(realPath, filename);
FileInputStream fileInputStream = new FileInputStream(file);
//獲取響應型別
String substring = filename.substring(filename.lastIndexOf("."));
//設定響應型別
response.setContentType(substring);
//設定響應頭
response.setHeader("Content-Disposition", "attachment;fileName=" + filename);
//獲取輸出流
ServletOutputStream outputStream = response.getOutputStream();
//檔案Copy
FileCopyUtils.copy(fileInputStream,outputStream);
}
補充.我的後期專案.yml
server:
port: 9090
context-path: /cmfz
jsp-servlet:
init-parameters:
development: true #開啟jsp的熱部署配置
tomcat:
max-http-post-size: -1
spring:
mvc:
view:
prefix: /
suffix: .jsp
profiles:
active: dev #啟用哪個檔案生效
datasource:
type: com.alibaba.druid.pool.DruidDataSource #指定資料來源
driver-class-name: com.mysql.jdbc.Driver #指定驅動
url: jdbc:mysql://localhost:3306/abc?characterEncoding=UTF-8 #指定url
username: root
password: root
jackson:
date-format: "yyyy-MM-dd" #適用responseBody時,設定全域性日期格式
time-zone: "GMT+08" #設定時區
http:
multipart:
enabled: true
max-file-size: 30MB #上傳檔案限制大小
max-request-size: 30MB #限制檔案大小
mybatis:
mapper-locations: classpath:com/baizhi/mapper/*Mapper.xml #指定mapper配置檔案位置
type-aliases-package: com.abc.pojo #指定起別名的包
資料來源測試
@Autowired
DataSourceProperties dataSourceProperties;
@Autowired
ApplicationContext applicationContext;
@Test
public void testttt() throws SQLException {
DataSource dataSource = applicationContext.getBean(DataSource.class);
System.out.println(dataSource.getConnection());
}