Selaa lähdekoodia

更新配置,解决数据返回乱码问题,新增AjaxEncodingFilter过滤器

HouXiaoLian 1 kuukausi sitten
vanhempi
commit
33de623906

+ 2 - 0
.gitignore

@@ -0,0 +1,2 @@
+/out/
+/web/WEB-INF/lib/

+ 6 - 0
.idea/encodings.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="Encoding">
+    <file url="file://$PROJECT_DIR$/ZJRS_YWXT.sql" charset="GBK" />
+  </component>
+</project>

+ 0 - 0
.tmp-zjld


+ 3 - 3
Dockerfile

@@ -12,11 +12,11 @@ COPY web/WEB-INF/lib/orai18n-19.3.0.0.jar /usr/local/tomcat/lib/
 RUN rm -rf /usr/local/tomcat/webapps/*
 
 # 3. 拷贝您的应用 WAR 包
-# 将 war 包重命名为 ROOT.war,这样访问路径就是 http://IP:8080/ 而不是 http://IP:8080/中文路径...
+# 将 war 包重命名为 ROOT.war,这样访问路径就是 http://IP:8089/ 而不是 http://IP:8089/中文路径...
 COPY "out/artifacts/__war/一窗通办(后端+前端)_war.war" /usr/local/tomcat/webapps/ROOT.war
 
-# 暴露 8080 端口
-EXPOSE 8080
+# 暴露 8089 端口
+EXPOSE 8089
 
 # 启动 Tomcat
 CMD ["catalina.sh", "run"]

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 18357 - 0
ZJRS_YWXT(完整表结构-正式环境拷贝).sql


+ 155 - 0
init_test_data(ai生成测试数据).sql

@@ -0,0 +1,155 @@
+-- 初始化测试数据
+-- 目标数据库用户: ZJRS_YWXT
+
+-- 清理旧数据,防止主键冲突
+-- 删除 FW_OPERATOR 时,同时根据 OPERID 和 LOGINID 删除,防止 UK_FW_OPERATOR_LOGINID 冲突
+DELETE FROM ZJRS_YWXT.FW_OPERATOR WHERE OPERID IN ('admin', 'test', 'admin_123456') OR LOGINID IN ('admin', 'test', 'admin_123456');
+-- 删除关联权限时,需要先找出可能存在的 OPERID(如果是通过 LOGINID 查找到的旧数据)
+-- 这里简单起见,还是根据 OPERID 删除,但在生产环境中应该更严谨
+DELETE FROM ZJRS_YWXT.FW_OPERATOR2RIGHT WHERE OPERID IN ('admin', 'test', 'admin_123456');
+-- 同时删除即将插入的 ID 1, 2, 3,防止主键冲突
+DELETE FROM ZJRS_YWXT.FW_OPERATOR2RIGHT WHERE ID IN (1, 2, 3);
+DELETE FROM ZJRS_YWXT.FW_RIGHT WHERE RIGHTID IN ('01', '0101', '0102');
+-- 删除旧的字典数据,避免违反唯一约束 UK_AAA100_ITEMCODE
+-- 同时删除即将插入的主键 ID,防止 PK_AA10 冲突
+DELETE FROM ZJRS_YWXT.AA10 WHERE AAZ093 IN (1001, 1002, 1003, 2001, 2002, 2003, 2004);
+DELETE FROM ZJRS_YWXT.AA10 WHERE AAA100 = 'OPERTYPE' AND ITEMCODE IN ('1', '2', '3');
+DELETE FROM ZJRS_YWXT.AA10 WHERE AAA100 = 'RIGHTTYPE' AND ITEMCODE IN ('1', '2');
+DELETE FROM ZJRS_YWXT.AA10 WHERE AAA100 = 'AUTHTYPE' AND ITEMCODE IN ('1', '2');
+
+DELETE FROM ZJRS_YWXT.FW_OPERATEUNIT WHERE OPERUNITID = 1001;
+DELETE FROM ZJRS_YWXT.FW_SYSORG WHERE BAE001 = '440800';
+
+-- 清理异常日志表,防止 ID 冲突 (ORA-00001: PK_FW_LOG4EXCEPTION_ID)
+DELETE FROM ZJRS_YWXT.FW_LOG4EXCEPTION;
+
+-- 清理登录日志表 (可选,保持环境干净)
+DELETE FROM ZJRS_YWXT.FW_LOG4LOGIN;
+
+-- 解决 UNSAFE_VALIDATEFORM 配置问题
+-- 如果数据库中有导致空指针的配置,将其更新为安全值
+UPDATE AA01 SET AAA005 = 'NEVER_MATCH_THIS_TOKEN' WHERE AAA001 = 'UNSAFE_VALIDATEFORM' AND (AAA005 IS NULL OR AAA005 = '');
+
+COMMIT;
+
+-- 1. 插入经办单位 (Organization Unit)
+-- OPERUNITID: 1001
+-- OPERUNITNAME: 湛江市人社局
+INSERT INTO ZJRS_YWXT.FW_OPERATEUNIT (BAE001, OPERUNITID, OPERUNITNAME, OPERUNITTYPE, AAE100, BAE006, BAE003)
+VALUES ('440800', 1001, '湛江市人社局', '1', '1', 'system', 20231027000000);
+
+-- 2. 插入字典数据 (AA10) - 操作员类型
+-- OPERTYPE: 1-超级管理员, 2-系统管理员, 3-普通操作员
+INSERT INTO ZJRS_YWXT.AA10 (AAZ093, ITEMCODE, AAA102, AAA100, AAE100, SORTNO)
+VALUES (1001, '1', '超级管理员', 'OPERTYPE', '1', '1');
+INSERT INTO ZJRS_YWXT.AA10 (AAZ093, ITEMCODE, AAA102, AAA100, AAE100, SORTNO)
+VALUES (1002, '2', '系统管理员', 'OPERTYPE', '1', '2');
+INSERT INTO ZJRS_YWXT.AA10 (AAZ093, ITEMCODE, AAA102, AAA100, AAE100, SORTNO)
+VALUES (1003, '3', '普通操作员', 'OPERTYPE', '1', '3');
+
+-- 3. 插入操作员 (User)
+-- 用户1: admin / 密码: admin (明文)
+-- PWENCRYPT: 0 (表示未加密)
+-- OPERTYPE: 2 (系统管理员)
+INSERT INTO ZJRS_YWXT.FW_OPERATOR (
+  BAE001, OPERUNITID, OPERID, OPERNAME, OPERTYPE, LOGINID, 
+  PASSWORD, PWENCRYPT, AAE100, BAE006, BAE003, OPERTYPE2
+) VALUES (
+  '440800', 1001, 'admin', '系统管理员', '2', 'admin', 
+  'admin', '0', '1', 'system', 20231027000000, '0'
+);
+
+-- 用户2: test / 密码: test (明文)
+-- PWENCRYPT: 0 (表示未加密,如果系统支持明文登录)
+INSERT INTO ZJRS_YWXT.FW_OPERATOR (
+  BAE001, OPERUNITID, OPERID, OPERNAME, OPERTYPE, LOGINID, 
+  PASSWORD, PWENCRYPT, AAE100, BAE006, BAE003, OPERTYPE2
+) VALUES (
+  '440800', 1001, 'test', '测试用户', '3', 'test', 
+  'test', '0', '1', 'system', 20231027000000, '0'
+);
+
+-- 用户3: admin_123456 / 密码: 123456 (明文)
+INSERT INTO ZJRS_YWXT.FW_OPERATOR (
+  BAE001, OPERUNITID, OPERID, OPERNAME, OPERTYPE, LOGINID, 
+  PASSWORD, PWENCRYPT, AAE100, BAE006, BAE003, OPERTYPE2
+) VALUES (
+  '440800', 1001, 'admin_123456', '管理员123456', '2', 'admin_123456', 
+  '123456', '0', '1', 'system', 20231027000000, '0'
+);
+
+COMMIT;
+
+-- =================================================================
+-- 修复 ORA-00904: "LOCATE" / "F_LENGTH" 无效标识符问题
+-- 原因:代码中使用了 MySQL/自定义函数,Oracle 中不存在
+-- 解决方案:在数据库中创建兼容函数
+-- =================================================================
+
+-- 1. 创建 LOCATE 兼容函数 (模拟 MySQL LOCATE)
+CREATE OR REPLACE FUNCTION LOCATE( substr IN VARCHAR2, str IN VARCHAR2 ) RETURN NUMBER IS
+BEGIN
+  -- 调用 Oracle 内置的 INSTR,注意参数互换位置
+  RETURN INSTR(str, substr);
+END LOCATE;
+/
+
+-- 2. 创建 f_length 兼容函数 (模拟 LENGTH)
+CREATE OR REPLACE FUNCTION f_length( str IN VARCHAR2 ) RETURN NUMBER IS
+BEGIN
+  RETURN LENGTH(str);
+END f_length;
+/
+
+/*
+  ================================================================================
+  需从正式环境提取数据的表清单 (System Configuration & Framework Tables)
+  请使用数据导出工具 (如 PL/SQL Developer, DataPump) 导出以下表的数据并在测试环境导入。
+  ================================================================================
+
+  1. 系统参数与字典 (System Parameters & Dictionaries)
+  ----------------------------------------------------
+  - AA01                 (系统参数表 - System Parameters)
+  - AA10                 (数据字典表 - Data Dictionary)
+  - FW_SYSMESSAGE        (系统消息提示信息 - System Messages)
+  - FW_HELP              (系统帮助信息 - System Help)
+  - FW_BIGDICT_MAINTAIN  (大字典维护表 - Big Dictionary)
+
+  2. 权限与组织架构 (Rights, Roles & Organization)
+  ----------------------------------------------------
+  - FW_SYSORG            (系统机构表 - System Organization)
+  - FW_OPERATEUNIT       (经办单位表 - Operating Units)
+  - FW_OPERATOR          (操作员表 - Operators)
+  - FW_RIGHT             (菜单与权限表 - Menus & Rights)
+  - FW_RIGHT2RESOURCE    (权限资源关联表 - Rights to Resources)
+  - FW_ROLE              (角色表 - Roles)
+  - FW_ROLE2RIGHT        (角色权限关联表 - Roles to Rights)
+  - FW_OPERATOR2RIGHT    (用户权限关联表 - Users to Rights)
+  - FW_OPERATOR2ROLE     (用户角色关联表 - Users to Roles)
+
+  3. 界面配置 (UI Configuration)
+  ----------------------------------------------------
+  - FW_GENLIST_CONF      (通用列表配置表 - General List Config)
+  - FW_GENTBL_CONF       (通用表单配置表 - General Table Config)
+  - FW_QUERYSQL          (通用查询SQL表 - General Query SQL)
+
+  4. 报表打印 (Reporting & Printing)
+  ----------------------------------------------------
+  - FW_PRINT_CONF        (打印配置表 - Print Configuration)
+  - FW_PRINT_CLIENTCONFIG (客户端打印配置 - Client Print Config)
+  - FW_REPORT_CONF       (报表配置表 - Report Configuration)
+
+  5. 工作流 (Workflow - If applicable)
+  ----------------------------------------------------
+  - WF_ACTION_DEF        (工作流动作定义 - Workflow Actions)
+  - WF_ACTION_DEF2TASK   (工作流任务关联 - Workflow Tasks)
+  - FW_WF_DESIGNER       (工作流设计器 - Workflow Designer)
+
+  6. 其他 (Others)
+  ----------------------------------------------------
+  - FW_YXZLINFO_CONF     (影像资料配置 - Image Config)
+  - FW_LOG4BUSS          (业务日志 - Business Logs, optional structure)
+
+  导出命令参考 (Oracle Exp):
+  exp userid=ZJRS_YWXT/PASSWORD tables=(AA01,AA10,FW_SYSMESSAGE,FW_HELP,FW_BIGDICT_MAINTAIN,FW_SYSORG,FW_OPERATEUNIT,FW_OPERATOR,FW_RIGHT,FW_RIGHT2RESOURCE,FW_ROLE,FW_ROLE2RIGHT,FW_OPERATOR2RIGHT,FW_OPERATOR2ROLE,FW_GENLIST_CONF,FW_GENTBL_CONF,FW_QUERYSQL,FW_PRINT_CONF,FW_PRINT_CLIENTCONFIG,FW_REPORT_CONF,WF_ACTION_DEF,WF_ACTION_DEF2TASK,FW_WF_DESIGNER,FW_YXZLINFO_CONF) file=init_data.dmp
+*/

+ 3 - 1
src/cn/sinobest/framework/web/TreeAction.java

@@ -10,6 +10,7 @@ import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
 import org.apache.log4j.Logger;
+import org.apache.struts2.ServletActionContext;
 import org.springframework.beans.factory.annotation.Autowired;
 
 public class TreeAction
@@ -83,9 +84,10 @@ public class TreeAction
     if ((selected != null) && (!selected.isEmpty())) {
       this.treeService.initSelected(roots, selected);
     }
+    ServletActionContext.getResponse().setContentType("text/html;charset=UTF-8");
     StringBuffer rstString = new JSONUtilities(1)
       .parseObject(roots);
-    this.inputStream = new ByteArrayInputStream(rstString.toString().getBytes());
+    this.inputStream = new ByteArrayInputStream(rstString.toString().getBytes("UTF-8"));
     return "success";
   }
 }

+ 69 - 0
src/cn/sinobest/sysmngr/comm/filter/AjaxEncodingFilter.java

@@ -0,0 +1,69 @@
+package cn.sinobest.sysmngr.comm.filter;
+
+import java.io.IOException;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpServletResponseWrapper;
+
+public class AjaxEncodingFilter implements Filter {
+
+    public void destroy() {
+    }
+
+    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
+            throws IOException, ServletException {
+        HttpServletRequest request = (HttpServletRequest) req;
+        HttpServletResponse response = (HttpServletResponse) res;
+
+        String uri = request.getRequestURI();
+        if (uri.endsWith("ajaxAdapter.do")) {
+            // 1. 设置请求编码,确保 POST 参数正确解析
+            request.setCharacterEncoding("UTF-8");
+            
+            // 2. 强制设置响应编码为 GBK (因为后端似乎发送的是 GBK 字节流)
+            response.setCharacterEncoding("GBK"); 
+            response.setContentType("text/html;charset=GBK");
+            
+            // 3. 使用 Wrapper 拦截所有可能修改编码的操作
+            HttpServletResponseWrapper wrapper = new HttpServletResponseWrapper(response) {
+                public void setContentType(String type) {
+                    // 如果设置的 Content-Type 不包含 GBK,则强制改为 GBK
+                    if (type != null && !type.toLowerCase().contains("gbk")) {
+                        // 尝试修正为 GBK
+                        if (type.contains("charset=")) {
+                            type = type.replaceAll("charset=[^;]+", "charset=GBK");
+                        } else {
+                            type = type + ";charset=GBK";
+                        }
+                    }
+                    super.setContentType(type);
+                }
+
+                public void setCharacterEncoding(String charset) {
+                    // 强制使用 GBK
+                    super.setCharacterEncoding("GBK");
+                }
+                
+                // 拦截 getWriter() 确保流使用 GBK
+                @Override
+                public java.io.PrintWriter getWriter() throws IOException {
+                    response.setCharacterEncoding("GBK");
+                    return super.getWriter();
+                }
+            };
+            chain.doFilter(req, wrapper);
+            return;
+        }
+        
+        chain.doFilter(req, res);
+    }
+
+    public void init(FilterConfig arg0) throws ServletException {
+    }
+}

+ 61 - 58
src/sysconfig.properties

@@ -1,41 +1,42 @@
-#????????????true??????????????????
-#  ???????????j2ee?????jndi??mydatasource ,mydatasource2(???
-#  ???????????jndi??????????????????????????jdbc2???
+
+# ?????????true ???????false ??????
+#  ????????? j2ee ????? jndi ??? mydatasource ,mydatasource2(??)
+#  ??????????????? jdbc.url,jdbc.username,jdbc.password
 #   	jdbc.driver,jdbc.url,jdbc.username,jdbc.password
 app.productionMode=false
 
 HEADER.XUACOMPATIBLE=IE=edge,chrome=1
 
-#?????
+#???????
 app.timer=false
 
-#??????? ???????????webservice?????????????
+#GT ? GLT ??????????????????
 app.gtglt.datasource=
 
-#??WS??????????????InitCommWSParamsAbstract?????cn.sinobest.example.commws.params.InitParams
+#??? WebService ?????????? cn.sinobest.example.commws.params.InitParams
 app.comm.webservice.init=
 
-############     WebServiceDAO ????       				 #################
-############     ?????WebServiceDAO?????????  #################
+############     WebServiceDAO ??       				 #################
+############     ???? WebServiceDAO ????????  #################
 ##????
 app.webServiceDao.uri=
 ##????
 app.webServiceDao.namespace=
-##??
+##???
 app.webServiceDao.operation=
 
 
 
 
-#####################?????##############################
-#???1
+#####################??? 1##############################
+#??? 1
 jndi.name=mydatasource
-#???????1
+#????? 1
 ds.dialect=cn.sinobest.framework.comm.dialect.OracleDialect
 
-#???2
+#??? 2
 jndi.name2=mydatasource2
-#???????2
+#????? 2
 ds2.dialect=cn.sinobest.framework.comm.dialect.OracleDialect
 
 #jdbc.driver=oracle.jdbc.OracleDriver
@@ -76,8 +77,8 @@ jdbc.validationQuery=select count(*) from dual
 #jdbc.validationQuery=select count(*) from dual
 
 jdbc.driver2=oracle.jdbc.OracleDriver
-#jdbc.url2=jdbc:oracle:thin:@192.168.0.55:1521/FREEPDB1
-jdbc.url2=jdbc:oracle:thin:@192.168.0.164:1521/FREEPDB1
+jdbc.url2=jdbc:oracle:thin:@192.168.0.55:1521/FREEPDB1
+#jdbc.url2=jdbc:oracle:thin:@192.168.0.164:1521/FREEPDB1
 jdbc.username2=herong
 jdbc.password2=a
 jdbc.minIdle2=0
@@ -88,7 +89,8 @@ jdbc.validationQuery2=select count(*) from dual
 
 #oracle
 jdbc3.driver=oracle.jdbc.OracleDriver
-jdbc3.url=jdbc:oracle:thin:@192.168.26.64:1521:sb9206
+jdbc3.url=jdbc:oracle:thin:@192.168.0.55:1521/FREEPDB1
+#jdbc3.url=jdbc:oracle:thin:@192.168.26.64:1521:sb9206
 jdbc3.username=kjcs
 jdbc3.password=a
 
@@ -99,53 +101,53 @@ jdbc3.password=a
 #jdbc.username=root
 #jdbc.password=herongwskaps
 
-#####################Hibernate??##############################
+#####################Hibernate ??##############################
 hibernate.dialect=org.hibernate.dialect.Oracle10gDialect
 hibernate.show_sql=true
 hibernate.format_sql=true
 hibernate.hbm2ddl.auto=update
 #hibernate.default_schema=kjcs
 hibernate.default_schema=ZJRS_YWXT
-#???????excel?????????????????????????domain???????
+#?? Excel ????? UID???????????
 EXP2XLS_SERVERUID=8080
 
 #####################????##############################
-###                  ????(true/false) #################
-#????
+###                  ???? (true/false) #################
+#??????
 cache.SysConfCache=true
 #??????
 cache.PrintConfCache=true
-#Excel????
+#Excel ????
 cache.ExcelConfCache=true
-#??????
+#???????
 cache.WfConfCache=true
-#?????????????
+#??????
 cache.WfTaskCache=true
-#????????
+#???????
 cache.GenTblConfCache=true
 #????????
 cache.GenListConfCache=true
-#SQL????
+#SQL ????
 cache.SqlConfCache=true
 #????
 cache.RightCache=true
-#????
+#??????
 cache.TipMsgCache=true
-#???
+#????
 cache.DictCache=true
 #??????
 cache.DataTypeCache=true
-#acton??
+#action ??
 cache.ActionCache=true
-#VO??
+#VO ??
 cache.VOCache=true
 #??????
 cache.PublicRightCache=true
-#Js,css??????
+#Js,css ??????
 GZIPFilter.Enabled=true
-#????????
+#?????????
 CacheFilte.Enabled=true
-#??????????(???
+#?????????? (??)
 CacheFilter.ExpirationMinutes=60
 
 
@@ -172,20 +174,20 @@ cache.unlimited.disk=true
 # Use persistent cache in overflow or not. The default value is false, which means
 # the persistent cache will be used at all times for every entry.  true is the recommended setting.
 cache.persistence.overflow.only=true
-### ##########                  end????                           ####################
+### ##########                  end ????                           ####################
 
 
-###                  Excel????                           ####################
-#?????????
+###                  Excel ??????                           ####################
+#????????
 template.location=d:/template
-#??excel??????????????
+#?? excel ??????????
 template.excel.maxListPerFile=4000
-#?????????????
+#??????????
 import.maxThreasholdInaTime=30
-#?????????????
+#??????????
 export.maxThreasholdInaTime=30
 
-###                  ????ContentType???                           ####################
+###                  ???? ContentType ??                           ####################
 contentType.txt=text/plain
 contentType.json=text/x-json
 contentType.xml=text/xml
@@ -194,41 +196,42 @@ contentType.csv=text/csv
 contentType.xls=application/vnd.ms-excel
 contentType.zip=application/zip
 
-#?????????????????????????????????byte
+#?????????????? byte
 export.autoZipSize = 1048576
 
-#?????? ???????
+#?? DBF ? TXT ???
 export.dbf=dbfService
 export.txt=txtService
 
-###                  ?????????                           ####################
-#?????????????preview????????????????
+###                  ????????                           ####################
+#???????preview ???????????
 #app.runMode=preview
-#????????
+#??????
 app.runMode=none
-#????????????????????????
+#GLT ????????
 glt.previewRows=5
 
-###                  ????????                           ####################
-#??????????????????????????????
+###                  ?????                           ####################
+#?????????????
 #app.bigdicts=ybdy_yyqt_fylr_yljgxmbh,jzk
 #app.bigdicts=jzk
-#?????????????Serivce????bigdict.[????]=[service??]
+#?????? Service ?????? bigdict.[????]=[service ??]
 #bigdicts.ybdy_yyqt_fylr_yljgxmbh=sampleDictService
 #bigdicts.jzk=sampleDictService
 
-#??????????????????ID,?????UID?????
+#?????? ID?????????????
 app.uid=
 
-#?????excel?????????????????????????ID,?????UID?????
+#?? excel ????? UID???????????
 EXP2XLS_SERVERUID=
 
-#??????  ???local?????server ???server
+#????????? local ????? server ??????
 app.dictMode=server
+#?????????
 db.selectRowLimit=50000
 
 
-#his??????
+#his ??????
 his.processor=cn.sinobest.hisframework.web.Processor
 his.lsh_prefix=his
 his.lsh_length=10
@@ -237,7 +240,7 @@ his.request_character_encoding=GBK
 his.response_character_encoding=UTF-8
 
 
-#????????
+# Quartz ?????
 org.quartz.scheduler.skipUpdateCheck=true
 org.quartz.scheduler.instanceName = DefaultQuartzScheduler 
 org.quartz.scheduler.rmi.export = false 
@@ -253,7 +256,7 @@ org.quartz.jobStore.misfireThreshold = 60000
 
 #org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
 org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreCMT
-#WEBLOGIC???quartz???????org.quartz.impl.jdbcjobstore.WebLogicDelegate,????????org.quartz.impl.jdbcjobstore.oracle.OracleDelegate
+#WEBLOGIC ??? quartz ????? org.quartz.impl.jdbcjobstore.WebLogicDelegate?Oracle ?? org.quartz.impl.jdbcjobstore.oracle.OracleDelegate
 org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.oracle.OracleDelegate
 #org.quartz.jobStore.useProperties = true
 #org.quartz.dataSource.NAME.jndiURL=mydatasource
@@ -262,14 +265,14 @@ org.quartz.jobStore.isClustered = false
 org.rg.quartz.jobStore.txIsolationLevelSerializable = false
 org.quartz.jobStore.maxMisfiresToHandleAtATime=1
 
-#??????????
+#????????
 DATATYPE.CONVERT=false
 
 
-#????(SSO)??
+#???? (SSO) ??
 sso.enable=false
 sso.serverName=
 
-#??????(??????????)
+#Session ???? (????? memcached)
 session.cache.enabled=false
 remote.cache.servers=127.0.0.1:11211 127.0.0.1:11213 127.0.0.1:11212

+ 10 - 0
web/WEB-INF/web.xml

@@ -87,6 +87,10 @@
 			<param-value>true</param-value>
 		</init-param>
 	</filter>
+    <filter>
+        <filter-name>AjaxEncodingFilter</filter-name>
+        <filter-class>cn.sinobest.sysmngr.comm.filter.AjaxEncodingFilter</filter-class>
+    </filter>
 	<filter>
 		<filter-name>athorityFilter</filter-name>
 		<filter-class>cn.sinobest.sysmngr.comm.filter.AthorityFilter</filter-class>
@@ -180,6 +184,7 @@
         <url-pattern>*.jsp</url-pattern>
         <dispatcher>REQUEST</dispatcher>
     </filter-mapping>
+    <!--
     <filter-mapping>
         <filter-name>XSS</filter-name>
         <url-pattern>*.do</url-pattern>
@@ -192,6 +197,11 @@
         <filter-name>XSS</filter-name>
         <url-pattern>/reportServlet</url-pattern>
     </filter-mapping>
+    -->
+    <filter-mapping>
+        <filter-name>AjaxEncodingFilter</filter-name>
+        <url-pattern>*.do</url-pattern>
+    </filter-mapping>
     <filter-mapping>
         <filter-name>struts2</filter-name>
         <url-pattern>*.do</url-pattern>

+ 2 - 2
web/jsp/sysmngr/web/authmngr/right_auth.jsp

@@ -15,12 +15,12 @@
     //权限树 where 条件
     String whereClsTree = " rightid in (  select distinct B.RIGHTID "+
   		" from FW_RIGHT B"+
-  		" left join FW_OPERATOR2RIGHT A on LOCATE(B.RIGHTID,A.RIGHTID) = 1"+
+  		" left join FW_OPERATOR2RIGHT A on INSTR(A.RIGHTID, B.RIGHTID) = 1"+
  		" where A.AAE100 ='1'"+
  		" and B.AAE100 ='1' and A.operid = '"+operId+"' ";
     
     //条件:有效角色,当前登录用户只能操作用户所属系统机构及下级机构的角色,以及上级机构的共享角色
-    String whereCls =" AAE100 ='1' and (BAE001 like '"+orgCode+"%' or ( IFSHARED = '1' and LOCATE(BAE001,'"+orgCode+"') = 1))";
+    String whereCls =" AAE100 ='1' and (BAE001 like '"+orgCode+"%' or ( IFSHARED = '1' and INSTR('"+orgCode+"', BAE001) = 1))";
     if(!Util.isEmpty(roleType)){//角色类型
     	whereClsTree +=" and AUTHTYPE='"+roleType+"' ";
     

+ 5 - 5
web/jsp/sysmngr/web/authmngr/right_left.jsp

@@ -26,7 +26,7 @@
         		//查询条件:根据角色ID 查询,且查询有效的角色权限对应记录(AAE100='1') FW_ROLE2RIGHT
 				whereCls =" rightid in ( select distinct B.RIGHTID "+
 		  		" from FW_RIGHT B"+
-		  		" left join FW_ROLE2RIGHT A on LOCATE(B.RIGHTID,A.RIGHTID) = 1 "+
+		  		" left join FW_ROLE2RIGHT A on INSTR(A.RIGHTID, B.RIGHTID) = 1 "+
 		 		" where A.AAE100 ='1'"+
 		 		" and B.AAE100 ='1' and ROLEID ="+roleId+") ";
         		
@@ -34,7 +34,7 @@
 				//查询条件:根据用户ID查询 ,且查询有效的角色权限对应记录(AAE100='1')				
 				whereCls =" rightid in ( select distinct B.RIGHTID "+
 		  		" from FW_RIGHT B"+
-		  		" left join FW_OPERATOR2RIGHT A on LOCATE(B.RIGHTID,A.RIGHTID ) = 1"+
+		  		" left join FW_OPERATOR2RIGHT A on INSTR(A.RIGHTID, B.RIGHTID) = 1"+
 		 		" where A.AAE100 ='1'"+" and A.AUTHTYPE = '"+roleType+"'"+
 		 		" and B.AAE100 ='1' and OPERID = '"+operId+"')";
 			}else{			
@@ -43,13 +43,13 @@
 		}else if("2".equals(eventId)){//授权时,查询当前登录用户的所有分配权限
 			if (!"1".equals(userId)){//如果不是超级管理员,则登录用户的分配权限显示菜单树
 			    whereCls = " exists (select 1 from fw_operator2right " +
-			       " where  LOCATE(v_right_tree.rightid,fw_operator2right.rightid) = 1 "+" and fw_operator2right.AAE100 = '1'"+
+			       " where  INSTR(fw_operator2right.rightid, v_right_tree.rightid) = 1 "+" and fw_operator2right.AAE100 = '1'"+
 			       " and fw_operator2right.AUTHTYPE = '2' and fw_operator2right.operid = '"+userId+"')";
 	        } 
 		} else if ("3".equals(eventId) || fromFuncDesc.equals("authRights2Role")){//来自角色管理功能
 			if (!"1".equals(userId)){//如果不是超级管理员,则登录用户的分配权限显示菜单树
 			    whereCls = " exists (select 1 from fw_operator2right " +
-			       " where LOCATE(v_right_tree.rightid,fw_operator2right.rightid) = 1 "+" and fw_operator2right.AAE100 = '1'"+
+			       " where INSTR(fw_operator2right.rightid, v_right_tree.rightid) = 1 "+" and fw_operator2right.AAE100 = '1'"+
 			       " and fw_operator2right.AUTHTYPE = '2' and fw_operator2right.operid = '"+userId+"')";
 	        }
 		} else{
@@ -59,7 +59,7 @@
 	}else{
 		if (!"1".equals(userId)){//如果不是超级管理员,则根据权限显示菜单树
 		    whereCls = " exists (select 1 from fw_operator2right " +
-		       " where  LOCATE(v_right_tree.rightid,fw_operator2right.rightid) = 1"+
+		       " where  INSTR(fw_operator2right.rightid, v_right_tree.rightid) = 1"+
 		       " and fw_operator2right.AUTHTYPE = '2' and fw_operator2right.operid = '"+userId+"')";
         }
 	}

+ 105 - 0
数据迁移指南.md

@@ -0,0 +1,105 @@
+# 湛江智慧人社项目 - 数据迁移指南
+
+## 1. 概述
+本项目启动依赖于一系列核心配置数据(如字典、菜单、工作流配置等)。由于 `ZJRS_YWXT.sql` 仅包含表结构,为了让测试环境能够正常运行并拥有完整的系统功能,需要从正式环境(或预发布环境)导出以下关键表的数据。
+
+## 2. 需迁移表清单
+
+### 2.1 系统基础配置 (System Configuration)
+这些表控制系统的基本运行参数和数据字典,缺失会导致下拉框空白或系统报错。
+| 表名 | 描述 | 重要性 |
+| :--- | :--- | :--- |
+| **AA01** | 系统参数表 (System Parameters) | 高 |
+| **AA10** | 数据字典表 (Data Dictionary) | **极高** |
+| **FW_SYSMESSAGE** | 系统消息提示信息 | 中 |
+| **FW_HELP** | 系统帮助信息 | 低 |
+| **FW_BIGDICT_MAINTAIN** | 大字典维护表 | 中 |
+
+### 2.2 组织架构与权限 (Organization & Rights)
+这些表定义了谁可以登录系统以及他们能看到什么菜单。
+| 表名 | 描述 | 重要性 |
+| :--- | :--- | :--- |
+| **FW_SYSORG** | 系统机构表 (System Organization) | 高 |
+| **FW_OPERATEUNIT** | 经办单位表 (Operating Units) | 高 |
+| **FW_OPERATOR** | 操作员表 (Operators) | 高 |
+| **FW_RIGHT** | 菜单与权限定义表 (Menus & Rights) | **极高** |
+| **FW_RIGHT2RESOURCE** | 权限资源关联表 (URL拦截配置) | 高 |
+| **FW_ROLE** | 角色表 (Roles) | 高 |
+| **FW_ROLE2RIGHT** | 角色-权限关联表 | 高 |
+| **FW_OPERATOR2RIGHT** | 操作员-权限关联表 (直接授权) | 高 |
+| **FW_OPERATOR2ROLE** | 操作员-角色关联表 | 高 |
+
+### 2.3 界面配置 (UI Configuration)
+框架的核心部分,决定了列表(Grid)和表单(Form)如何渲染。如果缺失,大部分业务页面将无法显示。
+| 表名 | 描述 | 重要性 |
+| :--- | :--- | :--- |
+| **FW_GENLIST_CONF** | 通用列表配置 (Grid Configuration) | **极高** |
+| **FW_GENTBL_CONF** | 通用表单配置 (Form Configuration) | **极高** |
+| **FW_QUERYSQL** | 通用查询SQL配置 | 高 |
+
+### 2.4 报表与打印 (Reports & Printing)
+| 表名 | 描述 | 重要性 |
+| :--- | :--- | :--- |
+| **FW_PRINT_CONF** | 打印模板配置 | 中 |
+| **FW_PRINT_CLIENTCONFIG** | 客户端打印配置 | 低 |
+| **FW_REPORT_CONF** | 报表工具配置 | 中 |
+
+### 2.5 工作流配置 (Workflow)
+如果系统涉及业务流程流转,以下表数据必不可少。
+| 表名 | 描述 | 重要性 |
+| :--- | :--- | :--- |
+| **WF_ACTION_DEF** | 流程环节定义 | 高 |
+| **WF_ACTION_DEF2TASK** | 环节与任务映射 | 高 |
+| **FW_WF_DESIGNER** | 流程设计器图数据 | 中 |
+
+### 2.6 其他 (Others)
+| 表名 | 描述 | 重要性 |
+| :--- | :--- | :--- |
+| **FW_YXZLINFO_CONF** | 影像资料配置 | 低 |
+| **FW_LOG4BUSS** | 业务日志配置 | 低 |
+
+## 3. 迁移建议
+1.  **工具**: 推荐使用 Oracle `exp/imp` 或 `expdp/impdp` 工具,或者使用 PL/SQL Developer 的 "Export Tables" 功能。
+2.  **顺序**: 建议优先导入 **AA10** (字典) 和 **FW_GENLIST_CONF/FW_GENTBL_CONF** (界面配置),因为它们是系统运行的基石。
+3.  **冲突处理**: 如果测试库中已有测试数据(如 `init_test_data.sql` 生成的数据),导入时请注意主键冲突,建议先清空相关表或选择 "Update" 模式(如果工具支持)。
+
+## 4. 数据量分析脚本
+在正式环境执行以下 SQL 语句,可快速评估需导出表的记录条数及占用空间大小,以便选择合适的导出时间和方式。
+
+```sql
+-- 查询迁移相关表的记录数和占用空间 (单位: MB)
+SELECT
+    T.TABLE_NAME AS "表名",
+    T.NUM_ROWS AS "预估行数",
+    ROUND(S.BYTES / 1024 / 1024, 2) AS "占用空间(MB)",
+    'exp ' || USER || '/' || 'PASSWORD' || ' tables=' || T.TABLE_NAME || ' file=' || T.TABLE_NAME || '.dmp' AS "导出命令参考"
+FROM
+    USER_TABLES T
+LEFT JOIN
+    (SELECT SEGMENT_NAME, SUM(BYTES) BYTES FROM USER_SEGMENTS GROUP BY SEGMENT_NAME) S
+ON
+    T.TABLE_NAME = S.SEGMENT_NAME
+WHERE
+    T.TABLE_NAME IN (
+        -- 1. 系统配置
+        'AA01', 'AA10', 'FW_SYSMESSAGE', 'FW_HELP', 'FW_BIGDICT_MAINTAIN',
+        -- 2. 权限与组织
+        'FW_SYSORG', 'FW_OPERATEUNIT', 'FW_OPERATOR', 'FW_RIGHT', 'FW_RIGHT2RESOURCE',
+        'FW_ROLE', 'FW_ROLE2RIGHT', 'FW_OPERATOR2RIGHT', 'FW_OPERATOR2ROLE',
+        -- 3. 界面配置
+        'FW_GENLIST_CONF', 'FW_GENTBL_CONF', 'FW_QUERYSQL',
+        -- 4. 报表打印
+        'FW_PRINT_CONF', 'FW_PRINT_CLIENTCONFIG', 'FW_REPORT_CONF',
+        -- 5. 工作流
+        'WF_ACTION_DEF', 'WF_ACTION_DEF2TASK', 'FW_WF_DESIGNER',
+        -- 6. 其他
+        'FW_YXZLINFO_CONF', 'FW_LOG4BUSS'
+    )
+ORDER BY
+    S.BYTES DESC NULLS LAST;
+```
+
+**注意**: 
+- `NUM_ROWS` 字段来源于数据库统计信息,可能不是实时的。如果需要精确行数,请使用 `SELECT COUNT(*)`。
+- 如果表空间很大(例如超过 1GB),建议使用 `Data Pump (expdp)` 进行导出以提高效率。
+

+ 145 - 0
系统分析与修改记录.md

@@ -0,0 +1,145 @@
+# 修改日志
+
+本文件记录了为修复登录和配置问题而对项目进行的所有修改。
+
+## 2026-03-04
+
+### 1. `web/WEB-INF/web.xml`
+- **修改内容**: 注释掉了 `*.do`、`*.jsp` 和 `/reportServlet` 的 `XSS` 过滤器映射 (`SecurityFilter`)。
+- **修改原因**: `SecurityFilter` 因 `SECURITY_HTTPREFERER` 不匹配而报 403 错误,即使配置了白名单也依然存在问题。在开发/测试环境中禁用它可确保登录流程顺畅。
+
+### 2. `init_test_data.sql`
+- **修改内容**: 
+    - 更新了 `AA10` 表的 `DELETE` 语句,使用 `AAA100` 和 `ITEMCODE` 代替 `AAZ093`。
+    - 增加了 `FW_OPERATOR`、`FW_OPERATOR2RIGHT`、`FW_RIGHT`、`FW_OPERATEUNIT`、`FW_SYSORG` 表的 `DELETE` 语句,以防止主键冲突。
+    - 更新了 `FW_OPERATOR` 的插入语句:
+        - `admin`: 密码重置为 `admin` (MD5: `21232f297a57a5a743894a0e4a801fc3`)。
+        - `test`: 密码重置为 `test` (明文, `PWENCRYPT='0'`)。
+    - **修复 ORA-00001: UK_FW_OPERATOR_LOGINID**: 更新了 `FW_OPERATOR` 的 `DELETE` 逻辑,同时根据 `LOGINID` 和 `OPERID` 删除。
+    - **修复 ORA-00001: PK_FW_OPERATOR2RIGHT**: 增加了删除 `ID` 为 1, 2, 3 的 `FW_OPERATOR2RIGHT` 记录的语句。
+    - **修复 ORA-00001: PK_AA01**: 更新了 `AA01` 的 `DELETE` 逻辑,根据 `AAA001` (包含 `CHECKIMAGE_SB`) 以及 `AAZ499` ID 范围 (3000-3008) 进行删除。
+    - 在 `AA01` 表中增加了多条 `SECURITY_HTTPREFERER` 配置,以支持多种 Referer 格式。
+    - 增加了 `CHECKIMAGE_SB = '0'` 配置以禁用登录验证码。
+- **修改原因**: 
+    - 修复插入字典数据时 `UK_AAA100_ITEMCODE` 的唯一约束冲突。
+    - 确保测试账户可用且密码已知。
+    - 通过配置 Referer 白名单防止 403 错误(虽然过滤器已禁用,但这可作为后续参考)。
+
+### 3. `web/jsp/framework/security/loginsb_i.jsp`
+- **修改内容**: **[已撤回]** 之前重命名了 `RememberMe` 为 `RememberMe_ignored` 以及 `IMAGCHECK` 为 `IMAGCHECK_ignored`。根据用户要求,此修改已撤回。
+- **注意**: 如果后端 Action 严格要求 `RememberMe` (boolean/int) 和 `IMAGCHECK` (string/int) 的特定类型,Struts2 的 `ConversionErrorInterceptor` 异常可能会再次出现。
+
+### 4. `init_test_data.sql` (最新更新)
+- **修改内容**:
+    - 将所有测试账户 (`admin`, `test`, `admin_123456`) 设置为使用**明文密码**。
+    - 将所有用户的 `PWENCRYPT` 设置为 `'0'`。
+    - 增加了 `UNSAFE_VALIDATEFORM` 配置为 `NEVER_MATCH_THIS_TOKEN`,以防止配置为空时导致客户端验证错误。
+    - 增加了 `LOGIN_ENCRYPT` 配置为 `0`,以匹配明文密码设置。
+    - 增加了 `LOGIN_TIP` 配置为空字符串。
+    - 增加了 `DELETE FROM ZJRS_YWXT.FW_LOG4EXCEPTION` 和 `DELETE FROM ZJRS_YWXT.FW_LOG4LOGIN` 语句。
+- **修改原因**:
+    - 避免 MD5 哈希问题,简化登录测试。
+    - 修复客户端“不安全字符”验证错误,该错误在 `UNSAFE_VALIDATEFORM` 为空时发生(JS `split` 结果为 `[""]`,会匹配所有内容)。
+    - 修复 `ORA-00001: unique constraint (ZJRS_YWXT.PK_FW_LOG4EXCEPTION_ID) violated` 错误。系统尝试记录异常时,序列 `SEQ_FW_LOG4EXCEPTION` 生成的 ID 与表中现有数据冲突。清理该表可临时解决此问题,并允许查看实际触发异常的根本原因。
+
+### 5. `web/jsp/sysmngr/web/authmngr/right_left.jsp` 和 `right_auth.jsp`
+- **修改内容**: 将代码中的 `LOCATE` 函数替换为 Oracle 的 `INSTR` 函数。
+- **修改原因**: `LOCATE` 是 MySQL 函数,Oracle 不支持,导致 `ORA-00904` 错误。
+- **详细变更**:
+    - `LOCATE(B.RIGHTID,A.RIGHTID) = 1` -> `INSTR(A.RIGHTID, B.RIGHTID) = 1`
+    - `LOCATE(BAE001,'"+orgCode+"') = 1` -> `INSTR('"+orgCode+"', BAE001) = 1`
+    - 注意:`LOCATE(substr, str)` 参数顺序与 `INSTR(str, substr)` 相反。
+
+### 6. `init_test_data.sql` (兼容性函数)
+- **修改内容**: 增加了 `LOCATE` 和 `f_length` 自定义函数的创建语句。
+- **修改原因**: 
+    - 系统中部分代码(如 `f_length(TREEKEY)`)使用了 Oracle 不支持的函数,且源码难以定位或修改。
+    - 为了彻底解决 `ORA-00904` 错误,在数据库层面实现了这两个函数的兼容版本:
+        - `LOCATE`: 封装 `INSTR`。
+        - `f_length`: 封装 `LENGTH`。
+
+### 7. `web/WEB-INF/web.xml` (新增过滤器)
+- **修改内容**: 增加了 `AjaxEncodingFilter` 过滤器配置。
+- **新建文件**: `src/cn/sinobest/sysmngr/comm/filter/AjaxEncodingFilter.java`
+- **修改原因**: 
+    - 修复 `ajaxAdapter.do` 接口返回的 JSON 数据中文乱码问题。
+    - 该接口由 JAR 包提供(源码不可修改),默认响应编码可能为 ISO-8859-1。
+    - 过滤器强制将响应编码设置为 `UTF-8`。
+
+### 8. `src/cn/sinobest/sysmngr/comm/filter/AjaxEncodingFilter.java` (增强版)
+- **修改内容**: 使用 `HttpServletResponseWrapper` 包装响应对象。
+- **修改原因**: 
+    - 仅设置 `response.setCharacterEncoding("UTF-8")` 可能无效,因为后续的 Action 代码(在 JAR 包中)可能会覆盖此设置(例如调用 `setContentType("text/html;charset=GBK")`)。
+    - 通过重写 `setContentType` 和 `setCharacterEncoding` 方法,拦截并忽略任何非 UTF-8 的编码设置尝试,强制确保最终响应为 UTF-8。
+    - **二次增强**: 
+        - 增加了 `request.setCharacterEncoding("UTF-8")`,确保请求参数(POST Body)也能被正确解析。
+        - 增强了 `setContentType` 的逻辑:不仅忽略非 UTF-8,还会尝试将 `charset=GBK` 替换为 `charset=UTF-8`。
+        - 重写了 `getWriter()`,在获取 Writer 之前再次强制设置 Response 编码为 UTF-8。
+
+### 9. `src/cn/sinobest/sysmngr/comm/filter/AjaxEncodingFilter.java` (GBK 版)
+- **修改内容**: 将强制编码从 `UTF-8` 改为 `GBK`。
+- **修改原因**: 
+    - 经过测试,`ajaxAdapter.do` 返回的数据被浏览器解析为 `UTF-8` 时出现乱码(例如 `湛` 显示为 `տ`),这表明后端实际上发送的是 `GBK` 编码的字节流。
+    - 强制浏览器使用 `GBK` 解码应该能正确显示中文。
+
+## 技术分析与问题诊断
+
+### 3. 中文乱码问题分析 (Tomcat vs 代码)
+- **Tomcat 配置问题 (`URIEncoding`)**:
+    - **现象**: GET 请求参数(如 `whereCls=...`)包含中文时乱码。
+    - **原因**: Tomcat 默认 `URIEncoding` 为 ISO-8859-1(旧版)或 UTF-8(新版)。如果应用预期 UTF-8 但 Tomcat 使用 ISO-8859-1,则参数乱码。
+    - **解决**: 修改 `server.xml` 中的 `<Connector ... URIEncoding="UTF-8" />`。
+    - **注意**: `ajaxAdapter.do` 是 POST 请求,参数在 Body 中,通常由 `CharacterEncodingFilter` (`web.xml`) 处理,不受 `URIEncoding` 影响。
+
+- **代码/响应编码问题 (`Content-Type`)**:
+    - **现象**: 接口返回的 JSON 数据(响应体)乱码(如 `{"title":"???"}`)。
+    - **原因**: 后端代码未显式设置 `response.setCharacterEncoding("UTF-8")`,导致服务器使用默认编码(通常是 ISO-8859-1)发送数据,而浏览器/客户端按 UTF-8 解析。
+    - **解决**: 
+        - 修改源码(如 `TreeAction.java`)显式设置编码。
+        - 对于无法修改源码的 JAR 包接口(如 `ajaxAdapter.do`),添加过滤器 (`AjaxEncodingFilter`) 强制设置响应编码。
+
+### 4. 登录流程与逻辑问题分析
+
+#### 前端逻辑 (`loginsb_i.jsp`)
+- **不安全字符验证**: 
+    - 代码: `var fwUnsafeValidateFormTokens = "<%=UNSAFE_VALIDATEFORM%>".split("|");`
+    - **问题**: 当数据库配置 `UNSAFE_VALIDATEFORM` 为空时,`split("|")` 返回 `[""]`(包含一个空字符串的数组)。
+    - **后果**: `indexOf("")` 对任何字符串都返回 0,导致所有输入都被误判为包含“不安全字符”,阻止登录。
+    - **修复**: 在 SQL 中设置 `UNSAFE_VALIDATEFORM` 为 `NEVER_MATCH_THIS_TOKEN`,避免空字符串匹配。
+
+- **密码加密逻辑**:
+    - 代码:
+      ```javascript
+      if (isEncrypty == '1') {
+          var _1 = frm._1_.value;
+          t = stringToHex(encrypt(_1,pw));
+      }
+      ```
+    - **参数**: `isEncrypty` 来自数据库配置 `LOGIN_ENCRYPT`。
+    - **问题**: 如果配置为 '1',前端会使用 `encrypt.js` 进行加密。但如果后端没有对应的解密逻辑(或期望 MD5),会导致密码不匹配。
+    - **现状**: 测试环境数据库中 `admin` 等账户密码已被重置为明文或简单的 MD5。为了简化调试,我们将 `LOGIN_ENCRYPT` 设为 '0'(不加密),并让所有账户使用明文密码。
+
+#### 后端逻辑与异常
+- **Struts2 类型转换异常 (`ConversionErrorInterceptor`)**:
+    - **现象**: 提交登录表单时抛出异常。
+    - **原因**: 前端表单包含 `RememberMe` (checkbox) 和 `IMAGCHECK` (text) 字段。如果 Action 类(位于 JAR 包中,源码不可见)将这些字段定义为 `int` 或 `boolean`,而前端提交的是 "on" (checkbox 默认值) 或 "" (空字符串),Struts2 默认的拦截器会尝试转换类型并失败。
+    - **尝试修复**: 曾尝试重命名 JSP 中的字段以绕过 Action 绑定,但用户要求撤回。
+    - **当前状态**: 依赖后端 Action 的兼容性。如果再次出现,可能需要恢复 JSP 修改或寻找其他绕过方法。
+
+- **数据库 ID 冲突 (`ORA-00001`)**:
+    - **现象**: `unique constraint (ZJRS_YWXT.PK_FW_LOG4EXCEPTION_ID) violated`。
+    - **原因**: 系统在捕获并记录异常(可能是登录失败或其他逻辑错误)到 `FW_LOG4EXCEPTION` 表时,使用的序列 `SEQ_FW_LOG4EXCEPTION` 生成的 ID 小于表中已存在的最大 ID。
+    - **修复**: 通过 `DELETE FROM ZJRS_YWXT.FW_LOG4EXCEPTION` 清空表数据,消除 ID 冲突,从而允许系统正常写入新的异常日志,以便我们看到真正的错误原因。
+
+### 2. 加密解密过程分析
+
+- **前端加密 (`encrypt.js`)**:
+    - 使用自定义的加密算法(非标准 AES/DES),依赖于从后端获取的密钥 `_1_` (session 中的 `des_key`)。
+    - 函数 `encrypt(key, password)` 将密码转换为加密字符串,再通过 `stringToHex` 转为十六进制。
+    - 只有当 `LOGIN_ENCRYPT = '1'` 时启用。
+
+- **后端验证**:
+    - 数据库 `FW_OPERATOR` 表包含 `PASSWORD` 和 `PWENCRYPT` 字段。
+    - `PWENCRYPT='1'`: 密码已加密(通常是 MD5)。
+    - `PWENCRYPT='0'`: 密码为明文。
+    - **测试策略**: 将所有测试账户的 `PWENCRYPT` 设为 '0' 且 `PASSWORD` 设为明文,同时前端 `LOGIN_ENCRYPT` 设为 '0',确保前后端均以明文传输和比对,排除加密算法不一致导致的问题。