refactor: 2.0 版本重构

新增:
1. 新增EventBus
2. 新增 邮箱、手机、用户名 + 密码登陆
3. 新增 邮箱 + 验证码 登录
4. 新增 手机号 + 验证码 登录
5. 新增个人修改手机号 前置身份校验
6. 新增个人修改邮箱 前置身份校验
7. 新增个人中心忘记密码 前置身份校验
8. 新增使用ResultWrapper 代替 ResultVo 返回数据

优化:
1. 优化接口加密
2. 优化CrudService实现
3. 变更自动日志记录模式到自定义记录
4. 优化导出Excel模式为认证模式
5. 优化用户Redis缓存
6. 移除Shiro,变更使用SpringSecurity 作为权限验证

升级/修复:
1. 修复 SecurityCache 缓存穿透BUG
2. 升级 mybatis-plus 版本至 3.5.2 修复若干CVE
3. 升级 springboot 版本至 2.5.6 修复若干CVE
4. 升级 mysql版本至8.0.28  修复 CVE-2022-21363
5. 升级 guava 版本至 30.0.android 修复 修复 CVE-2020-8908
6. 升级 bouncycastle 版本至 1.69 修复 Cxa9261daf-3755
7. 升级 protobuf-java 版本至 3.18.2 修复 CVE-2021-22569
8. 升级 logback 版本至 修复 CVE-2021-42550
pull/19/head
Parker 3 years ago
parent 077196058c
commit edd6dcec59

@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier same "printed page" as the copyright notice for easier
identification within third-party archives. identification within third-party archives.
Copyright [yyyy] [name of copyright owner] Copyright [2020] [OPSLI 快速开发平台 https://www.opsli.com]
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

File diff suppressed because one or more lines are too long

@ -0,0 +1,14 @@
FROM mysql:8.0.19
MAINTAINER opsli.com
LABEL version=V1.3.3
LABEL description=OPSLI-快速开发平台
LABEL qqGroup=724850675
ENV TZ=Asia/Shanghai
# 切换为上海时区
RUN ln -sf /usr/share/zoneinfo/$TZ /etc/localtime \
&& echo $TZ > /etc/timezone
COPY ./opsli-boot.sql /docker-entrypoint-initdb.d

File diff suppressed because one or more lines are too long

@ -2,7 +2,7 @@ version: '3.3'
services: services:
# 构建 MySQL数据库 这里不指定数据库文件 防止误操作 等隐患问题 # 构建 MySQL数据库 这里不指定数据库文件 防止误操作 等隐患问题
opsli-boot-mysql: opsli-boot-mysql:
build: ./db-file build: ./db-file/2.0版本
image: opsli-boot-mysql image: opsli-boot-mysql
restart: always restart: always
environment: environment:

@ -10,7 +10,7 @@ import java.io.Serializable;
/** /**
* *
* *
* @author * @author Parker
* @date 2021-01-24 12:48 * @date 2021-01-24 12:48
**/ **/
@Data @Data

@ -0,0 +1,42 @@
/**
* Copyright 2020 OPSLI https://www.opsli.com
* <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.api.base.encrypt;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.opsli.common.annotation.validator.Validator;
import org.opsli.common.annotation.validator.ValidatorLenMax;
import org.opsli.common.enums.ValidatorType;
import java.io.Serializable;
/**
*
*
* @author Parker
* @date 2021-01-24 12:48
**/
@Data
public class EncryptModel implements Serializable {
private static final long serialVersionUID = 1L;
@Validator({ValidatorType.IS_NOT_NULL})
@ValidatorLenMax(2000)
@ApiModelProperty(value = "加密数据")
private String encryptData;
}

@ -1,207 +0,0 @@
package org.opsli.api.base.result;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.http.HttpStatus;
import java.io.Serializable;
/**
* API
* Feign
* @JsonProperty null
*
* @date 202051510:40:54
* @author Parker
*/
@Data
@ApiModel(value="视图层返回Api对象",
description="视图层返回Api对象 success:成功状态 code:编号 msg:信息 timestamp:时间戳 data:数据")
public class ResultVo<T> implements Serializable {
private static final long serialVersionUID = 1L;
/** 默认成功信息 */
public static final String DEF_SUCCESS_MSG = "操作成功!";
/** 默认失败信息 */
public static final String DEF_ERROR_MSG = "操作失败!";
/** 成功状态 */
@ApiModelProperty(value = "成功状态")
@JsonProperty("success")
private boolean success;
/** 消息 */
@ApiModelProperty(value = "消息")
@JsonProperty("msg")
private String msg;
/** 状态码 */
@ApiModelProperty(value = "状态码")
@JsonProperty("code")
private Integer code;
/** 时间戳 */
@ApiModelProperty(value = "时间戳")
@JsonProperty("timestamp")
private Long timestamp;
/** 数据对象 */
@ApiModelProperty(value = "数据")
@JsonProperty("data")
private T data;
public T getData() {
return data;
}
public ResultVo<T> setData(T data) {
this.data = data;
return this;
}
/**
* Json
* @return String
*/
public String toJsonStr(){
return JSONObject.toJSONString(this);
}
// ===========================================
/**
*
*/
public ResultVo() {
// 初始化值
this.success = true;
this.msg = DEF_SUCCESS_MSG;
this.code = HttpStatus.OK.value();
this.timestamp = System.currentTimeMillis();
}
// ================================== 静态方法 ===================================
/**
*
* @return ResultVo<Object>
*/
@JsonIgnore
public static ResultVo<Object> success() {
return new ResultVo<>();
}
/**
*
* @param msg
* @return ResultVo<Object>
*/
@JsonIgnore
public static ResultVo<Object> success(String msg) {
ResultVo<Object> ret = new ResultVo<>();
ret.setMsg(msg);
return ret;
}
/**
*
* @param data
* @param <T>
* @return ResultVo<T>
*/
@JsonIgnore
public static <T> ResultVo<T> success(T data) {
ResultVo<T> ret = new ResultVo<>();
ret.setData(data);
return ret;
}
/**
*
* @param msg
* @param data
* @param <T>
* @return ResultVo<T>
*/
@JsonIgnore
public static <T> ResultVo<T> success(String msg, T data) {
ResultVo<T> ret = new ResultVo<>();
ret.setMsg(msg);
ret.setData(data);
return ret;
}
/**
*
* @param msg
* @param data
* @param <T>
* @return ResultVo<T>
*/
@JsonIgnore
public static <T> ResultVo<T> success(Integer code, String msg, T data) {
ResultVo<T> ret = new ResultVo<>();
ret.setCode(code);
ret.setMsg(msg);
ret.setData(data);
return ret;
}
/**
*
* @return ResultVo<Object>
*/
@JsonIgnore
public static ResultVo<Object> error() {
return ResultVo.error(
HttpStatus.INTERNAL_SERVER_ERROR.value()
, DEF_ERROR_MSG, null);
}
/**
*
* @param msg
* @return ResultVo<Object>
*/
@JsonIgnore
public static ResultVo<Object> error(String msg) {
return ResultVo.error(
HttpStatus.INTERNAL_SERVER_ERROR.value()
, msg, null);
}
/**
*
* @param code
* @param msg
* @return ResultVo<T>
*/
@JsonIgnore
public static ResultVo<Object> error(Integer code, String msg) {
return ResultVo.error(code, msg, null);
}
/**
*
* @param code
* @param data
* @param <T>
* @return ResultVo<T>
*/
@JsonIgnore
public static <T> ResultVo<T> error(Integer code, String msg, T data) {
ResultVo<T> ret = new ResultVo<>();
ret.setMsg(msg);
ret.setCode(code);
ret.setData(data);
ret.setSuccess(false);
return ret;
}
}

@ -0,0 +1,263 @@
/**
* Copyright 2020 OPSLI https://www.opsli.com
* <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.api.base.result;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.*;
import lombok.experimental.Accessors;
import org.opsli.common.base.msg.BaseMsg;
import java.io.Serializable;
/**
*
*
* @author Parker
* @date 2021123015:31:41
*/
@Data
@Builder
@Accessors(chain = true)
@AllArgsConstructor
@NoArgsConstructor
@ApiModel(value = "基础返回实体",
description="视图层返回Api对象 code:编号 msg:信息 timestamp:时间戳 data:数据")
public class ResultWrapper<T> implements Serializable {
private static final long serialVersionUID = 1L;
/**
*
*/
@ApiModelProperty(name = "msg", dataType = "string", value = "响应信息")
private String msg;
/**
* 0-1
*/
@ApiModelProperty(name = "code", dataType = "int", value = "响应码")
private int code;
/**
*
*/
@ApiModelProperty(name = "data", dataType = "object", value = "数据内容")
private T data;
/**
*
*/
@ApiModelProperty(name = "timestamp", dataType = "long", value = "时间戳")
private long timestamp;
/**
* ,
* {@link StateCodeEnum#SUCCESS}
* @param <T>
* @return ResultWrapper<T>
*/
public static <T> ResultWrapper<T> getSuccessResultWrapperByMsg(String msg) {
return ResultWrapper.<T>builder()
.code(StateCodeEnum.SUCCESS.getCode())
.msg(msg)
.timestamp(System.currentTimeMillis())
.build();
}
/**
* ,
* {@link StateCodeEnum#SUCCESS}
* @param <T>
* @return ResultWrapper<T>
*/
public static <T> ResultWrapper<T> getSuccessResultWrapper() {
return getSuccessResultWrapper(null);
}
/**
* ,
* {@link StateCodeEnum#SUCCESS}
* @param data
* @param <T>
* @return ResultWrapper<T>
*/
public static <T> ResultWrapper<T> getSuccessResultWrapper(T data) {
return ResultWrapper.<T>builder()
.code(StateCodeEnum.SUCCESS.getCode())
.msg(StateCodeEnum.SUCCESS.getMsg())
.data(data)
.timestamp(System.currentTimeMillis())
.build();
}
/**
*
* {@link StateCodeEnum#ERROR}
* @param <T>
* @return ResultWrapper<T>
*/
public static <T> ResultWrapper<T> getErrorResultWrapper() {
return getErrorResultWrapper(null);
}
/**
*
* {@link StateCodeEnum#ERROR}
* @param data
* @param <T>
* @return ResultWrapper<T>
*/
public static <T> ResultWrapper<T> getErrorResultWrapper(T data) {
return ResultWrapper.<T>builder()
.code(StateCodeEnum.ERROR.getCode())
.msg(StateCodeEnum.ERROR.getMsg())
.data(data)
.timestamp(System.currentTimeMillis())
.build();
}
/**
* 便
* @param stateCode
* @param <T>
* @return ResultWrapper<T>
*/
public static <T> ResultWrapper<T> getCustomResultWrapper(StateCodeEnum stateCode) {
return getCustomResultWrapper(null, stateCode);
}
/**
* 便
* @param data
* @param stateCode
* @param <T>
* @return ResultWrapper<T>
*/
public static <T> ResultWrapper<T> getCustomResultWrapper(T data, StateCodeEnum stateCode) {
return ResultWrapper.<T>builder()
.code(stateCode.getCode())
.msg(stateCode.getMsg())
.data(data)
.timestamp(System.currentTimeMillis())
.build();
}
/**
* 便
* @param baseMsg
* @param <T>
* @return ResultWrapper<T>
*/
public static <T> ResultWrapper<T> getCustomResultWrapper(BaseMsg baseMsg) {
return getCustomResultWrapper(null, baseMsg);
}
/**
* 便
* @param data
* @param baseMsg
* @param <T>
* @return ResultWrapper<T>
*/
public static <T> ResultWrapper<T> getCustomResultWrapper(T data, BaseMsg baseMsg) {
return ResultWrapper.<T>builder()
.code(baseMsg.getCode())
.msg(baseMsg.getMessage())
.data(data)
.timestamp(System.currentTimeMillis())
.build();
}
/**
* 便
* {@link StateCodeEnum#SUCCESS}
* @param data
* @param code
* @param msg
* @param <T>
* @return ResultWrapper<T>
*/
public static <T> ResultWrapper<T> getCustomResultWrapper(T data, int code, String msg) {
return ResultWrapper.<T>builder()
.code(code)
.msg(msg)
.data(data)
.timestamp(System.currentTimeMillis())
.build();
}
/**
* 便
* {@link StateCodeEnum#SUCCESS}
* @param code
* @param msg
* @param <T>
* @return ResultWrapper<T>
*/
public static <T> ResultWrapper<T> getCustomResultWrapper(int code, String msg) {
return ResultWrapper.<T>builder()
.code(code)
.msg(msg)
.data(null)
.timestamp(System.currentTimeMillis())
.build();
}
/**
* ,
* @param resultWrapper
* @param <T>
* @return boolean
*/
public static <T> boolean isSuccess(ResultWrapper<T> resultWrapper) {
if(null == resultWrapper){
return false;
}
return StateCodeEnum.SUCCESS.getCode() == resultWrapper.getCode();
}
/**
*
*
* @author Parker
* @date 2021123015:29:29
*/
@Getter
@AllArgsConstructor
public enum StateCodeEnum {
/** 请求状态枚举 */
SUCCESS(0, "请求成功"),
FAILURE(-1, "操作失败"),
ERROR(-1, "服务器异常");
private final int code;
private final String msg;
}
}

@ -15,7 +15,7 @@
*/ */
package org.opsli.api.web.gentest.carinfo; package org.opsli.api.web.gentest.carinfo;
import org.opsli.api.base.result.ResultVo; import org.opsli.api.base.result.ResultWrapper;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartHttpServletRequest; import org.springframework.web.multipart.MultipartHttpServletRequest;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
@ -25,7 +25,7 @@ import org.opsli.api.wrapper.gentest.carinfo.TestCarModel;
/** /**
* * Api
* *
* API @GetMapping @PostMapping * API @GetMapping @PostMapping
* Mapping Controller * Mapping Controller
@ -33,98 +33,97 @@ import org.opsli.api.wrapper.gentest.carinfo.TestCarModel;
* *
* *
* @author Parker * @author Parker
* @date 2020-12-20 20:12:57 * @date 2022-08-06 23:53:30
*/ */
public interface TestCarRestApi { public interface TestCarRestApi {
/** 标题 */ /** 标题 */
String TITLE = "汽车信息管理"; String TITLE = "测试汽车";
/** 子标题 */ /** 子标题 */
String SUB_TITLE = "汽车信息"; String SUB_TITLE = "测试汽车";
/** /**
* *
* @param model * @param model
* @return ResultVo * @return ResultWrapper
*/ */
@GetMapping("/get") @GetMapping("/get")
ResultVo<TestCarModel> get(TestCarModel model); ResultWrapper<TestCarModel> get(TestCarModel model);
/** /**
* *
* @param pageNo * @param pageNo
* @param pageSize * @param pageSize
* @param request request * @param request request
* @return ResultVo * @return ResultWrapper
*/ */
@GetMapping("/findPage") @GetMapping("/findPage")
ResultVo<?> findPage( ResultWrapper<?> findPage(
@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo, @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize, @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
HttpServletRequest request HttpServletRequest request
); );
/** /**
* *
* @param model * @param model
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/insert") @PostMapping("/insert")
ResultVo<?> insert(@RequestBody TestCarModel model); ResultWrapper<?> insert(@RequestBody TestCarModel model);
/** /**
* *
* @param model * @param model
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/update") @PostMapping("/update")
ResultVo<?> update(@RequestBody TestCarModel model); ResultWrapper<?> update(@RequestBody TestCarModel model);
/** /**
* *
* @param id ID * @param id ID
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/del") @PostMapping("/del")
ResultVo<?> del(String id); ResultWrapper<?> del(String id);
/** /**
* *
* @param ids ID * @param ids ID
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/delAll") @PostMapping("/delAll")
ResultVo<?> delAll(String ids); ResultWrapper<?> delAll(String ids);
/** /**
* Excel * Excel
*
* Token
*
* 使2
*
* socketJava
* response javascript alert
* *
* @param type
* @param request request * @param request request
* @param response response
*/ */
@GetMapping("/exportExcel") @GetMapping("/excel/auth/{type}")
void exportExcel(HttpServletRequest request, HttpServletResponse response); ResultWrapper<String> exportExcelAuth(
@PathVariable("type") String type,
HttpServletRequest request);
/** /**
* Excel * Excel
* @param request request *
* @return ResultVo * @param certificate
* @param response response
*/ */
@PostMapping("/importExcel") @GetMapping("/excel/export/{certificate}")
ResultVo<?> importExcel(MultipartHttpServletRequest request); void exportExcel(
@PathVariable("certificate") String certificate,
HttpServletResponse response);
/** /**
* Excel * Excel
* @param response response * @param request request
* @return ResultWrapper
*/ */
@GetMapping("/importExcel/template") @PostMapping("/importExcel")
void importTemplate(HttpServletResponse response); ResultWrapper<?> importExcel(MultipartHttpServletRequest request);
} }

@ -15,11 +15,8 @@
*/ */
package org.opsli.api.web.gentest.user; package org.opsli.api.web.gentest.user;
import org.opsli.api.base.result.ResultVo; import org.opsli.api.base.result.ResultWrapper;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartHttpServletRequest; import org.springframework.web.multipart.MultipartHttpServletRequest;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
@ -48,20 +45,20 @@ public interface TestUserRestApi {
/** /**
* *
* @param model * @param model
* @return ResultVo * @return ResultWrapper
*/ */
@GetMapping("/get") @GetMapping("/get")
ResultVo<TestUserModel> get(TestUserModel model); ResultWrapper<TestUserModel> get(TestUserModel model);
/** /**
* *
* @param pageNo * @param pageNo
* @param pageSize * @param pageSize
* @param request request * @param request request
* @return ResultVo * @return ResultWrapper
*/ */
@GetMapping("/findPage") @GetMapping("/findPage")
ResultVo<?> findPage( ResultWrapper<?> findPage(
@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo, @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize, @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
HttpServletRequest request HttpServletRequest request
@ -70,56 +67,64 @@ public interface TestUserRestApi {
/** /**
* *
* @param model * @param model
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/insert") @PostMapping("/insert")
ResultVo<?> insert(@RequestBody TestUserModel model); ResultWrapper<?> insert(@RequestBody TestUserModel model);
/** /**
* *
* @param model * @param model
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/update") @PostMapping("/update")
ResultVo<?> update(@RequestBody TestUserModel model); ResultWrapper<?> update(@RequestBody TestUserModel model);
/** /**
* *
* @param id ID * @param id ID
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/del") @PostMapping("/del")
ResultVo<?> del(String id); ResultWrapper<?> del(String id);
/** /**
* *
* @param ids ID * @param ids ID
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/delAll") @PostMapping("/delAll")
ResultVo<?> delAll(String ids); ResultWrapper<?> delAll(String ids);
/** /**
* Excel * Excel
*
* @param type
* @param request request * @param request request
*/
@GetMapping("/excel/auth/{type}")
ResultWrapper<String> exportExcelAuth(
@PathVariable("type") String type,
HttpServletRequest request);
/**
* Excel
*
* @param certificate
* @param response response * @param response response
*/ */
@GetMapping("/exportExcel") @GetMapping("/excel/export/{certificate}")
void exportExcel(HttpServletRequest request, HttpServletResponse response); void exportExcel(
@PathVariable("certificate") String certificate,
HttpServletResponse response);
/** /**
* Excel * Excel
* @param request request * @param request request
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/importExcel") @PostMapping("/importExcel")
ResultVo<?> importExcel(MultipartHttpServletRequest request); ResultWrapper<?> importExcel(MultipartHttpServletRequest request);
/**
* Excel
* @param response response
*/
@GetMapping("/importExcel/template")
void importTemplate(HttpServletResponse response);
} }

@ -15,7 +15,7 @@
*/ */
package org.opsli.api.web.system.area; package org.opsli.api.web.system.area;
import org.opsli.api.base.result.ResultVo; import org.opsli.api.base.result.ResultWrapper;
import org.opsli.api.wrapper.system.area.SysAreaModel; import org.opsli.api.wrapper.system.area.SysAreaModel;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
@ -48,80 +48,57 @@ public interface SysAreaRestApi {
/** /**
* *
* @param model * @param model
* @return ResultVo * @return ResultWrapper
*/ */
@GetMapping("/get") @GetMapping("/get")
ResultVo<SysAreaModel> get(SysAreaModel model); ResultWrapper<SysAreaModel> get(SysAreaModel model);
/** /**
* *
* @param parentId ID * @param parentId ID
* @return ResultVo * @return ResultWrapper
*/ */
@GetMapping("/findTree") @GetMapping("/findTree")
ResultVo<?> findTree(String parentId); ResultWrapper<?> findTree(String parentId);
/** /**
* *
* @param deep * @param deep
* @return ResultVo * @return ResultWrapper
*/ */
@GetMapping("/findTreeAll") @GetMapping("/findTreeAll")
ResultVo<?> findTreeAll(@RequestParam(name = "deep", defaultValue = "3", required = false) Integer deep); ResultWrapper<?> findTreeAll(@RequestParam(name = "deep", defaultValue = "3", required = false) Integer deep);
/** /**
* *
* @param model * @param model
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/insert") @PostMapping("/insert")
ResultVo<?> insert(@RequestBody SysAreaModel model); ResultWrapper<?> insert(@RequestBody SysAreaModel model);
/** /**
* *
* @param model * @param model
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/update") @PostMapping("/update")
ResultVo<?> update(@RequestBody SysAreaModel model); ResultWrapper<?> update(@RequestBody SysAreaModel model);
/** /**
* *
* @param id ID * @param id ID
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/del") @PostMapping("/del")
ResultVo<?> del(String id); ResultWrapper<?> del(String id);
/** /**
* *
* @param ids ID * @param ids ID
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/delAll") @PostMapping("/delAll")
ResultVo<?> delAll(String ids); ResultWrapper<?> delAll(String ids);
/**
* Excel
* @param request request
* @param response response
*/
@GetMapping("/exportExcel")
void exportExcel(HttpServletRequest request, HttpServletResponse response);
/**
* Excel
* @param request request
* @return ResultVo
*/
@PostMapping("/importExcel")
ResultVo<?> importExcel(MultipartHttpServletRequest request);
/**
* Excel
* @param response response
*/
@GetMapping("/importExcel/template")
void importTemplate(HttpServletResponse response);
} }

@ -15,7 +15,7 @@
*/ */
package org.opsli.api.web.system.dict; package org.opsli.api.web.system.dict;
import org.opsli.api.base.result.ResultVo; import org.opsli.api.base.result.ResultWrapper;
import org.opsli.api.wrapper.system.dict.DictModel; import org.opsli.api.wrapper.system.dict.DictModel;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
@ -48,20 +48,20 @@ public interface DictApi {
/** /**
* *
* @param model * @param model
* @return ResultVo * @return ResultWrapper
*/ */
@GetMapping("/get") @GetMapping("/get")
ResultVo<DictModel> get(DictModel model); ResultWrapper<DictModel> get(DictModel model);
/** /**
* *
* @param pageNo * @param pageNo
* @param pageSize * @param pageSize
* @param request request * @param request request
* @return ResultVo * @return ResultWrapper
*/ */
@GetMapping("/findPage") @GetMapping("/findPage")
ResultVo<?> findPage( ResultWrapper<?> findPage(
@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo, @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize, @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
HttpServletRequest request HttpServletRequest request
@ -70,65 +70,42 @@ public interface DictApi {
/** /**
* *
* @param model * @param model
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/insert") @PostMapping("/insert")
ResultVo<?> insert(@RequestBody DictModel model); ResultWrapper<?> insert(@RequestBody DictModel model);
/** /**
* *
* @param model * @param model
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/update") @PostMapping("/update")
ResultVo<?> update(@RequestBody DictModel model); ResultWrapper<?> update(@RequestBody DictModel model);
/** /**
* *
* @param id ID * @param id ID
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/del") @PostMapping("/del")
ResultVo<?> del(String id); ResultWrapper<?> del(String id);
/** /**
* *
* @param ids ID * @param ids ID
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/delAll") @PostMapping("/delAll")
ResultVo<?> delAll(String ids); ResultWrapper<?> delAll(String ids);
/**
* Excel
* @param request request
* @param response response
*/
@GetMapping("/exportExcel")
void exportExcel(HttpServletRequest request, HttpServletResponse response);
/**
* Excel
* @param request request
* @return ResultVo
*/
@PostMapping("/importExcel")
ResultVo<?> importExcel(MultipartHttpServletRequest request);
/**
* Excel
* @param response response
*/
@GetMapping("/importExcel/template")
void importTemplate(HttpServletResponse response);
/** /**
* *
* *
* @param typeCode * @param typeCode
* @return ResultVo * @return ResultWrapper
*/ */
@GetMapping("/getDictListByCode") @GetMapping("/getDictListByCode")
ResultVo<?> getDictListByCode(String typeCode); ResultWrapper<?> getDictListByCode(String typeCode);
} }

@ -15,7 +15,7 @@
*/ */
package org.opsli.api.web.system.dict; package org.opsli.api.web.system.dict;
import org.opsli.api.base.result.ResultVo; import org.opsli.api.base.result.ResultWrapper;
import org.opsli.api.wrapper.system.dict.DictDetailModel; import org.opsli.api.wrapper.system.dict.DictDetailModel;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
@ -49,20 +49,20 @@ public interface DictDetailApi {
/** /**
* *
* @param model * @param model
* @return ResultVo * @return ResultWrapper
*/ */
@GetMapping("/get") @GetMapping("/get")
ResultVo<DictDetailModel> get(DictDetailModel model); ResultWrapper<DictDetailModel> get(DictDetailModel model);
/** /**
* *
* @param pageNo * @param pageNo
* @param pageSize * @param pageSize
* @param request request * @param request request
* @return ResultVo * @return ResultWrapper
*/ */
@GetMapping("/findPage") @GetMapping("/findPage")
ResultVo<?> findPage( ResultWrapper<?> findPage(
@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo, @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize, @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
HttpServletRequest request HttpServletRequest request
@ -71,57 +71,34 @@ public interface DictDetailApi {
/** /**
* *
* @param model * @param model
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/insert") @PostMapping("/insert")
ResultVo<?> insert(@RequestBody DictDetailModel model); ResultWrapper<?> insert(@RequestBody DictDetailModel model);
/** /**
* *
* @param model * @param model
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/update") @PostMapping("/update")
ResultVo<?> update(@RequestBody DictDetailModel model); ResultWrapper<?> update(@RequestBody DictDetailModel model);
/** /**
* *
* @param id ID * @param id ID
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/del") @PostMapping("/del")
ResultVo<?> del(String id); ResultWrapper<?> del(String id);
/** /**
* *
* @param ids ID * @param ids ID
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/delAll") @PostMapping("/delAll")
ResultVo<?> delAll(String ids); ResultWrapper<?> delAll(String ids);
/**
* Excel
* @param request request
* @param response response
*/
@GetMapping("/exportExcel")
void exportExcel(HttpServletRequest request, HttpServletResponse response);
/**
* Excel
* @param request request
* @return ResultVo
*/
@PostMapping("/importExcel")
ResultVo<?> importExcel(MultipartHttpServletRequest request);
/**
* Excel
* @param response response
*/
@GetMapping("/importExcel/template")
void importTemplate(HttpServletResponse response);
// ================================ // ================================
@ -130,9 +107,9 @@ public interface DictDetailApi {
* *
* *
* @param typeCode * @param typeCode
* @return ResultVo * @return ResultWrapper
*/ */
@GetMapping("/findListByTypeCode") @GetMapping("/findListByTypeCode")
ResultVo<List<DictDetailModel>> findListByTypeCode(String typeCode); ResultWrapper<List<DictDetailModel>> findListByTypeCode(String typeCode);
} }

@ -15,7 +15,7 @@
*/ */
package org.opsli.api.web.system.logs; package org.opsli.api.web.system.logs;
import org.opsli.api.base.result.ResultVo; import org.opsli.api.base.result.ResultWrapper;
import org.opsli.api.wrapper.system.logs.LogsModel; import org.opsli.api.wrapper.system.logs.LogsModel;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
@ -48,10 +48,10 @@ public interface LoginLogsApi {
* @param pageNo * @param pageNo
* @param pageSize * @param pageSize
* @param request request * @param request request
* @return ResultVo * @return ResultWrapper
*/ */
@GetMapping("/findPage") @GetMapping("/findPage")
ResultVo<?> findPage( ResultWrapper<?> findPage(
@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo, @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize, @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
HttpServletRequest request HttpServletRequest request

@ -15,7 +15,7 @@
*/ */
package org.opsli.api.web.system.logs; package org.opsli.api.web.system.logs;
import org.opsli.api.base.result.ResultVo; import org.opsli.api.base.result.ResultWrapper;
import org.opsli.api.wrapper.system.logs.LogsModel; import org.opsli.api.wrapper.system.logs.LogsModel;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
@ -45,20 +45,20 @@ public interface LogsApi {
/** /**
* *
* @param model * @param model
* @return ResultVo * @return ResultWrapper
*/ */
@GetMapping("/get") @GetMapping("/get")
ResultVo<LogsModel> get(LogsModel model); ResultWrapper<LogsModel> get(LogsModel model);
/** /**
* *
* @param pageNo * @param pageNo
* @param pageSize * @param pageSize
* @param request request * @param request request
* @return ResultVo * @return ResultWrapper
*/ */
@GetMapping("/findPage") @GetMapping("/findPage")
ResultVo<?> findPage( ResultWrapper<?> findPage(
@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo, @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize, @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
HttpServletRequest request HttpServletRequest request
@ -68,8 +68,8 @@ public interface LogsApi {
/** /**
* *
* @param model * @param model
* @return ResultVo * @return ResultWrapper
*/ */
ResultVo<?> insert(LogsModel model); ResultWrapper<?> insert(LogsModel model);
} }

@ -0,0 +1,92 @@
/**
* Copyright 2020 OPSLI https://www.opsli.com
* <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.api.web.system.logs;
import org.opsli.api.base.result.ResultWrapper;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.opsli.api.wrapper.system.logs.OperationLogModel;
/**
* Api
*
* API @GetMapping @PostMapping
* Mapping Controller
*
*
*
* @author Parker
* @date 2022-07-26 19:21:57
*/
public interface OperationLogRestApi {
/** 标题 */
String TITLE = "行为日志";
/** 子标题 */
String SUB_TITLE = "行为日志";
/**
*
* @param model
* @return ResultWrapper
*/
@GetMapping("/get")
ResultWrapper<OperationLogModel> get(OperationLogModel model);
/**
*
* @param pageNo
* @param pageSize
* @param request request
* @return ResultWrapper
*/
@GetMapping("/findPage")
ResultWrapper<?> findPage(
@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
HttpServletRequest request
);
/**
* Excel
*
* @param type
* @param request request
*/
@GetMapping("/excel/auth/{type}")
ResultWrapper<String> exportExcelAuth(
@PathVariable("type") String type,
HttpServletRequest request);
/**
* Excel
*
* @param certificate
* @param response response
*/
@GetMapping("/excel/export/{certificate}")
void exportExcel(
@PathVariable("certificate") String certificate,
HttpServletResponse response);
}

@ -15,7 +15,7 @@
*/ */
package org.opsli.api.web.system.menu; package org.opsli.api.web.system.menu;
import org.opsli.api.base.result.ResultVo; import org.opsli.api.base.result.ResultWrapper;
import org.opsli.api.wrapper.system.menu.MenuFullModel; import org.opsli.api.wrapper.system.menu.MenuFullModel;
import org.opsli.api.wrapper.system.menu.MenuModel; import org.opsli.api.wrapper.system.menu.MenuModel;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
@ -52,71 +52,71 @@ public interface MenuApi {
* *
* *
* @param request request * @param request request
* @return ResultVo * @return ResultWrapper
*/ */
@GetMapping("/findMenuTreePage") @GetMapping("/findMenuTreePage")
ResultVo<?> findMenuTreePage(HttpServletRequest request); ResultWrapper<?> findMenuTreePage(HttpServletRequest request);
/** /**
* *
* *
* @param parentId ID * @param parentId ID
* @return ResultVo * @return ResultWrapper
*/ */
@GetMapping("/findMenuTreePageByLazy") @GetMapping("/findMenuTreePageByLazy")
ResultVo<?> findMenuTreePageByLazy(String parentId); ResultWrapper<?> findMenuTreePageByLazy(String parentId);
/** /**
* *
* @param parentId ID * @param parentId ID
* @param id ID * @param id ID
* @return ResultVo * @return ResultWrapper
*/ */
@GetMapping("/findMenuTreeByLazy") @GetMapping("/findMenuTreeByLazy")
ResultVo<?> findMenuTreeByLazy(String parentId, String id); ResultWrapper<?> findMenuTreeByLazy(String parentId, String id);
/** /**
* *
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/findMenuTree") @PostMapping("/findMenuTree")
ResultVo<?> findMenuTree(); ResultWrapper<?> findMenuTree();
/** /**
* - * -
* *
* @param label * @param label
* @return ResultVo * @return ResultWrapper
*/ */
@GetMapping("/getMenuAndPermsTree") @GetMapping("/getMenuAndPermsTree")
ResultVo<?> getMenuAndPermsTree(String label); ResultWrapper<?> getMenuAndPermsTree(String label);
/** /**
* *
* @return ResultVo * @return ResultWrapper
*/ */
@GetMapping("/findList") @GetMapping("/findList")
ResultVo<List<MenuModel>> findList(); ResultWrapper<List<MenuModel>> findList();
/** /**
* *
* @param model * @param model
* @return ResultVo * @return ResultWrapper
*/ */
@GetMapping("/get") @GetMapping("/get")
ResultVo<MenuModel> get(MenuModel model); ResultWrapper<MenuModel> get(MenuModel model);
/** /**
* *
* @param pageNo * @param pageNo
* @param pageSize * @param pageSize
* @param request request * @param request request
* @return ResultVo * @return ResultWrapper
*/ */
@GetMapping("/findPage") @GetMapping("/findPage")
ResultVo<?> findPage( ResultWrapper<?> findPage(
@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo, @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize, @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
HttpServletRequest request HttpServletRequest request
@ -125,58 +125,34 @@ public interface MenuApi {
/** /**
* *
* @param model * @param model
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/insert") @PostMapping("/insert")
ResultVo<?> insert(@RequestBody MenuModel model); ResultWrapper<?> insert(@RequestBody MenuModel model);
/** /**
* *
* @param model * @param model
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/update") @PostMapping("/update")
ResultVo<?> update(@RequestBody MenuModel model); ResultWrapper<?> update(@RequestBody MenuModel model);
/** /**
* *
* @param id ID * @param id ID
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/del") @PostMapping("/del")
ResultVo<?> del(String id); ResultWrapper<?> del(String id);
/** /**
* *
* @param ids ID * @param ids ID
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/delAll") @PostMapping("/delAll")
ResultVo<?> delAll(String ids); ResultWrapper<?> delAll(String ids);
/**
* Excel
* @param request request
* @param response response
*/
@GetMapping("/exportExcel")
void exportExcel(HttpServletRequest request, HttpServletResponse response);
/**
* Excel
* @param request request
* @return ResultVo
*/
@PostMapping("/importExcel")
ResultVo<?> importExcel(MultipartHttpServletRequest request);
/**
* Excel
* @param response response
*/
@GetMapping("/importExcel/template")
void importTemplate(HttpServletResponse response);
// ================= 普通 // ================= 普通
@ -184,14 +160,14 @@ public interface MenuApi {
/** /**
* *
* @param permissions * @param permissions
* @return ResultVo * @return ResultWrapper
*/ */
ResultVo<MenuModel> getByPermissions(String permissions); ResultWrapper<MenuModel> getByPermissions(String permissions);
/** /**
* *
* @param menuFullModel * @param menuFullModel
* @return ResultVo * @return ResultWrapper
*/ */
ResultVo<?> saveMenuByFull(@RequestBody MenuFullModel menuFullModel); ResultWrapper<?> saveMenuByFull(@RequestBody MenuFullModel menuFullModel);
} }

@ -17,11 +17,8 @@
package org.opsli.api.web.system.options; package org.opsli.api.web.system.options;
import org.opsli.api.base.result.ResultVo; import org.opsli.api.base.result.ResultWrapper;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartHttpServletRequest; import org.springframework.web.multipart.MultipartHttpServletRequest;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
@ -55,20 +52,20 @@ public interface OptionsApi {
/** /**
* *
* @param model * @param model
* @return ResultVo * @return ResultWrapper
*/ */
@GetMapping("/get") @GetMapping("/get")
ResultVo<OptionsModel> get(OptionsModel model); ResultWrapper<OptionsModel> get(OptionsModel model);
/** /**
* *
* @param pageNo * @param pageNo
* @param pageSize * @param pageSize
* @param request request * @param request request
* @return ResultVo * @return ResultWrapper
*/ */
@GetMapping("/findPage") @GetMapping("/findPage")
ResultVo<?> findPage( ResultWrapper<?> findPage(
@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo, @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize, @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
HttpServletRequest request HttpServletRequest request
@ -77,108 +74,105 @@ public interface OptionsApi {
/** /**
* *
* @param model * @param model
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/insert") @PostMapping("/insert")
ResultVo<?> insert(@RequestBody OptionsModel model); ResultWrapper<?> insert(@RequestBody OptionsModel model);
/** /**
* *
* @param model * @param model
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/update") @PostMapping("/update")
ResultVo<?> update(@RequestBody OptionsModel model); ResultWrapper<?> update(@RequestBody OptionsModel model);
/** /**
* *
* @param params Map * @param params Map
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/updateOptions") @PostMapping("/updateOptions")
ResultVo<?> updateOptions(@RequestBody Map<String, String> params); ResultWrapper<?> updateOptions(@RequestBody Map<String, String> params);
/** /**
* *
* @param id ID * @param id ID
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/del") @PostMapping("/del")
ResultVo<?> del(String id); ResultWrapper<?> del(String id);
/** /**
* *
* @param ids ID * @param ids ID
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/delAll") @PostMapping("/delAll")
ResultVo<?> delAll(String ids); ResultWrapper<?> delAll(String ids);
/** /**
* Excel * Excel
*
* Token
*
* 使2
*
* socketJava
* response javascript alert
* *
* @param type
* @param request request * @param request request
*/
@GetMapping("/excel/auth/{type}")
ResultWrapper<String> exportExcelAuth(
@PathVariable("type") String type,
HttpServletRequest request);
/**
* Excel
*
* @param certificate
* @param response response * @param response response
* @return ResultVo
*/ */
@GetMapping("/exportExcel") @GetMapping("/excel/export/{certificate}")
void exportExcel(HttpServletRequest request, HttpServletResponse response); void exportExcel(
@PathVariable("certificate") String certificate,
HttpServletResponse response);
/** /**
* Excel * Excel
* @param request request * @param request request
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/importExcel") @PostMapping("/importExcel")
ResultVo<?> importExcel(MultipartHttpServletRequest request); ResultWrapper<?> importExcel(MultipartHttpServletRequest request);
/**
* Excel
* @param response response
* @return ResultVo
*/
@GetMapping("/importExcel/template")
void importTemplate(HttpServletResponse response);
// ========================== // ==========================
/** /**
* *
* @param optionCode * @param optionCode
* @return ResultVo * @return ResultWrapper
*/ */
@GetMapping("/getByCode") @GetMapping("/getByCode")
ResultVo<OptionsModel> getByCode(String optionCode); ResultWrapper<OptionsModel> getByCode(String optionCode);
/** /**
* *
* @return ResultVo * @return ResultWrapper
*/ */
@GetMapping("/findAllOptions") @GetMapping("/findAllOptions")
ResultVo<Map<String, OptionsModel>> findAllOptions(); ResultWrapper<Map<String, OptionsModel>> findAllOptions();
/** /**
* *
* @return ResultVo * @return ResultWrapper
*/ */
@GetMapping("/findAll") @GetMapping("/findAll")
ResultVo<List<OptionsModel>> findAll(); ResultWrapper<List<OptionsModel>> findAll();
/** /**
* *
* *
* @param type * @param type
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/createCrypto") @PostMapping("/createCrypto")
ResultVo<?> createCrypto(String type); ResultWrapper<?> createCrypto(String type);
} }

@ -15,11 +15,8 @@
*/ */
package org.opsli.api.web.system.org; package org.opsli.api.web.system.org;
import org.opsli.api.base.result.ResultVo; import org.opsli.api.base.result.ResultWrapper;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartHttpServletRequest; import org.springframework.web.multipart.MultipartHttpServletRequest;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
@ -50,90 +47,67 @@ public interface SysOrgRestApi {
* *
* @param parentId ID * @param parentId ID
* @param id ID * @param id ID
* @return ResultVo * @return ResultWrapper
*/ */
@GetMapping("/findTreeLazy") @GetMapping("/findTreeLazy")
ResultVo<?> findTreeLazy(String parentId, String id); ResultWrapper<?> findTreeLazy(String parentId, String id);
/** /**
* *
* @param isGen * @param isGen
* @param id ID * @param id ID
* @return ResultVo * @return ResultWrapper
*/ */
@GetMapping("/findTreeByDef") @GetMapping("/findTreeByDef")
ResultVo<?> findTreeByDef(boolean isGen, String id); ResultWrapper<?> findTreeByDef(boolean isGen, String id);
/** /**
* *
* @return ResultVo * @return ResultWrapper
*/ */
@GetMapping("/findTreeByDefWithUserToLike") @GetMapping("/findTreeByDefWithUserToLike")
ResultVo<?> findTreeByDefWithUserToLike(); ResultWrapper<?> findTreeByDefWithUserToLike();
// ================ // ================
/** /**
* *
* @param model * @param model
* @return ResultVo * @return ResultWrapper
*/ */
@GetMapping("/get") @GetMapping("/get")
ResultVo<SysOrgModel> get(SysOrgModel model); ResultWrapper<SysOrgModel> get(SysOrgModel model);
/** /**
* *
* @param model * @param model
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/insert") @PostMapping("/insert")
ResultVo<?> insert(@RequestBody SysOrgModel model); ResultWrapper<?> insert(@RequestBody SysOrgModel model);
/** /**
* *
* @param model * @param model
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/update") @PostMapping("/update")
ResultVo<?> update(@RequestBody SysOrgModel model); ResultWrapper<?> update(@RequestBody SysOrgModel model);
/** /**
* *
* @param id ID * @param id ID
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/del") @PostMapping("/del")
ResultVo<?> del(String id); ResultWrapper<?> del(String id);
/** /**
* *
* @param ids ID * @param ids ID
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/delAll") @PostMapping("/delAll")
ResultVo<?> delAll(String ids); ResultWrapper<?> delAll(String ids);
/**
* Excel
* @param request request
* @param response response
*/
@GetMapping("/exportExcel")
void exportExcel(HttpServletRequest request, HttpServletResponse response);
/**
* Excel
* @param request request
* @return ResultVo
*/
@PostMapping("/importExcel")
ResultVo<?> importExcel(MultipartHttpServletRequest request);
/**
* Excel
* @param response response
*/
@GetMapping("/importExcel/template")
void importTemplate(HttpServletResponse response);
} }

@ -15,12 +15,9 @@
*/ */
package org.opsli.api.web.system.role; package org.opsli.api.web.system.role;
import org.opsli.api.base.result.ResultVo; import org.opsli.api.base.result.ResultWrapper;
import org.opsli.api.wrapper.system.role.RoleModel; import org.opsli.api.wrapper.system.role.RoleModel;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartHttpServletRequest; import org.springframework.web.multipart.MultipartHttpServletRequest;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
@ -48,20 +45,20 @@ public interface RoleApi {
/** /**
* *
* @param model * @param model
* @return ResultVo * @return ResultWrapper
*/ */
@GetMapping("/get") @GetMapping("/get")
ResultVo<RoleModel> get(RoleModel model); ResultWrapper<RoleModel> get(RoleModel model);
/** /**
* *
* @param pageNo * @param pageNo
* @param pageSize * @param pageSize
* @param request request * @param request request
* @return ResultVo * @return ResultWrapper
*/ */
@GetMapping("/findPage") @GetMapping("/findPage")
ResultVo<?> findPage( ResultWrapper<?> findPage(
@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo, @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize, @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
HttpServletRequest request HttpServletRequest request
@ -70,56 +67,63 @@ public interface RoleApi {
/** /**
* *
* @param model * @param model
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/insert") @PostMapping("/insert")
ResultVo<?> insert(@RequestBody RoleModel model); ResultWrapper<?> insert(@RequestBody RoleModel model);
/** /**
* *
* @param model * @param model
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/update") @PostMapping("/update")
ResultVo<?> update(@RequestBody RoleModel model); ResultWrapper<?> update(@RequestBody RoleModel model);
/** /**
* *
* @param id ID * @param id ID
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/del") @PostMapping("/del")
ResultVo<?> del(String id); ResultWrapper<?> del(String id);
/** /**
* *
* @param ids ID * @param ids ID
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/delAll") @PostMapping("/delAll")
ResultVo<?> delAll(String ids); ResultWrapper<?> delAll(String ids);
/** /**
* Excel * Excel
*
* @param type
* @param request request * @param request request
*/
@GetMapping("/excel/auth/{type}")
ResultWrapper<String> exportExcelAuth(
@PathVariable("type") String type,
HttpServletRequest request);
/**
* Excel
*
* @param certificate
* @param response response * @param response response
*/ */
@GetMapping("/exportExcel") @GetMapping("/excel/export/{certificate}")
void exportExcel(HttpServletRequest request, HttpServletResponse response); void exportExcel(
@PathVariable("certificate") String certificate,
HttpServletResponse response);
/** /**
* Excel * Excel
* @param request request * @param request request
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/importExcel") @PostMapping("/importExcel")
ResultVo<?> importExcel(MultipartHttpServletRequest request); ResultWrapper<?> importExcel(MultipartHttpServletRequest request);
/**
* Excel
* @param response response
*/
@GetMapping("/importExcel/template")
void importTemplate(HttpServletResponse response);
} }

@ -15,7 +15,7 @@
*/ */
package org.opsli.api.web.system.role; package org.opsli.api.web.system.role;
import org.opsli.api.base.result.ResultVo; import org.opsli.api.base.result.ResultWrapper;
import org.opsli.api.wrapper.system.role.RoleMenuRefModel; import org.opsli.api.wrapper.system.role.RoleMenuRefModel;
import org.opsli.api.wrapper.system.role.RoleModel; import org.opsli.api.wrapper.system.role.RoleModel;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
@ -49,18 +49,18 @@ public interface RoleMenuRefApi {
/** /**
* *
* @param model Id * @param model Id
* @return ResultVo * @return ResultWrapper
*/ */
@GetMapping("/getPerms") @GetMapping("/getPerms")
ResultVo<?> getPerms(RoleMenuRefModel model); ResultWrapper<?> getPerms(RoleMenuRefModel model);
/** /**
* *
* @param model roleId Id * @param model roleId Id
* @param model permsIds Id * @param model permsIds Id
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/setPerms") @PostMapping("/setPerms")
ResultVo<?> setPerms(@RequestBody RoleMenuRefModel model); ResultWrapper<?> setPerms(@RequestBody RoleMenuRefModel model);
} }

@ -15,12 +15,9 @@
*/ */
package org.opsli.api.web.system.tenant; package org.opsli.api.web.system.tenant;
import org.opsli.api.base.result.ResultVo; import org.opsli.api.base.result.ResultWrapper;
import org.opsli.api.wrapper.system.tenant.TenantModel; import org.opsli.api.wrapper.system.tenant.TenantModel;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartHttpServletRequest; import org.springframework.web.multipart.MultipartHttpServletRequest;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
@ -48,20 +45,20 @@ public interface TenantApi {
/** /**
* *
* @param model * @param model
* @return ResultVo * @return ResultWrapper
*/ */
@GetMapping("/get") @GetMapping("/get")
ResultVo<TenantModel> get(TenantModel model); ResultWrapper<TenantModel> get(TenantModel model);
/** /**
* *
* @param pageNo * @param pageNo
* @param pageSize * @param pageSize
* @param request request * @param request request
* @return ResultVo * @return ResultWrapper
*/ */
@GetMapping("/findPage") @GetMapping("/findPage")
ResultVo<?> findPage( ResultWrapper<?> findPage(
@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo, @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize, @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
HttpServletRequest request HttpServletRequest request
@ -70,57 +67,65 @@ public interface TenantApi {
/** /**
* *
* @param model * @param model
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/insert") @PostMapping("/insert")
ResultVo<?> insert(@RequestBody TenantModel model); ResultWrapper<?> insert(@RequestBody TenantModel model);
/** /**
* *
* @param model * @param model
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/update") @PostMapping("/update")
ResultVo<?> update(@RequestBody TenantModel model); ResultWrapper<?> update(@RequestBody TenantModel model);
/** /**
* *
* @param id ID * @param id ID
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/del") @PostMapping("/del")
ResultVo<?> del(String id); ResultWrapper<?> del(String id);
/** /**
* *
* @param ids ID * @param ids ID
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/delAll") @PostMapping("/delAll")
ResultVo<?> delAll(String ids); ResultWrapper<?> delAll(String ids);
/** /**
* Excel * Excel
*
* @param type
* @param request request * @param request request
*/
@GetMapping("/excel/auth/{type}")
ResultWrapper<String> exportExcelAuth(
@PathVariable("type") String type,
HttpServletRequest request);
/**
* Excel
*
* @param certificate
* @param response response * @param response response
*/ */
@GetMapping("/exportExcel") @GetMapping("/excel/export/{certificate}")
void exportExcel(HttpServletRequest request, HttpServletResponse response); void exportExcel(
@PathVariable("certificate") String certificate,
HttpServletResponse response);
/** /**
* Excel * Excel
* @param request request * @param request request
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/importExcel") @PostMapping("/importExcel")
ResultVo<?> importExcel(MultipartHttpServletRequest request); ResultWrapper<?> importExcel(MultipartHttpServletRequest request);
/**
* Excel
* @param response response
*/
@GetMapping("/importExcel/template")
void importTemplate(HttpServletResponse response);
/** /**
@ -128,18 +133,18 @@ public interface TenantApi {
* *
* @param tenantId ID * @param tenantId ID
* @param enable * @param enable
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/enableTenant") @PostMapping("/enableTenant")
ResultVo<?> enableTenant(String tenantId, String enable); ResultWrapper<?> enableTenant(String tenantId, String enable);
// ========================= // =========================
/** /**
* *
* @param tenantId * @param tenantId
* @return ResultVo * @return ResultWrapper
*/ */
@GetMapping("/getTenantByUsable") @GetMapping("/getTenantByUsable")
ResultVo<TenantModel> getTenantByUsable(String tenantId); ResultWrapper<TenantModel> getTenantByUsable(String tenantId);
} }

@ -15,14 +15,12 @@
*/ */
package org.opsli.api.web.system.user; package org.opsli.api.web.system.user;
import org.opsli.api.base.result.ResultVo; import org.opsli.api.base.encrypt.EncryptModel;
import org.opsli.api.base.result.ResultWrapper;
import org.opsli.api.wrapper.system.menu.MenuModel; import org.opsli.api.wrapper.system.menu.MenuModel;
import org.opsli.api.wrapper.system.role.RoleModel; import org.opsli.api.wrapper.system.role.RoleModel;
import org.opsli.api.wrapper.system.user.*; import org.opsli.api.wrapper.system.user.*;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartHttpServletRequest; import org.springframework.web.multipart.MultipartHttpServletRequest;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
@ -51,97 +49,123 @@ public interface UserApi {
/** /**
* *
* @param request request * @param request request
* @return ResultVo * @return ResultWrapper
*/ */
@GetMapping("/getInfo") @GetMapping("/getInfo")
ResultVo<UserInfo> getInfo(HttpServletRequest request); ResultWrapper<UserInfo> getInfo(HttpServletRequest request);
/** /**
* *
* *
* @param userId ID * @param userId ID
* @return ResultVo * @return ResultWrapper
*/ */
@GetMapping("/getInfoById") @GetMapping("/getInfoById")
ResultVo<UserInfo> getInfoById(String userId); ResultWrapper<UserInfo> getInfoById(String userId);
/** /**
* *
* @return ResultVo * @return ResultWrapper
*/ */
@GetMapping("/getOrg") @GetMapping("/getOrg")
ResultVo<?> getOrg(); ResultWrapper<?> getOrg();
/** /**
* *
* *
* @param userId ID * @param userId ID
* @return ResultVo * @return ResultWrapper
*/ */
@GetMapping("/getOrgByUserId") @GetMapping("/getOrgByUserId")
ResultVo<?> getOrgByUserId(String userId); ResultWrapper<?> getOrgByUserId(String userId);
/** /**
* userId Id * userId Id
* @param userId Id * @param userId Id
* @return ResultVo * @return ResultWrapper
*/ */
@GetMapping("/getRoleIdsByUserId") @GetMapping("/getRoleIdsByUserId")
ResultVo<List<String>> getRoleIdsByUserId(String userId); ResultWrapper<List<String>> getRoleIdsByUserId(String userId);
/**
* ID
*
* @param encryptModel
* @return ResultVo
*/
@PostMapping("/updatePasswordById")
ResultWrapper<?> updatePasswordById(@RequestBody EncryptModel encryptModel);
/** /**
* *
* @param userPassword * @param encryptModel
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/updatePassword") @PostMapping("/updatePassword")
ResultVo<?> updatePassword(@RequestBody UserPassword userPassword); ResultWrapper<?> updatePassword(@RequestBody EncryptModel encryptModel);
/** /**
* ID *
* * @param encryptModel
* @param userPassword * @return ResultWrapper
* @return ResultVo
*/ */
@PostMapping("/updatePasswordById") @PostMapping("/updateEmail")
ResultVo<?> updatePasswordById(@RequestBody ToUserPassword userPassword); ResultWrapper<?> updateEmail(@RequestBody EncryptModel encryptModel);
/**
*
* @param encryptModel
* @return ResultWrapper
*/
@PostMapping("/updateMobile")
ResultWrapper<?> updateMobile(@RequestBody EncryptModel encryptModel);
/** /**
* ID * ID
* *
* @param userId ID * @param encryptModel ID
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/resetPasswordById") @PostMapping("/resetPasswordById")
ResultVo<?> resetPasswordById(String userId); ResultWrapper<?> resetPasswordById(@RequestBody EncryptModel encryptModel);
/** /**
* *
* *
* @param userId ID * @param encryptModel EnableUserModel
* @param enable * @return ResultWrapper
* @return ResultVo
*/ */
@PostMapping("/enableAccount") @PostMapping("/enableAccount")
ResultVo<?> enableAccount(String userId, String enable); ResultWrapper<?> enableAccount(@RequestBody EncryptModel encryptModel);
/**
*
*
* @param encryptModel
* @return ResultWrapper
*/
@PostMapping("/updatePasswordByForget")
ResultWrapper<?> updatePasswordByForget(@RequestBody EncryptModel encryptModel);
/** /**
* *
* @param userAvatarModel * @param userAvatarModel
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/updateAvatar") @PostMapping("/updateAvatar")
ResultVo<?> updateAvatar(@RequestBody UserAvatarModel userAvatarModel); ResultWrapper<?> updateAvatar(@RequestBody UserAvatarModel userAvatarModel);
/** /**
* *
* @param model * @param model
* @return ResultVo * @return ResultWrapper
*/ */
@GetMapping("/get") @GetMapping("/get")
ResultVo<UserModel> get(UserModel model); ResultWrapper<UserModel> get(UserModel model);
/** /**
* *
@ -149,10 +173,10 @@ public interface UserApi {
* @param pageSize * @param pageSize
* @param orgIdGroup ID * @param orgIdGroup ID
* @param request request * @param request request
* @return ResultVo * @return ResultWrapper
*/ */
@GetMapping("/findPage") @GetMapping("/findPage")
ResultVo<?> findPage( ResultWrapper<?> findPage(
@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo, @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize, @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
@RequestParam(name = "orgIdGroup") String orgIdGroup, @RequestParam(name = "orgIdGroup") String orgIdGroup,
@ -164,10 +188,10 @@ public interface UserApi {
* @param pageNo * @param pageNo
* @param pageSize * @param pageSize
* @param request request * @param request request
* @return ResultVo * @return ResultWrapper
*/ */
@GetMapping("/findPageByTenant") @GetMapping("/findPageByTenant")
ResultVo<?> findPageByTenant( ResultWrapper<?> findPageByTenant(
@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo, @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize, @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
HttpServletRequest request HttpServletRequest request
@ -178,91 +202,114 @@ public interface UserApi {
/** /**
* *
* @param model * @param model
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/insert") @PostMapping("/insert")
ResultVo<?> insert(@RequestBody UserModel model); ResultWrapper<?> insert(@RequestBody UserModel model);
/** /**
* *
* @param model * @param model
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/update") @PostMapping("/update")
ResultVo<?> update(@RequestBody UserModel model); ResultWrapper<?> update(@RequestBody UserModel model);
/** /**
* *
* @param model * @param model
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/updateSelf") @PostMapping("/updateSelf")
ResultVo<?> updateSelf(@RequestBody UserModel model); ResultWrapper<?> updateSelf(@RequestBody UserModel model);
/** /**
* *
* @param id ID * @param encryptModel id ID
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/del") @PostMapping("/del")
ResultVo<?> del(String id); ResultWrapper<?> del(@RequestBody EncryptModel encryptModel);
/** /**
* *
* @param ids ID * @param encryptModel ids ID
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/delAll") @PostMapping("/delAll")
ResultVo<?> delAll(String ids); ResultWrapper<?> delAll(@RequestBody EncryptModel encryptModel);
/** /**
* Excel * Excel
*
* @param type
* @param request request * @param request request
*/
@GetMapping("/excel/auth/{type}")
ResultWrapper<String> exportExcelAuth(
@PathVariable("type") String type,
HttpServletRequest request);
/**
* Excel
*
* @param certificate
* @param response response * @param response response
*/ */
@GetMapping("/exportExcel") @GetMapping("/excel/export/{certificate}")
void exportExcel(HttpServletRequest request, HttpServletResponse response); void exportExcel(
@PathVariable("certificate") String certificate,
HttpServletResponse response);
/** /**
* Excel * Excel
* @param request request * @param request request
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/importExcel") @PostMapping("/importExcel")
ResultVo<?> importExcel(MultipartHttpServletRequest request); ResultWrapper<?> importExcel(MultipartHttpServletRequest request);
/**
* Excel
* @param response response
*/
@GetMapping("/importExcel/template")
void importTemplate(HttpServletResponse response);
/** /**
* *
* @param tenantId ID * @param tenantId ID
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/switchTenant") @PostMapping("/switchTenant")
ResultVo<?> switchTenant(String tenantId); ResultWrapper<?> switchTenant(String tenantId);
/** /**
* *
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/switchOneself") @PostMapping("/switchOneself")
ResultVo<?> switchOneself(); ResultWrapper<?> switchOneself();
/** /**
* username * username
* @param username * @param username
* @return ResultVo * @return ResultWrapper
*/ */
//@GetMapping("/getUserByUsername") //@GetMapping("/getUserByUsername")
ResultVo<UserModel> getUserByUsername(String username); ResultWrapper<UserModel> getUserByUsername(String username);
/**
*
* @param mobile
* @return ResultWrapper
*/
ResultWrapper<UserModel> getUserByMobile(String mobile);
/**
*
* @param email
* @return ResultWrapper
*/
ResultWrapper<UserModel> getUserByEmail(String email);

@ -15,7 +15,7 @@
*/ */
package org.opsli.api.web.system.user; package org.opsli.api.web.system.user;
import org.opsli.api.base.result.ResultVo; import org.opsli.api.base.result.ResultWrapper;
import org.opsli.api.wrapper.system.org.SysOrgModel; import org.opsli.api.wrapper.system.org.SysOrgModel;
import org.opsli.api.wrapper.system.user.UserOrgRefModel; import org.opsli.api.wrapper.system.user.UserOrgRefModel;
import org.opsli.api.wrapper.system.user.UserOrgRefWebModel; import org.opsli.api.wrapper.system.user.UserOrgRefWebModel;
@ -47,25 +47,25 @@ public interface UserOrgRefApi {
/** /**
* *
* @param model * @param model
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/setOrg") @PostMapping("/setOrg")
ResultVo<?> setOrg(@RequestBody UserOrgRefWebModel model); ResultWrapper<?> setOrg(@RequestBody UserOrgRefWebModel model);
/** /**
* ID * ID
* @param userId ID * @param userId ID
* @return List * @return List
*/ */
ResultVo<List<UserOrgRefModel>> findListByUserId(String userId); ResultWrapper<List<UserOrgRefModel>> findListByUserId(String userId);
/** /**
* userId * userId
* @param userId Id * @param userId Id
* @return ResultVo * @return ResultWrapper
*/ */
//@GetMapping("/getRolesByUserId") //@GetMapping("/getRolesByUserId")
ResultVo<UserOrgRefModel> getDefOrgByUserId(String userId); ResultWrapper<UserOrgRefModel> getDefOrgByUserId(String userId);
} }

@ -15,7 +15,7 @@
*/ */
package org.opsli.api.web.system.user; package org.opsli.api.web.system.user;
import org.opsli.api.base.result.ResultVo; import org.opsli.api.base.result.ResultWrapper;
import org.opsli.api.wrapper.system.menu.MenuModel; import org.opsli.api.wrapper.system.menu.MenuModel;
import org.opsli.api.wrapper.system.role.RoleMenuRefModel; import org.opsli.api.wrapper.system.role.RoleMenuRefModel;
import org.opsli.api.wrapper.system.role.RoleModel; import org.opsli.api.wrapper.system.role.RoleModel;
@ -48,50 +48,50 @@ public interface UserRoleRefApi {
/** /**
* *
* @param userId ID * @param userId ID
* @return ResultVo * @return ResultWrapper
*/ */
@GetMapping("/getRoles") @GetMapping("/getRoles")
ResultVo<?> getRoles(String userId); ResultWrapper<?> getRoles(String userId);
/** /**
* *
* @param model * @param model
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/setRoles") @PostMapping("/setRoles")
ResultVo<?> setRoles(@RequestBody UserRoleRefModel model); ResultWrapper<?> setRoles(@RequestBody UserRoleRefModel model);
/** /**
* userId * userId
* @param userId Id * @param userId Id
* @return ResultVo * @return ResultWrapper
*/ */
//@GetMapping("/getRolesByUserId") //@GetMapping("/getRolesByUserId")
ResultVo<List<String>> getRolesByUserId(String userId); ResultWrapper<List<String>> getRolesByUserId(String userId);
/** /**
* userId * userId
* @param userId Id * @param userId Id
* @return ResultVo * @return ResultWrapper
*/ */
//@GetMapping("/getRolesByUserId") //@GetMapping("/getRolesByUserId")
ResultVo<RoleModel> getDefRoleByUserId(String userId); ResultWrapper<RoleModel> getDefRoleByUserId(String userId);
/** /**
* userId * userId
* @param userId Id * @param userId Id
* @return ResultVo * @return ResultWrapper
*/ */
//@GetMapping("/queryAllPerms") //@GetMapping("/queryAllPerms")
ResultVo<List<String>> getAllPerms(String userId); ResultWrapper<List<String>> getAllPerms(String userId);
/** /**
* userId * userId
* @param userId Id * @param userId Id
* @return ResultVo * @return ResultWrapper
*/ */
//@GetMapping("/queryAllPerms") //@GetMapping("/queryAllPerms")
ResultVo<List<MenuModel>> getMenuListByUserId(String userId); ResultWrapper<List<MenuModel>> getMenuListByUserId(String userId);
} }

@ -1,8 +1,9 @@
package org.opsli.api.web.test; package org.opsli.api.web.test;
import org.opsli.api.base.result.ResultVo; import org.opsli.api.base.result.ResultWrapper;
import org.opsli.api.wrapper.test.TestModel; import org.opsli.api.wrapper.test.TestModel;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartHttpServletRequest; import org.springframework.web.multipart.MultipartHttpServletRequest;
@ -28,93 +29,93 @@ public interface TestApi {
/** /**
* *
* @return ResultVo * @return ResultWrapper
*/ */
@GetMapping("/sendMail") @GetMapping("/sendMail")
ResultVo<?> sendMail(); ResultWrapper<?> sendMail();
/** /**
* Redis * Redis
* @return ResultVo * @return ResultWrapper
*/ */
@GetMapping("/sendMsg") @GetMapping("/sendMsg")
ResultVo<?> sendMsg(); ResultWrapper<?> sendMsg();
/** /**
* Redis * Redis
* @return ResultVo * @return ResultWrapper
*/ */
@GetMapping("/redisTest") @GetMapping("/redisTest")
ResultVo<?> redisTest(); ResultWrapper<?> redisTest();
/** /**
* Redis * Redis
* @return ResultVo * @return ResultWrapper
*/ */
@GetMapping("/testLock") @GetMapping("/testLock")
ResultVo<?> testLock(); ResultWrapper<?> testLock();
/** /**
* *
* @param entity entity * @param entity entity
* @return ResultVo * @return ResultWrapper
*/ */
@GetMapping("/insert") @GetMapping("/insert")
ResultVo<TestModel> insert(TestModel entity); ResultWrapper<TestModel> insert(TestModel entity);
/** /**
* *
* @param entity entity * @param entity entity
* @return ResultVo * @return ResultWrapper
*/ */
@GetMapping("/update") @GetMapping("/update")
ResultVo<TestModel> update(TestModel entity); ResultWrapper<TestModel> update(TestModel entity);
/** /**
* *
* @param entity entity * @param entity entity
* @return ResultVo * @return ResultWrapper
*/ */
@GetMapping("/get") @GetMapping("/get")
ResultVo<TestModel> get(TestModel entity); ResultWrapper<TestModel> get(TestModel entity);
/** /**
* *
* @param id id * @param id id
* @return ResultVo * @return ResultWrapper
*/ */
@GetMapping("/del") @GetMapping("/del")
ResultVo<?> del(String id); ResultWrapper<?> del(String id);
/** /**
* *
* @return ResultVo * @return ResultWrapper
*/ */
@GetMapping("/delAll") @GetMapping("/delAll")
ResultVo<?> delAll(); ResultWrapper<?> delAll();
/** /**
* *
* @param request request * @param request request
* @return ResultVo * @return ResultWrapper
*/ */
@GetMapping("/findList") @GetMapping("/findList")
ResultVo<List<TestModel>> findList(HttpServletRequest request); ResultWrapper<List<TestModel>> findList(HttpServletRequest request);
/** /**
* *
* @return ResultVo * @return ResultWrapper
*/ */
@GetMapping("/findAllList") @GetMapping("/findAllList")
ResultVo<List<TestModel>> findAllList(); ResultWrapper<List<TestModel>> findAllList();
/** /**
@ -123,10 +124,10 @@ public interface TestApi {
* @param pageNo * @param pageNo
* @param pageSize * @param pageSize
* @param request request * @param request request
* @return ResultVo * @return ResultWrapper
*/ */
@GetMapping("/findPage") @GetMapping("/findPage")
ResultVo<?> findPage( ResultWrapper<?> findPage(
@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo, @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize, @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
HttpServletRequest request HttpServletRequest request
@ -134,29 +135,36 @@ public interface TestApi {
/** /**
* Excel * Excel
* *
* @param type
* @param request request * @param request request
*/
@GetMapping("/excel/auth/{type}")
ResultWrapper<String> exportExcelAuth(
@PathVariable("type") String type,
HttpServletRequest request);
/**
* Excel
*
* @param certificate
* @param response response * @param response response
*/ */
@GetMapping("/exportExcel") @GetMapping("/excel/export/{certificate}")
void exportExcel(HttpServletRequest request, HttpServletResponse response); void exportExcel(
@PathVariable("certificate") String certificate,
HttpServletResponse response);
/** /**
* Excel * Excel
* *
* @param request request * @param request request
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/importExcel") @PostMapping("/importExcel")
ResultVo<?> importExcel(MultipartHttpServletRequest request); ResultWrapper<?> importExcel(MultipartHttpServletRequest request);
/**
* Excel
*
* @param response response
*/
@GetMapping("/importExcel/template")
void importTemplate(HttpServletResponse response);
} }

@ -15,12 +15,9 @@
*/ */
package org.opsli.api.web.test; package org.opsli.api.web.test;
import org.opsli.api.base.result.ResultVo; import org.opsli.api.base.result.ResultWrapper;
import org.opsli.api.wrapper.test.TestModel; import org.opsli.api.wrapper.test.TestModel;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartHttpServletRequest; import org.springframework.web.multipart.MultipartHttpServletRequest;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
@ -48,20 +45,20 @@ public interface TestRestApi {
/** /**
* *
* @param model * @param model
* @return ResultVo * @return ResultWrapper
*/ */
@GetMapping("/get") @GetMapping("/get")
ResultVo<TestModel> get(TestModel model); ResultWrapper<TestModel> get(TestModel model);
/** /**
* *
* @param pageNo * @param pageNo
* @param pageSize * @param pageSize
* @param request request * @param request request
* @return ResultVo * @return ResultWrapper
*/ */
@GetMapping("/findPage") @GetMapping("/findPage")
ResultVo<?> findPage( ResultWrapper<?> findPage(
@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo, @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize, @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
HttpServletRequest request HttpServletRequest request
@ -70,56 +67,65 @@ public interface TestRestApi {
/** /**
* *
* @param model * @param model
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/insert") @PostMapping("/insert")
ResultVo<?> insert(@RequestBody TestModel model); ResultWrapper<?> insert(@RequestBody TestModel model);
/** /**
* *
* @param model * @param model
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/update") @PostMapping("/update")
ResultVo<?> update(@RequestBody TestModel model); ResultWrapper<?> update(@RequestBody TestModel model);
/** /**
* *
* @param id ID * @param id ID
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/del") @PostMapping("/del")
ResultVo<?> del(String id); ResultWrapper<?> del(String id);
/** /**
* *
* @param ids ID * @param ids ID
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/delAll") @PostMapping("/delAll")
ResultVo<?> delAll(String ids); ResultWrapper<?> delAll(String ids);
/** /**
* Excel * Excel
*
* @param type
* @param request request * @param request request
*/
@GetMapping("/excel/auth/{type}")
ResultWrapper<String> exportExcelAuth(
@PathVariable("type") String type,
HttpServletRequest request);
/**
* Excel
*
* @param certificate
* @param response response * @param response response
*/ */
@GetMapping("/exportExcel") @GetMapping("/excel/export/{certificate}")
void exportExcel(HttpServletRequest request, HttpServletResponse response); void exportExcel(
@PathVariable("certificate") String certificate,
HttpServletResponse response);
/** /**
* Excel * Excel
* @param request request * @param request request
* @return ResultVo * @return ResultWrapper
*/ */
@PostMapping("/importExcel") @PostMapping("/importExcel")
ResultVo<?> importExcel(MultipartHttpServletRequest request); ResultWrapper<?> importExcel(MultipartHttpServletRequest request);
/**
* Excel
* @param response response
*/
@GetMapping("/importExcel/template")
void importTemplate(HttpServletResponse response);
} }

@ -15,6 +15,7 @@
*/ */
package org.opsli.api.wrapper.gentest.carinfo; package org.opsli.api.wrapper.gentest.carinfo;
import java.math.BigDecimal;
import java.util.Date; import java.util.Date;
import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.annotation.ExcelProperty;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
@ -23,16 +24,17 @@ import lombok.EqualsAndHashCode;
import org.opsli.api.base.warpper.ApiWrapper; import org.opsli.api.base.warpper.ApiWrapper;
import org.opsli.common.annotation.validator.Validator; import org.opsli.common.annotation.validator.Validator;
import org.opsli.common.annotation.validator.ValidatorLenMax; import org.opsli.common.annotation.validator.ValidatorLenMax;
import org.opsli.common.annotation.validator.ValidatorLenMin;
import org.opsli.common.enums.ValidatorType; import org.opsli.common.enums.ValidatorType;
import org.opsli.plugins.excel.annotation.ExcelInfo; import org.opsli.plugins.excel.annotation.ExcelInfo;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
import org.springframework.format.annotation.DateTimeFormat; import org.springframework.format.annotation.DateTimeFormat;
/** /**
* * Model
* *
* @author Parker * @author Parker
* @date 2020-12-20 20:12:57 * @date 2022-08-06 23:53:30
*/ */
@Data @Data
@EqualsAndHashCode(callSuper = false) @EqualsAndHashCode(callSuper = false)
@ -42,7 +44,10 @@ public class TestCarModel extends ApiWrapper {
@ApiModelProperty(value = "汽车名称") @ApiModelProperty(value = "汽车名称")
@ExcelProperty(value = "汽车名称", order = 1) @ExcelProperty(value = "汽车名称", order = 1)
@ExcelInfo @ExcelInfo
@Validator({ValidatorType.IS_NOT_NULL, ValidatorType.IS_GENERAL_WITH_CHINESE}) @Validator({
ValidatorType.IS_GENERAL_WITH_CHINESE,
ValidatorType.IS_NOT_NULL
})
@ValidatorLenMax(20) @ValidatorLenMax(20)
private String carName; private String carName;
@ -50,7 +55,10 @@ public class TestCarModel extends ApiWrapper {
@ApiModelProperty(value = "汽车类型") @ApiModelProperty(value = "汽车类型")
@ExcelProperty(value = "汽车类型", order = 2) @ExcelProperty(value = "汽车类型", order = 2)
@ExcelInfo @ExcelInfo
@Validator({ValidatorType.IS_NOT_NULL, ValidatorType.IS_GENERAL_WITH_CHINESE}) @Validator({
ValidatorType.IS_GENERAL_WITH_CHINESE,
ValidatorType.IS_NOT_NULL
})
@ValidatorLenMax(20) @ValidatorLenMax(20)
private String carType; private String carType;
@ -58,7 +66,9 @@ public class TestCarModel extends ApiWrapper {
@ApiModelProperty(value = "汽车品牌") @ApiModelProperty(value = "汽车品牌")
@ExcelProperty(value = "汽车品牌", order = 3) @ExcelProperty(value = "汽车品牌", order = 3)
@ExcelInfo @ExcelInfo
@Validator({ValidatorType.IS_GENERAL_WITH_CHINESE}) @Validator({
ValidatorType.IS_GENERAL_WITH_CHINESE
})
@ValidatorLenMax(50) @ValidatorLenMax(50)
private String carBrand; private String carBrand;
@ -66,6 +76,9 @@ public class TestCarModel extends ApiWrapper {
@ApiModelProperty(value = "生产日期") @ApiModelProperty(value = "生产日期")
@ExcelProperty(value = "生产日期", order = 4) @ExcelProperty(value = "生产日期", order = 4)
@ExcelInfo @ExcelInfo
@Validator({
ValidatorType.IS_NOT_NULL
})
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd") @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd")
@DateTimeFormat(pattern = "yyyy-MM-dd") @DateTimeFormat(pattern = "yyyy-MM-dd")
private Date produceData; private Date produceData;
@ -74,6 +87,9 @@ public class TestCarModel extends ApiWrapper {
@ApiModelProperty(value = "是否启用") @ApiModelProperty(value = "是否启用")
@ExcelProperty(value = "是否启用", order = 5) @ExcelProperty(value = "是否启用", order = 5)
@ExcelInfo( dictType = "no_yes" ) @ExcelInfo( dictType = "no_yes" )
@Validator({
ValidatorType.IS_NOT_NULL
})
@ValidatorLenMax(1) @ValidatorLenMax(1)
private String izUsable; private String izUsable;

@ -71,4 +71,10 @@ public class LoginLogsModel extends ApiWrapper {
@ApiModelProperty(value = "用户代理") @ApiModelProperty(value = "用户代理")
private String userAgent; private String userAgent;
/**
*
*/
@ApiModelProperty(value = "登陆来源")
private String loginFrom;
} }

@ -0,0 +1,132 @@
/**
* Copyright 2020 OPSLI https://www.opsli.com
* <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.api.wrapper.system.logs;
import java.math.BigDecimal;
import java.util.Date;
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.validator.Validator;
import org.opsli.common.annotation.validator.ValidatorLenMax;
import org.opsli.common.annotation.validator.ValidatorLenMin;
import org.opsli.common.enums.ValidatorType;
import org.opsli.plugins.excel.annotation.ExcelInfo;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.springframework.format.annotation.DateTimeFormat;
/**
* Model
*
* @author Parker
* @date 2022-07-26 19:21:57
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class OperationLogModel extends ApiWrapper {
/** 多租户字段 */
private String tenantId;
/** 日志等级 */
@ApiModelProperty(value = "日志等级")
@ExcelProperty(value = "日志等级", order = 1)
@ExcelInfo( dictType = "log_level" )
@ValidatorLenMax(8)
private String level;
/** 被操作的系统模块 */
@ApiModelProperty(value = "被操作的系统模块")
@ExcelProperty(value = "被操作的系统模块", order = 2)
@ExcelInfo( dictType = "log_model_type" )
@ValidatorLenMax(20)
private String moduleId;
/** 方法名 */
@ApiModelProperty(value = "方法名")
@ExcelProperty(value = "方法名", order = 3)
@ExcelInfo
@ValidatorLenMax(100)
private String method;
/** 参数 */
@ApiModelProperty(value = "参数")
@ExcelProperty(value = "参数", order = 4)
@ExcelInfo
@ValidatorLenMax(20000)
private String args;
/** 操作人id */
@ApiModelProperty(value = "操作人id")
@ExcelProperty(value = "操作人id", order = 5)
@ExcelInfo
@ValidatorLenMax(19)
private String userId;
/** 操作账号 */
@ApiModelProperty(value = "操作账号")
@ExcelProperty(value = "操作账号", order = 6)
@ExcelInfo
@ValidatorLenMax(32)
private String username;
/** 操作人真实名称 */
@ApiModelProperty(value = "操作人真实名称")
@ExcelProperty(value = "操作人真实名称", order = 7)
@ExcelInfo
@ValidatorLenMax(50)
private String realName;
/** 日志描述 */
@ApiModelProperty(value = "日志描述")
@ExcelProperty(value = "日志描述", order = 8)
@ExcelInfo
@ValidatorLenMax(255)
private String description;
/** 操作类型 */
@ApiModelProperty(value = "操作类型")
@ExcelProperty(value = "操作类型", order = 9)
@ExcelInfo( dictType = "log_operation_type" )
@ValidatorLenMax(20)
private String operationType;
/** 方法运行时间 */
@ApiModelProperty(value = "方法运行时间")
@ExcelProperty(value = "方法运行时间", order = 10)
@ExcelInfo
@ValidatorLenMax(19)
private String runTime;
/** 方法返回值 */
@ApiModelProperty(value = "方法返回值")
@ExcelProperty(value = "方法返回值", order = 11)
@ExcelInfo
@ValidatorLenMax(20000)
private String returnValue;
/** 日志请求类型 */
@ApiModelProperty(value = "日志请求类型")
@ExcelProperty(value = "日志请求类型", order = 12)
@ExcelInfo( dictType = "log_type" )
@ValidatorLenMax(8)
private String logType;
}

@ -0,0 +1,42 @@
/**
* Copyright 2020 OPSLI https://www.opsli.com
* <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.api.wrapper.system.user;
import lombok.Data;
import org.opsli.common.annotation.validator.Validator;
import org.opsli.common.annotation.validator.ValidatorLenMax;
import org.opsli.common.enums.ValidatorType;
/**
*
*
* @author Parker
* @date 2022-07-16 8:14 PM
**/
@Data
public class EnableUserModel {
/** 主键 */
@Validator({ValidatorType.IS_NOT_NULL})
@ValidatorLenMax(50)
private String userId;
/** 是否启用 */
@Validator({ValidatorType.IS_NOT_NULL})
@ValidatorLenMax(10)
private String enabled;
}

@ -51,12 +51,6 @@ public class ToUserPassword implements Serializable {
@ValidatorLenMax(50) @ValidatorLenMax(50)
private String newPassword; private String newPassword;
/** 盐值,密码秘钥 前端不可改*/
@ApiModelProperty(value = "盐值,密码秘钥 前端不可改")
@ExcelIgnore
@ValidatorLenMax(50)
private String salt;
/** 登录密码强度 前端不可改 */ /** 登录密码强度 前端不可改 */
@ApiModelProperty(value = "登录密码强度 前端不可改") @ApiModelProperty(value = "登录密码强度 前端不可改")
@ExcelIgnore @ExcelIgnore

@ -0,0 +1,46 @@
/**
* Copyright 2020 OPSLI https://www.opsli.com
* <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.api.wrapper.system.user;
import lombok.Data;
import org.opsli.common.annotation.validator.Validator;
import org.opsli.common.annotation.validator.ValidatorLenMax;
import org.opsli.common.enums.ValidatorType;
/**
*
*
* @author Parker
* @date 2022-07-16 8:14 PM
**/
@Data
public class UpdateUserEmailModel {
/** 主键 */
@Validator({ValidatorType.IS_NOT_NULL, ValidatorType.IS_EMAIL})
@ValidatorLenMax(50)
private String email;
/** 验证码 */
@Validator({ValidatorType.IS_NOT_NULL})
@ValidatorLenMax(20)
private String verificationCode;
/** 凭证 */
@Validator({ValidatorType.IS_NOT_NULL})
private String certificate;
}

@ -0,0 +1,46 @@
/**
* Copyright 2020 OPSLI https://www.opsli.com
* <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.api.wrapper.system.user;
import lombok.Data;
import org.opsli.common.annotation.validator.Validator;
import org.opsli.common.annotation.validator.ValidatorLenMax;
import org.opsli.common.enums.ValidatorType;
/**
*
*
* @author Parker
* @date 2022-07-16 8:14 PM
**/
@Data
public class UpdateUserMobileModel {
/** 主键 */
@Validator({ValidatorType.IS_NOT_NULL, ValidatorType.IS_MOBILE})
@ValidatorLenMax(50)
private String mobile;
/** 验证码 */
@Validator({ValidatorType.IS_NOT_NULL})
@ValidatorLenMax(20)
private String verificationCode;
/** 凭证 */
@Validator({ValidatorType.IS_NOT_NULL})
private String certificate;
}

@ -0,0 +1,53 @@
/**
* Copyright 2020 OPSLI https://www.opsli.com
* <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.api.wrapper.system.user;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.opsli.common.annotation.validator.Validator;
import org.opsli.common.annotation.validator.ValidatorLenMax;
import org.opsli.common.annotation.validator.ValidatorLenMin;
import org.opsli.common.enums.ValidatorType;
import java.io.Serializable;
/**
*
*
* @author Parker
* @date 2020-09-16 17:33
*/
@Data
@EqualsAndHashCode(callSuper = false)
@ExcelIgnoreUnannotated
public class UpdateUserPasswordByForgetModel implements Serializable {
private static final long serialVersionUID = 1L;
/** 新密码 */
@ApiModelProperty(value = "新密码")
@Validator({ValidatorType.IS_NOT_NULL, ValidatorType.IS_SECURITY_PASSWORD})
@ValidatorLenMin(6)
@ValidatorLenMax(50)
private String newPassword;
/** 凭证 */
@Validator({ValidatorType.IS_NOT_NULL})
private String certificate;
}

@ -56,12 +56,12 @@ public class UserInfo extends ApiWrapper {
/** 手机 */ /** 手机 */
@ApiModelProperty(value = "手机") @ApiModelProperty(value = "手机")
@Validator({ValidatorType.IS_MOBILE}) @Validator({ValidatorType.IS_NOT_NULL, ValidatorType.IS_MOBILE})
private String mobile; private String mobile;
/** 邮箱 */ /** 邮箱 */
@ApiModelProperty(value = "邮箱") @ApiModelProperty(value = "邮箱")
@Validator({ValidatorType.IS_EMAIL}) @Validator({ValidatorType.IS_NOT_NULL, ValidatorType.IS_EMAIL})
private String email; private String email;
/** 工号 */ /** 工号 */

@ -60,12 +60,6 @@ public class UserModel extends ApiWrapper {
@ValidatorLenMax(1) @ValidatorLenMax(1)
private String passwordLevel; private String passwordLevel;
/** 盐值,密码秘钥 */
@ApiModelProperty(value = "盐值,密码秘钥")
@ExcelIgnore
@ValidatorLenMax(50)
private String secretKey;
/** 是否启用 */ /** 是否启用 */
@ApiModelProperty(value = "是否启用") @ApiModelProperty(value = "是否启用")
@ExcelIgnore @ExcelIgnore
@ -84,14 +78,14 @@ public class UserModel extends ApiWrapper {
@ApiModelProperty(value = "手机") @ApiModelProperty(value = "手机")
@ExcelProperty(value = "手机", order = 2) @ExcelProperty(value = "手机", order = 2)
@ExcelInfo @ExcelInfo
@Validator({ValidatorType.IS_MOBILE}) @Validator({ValidatorType.IS_NOT_NULL, ValidatorType.IS_MOBILE})
private String mobile; private String mobile;
/** 邮箱 */ /** 邮箱 */
@ApiModelProperty(value = "邮箱") @ApiModelProperty(value = "邮箱")
@ExcelProperty(value = "邮箱", order = 3) @ExcelProperty(value = "邮箱", order = 3)
@ExcelInfo @ExcelInfo
@Validator({ValidatorType.IS_EMAIL}) @Validator({ValidatorType.IS_NOT_NULL, ValidatorType.IS_EMAIL})
@ValidatorLenMax(100) @ValidatorLenMax(100)
private String email; private String email;

@ -58,12 +58,6 @@ public class UserPassword implements Serializable {
@ValidatorLenMax(50) @ValidatorLenMax(50)
private String newPassword; private String newPassword;
/** 盐值,密码秘钥 前端不可改*/
@ApiModelProperty(value = "盐值,密码秘钥 前端不可改")
@ExcelIgnore
@ValidatorLenMax(50)
private String salt;
/** 登录密码强度 前端不可改 */ /** 登录密码强度 前端不可改 */
@ApiModelProperty(value = "登录密码强度 前端不可改") @ApiModelProperty(value = "登录密码强度 前端不可改")
@ExcelIgnore @ExcelIgnore

@ -64,12 +64,6 @@ public class UserWebModel extends ApiWrapper {
@ValidatorLenMax(1) @ValidatorLenMax(1)
private String passwordLevel; private String passwordLevel;
/** 盐值,密码秘钥 */
@ApiModelProperty(value = "盐值,密码秘钥")
@ExcelIgnore
@ValidatorLenMax(50)
private String secretKey;
/** 启用状态 */ /** 启用状态 */
@ApiModelProperty(value = "启用状态") @ApiModelProperty(value = "启用状态")
@ExcelIgnore @ExcelIgnore

@ -70,13 +70,20 @@ public class ResultVoMap extends HashMap<String,Object> implements Serializable
// ------------------------------------------- // -------------------------------------------
@JsonIgnore//返回对象时忽略此属性 /**
*
*/
@JsonIgnore
public static ResultVoMap success(String msg) { public static ResultVoMap success(String msg) {
ResultVoMap j = new ResultVoMap(); ResultVoMap j = new ResultVoMap();
j.setMsg(msg); j.setMsg(msg);
return j; return j;
} }
@JsonIgnore//返回对象时忽略此属性
/**
*
*/
@JsonIgnore//
public static ResultVoMap error(String msg) { public static ResultVoMap error(String msg) {
ResultVoMap j = new ResultVoMap(); ResultVoMap j = new ResultVoMap();
j.setSuccess(false); j.setSuccess(false);
@ -84,14 +91,20 @@ public class ResultVoMap extends HashMap<String,Object> implements Serializable
return j; return j;
} }
@JsonIgnore//返回对象时忽略此属性 /**
*
*/
@JsonIgnore
public static ResultVoMap success(Map<String, Object> map) { public static ResultVoMap success(Map<String, Object> map) {
ResultVoMap restResponse = new ResultVoMap(); ResultVoMap restResponse = new ResultVoMap();
restResponse.putAll(map); restResponse.putAll(map);
return restResponse; return restResponse;
} }
@JsonIgnore//返回对象时忽略此属性 /**
*
*/
@JsonIgnore
public static ResultVoMap success() { public static ResultVoMap success() {
return new ResultVoMap(); return new ResultVoMap();
} }

@ -3,7 +3,7 @@ package org.opsli.common.constants;
/** /**
* Redis * Redis
* {} * {}
* @author * @author Parker
* @date 2021/12/10 19:52 * @date 2021/12/10 19:52
*/ */
public final class RedisConstants { public final class RedisConstants {
@ -47,9 +47,12 @@ public final class RedisConstants {
/** 用户ID 和 菜单 */ /** 用户ID 和 菜单 */
public static final String PREFIX_USER_ID_MENUS = "kv#{}:user_id:menus:"; public static final String PREFIX_USER_ID_MENUS = "kv#{}:user_id:menus:";
/** 用户名 */ /** 用户名 + 用户ID */
public static final String PREFIX_USERNAME = "kv#{}:username:"; public static final String PREFIX_USER_USERNAME = "kv#{}:user:username_id:";
/** 手机号 + 用户ID */
public static final String PREFIX_USER_MOBILE = "kv#{}:user:mobile_id:";
/** 邮箱 + 用户ID */
public static final String PREFIX_USER_EMAIL = "kv#{}:user:email_id:";
/** 票据 */ /** 票据 */
@ -61,8 +64,21 @@ public final class RedisConstants {
/** 账号失败锁定KEY */ /** 账号失败锁定KEY */
public static final String PREFIX_ACCOUNT_SLIP_LOCK = "kv#{}:account:slip:lock:"; public static final String PREFIX_ACCOUNT_SLIP_LOCK = "kv#{}:account:slip:lock:";
/** 临时邮箱验证码 */
public static final String PREFIX_TMP_EMAIL_CODE_NAME = "kv#{}:verification:email:code:";
/** 临时手机验证码 */
public static final String PREFIX_TMP_MOBILE_CODE_NAME = "kv#{}:verification:mobile:code:";
/** 验证码凭证 用于验证码二次校验(唯一流水号 increment) */
public static final String PREFIX_TMP_VERIFICATION_CERTIFICATE_NUM_NAME = "kv#{}:verification:certificate-num";
/** 验证码凭证 用于验证码二次校验 */
public static final String PREFIX_TMP_VERIFICATION_CERTIFICATE_NAME = "kv#{}:verification:certificate:";
/** Excel 导出(唯一流水号 increment) */
public static final String PREFIX_TMP_EXCEL_EXPORT_NUM_NAME = "kv#{}:excel-export-num";
/** Excel 导出 凭证 */
public static final String PREFIX_TMP_EXCEL_EXPORT_NAME = "kv#{}:excel-export:";
private RedisConstants(){} private RedisConstants(){}
} }

@ -17,6 +17,9 @@ public final class SignConstants {
/** 租户ID */ /** 租户ID */
public static final String TENANT_ID = "tenantId"; public static final String TENANT_ID = "tenantId";
/** 登陆来源 */
public static final String LOGIN_FROM = "loginFrom";
/** 时间戳 */ /** 时间戳 */
public static final String TIMESTAMP = "timestamp"; public static final String TIMESTAMP = "timestamp";

@ -19,7 +19,7 @@ package org.opsli.common.enums;
/** /**
* *
* *
* @author : * @author : Parker
* @date : 2020-09-17 23:40 * @date : 2020-09-17 23:40
*/ */
public enum DictType { public enum DictType {

@ -0,0 +1,77 @@
/**
* Copyright 2020 OPSLI https://www.opsli.com
* <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.common.enums;
import cn.hutool.core.bean.BeanUtil;
import java.util.Arrays;
/**
*
*
* @author
* @date 2020-09-17 23:40
*/
public enum LoginFromEnum {
/** 账号 */
PC("0"),
/** APP - 安卓 */
APP_ANDROID("1"),
/** APP - 苹果 */
APP_IOS("2"),
/** 微信小程序 */
WX_APPLET("3"),
/** h5 */
H5("4"),
/** 未知 */
UNKNOWN("-1"),
;
private final static String FILED_NAME = "loginFrom";
/***/
private final String type;
LoginFromEnum(String type){
this.type = type;
}
public String getType() {
return this.type;
}
public static LoginFromEnum getByCode(String code){
return Arrays.stream(LoginFromEnum.values())
.filter(value -> value.getType().equals(code))
.findFirst().orElse(LoginFromEnum.UNKNOWN);
}
public static LoginFromEnum getByBean(Object bean){
if(null == bean || !BeanUtil.isBean(bean.getClass())){
return LoginFromEnum.UNKNOWN;
}
Object fieldValue = BeanUtil.getFieldValue(bean, FILED_NAME);
if(null == fieldValue){
return LoginFromEnum.UNKNOWN;
}
return getByCode((String) fieldValue);
}
}

@ -0,0 +1,61 @@
/**
* Copyright 2020 OPSLI https://www.opsli.com
* <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.common.enums;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.StrUtil;
/**
*
*
* @author Parker
* @date 2022-07-21 2:07 PM
**/
public enum LoginModelType {
/** 未知 */
UNKNOWN,
/** 账号 */
ACCOUNT,
/** 手机 */
MOBILE,
/** 邮箱 */
EMAIL
;
public static LoginModelType getTypeByStr(String principal){
if(StrUtil.isBlank(principal)){
return UNKNOWN;
}
// 手机号
if(Validator.isMobile(principal)){
return MOBILE;
}
// 邮箱
else if(Validator.isEmail(principal)){
return EMAIL;
}
// 默认账号
return ACCOUNT;
}
}

@ -0,0 +1,53 @@
/**
* Copyright 2020 OPSLI https://www.opsli.com
* <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.common.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Optional;
/**
*
*
* @author
* @date 2022-08-01 12:49 PM
**/
@AllArgsConstructor
@Getter
public enum VerificationTypeEnum {
/** 类型 */
LOGIN("0"),
AUTH("1")
;
/** 类型 */
private final String type;
public static Optional<VerificationTypeEnum> getEnumByType(String type){
VerificationTypeEnum[] types = values();
for (VerificationTypeEnum typeEnum : types) {
if(typeEnum.type.equals(type)){
return Optional.of(typeEnum);
}
}
return Optional.empty();
}
}

@ -32,7 +32,7 @@ import java.util.concurrent.atomic.AtomicInteger;
* 线线 * 线线
* 202111214:07:54 线 * 202111214:07:54 线
* *
* @author * @author Parker
* @date 2020-12-10 10:36 * @date 2020-12-10 10:36
*/ */
@Slf4j @Slf4j

@ -31,7 +31,7 @@ import java.util.concurrent.atomic.AtomicInteger;
* 线 * 线
* 线线 * 线线
* *
* @author * @author Parker
* @date 2020-12-10 10:36 * @date 2020-12-10 10:36
*/ */
@Slf4j @Slf4j

@ -1,3 +1,18 @@
/**
* Copyright 2020 OPSLI https://www.opsli.com
* <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.common.thread; package org.opsli.common.thread;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
@ -14,7 +29,7 @@ import java.util.function.Function;
/** /**
* 线 - 线 * 线 - 线
* *
* @author * @author Parker
* @date 2020-10-08 10:24 * @date 2020-10-08 10:24
*/ */
@Slf4j @Slf4j

@ -1,3 +1,18 @@
/**
* Copyright 2020 OPSLI https://www.opsli.com
* <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.common.thread; package org.opsli.common.thread;
import cn.hutool.core.thread.ThreadUtil; import cn.hutool.core.thread.ThreadUtil;
@ -11,7 +26,7 @@ import java.util.concurrent.ExecutorService;
/** /**
* 线 * 线
* *
* @author * @author Parker
* @date 2021/8/27 17:00 * @date 2021/8/27 17:00
*/ */
@Slf4j @Slf4j

@ -0,0 +1,388 @@
package org.opsli.common.utils;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Hashids designed for Generating short hashes from numbers (like YouTube and Bitly), obfuscate
* database IDs, use them as forgotten password hashes, invitation codes, store shard numbers.
* <p>
* This is implementation of http://hashids.org v1.0.0 version.
*
* This implementation is immutable, thread-safe, no lock is necessary.
*
* @author <a href="mailto:fanweixiao@gmail.com">fanweixiao</a>
* @author <a href="mailto:terciofilho@gmail.com">Tercio Gaudencio Filho</a>
* @since 0.3.3
*/
public class HashIdsUtil {
/**
* Max number that can be encoded with Hashids.
*/
public static final long MAX_NUMBER = 9007199254740992L;
private static final String DEFAULT_ALPHABET = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
private static final String DEFAULT_SEPS = "cfhistuCFHISTU";
private static final String DEFAULT_SALT = "";
private static final int DEFAULT_MIN_HASH_LENGTH = 0;
private static final int MIN_ALPHABET_LENGTH = 16;
private static final double SEP_DIV = 3.5;
private static final int GUARD_DIV = 12;
private final String salt;
private final int minHashLength;
private final String alphabet;
private final String seps;
private final String guards;
public HashIdsUtil() {
this(DEFAULT_SALT);
}
public HashIdsUtil(String salt) {
this(salt, 0);
}
public HashIdsUtil(String salt, int minHashLength) {
this(salt, minHashLength, DEFAULT_ALPHABET);
}
public HashIdsUtil(String salt, int minHashLength, String alphabet) {
this.salt = salt != null ? salt : DEFAULT_SALT;
this.minHashLength = minHashLength > 0 ? minHashLength : DEFAULT_MIN_HASH_LENGTH;
final StringBuilder uniqueAlphabet = new StringBuilder();
for (int i = 0; i < alphabet.length(); i++) {
if (uniqueAlphabet.indexOf(String.valueOf(alphabet.charAt(i))) == -1) {
uniqueAlphabet.append(alphabet.charAt(i));
}
}
alphabet = uniqueAlphabet.toString();
if (alphabet.length() < MIN_ALPHABET_LENGTH) {
throw new IllegalArgumentException(
"alphabet must contain at least " + MIN_ALPHABET_LENGTH + " unique characters");
}
if (alphabet.contains(" ")) {
throw new IllegalArgumentException("alphabet cannot contains spaces");
}
// seps should contain only characters present in alphabet;
// alphabet should not contains seps
String seps = DEFAULT_SEPS;
for (int i = 0; i < seps.length(); i++) {
final int j = alphabet.indexOf(seps.charAt(i));
if (j == -1) {
seps = seps.substring(0, i) + " " + seps.substring(i + 1);
} else {
alphabet = alphabet.substring(0, j) + " " + alphabet.substring(j + 1);
}
}
alphabet = alphabet.replaceAll("\\s+", "");
seps = seps.replaceAll("\\s+", "");
seps = HashIdsUtil.consistentShuffle(seps, this.salt);
if ((seps.isEmpty()) || (((float) alphabet.length() / seps.length()) > SEP_DIV)) {
int seps_len = (int) Math.ceil(alphabet.length() / SEP_DIV);
if (seps_len == 1) {
seps_len++;
}
if (seps_len > seps.length()) {
final int diff = seps_len - seps.length();
seps += alphabet.substring(0, diff);
alphabet = alphabet.substring(diff);
} else {
seps = seps.substring(0, seps_len);
}
}
alphabet = HashIdsUtil.consistentShuffle(alphabet, this.salt);
// use double to round up
final int guardCount = (int) Math.ceil((double) alphabet.length() / GUARD_DIV);
String guards;
if (alphabet.length() < 3) {
guards = seps.substring(0, guardCount);
seps = seps.substring(guardCount);
} else {
guards = alphabet.substring(0, guardCount);
alphabet = alphabet.substring(guardCount);
}
this.guards = guards;
this.alphabet = alphabet;
this.seps = seps;
}
/**
* Encrypt numbers to string
*
* @param numbers
* the numbers to encrypt
* @return the encrypt string
*/
public String encode(long... numbers) {
if (numbers.length == 0) {
return "";
}
for (final long number : numbers) {
if (number < 0) {
return "";
}
if (number > MAX_NUMBER) {
throw new IllegalArgumentException("number can not be greater than " + MAX_NUMBER + "L");
}
}
return this._encode(numbers);
}
/**
* Decrypt string to numbers
*
* @param hash
* the encrypt string
* @return decryped numbers
*/
public long[] decode(String hash) {
if (hash.isEmpty()) {
return new long[0];
}
String validChars = this.alphabet + this.guards + this.seps;
for (int i = 0; i < hash.length(); i++) {
if(validChars.indexOf(hash.charAt(i)) == -1) {
return new long[0];
}
}
return this._decode(hash, this.alphabet);
}
/**
* Encrypt hexa to string
*
* @param hexa
* the hexa to encrypt
* @return the encrypt string
*/
public String encodeHex(String hexa) {
if (!hexa.matches("^[0-9a-fA-F]+$")) {
return "";
}
final List<Long> matched = new ArrayList<Long>();
final Matcher matcher = Pattern.compile("[\\w\\W]{1,12}").matcher(hexa);
while (matcher.find()) {
matched.add(Long.parseLong("1" + matcher.group(), 16));
}
// conversion
final long[] result = new long[matched.size()];
for (int i = 0; i < matched.size(); i++) {
result[i] = matched.get(i);
}
return this.encode(result);
}
/**
* Decrypt string to numbers
*
* @param hash
* the encrypt string
* @return decryped numbers
*/
public String decodeHex(String hash) {
final StringBuilder result = new StringBuilder();
final long[] numbers = this.decode(hash);
for (final long number : numbers) {
result.append(Long.toHexString(number).substring(1));
}
return result.toString();
}
public static int checkedCast(long value) {
final int result = (int) value;
if (result != value) {
// don't use checkArgument here, to avoid boxing
throw new IllegalArgumentException("Out of range: " + value);
}
return result;
}
/* Private methods */
private String _encode(long... numbers) {
long numberHashInt = 0;
for (int i = 0; i < numbers.length; i++) {
numberHashInt += (numbers[i] % (i + 100));
}
String alphabet = this.alphabet;
final char ret = alphabet.charAt((int) (numberHashInt % alphabet.length()));
long num;
long sepsIndex, guardIndex;
String buffer;
final StringBuilder ret_strB = new StringBuilder(this.minHashLength);
ret_strB.append(ret);
char guard;
for (int i = 0; i < numbers.length; i++) {
num = numbers[i];
buffer = ret + this.salt + alphabet;
alphabet = HashIdsUtil.consistentShuffle(alphabet, buffer.substring(0, alphabet.length()));
final String last = HashIdsUtil.hash(num, alphabet);
ret_strB.append(last);
if (i + 1 < numbers.length) {
if (last.length() > 0) {
num %= (last.charAt(0) + i);
sepsIndex = (int) (num % this.seps.length());
} else {
sepsIndex = 0;
}
ret_strB.append(this.seps.charAt((int) sepsIndex));
}
}
String ret_str = ret_strB.toString();
if (ret_str.length() < this.minHashLength) {
guardIndex = (numberHashInt + (ret_str.charAt(0))) % this.guards.length();
guard = this.guards.charAt((int) guardIndex);
ret_str = guard + ret_str;
if (ret_str.length() < this.minHashLength) {
guardIndex = (numberHashInt + (ret_str.charAt(2))) % this.guards.length();
guard = this.guards.charAt((int) guardIndex);
ret_str += guard;
}
}
final int halfLen = alphabet.length() / 2;
while (ret_str.length() < this.minHashLength) {
alphabet = HashIdsUtil.consistentShuffle(alphabet, alphabet);
ret_str = alphabet.substring(halfLen) + ret_str + alphabet.substring(0, halfLen);
final int excess = ret_str.length() - this.minHashLength;
if (excess > 0) {
final int start_pos = excess / 2;
ret_str = ret_str.substring(start_pos, start_pos + this.minHashLength);
}
}
return ret_str;
}
private long[] _decode(String hash, String alphabet) {
final ArrayList<Long> ret = new ArrayList<Long>();
int i = 0;
final String regexp = "[" + this.guards + "]";
String hashBreakdown = hash.replaceAll(regexp, " ");
String[] hashArray = hashBreakdown.split(" ");
if (hashArray.length == 3 || hashArray.length == 2) {
i = 1;
}
if (hashArray.length > 0) {
hashBreakdown = hashArray[i];
if (!hashBreakdown.isEmpty()) {
final char lottery = hashBreakdown.charAt(0);
hashBreakdown = hashBreakdown.substring(1);
hashBreakdown = hashBreakdown.replaceAll("[" + this.seps + "]", " ");
hashArray = hashBreakdown.split(" ");
String subHash, buffer;
for (final String aHashArray : hashArray) {
subHash = aHashArray;
buffer = lottery + this.salt + alphabet;
alphabet = HashIdsUtil.consistentShuffle(alphabet, buffer.substring(0, alphabet.length()));
ret.add(HashIdsUtil.unhash(subHash, alphabet));
}
}
}
// transform from List<Long> to long[]
long[] arr = new long[ret.size()];
for (int k = 0; k < arr.length; k++) {
arr[k] = ret.get(k);
}
if (!this.encode(arr).equals(hash)) {
arr = new long[0];
}
return arr;
}
private static String consistentShuffle(String alphabet, String salt) {
if (salt.length() <= 0) {
return alphabet;
}
int asc_val, j;
final char[] tmpArr = alphabet.toCharArray();
for (int i = tmpArr.length - 1, v = 0, p = 0; i > 0; i--, v++) {
v %= salt.length();
asc_val = salt.charAt(v);
p += asc_val;
j = (asc_val + v + p) % i;
final char tmp = tmpArr[j];
tmpArr[j] = tmpArr[i];
tmpArr[i] = tmp;
}
return new String(tmpArr);
}
private static String hash(long input, String alphabet) {
String hash = "";
final int alphabetLen = alphabet.length();
do {
final int index = (int) (input % alphabetLen);
if (index >= 0 && index < alphabet.length()) {
hash = alphabet.charAt(index) + hash;
}
input /= alphabetLen;
} while (input > 0);
return hash;
}
private static Long unhash(String input, String alphabet) {
long number = 0, pos;
for (int i = 0; i < input.length(); i++) {
pos = alphabet.indexOf(input.charAt(i));
number = number * alphabet.length() + pos;
}
return number;
}
/**
* Get Hashid algorithm version.
*
* @return Hashids algorithm version implemented.
*/
public String getVersion() {
return "1.0.0";
}
}

@ -15,6 +15,8 @@
*/ */
package org.opsli.common.utils; package org.opsli.common.utils;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.StrUtil;
import com.google.common.cache.Cache; import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheBuilder;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
@ -25,7 +27,6 @@ import org.opsli.common.thread.AsyncProcessExecutor;
import org.opsli.common.thread.AsyncProcessExecutorFactory; import org.opsli.common.thread.AsyncProcessExecutorFactory;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import java.time.Duration;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -39,6 +40,8 @@ import java.util.concurrent.TimeUnit;
@Slf4j @Slf4j
public final class RateLimiterUtil { public final class RateLimiterUtil {
/** 默认IP */
public static final String DEFAULT_IP = "unknown";
/** 默认QPS */ /** 默认QPS */
public static final double DEFAULT_QPS = 10d; public static final double DEFAULT_QPS = 10d;
/** 默认缓存个数 超出后流量自动清理 */ /** 默认缓存个数 超出后流量自动清理 */
@ -46,7 +49,7 @@ public final class RateLimiterUtil {
/** 默认缓存时效 超出后自动清理 */ /** 默认缓存时效 超出后自动清理 */
private static final int DEFAULT_CACHE_TIME = 5; private static final int DEFAULT_CACHE_TIME = 5;
/** 默认等待时长 */ /** 默认等待时长 */
private static final int DEFAULT_WAIT = 5000; private static final int DEFAULT_WAIT = 500;
/** 限流器单机缓存 */ /** 限流器单机缓存 */
private static final Cache<String, Map<String, RateLimiterUtil.RateLimiterInner> > LFU_CACHE; private static final Cache<String, Map<String, RateLimiterUtil.RateLimiterInner> > LFU_CACHE;
@ -108,6 +111,11 @@ public final class RateLimiterUtil {
*/ */
@SuppressWarnings("UnstableApiUsage") @SuppressWarnings("UnstableApiUsage")
public static boolean enter(String clientIpAddress, String resource, Double dfQps) { public static boolean enter(String clientIpAddress, String resource, Double dfQps) {
// IP 为空补偿器
if(StrUtil.isBlank(clientIpAddress)){
clientIpAddress = DEFAULT_IP;
}
// 计时器 // 计时器
long t1 = System.currentTimeMillis(); long t1 = System.currentTimeMillis();
@ -152,7 +160,7 @@ public final class RateLimiterUtil {
RateLimiter rateLimiter = rateLimiterObj.getRateLimiter(); RateLimiter rateLimiter = rateLimiterObj.getRateLimiter();
//非阻塞 //非阻塞
if (!rateLimiter.tryAcquire(Duration.ofMillis(DEFAULT_WAIT))) { if (!rateLimiter.tryAcquire(DEFAULT_WAIT, TimeUnit.MILLISECONDS)) {
//限速中,提示用户 //限速中,提示用户
log.error("限流器 - 访问频繁 耗时: "+ (System.currentTimeMillis() - t1) + "ms, IP地址: " + clientIpAddress + ", URI: " + resource); log.error("限流器 - 访问频繁 耗时: "+ (System.currentTimeMillis() - t1) + "ms, IP地址: " + clientIpAddress + ", URI: " + resource);
return false; return false;
@ -183,17 +191,39 @@ public final class RateLimiterUtil {
public static void main(String[] args) { public static void main(String[] args) {
int count = 500; // int count = 500;
RateLimiterUtil.removeIp("127.0.0.1"); // RateLimiterUtil.removeIp("127.0.0.1");
AsyncProcessExecutor normalExecutor = AsyncProcessExecutorFactory.createNormalExecutor(); // AsyncProcessExecutor normalExecutor = AsyncProcessExecutorFactory.createNormalExecutor();
for (int i = 0; i < count; i++) { // for (int i = 0; i < count; i++) {
// normalExecutor.put(()->{
// RateLimiter rateLimiter = RateLimiter.create(1);
//
//
// boolean enter = RateLimiterUtil.enter("127.0.0.1","/api/v1", 2d);
// System.out.println(enter);
// });
// }
// normalExecutor.execute();
int count = 3;
RateLimiter rateLimiter = RateLimiter.create(count);
AsyncProcessExecutor normalExecutor = AsyncProcessExecutorFactory.createWaitExecutor();
int num = 0;
while (true){
System.out.println("------------"+ (++num) +"------------");
for (int i = 0; i < count+1; i++) {
normalExecutor.put(()->{ normalExecutor.put(()->{
boolean enter = RateLimiterUtil.enter("127.0.0.1","/api/v1", 2d); boolean tryAcquire = rateLimiter.tryAcquire(500, TimeUnit.MILLISECONDS);
System.out.println(enter); System.out.println(tryAcquire);
}); });
} }
normalExecutor.execute(); normalExecutor.execute();
ThreadUtil.sleep(1100);
} }
}
} }

@ -0,0 +1,48 @@
/**
* Copyright 2020 OPSLI https://www.opsli.com
* <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.common.utils;
import cn.hutool.core.util.RandomUtil;
/**
*
* <a href="https://huzb.me/2018/03/23/%E7%AE%80%E5%8D%95%E7%9A%84%E5%AF%86%E7%A0%81%E5%AD%A6%E7%94%9F%E6%88%90%E5%94%AF%E4%B8%80%E9%82%80%E8%AF%B7%E7%A0%81">...</a>
*
* @author Parker
* @date 20220711 14:07
*/
public final class UniqueStrGeneratorUtils {
private static final String BEGIN_SALT = "opsli_2022_begin";
private static final String END_SALT = "opsli_2022_end";
private static final String CONTENT_SALT = "opsli_2022";
private static final HashIdsUtil DISTURB_HASH_ID_BEGIN = new HashIdsUtil(BEGIN_SALT, 2);
private static final HashIdsUtil DISTURB_HASH_ID_END = new HashIdsUtil(END_SALT, 3);
private static final HashIdsUtil CONTENT_HASH_ID = new HashIdsUtil(CONTENT_SALT, 7);
/** 生成 */
public static String generator(long i) {
int begin = RandomUtil.randomInt(0, 10);
int end = RandomUtil.randomInt(10, 100);
String disturbHashIdBeginStr = DISTURB_HASH_ID_BEGIN.encode(begin);
String disturbHashIdEndStr = DISTURB_HASH_ID_END.encode(end);
String contentHashIdStr = CONTENT_HASH_ID.encode(i);
return disturbHashIdBeginStr + contentHashIdStr + disturbHashIdEndStr;
}
}

@ -48,6 +48,13 @@
<version>${plugins.version}</version> <version>${plugins.version}</version>
</dependency> </dependency>
<!-- 引入短信插件 -->
<dependency>
<groupId>org.opsliframework.boot</groupId>
<artifactId>opsli-plugins-sms</artifactId>
<version>${plugins.version}</version>
</dependency>
<!-- 引入Redis插件 --> <!-- 引入Redis插件 -->
<dependency> <dependency>
<groupId>org.opsliframework.boot</groupId> <groupId>org.opsliframework.boot</groupId>
@ -55,6 +62,13 @@
<version>${plugins.version}</version> <version>${plugins.version}</version>
</dependency> </dependency>
<!-- 引入Security插件 -->
<dependency>
<groupId>org.opsliframework.boot</groupId>
<artifactId>opsli-plugins-security</artifactId>
<version>${plugins.version}</version>
</dependency>
<!-- 引入Redisson插件 --> <!-- 引入Redisson插件 -->
<dependency> <dependency>
<groupId>org.opsliframework.boot</groupId> <groupId>org.opsliframework.boot</groupId>
@ -78,12 +92,6 @@
<!-- ———————————————————— 集成Shiro鉴权安全认证 - 开始 ———————————————————— --> <!-- ———————————————————— 集成Shiro鉴权安全认证 - 开始 ———————————————————— -->
<!-- ShiroRedis包 -->
<dependency>
<groupId>org.crazycake</groupId>
<artifactId>shiro-redis-spring-boot-starter</artifactId>
</dependency>
<!-- captcha 验证码 --> <!-- captcha 验证码 -->
<dependency> <dependency>
<groupId>com.github.whvcse</groupId> <groupId>com.github.whvcse</groupId>
@ -96,6 +104,11 @@
<artifactId>java-jwt</artifactId> <artifactId>java-jwt</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.jfinal</groupId>
<artifactId>enjoy</artifactId>
</dependency>
<!-- ———————————————————— 集成Shiro鉴权安全认证 - 结束 ———————————————————— --> <!-- ———————————————————— 集成Shiro鉴权安全认证 - 结束 ———————————————————— -->
<!-- ———————————————————— 集成数据库相关配置 - 开始 ———————————————————— --> <!-- ———————————————————— 集成数据库相关配置 - 开始 ———————————————————— -->
@ -127,7 +140,20 @@
<dependency> <dependency>
<groupId>mysql</groupId> <groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId> <artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
<scope>runtime</scope> <scope>runtime</scope>
<exclusions>
<!-- 修复 CVE-2021-22569 -->
<exclusion>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 修复 CVE-2021-22569 -->
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
</dependency> </dependency>
<!-- sqlserver--> <!-- sqlserver-->
@ -149,6 +175,7 @@
<groupId>org.postgresql</groupId> <groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId> <artifactId>postgresql</artifactId>
<scope>runtime</scope> <scope>runtime</scope>
<version>${postgresql.version}</version>
</dependency> </dependency>
<!-- ———————————————————— 集成数据库相关配置 - 结束 ———————————————————— --> <!-- ———————————————————— 集成数据库相关配置 - 结束 ———————————————————— -->

@ -0,0 +1,46 @@
/**
* Copyright 2020 OPSLI https://www.opsli.com
* <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.autoconfigure.conf;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* Cors
*
* @author Parker
* @date 2022071412:57:33
**/
@Configuration
public class CorsConfig implements WebMvcConfigurer {
/**
*
*
* @param registry registry
*/
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOriginPatterns("*")
.allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("*")
.allowCredentials(true)
.maxAge(7200);
}
}

@ -15,7 +15,8 @@
*/ */
package org.opsli.core.autoconfigure.conf; package org.opsli.core.autoconfigure.conf;
import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor; import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactory;
import org.opsli.core.filters.interceptor.MybatisAutoFillInterceptor; import org.opsli.core.filters.interceptor.MybatisAutoFillInterceptor;
@ -35,13 +36,20 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
@Configuration @Configuration
public class MyBatisPlusConfig { public class MyBatisPlusConfig {
/*** /**
* *
* @return
*/ */
@Bean @Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor(){ public MybatisPlusInterceptor mybatisPlusInterceptor() {
return new OptimisticLockerInterceptor(); MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
// 乐观锁
mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
// 防止全表更新与删除插件
//mybatisPlusInterceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());
return mybatisPlusInterceptor;
} }
/** /**

@ -0,0 +1,141 @@
/**
* Copyright 2020 OPSLI https://www.opsli.com
* <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.autoconfigure.conf;
import cn.hutool.extra.spring.SpringUtil;
import com.google.common.collect.Lists;
import lombok.AllArgsConstructor;
import org.opsli.core.security.filter.JwtAuthenticationTokenFilter;
import org.opsli.core.security.service.UidUserDetailDetailServiceImpl;
import org.opsli.plugins.security.exception.handler.AccessDeniedHandlerImpl;
import org.opsli.plugins.security.exception.handler.AuthenticationEntryPointImpl;
import org.opsli.plugins.security.properties.AuthProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import java.util.List;
import java.util.Map;
/**
* Security
*
* @author Parker
* @date 2022071412:57:33
**/
@AllArgsConstructor
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled=true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final AuthProperties authProperties;
private final AccessDeniedHandlerImpl accessDeniedHandler;
private final AuthenticationEntryPointImpl authenticationEntryPoint;
private final UidUserDetailDetailServiceImpl uidUserDetailDetailService;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.headers()
// 默认关闭 Security 的 xss防护与系统本身的 xss防护冲突
.xssProtection().disable()
// 允许Iframe加载
.frameOptions().disable()
.and()
// 关闭csrf token认证不需要csrf防护
.csrf().disable();
// 初始化 initAuthorizeRequests
this.initAuthorizeRequests(http);
}
/**
* URL
* @param http http
*/
private void initAuthorizeRequests(HttpSecurity http) throws Exception {
// 设置URL 未登陆前可访问URL
List<String> anonymousList = authProperties.getUrlExclusion().getAnonymous();
if(null != anonymousList){
String[] urlExclusionArray = anonymousList.toArray(new String[0]);
http.authorizeRequests()
// URL 未登陆前可访问
.antMatchers(urlExclusionArray).anonymous();
}
// 设置URL白名单
List<String> permitAll = authProperties.getUrlExclusion().getPermitAll();
if(null != permitAll){
String[] urlExclusionArray = permitAll.toArray(new String[0]);
http.authorizeRequests()
// URL 白名单
.antMatchers(urlExclusionArray).permitAll();
}
// 除上面外的所有请求全部需要鉴权认证
http.authorizeRequests()
.anyRequest().authenticated();
// 添加过滤器
// 注意 自定义 Filter 不要交给 Spring管理
http.addFilterBefore(new JwtAuthenticationTokenFilter(uidUserDetailDetailService),
UsernamePasswordAuthenticationFilter.class);
// 异常处理
http.exceptionHandling()
.accessDeniedHandler(accessDeniedHandler)
.authenticationEntryPoint(authenticationEntryPoint);
}
/**
*
*/
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected AuthenticationManager authenticationManager() {
// 设置 多Provider
Map<String, AuthenticationProvider> providerMap =
SpringUtil.getBeansOfType(AuthenticationProvider.class);
List<AuthenticationProvider> authenticationProviderList =
Lists.newArrayListWithCapacity(providerMap.size());
for (Map.Entry<String, AuthenticationProvider> providerEntry : providerMap.entrySet()) {
authenticationProviderList.add(providerEntry.getValue());
}
ProviderManager authenticationManager = new ProviderManager(authenticationProviderList);
//不擦除认证密码擦除会导致TokenBasedRememberMeServices因为找不到Credentials再调用UserDetailsService而抛出UsernameNotFoundException
authenticationManager.setEraseCredentialsAfterAuthentication(false);
return authenticationManager;
}
}

@ -1,198 +0,0 @@
/**
* Copyright 2020 OPSLI https://www.opsli.com
* <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.autoconfigure.conf;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ClassUtil;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy;
import org.apache.shiro.authc.pam.ModularRealmAuthenticator;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
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.autoconfigure.properties.ApiPathProperties;
import org.opsli.core.autoconfigure.properties.GlobalProperties;
import org.opsli.core.security.shiro.authenticator.CustomModularRealmAuthenticator;
import org.opsli.core.security.shiro.filter.CustomShiroFilter;
import org.opsli.core.security.shiro.realm.FlagRealm;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import javax.servlet.Filter;
import java.lang.reflect.Modifier;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Shiro
*
* token -
*
* @author Parker
* @date 2017-04-20 18:33
*/
@Configuration
public class ShiroConfig {
/**
* filer
* @param securityManager
* @return ShiroFilterFactoryBean
*/
@Bean("shiroFilter")
public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager,
GlobalProperties globalProperties, ApiPathProperties apiPathProperties) {
ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
shiroFilter.setSecurityManager(securityManager);
//oauth过滤
Map<String, Filter> filters = Maps.newHashMapWithExpectedSize(1);
filters.put("last_filter", new CustomShiroFilter());
shiroFilter.setFilters(filters);
Map<String, String> filterMap = Maps.newLinkedHashMap();
// 加载排除URL
if(globalProperties.getAuth() != null &&
globalProperties.getAuth().getToken() != null){
Set<String> urlExclusion = globalProperties.getAuth().getToken().getUrlExclusion();
if(CollUtil.isNotEmpty(urlExclusion)){
for (String excUrl : urlExclusion) {
filterMap.put(excUrl, "anon");
}
}
}
// 登录接口拦截
filterMap.put("/system/login", "anon");
filterMap.put("/system/publicKey", "anon");
filterMap.put("/system/slipCount", "anon");
filterMap.put("/captcha*", "anon");
// 导出Excel\模版 不做自动拦截 手动拦截
filterMap.put(apiPathProperties.getGlobalPrefix() + "/**/exportExcel", "anon");
filterMap.put(apiPathProperties.getGlobalPrefix() + "/**/importExcel/template", "anon");
filterMap.put("/webjars/**", "anon");
filterMap.put("/druid/**", "anon");
filterMap.put("/app/**", "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("/**", "last_filter");
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(SessionManager sessionManager) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setSessionManager(sessionManager);
// 设置验证器为自定义验证器
securityManager.setAuthenticator(modularRealmAuthenticator());
List<Realm> realms = Lists.newArrayList();
// 拿到state包下 实现了 FlagRealm 接口的,所有子类
Set<Class<?>> clazzSet = ClassUtil.scanPackageBySuper(
FlagRealm.class.getPackage().getName(),
FlagRealm.class
);
for (Class<?> aClass : clazzSet) {
// 位运算 去除抽象类
if((aClass.getModifiers() & Modifier.ABSTRACT) != 0){
continue;
}
try {
realms.add((Realm) aClass.newInstance());
} catch (Exception ignored){ }
}
if(CollUtil.isNotEmpty(realms)){
// 追加 Realms
securityManager.setRealms(realms);
}
return securityManager;
}
/**
* Realm使
*/
@Bean("modularRealmAuthenticator")
public ModularRealmAuthenticator modularRealmAuthenticator(){
CustomModularRealmAuthenticator authenticator = new CustomModularRealmAuthenticator();
authenticator.setAuthenticationStrategy(new AtLeastOneSuccessfulStrategy());
return authenticator;
}
// ===================== 固定三板斧 =====================
// 其实 没有 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 AuthorizationAttributeSourceAdvisor
*/
@Bean("authorizationAttributeSourceAdvisor")
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
advisor.setSecurityManager(securityManager);
return advisor;
}
}

@ -26,6 +26,7 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter; import org.springframework.web.filter.CorsFilter;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.PathMatchConfigurer; import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@ -67,23 +68,18 @@ public class SpringWebMvcConfig implements WebMvcConfigurer, WebMvcRegistrations
/** /**
* *
* @return CorsFilter *
* @param registry registry
*/ */
@Bean // @Override
public CorsFilter corsFilter() { // public void addCorsMappings(CorsRegistry registry) {
final UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource(); // registry.addMapping("/**")
final CorsConfiguration corsConfiguration = new CorsConfiguration(); // .allowedOriginPatterns("*")
/* 是否允许请求带有验证信息 */ // .allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS")
corsConfiguration.setAllowCredentials(true); // .allowedHeaders("*")
/* 允许访问的客户端域名 */ // .allowCredentials(true)
corsConfiguration.addAllowedOrigin("*"); // .maxAge(7200);
/* 允许服务端访问的客户端请求头 */ // }
corsConfiguration.addAllowedHeader("*");
/* 允许访问的方法名,GET POST等 */
corsConfiguration.addAllowedMethod("*");
urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
return new CorsFilter(urlBasedCorsConfigurationSource);
}
@Override @Override
public void addInterceptors(InterceptorRegistry registry) { public void addInterceptors(InterceptorRegistry registry) {

@ -90,9 +90,6 @@ public class GlobalProperties {
/** 有效时间 (分钟)*/ /** 有效时间 (分钟)*/
private Integer effectiveTime; private Integer effectiveTime;
/** 排除URL*/
private Set<String> urlExclusion;
} }
/** /**

@ -0,0 +1,43 @@
/**
* Copyright 2020 OPSLI https://www.opsli.com
* <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.autoconfigure.properties;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* Token
*
* @author Parker
* @date 2020-09-15
*/
@Component
@ConfigurationProperties(prefix = TokenProperties.PROP_PREFIX)
@Data
@EqualsAndHashCode(callSuper = false)
public class TokenProperties {
public static final String PROP_PREFIX = "opsli.auth.token";
/** 盐 */
private String secret;
/** 有效时间 */
private int effectiveTime;
}

@ -16,7 +16,6 @@
package org.opsli.core.base.controller; package org.opsli.core.base.controller;
import cn.hutool.core.annotation.AnnotationUtil;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil; import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.convert.Convert; import cn.hutool.core.convert.Convert;
@ -24,36 +23,42 @@ import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.TimeInterval; import cn.hutool.core.date.TimeInterval;
import cn.hutool.core.lang.tree.Tree; import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.excel.support.ExcelTypeEnum; import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.util.CollectionUtils; import com.alibaba.excel.util.CollectionUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.opsli.api.base.result.ResultVo; import org.opsli.api.base.result.ResultWrapper;
import org.opsli.api.base.warpper.ApiWrapper; import org.opsli.api.base.warpper.ApiWrapper;
import org.opsli.api.wrapper.system.user.UserModel; import org.opsli.api.wrapper.system.user.UserModel;
import org.opsli.common.annotation.RequiresPermissionsCus; import org.opsli.common.constants.RedisConstants;
import org.opsli.common.annotation.hotdata.EnableHotData;
import org.opsli.common.constants.TreeConstants; import org.opsli.common.constants.TreeConstants;
import org.opsli.common.enums.ExcelOperate; import org.opsli.common.enums.ExcelOperate;
import org.opsli.common.exception.ServiceException; import org.opsli.common.exception.ServiceException;
import org.opsli.common.exception.TokenException; import org.opsli.common.utils.UniqueStrGeneratorUtils;
import org.opsli.common.utils.OutputStreamUtil;
import org.opsli.common.utils.WrapperUtil; import org.opsli.common.utils.WrapperUtil;
import org.opsli.core.autoconfigure.properties.GlobalProperties; import org.opsli.core.autoconfigure.properties.GlobalProperties;
import org.opsli.core.base.entity.BaseEntity; import org.opsli.core.base.entity.BaseEntity;
import org.opsli.core.base.entity.HasChildren; import org.opsli.core.base.entity.HasChildren;
import org.opsli.core.base.service.interfaces.CrudServiceInterface; import org.opsli.core.base.service.interfaces.CrudServiceInterface;
import org.opsli.core.cache.CacheUtil;
import org.opsli.core.msg.CoreMsg; import org.opsli.core.msg.CoreMsg;
import org.opsli.core.msg.TokenMsg; import org.opsli.core.persistence.querybuilder.QueryBuilder;
import org.opsli.core.security.shiro.realm.JwtRealm; import org.opsli.core.persistence.querybuilder.WebQueryBuilder;
import org.opsli.core.utils.ExcelUtil; import org.opsli.core.utils.ExcelUtil;
import org.opsli.core.utils.UserUtil; import org.opsli.core.utils.UserUtil;
import org.opsli.plugins.excel.exception.ExcelPluginException; import org.opsli.plugins.excel.exception.ExcelPluginException;
import org.opsli.plugins.excel.listener.BatchExcelListener; import org.opsli.plugins.excel.listener.BatchExcelListener;
import org.opsli.plugins.redis.RedisPlugin;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestParam;
@ -61,10 +66,11 @@ import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest; import org.springframework.web.multipart.MultipartHttpServletRequest;
import javax.annotation.PostConstruct; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method; import java.io.Serializable;
import java.util.*; import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function; import java.util.function.Function;
/** /**
@ -77,14 +83,8 @@ import java.util.function.Function;
@RestController @RestController
public abstract class BaseRestController <T extends BaseEntity, E extends ApiWrapper, S extends CrudServiceInterface<T,E>>{ public abstract class BaseRestController <T extends BaseEntity, E extends ApiWrapper, S extends CrudServiceInterface<T,E>>{
/** 开启热点数据状态 */ /** 凭证 10分钟失效 */
protected boolean hotDataFlag = false; private static final int CERTIFICATE_EXPIRED_MINUTE = 10;
/** Entity Clazz 类 */
protected Class<T> entityClazz;
/** Model Clazz 类 */
protected Class<E> modelClazz;
/** 配置类 */ /** 配置类 */
@Autowired @Autowired
@ -94,6 +94,10 @@ public abstract class BaseRestController <T extends BaseEntity, E extends ApiWra
@Autowired(required = false) @Autowired(required = false)
protected S IService; protected S IService;
/** Redis 类 */
@Autowired
private RedisPlugin redisPlugin;
/** /**
* *
* id * id
@ -103,15 +107,18 @@ public abstract class BaseRestController <T extends BaseEntity, E extends ApiWra
*/ */
@ModelAttribute @ModelAttribute
public E get(@RequestParam(required=false) String id) { public E get(@RequestParam(required=false) String id) {
if(StrUtil.isEmpty(id)){
return null;
}
return IService.get(id); return IService.get(id);
} }
/** /**
* Excel * Excel
* @param request request * @param request request
* @return ResultVo * @return ResultWrapper
*/ */
protected ResultVo<?> importExcel(MultipartHttpServletRequest request){ protected ResultWrapper<?> importExcel(MultipartHttpServletRequest request){
// 计时器 // 计时器
TimeInterval timer = DateUtil.timer(); TimeInterval timer = DateUtil.timer();
Iterator<String> itr = request.getFileNames(); Iterator<String> itr = request.getFileNames();
@ -119,21 +126,20 @@ public abstract class BaseRestController <T extends BaseEntity, E extends ApiWra
List<MultipartFile> files = request.getFiles(uploadedFile); List<MultipartFile> files = request.getFiles(uploadedFile);
if (CollectionUtils.isEmpty(files)) { if (CollectionUtils.isEmpty(files)) {
// 请选择文件 // 请选择文件
return ResultVo.error(CoreMsg.EXCEL_FILE_NULL.getCode(), return ResultWrapper.getCustomResultWrapper(CoreMsg.EXCEL_FILE_NULL);
CoreMsg.EXCEL_FILE_NULL.getMessage());
} }
ResultVo<?> resultVo ; ResultWrapper<?> resultVo ;
String msgInfo; String msgInfo;
try { try {
UserModel user = UserUtil.getUser(); UserModel user = UserUtil.getUser();
Date currDate = DateUtil.date(); Date currDate = DateUtil.date();
// 导入优化为 监听器 模式 超过一定阈值直接释放资源 防止导入数据导致系统 OOM // 导入优化为 监听器 模式 超过一定阈值直接释放资源 防止导入数据导致系统 OOM
ExcelUtil.getInstance().readExcelByListener(files.get(0), modelClazz, new BatchExcelListener<E>() { ExcelUtil.getInstance().readExcelByListener(files.get(0), IService.getModelClass(), new BatchExcelListener<E>() {
@Override @Override
public void saveData(List<E> dataList) { public void saveData(List<E> dataList) {
// 处理字典数据 // 处理字典数据
List<E> disposeData = ExcelUtil.getInstance().handleDatas(dataList, modelClazz, ExcelOperate.READ); List<E> disposeData = ExcelUtil.getInstance().handleDatas(dataList, IService.getModelClass(), ExcelOperate.READ);
// 手动赋值 必要数据 防止频繁开启Redis网络IO // 手动赋值 必要数据 防止频繁开启Redis网络IO
for (E model : disposeData) { for (E model : disposeData) {
model.setIzManual(true); model.setIzManual(true);
@ -152,7 +158,7 @@ public abstract class BaseRestController <T extends BaseEntity, E extends ApiWra
// 提示信息 // 提示信息
msgInfo = StrUtil.format(CoreMsg.EXCEL_IMPORT_SUCCESS.getMessage(), DateUtil.formatBetween(timerCount)); msgInfo = StrUtil.format(CoreMsg.EXCEL_IMPORT_SUCCESS.getMessage(), DateUtil.formatBetween(timerCount));
// 导出成功 // 导出成功
resultVo = ResultVo.success(msgInfo); resultVo = ResultWrapper.getSuccessResultWrapper(msgInfo);
resultVo.setCode(CoreMsg.EXCEL_IMPORT_SUCCESS.getCode()); resultVo.setCode(CoreMsg.EXCEL_IMPORT_SUCCESS.getCode());
} catch (ExcelPluginException e) { } catch (ExcelPluginException e) {
@ -162,7 +168,8 @@ public abstract class BaseRestController <T extends BaseEntity, E extends ApiWra
msgInfo = StrUtil.format(CoreMsg.EXCEL_IMPORT_ERROR.getMessage(), DateUtil.formatBetween(timerCount), msgInfo = StrUtil.format(CoreMsg.EXCEL_IMPORT_ERROR.getMessage(), DateUtil.formatBetween(timerCount),
e.getMessage()); e.getMessage());
// 导入失败 // 导入失败
resultVo = ResultVo.error(CoreMsg.EXCEL_IMPORT_ERROR.getCode(), msgInfo); resultVo = ResultWrapper.getCustomResultWrapper(
CoreMsg.EXCEL_IMPORT_ERROR.getCode(), msgInfo);
} }
// 记录导出日志 // 记录导出日志
log.info(msgInfo); log.info(msgInfo);
@ -170,64 +177,25 @@ public abstract class BaseRestController <T extends BaseEntity, E extends ApiWra
} }
/** /**
* * Excel
* @param fileName
* @param response response
*/
protected void importTemplate(String fileName, HttpServletResponse response, Method method){
this.excelExport(fileName + " 模版 ",null, response, method);
}
/**
*
*
* Token
*
* 使2
*
* socketJava
* response javascript alert
* *
* @param fileName * @param type ExcelExcel
* @param queryWrapper * @param subName
* @param response response * @param request request
* @return Optional<String>
*/ */
protected void excelExport(String fileName, QueryWrapper<T> queryWrapper, HttpServletResponse response, protected Optional<String> excelExportAuth(String type, String subName, HttpServletRequest request){
Method method){ // 封装缓存数据
// 权限认证 ExcelExportCache exportCache;
try { if(ExcelExportCache.EXCEL_EXPORT.equals(type)){
if(method == null){ // 异常检测
// 无权访问该方法 QueryBuilder<T> queryBuilder = new WebQueryBuilder<>(IService.getEntityClass(), request.getParameterMap());
throw new TokenException(TokenMsg.EXCEPTION_NOT_AUTH); QueryWrapper<T> queryWrapper = queryBuilder.build();
}
// Token 认证
JwtRealm.authToken();
RequiresPermissionsCus permissionsCus = method.getAnnotation(RequiresPermissionsCus.class);
if(permissionsCus != null){
// 方法权限认证
JwtRealm.authPerms(permissionsCus.value());
}
}catch (TokenException e){
// 推送错误信息
OutputStreamUtil.exceptionResponse(e.getMessage(), response);
return;
}
// 计时器
TimeInterval timer = DateUtil.timer();
String msgInfo;
ResultVo<?> resultVo;
List<E> modelList = Lists.newArrayList();
try {
if(queryWrapper != null){
// 导出数量限制 -1 为无限制 // 导出数量限制 -1 为无限制
Integer exportMaxCount = globalProperties.getExcel().getExportMaxCount(); Integer exportMaxCount = globalProperties.getExcel().getExportMaxCount();
if(exportMaxCount != null && exportMaxCount > -1){ if(exportMaxCount != null && exportMaxCount > -1){
// 获得数量 大于 阈值 禁止导出, 防止OOM // 获得数量 大于 阈值 禁止导出, 防止OOM
int count = IService.count(queryWrapper); long count = IService.count(queryWrapper);
if(count > exportMaxCount){ if(count > exportMaxCount){
String maxError = StrUtil.format(CoreMsg.EXCEL_HANDLE_MAX.getMessage(), count, String maxError = StrUtil.format(CoreMsg.EXCEL_HANDLE_MAX.getMessage(), count,
exportMaxCount); exportMaxCount);
@ -236,42 +204,86 @@ public abstract class BaseRestController <T extends BaseEntity, E extends ApiWra
} }
} }
// 封装缓存数据
exportCache = ExcelExportCache.builder()
.subName(subName)
.parameterMapStr(JSONUtil.toJsonStr(request.getParameterMap()))
.type(type)
.build();
}else if(ExcelExportCache.EXCEL_IMPORT_TEMPLATE_EXPORT.equals(type)){
// 封装缓存数据
exportCache = ExcelExportCache.builder()
.subName(subName+ " 模版 ")
.parameterMapStr(JSONUtil.toJsonStr(request.getParameterMap()))
.type(type)
.build();
}else {
return Optional.empty();
}
// 缓存Key
Long increment = redisPlugin
.increment(CacheUtil.formatKey(RedisConstants.PREFIX_TMP_EXCEL_EXPORT_NUM_NAME));
String certificate = UniqueStrGeneratorUtils.generator(increment);
// 缓存Key
String certificateCacheKeyTmp = CacheUtil.formatKey(
RedisConstants.PREFIX_TMP_EXCEL_EXPORT_NAME + certificate);
redisPlugin.put(certificateCacheKeyTmp, exportCache, CERTIFICATE_EXPIRED_MINUTE, TimeUnit.MINUTES);
return Optional.of(certificate);
}
/**
* Excel
*
* @param response response
*/
protected void excelExport(String certificate, HttpServletResponse response){
// 缓存Key
String certificateCacheKeyTmp = CacheUtil.formatKey(
RedisConstants.PREFIX_TMP_EXCEL_EXPORT_NAME + certificate);
Object cacheObj = redisPlugin.get(certificateCacheKeyTmp);
ExcelExportCache cache = Convert.convert(ExcelExportCache.class, cacheObj);
if(cache == null){
return;
}
// 主题名称
String subName = cache.getSubName();
List<E> modelList = null;
// 如果导出Excel 需要查询数据
if(ExcelExportCache.EXCEL_EXPORT.equals(cache.getType())){
// 参数Map
Map<String, String[]> parameterMap = new HashMap<>();
JSONObject jsonObject = JSONUtil.parseObj(cache.getParameterMapStr());
jsonObject.forEach((k, v) -> {
JSONArray values = (JSONArray) v;
String[] parameters = (String[]) values.toArray(String.class);
parameterMap.put(k, parameters);
});
QueryBuilder<T> queryBuilder = new WebQueryBuilder<>(IService.getEntityClass(), parameterMap);
QueryWrapper<T> queryWrapper = queryBuilder.build();
List<T> entityList = IService.findList(queryWrapper); List<T> entityList = IService.findList(queryWrapper);
// 转化类型 // 转化类型
modelList = WrapperUtil.transformInstance(entityList, modelClazz); modelList = WrapperUtil.transformInstance(entityList, IService.getModelClass());
} }
// 导出Excel // 导出Excel
ExcelUtil.getInstance().writeExcel(response, modelList ,fileName,"sheet", modelClazz ,ExcelTypeEnum.XLSX); ExcelUtil.getInstance().writeExcel(
// 花费毫秒数 response, modelList, subName,"sheet", IService.getModelClass() ,ExcelTypeEnum.XLSX);
long timerCount = timer.interval();
// 提示信息
msgInfo = StrUtil.format(CoreMsg.EXCEL_EXPORT_SUCCESS.getMessage(), modelList.size(),
DateUtil.formatBetween(timerCount));
// 导出成功
resultVo = ResultVo.success(msgInfo);
resultVo.setCode(CoreMsg.EXCEL_EXPORT_SUCCESS.getCode());
} catch (ExcelPluginException e) {
// 花费毫秒数
long timerCount = timer.interval();
// 提示信息
msgInfo = StrUtil.format(CoreMsg.EXCEL_EXPORT_ERROR.getMessage(), DateUtil.formatBetween(timerCount), e.getMessage());
// 导出失败
resultVo = ResultVo.error(CoreMsg.EXCEL_EXPORT_ERROR.getCode(), msgInfo);
}finally {
// 清空list
modelList.clear();
}
// 记录导出日志
log.info(msgInfo);
// 导出异常 // 删除凭证
if(!resultVo.isSuccess()){ redisPlugin.del(certificateCacheKeyTmp);
// 无权访问该方法
OutputStreamUtil.exceptionResponse(resultVo.getMsg(), response);
}
} }
/** /**
* *
*/ */
@ -347,34 +359,28 @@ public abstract class BaseRestController <T extends BaseEntity, E extends ApiWra
// ================================================= // =================================================
@PostConstruct
public void init(){
try {
this.modelClazz = IService.getModelClazz();
this.entityClazz = IService.getEntityClazz();
if(IService != null){
// 判断Service 是否包含 热数据注解
this.hotDataFlag = AnnotationUtil.hasAnnotation(IService.getServiceClazz(),
EnableHotData.class);
}
}catch (Exception e){
log.error(e.getMessage(),e);
}
}
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Data
public static class ExcelExportCache implements Serializable {
private static final long serialVersionUID = 1L;
public final static String EXCEL_IMPORT_TEMPLATE_EXPORT = "import-template-export";
public final static String EXCEL_EXPORT = "export";
/**
*
* @return E
*/
private E createModel() {
try {
Class<E> modelClazz = this.modelClazz;
return modelClazz.newInstance();
} catch (Exception e) {
log.error(e.getMessage(),e);
}
return null;
}
/** 主题名 */
private String subName;
/** 类型 */
private String type;
/** 请求参数Map */
private String parameterMapStr;
}
} }

@ -0,0 +1,62 @@
/**
* Copyright 2020 OPSLI https://www.opsli.com
* <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.base.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
*
*
* @author Parker
* @date 2021122216:22:37
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class LoginUserDto implements Serializable {
private static final long serialVersionUID = 1L;
/** 用户ID */
private String uid;
/** 用户名 */
private String username;
/** 用户昵称 */
private String nickname;
/** 租户ID */
private String tenantId;
/** 手机 */
private String mobile;
/** 邮箱 */
private String email;
/** 登录来源: 0:PC端1:APP-安卓 2:APP-IOS 3:小程序 */
private String loginFrom;
/** 登录ip */
private String loginIp;
}

@ -16,10 +16,14 @@
package org.opsli.core.base.service.impl; package org.opsli.core.base.service.impl;
import cn.hutool.core.convert.Convert; import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.TypeUtil; import cn.hutool.core.util.TypeUtil;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.toolkit.ReflectionKit;
import com.baomidou.mybatisplus.core.toolkit.reflect.SpringReflectionHelper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageInfo; import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -35,6 +39,7 @@ import org.opsli.core.persistence.querybuilder.QueryBuilder;
import org.opsli.core.persistence.querybuilder.chain.QueryDataPermsHandler; import org.opsli.core.persistence.querybuilder.chain.QueryDataPermsHandler;
import org.opsli.core.persistence.querybuilder.chain.QueryTenantHandler; import org.opsli.core.persistence.querybuilder.chain.QueryTenantHandler;
import org.opsli.core.persistence.querybuilder.conf.WebQueryConf; import org.opsli.core.persistence.querybuilder.conf.WebQueryConf;
import org.springframework.core.GenericTypeResolver;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
@ -64,12 +69,8 @@ import java.util.Map;
public abstract class CrudServiceImpl<M extends BaseMapper<T>, T extends BaseEntity, E extends ApiWrapper> public abstract class CrudServiceImpl<M extends BaseMapper<T>, T extends BaseEntity, E extends ApiWrapper>
extends BaseService<M, T> implements CrudServiceInterface<T,E> { extends BaseService<M, T> implements CrudServiceInterface<T,E> {
/** JSON tmp */
private static final String JSON_TMP = "{\"id\":\"1\"}";
/** Entity Clazz 类 */
protected Class<T> entityClazz;
/** Model Clazz 类 */ /** Model Clazz 类 */
protected Class<E> modelClazz; protected Class<E> modelClazz = getInnerModelClazz();
@Override @Override
public E get(String id) { public E get(String id) {
@ -213,7 +214,7 @@ public abstract class CrudServiceImpl<M extends BaseMapper<T>, T extends BaseEnt
@Override @Override
public List<T> findList(QueryWrapper<T> queryWrapper) { public List<T> findList(QueryWrapper<T> queryWrapper) {
// 数据处理责任链 // 数据处理责任链
QueryWrapper<T> qWrapper = this.addHandler(entityClazz, queryWrapper); QueryWrapper<T> qWrapper = this.addHandler(this.getEntityClass(), queryWrapper);
return super.list(qWrapper); return super.list(qWrapper);
} }
@ -221,7 +222,7 @@ public abstract class CrudServiceImpl<M extends BaseMapper<T>, T extends BaseEnt
@Override @Override
public List<T> findAllList() { public List<T> findAllList() {
// 数据处理责任链 // 数据处理责任链
QueryWrapper<T> qWrapper = this.addHandler(entityClazz); QueryWrapper<T> qWrapper = this.addHandler(this.getEntityClass());
return super.list(qWrapper); return super.list(qWrapper);
} }
@ -229,7 +230,7 @@ public abstract class CrudServiceImpl<M extends BaseMapper<T>, T extends BaseEnt
@Override @Override
public Page<T,E> findPage(Page<T,E> page) { public Page<T,E> findPage(Page<T,E> page) {
// 数据处理责任链 // 数据处理责任链
QueryWrapper<T> qWrapper = this.addHandler(entityClazz, page.getQueryWrapper()); QueryWrapper<T> qWrapper = this.addHandler(this.getEntityClass(), page.getQueryWrapper());
page.pageHelperBegin(); page.pageHelperBegin();
try{ try{
List<T> list = super.list(qWrapper); List<T> list = super.list(qWrapper);
@ -245,7 +246,7 @@ public abstract class CrudServiceImpl<M extends BaseMapper<T>, T extends BaseEnt
@Override @Override
public Page<T,E> findPageNotCount(Page<T,E> page) { public Page<T,E> findPageNotCount(Page<T,E> page) {
// 数据处理责任链 // 数据处理责任链
QueryWrapper<T> qWrapper = this.addHandler(entityClazz, page.getQueryWrapper()); QueryWrapper<T> qWrapper = this.addHandler(this.getEntityClass(), page.getQueryWrapper());
page.pageHelperBegin(false); page.pageHelperBegin(false);
try{ try{
List<T> list = super.list(qWrapper); List<T> list = super.list(qWrapper);
@ -286,7 +287,7 @@ public abstract class CrudServiceImpl<M extends BaseMapper<T>, T extends BaseEnt
* @return T * @return T
*/ */
protected T transformM2T(E model){ protected T transformM2T(E model){
return WrapperUtil.transformInstance(model, entityClazz); return WrapperUtil.transformInstance(model, this.getEntityClass());
} }
/** /**
@ -296,7 +297,7 @@ public abstract class CrudServiceImpl<M extends BaseMapper<T>, T extends BaseEnt
* @return List<T> * @return List<T>
*/ */
protected List<T> transformMs2Ts(List<E> models){ protected List<T> transformMs2Ts(List<E> models){
return WrapperUtil.transformInstance(models, entityClazz); return WrapperUtil.transformInstance(models, this.getEntityClass());
} }
/** /**
@ -342,26 +343,8 @@ public abstract class CrudServiceImpl<M extends BaseMapper<T>, T extends BaseEnt
// ======================== 初始化 ======================== // ======================== 初始化 ========================
/**
*
*/
@PostConstruct
public void init(){
try {
this.modelClazz = this.getInnerModelClazz();
this.entityClazz = this.getInnerEntityClazz();
}catch (Exception e){
log.error(e.getMessage(),e);
}
}
@Override @Override
public Class<T> getEntityClazz() { public Class<E> getModelClass() {
return entityClazz;
}
@Override
public Class<E> getModelClazz() {
return modelClazz; return modelClazz;
} }
@ -371,56 +354,8 @@ public abstract class CrudServiceImpl<M extends BaseMapper<T>, T extends BaseEnt
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public Class<E> getInnerModelClazz(){ public Class<E> getInnerModelClazz(){
String typeName = "E"; Class<?>[] typeArguments = GenericTypeResolver.resolveTypeArguments(this.getClass(), CrudServiceImpl.class);
Class<E> tClass = null; return null == typeArguments ? null : (Class<E>) typeArguments[2];
Map<Type, Type> typeMap = TypeUtil.getTypeMap(this.getClass());
for (Map.Entry<Type, Type> typeTypeEntry : typeMap.entrySet()) {
Type entryKey = typeTypeEntry.getKey();
Type entryValue = typeTypeEntry.getValue();
// 如果等于当前类型名称则进入
if(entryKey != null && entryValue != null){
if(StringUtils.equals(typeName, entryKey.getTypeName())){
// 小技巧 json 转换 obj 然后 转换成 type对象
Object convert = Convert.convert(entryValue, JSONObject.parse(JSON_TMP));
if(convert instanceof ApiWrapper) {
tClass = (Class<E>) entryValue;
break;
}
}
}
}
return tClass;
}
/**
* Entity Clazz
* @return Class<T>
*/
@SuppressWarnings("unchecked")
private Class<T> getInnerEntityClazz(){
String typeName = "T";
Class<T> tClass = null;
Map<Type, Type> typeMap = TypeUtil.getTypeMap(this.getClass());
for (Map.Entry<Type, Type> typeTypeEntry : typeMap.entrySet()) {
Type entryKey = typeTypeEntry.getKey();
Type entryValue = typeTypeEntry.getValue();
// 如果等于当前类型名称则进入
if(entryKey != null && entryValue != null){
if(StringUtils.equals(typeName, entryKey.getTypeName())){
// 小技巧 json 转换 obj 然后 转换成 type对象
Object convert = Convert.convert(entryValue, JSONObject.parse(JSON_TMP));
if(convert instanceof ApiWrapper) {
tClass = (Class<T>) entryValue;
break;
}
}
}
}
return tClass;
} }
} }

@ -44,6 +44,13 @@ import java.util.List;
public interface CrudServiceInterface<T extends BaseEntity, E extends ApiWrapper> extends BaseServiceInterface<T> { public interface CrudServiceInterface<T extends BaseEntity, E extends ApiWrapper> extends BaseServiceInterface<T> {
/**
* Model Class
* @return Class<E>
*/
Class<E> getModelClass();
/** /**
* *
* *
@ -203,18 +210,6 @@ public interface CrudServiceInterface<T extends BaseEntity, E extends ApiWrapper
Page<T,E> findPageNotCount(Page<T,E> page); Page<T,E> findPageNotCount(Page<T,E> page);
/**
* Model Clazz
* @return Class
*/
Class<E> getModelClazz();
/**
* Entity Clazz
* @return Class
*/
Class<T> getEntityClazz();
} }

@ -25,7 +25,9 @@ import com.google.common.util.concurrent.Striped;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.RedisTemplate;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.Lock;
@ -37,6 +39,8 @@ import java.util.function.Function;
* 使 * 使
* *
* Redis String Hash * Redis String Hash
*
* RedisTemplate LRU cache 穿 N
* *
* @author Parker * @author Parker
* @date 2021/12/10 12:39 * @date 2021/12/10 12:39
@ -373,6 +377,10 @@ public final class SecurityCache {
throw new RuntimeException("入参[redisTemplate,key,callbackSource]必填"); throw new RuntimeException("入参[redisTemplate,key,callbackSource]必填");
} }
// 先判断本地缓存是否存在 默认为存在(类似于伪布隆过滤)
if(isNonExist(key)){
return null;
}
// 缓存 Object 对象 // 缓存 Object 对象
Map<String, Object> cache = getAllHashCacheObject(redisTemplate, key, null); Map<String, Object> cache = getAllHashCacheObject(redisTemplate, key, null);
// 如果缓存不为空 则直接返回 // 如果缓存不为空 则直接返回
@ -387,6 +395,11 @@ public final class SecurityCache {
try { try {
// 尝试获得锁 // 尝试获得锁
if(lock.tryLock(DEFAULT_LOCK_TIME, TimeUnit.SECONDS)){ if(lock.tryLock(DEFAULT_LOCK_TIME, TimeUnit.SECONDS)){
// 先判断本地缓存是否存在 默认为存在(类似于伪布隆过滤)
if(isNonExist(key)){
return null;
}
// 梅开二度 如果查到后 直接返回 // 梅开二度 如果查到后 直接返回
cache = getAllHashCacheObject(redisTemplate, key, null); cache = getAllHashCacheObject(redisTemplate, key, null);
// 如果缓存不为空 则直接返回 // 如果缓存不为空 则直接返回
@ -588,48 +601,28 @@ public final class SecurityCache {
/** /**
* *
* @param redisTemplate redisTemplate * @param redisTemplate redisTemplate
* @param keys * @param keys
*/ */
public static boolean removeMore( public static boolean remove(
final RedisTemplate<String, Object> redisTemplate, final RedisTemplate<String, Object> redisTemplate,
final String... keys) { final String... keys) {
if (null == redisTemplate || null == keys) { if (null == redisTemplate || null == keys) {
throw new RuntimeException("入参[redisTemplate,keys]必填");
}
int count = keys.length;
for (String key : keys) {
boolean isRemove = remove(redisTemplate, key);
if(isRemove){
count--;
}
}
return 0 == count;
}
/**
*
* @param redisTemplate redisTemplate
* @param key
*/
public static boolean remove(
final RedisTemplate<String, Object> redisTemplate,
final String key) {
if (null == redisTemplate || null == key) {
throw new RuntimeException("入参[redisTemplate,key]必填"); throw new RuntimeException("入参[redisTemplate,key]必填");
} }
List<String> removeKeyList = new ArrayList<>();
for (String key : keys) {
// 清除本地记录 // 清除本地记录
LFU_NULL_CACHE.invalidate(key); LFU_NULL_CACHE.invalidate(key);
String cacheKeyByKv = StrUtil.addPrefixIfNot(key, CACHE_PREFIX_KV); removeKeyList.add(StrUtil.addPrefixIfNot(key, CACHE_PREFIX_KV));
String cacheKeyByHash = StrUtil.addPrefixIfNot(key, CACHE_PREFIX_HASH); removeKeyList.add(StrUtil.addPrefixIfNot(key, CACHE_PREFIX_HASH));
}
// 清除缓存 // 清除缓存
redisTemplate.delete(cacheKeyByKv); redisTemplate.delete(removeKeyList);
redisTemplate.delete(cacheKeyByHash);
return true; return true;
} }

@ -0,0 +1,43 @@
/**
* Copyright 2020 OPSLI https://www.opsli.com
* <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.eventbus;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
/**
* EventBus Spring
*
* @author Parker
* @date 202112710:39:16
*/
public abstract class AbstractSpringEventBus implements IEventBus, ApplicationContextAware {
private ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.context = applicationContext;
this.scanConsumer(null);
}
@Override
public void scanConsumer(String packageName) {
context.getBeansOfType(IEventConsumer.class).forEach((k,v)->{
this.addConsumer(v);
});
}
}

@ -0,0 +1,48 @@
/**
* Copyright 2020 OPSLI https://www.opsli.com
* <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.eventbus;
/**
* EventBus
*
* @author Parker
* @date 202112710:38:24
*/
public interface IEventBus {
/**
*
* @param event
*/
void post(Object event);
/**
*
* @param obj classkey
*/
void addConsumer(Object obj);
/**
*
* @param obj classkey
*/
void removeConsumer(Object obj);
/**
*
* @param packageName
*/
void scanConsumer(String packageName);
}

@ -1,5 +1,5 @@
/** /**
* Copyright 2018 http://www.renren.io * Copyright 2020 OPSLI https://www.opsli.com
* <p> * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); you may not * 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 * use this file except in compliance with the License. You may obtain a copy of
@ -13,22 +13,20 @@
* License for the specific language governing permissions and limitations under * License for the specific language governing permissions and limitations under
* the License. * the License.
*/ */
package org.opsli.core.eventbus;
package org.opsli.core.security.shiro.utils;
/** /**
* RedisKeys * EventBus
* *
* @author Mark sunlightcs@gmail.com * @author Parker
* @since 3.0.0 2017-07-18 * @date 2020/9/25 12:19
*/ */
public class RedisKeys { public interface IEventConsumer<T> {
public static String getSysConfigKey(String key){ /**
return "system:config:" + key; *
} * @param event
*/
void consumer(T event);
public static String getShiroSessionKey(String key){
return "sessionid:" + key;
}
} }

@ -43,7 +43,7 @@ import static org.opsli.common.constants.OrderConstants.LIMITER_AOP_SORT;
/** /**
* *
* *
* @author * @author Parker
* @date 2020-09-16 * @date 2020-09-16
*/ */
@Slf4j @Slf4j

@ -1,75 +0,0 @@
/**
* Copyright 2020 OPSLI https://www.opsli.com
* <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.filters.aspect;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.TimeInterval;
import lombok.extern.slf4j.Slf4j;
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.core.utils.LogUtil;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
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 LogAop {
@Pointcut("execution(public * org.opsli..*.*Controller*.*(..))")
public void requestMapping() {
}
/**
* post
* @param point point
*/
@Around("requestMapping()")
public Object tokenAop(ProceedingJoinPoint point) throws Throwable {
// 计时器
TimeInterval timer = DateUtil.timer();
// 执行
Exception exception = null;
// 防止线程抛异常 线程变量不回收 导致oom
Object returnValue;
try {
// 执行正常操作
returnValue = point.proceed();
}catch (Exception e){
exception = e;
throw e;
} finally {
// 花费毫秒数
long timerCount = timer.interval();
//保存日志
LogUtil.saveLog(point, exception, timerCount);
}
return returnValue;
}
}

@ -1,190 +0,0 @@
/**
* Copyright 2020 OPSLI https://www.opsli.com
* <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.filters.aspect;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.TypeUtil;
import lombok.extern.slf4j.Slf4j;
import opsli.plugins.crypto.CryptoPlugin;
import opsli.plugins.crypto.enums.CryptoSymmetricType;
import opsli.plugins.crypto.model.CryptoAsymmetric;
import opsli.plugins.crypto.model.CryptoSymmetric;
import opsli.plugins.crypto.strategy.CryptoAsymmetricService;
import opsli.plugins.crypto.strategy.CryptoSymmetricService;
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.aspectj.lang.reflect.MethodSignature;
import org.opsli.api.base.encrypt.BaseEncrypt;
import org.opsli.api.base.result.ResultVo;
import org.opsli.common.annotation.LoginCrypto;
import org.opsli.common.exception.ServiceException;
import org.opsli.core.msg.CoreMsg;
import org.opsli.core.options.CryptoConfigFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Map;
import static org.opsli.common.constants.OrderConstants.ENCRYPT_ADN_DECRYPT_AOP_SORT;
/**
*
*
* @author parker
* @date 2021-01-23
*/
@Slf4j
@Order(ENCRYPT_ADN_DECRYPT_AOP_SORT)
@Aspect
@Component
public class LoginCryptoAop {
@Pointcut("@annotation(org.opsli.common.annotation.LoginCrypto)")
public void encryptAndDecrypt() {
}
/**
* post
* @param point point
*/
@Around("encryptAndDecrypt()")
public Object encryptAndDecryptHandle(ProceedingJoinPoint point) throws Throwable {
// 获得请求参数
Object[] args = point.getArgs();
// 返回结果
Object returnValue;
MethodSignature signature = (MethodSignature) point.getSignature();
// 获得 方法
Method method = signature.getMethod();
// 获得方法注解
LoginCrypto annotation =
method.getAnnotation(LoginCrypto.class);
// 获得非对称加解密 执行器
CryptoAsymmetricService asymmetric = null;
// 非对称加解密模型
CryptoAsymmetric cryptoAsymmetric = null;
if(annotation != null && annotation.enable()){
asymmetric = CryptoPlugin.getAsymmetric();
cryptoAsymmetric = CryptoConfigFactory.INSTANCE.getCryptoAsymmetric();
}
// 1. 请求解密
if(annotation != null && annotation.enable()){
if(cryptoAsymmetric != null){
enterDecrypt(args, method, asymmetric, cryptoAsymmetric);
}
}
// 2. 执行方法
returnValue = point.proceed(args);
// 3. 返回加密 返回加密为对称加密
if(annotation != null && annotation.enable()){
if(cryptoAsymmetric != null){
CryptoSymmetricService symmetric = CryptoPlugin.getSymmetric();
CryptoSymmetric symmetricModel = symmetric.createNilModel();
symmetricModel.setCryptoType(CryptoSymmetricType.DES);
symmetricModel.setPrivateKey(cryptoAsymmetric.getPublicKey());
// 执行加密操作
returnValue = resultEncrypt(returnValue, symmetric, symmetricModel);
}
}
return returnValue;
}
/**
*
* @param args
* @param method
* @param asymmetric
* @param cryptoModel
*/
private void enterDecrypt(Object[] args, Method method, CryptoAsymmetricService asymmetric, CryptoAsymmetric cryptoModel) {
for (int i = 0; i < args.length; i++) {
Object arg = args[i];
// 参数校验
if(arg instanceof BaseEncrypt){
// 获得加密数据
BaseEncrypt baseEncrypt = (BaseEncrypt) arg;
String encryptData = baseEncrypt.getEncryptData();
// 解密对象
Object dataToObj = asymmetric.decryptToObj(cryptoModel, encryptData);
// 根据方法类型转化对象
Type type = TypeUtil.getParamType(method, i);
Object obj = Convert.convert(type, dataToObj);
// 修改缓存中设备数据 空值不覆盖
Map<String, Object> modelBeanMap = BeanUtil.beanToMap(obj);
modelBeanMap.entrySet().removeIf(entry -> entry.getValue() == null);
// 反射赋值
Field[] fields = ReflectUtil.getFields(arg.getClass());
for (Field f : fields) {
Object val = modelBeanMap.get(f.getName());
if(val == null){
continue;
}
//根据需要,将相关属性赋上默认值
BeanUtil.setProperty(arg, f.getName(), val);
}
}
}
}
/**
*
* @param returnValue
* @param symmetric
* @param cryptoModel
* @return Object
*/
@SuppressWarnings("unchecked")
private Object resultEncrypt(Object returnValue, CryptoSymmetricService symmetric, CryptoSymmetric cryptoModel) {
if(returnValue != null){
try {
// 执行加密过程
if(returnValue instanceof ResultVo){
// 重新赋值 data
ResultVo<Object> ret = (ResultVo<Object>) returnValue;
ret.setData(
symmetric.encrypt(cryptoModel, ret.getData())
);
}else {
returnValue = symmetric.encrypt(cryptoModel, returnValue);
}
}catch (Exception e){
// 非对称加密失败
throw new ServiceException(CoreMsg.OTHER_EXCEPTION_CRYPTO_EN);
}
}
return returnValue;
}
}

@ -38,7 +38,7 @@ import static org.opsli.common.constants.OrderConstants.SEARCH_HIS_AOP_SORT;
/** /**
* AOP * AOP
* *
* @author * @author Parker
* @date 2020-09-16 * @date 2020-09-16
*/ */
@Slf4j @Slf4j

@ -27,7 +27,7 @@ import javax.servlet.http.HttpServletResponse;
/** /**
* , jwt token * , jwt token
* *
* @author * @author Parker
* @date 2021122216:35:20 * @date 2021122216:35:20
*/ */
@Slf4j @Slf4j

@ -18,14 +18,9 @@ package org.opsli.core.handler;
import cn.hutool.core.text.StrFormatter; import cn.hutool.core.text.StrFormatter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.IncorrectCredentialsException; import org.opsli.api.base.result.ResultWrapper;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.pam.UnsupportedTokenException;
import org.apache.shiro.authz.AuthorizationException;
import org.opsli.api.base.result.ResultVo;
import org.opsli.common.exception.*; import org.opsli.common.exception.*;
import org.opsli.core.msg.CoreMsg; import org.opsli.core.msg.CoreMsg;
import org.opsli.core.msg.TokenMsg;
import org.springframework.core.annotation.Order; import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
@ -86,9 +81,9 @@ public class GlobalExceptionHandler {
@ExceptionHandler(ServiceException.class) @ExceptionHandler(ServiceException.class)
@ResponseStatus(HttpStatus.OK) @ResponseStatus(HttpStatus.OK)
@ResponseBody @ResponseBody
public ResultVo<?> businessException(ServiceException e) { public ResultWrapper<?> businessException(ServiceException e) {
log.warn("业务异常 - 异常编号:{} - 异常信息:{}",e.getCode(),e.getMessage()); log.warn("业务异常 - 异常编号:{} - 异常信息:{}",e.getCode(),e.getMessage());
return ResultVo.error(e.getCode(), e.getMessage()); return ResultWrapper.getCustomResultWrapper(e.getCode(), e.getMessage());
} }
/** /**
@ -97,8 +92,8 @@ public class GlobalExceptionHandler {
@ExceptionHandler(EmptyException.class) @ExceptionHandler(EmptyException.class)
@ResponseStatus(HttpStatus.OK) @ResponseStatus(HttpStatus.OK)
@ResponseBody @ResponseBody
public ResultVo<?> emptyException(EmptyException e) { public ResultWrapper<?> emptyException(EmptyException e) {
return ResultVo.error(e.getCode(), e.getMessage()); return ResultWrapper.getCustomResultWrapper(e.getCode(), e.getMessage());
} }
/** /**
@ -107,68 +102,19 @@ public class GlobalExceptionHandler {
@ExceptionHandler(JwtException.class) @ExceptionHandler(JwtException.class)
@ResponseStatus(HttpStatus.OK) @ResponseStatus(HttpStatus.OK)
@ResponseBody @ResponseBody
public ResultVo<?> jwtException(JwtException e) { public ResultWrapper<?> jwtException(JwtException e) {
return ResultVo.error(e.getCode(), e.getMessage()); return ResultWrapper.getCustomResultWrapper(e.getCode(), e.getMessage());
} }
/**
* Shiro
*/
@ExceptionHandler(IncorrectCredentialsException.class)
@ResponseStatus(HttpStatus.UNAUTHORIZED)
@ResponseBody
public ResultVo<?> incorrectCredentialsException(IncorrectCredentialsException e) {
// token失效请重新登录
return ResultVo.error(e.getMessage());
}
/**
* Shiro
*/
@ExceptionHandler(LockedAccountException.class)
@ResponseStatus(HttpStatus.OK)
@ResponseBody
public ResultVo<?> lockedAccountException(LockedAccountException e) {
// 账号已被锁定,请联系管理员
return ResultVo.error(e.getMessage());
}
/**
* Shiro
*/
@ExceptionHandler(AuthorizationException.class)
@ResponseStatus(HttpStatus.OK)
@ResponseBody
public ResultVo<?> authorizationException(AuthorizationException e) {
// 无权访问该方法
return ResultVo.error(TokenMsg.EXCEPTION_NOT_AUTH.getCode(),
TokenMsg.EXCEPTION_NOT_AUTH.getMessage()
);
}
/**
* Shiro
*/
@ExceptionHandler(UnsupportedTokenException.class)
@ResponseStatus(HttpStatus.OK)
@ResponseBody
public ResultVo<?> unsupportedTokenException(UnsupportedTokenException e) {
// 找不到认证授权器
return ResultVo.error(TokenMsg.EXCEPTION_NOT_REALM.getCode(),
TokenMsg.EXCEPTION_NOT_REALM.getMessage()
);
}
/** /**
* Token * Token
*/ */
@ExceptionHandler(TokenException.class) @ExceptionHandler(TokenException.class)
@ResponseStatus(HttpStatus.OK) @ResponseStatus(HttpStatus.OK)
@ResponseBody @ResponseBody
public ResultVo<?> tokenException(TokenException e) { public ResultWrapper<?> tokenException(TokenException e) {
// Token 异常 // Token 异常
return ResultVo.error(e.getCode(), e.getMessage()); return ResultWrapper.getCustomResultWrapper(e.getCode(), e.getMessage());
} }
/** /**
@ -177,8 +123,8 @@ public class GlobalExceptionHandler {
@ExceptionHandler(WafException.class) @ExceptionHandler(WafException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST) @ResponseStatus(HttpStatus.BAD_REQUEST)
@ResponseBody @ResponseBody
public ResultVo<?> wafException(WafException e) { public ResultWrapper<?> wafException(WafException e) {
return ResultVo.error(e.getCode(), e.getMessage()); return ResultWrapper.getCustomResultWrapper(e.getCode(), e.getMessage());
} }
// ============================ // ============================
@ -189,9 +135,9 @@ public class GlobalExceptionHandler {
@ExceptionHandler(NullPointerException.class) @ExceptionHandler(NullPointerException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ResponseBody @ResponseBody
public ResultVo<?> nullPointerException(NullPointerException e) { public ResultWrapper<?> nullPointerException(NullPointerException e) {
log.error("空指针异常:{}",e.getMessage(),e); log.error("空指针异常:{}",e.getMessage(),e);
return ResultVo.error(e.getMessage()); return ResultWrapper.getErrorResultWrapper();
} }
@ -201,9 +147,9 @@ public class GlobalExceptionHandler {
@ExceptionHandler(SQLIntegrityConstraintViolationException.class) @ExceptionHandler(SQLIntegrityConstraintViolationException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ResponseBody @ResponseBody
public ResultVo<?> sqlIntegrityConstraintViolationException(EmptyException e) { public ResultWrapper<?> sqlIntegrityConstraintViolationException(EmptyException e) {
log.error("数据异常:{}",e.getMessage(),e); log.error("数据异常:{}",e.getMessage(),e);
return ResultVo.error(e.getCode(), CoreMsg.SQL_EXCEPTION_INTEGRITY_CONSTRAINT_VIOLATION.getMessage()); return ResultWrapper.getCustomResultWrapper(e.getCode(), CoreMsg.SQL_EXCEPTION_INTEGRITY_CONSTRAINT_VIOLATION.getMessage());
} }
/** /**
@ -212,17 +158,17 @@ public class GlobalExceptionHandler {
@ExceptionHandler(SQLException.class) @ExceptionHandler(SQLException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ResponseBody @ResponseBody
public ResultVo<?> sqlException(SQLException e) { public ResultWrapper<?> sqlException(SQLException e) {
//log.error("数据异常:{}",e.getMessage(),e); //log.error("数据异常:{}",e.getMessage(),e);
// 默认值异常 // 默认值异常
if(StringUtils.contains(e.getMessage(),SQL_EXCEPTION)){ if(StringUtils.contains(e.getMessage(),SQL_EXCEPTION)){
String field = e.getMessage().replaceAll("Field '","") String field = e.getMessage().replaceAll("Field '","")
.replaceAll("' doesn't have a default value",""); .replaceAll("' doesn't have a default value","");
String msg = StrFormatter.format(CoreMsg.SQL_EXCEPTION_NOT_HAVE_DEFAULT_VALUE.getMessage(), field); String msg = StrFormatter.format(CoreMsg.SQL_EXCEPTION_NOT_HAVE_DEFAULT_VALUE.getMessage(), field);
return ResultVo.error(CoreMsg.SQL_EXCEPTION_NOT_HAVE_DEFAULT_VALUE.getCode(), msg); return ResultWrapper.getCustomResultWrapper(CoreMsg.SQL_EXCEPTION_NOT_HAVE_DEFAULT_VALUE.getCode(), msg);
} }
String msg = StrFormatter.format(CoreMsg.SQL_EXCEPTION_UNKNOWN.getMessage(), e.getMessage()); String msg = StrFormatter.format(CoreMsg.SQL_EXCEPTION_UNKNOWN.getMessage(), e.getMessage());
return ResultVo.error(CoreMsg.SQL_EXCEPTION_UNKNOWN.getCode(), msg); return ResultWrapper.getCustomResultWrapper(CoreMsg.SQL_EXCEPTION_UNKNOWN.getCode(), msg);
} }
} }

@ -28,7 +28,7 @@ import java.util.Optional;
/** /**
* *
* *
* @author * @author Parker
* @date 2021122216:22:59 * @date 2021122216:22:59
*/ */
public final class UserContextHolder { public final class UserContextHolder {

@ -0,0 +1,84 @@
/**
* Copyright 2020 OPSLI https://www.opsli.com
* <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.log.annotation;
import org.opsli.core.log.enums.*;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
*
*
* @author Parker
* @date 202171520:28:24
*/
@Target({ElementType.METHOD}) //注解作用于方法级别
@Retention(RetentionPolicy.RUNTIME) //运行时起作用
public @interface OperateLogger {
/**
*
*/
boolean loggable() default true;
/**
*
* 使: ${tel}
*/
String description() default "";
/**
*
*/
ModuleEnum module() default ModuleEnum.MODULE_COMMON;
/**
* (enum): select,insert,update,delete
*/
OperationTypeEnum operationType() default OperationTypeEnum.UNKNOWN;
/**
*
*/
LogTypeEnum type() default LogTypeEnum.BACKEND;
/**
*
*/
LogLevelEnum level() default LogLevelEnum.INFO;
/**
* ,
* ALL-, BEFORE-, AFTER-
*/
LogScopeEnum scope() default LogScopeEnum.ALL;
/**
*
*/
boolean db() default false;
/**
*
*/
boolean console() default true;
}

@ -0,0 +1,220 @@
/**
* Copyright 2020 OPSLI https://www.opsli.com
* <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.log.aspect;
import cn.hutool.json.JSONUtil;
import com.google.common.collect.Maps;
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.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.opsli.common.utils.MessUtil;
import org.opsli.core.base.dto.LoginUserDto;
import org.opsli.core.holder.UserContextHolder;
import org.opsli.core.log.annotation.OperateLogger;
import org.opsli.core.log.bean.OperationLog;
import org.opsli.core.log.bus.OperationLogEventBus;
import org.opsli.core.log.enums.LogLevelEnum;
import org.opsli.core.log.enums.LogScopeEnum;
import org.opsli.core.utils.UserTokenUtil;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
/**
*
*
* @author Parker
* @date 202171520:28:24
*/
@Slf4j
@Aspect
@Component
@Order(50)
public class OperateLogAspect {
/** 替换条件 */
private static final String RE = "\\$\\{([\\w\\.\\-\\/\\+\\$\\#\\@\\!\\^\\&\\(\\)]+)\\}";
@Resource
private OperationLogEventBus operationLogEventBus;
@Pointcut("@annotation(org.opsli.core.log.annotation.OperateLogger)")
public void operationLog(){}
/**
* MethodInterceptor
*/
@Around("operationLog()")
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
Object result = null;
long time = System.currentTimeMillis();
try {
result = joinPoint.proceed();
return result;
} finally {
time = System.currentTimeMillis() - time;
try {
// 方法执行完成后增加日志
addOperationLog(joinPoint, result, time);
}catch (Exception e){
log.error("LogAspect 操作失败:{}" + e.getMessage());
e.printStackTrace();
}
}
}
/**
*
* @param joinPoint point
* @param result
* @param time
*/
private void addOperationLog(JoinPoint joinPoint, Object result, long time){
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
OperateLogger annotation = signature.getMethod()
.getAnnotation(OperateLogger.class);
if(annotation == null || !annotation.loggable()){
return;
}
OperationLog operationLog = new OperationLog();
// 参数
String argsStr = null;
try {
argsStr = JSONUtil.toJsonStr(joinPoint.getArgs());
}catch (Exception ignored){}
// 结果
String resultStr = null;
try {
resultStr = JSONUtil.toJsonStr(result);
}catch (Exception ignored){}
if(LogScopeEnum.REQUEST.equals(annotation.scope())){
operationLog.setArgs(argsStr);
} else if(LogScopeEnum.RESPONSE.equals(annotation.scope())){
operationLog.setReturnValue(resultStr);
} else if(LogScopeEnum.ALL.equals(annotation.scope())){
operationLog.setArgs(argsStr);
operationLog.setReturnValue(resultStr);
}
operationLog.setId(UUID.randomUUID().toString());
operationLog.setRunTime(time);
operationLog.setCreateTime(System.currentTimeMillis());
operationLog.setMethod(signature.getDeclaringTypeName() + "." + signature.getName());
operationLog.setLevel(annotation.level().getValue());
operationLog.setDescription(
// 对当前登录用户和占位符处理
getDetail(
((MethodSignature) joinPoint.getSignature()).getParameterNames(),
joinPoint.getArgs(),
annotation)
);
operationLog.setOperationType(annotation.operationType().getValue());
operationLog.setLogType(annotation.type().getValue());
operationLog.setModuleId(annotation.module().getId());
// 当前Token
Optional<String> tokenOptional = UserContextHolder.getToken();
if(tokenOptional.isPresent()){
LoginUserDto loginUserDto = UserTokenUtil.getLoginUserDto(tokenOptional.get()).orElse(null);
if(null != loginUserDto){
operationLog.setUserId(String.valueOf(loginUserDto.getUid()));
operationLog.setUsername(loginUserDto.getUsername());
operationLog.setRealName(loginUserDto.getNickname());
operationLog.setTenantId(loginUserDto.getTenantId());
}
}
// 输出控制台
if(annotation.console()){
printToConsole(annotation.level(), operationLog);
}
// 存入数据库
if(annotation.db()){
operationLogEventBus.post(operationLog);
}
}
/**
*
* @param level
* @param operationLog
*/
private void printToConsole(LogLevelEnum level, OperationLog operationLog){
switch (level){
case INFO:
log.info("记录日志:{}" , operationLog);
break;
case DEBUG:
log.debug("记录日志:{}" , operationLog);
break;
case WARN:
log.warn("记录日志:{}" , operationLog);
break;
case ERROR:
log.error("记录日志:{}" , operationLog);
break;
case TRACE:
log.trace("记录日志:{}" , operationLog);
break;
default:
break;
}
}
/**
*
* @param argNames
* @param args
* @param annotation
* @return
*/
private String getDetail(String[] argNames, Object[] args, OperateLogger annotation){
Map<String, Object> map = Maps.newHashMap();
for(int i = 0;i < argNames.length;i++){
map.put(argNames[i], args[i]);
}
String description = annotation.description();
try {
// 当前用户信息
Optional<String> tokenOptional = UserContextHolder.getToken();
if(tokenOptional.isPresent()){
LoginUserDto loginUserDto = UserTokenUtil.getLoginUserDto(tokenOptional.get()).orElse(null);
if(null != loginUserDto){
description = "'" + loginUserDto.getNickname() + "'=> " + annotation.description();
}
}
description = MessUtil.getMes(description, RE, "${", "}", map);
}catch (Exception e){
e.printStackTrace();
}
return description;
}
}

@ -0,0 +1,82 @@
/**
* Copyright 2020 OPSLI https://www.opsli.com
* <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.log.bean;
import lombok.Data;
import lombok.ToString;
import java.io.Serializable;
/**
*
*
* @author Parker
* @date 202171520:28:24
*/
@Data
@ToString
public class OperationLog implements Serializable {
private static final long serialVersionUID = 1L;
/** 日志ID */
private String id;
/** 创建时间 */
private long createTime;
/** 日志等级 */
private String level;
/** 被操作的系统模块 */
private String moduleId;
/** 方法名 */
private String method;
/** 参数 */
private String args;
/** 操作人id */
private String userId;
/** 操作人用户名 */
private String username;
/** 真实姓名 */
private String realName;
/** 日志描述 */
private String description;
/** 操作类型 */
private String operationType;
/** 方法运行时间 */
private Long runTime;
/** 方法返回值 */
private String returnValue;
/** 租户ID */
private String tenantId;
/**
*
*/
private String logType;
}

@ -0,0 +1,72 @@
/**
* Copyright 2020 OPSLI https://www.opsli.com
* <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.log.bus;
import com.google.common.eventbus.AsyncEventBus;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.SubscriberExceptionContext;
import com.google.common.eventbus.SubscriberExceptionHandler;
import lombok.extern.slf4j.Slf4j;
import org.opsli.common.thread.ThreadPoolFactory;
import org.opsli.core.eventbus.AbstractSpringEventBus;
import org.springframework.stereotype.Component;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* 线
* @author
* @date 202112710:42:39
*/
@Component
@Slf4j
public class OperationLogEventBus extends AbstractSpringEventBus implements SubscriberExceptionHandler {
private final EventBus eventBus;
public OperationLogEventBus() {
// 异步事件配置线程池
eventBus = new AsyncEventBus(
ThreadPoolFactory.createInitThreadPool(5, 10, 60, TimeUnit.SECONDS,
1024, "Operation-Log-Event-Bus",
new ThreadPoolExecutor.CallerRunsPolicy()
)
, this
);
}
@Override
public void post(Object event) {
eventBus.post(event);
}
@Override
public void addConsumer(Object obj) {
eventBus.register(obj);
}
@Override
public void removeConsumer(Object obj) {
eventBus.unregister(obj);
}
@Override
public void handleException(Throwable exception, SubscriberExceptionContext context) {
log.error("user event handler exception", exception);
}
}

@ -13,23 +13,29 @@
* License for the specific language governing permissions and limitations under * License for the specific language governing permissions and limitations under
* the License. * the License.
*/ */
package org.opsli.common.annotation; package org.opsli.core.log.enums;
import java.lang.annotation.ElementType; import lombok.AllArgsConstructor;
import java.lang.annotation.Retention; import lombok.Getter;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/** /**
* *
* *
* @author Parker * @author Parker
* @date 2020-09-22 17:07 * @date 202171520:28:24
*/ */
@Target({ElementType.TYPE, ElementType.METHOD}) @Getter
@Retention(RetentionPolicy.RUNTIME) @AllArgsConstructor
public @interface RequiresPermissionsCus { public enum LogLevelEnum {
String[] value(); /**
*
*/
DEBUG("-1"),
INFO("0"),
WARN("1"),
ERROR("2"),
TRACE("3");
private final String value;
} }

@ -13,25 +13,31 @@
* License for the specific language governing permissions and limitations under * License for the specific language governing permissions and limitations under
* the License. * the License.
*/ */
package org.opsli.common.annotation; package org.opsli.core.log.enums;
import java.lang.annotation.*;
/** /**
* *
*
*
* *
* @author Parker * @author Parker
* @date 202151814:46:02 * @date 202171520:28:24
*/
public enum LogScopeEnum {
/**
*
*/ */
@Target(ElementType.METHOD) ALL(0),
@Retention(RetentionPolicy.RUNTIME) REQUEST(1),
@Documented RESPONSE(2)
public @interface LoginCrypto { ;
private final int value;
/** 加密启用状态 */ public int getValue() {
boolean enable() default true; return value;
}
LogScopeEnum(int value) {
this.value = value;
}
} }

@ -13,25 +13,36 @@
* License for the specific language governing permissions and limitations under * License for the specific language governing permissions and limitations under
* the License. * the License.
*/ */
package org.opsli.common.annotation; package org.opsli.core.log.enums;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/** /**
* *
* @author parker *
* @date 2020-09-12 * @author Parker
* @date 202171520:28:24
*/ */
@Target(ElementType.METHOD) public enum LogTypeEnum {
@Retention(RetentionPolicy.RUNTIME)
@Documented /** WEB */
public @interface EnableLog { WEB("0"),
/** 客户端 */
CLIENT("1"),
/** 后端 */
BACKEND("2"),
/** 标题 */ /** 程序自动 */
String title() default ""; AUTO("3")
;
private final String value;
public String getValue() {
return value;
}
LogTypeEnum(String value) {
this.value = value;
}
} }

@ -0,0 +1,66 @@
/**
* Copyright 2020 OPSLI https://www.opsli.com
* <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.log.enums;
/**
*
*
* @author Parker
* @date 202171520:19:27
*/
public enum ModuleEnum {
/** 模块 */
MODULE_UNKNOWN("-1", "未知(请配置模块)"),
MODULE_COMMON("00", "公共模块"),
MODULE_USER("01", "用户模块"),
MODULE_ROLE("02", "角色模块"),
MODULE_MENU("03", "菜单模块"),
MODULE_ORG("04", "组织模块"),
MODULE_DICT("05", "字典模块"),
MODULE_TENANT("06", "租户模块"),
MODULE_AREA("07", "地区模块"),
MODULE_MONITOR("08", "监控模块"),
MODULE_GENERATOR("09", "代码生成器"),
MODULE_OPERATION("11", "行为日志"),
MODULE_TEST("100", "测试模块"),
MODULE_TEST_USER("101", "测试用户模块"),
MODULE_TEST_CAR("102", "测试汽车模块"),
;
private final String id;
private final String name;
ModuleEnum(String id, String name) {
this.id = id;
this.name = name;
}
public String getId() {
return id;
}
public String getName() {
return name;
}
}

@ -0,0 +1,48 @@
/**
* Copyright 2020 OPSLI https://www.opsli.com
* <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.log.enums;
/**
*
*
* @author Parker
* @date 202171520:27:27
*/
public enum OperationTypeEnum {
/**
*
*/
UNKNOWN("unknown"),
DELETE("delete"),
SELECT("select"),
UPDATE("update"),
INSERT("insert");
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
OperationTypeEnum(String s) {
this.value = s;
}
}

@ -30,14 +30,20 @@ public enum TokenMsg implements BaseMsg {
*/ */
EXCEPTION_TOKEN_CREATE_ERROR(12000,"生成Token失败"), EXCEPTION_TOKEN_CREATE_ERROR(12000,"生成Token失败"),
EXCEPTION_TOKEN_CREATE_LIMIT_ERROR(12001,"您的账号已在其他设备登录"), EXCEPTION_TOKEN_CREATE_LIMIT_ERROR(12001,"您的账号已在其他设备登录"),
EXCEPTION_TOKEN_LOSE_EFFICACY(401,"Token失效请重新登录"), EXCEPTION_TOKEN_LOSE_EFFICACY(401,"凭证已过期,请重新登陆"),
AUTH_CREDENTIALS_INVALID(100208, "凭证已过期,请重新登陆"),
AUTH_AUTH_INVALID(100209, "认证失败,请重新登陆"),
/** /**
* *
*/ */
EXCEPTION_CAPTCHA_CERTIFICATE_ERROR(12097, "凭证验证失败,请刷新重试"),
EXCEPTION_CAPTCHA_ARGS_NULL(12098, "参数异常"),
EXCEPTION_CAPTCHA_OFTEN(12099, "已获取验证码,请勿频繁获取"),
EXCEPTION_CAPTCHA_ERROR(12100,"验证码不正确!"), EXCEPTION_CAPTCHA_ERROR(12100,"验证码不正确!"),
EXCEPTION_CAPTCHA_NULL(12201, "验证码已失效"), EXCEPTION_CAPTCHA_NULL(12201, "验证码已失效, 请重新生成"),
EXCEPTION_CAPTCHA_UUID_NULL(12202, "验证码UUID为空"), EXCEPTION_CAPTCHA_UUID_NULL(12202, "验证码UUID为空"),
EXCEPTION_CAPTCHA_CODE_NULL(12203, "验证码为空"), EXCEPTION_CAPTCHA_CODE_NULL(12203, "验证码为空"),
EXCEPTION_LOGIN_ACCOUNT_NO(12101,"账号或密码不正确!"), EXCEPTION_LOGIN_ACCOUNT_NO(12101,"账号或密码不正确!"),

@ -0,0 +1,81 @@
/**
* Copyright 2020 OPSLI https://www.opsli.com
* <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.filter;
import lombok.AllArgsConstructor;
import org.opsli.core.base.dto.LoginUserDto;
import org.opsli.core.security.service.UidUserDetailDetailServiceImpl;
import org.opsli.core.utils.UserTokenUtil;
import org.opsli.plugins.security.authentication.AfterAuthenticationToken;
import org.opsli.plugins.security.exception.AuthException;
import org.opsli.plugins.security.exception.errorcode.AuthErrorCodeEnum;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* JWT
* filter Spring
* @author Parker
* @date 2022072216:16:42
*/
@AllArgsConstructor
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
private final UidUserDetailDetailServiceImpl uidUserDetailDetailService;
@Override
protected void doFilterInternal(
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
// 获取token
String token = UserTokenUtil.getRequestToken(request);
if (!StringUtils.hasText(token)) {
//放行
filterChain.doFilter(request, response);
return;
}
// 验证Token
UserTokenUtil.verify(token);
// 获得登陆用户信息
LoginUserDto loginUserDto = UserTokenUtil.getLoginUserDto(token)
// 认证无效
.orElseThrow(() -> new AuthException(AuthErrorCodeEnum.AUTH_AUTH_INVALID));
// 这里用Uid 获取用户信息,因为涉及到超管切换租户身份
// 非 租户系统 可以直接使用 用户名获取信息
UserDetails userDetails = uidUserDetailDetailService.loadUserByPrincipal(loginUserDto.getUid())
// 认证无效
.orElseThrow(() -> new AuthException(AuthErrorCodeEnum.AUTH_AUTH_INVALID));
AfterAuthenticationToken authenticationToken =
new AfterAuthenticationToken(userDetails, null, userDetails.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
//放行
filterChain.doFilter(request, response);
}
}

@ -0,0 +1,108 @@
/**
* Copyright 2020 OPSLI https://www.opsli.com
* <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.service;
import cn.hutool.core.util.StrUtil;
import lombok.AllArgsConstructor;
import org.opsli.api.wrapper.system.user.UserModel;
import org.opsli.common.enums.DictType;
import org.opsli.core.utils.UserUtil;
import org.opsli.plugins.security.UserDetailModel;
import org.opsli.plugins.security.authentication.EmailCodeAuthenticationToken;
import org.opsli.plugins.security.authentication.EmailPasswordAuthenticationToken;
import org.opsli.plugins.security.properties.AuthProperties;
import org.opsli.plugins.security.service.ILoadUserDetailService;
import org.opsli.plugins.security.utils.PasswordUtil;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.util.*;
import java.util.stream.Collectors;
/**
* + Service
*
*
* @author Parker
* @date 2022-07-14 4:44 PM
**/
@AllArgsConstructor
@Service
public class EmailUserDetailDetailServiceImpl implements ILoadUserDetailService {
private static final String DEFAULT_ROLE_PREFIX = "ROLE_";
private final AuthProperties authProperties;
@Override
public Collection<Class<? extends Authentication>> getClassTypes() {
List<Class<? extends Authentication>> classes = new ArrayList<>();
classes.add(EmailCodeAuthenticationToken.class);
classes.add(EmailPasswordAuthenticationToken.class);
return classes;
}
@Override
public Optional<UserDetails> loadUserByPrincipal(Object principal) {
UserModel userModel = UserUtil.getUserByEmail((String) principal);
if(null == userModel){
return Optional.empty();
}
// 处理权限数据
List<String> authorities = new ArrayList<>();
List<String> userRoles = UserUtil.getUserRolesByUserId(userModel.getId());
List<String> userAllPerms = UserUtil.getUserAllPermsByUserId(userModel.getId());
for (String userRole : userRoles) {
authorities.add(DEFAULT_ROLE_PREFIX+userRole);
}
authorities.addAll(userAllPerms);
// 清除空的 授权
authorities.removeIf(StrUtil::isEmpty);
List<GrantedAuthority> grantedAuthorities = authorities.stream()
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toList());
UserDetailModel userDetailModel = UserDetailModel.builder()
.username(userModel.getUsername())
.password(userModel.getPassword())
// 账户启动
.enabled(
DictType.NO_YES_YES.getValue().equals(userModel.getEnable()))
// 账户未过期(如果需要 请自行扩展字段)
.accountNonExpired(
DictType.NO_YES_YES.getValue().equals(userModel.getEnable()))
// 账户未锁定(如果需要 请自行扩展字段)
.accountNonLocked(
DictType.NO_YES_YES.getValue().equals(userModel.getEnable()))
// 判断凭证是否过期(默认不判断 如果需要 请自行扩展过期后修改密码操作)
.credentialsNonExpired(
PasswordUtil.isCredentialsNonExpired(
userModel.getPassword(), authProperties.getCredentialsExpired()))
// 授权信息
.authorities(grantedAuthorities)
.build();
return Optional.ofNullable(userDetailModel);
}
}

@ -0,0 +1,110 @@
/**
* Copyright 2020 OPSLI https://www.opsli.com
* <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.service;
import cn.hutool.core.util.StrUtil;
import lombok.AllArgsConstructor;
import org.opsli.api.wrapper.system.user.UserModel;
import org.opsli.common.enums.DictType;
import org.opsli.core.utils.UserUtil;
import org.opsli.plugins.security.UserDetailModel;
import org.opsli.plugins.security.authentication.MobileCodeAuthenticationToken;
import org.opsli.plugins.security.authentication.MobilePasswordAuthenticationToken;
import org.opsli.plugins.security.properties.AuthProperties;
import org.opsli.plugins.security.service.ILoadUserDetailService;
import org.opsli.plugins.security.utils.PasswordUtil;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
/**
* + Service
*
*
* @author Parker
* @date 2022-07-14 4:44 PM
**/
@AllArgsConstructor
@Service
public class MobileUserDetailDetailServiceImpl implements ILoadUserDetailService {
private static final String DEFAULT_ROLE_PREFIX = "ROLE_";
private final AuthProperties authProperties;
@Override
public Collection<Class<? extends Authentication>> getClassTypes() {
List<Class<? extends Authentication>> classes = new ArrayList<>();
classes.add(MobileCodeAuthenticationToken.class);
classes.add(MobilePasswordAuthenticationToken.class);
return classes;
}
@Override
public Optional<UserDetails> loadUserByPrincipal(Object principal) {
UserModel userModel = UserUtil.getUserByMobile((String) principal);
if(null == userModel){
return Optional.empty();
}
// 处理权限数据
List<String> authorities = new ArrayList<>();
List<String> userRoles = UserUtil.getUserRolesByUserId(userModel.getId());
List<String> userAllPerms = UserUtil.getUserAllPermsByUserId(userModel.getId());
for (String userRole : userRoles) {
authorities.add(DEFAULT_ROLE_PREFIX+userRole);
}
authorities.addAll(userAllPerms);
// 清除空的 授权
authorities.removeIf(StrUtil::isEmpty);
List<GrantedAuthority> grantedAuthorities = authorities.stream()
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toList());
UserDetailModel userDetailModel = UserDetailModel.builder()
.username(userModel.getUsername())
.password(userModel.getPassword())
// 账户启动
.enabled(
DictType.NO_YES_YES.getValue().equals(userModel.getEnable()))
// 账户未过期(如果需要 请自行扩展字段)
.accountNonExpired(
DictType.NO_YES_YES.getValue().equals(userModel.getEnable()))
// 账户未锁定(如果需要 请自行扩展字段)
.accountNonLocked(
DictType.NO_YES_YES.getValue().equals(userModel.getEnable()))
// 判断凭证是否过期(默认不判断 如果需要 请自行扩展过期后修改密码操作)
.credentialsNonExpired(
PasswordUtil.isCredentialsNonExpired(
userModel.getPassword(), authProperties.getCredentialsExpired()))
// 授权信息
.authorities(grantedAuthorities)
.build();
return Optional.ofNullable(userDetailModel);
}
}

@ -0,0 +1,102 @@
/**
* Copyright 2020 OPSLI https://www.opsli.com
* <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.service;
import cn.hutool.core.util.StrUtil;
import lombok.AllArgsConstructor;
import org.opsli.api.wrapper.system.user.UserModel;
import org.opsli.common.enums.DictType;
import org.opsli.core.utils.UserUtil;
import org.opsli.plugins.security.UserDetailModel;
import org.opsli.plugins.security.properties.AuthProperties;
import org.opsli.plugins.security.service.ILoadUserDetailService;
import org.opsli.plugins.security.utils.PasswordUtil;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.stream.Collectors;
/**
* ID Service
*
* @author Parker
* @date 2022-07-14 4:44 PM
**/
@AllArgsConstructor
@Service("uidUserDetailDetailService")
public class UidUserDetailDetailServiceImpl implements ILoadUserDetailService {
private static final String DEFAULT_ROLE_PREFIX = "ROLE_";
private final AuthProperties authProperties;
@Override
public Collection<Class<? extends Authentication>> getClassTypes() {
// 为空则不会进入 Token 工厂内
return null;
}
@Override
public Optional<UserDetails> loadUserByPrincipal(Object principal) {
UserModel userModel = UserUtil.getUser((String) principal);
if(null == userModel){
return Optional.empty();
}
// 处理权限数据
List<String> authorities = new ArrayList<>();
List<String> userRoles = UserUtil.getUserRolesByUserId(userModel.getId());
List<String> userAllPerms = UserUtil.getUserAllPermsByUserId(userModel.getId());
for (String userRole : userRoles) {
authorities.add(DEFAULT_ROLE_PREFIX+userRole);
}
authorities.addAll(userAllPerms);
// 清除空的 授权
authorities.removeIf(StrUtil::isEmpty);
List<GrantedAuthority> grantedAuthorities = authorities.stream()
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toList());
UserDetailModel userDetailModel = UserDetailModel.builder()
.username(userModel.getUsername())
.password(userModel.getPassword())
// 账户启动
.enabled(
DictType.NO_YES_YES.getValue().equals(userModel.getEnable()))
// 账户未过期(如果需要 请自行扩展字段)
.accountNonExpired(
DictType.NO_YES_YES.getValue().equals(userModel.getEnable()))
// 账户未锁定(如果需要 请自行扩展字段)
.accountNonLocked(
DictType.NO_YES_YES.getValue().equals(userModel.getEnable()))
// 判断凭证是否过期(默认不判断 如果需要 请自行扩展过期后修改密码操作)
.credentialsNonExpired(
PasswordUtil.isCredentialsNonExpired(
userModel.getPassword(), authProperties.getCredentialsExpired()))
// 授权信息
.authorities(grantedAuthorities)
.build();
return Optional.ofNullable(userDetailModel);
}
}

@ -0,0 +1,102 @@
/**
* Copyright 2020 OPSLI https://www.opsli.com
* <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.service;
import cn.hutool.core.util.StrUtil;
import lombok.AllArgsConstructor;
import org.opsli.api.wrapper.system.user.UserModel;
import org.opsli.common.enums.DictType;
import org.opsli.core.utils.UserUtil;
import org.opsli.plugins.security.UserDetailModel;
import org.opsli.plugins.security.properties.AuthProperties;
import org.opsli.plugins.security.service.ILoadUserDetailService;
import org.opsli.plugins.security.utils.PasswordUtil;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.stream.Collectors;
/**
* + Service
*
*
* @author Parker
* @date 2022-07-14 4:44 PM
**/
@AllArgsConstructor
@Service("usernameUserDetailDetailService")
public class UsernameUserDetailDetailServiceImpl implements ILoadUserDetailService {
private static final String DEFAULT_ROLE_PREFIX = "ROLE_";
private final AuthProperties authProperties;
@Override
public Collection<Class<? extends Authentication>> getClassTypes() {
return Collections.singleton(UsernamePasswordAuthenticationToken.class);
}
@Override
public Optional<UserDetails> loadUserByPrincipal(Object principal) {
UserModel userModel = UserUtil.getUserByUserName((String) principal);
if(null == userModel){
return Optional.empty();
}
// 处理权限数据
List<String> authorities = new ArrayList<>();
List<String> userRoles = UserUtil.getUserRolesByUserId(userModel.getId());
List<String> userAllPerms = UserUtil.getUserAllPermsByUserId(userModel.getId());
for (String userRole : userRoles) {
authorities.add(DEFAULT_ROLE_PREFIX+userRole);
}
authorities.addAll(userAllPerms);
// 清除空的 授权
authorities.removeIf(StrUtil::isEmpty);
List<GrantedAuthority> grantedAuthorities = authorities.stream()
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toList());
UserDetailModel userDetailModel = UserDetailModel.builder()
.username(userModel.getUsername())
.password(userModel.getPassword())
// 账户启动
.enabled(
DictType.NO_YES_YES.getValue().equals(userModel.getEnable()))
// 账户未过期(如果需要 请自行扩展字段)
.accountNonExpired(
DictType.NO_YES_YES.getValue().equals(userModel.getEnable()))
// 账户未锁定(如果需要 请自行扩展字段)
.accountNonLocked(
DictType.NO_YES_YES.getValue().equals(userModel.getEnable()))
// 判断凭证是否过期(默认不判断 如果需要 请自行扩展过期后修改密码操作)
.credentialsNonExpired(
PasswordUtil.isCredentialsNonExpired(
userModel.getPassword(), authProperties.getCredentialsExpired()))
// 授权信息
.authorities(grantedAuthorities)
.build();
return Optional.ofNullable(userDetailModel);
}
}

@ -1,46 +0,0 @@
package org.opsli.core.security.shiro.authenticator;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.pam.ModularRealmAuthenticator;
import org.apache.shiro.authc.pam.UnsupportedTokenException;
import org.apache.shiro.realm.Realm;
import java.util.Collection;
/**
* 使TokenRealm
*
* @author Parker
* @date 2020-09-16
*/
public class CustomModularRealmAuthenticator extends ModularRealmAuthenticator {
/**
* Realm
* realm.supports()RealmRealmsupports()
* @param realms realm
* @param token token
* @return AuthenticationInfo
*/
@Override
protected AuthenticationInfo doMultiRealmAuthentication(Collection<Realm> realms, AuthenticationToken token) {
// 判断getRealms()是否返回为空
assertRealmsConfigured();
// 通过supports()方法匹配对应的Realm
Realm uniqueRealm = null;
for (Realm realm : realms) {
if (realm.supports(token)) {
uniqueRealm = realm;
break;
}
}
if (uniqueRealm == null) {
throw new UnsupportedTokenException();
}
return uniqueRealm.getAuthenticationInfo(token);
}
}

@ -1,256 +0,0 @@
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;
}
}

@ -1,85 +0,0 @@
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;
}
}

@ -1,147 +0,0 @@
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;
}
}

@ -1,83 +0,0 @@
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;
}
}

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

Loading…
Cancel
Save