fix(登录问题): 修复登录用户缓存为空的问题

This commit is contained in:
zhuangpeng.li
2025-04-23 11:39:44 +08:00
parent 201bbfeefb
commit 0215feb4b0
18 changed files with 979 additions and 111 deletions

View File

@@ -1,126 +1,175 @@
package com.fastbee.common.core.domain; package com.fastbee.common.core.domain;
import java.io.Serializable; import cn.hutool.core.util.ObjectUtil;
import java.util.Date; import com.baomidou.mybatisplus.annotation.TableField;
import java.util.HashMap; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import java.io.Serializable;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/** /**
* Entity基类 * Entity基类
* *
* @author ruoyi * @author ruoyi
*/ */
public class BaseEntity implements Serializable public class BaseEntity implements Serializable {
{
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** 搜索值 */ /**
* 搜索值
*/
@TableField(exist = false)
@ApiModelProperty("搜索值") @ApiModelProperty("搜索值")
@JsonIgnore @JsonIgnore
private String searchValue; private String searchValue;
/** 创建者 */ /**
* 创建者
*/
@ApiModelProperty("创建者") @ApiModelProperty("创建者")
private String createBy; private String createBy;
/** 创建时间 */ /**
* 创建时间
*/
@ApiModelProperty("创建时间") @ApiModelProperty("创建时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime; private Date createTime;
/** 更新者 */ /**
* 更新者
*/
@ApiModelProperty("更新者") @ApiModelProperty("更新者")
private String updateBy; private String updateBy;
/** 更新时间 */ /**
* 更新时间
*/
@ApiModelProperty("更新时间") @ApiModelProperty("更新时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateTime; private Date updateTime;
/** 备注 */ /**
* 备注
*/
@ApiModelProperty("备注") @ApiModelProperty("备注")
private String remark; private String remark;
/** 请求参数 */ /**
* 当前记录起始索引 默认值
*/
public static final int DEFAULT_PAGE_NUM = 1;
/**
* 每页显示记录数 默认值 默认查全部
*/
public static final int DEFAULT_PAGE_SIZE = Integer.MAX_VALUE;
/**
* 构建分页对象
*/
public <T> Page<T> buildPage() {
Integer pageNum = ObjectUtil.defaultIfNull(this.pageNum, DEFAULT_PAGE_NUM);
Integer pageSize = ObjectUtil.defaultIfNull(this.pageSize, DEFAULT_PAGE_SIZE);
if (pageNum <= 0) {
pageNum = DEFAULT_PAGE_NUM;
}
Page<T> page = new Page<>(pageNum, pageSize);
return page;
}
public Integer getPageNum() {
return ObjectUtil.defaultIfNull(this.pageNum, DEFAULT_PAGE_NUM);
}
public void setPageNum(Integer pageNum) {
this.pageNum = pageNum;
}
public Integer getPageSize() {
return ObjectUtil.defaultIfNull(this.pageSize, DEFAULT_PAGE_SIZE);
}
public void setPageSize(Integer pageSize) {
this.pageSize = pageSize;
}
@TableField(exist = false)
private Integer pageNum;
@TableField(exist = false)
private Integer pageSize;
/**
* 请求参数
*/
@TableField(exist = false)
@ApiModelProperty("请求参数") @ApiModelProperty("请求参数")
@JsonInclude(JsonInclude.Include.NON_EMPTY) @JsonInclude(JsonInclude.Include.NON_EMPTY)
private Map<String, Object> params; private Map<String, Object> params;
public String getSearchValue() public String getSearchValue() {
{
return searchValue; return searchValue;
} }
public void setSearchValue(String searchValue) public void setSearchValue(String searchValue) {
{
this.searchValue = searchValue; this.searchValue = searchValue;
} }
public String getCreateBy() public String getCreateBy() {
{
return createBy; return createBy;
} }
public void setCreateBy(String createBy) public void setCreateBy(String createBy) {
{
this.createBy = createBy; this.createBy = createBy;
} }
public Date getCreateTime() public Date getCreateTime() {
{
return createTime; return createTime;
} }
public void setCreateTime(Date createTime) public void setCreateTime(Date createTime) {
{
this.createTime = createTime; this.createTime = createTime;
} }
public String getUpdateBy() public String getUpdateBy() {
{
return updateBy; return updateBy;
} }
public void setUpdateBy(String updateBy) public void setUpdateBy(String updateBy) {
{
this.updateBy = updateBy; this.updateBy = updateBy;
} }
public Date getUpdateTime() public Date getUpdateTime() {
{
return updateTime; return updateTime;
} }
public void setUpdateTime(Date updateTime) public void setUpdateTime(Date updateTime) {
{
this.updateTime = updateTime; this.updateTime = updateTime;
} }
public String getRemark() public String getRemark() {
{
return remark; return remark;
} }
public void setRemark(String remark) public void setRemark(String remark) {
{
this.remark = remark; this.remark = remark;
} }
public Map<String, Object> getParams() public Map<String, Object> getParams() {
{ if (params == null) {
if (params == null)
{
params = new HashMap<>(); params = new HashMap<>();
} }
return params; return params;
} }
public void setParams(Map<String, Object> params) public void setParams(Map<String, Object> params) {
{
this.params = params; this.params = params;
} }
} }

View File

@@ -0,0 +1,76 @@
package com.fastbee.common.core.domain;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
/**
* @author admin
* @version 1.0
* @description: 分页参数基础类
* @date 2024-11-15 18:00
*/
@Data
public class PageEntity implements Serializable {
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
@TableField(exist = false)
private Integer pageNum;
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
@TableField(exist = false)
private Integer pageSize;
/**
* 当前记录起始索引 默认值
*/
public static final int DEFAULT_PAGE_NUM = 1;
/**
* 每页显示记录数 默认值 默认查全部
*/
public static final int DEFAULT_PAGE_SIZE = Integer.MAX_VALUE;
/**
* 构建分页对象
*/
public <T> Page<T> buildPage() {
Integer pageNum = ObjectUtil.defaultIfNull(this.pageNum, DEFAULT_PAGE_NUM);
Integer pageSize = ObjectUtil.defaultIfNull(this.pageSize, DEFAULT_PAGE_SIZE);
if (pageNum <= 0) {
pageNum = DEFAULT_PAGE_NUM;
}
Page<T> page = new Page<>(pageNum, pageSize);
return page;
}
/**
* 请求参数
*/
@TableField(exist = false)
@ApiModelProperty("请求参数")
@JsonInclude(JsonInclude.Include.NON_EMPTY)
private Map<String, Object> params;
public Map<String, Object> getParams() {
if (params == null) {
params = new HashMap<>();
}
return params;
}
public Integer getPageNum() {
return ObjectUtil.defaultIfNull(this.pageNum, DEFAULT_PAGE_NUM);
}
public Integer getPageSize() {
return ObjectUtil.defaultIfNull(this.pageSize, DEFAULT_PAGE_SIZE);
}
}

View File

@@ -1,15 +1,16 @@
package com.fastbee.common.core.domain.model; package com.fastbee.common.core.domain.model;
import com.alibaba.fastjson2.annotation.JSONField;
import com.fastbee.common.core.domain.entity.SysUser;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection; import java.util.Collection;
import java.util.Set; import java.util.Set;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import com.alibaba.fastjson2.annotation.JSONField;
import com.fastbee.common.core.domain.entity.SysUser;
/** /**
* 登录用户身份权限 * 登录用户身份权限
* *
* @author ruoyi * @author ruoyi
*/ */
public class LoginUser implements UserDetails public class LoginUser implements UserDetails
@@ -31,6 +32,9 @@ public class LoginUser implements UserDetails
*/ */
private String token; private String token;
private String requestToken;
/** /**
* 登录时间 * 登录时间
*/ */
@@ -71,6 +75,36 @@ public class LoginUser implements UserDetails
*/ */
private SysUser user; private SysUser user;
private String language;
private Long deptUserId;
private Boolean neverExpire = Boolean.FALSE;
public Boolean getNeverExpire() {
return neverExpire;
}
public void setNeverExpire(Boolean neverExpire) {
this.neverExpire = neverExpire;
}
public String getLanguage() {
return language;
}
public Long getDeptUserId() {
return deptUserId;
}
public void setDeptUserId(Long deptUserId) {
this.deptUserId = deptUserId;
}
public void setLanguage(String language) {
this.language = language;
}
public Long getUserId() public Long getUserId()
{ {
return userId; return userId;
@@ -101,6 +135,14 @@ public class LoginUser implements UserDetails
this.token = token; this.token = token;
} }
public String getRequestToken() {
return requestToken;
}
public void setRequestToken(String requestToken) {
this.requestToken = requestToken;
}
public LoginUser() public LoginUser()
{ {
} }
@@ -119,6 +161,15 @@ public class LoginUser implements UserDetails
this.permissions = permissions; this.permissions = permissions;
} }
public LoginUser(Long userId, Long deptId, String language, SysUser user, Set<String> permissions)
{
this.userId = userId;
this.deptId = deptId;
this.user = user;
this.language = language;
this.permissions = permissions;
}
@JSONField(serialize = false) @JSONField(serialize = false)
@Override @Override
public String getPassword() public String getPassword()
@@ -144,7 +195,7 @@ public class LoginUser implements UserDetails
/** /**
* 指定用户是否解锁,锁定的用户无法进行身份验证 * 指定用户是否解锁,锁定的用户无法进行身份验证
* *
* @return * @return
*/ */
@JSONField(serialize = false) @JSONField(serialize = false)
@@ -156,7 +207,7 @@ public class LoginUser implements UserDetails
/** /**
* 指示是否已过期的用户的凭据(密码),过期的凭据防止认证 * 指示是否已过期的用户的凭据(密码),过期的凭据防止认证
* *
* @return * @return
*/ */
@JSONField(serialize = false) @JSONField(serialize = false)
@@ -168,7 +219,7 @@ public class LoginUser implements UserDetails
/** /**
* 是否可用 ,禁用的用户不能身份验证 * 是否可用 ,禁用的用户不能身份验证
* *
* @return * @return
*/ */
@JSONField(serialize = false) @JSONField(serialize = false)

View File

@@ -1,4 +1,4 @@
package com.fastbee.common.mabatis.enums; package com.fastbee.common.mybatis.enums;
import com.fastbee.common.utils.StringUtils; import com.fastbee.common.utils.StringUtils;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;

View File

@@ -1,4 +1,4 @@
package com.fastbee.framework.mybatis.mapper; package com.fastbee.common.mybatis.mapper;
import com.baomidou.mybatisplus.core.conditions.Wrapper; import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
@@ -9,7 +9,7 @@ import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.toolkit.Db; import com.baomidou.mybatisplus.extension.toolkit.Db;
import com.fastbee.common.core.domain.PageParam; import com.fastbee.common.core.domain.PageParam;
import com.fastbee.common.core.domain.PageResult; import com.fastbee.common.core.domain.PageResult;
import com.fastbee.framework.mybatis.utils.MyBatisUtils; import com.fastbee.common.mybatis.utils.MyBatisUtils;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
import java.util.Collection; import java.util.Collection;

View File

@@ -1,4 +1,4 @@
package com.fastbee.framework.mybatis.utils; package com.fastbee.common.mybatis.utils;
import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.metadata.OrderItem; import com.baomidou.mybatisplus.core.metadata.OrderItem;

View File

@@ -1,14 +1,11 @@
package com.fastbee.framework.config; package com.fastbee.framework.config;
import java.nio.charset.Charset;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONReader; import com.alibaba.fastjson2.JSONReader;
import com.alibaba.fastjson2.JSONWriter; import com.alibaba.fastjson2.JSONWriter;
import com.alibaba.fastjson2.filter.Filter;
import com.fastbee.common.constant.Constants;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
import java.nio.charset.Charset;
/** /**
* Redis使用FastJson序列化 * Redis使用FastJson序列化
@@ -19,8 +16,6 @@ public class FastJson2JsonRedisSerializer<T> implements RedisSerializer<T>
{ {
public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8"); public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
static final Filter AUTO_TYPE_FILTER = JSONReader.autoTypeFilter(Constants.JSON_WHITELIST_STR);
private Class<T> clazz; private Class<T> clazz;
public FastJson2JsonRedisSerializer(Class<T> clazz) public FastJson2JsonRedisSerializer(Class<T> clazz)
@@ -48,6 +43,6 @@ public class FastJson2JsonRedisSerializer<T> implements RedisSerializer<T>
} }
String str = new String(bytes, DEFAULT_CHARSET); String str = new String(bytes, DEFAULT_CHARSET);
return JSON.parseObject(str, clazz, AUTO_TYPE_FILTER); return JSON.parseObject(str, clazz, JSONReader.Feature.SupportAutoType);
} }
} }

View File

@@ -1,7 +1,6 @@
package com.fastbee.framework.config; package com.fastbee.framework.config;
import org.springframework.cache.annotation.CachingConfigurerSupport; import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.connection.RedisConnectionFactory;
@@ -11,11 +10,10 @@ import org.springframework.data.redis.serializer.StringRedisSerializer;
/** /**
* redis配置 * redis配置
* *
* @author ruoyi * @author ruoyi
*/ */
@Configuration @Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport public class RedisConfig extends CachingConfigurerSupport
{ {
@Bean @Bean

View File

@@ -3,7 +3,7 @@ package com.fastbee.framework.mybatis.helper;
import cn.hutool.core.convert.Convert; import cn.hutool.core.convert.Convert;
import com.baomidou.dynamic.datasource.DynamicRoutingDataSource; import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import com.fastbee.common.exception.ServiceException; import com.fastbee.common.exception.ServiceException;
import com.fastbee.common.mabatis.enums.DataBaseType; import com.fastbee.common.mybatis.enums.DataBaseType;
import com.fastbee.common.utils.spring.SpringUtils; import com.fastbee.common.utils.spring.SpringUtils;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;

View File

@@ -2,6 +2,7 @@ package com.fastbee.framework.web.service;
import com.fastbee.common.constant.CacheConstants; import com.fastbee.common.constant.CacheConstants;
import com.fastbee.common.constant.Constants; import com.fastbee.common.constant.Constants;
import com.fastbee.common.core.domain.entity.SysUser;
import com.fastbee.common.core.domain.model.LoginUser; import com.fastbee.common.core.domain.model.LoginUser;
import com.fastbee.common.core.redis.RedisCache; import com.fastbee.common.core.redis.RedisCache;
import com.fastbee.common.utils.ServletUtils; import com.fastbee.common.utils.ServletUtils;
@@ -9,27 +10,33 @@ import com.fastbee.common.utils.StringUtils;
import com.fastbee.common.utils.ip.AddressUtils; import com.fastbee.common.utils.ip.AddressUtils;
import com.fastbee.common.utils.ip.IpUtils; import com.fastbee.common.utils.ip.IpUtils;
import com.fastbee.common.utils.uuid.IdUtils; import com.fastbee.common.utils.uuid.IdUtils;
import com.fastbee.system.domain.SysClient;
import com.fastbee.system.service.ISysClientService;
import eu.bitwalker.useragentutils.UserAgent; import eu.bitwalker.useragentutils.UserAgent;
import io.jsonwebtoken.Claims; import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts; import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm; import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
/** /**
* token验证处理 * token验证处理
* *
* @author ruoyi * @author ruoyi
*/ */
@Slf4j
@Component @Component
public class TokenService public class TokenService {
{
// 令牌自定义标识 // 令牌自定义标识
@Value("${token.header}") @Value("${token.header}")
private String header; private String header;
@@ -51,34 +58,37 @@ public class TokenService
@Autowired @Autowired
private RedisCache redisCache; private RedisCache redisCache;
@Autowired
private ISysClientService sysClientService;
@Autowired
private UserDetailsServiceImpl userDetailsServiceImpl;
/** /**
* 获取用户身份信息 * 获取用户身份信息
* *
* @return 用户信息 * @return 用户信息
*/ */
public LoginUser getLoginUser(HttpServletRequest request) public LoginUser getLoginUser(HttpServletRequest request) {
{
// 获取请求携带的令牌 // 获取请求携带的令牌
String token = getToken(request); String token = getToken(request);
if (StringUtils.isNotEmpty(token)) if (StringUtils.isNotEmpty(token)) {
{ try {
try
{
Claims claims = parseToken(token); Claims claims = parseToken(token);
// 解析对应的权限以及用户信息 // 解析对应的权限以及用户信息
String uuid = (String) claims.get(Constants.LOGIN_USER_KEY); String uuid = (String) claims.get(Constants.LOGIN_USER_KEY);
String userKey = getTokenKey(uuid); String userKey = getTokenKey(uuid);
LoginUser user = redisCache.getCacheObject(userKey); LoginUser user = redisCache.getCacheObject(userKey);
user.setRequestToken(token);
return user; return user;
} } catch (Exception e) {
catch (Exception e) log.info("获取缓存报错:{}", e.getMessage());
{
} }
} }
return null; return null;
} }
/** /**
* 获取用户身份信息 * 获取用户身份信息
* *
* @return 用户信息 * @return 用户信息
@@ -93,6 +103,7 @@ public class TokenService
LoginUser user = redisCache.getCacheObject(userKey); LoginUser user = redisCache.getCacheObject(userKey);
return user; return user;
} catch (Exception e) { } catch (Exception e) {
log.info("获取缓存报错:{}", e.getMessage());
} }
} }
return null; return null;
@@ -101,6 +112,7 @@ public class TokenService
/** /**
* 根据用户id获取用户身份信息 * 根据用户id获取用户身份信息
* 由于多端登录根据token获取的用户信息不一样所以增加一个根据用户id获取用户信息的缓存key以后多端需要获取用户最新信息就用这个方法吧 * 由于多端登录根据token获取的用户信息不一样所以增加一个根据用户id获取用户信息的缓存key以后多端需要获取用户最新信息就用这个方法吧
*
* @return 用户信息 * @return 用户信息
*/ */
public LoginUser getLoginUserByUserId(Long userId) { public LoginUser getLoginUserByUserId(Long userId) {
@@ -109,6 +121,7 @@ public class TokenService
String userKey = getUserIdKey(userId); String userKey = getUserIdKey(userId);
return redisCache.getCacheObject(userKey); return redisCache.getCacheObject(userKey);
} catch (Exception e) { } catch (Exception e) {
log.info("获取缓存报错:{}", e.getMessage());
} }
} }
return null; return null;
@@ -117,10 +130,8 @@ public class TokenService
/** /**
* 设置用户身份信息 * 设置用户身份信息
*/ */
public void setLoginUser(LoginUser loginUser) public void setLoginUser(LoginUser loginUser) {
{ if (StringUtils.isNotNull(loginUser) && StringUtils.isNotEmpty(loginUser.getToken())) {
if (StringUtils.isNotNull(loginUser) && StringUtils.isNotEmpty(loginUser.getToken()))
{
refreshToken(loginUser); refreshToken(loginUser);
} }
} }
@@ -128,10 +139,8 @@ public class TokenService
/** /**
* 删除用户身份信息 * 删除用户身份信息
*/ */
public void delLoginUser(String token) public void delLoginUser(String token) {
{ if (StringUtils.isNotEmpty(token)) {
if (StringUtils.isNotEmpty(token))
{
String userKey = getTokenKey(token); String userKey = getTokenKey(token);
redisCache.deleteObject(userKey); redisCache.deleteObject(userKey);
} }
@@ -143,8 +152,7 @@ public class TokenService
* @param loginUser 用户信息 * @param loginUser 用户信息
* @return 令牌 * @return 令牌
*/ */
public String createToken(LoginUser loginUser) public String createToken(LoginUser loginUser) {
{
String token = IdUtils.fastUUID(); String token = IdUtils.fastUUID();
loginUser.setToken(token); loginUser.setToken(token);
setUserAgent(loginUser); setUserAgent(loginUser);
@@ -155,18 +163,61 @@ public class TokenService
return createToken(claims); return createToken(claims);
} }
public int addToken(SysUser user, SysClient sysClient) {
UserDetails userDetails = userDetailsServiceImpl.createLoginUser(user);
LoginUser loginUser = (LoginUser) userDetails;
sysClient.setToken(Constants.TOKEN_PREFIX + createToken(loginUser, sysClient.getClientSecret(), Math.toIntExact(sysClient.getTimeout())));
return sysClientService.insertSysClient(sysClient);
}
public int updateToken(SysUser loginuser, SysClient sysClient) {
LoginUser user;
Claims claims = parseToken(sysClient);
if (claims == null) {
UserDetails userDetails = userDetailsServiceImpl.createLoginUser(loginuser);
user = (LoginUser) userDetails;
sysClient.setToken(Constants.TOKEN_PREFIX + createToken(user, sysClient.getClientSecret(), Math.toIntExact(sysClient.getTimeout())));
} else {
// 解析对应的权限以及用户信息
String uuid = (String) claims.get(Constants.LOGIN_USER_KEY);
String userKey = getTokenKey(uuid);
user = redisCache.getCacheObject(userKey);
if (user == null) {
UserDetails userDetails = userDetailsServiceImpl.createLoginUser(loginuser);
user = (LoginUser) userDetails;
}
log.debug("loginUser:{}", user);
if (sysClient.getEnable() != null && "1".equals(sysClient.getEnable())) {
delLoginUser(uuid);
sysClient.setToken(Constants.TOKEN_PREFIX + createToken(user, sysClient.getClientSecret(), Math.toIntExact(sysClient.getTimeout())));
} else if ("0".equals(sysClient.getEnable())) {
delLoginUser(uuid);
}
}
return sysClientService.updateSysClient(sysClient);
}
public String createToken(LoginUser loginUser, String secret, int expireTime) {
String token = IdUtils.fastUUID();
loginUser.setToken(token);
setUserAgent(loginUser);
refreshToken(loginUser, expireTime);
Map<String, Object> claims = new HashMap<>();
claims.put(Constants.LOGIN_USER_KEY, token);
return createToken(claims, secret);
}
/** /**
* 验证令牌有效期相差不足20分钟自动刷新缓存 * 验证令牌有效期相差不足20分钟自动刷新缓存
* *
* @param loginUser * @param loginUser
* @return 令牌 * @return 令牌
*/ */
public void verifyToken(LoginUser loginUser) public void verifyToken(LoginUser loginUser) {
{
long expireTime = loginUser.getExpireTime(); long expireTime = loginUser.getExpireTime();
long currentTime = System.currentTimeMillis(); long currentTime = System.currentTimeMillis();
if (expireTime - currentTime <= MILLIS_MINUTE_TEN) if (expireTime - currentTime <= MILLIS_MINUTE_TEN) {
{
refreshToken(loginUser); refreshToken(loginUser);
} }
} }
@@ -176,8 +227,7 @@ public class TokenService
* *
* @param loginUser 登录信息 * @param loginUser 登录信息
*/ */
public void refreshToken(LoginUser loginUser) public void refreshToken(LoginUser loginUser, int expireTime) {
{
loginUser.setLoginTime(System.currentTimeMillis()); loginUser.setLoginTime(System.currentTimeMillis());
loginUser.setExpireTime(loginUser.getLoginTime() + expireTime * MILLIS_MINUTE); loginUser.setExpireTime(loginUser.getLoginTime() + expireTime * MILLIS_MINUTE);
// 根据uuid将loginUser缓存 // 根据uuid将loginUser缓存
@@ -188,13 +238,29 @@ public class TokenService
redisCache.setCacheObject(userIdKey, loginUser, expireTime, TimeUnit.MINUTES); redisCache.setCacheObject(userIdKey, loginUser, expireTime, TimeUnit.MINUTES);
} }
public void refreshToken(LoginUser loginUser) {
loginUser.setLoginTime(System.currentTimeMillis());
loginUser.setExpireTime(loginUser.getLoginTime() + expireTime * MILLIS_MINUTE);
// 根据uuid将loginUser缓存
String userKey = getTokenKey(loginUser.getToken());
String userIdKey = getUserIdKey(loginUser.getUserId());
if (Boolean.TRUE.equals(loginUser.getNeverExpire())) {
redisCache.setCacheObject(userKey, loginUser);
// 使用token作为用户信息缓存key多端不能同步最新信息需要重新登录因此添加一个使用用户id作为缓存key
redisCache.setCacheObject(userIdKey, loginUser);
} else {
redisCache.setCacheObject(userKey, loginUser, expireTime, TimeUnit.MINUTES);
// 使用token作为用户信息缓存key多端不能同步最新信息需要重新登录因此添加一个使用用户id作为缓存key
redisCache.setCacheObject(userIdKey, loginUser, expireTime, TimeUnit.MINUTES);
}
}
/** /**
* 设置用户代理信息 * 设置用户代理信息
* *
* @param loginUser 登录信息 * @param loginUser 登录信息
*/ */
public void setUserAgent(LoginUser loginUser) public void setUserAgent(LoginUser loginUser) {
{
UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent")); UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent"));
String ip = IpUtils.getIpAddr(ServletUtils.getRequest()); String ip = IpUtils.getIpAddr(ServletUtils.getRequest());
loginUser.setIpaddr(ip); loginUser.setIpaddr(ip);
@@ -209,8 +275,14 @@ public class TokenService
* @param claims 数据声明 * @param claims 数据声明
* @return 令牌 * @return 令牌
*/ */
private String createToken(Map<String, Object> claims) private String createToken(Map<String, Object> claims) {
{ String token = Jwts.builder()
.setClaims(claims)
.signWith(SignatureAlgorithm.HS512, secret).compact();
return token;
}
private String createToken(Map<String, Object> claims, String secret) {
String token = Jwts.builder() String token = Jwts.builder()
.setClaims(claims) .setClaims(claims)
.signWith(SignatureAlgorithm.HS512, secret).compact(); .signWith(SignatureAlgorithm.HS512, secret).compact();
@@ -223,12 +295,23 @@ public class TokenService
* @param token 令牌 * @param token 令牌
* @return 数据声明 * @return 数据声明
*/ */
private Claims parseToken(String token) private Claims parseToken(String token) {
{
return Jwts.parser() return Jwts.parser()
.setSigningKey(secret) .setSigningKey(secret)
.parseClaimsJws(token) .parseClaimsJws(token)
.getBody(); .getBody();
}
private Claims parseToken(SysClient sysClient) {
if (sysClient.getClientSecret() != null && !Objects.equals(sysClient.getToken(), "")) {
return Jwts.parser()
.setSigningKey(sysClient.getClientSecret())
.parseClaimsJws(sysClient.getToken().substring(Constants.TOKEN_PREFIX.length()))
.getBody();
} else {
return null;
}
} }
/** /**
@@ -237,8 +320,7 @@ public class TokenService
* @param token 令牌 * @param token 令牌
* @return 用户名 * @return 用户名
*/ */
public String getUsernameFromToken(String token) public String getUsernameFromToken(String token) {
{
Claims claims = parseToken(token); Claims claims = parseToken(token);
return claims.getSubject(); return claims.getSubject();
} }
@@ -249,18 +331,15 @@ public class TokenService
* @param request * @param request
* @return token * @return token
*/ */
private String getToken(HttpServletRequest request) private String getToken(HttpServletRequest request) {
{
String token = request.getHeader(header); String token = request.getHeader(header);
if (StringUtils.isNotEmpty(token) && token.startsWith(Constants.TOKEN_PREFIX)) if (StringUtils.isNotEmpty(token) && token.startsWith(Constants.TOKEN_PREFIX)) {
{
token = token.replace(Constants.TOKEN_PREFIX, ""); token = token.replace(Constants.TOKEN_PREFIX, "");
} }
return token; return token;
} }
private String getTokenKey(String uuid) private String getTokenKey(String uuid) {
{
return CacheConstants.LOGIN_TOKEN_KEY + uuid; return CacheConstants.LOGIN_TOKEN_KEY + uuid;
} }

View File

@@ -29,6 +29,11 @@
<version>${dynamic-datasource.version}</version> <version>${dynamic-datasource.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@@ -0,0 +1,76 @@
package com.fastbee.system.convert;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fastbee.system.domain.SysClient;
import com.fastbee.system.domain.vo.SysClientVO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.List;
/**
* 系统授权Convert转换类
*
* @author zhuangpeng.li
* @date 2024-12-12
*/
@Mapper
public interface SysClientConvert
{
/** 代码生成区域 可直接覆盖**/
SysClientConvert INSTANCE = Mappers.getMapper(SysClientConvert.class);
/**
* 实体类转换为VO类
*
* @param sysClient
* @return 系统授权集合
*/
SysClientVO convertSysClientVO(SysClient sysClient);
/**
* VO类转换为实体类集合
*
* @param sysClientVO
* @return 系统授权集合
*/
SysClient convertSysClient(SysClientVO sysClientVO);
/**
* 实体类转换为VO类集合
*
* @param sysClientList
* @return 系统授权集合
*/
List<SysClientVO> convertSysClientVOList(List<SysClient> sysClientList);
/**
* VO类转换为实体类
*
* @param sysClientVOList
* @return 系统授权集合
*/
List<SysClient> convertSysClientList(List<SysClientVO> sysClientVOList);
/**
* 实体类转换为VO类分页
*
* @param sysClientPage
* @return 系统授权分页
*/
Page<SysClientVO> convertSysClientVOPage(Page<SysClient> sysClientPage);
/**
* VO类转换为实体类
*
* @param sysClientVOPage
* @return 系统授权分页
*/
Page<SysClient> convertSysClientPage(Page<SysClientVO> sysClientVOPage);
/** 代码生成区域 可直接覆盖END**/
/** 自定义代码区域 **/
/** 自定义代码区域 END**/
}

View File

@@ -0,0 +1,64 @@
package com.fastbee.system.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fastbee.common.core.domain.BaseEntity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 系统授权对象 sys_client
*
* @author zhuangpeng.li
* @date 2024-12-12
*/
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "SysClient", description = "系统授权 sys_client")
@Data
@TableName("sys_client" )
public class SysClient extends BaseEntity {
private static final long serialVersionUID=1L;
/** id唯一标识 */
@TableId(value = "id", type = IdType.AUTO)
@ApiModelProperty("id唯一标识")
private Long id;
/** 客户端key */
@ApiModelProperty("客户端key")
private String clientKey;
/** 客户端秘钥 */
@ApiModelProperty("客户端秘钥")
private String clientSecret;
/** 客户端token */
@ApiModelProperty("客户端token")
private String token;
/** 授权类型 */
@ApiModelProperty("授权类型")
private String grantType;
/** 设备类型 */
@ApiModelProperty("设备类型")
private String deviceType;
/** token固定超时 */
@ApiModelProperty("token固定超时")
private Long timeout;
/** 是否生效0-不生效1-生效) */
@ApiModelProperty("是否生效")
private String enable;
/** 删除标志0代表存在 2代表删除 */
@ApiModelProperty("删除标志")
@TableLogic
private String delFlag;
}

View File

@@ -0,0 +1,105 @@
package com.fastbee.system.domain.vo;
import com.fastbee.common.annotation.Excel;
import com.fastbee.common.core.domain.PageEntity;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.Date;
/**
* 系统授权对象 sys_client
*
* @author zhuangpeng.li
* @date 2024-12-12
*/
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "SysClientVO", description = "系统授权 sys_client")
@Data
public class SysClientVO extends PageEntity {
/** 代码生成区域 可直接覆盖**/
/** id唯一标识 */
@Excel(name = "id唯一标识")
@ApiModelProperty("id唯一标识")
private Long id;
/** 客户端key */
@Excel(name = "客户端key")
@ApiModelProperty("客户端key")
private String clientKey;
/** 客户端秘钥 */
@Excel(name = "客户端秘钥")
@ApiModelProperty("客户端秘钥")
private String clientSecret;
/** 客户端token */
@Excel(name = "客户端token")
@ApiModelProperty("客户端token")
private String token;
/** 授权类型 */
@Excel(name = "授权类型")
@ApiModelProperty("授权类型")
private String grantType;
/** 设备类型 */
@Excel(name = "设备类型")
@ApiModelProperty("设备类型")
private String deviceType;
/** token固定超时 */
@Excel(name = "token固定超时")
@ApiModelProperty("token固定超时")
private Long timeout;
/** 是否生效0-不生效1-生效) */
@ApiModelProperty("是否生效")
@Excel(name = "是否生效")
private String enable;
/** 删除标志0代表存在 2代表删除 */
@ApiModelProperty("删除标志")
@Excel(name = "删除标志")
private String delFlag;
/** 创建者 */
@Excel(name = "创建者")
@ApiModelProperty("创建者")
private String createBy;
/** 创建时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@ApiModelProperty("创建时间")
@Excel(name = "创建时间")
private Date createTime;
/** 更新者 */
@Excel(name = "更新者")
@ApiModelProperty("更新者")
private String updateBy;
/** 更新时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@ApiModelProperty("更新时间")
@Excel(name = "更新时间")
private Date updateTime;
/** 备注 */
@Excel(name = "备注")
@ApiModelProperty("备注")
private String remark;
/** 代码生成区域 可直接覆盖END**/
/** 自定义代码区域 **/
/** 自定义代码区域 END**/
}

View File

@@ -0,0 +1,49 @@
package com.fastbee.system.mapper;
import com.fastbee.common.mybatis.mapper.BaseMapperX;
import com.fastbee.system.domain.SysClient;
import java.util.List;
/**
* 系统授权Mapper接口
*
* @author zhuangpeng.li
* @date 2024-07-26
*/
public interface SysClientMapper extends BaseMapperX<SysClient>
{
/**
* 查询系统授权
*
* @param id 系统授权主键
* @return 系统授权
*/
public SysClient selectSysClientById(Long id);
/**
* 查询系统授权列表
*
* @param sysClient 系统授权
* @return 系统授权集合
*/
public List<SysClient> selectSysClientList(SysClient sysClient);
/**
* 新增系统授权
*
* @param sysClient 系统授权
* @return 结果
*/
public int insertSysClient(SysClient sysClient);
/**
* 修改系统授权
*
* @param sysClient 系统授权
* @return 结果
*/
public int updateSysClient(SysClient sysClient);
}

View File

@@ -0,0 +1,73 @@
package com.fastbee.system.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.fastbee.system.domain.SysClient;
import com.fastbee.system.domain.vo.SysClientVO;
import java.util.List;
/**
* 系统授权Service接口
*
* @author zhuangpeng.li
* @date 2024-07-26
*/
public interface ISysClientService extends IService<SysClient>
{
/**
* 查询系统授权
*
* @param id 系统授权主键
* @return 系统授权
*/
public SysClient selectSysClientById(Long id);
/**
* 查询系统授权列表
*
* @param sysClient 系统授权
* @return 系统授权集合
*/
public List<SysClientVO> selectSysClientList(SysClient sysClient);
/**
* 查询系统授权列表
*
* @param sysClient 系统授权
* @return 系统授权分页集合
*/
Page<SysClientVO> pageSysClientVO(SysClient sysClient);
/**
* 新增系统授权
*
* @param sysClient 系统授权
* @return 结果
*/
public int insertSysClient(SysClient sysClient);
/**
* 修改系统授权
*
* @param sysClient 系统授权
* @return 结果
*/
public int updateSysClient(SysClient sysClient);
/**
* 批量删除系统授权
*
* @param ids 需要删除的系统授权主键集合
* @return 结果
*/
public int deleteSysClientByIds(Long[] ids);
/**
* 删除系统授权信息
*
* @param id 系统授权主键
* @return 结果
*/
public int deleteSysClientById(Long id);
}

View File

@@ -0,0 +1,147 @@
package com.fastbee.system.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fastbee.common.utils.DateUtils;
import com.fastbee.common.utils.StringUtils;
import com.fastbee.system.convert.SysClientConvert;
import com.fastbee.system.domain.SysClient;
import com.fastbee.system.domain.vo.SysClientVO;
import com.fastbee.system.mapper.SysClientMapper;
import com.fastbee.system.service.ISysClientService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
* 系统授权Service业务层处理
*
* @author zhuangpeng.li
* @date 2024-07-26
*/
@Service
public class SysClientServiceImpl extends ServiceImpl<SysClientMapper,SysClient> implements ISysClientService
{
@Resource
private SysClientMapper sysClientMapper;
/**
* 查询系统授权
*
* @param id 系统授权主键
* @return 系统授权
*/
@Override
public SysClient selectSysClientById(Long id)
{
return sysClientMapper.selectById(id);
}
/**
* 查询系统授权列表
*
* @param sysClient 系统授权
* @return 系统授权
*/
@Override
public List<SysClientVO> selectSysClientList(SysClient sysClient)
{
LambdaQueryWrapper<SysClient> lqw = buildQueryWrapper(sysClient);
List<SysClient> sysClientList = baseMapper.selectList(lqw);
return SysClientConvert.INSTANCE.convertSysClientVOList(sysClientList);
}
/**
* 查询系统授权分页列表
*
* @param sysClient 系统授权
* @return 系统授权
*/
@Override
public Page<SysClientVO> pageSysClientVO(SysClient sysClient) {
LambdaQueryWrapper<SysClient> lqw = buildQueryWrapper(sysClient);
Page<SysClient> sysClientPage = baseMapper.selectPage(new Page<>(sysClient.getPageNum(), sysClient.getPageSize()), lqw);
return SysClientConvert.INSTANCE.convertSysClientVOPage(sysClientPage);
}
private LambdaQueryWrapper<SysClient> buildQueryWrapper(SysClient query) {
Map<String, Object> params = query.getParams();
LambdaQueryWrapper<SysClient> lqw = Wrappers.lambdaQuery();
lqw.eq(query.getId() != null, SysClient::getId, query.getId());
lqw.eq(StringUtils.isNotBlank(query.getClientKey()), SysClient::getClientKey, query.getClientKey());
lqw.eq(StringUtils.isNotBlank(query.getClientSecret()), SysClient::getClientSecret, query.getClientSecret());
lqw.eq(StringUtils.isNotBlank(query.getToken()), SysClient::getToken, query.getToken());
lqw.eq(StringUtils.isNotBlank(query.getGrantType()), SysClient::getGrantType, query.getGrantType());
lqw.eq(StringUtils.isNotBlank(query.getDeviceType()), SysClient::getDeviceType, query.getDeviceType());
lqw.eq(query.getTimeout() != null, SysClient::getTimeout, query.getTimeout());
lqw.eq(StringUtils.isNotBlank(query.getEnable()), SysClient::getEnable, query.getEnable());
lqw.eq(StringUtils.isNotBlank(query.getDelFlag()), SysClient::getDelFlag, query.getDelFlag());
lqw.eq(StringUtils.isNotBlank(query.getCreateBy()), SysClient::getCreateBy, query.getCreateBy());
lqw.eq(query.getCreateTime() != null, SysClient::getCreateTime, query.getCreateTime());
lqw.eq(StringUtils.isNotBlank(query.getUpdateBy()), SysClient::getUpdateBy, query.getUpdateBy());
lqw.eq(query.getUpdateTime() != null, SysClient::getUpdateTime, query.getUpdateTime());
lqw.eq(StringUtils.isNotBlank(query.getRemark()), SysClient::getRemark, query.getRemark());
if (!Objects.isNull(params.get("beginTime")) &&
!Objects.isNull(params.get("endTime"))) {
lqw.between(SysClient::getCreateTime, params.get("beginTime"), params.get("endTime"));
}
return lqw;
}
/**
* 新增系统授权
*
* @param sysClient 系统授权
* @return 结果
*/
@Override
public int insertSysClient(SysClient sysClient)
{
sysClient.setCreateTime(DateUtils.getNowDate());
return sysClientMapper.insert(sysClient);
}
/**
* 修改系统授权
*
* @param sysClient 系统授权
* @return 结果
*/
@Override
public int updateSysClient(SysClient sysClient)
{
sysClient.setUpdateTime(DateUtils.getNowDate());
return sysClientMapper.updateById(sysClient);
}
/**
* 批量删除系统授权
*
* @param ids 需要删除的系统授权主键
* @return 结果
*/
@Override
public int deleteSysClientByIds(Long[] ids)
{
return sysClientMapper.deleteBatchIds(Arrays.asList(ids));
}
/**
* 删除系统授权信息
*
* @param id 系统授权主键
* @return 结果
*/
@Override
public int deleteSysClientById(Long id)
{
return sysClientMapper.deleteById(id);
}
}

View File

@@ -0,0 +1,101 @@
<?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.fastbee.system.mapper.SysClientMapper">
<resultMap type="SysClient" id="SysClientResult">
<result property="id" column="id" />
<result property="clientKey" column="client_key" />
<result property="clientSecret" column="client_secret" />
<result property="token" column="token" />
<result property="grantType" column="grant_type" />
<result property="deviceType" column="device_type" />
<result property="timeout" column="timeout" />
<result property="enable" column="enable" />
<result property="delFlag" column="del_flag" />
<result property="createBy" column="create_by" />
<result property="createTime" column="create_time" />
<result property="updateBy" column="update_by" />
<result property="updateTime" column="update_time" />
<result property="remark" column="remark" />
</resultMap>
<sql id="selectSysClientVo">
select id, client_key, client_secret, token, grant_type, device_type, timeout, enable, del_flag, create_by, create_time, update_by, update_time, remark from sys_client
</sql>
<select id="selectSysClientList" parameterType="SysClient" resultMap="SysClientResult">
<include refid="selectSysClientVo"/>
<where>
<if test="clientKey != null and clientKey != ''"> and client_key = #{clientKey}</if>
<if test="clientSecret != null and clientSecret != ''"> and client_secret = #{clientSecret}</if>
<if test="token != null and token != ''"> and token = #{token}</if>
<if test="grantType != null and grantType != ''"> and grant_type = #{grantType}</if>
<if test="deviceType != null and deviceType != ''"> and device_type = #{deviceType}</if>
<if test="timeout != null "> and timeout = #{timeout}</if>
<if test="enable != null and enable != ''"> and enable = #{enable}</if>
and del_flag = '0'
</where>
</select>
<select id="selectSysClientById" parameterType="Long" resultMap="SysClientResult">
<include refid="selectSysClientVo"/>
where id = #{id} and del_flag = '0'
</select>
<insert id="insertSysClient" parameterType="SysClient" useGeneratedKeys="true" keyProperty="id">
insert into sys_client
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="clientKey != null">client_key,</if>
<if test="clientSecret != null">client_secret,</if>
<if test="token != null">token,</if>
<if test="grantType != null">grant_type,</if>
<if test="deviceType != null">device_type,</if>
<if test="timeout != null">timeout,</if>
<if test="enable != null">enable,</if>
<if test="delFlag != null">del_flag,</if>
<if test="createBy != null">create_by,</if>
<if test="createTime != null">create_time,</if>
<if test="updateBy != null">update_by,</if>
<if test="updateTime != null">update_time,</if>
<if test="remark != null">remark,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="clientKey != null">#{clientKey},</if>
<if test="clientSecret != null">#{clientSecret},</if>
<if test="token != null">#{token},</if>
<if test="grantType != null">#{grantType},</if>
<if test="deviceType != null">#{deviceType},</if>
<if test="timeout != null">#{timeout},</if>
<if test="enable != null">#{enable},</if>
<if test="delFlag != null">#{delFlag},</if>
<if test="createBy != null">#{createBy},</if>
<if test="createTime != null">#{createTime},</if>
<if test="updateBy != null">#{updateBy},</if>
<if test="updateTime != null">#{updateTime},</if>
<if test="remark != null">#{remark},</if>
</trim>
</insert>
<update id="updateSysClient" parameterType="SysClient">
update sys_client
<trim prefix="SET" suffixOverrides=",">
<if test="clientKey != null">client_key = #{clientKey},</if>
<if test="clientSecret != null">client_secret = #{clientSecret},</if>
<if test="token != null">token = #{token},</if>
<if test="grantType != null">grant_type = #{grantType},</if>
<if test="deviceType != null">device_type = #{deviceType},</if>
<if test="timeout != null">timeout = #{timeout},</if>
<if test="enable != null">enable = #{enable},</if>
<if test="delFlag != null">del_flag = #{delFlag},</if>
<if test="createBy != null">create_by = #{createBy},</if>
<if test="createTime != null">create_time = #{createTime},</if>
<if test="updateBy != null">update_by = #{updateBy},</if>
<if test="updateTime != null">update_time = #{updateTime},</if>
<if test="remark != null">remark = #{remark},</if>
</trim>
where id = #{id}
</update>
</mapper>