目录
day1
随堂笔记
1.@runwith爆红,是因为没有加junit依赖
2.我们可以加mapperscan+reporsery 代替 @mapper
3.mybatis日志,可以在控制台看sql语句
mybatis-plus.configuration.log-impl
=org.apache.ibatis.logging.stdout.StdOutImpl
4.全局唯一Id
分布式系统唯一ID生成方案汇总 - nick hao - 博客园唯一ID生成
https://www.cnblogs.com/haoxinyue/p/5208136.html
5.mp自动填充
(1)增加映射类对应的属性(驼峰规则)
(2)实现一个MetaObjectHandler的接口,重写方法,测试即可
6.可以加一个config类,配置特定的功能
@EnableTransactionManagement
@Configuration
@MapperScan("com.atguigu.mybatisplus.mapper")
public class MybatisPlusConfig {
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor(){
return new OptimisticLockerInterceptor();
}
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
@Bean
public ISqlInjector sqlInjector(){
return new LogicSqlInjector();
}
@Bean
@Profile({"dev","text"})
public PerformanceInterceptor performanceInterceptor(){
PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
performanceInterceptor.setMaxTime(5000);
performanceInterceptor.setFormat(true);
return performanceInterceptor;
}
}
7.wrapper条件构造器
总结分析:
1.MP代码流程:
Day2
随堂笔记
1.依赖在子模块已经引用了 ,子子模块可以直接进行使用
2.swagger的使用:
(1)主启动类添加
@ComponentScan(basePackages = {"com.atguigu"})
(2)引入swagger包的配置
3.条件查询+分页查询:
step1: 把条件值封装到对象里面,把对象传递到接口里面
4.异常处理
总结:
1.分页+查询的方式:
(1)创建查询对象
(2)controller层
@Api(description="讲师管理")
@RestController
@RequestMapping("/eduservice/teacher")
public class EduTeacherController {
//访问地址: http://localhost:8001/eduservice/teacher/findAll
//把service注入
@Autowired
private EduTeacherService teacherService;
//3 分页查询讲师的方法
//current 当前页
//limit 每页记录数
@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(); //数据list集合
// Map map = new HashMap();
// map.put("total",total);
// map.put("rows",records);
// return R.ok().data(map);
return R.ok().data("total",total).data("rows",records);
}
//4 条件查询带分页的方法
@PostMapping("pageTeacherCondition/{current}/{limit}")
public R pageTeacherCondition(@PathVariable long current,@PathVariable long limit,
@RequestBody(required = false) TeacherQuery teacherQuery) {
//创建page对象
Page<EduTeacher> pageTeacher = new Page<>(current,limit);
//构建条件
QueryWrapper<EduTeacher> wrapper = new QueryWrapper<>();
// 多条件组合查询
// mybatis学过 动态sql
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.ge("gmt_create",begin);
}
if(!StringUtils.isEmpty(end)) {
wrapper.le("gmt_create",end);
}
//调用方法实现条件查询分页
teacherService.page(pageTeacher,wrapper);
long total = pageTeacher.getTotal();//总记录数
List<EduTeacher> records = pageTeacher.getRecords(); //数据list集合
return R.ok().data("total",total).data("rows",records);
}
}
(3)如果要分页还需要借助分页插件
@Configuration
@MapperScan("com.atguigu.eduservice.mapper")
public class EduConfig {
/**
* 逻辑删除插件
*/
@Bean
public ISqlInjector sqlInjector() {
return new LogicSqlInjector();
}
/**
* 分页插件
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
}
Day3,4
1.babel报错:
2. ./ &../
Day 5
1.入职后,看懂他人已经写的代码,根据他人写的代码来进行调整。
2.错误:
(1)格式转换异常
org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'java.lang.Long'; nested exception is java.lang.NumberFormatException: For input string: "getTeacher“
原因,路径写错了,应该是 getTeacher/{id} 而我是/{id}这样的意思就是格式转换错误
(2)上传文件的空指针异常
原因:
官网文档为:
InputStream inputStream = new FileInputStream(filePath);
但是,我们在做的时候,使用的是springmvc的架构,所以我们要改一下,不能直接,new,而是要从前端传过来的数据进行获取
更改如下:
InputStream inputStream = file.getInputStream();
这样就不会报空指针异常了
Day7:
1.关联查询new对象的关键:
List<OneSubject> finalList=new ArrayList<>();
//封装1级别
// OneSubject oneSubject=new OneSubject();//这么写最后只会重复最后一个,因为地址值是一样的。
for (int i = 0; i <oneSubjectList.size() ; i++) {
OneSubject oneSubject=new OneSubject();
EduSubject eduSubject = oneSubjectList.get(i);
// oneSubject.setId(oneSubjectList.get(i).getId());
//oneSubject.setTitle(oneSubjectList.get(i).getTitle());
BeanUtils.copyProperties(eduSubject, oneSubject);
finalList.add(oneSubject);
2.前端需要什么,我们就在后端建立相关的实体类:
前端需要的属性,数据库的edu_course表不能提供完全,所以单独封装一个
@Data
public class CourseInfoVo {
@ApiModelProperty(value = "课程ID")
private String id;
@ApiModelProperty(value = "课程讲师ID")
private String teacherId;
@ApiModelProperty(value = "课程专业ID")
private String subjectId;
@ApiModelProperty(value = "课程标题")
private String title;
@ApiModelProperty(value = "课程销售价格,设置为0则可免费观看")
// 0.01
private BigDecimal price;
@ApiModelProperty(value = "总课时")
private Integer lessonNum;
@ApiModelProperty(value = "课程封面图片路径")
private String cover;
@ApiModelProperty(value = "课程简介")
private String description;
}
后期可以利用,BeanUtils.copyProperties(源数据,目标数据);将接受来的数据放到不同的表中
3.一对一的关系,ID得一样
@ApiModelProperty(value = "课程ID")
@TableId(value = "id", type = IdType.INPUT)//该值需要我们手动输入
private String id;
Day8
1.一对多封装:
public class EduChapterServiceImpl extends ServiceImpl<EduChapterMapper, EduChapter> implements EduChapterService {
@Override
public List<ChapterVo> getChapterVideo(String courseId) {
//这样是不行的,因为不是数组,所以要用basemapper的另一个方法,把他转换成数组
EduChapter eduChapter = baseMapper.selectById(courseId);
List<ChapterVo> finalList= new ArrayList<>();
2.一对多查询有优化,还有删除方式如下
3.多表查询手写xml的文件
使用AS和VO类对应
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.atguigu.eduservice.mapper.EduCourseDescriptionMapper">
<select id="getPublishInfo" resultType="com.atguigu.eduservice.entity.vo.CoursePublishVo">
SELECT ec.id,ec.title,ec.price,ec.lesson_num AS lessonNum,ec.cover,
et.name AS teacherName,
es1.title AS subjectLevelOne,
es2.title AS subjectLevelTwo
FROM edu_course ec LEFT OUTER JOIN edu_course_description ecd ON ec.id=ecd.id
LEFT OUTER JOIN edu_teacher et ON ec.teacher_id=et.id
LEFT OUTER JOIN edu_subject es1 ON ec.subject_parent_id=es1.id
LEFT OUTER JOIN edu_subject es2 ON ec.subject_id=es2.id
WHERE ec.id=#{courseId}
</select>
4.报错:
org.apache.ibatis.binding.BindingException: Invalid bound statement (not found)
(1)namespace等名字写错
(2)maven没有加载
Day9:
云视频点播,安装lib:
mvn install:install-file -DgroupId=com.aliyun -DartifactId=aliyun-sdk-vod-upload -Dversion=1.4.11 -Dpackaging=jar -Dfile=aliyun-java-vod-upload-1.4.11.jar
因为不用数据库,所以要注意排除:
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
Day10
1.feign的代码是在调用端写
2.feign的pathvariable注解
一定要注明参数
3.判断对象是否为空用这个
StringUtils.isEmpty(videoSourceId)
StringUtils.isEmpty( xxx )对括号中的内容判断是否为null 和 " " 空字符串。
而xxx == null ,是判断该对象是否为null。
4.把list集合按照逗号变成字符串
String join= StringUtils.join(list.toArray(),",");
Day11
1.@mapperScan可以加在主启动类上,当然也可以加载一个配置类上,如下:
@SpringBootApplication
@ComponentScan({"com.atguigu"}) //指定扫描位置
@MapperScan("com.atguigu.educms.mapper")
public class CmsApplication {
public static void main(String[] args) {
SpringApplication.run(CmsApplication.class, args);
}
}
@SpringBootApplication
@ComponentScan(basePackages = {"com.atguigu"})
@EnableDiscoveryClient
@EnableFeignClients
public class EduApplication {
public static void main(String[] args) {
SpringApplication.run(EduApplication.class, args);
}
}
@Configuration
@MapperScan("com.atguigu.eduservice.mapper")
public class EduConfig {
/**
* 逻辑删除插件
*/
@Bean
public ISqlInjector sqlInjector() {
return new LogicSqlInjector();
}
/**
* 分页插件
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
}
2.条件构造器可以拼接sql语句
QueryWrapper<CrmBanner> wrapper = new QueryWrapper<>();
wrapper.orderByDesc("id").last("limit 2");
3.Redis缓存——注解式
3、在接口中添加redis缓存
由于首页数据变化不是很频繁,而且首页访问量相对较大,所以我们有必要把首页接口数据缓存到redis缓存中,减少数据库压力和提高访问速度。
改造service-cms模块首页banner接口,首页课程与讲师接口类似
3.1 Spring Boot缓存注解
(1)缓存@Cacheable
根据方法对其返回结果进行缓存,下次请求时,如果缓存存在,则直接读取缓存数据返回;如果缓存不存在,则执行方法,并把返回的结果存入缓存中。一般用在查询方法上。
查看源码,属性值如下:
属性/方法名 | 解释 |
value | 缓存名,必填,它指定了你的缓存存放在哪块命名空间 |
cacheNames | 与 value 差不多,二选一即可 |
key | 可选属性,可以使用 SpEL 标签自定义缓存的key |
(2)缓存@CachePut
使用该注解标志的方法,每次都会执行,并将结果存入指定的缓存中。其他方法可以直接从响应的缓存中读取缓存数据,而不需要再去查询数据库。一般用在新增方法上。
查看源码,属性值如下:
属性/方法名 | 解释 |
value | 缓存名,必填,它指定了你的缓存存放在哪块命名空间 |
cacheNames | 与 value 差不多,二选一即可 |
key | 可选属性,可以使用 SpEL 标签自定义缓存的key |
(3)缓存@CacheEvict
使用该注解标志的方法,会清空指定的缓存。一般用在更新或者删除方法上
查看源码,属性值如下:
属性/方法名 | 解释 |
value | 缓存名,必填,它指定了你的缓存存放在哪块命名空间 |
cacheNames | 与 value 差不多,二选一即可 |
key | 可选属性,可以使用 SpEL 标签自定义缓存的key |
allEntries | 是否清空所有缓存,默认为 false。如果指定为 true,则方法调用后将立即清空所有的缓存 |
beforeInvocation | 是否在方法执行前就清空,默认为 false。如果指定为 true,则在方法执行前就会清空缓存 |
Day12
1、redisTemplate可以加泛型
@Autowired
private RedisTemplate<String,String> redisTemplate;
@GetMapping("/send/{phone}")
public R sendMsn(@PathVariable String phone){
//先查缓存有没有,有直接走缓存
String o = redisTemplate.opsForValue().get(phone);
2.同样也可以设置有效时间
if (isSend){
//也可以使用redistemplate设置有效时间。
//return之后没有句子,不然会报unreachable statement
redisTemplate.opsForValue().set("phone", phone,5,TimeUnit.MINUTES);
return R.ok();