package com.iplatform.base;
import com.iplatform.base.cache.DictCacheProvider;
import com.iplatform.base.di.PlatformDataImportEngine;
import com.iplatform.base.di.TemplateInfo;
import com.iplatform.base.service.DeptServiceImpl;
import com.iplatform.base.service.LogServiceImpl;
import com.iplatform.base.service.UserServiceImpl;
import com.iplatform.base.support.strategy.LoginStrategyManager;
import com.iplatform.base.util.MenuUtils;
import com.iplatform.core.BeanContextAware;
import com.iplatform.model.po.S_dept;
import com.iplatform.model.po.S_dict_data;
import com.iplatform.model.po.S_oper_log;
import com.iplatform.model.po.S_user_core;
import com.iplatform.model.po.S_user_login;
import com.walker.cache.CacheProvider;
import com.walker.infrastructure.utils.DateUtils;
import com.walker.infrastructure.utils.FileCopyUtils;
import com.walker.infrastructure.utils.NumberGenerator;
import com.walker.infrastructure.utils.PhoneNumberUtils;
import com.walker.infrastructure.utils.StringUtils;
import com.walker.push.PushManager;
import com.walker.web.CaptchaProvider;
import com.walker.web.CaptchaResult;
import com.walker.web.OrgType;
import com.walker.web.ResponseCode;
import com.walker.web.UserOnlineProvider;
import com.walker.web.UserPrincipal;
import com.walker.web.UserType;
import com.walker.web.WebAgentService;
import com.walker.web.WebUserAgent;
import com.walker.web.log.BusinessType;
import com.walker.web.log.OperateUser;
import com.walker.web.util.IdUtils;
import com.walker.web.util.ServletUtils;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TimerTask;
/**
* 系统控制器对象,业务所有 Controller
对象,都要继承该对象。
* @author 时克英
* @date 2022-12-01
*/
public abstract class SystemController extends AbstractFileOperateSpiController{
/**
* 更新给定用户登录缓存中的角色集合内容,roleIds。
*
* 1) 当用户变更角色后,可以直接刷新界面(重新请求用户信息)获取新的对应菜单权限。
*
* @param userId 用户ID
* @author 时克英
* @date 2023-12-28
*/
protected void updateLoginUserRoleListInCache(Long userId){
S_user_core userCore = this.getUser(userId);
if(userCore == null){
throw new PlatformRuntimeException("缓存中未查找到用户,这不正常,userId = " + userId, null);
}
S_user_login userLogin = this.getLoginStrategyManager().getUserLogin(userCore.getUser_name());
if(userLogin == null){
if(this.logger.isDebugEnabled()){
this.logger.debug("用户:{}不存在登录缓存,无需更新角色(roleId)缓存,userName={}", userId, userCore.getUser_name());
}
return;
}
UserPrincipal> existUserPrincipal = BeanContextAware.getBeanByType(UserOnlineProvider.class).getUserPrincipal(userLogin.getUuid());
List existRoleIdList = existUserPrincipal.getRoleIdList();
List roleIdList = this.getUserService().queryUserRoleIdList(userId);
if(this.logger.isDebugEnabled()){
this.logger.debug("给定用户:{},包含的角色:{}", userId, roleIdList);
}
if(StringUtils.isEmptyList(roleIdList)){
roleIdList = new ArrayList<>(4);
}
// 把原来用户已有的系统级权限角色重新写入,否则用户会重新让登录
if(existRoleIdList != null){
for(String securityRoleName : existRoleIdList){
if(securityRoleName.equals(SecurityConstants.ROLE_USER)
|| securityRoleName.equals(SecurityConstants.ROLE_ADMIN)
|| securityRoleName.equals(SecurityConstants.ROLE_SUPER_ADMIN)
|| securityRoleName.equals(SecurityConstants.ROLE_MERCHANT)){
roleIdList.add(securityRoleName);
}
}
}
DefaultUserPrincipal userPrincipal = new DefaultUserPrincipal(userCore);
userPrincipal.setRoleIdList(roleIdList);
// 更新缓存的登录信息
BeanContextAware.getBeanByType(UserOnlineProvider.class).cacheUserPrincipal(userLogin.getUuid(), userPrincipal, VariableConstants.DEFAULT_TOKEN_EXPIRED_MINUTES);
}
protected UserLoginCache getUserLoginCache(){
return BeanContextAware.getBeanByType(UserLoginCache.class);
}
/**
* 获得通知提醒模板配置缓存。
* @return
* @date 2023-08-25
*/
protected NotificationTemplateCache getNotificationTemplateCache(){
return BeanContextAware.getBeanByType(NotificationTemplateCache.class);
}
/**
* 写入成功操作日志
* @param userName 当前用户名,可以是登录ID或名字,可选
* @param operateUser 操作用户类型
* @param businessType 业务类型
* @param title 标题描述,可选
* @param input 输入参数,可选
* @param output 输出参数,可选
* @date 2023-08-13
*/
protected void systemLogSuccess(String userName, OperateUser operateUser, BusinessType businessType
, String title, String input, String output){
S_oper_log s_oper_log = this.acquireSystemLog(userName, operateUser, businessType, title, input, output);
AsyncManager.me().execute(new TimerTask() {
@Override
public void run() {
BeanContextAware.getBeanByType(LogServiceImpl.class).execInsertOperateLog(s_oper_log);
}
});
}
/**
* 写入错误日志
* @param userName 当前用户名,可以是登录ID或名字,可选
* @param operateUser 操作用户类型,可选
* @param businessType 业务类型,可选
* @param title 标题描述,可选
* @param input 输入参数,可选
* @param error 错误内容,必填
* @date 2023-08-13
*/
protected void systemLogError(String userName, OperateUser operateUser, BusinessType businessType, String title, String input, String error){
if(StringUtils.isEmpty(error)){
logger.warn("调用写入错误日志,但未提供错误内容,日志将不会保存:systemLogError --> error is null!");
return;
}
S_oper_log s_oper_log = this.acquireSystemLog(userName, operateUser, businessType, title, input, null);
s_oper_log.setStatus(ResponseCode.ERROR.getCode());
s_oper_log.setError_msg(StringUtils.substring(error, 0, Constants.LOG_ERROR_MAX_SIZE));
AsyncManager.me().execute(new TimerTask() {
@Override
public void run() {
BeanContextAware.getBeanByType(LogServiceImpl.class).execInsertOperateLog(s_oper_log);
}
});
}
private S_oper_log acquireSystemLog(String userName, OperateUser operateUser, BusinessType businessType
, String title, String input, String output){
if(operateUser == null){
operateUser = OperateUser.Manage;
}
if(businessType == null){
businessType = BusinessType.Other;
}
WebUserAgent agent = this.getCurrentWebUserAgent();
S_oper_log s_oper_log = new S_oper_log();
s_oper_log.setOper_id(NumberGenerator.getLongSequenceNumber());
s_oper_log.setOper_time(DateUtils.getDateTimeNumber());
s_oper_log.setStatus(ResponseCode.SUCCESS.getCode());
s_oper_log.setOper_name(userName);
s_oper_log.setOperate_user(operateUser.getIndex());
s_oper_log.setBusiness_type(businessType.getIndex());
s_oper_log.setOper_ip(agent.getIp());
s_oper_log.setOper_location(agent.getLocation());
s_oper_log.setRequest_method(agent.getMethod());
s_oper_log.setOper_url(agent.getUrl());
s_oper_log.setTitle(title);
if(StringUtils.isNotEmpty(input)){
s_oper_log.setOper_param(input);
}
if(StringUtils.isNotEmpty(output)){
s_oper_log.setJson_result(output);
}
return s_oper_log;
}
/**
* 返回登录策略管理器对象
* @return
* @date 2023-08-05
*/
protected LoginStrategyManager getLoginStrategyManager(){
return BeanContextAware.getBeanByType(LoginStrategyManager.class);
}
/**
* 返回当前web浏览器代理对象。
* @return
* @date 2023-07-25
*/
protected WebUserAgent getCurrentWebUserAgent(){
HttpServletRequest request = this.getRequest();
return this.getWebAgentService().getWebUserAgent(request.getHeader("User-Agent"), request);
}
protected WebAgentService getWebAgentService(){
return BeanContextAware.getBeanByType(WebAgentService.class);
}
/**
* 判断短信验证码是否正确。
* @param code 验证码
* @param uuid 请求验证码标识
* @return
* @date 2023-08-07
*/
protected boolean validateSmsCode(String code, String uuid){
CaptchaResult captchaResult = new CaptchaResult();
captchaResult.setCode(code);
captchaResult.setUuid(uuid);
return this.smsCaptchaProvider.validateCaptcha(captchaResult);
}
/**
* 发送短信验证码。
* @param phoneNumber 手机号
* @return 返回前端需要的uuid,提交登录使用
* @throws PlatformRuntimeException
* @date 2023-06-28
*/
protected Map sendSmsCodeValidation(String phoneNumber){
if(!PhoneNumberUtils.isCellPhoneNumber(phoneNumber)){
throw new PlatformRuntimeException("手机号码格式错误:" + phoneNumber);
}
String uuid = IdUtils.simpleUUID();
Map data = new HashMap<>(4);
data.put("uuid", uuid);
String verifyKey = Constants.CAPTCHA_CODE_PREFIX + uuid;
CaptchaResult captchaResult = this.smsCaptchaProvider.generateCaptcha(phoneNumber);
if(captchaResult == null){
// return ResponseValue.error("短信验证码生成错误, null");
throw new PlatformRuntimeException("短信验证码生成错误, null");
}
// 写入验证码 key 和 code 到缓存中
this.captchaCacheProvider.putCacheData(verifyKey, captchaResult.getCode(), 120);
if(this.logger.isDebugEnabled()){
this.logger.debug("生成短信验证码:{}, uuid:{}", captchaResult.getCode(), uuid);
}
data.put("message", "短信验证码已发送");
return data;
}
/**
* 返回用户归属值,如果是平台为'-1',如果为租户(商户)则为定义的商户ID。
*
* 注意要点:
* 1)因为系统框架中用户是长整形(Long),但商户中是(int)因此在实际添加商户数据时,需要按照序列来计算,这样只需要整形即可。
*
* @return
* @date 2023-06-05
*/
protected long getOwner(){
S_user_core user = this.getCurrentUser();
int userType = user.getUser_type();
if(userType == UserType.TYPE_SUPER){
return Constants.OWNER_PLATFORM;
}
// 其他人需要根据机构中"menu_type"字段区分是平台机构,还是业务独立机构
S_dept dept = this.getDept(user.getOrg_id());
if(dept.getMenu_type().intValue() == MenuUtils.MENU_SCOPE_PLATFORM){
return Constants.OWNER_PLATFORM;
}
// 机构ID就是业务创建的独立编号(如:商户id),这里商户是int,但系统机构中仍然使用bigint
return dept.getId();
}
/**
* 返回当前用户所在顶级单位,使用的菜单范围:平台0,商户(顶级独立单位菜单范围)4,后续可能会有其他值。
* @return
* @date 2023-06-01
*/
protected int getCurrentOrgMenuScope(){
long orgId = this.getCurrentUser().getOrg_id();
if(orgId == Constants.SUPERVISOR_ID){
// 超级管理员,返回平台菜单范围
return MenuUtils.MENU_SCOPE_PLATFORM;
}
return this.getDeptCacheProvider().getDept(orgId).getMenu_type();
}
/**
* 根据字典数据code,返回字典项名称。
* @param dictCode 字典项编码(主键)
* @return
* @date 2023-03-26
*/
protected String getDictName(long dictCode){
S_dict_data dict_data = this.getDictCacheProvider().getCacheData(String.valueOf(dictCode));
if(dict_data == null){
throw new IllegalStateException("缓存中未找到字典名称,dict_code = " + dictCode);
}
return dict_data.getDict_label();
}
/**
* 返回给定机构的名字。
* @param deptId 机构ID
* @return
* @date 2023-03-23
*/
protected String getDeptName(long deptId){
S_dept dept = this.getDept(deptId);
return dept == null ? "None":dept.getDept_name();
}
/**
* 返回给定id的部门对象
* @param deptId 部门ID
* @return
* @author 时克英
* @date 2023-03-23
*/
protected S_dept getDept(long deptId){
return this.getDeptCacheProvider().getDept(deptId);
}
/**
* 从缓存中返回给定的用户
* @param userId 用户id
* @return
* @date 2023-03-22
*/
public S_user_core getUser(long userId){
return this.getUserCacheProvider().getUser(userId);
}
/**
* 下载数据导入模板,该模板由系统自动生成。
* 业务需要提供数据库对应的'表名称',如:s_user_core
* @param tableName 表名
* @date 2023-03-18
*/
protected void downloadLocalImportTemplate(String tableName){
if(StringUtils.isEmpty(tableName)){
throw new IllegalArgumentException("请提供要导入数据的'表名称'!");
}
// 本地文件存储根路径,如: d:/temp/
String templatePath = this.acquireFileOperateSpi().getFileRootConfig();
// 生成的模板文件名称,如:demo.xlsx
String templateFileName = Constants.TEMPLATE_IMPORT_PREFIX + tableName + "_" + DateUtils.getDateTimeSecondForShow() + ".xlsx";
TemplateInfo templateInfo = new TemplateInfo();
// 2023-05-07 设置模板生成具体路径。
templateInfo.setTemplatePath(templatePath + templateFileName);
templateInfo.setTableName(tableName);
logger.debug("templateInfo = {}", templateInfo);
File templateFile = this.getDataImportEngine().generateTemplate(templateInfo);
try {
this.downloadSimpleFile(FileCopyUtils.copyToByteArray(templateFile), templateFileName);
} catch (IOException e) {
logger.error("下载模板错误:" + e.getMessage() + ", tableName=" + tableName, e);
ServletUtils.renderString(getResponse(), "下载模板错误:" + e.getMessage() + ", tableName=" + tableName);
}
}
/**
* 返回数据字典缓存对象。
* 注意:这种写法后续要改掉,统一由平台自动注入,无需单独设置。
* @return
* @date 2023-03-10
*/
protected DictCacheProvider getDictCacheProvider(){
// if(this.dictCacheProvider == null){
// this.dictCacheProvider = BeanContextAware.getBeanByType(DictCacheProvider.class);
// }
return this.dictCacheProvider;
}
/**
* 返回数据导入引擎实现对象,用来完成 Excel 导入功能。
* @return
* @date 2023-02-07
*/
protected PlatformDataImportEngine getDataImportEngine(){
// return BeanContextAware.getBeanByType(PlatformDataImportEngine.class);
return this.platformDataImportEngine;
}
public UserCacheProvider getUserCacheProvider() {
// if(this.userCacheProvider == null){
// this.userCacheProvider = BeanContextAware.getBeanByType(UserCacheProvider.class);
// }
return userCacheProvider;
}
public DeptCacheProvider getDeptCacheProvider() {
// if(this.deptCacheProvider == null){
// this.deptCacheProvider = BeanContextAware.getBeanByType(DeptCacheProvider.class);
// }
return deptCacheProvider;
}
/**
* 返回给定用户的顶级机构ID。
* @param userId
* @return
* @date 2022-12-15
*/
protected long getUserRootOrgId(long userId){
this.checkUserCacheProvider();
S_user_core user_core = this.userCacheProvider.getUser(userId);
if(user_core == null){
throw new IllegalStateException("缓存中未找到用户: " + userId);
}
return user_core.getOrg_id();
}
/**
* 根据机构(部门等非顶级ID)返回顶级机构ID。
* @param deptId
* @return
* @date 2022-12-12
*/
protected long getRootOrgIdByDept(long deptId){
if(this.deptCacheProvider == null){
throw new IllegalArgumentException("请先设置controller对象: deptCacheProvider");
}
S_dept dept = this.deptCacheProvider.getDept(deptId);
if(dept == null){
throw new IllegalStateException("缓存中未找到机构: " + deptId);
}
return dept.getOrg_id();
}
/**
* 返回当前登录用户可选择的根机构列表,即:第一级机构,通常是集团公司等。
* 这些也称为多租户,系统提供多单位(独立)维护,不同独立单位由各自管理员自行维护。
*
* 1.超级管理员可以看到所有独立机构列表
* 2.单位用户只能看到本单位(一个机构)
*
* @return
* @date 2022-12-01
*/
protected List getOrgListScope(){
DeptServiceImpl deptService = BeanContextAware.getBeanByType(DeptServiceImpl.class);
S_user_core currentUser = this.getCurrentUser();
List list = null;
if(currentUser.getUser_type().intValue() == UserType.TYPE_SUPER){
list = deptService.queryRootOrgList(0);
} else {
list = deptService.queryRootOrgList(currentUser.getOrg_id().longValue());
}
if(StringUtils.isEmptyList(list)){
// 不存在任何机构(数据库没有记录),需要创建默认机构
list = new ArrayList<>(2);
list.add(this.createDefaultOrg());
}
return list;
}
private void checkUserCacheProvider(){
if(this.userCacheProvider == null){
throw new IllegalStateException("UserCacheProvider 必须先设置到控制器中。");
}
}
private S_dept createDefaultOrg(){
S_dept root = new S_dept();
root.setId(0L);
root.setParent_id(0L);
root.setOrg_type(OrgType.TYPE_ORG);
root.setOrder_num(1);
root.setDept_name(Constants.DEFAULT_ORG_NAME);
return root;
}
public void setDeptCacheProvider(DeptCacheProvider deptCacheProvider) {
this.deptCacheProvider = deptCacheProvider;
}
public void setUserCacheProvider(UserCacheProvider userCacheProvider) {
this.userCacheProvider = userCacheProvider;
}
public void setPlatformDataImportEngine(PlatformDataImportEngine platformDataImportEngine) {
this.platformDataImportEngine = platformDataImportEngine;
}
public void setDictCacheProvider(DictCacheProvider dictCacheProvider) {
this.dictCacheProvider = dictCacheProvider;
}
public void setPushManager(PushManager pushManager) {
this.pushManager = pushManager;
}
public void setSmsCaptchaProvider(CaptchaProvider smsCaptchaProvider) {
this.smsCaptchaProvider = smsCaptchaProvider;
}
public void setCaptchaCacheProvider(CacheProvider captchaCacheProvider) {
this.captchaCacheProvider = captchaCacheProvider;
}
public CaptchaProvider getSmsCaptchaProvider() {
return smsCaptchaProvider;
}
public CacheProvider getCaptchaCacheProvider() {
return captchaCacheProvider;
}
protected UserServiceImpl getUserService(){
return BeanContextAware.getBeanByType(UserServiceImpl.class);
}
private CaptchaProvider smsCaptchaProvider;
private CacheProvider captchaCacheProvider;
/**
* 返回推送管理器对象,只有在特殊情况下需要业务直接调用该对象。
* @return
* @date 2023-04-25
*/
protected PushManager getPushManager() {
return pushManager;
}
private PushManager pushManager;
private DeptCacheProvider deptCacheProvider;
private UserCacheProvider userCacheProvider;
private PlatformDataImportEngine platformDataImportEngine;
private DictCacheProvider dictCacheProvider;
@Override
public void afterPropertiesSet() throws Exception {}
}