使用mybatis-plus进行多条件的分页查询
在后台管理中 , 常常需要设置多个条件来筛选数据 , 也就是多条件查询
多条件查询
Spring Boot+Mybatis多条件模糊查询,动态sql_fanminghao的博客-CSDN博客
使用动态SQL
在此 SQL 语句中, where 1=1 是多条件拼接时的小技巧, 后面的条件查询就可以都用 and 了。
使用 if 标签来处理动态 SQL
注意if标签里面的 test , 对应的应该是实体类的属性名
实体类
User.java
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108package com.miao.domain;import com.baomidou.mybatisplus.annotation.*;import io.swagger.annotations.ApiModel;import io.swagger.annotations.ApiModelProperty;import lombok.Data;import java.io.Serializable;import java.util.Date;import java.util.Objects;/** * * @TableName t_user */@TableName(value ="t_user")@Data@ApiModel("用户表")public class User implements Serializable { /** * 用户id */ @TableId(type = IdType.AUTO) @ApiModelProperty(value = "用户id") private Integer userId; /** * 用户昵称 */ @ApiModelProperty(value = "用户昵称") ...
返回错误码还是抛出异常?
首先,要明确一点的是,错误码和异常,这两者在程序的表达能力上是等价的。
它们都可以向调用者传达“与常规情况不一样的状态”。
考虑使用哪一种,更多地是从API的设计、系统的性能指标、新旧代码的一致性这3个角度来考虑的(本文主要从API设计的角度着手)。
我们返回异常, 比如return ResultUtil.fail( errorCode) , 如果直接把异常返回到用户使用层面 , 会有下面两点问题
总不能指望用户看懂java 的Exception
直接返回异常信息, 可能会造成安全问题
多使用异常机制的优点
不需要校验各种状态
而且异常信息方便排查错误
状态码字段
描述信息
异常调用栈
可以多自定义业务异常 , 然后使用异常机制,而不是使用状态码,然后各种校验。
举个例子, 注意下面的代码
12345678910if(StringUtils.isAnyBlank(userAccount, userPassword,checkPassword)){ return Result.fail("账户或密码不能为空!");}if(!userPassword.equals(checkPassword)){ return Result.fail("两次输入的密码不一致!");}if(RegexUtils.isStuCodeInvalid(stuCode)){ return Result.fail("请检查输入的学号是否正确!");}
对于上面的每一种出现错误, 我们都需要手动去返回fail, 这种方式与
throw new BusinessException(ErrorCode.PARAMS_ERROR,"账户或密码不能为空!");
看起来似乎一致, 返回的信息也大差不差
但是前提是当前我们实现的功能尚且简单, 逻辑比较简单, 并且出现异常的情况也比较少
那么如果我们以后业务复杂, 代码繁多, 如果还像上面这样一个一个的去手动返回异常,
效率将会十分低下, 而且代码也会看起来是否的臃肿
在这里的解决方法是定义异常类, 然后设置全局异常处理器 , 统一捕获异常,
然后以Result的形式返回
比如上面的代码就改为
12345678910if(StringUtils.isAnyBlank(userAccount, userP ...
使用swagger生成接口文档
简介
Swagger 是最流行的 API 开发工具,它遵循 OpenAPI Specification(OpenAPI 规范,也简称 OAS)。 Swagger 可以贯穿于整个 API 生态,如 API 的设计、编写 API 文档、测试和部署。 Swagger 是一种通用的,和编程语言无关的 API 描述规范。
官网:https://swagger.io/
导入swagger依赖
123456789101112 <!--swagger依赖--><dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.9.2</version></dependency><!--swagger ui--><dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>2.9.2</version></dependency>
编写swagger的配置类
1234567891011121314151617181920212223242526272829@Configuration@EnableSwagger2public class Swagger2Config { /** * 创建API应用 * apiInfo() 增加API相关信息 * 通过select()函数返回一个ApiSelectorBuilder实例,用来控制哪些接口暴露给Swagger来展现, * 指定扫描的包路径来定义指定要建立API的目录。 * @return */ @Bean public Docket coreApiConfig(){ return new Docket(DocumentationType.SWAGG ...
SpringBoot整合富文本编辑器
SpringBoot整合富文本编辑器
最近需要实现发帖子的功能, 考虑到帖子中会包含图片, 原本是想单独把图片设置出来单独上传, 后来想想觉得功能实现不够完整, 在网上看到有推荐使用富文本编辑器嵌入图片的, 于是打算用这个来实现发帖子的功能。
原本搜到了这一篇博客【JavaWeb】之富文本编辑器_´Code_Wang的博客-CSDN博客
原本打算用第一个TinyMCE ,看了一会文档发现官网文档给的上传demo 后端是php ,于是又搜到了集成Editor.md
https://gitee.com/pandao/editor.md
下面总结一下Editor.md 用法
使用springboot+ thymeleaf
Editor.md demo
下载editor.md
Editor下载https://gitee.com/pandao/editor.md
下载后解压导入springboot项目资源路径即可。
文件目录结构如下
可以没必要的示例文件和不需要的功能组件删除
设计数据库
12345678910111213create table `t_topic` ( `topic_id` bigint (20), `user_id` bigint (20), `tag_id` bigint (20), `topic_title` varchar (3072), `topic_content` text , `comment_count` bigint (20), `like_count` bigint (20), `is_selected` tinyint (4), `create_time` timestamp , `is_delete` int (11), `update_time` timestamp );
导入依赖
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081 ...
[02]实战篇(7)
8、达人探店
8.1、达人探店-发布探店笔记
发布探店笔记
探店笔记类似点评网站的评价,往往是图文结合。对应的表有两个:
tb_blog:探店笔记表,包含笔记中的标题、文字、图片等
tb_blog_co mments:其他用户对探店笔记的评价
具体发布流程
上传接口
1234567891011121314151617181920212223@Slf4j@RestController@RequestMapping("upload")public class UploadController { @PostMapping("blog") public Result uploadImage(@RequestParam("file") MultipartFile image) { try { // 获取原始文件名称 String originalFilename = image.getOriginalFilename(); // 生成新文件名 String fileName = createNewFileName(originalFilename); // 保存文件 image.transferTo(new File(SystemConstants.IMAGE_UPLOAD_DIR, fileName)); // 返回结果 log.debug("文件上传成功,{}", fileName); return Result.ok(fileName); } catch (IOException e) { throw new RuntimeException("文件上传失败", e); } }}
注意:同学们在操作时,需要修改SystemConstants.IMAGE_UPLOAD_DIR 自己图片所在的地址,在实际开发中图片一般会放在nginx上或者是云存储上。
BlogController
123456789101112131415161718@RestController@RequestMappin ...
java上传图片到腾讯云cos
引入相关依赖
123456789101112<!--腾讯云cos的依赖jar包--><dependency> <groupId>com.qcloud</groupId> <artifactId>cos_api</artifactId> <version>5.6.89</version></dependency><dependency> <groupId>com.tencent.cloud</groupId> <artifactId>cos-sts-java</artifactId> <version>3.0.5</version></dependency>
代码测试
12345678910111213141516171819202122232425@Testpublic void cosTest() { // 1 初始化用户身份信息(secretId, secretKey)。 // SECRETID和SECRETKEY请登录访问管理控制台 https://console.cloud.tencent.com/cam/capi 进行查看和管理 String secretId = "*************************"; String secretKey = "************************"; COSCredentials cred = new BasicCOSCredentials(secretId, secretKey); // 2 设置 bucket 的地域, COS 地域的简称请参照 https://cloud.tencent.com/document/product/436/6224 // clientConfig 中包含了设置 region, https(默认 http), 超时, 代理等 set 方法, 使用可参见源码或者常见问题 Java SDK 部分。 Region region = new Region("COS_REGION"); ...
常用正则
参考耗时一周,我打造了一个正则表达式学习神器!_哔哩哔哩_bilibili
史上最全常用正则表达式大全 - fozero - 博客园 (cnblogs.com)
在开发过程中, 经常需要使用校验, 每次搜索正则表达式非常浪费时间并且不靠谱, 从b站up主CodeSheep 处找到了常用正则总结, 在此保存方便以后查找。
在线测试正则表达式 : 正则表达式在线测试 | 菜鸟工具 (runoob.com)
数字校验
描述
正则表达式
备注
数字
^[0-9]*$
n位数字
^\d{n}$
至少n位数字
^\d{n,}$
m~n位数字
^\d{m,n}$
整数
^(-?[1-9]\d*)$
非0开头,包括正整数和负整数
正整数
^[1-9]\d*$
负整数
^-[1-9]\d*$
非负整数
`^(([1-9]\d*)
0)$`
非正整数
`^((-[1-9]\d*)
0)$`
浮点数
`^-?(?:[1-9]\d*.\d*
0.\d*[1-9]\d*
正浮点数
`^(?:[1-9]\d*.\d*
0.\d*[1-9]\d*)$`
负浮点数
`^-(?:[1-9]\d*.\d*
0.\d*[1-9]\d*)$`
非正浮点数
`^(?😦?:[1-9]\d*.\d+
0.\d*[1-9]\d*)
非负浮点数
`^(?:[1-9]\d*.\d+
0.\d+
仅一位小数
`^-?(?:0
[1-9][0-9]*).[0-9]{1}$`
最少一位小数
`^-?(?:0
[1-9][0-9]*).[0-9]{1,}$`
最多两位小数
`^-?(?:0
[1-9][0-9]*).[0-9]{1,2}$`
连续重复的数字
^(\d)\1+$
例如:111,222
字符校验
描述
正则表达式
备注
中文
^[\u4E00-\u9FA5]+$
全角字符
^[\uFF00-\uFFFF]+$
半角字符
^[\u0000-\u00FF]+$
英文字符串(大写)
^[A-Z]+$
英文字符串(小写)
^[a-z]+$
英文字符串(不区分大小写)
^[A-Za-z]+$
中文和数字
`^(?:[\u4E00-\u9FA5]{0,}
\d) ...
实战篇(5):分布式锁优化--redission[Redis]
之前的分布式锁已经足以面对绝大多数情况了, 下面的只是做拓展
5、分布式锁-redission
5.1 分布式锁-redission功能介绍
基于setnx实现的分布式锁存在下面的问题:
重入问题:重入问题是指 获得锁的线程可以再次进入到相同的锁的代码块中,可重入锁的意义在于防止死锁,比如HashTable这样的代码中,他的方法都是使用synchronized修饰的,假如他在一个方法内,调用另一个方法,那么此时如果是不可重入的,不就死锁了吗?所以可重入锁他的主要意义是防止死锁,我们的synchronized和Lock锁都是可重入的。
不可重试:是指目前的分布式只能尝试一次,我们认为合理的情况是:当线程在获得锁失败后,他应该能再次尝试获得锁。
**超时释放:**我们在加锁时增加了过期时间,这样的我们可以防止死锁,但是如果卡顿的时间超长,虽然我们采用了lua表达式防止删锁的时候,误删别人的锁,但是毕竟没有锁住,有安全隐患
主从一致性: 如果Redis提供了主从集群,当我们向集群写数据时,主机需要异步的将数据同步给从机,而万一在同步过去之前,主机宕机了,就会出现死锁问题。
那么什么是Redission呢
Redisson是一个在Redis的基础上实现的Java驻内存数据网格(In-Memory Data Grid)。它不仅提供了一系列的分布式的Java常用对象,还提供了许多分布式服务,其中就包含了各种分布式锁的实现。
Redission提供了分布式锁的多种多样的功能
5.2 分布式锁-Redission快速入门
引入依赖:
12345<dependency> <groupId>org.redisson</groupId> <artifactId>redisson</artifactId> <version>3.13.6</version></dependency>
配置Redisson客户端:
12345678910111213@Configurationpublic class RedissonConfig { @Bean public RedissonClient redissonClient(){ // 配置 Confi ...
实战篇(4):分布式锁[Redis]
4 分布式锁
4.1 基本原理和实现方式对比
分布式锁:满足分布式系统或集群模式下多进程可见并且互斥的锁。
分布式锁的核心思想就是让大家都使用同一把锁,只要大家使用的是同一把锁,那么我们就能锁住线程,不让线程进行,让程序串行执行,这就是分布式锁的核心思路
那么分布式锁他应该满足一些什么样的条件呢?
==可见性==:多个线程都能看到相同的结果,注意:这个地方说的可见性并不是并发编程中指的内存可见性,只是说多个进程之间都能感知到变化的意思
==互斥==:互斥是分布式锁的最基本的条件,使得程序串行执行
==高可用==:程序不易崩溃,时时刻刻都保证较高的可用性
==高性能==:由于加锁本身就让性能降低,所有对于分布式锁本身需要他就较高的加锁性能和释放锁性能
==安全性==:安全也是程序中必不可少的一环
常见的三种分布式锁
==Mysql==:mysql本身就带有锁机制,但是由于mysql性能本身一般,所以采用分布式锁的情况下,其实使用mysql作为分布式锁比较少见
==Redis==:redis作为分布式锁是非常常见的一种使用方式,现在企业级开发中基本都使用redis或者zookeeper作为分布式锁,
利用setnx这个方法,如果插入key成功,则表示获得到了锁,如果有人插入成功,其他人插入失败则表示无法获得到锁,利用这套逻辑来实现分布式锁
==Zookeeper==:zookeeper也是企业级开发中较好的一个实现分布式锁的方案,以后再学
4.2 Redis分布式锁的实现核心思路
实现分布式锁时需要实现的两个基本方法:
获取锁:
互斥:确保只能有一个线程获取锁
SET lock thread1 EX 10 NX
设置一个string类型的数据, ==过期时间为10s,== NX表示互斥 , 通过这个命令来保持过期以及互斥的原子性
设置过期时间是为了 防止 某个进程拿到了锁之后出现特殊情况比如宕机, 导致锁无法释放, 出现死锁
只需要设置过期时间, 到期自动释放锁即可
使用非阻塞式锁:尝试一次,成功返回true,失败返回false
阻塞式锁对CPU的浪费较多
释放锁:
手动释放
超时释放:获取锁时添加一个超时时间 => 防止redis出现故障导致死锁
核心思路⭐:
我们利用redis 的setNx 方法
当 ...
idea配置集群
在学习redis分布式锁的时候, 需要用到集群
下面是相关配置
单机
配置多个springboot
打开idea , 点击
点击Edit Configurations...
然后点击 右边空白中的 Add new run configuration...
然后填写相关的配置信息
注意需要修改端口号, 否则会造成
这里设置Name 为 MoreSpringboot
Main class 选择springboot的启动类, 这里就是com.hmdp.HmDianPingApplication
注意要把类名写全
然脏在 VM options 位置填入 -Dserver.port=8082
这个就是运行参数, 设置端口号避免端口冲突,
如果有其他的需求可以另外设置
然后点击apply
可以看到此时已经多了一个MoreSpringboot
右键点击Run
可以看到springboot启动成功
修改nginx配置
由于这个工程前端使用Nginx代理,
因此需要去Nginx的配置文件中更改相关配置
打开nginx.conf
修改相关配置设置负载均衡
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253worker_processes 1;events { worker_connections 1024;}http { include mime.types; default_type application/json; sendfile on; keepalive_timeout 65; server { listen 8080; server_name localhost; # 指定前端项目所在的位置 location / { root html/hmdp; index index.html index.htm; } error_page 500 502 503 504 ...




![[02]实战篇(7)](https://dhx-blog.oss-cn-beijing.aliyuncs.com/dhx/0bd44a2d1fusXjl.jpg)

![实战篇(5):分布式锁优化--redission[Redis]](https://dhx-blog.oss-cn-beijing.aliyuncs.com/dhx/29dcb7e6c56uLPs.jpg)
![实战篇(4):分布式锁[Redis]](https://dhx-blog.oss-cn-beijing.aliyuncs.com/dhx/42e0c9ed85sZSK3.jpg)





