部門列表查詢:
功能實現:
需求:查詢數據庫表中的所有部門數據,展示在頁面上。
準備工作:
- 準備數據庫表dept(部門表),實體類Dept。
- 在項目中引入mybatis的起步依賴,mysql的驅動包。
- 在項目的application.properties中引入mybatis的配置信息(數據庫連接、日志輸出)。
代碼實現:
?
定義mapper包,并且定義DeptMapper接口,并聲明接口方法。 改造之前編寫的dao、service的代碼,在service實現中注入mapper接口。
?1,先準備部門表的SQL
-- 部門管理
create table dept(id int unsigned primary key auto_increment comment '主鍵ID',name varchar(10) not null unique comment '部門名稱',create_time datetime not null comment '創建時間',update_time datetime not null comment '修改時間'
) comment '部門表';INSERT INTO `dept` VALUES (1,'學工部','2023-09-25 09:47:40','2023-09-25 09:47:40'),(2,'教研部','2023-09-25 09:47:40','2023-09-25 09:47:40'),(3,'咨詢部','2023-09-25 09:47:40','2023-09-25 09:47:40'),(4,'就業部','2023-09-25 09:47:40','2023-09-25 09:47:40'),(5,'人事部','2023-09-25 09:47:40','2023-09-25 09:47:40'),(6,'行政部','2023-09-27 14:00:00','2023-09-27 14:00:00'),(7,'綜合部','2023-09-25 14:44:19','2023-09-25 14:44:19');
?2,在項目中引入mybatis的依賴:
依賴的代碼:
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.31</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.2.11</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency>
3,在application.properties配置文件里面對mybatis進行配置
代碼:
#配置druid連接池
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
#配置數據庫連接信息
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/tlias
spring.datasource.username=root
spring.datasource.password=rootlogging.level.com.sde:debug#mybatis 的日志信息 -- 輸出控制臺
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl#開啟駝峰命名
mybatis.configuration.map-underscore-to-camel-case=true
在com.sde.pojo 包下定義一個Dept實體類:
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Dept {private Integer id;private String name;private LocalDateTime createTime;private LocalDateTime updateTime;}
在com.sde.mapper包下定義一個DeptMapper接口,并在里面寫一個查詢全部的方法。
@Mapper
public interface DeptMapper {@Select("select * from dept")public List<Dept> selectAll();}
在com.sde.service包里面創建一個 DeptService接口,并寫一個查詢全部的接口。
public interface DeptService {public List<Dept> getList();}
在com.sde.service包下面在創建一個子包,impl包,然后創建一個DeptServiceImpl類
@Service
public class DeptServiceImpl implements DeptService {@Autowiredprivate DeptMapper deptMapper;public List<Dept> getList(){return deptMapper.selectAll();}}
controller層,調用service,service調用mapper層。
在 com.sde.controller包下,創建一個DeptController類
部門相關的接口*/
@Slf4j
@RequestMapping("/depts")
@RestController
public class DeptController {@Autowiredprivate DeptService deptService;/*** 獲取全部部門* @return* @throws IOException*/@GetMappingpublic com.sde.utils.Result getDeptList() throws IOException {log.info("執行了查詢全部的操作");List<Dept> deptList = deptService.getList();// 響應數據return Result.success(deptList);}}
在Apifix里面進行測試
?可以發現在Apifox里面測試已經查到數據了,接下來進行前后端聯調測試
?數據封裝:
實體類的屬性名和數據庫表查詢返回的字段名一致,mybatis會自動封裝。
如果實體類屬性名和數據庫表查詢返回的字段名不一致,不能自動封裝。
?
?手動結果映射:
通過@Result 以及@Result 進行手動結果映射。
?
@Results({@Result(column = "create_time",property = "createTime"),@Result(column = "update_time",property = "updateTime")})@Select("select id,name,create_time,update_time from dept")public List<Dept> selectAll();
起別名:
在SQL語句中,對不一樣的列名起別名,別名和實體類屬性名一樣。
?
@Select("select id,name,create_time createTime,update_time updateTime from dept")
public List<Dept> selectAll();
?開啟駝峰命名:
如果字段名與屬性名符合駝峰命名規則,mybatis會自動通過駝峰命名規則映射。
?
#開啟駝峰命名
mybatis.configuration.map-underscore-to-camel-case=true
刪除部門:
思路分析:
controller
接收請求參數:DELETE /depts?id=8? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?簡單參數
?
? ?HttpServletRequest:
?? ??? ?通過原始的HttpServletRequest對象獲取請求參數
?? ??? ?比較繁瑣,需要類型轉換。
前端請求的路徑:http://localhost:8080/depts?id=6?
/*** 根據id刪除部門*/@DeleteMapping("/depts")public Result delete(HttpServletRequest request, Integer id){String parma = request.getParameter("id");int i = Integer.parseInt(parma);System.out.println("刪除部門的ID是:"+i);return Result.success();}
?
@RequestParam注解:
- ?? ??? ?通過Spring提供的 @RequestParam 注解,將請求參數綁定給方法形參。
?? ??? ?@RequestParam(" 方法的形參名")
- ??????????注意事項:??????@RequestParam注解required屬性默認為true,代表該參數必須傳遞,如果不傳遞將報錯。 如果參數可選,可以將屬性設置為false。
/*** 刪除部門信息* @param* @param* @return*/@DeleteMapping("/depts") //@Requestparam 注解用于接收根據前端指定參數名傳遞過來的參數值,// 適用于前端傳遞過來的參數名和后端方法形參名不一樣的情況@RequestParam 默認是必傳的。public Result delete(@RequestParam("id") Integer _id){System.out.println("刪除部門的ID是:"+ _id);return Result.success();}
?
? ? 方法的形參等于前端傳遞的參數名:
?? ??? ?如果請求參數名與形參變量名相同,直接定義方法形參即可接收。(省略@RequestParam)?? ??? ?public Result delete(Integer id){}
/*** 根據id刪除數據* @param id* @return*/@DeleteMapping //如果不帶@RequestParam注解,那么方法的形參名必須要和前端傳遞過來的參數名保持一致,不然獲取不到 就為 null了public Result delete( Integer id){log.info("要刪除的部門ID是:"+id);deptService.delete(id);return Result.success();}
創建deptMapper接口的方法:
@Mapper
public interface DeptMapper {/*** 根據刪除部門數據* @param id*/@Delete("delete from dept where id = #{id}")void delete(Integer id);}
創建deptService接口:
public interface DeptService {void delete(Integer id);}
創建deptServiceImpl實現類 實現deptService接口中的方法:
@Service
public class DeptServiceImpl implements DeptService {@Autowiredprivate DeptMapper deptMapper;@Overridepublic void delete(Integer id) {deptMapper.delete(id);}}
在Apifox里面測試:
#{...} 和 ${...}的區別:
#{}? 執行時會將#{...},替換成?生成預編譯SQL,并自動設置參數值。安全,性能高
${} 拼接SQL,直接將參數拼接在SQL語句中,存在SQL注入問題。多用于表明,字段名動態設置時使用。? 不安全,性能低。
如果mapper接口里面有一個方法,且只有一個普通類型的參數,那么可以在#{...} 里面的屬性名可以隨便寫。如 #{abc},#{sss}
示例:
/*** 根據id刪除* @param id*/@Select("delete from dept where id = #{abc}")void del(Integer id);
添加部門:
- ?? ?JSON格式的參數,通常會使用一個實體對象進行接收。
- ?? ?規則:JSON數據的鍵名和方法的形參對象的屬性名相同,并且需要使用@RequestBody注解標識。
編寫deptController層,接收前端請求,并響應數據。
/*** 部門相關的接口*/
@Slf4j
@RequestMapping("/depts")
@RestController
public class DeptController {@Autowiredprivate DeptService deptService;/*** 添加部門* @param dept* @return*/@PostMappingpublic Result add(@RequestBody Dept dept){log.info("新添加的數據::"+dept);deptService.add(dept);return Result.success();}}
編寫deptService接口:
public interface DeptService {void add(Dept dept);}
編寫deptServiceImpl實現類
@Service
public class DeptServiceImpl implements DeptService {@Autowiredprivate DeptMapper deptMapper;public List<Dept> getList(){return deptMapper.selectAll();}@Overridepublic void delete(Integer id) {deptMapper.delete(id);}@Overridepublic void add(Dept dept) {dept.setCreateTime(LocalDateTime.now());dept.setUpdateTime(LocalDateTime.now());deptMapper.insert(dept);}}
創建一個deptMapper接口:
@Mapper
public interface DeptMapper {@Select("select * from dept")public List<Dept> selectAll();/*** 根據刪除部門數據* @param id*/@Delete("delete from dept where id = #{id}")void delete(Integer id);/*** 添加部門* @param dept*/@Insert("insert into dept(name,create_time,update_time) values(#{name},#{createTime},#{updateTime})")void insert(Dept dept);}
在Apifox里面測試:
?
修改部門:
?? ?查詢回顯:
?? ??? ?路徑參數;通過url直接傳遞參數,使用{...}來標識該路徑參數,需要使用@Pathvariable獲取路徑參數
?controller 接收參數:接收請求參數(路徑參數):GET? /depts/1
在url中也可以攜帶多個路徑參數,例如:? /depts/1/6
@GetMapping("/depts/{id}/{sta}")
public Result getInfo(@PathVariable Integer id, @PathVariable Integer sta){
? ?//...
}
?
?
@GetMapping("/{id}/{username}")public Result getByIdAndName(@PathVariable Integer id,@PathVariable String username){log.info("查詢的參數是:{},{}"+id,username);return Result.success();}
?
/*** 根據id查詢* @param id* @return*/@GetMapping("/{id}")public Result getById(@PathVariable Integer id){log.info("根據ID查詢的id是:"+id);Dept dept = deptService.getById(id);return Result.success(dept);}
?
?? ?修改數據:
?? ??? ?public Result getInfo(@PathVariable Integer id){}
編寫deptService接口:
public interface DeptService {public List<Dept> getList();void delete(Integer id);void add(Dept dept);Dept getById(Integer id);void update(Dept dept);
}
?編寫deptServiceImpl實現類:
@Service
public class DeptServiceImpl implements DeptService {@Autowiredprivate DeptMapper deptMapper;public List<Dept> getList(){return deptMapper.selectAll();}@Overridepublic void delete(Integer id) {deptMapper.delete(id);}@Overridepublic void add(Dept dept) {dept.setCreateTime(LocalDateTime.now());dept.setUpdateTime(LocalDateTime.now());deptMapper.insert(dept);}@Overridepublic Dept getById(Integer id) {return deptMapper.getById(id);}@Overridepublic void update(Dept dept) {dept.setUpdateTime(LocalDateTime.now());deptMapper.update(dept);}
}
deptMapper接口:
@Mapper
public interface DeptMapper {@Select("select * from dept")public List<Dept> selectAll();/*** 根據刪除部門數據* @param id*/@Delete("delete from dept where id = #{id}")void delete(Integer id);/*** 添加部門* @param dept*/@Insert("insert into dept(name,create_time,update_time) values(#{name},#{createTime},#{updateTime})")void insert(Dept dept);/*** 根據id查詢* @param id* @return*/@Select("select * from dept where id = #{id}")Dept getById(Integer id);/*** 修改部門信息* @param dept*/// @Update("update dept set name = #{name},update_time = #{updateTime} where id = #{id}")void update(Dept dept);
}
在Apifox里面測試:
mybatis的動態SQL
在更新數據時,如何做到只更新某一個或幾個字段呢 ?
隨著用戶的輸入或外部條件的變化而變化的SQL語句,我們稱為 動態SQL。
<if>標簽:
用于判斷條件是否成立。使用test屬性進行條件判斷,如果條件為true,則拼接SQL
<set>標簽:
動態地在行首插入 SET 關鍵字,并會刪掉額外的逗號。(用在update語句中)
代碼:
<update id="update">update dept<set><if test="name != null and name != ''">name = #{name},</if><if test="updateTime != null">update_time = #{updateTime}</if></set>where id = #{id}</update>
一個完整的請求路徑,應該是類上的 @RequestMapping得到value值的屬性 + 方法上的 @RequestMapping 的value屬性。
日志技術:
程序中的日志,是用來記錄應用程序的運行信息,狀態信息,錯誤信息。
?
我們傳統的日志輸出方式,只能在控制臺輸出,有很多缺點。
- 硬編碼
- 只能輸出到控制臺
- 不便于擴展、維護
日志框架:
- JUL:這是JavaSE平臺提供的官方日志框架,也被稱為JUL。配置相對簡單,但不夠靈活,性能較差。
- Log4j:一個流行的日志框架,提供了靈活的配置選項,支持多種輸出目標。
- Logback:基于Log4j升級而來,提供了更多的功能和配置選項,性能由于Log4j。
- Slf4j(Simple Logging Facade for Java):簡單日志門面,提供了一套日志操作的標準接口及抽象類,允許應用程序使用不同的底層日志框架。
Logback快速入門:
準備工作:引入logback的依賴 (springboot中無需操作)、配置文件logback.xml
記錄日志:定義日志記錄對象Logger,記錄日志。
<!--slf4j--><dependency><groupId>com.googlecode.sli4j</groupId><artifactId>sli4j-slf4j</artifactId><version>2.0</version></dependency>
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個字符寬度 %logger{50}: 最長50個字符(超出.切割) %msg:日志消息,%n是換行符 --><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern></encoder></appender><!-- 日志輸出級別 --><root level="info"><appender-ref ref="STDOUT" /></root>
</configuration>
要先定義 日志記錄對象
// 定義日志記錄對象public static final Logger log = LoggerFactory.getLogger(LogTest.class);
測試類:
public class LogTest {// 定義日志記錄對象public static final Logger log = LoggerFactory.getLogger(LogTest.class);@Testpublic void testLog(){log.info("開始計算...");int sum = 0;try {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];}} catch (Exception e) {log.info("程序運行出錯...");}log.info("計算結果為: "+sum);log.info("結束計算...");}}
Logback配置文件詳解:
- 該配置文件是對Logback日志框架輸出的日志進行控制的,可以來配置輸出的格式、位置及日志開關等。
- 常用的兩種輸出日志的位置:控制臺、系統文件
<!-- 控制臺輸出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">...</appender><!-- 控制臺輸出 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">...</appender>
開啟日志:(ALL),取消日志(OFF)
?
<root level="ALL"> <appender-ref ref="STDOUT" /> <appender-ref ref="FILE" />
</root>
Logback日志級別:
日志級別指的是日志信息的類型,日志都會分級別,常見的日志級別如下(優先級由低到高)
可以在配置文件中,靈活的控制輸出那些類型的日志。(大于等于配置的日志級別的日志才會輸出)
示例我把這個級別調節成 info
<!-- 日志輸出級別 --><root level="info"><appender-ref ref="STDOUT" /></root>
然后運行 LogTest測試類
可以發現 只有日志級別大于等于 info級別的,才會輸出。
如果我把日志級別改成 trace最低的級別。
<!-- 日志輸出級別 --><root level="trace"><appender-ref ref="STDOUT" /></root>
在LogTest類里面測試:
?可以發現 大于等于 trace日志級別的都輸出了。
當我在logbacl.xml配置文件把日志級別改成 error最高級別
?
<!-- 日志輸出級別 --><root level="error"><appender-ref ref="STDOUT" /></root>
在LogTest測試類里面測試:
就只有一個 error級別的日志輸出了,因為它是最高的日志輸出級別。?
springboot 整合日志:
?
在spring boot項目中,我們不需要引入日志的依賴,因為spring boot默認引入的有。
因為在spring-boot-starter-web這個依賴里面,內置了這些日志框架。
?
我們要是想使用,只需要在 類上面引入即可? @Slf4j,不需要在創建日志輸出對象了,
因為這個注解里面,給我們創建的有log對象。我們直接調用log對象即可。
?
示例:
?
然后直接使用log調用即可:
示例1
效果:
示例2:
效果:
示例3:
?效果:
另一種寫法:
我們可以在 log.info("這里面加 {},{},{}....",在這里寫要輸出的值);
示例:
?
/*** 條件分頁查詢--多參數接收* @param* @param* @return*/@GetMappingpublic Result list(String name,Integer gender,@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate begin,@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end,@RequestParam(defaultValue = "1") Integer page,@RequestParam(defaultValue = "10") Integer pageSize){log.info("接收到前端傳遞來的參數:{},{},{},{},{},{}",name,gender,begin,end,page,pageSize);return Result.success();}
接收前端傳遞來的參數:
示例:
?
/*** 條件分頁查詢用對象接收* @param empQuery* @return*/@GetMappingpublic Result list(EmpQuery empQuery){log.info("接收到前端傳遞來的參數:{}",empQuery);PageBean pageBean = empService.wherePage(empQuery);return Result.success(pageBean);}
?示例:
/*** 新增員工的數據* @param emp* @return* @throws Exception*/@PostMappingpublic Result add(@RequestBody Emp emp) throws Exception {log.info("新增員工數據:{}",emp);empService.add(emp);return Result.success();}
效果: