项目技术介绍
项目采用–前后端分离开发
主要技术:
后端技术:springboot、springcloud、mybatis-plus、springcurity、redis、maven、easyexcel、jwt、oauth2
前端技术:vue+elementui+axios+nodejs
其他技术:阿里云 oss、阿里云视频点播服务、阿里云短信服务、微信支付和登录、docker、git、jenkins
准备工作
1.创建数据库guli,创建讲师数据表edu_teacher
数据库设计规则参考《阿里巴巴Java开发手册》
表必备三字段:id,gmt_create,gmt_modified
CREATE TABLE `edu_teacher` (
`id` char(19) NOT NULL COMMENT '讲师ID',
`name` varchar(20) NOT NULL COMMENT '讲师姓名',
`intro` varchar(500) NOT NULL DEFAULT '' COMMENT '讲师简介',
`career` varchar(500) DEFAULT NULL COMMENT '讲师资历,一句话说明讲师',
`level` int(10) unsigned NOT NULL COMMENT '头衔 1高级讲师 2首席讲师',
`avatar` varchar(255) DEFAULT NULL COMMENT '讲师头像',
`sort` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '排序',
`is_deleted` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '逻辑删除 1(true)已删除, 0(false)未删除',
`gmt_create` datetime NOT NULL COMMENT '创建时间',
`gmt_modified` datetime NOT NULL COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='讲师';
2.创建项目结构
创建父工程----pom类型,管理依赖版本和公共依赖 springboot工程
子模块一 maven工程
子子模块一 maven工程
子子模块二
子模块二
子子模块一
子子模块二
.……
环境搭建
1.创建一个springboot项目
2.修改springboot依赖的版本号为2.2.1.RELEASE
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RElEASE</version>
<relativePath/>
</parent>
3.修改类型为pom
<artifactId>guli_parent</artifactId>
<packaging>pom</packaging>
<version>0.0.1-SNAPSHOT</version>
4.删除pom.xml中的内容
删除
<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>
</dependencies>
5.添加< properties >确定依赖的版本
<properties>
<java.version>1.8</java.version>
<guli.version>0.0.1-SNAPSHOT</guli.version>
<mybatis-plus.version>3.0.5</mybatis-plus.version>
<velocity.version>2.0</velocity.version>
<swagger.version>2.9.2</swagger.version>
<aliyun.oss.version>2.8.3</aliyun.oss.version>
<jodatime.version>2.10.1</jodatime.version>
<poi.version>3.17</poi.version>
<commons-fileupload.version>1.3.1</commons-fileupload.version>
<commons-io.version>2.6</commons-io.version>
<httpclient.version>4.5.1</httpclient.version>
<jwt.version>0.7.0</jwt.version>
<aliyun-java-sdk-core.version>4.3.3</aliyun-java-sdk-core.version>
<aliyun-sdk-oss.version>3.1.0</aliyun-sdk-oss.version>
<aliyun-java-sdk-vod.version>2.15.2</aliyun-java-sdk-vod.version>
<aliyun-java-vod-upload.version>1.4.11</aliyun-java-vod-upload.version>
<aliyun-sdk-vod-upload.version>1.4.11</aliyun-sdk-vod-upload.version>
<fastjson.version>1.2.28</fastjson.version>
<gson.version>2.8.2</gson.version>
<json.version>20170516</json.version>
<commons-dbutils.version>1.7</commons-dbutils.version>
<canal.client.version>1.1.0</canal.client.version>
<docker.image.prefix>zx</docker.image.prefix>
<cloud-alibaba.version>0.2.2.RELEASE</cloud-alibaba.version>
</properties>
5.配置< dependencyManagement >锁定依赖版本
<dependencyManagement>
<dependencies>
<!--Spring Cloud-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${cloud-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--mybatis-plus 持久层-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<!-- velocity 模板引擎, Mybatis Plus 代码生成器需要 -->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>${velocity.version}</version>
</dependency>
<!--swagger-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${swagger.version}</version>
</dependency>
<!--swagger ui-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${swagger.version}</version>
</dependency>
<!--aliyunOSS-->
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>${aliyun.oss.version}</version>
</dependency>
<!--日期时间工具-->
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>${jodatime.version}</version>
</dependency>
<!--xls-->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>${poi.version}</version>
</dependency>
<!--xlsx-->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>${poi.version}</version>
</dependency>
<!--文件上传-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>${commons-fileupload.version}</version>
</dependency>
<!--commons-io-->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>${commons-io.version}</version>
</dependency>
<!--httpclient-->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>${httpclient.version}</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>${gson.version}</version>
</dependency>
<!-- JWT -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>${jwt.version}</version>
</dependency>
<!--aliyun-->
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
<version>${aliyun-java-sdk-core.version}</version>
</dependency>
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>${aliyun-sdk-oss.version}</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-vod</artifactId>
<version>${aliyun-java-sdk-vod.version}</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-vod-upload</artifactId>
<version>${aliyun-java-vod-upload.version}</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-sdk-vod-upload</artifactId>
<version>${aliyun-sdk-vod-upload.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>${json.version}</version>
</dependency>
<dependency>
<groupId>commons-dbutils</groupId>
<artifactId>commons-dbutils</artifactId>
<version>${commons-dbutils.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.otter</groupId>
<artifactId>canal.client</artifactId>
<version>${canal.client.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
6.删除src
7.建立子模块service,修改pom文件类型为pom(注意位置)
<artifactId>service</artifactId>
<packaging>pom</packaging>
8.添加依赖到子模块service中
注释掉springcloud依赖(暂时不用)
<dependencies>
<!--<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>-->
<!--hystrix依赖,主要是用 @HystrixCommand -->
<!--<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>-->
<!--服务注册-->
<!-- <dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>-->
<!--服务调用-->
<!-- <dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--mybatis-plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- velocity 模板引擎, Mybatis Plus 代码生成器需要 -->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
</dependency>
<!--swagger-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
</dependency>
<!--lombok用来简化实体类:需要安装lombok插件-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!--xls-->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
</dependency>
<!--httpclient-->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<!--commons-io-->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
</dependency>
<!--gson-->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
9.删除service模块下的src
10.建立子子模块service_edu(service模块下)
开发讲师管理模块
配置文件
在resources下创建application.yml文件
#服务端口
server:
port: 8001
#服务名 springcloud使用的
spring:
application:
name: service-edu
#环境设置:dev开发环境、test测试环境、prod生产环境
profiles:
active: dev
#mysql数据库连接
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/guli?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8
username: root
password: root
#Mybatis日志
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
编写controller、service、mapper内容
mp提供了代码生成器CodeGenerator,生成相关代码
1.在test的java目录下创建包com.atguigu.demo
2.CodeGenerator.java放入包com.atguigu.demo中
注意:最好改成绝对路径;mp需要单独配置数据库
CodeGenerator.java(复制时,最好复制上导入的包,要不然可能会爆红)
package com.atguigu.demo;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import org.junit.Test;
public class CodeGenerator {
@Test
public void run() {
// 1、创建代码生成器
AutoGenerator mpg = new AutoGenerator();
// 2、全局配置
GlobalConfig gc = new GlobalConfig();
String projectPath = System.getProperty("user.dir");
//最好修改为绝对路径
gc.setOutputDir("E:\\deaProjects\\guli\\service\\service_edu" + "/src/main/java");
gc.setAuthor("cai"); //作者名字
gc.setOpen(false); //生成后是否打开资源管理器
gc.setFileOverride(false); //重新生成时文件是否覆盖
//TeacherService
gc.setServiceName("%sService"); //去掉Service接口的首字母I
gc.setIdType(IdType.ID_WORKER_STR); //主键生成策略 19位 两种 ID_WORKER ID_WORKER_STR
gc.setDateType(DateType.ONLY_DATE);//定义生成的实体类中日期类型
gc.setSwagger2(true);//开启Swagger2模式
mpg.setGlobalConfig(gc);
// 3、数据源配置
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://localhost:3306/guli?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8");
dsc.setDriverName("com.mysql.cj.jdbc.Driver");
dsc.setUsername("root");
dsc.setPassword("root");
dsc.setDbType(DbType.MYSQL);//数据库类型
mpg.setDataSource(dsc);
// 4、包配置
PackageConfig pc = new PackageConfig();
pc.setModuleName("eduservice"); //模块名
//包 com.atguigu.eduservice
pc.setParent("com.atguigu");
//包 com.atguigu.eduservice.controller
pc.setController("controller");
pc.setEntity("entity");
pc.setService("service");
pc.setMapper("mapper");
mpg.setPackageInfo(pc);
// 5、策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setInclude("edu_teacher");//数据库表名,多个的话,可以逗号隔开
strategy.setNaming(NamingStrategy.underline_to_camel);//数据库表映射到实体的命名策略
strategy.setTablePrefix(pc.getModuleName() + "_"); //生成实体时去掉表前缀
strategy.setColumnNaming(NamingStrategy.underline_to_camel);//数据库表字段映射到实体的命名策略
strategy.setEntityLombokModel(true); // lombok 模型 @Accessors(chain = true) setter链式操作
strategy.setRestControllerStyle(true); //restful api风格控制器
strategy.setControllerMappingHyphenStyle(true); //url中驼峰转连字符
mpg.setStrategy(strategy);
// 6、执行
mpg.execute();
}
}
3.执行CodeGenerator
编写eduteacher后台管理api接口
查询所有讲师
1.创建启动类
注意启动类的位置!!
@SpringBootApplication
public class EduApplication {
public static void main(String[] args) {
SpringApplication.run(EduApplication.class,args);
}
}
2.创建配置类,配置mapper扫描和其他(config包下)
@MapperScan("com.atguigu.eduservice.mapper")
public class EduConfig {
}
3.查询所有讲师 —controller中
//@RestController:@Controller创建交给spring管理 @ResponseBody返回json数据
@RestController
@RequestMapping("/eduservice/teacher")
public class EduTeacherController {
//注入service
@Autowired
private EduTeacherService teacherService;
//查询讲师所有数据
//rest风格
@GetMapping("findAll")
public List<EduTeacher> findAllTeacher(){
//调用service中的方法,实现查询所有的操作
List<EduTeacher> list = teacherService.list(null);
return list;
}
}
4.最终测试
重新启动主启动类
http://localhost:8001//eduservice/teacher/findAll
5.统一返回的json时间格式
默认情况下,json时间格式是带有时区并且是世界标准时间,和我们的时间相差8个小时,在application.yml中设置
#返回json的全局时间格式
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
6.重新启动
逻辑删除讲师
1.EduConfig类中配置逻辑删除插件
@Configuration
@MapperScan("com.atguigu.eduservice.mapper")
public class EduConfig {
/**
* 逻辑删除插件
*/
@Bean
public ISqlInjector sqlInjector() {
return new LogicSqlInjector();
}
}
2.逻辑删除属性上添加注解
@ApiModelProperty(value = "逻辑删除 1(true)已删除, 0(false)未删除")
@TableLogic
private Boolean isDeleted;
3.编写controller中的方法
//逻辑删除所有讲师
//id值需要通过路径进行传递
@DeleteMapping("{id}")
//@PathVariable获取路径中的id值
public boolean removeTeacher(@PathVariable String id){
boolean flag = teacherService.removeById(id);
return flag;
}
4.如何测试?
借助工具测试:postman(了解,主要是前端用),swagger(重点)
整合swagger
优点:1.生成接口在线文档;2.方便接口测试
整合swagger
1.新建公共模块
guli父模块下创建子模块common,在common中创建子模块service_base
2.修改子模块common的pom文件
<artifactId>common</artifactId>
<packaging>pom</packaging>
添加依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<scope>provided </scope>
</dependency>
<!--mybatis-plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<scope>provided </scope>
</dependency>
<!--lombok用来简化实体类:需要安装lombok插件-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided </scope>
</dependency>
<!--swagger-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<scope>provided </scope>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<scope>provided </scope>
</dependency>
<!-- redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- spring2.X集成redis所需common-pool2
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.6.0</version>
</dependency>-->
</dependencies>
3.service_base模块的java下建立com.atguigu.servicebase包
创建swagger的配置类
package com.atguigu.servicebase;
import com.google.common.base.Predicates;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.service.Contact;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@Configuration //配置类
@EnableSwagger2 //swagger注解
public class SwaggerConfig {
@Bean
public Docket webApiConfig(){
return new Docket(DocumentationType.SWAGGER_2)
.groupName("webApi")
.apiInfo(webApiInfo())
.select()
.paths(Predicates.not(PathSelectors.regex("/admin/.*")))
.paths(Predicates.not(PathSelectors.regex("/error.*")))
.build();
}
private ApiInfo webApiInfo(){
return new ApiInfoBuilder()
.title("尚硅谷-谷粒学苑")
.description("本文档描述了谷粒学苑的接口定义")
.version("1.0")
.contact(new Contact("菜菜", "https://blog.csdn.net/qq_44918461?type=blog", "380693433@qq.com"))
.build();
}
}
4.具体使用
(1)在service模块的pom中 引入swagger
<!--引入swagger-->
<dependency>
<groupId>com.atguigu</groupId>
<artifactId>service_base</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
(2)service_edu的启动类中加注解,设置包扫描规则
目的:要使启动类扫描到swagger类,要加注解,不然只扫描当前包下的内容
@SpringBootApplication
@ComponentScan(basePackages = {"com.atguigu"} )//设置包的扫描规则
public class EduApplication {
public static void main(String[] args) {
SpringApplication.run(EduApplication.class,args);
}
}
启动主启动类
(3)访问swagger
http://localhost:8001/swagger-ui.htm
了解:定义接口说明和参数说明
定义在类上:@Api
定义在方法上:@ApiOperation
定义在参数上:@ApiParam
统一返回数据格式
json数据格式:2种
对象
数组
实际中两种混合使用
返回结果数据格式(列表)
分页会增加 total和rows(对应data)
{"success":布尔 //响应是否成功
"code":数字 //状态码
"message":字符串 //返回消息
"data":HashMap //返回数据,放在键值对种
}
1.在common模块创建子模块common_utils
2.创建interface,定义数据返回状态码
*成功 20000
*失败 20001
package com.atguigu.commonutils;
/**
* 统一结果状态码
*/
public interface ResultCode {
public static Integer SUCCESS=20000; //成功
public static Integer ERROR=20001; //失败
}
3.定义返回数据格式
package com.atguigu.commonutils;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.HashMap;
import java.util.Map;
@Data
public class R {
@ApiModelProperty(value = "是否成功")
private Boolean success;
@ApiModelProperty(value = "返回码")
private Integer code;
@ApiModelProperty(value = "返回消息")
private String message;
@ApiModelProperty(value = "返回数据")
private Map<String, Object> data = new HashMap<String, Object>();
//构造方法私有
private R(){}
//成功静态方法
public static R ok(){
R r=new R();
r.setSuccess(true);
r.setCode(ResultCode.SUCCESS);
r.setMessage("成功");
return r;
}
//失败静态方法
public static R error(){
R r=new R();
r.setSuccess(false);
r.setCode(ResultCode.ERROR);
r.setMessage("失败");
return r;
}
//下面四个方法返回this是链式编程 可以对类中的每一个属性单独设置
public R success(Boolean success){
this.setSuccess(success);
return this;
}
public R message(String message){
this.setMessage(message);
return this;
}
public R code(Integer code){
this.setCode(code);
return this;
}
public R data(String key,Object value){
this.data.put(key,value);
return this;
}
public R data(Map<String,Object> map){
this.setData(map);
return this;
}
}
4.具体使用
(1)在service模块种引入common_utils
<!--引入统一返回结果集-->
<dependency>
<groupId>com.atguigu</groupId>
<artifactId>common_utils</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
(2)接口方法返回结果都为R(注意导入的R的包)
//查询讲师所有数据
@GetMapping("findAll")
public R findAllTeacher(){
//调用service中的方法,实现查询所有的操作
List<EduTeacher> list = teacherService.list(null);
return R.ok().data("items",list);
}
@DeleteMapping("{id}")
//@PathVariable获取路径中的id值
public R removeTeacher(@ApiParam(name = "id",value = "讲师ID",required = true)
@PathVariable String id){
boolean flag = teacherService.removeById(id);
if (flag){
return R.ok();
}else {
return R.error();
}
}
讲师分页管理
1.配置mp分页插件
/**
* 分页插件
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
2.编写讲师分页查询接口的方法
//3.分页查询讲师的方法
@ApiOperation("讲师分页查询")
@GetMapping("pageTeacher/{current}/{limit}")
public R pageListTeacher(@PathVariable long current,
@PathVariable long limit){
//创建page对象
Page<EduTeacher> pageTeacher = new Page<>(current,limit);
//调用方法实现分页
//调用方法的时候,底层封装,把分页所有的数据封装到pageTeacher对象里面
teacherService.page(pageTeacher,null);
long total = pageTeacher.getTotal();//总记录数
List<EduTeacher> records = pageTeacher.getRecords();//每页记录数
//采用map集合的方式
Map map = new HashMap();
map.put("total",total);
map.put("rows",records);
return R.ok().data(map);
}
讲师多条件组合查询带分页
1.把条件值传递到接口里面
把条件封装到对象里面,把对象传递到接口里面 vo
2.根据条件值进行判断,拼接条件
注意:
@RequestBody 使用json传递数据,把json数据封装到对应的对象里面,需要使用post提交方式
@ResponseBody 返回数据,返回json数据
//4.条件查询带分页
//@RequestBody 使用json传递数据,把json数据封装到对应的对象里面,需要使用post提交方式参数值可以为空
//@ResponseBody 返回数据,返回json数据
@ApiOperation("多条件查询带分页")
@PostMapping("pageTeacherCondition/{current}/{limit}")
public R pageTeacherCondition(@PathVariable long current,
@PathVariable long limit,
@RequestBody(required = false) TeacherQuery teacherQuery){
//创建page对象
Page<EduTeacher> page = new Page<>(current,limit);
//构建条件
QueryWrapper<EduTeacher> wrapper = new QueryWrapper<>();
//wrapper 多条件组合查询
//取出数据
String name = teacherQuery.getName();
Integer level = teacherQuery.getLevel();
String begin = teacherQuery.getBegin();
String end = teacherQuery.getEnd();
//判断条件值是否为空,如果不为空,拼接条件
if (!StringUtils.isEmpty(name)){
//构建条件
wrapper.like("name",name);
}
if (!StringUtils.isEmpty(level)){
wrapper.eq("level",level);
}
if (!StringUtils.isEmpty(begin)){
//表中字段名称
wrapper.gt("gmt_create",begin);
}
if (!StringUtils.isEmpty(end)){
wrapper.le("gmt_create",end);
}
//调用方法,实现分页查询带分页
teacherService.page(page,wrapper);
return R.ok();
}
添加讲师
1.在实体类添加自动填充注解
添加@TableField
@ApiModelProperty(value = "创建时间")
@TableField(fill = FieldFill.INSERT)
private Date gmtCreate;
@ApiModelProperty(value = "更新时间")
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date gmtModified;
2.在service_base模块中
创建handler包,创建自动填充类 MyMetaObjectHandler
注意:传入属性名,不是字段名
package com.atguigu.servicebase.handler;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.util.Date;
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
//属性名称,不是字段名称
this.setFieldValByName("gmtCreate",new Date(),metaObject);
this.setFieldValByName("gmtModified",new Date(),metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
this.setFieldValByName("gmtModified",new Date(),metaObject);
}
}
3.编写controller
//5.添加讲师
@ApiOperation("添加讲师")
@PostMapping("addTeacher")
public R addTeacher(@RequestBody EduTeacher eduTeacher){
boolean save = teacherService.save(eduTeacher);
if (save){
return R.ok();
}else {
return R.error();
}
}
修改讲师
1.查询数据回显–根据讲师id进行查询
@ApiOperation("根据讲师id进行查询")
//根据讲师id进行查询
@GetMapping("getTeacher/{id}")
public R getTeacher(@PathVariable String id){
EduTeacher eduTeacher = teacherService.getById(id);
return R.ok().data("teacher",eduTeacher);
}
2.修改–讲师修改
测试时,json数据需要id值
//讲师修改功能
@ApiOperation("讲师修改功能")
@PostMapping("updateTeacher")
public R updateTeacher(@RequestBody EduTeacher eduTeacher){
boolean flag = teacherService.updateById(eduTeacher);
if (flag){
return R.ok();
}else {
return R.error();
}
}
统一异常处理
全局异常处理
1.创建统一异常处理类
在service_base中创建统一异常处理类
package com.atguigu.servicebase.exceptionhandler;
import com.atguigu.commonutils.R;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
@ControllerAdvice
public class GlobalExceptionHandler{
//指定出现什么异常执行这个方法
@ExceptionHandler(Exception.class)
@ResponseBody //为了能够返回数据
public R error(Exception e){
e.printStackTrace();
return R.ok().message("出现异常!!!");
}
}
2.测试
特定异常处理
//特定异常
@ExceptionHandler(ArithmeticException.class)
@ResponseBody //为了能够返回数据
public R error(ArithmeticException e){
e.printStackTrace();
return R.ok().message("特定异常!!!");
}
执行的规则:如果有特定异常,执行特定异常,如果没有,就执行全局异常。
自定义异常处理
1.创建自定义异常类,继承RuntimeException写以异常属性
package com.atguigu.servicebase.exceptionhandler;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 自定义异常类
*/
@Data
@NoArgsConstructor //生成无参构造
@AllArgsConstructor //生成有参构造
public class GuliException extends RuntimeException{
private Integer code;//状态码
private String msg;//异常信息
}
2…添加异常处理方法
//3.自定义异常
@ExceptionHandler(GuliException.class)
@ResponseBody //为了能够返回数据
public R error(GuliException e){
e.printStackTrace();
return R.ok().code(e.getCode()).message(e.getMsg());
}
3.业务中需要的位置抛出自定义异常(手动抛出),执行自定义异常
try{
int i = 10/0;
}catch (Exception e){
//执行自定义异常
throw new GuliException(20001,"执行了自定义异常");
}
日志
配置日志级别
OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL
默认springboot控制台默认级别INFO
设置日志级别
#设置日志级别
logging.level.root: WARN
统一日志处理(Logback日志)
日志工具Logback、log4j
1.删除application.yml中的日志配置
#Mybatis日志
#mybatis-plus:
#configuration:
#log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
#设置日志级别
#logging.level.root: INFO
2.在resources中创建logback-spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="10 seconds">
<!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设置为WARN,则低于WARN的信息都不会输出 -->
<!-- scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true -->
<!-- scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->
<!-- debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->
<contextName>logback</contextName>
<!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义变量后,可以使“${}”来使用变量。 -->
<property name="log.path" value="D:/java项目/gulischool/edu" />
<!-- 彩色日志 -->
<!-- 配置格式变量:CONSOLE_LOG_PATTERN 彩色日志格式 -->
<!-- magenta:洋红 -->
<!-- boldMagenta:粗红-->
<!-- cyan:青色 -->
<!-- white:白色 -->
<!-- magenta:洋红 -->
<property name="CONSOLE_LOG_PATTERN"
value="%yellow(%date{yyyy-MM-dd HH:mm:ss}) |%highlight(%-5level) |%blue(%thread) |%blue(%file:%line) |%green(%logger) |%cyan(%msg%n)"/>
<!--输出到控制台-->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
<!-- 例如:如果此处配置了INFO级别,则后面其他位置即使配置了DEBUG级别的日志,也不会被输出 -->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
<encoder>
<Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
<!-- 设置字符集 -->
<charset>UTF-8</charset>
</encoder>
</appender>
<!--输出到文件-->
<!-- 时间滚动输出 level为 INFO 日志 -->
<appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文件的路径及文件名 -->
<file>${log.path}/log_info.log</file>
<!--日志文件输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 每天日志归档路径以及格式 -->
<fileNamePattern>${log.path}/info/log-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文件保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文件只记录info级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 时间滚动输出 level为 WARN 日志 -->
<appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文件的路径及文件名 -->
<file>${log.path}/log_warn.log</file>
<!--日志文件输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset> <!-- 此处设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/warn/log-warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文件保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文件只记录warn级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>warn</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 时间滚动输出 level为 ERROR 日志 -->
<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文件的路径及文件名 -->
<file>${log.path}/log_error.log</file>
<!--日志文件输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset> <!-- 此处设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/error/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文件保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文件只记录ERROR级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!--
<logger>用来设置某一个包或者具体的某一个类的日志打印级别、以及指定<appender>。
<logger>仅有一个name属性,
一个可选的level和一个可选的addtivity属性。
name:用来指定受此logger约束的某一个包或者具体的某一个类。
level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
如果未设置此属性,那么当前logger将会继承上级的级别。
-->
<!--
使用mybatis的时候,sql语句是debug下才会打印,而这里我们只配置了info,所以想要查看sql语句的话,有以下两种操作:
第一种把<root level="INFO">改成<root level="DEBUG">这样就会打印sql,不过这样日志那边会出现很多其他消息
第二种就是单独给mapper下目录配置DEBUG模式,代码如下,这样配置sql语句会打印,其他还是正常DEBUG级别:
-->
<!--开发环境:打印控制台-->
<springProfile name="dev">
<!--可以输出项目中的debug日志,包括mybatis的sql日志-->
<logger name="com.guli" level="INFO" />
<!--
root节点是必选节点,用来指定最基础的日志输出级别,只有一个level属性
level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,默认是DEBUG
可以包含零个或多个appender元素。
-->
<root level="INFO">
<appender-ref ref="CONSOLE" />
<appender-ref ref="INFO_FILE" />
<appender-ref ref="WARN_FILE" />
<appender-ref ref="ERROR_FILE" />
</root>
</springProfile>
<!--生产环境:输出到文件-->
<springProfile name="pro">
<root level="INFO">
<appender-ref ref="CONSOLE" />
<appender-ref ref="DEBUG_FILE" />
<appender-ref ref="INFO_FILE" />
<appender-ref ref="ERROR_FILE" />
<appender-ref ref="WARN_FILE" />
</root>
</springProfile>
</configuration>
3.把异常信息输出到文件
(1)类上添加注解@SLf4j
(2)异常输出语句
@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler{
//3.自定义异常
@ExceptionHandler(GuliException.class)
@ResponseBody //为了能够返回数据
public R error(GuliException e){
//异常输出语句
log.error(e.getMessage());
e.printStackTrace();
return R.ok().code(e.getCode()).message(e.getMsg());
}
}