??📝個人主頁:哈__
期待您的關注?
目錄
一、🔥今日目標
二、📂打開SpringBoot項目?
2.1 導入所需依賴
2.2修改application.yml配置文件
?2.3導入MybatisPlus逆向工程工具
?2.4創建一個公用的返回值
?2.5創建CopyUtil工具類
?2.6創建MybatisPlus的配置類
三、使用MybatisPlus逆向工程生成Ebook
四、Ebook查詢功能的開發
一、🔥今日目標
上一篇文章已經帶領大家把前后端的SpringBoot和Vue的架子搭了起來,今天呢我就要帶大家開始上手開發我們的wiki知識庫了,今天主要是帶領大家把后端中一些基本的東西寫出來,例如依賴、部分的工具類等,還會帶大家實現電子書模塊的查詢功能,但是通過PostMan進行地測試的。
二、📂打開SpringBoot項目?
2.1 導入所需依賴
這里大家可能使用的不是阿里云服務器創建的SpringBoot項目,所以我把整個的POM文件復制了上來。依賴呢我現在只用到了這么多,如果后邊我們缺了什么依賴的話還會在加的。
<?xml version="1.0" encoding="UTF-8"?> <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 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.my</groupId><artifactId>hawiki</artifactId><version>0.0.1-SNAPSHOT</version><name>hawiki</name><description>hawiki</description><properties><java.version>1.8</java.version><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><spring-boot.version>2.7.16</spring-boot.version></properties><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><!--aop切面--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency><!--整合redis--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><!--數據校驗--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId></dependency><!--websocket通信--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.3.1</version></dependency><!-- mybatisplus逆向工程 --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-generator</artifactId><version>3.3.2</version></dependency><dependency><groupId>org.apache.velocity</groupId><artifactId>velocity</artifactId><version>1.7</version></dependency><!-- 數據庫驅動 --><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.70</version></dependency><!-- 工具類 --><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.18</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><!--日志--><dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>${spring-boot.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.8.1</version><configuration><source>1.8</source><target>1.8</target><encoding>UTF-8</encoding></configuration></plugin><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>${spring-boot.version}</version><configuration><mainClass>com.my.hawiki.HawikiApplication</mainClass><skip>true</skip></configuration><executions><execution><id>repackage</id><goals><goal>repackage</goal></goals></execution></executions></plugin></plugins></build></project>
2.2修改application.yml配置文件
在application.yml配置文件中,我們要配置數據庫的連接信息,還要配置redis的連接信息。
spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/wiki?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT&allowPublicKeyRetrieval=truetype: com.zaxxer.hikari.HikariDataSourceusername: rootpassword: 你的數據庫密碼 logging:config: classpath:logback-spring.xmllevel:com.my.hawiki.mapper: trace
?在上方的配置信息你看到了一個名字叫做logging的配置,這個是用來配置我們的日志輸出的,日志信息的配置類使用的是一個xml文件。內容具體如下。首先你要在你的項目的根目錄下創建一個名字叫做log的文件夾,這樣以后的日志信息就會保存到這個文件夾下的兩個文件中,一個叫做error.log,一個叫做trace.log。
<?xml version="1.0" encoding="UTF-8"?> <configuration><!-- <!– 修改一下路徑--><property name="PATH" value="./log"></property><appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"><encoder><!-- <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %highlight(%-5level) %blue(%-50logger{50}:%-4line) %thread %green(%-18X{LOG_ID}) %msg%n</Pattern>--><Pattern>%d{ss.SSS} %highlight(%-5level) %blue(%-30logger{30}:%-4line) %thread %green(%-18X{LOG_ID})%msg%n</Pattern></encoder></appender><appender name="TRACE_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"><file>${PATH}/trace.log</file><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><FileNamePattern>${PATH}/trace.%d{yyyy-MM-dd}.%i.log</FileNamePattern><timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"><maxFileSize>10MB</maxFileSize></timeBasedFileNamingAndTriggeringPolicy></rollingPolicy><layout><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %-50logger{50}:%-4line %green(%-18X{LOG_ID}) %msg%n</pattern></layout></appender><appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"><file>${PATH}/error.log</file><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><FileNamePattern>${PATH}/error.%d{yyyy-MM-dd}.%i.log</FileNamePattern><timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"><maxFileSize>10MB</maxFileSize></timeBasedFileNamingAndTriggeringPolicy></rollingPolicy><layout><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %-50logger{50}:%-4line %green(%-18X{LOG_ID}) %msg%n</pattern></layout><filter class="ch.qos.logback.classic.filter.LevelFilter"><level>ERROR</level><onMatch>ACCEPT</onMatch><onMismatch>DENY</onMismatch></filter></appender><root level="ERROR"><appender-ref ref="ERROR_FILE"/></root><root level="TRACE"><appender-ref ref="TRACE_FILE"/></root><root level="INFO"><appender-ref ref="STDOUT"/></root> </configuration>
?2.3導入MybatisPlus逆向工程工具
我在項目中創建了一個名字為util的軟件包。別的包大家可以先不用管,這些我之后都會說到的,這個util包呢主要就是保存我們的一些工具類。
MybatisPlus逆向工程的代碼如下。我另一篇文章也有些過這個逆向工程【Spring】SpringBoot整合MybatisPlusGernerator,MybatisPlus逆向工程-CSDN博客
要注意的是你一定要修改其中的數據庫連接信息。
public class MybatisGenerator {public static void main(String[] args) {AutoGenerator autoGenerator = new AutoGenerator();DataSourceConfig dataSourceConfig = new DataSourceConfig();dataSourceConfig.setDbType(DbType.MYSQL);dataSourceConfig.setDriverName("com.mysql.cj.jdbc.Driver");dataSourceConfig.setUsername("root");dataSourceConfig.setPassword("你的數據庫課密碼");dataSourceConfig.setUrl("jdbc:mysql://localhost:3306/wiki?useUnicode=true&characterEncoding=UTF-8");autoGenerator.setDataSource(dataSourceConfig);GlobalConfig globalConfig = new GlobalConfig();globalConfig.setOpen(false);globalConfig.setOutputDir(System.getProperty("user.dir")+"/src/main/java");globalConfig.setAuthor("CSDN__哈");globalConfig.setServiceName("%sService");autoGenerator.setGlobalConfig(globalConfig);PackageConfig packageConfig = new PackageConfig();packageConfig.setParent("com.my.hawiki");packageConfig.setEntity("domain");packageConfig.setMapper("mapper");//packageConfig.setController("controller");packageConfig.setService("service");packageConfig.setServiceImpl("service.impl");autoGenerator.setPackageInfo(packageConfig);StrategyConfig strategyConfig = new StrategyConfig();//是否需要lombokstrategyConfig.setEntityLombokModel(true);//設置命名格式strategyConfig.setNaming(NamingStrategy.underline_to_camel);strategyConfig.setColumnNaming(NamingStrategy.underline_to_camel);//設置我們的表名 你到底要生成哪張表的框架strategyConfig.setInclude("ebook");autoGenerator.setStrategy(strategyConfig);autoGenerator.execute();} }
?2.4創建一個公用的返回值
你可能不太理解這句話是什么意思,在SpringBoot項目當中,我們的每一個請求可能都會返回給前端數據,返回的數據一定是一個字符串。但這種方式并不適合我們的需求,比如我想返回的信息不僅僅是數據,還有一些其他的狀態信息。例如當我們程序沒出錯的時候,我想在返回一句話,查詢成功,如果出錯了我就返回查詢失敗,這樣返回多個參數信息,我們就不能使用字符串返回了。
我們需要的是這樣的返回值。這是一個JSON類型的數據,也可以說是一個對象類型的數據,我們直接返回一個對象的話也可以達到這種效果,前提是導入了fastjson依賴。
創建的CommonResp如下。這個類在util包下創建的我。
@Data @AllArgsConstructor public class CommonResp<T> {/*** 業務上的成功或失敗*/private boolean success = true;/*** 返回信息*/private String message;/*** 返回泛型數據,自定義類型*/private T content;@Overridepublic String toString() {final StringBuffer sb = new StringBuffer("ResponseDto{");sb.append("success=").append(success);sb.append(", message='").append(message).append('\'');sb.append(", content=").append(content);sb.append('}');return sb.toString();} }
?2.5創建CopyUtil工具類
這個工具類的作用就是把一個類轉換為另一個類的形式。也是在util包下。
import org.springframework.beans.BeanUtils; import org.springframework.util.CollectionUtils; import java.util.ArrayList; import java.util.List; public class CopyUtil {/*** 單體復制*/public static <T> T copy(Object source, Class<T> clazz) {if (source == null) {return null;}T obj = null;try {obj = clazz.newInstance();} catch (Exception e) {e.printStackTrace();return null;}BeanUtils.copyProperties(source, obj);return obj;}/*** 列表復制*/public static <T> List<T> copyList(List source, Class<T> clazz) {List<T> target = new ArrayList<>();if (!CollectionUtils.isEmpty(source)) {for (Object c : source) {T obj = copy(c, clazz);target.add(obj);}}return target;} }
?2.6創建MybatisPlus的配置類
這個類寫到了我創建出來的config包下
@Configuration public class MyBatisPlusConfig {@Beanpublic PaginationInterceptor paginationInterceptor() {PaginationInterceptor paginationInterceptor = new PaginationInterceptor();paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(false));return paginationInterceptor;} }
?到了這一步,我們今天的目標就完成的快差不多了,后端的工具類我們今天用到的也差不多就是這些。接下來我就帶大家實現電子書接口的查詢功能。
?這是我們的ebook的數據庫,接下來我就要寫接口去查詢這些內容了。
三、🌼使用MybatisPlus逆向工程生成Ebook
?打開我給大家的逆向工程的工具類,把你要生成的表的名稱填寫到對應的位置,上邊我已經給了注釋了,這里不再展示到底寫在哪里了,把表名改成ebook,然后右鍵運行工具類,等一段時間后就會生成以下幾個結構。
- controller
- service
- impl
- domain
- mapper
- xml
四、🤖Ebook查詢功能的開發
我們需要的都已經寫完了,接下來就去實現具體的功能,在這之前呢,我還需要寫兩個Param類,這兩個類的作用就是接收前端給后端傳輸的一些參數。
PageParam
@Data public class PageParam {@NotNull(message = "【頁碼】不能為空")private Integer page;@NotNull(message = "【每頁條數】不能為空")@Max(value = 1000, message = "【每頁條數】不能超過1000")private Integer size;}
EbookQueryParam
@EqualsAndHashCode(callSuper = true) @Data public class EbookQueryParam extends PageParam {private Long id;private String name;private Long categoryId2; }
除了這兩個Param外還需要兩個VO,VO的作用就是把我們的查詢結果進行一個二次封裝,然后在傳給前端,比如說你開發登錄功能,用戶成功登陸后,你不能把用戶的密碼直接返回給前端,而是要把這個密碼的字段刪掉在返回給前端。
PageVo
@Data public class PageVo<T> {private long total;private List<T> list; }
EbookQueryVo?
@Data public class EbookQueryVo {private Long id;private String name;private Long category1Id;private Long category2Id;private String description;private String cover;private Integer docCount;private Integer viewCount;private Integer voteCount; }
打開我們的EbookController,寫入以下代碼。
@RestController @RequestMapping("/ebook") public class EbookController {@ResourceEbookService ebookService;/*** 查詢電子書 帶有模糊查詢* @param ebookQueryParam 帶有數據校驗* @return*/@RequestMapping("/list")public CommonResp list(@Validated EbookQueryParam ebookQueryParam){PageVo<EbookQueryVo> list = ebookService.list(ebookQueryParam);return new CommonResp<>(true,"查找成功",list);} }
EbookService代碼如下。
public interface EbookService extends IService<Ebook> {PageVo<EbookQueryVo> list(EbookQueryParam ebookQueryParam); }
?EbookMapper代碼如下。
/*** <p>* 電子書 Mapper 接口* </p>** @author CSDN__哈* @since 2024-05-26*/ public interface EbookMapper extends BaseMapper<Ebook> {}
?EbookServiceImpl代碼如下。
package com.my.hawiki.service.impl;import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.StringUtils; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.my.hawiki.domain.Ebook; import com.my.hawiki.mapper.EbookMapper; import com.my.hawiki.param.EbookQueryParam; import com.my.hawiki.service.EbookService; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.my.hawiki.utils.CopyUtil; import com.my.hawiki.vo.EbookQueryVo; import com.my.hawiki.vo.PageVo; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.util.ArrayList; import java.util.List;/*** <p>* 電子書 服務實現類* </p>** @author CSDN__哈* @since 2024-05-26*/ @Service public class EbookServiceImpl extends ServiceImpl<EbookMapper, Ebook> implements EbookService {@ResourceEbookMapper ebookMapper;@Overridepublic PageVo<EbookQueryVo> list(EbookQueryParam ebookQueryParam) {// 這里創建了一個wrapper用于sql語句條件的拼接LambdaQueryWrapper<Ebook> lambdaQueryWrapper = new LambdaQueryWrapper<>();// 拼接我們傳過來的id 就相當于 where id = ??lambdaQueryWrapper.eq(ebookQueryParam.getId()!=null,Ebook::getId,ebookQueryParam.getId())// 相當于 where categoryid2 = ??.eq(ebookQueryParam.getCategoryId2()!=null,Ebook::getCategory2Id,ebookQueryParam.getCategoryId2())// 相當于 where name like %???%.like(StringUtils.isNotBlank(ebookQueryParam.getName()),Ebook::getName,ebookQueryParam.getName());// 這里使用MybataisPlus的page類,接收一下前端傳來了頁號和頁的大小Page<Ebook> page = new Page<>(ebookQueryParam.getPage(),ebookQueryParam.getSize());// 這里我們將從數據庫中查詢的結果封裝到一個Page類下Page<Ebook> resultPage = ebookMapper.selectPage(page, lambdaQueryWrapper);// 這里我創建了一個PageVo,用于返回給前端信息PageVo<EbookQueryVo> pageVo = new PageVo<>();List<EbookQueryVo> list = new ArrayList<>();// 從resultPage中獲取從數據庫中去除的結果,然后把數據插入到list中for (Ebook record : resultPage.getRecords()) {EbookQueryVo ebookQueryVo = CopyUtil.copy(record, EbookQueryVo.class);list.add(ebookQueryVo);}pageVo.setList(list);pageVo.setTotal(resultPage.getTotal());return pageVo;} }
好了這里就寫的差不多了,我們可以使用PostMan工具測試一下,這里大家需要自己安裝一下。
啟動我們的啟動類,并且在啟動類上加上一個mapper掃描。之后啟動項目
@MapperScan("com.my.hawiki.mapper")
?可以看到我傳入的page是1,size是5,查詢出來的結果沒問題。
但大家別忘了,我還有一個數據校驗呢,page和size不能為空。那我們什么也不傳入試一試。現在直接查不出來了。
我們看一下后臺日志。這里給我們報了個錯,說明我們的數據校驗是有作用的,那我不想讓他報錯,這我該怎么做呢?我還想使用CommomResp返回一個信息,告訴前端錯誤是什么。
54.346 WARN o.s.w.s.m.s.DefaultHandlerExceptionResolver:208 http-nio-8080-exec-7 Resolved [org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 2 errors<EOL>Field error in object 'ebookQueryParam' on field 'page': rejected value [null]; codes [NotNull.ebookQueryParam.page,NotNull.page,NotNull.java.lang.Integer,NotNull]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [ebookQueryParam.page,page]; arguments []; default message [page]]; default message [【頁碼】不能為空]<EOL>Field error in object 'ebookQueryParam' on field 'size': rejected value [null]; codes [NotNull.ebookQueryParam.size,NotNull.size,NotNull.java.lang.Integer,NotNull]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [ebookQueryParam.size,size]; arguments []; default message [size]]; default message [【每頁條數】不能為空]]
?這里我就要創建一個handler包,包下創建一個GlobalExceptionHandler。
GlobalExceptionHandler代碼如下。這個類的作用就是捕獲我們程序中的異常,然后作出處理。
import com.my.hawiki.utils.CommonResp; import org.springframework.validation.BindException; import org.springframework.validation.FieldError; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; @RestControllerAdvice public class GlobalExceptionHandler {/*** 校驗異常*/@ExceptionHandler(BindException.class)public CommonResp<String> handleBindException(BindException e) {StringBuilder errorMessage = new StringBuilder();for (FieldError fieldError : e.getFieldErrors()) {// 這里可以自定義錯誤信息的格式errorMessage.append(fieldError.getField()).append(":").append(fieldError.getDefaultMessage()).append("; ");}// 去掉最后一個分號和空格if (errorMessage.length() > 0) {errorMessage.setLength(errorMessage.length() - 2);}return new CommonResp<>(false, errorMessage.toString(), null);}}
接下來在重新啟動項目試試看。
大功告成, 電子書查詢接口的功能已經測試成功了。