在线教育项目 Day02
文章目录
概念介绍:前后端分离
前端:html、css、js、jq。主要作用:数据显示
ajax操作:调用后端数据(调用接口)
后端:controller、service、mapper。主要作用:返回数据或操作数据
开发接口:开发controller、service、mapper的过程(不是interface)
搭建项目环境
创建数据库
创建讲师数据库表(此处直接导入课程提供资料)
创建项目结构
创建父工程(springboot工程)(Maven阶段学习)
pom类型,管理依赖版本和存放公共依赖
子模块(Maven工程)
子子模块(Maven工程)
项目结构:父工程 → 子模块 → 子子模块
-
创建父工程(springboot工程:文件→新建→项目→spring initializ)
配置pom.xml:
<artifactId>guli_parent</artifactId> <packaging>pom</packaging> //表示当前类型是一个pom类型
在pom.xml中添加依赖版本
-
创建service子模块(Maven工程:文件→新建→项目→Maven)
注:在导入依赖时,首先需要修改版本为pom,其次需要将最开始的几个依赖注释掉,否则会报错。(xml文件的注释方法见本文最后)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kHn7XFum-1618664317176)(…/…/AppData/Roaming/Typora/typora-user-images/image-20210404200216888.png)]
讲师管理接口开发
讲师管理模块配置与生成代码
一、讲师管理模块配置
-
在service下面service-edu模块中创建配置文件:
resources目录下创建文件 application.properties:
(或者可以创建yml格式文件,但未学不会)
# 服务端口(port)
# 因为现在创建的项目都是web工程(浏览器访问,需要用到端口)
# 若不写,则默认为Tomcat的端口号8080
server.port=8001
# 服务名
spring.application.name=service-edu
# 环境设置:dev、test、prod(开发、测试、生产环境)
spring.profiles.active=dev
# mysql数据库连接
# 新版本,需要加上时区
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/guli?serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=mysql883721@
#mybatis日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
-
创建MP代码生成器
由MybatisPlus提供,可以生成controller service mapper。不用自己创建。
不要求会写代码,要求会改
需要修改的部分
- 修改代码生成的地址,改为本项目的绝对地址
- 根据项目设置的主键的类型(long、char),修改主键策略
//gc.setOutputDir(projectPath + "/src/main/java");//生成代码的输出目录 gc.setOutputDir("D:\\guli_parent\\service\\service_edu" + "/src/main/java"); //注意上下两行的区别 //被注释的部分使用的是相对路径,可能出错 //其下行使用绝对路径
gc.setIdType(IdType.ID_WORKER); //主键策略:ID_WORKER、ID_WORKER_STR
- 修改数据库配置
dsc.setUrl("jdbc:mysql://localhost:3306/数据库名称?serverTimezone=GMT%2B8 "); //修改数据库名称添加时区 dsc.setDriverName("com.mysql.cj.jdbc.Driver");//添加“cj” dsc.setPassword("***********");//修改为自己的数据库的密码
- 包配置
// 4、包配置
PackageConfig pc = new PackageConfig();
//改为实际上自己的包:
//执行后,会生成一个包,包名为com.atguigu.eduservice
pc.setParent("com.atguigu");
pc.setModuleName("eduservice"); //模块名
//包名为com.atguigu.eduservice.controller
pc.setController("controller");
//包名为com.atguigu.eduservice.entity
pc.setEntity("entity");
//包名为com.atguigu.eduservice.service,等等。顺序无所谓,都是按照此结构生成
pc.setService("service");
pc.setMapper("mapper");
mpg.setPackageInfo(pc);
- 策略配置
strategy.setInclude("edu_teacher");//自己的表的名称,如果有多张表,用逗号隔开
strategy.setTablePrefix(pc.getModuleName() + "_"); //生成实体时去掉表前缀
//将表中字段get_Course在实体类中变为getCourse
//此处不需要修改
执行结束:
service和mapper部分编写结束;但controller 部分中只有一个类,需要自己编写。
可能的失败的原因:路径错误、缺少依赖
二、编写后台管理api接口
-
编写controller代码
@RestController
注解的内部信息创建controller:
完成了controller调用service,service调用mapper
@RestController @RequestMapping("/eduservice/edu-teacher") //该注解表示最后访问的数据 public class EduTeacherController { //controller需要调用service方法,所以需要注入service方法 //把service注入 @Autowired private EduTeacherService teacherService; //1 查询讲师表所有数据 @GetMapping("findAll") public List<EduTeacher> findAllTeacher() { //此处的list<EduTeacher>为返回值类型 List<EduTeacher> list = teacherService.list(null); return list; } }
-
创建启动类
package com.atguigu.eduservice; //这是一个启动类。 //启动类的创建规范不太熟悉 import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class EduApplication { public static void main(String[] args) { SpringApplication.run(EduApplication.class, args); } }
-
创建配置类
@Configuration //配置类首先需要添加该注解 @MapperScan("package com.atguigu.eduservice.mapper;") //此处的地址为mapper的Interface地址,EduTeacherMapper的首行中 public class EduConfig { }
-
最终测试
运行启动类中的
main方法
此处报错,未解决
3、配置SQL执行性能分析插件
4、创建SpringBoot启动类
5、运行启动类
6、统一返回的json时间格式
在application.properties中配置:
#返回json的全局时间格式
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=GMT+8
三、讲师逻辑删除功能
- 配置逻辑删除插件
在EduConfig配置类中添加:
public class EduConfig {
/**
* 逻辑删除插件
*/
@Bean
public ISqlInjector sqlInjector() {
return new LogicSqlInjector();
}
@ApiModelProperty(value = "逻辑删除 1(true)已删除, 0(false)未删除")
@TableLogic
private Boolean isDeleted;
**注意:**使用逻辑删除时,必须添加注解@TableLogic
-
在controller中编写最终的删除方法
通过路径删除
此后删除惯用此方法
//2 逻辑删除讲师的方法 //删除一般使用delete提交方法 @DeleteMapping("{id}") //此处根据id删除。此处的id需要通过路径进行传递 //localhost:8001/edu/delete/1 此处的“1”就是通过路径传递的id值 public boolean removeTeacher(@PathVariable String id){ //上一行的作用,获取到路径中输入的id值 boolean flag = teacherService.removeById(id); return flag; }
3、测试删除
浏览器不可以进行delete测试(可以做get提交)
需要借助工具进行测试:
- swagger测试(重点)
- postman(了解)
整合Swagger进行接口测试
好处:
-
能生成在线接口文档(API)
-
方便进行接口的测试
做法:创建公共模块,整合swagger,为了使所有的模块都能使用
配置Swagger2
1、创建common模块
在guli-parent下创建子模块common
2、在common
中引入相关依赖
<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>
同时注意修改:
<artifactId>common</artifactId>
<packaging>pom</packaging>
项目的打包类型:pom、jar、war
packing默认是jar类型,
pom --> 父类型都为pom类型;
jar --> 内部调用或者是作服务使用;
war --> 需要部署的项目。
3、在common下面创建子模块 service-base
在模块service-base中,创建swagger的配置类
在service_base -src -mian -java
目录下新建一个包com.atguigu.servicebase.config
,
在其中创建一个配置类SwaggerConfig
注:需要手动导入类
@Configuration //配置类
@EnableSwagger2 //swagger注解
public class SwaggerConfig {
@Bean
public Docket webApiConfig(){
//实质上为配置swagger插件
//一般不需要修改,可能需要改组名、方法名或提示信息
return new Docket(DocumentationType.SWAGGER_2) //类型:swagger
.groupName("webApi")
.apiInfo(webApiInfo()) //下方的方法,可以设置其中的值
.select()
.paths(Predicates.not(PathSelectors.regex("/admin/.*")))
.paths(Predicates.not(PathSelectors.regex("/error.*")))
//路径中如果包含admin、error,就不显示
.build();
}
private ApiInfo webApiInfo(){
return new ApiInfoBuilder()
.title("网站-课程中心API文档")
.description("本文档描述了课程中心微服务接口定义")
.version("1.0")
.contact(new Contact("Helen", "http://atguigu.com", "55317332@qq.com"))
.build();
}
}
具体使用:
1. 在模块service模块中引入service-base:
此时的service-base在common中,需要导入到service中,才能被service_edu使用
地址:service -pom.xml
<dependency>
<groupId>com.atguigu</groupId>
<artifactId>service-base</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
-
在
service-edu
启动类上添加注解,进行测试地址:
service -service_edu -src -main -java -com.atguigu.eduservice -EduApplication
@ComponentScan(basePackages={"com.atguigu"}) //添加注解,修改启动类中的扫描规则 //若不改,只能扫描到当前项目中的类(swagger属于另一个配置类) //swaggerconfig的包也是以com.atguigu开头,可以在其中扫描
-
访问swagger
访问地址:http://localhost:8001/swagger-ui.html
P25,待补充
6、API模型
可以添加一些自定义设置,例如:
定义样例数据
@ApiModelProperty(value = "创建时间", example = "2019-01-01 8:00:00")
@TableField(fill = FieldFill.INSERT)
private Date gmtCreate;
@ApiModelProperty(value = "更新时间", example = "2019-01-01 8:00:00")
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date gmtModified;
5、定义接口说明和参数说明
在EduTeacherController上添加以下注解
作用:在测试时提供更好的显示,能显示中文提示
定义在类上:@Api
定义在方法上:@ApiOperation
定义在参数上:@ApiParam
@Api(description="讲师管理")
@RestController
@RequestMapping("/admin/edu/teacher")
public class TeacherAdminController {
@Autowired
private TeacherService teacherService;
@ApiOperation(value = "所有讲师列表")
@GetMapping
public List<Teacher> list(){
return teacherService.list(null);
}
@ApiOperation(value = "根据ID删除讲师")
@DeleteMapping("{id}")
public boolean removeById(
@ApiParam(name = "id", value = "讲师ID", required = true)
@PathVariable String id){
return teacherService.removeById(id);
}
}
统一返回结果对象
一、统一返回数据格式
不同人设置的返回值不同,0/1,true/false
项目中我们会将响应封装成json返回,一般我们会将所有接口的数据格式统一, 使前端(iOS Android, Web)对数据的操作更一致、轻松。
一般情况下,统一返回数据格式没有固定的格式,只要能描述清楚返回的数据状态以及要返回的具体数据就可以。但是一般会包含状态码、返回消息、数据这几部分内容
json数据的两种格式:对象、数组
定义统一结果:
{
"success": 布尔, //响应是否成功
"code": 数字, //响应码(int)
"message": 字符串, //返回消息
"data": HashMap //返回数据,放在键值对中
}
map格式:key + value
二、创建统一结果返回类
1、在common模块
下创建子模块common-utils
很多模块都会用到这一模块,所以同swagger一起放到common模块中
2、创建接口(interface)定义返回码
创建包com.atguigu.commonutils,创建接口 ResultCode.java
在其中定义响应码的固定值。或者可以写一个常量类。
public interface ResultCode {
//状态码,两个固定的值
public static Integer SUCCESS = 20000;//成功
public static Integer ERROR = 20001;//失败
}
4、创建结果类
创建类 R.java
@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(){}
//方法私有化,让其他人不可以创建(new),只能使用下方定义的两个static方法
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;
}
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;
}
}
二、统一返回结果使用
1、在service模块中添加依赖
此处报错未找到依赖
原因:创建common_utils和service_base时使用的名称不对,在依赖中需要修改名称
<dependency>
<groupId>com.atguigu</groupId>
<artifactId>common_utils</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
2、修改Controller中的返回结果
不清楚是哪一个controller
@ApiOperation(value = "所有讲师列表")
@GetMapping
public R list(){
List<Teacher> list = teacherService.list(null);
return R.ok().data("items", list);
}
3、Swagger中测试
分页与条件查询
分页
1、MyBatisPlusConfig中配置分页插件
地址:EduConfig
/**
* 分页插件
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
2、分页Controller方法
编写讲师分页查询接口的方法
TeacherAdminController(EduTeacherController.java
)中添加分页方法
//3. 分页查询讲师的方法
@GetMapping("pageTeacher/{current}/{limit}")
//此处为路径传值 pageTeacher/{current}/{limit},传入下方page所需的两个值
//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();
return R.ok();
//返回的结果参考统一结果返回的效果
//ok()是在那里定义的函数
//或者使用下面这种方法:
//Map map = new HashMap();
//map.put("total",total);
//map.put("records",records);
//return.R.ok().data(map);
}
注:本例中通过路径传值的方法需要掌握; Page<EduTeacher> pageTeacher = new Page<>(current,limit);
中需要填写参数
未解决:
-
Page<EduTeacher> pageTeacher = new Page<>(current,limit);
处,括号内引入的参数未出现提示; -
long total = pageTeacher.getTotal();//总记录数
处,getTotal方法未显示 -
Swagger测试
二、多条件组合查询(带分页功能)
根据讲师名称name,讲师头衔level、讲师入驻时间gmt_create(时间段)查询
1、创建查询对象
创建com.guli.edu.query包,创建TeacherQuery.java查询对象
2、service
接口
实现
3、controller
TeacherAdminController中修改 pageList方法:
增加参数TeacherQuery teacherQuery,非必选
4.在Swagger中测试
新增与修改
一、自动填充封装
1、在service-base模块中添加
创建包handler,创建自动填充类 MyMetaObjectHandler
2、在实体类添加自动填充注解
二、controller方法定义
-
新增
-
根据id查询
-
根据id修改
统一异常处理
一、创建统一异常处理器
在service-base中创建统一异常处理类GlobalExceptionHandler.java:
三、处理特定异常
1、添加异常处理方法
GlobalExceptionHandler.java中添加
四、自定义异常
1、创建自定义异常类
2、业务中需要的位置抛出GuliException
3、添加异常处理方法
GlobalExceptionHandler.java中添加
统一日志处理
遇到的问题及解决办法
SQL yog中使用SQL语句导入表
对于一个新建的数据库,无法打开query界面输入sql语句,需要先创建一个表。
此时,该数据库下没有表:
右键→创建表
创建表:
打开表:
刷新界面:
导入成功:
在 .xml 文件中添加注释
选中待注释的代码,使用快捷键:Ctrl + Shift + "/"
Maven导入依赖后的操作
需要按刷新键
进行刷新,即完成联网下载
粘贴文字到Typora时如何消除格式
Ctrl + Shift + V 完成去格式粘贴