5.缓存redis
redis简介
redis特点
- 内存数据库
- 单线程,多IO,高速读11w/s,写8w1/s
- 支持持久化
- 5种数据类型
- key-vlue
- list
- set
- zset
- hash
- 分布式锁
- 事务
- 集群方案
- 开源免费
-
业务:
- 搜索历史
- 热搜搜索
- 分布式锁
Memcache
支持更丰富的数据类型
效率没有redis高
详细介绍网站
https://www.cnblogs.com/baichunyu/p/11631660.html
中文官网
Redis默认端口:
端口6379,进程9368
Redis安装
-
RDM
安装RedisDesktopManager,新建连接:(1)自定义名字redis_local;(2)地址127.0.0.1 6379
-
Redis
Redis-x64-3.2.100压缩包解压至DevInstall,运行redis-server.exe
Redis基本命令
-
set key1 helloword
设置键值对,键为key1,值为helloword
-
get key1
获取键值对,获取键为key1的值
-
select 0
切换到0库
-
keys *
显示所有键,*可以有格式,如:k*意思为以k开头的键
-
dbsize
数据库的大小
-
flushdb
删除单库
-
flushall
删除全库,删库跑路~
-
type
-
append
-
strlen key3
-
incr key1
key1 +1
-
decr key1
key1 -1
-
incrby key3 10
key3 +30
-
decrby key3 10
key3 -10
-
exists key1
key1是否存在
字符串操作,超时,分布式锁,批量
-
getrange key4 0 -1
截取字符串,全部。0 3:前4个字符
-
setrang key4 1 ppp
设置指定范围内的值,设置key4,从下标1开始abcdef→apppef
-
expire key1 10
为key1设置10后超时
-
setex key5 10 tom
设置值的时候同时设置超时时间
-
setnx key6 aaaa
分布式锁,无才能设值1,有就执行失败0
-
mset key7 aaa key8 bbb key9 ccc
批量存
-
mget key7 key8 key9
批量取
-
msetnx key10 eeee key11 ffff key 12 ggg
所有key都不存在才能一起设置值
list操作
-
lpush catlist1 audi3 audi4 audi6
设置list值,左设值,左取值时是先进后出,出来是6 4 3
-
lrange carlist1 0 -1
正常取值,但是默认左list取值,没有右取值,这里的l表list
-
rpush carlist2 bwm3 bwm4 bwm5
右list设值时,队列机制,先进先出
-
lpop carlist1
正常出栈,但是默认左出栈,没有右出栈,这里l表list
-
lindex carlist2 1
取lsit中第一个值
-
llen carlist2
list中有几个元素
-
lrem catlist3 1 audi3
从左往右删,只删一个元素,元素叫audi3
-
lrem catlist3 0 audi3
从左往右删,把叫audi3全鲨了
-
ltrim carlist4 1 3
从左往右把除了下标1~3全鲨了
-
rpoplpush carlist5 carlist6
右拿左塞,从5到6
set操作
sadd set1 a b c d a b c d
往set中设置值,set无序唯一,不覆盖,追加设置值
smembers set
查看set中的值
sismember set1 a
set1中是否存在a,返回1有,返回0没有
scard set1
set1长度
srem set1 d c
删除d、c元素
spop set1
随机鲨一个set1中的元素
sdiff set1 set
显示set1中有的,但是set中没有的元素。set中有的但是set1中没有的元素不显示
sinter set1 set
set1与set的交集,显示共同存在的元素
sunion set1 set
set1与set的并集,显示二者都存在的元素并且自动去重
hash操作
hset user id u00001
设置user对象,第一个id属性值为u00001,覆盖设置值
hget user id
获取user对象id属性值
hmset user role admin gender man
批量追加属性及属性值
hmget user id role gender
批量根据属性获取属性值
hgetall user
获取user对象全部的属性及属性值
hlen user
user对象中有几个属性
hdel user gender
把user中gender属性连键带值全鲨了
hkeys user
获取user中键集
hvals user
获取user中值集
hsetnx user role root
分布式锁,user中没有role属性才能设置,否则无法设置
hincrbt user age 5
给user中age属性加5
zset操作
zadd zset1 60 tom 70 jack 50 mark 80 marry
zset设置值,可追加可覆盖
zrange zset 0 -1
查看所有值
zrange zset1 0 -1 withscores
带分值(排名权重)查看所有值
zrevrange zset1 0 -1
倒序查看所有值
zrangebyscore zset1 20 40
查看分值在20~40内的元素(包括首尾)
zrangebyscore zset1 (20 (40
查看分值在20~40内的元素(不包括首尾)
zrangebyscore zset1 20 40 limit 2 2
查看分值在20~40内的包括首尾),下标为2,往后2个的元素(分页处理)
zrem zset1 a
把叫a的元素鲨了
zrank zset1 c
显示c的下标
开源项目
微人事--烟雨江南
使用Idea操作redis
基本写法
测试类中使用时:测试类中需要加@RunWith
(SpringRunner.class)注解,才能运行
- 使用spring自动装配的RedisTemplate对象来获得redis的操作
- 塞进去的数据没有序列化
- 点的操作多,麻烦
package com.lcywings.sbt;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.test.context.junit4.SpringRunner;
@SpringBootTest
@RunWith(SpringRunner.class)
@Slf4j
public class Springboot04RedisLcywingsApplicationTests {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
// private RedisTemplate<Object, Object> redisTemplate;
@Test
public void TestRedisTemplate() {
// 清空当前数据库所有缓存数据
System.out.println("------ 清空当前数据库缓存 ------");
redisTemplate.getConnectionFactory().getConnection().flushDb();
// 使用java程序操作redis,存入数据
System.out.println("------ 向redis添加数据 ------");
redisTemplate.opsForValue().set("a", "1");
redisTemplate.opsForValue().set("KH89-NUM", 29);
// 使用java程序操作redis,存入数据
System.out.print("------ 向redis获取数据,");
System.out.println("数据是:" + redisTemplate.opsForValue().get("a") + " ------");
// 操作值,进行加减操作
long num = redisTemplate.opsForValue().increment("KH89-NUM", 2);
System.out.println("------ 操作redis数据,加2,结果为:" + num + " ------");
}
}
使用RedisUtil工具类
- 需要加装RedisUtil工具类
- 需要加装Redisconfig配置类
优点:
- 序列化
- 使用简单
RedisUtil工具类
package com.lcywings.sbt.util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundValueOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@Component
public class RedisUtils {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
/**
* 根据key 获取过期时间
*
* @param key 键 不能为null
* @return 时间(秒) 返回0代表为永久有效
*/
public long getExpire(String key) {
return redisTemplate.getExpire(key, TimeUnit.SECONDS);
}
/**
* 判断key是否存在
*
* @param key 键
* @return true 存在 false不存在
*/
public boolean hasKey(String key) {
try {
return redisTemplate.hasKey(key);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 删除缓存
*
* @param key 可以传一个值 或多个
*/
@SuppressWarnings("unchecked")
public void del(String... key) {
if (key != null && key.length > 0) {
if (key.length == 1) {
redisTemplate.delete(key[0]);
} else {
redisTemplate.delete(CollectionUtils.arrayToList(key));
}
}
}
// ============================String=============================
/**
* 普通缓存获取
*
* @param key 键
* @return 值
*/
public Object get(String key) {
return key == null ? null : redisTemplate.opsForValue().get(key);
}
/**
* 普通缓存放入
*
* @param key 键
* @param value 值
* @return true成功 false失败
*/
public boolean set(String key, Object value) {
try {
redisTemplate.opsForValue().set(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 普通缓存放入并设置时间
*
* @param key 键
* @param value 值
* @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期
* @return true成功 false 失败
*/
public boolean set(String key, Object value, long time) {
try {
if (time > 0) {
redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
} else {
set(key, value);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 递增
*
* @param key 键
* @param delta 要增加几(大于0)
* @return
*/
public long incr(String key, long delta) {
if (delta < 0) {
throw new RuntimeException("递增因子必须大于0");
}
return redisTemplate.opsForValue().increment(key, delta);
}
/**
* 递减
*
* @param key 键
* @param delta 要减少几(小于0)
* @return
*/
public long decr(String key, long delta) {
if (delta < 0) {
throw new RuntimeException("递减因子必须大于0");
}
return redisTemplate.opsForValue().increment(key, -delta);
}
/**
* HashGet
*
* @param key 键 不能为null
* @param item 项 不能为null
* @return 值
*/
public Object hget(String key, String item) {
return redisTemplate.opsForHash().get(key, item);
}
/**
* 获取hashKey对应的所有键值
*
* @param key 键
* @return 对应的多个键值
*/
public Map<Object, Object> hmget(String key) {
return redisTemplate.opsForHash().entries(key);
}
/**
* HashSet
*
* @param key 键
* @param map 对应多个键值
* @return true 成功 false 失败
*/
public boolean hmset(String key, Map<String, Object> map) {
try {
redisTemplate.opsForHash().putAll(key, map);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 指定缓存失效时间
*
* @param key 键
* @param time 时间(秒)
* @return
*/
public boolean expire(String key, long time) {
try {
if (time > 0) {
redisTemplate.expire(key, time, TimeUnit.SECONDS);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* HashSet 并设置时间
*
* @param key 键
* @param map 对应多个键值
* @param time 时间(秒)
* @return true成功 false失败
*/
public boolean hmset(String key, Map<String, Object> map, long time) {
try {
redisTemplate.opsForHash().putAll(key, map);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 向一张hash表中放入数据,如果不存在将创建
*
* @param key 键
* @param item 项
* @param value 值
* @return true 成功 false失败
*/
public boolean hset(String key, String item, Object value) {
try {
redisTemplate.opsForHash().put(key, item, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 向一张hash表中放入数据,如果不存在将创建
*
* @param key 键
* @param item 项
* @param value 值
* @param time 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
* @return true 成功 false失败
*/
public boolean hset(String key, String item, Object value, long time) {
try {
redisTemplate.opsForHash().put(key, item, value);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 删除hash表中的值
*
* @param key 键 不能为null
* @param item 项 可以使多个 不能为null
*/
public void hdel(String key, Object... item) {
redisTemplate.opsForHash().delete(key, item);
}
/**
* 判断hash表中是否有该项的值
*
* @param key 键 不能为null
* @param item 项 不能为null
* @return true 存在 false不存在
*/
public boolean hHasKey(String key, String item) {
return redisTemplate.opsForHash().hasKey(key, item);
}
/**
* hash递增 如果不存在,就会创建一个 并把新增后的值返回
*
* @param key 键
* @param item 项
* @param by 要增加几(大于0)
* @return
*/
public double hincr(String key, String item, double by) {
return redisTemplate.opsForHash().increment(key, item, by);
}
/**
* hash递减
*
* @param key 键
* @param item 项
* @param by 要减少记(小于0)
* @return
*/
public double hdecr(String key, String item, double by) {
return redisTemplate.opsForHash().increment(key, item, -by);
}
/**
* 根据key获取Set中的所有值
*
* @param key 键
* @return
*/
public Set<Object> sGet(String key) {
try {
return redisTemplate.opsForSet().members(key);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 根据value从一个set中查询,是否存在
*
* @param key 键
* @param value 值
* @return true 存在 false不存在
*/
public boolean sHasKey(String key, Object value) {
try {
return redisTemplate.opsForSet().isMember(key, value);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将数据放入set缓存
*
* @param key 键
* @param values 值 可以是多个
* @return 成功个数
*/
public long sSet(String key, Object... values) {
try {
return redisTemplate.opsForSet().add(key, values);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* 将set数据放入缓存
*
* @param key 键
* @param time 时间(秒)
* @param values 值 可以是多个
* @return 成功个数
*/
public long sSetAndTime(String key, long time, Object... values) {
try {
Long count = redisTemplate.opsForSet().add(key, values);
if (time > 0)
expire(key, time);
return count;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* 获取set缓存的长度
*
* @param key 键
* @return
*/
public long sGetSetSize(String key) {
try {
return redisTemplate.opsForSet().size(key);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* 移除值为value的
*
* @param key 键
* @param values 值 可以是多个
* @return 移除的个数
*/
public long setRemove(String key, Object... values) {
try {
Long count = redisTemplate.opsForSet().remove(key, values);
return count;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* 获取list缓存的内容
*
* @param key 键
* @param start 开始
* @param end 结束 0 到 -1代表所有值
* @return
*/
public List<Object> lGet(String key, long start, long end) {
try {
return redisTemplate.opsForList().range(key, start, end);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 获取list缓存的长度
*
* @param key 键
* @return
*/
public long lGetListSize(String key) {
try {
return redisTemplate.opsForList().size(key);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* 通过索引 获取list中的值
*
* @param key 键
* @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推
* @return
*/
public Object lGetIndex(String key, long index) {
try {
return redisTemplate.opsForList().index(key, index);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @return
*/
public boolean lSet(String key, Object value) {
try {
redisTemplate.opsForList().rightPush(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @param time 时间(秒)
* @return
*/
public boolean lSet(String key, Object value, long time) {
try {
redisTemplate.opsForList().rightPush(key, value);
if (time > 0)
expire(key, time);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @return
*/
public boolean lSet(String key, List<Object> value) {
try {
redisTemplate.opsForList().rightPushAll(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @param time 时间(秒)
* @return
*/
public boolean lSet(String key, List<Object> value, long time) {
try {
redisTemplate.opsForList().rightPushAll(key, value);
if (time > 0)
expire(key, time);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 根据索引修改list中的某条数据
*
* @param key 键
* @param index 索引
* @param value 值
* @return
*/
public boolean lUpdateIndex(String key, long index, Object value) {
try {
redisTemplate.opsForList().set(key, index, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 移除N个值为value
*
* @param key 键
* @param count 移除多少个
* @param value 值
* @return 移除的个数
*/
public long lRemove(String key, long count, Object value) {
try {
Long remove = redisTemplate.opsForList().remove(key, count, value);
return remove;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* 加锁
*
* @param key
* @param value
* @param expire
* @return 是否加锁成功
*/
public boolean lock(String key, Object value, long expire) {
if (null == value) {
value = new Byte[]{1};
}
if (redisTemplate.opsForValue().setIfAbsent(key, value)) {
expire(key, expire);
return true;
}
return false;
}
/**
* 解锁
*
* @param key
*/
public void delLock(String key) {
redisTemplate.delete(key);
}
public Set<String> keys(String nameSpace) {
return redisTemplate.keys("*" + nameSpace + "*");
}
/**
* 点击收藏
* @param key
* @param count
* @param ttl
* @return
*/
public boolean checkFreq(String key, long count, long ttl) {
boolean exists = redisTemplate.hasKey(key);
BoundValueOperations<String, Object> valueOps = redisTemplate.boundValueOps(key);
Long value = valueOps.increment(1);
if (value == null) value = count;
if (!exists) {
redisTemplate.expire(key, ttl, TimeUnit.SECONDS);
}
return value <= count;
}
}
Redisconfig配置类
@Autowired
private RedisUtils redisUtils;
@Test
public void testRedisUtil() {
// 使用redisUtils操作redis,存入数据
System.out.println("------ 向redis添加数据 ------");
redisUtils.set("a", "1");
redisUtils.set("KH89-NUM", 29);
// 使用redisUtils操作redis,获取数据
log.info("------ 向redis获取数据,数据是:{} ------", redisUtils.get("a"));
log.info("------ 向redis获取数据,数据是:{} ------", redisUtils.get("KH89-NUM"));
// 操作值,进行加减操作
long num = redisUtils.incr("KH89-NUM", 2);
log.info("------ 操作redis数据,学生人数加2,结果为:{} ------", redisUtils.get("KH89-NUM"));
// 如何将实体对象存入redis
User user = User.builder().userId("U0001").userName("Admin").userPwd("111111").build();
log.info("------ 用户详情:{} ------", user);
// 将对象存入Redis
redisUtils.set(user.getUserId(), user);
// 获取redis中存放的用户信息
String userJson = redisUtils.get(user.getUserId()).toString();
log.info("------ 向redis获取的String字符串,userJson:{} ------", userJson);
//转成JSON对象,再转成bean对象
User userInfo = JSON.parseObject(userJson, User.class);
log.info("------ 向redis获取数据,userInfo:{} ------", userInfo);
}
测试类使用
- 只能使用RedisTemplate<String, Object> redisTemplate;中的泛型种类
- 导入工具类,直接点出想用的操作
- 数据不会出问题
@Autowired
//RedisTemplate<Object, Object> redisTemplate;
RedisTemplate<String, Object> redisTemplate;
@Autowired
private RedisUtils redisUtils;
@Test
public void testRedisUtil() {
// 使用redisUtils操作redis,存入数据
System.out.println("------ 向redis添加数据 ------");
redisUtils.set("a", "1");
redisUtils.set("KH89-NUM", 29);
// 使用redisUtils操作redis,获取数据
log.info("------ 向redis获取数据,数据是:{} ------", redisUtils.get("a"));
log.info("------ 向redis获取数据,数据是:{} ------", redisUtils.get("KH89-NUM"));
// 操作值,进行加减操作
long num = redisUtils.incr("KH89-NUM", 2);
log.info("------ 操作redis数据,学生人数加2,结果为:{} ------", redisUtils.get("KH89-NUM"));
// 如何将实体对象存入redis
User user = User.builder().userId("U0001").userName("Admin").userPwd("111111").build();
log.info("------ 用户详情:{} ------", user);
// 将对象存入Redis
redisUtils.set(user.getUserId(), user);
// 获取redis中存放的用户信息
String userJson = redisUtils.get(user.getUserId()).toString();
log.info("------ 向redis获取的String字符串,userJson:{} ------", userJson);
//转成JSON对象,再转成bean对象
User userInfo = JSON.parseObject(userJson, User.class);
log.info("------ 向redis获取数据,userInfo:{} ------", userInfo);
}
在SpringBoot中导入静态页面&资源
小功能:
- 添加一个获取手机验证码的入口,浏览器输入手机号,点击获取验证码,将该手机的验证码存入redis,有效期是60s(在有效期内,使用该验证码可以返回该验证码正确或者错误,超出有效期,提示验证码失效,需要重新获取)
- 实现收藏功能(点一次是收藏,再点一次是取消收藏),为了防止用户恶意操作,增加限制(限制在固定的时间内,比如5s,最多点击次数,比如3次,超出次数不给点击,提示操作频繁,请稍后重新操作
依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
yml配置:
# 静态页面配置
spring:
mvc:
static-path-pattern: /**
# 静态资源的默认访问路径前缀
resources:
static-locations: classpath:/static
# controller返回 String后跳转到指定界面时的路径前缀
thymeleaf:
prefix: classpath:/templates/
静态资源放的位置:
resources的static下(新建js、css...文件)
页面放的位置:
resources的templates下
Controller
package com.lcywings.sbt.controller;
import com.lcywings.sbt.util.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.util.Random;
/**
* Created on 2021/7/25.
* <p>
* Author : Lcywings
* <p>
* Description :
*/
@Slf4j
@Controller
public class PhoneController {
@Autowired
RedisUtils redisUtils;
/**
* @author : Lcywings
* @date : 2021/7/25 21:45
* @acl : true
* @description : 去首页
*/
@RequestMapping("/go")
public String toIndex() {
redisUtils.del("qqqq");
return "index";
}
/**
* @author : Lcywings
* @date : 2021/7/25 21:19
* @acl : true
* @description : 发送手机验证码
*/
@GetMapping("/phoneSend")
@ResponseBody
public String phoneSend() {
Random random = new Random();
Integer phoneVal = 0;
do {
phoneVal = random.nextInt(10000);
}
while (phoneVal <= 999);
redisUtils.set("phoneVal", phoneVal, 60000);
log.info("------ 验证码为:{} ------", phoneVal);
return phoneVal + "";
}
/**
* @author : Lcywings
* @date : 2021/7/25 21:21
* @acl : true
* @description : 手机验证码校验
*/
@GetMapping("/login")
@ResponseBody
public String phoneVal(@RequestParam("val") String val) {
if (null == redisUtils.get("phoneVal"))
return "overtime";
if (val.equals(redisUtils.get("phoneVal").toString()))
return "yes";
else
return "no";
}
/**
* @author : Lcywings
* @date : 2021/7/25 23:06
* @acl : true
* @description : 点击收藏
*/
@GetMapping("/collect")
@ResponseBody
public String collect() {
// 模拟数据库收藏状态
if (null == redisUtils.get("collectState")) {
redisUtils.set("collectState", 0);
}
Integer collectState = Integer.valueOf(redisUtils.get("collectState") + "");
if (redisUtils.checkFreq("qqqq", 3, 5)) {
if (collectState == 1) {
redisUtils.set("collectState", 0);
return "0";
} else {
redisUtils.set("collectState", 1);
return "1";
}
} else {
Thread thread = new Thread(() -> {
try {
Thread.sleep(2000);
} catch (Exception e) {
e.printStackTrace();
}
redisUtils.del("qqqq");
});
return "3";
}
}
}
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title></title>
</head>
<body>
<table>
<tr>
<td>手机号:<input type="tel" name="phone"/>
<button name="phoneVal" id="phoneVal" onclick="sendPhone()">验证</button>
</td>
</tr>
<tr>
<td>验证码:<input type="text" name="val" id="val"/></td>
</tr>
<tr>
<td>
<button name="login" id="login" onclick="login()" style="width: 80%;align-self: center">登录</button>
</td>
</tr>
<tr>
<td>
<input style="font-size: 1.6875rem;" type="button" name="collect" id="collect" value="点击收藏"
onclick="collect()"/>
</td>
</tr>
</table>
</body>
<script type="text/javascript" src="/js/jquery-3.4.1.min.js"></script>
<script type="text/javascript">
function sendPhone() {
$.get("/phoneSend", function (data) {
alert("验证码发送成功!" + data)
});
}
function login() {
var val = $("#val").val();
alert("val:" + val);
$.get("/login", {"val": val}, function (data) {
if (data == "yes")
alert("登录成功!")
else if (data == "no")
alert("登录失败!")
else if (data == "overtime") {
alert("验证码超时!")
}
});
}
function collect() {
$.get("/collect", function (data) {
if (data == "1")
$("#collect").attr("value", "已收藏");
else if (data == "0")
$("#collect").attr("value", "点击收藏");
else if (data == "3")
alert("操作次数太频繁!")
});
}
</script>
</html>
Q.E.D.