1.準備工作
1.1開發規范
1.1.1前后端分離開發
我們目前基本都是采用的前后臺分離開發方式,如下圖所示:
那么基于前后臺分離開發的模式下,我們后臺開發者開發一個功能的具體流程如何呢?如下圖所示:
- 需求分析:首先我們需要閱讀需求文檔,分析需求,理解需求。
- 接口定義:查詢接口文檔中關于需求的接口的定義,包括地址,參數,響應數據類型等等
- 前后臺并行開發:各自按照接口文檔進行開發,實現需求
- 測試:前后臺開發完了,各自按照接口文檔進行測試
- 前后段聯調測試:前段工程請求后端工程,測試功能
1.1.2 Restful風格
在前后端進行交互的時候,我們需要基于當前主流的REST風格的API接口進行交互。
什么是REST風格呢?
- REST(Representational State Transfer),表述性狀態轉換,它是一種軟件架構風格。
傳統URL風格如下:
- http://localhost:8080/user/getById?id=1 GET:查詢id為1的用戶
- http://localhost:8080/user/saveUser POST:新增用戶
- http://localhost:8080/user/updateUser POST:修改用戶
- http://localhost:8080/user/deleteUser?id=1 GET:刪除id為1的用戶
我們看到,原始的傳統URL呢,定義比較復雜,而且將資源的訪問行為對外暴露出來了。而且,對于開發人員來說,每一個開發人員都有自己的命名習慣,就拿根據id查詢用戶信息來說的,不同的開發人員定義的路徑可能是這樣的:getById,selectById,queryById,loadById...
。 每一個人都有自己的命名習慣,如果都按照各自的習慣來,一個項目組,幾十號或上百號人,那最終開發出來的項目,將會變得難以維護,沒有一個統一的標準。
基于REST風格URL如下:
- http://localhost:8080/users/1 GET:查詢id為1的用戶
- http://localhost:8080/users POST:新增用戶
- http://localhost:8080/users PUT:修改用戶
- http://localhost:8080/users/1 DELETE:刪除id為1的用戶
其中總結起來,就一句話:通過URL定位要操作的資源,通過HTTP動詞(請求方式)來描述具體的操作。
在REST風格的URL中,通過四種請求方式,來操作數據的增刪改查。
- GET : 查詢
- POST :新增
- PUT : 修改
- DELETE :刪除
我們看到如果是基于REST風格,定義URL,URL將會更加簡潔、更加規范、更加優雅。
注意事項:
- REST是風格,是約定方式,約定不是規定,可以打破
- 描述模塊的功能通常使用復數,也就是加s的格式來描述,表示此類資源,而非單個資源。如:users、emps、books…
1.1.3 Apifox
因為在瀏覽器地中所發起的所有的請求,都是GET方式的請求。那大家就需要思考兩個問題:
- 前后端都在并行開發,后端開發完對應的接口之后,如何對接口進行請求測試呢?
- 前后端都在并行開發,前端開發過程中,如何獲取到數據,測試頁面的渲染展示呢?
那這里我們就可以借助一些接口測試工具,比如項:Postman、Apipost、Apifox等。
那這些工具的使用基本類似,只不過Apifox工具的功能更強強大、更加完善,所以在課程中,我們會采用功能更為強大的Apifox工具。
1.2工程搭建
1). 創建SpringBoot工程,并引入web開發起步依賴、mybatis、mysql驅動、lombok。
- 創建項目
2). 創建數據庫及對應的表結構,并在application.yml中配置數據庫的基本信息。
- 創建tlias數據庫,并準備dept部門表。
CREATE TABLE dept (id int unsigned PRIMARY KEY AUTO_INCREMENT COMMENT 'ID, 主鍵',name varchar(10) NOT NULL UNIQUE COMMENT '部門名稱',create_time datetime DEFAULT NULL COMMENT '創建時間',update_time datetime DEFAULT NULL COMMENT '修改時間'
) COMMENT '部門表';INSERT INTO dept VALUES (1,'學工部','2023-09-25 09:47:40','2024-07-25 09:47:40'),(2,'教研部','2023-09-25 09:47:40','2024-08-09 15:17:04'),(3,'咨詢部','2023-09-25 09:47:40','2024-07-30 21:26:24'),(4,'就業部','2023-09-25 09:47:40','2024-07-25 09:47:40'),(5,'人事部','2023-09-25 09:47:40','2024-07-25 09:47:40'),(6,'行政部','2023-11-30 20:56:37','2024-07-30 20:56:37');
- 在 application.yml 配置文件中配置數據庫的連接信息。
spring:application:name: tlias-web-management#mysql連接配置datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/tliasusername: rootpassword: 1234
mybatis:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
3). 準備基礎包結構,并引入實體類Dept及統一的響應結果封裝類Result
-
準備基礎包結構
-
實體類Dept
package com.itheima.pojo;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;import java.time.LocalDateTime;@Data
@NoArgsConstructor
@AllArgsConstructor
public class Dept {private Integer id;private String name;private LocalDateTime createTime;private LocalDateTime updateTime;
}
- 統一響應結果Result
package com.itheima.pojo;import lombok.Data;
import java.io.Serializable;/*** 后端統一返回結果*/
@Data
public class Result {private Integer code; //編碼:1成功,0為失敗private String msg; //錯誤信息private Object data; //數據public static Result success() {Result result = new Result();result.code = 1;result.msg = "success";return result;}public static Result success(Object object) {Result result = new Result();result.data = object;result.code = 1;result.msg = "success";return result;}public static Result error(String msg) {Result result = new Result();result.msg = msg;result.code = 0;return result;}}
-
基礎代碼結構
- DeptMapper
package com.itheima.mapper;import org.apache.ibatis.annotations.Mapper;@Mapper
public interface DeptMapper {
}
- DeptService
package com.itheima.service;public interface DeptService {
}
- DeptServiceImpl
package com.itheima.service.impl;import com.itheima.service.DeptService;
import org.springframework.stereotype.Service;@Service
public class DeptServiceImpl implements DeptService {
}
- DeptController
package com.itheima.controller;import org.springframework.web.bind.annotation.RestController;/*** 部門管理控制器*/
@RestController
public class DeptController {
}
2.查詢部門
2.1基本實現
2.1.1需求
查詢所有的部門數據,查詢出來展示在部門管理的頁面中。頁面原型效果如下:
2.1.2接口描述
1 基本信息
請求路徑:/depts > > 請求方式:GET > > 接口描述:該接口用于部門列表數據查詢
2 請求參數
無
3 響應數據
參數格式:application/json
參數說明:
響應數據樣例:
{"code": 1,"msg": "success","data": [{"id": 1,"name": "學工部","createTime": "2024-09-01T23:06:29","updateTime": "2024-09-01T23:06:29"},{"id": 2,"name": "教研部","createTime": "2022-09-01T23:06:29","updateTime": "2022-09-01T23:06:29"}]
}
2.1.3實現思路
明確了刪除部門的需求之后,再來梳理一下實現該功能時,三層架構每一層的職責:
- Controller層,負責接收前端發起的請求,并調用service查詢部門數據,然后響應結果。
- Service層,負責調用Mapper接口方法,查詢所有部門數據。
- Mapper層,執行查詢所有部門數據的操作。
2.1.4代碼實現
1). Controller層
在 DeptController 中,增加 list 方法,代碼如下:
/*** 部門管理控制器*/
@RestController
public class DeptController {@Autowiredprivate DeptService deptService;/*** 查詢部門列表*/@RequestMapping("/depts")public Result list(){List<Dept> deptList = deptService.findAll();return Result.success(deptList);}
}
2). Service層
在 DeptService 中,增加 findAll方法,代碼如下:
public interface DeptService {/*** 查詢所有部門*/public List<Dept> findAll();
}
在 DeptServiceImpl 中,增加 findAll方法,代碼如下:
@Service
public class DeptServiceImpl implements DeptService {@Autowiredprivate DeptMapper deptMapper;public List<Dept> findAll() {return deptMapper.findAll();}
}
3). Mapper層
在 DeptMapper 中,增加 findAll方法,代碼如下:
@Mapper
public interface DeptMapper {/*** 查詢所有部門*/@Select("select * from dept")public List<Dept> findAll();}
2.1.5接口測試
啟動項目,然后我們就可以打開Apifox進行測試了。
我們發現,已經查詢出了所有的部門數據,并且響應回來的就是json格式的數據,與接口文檔一致。 那接下來,我們再來測試一下,這個查詢操作,我們使用post、put、delete方式來請求,是否可以獲取到數據。
經過測試,我們發現,現在我們其實是可以通過任何方式的請求來訪問查詢部門的這個接口的。 而在接口文檔中,明確要求該接口的請求方式為GET,那么如何限制請求方式呢?
- 在controller方法上使用,@RequestMapping的衍生注解 @GetMapping。 該注解就是標識當前方法,必須以GET方式請求。
@RestController
public class DeptController {@Autowiredprivate DeptService deptService;/*** 查詢部門列表*/@GetMapping("/depts")public Result list(){List<Dept> deptList = deptService.findAll();return Result.success(deptList);}
}
- GET方式:@GetMapping
- POST方式:@PostMapping
- PUT方式:@PutMapping
- DELETE方式:@DeleteMapping
2.1.6數據封裝
在上述測試中,我們發現部門的數據中,id、name兩個屬性是有值的,但是createTime、updateTime兩個字段值并未成功封裝,而數據庫中是有對應的字段值的,這是為什么呢?
原因如下:
- 實體類屬性名和數據庫表查詢返回的字段名一致,mybatis會自動封裝。
- 如果實體類屬性名和數據庫表查詢返回的字段名不一致,不能自動封裝。
解決方案:
- 手動結果映射
- 起別名
- 開啟駝峰命名
如果字段名與屬性名符合駝峰命名規則,mybatis會自動通過駝峰命名規則映射。駝峰命名規則: abc_xyz => abcXyz
- 表中字段名:abc_xyz
- 類中屬性名:abcXyz
在application.yml中做如下配置,開啟開關。
mybatis:configuration:map-underscore-to-camel-case: true
要使用駝峰命名前提是 實體類的屬性 與 數據庫表中的字段名嚴格遵守駝峰命名。
2.2前后端聯調
2.2.1聯調測試
1.雙擊 nginx.exe 啟動Nginx,一閃而過,就說明nginx已啟動完成。
如果在任務管理器中,能看到上述兩個進程,就說明nginx已經啟動成功。
2.打開瀏覽器,訪問:http://localhost:90
2.2.2請求訪問流程
前端工程請求服務器的地址為 http://localhost:90/api/depts
,是如何訪問到后端的tomcat服務器的?
其實這里,是通過前端服務Nginx中提供的反向代理功能實現的。
1). 瀏覽器發起請求,請求的是localhost:90 ,那其實請求的是nginx服務器。
2). 在nginx服務器中呢,并沒有對請求直接進行處理,而是將請求轉發給了后端的tomcat服務器,最終由tomcat服務器來處理該請求。
這個過程就是通過nginx的反向代理實現的。 那為什么瀏覽器不直接請求后端的tomcat服務器,而是直接請求nginx服務器呢,主要有以下幾點原因:
1). 安全:由于后端的tomcat服務器一般都會搭建集群,會有很多的服務器,把所有的tomcat暴露給前端,讓前端直接請求tomcat,對于后端服務器是比較危險的。
2). 靈活:基于nginx的反向代理實現,更加靈活,后端想增加、減少服務器,對于前端來說是無感知的,只需要在nginx中配置即可。
3). 負載均衡:基于nginx的反向代理,可以很方便的實現后端tomcat的負載均衡操作。
具體的請求訪問流程如下:
- location:用于定義匹配特定uri請求的規則。
- ^~ /api/:表示精確匹配,即只匹配以/api/開頭的路徑。
- rewrite:該指令用于重寫匹配到的uri路徑。
- proxy_pass:該指令用于代理轉發,它將匹配到的請求轉發給位于后端的指令服務器。
3.刪除部門
3.1需求
刪除部門數據。在點擊 “刪除” 按鈕,會根據ID刪除部門數據。
3.2接口描述
1 基本信息
請求路徑:/depts > > 請求方式:DELETE > > 接口描述:該接口用于根據ID刪除部門數據
2 請求參數
參數說明:
請求參數樣例:
/depts?id=1
/depts?id=2
3 響應數據
參數格式:application/json
參數說明:
響應數據樣例:
{"code":1,"msg":"success","data":null
}
3.3思路分析
明確了刪除部門的需求之后,再來梳理一下實現該功能時,三層架構每一層的職責:
3.4簡單參數接收
- 如果請求參數名與形參變量名相同,直接定義方法形參即可接收。(省略@RequestParam)
@DeleteMapping("/depts")
public Result delete(Integer id){System.out.println("根據ID刪除部門: " + deptId);return Result.success();
}
3.5代碼實現
1). Controller層
在 DeptMapper 中,增加 delete 方法,代碼實現如下:
/*** 根據id刪除部門 - delete http://localhost:8080/depts?id=1*/
@DeleteMapping("/depts")
public Result delete(Integer id){System.out.println("根據id刪除部門, id=" + id);deptService.deleteById(id);return Result.success();
}
2). Service層
在 DeptService 中,增加 deleteById 方法,代碼實現如下:
/*** 根據id刪除部門*/
void deleteById(Integer id);
在 DeptServiceImpl 中,增加 deleteById 方法,代碼實現如下:
public void deleteById(Integer id) {deptMapper.deleteById(id);
}
3). Mapper層
在 DeptMapper 中,增加 deleteById 方法,代碼實現如下:
/*** 根據id刪除部門*/
@Delete("delete from dept where id = #{id}")
void deleteById(Integer id);
如果mapper接口方法形參只有一個普通類型的參數,#{…} 里面的屬性名可以隨便寫,如:#{id}、#{value}。
對于 DML 語句來說,執行完畢,也是有返回值的,返回值代表的是增刪改操作,影響的記錄數,所以可以將執行 DML 語句的方法返回值設置為 Integer。 但是一般開發時,是不需要這個返回值的,所以也可以設置為void。
代碼編寫完畢之后,我們就可以啟動服務,進行測試了。
4.新增部門
4.1需求
點擊 “新增部門” 的按鈕之后,彈出新增部門表單,填寫部門名稱之后,點擊確定之后,保存部門數據。
4.2接口描述
1.3.1 基本信息
請求路徑:/depts > > 請求方式:POST > > 接口描述:該接口用于添加部門數據
1.3.2 請求參數
格式:application/json
參數說明:
請求參數樣例:
{"name": "教研部"
}
1.3.3 響應數據
參數格式:application/json
參數說明:
響應數據樣例:
{"code":1,"msg":"success","data":null
}
4.3思路分析
明確了新增部門的需求之后,再來梳理一下實現該功能時,三層架構每一層的職責:
4.4 json參數接收
我們看到,在controller中,需要接收前端傳遞的請求參數。 那接下來,我們就先來看看在服務器端的Controller程序中,如何獲取json格式的參數。
- JSON格式的參數,通常會使用一個實體對象進行接收 。
- 規則:JSON數據的鍵名與方法形參對象的屬性名相同,并需要使用
@RequestBody
注解標識。
前端傳遞的請求參數格式為json,內容如下:{"name":"研發部"}
。這里,我們可以通過一個對象來接收,只需要保證對象中有name屬性即可。
4.5代碼實現
1). Controller層
在DeptController中增加方法save,具體代碼如下:
/*** 新增部門 - POST http://localhost:8080/depts 請求參數:{"name":"研發部"}*/
@PostMapping("/depts")
public Result save(@RequestBody Dept dept){System.out.println("新增部門, dept=" + dept);deptService.save(dept);return Result.success();
}
2). Service層
在DeptService中增加接口方法save,具體代碼如下:
/*** 新增部門*/
void save(Dept dept);
在DeptServiceImpl中增加save方法,完成添加部門的操作,具體代碼如下:
public void save(Dept dept) {//補全基礎屬性dept.setCreateTime(LocalDateTime.now());dept.setUpdateTime(LocalDateTime.now());//保存部門deptMapper.insert(dept);
}
3). Mapper層
/*** 保存部門*/
@Insert("insert into dept(name,create_time,update_time) values(#{name},#{createTime},#{updateTime})")
void insert(Dept dept);
如果在mapper接口中,需要傳遞多個參數,可以把多個參數封裝到一個對象中。 在SQL語句中獲取參數的時候,#{…} 里面寫的是對象的屬性名**【注意是屬性名,不是表的字段名】。**
代碼編寫完畢之后,我們就可以啟動服務,進行測試了。
5.修改部門
5.1查詢回顯
5.1.1需求
當我們點擊 “編輯” 的時候,需要根據ID查詢部門數據,然后用于頁面回顯展示。
5.1.2接口描述
1 基本信息
請求路徑:/depts/{id} > > 請求方式:GET > > 接口描述:該接口用于根據ID查詢部門數據
2 請求參數
參數格式:路徑參數
參數說明:
請求參數樣例:
/depts/1
/depts/3
3 響應數據
參數格式:application/json
參數說明:
響應數據樣例:
{"code": 1,"msg": "success","data": {"id": 1,"name": "學工部","createTime": "2022-09-01T23:06:29","updateTime": "2022-09-01T23:06:29"}
}
5.1.3思路分析
5.1.4路徑參數接收
/depts/1,/depts/2 這種在url中傳遞的參數,我們稱之為路徑參數。 那么如何接收這樣的路徑參數呢 ?
路徑參數:通過請求URL直接傳遞參數,使用{…}來標識該路徑參數,需要使用 @PathVariable獲取路徑參數。如下所示:
如果路徑參數名與controller方法形參名稱一致,@PathVariable
注解的value屬性是可以省略的。
5.1.5代碼實現
1). Controller層
在 DeptController 中增加 getById方法,具體代碼如下:
/*** 根據ID查詢 - GET http://localhost:8080/depts/1*/
@GetMapping("/depts/{id}")
public Result getById(@PathVariable Integer id){System.out.println("根據ID查詢, id=" + id);Dept dept = deptService.getById(id);return Result.success(dept);
}
2). Service層
在 DeptService 中增加 getById方法,具體代碼如下:
/*** 根據id查詢部門*/
Dept getById(Integer id);
在 DeptServiceImpl 中增加 getById方法,具體代碼如下:
public Dept getById(Integer id) {return deptMapper.getById(id);
}
3). Mapper層
在 DeptMapper 中增加 getById 方法,具體代碼如下:
/**
* 根據ID查詢部門數據
*/
@Select("select id, name, create_time, update_time from dept where id = #{id}")
Dept getById(Integer id);
代碼編寫完畢之后,我們就可以啟動服務,進行測試了。
5.2修改數據
5.2.1需求
5.2.2接口描述
1 基本信息
請求路徑:/depts > > 請求方式:PUT > > 接口描述:該接口用于修改部門數據
2 請求參數
格式:application/json
參數說明:
請求參數樣例:
{"id": 1,"name": "教研部"
}
3 響應數據
參數格式:application/json
參數說明:
響應數據樣例:
{"code":1,"msg":"success","data":null
}
5.2.3思路分析
5.2.4代碼實現
1). Controller層
在 DeptController 中增加 update 方法,具體代碼如下:
/*** 修改部門 - PUT http://localhost:8080/depts 請求參數:{"id":1,"name":"研發部"}*/
@PutMapping("/depts")
public Result update(@RequestBody Dept dept){System.out.println("修改部門, dept=" + dept);deptService.update(dept);return Result.success();
}
2). Service層
在 DeptService 中增加 update 方法。
/*** 修改部門*/
void update(Dept dept);
在 DeptServiceImpl 中增加 update 方法。 由于是修改操作,每一次修改數據,都需要更新updateTime。所以,具體代碼如下:
public void update(Dept dept) {//補全基礎屬性dept.setUpdateTime(LocalDateTime.now());//保存部門deptMapper.update(dept);
}
3). Mapper層
在 DeptMapper 中增加 update 方法,具體代碼如下:
/*** 更新部門*/
@Update("update dept set name = #{name},update_time = #{updateTime} where id = #{id}")
void update(Dept dept);
代碼編寫完畢之后,我們就可以啟動服務,進行測試了。
修改完成之后,我們可以看到最新的數據,如下:
5.2.5 @RequestMapping
到此呢,關于基本的部門的增刪改查功能,我們已經實現了。 我們會發現,我們在 DeptController 中所定義的方法,所有的請求路徑,都是 /depts 開頭的,只要操作的是部門數據,請求路徑都是 /depts 開頭。
那么這個時候,我們其實是可以把這個公共的路徑 /depts 抽取到類上的,那在各個方法上,就可以省略了這個 /depts 路徑。 代碼如下:
一個完整的請求路徑,應該是類上的 @RequestMapping 的value屬性 + 方法上的
@RequestMapping的value屬性。
6.日志技術
6.1概述
如果通過 System.out.println(…) 來記錄日志,會存在以下幾點問題:
- 硬編碼。所有的記錄日志的代碼,都是硬編碼,沒有辦法做到靈活控制,要想不輸出這個日志了,只能刪除掉記錄日志的代碼。
- 只能輸出日志到控制臺。
- 不便于程序的擴展、維護。
所以,在現在的項目開發中,我們一般都會使用專業的日志框架,來解決這些問題。
6.2日志框架
- JUL:這是JavaSE平臺提供的官方日志框架,也被稱為JUL。配置相對簡單,但不夠靈活,性能較差。
- Log4j:一個流行的日志框架,提供了靈活的配置選項,支持多種輸出目標。
- Logback:基于Log4j升級而來,提供了更多的功能和配置選項,性能由于Log4j。
- Slf4j:(Simple Logging Facade for Java)簡單日志門面,提供了一套日志操作的標準接口及抽象類,允許應用程序使用不同的底層日志框架。
6.3 Logback入門
1). 準備工作:引入logback的依賴(springboot中無需引入,在springboot中已經傳遞了此依賴)
<dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.4.11</version>
</dependency>
2). 引入配置文件 logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration><!-- 控制臺輸出 --><appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><!--格式化輸出:%d表示日期,%thread表示線程名,%-5level:級別從左顯示5個字符寬度 %msg:日志消息,%n是換行符 --><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}-%msg%n</pattern></encoder></appender><!-- 日志輸出級別 --><root level="ALL"><appender-ref ref="STDOUT" /></root>
</configuration>
3). 記錄日志:定義日志記錄對象Logger,記錄日志
public class LogTest {//定義日志記錄對象private static final Logger log = LoggerFactory.getLogger(LogTest.class);@Testpublic void testLog(){log.debug("開始計算...");int sum = 0;int[] nums = {1, 5, 3, 2, 1, 4, 5, 4, 6, 7, 4, 34, 2, 23};for (int i = 0; i < nums.length; i++) {sum += nums[i];}log.info("計算結果為: "+sum);log.debug("結束計算...");}}
運行單元測試,可以在控制臺中看到輸出的日志,如下所示:
我們可以看到在輸出的日志信息中,不僅輸出了日志的信息,還包括:日志的輸出時間、線程名、具體在那個類中輸出的。
6.4 Logback配置文件
Logback日志框架的配置文件叫 logback.xml 。
該配置文件是對Logback日志框架輸出的日志進行控制的,可以來配置輸出的格式、位置及日志開關等。
常用的兩種輸出日志的位置:控制臺、系統文件。
1). 如果需要輸出日志到控制臺。添加如下配置:
<!-- 控制臺輸出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><!--格式化輸出:%d 表示日期,%thread 表示線程名,%-5level表示級別從左顯示5個字符寬度,%msg表示日志消息,%n表示換行符 --><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}-%msg%n</pattern></encoder>
</appender>
2). 如果需要輸出日志到文件。添加如下配置:
<!-- 按照每天生成日志文件 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"><rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"><!-- 日志文件輸出的文件名, %i表示序號 --><FileNamePattern>D:/tlias-%d{yyyy-MM-dd}-%i.log</FileNamePattern><!-- 最多保留的歷史日志文件數量 --><MaxHistory>30</MaxHistory><!-- 最大文件大小,超過這個大小會觸發滾動到新文件,默認為 10MB --><maxFileSize>10MB</maxFileSize></rollingPolicy><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><!--格式化輸出:%d 表示日期,%thread 表示線程名,%-5level表示級別從左顯示5個字符寬度,%msg表示日志消息,%n表示換行符 --><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}-%msg%n</pattern></encoder>
</appender>
3). 日志開關配置 (開啟日志(ALL),取消日志(OFF))
<!-- 日志輸出級別 -->
<root level="ALL"><!--輸出到控制臺--><appender-ref ref="STDOUT" /><!--輸出到文件--><appender-ref ref="FILE" />
</root>
6.5 Logback日志級別
日志級別指的是日志信息的類型,日志都會分級別,常見的日志級別如下(優先級由低到高):
可以在配置文件logback.xml中,靈活的控制輸出那些類型的日志。(大于等于配置的日志級別的日志才會輸出)
<!-- 日志輸出級別 -->
<root level="info"><!--輸出到控制臺--><appender-ref ref="STDOUT" /><!--輸出到文件--><appender-ref ref="FILE" />
</root>
6.6案例日志記錄
/*** 部門管理控制器*/
@Slf4j
@RequestMapping("/depts")
@RestController
public class DeptController {@Autowiredprivate DeptService deptService;/*** 查詢部門列表*///@RequestMapping(value = "/depts", method = RequestMethod.GET)@GetMappingpublic Result list(){//System.out.println("查詢部門列表");log.info("查詢部門列表");List<Dept> deptList = deptService.findAll();return Result.success(deptList);}/*** 根據id刪除部門 - delete http://localhost:8080/depts?id=1*/@DeleteMappingpublic Result delete(Integer id){//System.out.println("根據id刪除部門, id=" + id);log.info("根據id刪除部門, id: {}" , id);deptService.deleteById(id);return Result.success();}/*** 新增部門 - POST http://localhost:8080/depts 請求參數:{"name":"研發部"}*/@PostMappingpublic Result save(@RequestBody Dept dept){//System.out.println("新增部門, dept=" + dept);log.info("新增部門, dept: {}" , dept);deptService.save(dept);return Result.success();}/*** 根據ID查詢 - GET http://localhost:8080/depts/1*/@GetMapping("/{id}")public Result getById(@PathVariable Integer id){//System.out.println("根據ID查詢, id=" + id);log.info("根據ID查詢, id: {}" , id);Dept dept = deptService.getById(id);return Result.success(dept);}/*** 修改部門 - PUT http://localhost:8080/depts 請求參數:{"id":1,"name":"研發部"}*/@PutMappingpublic Result update(@RequestBody Dept dept){//System.out.println("修改部門, dept=" + dept);log.info("修改部門, dept: {}" , dept);deptService.update(dept);return Result.success();}
}
lombok中提供的@Slf4j注解,可以簡化定義日志記錄器這步操作。添加了該注解,就相當于在類中定義了日志記錄器,就下面這句代碼:
private static Logger log = LoggerFactory. getLogger(Xxx. class);