前言
最终目的是使用redis存取字典表。这个案例就将使用到springboot+redis,但在此过程中遇见很多问题,逐个击破,最后实现功能。
准备工作
这里只是实现springboo集成redis,加上前端集成layui,如果单纯只是想使用springboot+layui的办法,在另一篇文章已经给出。
这里我的目的是从mysql数据库获取值,如果不想这么麻烦,也可以将所有事情直接交给前端,使用layui和layui的插件。在另一篇文章中也有相关说明。
首先需要以下依赖:
注:只展示redis所需要的
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<dependency>
utils
这里使用Jedis来对redis数据库进行操作,但是个人目前还没找到直接用注解或是系统配置文件自动配置的方法,因此这里还是需要使用JedisUtils工具类,注入配置文件,启动redis。
我这里的目的只是想使用redis存取值,不需要那么复杂的操作,因此工具类也只是一个简单的连接工具而已,并没有什么复杂的方法。
JedisPoolUtils:
public class JedisPoolUtils {
private static JedisPool jedisPool;
//类加载之前会执行的代码块
static {
//1.读取配置文件
InputStream is =JedisPoolUtils.class.getClassLoader().getResourceAsStream("redis.properties");
//2.创建Properties
Properties pro = new Properties();
//3.
try {
pro.load(is);
} catch (IOException e) {
e.printStackTrace();
}
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(Integer.parseInt(pro.getProperty("maxTotal")));
config.setMaxIdle(Integer.parseInt(pro.getProperty("maxIdle")));
jedisPool=new JedisPool(config,"localhost",Integer.parseInt(pro.getProperty("port")));
}
public static Jedis getJedis(){
Jedis jedis = jedisPool.getResource();
return jedis;
}
public static void main(String[] args) {
System.out.println(JedisPoolUtils.getJedis());
}
}
jedis.properties:
需要什么配什么,不用配那么多
host=127.0.0.1
port=6379
maxTotal=50
maxIdle=10
后端代码
如果是使用redis存下来的值,就不会到数据访问层,况且springboot也没有使用到dao层,之前使用的是mapper接口的方法,这里也不会访问到那里去。
redis存取值可以止步于service层或者是controller层,controller层不方便写一些底层代码,因此放在service实现类里。
service接口
@Mapper
public interface SelectMapper {
List<Province1> query();
List<City1> queryById(String id);
}
service接口
public interface SelectService {
String getProvinceJson();
String getCityJson(String pId);
}
service实现类
这里可以整合为一个方法放在utils类中直接调用,按道理来说底层代码也确实应该这么做,但这里不必吹毛求疵了,个人技术也还没到自己编写底层工具类的程度。
@Service
public class SelectServiceImpl implements SelectService {
@Resource
SelectMapper selectMapper;
Jedis jedis = JedisPoolUtils.getJedis();
ObjectMapper objectMapper = new ObjectMapper();
@Override
public String getProvinceJson() {
String province_json = jedis.get("province");
if (province_json == null || province_json.length()==0) {
List<Province1> query = selectMapper.query();
try {
province_json = objectMapper.writeValueAsString(query);
}catch (JsonProcessingException e) {
e.printStackTrace();
}
jedis.set("province",province_json);
jedis.close();
}else {
System.out.println("有数据,直接使用redis缓存");
}
return province_json ;
}
@Override
public String getCityJson(String id) {
String city_json = jedis.get("city"+id);
if (city_json == null || city_json.length()==0) {
List<City1> query = selectMapper.queryById(id);
try {
city_json = objectMapper.writeValueAsString(query);
}catch (JsonProcessingException e) {
e.printStackTrace();
}
jedis.set("city",city_json);
jedis.close();
}else {
System.out.println("有数据,直接使用redis缓存");
}
return city_json ;
}
}
注:记住要关闭jedis,否则无法拿值。
controller控制层类
@Controller
@RequestMapping("/query")
public class SelectController {
@Resource
SelectService selectService;
@ResponseBody
@RequestMapping("/getP")
public String getP(){
String query = selectService.getProvinceJson();
return query;
}
@ResponseBody
@RequestMapping("/getC")
public String getC(@RequestParam String id){
String queryCity = selectService.getCityJson(id);
return queryCity;
}
}
注:
写完之后一定要写测试类测试是否能取到值,否则后面找错更麻烦。这也是我遇到的问题之一,花费了很长时间找问题。这里需要注意springboot使用test测试类需要添加两个注解,在另一篇文章也有写到,不想找的话直接看下面也可
@RunWith(SpringRunner.class)
@SpringBootTest
public class Test {
@Resource
SelectService selectService;
@org.junit.Test
public void query(){
List<City1> query = selectService.queryById("1001");
query.forEach(city1 -> System.out.println(city1));
}
}
前端部分
这里前端直接使用layui框架,相关代码是直接重复造了我另一篇文章的轮子。
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Title</title> <script src="js/layui/layui.js"></script> <link rel="stylesheet" href="js/layui/css/layui.css"></head><body><form class="layui-form"> <div class="layui-input-inline"> <select id="province" name="province" lay-verify="required" class="select" lay-filter="brickType"> <option id="pid" value="" >请选择省</option> </select> </div> <div class="layui-input-inline"> <select id="city" name="city" lay-verify="required" class="select"> <option id="cid" value="" >请选择市</option> </select> </div></form><script> layui.use('form',function(){ var $ = layui.jquery; var form = layui.form; $.ajax({ url: '/query/getP', dataType: 'json', type: 'post', success: function(query) { //$("#province").append(new Option("请选择省", "0")); $.each(query, function(index, item) { $('#province').append(new Option(pvalue =item.name,pid =item.id)); }); form.render("select"); } }); form.on('select(brickType)', function(data){ var val=data.value; //console.info(val); $.ajax({ url: '/query/getC', data:{id:val}, dataType: 'json', type: 'post', success: function(queryCity) { //$("#province").append(new Option("请选择省", "0")); $('#city').empty(); $.each(queryCity, function(index, item) { $('#city').append(new Option(cvalue =item.name,cid =item.id)); }); form.render("select"); } }); }); });
注
- 1.前端编写注意边写边测试。否则后面很难找bug。
最终效果
数据是自己写在mysql里面的,所以值不是很多
再返回Java后台,在service的实现类中已经写明,如果能从redis中获取数据,就会在后台打印一串文字,通过刷新页面。
后台输出如下值:
说明使用的是redis中的值,并没有返回到mysql。
在redis客户端中也可以查到值(忽略编码格式):
写在后面
以上代码还存在一些缺陷,比如字典表值改变了,就不能及时获取到更新后的mysql数据。
最笨的方法就是定时更新,其次可以在mysql数据update之后要么更新redis,要么在update中嵌入语句,直接删除之前的redis。
个人觉得直接删除的方法比较适用。
最后,在整个过程中需要保持redis服务器开启。