准备redis工具类 对redis进行操作
package cn.itsource.wyj.util; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPoolConfig; import java.io.IOException; import java.util.Properties; /** * 获取连接池对象 */ public enum RedisUtils { INSTANCE; static JedisPool jedisPool = null; static { //1 创建连接池配置对象 JedisPoolConfig config = new JedisPoolConfig(); //2 进行配置-四个配置 config.setMaxIdle(1);//最小连接数 config.setMaxTotal(11);//最大连接数 config.setMaxWaitMillis(10 * 1000L);//最长等待时间 config.setTestOnBorrow(true);//测试连接时是否畅通 //3 通过配置对象创建连接池对象 Properties properties = null; try { properties = new Properties(); properties.load(RedisUtils.class.getClassLoader().getResourceAsStream("redis.properties")); } catch (IOException e) { e.printStackTrace(); } String host = properties.getProperty("redis.host"); String port = properties.getProperty("redis.port"); String password = properties.getProperty("redis.password"); String timeout = properties.getProperty("redis.timeout"); jedisPool = new JedisPool(config, host, Integer.valueOf(port),Integer.valueOf(timeout), password); } //获取连接 public Jedis getSource() { return jedisPool.getResource(); } //关闭资源 public void closeSource(Jedis jedis) { if (jedis != null) { jedis.close(); } } /** * 设置字符值 * * @param key * @param value */ public void set(String key, String value) { Jedis jedis = getSource(); jedis.set(key, value); closeSource(jedis); } /** * 设置 * @param key * @param value */ public void set(byte[] key, byte[] value) { Jedis jedis = getSource(); jedis.set(key, value); closeSource(jedis); } /** * 删除缓存 * @param key 通过key删除值 */ public boolean del(String key) { Jedis jedis = getSource(); Long result = jedis.del(key); closeSource(jedis); return result>0;//大于0删除成功 否则失败 } /** * * @param key * @return */ public byte[] get(byte[] key) { Jedis jedis = getSource(); try { return jedis.get(key); } catch (Exception e) { e.printStackTrace(); } finally { closeSource(jedis); } return null; } /** * 设置字符值 * * @param key */ public String get(String key) { Jedis jedis = getSource(); try { return jedis.get(key); } catch (Exception e) { e.printStackTrace(); } finally { closeSource(jedis); } return null; } } 编写redis控制层进行缓存获取缓存清除缓存 package cn.itsource.wyj.controller; import cn.itsource.wyj.util.AjaxResult; import cn.itsource.wyj.util.RedisUtils; import org.springframework.web.bind.annotation.*; @RestController @RequestMapping("/redis") public class RedisController { @RequestMapping(value = "/set",method = RequestMethod.POST) public AjaxResult set(@RequestParam("key")String key,@RequestParam("value")String value){ try { RedisUtils.INSTANCE.set(key,value); return AjaxResult.me(); } catch (Exception e) { e.printStackTrace(); return AjaxResult.me().setSuccess(false).setMessage("保存失败"); } } @RequestMapping("/get/{key}") public AjaxResult get(@PathVariable("key")String key){ try { String s = RedisUtils.INSTANCE.get(key); return AjaxResult.me().setResultObj(s); } catch (Exception e) { e.printStackTrace(); return AjaxResult.me().setSuccess(false).setMessage("获取失败"); } } @RequestMapping("/del/{key}") public AjaxResult del(@PathVariable("key")String key){ boolean res = RedisUtils.INSTANCE.del(key); return AjaxResult.me().setSuccess(res).setMessage(!res?"删除成功":"删除失败"); } }用postman做简单的测试
在公共微服务子模块common-feign微服务集成feign 和熔断器导包 <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> 编写feign接口 注意开启feign客户端 使用工厂降级方法将redis控制层的方法复制过来. package cn.itsource.wyj.feign.client; import cn.itsource.wyj.util.AjaxResult; import cn.itsource.wyj.feign.fallbackFactory.CommonFallbackFactory; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; /** * feign接口 */ @FeignClient(value = "common-server",fallbackFactory = CommonFallbackFactory.class) public interface CommonFeignClient { //保存 @RequestMapping(value = "/redis/set",method = RequestMethod.POST) public AjaxResult set(@RequestParam("key")String key, @RequestParam("value")String value); //获取 @RequestMapping("/redis/get/{key}") public AjaxResult get(@PathVariable("key")String key); //清除缓存 @RequestMapping("/redis/del/{key}") public AjaxResult del(@PathVariable("key")String key); } 遍写降级类创建类实现FallbackFactory 泛型为feign的接口实现方法 然后new feign接口写匿名内部类创建一个日志对象 //创建一个日志对象 private Logger logger=LoggerFactory.getLogger(CommonFallbackFactory.class); 抛出异常,打印日志 返回错误 package cn.itsource.wyj.feign.fallbackFactory; import cn.itsource.wyj.feign.client.CommonFeignClient; import cn.itsource.wyj.util.AjaxResult; import feign.hystrix.FallbackFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; @Component public class CommonFallbackFactory implements FallbackFactory<CommonFeignClient> { //创建一个日志对象 private Logger logger=LoggerFactory.getLogger(CommonFallbackFactory.class); @Override public CommonFeignClient create(Throwable throwable) { //使用匿名内部类的方式来new接口 return new CommonFeignClient() { @Override public AjaxResult set(String key, String value) { //打印异常信息 throwable.printStackTrace(); //打印日志 logger.error("redis服务不可用[set]"); return AjaxResult.me().setSuccess(false).setMessage("redis服务不可用[set]"); } @Override public AjaxResult get(String key) { //打印异常信息 throwable.printStackTrace(); //打印日志 logger.error("redis服务不可用[get]"); return AjaxResult.me().setSuccess(false).setMessage("redis服务不可用[get]"); } @Override public AjaxResult del(String key) { //打印异常信息 throwable.printStackTrace(); //打印日志 logger.error("redis服务不可用[del]"); return AjaxResult.me().setSuccess(false).setMessage("redis服务不可用[del]"); } }; } }去课程微服务启动类开启feign 注意feign接口所在包名和课程微服务包名一样 否则报错spring扫描不到feign接口
package cn.itsource.wyj; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.cloud.netflix.zuul.EnableZuulProxy; import org.springframework.cloud.openfeign.EnableFeignClients; @SpringBootApplication @EnableEurekaClient//开启eureka客户端支持 @EnableZuulProxy @EnableFeignClients public class CourseApplication { public static void main(String[] args) { SpringApplication.run(CourseApplication.class); } } 进行逻辑代码处理(前台需要的数据是树形化数据)1使用mybatis plus的内嵌循环查询 (效率较低,比较简单)
1.1调用mapper方法 在数据库进行查询1.2查询数据,先查询父级数据(父id没有或者为0就是父级数据)1.3对子级数据集合进行自定义映射(子集何domain里面一个是一个课程分类的一个集合)1.4在集合映射时根据父级id查询数据,这样满足条件的数据就在子集合中实现了数据树形化具体代码如下 service层方法 courseTypeMapper.loadtreeData(); sql实现 <!-- 通用查询映射结果 --> <resultMap id="BaseResultMap" type="cn.itsource.wyj.domain.CourseType"> <id column="id" property="id" /> <result column="createTime" property="createTime" /> <result column="updateTime" property="updateTime" /> <result column="name" property="name" /> <result column="pid" property="pid" /> <result column="logo" property="logo" /> <result column="description" property="description" /> <result column="sortIndex" property="sortIndex" /> <result column="path" property="path" /> <result column="totalCount" property="totalCount" /> <collection property="children" column="id" select="cn.itsource.wyj.mapper.CourseTypeMapper.loadCourseTypeByPid"/> </resultMap> <!--查询一级--> <select id="loadtreeData" resultMap="BaseResultMap"> SELECT id, createTime, updateTime, name, pid, logo, description, sortIndex, path, totalCount FROM t_course_type where pid=0 </select> <!--查询子集--> <select id="loadCourseTypeByPid" resultMap="BaseResultMap"> SELECT id, createTime, updateTime, name, pid, logo, description, sortIndex, path, totalCount FROM t_course_type where pid=#{id} </select>2.方式二:查询所有判断去是否是一级 一级直接装到集合 不是一级就加到父级集合中(效率高,稍微有点复杂) 2.1 先去查询所有的扁平化数据 2.2 然后去循环,判断父级id是否为0或者为空,如果是那么申明一个集合添加这些数据 2.3 如果不是那么就再次循环所有的扁平化数据,用已经确定不是父级的这条数据去和循环的数据比较 2.4 用已经确定不是父级的这条数据的父级id去等于循环数据的id如果相等了那该条数据就是父级就不在循环。 2.5 就把已经确定不是父级的这条数据添加到自己的父级中去。 2.6 返回集合 具体代码如下 service层
/** * 把扁平化的数据进行树状化 * @param allcourseType 查询到的遍平化数据 * @return 树状化数据 */ private List<CourseType> treeDataHandler(List<CourseType> allcourseType) { /** * 查询树状展示数据 */ //方式一 使用mybatis 嵌套查询 //return courseTypeMapper.loadtreeData(); //方式二 查询所有判断是否是一级 一级直接装到集合 不是一级就加到父级集合中 List<CourseType> parentType=new ArrayList<>(); //循环所有的课程分类 allcourseType.forEach(courseType -> { if(courseType.getPid()!=null){ //如果pid==0就是父级课程分类 if(courseType.getPid().longValue()==0){ parentType.add(courseType); }else { CourseType parentTypes=null; //如果不满足那么courseType就不是父类 就需要去找父类 循环数据id=courseType.pid for (CourseType type : allcourseType) { if(type.getId().equals(courseType.getPid())){ parentTypes=type; break; } } parentTypes.getChildren().add(courseType); } } }); return parentType; }方式三 使用递归方式(麻烦)不推荐
当对课程进行增加修改和删除时要对缓存进行清理 复写mybatis plus的方法 操作成功就去清除缓存 具体代码在下面都有。这里将清除缓存提取成一个方法 增添改删调用就可以了,具体实现下面代码有。
/** * 增加修改删除成功时就对数据缓存进行清理 */ private void ClearCourseTypeByRedis(boolean res){ AjaxResult cleanAj = commonFeignClient.del("KEY_COURES_TYPE"); System.out.println("-------------"); System.out.println(cleanAj.isSuccess()); if(!cleanAj.isSuccess()){ //如果没有清理成功那么就去根据业务做处理 允许脏数据就不抛异常回滚 不允许脏数据就抛异常回滚数据 比如金融这些 logger.error("清除缓存失败"); } }使用方式一对数据进行树形化缓存比较简单
使用方式二对数据进行树形化缓存