<properties>
<mybatis-plus.version>3.1.0</mybatis-plus.version>
<redisson.version>3.10.6</redisson.version>
</properties>
<!-- 使用redisson集成分布式锁等 -->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>${redisson.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
如:
CREATE TABLE `tz_area` (
`area_id` bigint(20) NOT NULL AUTO_INCREMENT,
`area_name` varchar(50) DEFAULT NULL,
`parent_id` bigint(20) DEFAULT NULL,
`level` int(1) DEFAULT NULL,
PRIMARY KEY (`area_id`),
KEY `parent_id` (`parent_id`) COMMENT '上级id'
) ENGINE=InnoDB AUTO_INCREMENT=659006000001 DEFAULT CHARSET=utf8;
import java.io.Serializable;
import java.util.List;
import com.baomidou.mybatisplus.annotation.*;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@TableName("tz_area")
public class Area implements Serializable {
private static final long serialVersionUID = -6013320537436191451L;
@TableId
@ApiModelProperty(value = "地区id",required=true)
private Long areaId;
@ApiModelProperty(value = "地区名称",required=true)
private String areaName;
@ApiModelProperty(value = "地区上级id",required=true)
private Long parentId;
@ApiModelProperty(value = "地区层级",required=true)
private Integer level;
@TableField(exist=false)
private List<Area> areas;
}
import com.shop.bean.model.Area;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.shop.common.util.PageAdapter;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface AreaMapper extends BaseMapper<Area> {
}
对应dao层的方法,在mapper.xml配置sql语句
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.shop.dao.AreaMapper">
<resultMap id="BaseResultMap" type="com.yami.shop.bean.model.Area">
<!--
WARNING - @mbg.generated
-->
<id column="area_id" jdbcType="BIGINT" property="areaId"/>
<result column="area_name" jdbcType="VARCHAR" property="areaName"/>
<result column="parent_id" jdbcType="BIGINT" property="parentId"/>
<result column="level" jdbcType="INTEGER" property="level"/>
</resultMap>
</mapper>
spring:
# 环境 dev|test|prod quart定时任务
profiles:
active: dev,quartz
#文件上传设置
servlet:
multipart:
max-file-size: 100MB
max-request-size: 100MB
enabled: true
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
# mybaits-plus配置
mybatis-plus:
# MyBatis Mapper所对应的XML文件位置
mapper-locations: classpath*:/mapper/*Mapper.xml
global-config:
# 关闭MP3.0自带的banner
banner: false
db-config:
# 主键类型 0:数据库ID自增 1.未定义 2.用户输入 3 id_worker 4.uuid 5.id_worker字符串表示
id-type: AUTO
#字段策略 0:"忽略判断",1:"非 NULL 判断"),2:"非空判断"
field-strategy: NOT_NULL
# 默认数据库表下划线命名
table-underline: true
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.shop.bean.model.Area;
import java.util.List;
import java.util.Map;
public interface AreaService extends IService<Area> {
/**
* 通过pid 查找地址接口
*
* @param pid 父id
* @return
*/
List<Area> listByPid(Long pid);
/**
* 通过pid 清除地址缓存
*
* @param pid
*/
void removeAreaCacheByParentId(Long pid);
}
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.shop.bean.model.Area;
import com.shop.dao.AreaMapper;
import com.shop.service.AreaService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Service
public class AreaServiceImpl extends ServiceImpl<AreaMapper, Area> implements AreaService {
@Autowired
private AreaMapper areaMapper;
@Override
@Cacheable(cacheNames = "area", key = "#pid")
public List<Area> listByPid(Long pid) {
return areaMapper.selectList(new LambdaQueryWrapper<Area>().eq(Area::getParentId, pid));
}
@Override
@CacheEvict(cacheNames = "area", key = "#pid")
public void removeAreaCacheByParentId(Long pid) {
}
}
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.shop.common.util.PageParam;
import com.shop.bean.model.Area;
import com.shop.service.AreaService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.util.List;
import java.util.Map;
/**
* @author lgh on 2018/10/26.
*/
@RestController
@RequestMapping("/admin/area")
public class AreaController {
@Autowired
private AreaService areaService;
/**
* 分页获取
*/
@GetMapping("/page")
@PreAuthorize("@pms.hasPermission('admin:area:page')")
public ResponseEntity<IPage<Area>> page(Area area,PageParam<Area> page) {
IPage<Area> sysUserPage = areaService.page(page, new LambdaQueryWrapper<Area>());
return ResponseEntity.ok(sysUserPage);
}
/**
* 获取省市
*/
@GetMapping("/list")
@PreAuthorize("@pms.hasPermission('admin:area:list')")
public ResponseEntity<List<Area>> list(Area area) {
List<Area> areas = areaService.list(new LambdaQueryWrapper<Area>()
.like(area.getAreaName() != null, Area::getAreaName, area.getAreaName()));
return ResponseEntity.ok(areas);
}
/**
* 通过父级id获取区域列表
*/
@GetMapping("/listByPid")
public ResponseEntity<List<Area>> listByPid(Long pid) {
List<Area> list = areaService.listByPid(pid);
return ResponseEntity.ok(list);
}
/**
* 获取信息
*/
@GetMapping("/info/{id}")
@PreAuthorize("@pms.hasPermission('admin:area:info')")
public ResponseEntity<Area> info(@PathVariable("id") Long id) {
Area area = areaService.getById(id);
return ResponseEntity.ok(area);
}
/**
* 保存
*/
@PostMapping
@PreAuthorize("@pms.hasPermission('admin:area:save')")
public ResponseEntity<Void> save(@Valid @RequestBody Area area) {
if (area.getParentId() != null) {
Area parentArea = areaService.getById(area.getParentId());
area.setLevel(parentArea.getLevel() + 1);
areaService.removeAreaCacheByParentId(area.getParentId());
}
areaService.save(area);
return ResponseEntity.ok().build();
}
/**
* 修改
*/
@PutMapping
@PreAuthorize("@pms.hasPermission('admin:area:update')")
public ResponseEntity<Void> update(@Valid @RequestBody Area area) {
areaService.updateById(area);
areaService.removeAreaCacheByParentId(area.getParentId());
return ResponseEntity.ok().build();
}
/**
* 删除
*/
@DeleteMapping("/{id}")
@PreAuthorize("@pms.hasPermission('admin:area:delete')")
public ResponseEntity<Void> delete(@PathVariable Long id) {
Area area = areaService.getById(id);
areaService.removeById(id);
areaService.removeAreaCacheByParentId(area.getParentId());
return ResponseEntity.ok().build();
}
}
配置redission.yml
# 单节点设置
singleServerConfig:
address: redis://127.0.0.1:6379
database: 0
password: null
idleConnectionTimeout: 10000
pingTimeout: 1000
connectTimeout: 10000
timeout: 3000
retryAttempts: 3
retryInterval: 1500
reconnectionTimeout: 3000
failedAttempts: 3
clientName: null
# 发布和订阅连接的最小空闲连接数 默认1
subscriptionConnectionMinimumIdleSize: 1
# 发布和订阅连接池大小 默认50
subscriptionConnectionPoolSize: 10
# 单个连接最大订阅数量 默认5
subscriptionsPerConnection: 5
# 最小空闲连接数 默认32,现在暂时不需要那么多的线程
connectionMinimumIdleSize: 4
# connectionPoolSize 默认64,现在暂时不需要那么多的线程
connectionPoolSize: 20
# 这个线程池数量被所有RTopic对象监听器,RRemoteService调用者和RExecutorService任务共同共享。
threads: 0
# 这个线程池数量是在一个Redisson实例内,被其创建的所有分布式数据类型和服务,以及底层客户端所一同共享的线程池里保存的线程数量。
nettyThreads: 0
codec:
class: com.yami.shop.common.serializer.redisson.FstCodec
transportMode: NIO
编写RedisUtil工具类
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.CollectionUtils;
public class RedisUtil {
private static RedisTemplate<String,Object> redisTemplate = SpringContextUtils.getBean("redisTemplate",RedisTemplate.class);
//=============================common============================
/**
* 指定缓存失效时间
* @param key 键
* @param time 时间(秒)
* @return
*/
public static 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;
}
}
/**
* 根据key 获取过期时间
* @param key 键 不能为null
* @return 时间(秒) 返回0代表为永久有效 失效时间为负数,说明该主键未设置失效时间(失效时间默认为-1)
*/
public static long getExpire(String key){
return redisTemplate.getExpire(key,TimeUnit.SECONDS);
}
/**
* 判断key是否存在
* @param key 键
* @return true 存在 false 不存在
*/
public static boolean hasKey(String key){
try {
return redisTemplate.hasKey(key);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 删除缓存
* @param key 可以传一个值 或多个
*/
@SuppressWarnings("unchecked")
public static 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 值
*/
@SuppressWarnings("unchecked")
public static <T> T get(String key){
return key==null?null:(T)redisTemplate.opsForValue().get(key);
}
/**
* 普通缓存放入
* @param key 键
* @param value 值
* @return true成功 false失败
*/
public static 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 static 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;
}
}
/**
* 递增 此时value值必须为int类型 否则报错
* @param key 键
* @param delta 要增加几(大于0)
* @return
*/
public static 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 static long decr(String key, long delta){
if(delta<0){
throw new RuntimeException("递减因子必须大于0");
}
return redisTemplate.opsForValue().increment(key, -delta);
}
}
在需要缓存的地方调用该工具类即可,如controller层
@GetMapping("/captcha.jpg")
public void login(HttpServletResponse response,String uuid) {
//定义图形验证码的长、宽、验证码字符数、干扰元素个数 300s后过期
SimpleCaptcha simpleCaptcha = new SimpleCaptcha(200, 50, 4, 20);
try {
simpleCaptcha.write(response.getOutputStream());
RedisUtil.set(SecurityConstants.SPRING_SECURITY_RESTFUL_IMAGE_CODE+uuid, simpleCaptcha.getCode(), 300);
} catch (IOException e) {
e.printStackTrace();
}
}