📝个人主页:哈__
期待您的关注
目录
一、🔥今日目标
二、📂打开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.Driver url: jdbc:mysql://localhost:3306/wiki?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT&allowPublicKeyRetrieval=true type: com.zaxxer.hikari.HikariDataSource username: root password: 你的数据库密码 logging: config: classpath:logback-spring.xml level: 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(); //是否需要lombok strategyConfig.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; @Override public 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 { @Bean public 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 { @Resource EbookService 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 { @Resource EbookMapper ebookMapper; @Override public 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); } }
接下来在重新启动项目试试看。
大功告成, 电子书查询接口的功能已经测试成功了。