尚硅谷-全栈在线教育项目-谷粒学院【Spring Boot + Spring Cloud Alibaba + Vue.js】
文章目录0、视频地址1、 项目下载2、他人写的项目总结和笔记(有一定的改进,简历改进在本地项目文件夹)2.1、项目笔记2.2、项目总结12.3、项目总结22.4项目总结33、问题与解决问题day04 03问题day 05问题 day 05问题day11~day12问题day 19问题p41问题p51问题二问题三问题五问题六问题 p352问题p325问题P355问题P355问题十二问题十六问题十八0
文章目录
0、视频地址
1、 项目下载
谷粒项目
链接:https://pan.baidu.com/s/1iA_wK_4alIugw8yFUKDjHA
提取码:db3m
2、他人写的项目总结和笔记(有一定的改进,简历改进在本地项目文件夹)
2.1、项目笔记
2.2、项目总结1
2.3、项目总结2
整完了,顺带整合了 SpringSecurity。使用 Redis 缓存 jwt 实现了 jwt 的自动续约
可以参考: https://github.com/antigenMHC/ErCiYuan
2.4项目总结3
2.5、项目总结4
https://github.com/liusCoding/guli-online-college-project
3、问题与解决
问题day04 03
如果你在day04 03中vue-admin-template首次登录,并没有像老师那样进入的是login页面,而是直接跳过登录页面,不要慌,把浏览器cookie清除试试。(推测你第一次登录vue- admin-master这个时候记住密码了)
问题day 05
你好,我现在看到day5前端设计的表单设计,在实现点击编辑按钮反显到添加讲师页面时,报network error 但是我在teachercontroller中已经加了跨域注解,前段teacher. js中getbyID的URL也正确,请问这种问题怎么解决呢?
无双M请问你解决了吗?我也遇到了,我是认为是id字段过长,才不行,我在数据库手动把teacher表id改小就没事了,但是这个很low,请教啊!
解决了
:把控制器接收参数的类型改为long,或string就OK了[大笑][大笑]
你好,请问怎么解决的?
请问本来getById()传的不就是String id吗,数据库也是char类型的
无双M回复 @不要熬夜了哦 :就是控制器参数类型用string或者long
问题 day 05
位置描述:day05,讲师管理前端。
问题描述:分页查询,删除讲师,添加讲师,编辑讲师功能都没有问题。
但是,新添加的讲师,在讲师列表中修改和删除时,
前端却提示:未知错误
后端控制台打印是:Caused by: java.lang.NumberFormatException: For input string: 1335353508001587201
个人尝试解决:手动在数据库中将teacher表的id字段改小,如:“1335”,却能正常删除和编辑!!
求赐教!!!
解决了,我在teachercontroller中,使用string代替integer接受参数就OK了
数字太长,超过了js中number类型的安全范围(2^53 = 9007199254740992),所以替换成String就好了
问题day11~day12
踩个坑,在day11~day12那,视频点播,如果JDK是1.8以上的,那么点播的相关POM依赖, 要严格按照官方文档给的版本配置,否则会显示上传失败,然后控制台那一直显示视频上传中。。
自己要注册域名吗?然后自己备案这些吗?
要,去万网买个你喜欢的域名,icu的最便宜5块一年;然后去阿里云服务器注册,备案。然而实际上这些不做,貌似不是很影响接下来的流程。所以可以先搁置
那请问您是买个哪一个,有备案吗?
有尝试备案过,然后因为自拍照片不合格被驳回了,哈哈。其实整个流程下来很容易的,你下个阿里云App,里面有完整的备案流程,我记得流程是这样:1.先买个域名;2.然后去阿里云控制台买个云服务器,我买了个一年90元的centOS7;这两个是必须有才能备案的,有了这两个后,先实名认证域名,很简单的,一般隔天就能认证好,认证好三天后,才可以备案,备案用阿里云App去备案就行了,里面有流程指导
day11的时候,不做域名加速可以吗?嫌麻烦,如果不是很影响后面的学习
实际上并不影响后面的课程,照着做下去事没问题的
问题day 19
在第19天订单那里,跳转不到订单页面,是因为token没传给后端
在api方法那加上代码
// 通过请求头发送token
headers: { token: cookie.get(guli_jwt_token) }
这真的是个坑 headers: { token: cookie.get(hzau_jwt_token) }
问题p41
对P41有很大的疑问,为什么要把BasicEntity放在其他module下面,而不是service_edu?我试过放在service_base下面但是创建的实体类不能引用BasicEntity
其他模块例如service_cms,它的实体类也要继承BaseEntity。不能引用是因为启动类没加@ComponentScan注解扫描吧
附近的决定因为后面还有其他的业务,里边也有实体类,而basicEntity是所有实体类共有属性的类,如果房子啊service_edu,后面 的业务就引用不了,service_base下面可以引用,可能你的service业务没有导入service_base依赖
是的了,service那边没引用
问题p51
如果你在在p51教师的模糊查询,name你填的是汉字,可发现怎么也查不出来。在老师给的application.yaml中数据库连接配置:jdbc:mysql://localhost3306db191125_guli_eduserverTimezone=GMT%2B8,配置characterEncoding=utf8
问题p94
p94,05不用模拟,base api换成https://easy-mock.com/mock/5950a2419adc231f356a6636/vue-admin就可以了
问题 p352
P325,当使用Swagger测试上传视频时遇到控制台报错“com/aliyun/oss/internal/OSSUdfOperation”的信息,阿里云点播控制台中一直显示“上传中”的情况。请先确定JDK版本是否为JDK1.8,然后可以将版本控制器中“aliyun.oss.version”的版本改为3.1.0
问题p325
p325中视频上传,aliyun-java-vod-upload组件版本使用1.4.11,测试不能通过;改为1.4.14即可
问题P355
P355,如果在执行npm install后,在执行npm run dev 的时候报错,请先找到指定的报错文件然后执行一次ctrl+s的操作
把那个_id.vue保存一下(ctrl+s)就可以了
问题P355
P355运行错误的原因:Tab键打出的空格被ESlint检测到了,把_id.vue文件的153行li class=lh-menu-second ml30语句前面的空格删除就行,在回车一下,记得C+S
问题二
流媒体技术学习笔记之(四)解决问题video.js 播放m3u8格式的文件,根据官方的文档添加videojs-contrib-hls也不行的原因解决了
问题三
再全局安装webpack 和webpack-cli在执行webpack -v,进入死循环一样一直叫你安装webpack-cli。百度也解决不了,不要慌。那你就不要全局安装,解压老师给的vue-admin-master或者那个简单的,现在vs控制台,npm install webpack npm install webpack-cli 再执行老师的命令npm install npm run dev
问题五
遇到common_util打包失败:
首先在preference-build tool-Maven下,勾选两个override,然后打开local repository,找到common_util,把它给删了;然后其他地方的配置基本和原来的一样,不过我删掉了最大的那个父Pom里的springboot-maven-plugin;然后点击IDEA右边工具栏的Maven,点击install,就好了。
对了,还要在project structurn里面选中爆红的common_util,修改它的class和source,分别修改为,install之后,在common_util包里面生成target里面对应的文件夹和jar包
问题六
3.1以下的 mp有BUG ,删除时,如果用service调用remove方法,无论删除与否都会返回true,用mapper调用delete方法则可以通过int返回更新数据库条目判断是否删除成功
两个方法功能相同,返回值类型不同
如果一定要调用service中的remove方法,请把MP版本更新为3.2.0
问题十二
微信登录老师的现在还能用吗
将guli.shop换为localhost:8160就可以了,亲测可用
微信扫码失效的,使用新的,首先将模块启动端口改成8160(一定得是这个,其他的没用),其次将redirect_url 改为:http://localhost:8160/api/ucenter/wx/callback
问题十六
为什么老是出现org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.qy.mybatis_plus.mapper.UserMapper.selectList 问题呐 有大佬知道的么?
GuJeonPamapper xml文件打包时忽略了, 在依赖里加东西,还得再配置文件里加上mapper文件的路径地址
问题十八
打包始终不成功 弄了好久了 除了打common util能成功 但是service base打包找不到common util的依赖包
https://blog.csdn.net/caoweifeng12/article/details/107335517 已解决可以参考一下
可能需要 clean + install一下,jar包就出来了,我的是这样,然后在project structure的module里面找到缺失的那个包,修改他的classpath和source
4、我的笔记
mybatisplus
让天下没有难学的技术
官网:http://mp.baomidou.com
参考教程:http://mp.baomidou.com/guide/
一、简介
MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
润物无声
只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑。
效率至上
只需简单配置,即可快速进行 CRUD 操作,从而节省大量时间。
丰富功能
热加载、代码生成、分页、性能分析等功能一应俱全。
二、创建并初始化数据库
1、创建数据库
mybatis_plus
2、创建 User 表
其对应的数据库 Schema 脚本如下:
CREATE TABLE user
(
id BIGINT(20) NOT NULL COMMENT '主键ID',
name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
age INT(11) NULL DEFAULT NULL COMMENT '年龄',
email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY (id)
);
其对应的数据库 Data 脚本如下:
INSERT INTO user (id, name, age, email) VALUES
(1, 'Jone', 18, 'test1@baomidou.com'),
(2, 'Jack', 20, 'test2@baomidou.com'),
(3, 'Tom', 28, 'test3@baomidou.com'),
(4, 'Sandy', 21, 'test4@baomidou.com'),
(5, 'Billie', 24, 'test5@baomidou.com');
三、确认idea配置
1、打开配置
2、Java编译器
3、项目和文件的编码
4、Maven配置
四、创建项目
1、初始化工程
使用 Spring Initializr 快速初始化一个 Spring Boot 工程
Group:com.atguigu
Artifact:mybatis_plus
版本:2.2.1.RELEASE
2、引入依赖
注意:引入 MyBatis-Plus 之后请不要再次引入 MyBatis,以避免因版本差异导致的问题。
<!--mybatis-plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.1</version>
</dependency>
<!--mysql运行时依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!--lombok用来简化实体类-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
3、idea中安装lombok插件
(1)idea2019版本
(2)idea2018版本
五、编写代码
1、配置
在 application.properties 配置文件中添加 MySQL 数据库的相关配置:
#mysql数据库连接
spring boot 2.1及以上(内置jdbc8驱动)
注意:driver和url的变化
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/db1911256_mybatis_plus?serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=990325
注意:
1、这里的 url 使用了 ?serverTimezone=GMT%2B8 后缀,因为8.0版本的jdbc驱动需要添加这个后缀,否则运行测试用例报告如下错误:
java.sql.SQLException: The server time zone value ‘Öйú±ê׼ʱ¼ä’ is unrecognized or represents more
2、这里的 driver-class-name 使用了 com.mysql.cj.jdbc.Driver ,在 jdbc 8 中 建议使用这个驱动,否则运行测试用例的时候会有 WARN 信息
2、主类
在 Spring Boot 启动类中添加 @MapperScan 注解,扫描 Mapper 文件夹
package com.atguigu.mybatis_plus;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.atguigu.mybatis_plus.mapper")
public class MybatisPlusApplication {
public static void main(String[] args) {
SpringApplication.run(MybatisPlusApplication.class, args);
}
}
3、实体
创建包 entity 编写实体类 User.java(此处使用了 Lombok 简化代码)
package com.atguigu.mybatis_plus.entity;
import lombok.Data;
/**
* @Author ljm
* @Date 2021/9/25 21:32
* @Version 1.0
*/
@Data
public class User {
private Long id;
private String name;
private Integer age;
private String email;
}
查看编译结果
4、mapper
创建包 mapper 编写Mapper 接口: UserMapper.java
package com.atguigu.mybatis_plus.mapper;
import com.atguigu.mybatis_plus.entity.User;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
/**
* @Author ljm
* @Date 2021/9/25 21:34
* @Version 1.0
*/
// https://www.jianshu.com/p/3942f6b4fa75 用法
@Repository
public interface UserMapper extends BaseMapper<User> {
}
5、测试
添加测试类,进行功能测试:
package com.atguigu.mybatis_plus;
import com.atguigu.mybatis_plus.entity.User;
import com.atguigu.mybatis_plus.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
@SpringBootTest
class MybatisPlusApplicationTests {
@Autowired
private UserMapper userMapper;
@Test
void testSelectList() {
List<User> users = userMapper.selectList(null);
users.forEach(System.out::println);
}
}
注意:
IDEA在 userMapper 处报错,因为找不到注入的对象,因为类是动态创建的,但是程序可以正确的执行。
为了避免报错,可以在 dao 层 的接口上添加 @Repository 注
通过以上几个简单的步骤,我们就实现了 User 表的 CRUD 功能,甚至连 XML 文件都不用编写!
查看控制台输出:
6、查看sql输出日志
#mybatis日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
三、MP的主键策略
1、ASSIGN_ID
MyBatis-Plus默认的主键策略是:ASSIGN_ID (使用了雪花算法)
@TableId(type = IdType.ASSIGN_ID)
private String id;
2、AUTO 自增策略
需要在创建数据表的时候设置主键自增
实体字段中配置 @TableId(type = IdType.AUTO)
@TableId(type = IdType.AUTO)
private Long id;
要想影响所有实体的配置,可以设置全局主键配置
#全局设置主键生成策略
mybatis-plus.global-config.db-config.id-type=auto
一、更新操作
注意:update时生成的sql自动是动态sql:UPDATE user SET age=? WHERE id=?
@Test
public void testUpdateById(){
User user = new User();
user.setId(1L);
user.setAge(28);
int result = userMapper.updateById(user);
System.out.println("影响的行数:" + result);
}
二、自动填充
需求描述:
项目中经常会遇到一些数据,每次都使用相同的方式填充,例如记录的创建时间,更新时间等。
我们可以使用MyBatis Plus的自动填充功能,完成这些字段的赋值工作
1、数据库修改
在User表中添加datetime类型的新的字段 create_time、update_time
2、实体类修改
实体上增加字段并添加自动填充注解
@Data
public class User {
@TableField(fill = FieldFill.INSERT)
private Date createTime;
//@TableField(fill = FieldFill.UPDATE)
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
}
3、实现元对象处理器接口
注意:不要忘记添加 @Component 注解
package com.atguigu.mybatis_plus.handler;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.util.Date;
/**
* @Author ljm
* @Date 2021/9/26 19:49
* @Version 1.0
*/
// spring初始化对象,Component表示注解类的对象就会自动被spring初始化出来
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
System.out.println("insertfill=====");
//对象赋值
this.setFieldValByName("createTime",new Date(),metaObject);
this.setFieldValByName("updateTime",new Date(),metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
System.out.println("updatefill=====");
this.setFieldValByName("updateTime",new Date(),metaObject);
}
}
4、测试
三、乐观锁
1、场景
一件商品,成本价是80元,售价是100元。老板先是通知小李,说你去把商品价格增加50元。小李正在玩游戏,耽搁了一个小时。正好一个小时后,老板觉得商品价格增加到150元,价格太高,可能会影响销量。又通知小王,你把商品价格降低30元。
此时,小李和小王同时操作商品后台系统。小李操作的时候,系统先取出商品价格100元;小王也在操作,取出的商品价格也是100元。小李将价格加了50元,并将100+50=150元存入了数据库;小王将商品减了30元,并将100-30=70元存入了数据库。是的,如果没有锁,小李的操作就完全被小王的覆盖了。
现在商品价格是70元,比成本价低10元。几分钟后,这个商品很快出售了1千多件商品,老板亏1多万。
2、乐观锁与悲观锁
上面的故事,如果是乐观锁,小王保存价格前,会检查下价格是否被人修改过了。如果被修改过了,则重新取出的被修改后的价格,150元,这样他会将120元存入数据库。
如果是悲观锁,小李取出数据后,小王只能等小李操作完之后,才能对价格进行操作,也会保证最终的价格是120元。
接下来将我们演示这一过程:
3、模拟修改冲突
(1)数据库中增加商品表(2)添加数据
CREATE TABLE product
(
id BIGINT(20) NOT NULL COMMENT '主键ID',
name VARCHAR(30) NULL DEFAULT NULL COMMENT '商品名称',
price INT(11) DEFAULT 0 COMMENT '价格',
version INT(11) DEFAULT 0 COMMENT '乐观锁版本号',
PRIMARY KEY (id)
);
INSERT INTO product (id, NAME, price) VALUES (1, '外星人笔记本', 100);
(3)实体类
package com.atguigu.mybatis_plus.entity;
import com.baomidou.mybatisplus.annotation.Version;
import lombok.Data;
/**
* @Author ljm
* @Date 2021/9/26 20:21
* @Version 1.0
*/
@Data
public class Product {
private Long id;
private String name;
private Integer price;
@Version
private Integer version;
}
(4)Mapper
package com.atguigu.mybatis_plus.mapper;
import com.atguigu.mybatis_plus.entity.Product;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.springframework.stereotype.Repository;
/**
* @Author ljm
* @Date 2021/9/26 20:22
* @Version 1.0
*/
@Repository
public interface ProductMapper extends BaseMapper<Product> {
}
(5)测试
@Autowired
private ProductMapper productMapper;
@Test
public void testConcurrentUpdate() {
//1、 小李获取数据
Product p1 = productMapper.selectById(1L);
System.out.println("小李取出的价格"+p1.getPrice());
// 2、 小王获取数据
Product p2 = productMapper.selectById(1L);
System.out.println("小王取出的价格"+p2.getPrice());
// 3、小李加了50元存入数据库
p1.setPrice(p1.getPrice()+50);
productMapper.updateById(p1);
// 4、小王减了30元存入数据库
p2.setPrice(p2.getPrice()-30);
int i = productMapper.updateById(p2);
if (i==0) {
System.out.println("小王更新失败");
//发起重试
p2 = productMapper.selectById(1L);
p2.setPrice(p2.getPrice() -30);
productMapper.updateById(p2);
}
//5、其他人看到的结果.最后的结果
Product p3 = productMapper.selectById(1L);
System.out.println("" +
"最后的结果"+p3.getPrice());
}
4、解决方案
数据库中添加version字段
取出记录时,获取当前version
SELECT id,`name`,price,`version` FROM product WHERE id=1
更新时,version + 1,如果where语句中的version版本不对,则更新失败
UPDATE product SET price=price+50, `version`=`version` + 1 WHERE id=1 AND `version`=1
5、乐观锁实现
(1)修改实体类
添加 @Version 注解
@Version
private Integer version;
(2)创建配置文件
创建包config,创建文件MybatisPlusConfig.java
此时可以删除主类中的 @MapperScan 扫描注解
(3)注册乐观锁插件 在 MybatisPlusConfig 中注册 Bean
package com.atguigu.mybatis_plus.config;
import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;
/**
* @Author ljm
* @Date 2021/9/26 20:57
* @Version 1.0
*/
//做事务处理
@EnableTransactionManagement
//配置类
@Configuration
public class MybatisPlusConfig {
//spring当中可以被初始化出来的对象
@Bean
//乐观锁插件
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
}
(4)测试
一、查询
1、通过多个id批量查询
完成了动态sql的foreach的功能
@Test
public void testSelectBatchIds(){
List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
users.forEach(System.out::println);
}
2、简单的条件查询
通过map封装查询条件
注意:map中的key对应数据库中的列名。如:数据库user_id,实体类是userId,这时map的key需要填写user_id
@Test
public void testSelectByMap() {
HashMap<String, Object> map = new HashMap<>();
map.put("name","helen");
map.put("age",18);
List<User> users = userMapper.selectByMap(map);
users.forEach(System.out::println);
}
二、分页
1、分页插件
MyBatis Plus自带分页插件,只要简单的配置即可实现分页功能
(1)添加分页插件
配置类中添加@Bean配置
/**
* 分页插件
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
(2)测试selectPage分页
测试:最终通过page对象获取相关数据
@Test
public void testSelectPage(){
Page<User> page = new Page<>(1, 5);
Page<User> pageParam = userMapper.selectPage(page, null);
List<User> records = pageParam.getRecords();
records.forEach(System.out::println);
System.out.println(pageParam.getPages());//总页数
System.out.println(pageParam.getTotal());//总记录数
System.out.println(pageParam.getCurrent());//当前页码号
System.out.println(pageParam.getSize());//每页记录数
System.out.println(pageParam.hasNext());//是否有下一页
System.out.println(pageParam.hasPrevious());//是否有上一页
}
2、返回指定的列
当指定了特定的查询列时,希望分页结果列表只返回被查询的列,而不是很多null值
测试selectMapsPage分页:结果集是Map
@Test
public void testSelectPage(){
QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
queryWrapper.select("id","name");
Page<Map<String,Object>> page = new Page<>(1, 5);
Page<Map<String, Object>> pageParam = userMapper.selectMapsPage(page, queryWrapper);
List<Map<String, Object>> records = pageParam.getRecords();
records.forEach(System.out::println);
System.out.println(pageParam.getPages());//总页数
System.out.println(pageParam.getTotal());//总记录数
System.out.println(pageParam.getCurrent());//当前页码号
System.out.println(pageParam.getSize());//每页记录数
System.out.println(pageParam.hasNext());//是否有下一页
System.out.println(pageParam.hasPrevious());//是否有上一页
}
一、删除
1、根据id删除记录
@Test
public void testDeleteById() {
int i = userMapper.deleteById(5L);
System.out.println("删除了"+i+"行");
}
2、批量删除
@Test
public void testDeleteBatchIds() {
int i = userMapper.deleteBatchIds(Arrays.asList(10,11,12));
System.out.println("删除了"+i+"行");
}
3、简单条件删除
@Test
public void testDeleteByMap(){
HashMap<String, Object> map = new HashMap<>();
map.put("name","helen");
map.put("age","18");
int i = userMapper.deleteByMap(map);
System.out.println("删除了"+i+"行");
}
二、逻辑删除
1、物理删除和逻辑删除
物理删除:真实删除,将对应数据从数据库中删除,之后查询不到此条被删除数据
逻辑删除:假删除,将对应数据中代表是否被删除字段状态修改为“被删除状态”,之后在数据库中仍旧能看到此条数据记录
逻辑删除的使用场景:
可以进行数据恢复
有关联数据,不便删除
2、逻辑删除实现流程
(1)数据库修改
添加 deleted字段
ALTER TABLE `user` ADD COLUMN `deleted` boolean DEFAULT false
(2)实体类修改
添加deleted 字段,并加上 @TableLogic 注解
@TableLogic
private Integer deleted;
3)配置(可选)
application.properties 加入以下配置,此为默认值,如果你的默认值和mp默认的一样,该配置可无
mybatis-plus.global-config.db-config.logic-delete-value=1
mybatis-plus.global-config.db-config.logic-not-delete-value=0
(4)测试
测试后发现,数据并没有被删除,deleted字段的值由0变成了1
测试后分析打印的sql语句,是一条update
注意:被删除前,数据的deleted 字段的值必须是 0,才能被选取出来执行逻辑删除的操作
@Test
public void testLogicDelete() {
int result = userMapper.deleteById(1L);
System.out.println(result);
}
(5)测试逻辑删除后的查询
MyBatis Plus中查询操作也会自动添加逻辑删除字段的判断
@Test
public void testLogicDeleteSelect() {
List<User> users = userMapper.selectList(null);
users.forEach(System.out::println);
}
一、wapper介绍
Wrapper : 条件构造抽象类,最顶端父类
AbstractWrapper : 用于查询条件封装,生成 sql 的 where 条件
QueryWrapper : 查询条件封装
UpdateWrapper : Update 条件封装
AbstractLambdaWrapper : 使用Lambda 语法
LambdaQueryWrapper :用于Lambda语法使用的查询Wrapper
LambdaUpdateWrapper : Lambda 更新封装Wrapper
@SpringBootTest
public class QueryWrapperTests {
@Autowired
private UserMapper userMapper;
}
二、测试用例
1、ge、gt、le、lt、isNull、isNotNull
@Test
public void testDelete() {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper
.isNull("name")
.ge("age", 12)
.isNotNull("email");
int result = userMapper.delete(queryWrapper);
System.out.println("delete return count = " + result);
}
2、eq、ne
注意:seletOne()返回的是一条实体记录,当出现多条时会报错
@Test
public void testSelectOne() {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("name", "Tom");
User user = userMapper.selectOne(queryWrapper);//只能返回一条记录,多余一条则抛出异常
System.out.println(user);
}
3、between、notBetween
包含大小边界
@Test
public void testSelectCount() {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.between("age", 20, 30);
Integer count = userMapper.selectCount(queryWrapper); //返回数据数量
System.out.println(count);
}
4、like、notLike、likeLeft、likeRight
selectMaps()返回Map集合列表,通常配合select()使用
@Test
public void testSelectMaps() {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper
.select("name", "age")
.like("name", "e")
.likeRight("email", "5");
List<Map<String, Object>> maps = userMapper.selectMaps(queryWrapper);//返回值是Map列表
maps.forEach(System.out::println);
}
5、in、notIn、inSql、notinSql、exists、notExists
n、notIn:
notIn("age",{1,2,3})--->age not in (1,2,3)
notIn("age", 1, 2, 3)--->age not in (1,2,3)
inSql、notinSql:可以实现子查询
例: inSql("age", "1,2,3,4,5,6")--->age in (1,2,3,4,5,6)
例: inSql("id", "select id from table where id < 3")--->id in (select id from table where id < 3)
@Test
public void testSelectObjs() {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
// queryWrapper.in("id", 1, 2, 3);
queryWrapper.inSql("id", "select id from user where id <= 3");
List<Object> objects = userMapper.selectObjs(queryWrapper);//返回值是Object列表
objects.forEach(System.out::println);
}
6、or、and
注意:这里使用的是 UpdateWrapper
不调用or则默认为使用 and 连
@Test
public void testUpdate1() {
//修改值
User user = new User();
user.setAge(99);
user.setName("Andy");
//修改条件
UpdateWrapper<User> userUpdateWrapper = new UpdateWrapper<>();
userUpdateWrapper
.like("name", "h")
.or()
.between("age", 20, 30);
int result = userMapper.update(user, userUpdateWrapper);
System.out.println(result);
}
7、lambda表达式
lambda表达式内的逻辑优先运算
@Test
public void testUpdate2() {
//修改值
User user = new User();
user.setAge(99);
user.setName("Andy");
//修改条件
UpdateWrapper<User> userUpdateWrapper = new UpdateWrapper<>();
userUpdateWrapper
.like("name", "n")
.or(i -> i.like("name", "a").eq("age", 20));
int result = userMapper.update(user, userUpdateWrapper);
System.out.println(result);
}
8、orderBy、orderByDesc、orderByAsc
@Test
public void testSelectListOrderBy() {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.orderByDesc("age", "id");
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}
9、set、setSql
最终的sql会合并 user.setAge(),以及 userUpdateWrapper.set() 和 setSql() 中 的字段
@Test
public void testUpdateSet() {
//修改值
User user = new User();
user.setAge(60);
//修改条件
UpdateWrapper<User> userUpdateWrapper = new UpdateWrapper<>();
userUpdateWrapper
.like("name", "h")
.set("name", "Peter")//除了可以查询还可以使用set设置修改的字段
.setSql(" email = '123@qq.com'");//可以有子查询
int result = userMapper.update(user, userUpdateWrapper);
}
三、查询方式
一、工程结构
guli_parent :根目录(父工程),管理四个子模块:
canal_client : canal 数据库表同步模块(统计同步数据)
common :公共模块父节点
common_util :工具类模块,所有模块都可以依赖于它
service_base : service 服务的 base 包,包含 service 服务的公共配置类,所有 service 模块依赖于它
spring_security :认证与授权模块,需要认证授权的 service 服务依赖于它
infrastructure :基础服务模块父节点
api_gateway : api 网关服务
service : api 接口服务父节点
service_edu :教学相关 api 接口服务
service_oss :阿里云 oss api 接口服务
service_acl :用户权限管理 api 接口服务(用户管理、角色管理和权限管理等)
service_cms : cms api 接口服务
service_sms :短信 api 接口服务
service_trade :订单和支付相关 api 接口服务
service_statistics :统计报表 api 接口服务
service_ucenter :会员 api 接口服务
service_vod :视频点播 api 接口服务
ctrl+n搜索文件中的类
ctrl+shift+n搜索配置的类
vscode快捷键
!然后回车出现html主题
ul>li*3变为
更多推荐
所有评论(0)