1.5 Spring表达式语言(SpEL)

news/2025/2/12 4:06:02/

1.5 Spring表达式语言(SpEL)

1.5.1 资源注入表达式实战(深度工程应用)

SpEL基础语法全景

表达式类型:├─ 字面量:#{'Hello World'}├─ 属性引用:#{systemProperties['user.timezone']}├─ 方法调用:#{T(java.lang.Math).random()}├─ 运算符:│    ├─ 算术:+,-,*,/,%,^│    ├─ 关系:eq,ne,lt,gt,le,ge│    └─ 逻辑:and,or,not└─ 集合操作:#{users.?[age > 18]}

动态配置注入案例

java">@Configuration
public class DynamicConfig {// 注入操作系统时区@Value("#{systemProperties['user.timezone']}")private String systemTimezone;// 注入随机端口(8000-9000)@Value("#{T(java.util.concurrent.ThreadLocalRandom).current().nextInt(8000,9000)}")private int serverPort;// 注入环境变量@Value("#{environment['DATABASE_URL'] ?: 'jdbc:mysql://localhost:3306/default'}")private String databaseUrl;// 注入集合元素@Value("#{'${allowed.ips}'.split(',')}")private List<String> allowedIps;// 注入Bean属性@Value("#{dataSource.url}")private String datasourceUrl;
}

多环境配置表达式方案

# application-dev.properties
app.notification.enabled=true
app.cache.size=1000# application-prod.properties
app.notification.enabled=false
app.cache.size=5000
java">@Service
public class SystemService {// 根据环境动态启用功能@Value("#{${app.notification.enabled} ? 'ENABLED' : 'DISABLED'}")private String notificationStatus;// 动态计算缓存超时时间@Value("#{${app.cache.size} * 60 * 1000}")private long cacheTimeout;
}

1.5.2 条件化配置的表达式技巧(生产级方案)

组合条件表达式实战

java">@Configuration
@Conditional( value = OnRequiredServicesCondition.class
)
public class ServiceConfiguration {@Bean@ConditionalOnExpression("#{environment.getProperty('app.mode') == 'cluster' && " +"T(java.net.InetAddress).getLocalHost().hostName.startsWith('node-')}")public ClusterService clusterService() {return new ClusterServiceImpl();}
}public class OnRequiredServicesCondition implements Condition {@Overridepublic boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {Environment env = context.getEnvironment();return env.containsProperty("DB_MASTER_URL") &&env.containsProperty("CACHE_SERVERS");}
}

表达式驱动特性开关

java">@RestController
public class FeatureController {// 根据配置动态启用API版本@GetMapping("/v2/data")@ConditionalOnExpression("#{environment['app.feature.v2-api'] == 'enabled'}")public ResponseEntity<?> getDataV2() {// 新版实现逻辑}// 根据日期范围启用功能@Scheduled(fixedRate = 60000)@ConditionalOnExpression("#{T(java.time.LocalDate).now().isAfter(T(java.time.LocalDate).parse('2024-01-01'))}")public void executeYearlyTask() {// 2024年后启用的任务}
}

1.5.3 安全权限表达式进阶用法(金融系统案例)

方法级安全控制

java">@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {// 启用方法级安全注解
}@Service
public class AccountService {// 账户必须属于当前用户@PreAuthorize("#account.owner == authentication.name")public void updateAccount(Account account) {// 更新逻辑}// 交易金额限制@PreAuthorize("#amount <= 100000 or hasRole('VIP')")public void transfer(BigDecimal amount) {// 转账逻辑}// 审计日志访问控制@PostFilter("filterObject.operator == authentication.name or hasAuthority('AUDIT_READ_ALL')")public List<AuditLog> getLogs() {// 查询日志逻辑}
}

自定义权限表达式

java">// 1. 定义根安全对象
public class CustomSecurityExpressionRoot extends SecurityExpressionRoot {public CustomSecurityExpressionRoot(Authentication a) {super(a);}public boolean isInDepartment(String deptCode) {User user = (User) this.authentication.getPrincipal();return user.getDepartments().contains(deptCode);}
}// 2. 注册自定义表达式处理器
public class CustomMethodSecurityExpressionHandler extends DefaultMethodSecurityExpressionHandler {@Overrideprotected SecurityExpressionRoot createSecurityExpressionRoot(Authentication authentication, MethodInvocation invocation) {return new CustomSecurityExpressionRoot(authentication);}
}// 3. 配置安全策略
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {@Overrideprotected MethodSecurityExpressionHandler createExpressionHandler() {return new CustomMethodSecurityExpressionHandler();}
}// 4. 业务层使用
@Service
public class FinanceService {@PreAuthorize("isInDepartment('FINANCE')")public void approvePayment() {// 财务审批逻辑}
}

1.5.4 SpEL高级特性实战(数据转换与校验)

类型安全转换表达式

java">public class DataValidator {// 强制类型转换@Value("#{T(java.time.LocalDate).parse('${app.startDate}')}")private LocalDate startDate;// 集合元素转换@Value("#{'${app.ports}'.split(',').?[T(java.lang.Integer).parseInt(#this)]}")private List<Integer> activePorts;// 映射转换@Value("#{${app.ratios}.entrySet().stream().collect(T(java.util.Map).Entry.comparingByValue())}")private Map<String, Double> sortedRatios;
}

动态校验规则引擎

java">public class OrderValidationRules {// 从配置文件加载规则@Value("#{'${validation.order.amount}'.split(':')}")private List<String> amountRules;public boolean validateAmount(BigDecimal amount) {String operator = amountRules.get(0);BigDecimal limit = new BigDecimal(amountRules.get(1));switch (operator) {case "gt": return amount.compareTo(limit) > 0;case "lt": return amount.compareTo(limit) < 0;default: throw new IllegalArgumentException("无效运算符");}}
}// 配置示例
validation.order.amount=gt:1000

http://www.ppmy.cn/news/1571321.html

相关文章

BS架构(笔记整理)

楔子.基本概念 1.在网络架构中&#xff1a; 服务器通常是集中式计算资源&#xff0c;负责处理和存储数据&#xff1b;客户机是请求这些服务的终端设备&#xff0c;可能是个人电脑或移动设备&#xff1b;浏览器则是客户机上用来与服务器交互的工具&#xff0c;负责展示网页内容…

WebSocket学习记录

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、什么是WebSocket二、为什么需要WebSocket三、WebSocket的工作原理四、如何使用WebSocket总结 前言 本文旨在深入探讨WebSocket协议的基础知识、工作原理以…

Unity3D Shader 简析:变体与缓存详解

引言 在 Unity3D 中&#xff0c;Shader 是渲染管线的核心部分&#xff0c;负责控制物体的外观和材质表现。Shader 的变体&#xff08;Variants&#xff09;和缓存机制是优化渲染性能的关键。本文将深入探讨 Unity3D 中 Shader 变体的概念、缓存机制以及如何通过代码实现和管理…

通过nginx配置解决跨源资源共享(CORS)漏洞

漏洞名称&#xff1a; 跨源资源共享不安全配置漏洞 风险等级&#xff1a; 中 详细描述&#xff1a; 跨源资源共享&#xff08;CORS&#xff09;是一种机制&#xff0c;允许不同源之间的Web资源相互交互。在CORS不安全配置漏洞中&#xff0c;Web应用的服务器被误配置为允许…

13.3 使用 Chat Prompt Template 设计专业翻译提示模板

使用 Chat Prompt Template 设计专业翻译提示模板 关键词:LangChain 翻译模板, 多语言支持, 术语一致性, 动态变量替换, 格式控制 1. 翻译模板核心要素设计 一个专业的翻译提示模板需要包含以下关键组件: 组件作用描述示例片段角色定义明确模型身份“你是一名专业翻译引擎”…

PHP音视频课程培训系统

&#x1f4da; 音视频课程培训系统——为您量身定制的智慧学习空间 &#x1f527; 这是一款匠心独运的课程培训系统&#xff0c;基于ThinkPHP与Uniapp先进框架精心构筑。它不仅集成了音视频课程点播、付费文档获取、活动报名等多元化功能&#xff0c;更致力于为您打造一站式、…

kafka查看topic消息是否堆积

消费kafka topic命令 集群&#xff1a; kafka-console-consumer.sh --zookeeper <ip:2181>,<ip:2181>,<ip:2181> --topic <topic_name>单例&#xff1a; kafka-console-consumer.sh --zookeeper <ip:2181> --topic <topic_name>查看kafka…

鼠标滚轮冒泡事件@wheel.stop

我有一个页面,是在画布上的组件,但是组件中有一个table,table中数据多了,就会出现滚动条,正常情况下,滚动条用鼠标滚轮就可以滑动,但是这个table是在画布上,滚动滚轮会让画布缩放 在table外层的div上加上 wheel.stop,就生效了 wheel.stop 用途&#xff1a;这个修饰符用于处理鼠…