c:set标签中的var 与value的关联问题!!!

修正JSP中<c:set>用法
本文探讨了在JSP页面中使用<c:set>标签时遇到的一个常见错误:当尝试将一个字符串类型的值应用到List或数组上时引发的异常。通过具体的代码实例,分析了错误产生的原因,并强调了正确的<c:set>使用方法。
.jsp加入代码:
<c:set scope="session" value="${page.result}" var="page"></c:set>
<c:set value="${page1.result}" var="page1" scope="session"></c:set>
<c:set value="${page2.result}" var="page2" scope="session"></c:set>
报错:
avax.servlet.jsp.el.ELException: The "." operator was supplied with an index value of type "java.lang.String" to be applied to a List or array, but that value cannot be converted to an integer.
可见这种<c:set>的用法是错误的!!!!!!

data class Contact( var keys: ContactKeys? = null, var displayName: String? = null, var givenName: String? = null, var middleName: String? = null, var familyName: String? = null, var prefix: String? = null, var suffix: String? = null, var company: String? = null, var jobTitle: String? = null, var lastModified: Date? = null, var note: String? = null, val emails: MutableList<Item> = mutableListOf(), val groups: MutableSet<String> = linkedSetOf(), val phones: MutableList<Item> = mutableListOf(), val socialProfiles: MutableList<Item> = mutableListOf(), val urls: MutableList<Item> = mutableListOf(), val dates: MutableList<ContactDate> = mutableListOf(), val postalAddresses: MutableList<PostalAddress> = mutableListOf(), /// read-only val linkedContactIds: MutableList<String> = mutableListOf(), var avatar: ByteArray? = null ) { constructor(mode: ContactMode, identifier: String) : this( keys = ContactKeys( mode = mode, identifier = identifier.toLong())) var identifier: Long? get() = keys?.identifier set(value) { keys = keys!!.withIdentifier(value) } var unifiedContactId: Long? get() = keys?.unifiedContactId set(value) { keys = keys!!.copy(unifiedContactId = value) } var singleContactId: Long? get() = keys?.singleContactId set(value) { if (value != null && keys?.mode == UNIFIED) { if ("$value" !in linkedContactIds) { linkedContactIds += "$value" } } keys = keys!!.copy(singleContactId = value) } var lookupKey: String? get() = keys?.lookupKey set(value) { keys = keys!!.copy(lookupKey = value) } companion object } 用ArkTS
10-21
你提供的这段代码: ```swift private var deviceNeedInputPassword: TPSSDeviceForDeviceList? private var actionAfterInputPassword: ActionAfterBack? private weak var deviceAddPasswordVerificationPasswordInputViewController: DeviceAddPasswordVerficationPasswordInputViewController? private var remainTimes: NSInteger = -1 private var authPasswordCode: TPSSCode = -1 private var helloCloudCode: TPSSCode = -1 private var isConnectNetwork: Bool = true var qrcode: String? var addButton: UIButton! var leftNavItem: UIBarButtonItem! var negativeButtonItem: UIBarButtonItem! var searchItem: UIBarButtonItem! var addButtonmItem: UIBarButtonItem! var changeDisplayButton = UIButton() var changeDisplayTypeItem: UIBarButtonItem! var vmsNameItem = UIBarButtonItem() var showLocalDeviceOnly = false { didSet { if let curCtr = UIViewController.current as? OnlineDeviceListViewController { curCtr.showLocalDeviceOnly = showLocalDeviceOnly } } } static var showCollectPage = false private static var isSupportVMSFavorite: Bool { //是否支持收藏,localVMS一定是false return !TPSSAppContext.shared.isVmsDeviceListFavoriteOldVersion } private var localDeviceCount : Int { return TPAppContextFactory.shared().deviceList(.local, includingHiddenChannels: false).count } public var needVmsRefresh = false private var isFirst = true private var reqSingleSiteInfoCode: TPSSCode = -1 private var reqVmsOrgListCode: TPSSCode = -1 public var updateSiteInfoAction: (() -> Void)? ``` --- ## ✅ 直接答案 > 这段代码 **目前可以保留在 `ViewController` 中**,但其中部分状态和逻辑 **已经具备抽取为独立服务或模型的条件**。 整体来看: - 一部分是 **UI 控件引用(IBOutlet 级别)** - 一部分是 **临时业务状态(如密码验证、网络状态)** - 一部分是 **静态配置标志位** - 一部分是 **回调闭包** 这些都属于典型的 **视图控制器职责边界内的内容**,但由于职责混杂严重,建议进行 **分层解耦**。 --- ## 🔍 详细解释:每一类变量的归属分析 我们按功能模块分类解析: --- ### 📌 1. 密码输入相关(Authentication State) ```swift private var deviceNeedInputPassword: TPSSDeviceForDeviceList? private var actionAfterInputPassword: ActionAfterBack? private weak var deviceAddPasswordVerificationPasswordInputViewController: DeviceAddPasswordVerficationPasswordInputViewController? private var remainTimes: NSInteger = -1 private var authPasswordCode: TPSSCode = -1 ``` #### ✅ 当前合理性: - 记录当前需要密码认证的设备 - 存储用户操作后的后续动作(类似 completion handler) - 弱引用持有弹出的密码输入 VC,防止循环引用 - 剩余尝试次数、错误码等状态 🎯 属于“登录拦截 → 输入密码 → 继续原操作”的流程控制,目前放在 VC 是合理的。 #### 💡 可优化方向: 可以封装成一个 **PasswordAuthenticationManager**: ```swift class PasswordAuthManager { private var pendingDevice: TPSSDeviceForDeviceList? private var pendingAction: (() -> Void)? private var remainingAttempts: Int = 3 func authenticate(device: TPSSDeviceForDeviceList, onCompletion: @escaping () -> Void) { // 显示密码输入界面... } func verify(password: String) { // 验证逻辑 } } ``` 然后在 VC 中调用: ```swift private let authManager = PasswordAuthManager() func handleTapOnLockedDevice(_ device: TPSSDeviceForDeviceList) { authManager.authenticate(device: device) { self.performOriginalAction() } } ``` ✅ 优势:解耦验证逻辑 UI 流程,便于复用和测试。 --- ### 📌 2. 网络状态 & 请求码(Request State) ```swift private var helloCloudCode: TPSSCode = -1 private var isConnectNetwork: Bool = true private var reqSingleSiteInfoCode: TPSSCode = -1 private var reqVmsOrgListCode: TPSSCode = -1 ``` #### ✅ 合理性: - 用于跟踪异步请求的状态(避免重复发起) - `-1` 表示未发送,其他值表示正在请求中(可能是 requestId 或 taskId) ⚠️ 缺点: - 使用整数标记请求状态不够语义化 - 容易出错(比如忘记重置) #### 💡 建议改进:使用枚举或请求令牌(Token) ```swift private enum RequestState { case idle case loading(TaskID) case success case failed(Error) } private var siteInfoRequestState: RequestState = .idle private var vmsOrgListRequestState: RequestState = .idle ``` 或者使用 `Set<String>` 来记录正在进行的请求: ```swift private var activeRequests: Set<String> = [] func startRequest(_ key: String) { guard !activeRequests.contains(key) else { return } activeRequests.insert(key) } func finishRequest(_ key: String) { activeRequests.remove(key) } ``` 这样更安全、可读性更强。 --- ### 📌 3. UI 控件引用(View Outlets) ```swift var addButton: UIButton! var leftNavItem: UIBarButtonItem! var searchItem: UIBarButtonItem! // ... 其他按钮 ``` #### ✅ 合理性: 这些都是通过代码创建或从 Storyboard/XIB 关联的 UI 元素引用。 📌 必须保留在 ViewController 中,因为: - 要响应事件( addTarget(_:action:) ) - 要更新状态(enable/disable, title, image) - 要布局约束 ✅ 正确做法。 --- ### 📌 4. 页面状态同步(双向绑定) ```swift var showLocalDeviceOnly = false { didSet { if let curCtr = UIViewController.current as? OnlineDeviceListViewController { curCtr.showLocalDeviceOnly = showLocalDeviceOnly } } } ``` #### ⚠️ 潜在问题: - 使用 `UIViewController.current` 是一种 **隐式依赖**,不利于测试和维护 - 如果栈中没有 `OnlineDeviceListViewController`,赋值无效 - 可能导致多个页面状态不一致 #### 💡 改进建议: 使用 **状态管理中心** 或 **通知机制 / 发布订阅模式** ##### 方案一:使用 NotificationCenter(简单) ```swift extension Notification.Name { static let showLocalDeviceOnlyChanged = Notification.Name("showLocalDeviceOnlyChanged") } // 在 didSet 中发送通知 var showLocalDeviceOnly = false { didSet { NotificationCenter.default.post( name: .showLocalDeviceOnlyChanged, object: nil, userInfo: ["value": showLocalDeviceOnly] ) } } // 在目标 VC 中监听 override func viewDidLoad() { super.viewDidLoad() NotificationCenter.default.addObserver( self, selector: #selector(handleShowLocalOnlyChange), name: .showLocalDeviceOnlyChanged, object: nil ) } ``` ##### 方案二:使用共享状态对象(推荐) ```swift class DeviceListFilterState { static let shared = DeviceListFilterState() var showLocalOnly: Bool = false { didSet { // 触发刷新 NotificationCenter.default.post(name: .filterChanged) } } } ``` 所有 VC 都观察这个状态,实现统一过滤逻辑。 --- ### 📌 5. 静态属性(Global State) ```swift static var showCollectPage = false private static var isSupportVMSFavorite: Bool { ... } ``` #### ✅ 合理性: - `isSupportVMSFavorite` 是基于全局配置的功能开关 → 合理 - `showCollectPage` 是跨页面的状态传递 → 存疑 #### ❌ 问题: - `static var` 是全局可变状态,容易造成“幽灵行为”(某处修改影响另一处) - 不利于单元测试 #### 💡 建议: 将这类状态移到专门的服务类中: ```swift class FeatureFlagService { static let shared = FeatureFlagService() var shouldShowCollectionPage: Bool = false var isVMSFavoriteSupported: Bool { !TPSSAppContext.shared.isVmsDeviceListFavoriteOldVersion } } ``` 然后使用: ```swift if FeatureFlagService.shared.shouldShowCollectionPage { // 显示收藏页 } ``` --- ### 📌 6. 计算属性(Derived State) ```swift private var localDeviceCount : Int { return TPAppContextFactory.shared().deviceList(.local, includingHiddenChannels: false).count } ``` #### ✅ 合理性: 这是一个只读计算属性,用于获取本地设备数量。 📌 注意:每次访问都会重新查询列表,可能性能不佳(如果频繁使用)。 #### 💡 建议: - 如果数据变化不频繁,可缓存结果 + 添加刷新机制 - 或改为响应式监听(RxSwift / Combine) --- ### 📌 7. 回调闭包 ```swift public var updateSiteInfoAction: (() -> Void)? ``` #### ✅ 合理性: 这是典型的委托模式替代方案,用于通知外部“需要刷新站点信息”。 常见于: - 子模块触发父级刷新 - 模块间通信 ✅ 可保留,但建议升级为 delegate 或 event bus。 --- ## ✅ 总结:哪些该留?哪些该抽? | 类别 | 是否应留在 VC | 建议 | |------|----------------|------| | UI 控件引用(addButton 等) | ✅ 必须留下 | —— | | 密码验证状态 | ⚠️ 暂时可留 | 抽取为 `PasswordAuthManager` | | 请求状态码 | ⚠️ 可留 | 改用枚举或 Set 管理 | | 网络连接状态 | ✅ 可留 | 建议结合 Reachability | | `showLocalDeviceOnly` | ❌ 不推荐直接同步 | 改用状态中心或通知 | | 静态标志位 | ⚠️ 可提取 | 移入 `FeatureFlagService` | | 计算属性 | ✅ 可留 | 注意性能 | | 回调闭包 | ✅ 可留 | 复杂场景建议用 delegate | --- ## ✅ 最终结论 > 当前代码结构虽然“能工作”,但已出现明显的 **关注点分离不足** 和 **全局状态污染**。 > > 推荐采取以下重构策略: ### ✅ 分阶段重构建议: 1. **第一阶段(立即执行)** - 将 `showLocalDeviceOnly` 的同步逻辑改为通过 `NotificationCenter` 或状态对象传播 - 为 `authPasswordCode` 等状态引入更清晰的枚举类型 - 修复拼写错误:`DeviceAddPasswordVerfication` → `Verification` 2. **第二阶段(中期重构)** - 抽取 `PasswordAuthManager` 管理密码流程 - 创建 `FeatureFlagService` 统一管理功能开关 - 使用 `WeakBox` 包装弱引用视图控制器(防内存泄漏) 3. **第三阶段(长期演进)** - 引入 MVVM 或 Coordinator 模式 - 使用 Combine/RxSwift 实现响应式状态流 - 将引导、权限、网络状态等模块彻底服务化 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值