系统图标使用自定义CDN地址(内网部署)

在实际项目中,客户网络环境不能访问外网即纯内网部署。此时需要将所有的静态资源都放在客户内部的CDN上,该篇详细说明实现步骤。

实现步骤

1、把图片等静态资源上传到本地CDN上(如MINIO、Nginx等),图片等静态资源找 数式支持人员 提供;

  • 【注意】:MINIO情况,放置图片等静态资源的桶权限需设置为公共读

2、项目中YAML的OSS配置,使用本地CDN、并指定使用的本地CDN图标的标识appLogoUseCdn: true, OSS配置参考如下:

  • 本地CDN使用MINIO(仅示例需根据实际情况修改)

    cdn:
    oss:
    name: MINIO
    type: MINIO
    # MINIO的配置根据实际情况修改
    bucket: pamirs(您的bucket)
    # 上传和下载地址根据实际情况修改
    uploadUrl: http://39.103.145.77:9000
    downloadUrl: http://39.103.145.77:9000
    accessKeyId: 您的accessKeyId
    accessKeySecret: 您的accessKeySecret
    # mainDir对用CDN的图片目录,根据项目情况自行修改
    mainDir: upload/demo/
    validTime: 3600000
    timeout: 600000
    active: true
    referer:
    # 使用客户自己的CDN的图片,否则系统默认的从数式的CDN中获取
    appLogoUseCdn: true
  • 或本地CDN使用Nginx(仅示例需根据实际情况修改)

    cdn:
    oss:
    name: 本地文件NG系统
    type: LOCAL
    bucket:
    # uploadUrl 这个是Oinone后端服务地址和端口
    uploadUrl: http://192.168.0.129:8099
    # downloadUrl前端地址,即直接映射在nginx的静态资源的路径和端口
    downloadUrl: http://192.168.0.129:9999
    validTime: 3600000
    timeout: 600000
    active: true
    referer:
    # 本地Nginx静态资源目录
    localFolderUrl: /opt/pamirs/static
    # 使用客户自己的CDN的图片,否则系统默认的从数式的CDN中获取
    appLogoUseCdn: true

3、前端工程
3.1 前端源码工程,在.evn中把 STATIC_IMG地址进行修改;http(https)、IP和端口改成与CDN对应的配置,URL中/oinone/static/images是固定的;例如:
系统图标使用自定义CDN地址(内网部署)

  • 本地CDN使用MINIO(仅示例需根据实际情况修改)
    STATIC_IMG: 'http://39.103.145.77:9000/pamirs(这里替换为OSS中的bucket)/oinone/static/images'
  • 或本地CDN使用Nginx(仅示例需根据实际情况修改)
    STATIC_IMG: 'http://192.168.0.129:9999/static/oinone/static/images'

3.2 对于已经打包好的前端资源
对于已打包好的前端资源即无法修改.evn的情况;需在前端资源的根目录,新建config/manifest.js. 如果已存在则不需要新建,同时原来的内容也不需要删除(追加即可),需增加的配置:
系统图标使用自定义CDN地址(内网部署)

  • 本地CDN使用MINIO(仅示例需根据实际情况修改)
    runtimeConfigResolve({
    STATIC_IMG: 'http://39.103.145.77:9000/pamirs(这里替换为OSS中的bucket)/oinone/static/images',
    plugins: {
    usingRemote: true
    }
    })
  • 或本地CDN使用Nginx(仅示例需根据实际情况修改)
    runtimeConfigResolve({
    STATIC_IMG: 'http://192.168.0.129:9999/static/oinone/static/images',
    plugins: {
    usingRemote: true
    }
    })

Oinone社区 作者:望闲原创文章,如若转载,请注明出处:https://doc.oinone.top/dai-ma-shi-jian/20385.html

访问Oinone官网:https://www.oinone.top获取数式Oinone低代码应用平台体验

(0)
望闲的头像望闲数式管理员
上一篇 2025年2月7日 pm4:19
下一篇 2025年2月12日 pm5:25

相关推荐

  • 蓝绿发布

    背景 应用程序升级面临最大挑战是新旧业务切换,将软件从测试的最后阶段带到生产环境,同时要保证系统不间断提供服务。长期以来,业务升级渐渐形成了几个发布策略:蓝绿发布、灰度发布和滚动发布,目的是尽可能避免因发布导致的流量丢失或服务不可用问题。 本文主要介绍Oinone平台如何实现蓝绿发布。蓝绿发布:项目逻辑上分为AB组,在项目系统时,首先把A组从负载均衡中摘除,进行新版本的部署。B组仍然继续提供服务。 需求 统一权限统一登录信息不同业务数据 实现方案 首先需要两个环境并统一流量入口,这里使用Nginx配置负载均衡:nginx如何配置后端服务的负载均衡 统一权限配置 在蓝绿环境添加不同的redis前缀 spring: redis: prefix: xxx 在蓝绿环境的修改AuthRedisTemplate Bean,利用setKeySerializer去掉redis前缀。 可以使用@Profile注解指定仅线上环境生效。 @Configuration // @Profile("prod") public class AuthRedisTemplateConfig { @Bean(AuthConstants.REDIS_TEMPLATE_BEAN_NAME) public AuthRedisTemplate<?> authRedisTemplate( RedisConnectionFactory redisConnectionFactory, PamirsStringRedisSerializer pamirsStringRedisSerializer ) { AuthRedisTemplate<Object> template = new AuthRedisTemplate<Object>(redisConnectionFactory, pamirsStringRedisSerializer) { @Override public void afterPropertiesSet() { // 重写 key serializer,去掉前缀隔离 this.setKeySerializer(new PamirsStringRedisSerializer(null)); super.afterPropertiesSet(); } }; return template; } } 统一登录 在蓝绿环境自定义实现pro.shushi.pamirs.user.api.spi.UserCacheApi SPI,去除redis前缀 package pro.shushi.pamirs.top.core.spi; import com.alibaba.fastjson.JSON; import com.google.common.collect.Sets; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.annotation.Order; import org.springframework.dao.DataAccessException; import org.springframework.data.redis.core.RedisOperations; import org.springframework.data.redis.core.SessionCallback; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import pro.shushi.pamirs.auth.api.cache.redis.AuthRedisTemplate; import pro.shushi.pamirs.meta.api.dto.model.PamirsUserDTO; import pro.shushi.pamirs.meta.api.dto.protocol.PamirsRequestVariables; import pro.shushi.pamirs.meta.api.session.PamirsSession; import pro.shushi.pamirs.meta.common.spi.SPI; import pro.shushi.pamirs.user.api.cache.UserCache; import pro.shushi.pamirs.user.api.configure.UserConfigure; import pro.shushi.pamirs.user.api.spi.UserCacheApi; import java.net.URI; import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.Set; import java.util.concurrent.TimeUnit; @Order(1) @Component @SPI.Service("MyUserCache") public class MyUserCache implements UserCacheApi { private static final Set<String> DEFAULT_FILTER_URIS = Collections.singleton("/pamirs/message"); @Autowired private AuthRedisTemplate redisTemplate; @Override public PamirsUserDTO getSessionUser(String key) { String objectValue = getUserCacheAndRenewed(key); if (StringUtils.isNotBlank(objectValue)) { return JSON.parseObject(objectValue, PamirsUserDTO.class); } return null; } @Override public void setSessionUser(String key, PamirsUserDTO user, Integer expire) { user.setPassword(null); expire = getExpire(expire); redisTemplate.opsForValue().set(key.replace("'", " "), JSON.toJSONString(user), expire, TimeUnit.SECONDS); // 当前的实现是一个user可以在多个客户端登录,需要在管理端修改user权限后强制清除掉该用户已登录的session,所以需要记录uid对应所有已登录的sessionId String userRelSessionKey = UserCache.createUserRelSessionKey(user.getUserId()); redisTemplate.opsForSet().add(userRelSessionKey, key); redisTemplate.expire(userRelSessionKey,…

    2025年9月18日
    54100
  • 部分模型不动态修改表结构(由单独DDL处理)

    需求描述 实际项目中, 存在部分模型不动态修改表结构,由单独DDL脚本处理,常见的场景有: 已存在库和表中使用Oinone进行功能开发,此时对于已经存在的表对应的模型不允许改表结构 其他情况不希望动态改变表结构的情况 实现步骤 新建NODDL的基础模型 模型公共字段 公共字段说明:使用Oinone进行开发时,业务模型需继承基础IdModel(或者由IdModel衍生出的子类),这些基础模型有createDate(创建时间)、writeDate(更新时间)、createUid(创建人ID)和writeUid(更新人ID)等公共字段;实际表中公共字段可能与Oinone有所不同。 实现方式 方式1:公共属性字段用平台提供的createDate、writeDate、createUid和writeUid,通过指定column与表中的实际字段对应.【推荐】该方式,公共字段的处理可以继续使用平台的默认赋值处理方式; 方式2:继承平台的时候,把公共字段排除掉(配置unInheritedFields),然后自行加通用字段:排除字段:@Model.Advanced(type= ModelTypeEnum.ABSTRACT, ordering = "createAt DESC, id DESC", unInheritedFields = {"createUid","writeUid","createDate","writeDate"})【不推荐】该方式,公共字段的赋值逻辑需要自行处理,略显复杂; 实现方式举例 下面的示例以方式1举例;假设表的基础字段分别是:createAt、updateAt、createId和updateId 与平台的不同. 不自动DDL的抽象模型示例 import pro.shushi.pamirs.meta.annotation.Field; import pro.shushi.pamirs.meta.annotation.Model; import pro.shushi.pamirs.meta.base.IdModel; import pro.shushi.pamirs.meta.enmu.FieldStrategyEnum; import pro.shushi.pamirs.meta.enmu.ModelTypeEnum; import java.util.Date; /** * 假设表的基础字段分别是:createAt、updateAt、createId和updateId 与平台的不同 */ @Model.model(BaseNoDdlModel.MODEL_MODEL) @Model(displayName = "不自动DDL的抽象模型") @Model.Advanced(type= ModelTypeEnum.ABSTRACT, ordering = "createAt DESC, id DESC") public abstract class BaseNoDdlModel extends IdModel { public static final String MODEL_MODEL = "hr.std.BaseNoDdlModel"; // 如果原表的主键的列名不是ID的情况,这里可以定义column指定ID属性对应的列名 /** @Field.PrimaryKey @Field(displayName = "主键ID") @Field.Advanced(column = "XLH") private Long id; **/ // 下面这几个字段按实际项目中的情况来增加,包括字段名 @Field.Advanced(columnDefinition = "DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP", column = "createAt", insertStrategy = FieldStrategyEnum.NEVER, updateStrategy = FieldStrategyEnum.NEVER, batchStrategy = FieldStrategyEnum.NEVER) @Field(displayName = "创建时间", priority = 200) private Date createDate; @Field.Advanced(columnDefinition = "DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP", column = "updateAt", batchStrategy = FieldStrategyEnum.NEVER) @Field(displayName = "更新时间", priority = 210) private Date writeDate; @Field.Advanced(column = "createId") @Field(displayName = "创建人ID", priority = 220, invisible = true) private Long createUid; @Field.Advanced(column = "updateId") @Field(displayName = "更新人ID", priority = 230, invisible = true) private Long writeUid; } 不需动态DDL的业务模型,业务模型继承BaseNoDdlModel。 其他业务模型如果有相同的需求类似的做法 /** * 测试合同表 */ @Model.model(InspectionInfo.MODEL_MODEL) @Model(displayName = "合同", labelFields…

    2025年2月22日
    92100
  • 模型定义在数据库中的映射

    模型定义在数据库中的映射 Oinone中通过定义模型来建立数据表,使用注解的方式来使多张表之间的关联。 数据库字段与模型定义字段映射 package pro.shushi.pamirs.top.api.model; import pro.shushi.pamirs.core.common.enmu.DataStatusEnum; import pro.shushi.pamirs.meta.annotation.Field; import pro.shushi.pamirs.meta.annotation.Model; import pro.shushi.pamirs.meta.base.IdModel; import pro.shushi.pamirs.meta.enmu.DateFormatEnum; import pro.shushi.pamirs.meta.enmu.DateTypeEnum; import pro.shushi.pamirs.meta.enmu.MimeTypeEnum; import java.math.BigDecimal; import java.util.Date; @Model.model(PamirsDemo.MODEL_MODEL) @Model(displayName = “PamirsDemo”) public class PamirsDemo extends IdModel { public static final String MODEL_MODEL = “top.PamirsDemo”; @Field.Binary(mime = MimeTypeEnum.html) @Field(displayName = “二进制类型”) private Byte[] byteType; @Field.Integer @Field(displayName = “整数”) private Long longType; @Field.Float @Field(displayName = “浮点数”) private BigDecimal floatType; @Field.Boolean @Field(displayName = “布尔类型”) private Boolean booleanType; @Field.Enum @Field(displayName = “枚举”) private DataStatusEnum enumType; @Field.String @Field(displayName = “字符串”) private String stringType; @Field.Text @Field(displayName = “多行文本”) private String textType; @Field.Html @Field(displayName = “富文本”) private String richText; @Field.Date(type = DateTypeEnum.DATE, format = DateFormatEnum.DATE) @Field(displayName = “日期类型”) private Date dataType; @Field.Date(type = DateTypeEnum.DATETIME, format = DateFormatEnum.DATETIME) @Field(displayName = “日期时间类型”) private Date dataTimeType; @Field.Money @Field(displayName = “金额”) private BigDecimal amount; } 更多字段基础请参考文档字段基础与复合 多对一的关系映射 例:设计一张教师表,一张科目表,教师表对科目表属于多对一的关系,在教师表中使用科目id管理关联关系。 教师表teacher 科目表professional 那么在Oinone的模型定义中,这两张表定义是这样的; 教师模型 package pro.shushi.pamirs.top.api.model; import pro.shushi.pamirs.meta.annotation.Field; import pro.shushi.pamirs.meta.annotation.Model; import pro.shushi.pamirs.meta.base.IdModel; @Model.model(Teacher.MODEL_MODEL) @Model(displayName = “教师”, summary = “教师”) public class Teacher extends IdModel { public static final String MODEL_MODEL = “top.Teacher”; @Field.String @Field(displayName = “教师名字”) private String teacherName; @Field.Integer @Field(displayName = “科目id”) private Long professionalId; @Field(displayName…

    2024年8月16日
    1.2K00
  • 如何扩展行为权限

    注意:5.2.8 以上版本适用 需求 我们的权限控制需要在页面上有交互才可以在管理中心控制该动作权限,在没有页面交互的动作是不能进行授权操作的。所以本文章将介绍如何将页面上没有交互的动作接入到系统权限中管理。 一、扩展系统权限的菜单页面 实现 步骤: 创建授权节点实现权限节点扩展接口:pro.shushi.pamirs.auth.api.extend.load.PermissionNodeLoadExtendApi#buildRootPermissions @Component @Order(88) public class MyTestNodeLoadExtend implements PermissionNodeLoadExtendApi { public static final String MODEL = AuthTest.MODEL_MODEL; public static final String MODULE = TopModule.MODULE_MODULE; public static final String FUN = "dataStatus"; @Override public List<PermissionNode> buildRootPermissions(PermissionLoadContext loadContext, List<PermissionNode> nodes) { //创建授权根节点 PermissionNode root = createMyNode(); List<PermissionNode> newNodes = new ArrayList<>(); //从缓存中读取需要授权的Action Action cacheAction = PamirsSession.getContext().getExtendCache(ActionCacheApi.class).get(MODEL, FUN); if (cacheAction != null) { //将该Action放入权限树 //权限鉴权的path路径是根据【cacheAction.getModel() + cacheAction.getName()】拼接的。和MODULE没有关系,这里MODULE可以自定义。 AuthNodeHelper.addNode(newNodes, root, AuthNodeHelper.createActionNode(MODULE, cacheAction, root)); } nodes.add(0, root); return newNodes; } private PermissionNode createMyNode() { return AuthNodeHelper.createNodeWithTranslate("MyNode", "自定义节点"); } } 在管理中心中我们可以看到代码里创建的授权节点。 给角色分配该动作的权限,调用我们配置的AuthTest模型的dataStatus动作看效果。 二、扩展菜单下的动作权限 实现 步骤: 创建viewAction用于作为权限菜单"permissionExtension"是自定义的viewAction的name,用于下面拼path路径鉴权。因为这里只需要在系统权限那边利用这个viewAction创建出授权节点。所以”权限扩展form“可以随意定义名字,系统会拿默认视图。 @Model.model(AuthTest.MODEL_MODEL) @Component @UxRouteButton( action = @UxAction(name = "permissionExtension", displayName = "权限扩展", label = "权限扩展", contextType = ActionContextTypeEnum.CONTEXT_FREE), value = @UxRoute(model = AuthTest.MODEL_MODEL, viewName = "权限扩展form", openType = ActionTargetEnum.ROUTER)) public class AuthTestAction { @Action(displayName = "启用", contextType = ActionContextTypeEnum.SINGLE) public AuthTest dataStatus(AuthTest data) { data.setOrgName("给个值"); return data; } } 创建授权节点实现权限节点扩展接口:pro.shushi.pamirs.auth.api.extend.load.PermissionNodeLoadExtendApi#buildRootPermissions @Component @Order(88) public class MyTestNodeLoadExtend implements PermissionNodeLoadExtendApi { //创建授权根节点 @Override public List<PermissionNode> buildRootPermissions(PermissionLoadContext loadContext, List<PermissionNode> nodes) { PermissionNode root = AuthNodeHelper.createNodeWithTranslate("CustomNode", "自定义节点"); List<PermissionNode> newNodes = new ArrayList<>(); newNodes.add(root); ViewAction viewAction = new ViewAction().setModel(AuthTest.MODEL_MODEL).setName("permissionExtension").queryOne(); //将该Action放入权限树 //权限鉴权的path路径是根据【viewAction.getModel(),…

    2024年11月1日
    76800
  • 读写分离

    总体介绍 Oinone的读写分离方案是基于Sharding-JDBC的整合方案,要先具备一些Sharding-JDBC的知识。 [Sharding-JDBC] 读写分离依赖于主从复制来同步数据,从库复制数据后,才能通过读写分离策略将读请求分发到从库,实现读写操作的分流,请根据业务需求自行实现主从配置。 配置读写策略 配置 top_demo 模块走读写分离的逻辑数据源 pamirsSharding。 配置数据源。 为 pamirsSharding 配置数据源以及 sharding 规则。 指定需要被sharding-jdbc接管的模块 指定top_demo模块给 Sharding-JDBC 接管,接管逻辑数据源名为 pamirsSharding pamirs: framework: data: ds-map: base: base top_demo: pamirsSharding 配置数据源 pamirs: datasource: pamirsMaster: driverClassName: com.mysql.cj.jdbc.Driver type: com.alibaba.druid.pool.DruidDataSource url: jdbc:mysql://127.0.0.1:3306/61_pamirs_mydemo_master?useSSL=false&allowPublicKeyRetrieval=true&useServerPrepStmts=true&cachePrepStmts=true&useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&autoReconnect=true&allowMultiQueries=true username: root password: ma123456 initialSize: 5 maxActive: 200 minIdle: 5 maxWait: 60000 timeBetweenEvictionRunsMillis: 60000 testWhileIdle: true testOnBorrow: false testOnReturn: false poolPreparedStatements: true asyncInit: true pamirsSlaver: # 从库数据源配置 driverClassName: com.mysql.cj.jdbc.Driver type: com.alibaba.druid.pool.DruidDataSource url: jdbc:mysql://127.0.0.1:3306/61_pamirs_mydemo_slaver?useSSL=false&allowPublicKeyRetrieval=true&useServerPrepStmts=true&cachePrepStmts=true&useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&autoReconnect=true&allowMultiQueries=true username: root password: ma123456 initialSize: 5 maxActive: 200 minIdle: 5 maxWait: 60000 timeBetweenEvictionRunsMillis: 60000 testWhileIdle: true testOnBorrow: false testOnReturn: false poolPreparedStatements: true asyncInit: true 配置读写数据源及规则 pamirs: sharding: define: data-sources: pamirsSharding: pamirsMaster # 为逻辑数据源pamirsSharding指向主数据源pamirsMaster。 models: "[trigger.PamirsSchedule]": tables: 0..13 rule: pamirsSharding: actual-ds: # 指定逻辑数据源pamirsSharding代理的数据源为pamirsMaster、pamirsSlaver – pamirsMaster – pamirsSlaver # 以下配置跟sharding-jdbc配置一致 replicaQueryRules: – data-sources: pamirsSharding: primaryDataSourceName: pamirsMaster # 写库数据源 replicaDataSourceNames: – pamirsSlaver # 读库数据源 loadBalancerName: round_robin load-balancers: round_robin: type: ROUND_ROBIN # 读写规则

    2025年5月22日
    45700

Leave a Reply

登录后才能评论