权限验证 + 用户/角色/菜单 增删改查

v1.4.1
Parker 4 years ago
parent dddb0b322e
commit 29919cadc3

@ -139,8 +139,8 @@ public class ResultVo<T> implements Serializable {
* @return ResultVo<Object>
*/
@JsonIgnore//返回对象时忽略此属性
public static ResultVo<Object> error(String msg) {
ResultVo<Object> ret = new ResultVo<>();
public static <T> ResultVo<T> error(String msg) {
ResultVo<T> ret = new ResultVo<>();
ret.setMsg(msg);
ret.setCode(HttpStatus.INTERNAL_SERVER_ERROR.value());
ret.setSuccess(false);
@ -154,8 +154,8 @@ public class ResultVo<T> implements Serializable {
* @return ResultVo<T>
*/
@JsonIgnore//返回对象时忽略此属性
public static ResultVo<Object> error(int code, String msg) {
ResultVo<Object> ret = new ResultVo<>();
public static <T> ResultVo<T> error(int code, String msg) {
ResultVo<T> ret = new ResultVo<>();
ret.setMsg(msg);
ret.setCode(code);
ret.setSuccess(false);

@ -3,6 +3,7 @@ package org.opsli.api.base.warpper;
import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.*;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.Version;
import com.fasterxml.jackson.annotation.JsonFormat;
@ -90,4 +91,7 @@ public abstract class ApiWrapper implements Serializable {
@Version
private Integer version;
/** 是否是内部Api调用 */
@TableField(exist = false)
private Boolean izApi = false;
}

@ -6,7 +6,7 @@ import io.swagger.annotations.ApiModelProperty;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.opsli.api.msg.ValidationMsg;
import org.opsli.api.wrapper.system.dict.SysDictModel;
import org.opsli.api.wrapper.system.dict.DictModel;
import org.opsli.common.annotation.validation.ValidationArgs;
import org.opsli.common.annotation.validation.ValidationArgsMax;
import org.opsli.common.annotation.validation.ValidationArgsMin;
@ -334,13 +334,13 @@ public final class ValidationUtil {
}
public static void main(String[] args) {
SysDictModel sysDictModel = new SysDictModel();
sysDictModel.setTypeCode("asdsa");
sysDictModel.setTypeName("阿哈哈哈哈");
sysDictModel.setRemark("测试11232131231231223123");
sysDictModel.setIzLock('1');
DictModel dictModel = new DictModel();
dictModel.setTypeCode("asdsa");
dictModel.setTypeName("阿哈哈哈哈");
dictModel.setRemark("测试11232131231231223123");
dictModel.setIzLock('1');
ValidationUtil.verify(sysDictModel);
ValidationUtil.verify(dictModel);
}

@ -1,7 +1,7 @@
package org.opsli.api.web.system.dict;
import org.opsli.api.base.result.ResultVo;
import org.opsli.api.wrapper.system.dict.SysDictModel;
import org.opsli.api.wrapper.system.dict.DictModel;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
@ -36,7 +36,7 @@ public interface DictApi {
* @return ResultVo
*/
@GetMapping("/get")
ResultVo<SysDictModel> get(SysDictModel model);
ResultVo<DictModel> get(DictModel model);
/**
*
@ -58,7 +58,7 @@ public interface DictApi {
* @return ResultVo
*/
@PostMapping("/insert")
ResultVo<?> insert(SysDictModel model);
ResultVo<?> insert(DictModel model);
/**
*
@ -66,7 +66,7 @@ public interface DictApi {
* @return ResultVo
*/
@PostMapping("/update")
ResultVo<?> update(SysDictModel model);
ResultVo<?> update(DictModel model);
/**
*

@ -1,7 +1,7 @@
package org.opsli.api.web.system.dict;
import org.opsli.api.base.result.ResultVo;
import org.opsli.api.wrapper.system.dict.SysDictDetailModel;
import org.opsli.api.wrapper.system.dict.DictDetailModel;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
@ -28,7 +28,6 @@ import java.util.List;
*/
public interface DictDetailApi {
/** 标题 */
String TITLE = "数据字典明细";
/**
@ -37,7 +36,7 @@ public interface DictDetailApi {
* @return ResultVo
*/
@GetMapping("/get")
ResultVo<SysDictDetailModel> get(SysDictDetailModel model);
ResultVo<DictDetailModel> get(DictDetailModel model);
/**
*
@ -59,7 +58,7 @@ public interface DictDetailApi {
* @return ResultVo
*/
@PostMapping("/insert")
ResultVo<?> insert(SysDictDetailModel model);
ResultVo<?> insert(DictDetailModel model);
/**
*
@ -67,7 +66,7 @@ public interface DictDetailApi {
* @return ResultVo
*/
@PostMapping("/update")
ResultVo<?> update(SysDictDetailModel model);
ResultVo<?> update(DictDetailModel model);
/**
*
@ -120,6 +119,6 @@ public interface DictDetailApi {
* @return
*/
@GetMapping("/findListByTypeCode")
ResultVo<List<SysDictDetailModel>> findListByTypeCode(String typeCode);
ResultVo<List<DictDetailModel>> findListByTypeCode(String typeCode);
}

@ -0,0 +1,113 @@
package org.opsli.api.web.system.menu;
import org.opsli.api.base.result.ResultVo;
import org.opsli.api.wrapper.system.menu.MenuModel;
import org.opsli.api.wrapper.system.user.UserModel;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @BelongsProject: opsli-boot
* @BelongsPackage: org.opsli.modulars.test.web
* @Author: Parker
* @CreateTime: 2020-09-13 17:40
* @Description: API
*
* API @GetMapping @PostMapping
* Mapping Controller
*
*
*
*
*/
public interface MenuApi {
/** 标题 */
String TITLE = "菜单";
/**
*
* @param model
* @return ResultVo
*/
@GetMapping("/get")
ResultVo<MenuModel> get(MenuModel model);
/**
*
* @param pageNo
* @param pageSize
* @param request request
* @return ResultVo
*/
@GetMapping("/findPage")
ResultVo<?> findPage(
@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
HttpServletRequest request
);
/**
*
* @param model
* @return ResultVo
*/
@PostMapping("/insert")
ResultVo<?> insert(MenuModel model);
/**
*
* @param model
* @return ResultVo
*/
@PostMapping("/update")
ResultVo<?> update(MenuModel model);
/**
*
* @param id ID
* @return ResultVo
*/
@PostMapping("/del")
ResultVo<?> del(String id);
/**
*
* @param ids ID
* @return ResultVo
*/
@PostMapping("/delAll")
ResultVo<?> delAll(String[] ids);
/**
* Excel
* @param request request
* @param response response
* @return ResultVo
*/
@GetMapping("/exportExcel")
ResultVo<?> exportExcel(HttpServletRequest request, HttpServletResponse response);
/**
* Excel
* @param request request
* @return ResultVo
*/
@GetMapping("/exportImport")
ResultVo<?> excelImport(MultipartHttpServletRequest request);
/**
* Excel
* @param response response
* @return ResultVo
*/
@GetMapping("/exportImport/template")
ResultVo<?> importTemplate(HttpServletResponse response);
}

@ -0,0 +1,112 @@
package org.opsli.api.web.system.role;
import org.opsli.api.base.result.ResultVo;
import org.opsli.api.wrapper.system.role.RoleModel;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @BelongsProject: opsli-boot
* @BelongsPackage: org.opsli.modulars.test.web
* @Author: Parker
* @CreateTime: 2020-09-13 17:40
* @Description: API
*
* API @GetMapping @PostMapping
* Mapping Controller
*
*
*
*
*/
public interface RoleApi {
/** 标题 */
String TITLE = "角色";
/**
*
* @param model
* @return ResultVo
*/
@GetMapping("/get")
ResultVo<RoleModel> get(RoleModel model);
/**
*
* @param pageNo
* @param pageSize
* @param request request
* @return ResultVo
*/
@GetMapping("/findPage")
ResultVo<?> findPage(
@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
HttpServletRequest request
);
/**
*
* @param model
* @return ResultVo
*/
@PostMapping("/insert")
ResultVo<?> insert(RoleModel model);
/**
*
* @param model
* @return ResultVo
*/
@PostMapping("/update")
ResultVo<?> update(RoleModel model);
/**
*
* @param id ID
* @return ResultVo
*/
@PostMapping("/del")
ResultVo<?> del(String id);
/**
*
* @param ids ID
* @return ResultVo
*/
@PostMapping("/delAll")
ResultVo<?> delAll(String[] ids);
/**
* Excel
* @param request request
* @param response response
* @return ResultVo
*/
@GetMapping("/exportExcel")
ResultVo<?> exportExcel(HttpServletRequest request, HttpServletResponse response);
/**
* Excel
* @param request request
* @return ResultVo
*/
@GetMapping("/exportImport")
ResultVo<?> excelImport(MultipartHttpServletRequest request);
/**
* Excel
* @param response response
* @return ResultVo
*/
@GetMapping("/exportImport/template")
ResultVo<?> importTemplate(HttpServletResponse response);
}

@ -0,0 +1,148 @@
package org.opsli.api.web.system.user;
import org.opsli.api.base.result.ResultVo;
import org.opsli.api.wrapper.system.menu.MenuModel;
import org.opsli.api.wrapper.system.role.RoleModel;
import org.opsli.api.wrapper.system.user.UserModel;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
* @BelongsProject: opsli-boot
* @BelongsPackage: org.opsli.modulars.test.web
* @Author: Parker
* @CreateTime: 2020-09-13 17:40
* @Description: API
*
* API @GetMapping @PostMapping
* Mapping Controller
*
*
*
*
*/
public interface UserApi {
/** 标题 */
String TITLE = "用户信息";
/**
*
* @param model
* @return ResultVo
*/
@GetMapping("/get")
ResultVo<UserModel> get(UserModel model);
/**
*
* @param pageNo
* @param pageSize
* @param request request
* @return ResultVo
*/
@GetMapping("/findPage")
ResultVo<?> findPage(
@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
HttpServletRequest request
);
/**
*
* @param model
* @return ResultVo
*/
@PostMapping("/insert")
ResultVo<?> insert(UserModel model);
/**
*
* @param model
* @return ResultVo
*/
@PostMapping("/update")
ResultVo<?> update(UserModel model);
/**
*
* @param id ID
* @return ResultVo
*/
@PostMapping("/del")
ResultVo<?> del(String id);
/**
*
* @param ids ID
* @return ResultVo
*/
@PostMapping("/delAll")
ResultVo<?> delAll(String[] ids);
/**
* Excel
* @param request request
* @param response response
* @return ResultVo
*/
@GetMapping("/exportExcel")
ResultVo<?> exportExcel(HttpServletRequest request, HttpServletResponse response);
/**
* Excel
* @param request request
* @return ResultVo
*/
@GetMapping("/exportImport")
ResultVo<?> excelImport(MultipartHttpServletRequest request);
/**
* Excel
* @param response response
* @return ResultVo
*/
@GetMapping("/exportImport/template")
ResultVo<?> importTemplate(HttpServletResponse response);
/**
* username
* @param username
* @return ResultVo
*/
//@GetMapping("/getUserByUsername")
ResultVo<UserModel> getUserByUsername(String username);
/**
* userId
* @param userId Id
* @return ResultVo
*/
//@GetMapping("/getRolesByUserId")
ResultVo<List<String>> getRolesByUserId(String userId);
/**
* userId
* @param userId Id
* @return ResultVo
*/
//@GetMapping("/queryAllPerms")
ResultVo<List<String>> getAllPerms(String userId);
/**
* userId
* @param userId Id
* @return ResultVo
*/
//@GetMapping("/queryAllPerms")
ResultVo<List<MenuModel>> getMenuListByUserId(String userId);
}

@ -9,7 +9,7 @@ import org.opsli.api.base.warpper.ApiWrapper;
import org.opsli.common.annotation.validation.ValidationArgs;
import org.opsli.common.annotation.validation.ValidationArgsMax;
import org.opsli.common.enums.ValiArgsType;
import org.opsli.plugins.excel.annotation.CellStyleFormat;
import org.opsli.plugins.excel.annotation.ExcelInfo;
/**
* @BelongsProject: opsli-boot
@ -20,7 +20,7 @@ import org.opsli.plugins.excel.annotation.CellStyleFormat;
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class SysDictDetailModel extends ApiWrapper {
public class DictDetailModel extends ApiWrapper {
/** 字典ID */
@ -40,7 +40,7 @@ public class SysDictDetailModel extends ApiWrapper {
/** 字典名称 */
@ApiModelProperty(value = "字典名称")
@ExcelProperty(value = "字典名称", order = 1)
@CellStyleFormat
@ExcelInfo
// 验证器
@ValidationArgs({ValiArgsType.IS_NOT_NULL, ValiArgsType.IS_GENERAL_WITH_CHINESE})
@ValidationArgsMax(120)
@ -49,32 +49,34 @@ public class SysDictDetailModel extends ApiWrapper {
/** 字典值 */
@ApiModelProperty(value = "字典值")
@ExcelProperty(value = "字典值", order = 2)
@CellStyleFormat
@ExcelInfo
// 验证器
@ValidationArgs({ValiArgsType.IS_NOT_NULL})
@ValidationArgsMax(120)
private String dictValue;
/** 是否内置数据 */
@ApiModelProperty(value = "是否内置数据")
/** 是否内置数据 0是 1否*/
@ApiModelProperty(value = "是否内置数据 0是 1否")
@ExcelProperty(value = "是否内置数据", order = 2)
@CellStyleFormat
@ExcelInfo(dictType = "yes_no")
// 验证器
@ValidationArgs({ValiArgsType.IS_NOT_NULL})
@ValidationArgsMax(1)
private Character izLock;
/** 排序 */
@ApiModelProperty(value = "排序")
@ExcelProperty(value = "排序", order = 2)
@CellStyleFormat
@ExcelInfo
// 验证器
@ValidationArgs({ValiArgsType.IS_NOT_NULL, ValiArgsType.IS_NUMBER})
@ValidationArgsMax(10)
private Integer sortNo;
/** 备注 */
@ApiModelProperty(value = "备注")
@ExcelProperty(value = "备注", order = 2)
@CellStyleFormat
@ExcelInfo
// 验证器
@ValidationArgsMax(255)
private String remark;

@ -1,29 +1,62 @@
package org.opsli.api.wrapper.system.dict;
import com.alibaba.excel.annotation.ExcelProperty;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.opsli.api.base.warpper.ApiWrapper;
import org.opsli.common.annotation.validation.ValidationArgs;
import org.opsli.common.annotation.validation.ValidationArgsMax;
import org.opsli.common.enums.ValiArgsType;
import org.opsli.plugins.excel.annotation.ExcelInfo;
/**
* @BelongsProject: opsli-boot
* @BelongsPackage: org.opsli.modulars.test.entity
* @Author: Parker
* @CreateTime: 2020-09-16 17:33
* @Description: -
* @Description:
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class DictModel {
public class DictModel extends ApiWrapper {
/** 类型编号 - 冗余 */
/** 字典类型编号 */
@ApiModelProperty(value = "字典类型编号")
@ExcelProperty(value = "字典类型编号", order = 1)
@ExcelInfo
// 验证器
@ValidationArgs({ValiArgsType.IS_NOT_NULL, ValiArgsType.IS_GENERAL})
@ValidationArgsMax(120)
private String typeCode;
/** 字典名称 */
private String dictName;
/** 字典类型名称 */
@ApiModelProperty(value = "字典类型名称")
@ExcelProperty(value = "字典类型名称", order = 2)
@ExcelInfo
// 验证器
@ValidationArgs({ValiArgsType.IS_NOT_NULL, ValiArgsType.IS_GENERAL_WITH_CHINESE})
@ValidationArgsMax(120)
private String typeName;
/** 是否内置数据 0是 1否*/
@ApiModelProperty(value = "是否内置数据 0是 1否")
@ExcelProperty(value = "是否内置数据", order = 3)
@ExcelInfo(dictType = "yes_no")
// 验证器
@ValidationArgs(ValiArgsType.IS_NOT_NULL)
@ValidationArgsMax(1)
private Character izLock;
/** 字典值 */
private String dictValue;
/** 备注 */
@ApiModelProperty(value = "备注")
@ExcelProperty(value = "备注", order = 4)
@ExcelInfo
// 验证器
@ValidationArgsMax(255)
private String remark;
/** 消息 */
private SysDictDetailModel model;
}

@ -0,0 +1,29 @@
package org.opsli.api.wrapper.system.dict;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* @BelongsProject: opsli-boot
* @BelongsPackage: org.opsli.modulars.test.entity
* @Author: Parker
* @CreateTime: 2020-09-16 17:33
* @Description: -
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class DictWrapper {
/** 类型编号 - 冗余 */
private String typeCode;
/** 字典名称 */
private String dictName;
/** 字典值 */
private String dictValue;
/** 消息 */
private DictDetailModel model;
}

@ -1,61 +0,0 @@
package org.opsli.api.wrapper.system.dict;
import com.alibaba.excel.annotation.ExcelProperty;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.opsli.api.base.warpper.ApiWrapper;
import org.opsli.common.annotation.validation.ValidationArgs;
import org.opsli.common.annotation.validation.ValidationArgsMax;
import org.opsli.common.enums.ValiArgsType;
import org.opsli.plugins.excel.annotation.CellStyleFormat;
/**
* @BelongsProject: opsli-boot
* @BelongsPackage: org.opsli.modulars.test.entity
* @Author: Parker
* @CreateTime: 2020-09-16 17:33
* @Description:
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class SysDictModel extends ApiWrapper {
/** 字典类型编号 */
@ApiModelProperty(value = "字典类型编号")
@ExcelProperty(value = "字典类型编号", order = 1)
@CellStyleFormat
// 验证器
@ValidationArgs({ValiArgsType.IS_NOT_NULL, ValiArgsType.IS_GENERAL})
@ValidationArgsMax(120)
private String typeCode;
/** 字典类型名称 */
@ApiModelProperty(value = "字典类型名称")
@ExcelProperty(value = "字典类型名称", order = 2)
@CellStyleFormat
// 验证器
@ValidationArgs({ValiArgsType.IS_NOT_NULL, ValiArgsType.IS_GENERAL_WITH_CHINESE})
@ValidationArgsMax(120)
private String typeName;
/** 是否内置数据 */
@ApiModelProperty(value = "是否内置数据")
@ExcelProperty(value = "是否内置数据", order = 3)
@CellStyleFormat
// 验证器
@ValidationArgs(ValiArgsType.IS_NOT_NULL)
private Character izLock;
/** 备注 */
@ApiModelProperty(value = "备注")
@ExcelProperty(value = "备注", order = 4)
@CellStyleFormat
// 验证器
@ValidationArgsMax(255)
private String remark;
}

@ -0,0 +1,77 @@
package org.opsli.api.wrapper.system.menu;
import com.alibaba.excel.annotation.ExcelProperty;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.opsli.api.base.warpper.ApiWrapper;
import org.opsli.common.annotation.validation.ValidationArgs;
import org.opsli.common.annotation.validation.ValidationArgsMax;
import org.opsli.common.enums.ValiArgsType;
import org.opsli.plugins.excel.annotation.ExcelInfo;
/**
* @BelongsProject: opsli-boot
* @BelongsPackage: org.opsli.modulars.test.entity
* @Author: Parker
* @CreateTime: 2020-09-16 17:33
* @Description:
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class MenuModel extends ApiWrapper {
/** 父级主键 */
@ApiModelProperty(value = "父级主键")
@ExcelProperty(value = "父级主键", order = 1)
@ExcelInfo
// 验证器
@ValidationArgs(ValiArgsType.IS_NOT_NULL)
@ValidationArgsMax(20)
private String parentId;
/** 菜单编号 */
@ApiModelProperty(value = "菜单编号")
@ExcelProperty(value = "菜单编号", order = 2)
@ExcelInfo
// 验证器
@ValidationArgs({ValiArgsType.IS_NOT_NULL,ValiArgsType.IS_GENERAL})
@ValidationArgsMax(50)
private String menuCode;
/** 菜单名称 */
@ApiModelProperty(value = "菜单名称")
@ExcelProperty(value = "菜单名称", order = 3)
@ExcelInfo
// 验证器
@ValidationArgs({ValiArgsType.IS_NOT_NULL,ValiArgsType.IS_GENERAL_WITH_CHINESE})
@ValidationArgsMax(50)
private String menuName;
/** 图标 */
@ApiModelProperty(value = "图标")
@ExcelProperty(value = "图标", order = 4)
@ExcelInfo
// 验证器
@ValidationArgsMax(50)
private String icon;
/** 项目类型:1-菜单2-按钮3-链接4-表单 */
@ApiModelProperty(value = "项目类型:1-菜单2-按钮3-链接4-表单")
@ExcelProperty(value = "项目类型", order = 5)
@ExcelInfo(dictType = "menuType")
// 验证器
@ValidationArgs({ValiArgsType.IS_NOT_NULL})
@ValidationArgsMax(20)
private String type;
/** url地址 */
@ApiModelProperty(value = "url地址")
@ExcelProperty(value = "url地址", order = 6)
@ExcelInfo
// 验证器
@ValidationArgsMax(200)
private String url;
}

@ -0,0 +1,61 @@
package org.opsli.api.wrapper.system.role;
import com.alibaba.excel.annotation.ExcelProperty;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.opsli.api.base.warpper.ApiWrapper;
import org.opsli.common.annotation.validation.ValidationArgs;
import org.opsli.common.annotation.validation.ValidationArgsMax;
import org.opsli.common.enums.ValiArgsType;
import org.opsli.plugins.excel.annotation.ExcelInfo;
/**
* @BelongsProject: opsli-boot
* @BelongsPackage: org.opsli.modulars.test.entity
* @Author: Parker
* @CreateTime: 2020-09-16 17:33
* @Description:
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class RoleModel extends ApiWrapper {
/** 角色编码 */
@ApiModelProperty(value = "角色编码")
@ExcelProperty(value = "角色编码", order = 1)
@ExcelInfo
// 验证器
@ValidationArgs({ValiArgsType.IS_NOT_NULL,ValiArgsType.IS_GENERAL})
@ValidationArgsMax(50)
private String roleCode;
/** 角色名称 */
@ApiModelProperty(value = "角色编码")
@ExcelProperty(value = "角色编码", order = 2)
@ExcelInfo
// 验证器
@ValidationArgs({ValiArgsType.IS_NOT_NULL,ValiArgsType.IS_GENERAL})
@ValidationArgsMax(50)
private String roleName;
/** 是否内置数据 0是 1否*/
@ApiModelProperty(value = "是否内置数据 0是 1否")
@ExcelProperty(value = "是否内置数据", order = 3)
@ExcelInfo(dictType = "yes_no")
// 验证器
@ValidationArgs({ValiArgsType.IS_NOT_NULL,ValiArgsType.IS_GENERAL})
@ValidationArgsMax(1)
private Character izLock;
/** 备注 */
@ApiModelProperty(value = "备注")
@ExcelProperty(value = "备注", order = 4)
@ExcelInfo
// 验证器
@ValidationArgsMax(255)
private String remark;
}

@ -0,0 +1,121 @@
package org.opsli.api.wrapper.system.user;
import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.opsli.api.base.warpper.ApiWrapper;
import org.opsli.common.annotation.validation.ValidationArgs;
import org.opsli.common.annotation.validation.ValidationArgsMax;
import org.opsli.common.enums.ValiArgsType;
import org.opsli.plugins.excel.annotation.ExcelInfo;
/**
* @BelongsProject: opsli-boot
* @BelongsPackage: org.opsli.modulars.test.entity
* @Author: Parker
* @CreateTime: 2020-09-16 17:33
* @Description:
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class UserModel extends ApiWrapper {
/** 登录账户 */
@ApiModelProperty(value = "登录账户")
@ExcelIgnore
// 验证器
@ValidationArgs({ValiArgsType.IS_NOT_NULL,ValiArgsType.IS_GENERAL})
@ValidationArgsMax(32)
private String username;
/** 登录密码 */
@ApiModelProperty(value = "登录密码")
@ExcelIgnore
// 验证器
@ValidationArgsMax(50)
private String password;
/** 盐值,密码秘钥 */
@ApiModelProperty(value = "盐值,密码秘钥")
@ExcelIgnore
// 验证器
@ValidationArgsMax(50)
private String secretkey;
/** 是否锁定 */
@ApiModelProperty(value = "是否锁定")
@ExcelIgnore
// 验证器
@ValidationArgs({ValiArgsType.IS_NOT_NULL})
@ValidationArgsMax(1)
private Character locked;
/** 真实姓名 */
@ApiModelProperty(value = "真实姓名")
@ExcelProperty(value = "真实姓名", order = 1)
@ExcelInfo
// 验证器
@ValidationArgs({ValiArgsType.IS_NOT_NULL,ValiArgsType.IS_GENERAL_WITH_CHINESE})
@ValidationArgsMax(50)
private String realName;
/** 手机 */
@ApiModelProperty(value = "手机")
@ExcelProperty(value = "手机", order = 2)
@ExcelInfo
// 验证器
@ValidationArgs({ValiArgsType.IS_MOBILE})
private String mobile;
/** 邮箱 */
@ApiModelProperty(value = "邮箱")
@ExcelProperty(value = "邮箱", order = 3)
@ExcelInfo
// 验证器
@ValidationArgs({ValiArgsType.IS_EMAIL})
private String email;
/** 工号 */
@ApiModelProperty(value = "工号")
@ExcelProperty(value = "工号", order = 4)
@ExcelInfo
// 验证器
@ValidationArgs({ValiArgsType.IS_GENERAL})
@ValidationArgsMax(32)
private String no;
/** 头像 */
@ApiModelProperty(value = "头像")
@ExcelIgnore
// 验证器
@ValidationArgsMax(255)
private String avatar;
/** 最后登陆IP */
@ApiModelProperty(value = "最后登陆IP")
@ExcelIgnore
// 验证器
@ValidationArgs(ValiArgsType.IS_IPV4)
private String loginIp;
/** 备注 */
@ApiModelProperty(value = "备注")
@ExcelProperty(value = "备注", order = 5)
@ExcelInfo
// 验证器
@ValidationArgsMax(255)
private String remark;
/** 多租户字段 */
@ApiModelProperty(value = "多租户ID")
@ExcelIgnore
// 验证器
@ValidationArgsMax(20)
private String tenantId;
}

@ -1,23 +0,0 @@
package org.opsli.common.annotation;
import java.lang.annotation.*;
/**
* @BelongsProject: opsli-boot
* @BelongsPackage: org.opsli.common.annotation
* @Author: Parker
* @CreateTime: 2020-09-16 16:36
* @Description:
*
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@Documented
public @interface DictType {
/** 字典类型 code */
String value();
}

@ -1,4 +1,4 @@
package org.opsli.common.annotation;
package org.opsli.common.annotation.hotdata;
import org.opsli.common.constants.CacheConstants;

@ -1,4 +1,4 @@
package org.opsli.common.annotation;
package org.opsli.common.annotation.hotdata;
import org.opsli.common.constants.CacheConstants;

@ -0,0 +1,30 @@
package org.opsli.common.api;
/**
* 线 Token
*
* @author parker
* @date 2020-09-15
*/
public class TokenThreadLocal {
/** 临时线程存储 token 容器 */
private static final ThreadLocal<String> tokenData = new ThreadLocal<>();
public static void put(String token) {
if (tokenData.get() == null) {
tokenData.set(token);
}
}
public static String get() {
return tokenData.get();
}
public static void remove() {
try {
tokenData.remove();
}catch (Exception e){}
}
}

@ -7,6 +7,8 @@ package org.opsli.common.constants;
*/
public interface OrderConstants {
/** token */
int TOKEN_AOP_SORT = 150;
/** 热点数据加载顺序 */
int HOT_DATA_ORDER = 180;

@ -0,0 +1,21 @@
package org.opsli.common.constants;
/**
* @BelongsProject: opsli-boot
* @BelongsPackage: org.opsli.common.constants
* @Author: Parker
* @CreateTime: 2020-09-16 17:42
* @Description:
*/
public interface SignConstants {
/** username */
String ACCOUNT = "account";
/** user Id */
String USER_ID = "userId";
/** 时间戳 */
String TIMESTAMP = "timestamp";
}

@ -47,7 +47,44 @@
<version>${plugins.version}</version>
</dependency>
<!-- ———————————————————— 集成Shiro鉴权安全认证 - 开始 ———————————————————— -->
<dependency>
<groupId>org.crazycake</groupId>
<artifactId>shiro-redis-spring-boot-starter</artifactId>
<version>3.3.1</version>
</dependency>
<!--shiro-->
<!-- <dependency>-->
<!-- <groupId>org.apache.shiro</groupId>-->
<!-- <artifactId>shiro-spring-boot-starter</artifactId>-->
<!-- </dependency>-->
<!-- &lt;!&ndash; shiro-redis &ndash;&gt;-->
<!-- <dependency>-->
<!-- <groupId>org.crazycake</groupId>-->
<!-- <artifactId>shiro-redis</artifactId>-->
<!-- <exclusions>-->
<!-- <exclusion>-->
<!-- <groupId>org.apache.shiro</groupId>-->
<!-- <artifactId>shiro-core</artifactId>-->
<!-- </exclusion>-->
<!-- </exclusions>-->
<!-- </dependency>-->
<!-- kaptcha -->
<dependency>
<groupId>com.github.axet</groupId>
<artifactId>kaptcha</artifactId>
</dependency>
<!-- JWT -->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
</dependency>
<!-- ———————————————————— 集成Shiro鉴权安全认证 - 结束 ———————————————————— -->
</dependencies>

@ -8,9 +8,9 @@ import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.opsli.api.base.warpper.ApiWrapper;
import org.opsli.common.annotation.EnableHotData;
import org.opsli.common.annotation.HotDataDel;
import org.opsli.common.annotation.HotDataPut;
import org.opsli.common.annotation.hotdata.EnableHotData;
import org.opsli.common.annotation.hotdata.HotDataDel;
import org.opsli.common.annotation.hotdata.HotDataPut;
import org.opsli.common.constants.CacheConstants;
import org.opsli.core.cache.local.CacheUtil;
import org.opsli.core.cache.pushsub.entity.CacheDataEntity;
@ -47,11 +47,11 @@ public class CacheDataAop {
@Autowired
private RedisPlugin redisPlugin;
@Pointcut("@annotation(org.opsli.common.annotation.HotDataPut)")
@Pointcut("@annotation(org.opsli.common.annotation.hotdata.HotDataPut)")
public void hotDataPut() {
}
@Pointcut("@annotation(org.opsli.common.annotation.HotDataDel)")
@Pointcut("@annotation(org.opsli.common.annotation.hotdata.HotDataDel)")
public void hotDataDel() {
}

@ -0,0 +1,76 @@
package org.opsli.core.aspect;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.opsli.common.api.TokenThreadLocal;
import org.opsli.common.exception.ServiceException;
import org.opsli.core.utils.UserTokenUtil;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import static org.opsli.common.constants.OrderConstants.TOKEN_AOP_SORT;
/**
*
*
* @author parker
* @date 2020-09-16
*/
@Slf4j
@Order(TOKEN_AOP_SORT)
@Aspect
@Component
public class TokenAop {
@Pointcut("execution(public * org.opsli.modulars*..*.*Controller*.*(..))")
public void requestMapping() {
}
/**
* post
* @param point
*/
@Around("requestMapping()")
public Object tokenAop(ProceedingJoinPoint point) throws Throwable {
// 将 Token放入 线程缓存
try {
RequestAttributes ra = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes sra = (ServletRequestAttributes) ra;
HttpServletRequest request = sra.getRequest();
String requestToken = UserTokenUtil.getRequestToken(request);
if(StringUtils.isNotEmpty(requestToken)){
// 放入当前线程缓存中
TokenThreadLocal.put(requestToken);
}
}catch (ServiceException e){
throw e;
}catch (Exception e){
log.error(e.getMessage(),e);
}
// 防止线程抛异常 线程变量不回收 导致oom
Object returnValue = null;
try {
// 执行正常操作
Object[] args= point.getArgs();
returnValue = point.proceed(args);
} finally {
// 线程销毁时 删除 token
TokenThreadLocal.remove();
}
return returnValue;
}
}

@ -2,27 +2,19 @@ package org.opsli.core.aspect;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.opsli.api.base.warpper.ApiWrapper;
import org.opsli.api.utils.ValidationUtil;
import org.opsli.common.annotation.HotDataPut;
import org.opsli.common.exception.ServiceException;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import static org.opsli.common.constants.OrderConstants.PARAM_VALIDATE_AOP_SORT;

@ -13,7 +13,7 @@ import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.opsli.api.base.result.ResultVo;
import org.opsli.api.base.warpper.ApiWrapper;
import org.opsli.common.annotation.EnableHotData;
import org.opsli.common.annotation.hotdata.EnableHotData;
import org.opsli.common.exception.ServiceException;
import org.opsli.common.msg.CommonMsg;
import org.opsli.common.utils.WrapperUtil;
@ -104,16 +104,21 @@ public abstract class BaseRestController <T extends BaseEntity, E extends ApiWra
.setLockTimeOut(10000L);
// 这里增加分布式锁 防止缓存击穿
if(hotDataFlag){
// 加锁
redisLock = redisLockPlugins.tryLock(redisLock);
if(redisLock == null){
throw new ServiceException(CoreMsg.CACHE_PUNCTURE_EXCEPTION);
try {
// 加锁
redisLock = redisLockPlugins.tryLock(redisLock);
if(redisLock == null){
throw new ServiceException(CoreMsg.CACHE_PUNCTURE_EXCEPTION);
}
// 如果缓存没读到 则去数据库读
model = WrapperUtil.transformInstance(IService.get(id),modelClazz);
}catch (Exception e){
log.error(e.getMessage(), e);
}finally {
// 释放锁
redisLockPlugins.unLock(redisLock);
redisLock = null;
}
// 如果缓存没读到 则去数据库读
model = WrapperUtil.transformInstance(IService.get(id),modelClazz);
// 释放锁
redisLockPlugins.unLock(redisLock);
redisLock = null;
}else{
// 如果缓存没读到 则去数据库读
model = WrapperUtil.transformInstance(IService.get(id),modelClazz);

@ -2,7 +2,7 @@ package org.opsli.core.cache.pushsub.handler;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.opsli.api.wrapper.system.dict.DictModel;
import org.opsli.api.wrapper.system.dict.DictWrapper;
import org.opsli.common.constants.CacheConstants;
import org.opsli.common.constants.DictConstants;
import org.opsli.core.cache.local.CacheUtil;
@ -14,7 +14,6 @@ import org.opsli.plugins.cache.EhCachePlugin;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.Collection;
import java.util.List;
/**
* @BelongsProject: opsli-boot
@ -43,30 +42,30 @@ public class DictHandler implements RedisPushSubHandler{
Collection<Object> dicts = (Collection<Object>) msgJson.get(MsgArgsType.DICT_MODELS.toString());
for (Object dictObj : dicts) {
JSONObject jsonObject = (JSONObject) dictObj;
DictModel dictModel = JSONObject.toJavaObject(jsonObject, DictModel.class);
this.handler(dictModel, type);
DictWrapper dictWrapperModel = JSONObject.toJavaObject(jsonObject, DictWrapper.class);
this.handler(dictWrapperModel, type);
}
} else if(DictModelType.OBJECT == dictModelType){
Object dictObj = msgJson.get(MsgArgsType.DICT_MODEL.toString());
JSONObject jsonObject = (JSONObject) dictObj;
DictModel dictModel = JSONObject.toJavaObject(jsonObject, DictModel.class);
this.handler(dictModel, type);
DictWrapper dictWrapperModel = JSONObject.toJavaObject(jsonObject, DictWrapper.class);
this.handler(dictWrapperModel, type);
}
}
/**
* -
* @param dictModel
* @param dictWrapperModel
* @param type
*/
private void handler(DictModel dictModel, CacheType type){
private void handler(DictWrapper dictWrapperModel, CacheType type){
// 解析 key
String ehKeyByName = CacheUtil.handleKey(CacheConstants.EDEN_HASH_DATA,
DictConstants.CACHE_PREFIX_NAME + dictModel.getTypeCode() + ":" + dictModel.getDictName());
DictConstants.CACHE_PREFIX_NAME + dictWrapperModel.getTypeCode() + ":" + dictWrapperModel.getDictName());
String ehKeyByValue = CacheUtil.handleKey(CacheConstants.EDEN_HASH_DATA,
DictConstants.CACHE_PREFIX_VALUE + dictModel.getTypeCode() + ":" + dictModel.getDictValue());
DictConstants.CACHE_PREFIX_VALUE + dictWrapperModel.getTypeCode() + ":" + dictWrapperModel.getDictValue());
// 缓存更新
if(CacheType.UPDATE == type){
@ -74,7 +73,7 @@ public class DictHandler implements RedisPushSubHandler{
ehCachePlugin.delete(CacheConstants.HOT_DATA, ehKeyByValue);
// 统一转换为 JSONObject
String jsonStr = JSONObject.toJSONString(dictModel.getModel());
String jsonStr = JSONObject.toJSONString(dictWrapperModel.getModel());
JSONObject value = JSONObject.parseObject(jsonStr);
ehCachePlugin.put(CacheConstants.HOT_DATA, ehKeyByName, value);
ehCachePlugin.put(CacheConstants.HOT_DATA, ehKeyByValue, value);

@ -3,7 +3,7 @@ package org.opsli.core.cache.pushsub.msgs;
import com.alibaba.fastjson.JSONObject;
import lombok.Data;
import lombok.experimental.Accessors;
import org.opsli.api.wrapper.system.dict.DictModel;
import org.opsli.api.wrapper.system.dict.DictWrapper;
import org.opsli.core.cache.pushsub.enums.CacheType;
import org.opsli.core.cache.pushsub.enums.DictModelType;
import org.opsli.core.cache.pushsub.enums.MsgArgsType;
@ -33,11 +33,11 @@ public final class DictMsgFactory extends BaseSubMessage{
/**
*
*/
public static BaseSubMessage createMsg(DictModel dictModel, CacheType cacheType){
public static BaseSubMessage createMsg(DictWrapper dictWrapperModel, CacheType cacheType){
BaseSubMessage baseSubMessage = new BaseSubMessage();
// 数据
JSONObject jsonObj = new JSONObject();
jsonObj.put(MsgArgsType.DICT_MODEL.toString(),dictModel);
jsonObj.put(MsgArgsType.DICT_MODEL.toString(), dictWrapperModel);
jsonObj.put(MsgArgsType.DICT_MODEL_TYPE.toString(), DictModelType.OBJECT);
jsonObj.put(MsgArgsType.DICT_TYPE.toString(),cacheType.toString());
@ -49,11 +49,11 @@ public final class DictMsgFactory extends BaseSubMessage{
/**
*
*/
public static BaseSubMessage createMsg(List<DictModel> dictModels, CacheType cacheType){
public static BaseSubMessage createMsg(List<DictWrapper> dictWrapperModels, CacheType cacheType){
BaseSubMessage baseSubMessage = new BaseSubMessage();
// 数据
JSONObject jsonObj = new JSONObject();
jsonObj.put(MsgArgsType.DICT_MODELS.toString(),dictModels);
jsonObj.put(MsgArgsType.DICT_MODELS.toString(), dictWrapperModels);
jsonObj.put(MsgArgsType.DICT_MODEL_TYPE.toString(), DictModelType.COLLECTION);
jsonObj.put(MsgArgsType.DICT_TYPE.toString(),cacheType.toString());

@ -0,0 +1,34 @@
package org.opsli.core.conf;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.google.code.kaptcha.util.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Properties;
/**
*
*
* @author
* @date 2017-04-20 19:22
*/
@Configuration
public class KaptchaConfig {
@Bean
public DefaultKaptcha producer() {
Properties properties = new Properties();
properties.put("kaptcha.border", "no");
properties.put("kaptcha.textproducer.font.color", "black");
properties.put("kaptcha.textproducer.char.space", "10");
properties.put("kaptcha.textproducer.char.string", "1234567890");
properties.put("kaptcha.textproducer.char.length", "4");
Config config = new Config(properties);
DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
defaultKaptcha.setConfig(config);
return defaultKaptcha;
}
}

@ -2,7 +2,8 @@ package org.opsli.core.conf;
import lombok.extern.slf4j.Slf4j;
import org.opsli.core.cache.pushsub.receiver.RedisPushSubReceiver;
import org.opsli.plugins.redis.pushsub.receiver.BaseReceiver;
import org.opsli.plugins.redis.conf.RedisPluginConfig;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@ -11,7 +12,6 @@ import org.springframework.data.redis.listener.PatternTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;
import javax.annotation.Resource;
/**
* @author : parker
@ -22,11 +22,10 @@ import javax.annotation.Resource;
**/
@Slf4j
@Configuration
@AutoConfigureAfter(RedisPluginConfig.class)
@ConditionalOnProperty(name = "spring.redis.pushsub.enable", havingValue = "true")
public class RedisMessageListenerConfig {
@Resource
private LettuceConnectionFactory factory;
/**
* redis
@ -36,10 +35,10 @@ public class RedisMessageListenerConfig {
*/
@Bean
public RedisMessageListenerContainer container() {
public RedisMessageListenerContainer container(LettuceConnectionFactory lettuceConnectionFactory) {
RedisPushSubReceiver receiver = new RedisPushSubReceiver();
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(factory);
container.setConnectionFactory(lettuceConnectionFactory);
//订阅了的通道
container.addMessageListener(listenerAdapter(new RedisPushSubReceiver()), new PatternTopic(receiver.getListenerChannel()));

@ -0,0 +1,125 @@
package org.opsli.core.conf;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.opsli.core.security.shiro.filter.OAuth2Filter;
import org.opsli.core.security.shiro.realm.OAuth2Realm;
import org.opsli.plugins.redis.conf.RedisPluginConfig;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import javax.servlet.Filter;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* Shiro
*
* token -
*
* @author parker
* @date 2017-04-20 18:33
*/
@Configuration
@AutoConfigureAfter(RedisPluginConfig.class)
public class ShiroConfig {
/**
* filer
* @param securityManager
* @return
*/
@Bean("shiroFilter")
public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
shiroFilter.setSecurityManager(securityManager);
//oauth过滤
Map<String, Filter> filters = new HashMap<>();
filters.put("oauth2", new OAuth2Filter());
shiroFilter.setFilters(filters);
Map<String, String> filterMap = new LinkedHashMap<>();
filterMap.put("/webjars/**", "anon");
filterMap.put("/druid/**", "anon");
filterMap.put("/app/**", "anon");
filterMap.put("/sys/login", "anon");
filterMap.put("/swagger/**", "anon");
filterMap.put("/v2/api-docs", "anon");
filterMap.put("/doc.html", "anon");
filterMap.put("/swagger-ui.html", "anon");
filterMap.put("/swagger-resources/**", "anon");
filterMap.put("/captcha.jpg", "anon");
filterMap.put("/ueditor/**", "anon");
filterMap.put("/**", "oauth2");
shiroFilter.setFilterChainDefinitionMap(filterMap);
return shiroFilter;
}
@Bean("sessionManager")
public SessionManager sessionManager(){
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
sessionManager.setSessionValidationSchedulerEnabled(true);
sessionManager.setSessionIdCookieEnabled(true);
return sessionManager;
}
@Bean("securityManager")
public DefaultWebSecurityManager securityManager(OAuth2Realm oAuth2Realm, SessionManager sessionManager,LettuceConnectionFactory lettuceConnectionFactory) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(oAuth2Realm);
securityManager.setSessionManager(sessionManager);
return securityManager;
}
@Bean
public OAuth2Realm oAuth2Realm() {
return new OAuth2Realm();
}
// ===================== 固定三板斧 =====================
// 其实 没有 Spring Security 配置起来简单
//
@Bean("lifecycleBeanPostProcessor")
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
@Bean("defaultAdvisorAutoProxyCreator")
@DependsOn("lifecycleBeanPostProcessor")
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator proxyCreator = new DefaultAdvisorAutoProxyCreator();
proxyCreator.setProxyTargetClass(true);
proxyCreator.setUsePrefix(true);
proxyCreator.setAdvisorBeanNamePrefix("_no_advisor");
return proxyCreator;
}
/**
* shiro
* @param securityManager
* @return
*/
@Bean("authorizationAttributeSourceAdvisor")
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
advisor.setSecurityManager(securityManager);
return advisor;
}
}

@ -8,6 +8,7 @@ import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.*;
import org.opsli.api.wrapper.system.user.UserModel;
import org.opsli.common.constants.MyBatisConstants;
import org.opsli.core.utils.UserUtil;
import org.springframework.stereotype.Component;
@ -79,13 +80,14 @@ public class AutoFillInterceptor implements Interceptor {
* @param arg
*/
public void insertFill(Object arg) {
UserModel userModel = UserUtil.getUser();
Field[] fields = ReflectUtil.getFields(arg.getClass());
for (Field f : fields) {
f.setAccessible(true);
switch (f.getName()) {
// 创建人
case MyBatisConstants.FIELD_CREATE_BY:
setProperty(arg, MyBatisConstants.FIELD_CREATE_BY, "测试");
setProperty(arg, MyBatisConstants.FIELD_CREATE_BY, userModel.getId());
break;
// 创建日期
case MyBatisConstants.FIELD_CREATE_TIME:
@ -93,7 +95,7 @@ public class AutoFillInterceptor implements Interceptor {
break;
// 更新人
case MyBatisConstants.FIELD_UPDATE_BY:
setProperty(arg, MyBatisConstants.FIELD_UPDATE_BY, "测试");
setProperty(arg, MyBatisConstants.FIELD_UPDATE_BY, userModel.getId());
break;
// 更新日期
case MyBatisConstants.FIELD_UPDATE_TIME:
@ -123,6 +125,7 @@ public class AutoFillInterceptor implements Interceptor {
* @param arg
*/
public void updateFill(Object arg) {
UserModel userModel = UserUtil.getUser();
// 2020-09-19
// 修改这儿 有可能会拿到一个 MapperMethod需要特殊处理
Field[] fields;
@ -145,7 +148,7 @@ public class AutoFillInterceptor implements Interceptor {
switch (f.getName()) {
// 更新人
case MyBatisConstants.FIELD_UPDATE_BY:
setProperty(arg, MyBatisConstants.FIELD_UPDATE_BY, "测试修改");
setProperty(arg, MyBatisConstants.FIELD_UPDATE_BY, userModel.getId());
break;
// 更新日期
case MyBatisConstants.FIELD_UPDATE_TIME:

@ -0,0 +1,38 @@
package org.opsli.core.filter;
import org.apache.commons.lang3.StringUtils;
import org.opsli.common.api.TokenThreadLocal;
import org.opsli.core.utils.UserTokenUtil;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
* Token token
*/
public class TokenFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
// 获得请求中 Token
String requestToken = UserTokenUtil.getRequestToken(request);
if(StringUtils.isNotEmpty(requestToken)){
// 放入当前线程缓存中
TokenThreadLocal.put(requestToken);
}
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
// 线程销毁时 删除 token
TokenThreadLocal.remove();
}
}

@ -1,4 +1,4 @@
package org.opsli.general;
package org.opsli.core.general;
import cn.hutool.core.lang.Console;
import cn.hutool.core.thread.ThreadUtil;
@ -23,9 +23,10 @@ public enum StartPrint {
INSTANCE;
/**
*
*
*/
public void print(Environment env){
public void successPrint(Environment env){
// 睡一秒打印
ThreadUtil.sleep(1, TimeUnit.SECONDS);
String ip = "localhost";
@ -38,11 +39,25 @@ public enum StartPrint {
String contextPath = env.getProperty("server.servlet.context-path");
StringBuilder printStr = new StringBuilder();
printStr.append("\n----------------------------------------------------------\n")
.append("Opsli-Boot 框架启动! 相关URLs:\n")
.append("Opsli-Boot 框架启动成功! 相关URLs:\n")
.append("项目地址: \t\thttp://" + ip + ":" + serverPort + contextPath + "/\n")
.append("Doc文档: \t\thttp://" + ip + ":" + serverPort + contextPath + "/doc.html\n")
.append("----------------------------------------------------------\n");
Console.log(printStr.toString());
}
/**
*
*
*/
public void errorPrint(){
// 睡一秒打印
ThreadUtil.sleep(1, TimeUnit.SECONDS);
StringBuilder printStr = new StringBuilder();
printStr.append("\n----------------------------------------------------------\n")
.append("Opsli-Boot 框架启动失败! 请检查相关配置!\n")
.append("----------------------------------------------------------\n");
Console.log(printStr.toString());
}
}

@ -0,0 +1,22 @@
package org.opsli.core.listener;
import lombok.extern.slf4j.Slf4j;
import org.opsli.core.general.StartPrint;
import org.springframework.boot.context.event.ApplicationFailedEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
/**
*
*
* @author parker
* @date 2020-03-31 13:56
*/
@Component
@Slf4j
public class ApplicationFailedEventListener implements ApplicationListener<ApplicationFailedEvent> {
@Override
public void onApplicationEvent(ApplicationFailedEvent event) {
StartPrint.INSTANCE.errorPrint();
}
}

@ -0,0 +1,24 @@
package org.opsli.core.listener;
import lombok.extern.slf4j.Slf4j;
import org.opsli.core.general.StartPrint;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.stereotype.Component;
/**
*
*
* @author parker
* @date 2020-03-31 13:56
*/
@Component
@Slf4j
public class ApplicationReadyEventListene implements ApplicationListener<ApplicationReadyEvent> {
@Override
public void onApplicationEvent(ApplicationReadyEvent event) {
ConfigurableApplicationContext applicationContext = event.getApplicationContext();
StartPrint.INSTANCE.successPrint(applicationContext.getEnvironment());
}
}

@ -0,0 +1,256 @@
package org.opsli.core.security.shiro.cache;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.CollectionUtils;
import org.opsli.core.security.shiro.exception.PrincipalIdNullException;
import org.opsli.core.security.shiro.exception.PrincipalInstanceException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
/**
* @author: sunzhiqiang
* @date: 2018/6/22
* @description: shiro-redis Git https://github.com/alexxiyang/shiro-redis
*/
public class RedisCache<K, V> implements Cache<K, V> {
private static Logger logger = LoggerFactory.getLogger(RedisCache.class);
private RedisManager redisManager;
private String keyPrefix = "";
private int expire = 0;
private String principalIdFieldName = RedisCacheManager.DEFAULT_PRINCIPAL_ID_FIELD_NAME;
/**
* Construction
* @param redisManager
*/
public RedisCache(RedisManager redisManager, String prefix, int expire, String principalIdFieldName) {
if (redisManager == null) {
throw new IllegalArgumentException("redisManager cannot be null.");
}
this.redisManager = redisManager;
if (prefix != null && !"".equals(prefix)) {
this.keyPrefix = prefix;
}
if (expire != -1) {
this.expire = expire;
}
if (principalIdFieldName != null && !"".equals(principalIdFieldName)) {
this.principalIdFieldName = principalIdFieldName;
}
}
@Override
public V get(K key) throws CacheException {
logger.debug("get key [{}]",key);
if (key == null) {
return null;
}
try {
String redisCacheKey = getRedisCacheKey(key);
Object rawValue = redisManager.get(redisCacheKey);
if (rawValue == null) {
return null;
}
V value = (V) rawValue;
return value;
} catch (Exception e) {
throw new CacheException(e);
}
}
@Override
public V put(K key, V value) throws CacheException {
logger.debug("put key [{}]",key);
if (key == null) {
logger.warn("Saving a null key is meaningless, return value directly without call Redis.");
return value;
}
try {
String redisCacheKey = getRedisCacheKey(key);
redisManager.set(redisCacheKey, value != null ? value : null, expire);
return value;
} catch (Exception e) {
throw new CacheException(e);
}
}
@Override
public V remove(K key) throws CacheException {
logger.debug("remove key [{}]",key);
if (key == null) {
return null;
}
try {
String redisCacheKey = getRedisCacheKey(key);
Object rawValue = redisManager.get(redisCacheKey);
V previous = (V) rawValue;
redisManager.del(redisCacheKey);
return previous;
} catch (Exception e) {
throw new CacheException(e);
}
}
private String getRedisCacheKey(K key) {
if (key == null) {
return null;
}
return this.keyPrefix + getStringRedisKey(key);
}
private String getStringRedisKey(K key) {
String redisKey;
if (key instanceof PrincipalCollection) {
redisKey = getRedisKeyFromPrincipalIdField((PrincipalCollection) key);
} else {
redisKey = key.toString();
}
return redisKey;
}
private String getRedisKeyFromPrincipalIdField(PrincipalCollection key) {
String redisKey;
Object principalObject = key.getPrimaryPrincipal();
Method pincipalIdGetter = null;
Method[] methods = principalObject.getClass().getDeclaredMethods();
for (Method m:methods) {
if (RedisCacheManager.DEFAULT_PRINCIPAL_ID_FIELD_NAME.equals(this.principalIdFieldName)
&& ("getAuthCacheKey".equals(m.getName()) || "getId".equals(m.getName()))) {
pincipalIdGetter = m;
break;
}
if (m.getName().equals("get" + this.principalIdFieldName.substring(0, 1).toUpperCase() + this.principalIdFieldName.substring(1))) {
pincipalIdGetter = m;
break;
}
}
if (pincipalIdGetter == null) {
throw new PrincipalInstanceException(principalObject.getClass(), this.principalIdFieldName);
}
try {
Object idObj = pincipalIdGetter.invoke(principalObject);
if (idObj == null) {
throw new PrincipalIdNullException(principalObject.getClass(), this.principalIdFieldName);
}
redisKey = idObj.toString();
} catch (IllegalAccessException e) {
throw new PrincipalInstanceException(principalObject.getClass(), this.principalIdFieldName, e);
} catch (InvocationTargetException e) {
throw new PrincipalInstanceException(principalObject.getClass(), this.principalIdFieldName, e);
}
return redisKey;
}
@Override
public void clear() throws CacheException {
logger.debug("clear cache");
Set<String> keys = null;
try {
keys = redisManager.scan(this.keyPrefix + "*");
} catch (Exception e) {
logger.error("get keys error", e);
}
if (keys == null || keys.size() == 0) {
return;
}
for (String key: keys) {
redisManager.del(key);
}
}
@Override
public int size() {
Long longSize = 0L;
try {
longSize = new Long(redisManager.scanSize(this.keyPrefix + "*"));
} catch (Exception e) {
logger.error("get keys error", e);
}
return longSize.intValue();
}
@SuppressWarnings("unchecked")
@Override
public Set<K> keys() {
Set<String> keys = null;
try {
keys = redisManager.scan(this.keyPrefix + "*");
} catch (Exception e) {
logger.error("get keys error", e);
return Collections.emptySet();
}
if (CollectionUtils.isEmpty(keys)) {
return Collections.emptySet();
}
Set<K> convertedKeys = new HashSet<K>();
for (String key:keys) {
try {
convertedKeys.add((K) key);
} catch (Exception e) {
logger.error("deserialize keys error", e);
}
}
return convertedKeys;
}
@Override
public Collection<V> values() {
Set<String> keys = null;
try {
keys = redisManager.scan(this.keyPrefix + "*");
} catch (Exception e) {
logger.error("get values error", e);
return Collections.emptySet();
}
if (CollectionUtils.isEmpty(keys)) {
return Collections.emptySet();
}
List<V> values = new ArrayList<V>(keys.size());
for (String key : keys) {
V value = null;
try {
value = (V) redisManager.get(key);
} catch (Exception e) {
logger.error("deserialize values= error", e);
}
if (value != null) {
values.add(value);
}
}
return Collections.unmodifiableList(values);
}
public String getKeyPrefix() {
return keyPrefix;
}
public void setKeyPrefix(String keyPrefix) {
this.keyPrefix = keyPrefix;
}
public String getPrincipalIdFieldName() {
return principalIdFieldName;
}
public void setPrincipalIdFieldName(String principalIdFieldName) {
this.principalIdFieldName = principalIdFieldName;
}
}

@ -0,0 +1,85 @@
package org.opsli.core.security.shiro.cache;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.apache.shiro.cache.CacheManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
* @description: shiro-redis Git https://github.com/alexxiyang/shiro-redis
*/
public class RedisCacheManager implements CacheManager {
private final Logger logger = LoggerFactory.getLogger(RedisCacheManager.class);
/**
* fast lookup by name map
*/
private final ConcurrentMap<String, Cache> caches = new ConcurrentHashMap<String, Cache>();
private RedisManager redisManager;
/**
* expire time in seconds
*/
private static final int DEFAULT_EXPIRE = 1800;
private int expire = DEFAULT_EXPIRE;
/**
* The Redis key prefix for caches
*/
public static final String DEFAULT_CACHE_KEY_PREFIX = "shiro:cache:";
private String keyPrefix = DEFAULT_CACHE_KEY_PREFIX;
public static final String DEFAULT_PRINCIPAL_ID_FIELD_NAME = "authCacheKey or id";
private String principalIdFieldName = DEFAULT_PRINCIPAL_ID_FIELD_NAME;
@Override
public <K, V> Cache<K, V> getCache(String name) throws CacheException {
logger.debug("get cache, name={}",name);
Cache cache = caches.get(name);
if (cache == null) {
cache = new RedisCache<K, V>(redisManager,keyPrefix + name + ":", expire, principalIdFieldName);
caches.put(name, cache);
}
return cache;
}
public RedisManager getRedisManager() {
return redisManager;
}
public void setRedisManager(RedisManager redisManager) {
this.redisManager = redisManager;
}
public String getKeyPrefix() {
return keyPrefix;
}
public void setKeyPrefix(String keyPrefix) {
this.keyPrefix = keyPrefix;
}
public int getExpire() {
return expire;
}
public void setExpire(int expire) {
this.expire = expire;
}
public String getPrincipalIdFieldName() {
return principalIdFieldName;
}
public void setPrincipalIdFieldName(String principalIdFieldName) {
this.principalIdFieldName = principalIdFieldName;
}
}

@ -0,0 +1,147 @@
package org.opsli.core.security.shiro.cache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.util.CollectionUtils;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
*
* @author sunzhiqiang
* springredisredisTemplate
*/
public class RedisManager {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
//=============================common============================
/**
*
* @param key
* @param time ()
*/
public void expire(String key,long time){
redisTemplate.expire(key, time, TimeUnit.SECONDS);
}
/**
* key
* @param key
* @return true false
*/
public Boolean hasKey(String key){
return redisTemplate.hasKey(key);
}
/**
*
* @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));
}
}
}
/**
* key
* @param keys
*/
public void del(Collection keys){
redisTemplate.delete(keys);
}
//============================String=============================
/**
*
* @param key
* @return
*/
public Object get(String key){
return redisTemplate.opsForValue().get(key);
}
/**
*
* @param key
* @param value
*/
public void set(String key,Object value) {
redisTemplate.opsForValue().set(key, value);
}
/**
*
* @param key
* @param value
* @param time () time0 time0
*/
public void set(String key,Object value,long time){
if(time>0){
redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
}else{
set(key, value);
}
}
/**
* 使scan key
* @param key
* @return
*/
public Set<String> scan(String key){
Set<String> execute = this.redisTemplate.execute(new RedisCallback<Set<String>>() {
@Override
public Set<String> doInRedis(RedisConnection connection) throws DataAccessException {
Set<String> binaryKeys = new HashSet<>();
Cursor<byte[]> cursor = connection.scan(new ScanOptions.ScanOptionsBuilder().match(key).count(1000).build());
while (cursor.hasNext()) {
binaryKeys.add(new String(cursor.next()));
}
return binaryKeys;
}
});
return execute;
}
/**
* 使scan key
* session,线
* @param key
* @return
*/
public Long scanSize(String key){
long dbSize = this.redisTemplate.execute(new RedisCallback<Long>() {
@Override
public Long doInRedis(RedisConnection connection) throws DataAccessException {
long count = 0L;
Cursor<byte[]> cursor = connection.scan(ScanOptions.scanOptions().match(key).count(1000).build());
while (cursor.hasNext()) {
cursor.next();
count++;
}
return count;
}
});
return dbSize;
}
}

@ -0,0 +1,83 @@
package org.opsli.core.security.shiro.cache.serializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
import java.io.*;
/**
* <p></p>
*
* @author sunzhiqiang23
* @date 2020-04-27 19:48
*/
public class SerializeUtils implements RedisSerializer {
private static Logger logger = LoggerFactory.getLogger(SerializeUtils.class);
public static boolean isEmpty(byte[] data) {
return (data == null || data.length == 0);
}
/**
*
* @param object
* @return
* @throws SerializationException
*/
@Override
public byte[] serialize(Object object) throws SerializationException {
byte[] result = null;
if (object == null) {
return new byte[0];
}
try (
ByteArrayOutputStream byteStream = new ByteArrayOutputStream(128);
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteStream)
){
if (!(object instanceof Serializable)) {
throw new IllegalArgumentException(SerializeUtils.class.getSimpleName() + " requires a Serializable payload " +
"but received an object of type [" + object.getClass().getName() + "]");
}
objectOutputStream.writeObject(object);
objectOutputStream.flush();
result = byteStream.toByteArray();
} catch (Exception ex) {
logger.error("Failed to serialize",ex);
}
return result;
}
/**
*
* @param bytes
* @return
* @throws SerializationException
*/
@Override
public Object deserialize(byte[] bytes) throws SerializationException {
Object result = null;
if (isEmpty(bytes)) {
return null;
}
try (
ByteArrayInputStream byteStream = new ByteArrayInputStream(bytes);
ObjectInputStream objectInputStream = new ObjectInputStream(byteStream)
){
result = objectInputStream.readObject();
} catch (Exception e) {
logger.error("Failed to deserialize",e);
}
return result;
}
}

@ -0,0 +1,10 @@
package org.opsli.core.security.shiro.exception;
public class PrincipalIdNullException extends RuntimeException {
private static final String MESSAGE = "Principal Id shouldn't be null!";
public PrincipalIdNullException(Class clazz, String idMethodName) {
super(clazz + " id field: " + idMethodName + ", value is null\n" + MESSAGE);
}
}

@ -0,0 +1,18 @@
package org.opsli.core.security.shiro.exception;
public class PrincipalInstanceException extends RuntimeException {
private static final String MESSAGE = "We need a field to identify this Cache Object in Redis. "
+ "So you need to defined an id field which you can get unique id to identify this principal. "
+ "For example, if you use UserInfo as Principal class, the id field maybe userId, userName, email, etc. "
+ "For example, getUserId(), getUserName(), getEmail(), etc.\n"
+ "Default value is \"id\", that means your principal object has a method called \"getId()\"";
public PrincipalInstanceException(Class clazz, String idMethodName) {
super(clazz + " must has getter for field: " + idMethodName + "\n" + MESSAGE);
}
public PrincipalInstanceException(Class clazz, String idMethodName, Exception e) {
super(clazz + " must has getter for field: " + idMethodName + "\n" + MESSAGE, e);
}
}

@ -0,0 +1,92 @@
package org.opsli.core.security.shiro.filter;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.web.filter.authc.AuthenticatingFilter;
import org.opsli.api.base.result.ResultVo;
import org.opsli.core.security.shiro.token.OAuth2Token;
import org.opsli.core.utils.UserTokenUtil;
import org.springframework.web.bind.annotation.RequestMethod;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* oauth2
*
* 401
*
*
*
* @author
* @date 2017-05-20 13:00
*/
public class OAuth2Filter extends AuthenticatingFilter {
@Override
protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) throws Exception {
//获取请求token
String token = UserTokenUtil.getRequestToken((HttpServletRequest) request);
if(StringUtils.isBlank(token)){
return null;
}
return new OAuth2Token(token);
}
@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
if(((HttpServletRequest) request).getMethod().equals(RequestMethod.OPTIONS.name())){
return true;
}
// remeberMe ,remeberMe特殊页面需要授权
return false;
}
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
//获取请求token如果token不存在直接返回401
String token = UserTokenUtil.getRequestToken((HttpServletRequest) request);
if(StringUtils.isBlank(token)){
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
httpResponse.setHeader("Access-Control-Allow-Origin", httpServletRequest.getHeader("Origin"));
httpResponse.setContentType("application/json; charset=utf-8");
ResultVo<Object> error = ResultVo.error(401, "令牌失效");
httpResponse.getWriter().print(error.toJsonStr());
return false;
}
return executeLogin(request, response);
}
@Override
protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.setContentType("application/json;charset=utf-8");
httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
httpResponse.setHeader("Access-Control-Allow-Origin", httpServletRequest.getHeader("Origin"));
try {
//处理登录失败的异常
Throwable throwable = e.getCause() == null ? e : e.getCause();
ResultVo<Object> error = ResultVo.error(401, throwable.getMessage());
httpResponse.getWriter().print(error.toJsonStr());
} catch (IOException e1) {
}
return false;
}
}

@ -0,0 +1,76 @@
package org.opsli.core.security.shiro.realm;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.opsli.api.wrapper.system.user.UserModel;
import org.opsli.core.security.shiro.token.OAuth2Token;
import org.opsli.core.utils.UserTokenUtil;
import org.opsli.core.utils.UserUtil;
import org.springframework.stereotype.Component;
import java.util.List;
/**
*
*
* @author
* @date 2017-05-20 14:00
*/
@Component
public class OAuth2Realm extends AuthorizingRealm {
@Override
public boolean supports(AuthenticationToken token) {
return token instanceof OAuth2Token;
}
/**
* ()
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
UserModel user = (UserModel) principals.getPrimaryPrincipal();
String userId = user.getId();
//用户权限列表
List<String> permsSet = UserUtil.getUserAllPermsByUserId(userId);
//用户角色列表
List<String> rolesSet = UserUtil.getUserRolesByUserId(userId);
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.addStringPermissions(permsSet);
info.addRoles(rolesSet);
return info;
}
/**
* ()
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
String accessToken = (String) token.getPrincipal();
// 1. 校验 token 是否有效
boolean verify = UserTokenUtil.verify(accessToken);
if(!verify){
throw new IncorrectCredentialsException("token失效请重新登录");
}
// 2. 查询 用户信息
String userId = UserTokenUtil.getUserIdByToken(accessToken);
UserModel user = UserUtil.getUser(userId);
// 3. 校验账户是否锁定
if(user == null || user.getLocked().equals('1')){
throw new LockedAccountException("账号已被锁定,请联系管理员");
}
return new SimpleAuthenticationInfo(user, accessToken, getName());
}
}

@ -0,0 +1,29 @@
package org.opsli.core.security.shiro.session;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.SessionListener;
/**
* <p></p>
*
* @author sunzhiqiang23
* @date 2020-04-25 17:29
*/
public class MySessionListener implements SessionListener {
@Override
public void onStart(Session session) {
System.out.println("会话创建:" + session.getId());
}
@Override
public void onStop(Session session) {
System.out.println("会话退出:" + session.getId());
}
@Override
public void onExpiration(Session session) {
System.out.println("会话过期:" + session.getId());
}
}

@ -0,0 +1,32 @@
package org.opsli.core.security.shiro.session;
import org.apache.shiro.session.Session;
import java.util.Date;
/**
* <p></p>
*
* @author sunzhiqiang23
* @date 2020-04-27 20:52
*/
public class SessionInMemory {
private Session session;
private Date createTime;
public Session getSession() {
return session;
}
public void setSession(Session session) {
this.session = session;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
}

@ -0,0 +1,131 @@
package org.opsli.core.security.shiro.session;
import org.apache.shiro.session.mgt.SimpleSession;
import java.io.Serializable;
import java.util.Date;
/**
* <p></p>
*
* @author sunzhiqiang23
* @date 2020-04-27 20:38
*/
import java.util.Map;
/**
* @author: sunzhiqiang
* @date: 2020-04-27 20:38
* @description: SimpleSession lastAccessTimeSessionDao update
* lastAccessTime SessionDao update
*/
public class ShiroSession extends SimpleSession implements Serializable {
// 除lastAccessTime以外其他字段发生改变时为true
private boolean isChanged = false;
public ShiroSession() {
super();
this.setChanged(true);
}
public ShiroSession(String host) {
super(host);
this.setChanged(true);
}
@Override
public void setId(Serializable id) {
super.setId(id);
this.setChanged(true);
}
@Override
public void setStopTimestamp(Date stopTimestamp) {
super.setStopTimestamp(stopTimestamp);
this.setChanged(true);
}
@Override
public void setExpired(boolean expired) {
super.setExpired(expired);
this.setChanged(true);
}
@Override
public void setTimeout(long timeout) {
super.setTimeout(timeout);
this.setChanged(true);
}
@Override
public void setHost(String host) {
super.setHost(host);
this.setChanged(true);
}
@Override
public void setAttributes(Map<Object, Object> attributes) {
super.setAttributes(attributes);
this.setChanged(true);
}
@Override
public void setAttribute(Object key, Object value) {
super.setAttribute(key, value);
this.setChanged(true);
}
@Override
public Object removeAttribute(Object key) {
this.setChanged(true);
return super.removeAttribute(key);
}
/**
*
*/
@Override
public void stop() {
super.stop();
this.setChanged(true);
}
/**
*
*/
@Override
protected void expire() {
this.stop();
this.setExpired(true);
}
public boolean isChanged() {
return isChanged;
}
public void setChanged(boolean isChanged) {
this.isChanged = isChanged;
}
@Override
public boolean equals(Object obj) {
return super.equals(obj);
}
@Override
protected boolean onEquals(SimpleSession ss) {
return super.onEquals(ss);
}
@Override
public int hashCode() {
return super.hashCode();
}
@Override
public String toString() {
return super.toString();
}
}

@ -0,0 +1,53 @@
package org.opsli.core.security.shiro.session;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.SessionKey;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.apache.shiro.web.session.mgt.WebSessionKey;
import javax.servlet.ServletRequest;
import java.io.Serializable;
/**
* <p>访redis</p>
*
* @author sunzhiqiang23
* @date 2020-04-27 20:58
*/
@Slf4j
public class ShiroSessionManager extends DefaultWebSessionManager {
/**
* session
* 访redis
* @param sessionKey
* @return
* @throws UnknownSessionException
*/
@Override
protected Session retrieveSession(SessionKey sessionKey) throws UnknownSessionException {
Serializable sessionId = getSessionId(sessionKey);
ServletRequest request = null;
if (sessionKey instanceof WebSessionKey) {
request = ((WebSessionKey) sessionKey).getServletRequest();
}
if (request != null && null != sessionId) {
Object sessionObj = request.getAttribute(sessionId.toString());
if (sessionObj != null) {
log.debug("read session from request");
return (Session) sessionObj;
}
}
Session session = super.retrieveSession(sessionKey);
if (request != null && null != sessionId) {
request.setAttribute(sessionId.toString(), session);
}
return session;
}
}

@ -0,0 +1,29 @@
package org.opsli.core.security.shiro.token;
import org.apache.shiro.authc.AuthenticationToken;
/**
* jwt token
*
* @author parker
* @date 2017-05-20 13:22
*/
public class JwtToken implements AuthenticationToken {
private String token;
public JwtToken(String token){
this.token = token;
}
@Override
public String getPrincipal() {
return token;
}
@Override
public Object getCredentials() {
return token;
}
}

@ -0,0 +1,29 @@
package org.opsli.core.security.shiro.token;
import org.apache.shiro.authc.AuthenticationToken;
/**
* OAuth2 token
*
* @author
* @date 2017-05-20 13:22
*/
public class OAuth2Token implements AuthenticationToken {
private String token;
public OAuth2Token(String token){
this.token = token;
}
@Override
public String getPrincipal() {
return token;
}
@Override
public Object getCredentials() {
return token;
}
}

@ -0,0 +1,34 @@
/**
* Copyright 2018 http://www.renren.io
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.opsli.core.security.shiro.utils;
/**
* RedisKeys
*
* @author Mark sunlightcs@gmail.com
* @since 3.0.0 2017-07-18
*/
public class RedisKeys {
public static String getSysConfigKey(String key){
return "system:config:" + key;
}
public static String getShiroSessionKey(String key){
return "sessionid:" + key;
}
}

@ -0,0 +1,84 @@
/**
* Copyright 2018 http://www.renren.io
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.opsli.core.security.shiro.utils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.opsli.api.wrapper.system.user.UserModel;
/**
* Shiro
*
* @author
* @date 20161112 9:49:19
*/
public class ShiroUtils {
/** 加密算法 */
public final static String hashAlgorithmName = "MD5";
/** 循环次数 */
public final static int hashIterations = 1;
public static String sha256(String password, String salt) {
return new SimpleHash(hashAlgorithmName, password, salt, hashIterations).toString();
}
public static Session getSession() {
return SecurityUtils.getSubject().getSession();
}
public static Subject getSubject() {
return SecurityUtils.getSubject();
}
public static UserModel getUser() {
return (UserModel) SecurityUtils.getSubject().getPrincipal();
}
public static String getUserId() {
return getUser().getId();
}
public static void setSessionAttribute(Object key, Object value) {
getSession().setAttribute(key, value);
}
public static Object getSessionAttribute(Object key) {
return getSession().getAttribute(key);
}
public static boolean isLogin() {
return SecurityUtils.getSubject().getPrincipal() != null;
}
public static void logout() {
SecurityUtils.getSubject().logout();
}
public static String getKaptcha(String key) throws RuntimeException {
Object kaptcha = getSessionAttribute(key);
if(kaptcha == null){
throw new RuntimeException("验证码已失效");
}
getSession().removeAttribute(key);
return kaptcha.toString();
}
}

@ -0,0 +1,34 @@
package org.opsli.core.utils;
import java.io.UnsupportedEncodingException;
import java.util.Base64;
/**
* Base64
* @author
* @date 2018/11/05 23:10
*/
public final class Base64ConvertUtil {
/**
*
* @param str
* @return java.lang.String
*/
public static String encode(String str) throws UnsupportedEncodingException {
byte[] encodeBytes = Base64.getEncoder().encode(str.getBytes("utf-8"));
return new String(encodeBytes);
}
/**
*
* @param str
* @return java.lang.String
*/
public static String decode(String str) throws UnsupportedEncodingException {
byte[] decodeBytes = Base64.getDecoder().decode(str.getBytes("utf-8"));
return new String(decodeBytes);
}
// ==============
private Base64ConvertUtil(){}
}

@ -0,0 +1,88 @@
package org.opsli.core.utils;
import com.alibaba.fastjson.JSONObject;
import com.google.code.kaptcha.Producer;
import org.apache.commons.lang3.StringUtils;
import org.opsli.plugins.redis.RedisPlugin;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.awt.image.BufferedImage;
/**
*
*
* @author parker
* @since 2.0.0 2018-02-10
*/
@Component
public class CaptchaUtil{
/** 缓存前缀 */
private static final String PREFIX = "opsli:temp:captcha:";
/** 默认验证码保存 5 分钟 */
private static final int TIME_OUT = 300;
/** Redis插件 */
private static RedisPlugin redisPlugin;
/** 谷歌验证码 */
private static Producer producer;
/**
*
* @param uuid
* @return
*/
public static BufferedImage getCaptcha(String uuid) {
if(StringUtils.isBlank(uuid)){
throw new RuntimeException("uuid不能为空");
}
//生成文字验证码
String code = producer.createText();
boolean ret = redisPlugin.put(PREFIX + uuid, code, TIME_OUT);
if(ret){
return producer.createImage(code);
}
return null;
}
/**
*
* @param uuid
* @param code
* @return
*/
public static boolean validate(String uuid, String code) {
if(StringUtils.isEmpty(uuid)) return false;
// 验证码
String codeTemp = (String) redisPlugin.get(PREFIX + uuid);
if(StringUtils.isEmpty(codeTemp)){
return false;
}
//删除验证码
redisPlugin.del(PREFIX + uuid);
return codeTemp.equalsIgnoreCase(code);
}
// ==========================
@Autowired
public void setRedisPlugin(RedisPlugin redisPlugin) {
CaptchaUtil.redisPlugin = redisPlugin;
}
@Autowired
public void setProducer(Producer producer) {
CaptchaUtil.producer = producer;
}
}

@ -6,8 +6,8 @@ import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.opsli.api.base.result.ResultVo;
import org.opsli.api.web.system.dict.DictDetailApi;
import org.opsli.api.wrapper.system.dict.DictModel;
import org.opsli.api.wrapper.system.dict.SysDictDetailModel;
import org.opsli.api.wrapper.system.dict.DictWrapper;
import org.opsli.api.wrapper.system.dict.DictDetailModel;
import org.opsli.common.constants.CacheConstants;
import org.opsli.common.constants.DictConstants;
import org.opsli.core.cache.local.CacheUtil;
@ -50,29 +50,31 @@ public class DictUtil {
* @return
*/
public static String getDictNameByValue(String typeCode, String dictValue, String defaultVal){
try {
String dictName = "";
SysDictDetailModel cacheModel = CacheUtil.getHash(DictConstants.CACHE_PREFIX_VALUE + typeCode,
dictValue, SysDictDetailModel.class);
if (cacheModel != null){
dictName = cacheModel.getDictName();
}
if (StringUtils.isNotEmpty(dictName)) return dictName;
String dictName = "";
DictDetailModel cacheModel = CacheUtil.getHash(DictConstants.CACHE_PREFIX_VALUE + typeCode,
dictValue, DictDetailModel.class);
if (cacheModel != null){
dictName = cacheModel.getDictName();
}
if (StringUtils.isNotEmpty(dictName)) return dictName;
// 防止缓存穿透判断
boolean hasNilFlag = CacheUtil.hasNilFlag("dict:" + typeCode + ":" + dictValue);
if(hasNilFlag){
return defaultVal;
}
// 防止缓存穿透判断
boolean hasNilFlag = CacheUtil.hasNilFlag("dict:" + typeCode + ":" + dictValue);
if(hasNilFlag){
return defaultVal;
}
// 锁凭证 redisLock 贯穿全程
RedisLock redisLock = new RedisLock();
redisLock.setLockName("dictLock:" + typeCode + ":" + dictValue)
.setAcquireTimeOut(3000L)
.setLockTimeOut(5000L);
// 锁凭证 redisLock 贯穿全程
RedisLock redisLock = new RedisLock();
redisLock.setLockName("dictLock:" + typeCode + ":" + dictValue)
.setAcquireTimeOut(3000L)
.setLockTimeOut(5000L);
try {
// 这里增加分布式锁 防止缓存击穿
// ============ 尝试加锁
redisLock = redisLockPlugins.tryLock(redisLock);
@ -81,40 +83,42 @@ public class DictUtil {
}
// 查询数据库 并保存到缓存内
ResultVo<List<SysDictDetailModel>> resultVo = dictDetailApi.findListByTypeCode(typeCode);
ResultVo<List<DictDetailModel>> resultVo = dictDetailApi.findListByTypeCode(typeCode);
if(resultVo.isSuccess()){
List<SysDictDetailModel> sysDictDetailModels = resultVo.getData();
for (SysDictDetailModel model : sysDictDetailModels) {
List<DictDetailModel> dictDetailModels = resultVo.getData();
for (DictDetailModel model : dictDetailModels) {
if(model.getDictValue().equals(dictValue)){
// 名称
dictName = model.getDictName();
DictModel dictModel = new DictModel();
dictModel.setTypeCode(model.getTypeCode());
dictModel.setDictName(model.getDictName());
dictModel.setDictValue(model.getDictValue());
dictModel.setModel(model);
DictWrapper dictWrapperModel = new DictWrapper();
dictWrapperModel.setTypeCode(model.getTypeCode());
dictWrapperModel.setDictName(model.getDictName());
dictWrapperModel.setDictValue(model.getDictValue());
dictWrapperModel.setModel(model);
// 保存至缓存
DictUtil.put(dictModel);
DictUtil.put(dictWrapperModel);
break;
}
}
}
// ============ 释放锁
redisLockPlugins.unLock(redisLock);
redisLock = null;
// 如果名称还是 为空 则赋默认值
if(StringUtils.isEmpty(dictName)){
// 加入缓存防穿透
// 设置空变量 用于防止穿透判断
CacheUtil.putNilFlag("dict:" + typeCode + ":" + dictValue);
dictName = defaultVal;
}
return dictName;
}catch (Exception e){
log.error(e.getMessage(),e);
return defaultVal;
}finally {
// ============ 释放锁
redisLockPlugins.unLock(redisLock);
redisLock = null;
}
// 如果名称还是 为空 则赋默认值
if(StringUtils.isEmpty(dictName)){
// 加入缓存防穿透
// 设置空变量 用于防止穿透判断
CacheUtil.putNilFlag("dict:" + typeCode + ":" + dictValue);
dictName = defaultVal;
}
return dictName;
}
/**
@ -125,26 +129,28 @@ public class DictUtil {
* @return
*/
public static String getDictValueByName(String typeCode, String dictName, String defaultVal){
try {
String dictValue = "";
SysDictDetailModel cacheModel = CacheUtil.getHash(DictConstants.CACHE_PREFIX_NAME + typeCode,
dictName, SysDictDetailModel.class);
if (cacheModel != null){
dictValue = cacheModel.getDictValue();
}
if (StringUtils.isNotEmpty(dictValue)) return dictValue;
// 防止缓存穿透判断
boolean hasNilFlag = CacheUtil.hasNilFlag("dict:" + typeCode + ":" + dictName);
if(hasNilFlag){
return defaultVal;
}
String dictValue = "";
DictDetailModel cacheModel = CacheUtil.getHash(DictConstants.CACHE_PREFIX_NAME + typeCode,
dictName, DictDetailModel.class);
if (cacheModel != null){
dictValue = cacheModel.getDictValue();
}
if (StringUtils.isNotEmpty(dictValue)) return dictValue;
// 防止缓存穿透判断
boolean hasNilFlag = CacheUtil.hasNilFlag("dict:" + typeCode + ":" + dictName);
if(hasNilFlag){
return defaultVal;
}
// 锁凭证 redisLock 贯穿全程
RedisLock redisLock = new RedisLock();
redisLock.setLockName("dictLock:" + typeCode + ":" + dictName)
.setAcquireTimeOut(3000L)
.setLockTimeOut(10000L);
// 锁凭证 redisLock 贯穿全程
RedisLock redisLock = new RedisLock();
redisLock.setLockName("dictLock:" + typeCode + ":" + dictName)
.setAcquireTimeOut(3000L)
.setLockTimeOut(10000L);
try {
// 这里增加分布式锁 防止缓存击穿
// ============ 尝试加锁
redisLock = redisLockPlugins.tryLock(redisLock);
@ -153,40 +159,43 @@ public class DictUtil {
}
// 查询数据库 并保存到缓存内
ResultVo<List<SysDictDetailModel>> resultVo = dictDetailApi.findListByTypeCode(typeCode);
ResultVo<List<DictDetailModel>> resultVo = dictDetailApi.findListByTypeCode(typeCode);
if(resultVo.isSuccess()){
List<SysDictDetailModel> sysDictDetailModels = resultVo.getData();
for (SysDictDetailModel model : sysDictDetailModels) {
List<DictDetailModel> dictDetailModels = resultVo.getData();
for (DictDetailModel model : dictDetailModels) {
if(model.getDictName().equals(dictName)){
// 值
dictValue = model.getDictValue();
DictModel dictModel = new DictModel();
dictModel.setTypeCode(model.getTypeCode());
dictModel.setDictName(model.getDictName());
dictModel.setDictValue(model.getDictValue());
dictModel.setModel(model);
DictWrapper dictWrapperModel = new DictWrapper();
dictWrapperModel.setTypeCode(model.getTypeCode());
dictWrapperModel.setDictName(model.getDictName());
dictWrapperModel.setDictValue(model.getDictValue());
dictWrapperModel.setModel(model);
// 保存至缓存
DictUtil.put(dictModel);
DictUtil.put(dictWrapperModel);
break;
}
}
}
// ============ 释放锁
redisLockPlugins.unLock(redisLock);
redisLock = null;
// 如果值还是 为空 则赋默认值
if(StringUtils.isEmpty(dictValue)){
// 加入缓存防穿透
// 设置空变量 用于防止穿透判断
CacheUtil.putNilFlag("dict:" + typeCode + ":" + dictName);
dictValue = defaultVal;
}
return dictValue;
}catch (Exception e){
log.error(e.getMessage(),e);
return defaultVal;
}finally {
// ============ 释放锁
redisLockPlugins.unLock(redisLock);
redisLock = null;
}
// 如果值还是 为空 则赋默认值
if(StringUtils.isEmpty(dictValue)){
// 加入缓存防穿透
// 设置空变量 用于防止穿透判断
CacheUtil.putNilFlag("dict:" + typeCode + ":" + dictName);
dictValue = defaultVal;
}
return dictValue;
}
/**
@ -194,8 +203,8 @@ public class DictUtil {
* @param typeCode
* @return
*/
public static List<DictModel> getDictList(String typeCode){
List<DictModel> dictModels = Lists.newArrayList();
public static List<DictWrapper> getDictList(String typeCode){
List<DictWrapper> dictWrapperModels = Lists.newArrayList();
try {
String key = CacheUtil.handleKey(CacheConstants.EDEN_HASH_DATA, DictConstants.CACHE_PREFIX_VALUE + typeCode);
Map<Object, Object> dictMap = redisPlugin.hGetAll(key);
@ -206,18 +215,18 @@ public class DictUtil {
if(jsonObject == null){
continue;
}
SysDictDetailModel model = jsonObject.toJavaObject(SysDictDetailModel.class);
DictModel dictModel = new DictModel();
dictModel.setTypeCode(typeCode);
dictModel.setDictName(model.getDictName());
dictModel.setDictValue(model.getDictValue());
dictModels.add(dictModel);
DictDetailModel model = jsonObject.toJavaObject(DictDetailModel.class);
DictWrapper dictWrapperModel = new DictWrapper();
dictWrapperModel.setTypeCode(typeCode);
dictWrapperModel.setDictName(model.getDictName());
dictWrapperModel.setDictValue(model.getDictValue());
dictWrapperModels.add(dictWrapperModel);
}
}catch (Exception e){
log.error(e.getMessage(),e);
dictModels = Lists.newArrayList();
dictWrapperModels = Lists.newArrayList();
}
return dictModels;
return dictWrapperModels;
}
@ -229,7 +238,7 @@ public class DictUtil {
* @param model
* @return
*/
public static void put(DictModel model){
public static void put(DictWrapper model){
CacheUtil.putEdenHash(DictConstants.CACHE_PREFIX_NAME + model.getTypeCode(),
model.getDictName(), model.getModel());
CacheUtil.putEdenHash(DictConstants.CACHE_PREFIX_VALUE + model.getTypeCode(),
@ -244,7 +253,7 @@ public class DictUtil {
* @param model
* @return
*/
public static void del(DictModel model){
public static void del(DictWrapper model){
CacheUtil.delEdenHash(DictConstants.CACHE_PREFIX_NAME + model.getTypeCode(), model.getDictName());
CacheUtil.delEdenHash(DictConstants.CACHE_PREFIX_VALUE + model.getTypeCode(), model.getDictValue());
}
@ -255,9 +264,9 @@ public class DictUtil {
* @return
*/
public static void delAll(String typeCode){
List<DictModel> dictList = DictUtil.getDictList(typeCode);
for (DictModel dictModel : dictList) {
DictUtil.del(dictModel);
List<DictWrapper> dictWrapperList = DictUtil.getDictList(typeCode);
for (DictWrapper dictWrapperModel : dictWrapperList) {
DictUtil.del(dictWrapperModel);
}
}
@ -276,6 +285,6 @@ public class DictUtil {
@Autowired
public void setDictDetailApi(DictDetailApi dictDetailApi) {
DictUtil.dictDetailApi = dictDetailApi;
// DictUtil.dictDetailApi = dictDetailApi;
}
}

@ -5,7 +5,7 @@ import com.alibaba.excel.support.ExcelTypeEnum;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.opsli.api.wrapper.system.dict.DictModel;
import org.opsli.api.wrapper.system.dict.DictWrapper;
import org.opsli.common.enums.ExcelOperate;
import org.opsli.plugins.excel.ExcelPlugin;
import org.opsli.plugins.excel.annotation.ExcelInfo;
@ -75,7 +75,7 @@ public class ExcelUtil extends ExcelPlugin {
// 字段名 - 字典code
Map<String,String> fieldAndTypeCode = Maps.newHashMap();
// 字典code - 字典值
Map<String,List<DictModel>> typeCodeAndValue = null;
Map<String,List<DictWrapper>> typeCodeAndValue = null;
Field[] fields = ReflectUtil.getFields(typeClazz);
for (Field field : fields) {
@ -116,7 +116,7 @@ public class ExcelUtil extends ExcelPlugin {
* @return
*/
private <T> void handleDict(T data, ExcelOperate operate, Map<String,String> fieldAndTypeCode,
Map<String,List<DictModel>> typeCodeAndValue
Map<String,List<DictWrapper>> typeCodeAndValue
){
// 如果没有字典 则直接退出
if(fieldAndTypeCode.size() == 0 || typeCodeAndValue == null || typeCodeAndValue.size() == 0){
@ -129,9 +129,9 @@ public class ExcelUtil extends ExcelPlugin {
String fieldName = entry.getKey();
String typeCode = entry.getValue();
String fieldValue = (String) ReflectUtil.getFieldValue(data, fieldName);
List<DictModel> dictModels = typeCodeAndValue.get(typeCode);
List<DictWrapper> dictWrapperModels = typeCodeAndValue.get(typeCode);
// 匹配字典
String dictVal = this.matchingDict(dictModels, fieldValue, operate);
String dictVal = this.matchingDict(dictWrapperModels, fieldValue, operate);
if(StringUtils.isEmpty(dictVal)){
continue;
}
@ -148,43 +148,43 @@ public class ExcelUtil extends ExcelPlugin {
* @param fieldAndTypeCode
* @return
*/
public Map<String,List<DictModel>> getDictMap(Map<String,String> fieldAndTypeCode){
public Map<String,List<DictWrapper>> getDictMap(Map<String,String> fieldAndTypeCode){
// 字典code - 字典值
Map<String,List<DictModel>> typeCodeAndValue = Maps.newHashMap();
Map<String,List<DictWrapper>> typeCodeAndValue = Maps.newHashMap();
// 取Redis 值
for (Map.Entry<String, String> entry : fieldAndTypeCode.entrySet()) {
String typeCode = entry.getValue();
List<DictModel> dictList = DictUtil.getDictList(typeCode);
List<DictWrapper> dictWrapperList = DictUtil.getDictList(typeCode);
// 如果字典 List 为空 则走下一个
if(dictList == null || dictList.size() == 0) continue;
typeCodeAndValue.put(typeCode, dictList);
if(dictWrapperList == null || dictWrapperList.size() == 0) continue;
typeCodeAndValue.put(typeCode, dictWrapperList);
}
return typeCodeAndValue;
}
/**
*
* @param dictModels
* @param dictWrapperModels
* @param fieldValue
* @param operate
* @return
*/
private String matchingDict(List<DictModel> dictModels, String fieldValue, ExcelOperate operate){
private String matchingDict(List<DictWrapper> dictWrapperModels, String fieldValue, ExcelOperate operate){
String val = "";
for (DictModel dictModel : dictModels) {
for (DictWrapper dictWrapperModel : dictWrapperModels) {
// 读操作
if(ExcelOperate.READ == operate){
// 判断 Excel 读入 字典名称是否与 当前字典匹配
if(dictModel.getDictName().equals(fieldValue)){
val = dictModel.getDictValue();
if(dictWrapperModel.getDictName().equals(fieldValue)){
val = dictWrapperModel.getDictValue();
break;
}
}
// 写操作
else if(ExcelOperate.WRITE == operate){
// 判断 Excel 写出 字典值是否与 当前字典匹配
if(dictModel.getDictValue().equals(fieldValue)){
val = dictModel.getDictName();
if(dictWrapperModel.getDictValue().equals(fieldValue)){
val = dictWrapperModel.getDictName();
break;
}
}

@ -0,0 +1,110 @@
package org.opsli.core.utils;
import cn.hutool.setting.dialect.Props;
import cn.hutool.setting.dialect.PropsUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.DecodedJWT;
import lombok.extern.slf4j.Slf4j;
import org.opsli.common.constants.SignConstants;
import java.io.UnsupportedEncodingException;
import java.util.Date;
/**
* JWT
* @author sunzhiqiang23
* @date 2020/05/29 21:23
*/
@Slf4j
public final class JwtUtil {
/**
* 120
*/
public static final long EXPIRE;
/**
* JWT(Base64)
*/
private static final String encryptJWTKey="a30ade6452725123436288ccae58570738ee";
static {
Props props = PropsUtil.get("application.yaml");
// token 有效时间
EXPIRE = props.getLong("opsli.token-effective-time", 120L) * 60 * 1000;
}
/**
* JWT
* @param token Token
* @return boolean
*/
public static boolean verify(String token) {
try {
String secret = getClaim(token, SignConstants.ACCOUNT) + Base64ConvertUtil.decode(encryptJWTKey);
Algorithm algorithm = Algorithm.HMAC256(secret);
JWTVerifier verifier = JWT.require(algorithm).build();
verifier.verify(token);
return true;
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("认证解密异常:" + e.getMessage());
}
}
/**
* Token
* @param token
* @param claim
* @return java.lang.String
*/
public static String getClaim(String token, String claim) {
try {
DecodedJWT jwt = JWT.decode(token);
return jwt.getClaim(claim).asString();
} catch (JWTDecodeException e) {
throw new RuntimeException("解密异常:" + e.getMessage());
}
}
/**
*
* @param account
* @return java.lang.String Token
*/
public static String sign(String account, String userId) {
try {
// 帐号加JWT私钥加密
String secret = account + Base64ConvertUtil.decode(encryptJWTKey);
// 此处过期时间是以毫秒为单位所以乘以1000
Date date = new Date(System.currentTimeMillis() + EXPIRE);
Algorithm algorithm = Algorithm.HMAC256(secret);
// 附带account帐号信息
return JWT.create()
.withClaim(SignConstants.ACCOUNT, account)
.withClaim(SignConstants.USER_ID, userId)
.withClaim(SignConstants.TIMESTAMP, String.valueOf(System.currentTimeMillis()))
// token 过期时间
.withExpiresAt(date)
.sign(algorithm);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("加密异常:" + e.getMessage());
}
}
public static void main(String[] args) {
String aaaaaa = JwtUtil.sign("aaaaaa","123123");
boolean verify = JwtUtil.verify(aaaaaa);
System.out.println(aaaaaa);
System.out.println(verify);
}
// ==================
private JwtUtil(){}
}

@ -0,0 +1,57 @@
package org.opsli.core.utils;
import java.security.MessageDigest;
import java.util.UUID;
/**
* token
*
* @author Parker
* @date 2017-05-20 14:41
*/
public final class TokenGenerator {
public static String generateValue() {
return generateValue(UUID.randomUUID().toString());
}
private static final char[] hexCode = "0123456789abcdef".toCharArray();
/**
* Token
* @param param
* @return
*/
public static String generateValue(String param) {
try {
MessageDigest algorithm = MessageDigest.getInstance("MD5");
algorithm.reset();
algorithm.update(param.getBytes());
byte[] messageDigest = algorithm.digest();
return toHexString(messageDigest);
} catch (Exception e) {
throw new RuntimeException("生成Token失败", e);
}
}
public static String toHexString(byte[] data) {
if(data == null) {
return null;
}
StringBuilder r = new StringBuilder(data.length*2);
for ( byte b : data) {
r.append(hexCode[(b >> 4) & 0xF]);
r.append(hexCode[(b & 0xF)]);
}
return r.toString();
}
// =========================
private TokenGenerator(){}
}

@ -0,0 +1,183 @@
package org.opsli.core.utils;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.opsli.api.base.result.ResultVo;
import org.opsli.api.wrapper.system.user.UserModel;
import org.opsli.common.constants.SignConstants;
import org.opsli.plugins.redis.RedisPlugin;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
/**
* User Token Util
*
* @author parker
*/
@Slf4j
@Component
public class UserTokenUtil {
/** 缓存前缀 */
private static final String PREFIX = "opsli:ticket:";
/** Redis插件 */
private static RedisPlugin redisPlugin;
/**
* user Token
* @param user
* @return
*/
public static ResultVo<Map<String,Object>> createToken(UserModel user) {
if (user == null) {
return ResultVo.error("生成Token失败");
}
Map<String,Object> map = Maps.newHashMapWithExpectedSize(2);
try {
// 生效时间
int expire = Integer.parseInt(
String.valueOf(JwtUtil.EXPIRE)
);
// 生成 Token 包含 username userId timestamp
String signToken = JwtUtil.sign(user.getUsername(), user.getId());
// 生成MD5 16进制码 用于缩减存储
String signTokenHex = new Md5Hash(signToken).toHex();
// 获得当前时间戳时间
long timestamp = Long.parseLong(JwtUtil.getClaim(signToken, SignConstants.TIMESTAMP));
DateTime currDate = DateUtil.date(timestamp);
// 获得失效偏移量时间
DateTime dateTime = DateUtil.offsetMillisecond(currDate, expire);
long endTimestamp = dateTime.getTime();
// token 缓存真实失效时间 建议大于 最终时间 -- 多加了20分钟的失效时间
// 在redis存一份 token 是为了防止 认为造假
boolean tokenFlag = redisPlugin.put(PREFIX + signTokenHex, endTimestamp, expire + 20);
if(tokenFlag){
map.put("token", signToken);
map.put("expire", endTimestamp);
return ResultVo.success(map);
}
return ResultVo.error("生成Token失败");
}catch (Exception e){
log.error(e.getMessage() , e);
return ResultVo.error(e.getMessage());
}
}
/**
* Token ID
* @param token
* @return
*/
public static String getUserIdByToken(String token) {
if(StringUtils.isEmpty(token)) return null;
String userId = "";
try {
userId = JwtUtil.getClaim(token, SignConstants.USER_ID);
}catch (Exception e){}
return userId;
}
/**
* Token username
* @param token
* @return
*/
public static String getUserNameByToken(String token) {
if(StringUtils.isEmpty(token)) return null;
String username = "";
try {
username = JwtUtil.getClaim(token, SignConstants.ACCOUNT);
}catch (Exception e){}
return username;
}
/**
* 退
* @param token
*/
public static void logout(String token) {
if(StringUtils.isEmpty(token)) return;
try {
// 生成MD5 16进制码 用于缩减存储
String signTokenHex = new Md5Hash(token).toHex();
redisPlugin.del(PREFIX + signTokenHex);
}catch (Exception e){}
}
/**
* token
* @param token
*/
public static boolean verify(String token) {
if(StringUtils.isEmpty(token)) return false;
try {
// 1. 校验是否是有效的 token
boolean tokenVerify = JwtUtil.verify(token);
if(!tokenVerify){
return false;
}
// 2. 校验当前缓存中token是否失效
// 生成MD5 16进制码 用于缩减存储
String signTokenHex = new Md5Hash(token).toHex();
Long endTimestamp = (Long) redisPlugin.get(PREFIX + signTokenHex);
if(endTimestamp == null){
return false;
}
// JWT 自带过期校验 无需多做处理
}catch (TokenExpiredException e){
return false;
}catch (Exception e){
return false;
}
return true;
}
// ==========================
/**
* token
*/
public static String getRequestToken(HttpServletRequest httpRequest){
//从header中获取token
String token = httpRequest.getHeader("token");
//如果header中不存在token则从参数中获取token
if(StringUtils.isBlank(token)){
token = httpRequest.getParameter("token");
}
return token;
}
@Autowired
public void setRedisPlugin(RedisPlugin redisPlugin) {
UserTokenUtil.redisPlugin = redisPlugin;
}
}

@ -1,5 +1,22 @@
package org.opsli.core.utils;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.opsli.api.base.result.ResultVo;
import org.opsli.api.web.system.user.UserApi;
import org.opsli.api.wrapper.system.menu.MenuModel;
import org.opsli.api.wrapper.system.user.UserModel;
import org.opsli.common.api.TokenThreadLocal;
import org.opsli.core.cache.local.CacheUtil;
import org.opsli.plugins.redis.RedisLockPlugins;
import org.opsli.plugins.redis.lock.RedisLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* @BelongsProject: opsli-boot
* @BelongsPackage: org.opsli.core.utils
@ -7,20 +24,483 @@ package org.opsli.core.utils;
* @CreateTime: 2020-09-19 20:03
* @Description:
*/
public final class UserUtil {
@Slf4j
@Component
public class UserUtil {
/** 超级管理员名称 */
private static final String SUPER_ADMIN = "system";
private static final String PREFIX_ID = "userId:";
private static final String PREFIX_ID_ROLES = "userId:roles:";
private static final String PREFIX_ID_PERMISSIONS = "userId:permissions:";
private static final String PREFIX_ID_MENUS = "userId:menus:";
private static final String PREFIX_USERNAME = "username:";
/** Redis分布式锁 */
private static RedisLockPlugins redisLockPlugins;
/** 用户Service */
private static UserApi userApi;
/**
*
* @return
*/
public static UserModel getUser(){
String token = TokenThreadLocal.get();
if(StringUtils.isEmpty(token)){
return null;
}
String userId = UserTokenUtil.getUserIdByToken(token);
UserModel user = getUser(userId);
if(user == null){
throw new RuntimeException("Token 失效");
}
return user;
}
/**
* ID
* @param userId
* @return
*/
public static UserModel getUser(String userId){
// 先从缓存里拿
UserModel userModel = CacheUtil.get(PREFIX_ID + userId, UserModel.class);
if (userModel != null){
return userModel;
}
// 拿不到 --------
// 防止缓存穿透判断
boolean hasNilFlag = CacheUtil.hasNilFlag(PREFIX_ID + userId);
if(hasNilFlag){
return null;
}
// 锁凭证 redisLock 贯穿全程
RedisLock redisLock = new RedisLock();
redisLock.setLockName(PREFIX_ID + userId)
.setAcquireTimeOut(3000L)
.setLockTimeOut(5000L);
try {
// 这里增加分布式锁 防止缓存击穿
// ============ 尝试加锁
redisLock = redisLockPlugins.tryLock(redisLock);
if(redisLock == null){
return null;
}
// 查询数据库
UserModel userModelTemp = new UserModel();
userModelTemp.setId(userId);
// 设置为系统内部调用 否则 会拿到 空值
userModelTemp.setIzApi(true);
ResultVo<UserModel> resultVo = userApi.get(userModelTemp);
if(resultVo.isSuccess()){
userModel = resultVo.getData();
// 存入缓存
CacheUtil.put(PREFIX_ID + userId, userModel);
}
}catch (Exception e){
log.error(e.getMessage(),e);
}finally {
// ============ 释放锁
redisLockPlugins.unLock(redisLock);
redisLock = null;
}
if(userModel == null){
// 设置空变量 用于防止穿透判断
CacheUtil.putNilFlag(PREFIX_ID + userId);
return null;
}
return userModel;
}
private UserUtil(){}
/**
* userName
* @param userName
* @return
*/
public static UserModel getUserByUserName(String userName){
// 先从缓存里拿
UserModel userModel = CacheUtil.get(PREFIX_USERNAME + userName, UserModel.class);
if (userModel != null){
return userModel;
}
// 拿不到 --------
// 防止缓存穿透判断
boolean hasNilFlag = CacheUtil.hasNilFlag(PREFIX_USERNAME + userName);
if(hasNilFlag){
return null;
}
// 锁凭证 redisLock 贯穿全程
RedisLock redisLock = new RedisLock();
redisLock.setLockName(PREFIX_USERNAME + userName)
.setAcquireTimeOut(3000L)
.setLockTimeOut(5000L);
try {
// 这里增加分布式锁 防止缓存击穿
// ============ 尝试加锁
redisLock = redisLockPlugins.tryLock(redisLock);
if(redisLock == null){
return null;
}
// 查询数据库
ResultVo<UserModel> resultVo = userApi.getUserByUsername(userName);
if(resultVo.isSuccess()){
userModel = resultVo.getData();
// 存入缓存
CacheUtil.put(PREFIX_USERNAME + userName, userModel);
}
}catch (Exception e){
log.error(e.getMessage(),e);
}finally {
// ============ 释放锁
redisLockPlugins.unLock(redisLock);
redisLock = null;
}
if(userModel == null){
// 设置空变量 用于防止穿透判断
CacheUtil.putNilFlag(PREFIX_USERNAME + userName);
return null;
}
return userModel;
}
/**
* userId
* @param userId
* @return
*/
public static List<String> getUserRolesByUserId(String userId){
List<String> roles = null;
// 先从缓存里拿
List rolesObj = CacheUtil.get(PREFIX_ID_ROLES + userId, List.class);
if (rolesObj != null && !rolesObj.isEmpty()){
roles = Lists.newArrayListWithCapacity(rolesObj.size());
for (Object role : rolesObj) {
roles.add((String) role);
}
return roles;
}
// 拿不到 --------
// 防止缓存穿透判断
boolean hasNilFlag = CacheUtil.hasNilFlag(PREFIX_ID_ROLES + userId);
if(hasNilFlag){
return null;
}
// 锁凭证 redisLock 贯穿全程
RedisLock redisLock = new RedisLock();
redisLock.setLockName(PREFIX_ID_ROLES + userId)
.setAcquireTimeOut(3000L)
.setLockTimeOut(5000L);
try {
// 这里增加分布式锁 防止缓存击穿
// ============ 尝试加锁
redisLock = redisLockPlugins.tryLock(redisLock);
if(redisLock == null){
return null;
}
// 查询数据库
ResultVo<List<String>> resultVo = userApi.getRolesByUserId(userId);
if(resultVo.isSuccess()){
roles = resultVo.getData();
// 存入缓存
CacheUtil.put(PREFIX_ID_ROLES + userId, roles);
}
}catch (Exception e){
log.error(e.getMessage(),e);
}finally {
// ============ 释放锁
redisLockPlugins.unLock(redisLock);
redisLock = null;
}
if(roles == null){
// 设置空变量 用于防止穿透判断
CacheUtil.putNilFlag(PREFIX_ID_ROLES + userId);
return null;
}
return roles;
}
/**
* userId
* @param userId
* @return
*/
public static List<String> getUserAllPermsByUserId(String userId){
List<String> permissions = null;
// 先从缓存里拿
List permissionsObj = CacheUtil.get(PREFIX_ID_PERMISSIONS + userId, List.class);
if (permissionsObj != null && !permissionsObj.isEmpty()){
permissions = Lists.newArrayListWithCapacity(permissionsObj.size());
for (Object permission : permissionsObj) {
permissions.add((String) permission);
}
return permissions;
}
// 拿不到 --------
// 防止缓存穿透判断
boolean hasNilFlag = CacheUtil.hasNilFlag(PREFIX_ID_PERMISSIONS + userId);
if(hasNilFlag){
return null;
}
// 锁凭证 redisLock 贯穿全程
RedisLock redisLock = new RedisLock();
redisLock.setLockName(PREFIX_ID_PERMISSIONS + userId)
.setAcquireTimeOut(3000L)
.setLockTimeOut(5000L);
try {
// 这里增加分布式锁 防止缓存击穿
// ============ 尝试加锁
redisLock = redisLockPlugins.tryLock(redisLock);
if(redisLock == null){
return null;
}
// 查询数据库
ResultVo<List<String>> resultVo = userApi.getAllPerms(userId);
if(resultVo.isSuccess()){
permissions = resultVo.getData();
// 存入缓存
CacheUtil.put(PREFIX_ID_PERMISSIONS + userId, permissions);
}
}catch (Exception e){
log.error(e.getMessage(),e);
}finally {
// ============ 释放锁
redisLockPlugins.unLock(redisLock);
redisLock = null;
}
if(permissions == null){
// 设置空变量 用于防止穿透判断
CacheUtil.putNilFlag(PREFIX_ID_PERMISSIONS + userId);
return null;
}
return permissions;
}
/**
* userId
* @param userId
* @return
*/
public static List<MenuModel> getMenuListByUserId(String userId){
List<MenuModel> menus = null;
// 先从缓存里拿
List menusObj = CacheUtil.get(PREFIX_ID_MENUS + userId, List.class);
if (menusObj != null && !menusObj.isEmpty()){
menus = Lists.newArrayListWithCapacity(menusObj.size());
for (Object menu : menusObj) {
JSONObject jsonObject = (JSONObject) menu;
if(jsonObject != null){
menus.add(jsonObject.toJavaObject(MenuModel.class));
}
}
return menus;
}
// 拿不到 --------
// 防止缓存穿透判断
boolean hasNilFlag = CacheUtil.hasNilFlag(PREFIX_ID_MENUS + userId);
if(hasNilFlag){
return null;
}
// 锁凭证 redisLock 贯穿全程
RedisLock redisLock = new RedisLock();
redisLock.setLockName(PREFIX_ID_MENUS + userId)
.setAcquireTimeOut(3000L)
.setLockTimeOut(5000L);
try {
// 这里增加分布式锁 防止缓存击穿
// ============ 尝试加锁
redisLock = redisLockPlugins.tryLock(redisLock);
if(redisLock == null){
return null;
}
// 查询数据库
ResultVo<List<MenuModel>> resultVo = userApi.getMenuListByUserId(userId);
if(resultVo.isSuccess()){
menus = resultVo.getData();
// 存入缓存
CacheUtil.put(PREFIX_ID_MENUS + userId, menus);
}
}catch (Exception e){
log.error(e.getMessage(),e);
}finally {
// ============ 释放锁
redisLockPlugins.unLock(redisLock);
redisLock = null;
}
if(menus == null){
// 设置空变量 用于防止穿透判断
CacheUtil.putNilFlag(PREFIX_ID_MENUS + userId);
return null;
}
return menus;
}
// ============== 刷新缓存 ==============
/**
*
* @param user
* @return
*/
public static void refreshUser(UserModel user){
if(user == null || StringUtils.isEmpty(user.getId())){
return;
}
UserModel userModelById = CacheUtil.get(PREFIX_ID + user.getId(), UserModel.class);
UserModel userModelByUsername = CacheUtil.get(PREFIX_USERNAME + user.getUsername(),
UserModel.class);
// 只要有一个不为空 则执行刷新
if (userModelById != null || userModelByUsername != null){
// 先删除
CacheUtil.del(PREFIX_ID + user.getId());
CacheUtil.del(PREFIX_USERNAME + user.getUsername());
// 再赋值
CacheUtil.put(PREFIX_ID + user.getId(), user);
CacheUtil.put(PREFIX_USERNAME + user.getUsername(), user);
// 清除空拦截
CacheUtil.putNilFlag(PREFIX_ID + user.getId());
CacheUtil.putNilFlag(PREFIX_USERNAME + user.getUsername());
}
}
/**
*
* @param userId
* @param roleCodes
* @return
*/
public static void refreshUserRoles(String userId, List<String> roleCodes){
if(roleCodes == null || roleCodes.isEmpty()){
return;
}
List list = CacheUtil.get(PREFIX_ID_ROLES + userId, List.class);
if(list != null && !list.isEmpty()){
// 先删除
CacheUtil.del(PREFIX_ID_ROLES + userId);
// 存入缓存
CacheUtil.put(PREFIX_ID_ROLES + userId, list);
// 清除空拦截
CacheUtil.putNilFlag(PREFIX_ID_ROLES + userId);
}
}
/**
*
* @param userId
* @param permissions
* @return
*/
public static void refreshUserAllPerms(String userId, List<String> permissions){
if(permissions == null || permissions.isEmpty()){
return;
}
List list = CacheUtil.get(PREFIX_ID_PERMISSIONS + userId, List.class);
if(list != null && !list.isEmpty()){
// 先删除
CacheUtil.del(PREFIX_ID_PERMISSIONS + userId);
// 存入缓存
CacheUtil.put(PREFIX_ID_PERMISSIONS + userId, list);
// 清除空拦截
CacheUtil.putNilFlag(PREFIX_ID_PERMISSIONS + userId);
}
}
/**
*
* @param userId
* @param menus
* @return
*/
public static void refreshUserMenus(String userId, List<MenuModel> menus){
if(menus == null || menus.isEmpty()){
return;
}
List list = CacheUtil.get(PREFIX_ID_MENUS + userId, List.class);
if(list != null && !list.isEmpty()){
// 先删除
CacheUtil.del(PREFIX_ID_MENUS + userId);
// 存入缓存
CacheUtil.put(PREFIX_ID_MENUS + userId, list);
// 清除空拦截
CacheUtil.putNilFlag(PREFIX_ID_MENUS + userId);
}
}
/**
* ID
* @return
*/
public static String getTenantId(){
// TODO 如果 没取到多租户ID 也按照默认值赋值 且不可删除默认多租户数据
// TODO 判断权限 如果是 admin 超级管理员 则租户ID清空 且findList 不做处理 否则默认都会做处理
// TODO 如果表中 没有 tenant_id 字段 则不进行多租户处理
// 判断权限 如果是 admin 超级管理员 则租户ID清空 且findList 不做处理 否则默认都会做处理
// 如果表中 没有 tenant_id 字段 则不进行多租户处理
return "a121321255";
UserModel user = getUser();
if(user == null){
throw new RuntimeException("用户为空");
}
// 如果是超级管理员 则不进行租户处理
if(SUPER_ADMIN.equals(user.getUsername())){
return null;
}
return user.getTenantId();
}
// =====================================
@Autowired
public void setRedisLockPlugins(RedisLockPlugins redisLockPlugins) {
UserUtil.redisLockPlugins = redisLockPlugins;
}
@Autowired
public void setUserApi(UserApi userApi) {
UserUtil.userApi = userApi;
}
}

@ -15,9 +15,18 @@ public enum SystemMsg implements BaseMsg {
/**
*
*/
EXCEL_DICT_UNIQUE(20000,"字典编号重复,该字典已存在!"),
EXCEL_DICT_DETAIL_UNIQUE(20001,"字典名称或值重复,该字典已存在!"),
EXCEPTION_DICT_UNIQUE(20000,"字典编号重复,该字典已存在!"),
EXCEPTION_DICT_DETAIL_UNIQUE(20001,"字典名称或值重复,该字典已存在!"),
/**
*
*/
EXCEPTION_ROLE_UNIQUE(20000,"角色编号重复,该角色已存在!"),
/**
*
*/
EXCEPTION_USER_UNIQUE(20000,"该用户已存在!"),
;

@ -24,7 +24,7 @@ public class SysDict extends BaseEntity {
/** 字典类型名称 */
private String typeName;
/** 是否内置数据 */
/** 是否内置数据 0是 1否*/
private Character izLock;
/** 备注 */

@ -29,7 +29,7 @@ public class SysDictDetail extends BaseEntity {
/** 字典值 */
private String dictValue;
/** 是否内置数据 */
/** 是否内置数据 0是 1否*/
private Character izLock;
/** 排序 */

@ -1,6 +1,6 @@
package org.opsli.modulars.system.dict.service;
import org.opsli.api.wrapper.system.dict.SysDictDetailModel;
import org.opsli.api.wrapper.system.dict.DictDetailModel;
import org.opsli.core.base.service.interfaces.CrudServiceInterface;
import org.opsli.modulars.system.dict.entity.SysDictDetail;
@ -13,7 +13,7 @@ import java.util.List;
* @CreateTime: 2020-09-17 13:07
* @Description:
*/
public interface IDictDetailService extends CrudServiceInterface<SysDictDetail, SysDictDetailModel> {
public interface IDictDetailService extends CrudServiceInterface<SysDictDetail, DictDetailModel> {
/**
* ID
@ -28,6 +28,6 @@ public interface IDictDetailService extends CrudServiceInterface<SysDictDetail,
* @param typeCode
* @return
*/
List<SysDictDetailModel> findListByTypeCode(String typeCode);
List<DictDetailModel> findListByTypeCode(String typeCode);
}

@ -1,6 +1,6 @@
package org.opsli.modulars.system.dict.service;
import org.opsli.api.wrapper.system.dict.SysDictModel;
import org.opsli.api.wrapper.system.dict.DictModel;
import org.opsli.core.base.service.interfaces.CrudServiceInterface;
import org.opsli.modulars.system.dict.entity.SysDict;
@ -12,7 +12,7 @@ import org.opsli.modulars.system.dict.entity.SysDict;
* @CreateTime: 2020-09-17 13:07
* @Description:
*/
public interface IDictService extends CrudServiceInterface<SysDict, SysDictModel> {
public interface IDictService extends CrudServiceInterface<SysDict, DictModel> {
}

@ -4,13 +4,12 @@ import cn.hutool.core.convert.Convert;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;
import org.opsli.api.wrapper.system.dict.DictDetailModel;
import org.opsli.api.wrapper.system.dict.DictModel;
import org.opsli.api.wrapper.system.dict.SysDictDetailModel;
import org.opsli.api.wrapper.system.dict.SysDictModel;
import org.opsli.api.wrapper.system.dict.DictWrapper;
import org.opsli.common.constants.MyBatisConstants;
import org.opsli.common.exception.ServiceException;
import org.opsli.common.utils.HumpUtil;
import org.opsli.common.utils.WrapperUtil;
import org.opsli.core.base.service.impl.CrudServiceImpl;
import org.opsli.core.cache.pushsub.enums.CacheType;
import org.opsli.core.cache.pushsub.msgs.DictMsgFactory;
@ -39,7 +38,7 @@ import java.util.List;
* @Description:
*/
@Service
public class DictDetailServiceImpl extends CrudServiceImpl<DictDetailMapper, SysDictDetail, SysDictDetailModel> implements IDictDetailService {
public class DictDetailServiceImpl extends CrudServiceImpl<DictDetailMapper, SysDictDetail, DictDetailModel> implements IDictDetailService {
@Autowired(required = false)
private DictDetailMapper mapper;
@ -55,35 +54,35 @@ public class DictDetailServiceImpl extends CrudServiceImpl<DictDetailMapper, Sys
*/
@Transactional(rollbackFor = Exception.class)
@Override
public SysDictDetailModel insert(SysDictDetailModel model) {
public DictDetailModel insert(DictDetailModel model) {
SysDictDetail entity = WrapperUtil.transformInstance(model, SysDictDetail.class);
SysDictDetail entity = super.transformM2T(model);
// 唯一验证
Integer count = mapper.uniqueVerificationByNameOrValue(entity);
if(count != null && count > 0){
// 重复
throw new ServiceException(SystemMsg.EXCEL_DICT_DETAIL_UNIQUE);
throw new ServiceException(SystemMsg.EXCEPTION_DICT_DETAIL_UNIQUE);
}
SysDictDetailModel ret = super.insert(model);
DictDetailModel ret = super.insert(model);
if(ret != null){
DictModel dictModel = new DictModel();
dictModel.setTypeCode(model.getTypeCode());
dictModel.setDictName(model.getDictName());
dictModel.setDictValue(model.getDictValue());
dictModel.setModel(ret);
DictWrapper dictWrapperModel = new DictWrapper();
dictWrapperModel.setTypeCode(model.getTypeCode());
dictWrapperModel.setDictName(model.getDictName());
dictWrapperModel.setDictValue(model.getDictValue());
dictWrapperModel.setModel(ret);
// 先删老缓存
DictUtil.del(dictModel);
DictUtil.del(dictWrapperModel);
// 广播缓存数据 - 通知其他服务器同步数据
redisPlugin.sendMessage(
DictMsgFactory.createMsg(dictModel, CacheType.DELETE)
DictMsgFactory.createMsg(dictWrapperModel, CacheType.DELETE)
);
// 再存 防止脏数据
DictUtil.put(dictModel);
DictUtil.put(dictWrapperModel);
// 广播缓存数据 - 通知其他服务器同步数据
redisPlugin.sendMessage(
DictMsgFactory.createMsg(dictModel, CacheType.UPDATE)
DictMsgFactory.createMsg(dictWrapperModel, CacheType.UPDATE)
);
}
@ -97,43 +96,43 @@ public class DictDetailServiceImpl extends CrudServiceImpl<DictDetailMapper, Sys
*/
@Transactional(rollbackFor = Exception.class)
@Override
public SysDictDetailModel update(SysDictDetailModel model) {
public DictDetailModel update(DictDetailModel model) {
SysDictDetail entity = WrapperUtil.transformInstance(model, SysDictDetail.class);
SysDictDetail entity = super.transformM2T(model);
// 唯一验证
Integer count = mapper.uniqueVerificationByNameOrValue(entity);
if(count != null && count > 0){
// 重复
throw new ServiceException(SystemMsg.EXCEL_DICT_DETAIL_UNIQUE);
throw new ServiceException(SystemMsg.EXCEPTION_DICT_DETAIL_UNIQUE);
}
// 旧数据 用于删除老缓存
SysDictDetailModel oldModel = this.get(model);
DictDetailModel oldModel = this.get(model);
SysDictDetailModel ret = super.update(model);
DictDetailModel ret = super.update(model);
if(ret != null){
// 先删老缓存
DictModel oldDictModel = new DictModel();
oldDictModel.setTypeCode(oldModel.getTypeCode());
oldDictModel.setDictName(oldModel.getDictName());
oldDictModel.setDictValue(oldModel.getDictValue());
DictUtil.del(oldDictModel);
DictWrapper oldDictWrapperModel = new DictWrapper();
oldDictWrapperModel.setTypeCode(oldModel.getTypeCode());
oldDictWrapperModel.setDictName(oldModel.getDictName());
oldDictWrapperModel.setDictValue(oldModel.getDictValue());
DictUtil.del(oldDictWrapperModel);
// 广播缓存数据 - 通知其他服务器同步数据
redisPlugin.sendMessage(
DictMsgFactory.createMsg(oldDictModel, CacheType.DELETE)
DictMsgFactory.createMsg(oldDictWrapperModel, CacheType.DELETE)
);
// 再put新缓存
DictModel dictModel = new DictModel();
dictModel.setTypeCode(model.getTypeCode());
dictModel.setDictName(model.getDictName());
dictModel.setDictValue(model.getDictValue());
dictModel.setModel(ret);
DictUtil.put(dictModel);
DictWrapper dictWrapperModel = new DictWrapper();
dictWrapperModel.setTypeCode(model.getTypeCode());
dictWrapperModel.setDictName(model.getDictName());
dictWrapperModel.setDictValue(model.getDictValue());
dictWrapperModel.setModel(ret);
DictUtil.put(dictWrapperModel);
// 广播缓存数据 - 通知其他服务器同步数据
redisPlugin.sendMessage(
DictMsgFactory.createMsg(dictModel, CacheType.UPDATE)
DictMsgFactory.createMsg(dictWrapperModel, CacheType.UPDATE)
);
}
@ -148,18 +147,18 @@ public class DictDetailServiceImpl extends CrudServiceImpl<DictDetailMapper, Sys
*/
@Override
public boolean delete(String id) {
SysDictDetailModel sysDictDetailModel = this.get(id);
DictDetailModel dictDetailModel = this.get(id);
boolean ret = super.delete(id);
if(ret){
DictModel dictModel = new DictModel();
dictModel.setTypeCode(sysDictDetailModel.getTypeCode());
dictModel.setDictName(sysDictDetailModel.getDictName());
dictModel.setDictValue(sysDictDetailModel.getDictValue());
DictWrapper dictWrapperModel = new DictWrapper();
dictWrapperModel.setTypeCode(dictDetailModel.getTypeCode());
dictWrapperModel.setDictName(dictDetailModel.getDictName());
dictWrapperModel.setDictValue(dictDetailModel.getDictValue());
// 删除缓存
DictUtil.del(dictModel);
DictUtil.del(dictWrapperModel);
// 广播缓存数据 - 通知其他服务器同步数据
redisPlugin.sendMessage(
DictMsgFactory.createMsg(dictModel, CacheType.DELETE)
DictMsgFactory.createMsg(dictWrapperModel, CacheType.DELETE)
);
}
return ret;
@ -171,19 +170,19 @@ public class DictDetailServiceImpl extends CrudServiceImpl<DictDetailMapper, Sys
* @return
*/
@Override
public boolean delete(SysDictDetailModel model) {
SysDictDetailModel sysDictDetailModel = this.get(model);
public boolean delete(DictDetailModel model) {
DictDetailModel dictDetailModel = this.get(model);
boolean ret = super.delete(model);
if(ret){
DictModel dictModel = new DictModel();
dictModel.setTypeCode(sysDictDetailModel.getTypeCode());
dictModel.setDictName(sysDictDetailModel.getDictName());
dictModel.setDictValue(sysDictDetailModel.getDictValue());
DictWrapper dictWrapperModel = new DictWrapper();
dictWrapperModel.setTypeCode(dictDetailModel.getTypeCode());
dictWrapperModel.setDictName(dictDetailModel.getDictName());
dictWrapperModel.setDictValue(dictDetailModel.getDictValue());
// 删除缓存
DictUtil.del(dictModel);
DictUtil.del(dictWrapperModel);
// 广播缓存数据 - 通知其他服务器同步数据
redisPlugin.sendMessage(
DictMsgFactory.createMsg(dictModel, CacheType.DELETE)
DictMsgFactory.createMsg(dictWrapperModel, CacheType.DELETE)
);
}
return ret;
@ -205,20 +204,20 @@ public class DictDetailServiceImpl extends CrudServiceImpl<DictDetailMapper, Sys
if(ret){
if(list != null && list.size() > 0){
List<DictModel> dictModels = Lists.newArrayListWithCapacity(list.size());
List<DictWrapper> dictWrapperModels = Lists.newArrayListWithCapacity(list.size());
// 删除缓存
for (SysDictDetail sysDictDetail : list) {
DictModel dictModel = new DictModel();
dictModel.setTypeCode(sysDictDetail.getTypeCode());
dictModel.setDictName(sysDictDetail.getDictName());
dictModel.setDictValue(sysDictDetail.getDictValue());
DictWrapper dictWrapperModel = new DictWrapper();
dictWrapperModel.setTypeCode(sysDictDetail.getTypeCode());
dictWrapperModel.setDictName(sysDictDetail.getDictName());
dictWrapperModel.setDictValue(sysDictDetail.getDictValue());
// 删除缓存
DictUtil.del(dictModel);
dictModels.add(dictModel);
DictUtil.del(dictWrapperModel);
dictWrapperModels.add(dictWrapperModel);
}
// 广播缓存数据 - 通知其他服务器同步数据
redisPlugin.sendMessage(
DictMsgFactory.createMsg(dictModels, CacheType.DELETE)
DictMsgFactory.createMsg(dictWrapperModels, CacheType.DELETE)
);
}
@ -232,13 +231,13 @@ public class DictDetailServiceImpl extends CrudServiceImpl<DictDetailMapper, Sys
* @return
*/
@Override
public boolean deleteAll(Collection<SysDictDetailModel> models) {
public boolean deleteAll(Collection<DictDetailModel> models) {
QueryBuilder<SysDictDetail> queryBuilder = new GenQueryBuilder<>();
QueryWrapper<SysDictDetail> queryWrapper = queryBuilder.build();
List<String> idList = Lists.newArrayListWithCapacity(models.size());
for (SysDictDetailModel model : models) {
for (DictDetailModel model : models) {
idList.add(model.getId());
}
queryWrapper.in(HumpUtil.humpToUnderline(MyBatisConstants.FIELD_ID),idList);
@ -249,20 +248,20 @@ public class DictDetailServiceImpl extends CrudServiceImpl<DictDetailMapper, Sys
if(ret){
if(list != null && list.size() > 0){
List<DictModel> dictModels = Lists.newArrayListWithCapacity(list.size());
List<DictWrapper> dictWrapperModels = Lists.newArrayListWithCapacity(list.size());
// 删除缓存
for (SysDictDetail sysDictDetail : list) {
DictModel dictModel = new DictModel();
dictModel.setTypeCode(sysDictDetail.getTypeCode());
dictModel.setDictName(sysDictDetail.getDictName());
dictModel.setDictValue(sysDictDetail.getDictValue());
DictWrapper dictWrapperModel = new DictWrapper();
dictWrapperModel.setTypeCode(sysDictDetail.getTypeCode());
dictWrapperModel.setDictName(sysDictDetail.getDictName());
dictWrapperModel.setDictValue(sysDictDetail.getDictValue());
// 删除缓存
DictUtil.del(dictModel);
dictModels.add(dictModel);
DictUtil.del(dictWrapperModel);
dictWrapperModels.add(dictWrapperModel);
}
// 广播缓存数据 - 通知其他服务器同步数据
redisPlugin.sendMessage(
DictMsgFactory.createMsg(dictModels, CacheType.DELETE)
DictMsgFactory.createMsg(dictWrapperModels, CacheType.DELETE)
);
}
}
@ -286,22 +285,22 @@ public class DictDetailServiceImpl extends CrudServiceImpl<DictDetailMapper, Sys
queryWrapper.eq(key, parentId);
boolean removeFlag = super.remove(queryWrapper);
if(removeFlag){
SysDictModel sysDictModel = iDictService.get(parentId);
List<SysDictDetailModel> listByTypeCode = this.findListByTypeCode(sysDictModel.getTypeCode());
DictModel dictModel = iDictService.get(parentId);
List<DictDetailModel> listByTypeCode = this.findListByTypeCode(dictModel.getTypeCode());
if(listByTypeCode != null && listByTypeCode.size() > 0){
List<DictModel> dictList = Lists.newArrayListWithCapacity(listByTypeCode.size());
for (SysDictDetailModel sysDictDetailModel : listByTypeCode) {
DictModel dictModel = new DictModel();
dictModel.setTypeCode(sysDictDetailModel.getTypeCode());
dictModel.setDictName(sysDictDetailModel.getDictName());
dictModel.setDictValue(sysDictDetailModel.getDictValue());
dictList.add(dictModel);
List<DictWrapper> dictWrapperList = Lists.newArrayListWithCapacity(listByTypeCode.size());
for (DictDetailModel dictDetailModel : listByTypeCode) {
DictWrapper dictWrapperModel = new DictWrapper();
dictWrapperModel.setTypeCode(dictDetailModel.getTypeCode());
dictWrapperModel.setDictName(dictDetailModel.getDictName());
dictWrapperModel.setDictValue(dictDetailModel.getDictValue());
dictWrapperList.add(dictWrapperModel);
}
// 删除缓存
DictUtil.delAll(sysDictModel.getTypeCode());
DictUtil.delAll(dictModel.getTypeCode());
// 广播缓存数据 - 通知其他服务器同步数据
redisPlugin.sendMessage(
DictMsgFactory.createMsg(dictList, CacheType.DELETE)
DictMsgFactory.createMsg(dictWrapperList, CacheType.DELETE)
);
}
}
@ -315,7 +314,7 @@ public class DictDetailServiceImpl extends CrudServiceImpl<DictDetailMapper, Sys
* @return
*/
@Override
public List<SysDictDetailModel> findListByTypeCode(String typeCode) {
public List<DictDetailModel> findListByTypeCode(String typeCode) {
if(StringUtils.isEmpty(typeCode)) return null;
String key = HumpUtil.humpToUnderline("typeCode");
@ -327,7 +326,7 @@ public class DictDetailServiceImpl extends CrudServiceImpl<DictDetailMapper, Sys
queryWrapper.eq(deleted, '0');
List<SysDictDetail> list = this.findList(queryWrapper);
// 转化对象
return WrapperUtil.transformInstance(list, SysDictDetailModel.class);
return super.transformTs2Ms(list);
}
}

@ -1,10 +1,9 @@
package org.opsli.modulars.system.dict.service.impl;
import org.apache.commons.lang3.StringUtils;
import org.opsli.api.wrapper.system.dict.SysDictDetailModel;
import org.opsli.api.wrapper.system.dict.SysDictModel;
import org.opsli.api.wrapper.system.dict.DictDetailModel;
import org.opsli.api.wrapper.system.dict.DictModel;
import org.opsli.common.exception.ServiceException;
import org.opsli.common.utils.WrapperUtil;
import org.opsli.core.base.service.impl.CrudServiceImpl;
import org.opsli.modulars.system.SystemMsg;
import org.opsli.modulars.system.dict.entity.SysDict;
@ -27,7 +26,7 @@ import java.util.List;
* @Description:
*/
@Service
public class DictServiceImpl extends CrudServiceImpl<DictMapper, SysDict, SysDictModel> implements IDictService {
public class DictServiceImpl extends CrudServiceImpl<DictMapper, SysDict, DictModel> implements IDictService {
@Autowired(required = false)
private DictMapper mapper;
@ -35,15 +34,15 @@ public class DictServiceImpl extends CrudServiceImpl<DictMapper, SysDict, SysDic
private IDictDetailService iDictDetailService;
@Override
public SysDictModel insert(SysDictModel model) {
public DictModel insert(DictModel model) {
if(model == null) return null;
SysDict entity = WrapperUtil.transformInstance(model, SysDict.class);
SysDict entity = super.transformM2T(model);
// 唯一验证
Integer count = mapper.uniqueVerificationByCode(entity);
if(count != null && count > 0){
// 重复
throw new ServiceException(SystemMsg.EXCEL_DICT_UNIQUE);
throw new ServiceException(SystemMsg.EXCEPTION_DICT_UNIQUE);
}
return super.insert(model);
@ -51,28 +50,28 @@ public class DictServiceImpl extends CrudServiceImpl<DictMapper, SysDict, SysDic
@Transactional(rollbackFor = Exception.class)
@Override
public SysDictModel update(SysDictModel model) {
public DictModel update(DictModel model) {
if(model == null) return null;
SysDict entity = WrapperUtil.transformInstance(model, SysDict.class);
SysDict entity = super.transformM2T(model);
// 唯一验证
Integer count = mapper.uniqueVerificationByCode(entity);
if(count != null && count > 0){
// 重复
throw new ServiceException(SystemMsg.EXCEL_DICT_UNIQUE);
throw new ServiceException(SystemMsg.EXCEPTION_DICT_UNIQUE);
}
SysDictModel updateRet = super.update(model);
DictModel updateRet = super.update(model);
// 字典主表修改 子表跟着联动 (验证是否改了编号)/ 或者修改不允许改编号
List<SysDictDetailModel> listByTypeCode = null;
List<DictDetailModel> listByTypeCode = null;
if(StringUtils.isNotEmpty(model.getTypeCode())){
listByTypeCode = iDictDetailService.findListByTypeCode(model.getTypeCode());
}
if(listByTypeCode != null && listByTypeCode.size() > 0){
for (SysDictDetailModel sysDictDetailModel : listByTypeCode) {
sysDictDetailModel.setTypeCode(updateRet.getTypeCode());
iDictDetailService.update(sysDictDetailModel);
for (DictDetailModel dictDetailModel : listByTypeCode) {
dictDetailModel.setTypeCode(updateRet.getTypeCode());
iDictDetailService.update(dictDetailModel);
}
}
@ -91,7 +90,7 @@ public class DictServiceImpl extends CrudServiceImpl<DictMapper, SysDict, SysDic
@Transactional(rollbackFor = Exception.class)
@Override
public boolean delete(SysDictModel model) {
public boolean delete(DictModel model) {
if(model == null || StringUtils.isEmpty(model.getId())){
return false;
}
@ -118,11 +117,11 @@ public class DictServiceImpl extends CrudServiceImpl<DictMapper, SysDict, SysDic
@Transactional(rollbackFor = Exception.class)
@Override
public boolean deleteAll(Collection<SysDictModel> models) {
public boolean deleteAll(Collection<DictModel> models) {
if(models == null || models.isEmpty()) return false;
// 删除字典明细表
for (SysDictModel model : models) {
for (DictModel model : models) {
if(model == null || StringUtils.isEmpty(model.getId())){
continue;
}

@ -4,7 +4,7 @@ import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.opsli.api.base.result.ResultVo;
import org.opsli.api.web.system.dict.DictDetailApi;
import org.opsli.api.wrapper.system.dict.SysDictDetailModel;
import org.opsli.api.wrapper.system.dict.DictDetailModel;
import org.opsli.common.annotation.ApiRestController;
import org.opsli.core.base.concroller.BaseRestController;
import org.opsli.core.persistence.Page;
@ -27,8 +27,8 @@ import java.util.List;
* @Description:
*/
@Slf4j
@ApiRestController("/dict/detail")
public class DictDetailRestController extends BaseRestController<SysDictDetail, SysDictDetailModel, IDictDetailService>
@ApiRestController("/sys/dict/detail")
public class DictDetailRestController extends BaseRestController<SysDictDetail, DictDetailModel, IDictDetailService>
implements DictDetailApi {
@ -39,7 +39,11 @@ public class DictDetailRestController extends BaseRestController<SysDictDetail,
*/
@ApiOperation(value = "获得单条字典数据", notes = "获得单条字典数据 - ID")
@Override
public ResultVo<SysDictDetailModel> get(SysDictDetailModel model) {
public ResultVo<DictDetailModel> get(DictDetailModel model) {
// 如果系统内部调用 则直接查数据库
if(model != null && model.getIzApi() != null && model.getIzApi()){
model = IService.get(model);
}
return ResultVo.success(model);
}
@ -55,7 +59,7 @@ public class DictDetailRestController extends BaseRestController<SysDictDetail,
public ResultVo<?> findPage(Integer pageNo, Integer pageSize, HttpServletRequest request) {
QueryBuilder<SysDictDetail> queryBuilder = new WebQueryBuilder<>(SysDictDetail.class, request.getParameterMap());
Page<SysDictDetail, SysDictDetailModel> page = new Page<>(pageNo, pageSize);
Page<SysDictDetail, DictDetailModel> page = new Page<>(pageNo, pageSize);
page.setQueryWrapper(queryBuilder.build());
page = IService.findPage(page);
@ -69,7 +73,7 @@ public class DictDetailRestController extends BaseRestController<SysDictDetail,
*/
@ApiOperation(value = "新增字典数据", notes = "新增字典数据")
@Override
public ResultVo<?> insert(SysDictDetailModel model) {
public ResultVo<?> insert(DictDetailModel model) {
// 调用新增方法
IService.insert(model);
return ResultVo.success("新增字典数据成功");
@ -82,7 +86,7 @@ public class DictDetailRestController extends BaseRestController<SysDictDetail,
*/
@ApiOperation(value = "修改字典数据", notes = "修改字典数据")
@Override
public ResultVo<?> update(SysDictDetailModel model) {
public ResultVo<?> update(DictDetailModel model) {
// 调用修改方法
IService.update(model);
return ResultVo.success("修改字典数据");
@ -159,7 +163,7 @@ public class DictDetailRestController extends BaseRestController<SysDictDetail,
@ApiOperation(value = "根据字典类型编号 查询出所有字典", notes = "根据字典类型编号 查询出所有字典")
// 权限
@Override
public ResultVo<List<SysDictDetailModel>> findListByTypeCode(String typeCode) {
public ResultVo<List<DictDetailModel>> findListByTypeCode(String typeCode) {
return ResultVo.success(IService.findListByTypeCode(typeCode));
}
}

@ -4,9 +4,9 @@ import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.opsli.api.base.result.ResultVo;
import org.opsli.api.web.system.dict.DictApi;
import org.opsli.api.web.system.dict.DictDetailApi;
import org.opsli.api.wrapper.system.dict.SysDictModel;
import org.opsli.api.wrapper.system.dict.DictModel;
import org.opsli.common.annotation.ApiRestController;
import org.opsli.common.api.TokenThreadLocal;
import org.opsli.core.base.concroller.BaseRestController;
import org.opsli.core.persistence.Page;
import org.opsli.core.persistence.querybuilder.QueryBuilder;
@ -27,8 +27,8 @@ import javax.servlet.http.HttpServletResponse;
* @Description:
*/
@Slf4j
@ApiRestController("/dict")
public class DictRestController extends BaseRestController<SysDict, SysDictModel, IDictService>
@ApiRestController("/sys/dict")
public class DictRestController extends BaseRestController<SysDict, DictModel, IDictService>
implements DictApi {
@ -39,7 +39,12 @@ public class DictRestController extends BaseRestController<SysDict, SysDictModel
*/
@ApiOperation(value = "获得单条字典明细数据", notes = "获得单条字典明细数据 - ID")
@Override
public ResultVo<SysDictModel> get(SysDictModel model) {
public ResultVo<DictModel> get(DictModel model) {
// 如果系统内部调用 则直接查数据库
if(model != null && model.getIzApi() != null && model.getIzApi()){
model = IService.get(model);
}
System.out.println(TokenThreadLocal.get());
return ResultVo.success(model);
}
@ -55,7 +60,7 @@ public class DictRestController extends BaseRestController<SysDict, SysDictModel
public ResultVo<?> findPage(Integer pageNo, Integer pageSize, HttpServletRequest request) {
QueryBuilder<SysDict> queryBuilder = new WebQueryBuilder<>(SysDict.class, request.getParameterMap());
Page<SysDict, SysDictModel> page = new Page<>(pageNo, pageSize);
Page<SysDict, DictModel> page = new Page<>(pageNo, pageSize);
page.setQueryWrapper(queryBuilder.build());
page = IService.findPage(page);
@ -69,7 +74,7 @@ public class DictRestController extends BaseRestController<SysDict, SysDictModel
*/
@ApiOperation(value = "新增字典明细数据", notes = "新增字典明细数据")
@Override
public ResultVo<?> insert(SysDictModel model) {
public ResultVo<?> insert(DictModel model) {
// 调用新增方法
IService.insert(model);
return ResultVo.success("新增字典明细数据成功");
@ -82,7 +87,7 @@ public class DictRestController extends BaseRestController<SysDict, SysDictModel
*/
@ApiOperation(value = "修改字典明细数据", notes = "修改字典明细数据")
@Override
public ResultVo<?> update(SysDictModel model) {
public ResultVo<?> update(DictModel model) {
// 调用修改方法
IService.update(model);
return ResultVo.success("修改字典明细数据成功");
@ -125,7 +130,7 @@ public class DictRestController extends BaseRestController<SysDict, SysDictModel
@Override
public ResultVo<?> exportExcel(HttpServletRequest request, HttpServletResponse response) {
QueryBuilder<SysDict> queryBuilder = new WebQueryBuilder<>(SysDict.class, request.getParameterMap());
return super.excelExport(DictDetailApi.TITLE, queryBuilder.build(), response);
return super.excelExport(DictApi.TITLE, queryBuilder.build(), response);
}
/**
@ -147,7 +152,7 @@ public class DictRestController extends BaseRestController<SysDict, SysDictModel
@ApiOperation(value = "导出Excel模版", notes = "导出Excel模版")
@Override
public ResultVo<?> importTemplate(HttpServletResponse response) {
return super.importTemplate(DictDetailApi.TITLE, response);
return super.importTemplate(DictApi.TITLE, response);
}
}

@ -0,0 +1,49 @@
/**
*
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.opsli.modulars.system.login.entity;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
*
*
* @author liuzp
* @since 2.0.0 2018-01-25
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class LoginForm {
/** 用户名 */
@ApiModelProperty(value = "用户名")
private String username;
/** 密码 */
@ApiModelProperty(value = "密码")
private String password;
/** 验证码 */
@ApiModelProperty(value = "验证码")
private String captcha;
/** UUID */
@ApiModelProperty(value = "UUID")
private String uuid;
}

@ -0,0 +1,99 @@
package org.opsli.modulars.system.login.web;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.opsli.api.base.result.ResultVo;
import org.opsli.api.wrapper.system.user.UserModel;
import org.opsli.common.api.TokenThreadLocal;
import org.opsli.core.utils.CaptchaUtil;
import org.opsli.core.utils.UserTokenUtil;
import org.opsli.core.utils.UserUtil;
import org.opsli.modulars.system.login.entity.LoginForm;
import org.springframework.web.bind.annotation.*;
import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.IOException;
/**
* / /
*
* @author parker
* @date 2020-05-23 13:30
*
* api
*
*/
@Slf4j
@RestController
public class LoginRestController {
/**
*
*/
@ApiOperation(value = "登录", notes = "登录")
@PostMapping("/sys/login")
public ResultVo<?> login(@RequestBody LoginForm form){
boolean captcha = CaptchaUtil.validate(form.getUuid(), form.getCaptcha());
if(!captcha){
return ResultVo.error("验证码不正确");
}
//用户信息
UserModel user = UserUtil.getUserByUserName(form.getUsername());;
//账号不存在、密码错误
if(user == null ||
!user.getPassword().equals(new Md5Hash(form.getPassword(), user.getSecretkey()).toHex())) {
return ResultVo.error("账号或密码不正确");
}
//账号锁定
if(user.getLocked() == 1){
return ResultVo.error("账号已被锁定,请联系管理员");
}
//生成token并保存到Redis
return UserTokenUtil.createToken(user);
}
/**
*
*/
@ApiOperation(value = "登出", notes = "登出")
@PostMapping("/sys/logout")
public ResultVo<?> logout() {
String token = TokenThreadLocal.get();
if(StringUtils.isEmpty(token)){
return ResultVo.success("登出失败没有授权Token");
}
UserTokenUtil.logout(token);
return ResultVo.success("登出成功!");
}
/**
*
*/
@ApiOperation(value = "验证码", notes = "验证码")
@GetMapping("captcha.jpg")
public void captcha(String uuid, HttpServletResponse response) throws IOException {
response.setHeader("Cache-Control", "no-store, no-cache");
response.setContentType("image/jpeg");
//获取图片验证码
BufferedImage image = CaptchaUtil.getCaptcha(uuid);
if(image != null){
ServletOutputStream out = response.getOutputStream();
ImageIO.write(image, "jpg", out);
IOUtils.closeQuietly(out);
}
}
}

@ -0,0 +1,45 @@
package org.opsli.modulars.system.menu.entity;
import com.baomidou.mybatisplus.annotation.TableLogic;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.opsli.core.base.entity.BaseEntity;
/**
* @BelongsProject: opsli-boot
* @BelongsPackage: org.opsli.modulars.test.entity
* @Author: Parker
* @CreateTime: 2020-09-16 17:33
* @Description:
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class SysMenu extends BaseEntity {
/** 父级主键 */
private String parentId;
/** 菜单编号 */
private String menuCode;
/** 菜单名称 */
private String menuName;
/** 图标 */
private String icon;
/** 项目类型:1-菜单2-按钮3-链接4-表单 */
private String type;
/** url地址 */
private String url;
// ========================================
/** 逻辑删除字段 */
@TableLogic
private Integer deleted;
}

@ -0,0 +1,24 @@
package org.opsli.modulars.system.menu.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.opsli.modulars.system.menu.entity.SysMenu;
/**
* @BelongsProject: opsli-boot
* @BelongsPackage: org.opsli.modulars.test.mapper
* @Author: Parker
* @CreateTime: 2020-09-17 13:01
* @Description: Mapper
*/
@Mapper
public interface MenuMapper extends BaseMapper<SysMenu> {
/**
*
* @param entity
* @return
*/
Integer uniqueVerificationByCode(SysMenu entity);
}

@ -0,0 +1,41 @@
<?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="org.opsli.modulars.system.menu.mapper.MenuMapper">
<!-- 数据库字段 -->
<sql id="SysRoleColumns">
a.id as id,
a.parent_id as parentId,
a.menu_code as menuCode,
a.menu_name as menuName,
a.icon as icon,
a.type as type,
a.url as url,
a.iz_lock as izLock,
a.create_by as createBy,
a.create_time as createTime,
a.update_by as updateBy,
a.update_time as updateTime,
a.version as version,
a.deleted as deleted
</sql>
<sql id="SysRoleJoins">
</sql>
<select id="uniqueVerificationByCode" parameterType="SysMenu" resultType="Integer">
select
count(0)
from
sys_menu a
where
a.menu_code = #{menuCode}
and a.deleted = 0
<if test="id != null and id != ''">
AND a.id != #{id}
</if>
</select>
</mapper>

@ -0,0 +1,18 @@
package org.opsli.modulars.system.menu.service;
import org.opsli.api.wrapper.system.menu.MenuModel;
import org.opsli.core.base.service.interfaces.CrudServiceInterface;
import org.opsli.modulars.system.menu.entity.SysMenu;
/**
* @BelongsProject: opsli-boot
* @BelongsPackage: org.opsli.modulars.test.service
* @Author: Parker
* @CreateTime: 2020-09-17 13:07
* @Description:
*/
public interface IMenuService extends CrudServiceInterface<SysMenu, MenuModel> {
}

@ -0,0 +1,62 @@
package org.opsli.modulars.system.menu.service.impl;
import org.opsli.api.wrapper.system.menu.MenuModel;
import org.opsli.common.exception.ServiceException;
import org.opsli.common.utils.WrapperUtil;
import org.opsli.core.base.service.impl.CrudServiceImpl;
import org.opsli.modulars.system.SystemMsg;
import org.opsli.modulars.system.menu.entity.SysMenu;
import org.opsli.modulars.system.menu.mapper.MenuMapper;
import org.opsli.modulars.system.menu.service.IMenuService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* @BelongsProject: opsli-boot
* @BelongsPackage: org.opsli.modulars.test.service
* @Author: Parker
* @CreateTime: 2020-09-16 17:34
* @Description:
*/
@Service
public class MenuServiceImpl extends CrudServiceImpl<MenuMapper, SysMenu, MenuModel> implements IMenuService {
@Autowired(required = false)
private MenuMapper mapper;
@Override
public MenuModel insert(MenuModel model) {
if(model == null) return null;
SysMenu entity = super.transformM2T(model);
// 唯一验证
Integer count = mapper.uniqueVerificationByCode(entity);
if(count != null && count > 0){
// 重复
throw new ServiceException(SystemMsg.EXCEPTION_ROLE_UNIQUE);
}
return super.insert(model);
}
@Transactional(rollbackFor = Exception.class)
@Override
public MenuModel update(MenuModel model) {
if(model == null) return null;
SysMenu entity = super.transformM2T(model);
// 唯一验证
Integer count = mapper.uniqueVerificationByCode(entity);
if(count != null && count > 0){
// 重复
throw new ServiceException(SystemMsg.EXCEPTION_ROLE_UNIQUE);
}
return super.update(model);
}
}

@ -0,0 +1,156 @@
package org.opsli.modulars.system.menu.web;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.opsli.api.base.result.ResultVo;
import org.opsli.api.web.system.menu.MenuApi;
import org.opsli.api.wrapper.system.menu.MenuModel;
import org.opsli.common.annotation.ApiRestController;
import org.opsli.core.base.concroller.BaseRestController;
import org.opsli.core.persistence.Page;
import org.opsli.core.persistence.querybuilder.QueryBuilder;
import org.opsli.core.persistence.querybuilder.WebQueryBuilder;
import org.opsli.modulars.system.menu.entity.SysMenu;
import org.opsli.modulars.system.menu.service.IMenuService;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @BelongsProject: opsli-boot
* @BelongsPackage: org.opsli.modulars.test.web
* @Author: Parker
* @CreateTime: 2020-09-13 17:40
* @Description:
*/
@Slf4j
@ApiRestController("/sys/menu")
public class MenuRestController extends BaseRestController<SysMenu, MenuModel, IMenuService>
implements MenuApi {
/**
*
* @param model
* @return ResultVo
*/
@ApiOperation(value = "获得单条字典明细数据", notes = "获得单条字典明细数据 - ID")
@Override
public ResultVo<MenuModel> get(MenuModel model) {
// 如果系统内部调用 则直接查数据库
if(model != null && model.getIzApi() != null && model.getIzApi()){
model = IService.get(model);
}
return ResultVo.success(model);
}
/**
*
* @param pageNo
* @param pageSize
* @param request request
* @return ResultVo
*/
@ApiOperation(value = "获得分页数据", notes = "获得分页数据 - 查询构造器")
@Override
public ResultVo<?> findPage(Integer pageNo, Integer pageSize, HttpServletRequest request) {
QueryBuilder<SysMenu> queryBuilder = new WebQueryBuilder<>(SysMenu.class, request.getParameterMap());
Page<SysMenu, MenuModel> page = new Page<>(pageNo, pageSize);
page.setQueryWrapper(queryBuilder.build());
page = IService.findPage(page);
return ResultVo.success(page.getBootstrapData());
}
/**
*
* @param model
* @return ResultVo
*/
@ApiOperation(value = "新增字典明细数据", notes = "新增字典明细数据")
@Override
public ResultVo<?> insert(MenuModel model) {
// 调用新增方法
IService.insert(model);
return ResultVo.success("新增字典明细数据成功");
}
/**
*
* @param model
* @return ResultVo
*/
@ApiOperation(value = "修改字典明细数据", notes = "修改字典明细数据")
@Override
public ResultVo<?> update(MenuModel model) {
// 调用修改方法
IService.update(model);
return ResultVo.success("修改字典明细数据成功");
}
/**
*
* @param id ID
* @return ResultVo
*/
@ApiOperation(value = "删除字典明细数据数据", notes = "删除字典明细数据数据")
@Override
public ResultVo<?> del(String id){
IService.delete(id);
return ResultVo.success("删除字典明细数据成功");
}
/**
*
* @param ids ID
* @return ResultVo
*/
@ApiOperation(value = "批量删除字典明细数据数据", notes = "批量删除字典明细数据数据")
@Override
public ResultVo<?> delAll(String[] ids){
IService.deleteAll(ids);
return ResultVo.success("批量删除字典明细数据成功");
}
/**
* Excel
* @param request request
* @param response response
* @return ResultVo
*/
@ApiOperation(value = "导出Excel", notes = "导出Excel")
@Override
public ResultVo<?> exportExcel(HttpServletRequest request, HttpServletResponse response) {
QueryBuilder<SysMenu> queryBuilder = new WebQueryBuilder<>(SysMenu.class, request.getParameterMap());
return super.excelExport(MenuApi.TITLE, queryBuilder.build(), response);
}
/**
* Excel
* @param request request
* @return ResultVo
*/
@ApiOperation(value = "导入Excel", notes = "导入Excel")
@Override
public ResultVo<?> excelImport(MultipartHttpServletRequest request) {
return super.excelImport(request);
}
/**
* Excel
* @param response response
* @return ResultVo
*/
@ApiOperation(value = "导出Excel模版", notes = "导出Excel模版")
@Override
public ResultVo<?> importTemplate(HttpServletResponse response) {
return super.importTemplate(MenuApi.TITLE, response);
}
}

@ -0,0 +1,40 @@
package org.opsli.modulars.system.role.entity;
import com.baomidou.mybatisplus.annotation.TableLogic;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.opsli.core.base.entity.BaseEntity;
/**
* @BelongsProject: opsli-boot
* @BelongsPackage: org.opsli.modulars.test.entity
* @Author: Parker
* @CreateTime: 2020-09-16 17:33
* @Description:
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class SysRole extends BaseEntity {
/** 角色编码 */
private String roleCode;
/** 角色名称 */
private String roleName;
/** 是否内置数据 0是 1否*/
private Character izLock;
/** 备注 */
private String remark;
// ========================================
/** 逻辑删除字段 */
@TableLogic
private Integer deleted;
}

@ -0,0 +1,24 @@
package org.opsli.modulars.system.role.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.opsli.modulars.system.role.entity.SysRole;
/**
* @BelongsProject: opsli-boot
* @BelongsPackage: org.opsli.modulars.test.mapper
* @Author: Parker
* @CreateTime: 2020-09-17 13:01
* @Description: Mapper
*/
@Mapper
public interface RoleMapper extends BaseMapper<SysRole> {
/**
*
* @param entity
* @return
*/
Integer uniqueVerificationByCode(SysRole entity);
}

@ -0,0 +1,38 @@
<?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="org.opsli.modulars.system.role.mapper.RoleMapper">
<!-- 数据库字段 -->
<sql id="SysRoleColumns">
a.id as id,
a.role_code as roleCode,
a.role_name as roleName,
a.iz_lock as izLock,
a.remark as remark,
a.create_by as createBy,
a.create_time as createTime,
a.update_by as updateBy,
a.update_time as updateTime,
a.version as version,
a.deleted as deleted
</sql>
<sql id="SysRoleJoins">
</sql>
<select id="uniqueVerificationByCode" parameterType="SysRole" resultType="Integer">
select
count(0)
from
sys_role a
where
a.role_code = #{roleCode}
and a.deleted = 0
<if test="id != null and id != ''">
AND a.id != #{id}
</if>
</select>
</mapper>

@ -0,0 +1,18 @@
package org.opsli.modulars.system.role.service;
import org.opsli.api.wrapper.system.role.RoleModel;
import org.opsli.core.base.service.interfaces.CrudServiceInterface;
import org.opsli.modulars.system.role.entity.SysRole;
/**
* @BelongsProject: opsli-boot
* @BelongsPackage: org.opsli.modulars.test.service
* @Author: Parker
* @CreateTime: 2020-09-17 13:07
* @Description:
*/
public interface IRoleService extends CrudServiceInterface<SysRole, RoleModel> {
}

@ -0,0 +1,61 @@
package org.opsli.modulars.system.role.service.impl;
import org.opsli.api.wrapper.system.role.RoleModel;
import org.opsli.common.exception.ServiceException;
import org.opsli.core.base.service.impl.CrudServiceImpl;
import org.opsli.modulars.system.SystemMsg;
import org.opsli.modulars.system.role.entity.SysRole;
import org.opsli.modulars.system.role.mapper.RoleMapper;
import org.opsli.modulars.system.role.service.IRoleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* @BelongsProject: opsli-boot
* @BelongsPackage: org.opsli.modulars.test.service
* @Author: Parker
* @CreateTime: 2020-09-16 17:34
* @Description:
*/
@Service
public class RoleServiceImpl extends CrudServiceImpl<RoleMapper, SysRole, RoleModel> implements IRoleService {
@Autowired(required = false)
private RoleMapper mapper;
@Override
public RoleModel insert(RoleModel model) {
if(model == null) return null;
SysRole entity = super.transformM2T(model);
// 唯一验证
Integer count = mapper.uniqueVerificationByCode(entity);
if(count != null && count > 0){
// 重复
throw new ServiceException(SystemMsg.EXCEPTION_ROLE_UNIQUE);
}
return super.insert(model);
}
@Transactional(rollbackFor = Exception.class)
@Override
public RoleModel update(RoleModel model) {
if(model == null) return null;
SysRole entity = super.transformM2T(model);
// 唯一验证
Integer count = mapper.uniqueVerificationByCode(entity);
if(count != null && count > 0){
// 重复
throw new ServiceException(SystemMsg.EXCEPTION_ROLE_UNIQUE);
}
return super.update(model);
}
}

@ -0,0 +1,156 @@
package org.opsli.modulars.system.role.web;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.opsli.api.base.result.ResultVo;
import org.opsli.api.web.system.role.RoleApi;
import org.opsli.api.wrapper.system.role.RoleModel;
import org.opsli.common.annotation.ApiRestController;
import org.opsli.core.base.concroller.BaseRestController;
import org.opsli.core.persistence.Page;
import org.opsli.core.persistence.querybuilder.QueryBuilder;
import org.opsli.core.persistence.querybuilder.WebQueryBuilder;
import org.opsli.modulars.system.role.entity.SysRole;
import org.opsli.modulars.system.role.service.IRoleService;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @BelongsProject: opsli-boot
* @BelongsPackage: org.opsli.modulars.test.web
* @Author: Parker
* @CreateTime: 2020-09-13 17:40
* @Description:
*/
@Slf4j
@ApiRestController("/sys/role")
public class RoleRestController extends BaseRestController<SysRole, RoleModel, IRoleService>
implements RoleApi {
/**
*
* @param model
* @return ResultVo
*/
@ApiOperation(value = "获得单条字典明细数据", notes = "获得单条字典明细数据 - ID")
@Override
public ResultVo<RoleModel> get(RoleModel model) {
// 如果系统内部调用 则直接查数据库
if(model != null && model.getIzApi() != null && model.getIzApi()){
model = IService.get(model);
}
return ResultVo.success(model);
}
/**
*
* @param pageNo
* @param pageSize
* @param request request
* @return ResultVo
*/
@ApiOperation(value = "获得分页数据", notes = "获得分页数据 - 查询构造器")
@Override
public ResultVo<?> findPage(Integer pageNo, Integer pageSize, HttpServletRequest request) {
QueryBuilder<SysRole> queryBuilder = new WebQueryBuilder<>(SysRole.class, request.getParameterMap());
Page<SysRole, RoleModel> page = new Page<>(pageNo, pageSize);
page.setQueryWrapper(queryBuilder.build());
page = IService.findPage(page);
return ResultVo.success(page.getBootstrapData());
}
/**
*
* @param model
* @return ResultVo
*/
@ApiOperation(value = "新增字典明细数据", notes = "新增字典明细数据")
@Override
public ResultVo<?> insert(RoleModel model) {
// 调用新增方法
IService.insert(model);
return ResultVo.success("新增字典明细数据成功");
}
/**
*
* @param model
* @return ResultVo
*/
@ApiOperation(value = "修改字典明细数据", notes = "修改字典明细数据")
@Override
public ResultVo<?> update(RoleModel model) {
// 调用修改方法
IService.update(model);
return ResultVo.success("修改字典明细数据成功");
}
/**
*
* @param id ID
* @return ResultVo
*/
@ApiOperation(value = "删除字典明细数据数据", notes = "删除字典明细数据数据")
@Override
public ResultVo<?> del(String id){
IService.delete(id);
return ResultVo.success("删除字典明细数据成功");
}
/**
*
* @param ids ID
* @return ResultVo
*/
@ApiOperation(value = "批量删除字典明细数据数据", notes = "批量删除字典明细数据数据")
@Override
public ResultVo<?> delAll(String[] ids){
IService.deleteAll(ids);
return ResultVo.success("批量删除字典明细数据成功");
}
/**
* Excel
* @param request request
* @param response response
* @return ResultVo
*/
@ApiOperation(value = "导出Excel", notes = "导出Excel")
@Override
public ResultVo<?> exportExcel(HttpServletRequest request, HttpServletResponse response) {
QueryBuilder<SysRole> queryBuilder = new WebQueryBuilder<>(SysRole.class, request.getParameterMap());
return super.excelExport(RoleApi.TITLE, queryBuilder.build(), response);
}
/**
* Excel
* @param request request
* @return ResultVo
*/
@ApiOperation(value = "导入Excel", notes = "导入Excel")
@Override
public ResultVo<?> excelImport(MultipartHttpServletRequest request) {
return super.excelImport(request);
}
/**
* Excel
* @param response response
* @return ResultVo
*/
@ApiOperation(value = "导出Excel模版", notes = "导出Excel模版")
@Override
public ResultVo<?> importTemplate(HttpServletResponse response) {
return super.importTemplate(RoleApi.TITLE, response);
}
}

@ -0,0 +1,62 @@
package org.opsli.modulars.system.user.entity;
import com.baomidou.mybatisplus.annotation.TableLogic;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.opsli.core.base.entity.BaseEntity;
/**
* @BelongsProject: opsli-boot
* @BelongsPackage: org.opsli.modulars.test.entity
* @Author: Parker
* @CreateTime: 2020-09-16 17:33
* @Description:
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class SysUser extends BaseEntity {
/** 登录账户 */
private String username;
/** 登录密码 */
private String password;
/** 盐值,密码秘钥 */
private String secretKey;
/** 是否锁定 */
private String locked;
/** 真实姓名 */
private String realName;
/** 手机 */
private String mobile;
/** 邮箱 */
private String email;
/** 工号 */
private String no;
/** 头像 */
private String avatar;
/** 最后登陆IP */
private String loginIp;
/** 备注 */
private String remark;
// ========================================
/** 逻辑删除字段 */
@TableLogic
private Integer deleted;
/** 多租户字段 */
private String tenantId;
}

@ -0,0 +1,48 @@
package org.opsli.modulars.system.user.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.opsli.modulars.system.menu.entity.SysMenu;
import org.opsli.modulars.system.user.entity.SysUser;
import java.util.List;
/**
* @BelongsProject: opsli-boot
* @BelongsPackage: org.opsli.modulars.test.mapper
* @Author: Parker
* @CreateTime: 2020-09-17 13:01
* @Description: Mapper
*/
@Mapper
public interface UserMapper extends BaseMapper<SysUser> {
/**
*
* @param entity
* @return
*/
Integer uniqueVerificationByUsername(SysUser entity);
/**
* ID
* @param userId
* @return
*/
List<String> getRoleCodeList(String userId);
/**
* ID
* @param userId
* @return
*/
List<String> queryAllPerms(String userId);
/**
* ID
* @param userId
* @return
*/
List<SysMenu> findMenuListByUserId(String userId);
}

@ -0,0 +1,94 @@
<?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="org.opsli.modulars.system.user.mapper.UserMapper">
<!-- 数据库字段 -->
<sql id="SysDictColumns">
a.id as id,
a.username as username,
a.password as password,
a.secret_key as secretKey,
a.no as no,
a.real_name as realName,
a.locked as locked,
a.mobile as mobile,
a.email as email,
a.avatar as avatar,
a.login_ip as loginIp,
a.remark as remark,
a.tenant_id as tenantId,
a.create_by as createBy,
a.create_time as createTime,
a.update_by as updateBy,
a.update_time as updateTime,
a.version as version,
a.deleted as deleted
</sql>
<sql id="SysDictJoins">
</sql>
<select id="uniqueVerificationByUsername" parameterType="SysUser" resultType="Integer">
select
count(0)
from
sys_user a
where
a.username = #{username}
and a.deleted = 0
<if test="id != null and id != ''">
AND a.id != #{id}
</if>
</select>
<select id="queryAllPerms" resultType="String">
select
a.menu_code
from
sys_menu a,
sys_role_menu_ref b,
sys_user_role_ref c
where
a.id = b.module_id
and b.role_id = c.role_id
and a.type in ( '2', '3', '4' )
and c.user_id = #{userId}
where
</select>
<select id="getRoleCodeList" resultType="String">
select
b.role_code
from
sys_user_role_ref a,
sys_role b
where
a.role_id = b.id
and a.user_id = #{userId}
</select>
<!-- 根据用户id查询菜单列表-->
<select id="findMenuListByUserId" resultType="SysMenu">
select
c.id,
c.icon,
c.menu_name,
c.url,
c.parent_Id
from
sys_user_role_ref a,
sys_role_menu_ref b,
sys_menu c
where
a.role_Id = b.role_Id
and b.menu_id = c.id
and c.parent_id != -1
and a.user_id = #{userId}
and c.type = '1'
order by c.id
</select>
</mapper>

@ -0,0 +1,48 @@
package org.opsli.modulars.system.user.service;
import org.opsli.api.wrapper.system.menu.MenuModel;
import org.opsli.api.wrapper.system.user.UserModel;
import org.opsli.core.base.service.interfaces.CrudServiceInterface;
import org.opsli.modulars.system.user.entity.SysUser;
import java.util.List;
/**
* @BelongsProject: opsli-boot
* @BelongsPackage: org.opsli.modulars.test.service
* @Author: Parker
* @CreateTime: 2020-09-17 13:07
* @Description:
*/
public interface IUserService extends CrudServiceInterface<SysUser, UserModel> {
/**
*
* @param username
* @return
*/
UserModel queryByUserName(String username);
/**
* ID
* @param userId
* @return
*/
List<String> getRoleCodeList(String userId);
/**
* ID
* @param userId
* @return
*/
List<String> getAllPerms(String userId);
/**
* ID
* @param userId
* @return
*/
List<MenuModel> getMenuListByUserId(String userId);
}

@ -0,0 +1,102 @@
package org.opsli.modulars.system.user.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.opsli.api.wrapper.system.menu.MenuModel;
import org.opsli.api.wrapper.system.user.UserModel;
import org.opsli.common.exception.ServiceException;
import org.opsli.common.utils.HumpUtil;
import org.opsli.common.utils.WrapperUtil;
import org.opsli.core.base.service.impl.CrudServiceImpl;
import org.opsli.core.persistence.querybuilder.GenQueryBuilder;
import org.opsli.core.persistence.querybuilder.QueryBuilder;
import org.opsli.core.utils.UserUtil;
import org.opsli.modulars.system.SystemMsg;
import org.opsli.modulars.system.menu.entity.SysMenu;
import org.opsli.modulars.system.user.entity.SysUser;
import org.opsli.modulars.system.user.mapper.UserMapper;
import org.opsli.modulars.system.user.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
/**
* @BelongsProject: opsli-boot
* @BelongsPackage: org.opsli.modulars.test.service
* @Author: Parker
* @CreateTime: 2020-09-16 17:34
* @Description:
*/
@Service
public class UserServiceImpl extends CrudServiceImpl<UserMapper, SysUser, UserModel> implements IUserService {
@Autowired(required = false)
private UserMapper mapper;
@Override
public UserModel insert(UserModel model) {
if(model == null) return null;
SysUser entity = super.transformM2T(model);
// 唯一验证
Integer count = mapper.uniqueVerificationByUsername(entity);
if(count != null && count > 0){
// 重复
throw new ServiceException(SystemMsg.EXCEPTION_USER_UNIQUE);
}
return super.insert(model);
}
@Transactional(rollbackFor = Exception.class)
@Override
public UserModel update(UserModel model) {
if(model == null) return null;
SysUser entity = super.transformM2T(model);
// 唯一验证
Integer count = mapper.uniqueVerificationByUsername(entity);
if(count != null && count > 0){
// 重复
throw new ServiceException(SystemMsg.EXCEPTION_USER_UNIQUE);
}
UserModel update = super.update(model);
if(update != null){
// 刷新用户缓存
UserUtil.refreshUser(update);
}
return update;
}
@Override
public UserModel queryByUserName(String username) {
String key = HumpUtil.humpToUnderline("username");
QueryBuilder<SysUser> queryBuilder = new GenQueryBuilder<>();
QueryWrapper<SysUser> queryWrapper = queryBuilder.build();
queryWrapper.eq(key, username);
SysUser user = this.getOne(queryWrapper);
return super.transformT2M(user);
}
@Override
public List<String> getRoleCodeList(String userId) {
return mapper.getRoleCodeList(userId);
}
@Override
public List<String> getAllPerms(String userId) {
return mapper.queryAllPerms(userId);
}
@Override
public List<MenuModel> getMenuListByUserId(String userId) {
List<SysMenu> menuList = mapper.findMenuListByUserId(userId);
return WrapperUtil.transformInstance(menuList, MenuModel.class);
}
}

@ -0,0 +1,206 @@
package org.opsli.modulars.system.user.web;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.opsli.api.base.result.ResultVo;
import org.opsli.api.web.system.user.UserApi;
import org.opsli.api.wrapper.system.menu.MenuModel;
import org.opsli.api.wrapper.system.user.UserModel;
import org.opsli.common.annotation.ApiRestController;
import org.opsli.core.base.concroller.BaseRestController;
import org.opsli.core.persistence.Page;
import org.opsli.core.persistence.querybuilder.QueryBuilder;
import org.opsli.core.persistence.querybuilder.WebQueryBuilder;
import org.opsli.modulars.system.user.entity.SysUser;
import org.opsli.modulars.system.user.service.IUserService;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
* @BelongsProject: opsli-boot
* @BelongsPackage: org.opsli.modulars.test.web
* @Author: Parker
* @CreateTime: 2020-09-13 17:40
* @Description:
*/
@Slf4j
@ApiRestController("/sys/user")
public class UserRestController extends BaseRestController<SysUser, UserModel, IUserService>
implements UserApi {
/**
*
* @param model
* @return ResultVo
*/
@ApiOperation(value = "获得单条字典明细数据", notes = "获得单条字典明细数据 - ID")
@Override
public ResultVo<UserModel> get(UserModel model) {
// 如果系统内部调用 则直接查数据库
if(model != null && model.getIzApi() != null && model.getIzApi()){
model = IService.get(model);
}
return ResultVo.success(model);
}
/**
*
* @param pageNo
* @param pageSize
* @param request request
* @return ResultVo
*/
@ApiOperation(value = "获得分页数据", notes = "获得分页数据 - 查询构造器")
@Override
public ResultVo<?> findPage(Integer pageNo, Integer pageSize, HttpServletRequest request) {
QueryBuilder<SysUser> queryBuilder = new WebQueryBuilder<>(SysUser.class, request.getParameterMap());
Page<SysUser, UserModel> page = new Page<>(pageNo, pageSize);
page.setQueryWrapper(queryBuilder.build());
page = IService.findPage(page);
return ResultVo.success(page.getBootstrapData());
}
/**
*
* @param model
* @return ResultVo
*/
@ApiOperation(value = "新增字典明细数据", notes = "新增字典明细数据")
@Override
public ResultVo<?> insert(UserModel model) {
// 调用新增方法
IService.insert(model);
return ResultVo.success("新增字典明细数据成功");
}
/**
*
* @param model
* @return ResultVo
*/
@ApiOperation(value = "修改字典明细数据", notes = "修改字典明细数据")
@Override
public ResultVo<?> update(UserModel model) {
// 调用修改方法
IService.update(model);
return ResultVo.success("修改字典明细数据成功");
}
/**
*
* @param id ID
* @return ResultVo
*/
@ApiOperation(value = "删除字典明细数据数据", notes = "删除字典明细数据数据")
@Override
public ResultVo<?> del(String id){
IService.delete(id);
return ResultVo.success("删除字典明细数据成功");
}
/**
*
* @param ids ID
* @return ResultVo
*/
@ApiOperation(value = "批量删除字典明细数据数据", notes = "批量删除字典明细数据数据")
@Override
public ResultVo<?> delAll(String[] ids){
IService.deleteAll(ids);
return ResultVo.success("批量删除字典明细数据成功");
}
/**
* Excel
* @param request request
* @param response response
* @return ResultVo
*/
@ApiOperation(value = "导出Excel", notes = "导出Excel")
@Override
public ResultVo<?> exportExcel(HttpServletRequest request, HttpServletResponse response) {
QueryBuilder<SysUser> queryBuilder = new WebQueryBuilder<>(SysUser.class, request.getParameterMap());
return super.excelExport(UserApi.TITLE, queryBuilder.build(), response);
}
/**
* Excel
* @param request request
* @return ResultVo
*/
@ApiOperation(value = "导入Excel", notes = "导入Excel")
@Override
public ResultVo<?> excelImport(MultipartHttpServletRequest request) {
return super.excelImport(request);
}
/**
* Excel
* @param response response
* @return ResultVo
*/
@ApiOperation(value = "导出Excel模版", notes = "导出Excel模版")
@Override
public ResultVo<?> importTemplate(HttpServletResponse response) {
return super.importTemplate(UserApi.TITLE, response);
}
/**
* username
* @param username
* @return ResultVo
*/
@ApiOperation(value = "根据 username 获得用户", notes = "根据 username 获得用户")
@Override
public ResultVo<UserModel> getUserByUsername(String username) {
UserModel userModel = IService.queryByUserName(username);
if(userModel != null){
return ResultVo.success(userModel);
}
return ResultVo.error("没有该用户");
}
/**
* userId
* @param userId Id
* @return ResultVo
*/
@Override
public ResultVo<List<String>> getRolesByUserId(String userId) {
List<String> roleCodeList = IService.getRoleCodeList(userId);
return ResultVo.success(roleCodeList);
}
/**
* userId
* @param userId Id
* @return ResultVo
*/
@Override
public ResultVo<List<String>> getAllPerms(String userId) {
List<String> allPerms = IService.getAllPerms(userId);
return ResultVo.success(allPerms);
}
/**
* userId
* @param userId Id
* @return ResultVo
*/
@Override
public ResultVo<List<MenuModel>> getMenuListByUserId(String userId) {
List<MenuModel> menuModelList = IService.getMenuListByUserId(userId);
return ResultVo.success(menuModelList);
}
}

@ -1,9 +1,9 @@
package org.opsli.modulars.test.service.impl;
import org.opsli.api.wrapper.test.TestModel;
import org.opsli.common.annotation.EnableHotData;
import org.opsli.common.annotation.HotDataDel;
import org.opsli.common.annotation.HotDataPut;
import org.opsli.common.annotation.hotdata.EnableHotData;
import org.opsli.common.annotation.hotdata.HotDataDel;
import org.opsli.common.annotation.hotdata.HotDataPut;
import org.opsli.core.base.service.impl.CrudServiceImpl;
import org.opsli.modulars.test.entity.TestEntity;
import org.opsli.modulars.test.mapper.TestMapper;

@ -3,17 +3,15 @@ package org.opsli.modulars.test.web;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.RandomUtil;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.opsli.api.base.result.ResultVo;
import org.opsli.api.web.test.TestApi;
import org.opsli.api.wrapper.system.dict.DictModel;
import org.opsli.api.wrapper.system.dict.DictWrapper;
import org.opsli.api.wrapper.test.TestModel;
import org.opsli.common.annotation.ApiRestController;
import org.opsli.common.utils.WrapperUtil;
import org.opsli.core.base.concroller.BaseRestController;
import org.opsli.core.cache.local.CacheUtil;
import org.opsli.core.cache.pushsub.enums.CacheType;
import org.opsli.core.cache.pushsub.msgs.DictMsgFactory;
import org.opsli.core.persistence.Page;
@ -84,7 +82,7 @@ public class TestRestRestController extends BaseRestController<TestEntity, TestM
@ApiOperation(value = "发送 Redis 订阅消息", notes = "发送 Redis 订阅消息")
@Override
public ResultVo<?> sendMsg(){
DictModel model = new DictModel();
DictWrapper model = new DictWrapper();
BaseSubMessage msg = DictMsgFactory.createMsg(model, CacheType.UPDATE);
@ -302,7 +300,7 @@ public class TestRestRestController extends BaseRestController<TestEntity, TestM
@ApiOperation(value = "批量插入1000个随机新增数据", notes = "批量插入1000个随机新增数据")
@GetMapping("/insertAll")
public ResultVo<Boolean> insertAll(){
List<DictModel> testType = DictUtil.getDictList("testType");
List<DictWrapper> testType = DictUtil.getDictList("testType");
List<TestModel> datas = new ArrayList<>();
// 转化对象 处理 ApiModel 与 本地对象

@ -430,9 +430,38 @@ public class RedisPlugin {
* @return
*/
public boolean hPut(String key, String field, Object value) {
return this.hPut(key, field, value, -1, TimeUnit.SECONDS);
}
/**
* Hash
* @param key
* @param field
* @param value
* @return
*/
public boolean hPut(String key, String field, Object value, long timeout) {
return this.hPut(key, field, value, timeout, TimeUnit.SECONDS);
}
/**
*
*
*
* @param key Redis
* @param field
* @param value
* @param timeout
* @param unit
* @return boolean
*/
public boolean hPut(String key, String field, Object value, long timeout, TimeUnit unit) {
boolean ret = false;
try {
redisTemplate.opsForHash().put(key, field, value);
if (timeout > 0) {
expire(key, timeout, unit);
}
ret = true;
} catch (Exception e) {
log.error(e.getMessage(),e);

@ -1,19 +1,14 @@
package org.opsli;
import org.opsli.general.StartPrint;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@SpringBootApplication()
public class OpsliApplication {
public static void main(String[] args){
ConfigurableApplicationContext application = SpringApplication.run(OpsliApplication.class, args);
// 打印启动日志
StartPrint.INSTANCE.print(application.getEnvironment());
SpringApplication.run(OpsliApplication.class, args);
}
}

@ -44,6 +44,9 @@ spring:
autoconfigure:
exclude:
- com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure
#
#main:
# allow-bean-definition-overriding: true
# 邮件设置
mail:
host: smtp.qq.com
@ -142,3 +145,8 @@ mybatis-plus:
call-setters-on-nulls: true
# 打印SQL 开发测试使用 生产关闭 ***
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
# opsli 自定义配置
opsli:
# token 有效时间 (分钟) 2小时
token-effective-time: 120

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save