init: 导入项目

This commit is contained in:
fengjun
2024-07-02 11:40:01 +08:00
commit 4c8e6701f2
7158 changed files with 1199718 additions and 0 deletions

134
Webplatform/pom.xml Normal file
View File

@@ -0,0 +1,134 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.ag.jngh</groupId>
<artifactId>AG_ONE</artifactId>
<version>1.0</version>
</parent>
<artifactId>Webplatform</artifactId>
<version>1.0</version>
<packaging>jar</packaging>
<name>Webplatform Maven Webapp</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>AgquartzallGroup</groupId>
<artifactId>AgquartzallArtifact</artifactId>
<version>1.6.6</version>
</dependency>
<dependency>
<groupId>AgzipGroup</groupId>
<artifactId>AgzipArtifact</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>com.yahoo.platform.yui</groupId>
<artifactId>yuicompressor</artifactId>
<version>2.4.8</version>
</dependency>
<dependency>
<groupId>org.eclipse.birt.runtime.3_7_1</groupId>
<artifactId>org.mozilla.javascript</artifactId>
<version>1.7.2</version>
</dependency>
<dependency>
<groupId>javax.mail</groupId>
<artifactId>javax.mail-api</artifactId>
<version>1.5.3</version>
</dependency>
<!-- 生成word start
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-scratchpad</artifactId>
<version>3.0.2-FINAL</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.15</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml-schemas</artifactId>
<version>3.15</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.15</version>
</dependency>-->
<dependency>
<groupId>anji-jsonGroup</groupId>
<artifactId>anji-jsonArtifact</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.12</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.ag.jngh</groupId>
<artifactId>commonapi</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
<build>
<finalName>Webplatform</finalName>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>

View File

@@ -0,0 +1,165 @@
/*
Copyright (c) putdb.com, all rights reserved.
Contact: contact@putdb.com
Visit: http://www.ag6666666
*/
package com.wb.common;
import com.wb.tool.TaskManager;
import com.wb.util.FileUtil;
import com.wb.util.StringUtil;
import com.wb.util.SysUtil;
import com.wb.util.WebUtil;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.concurrent.ConcurrentHashMap;
/**
* WebBuilder基本过滤器拦截所有的请求路径。任何对应用发起的请求都会触发doFilter方法。
* <p>
* 主要作用有:
* 初始化系统,完成对静态变量的设置和计划任务的加载。
* 对XWL模块的访问处理解析对模块文件的访问。
* 缓存wb目录下的资源缓存文件内容至内存并根据需要启用gzip压缩以提高响应性能。
* 禁止对系统目录的访问禁止从外部对wb/system进行访问。
* </p>
*
* @author Jie Chen
* @version 7
* @see com.wb.common.FileBuffer
* @see com.wb.common.Parser
*/
public class Base implements Filter {
/** Servlet上下文对象。 */
public static ServletContext servletContext;
/** 应用目录的根路径。 */
public static File path;
/** 应用目录的根路径长度。 */
public static int pathLen;
/** 模块文件的根路径。 */
public static File modulePath;
/** 模块目录路径文本。 */
public static String modulePathText;
/** 模块目录路径长度。 */
public static int modulePathLen;
/** 系统的启动时间。 */
public static Date startTime;
/** 提供静态ConcurrentHashMap该对象可为任何应用使用。 */
public static ConcurrentHashMap<String, Object> map = new ConcurrentHashMap<String, Object>();
/** 是否初始化失败。 */
private static boolean initFailed;
/** 初始化失败异常对象。 */
private static Throwable initError;
/**
* WebBuilder过滤器实现对xwl文件的执行文件的缓存和系统文件的保护功能。
*
* @param request ServletRequest 请求对象。
* @param response ServletResponse 响应对象。
* @param chain 过滤器链。
* @throws ServletException 如果执行过程中发生异常将抛出。
*/
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
if (initFailed)
throw new RuntimeException(initError);
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
String url, xwl;
url = req.getServletPath();
xwl = UrlBuffer.get(url);
if (xwl != null) {
// WebBuilder模块
request.setCharacterEncoding("utf-8");
if (xwl.isEmpty()) {
xwl = request.getParameter("xwl");
if (xwl == null) {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST,
"null xwl");
return;
}
xwl = StringUtil.concat(xwl, ".xwl");
}
setRequest(req);
com.wb.common.Parser parser = new Parser(req, resp);
parser.parse(xwl);
} else {
String lowerUrl = url.toLowerCase();
if (lowerUrl.startsWith("/wb/modules/")
|| lowerUrl.startsWith("/wb/system/")) {
// 系统保护的目录
resp.sendError(HttpServletResponse.SC_FORBIDDEN, url);
} else if (com.wb.common.Var.cacheEnabled && lowerUrl.startsWith("/wb/")) {
// WebBuilder缓存目录
FileBuffer.service(url, req, resp);
} else {
// 其他交由用户自定义处理
chain.doFilter(request, response);
}
}
}
/**
* 系统的初始化以及定义系统常用的静态变量。
*
* @param config 过滤器配置对象。
* @throws ServletException 如果执行过程中发生异常将抛出。
*/
public void init(FilterConfig config) throws ServletException {
try {
startTime = new Date();
servletContext = config.getServletContext();
path = new File(servletContext.getRealPath("/"));
pathLen = FileUtil.getPath(path).length() + 1;
modulePath = new File(path, "wb/modules");
modulePathText = FileUtil.getPath(Base.modulePath);
modulePathLen = modulePathText.length() + 1;
SysUtil.reload(2);
if (!Var.jndi.isEmpty()) {
// 如果默认jndi为空表示数据库未配置。待安装配置完成后加载数据库相关类。
SysUtil.reload(3);
TaskManager.start();
}
} catch (Throwable e) {
initFailed = true;
initError = e;
}
}
/**
* 对request对象进行一些属性设置。
*/
private void setRequest(HttpServletRequest request) {
request.setAttribute("sys.date", new Date());
request.setAttribute("sys.id", SysUtil.getId());
request.setAttribute("sys.userid", request.getSession().getAttribute("sys.user"));
request.setAttribute("sys.tentantid", request.getSession().getAttribute("sys.tentantid"));
request.setAttribute("sys.deptcod", request.getSession().getAttribute("sys.deptcod"));
request.setAttribute("sys.portcod", request.getSession().getAttribute("sys.portcod"));
//System.out.println(request.getSession().getAttribute("sys.portcod"));
WebUtil.setLanguage(request);
}
/**
* 系统停止时执行,完成系统的清理。
*/
public void destroy() {
try {
TaskManager.stop();
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
}

View File

@@ -0,0 +1,81 @@
package com.wb.common;
import com.wb.util.StringUtil;
/**
* Created by Guo on 2016/7/7.
*/
public class Code {
private String fldId;
private String fldNam;
private String sysCod;
private String cName;
private String eName;
private String comNam1;
private String comNam2;
private String tentantId;
private String parId;
public String getComNam1() {
return comNam1;
}
public void setComNam1(String comNam1) {
this.comNam1 = comNam1;
}
public String getComNam2() {
return comNam2;
}
public void setComNam2(String comNam2) {
this.comNam2 = comNam2;
}
public void setFldId(String fldId) {
this.fldId = fldId;
}
public void setFldNam(String fldNam) {
this.fldNam = fldNam;
}
public void setSysCod(String sysCod) {
this.sysCod = sysCod;
}
public void setcName(String cName) {
this.cName = cName;
}
public void seteName(String eName) {
this.eName = eName;
}
public void setTentantId(String tentantId) {
this.tentantId = tentantId;
}
public String getFldId() {
return fldId;
}
public String getFldNam() {
return fldNam;
}
public String getSysCod() {
return sysCod;
}
public String getcName() {
return cName;
}
public String geteName() {
return eName;
}
public String getTentantId() {
if(StringUtil.isEmpty(tentantId))
return "@@@";
else
return tentantId;
}
public String getParId() {
if(StringUtil.isEmpty(parId))
return "@@@";
else
return parId;
}
public void setParId(String parId) {
this.parId = parId;
}
}

View File

@@ -0,0 +1,275 @@
package com.wb.common;
import com.wb.util.DbUtil;
import com.wb.util.StringUtil;
import com.wb.util.WebUtil;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/**
* Created by Administrator on 2017/4/17.
*/
public class CodeBuffer {
private static ArrayList<String> str = new ArrayList<String>();
private static ArrayList<String> Sql = new ArrayList<String>();
/**
* 键值数据缓存。
*/
public static ConcurrentHashMap<String, List<Code>> buffer;
public static void getkeyvalue(HttpServletRequest request, HttpServletResponse response) {
String key = request.getParameter("key");
String value = request.getParameter("value");
String result = "";
ConcurrentHashMap<Object, String> map = KVBuffer.buffer.get(key);
Set<Map.Entry<Object, String>> es = map.entrySet();
for (Map.Entry<Object, String> e : es) {
Object K=e.getKey();
String keytemp="";
if (K instanceof Integer){
keytemp=Integer.toString((Integer) K);
}else{
keytemp=StringUtil.quote((String) K);
}
if (keytemp.equals(value)) {
result = e.getValue();
break;
}
}
try {
WebUtil.send(response, result);//将修改数据同步返回表格
}catch (Exception e){
e.printStackTrace();
}
}
/**
* ??????
*
* @param request
* @param response
*/
public static void filter(HttpServletRequest request, HttpServletResponse response) {
String fldId = request.getParameter("fldId");
String name = request.getParameter("name");
String start = request.getParameter("start");
String limit = request.getParameter("limit");
String tenancyId = request.getParameter("TENANCY_ID");//租户
tenancyId = StringUtil.isEmpty(tenancyId) ? "@@@" : tenancyId;
String PARID = request.getParameter("parId");//父节点过滤
PARID = StringUtil.isEmpty(PARID) ? "@@@" : PARID;
Map m = request.getParameterMap();
String filterName = null;
// if(name!=null&&!name.equals(""))
filterName = request.getParameter("query");// ????
List<Code> list2 = buffer.get(fldId);// ????
List<Code> listNew = new ArrayList<Code>();
int size = 0;
if (list2 != null) {
size = list2.size();
if (start == null && filterName == null) {// ???????
listNew = list2;
} else if (start != null) {// ?????
int j = 0;
for (int i = 0; i < size; i++) {
if (compareCode(list2.get(i), PARID, filterName, tenancyId)) {
if (Integer.parseInt(start) <= j
&& Integer.parseInt(start)
+ Integer.parseInt(limit) > j)
listNew.add(list2.get(i));
j++;
}
}
size = j;
} else if (start == null && filterName != null) {// ??????
for (int i = 0; i < size; i++) {
if (list2.get(i).getcName().contains(filterName) || list2.get(i).geteName().contains(filterName) || list2.get(i).getSysCod().contains(filterName)) {
listNew.add(list2.get(i));
}
}
size = listNew.size();
}
} else {
listNew = null;
}
try {
response.setContentType("text/xml;charset=UTF-8");
PrintWriter pw = response.getWriter();
pw.print(getJson(size, listNew, "EN"));
pw.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public static String getJson(int s, List<Code> list, Object language) {
List<Code> listnew = list;
int size = 0;
if (list != null)
size = list.size();
String styr = "{total:2,metaData:{totalProperty:\"total\",root:\"row\",fields:[{name:\"ID\",type:\"string\"},"
+ "{name:\"NAME\",type:\"string\"}]},"
+ "row:[{\"ID\":\"ATSTA\",\"NAME\":\"STAINACH\"},{\"ID\":\"ATSTC\",\"NAME\":\"STOCKERAU\"}]} ";
StringBuffer str = new StringBuffer(
"{total:"
+ s
+ ","
+ "metaData:{"
+ "totalProperty:\"total\",root:\"row\","
+ "fields:["
+ "{name:\"ID\",type:\"string\"},"
+ "{name:\"CNAME\",type:\"string\"},{name:\"ENAME\",type:\"string\"},{name:\"TENANCY_ID\",type:\"string\"}]},"
+ "row:[");
for (int i = 0; i < size; i++) {
if (i != size - 1)
str.append("{\"ID\":\"" + listnew.get(i).getSysCod()
+ "\",\"CNAME\":\"" + listnew.get(i).getcName()
+ "\",\"ENAME\":\"" + listnew.get(i).geteName()
+ "\",\"TENANCY_ID\":\"" + listnew.get(i).getTentantId() + "\"},"
);
else
str.append("{\"ID\":\"" + listnew.get(i).getSysCod()
+ "\",\"CNAME\":\"" + listnew.get(i).getcName()
+ "\",\"ENAME\":\"" + listnew.get(i).geteName()
+ "\",\"TENANCY_ID\":\"" + listnew.get(i).getTentantId() + "\"}"
);
}
str.append("]} ");
//System.out.println(str.toString());
return str.toString();
}
/**
* 加载和初始化。
*/
public static synchronized void load() {
buffer = new ConcurrentHashMap<String, List<Code>>();
for (int i = 0; i < str.size(); i++) {
loadWbKey(str.get(i), Sql.get(i));
}
}
/**
* 加载和初始化
*
* @param l1
* @param l2
*/
public static synchronized void load(List<String> l1, List<String> l2) {
buffer = new ConcurrentHashMap<String, List<Code>>();
for (int i = 0; i < l1.size(); i++) {
loadWbKey(l1.get(i), l2.get(i));
}
}
//不同数据源 加载对应CODE 放入wbKey中
public static void loadWbKey(String Jndi, String sql) {
try {
Connection conn = null;
Statement st = null;
ResultSet rs = null;
String K, keyName = null, preKeyName = null;
List<Code> list = new ArrayList<Code>();
try {
conn = DbUtil.getConnection(Jndi);
st = conn.createStatement();
rs = st.executeQuery(sql);
while (rs.next()) {
keyName = rs.getString("KEY_NAME");
if (preKeyName != null && !preKeyName.equals(keyName)) {
buffer.put(preKeyName, list);
list = new ArrayList<Code>();
}
Code code = new Code();
code.setFldId(keyName);
code.setFldNam(rs.getString("KEY_NAME"));
code.setSysCod(rs.getString("K"));// 代码主键
code.setcName(rs.getString("V"));// 代码中文名
code.seteName(rs.getString("V"));// 代码英文名
code.setComNam1(rs.getString("COMV"));// comName
code.setComNam2(rs.getString("COMV2"));// comName
//code.setTentantId( rs.getString("TENANCY_ID"));// ??????????
//code.setParId( rs.getString("PARID"));// ??????????
list.add(code);
preKeyName = keyName;
}
if (preKeyName != null)
buffer.put(preKeyName, list);
} finally {
DbUtil.close(rs);
DbUtil.close(st);
DbUtil.close(conn);
}
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
/**
* 获取指定键对应的值。
*
* @param map 键值对照map。
* @param request 请求对象,用于多国语言支持。
* @param key 键。
* @return 键对应的字符串值。
*/
private static String getValue(ConcurrentHashMap<?, ?> map,
HttpServletRequest request, Object key) {
Object value;
String str;
if (key instanceof Number)
value = map.get(((Number) key).intValue());
else
value = map.get(key.toString());
if (value == null)
return key.toString();
str = value.toString();
if (str.startsWith("@Str."))
return Str.format(request, str.substring(5));
else
return str;
}
/**
* 获取指定键对应的值。
*
* @param parId 父节点。
* @param filterName 模糊查询。
* @return boolean。
*/
private static boolean compareCode(Code code, String parId, String filterName, String tentantId) {
boolean parBool = true, tentBool = true, filterBool = true;
if (!parId.equals("@@@"))//???????????
parBool = code.getComNam2().equals(parId);
if (!tentantId.equals("@@@"))//?????????
tentBool = code.getTentantId().equals(tentantId);
if (!StringUtil.isEmpty(filterName))//???????
{
filterBool = code.getcName().contains(filterName) || code.geteName().contains(filterName) || code.getSysCod().contains(filterName);
}
return filterBool && parBool && tentBool;
}
}

View File

@@ -0,0 +1,139 @@
package com.wb.common;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.HashMap;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/**
* 数据库数据字典。
*/
public class Dictionary {
/** 字典数据缓存。 */
public static ConcurrentHashMap<String, ConcurrentHashMap<String, com.wb.tool.DictRecord>> buffer;
/**
* 在指定表名的字典信息中查找指定字段名称的字典定义记录。
* @param tableNames 表名列表。
* @param fieldName 字段名称。
* @return 字典定义记录。
*/
public static com.wb.tool.DictRecord find(String[] tableNames, String fieldName) {
com.wb.tool.DictRecord dictRecord;
ConcurrentHashMap<String, com.wb.tool.DictRecord> fieldMap;
String upperFieldName = fieldName.toUpperCase();
for (String tableName : tableNames) {
fieldMap = buffer.get(tableName.toUpperCase());
if (fieldMap != null) {
dictRecord = fieldMap.get(upperFieldName);
if (dictRecord != null) {
if (dictRecord.linkTo == null)
return dictRecord;
else {
String tableField[] = com.wb.util.StringUtil.split(dictRecord.linkTo.toUpperCase(), '.');
fieldMap = buffer.get(tableField[0]);
if (fieldMap == null)
return null;
else
return fieldMap.get(tableField[1]);
}
}
}
}
return null;
}
/**
* 获取指定表名的字典信息中所有配置有键值关系的字段组成的Map。如果未找到键值关系返回空的Map。
* @param tableNames 表名列表。
* @return 键值关系Map。
*/
public static HashMap<String, String> getKeyFields(String[] tableNames) {
HashMap<String, String> keyMap = new HashMap<String, String>();
com.wb.tool.DictRecord dictRecord;
ConcurrentHashMap<String, com.wb.tool.DictRecord> fieldMap;
for (String tableName : tableNames) {
fieldMap = buffer.get(tableName.toUpperCase());
if (fieldMap != null) {
Set<Entry<String, com.wb.tool.DictRecord>> es = fieldMap.entrySet();
for (Entry<String, com.wb.tool.DictRecord> e : es) {
dictRecord = e.getValue();
if (dictRecord.keyName != null)
keyMap.put(e.getKey(), dictRecord.keyName);
}
}
}
return keyMap;
}
/**
* 获得结果集当前记录的字典定义对象。
* @param rs 结果集。
* @return 字典记录定义对象。
* @throws Exception 读取过程发生异常。
*/
public static com.wb.tool.DictRecord getDictRecord(ResultSet rs) throws Exception {
com.wb.tool.DictRecord dictRecord = new com.wb.tool.DictRecord();
dictRecord.linkTo = com.wb.util.StringUtil.force(rs.getString("LINK_TO"));
dictRecord.listable = !"0".equals(rs.getString("LISTABLE"));
dictRecord.editable = !"0".equals(rs.getString("EDITABLE"));
dictRecord.dispText = com.wb.util.StringUtil.force(rs.getString("DISP_TEXT"));
dictRecord.dispWidth = rs.getInt("DISP_WIDTH");
if (rs.wasNull())
dictRecord.dispWidth = -1;
dictRecord.dispFormat = com.wb.util.StringUtil.force(rs.getString("DISP_FORMAT"));
dictRecord.autoWrap = "1".equals(rs.getString("AUTO_WRAP"));
dictRecord.allowBlank = com.wb.util.StringUtil.getBoolA(rs.getString("ALLOW_BLANK"));
dictRecord.readOnly = com.wb.util.StringUtil.getBoolA(rs.getString("READ_ONLY"));
dictRecord.keyName = com.wb.util.StringUtil.force(rs.getString("KEY_NAME"));
dictRecord.fieldSize = rs.getInt("FIELD_SIZE");
if (rs.wasNull())
dictRecord.fieldSize = -1;
dictRecord.decimalPrecision = rs.getInt("DECIMAL_PRECISION");
if (rs.wasNull())
dictRecord.decimalPrecision = -1;
dictRecord.validator = com.wb.util.StringUtil.force(rs.getString("VALIDATOR"));
dictRecord.renderer = com.wb.util.StringUtil.force(rs.getString("RENDERER"));
return dictRecord;
}
/**
* 加载和初始化。
*/
public static synchronized void load() {
try {
buffer = new ConcurrentHashMap<String, ConcurrentHashMap<String, com.wb.tool.DictRecord>>();
Connection conn = null;
Statement st = null;
ResultSet rs = null;
String tableName = null, preTableName = null;
ConcurrentHashMap<String, com.wb.tool.DictRecord> map = new ConcurrentHashMap<String, com.wb.tool.DictRecord>();
try {
conn = com.wb.util.DbUtil.getConnection();
st = conn.createStatement();
rs = st.executeQuery("select * from WB_DICT order by TABLE_NAME");
while (rs.next()) {
tableName = rs.getString("TABLE_NAME").toUpperCase();
if (preTableName != null && !preTableName.equals(tableName)) {
buffer.put(preTableName, map);
map = new ConcurrentHashMap<String, com.wb.tool.DictRecord>();
}
map.put(rs.getString("FIELD_NAME").toUpperCase(), getDictRecord(rs));
preTableName = tableName;
}
if (preTableName != null)
buffer.put(preTableName, map);
} finally {
com.wb.util.DbUtil.close(rs);
com.wb.util.DbUtil.close(st);
com.wb.util.DbUtil.close(conn);
}
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
}

View File

@@ -0,0 +1,150 @@
package com.wb.common;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.concurrent.ConcurrentHashMap;
import java.util.zip.GZIPOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.io.IOUtils;
/**
* WebBuilder缓存器任何对wb目录下请求的资源都会被缓存并视资源大小启用gzip压缩。
*/
public class FileBuffer {
/** 把文件缓存到HashMap中以提高文件访问性能。 */
private static ConcurrentHashMap<String, Object[]> buffer;
/**
* 为客户端提供高效的文件访问服务。
*
* @param path
* 请求的文件路径。
* @param request
* HttpServletRequest 请求对象。
* @param response
* HttpServletResponse 响应对象。
* @throws IOException
* 如果执行过程中发生异常将抛出。
*/
public static void service(String path, HttpServletRequest request,
HttpServletResponse response) throws IOException {
File file;
Object[] obj;
String pathKey;
byte[] bt = null;
boolean isGzip = false;
long lastModified;
pathKey = path.toLowerCase();
if (Var.uncheckModified) {
file = null;
lastModified = -1;
} else {
file = new File(Base.path, path);
lastModified = file.lastModified();
}
obj = buffer.get(pathKey);
if (obj != null) {
if (Var.uncheckModified || lastModified == (Long) obj[2]) {
isGzip = (Boolean) obj[0];
bt = (byte[]) obj[1];
if (Var.uncheckModified)
lastModified = (Long) obj[2];
}
}
if (bt == null) {
if (Var.uncheckModified) {
file = new File(Base.path, path);
lastModified = file.lastModified();
}
// 判断文件是否存在
if (lastModified == 0) {
response.sendError(HttpServletResponse.SC_NOT_FOUND, path);
return;
}
isGzip = file.length() >= Var.gzipMinSize;
bt = getBytes(file, isGzip);
obj = new Object[3];
obj[0] = isGzip;
obj[1] = bt;
obj[2] = lastModified;
buffer.put(pathKey, obj);
}
if (Var.cacheMaxAge != -1) {
if (Var.cacheMaxAge == 0)
response.setHeader("Cache-Control",
"no-cache, no-store, max-age=0, must-revalidate");
else {
response.setDateHeader("Last-Modified", new Date().getTime());
response.setHeader("Cache-Control", "max-age="
+ Var.cacheMaxAge);
}
}
String fileEtag = Long.toString(lastModified), reqEtag = request
.getHeader("If-None-Match");
if (fileEtag.equals(reqEtag)) {
response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
return;
}
response.setHeader("Etag", fileEtag);
if (isGzip)
response.setHeader("Content-Encoding", "gzip");
response.setCharacterEncoding("utf-8");
String contentType = Base.servletContext.getMimeType(path);
if (contentType == null)
contentType = "application/octet-stream";// 未知的下载类型
response.setContentType(contentType);
response.setContentLength(bt.length);
response.getOutputStream().write(bt);
response.flushBuffer();
}
/**
* 加载和初始化。
*/
public static synchronized void load() {
buffer = new ConcurrentHashMap<String, Object[]>();
}
/**
* 获取文件的字节数组。
*
* @param file
* 文件对象。
* @param isGzip
* 指定对文件是否使用gzip压缩。
* @return 以字节数组表达的文件数据。
* @throws IOException
* 如果读取文件时发生错误将抛出异常。
*/
private static byte[] getBytes(File file, boolean isGzip)
throws IOException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
InputStream is = new FileInputStream(file);
byte[] bt;
try {
if (isGzip) {
GZIPOutputStream gos = new GZIPOutputStream(bos);
try {
IOUtils.copy(is, gos);
} finally {
gos.close();
}
} else
IOUtils.copy(is, bos);
bt = bos.toByteArray();
} finally {
is.close();
}
return bt;
}
}

View File

@@ -0,0 +1,240 @@
package com.wb.common;
import com.wb.util.DbUtil;
import com.wb.util.StringUtil;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
public class KVBuffer {
private static List<String> jns=new ArrayList<String>();
private static List<String> kvSql=new ArrayList<String>();
private static List<String> codSql=new ArrayList<String>();
/**
* 键值数据缓存。
*/
public static ConcurrentHashMap<String, ConcurrentHashMap<Object, String>> buffer;
/**
* 获取指定键值的键值项列表数组组成的字符串。
* @param //key 键名称。
* @return 键值项列表。
*/
public static String getList(String keyName, String tenancyId) {
ConcurrentHashMap<Object, String> map = buffer.get(keyName);
if (map == null)
return "[]";
StringBuilder buf = new StringBuilder();
Set<Entry<Object, String>> es = map.entrySet();
boolean isFirst = true;
Object K;
String V;
buf.append("[");
for (Entry<Object, String> e : es) {
if (isFirst)
isFirst = false;
else
buf.append(",");
buf.append("{\"K\":");
K = e.getKey();
if (K instanceof Integer)
buf.append(Integer.toString((Integer) K));
else
buf.append(StringUtil.quote((String) K));
buf.append(",\"V\":");
V = e.getValue();
if (V.startsWith("@"))
V = V.substring(1);
else
V = StringUtil.quote(V);
buf.append(V);
buf.append("}");
}
buf.append("]");
return buf.toString();
}
/**
* 加载和初始化。
*/
public static synchronized void load() {
try {
buffer = new ConcurrentHashMap<String, ConcurrentHashMap<Object, String>>();
Connection conn = null;
Statement st = null;
ResultSet rs = null;
String K, keyName = null, preKeyName = null;
ConcurrentHashMap<Object, String> map = new ConcurrentHashMap<Object, String>();
try {
//getSqlS("ilog_code");
getSqlS("default");
CodeBuffer.load(jns,codSql);
//CodeBuffer.load();
conn = DbUtil.getConnection();
st = conn.createStatement();
rs = st.executeQuery("select KEY_ID,KEY_NAME, key_name key_note,K,V,TYPE from WB_KEY order by KEY_NAME ");
while (rs.next()) {
keyName = rs.getString("KEY_NAME");
if (preKeyName != null && !preKeyName.equals(keyName)) {
buffer.put(preKeyName, map);
map = new ConcurrentHashMap<Object, String>();
}
K = rs.getString("K");
map.put(rs.getInt("TYPE") == 1 ? K : Integer.parseInt(K),
rs.getString("V"));
preKeyName = keyName;
}
if (preKeyName != null)
buffer.put(preKeyName, map);
for (int i=0;i<jns.size();i++)
{
System.out.println(kvSql.get(i));
loadWbKey(jns.get(i),kvSql.get(i));
}
// for (int i=0;i<str.size();i++)
// {
// loadWbKey(str[i],Sql[i]);
// }
// loadMenu.loadMenuBuffer();
} finally {
DbUtil.close(rs);
DbUtil.close(st);
DbUtil.close(conn);
}
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
//不同数据源 加载对应CODE 放入wbKey中
public static void loadWbKey(String Jndi,String sql) {
try {
Connection conn = null;
Statement st = null;
ResultSet rs = null;
String K, keyName = null, preKeyName = null;
ConcurrentHashMap<Object, String> map = new ConcurrentHashMap<Object, String>();
try {
conn = DbUtil.getConnection(Jndi);
st = conn.createStatement();
rs = st.executeQuery(sql);
while (rs.next()) {
keyName = rs.getString("KEY_NAME");
if (preKeyName != null && !preKeyName.equals(keyName)) {
buffer.put(preKeyName, map);
map = new ConcurrentHashMap<Object, String>();
}
K = rs.getString("K");
map.put( K ,rs.getString("V"));
preKeyName = keyName;
}
if (preKeyName != null)
buffer.put(preKeyName, map);
} finally {
DbUtil.close(rs);
DbUtil.close(st);
DbUtil.close(conn);
}
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
/**
* 获取指定键对应的值。
* @param map 键值对照map。
* @param key 键。
* @return 键对应的字符串值。
*/
public static String getValue(ConcurrentHashMap<?, ?> map, Object key) {
Object value;
if (key == null)
return null;
if (key instanceof Number)
value = map.get(((Number) key).intValue());
else
value = map.get(key.toString());
if (value == null)
return key.toString();
else
return value.toString();
}
public static void getnames(){
System.out.println("=======");
}
private static void getSqlS(String jndi) {
Connection conn = null;
Statement st = null;
ResultSet rs = null;
String jnid=null;
int i=0;
List<String> jn=new ArrayList<String>();
List<String> kvsqls=new ArrayList<String>();
List<String> codSqls=new ArrayList<String>();
try {
String kvSql = "",
codSql= "";
conn = DbUtil.getConnection(jndi);
st = conn.createStatement();
rs = st.executeQuery("select KV_SQL ,COD_SQL,JNDI from CODE_SET order by JNDI,TABLE_NAME");
while (rs.next()) {
if (jnid != null && !jnid.equals(rs.getString("JNDI"))) {
jn.add(i, jnid);
kvsqls.add(i, "select * from ("+kvSql+") order by KEY_NAME");
codSqls.add(i, "select * from ("+codSql+") order by KEY_NAME");
kvSql="";
codSql="";
i++;
}
if(jnid==null||!jnid.equals(rs.getString("JNDI")))
{
kvSql += rs.getString("KV_SQL");
codSql +=rs.getString("COD_SQL");
}
else{
kvSql += " union all "+rs.getString("KV_SQL");
codSql +=" union all "+ rs.getString("COD_SQL");
}
jnid= rs.getString("JNDI");
}
if (jnid != null){
jn.add(i, jnid);
kvsqls.add(i, "select * from ("+kvSql+") order by KEY_NAME");
codSqls.add(i, "select * from ("+codSql+") order by KEY_NAME");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
jns=jn;
kvSql=kvsqls;
codSql=codSqls;
DbUtil.close(rs);
DbUtil.close(st);
DbUtil.close(conn);
}
}
public static boolean isRole(String userName, String url) {
return true;
}
public static List<KvBean> getAllByKey(String db_err_info, Object o) {
return new ArrayList<>();
}
}

View File

@@ -0,0 +1,905 @@
package com.wb.common;
import com.wb.controls.*;
import com.wb.interact.Controls;
import com.wb.util.*;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.IOUtils;
import org.json.JSONArray;
import org.json.JSONObject;
import org.springframework.beans.BeanUtils;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
/**
* 模块解析器,解析并执行模块文件。解析完成后,系统把生成的客户端脚本发送到客户端。
*/
public class Parser {
/**
* html头文本
*/
private StringBuilder headerHtml = new StringBuilder();
/**
* html脚文本
*/
private ArrayList<String> footerHtml = new ArrayList<String>(15);
/**
* html脚文本指针
*/
private int htmlPointer;
/**
* js头文本
*/
private StringBuilder headerScript = new StringBuilder();
/**
* js脚文本
*/
private ArrayList<String> footerScript = new ArrayList<String>(15);
/**
* js脚文本指针
*/
private int scriptPointer;
/**
* 是否是普通运行模式
*/
private HttpServletRequest request;
/**
* HttpServletResponse响应对象
*/
private HttpServletResponse response;
/**
* 普通运行模式
*/
public static final int RUN_NORMAL = 0;
/**
* 模块引用运行模式
*/
public static final int RUN_MODULE = 1;
/**
* 控件引用运行模式
*/
public static final int RUN_CONTROL = 2;
/**
* 外部调用模式
*/
public static final int RUN_INVOKE = 3;
//按钮功能
private Map menuRes = new HashMap();
/**
* XWL文件解析器构造函数。
*
* @param request HttpServletRequest 请求对象。
* @param response HttpServletRequest 响应对象。
*/
public Parser(HttpServletRequest request, HttpServletResponse response) {
this.request = request;
this.response = response;
}
/**
* 解析xwl模块。依次遍历模块内所有节点执行控件的create方法。
* 执行完成后系统自动关闭和释放资源。
*
* @param moduleFile xwl文件相对路径。
*/
public void parse(String moduleFile) throws ServletException {
boolean hasExcept = false;
List<FileItem> fileItemList = null;
ConcurrentHashMap<String, Object> varMap = null;
try {
varMap = new ConcurrentHashMap<String, Object>();
request.setAttribute("sys.varMap", varMap);
if (ServletFileUpload.isMultipartContent(request))
fileItemList = WebUtil.setUploadFile(request);
execute(moduleFile, request.getParameter("xwlt") == null ? RUN_NORMAL : RUN_INVOKE, null);
} catch (Throwable e) {
hasExcept = true;
WebUtil.showException(e, request, response);
} finally {
closeObjects(varMap, hasExcept);
if (fileItemList != null)
WebUtil.clearUploadFile(request, fileItemList);
}
}
/**
* 解析和执行xwl文件。依次遍历模块内所有节点执行对应控件的create方法。
*
* @param moduleFile xwl文件相对路径。
* RUN_NORMAL普通运行模式完成全部流程如果有前端脚本不返回入口。
* RUN_MODULE不验证权限不关闭资源如果有前端脚本不返回入口。
* RUN_CONTROL不验证权限不关闭资源如果有前端脚本返回app主入口。
* RUN_INVOKE完成全部流程如果有前端脚本返回整个app对象。
* @param xwlId 模块itemId名称用于在命名空间中子空间名称指定。
* @throws Exception 如果解析过程中发生异常将抛出。
*/
public void execute(String moduleFile, int runType, String xwlId) throws Exception {
JSONObject fullModule = XwlBuffer.get(moduleFile, false);
JSONObject module = (JSONObject) ((JSONArray) fullModule.opt("children")).opt(0);
JSONObject configs = (JSONObject) module.opt("configs");
//根据登录用户处理数据
String username = (String) request.getSession().getAttribute("sys.username");
Map mapMenuRes = (Map) request.getSession().getAttribute("mapMenuRes");
if (mapMenuRes != null) {
List data = (List) mapMenuRes.get(username);
for (int i = 0; data != null && i < data.size(); i++) {
Map map = (Map) data.get(i);
String url = (String) map.get("url");
if (moduleFile.equals(url)) {
menuRes.put(map.get("ename"), map.get("enabled"));
}
}
}
boolean runNormal = runType == RUN_NORMAL, runInvoke = runType == RUN_INVOKE;
if (runNormal || runInvoke) {
// 检查头信息是否一致
String method = getString(configs, "method"), tokens = getString(configs, "tokens");
if (!method.isEmpty() && !method.equalsIgnoreCase(request.getMethod())) {
throw new IllegalArgumentException("Method not allowed");
}
if (tokens.isEmpty() || !checkToken(tokens)) {
// 验证登录和权限
if (Boolean.TRUE.equals(fullModule.opt("loginRequired"))) {
if (!WebUtil.checkLogin(request, response))
return;// 未登录在checkLogin方法中返回SC_UNAUTHORIZED
// 未具备权限抛出异常
if (moduleFile.equals("dev/ide.xwl")) {
if (!WebUtil.canAccess(moduleFile, Session.getRoles(request), request))
throw new Exception(com.wb.common.Str.format(request, "forbidden",
StringUtil.select(fullModule.optString("title"), FileUtil.getFilename(moduleFile)),
moduleFile));
}
String isRedisRole = ResourceBundle.getBundle("system").getString("isRedisRole");
if ("1".equals(isRedisRole) && !KVBuffer.isRole(username, moduleFile)){
throw new RuntimeException("权限变化,请重新登录!");
}
//控制同一个账号多个用户登录
// if (!(request.getSession().getAttribute("sys.user")+request.getSession().getId()).equals(Var.getSessionuserid())) {
//
// throw new Exception(com.wb.common.Str.format(request, "forbiddenONeuser",
// StringUtil.select(fullModule.optString("title"), FileUtil.getFilename(moduleFile)),
// moduleFile));
// }
}
}
}
JSONObject events = (JSONObject) module.opt("events"), emptyJson = new JSONObject();
JSONObject moduleGeneral = (JSONObject) Controls.get("module").opt("general");
String namespace, theme = null, touchTheme = null, content;
boolean createFrame, libTypes[] = null;
boolean hasChildren = module.has("children"), hasEvents = events != null;
HttpSession session = null;
content = getString(configs, "logMessage");
if (!content.isEmpty())
LogUtil.info(request, content);
// initScript在importModule之前运行serverScript在importModule之后运行
content = ServerScript.getScript(configs, "initScript");
if (!content.isEmpty())
com.wb.common.ScriptBuffer.run(StringUtil.concat((String) configs.opt("id"), ".is"), content, request, response,
moduleFile);
content = getString(configs, "serverMethod");
if (!content.isEmpty())
SysUtil.executeMethod(content, request, response);
createFrame = getBool(configs, "createFrame", true);
if (createFrame && runNormal) {
String title, tagConfigs;
headerHtml.append(
"<!DOCTYPE html>\n<html>\n<head>\n<meta http-equiv=\"content-type\" content=\"text/html;charset=utf-8\"/>\n<meta name=\"description\" content=\"Welcome to www.ag6666666, we provide excellent solutions.\"/>\n<title>");
title = getString(configs, "title");
if (title.isEmpty()) {
title = fullModule.optString("title");// 默认页面标题为模块的标题
if (title.startsWith("Str."))
title = com.wb.common.Str.format(request, title.substring(4));
} else if (title.equals("-"))
title = null; // "-"表示标题为空
if (!StringUtil.isEmpty(title))
headerHtml.append(title);
headerHtml.append("</title>");
appendScript(headerHtml, getString(configs, "head"));
session = request.getSession(false);
theme = session == null ? null : (String) session.getAttribute("sys.theme");
theme = "modern";
if (theme == null)
theme = com.wb.common.Var.getString("sys.app.theme");
touchTheme = session == null ? null : (String) session.getAttribute("sys.touchTheme");
if (touchTheme == null)
touchTheme = com.wb.common.Var.getString("sys.app.touchTheme");
libTypes = setLinks(configs, theme, touchTheme);
tagConfigs = getString(configs, "tagConfigs");
if (tagConfigs.isEmpty())
headerHtml.append("\n</head>\n<body>");
else {
headerHtml.append("\n</head>\n<body ");
headerHtml.append(tagConfigs);
headerHtml.append('>');
}
headerScript.append("<script language=\"javascript\" type=\"text/javascript\">");
}
appendScript(headerHtml, getString(configs, "initHtml"));
if (createFrame) {
if (headerScript.length() > 0)
headerScript.append('\n');
if (runNormal && libTypes[1]) {
// 加载了Ext
headerScript.append("Ext.onReady(function(contextOptions,contextOwner){");
} else if (runNormal && libTypes[2]) {
// 加载了touch
headerScript.append("Ext.setup({");
if (hasChildren)
headerScript.append(getTouchViewport((JSONArray) module.opt("children"), moduleGeneral, runNormal));
headerScript.append("onReady:function(contextOptions,contextOwner){");
} else
headerScript.append("(function(contextOptions,contextOwner){");
namespace = (String) configs.opt("itemId");
// 如果模块itemId未改名则创建内部命名空间。
if (namespace.equals("module")) {
headerScript.append("\nvar app={};");
} else {
// 创建命名空间
headerScript.append("\nWb.ns(\"");
headerScript.append(namespace);
headerScript.append("\");\nvar app=");
headerScript.append(namespace);
headerScript.append(";");
}
if (runNormal && libTypes[2]) {
// 设置viewport appscope和引用
headerScript.append("\nthis.appScope=app;\napp[this.itemId]=this;");
}
headerScript.append("\napp.contextOwner=contextOwner;");
if (runNormal) {
// 设置常用变量
headerScript.append("\nwindow.app=app;\nWb.init({zo:");
if (com.wb.common.Var.useLocalTime) {
Calendar cal = Calendar.getInstance();
headerScript.append((cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET)) / 60000);
} else
headerScript.append("-1");
if (com.wb.common.Var.maskTimeout != 1500) {
headerScript.append(",mask:");
headerScript.append(com.wb.common.Var.maskTimeout);
}
if (com.wb.common.Var.ajaxTimeout != 0) {
headerScript.append(",timeout:");
headerScript.append(com.wb.common.Var.ajaxTimeout);
}
if (!"gray".equals(theme)) {
headerScript.append(",theme:\"");
headerScript.append(theme);
headerScript.append('\"');
}
if (!"classic".equals(touchTheme)) {
headerScript.append(",touchTheme:\"");
headerScript.append(touchTheme);
headerScript.append('\"');
}
theme = session == null ? null : (String) session.getAttribute("sys.editTheme");
theme = "modern";
if (theme == null)
theme = com.wb.common.Var.getString("sys.ide.editTheme");
if (!"default".equals(theme)) {
headerScript.append(",editTheme:\"");
headerScript.append(theme);
headerScript.append('\"');
}
headerScript.append("});");
} else if (runType == RUN_CONTROL || runType == RUN_MODULE) {
// 添加xwl控件有xwlId导入方法无xwlId
if (xwlId != null) {
headerScript.append("\ncontextOwner[");
headerScript.append(StringUtil.quote(xwlId));
headerScript.append("]=app;");
}
}
}
// 导入模块,在解析子控件之前执行
content = getString(configs, "importModules");
if (!content.isEmpty())
importModules(content);
// serverScript在导入模块之后运行在开始运行可使用initScript
content = ServerScript.getScript(configs, "serverScript");
if (!content.isEmpty())
ScriptBuffer.run(StringUtil.concat((String) configs.opt("id"), ".ss"), content, request, response,
moduleFile);
if (hasEvents) {
String beforeunload = getString(events, "beforeunload");
if (!beforeunload.isEmpty())
appendScript(headerScript,
StringUtil.concat("Wb.onUnload(function(){\n", beforeunload, "\n},contextOwner);"));
appendScript(headerScript, getString(events, "initialize"));
}
if (hasChildren)
scan(module, moduleGeneral, emptyJson, runNormal);
// 如果已经提交,则脚本无需再输出。
if (response.isCommitted())
return;
appendScript(headerHtml, getString(configs, "finalHtml"));
if (hasEvents)
appendScript(headerScript, getString(events, "finalize"));
if (createFrame) {
if (runNormal) {
if (libTypes[1]) // Ext
headerScript.append("\n});");
else if (libTypes[2])// touch
headerScript.append("\n}});");
else
headerScript.append("\n})();");
} else if (runType == RUN_CONTROL) {
headerScript.append("\nreturn Wb.optMain(app);\n})(null,app)");
} else if (runType == RUN_MODULE)
headerScript.append("\n})(null,app);");
else
// RUN_INVOKE
headerScript.append("\nreturn app;\n})();");// 不可带参数,在引用时自动传入
}
if (runNormal) {
if (createFrame)
headerScript.append("\n</script>\n</body>\n</html>");
output();
} else if (runInvoke)
output();
}
/**
* 检查当前请求url中带的_token参数是否有效。
*
* @param tokens 模块设置的token列表。
* @return true有效false无效。
*/
private boolean checkToken(String tokens) {
String token = request.getParameter("_token");
if (StringUtil.isEmpty(token))
return false;
String[] ls = StringUtil.split(tokens, ",");
for (String s : ls) {
if (token.equals(s.trim()))
return true;
}
return false;
}
/**
* 立即把脚本输出至客户端。
*
* @throws IOException
*/
public void output() throws IOException {
if (headerHtml.length() > 0 && headerScript.length() > 0)
headerHtml.append('\n');
// 把headerScript合并到headerHtml中并输出
headerHtml.append(headerScript);
if (headerHtml.length() > 0) {
if (WebUtil.jsonResponse(request))
WebUtil.send(response, headerHtml.toString(), true);
else
WebUtil.send(response, headerHtml);
}
}
/**
* 增加列排序功能
* @param bindArrayResult
* @return
*/
private static JSONArray sortProxyAndCdn(JSONArray bindArrayResult) {
Map datamap=new HashMap();
datamap.put("name",2);
datamap.put("value",1);
List<JSONObject> arrylist=new ArrayList<>();
for(int i=0;i<bindArrayResult.length();i++){
arrylist.add(bindArrayResult.getJSONObject(i));
}
Collections.sort(arrylist, new Comparator<JSONObject>() {
@Override
public int compare(JSONObject o1, JSONObject o2) {
if(((JSONObject)o1.get("configs")).has("dataIndex")&&((JSONObject)o2.get("configs")).has("dataIndex")) {
int a = Integer.parseInt(datamap.get(((JSONObject) o1.get("configs")).get("dataIndex").toString()).toString());
int b = Integer.parseInt(datamap.get(((JSONObject) o2.get("configs")).get("dataIndex").toString()).toString());
if (a > b) {
return -1;
} else if (a == b) {
return 0;
} else
return 1;
}else return 0;
}
});
JSONArray jsonArray = new JSONArray();
for(int h=0;h<arrylist.size();h++) {
JSONObject jsonObjectfinal=arrylist.get(h);
jsonArray.add(h,arrylist.get(h));
}
System.out.println("排序后:"+jsonArray);
return jsonArray;
}
/**
* 按顺序递归模块中所有节点内容并执行,如果节点生成客户端脚本将获取这些脚本。
*
* @param parentNode 当前节点对象。
* @param parentGeneral 父级点元数据常规配置信息。
* @param emptyJson 空JSON对象用于指定父控件空元数据。
* @param normalType 是否为普通运行模式。
*/
private void scan(JSONObject parentNode, JSONObject parentGeneral, JSONObject emptyJson, boolean normalType)
throws Exception {
JSONArray ja = (JSONArray) parentNode.opt("children");
Control control;
JSONObject jo, meta, general, configItems, configs;
String className, type, lastScript, itemId;
boolean isScriptControl, rootParent;
int i, j = ja.length(), k = j - 1, quoteIndex;
/* 控制列显示和排序
if (parentNode.has("configs")) {
if (((JSONObject) parentNode.get("configs")).get("itemId").equals("columns")) {
ja= sortProxyAndCdn(ja);
}
}*/
for (i = 0; i < j; i++) {
jo = (JSONObject) ja.opt(i);
configs = (JSONObject) jo.opt("configs");
if (configs.has("itemId")) {
itemId = configs.get("itemId").toString().trim();
if (menuRes.containsKey(itemId)){
configs.put("isRoleExists", "true");
if ("0".equals(menuRes.get(itemId))) {
configs.put("hidden", "true");
}else {
configs.put("hidden", "false");
}
}else if (configs.has("isRoleExists") && configs.has("hidden")){
configs.put("hidden", "false");
}
/*if (menuRes.get(itemId) != null) {
//continue;
configs.put("disabled", "true");
}else if (menuRes.size()>0 && configs.has("disabled")
&& menuRes.containsKey()&& "true".equals(configs.getString("disabled"))){
configs.put("disabled", "false");
}*/
}
type = (String) jo.opt("type");
meta = Controls.get(type);
general = (JSONObject) meta.opt("general");
className = (String) general.opt("class");
if (className == null) {
// 未指定类名
control = new ExtControl();
isScriptControl = true;
} else if (className.equals("null")) {
// 类名指定为null
control = null;
isScriptControl = false;
if (type.equals("xwl")) {
rootParent = Boolean.TRUE.equals(parentGeneral.opt("root"));
addModule(jo, rootParent);
if (!rootParent && i < j - 1)
headerScript.append(',');
}
} else {
if (className.indexOf('.') == -1)
className = "com.wb.controls." + className;
control = (Control) Class.forName(className).newInstance();
isScriptControl = control instanceof ScriptControl;
}
if (control != null) {
control.init(request, response, jo, meta, parentGeneral, i == k, normalType);
control.create();
}
if (isScriptControl) {
ScriptControl sc = (ScriptControl) control;
appendScript(headerHtml, sc.getHeaderHtml());
pushHtml(sc.getFooterHtml());
appendScript(headerScript, sc.getHeaderScript());
pushScript(sc.getFooterScript());
}
// 配置的子项作为控件
if (jo.has("children"))
scan(jo, general, emptyJson, normalType);
if (isScriptControl) {
appendScript(headerHtml, popHtml());
lastScript = popScript();
quoteIndex = lastScript.lastIndexOf('}');
if (quoteIndex != -1 && (configItems = (JSONObject) jo.opt("__configs")) != null) {
// 注入在XwlBuffer.optimize中自动生成的子项作为配置项
appendScript(headerScript, lastScript.substring(0, quoteIndex));
headerScript.append(',');
scan((JSONObject) configItems, emptyJson, emptyJson, normalType);
appendScript(headerScript, lastScript.substring(quoteIndex));
} else {
appendScript(headerScript, lastScript);
}
}
}
}
/**
* 解析xwl模块控件。
*
* @param jo 控件数据对象。
* @param rootParent 父控件是否为根控件。
*/
private void addModule(JSONObject jo, boolean rootParent) throws Exception {
JSONObject configs = (JSONObject) jo.opt("configs");
String file = getString(configs, "file");
if (file != null)
execute(FileUtil.getModuleFile(file), rootParent ? Parser.RUN_MODULE : Parser.RUN_CONTROL,
(String) configs.opt("itemId"));
}
/**
* 把指定footerHtml脚本添加到堆栈中。此方法较Stack类更高效。
*
* @param script 添加的footerHtml脚本。
*/
private void pushHtml(String script) {
htmlPointer++;
if (footerHtml.size() < htmlPointer)
footerHtml.add(script);
else
footerHtml.set(htmlPointer - 1, script);
}
/**
* 提取堆栈中最后一项footerHtml脚本。
*
* @return footerHtml脚本。
*/
private String popHtml() {
htmlPointer--;
return footerHtml.get(htmlPointer);
}
/**
* 把指定footerScript脚本添加到堆栈中。此方法较Stack类更高效。
*
* @param script 添加的footerScript脚本。
*/
private void pushScript(String script) {
scriptPointer++;
if (footerScript.size() < scriptPointer)
footerScript.add(script);
else
footerScript.set(scriptPointer - 1, script);
}
/**
* 提取堆栈中最后一项footerScript脚本。
*
* @return footerScript脚本。
*/
private String popScript() {
scriptPointer--;
return footerScript.get(scriptPointer);
}
/**
* 添加脚本至指定StringBuilder对象。如果添加之前已经存在脚本则换行后添加脚本。
*
* @param buf 需要被添加脚本的StringBuilder对象。
* @param script 添加的脚本。
*/
private void appendScript(StringBuilder buf, String script) {
if (!StringUtil.isEmpty(script)) {
if (buf.length() > 0)
buf.append('\n');
buf.append(script);
}
}
/**
* 导入在importModules属性中指定的子模块列表。
*
* @param modules 导入的模块列表。
* @throws Exception 导入过程发生异常。
*/
private void importModules(String modules) throws Exception {
JSONArray moduleArray = new JSONArray(modules);
int i, j = moduleArray.length();
for (i = 0; i < j; i++)
execute(FileUtil.getModuleFile((String) moduleArray.opt(i)), Parser.RUN_MODULE, null);
}
/**
* 设置模块的js和css链接。
*
* @param configs 模块的配置项。
* @param theme 界面方案名称。
* @return 加载的库列表。0 未知, 1 Ext, 2 Touch, 3 BS。
*/
private boolean[] setLinks(JSONObject configs, String theme, String touchTheme) {
ArrayList<String> cssArray = new ArrayList<String>(), jsArray = new ArrayList<String>();
JSONArray cssLinks = null, jsLinks = null;
String debugSuffix, value, cssLinksText, jsLinksText;
String loadJS = getString(configs, "loadJS");
String lang = (String) request.getAttribute("sys.useLang");
int i, j, index;
boolean libTypes[] = new boolean[4];
if (Var.debug)
debugSuffix = "-debug";
else
debugSuffix = "";
request.setAttribute("debugSuffix", debugSuffix);
cssLinksText = getString(configs, "cssLinks");
jsLinksText = getString(configs, "jsLinks");
if (!cssLinksText.isEmpty())
cssLinks = new JSONArray(cssLinksText);
if (!jsLinksText.isEmpty())
jsLinks = new JSONArray(jsLinksText);
if (loadJS.isEmpty())
loadJS = "ext";
jsArray.add(StringUtil.concat("wb/script/locale/wb-lang-", com.wb.common.Str.optLanguage(lang), debugSuffix, ".js"));
jsArray.add("wb/script/LodopFuncs.js");
//theme="modern";
if (loadJS.indexOf("ext") != -1) {
libTypes[1] = true;
cssArray.add(StringUtil.concat("wb/libs/ext/resources/ext-theme-", theme, "/ext-theme-", theme, "-all",
debugSuffix, ".css"));
jsArray.add(StringUtil.concat("wb/libs/ext/ext-all", debugSuffix, ".js"));
jsArray.add(
StringUtil.concat("wb/libs/ext/locale/ext-lang-", com.wb.common.Str.optExtLanguage(lang), debugSuffix, ".js"));
}
if (loadJS.indexOf("touch") != -1) {
libTypes[2] = true;
cssArray.add(StringUtil.concat("wb/libs/touch/resources/css/", touchTheme, debugSuffix, ".css"));
jsArray.add(
StringUtil.concat("wb/libs/touch/locale/t-lang-", Str.optTouchLanguage(lang), debugSuffix, ".js"));
jsArray.add(StringUtil.concat("wb/libs/touch/sencha-touch-all", debugSuffix, ".js"));
}
if (loadJS.indexOf("bootstrap") != -1) {
libTypes[3] = true;
cssArray.add(StringUtil.concat("wb/libs/bs/css/bootstrap", debugSuffix, ".css"));
jsArray.add(StringUtil.concat("wb/libs/jquery/jquery", debugSuffix, ".js"));
jsArray.add(StringUtil.concat("wb/libs/bs/js/bootstrap", debugSuffix, ".js"));
}
if (loadJS.indexOf("jquery") != -1)
jsArray.add("wb/libs/jquery/jquery" + debugSuffix + ".js");
cssArray.add(StringUtil.concat("wb/css/style", debugSuffix, ".css"));
jsArray.add(StringUtil.concat("wb/script/wb", debugSuffix, ".js"));
jsArray.add("supcan/binary/dynaload.js?123");
jsArray.add("wb/libs/ext/plugin/GridFilter.js");
jsArray.add("wb/libs/ext/plugin/Uppertextfield.js");
jsArray.add("wb/libs/ext/plugin/IconItemSave.js");
jsArray.add("wb/libs/ext/plugin/Ext.ux.grid.FilterBar.js");
if (cssLinks != null) {
j = cssLinks.length();
for (i = 0; i < j; i++) {
value = cssLinks.getString(i);
index = cssArray.indexOf(value);
// 允许重新设置css加载顺序
if (index != -1)
cssArray.remove(index);
cssArray.add(value);
}
}
if (jsLinks != null) {
j = jsLinks.length();
for (i = 0; i < j; i++) {
value = jsLinks.getString(i);
index = jsArray.indexOf(value);
// 允许重新设置js加载顺序
if (index != -1)
jsArray.remove(index);
jsArray.add(value);
}
}
for (String css : cssArray) {
headerHtml.append("\n<link type=\"text/css\" rel=\"stylesheet\" href=\"");
headerHtml.append(css);
headerHtml.append("\">");
}
for (String js : jsArray) {
headerHtml.append("\n<script type=\"text/javascript\" src=\"");
headerHtml.append(js);
headerHtml.append("\"></script>");
}
return libTypes;
}
/**
* 获取对象中指定名称的替换参数后的字符串值。
*
* @param object JSNObject对象。
* @param name 名称。
* @return 获取的值。如果值为空返回空字符串。
*/
private String getString(JSONObject object, String name) {
String value = (String) object.opt(name);
if (value == null)
return "";
else
return WebUtil.replaceParams(request, value);
}
/**
* 获取对象中指定名称的替换参数后的布尔值。
*
* @param object JSNObject对象。
* @param name 名称。
* @param defaultValue 默认值。
* @return 获取的值。如果值为空返回默认值。
*/
private boolean getBool(JSONObject object, String name, boolean defaultValue) {
String value = getString(object, name);
if (value.isEmpty())
return defaultValue;
else
return Boolean.parseBoolean(value);
}
/**
* 关闭存储在map中的对象。
*
* @param map 存储的map对象。
* @param isExcept 是否有异常,如果存在未提交事务且有异常将回滚事务否则提交事务。
*/
private void closeObjects(ConcurrentHashMap<String, Object> map, boolean isExcept) {
Object object;
Set<Entry<String, Object>> es = map.entrySet();
ArrayList<Connection> connList = new ArrayList<Connection>();
ArrayList<Statement> stList = new ArrayList<Statement>();
for (Entry<String, Object> e : es) {
object = e.getValue();
if (object != null) {
if (object instanceof ResultSet)
DbUtil.close((ResultSet) object);
else if (object instanceof Statement)
stList.add((Statement) object);
else if (object instanceof Connection)
connList.add((Connection) object);
else if (object instanceof InputStream)
IOUtils.closeQuietly((InputStream) object);
else if (object instanceof OutputStream)
IOUtils.closeQuietly((OutputStream) object);
}
}
for (Statement st : stList)
DbUtil.close(st);
for (Connection conn : connList) {
if (isExcept)
DbUtil.close(conn);
else
DbUtil.closeCommit(conn);
}
}
/**
* 获取touch模式viewport控件的脚本。
*
* @param items 模块根控件列表。
* @param parentGeneral 模块控件general属性。
* @param normalType 是否是普通运行模式。
* @return viewport控件脚本如果不存在viewport控件返回空串。
*/
private String getTouchViewport(JSONArray items, JSONObject parentGeneral, boolean normalType) throws Exception {
if (items == null)
return "";
JSONObject meta = Controls.get("tviewport");
StringBuilder script = new StringBuilder();
ExtControl control;
int i, j = items.length(), k = j - 1;
JSONObject jo;
for (i = 0; i < j; i++) {
jo = ((JSONObject) items.opt(i));
if ("tviewport".equals(jo.opt("type"))) {
control = new ExtControl();
control.normalMode = false;
control.init(request, response, jo, meta, parentGeneral, i == k, normalType);
control.create();
script.append("\nviewport:");
script.append(control.getHeaderScript());
script.append(control.getFooterScript());
script.append(',');
return script.toString();
}
}
return "";
}
/**
* 按顺序递归模块中所有节点内容并执行,如果节点生成客户端脚本将获取这些脚本。
*
* @param parentNode 当前节点对象。
* @param parentGeneral 父级点元数据常规配置信息。
* @param emptyJson 空JSON对象用于指定父控件空元数据。
* @param normalType 是否为普通运行模式。
*/
private String scanresult(JSONObject parentNode, JSONObject parentGeneral, JSONObject emptyJson, boolean normalType)
throws Exception {
JSONArray ja = (JSONArray) parentNode.opt("children");
DpAutoGenControl control = new DpAutoGenControl();
JSONObject jo, meta, general, configItems, configs;
String className, type, lastScript, itemId;
boolean isScriptControl, rootParent;
int i, j = ja.length(), k = j - 1, quoteIndex;
String data = "";
for (i = 0; i < j; i++) {
jo = (JSONObject) ja.opt(i);
configs = (JSONObject) jo.opt("configs");
if (configs.has("itemId")) {
itemId = configs.get("itemId").toString().trim();
if (menuRes.containsKey(itemId)){
if ("0".equals(menuRes.get(itemId))) {
configs.put("hidden", "true");
}else {
configs.put("hidden", "false");
}
}
}
type = (String) jo.opt("type");
meta = Controls.get(type);
general = (JSONObject) meta.opt("general");
className = (String) general.opt("class");
control.init(request, response, jo, meta, parentGeneral, i == k, normalType);
data = control.createfalse();
}
return data;
}
/**
* 解析和执行xwl文件。依次遍历模块内所有节点执行对应控件的create方法。
*
* @param moduleFile xwl文件相对路径。
* RUN_NORMAL普通运行模式完成全部流程如果有前端脚本不返回入口。
* RUN_MODULE不验证权限不关闭资源如果有前端脚本不返回入口。
* RUN_CONTROL不验证权限不关闭资源如果有前端脚本返回app主入口。
* RUN_INVOKE完成全部流程如果有前端脚本返回整个app对象。
* @param xwlId 模块itemId名称用于在命名空间中子空间名称指定。
* @throws Exception 如果解析过程中发生异常将抛出。
*/
public String executeresult(String moduleFile, int runType, String xwlId) throws Exception {
JSONObject fullModule = XwlBuffer.get(moduleFile, false);
JSONObject module = (JSONObject) ((JSONArray) fullModule.opt("children")).opt(0);
boolean runNormal = runType == RUN_NORMAL, runInvoke = runType == RUN_INVOKE;
JSONObject emptyJson = new JSONObject();
JSONObject moduleGeneral = (JSONObject) Controls.get("module").opt("general");
return scanresult(module, moduleGeneral, emptyJson, runNormal);
}
}

View File

@@ -0,0 +1,224 @@
package com.wb.common;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.io.IOUtils;
import com.wb.util.WebUtil;
import org.apache.logging.log4j.core.util.UuidUtil;
/**
* 存储和维护较大的文本或二进制数据至数据库。
* 如果数据较小长度小于255字节可使用{@link Value}类。
* 如果数据较小且对性能有高要求可使用{@link Var}类。
*
* @see Value
* @see Var
*/
public class Resource {
/**
* 获取当前用户指定编号的文本资源。如果资源不存在将返回defaultValue。
*
* @param request 当前用户请求的request对象。
* @param id 资源id编号。
* @param defaultValue 默认值。
* @return 获取的文本。
*/
public static String getString(HttpServletRequest request, String id,
String defaultValue) {
return getString(WebUtil.getIdWithUser(request, id), defaultValue);
}
/**
* 获取指定编号的文本资源。如果资源不存在将返回defaultValue。
*
* @param id 资源id编号。
* @param defaultValue 默认值。
* @return 获取的文本。
*/
public static String getString(String id, String defaultValue) {
try {
byte[] bytes = getBytes(id, null);
if (bytes == null)
return defaultValue;
else
return new String(bytes, "utf-8");
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
/**
* 获取指定编号的文本资源。如果资源不存在将返回null。
*
* @param id 资源id编号。
* @return 获取的文本。
*/
public static String getString(String id) {
return getString(id, null);
}
/**
* 获取当前用户指定编号的字节数组资源。如果资源不存在将返回defaultValue。
*
* @param request 当前用户请求的request对象。
* @param id 资源id编号。
* @param defaultValue 默认值。
* @return 获取的字节数组。
*/
public static byte[] getBytes(HttpServletRequest request, String id,
byte[] defaultValue) {
return getBytes(WebUtil.getIdWithUser(request, id), defaultValue);
}
/**
* 获取指定编号的字节数组资源。如果资源不存在将返回defaultValue。
*
* @param id 资源id编号。
* @param defaultValue 默认值。
* @return 获取的字节数组。
*/
public static byte[] getBytes(String id, byte[] defaultValue) {
Connection conn = null;
PreparedStatement st = null;
ResultSet rs = null;
try {
conn = com.wb.util.DbUtil.getConnection();
st = conn
.prepareStatement("select RES_CONTENT from WB_RESOURCE where RES_ID=?");
st.setString(1, id);
rs = st.executeQuery();
if (rs.next()) {
ByteArrayOutputStream os = new ByteArrayOutputStream();
InputStream is = rs.getBinaryStream(1);
if (is != null) {
try {
IOUtils.copy(is, os);
} finally {
is.close();
}
return os.toByteArray();
}
}
} catch (Throwable e) {
throw new RuntimeException(e);
} finally {
com.wb.util.DbUtil.close(rs);
com.wb.util.DbUtil.close(st);
com.wb.util.DbUtil.close(conn);
}
return defaultValue;
}
/**
*
* 把字符串作为资源存储到特定的数据库表中并在当前用户下指定id编号标识。
* 如果值为null将删除id指定的值。
* @param request 当前用户请求的request对象。
* @param id 资源id编号。
* @param data 存储的字符串。
*/
public static void set(HttpServletRequest request, String id, String data) {
set(WebUtil.getIdWithUser(request, id), data);
}
/**
* 把字符串作为资源存储到特定的数据库表中并以指定id编号标识。
* 如果值为null将删除id指定的值。
*
* @param id 资源id编号。
* @param data 存储的字符串。
*/
public static void set(String id, String data) {
try {
byte[] bytes;
if (data == null)
bytes = null;
else
bytes = data.getBytes("utf-8");
set(id, bytes);
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
/**
* 删除指定编号的资源。
*
* @param id 资源id编号。
*/
public static void remove(String id) {
set(id, (byte[]) null);
}
/**
* 删除当前用户指定编号的资源。
*
* @param request 请求对象。
* @param id 资源id编号。
*/
public static void remove(HttpServletRequest request, String id) {
set(request, id, (byte[]) null);
}
/**
* 把字节数组作为资源存储到特定的数据库表中并以指定id编号标识。
* 如果值为null将删除id指定的值。
* @param id 资源id编号。
* @param data 字节数组值。
*/
public static void set(String id, byte[] data) {
Connection conn = null;
PreparedStatement st = null;
boolean hasData = data != null;
try {
conn = com.wb.util.DbUtil.getConnection();
if (hasData)
conn.setAutoCommit(false);
st = conn
.prepareStatement("delete from WB_RESOURCE where RES_ID=?");
st.setString(1, id);
st.executeUpdate();
com.wb.util.DbUtil.close(st);
st = null;
if (hasData) {
st = conn
.prepareStatement("insert into WB_RESOURCE values(?,?,?)");
st.setString(1, id);
st.setBinaryStream(2, new ByteArrayInputStream(data),
data.length);
st.setString(3, UUID.randomUUID().toString().replaceAll("-",""));
st.executeUpdate();
conn.commit();
}
} catch (Throwable e) {
throw new RuntimeException(e);
} finally {
com.wb.util.DbUtil.close(st);
com.wb.util.DbUtil.close(conn);
}
}
/**
*
* 把字节数组作为资源存储到特定的数据库表中并在当前用户下指定id编号标识。
* 如果值为null将删除id指定的值。
* @param request 当前用户请求的request对象。
* @param id 资源id编号。
* @param data 字节数组值。
*/
public static void set(HttpServletRequest request, String id, byte[] data) {
set(WebUtil.getIdWithUser(request, id), data);
}
}

View File

@@ -0,0 +1,175 @@
package com.wb.common;
import java.io.File;
import java.util.ArrayList;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import javax.script.Bindings;
import javax.script.Compilable;
import javax.script.CompiledScript;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.quartz.JobExecutionContext;
/**
* JavaScript脚本执行和缓存器。缓存首次访问并编译后的脚本对象
*便于下次对脚本访问时无需编译而直接运行。
*/
public class ScriptBuffer {
/**
* JavaScript全局成员列表。
*/
public static ArrayList<String> globalMembers;
/**
* JavaScript引擎管理器对象。
*/
private static ScriptEngineManager manager;
/**
* JavaScript引擎对象。
*/
private static ScriptEngine engine;
/**
* JavaScript可编译的引擎对象。
*/
private static Compilable compilable;
/**
* 缓存编译后的JavaScript脚本的HashMap。
*/
private static ConcurrentHashMap<String, CompiledScript> buffer;
/**
* 在Web请求上下文中运行指定编号的脚本对象。首次运行脚本将被编译并缓存编译后的实例。
*
* @param id 脚本编号
* @param scriptText 脚本内容
* @param request Web上下文HttpServletRequest对象参数
* @param response Web上下文HttpServletResponse对象参数
* @param sourceURL 调试脚本时标识代码的文件路径
* @throws Exception 执行脚本发生错误
*/
public static Object run(String id, String scriptText, HttpServletRequest request, HttpServletResponse response,
String sourceURL) throws Exception {
CompiledScript script = buffer.get(id);
if (script == null) {
script = compilable.compile(encScript(scriptText, sourceURL, true));
buffer.put(id, script);
}
Bindings bindings = engine.createBindings();
bindings.put("request", request);
bindings.put("response", response);
return script.eval(bindings);
}
/**
* 包装执行的脚本添加sourceURL和app对象。如果在调试模块下添加调试信息。
* @param scriptText 脚本内容。
* @param sourceURL 脚本对应的源URL。
* @param addApp 是否添加app对象。
* @return 包装script。
*/
private static String encScript(String scriptText, String sourceURL, boolean addApp) {
StringBuilder buf = new StringBuilder(scriptText.length() + 100);
buf.append("(function main(){");
if (addApp)
buf.append("var app=Wb.getApp(request,response);");
buf.append(scriptText);
buf.append("\n})();");
if (!com.wb.util.StringUtil.isEmpty(sourceURL)) {
buf.append("\n//# sourceURL=");
buf.append(sourceURL);
}
return buf.toString();
}
/**
* 运行服务器端脚本。运行后的脚本不会进行缓存。
* @param scriptText 脚本内容
* @param sourceURL 脚本对应的源URL。
* @throws Exception 执行脚本发生错误
*/
public static Object run(String scriptText, String sourceURL) throws Exception {
CompiledScript script = compilable.compile(encScript(scriptText, sourceURL, false));
return script.eval();
}
/**
* 在计划任务中运行指定编号的脚本对象。首次运行脚本将被编译并缓存编译后的实例。
*
* @param taskId 计划任务编号
* @param scriptText 脚本内容
* @param jobContext 任务上下文对象
* @throws Exception 执行脚本发生错误
*/
public static void run(String taskId, String scriptText, JobExecutionContext jobContext) throws Exception {
CompiledScript script = buffer.get(taskId);
if (script == null) {
script = compilable.compile(encScript(scriptText, taskId, false));
buffer.put(taskId, script);
}
Bindings bindings = engine.createBindings();
bindings.put("jobContext", jobContext);
script.eval(bindings);
}
/**
* 加载和初始化。
*/
public static synchronized void load() {
try {
manager = new ScriptEngineManager();
engine = manager.getEngineByName("javascript");
compilable = (Compilable) engine;
buffer = new ConcurrentHashMap<String, CompiledScript>();
globalMembers = new ArrayList<String>();
loadUtils();
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
/**
* 删除缓存中指定编码前缀的所有脚本实例对象。
* @param id 脚本id编号的前缀
*/
public static void remove(String id) {
Set<Entry<String, CompiledScript>> es = buffer.entrySet();
String k;
for (Entry<String, CompiledScript> e : es) {
k = e.getKey();
if (k.startsWith(id))
buffer.remove(k);
}
}
/**
* 加载全局工具类方法。
* @throws Exception 加载过程发生异常。
*/
private static void loadUtils() throws Exception {
CompiledScript script;
String key;
String text = com.wb.util.FileUtil.readString(new File(Base.path, "wb/system/server.js"));
text += "\n//# sourceURL=server.js";
script = compilable.compile(text);
Bindings bindings = engine.createBindings();
script.eval(bindings);
Set<Entry<String, Object>> es = bindings.entrySet();
for (Entry<String, Object> e : es) {
key = e.getKey();
manager.put(e.getKey(), e.getValue());
globalMembers.add(key);
}
}
}

View File

@@ -0,0 +1,593 @@
package com.wb.common;
import com.wb.tool.Encrypter;
import com.wb.util.DbUtil;
import com.wb.util.StringUtil;
import com.wb.util.WebUtil;
import org.json.JSONArray;
import org.json.JSONObject;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.sql.ResultSet;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
public class Session {
/**
* 存放会话的HashMap。该对象仅用于辅助查看当前服务器在线用户列表。
* 在集群模式下,默认显示当前服务器的所有会话列表。
* 如果需要查看所有服务器的在线用户列表可以创建实现数据共享Map接口的对象即可
* 如实现Redis Map: userList = new RedisMap();
*/
public static Map<String, HashSet<HttpSession>> userList = new ConcurrentHashMap<String, HashSet<HttpSession>>();
/**
* 同步锁,用于执行同步操作。
*/
private static Object lock = new Object();
/**
* 验证登录是否合法,合法则成功登录,否则抛出异常。
* @param request 请求对象。
* @param response 响应对象。
* @throws Exception 登录验证过程发生异常。
*/
public static void verify(HttpServletRequest request, HttpServletResponse response) throws Exception {
String referer = StringUtil.opt(request.getHeader("Referer"));
String redirect = request.getParameter("redirect");
HttpSession session = request.getSession(false);
if (com.wb.common.Var.getBool("sys.session.verifyImage.enabled")) {
if (session == null)
throw new Exception(com.wb.common.Str.format(request, "vcExpired"));
String verifyCode = (String) session.getAttribute("sys.verifyCode");
// 每个验证码只允许一次有效,以防止暴力破解
session.removeAttribute("sys.verifyCode");
if (StringUtil.isEmpty(verifyCode) || !StringUtil.isSame(verifyCode, request.getParameter("verifyCode"))) {
throw new Exception(com.wb.common.Str.format(request, "vcInvalid"));
}
}
if (session != null)
session.invalidate();
createSession(request);
if (referer.endsWith("/login") || referer.endsWith("m?xwl=sys/session/login"))
referer = com.wb.common.Var.getString("sys.home");
if (referer.endsWith("/tlogin") || referer.endsWith("m?xwl=sys/session/tlogin"))
referer = com.wb.common.Var.getString("sys.homeMobile");
if (StringUtil.isEmpty(redirect))
WebUtil.send(response, referer);
else
response.sendRedirect(redirect);
}
/**
* 获取指定用户的所有会话列表信息。
*/
public static void getSessionList(HttpServletRequest request, HttpServletResponse response) throws Exception {
String user = request.getParameter("user");
int start = Integer.parseInt(request.getParameter("start"));
int limit = Integer.parseInt(request.getParameter("limit"));
int index = -1, end;
JSONArray rows = new JSONArray();
JSONObject row, result;
HashSet<HttpSession> sessions = userList.get(user);
if (limit > com.wb.common.Var.limitRecords)
limit = com.wb.common.Var.limitRecords;
end = start + limit;
if (sessions != null) {
for (HttpSession session : sessions) {
index++;
if (index < start)
continue;
else if (index >= end)
break;
row = new JSONObject();
row.put("ip", session.getAttribute("sys.ip"));
row.put("userAgent", session.getAttribute("sys.userAgent"));
row.put("createDate", new Date(session.getCreationTime()));
row.put("lastAccessDate", new Date(session.getLastAccessedTime()));
rows.put(row);
}
}
result = new JSONObject();
result.put("rows", rows);
result.put("total", sessions == null ? 0 : sessions.size());
WebUtil.send(response, result);
}
/**
* 获取所有在线用户的列表信息。
*/
public static void getUserList(HttpServletRequest request, HttpServletResponse response) throws Exception {
int start = Integer.parseInt(request.getParameter("start"));
int limit = Integer.parseInt(request.getParameter("limit"));
int index = -1, end, sessionCount;
JSONArray rows = new JSONArray();
JSONObject row, result;
HashSet<HttpSession> sessions;
HttpSession session;
Set<Entry<String, HashSet<HttpSession>>> es = userList.entrySet();
if (limit > com.wb.common.Var.limitRecords)
limit = com.wb.common.Var.limitRecords;
end = start + limit;
for (Entry<String, HashSet<HttpSession>> e : es) {
index++;
if (index < start)
continue;
else if (index >= end)
break;
sessions = e.getValue();
sessionCount = 0;
session = null;
for (HttpSession sess : sessions) {
if (session == null)
session = sess;
sessionCount++;
}
if (sessionCount == 0)
continue;
row = new JSONObject();
row.put("sessionCount", sessionCount);
row.put("user", e.getKey());
row.put("username", session.getAttribute("sys.username"));
row.put("dispname", session.getAttribute("sys.dispname"));
row.put("ip", session.getAttribute("sys.ip"));
row.put("userAgent", session.getAttribute("sys.userAgent"));
rows.put(row);
}
result = new JSONObject();
result.put("rows", rows);
result.put("total", userList.size());
WebUtil.send(response, result);
}
/**
* 注销当前登录用户的会话。
* @param request 请求对象
* @param response 响应对象
* @throws Exception 调用过程发生异常
*/
public static void logout(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpSession session = request.getSession(false);
if (session != null)
session.invalidate();
}
/**
* 获取当前用户的角色列表。如果当前用户未登录或未关联角色数据将返回null。
* @param request 当前用户关联的请求对象。
* @return 角色列表。
*/
public static String[] getRoles(HttpServletRequest request) throws Exception {
HttpSession session = request.getSession(false);
if (session == null)
return null;
else
return (String[]) session.getAttribute("sys.roles");
}
/**
* 创建会话。首先验证用户名称和密码是否合法如果非法抛出异常。如果合法创建HTTP会话
* 并存储当前用户数据至会话Attribute。
* @param request 请求对象。
* @throws Exception 创建会话失败。
private static void createSessionold(HttpServletRequest request) throws Exception {
int timeout = com.wb.common.Var.sessionTimeout;
HttpSession session;
String username = request.getParameter("username");
String password = request.getParameter("password");
String sqls="select a.USER_ID,a.DISPLAY_NAME,a.PASSWORD,a.USE_LANG from WB_USER a \n" +
"where a.user_name={?username?} and STATUS=1 group by a.USER_ID,a.DISPLAY_NAME,a.PASSWORD,\n" +
"a.USE_LANG ";
ResultSet rs = (ResultSet) DbUtil
.run(
request,
sqls);
if (!rs.next())
throw new IllegalArgumentException(com.wb.common.Str.format(request,
"userNotExist", username));
String userId = rs.getString("USER_ID");
String dispname = rs.getString("DISPLAY_NAME");
String useLang = rs.getString("USE_LANG");
// String tentantid = rs.getString("TENTANTID");
if (request.getParameter("linkflag")==null || request.getParameter("linkflag").equals("")) {//切换用户 标志,不需要密码判断
if (request.getParameter("passweb") != null) {
if (request.getParameter("passweb").equals("true")) {
if (!rs.getString("PASSWORD").equals(password))
throw new IllegalArgumentException(com.wb.common.Str.format(request,
"passwordInvalid"));
}
} else if (!rs.getString("PASSWORD").equals(Encrypter.getMD5(password)))
throw new IllegalArgumentException(Str.format(request,
"passwordInvalid"));
}
session = request.getSession(true);
// 登录的标志为存在会话且属性sys.logined为非null
session.setAttribute("sys.logined", true);
if (timeout == -1)
timeout = Integer.MAX_VALUE;
if (timeout > 0)
session.setMaxInactiveInterval(timeout);
session.setAttribute("sys.user", userId);
session.setAttribute("sys.username", username);
session.setAttribute("sys.dispname", dispname);
//session.setAttribute("sys.tentantid", tentantid);
//session.setAttribute("sys.TENANCY_ID", tentantid);
String sqllistsub="select MENU_ID,MENU_NAME,parent_menu,order_index from(select distinct MENU_ID,MENU_NAME,parent_menu,order_index " +
" from wb_menu where parent_menu='-1' and menu_type='2'\n" +
" start with menu_id in(select distinct wm.menu_id from wb_menu wm,wb_role_resource wrr " +
"where wm.menu_id=wrr.menu_id and wrr.role_id in(select role_id from wb_user_role where user_id='"+userId+"'))" +
" connect by prior parent_menu=menu_id) order by order_index ";
ResultSet subs = (ResultSet) DbUtil.run(request,sqllistsub);
StringBuilder sb = new StringBuilder();
String[] imgs = {"user.png","order.png","settle.png","settle.png","settle.png","settle.png","settle.png","settle.png","settle.png","settle.png","settle.png"};
int i=0;
while (subs.next()){
sb.append("<li>");
sb.append("<img src=\"wb/images/photos/"+imgs[i]+"\" style=\"margin-bottom:3px\"/>" +
"<a onclick=\"subsclick('"+subs.getString("MENU_ID")+"','"+username+"')\">"+subs.getString("MENU_NAME")+"</a>");
sb.append("</li>");
if(i==0){
request.getSession().setAttribute("sys.menuid",subs.getString("MENU_ID"));
}
i++;
}
session.setAttribute("subsList", sb.toString());
//得到用户权限信息
ResultSet selectUseRole = (ResultSet) DbUtil.run(request,"SELECT *\n" +
" FROM wb_menu\n" +
" WHERE menu_id IN (SELECT menu_id\n" +
" FROM wb_role_resource\n" +
" WHERE role_id in (SELECT role_id\n" +
" FROM wb_user_role\n" +
" WHERE user_id ='"+userId+"'))");
Map map = new HashMap();
while (selectUseRole.next()){
map.put(selectUseRole.getString("MENU_URL"),selectUseRole.getString("MENU_NAME"));
}
session.setAttribute("selectUseRole",map);
//得到用户角色信息
ResultSet useRole = (ResultSet) DbUtil.run(request,"SELECT * FROM wb_user_role WHERE user_id ='"+userId+"'");
Map map1 = new HashMap();
while (useRole.next()){
map1.put(useRole.getString("USER_ID"),useRole.getString("ROLE_ID"));
}
session.setAttribute("useRole",map1);
String menuSql = "SELECT (SELECT menu_url\n" +
" FROM wb_menu\n" +
" WHERE menu_id = parent_menu_id)\n" +
" url,\n" +
" menu_res_ename ename\n" +
" FROM wb_menu_res\n" +
" WHERE menu_res_id NOT IN (SELECT menu_res_id\n" +
" FROM wb_menu_res wmr, wb_role_resource wrr\n" +
" WHERE wmr.menu_res_id = wrr.menu_id\n" +
" AND role_id IN (SELECT role_id\n" +
" FROM wb_user_role\n" +
" WHERE user_id = '"+userId+"'))\n" +
"ORDER BY parent_menu_id";
//查询资源按钮
ResultSet menuRes = (ResultSet) DbUtil.run(request, menuSql);
Map mapMenuRes = new HashMap();
List<Map<String, String>> festivalList = new ArrayList<>();
while (menuRes.next()){
Map map2 = new HashMap();
map2.put("url",menuRes.getString("URL"));
map2.put("ename",menuRes.getString("ENAME"));
festivalList.add(map2);
}
mapMenuRes.put(username,festivalList);
session.setAttribute("mapMenuRes",mapMenuRes);
// userAgent最大长度限制为500个字符防止被注入大字符串
session.setAttribute("sys.userAgent", StringUtil.substring(request
.getHeader("user-agent"), 0, 500));
session.setAttribute("sys.ip", request.getRemoteAddr());
session.setAttribute("sys.lang", StringUtil.select(useLang, "auto"));
storeUserValues(request, session, userId);
com.wb.common.SimpleListener simpleListener = new SimpleListener();
if (com.wb.common.Var.uniqueLogin) {
String usernames[] = { username };
synchronized (lock) {
//removeSession(usernames);
session.setAttribute("simpleListener", simpleListener);
}
} else
session.setAttribute("simpleListener", simpleListener);
}*/
/**
* 创建会话。首先验证用户名称和密码是否合法如果非法抛出异常。如果合法创建HTTP会话
* 并存储当前用户数据至会话Attribute。
* mysql版本
* @param request 请求对象。
* @throws Exception 创建会话失败。
*/
@SuppressWarnings("unchecked")
private static void createSession(HttpServletRequest request) throws Exception {
int timeout = Var.sessionTimeout;
HttpSession session;
String username = request.getParameter("username");
String password = request.getParameter("password");
ResultSet rs = (ResultSet) DbUtil
.run(
request,
" select USER_ID,USER_NAME,DISPLAY_NAME,PASSWORD,USE_LANG ,WB_USER.TENANCY_ID, IS_SUPERUSER from WB_USER where USER_NAME={?username?} and STATUS=1");
if (!rs.next())
throw new IllegalArgumentException(Str.format(request,
"userNotExist", username));
String userId = rs.getString("USER_ID");
username = rs.getString("USER_NAME");
String dispname = rs.getString("DISPLAY_NAME");
String useLang = rs.getString("USE_LANG");
// String TENANCY_ID = rs.getString("TENANCY_ID");
// String ORG_ID = rs.getString("ORG_ID");
// String SHORT_COD = rs.getString("SHORT_COD");
// String GOV_CODE = rs.getString("GOV_CODE");
// String IS_SUPERUSER = rs.getString("IS_SUPERUSER");
// String NATURE = rs.getString("NATURE");
// String ORG_NAME = rs.getString("ORG_NAME");
String status = ResourceBundle.getBundle("system").getString("status");
if(!"1".equals(status)) {
if (!rs.getString("PASSWORD").equals(Encrypter.getMD5(password)))
throw new IllegalArgumentException(Str.format(request,
"passwordInvalid"));
}
session = request.getSession(true);
// 登录的标志为存在会话且属性sys.logined为非null
session.setAttribute("sys.logined", true);
if (timeout == -1)
timeout = Integer.MAX_VALUE;
if (timeout > 0)
session.setMaxInactiveInterval(timeout);
session.setAttribute("sys.TENANCY_ID", "default");//租户
session.setAttribute("sys.tenancyId", "default");//租户
// session.setAttribute("sys.ORG_ID", ORG_ID);//组织机构代码
// session.setAttribute("sys.IS_SUPERUSER", IS_SUPERUSER);//超级用户
// session.setAttribute("sys.NATURE", NATURE);//用户性质 2码头5驳船公司 4货主
session.setAttribute("sys.user", userId);//用户主键
// session.setAttribute("sys.SHORT_COD", SHORT_COD);//用户主键
// session.setAttribute("sys.GOV_CODE", GOV_CODE);//驳船COD
// session.setAttribute("sys.ORG_NAME", ORG_NAME);//驳船COD
session.setAttribute("sys.username", username);//用户显示名
session.setAttribute("sys.dispname", dispname);//用户登录名
ResultSet subs = (ResultSet) DbUtil.run(request, "select * from wb_menu where parent_menu='-1' and menu_type='2' order by order_index");
StringBuilder sb = new StringBuilder();
String[] imgs = {"user.png", "order.png", "settle.png", "user.png", "order.png", "settle.png", "user.png", "order.png", "settle.png", "user.png", "order.png", "settle.png"};
int i = 0;
while (subs.next()) {
sb.append("<li>");
sb.append("<img src=\"wb/images/photos/" + imgs[i] + "\" style=\"margin-bottom:3px\"/>" +
"<a onclick=\"subsclick('" + subs.getString("MENU_ID") + "','" + username + "')\">" + subs.getString("MENU_NAME") + "</a>");
sb.append("</li>");
if (i == 0) {
request.getSession().setAttribute("sys.menuid", subs.getString("MENU_ID"));
}
i++;
}
session.setAttribute("subsList", sb.toString());
//得到用户权限信息
ResultSet selectUseRole = (ResultSet) DbUtil.run(request, "SELECT *\n" +
" FROM wb_menu\n" +
" WHERE menu_id IN (SELECT menu_id\n" +
" FROM wb_role_resource\n" +
" WHERE role_id in (SELECT role_id\n" +
" FROM wb_user_role\n" +
" WHERE user_id = {?username?}))");
Map map = new HashMap();
while (selectUseRole.next()) {
String url = selectUseRole.getString("MENU_URL");
if (url.contains("m?xwl=")){
url = url.replace("m?xwl=", "");
}
if (!url.endsWith(".xwl")){
url += ".xwl";
}
map.put(url, selectUseRole.getString("MENU_NAME"));
}
session.setAttribute("selectUseRole", map);
//得到用户角色信息
ResultSet useRole = (ResultSet) DbUtil.run(request, "SELECT * FROM wb_user_role WHERE user_id = {?username?}");
Map map1 = new HashMap();
String roleIds = "";
while (useRole.next()) {
map1.put(useRole.getString("USER_ID"), useRole.getString("ROLE_ID"));
roleIds += useRole.getString("ROLE_ID") + ",";
}
//没卵用
session.setAttribute("useRole",map1);
//存储用户所有角色
session.setAttribute("roleIds", ","+roleIds);
//查询可访问的控件
String menuSql = "SELECT (SELECT menu_url\n" +
" FROM wb_menu\n" +
" WHERE menu_id = parent_menu_id)\n" +
" url,\n" +
" menu_res_ename ename, 0 enabled\n" +
" FROM wb_menu_res\n" +
" WHERE menu_res_id NOT IN (SELECT menu_res_id\n" +
" FROM wb_menu_res wmr, wb_role_resource wrr\n" +
" WHERE wmr.menu_res_id = wrr.menu_id\n" +
" AND role_id IN (SELECT role_id\n" +
" FROM wb_user_role\n" +
" WHERE user_id = '"+userId+"'))\n" +
" union all \n" +
"SELECT (SELECT menu_url\n" +
" FROM wb_menu\n" +
" WHERE menu_id = parent_menu_id)\n" +
" url,\n" +
" menu_res_ename ename,1 enabled\n" +
" FROM wb_menu_res\n" +
" WHERE menu_res_id IN (SELECT menu_res_id\n" +
" FROM wb_menu_res wmr, wb_role_resource wrr\n" +
" WHERE wmr.menu_res_id = wrr.menu_id\n" +
" AND role_id IN (SELECT role_id\n" +
" FROM wb_user_role\n" +
" WHERE user_id = '"+userId+"'))";
ResultSet menuRes = (ResultSet) DbUtil.run(request, menuSql);
Map mapMenuRes = new HashMap();
List<Map<String, String>> festivalList = new ArrayList<>();
while (menuRes.next()){
Map map2 = new HashMap();
String url = menuRes.getString("URL");
if (url.contains("m?xwl=")){
url = url.replace("m?xwl=", "");
}
if (!url.endsWith(".xwl")){
url += ".xwl";
}
map2.put("url", url);
map2.put("ename",menuRes.getString("ENAME"));
map2.put("enabled",menuRes.getString("ENABLED"));
festivalList.add(map2);
}
mapMenuRes.put(username,festivalList);
session.setAttribute("mapMenuRes",mapMenuRes);
// userAgent最大长度限制为500个字符防止被注入大字符串
session.setAttribute("sys.userAgent", StringUtil.substring(request
.getHeader("user-agent"), 0, 500));//浏览器
session.setAttribute("sys.ip", request.getRemoteAddr());//IP
session.setAttribute("sys.lang", StringUtil.select(useLang, "auto"));//语言包
DbUtil
.run(request,
"update WB_USER set LOGIN_TIMES=LOGIN_TIMES+1 where USER_ID={?sys.user?}");
storeUserValues(request, session, userId);
SimpleListener simpleListener = new SimpleListener();
if (Var.uniqueLogin) {
String usernames[] = {username};
synchronized (lock) {
removeSession(usernames);
session.setAttribute("sys.simpleListener", simpleListener);
}
} else
session.setAttribute("sys.simpleListener", simpleListener);
}
/**
* 存储用户数据至Session的Attribute.
* @param session 会话对象。
* @throws Exception 存储过程发生异常。
*/
private static void storeUserValues(HttpServletRequest request, HttpSession session, String userId)
throws Exception {
// 定义需要存储的名称列表,可以根据业务需要扩充列表
String names[] = com.wb.common.Var.sessionVars.split(",");
String valueIds[] = new String[names.length];
String fieldName, fieldValue, roleArray[];
ArrayList<String> roles = new ArrayList<String>();
ResultSet rs;
int i = 0;
// 角色
rs = (ResultSet) DbUtil.run(request,
"select ROLE_ID from WB_USER_ROLE where USER_ID={?sys.user?} and ROLE_ID<>'default'");
roles.add("default");// 默认每个用户都具有的角色
while (rs.next()) {
roles.add(rs.getString(1));
}
roleArray = roles.toArray(new String[roles.size()]);
session.setAttribute("sys.roles", roleArray);
session.setAttribute("sys.roleList", StringUtil.join(roleArray, ","));
// 其他数据
for (String name : names) {
valueIds[i++] = StringUtil.concat("'", name, "@", userId, "'");
}
rs = (ResultSet) DbUtil.run(request,
"select VAL_ID,VAL_CONTENT from WB_VALUE where VAL_ID in (" + StringUtil.join(valueIds, ",") + ")");
while (rs.next()) {
fieldName = rs.getString("VAL_ID");
fieldName = StringUtil.substring(fieldName, 0, fieldName.indexOf('@'));
fieldValue = rs.getString("VAL_CONTENT");
session.setAttribute("sys." + fieldName, fieldValue);
}
}
/**
* 移除指定用户帐户下所有session。
* @param userIds 用户id列表。
*/
public static void removeSession(String[] userIds) {
if (!com.wb.common.Var.recordSession)
return;
HashSet<HttpSession> sessions;
HttpSession[] sessionArray;
int i;
for (String userId : userIds) {
sessions = userList.get(userId);
if (sessions != null) {
sessionArray = new HttpSession[sessions.size()];
i = 0;
for (HttpSession session : sessions) {
sessionArray[i++] = session;
}
// 写入数组再invalid目的是避免HashMap ConcurrentModificationException异常
for (HttpSession session : sessionArray) {
session.invalidate();
}
userList.remove(userId);
}
}
}
/**
* 更新指定用户关联的session。
* @param userId 用户id。
* @param roles 角色列表。
* @param status 状态true更新角色false删除session。
*/
public static void updateSession(String userId, String roles[], boolean status) {
if (!Var.recordSession)
return;
HashSet<HttpSession> sessions = userList.get(userId);
if (sessions != null) {
if (status) {
for (HttpSession session : sessions) {
session.setAttribute("sys.roles", roles);
session.setAttribute("sys.roleList", StringUtil.join(roles, ","));
}
} else {
String[] userIds = { userId };
removeSession(userIds);
}
}
}
/**
* 校验用户密码是否正确。
*
* @param request 请求对象。
* @throws Exception 创建会话失败。
*/
public static void verifyPass(HttpServletRequest request, HttpServletResponse response) throws Exception {
String username = request.getParameter("username");
String password = request.getParameter("password");
String sqls = "select a.PASSWORD from WB_USER a \n" +
"where a.user_name={?username?} ";
ResultSet rs = (ResultSet) DbUtil.run( request, sqls);
String dpass = "";
while (rs.next()) {
dpass = rs.getString("PASSWORD");
}
if (dpass.equals(Encrypter.getMD5(password))){
WebUtil.send(response, "OK");
}else {
WebUtil.send(response, "NO");
}
}
}

View File

@@ -0,0 +1,79 @@
package com.wb.common;
import java.util.HashSet;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionBindingListener;
/**
* 监听会话创建和销毁过程,维护会话列表。
*/
public class SimpleListener implements HttpSessionBindingListener,
java.io.Serializable {
/**
* 序列化用的编号。
*/
private static final long serialVersionUID = 4490661288665900556L;
/**
* Session对象。
*/
private transient HttpSession session;
/**
* 用户ID。
*/
private String userId;
/**
* 用户名称。
*/
private String username;
/**
* IP地址。
*/
private String ip;
/**
* 同步锁。
*/
private static Object lock = new Object();
/**
* 当会话被创建时触发该方法。
*/
public void valueBound(HttpSessionBindingEvent event) {
session = event.getSession();
userId = (String) session.getAttribute("sys.user");
if (Var.log) {
username = (String) session.getAttribute("sys.username");
ip = (String) (String) session.getAttribute("sys.ip");
com.wb.util.LogUtil.log(username, ip, com.wb.util.LogUtil.INFO, "login");
}
// 允许同一用户账户在多终端上登录
if (Var.recordSession) {
synchronized (lock) {
HashSet<HttpSession> sessions = Session.userList.get(userId);
if (sessions == null)
sessions = new HashSet<HttpSession>();
sessions.add(session);
Session.userList.put(userId, sessions);
}
}
}
/**
* 当会话被销毁时触发该方法。
*/
public void valueUnbound(HttpSessionBindingEvent event) {
if (Var.log)
com.wb.util.LogUtil.log(username, ip, com.wb.util.LogUtil.INFO, "logout");
if (Var.recordSession) {
synchronized (lock) {
HashSet<HttpSession> sessions = Session.userList.get(userId);
if (sessions != null && session != null) {
sessions.remove(session);
if (sessions.isEmpty())
Session.userList.remove(userId);
}
}
}
}
}

View File

@@ -0,0 +1,220 @@
package com.wb.common;
import java.io.File;
import java.util.Set;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import javax.servlet.http.HttpServletRequest;
import org.json.JSONObject;
import com.wb.util.FileUtil;
import com.wb.util.JsonUtil;
import com.wb.util.StringUtil;
/**
* 支持多国语言的文字、数字和日期等。
*/
public class Str {
/**
* Wb的多语言HashMap。HashMap中名称为语言名称值为文字列表组成的map。
*/
private static ConcurrentHashMap<String, ConcurrentHashMap<String, String>> wbLang;
/**
* Ext的多语言HashMap用于获取所支持的语言种类。
*/
private static ConcurrentHashMap<String, String> extLang;
/**
* Touch的多语言HashMap用于获取所支持的语言种类。
*/
private static ConcurrentHashMap<String, String> touchLangList;
/**
* 根据配置文件把同一语言不同名称转换为指定名称的映射HashMap。
*/
private static ConcurrentHashMap<String, String> langMap;
/**
* 根据默认语言和输入参数,格式化指定的关键字。
*
* @param key
* 预定义的字符串关键字。
* @param args
* 填充到关键字中的参数列表。
* @return 格式化后的字符串。
* @see com.wb.common.Str#langFormat
*/
public static String format(String key, Object... args) {
return langFormat(com.wb.common.Var.defaultLanguage, key, args);
}
/**
* 根据当前客户端语言和输入参数,格式化指定的关键字。
*
* @param request
* 包含当前语言的request对象。
* @param key
* 预定义的字符串关键字。
* @param args
* 填充到关键字中的参数列表。
* @return 格式化后的字符串。
* @see com.wb.common.Str#langFormat
*/
public static String format(HttpServletRequest request, String key,
Object... args) {
return langFormat((String) request.getAttribute("sys.useLang"), key,
args);
}
/**
* 把指定语言转换为系统所支持的最接近的语言,如果无法匹配将返回系统的默认语言。
* 比如系统支持en_AU, en_GB, en 3种英文如果请求语言为en_GB则返回en_GB。
* 如果请求的是en_CA或en_US则返回最接近的en。如果未找到任何匹配则返回默认语言。
*
* @param map
* 存放语言的HashMap
* @param lang
* 需要转换的语言
* @return 转换后的语言
*/
private static String optLang(ConcurrentHashMap<String, ?> map, String lang) {
if (!StringUtil.isEmpty(lang)) {
if (map.containsKey(lang))
return lang;
int pos = lang.indexOf('_');
if (pos != -1) {
lang = lang.substring(0, pos);
if (map.containsKey(lang))
return lang;
}
}
return Var.defaultLanguage;
}
/**
* 把指定语言转换为wb所支持的语言如果未找到匹配则返回默认语言。
*
* @param lang
* 需要转换的语言
* @return 转换后的语言
* @see com.wb.common.Str#optLang
*/
public static String optLanguage(String lang) {
return optLang(wbLang, lang);
}
/**
* 把指定语言转换为ext所支持的语言如果未找到匹配则返回默认语言。
*
* @param lang 需要转换的语言
* @return 转换后的语言
* @see com.wb.common.Str#optLang
*/
public static String optExtLanguage(String lang) {
return optLang(extLang, lang);
}
public static String optTouchLanguage(String lang) {
return optLang(touchLangList, lang);
}
/**
* 根据配置文件映射不同名称的语言为指定的名称。比如根据配置zh_HANS-CN或zh_HANS可被映射为zh_CN。
*
* @param lang
* 需要映射的语言名称
* @return 映射后的语言名称
*/
public static String getMappedLang(String lang) {
return langMap.get(lang);
}
/**
* 根据当前的客户端语言,格式化关键字并填充参数,把指定关键字转换为格式化后的文本。
*
* @param lang 客户端语言名称。
* @param key 需要转换的带有参数的关键字。
* @param args 参数列表
* @return 格式化后的文本。
*/
public static String langFormat(String lang, String key, Object... args) {
ConcurrentHashMap<String, String> buffer = wbLang
.get(optLanguage(lang));
if (buffer == null)
return key;
String str = buffer.get(key);
if (str == null)
return key;
int i = 0;
for (Object object : args)
str = StringUtil.replaceAll(str, "{" + (i++) + "}",
object == null ? "null" : object.toString());
return str;
}
/**
* 加载和初始化。
*/
public static synchronized void load() {
try {
langMap = new ConcurrentHashMap<String, String>();
wbLang = new ConcurrentHashMap<String, ConcurrentHashMap<String, String>>();
ConcurrentHashMap<String, String> buffer;
File[] fs = FileUtil.listFiles(new File(com.wb.common.Base.path,
"wb/script/locale"));
JSONObject jo;
String name, langList[];
Set<Entry<String, Object>> es;
// 建立同一语言不同名称的映射关系
jo = JsonUtil.readObject(new File(com.wb.common.Base.path,
"wb/system/language.json"));
es = jo.entrySet();
for (Entry<String, Object> e : es) {
langList = StringUtil.split((String) e.getValue(), ',', true);
for (String ln : langList)
langMap.put(ln, e.getKey());
}
// 把wb多语言文件所支持的语言种类和文件内容放到map中
for (File file : fs) {
name = file.getName();
// 服务器端加载调试版本js在后台使用无区别
if (name.endsWith("-debug.js")) {
buffer = new ConcurrentHashMap<String, String>();
jo = JsonUtil.readObject(file);
es = jo.entrySet();
for (Entry<String, Object> e : es)
buffer.put(e.getKey(), (String) e.getValue());
wbLang.put(name.substring(8, name.length() - 9), buffer);
}
}
// 把ext多语言文件所支持的语言种类放到map中
extLang = new ConcurrentHashMap<String, String>();
fs = FileUtil.listFiles(new File(com.wb.common.Base.path, "wb/libs/ext/locale"));
for (File file : fs) {
name = file.getName();
if (!name.endsWith("-debug.js")) {
name = name.substring(9, name.length() - 3);
extLang.put(name, name);
}
}
// 把touch多语言文件所支持的语言种类放到map中
touchLangList = new ConcurrentHashMap<String, String>();
fs = FileUtil
.listFiles(new File(Base.path, "wb/libs/touch/locale"));
for (File f : fs) {
name = f.getName();
if (!name.endsWith("-debug.js")) {
name = name.substring(7, name.length() - 3);
touchLangList.put(name, name);
}
}
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
}

View File

@@ -0,0 +1,181 @@
package com.wb.common;
import java.io.File;
import java.io.IOException;
import java.util.Set;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import org.json.JSONObject;
import com.wb.util.FileUtil;
import com.wb.util.JsonUtil;
import com.wb.util.StringUtil;
/**
* URL地址映射器映射指定URL地址至对应的模块。
*/
public class UrlBuffer {
/** URL映射地址缓存HashMap。 */
public static ConcurrentHashMap<String, String> buffer;
/**
* URL映射文件。
*/
private static final File file = new File(Base.path, "wb/system/url.json");
/**
* 获取指定URL的模块相对路径。
* @param url URL地址。
* @return 模块相对路径。
*/
public static String get(String url) {
return buffer.get(url);
}
/**
* 设置模块的URL地址。
* @param url URL地址。
* @param path 模块相对路径。
*/
public static void put(String url, String path) {
buffer.put(url, path);
}
/**
* 检查指定文件设置的url是否存在。
* @param url 去掉前置"/"的URL地址。
* @param file 文件对象。
* @throws IOException 访问文件错误。
*/
public static boolean exists(String url, File file) throws IOException {
if (!StringUtil.isEmpty(url)) {
String urlPath = get('/' + url);
String relPath;
if (file == null)
relPath = null;
else
relPath = FileUtil.getModulePath(file);
if (urlPath != null
&& (relPath == null || !StringUtil.isSame(urlPath, relPath)))
return false;
}
return true;
}
/**
* 删除指定文件或目录的URL缓存。
* @param path 文件或目录的相对路径。
* @return 如果有记录被删除则返回true否则返回false。
*/
public static boolean remove(String path) {
Set<Entry<String, String>> es = buffer.entrySet();
String key, modulePath, delPath;
boolean result = false;
delPath = StringUtil.concat(path, "/");
for (Entry<String, String> e : es) {
key = e.getKey();
modulePath = StringUtil.concat(e.getValue(), "/");
if (modulePath.startsWith(delPath) && key.length() > 1) {
buffer.remove(key);
if (!result)
result = true;
}
}
return result;
}
/**
* 加载和初始化。
*/
public static synchronized void load() {
try {
buffer = new ConcurrentHashMap<String, String>();
JSONObject object = JsonUtil.readObject(file);
Set<Entry<String, Object>> es = object.entrySet();
for (Entry<String, Object> e : es)
put(e.getKey(), (String) e.getValue());
/*String portal = Var.getString("sys.portal");
// 根地址设置
if (portal.endsWith(".xwl"))
put("/", portal);
else
put("/", buffer.get("/" + portal));
System.out.println(buffer.get("/" + portal));*/
put("/", "sys/portal/index.xwl");
put("/m", ""); // 模块入口地址
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
/**
* 保存缓存中的数据至文件。
* @throws IOException
*/
public static void save() throws Exception {
// 该方法无需同步
Set<Entry<String, String>> es = buffer.entrySet();
JSONObject object = new JSONObject();
String key;
for (Entry<String, String> e : es) {
key = e.getKey();
if (!key.equals("/") && !key.equals("/m"))
object.put(key, e.getValue());
}
FileUtil.syncSave(file, object.toString());
}
/**
* 查找指定模块文件对应的URL。
* @param file 模块文件。
* @return 如果找到则返回URL否则返回null。
*/
public static String find(File file) {
String path = FileUtil.getModulePath(file);
if (path == null)
return null;
Set<Entry<String, String>> es = buffer.entrySet();
String key;
for (Entry<String, String> e : es) {
key = e.getKey();
if (path.equals(e.getValue()) && !key.equals("/"))
return key.substring(1);
}
return null;
}
/**
* 更改URL对应的模块至新的目录。
* @param src 源文件/目录。
* @param dest 目标文件/目录。
* @param isDir 更改的是文件还是目录。
* @return 如果被更改返回true否则返回false。
*/
public static boolean change(String src, String dest, boolean isDir) {
Set<Entry<String, String>> es = buffer.entrySet();
String path, key, value;
int srcLen = src.length() + 1;
boolean result = false;
src = src + '/';
if (isDir)
dest = dest + '/';
for (Entry<String, String> e : es) {
key = e.getKey();
value = e.getValue();
path = StringUtil.concat(value, "/");
if (path.startsWith(src)) {
if (isDir)
buffer.put(key, dest + value.substring(srcLen));
else
buffer.put(key, dest);
if (!result)
result = true;
}
}
return result;
}
}

View File

@@ -0,0 +1,458 @@
package com.wb.common;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Timestamp;
import java.util.Date;
import javax.servlet.http.HttpServletRequest;
import org.json.JSONObject;
import com.wb.util.WebUtil;
/**
* 存储和维护较小的字符串、数值、日期等至数据库。
* 如果数据较大长度大于255字节可使用{@link Resource}类。
* 如果数据较小且对性能有高要求可使用{@link Var}类。
*
* @see Resource
* @see Var
*/
public class Value {
/**
* 获取指定编号的整数值。如果值不存在返回defaultValue。
*
* @param id 值id编号。
* @param defaultValue 如果值不存在,返回此默认值。
* @return 获取的值。
*/
public static int getInt(String id, int defaultValue) {
String val = getString(id, null);
if (val == null)
return defaultValue;
else
return Integer.parseInt(val);
}
/**
* 获取当前用户指定编号的整数值。如果值不存在返回defaultValue。
*
* @param request 当前用户请求的request对象。
* @param id 值id编号。
* @param defaultValue 如果值不存在,返回此默认值。
* @return 获取的值
*/
public static int getInt(HttpServletRequest request, String id, int defaultValue) {
return getInt(WebUtil.getIdWithUser(request, id), defaultValue);
}
/**
* 获取指定编号的长整数值。如果值不存在返回defaultValue。
*
* @param id 值id编号。
* @param defaultValue 如果值不存在,返回此默认值。
* @return 获取的值。
*/
public static long getLong(String id, long defaultValue) {
String val = getString(id, null);
if (val == null)
return defaultValue;
else
return Long.parseLong(val);
}
/**
* 获取当前用户指定编号的长整数值。如果值不存在返回defaultValue。
*
* @param request 当前用户请求的request对象
* @param id 值id编号。
* @param defaultValue 如果值不存在,返回此默认值。
* @return 获取的值。
*/
public static long getLong(HttpServletRequest request, String id, long defaultValue) {
return getLong(WebUtil.getIdWithUser(request, id), defaultValue);
}
/**
* 获取指定编号的双精度值。如果值不存在返回defaultValue。
*
* @param id 值id编号。
* @param defaultValue 如果值不存在,返回此默认值。
* @return 获取的值。
*/
public static double getDouble(String id, double defaultValue) {
String val = getString(id, null);
if (val == null)
return defaultValue;
else
return Double.parseDouble(val);
}
/**
* 获取当前用户指定编号的双精度值。如果值不存在返回defaultValue。
*
* @param request 当前用户请求的request对象。
* @param id 值id编号。
* @param defaultValue 如果值不存在,返回此默认值。
* @return 获取的值
*/
public static double getDouble(HttpServletRequest request, String id, double defaultValue) {
return getDouble(WebUtil.getIdWithUser(request, id), defaultValue);
}
/**
* 获取指定编号的布尔值。如果值不存在返回defaultValue。
*
* @param id 值id编号。
* @param defaultValue 如果值不存在,返回此默认值。
* @return 获取的值。
*/
public static boolean getBool(String id, boolean defaultValue) {
String val = getString(id, null);
if (val == null)
return defaultValue;
else
return Boolean.parseBoolean(val);
}
/**
* 获取当前用户指定编号的布尔值。如果值不存在返回defaultValue。
*
* @param request 当前用户请求的request对象。
* @param id 值id编号。
* @param defaultValue 如果值不存在,返回此默认值。
* @return 获取的值。
*/
public static boolean getBool(HttpServletRequest request, String id, boolean defaultValue) {
return getBool(WebUtil.getIdWithUser(request, id), defaultValue);
}
/**
* 获取指定编号的日期值。如果值不存在返回defaultValue。
*
* @param id 值id编号。
* @param defaultValue 如果值不存在,返回此默认值。
* @return 获取的值。
*/
public static Timestamp getDate(String id, Timestamp defaultValue) {
String val = getString(id, null);
if (val == null)
return defaultValue;
else
return Timestamp.valueOf(val);
}
/**
* 获取当前用户指定编号的日期值。如果值不存在返回defaultValue。
*
* @param request 当前用户请求的request对象
* @param id 值id编号。
* @param defaultValue 如果值不存在,返回此默认值。
* @return 获取的值。
*/
public static Timestamp getDate(HttpServletRequest request, String id, Timestamp defaultValue) {
return getDate(WebUtil.getIdWithUser(request, id), defaultValue);
}
/**
* 获取当前用户指定编号的字符串值。如果值不存在返回defaultValue。
*
* @param request 当前用户请求的request对象。
* @param id 值id编号。
* @param defaultValue 如果值不存在,返回此默认值。
* @return 获取的值。
*/
public static String getString(HttpServletRequest request, String id, String defaultValue) {
return getString(WebUtil.getIdWithUser(request, id), defaultValue);
}
/**
* 获取指定编号的字符串值。如果值不存在返回defaultValue。
*
* @param id 值id编号。
* @param defaultValue 如果值不存在,返回此默认值。
* @return 获取的值。
*/
public static String getString(String id, String defaultValue) {
Connection conn = null;
PreparedStatement st = null;
ResultSet rs = null;
try {
conn = com.wb.util.DbUtil.getConnection();
st = conn.prepareStatement("select VAL_CONTENT from WB_VALUE where VAL_ID=?");
st.setString(1, id);
rs = st.executeQuery();
if (rs.next())
return rs.getString(1);
} catch (Throwable e) {
throw new RuntimeException(e);
} finally {
com.wb.util.DbUtil.close(rs);
com.wb.util.DbUtil.close(st);
com.wb.util.DbUtil.close(conn);
}
return defaultValue;
}
/**
* 获取当前用户指定编号列表的值组成的JSONObject。key为编号value为值。
* @param idList 值id编号列表多个id以逗号分隔。
* @return 获取的值列表组成的JSONObject。
*/
public static JSONObject getValues(HttpServletRequest request, String idList) {
Connection conn = null;
PreparedStatement st = null;
ResultSet rs = null;
String list[] = com.wb.util.StringUtil.split(idList, ',');
String params = com.wb.util.StringUtil.repeat("?,", list.length);
int index = 1;
JSONObject result = new JSONObject();
String name, user = request == null ? null : WebUtil.fetch(request, "sys.user");
params = params.substring(0, params.length() - 1);
try {
conn = com.wb.util.DbUtil.getConnection();
st = conn.prepareStatement("select VAL_ID,VAL_CONTENT from WB_VALUE where VAL_ID in (" + params + ")");
for (String id : list) {
if (user != null)
id = com.wb.util.StringUtil.concat(id, "@", com.wb.util.StringUtil.opt(user));
st.setString(index++, id);
}
rs = st.executeQuery();
while (rs.next()) {
name = rs.getString(1);
if (user != null)
name = com.wb.util.StringUtil.substring(name, 0, name.indexOf('@'));
result.put(name, rs.getString(2));
}
} catch (Throwable e) {
throw new RuntimeException(e);
} finally {
com.wb.util.DbUtil.close(rs);
com.wb.util.DbUtil.close(st);
com.wb.util.DbUtil.close(conn);
}
return result;
}
/**
* 获取指定编号列表的值组成的JSONObject。key为编号value为值。
* @param idList 值id编号列表多个id以逗号分隔。
* @return 获取的值列表组成的JSONObject。
*/
public static JSONObject getValues(String idList) {
return getValues(null, idList);
}
/**
*
* 把整数值存储到特定的数据库表中并指定id编号标识。
*
* @param id 值id编号
* @param value 存储的整数值
*/
public static void set(String id, int value) {
set(id, Integer.toString(value));
}
/**
*
* 把整数值存储到特定的数据库表中并在当前用户下指定id编号标识。
*
* @param request 当前用户请求的request对象
* @param id 值id编号
* @param value 存储的整数值
*/
public static void set(HttpServletRequest request, String id, int value) {
set(WebUtil.getIdWithUser(request, id), value);
}
/**
*
* 把浮点数值存储到特定的数据库表中并指定id编号标识。
*
* @param id 值id编号
* @param value 存储的浮点数值
*/
public static void set(String id, float value) {
set(id, Float.toString(value));
}
/**
*
* 把浮点数值存储到特定的数据库表中并在当前用户下指定id编号标识。
*
* @param request 当前用户请求的request对象
* @param id 值id编号
* @param value 存储的浮点数值
*/
public static void set(HttpServletRequest request, String id, float value) {
set(WebUtil.getIdWithUser(request, id), value);
}
/**
*
* 把长整数值存储到特定的数据库表中并指定id编号标识。
*
* @param id 值id编号
* @param value 存储的长整数值
*/
public static void set(String id, long value) {
set(id, Long.toString(value));
}
/**
*
* 把长整数值存储到特定的数据库表中并在当前用户下指定id编号标识。
*
* @param request 当前用户请求的request对象
* @param id 值id编号
* @param value 存储的长整数值
*/
public static void set(HttpServletRequest request, String id, long value) {
set(WebUtil.getIdWithUser(request, id), value);
}
/**
*
* 把双精度值存储到特定的数据库表中并指定id编号标识。
*
* @param id 值id编号
* @param value 存储的双精度值
*/
public static void set(String id, double value) {
set(id, Double.toString(value));
}
/**
*
* 把双精度值存储到特定的数据库表中并在当前用户下指定id编号标识。
*
* @param request 当前用户请求的request对象
* @param id 值id编号
* @param value 存储的双精度值
*/
public static void set(HttpServletRequest request, String id, double value) {
set(WebUtil.getIdWithUser(request, id), value);
}
/**
*
* 把布尔值存储到特定的数据库表中并指定id编号标识。
*
* @param id 值id编号
* @param value 存储的布尔值
*/
public static void set(String id, boolean value) {
set(id, Boolean.toString(value));
}
/**
*
* 把布尔值存储到特定的数据库表中并在当前用户下指定id编号标识。
*
* @param request 当前用户请求的request对象
* @param id 值id编号
* @param value 存储的布尔值
*/
public static void set(HttpServletRequest request, String id, boolean value) {
set(WebUtil.getIdWithUser(request, id), value);
}
/**
*
* 把日期值存储到特定的数据库表中并指定id编号标识。
* 如果值为null将删除id指定的值。
* @param id 值id编号
* @param value 存储的日期
*/
public static void set(String id, Date value) {
String v;
if (value == null)
v = null;
else
v = com.wb.util.DateUtil.dateToStr(value);
set(id, v);
}
/**
*
* 把日期值存储到特定的数据库表中并在当前用户下指定id编号标识。
* 如果值为null将删除id指定的值。
* @param request 当前用户请求的request对象
* @param id 值id编号
* @param value 存储的日期
*/
public static void set(HttpServletRequest request, String id, Date value) {
set(WebUtil.getIdWithUser(request, id), value);
}
/**
* 删除当前用户指定编号的值。
*
* @param id 值id编号
*/
public static void remove(HttpServletRequest request, String id) {
set(request, id, (String) null);
}
/**
* 删除指定编号的值。
*
* @param id 值id编号
*/
public static void remove(String id) {
set(id, (String) null);
}
/**
* 把字符串值存储到特定的数据库表中并在当前用户下指定id编号标识。
* 如果值为null将删除名称指定的值。
*
* @param request 当前用户请求的request对象
* @param id 值id编号
* @param value 存储的字符串
*/
public static void set(HttpServletRequest request, String id, String value) {
set(WebUtil.getIdWithUser(request, id), value);
}
/**
*
* 把字符串值存储到特定的数据库表中并指定id编号标识。
* 如果值为null将删除id指定的值。
*
* @param id 值id编号
* @param value 存储的字符串
*/
public static void set(String id, String value) {
Connection conn = null;
PreparedStatement st = null;
boolean hasValue = value != null;
try {
conn = com.wb.util.DbUtil.getConnection();
if (hasValue)
conn.setAutoCommit(false);
st = conn.prepareStatement("delete from WB_VALUE where VAL_ID=?");
st.setString(1, id);
st.executeUpdate();
com.wb.util.DbUtil.close(st);
st = null;
if (hasValue) {
st = conn.prepareStatement("insert into WB_VALUE values(?,?)");
st.setString(1, id);
st.setString(2, value);
st.executeUpdate();
conn.commit();
}
} catch (Throwable e) {
throw new RuntimeException(e);
} finally {
com.wb.util.DbUtil.close(st);
com.wb.util.DbUtil.close(conn);
}
}
}

View File

@@ -0,0 +1,275 @@
package com.wb.common;
import java.io.File;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.json.JSONArray;
import org.json.JSONObject;
/**
* 存储和维护较小的字符串、数值、日期等值至服务器文件并缓存在内存中。
* 如果数据较大长度大于255字节可使用{@link Resource}类。
* 如果数据较小且存储的数据的数量很多可使用{@link Value}类。
*
* @see Resource
* @see Value
*/
public class Var {
/** 是否停止检查文件是否更新,以提高系统效率。 */
public static boolean uncheckModified;
/** 通过WebUtil.send发送流时是否采用gzip压缩。 */
public static boolean sendStreamGzip;
/** 通过WebUtil.send发送的内容超过该字节大小时采用gzip压缩。 */
public static int sendGzipMinSize;
/** 是否打印错误信息。 */
public static boolean printError;
/** 是否记录日志。 */
public static boolean log;
/** 是否记录计划任务日志。 */
public static boolean taskLog;
/** 限定每次最多返回记录数。 */
public static int limitRecords;
/** 限定每次最多导出记录数。 */
public static int limitExportRecords;
/** 指定文件超过该字节大小时采用gzip压缩并缓存在内存中。 */
public static int gzipMinSize;
/** 是否缓存文件,以提高并发时的快速响应。 */
public static boolean cacheEnabled;
/** 缓存时长,-1默认0不缓存>0缓存以秒为单位的时长。 */
public static int cacheMaxAge;
/** 是否调试模式。 */
public static boolean debug;
/** 在主页home模块是否显示移动App。 */
public static boolean homeShowApp;
/** 是否允许控制台信息打印方法。 */
public static boolean consolePrint;
/** 是否在服务器控制台中打印信息。 */
public static boolean serverConsolePrint;
/** 是否允许批量执行数据库更新操作。 */
public static boolean batchUpdate;
/** 服务器会话超时时间,单位秒。 */
public static int sessionTimeout;
/** 每个帐户是否只允许维持单个会话。 */
public static boolean uniqueLogin;
/** 对于浮点值类型的字段设置变量参数值时是否强制使用double类型。 */
public static boolean useDouble;
/** Ajax操作超时时间单位毫秒。 */
public static int ajaxTimeout;
/** 多长时间操作未返回显示mask单位毫秒。 */
public static int maskTimeout;
/** 客户端是否根据时差转换服务器端时间为本地时间。 */
public static boolean useLocalTime;
/** 是否记录Session对象。 */
public static boolean recordSession;
/** 当字符串类型字段长度大于该值时作为文本字段类型处理。 */
public static int stringAsText;
/** 同步目录路径。 */
public static String syncPath;
/** 默认jndi。 */
public static String jndi;
/** 指定语言。 */
public static String language;
/** 如果指定语言找不到时使用的默认语言。 */
public static String defaultLanguage;
/** 应用服务器对URL使用的编码。 */
public static String urlEncoding;
/** 以逗号分隔的存储到session属性值名称列表。 */
public static String sessionVars;
/** 是否强制转换字段名称为大写。 */
public static boolean forceUpperCase;
/** 把指定字符串映射为空字符串。 */
public static String emptyString;
/** 单次从数据库提取的建议性记录数。 */
public static int fetchSize;
/** 变量存放的文件。 */
public static final File file = new File(Base.path, "wb/system/var.json");
public static String getSessionuserid() {
return sessionuserid;
}
public static void setSessionuserid(String sessionuserid) {
Var.sessionuserid = sessionuserid;
}
/**
* 全局session+userid
*/
public static String sessionuserid;
/**
* 把变量缓存到HashMap中以提高访问性能。
*/
public static ConcurrentHashMap<String, Object> buffer;
/**
* 获取指定名称的变量值。
*
* @param name 变量全名。
* @return 变量值
*/
public static Object get(String name) {
if (com.wb.util.StringUtil.isEmpty(name))
throw new NullPointerException("Var name \"" + name + "\" can not be blank");
Object val = buffer.get(name);
if (val == null)
throw new NullPointerException("Var \"" + name + "\" does not exist");
return val;
}
/**
* 获取指定名称的变量字符串值。
*
* @param name 变量全名。
* @return 变量值
*/
public static String getString(String name) {
return get(name).toString();
}
/**
* 获取指定名称的变量整数值。
*
* @param name 变量全名。
* @return 变量值
*/
public static int getInt(String name) {
Object val = get(name);
if (val instanceof Integer)
return (Integer) val;
throw new RuntimeException("Var \"" + name + "\" is not an integer value");
}
/**
* 获取指定名称的双精度值。
*
* @param name 变量全名。
* @return 变量值
*/
public static double getDouble(String name) {
Object val = get(name);
if (val instanceof Double)
return (Double) val;
throw new RuntimeException("Var \"" + name + "\" is not a double value");
}
/**
* 获取指定名称的变量布尔值。
*
* @param name 变量全名。
* @return 变量值
*/
public static boolean getBool(String name) {
Object val = get(name);
if (val instanceof Boolean)
return (Boolean) val;
throw new RuntimeException("Var \"" + name + "\" is not a boolean value");
}
/**
* 更新缓存中的变量值并把变量值写进文件。
*
* @param name 变量全名。
* @param value 变量值。
*/
public static synchronized void set(String name, Object value) {
if (name == null)
throw new NullPointerException("Null variable name");
if (value == null)
throw new NullPointerException("Null variable value");
try {
JSONObject object = com.wb.util.JsonUtil.readObject(file);
Object valObject = com.wb.util.JsonUtil.getValue(object, name, '.');
if (!(valObject instanceof JSONArray))
throw new RuntimeException("\"" + name + "\" is not a variable.");
JSONArray valArray = (JSONArray) valObject;
valArray.put(0, value);
com.wb.util.FileUtil.syncSave(file, object.toString(2));
buffer.put(name, value);
loadBasicVars();
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
/**
* 加载和初始化。
*/
public static synchronized void load() {
try {
buffer = new ConcurrentHashMap<String, Object>();
JSONObject object = com.wb.util.JsonUtil.readObject(file);
getValues(object, "");
loadBasicVars();
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
/**
* 遍历所有变量并把其完整路径作为名称放到缓存HashMap中。
*
* @param object 变量JSONObject对象
* @param parentName 上级变量路径名称
*/
private static void getValues(JSONObject object, String parentName) {
Set<Entry<String, Object>> items = object.entrySet();
Object value;
JSONArray jsonArray;
String name;
for (Entry<String, Object> item : items) {
value = item.getValue();
name = parentName + item.getKey();
if (value instanceof JSONObject)
getValues((JSONObject) value, name + '.');
else {
jsonArray = (JSONArray) value;
if ("double".equals(jsonArray.getJSONObject(2).opt("type")))
buffer.put(name, ((Number) jsonArray.opt(0)).doubleValue());
else
buffer.put(name, jsonArray.opt(0));
}
}
}
/**
* 加载经常使用的基本参数。
*/
public static void loadBasicVars() {
uncheckModified = !Var.getBool("sys.cache.checkModified");
sendStreamGzip = Var.getBool("sys.sendStreamGzip");
sendGzipMinSize = Var.getInt("sys.sendGzipMinSize");
printError = Var.getBool("sys.printError");
log = Var.getBool("sys.log");
taskLog = Var.getBool("sys.task.log");
limitRecords = Var.getInt("sys.controls.limitRecords");
limitExportRecords = Var.getInt("sys.controls.limitExportRecords");
gzipMinSize = Var.getInt("sys.cache.gzipMinSize");
cacheEnabled = Var.getBool("sys.cache.enabled");
cacheMaxAge = Var.getInt("sys.cache.maxAge");
debug = Var.getBool("sys.debug");
homeShowApp = Var.getBool("sys.app.homeShowApp");
consolePrint = Var.getBool("sys.ide.consolePrint");
serverConsolePrint = Var.getBool("sys.serverConsolePrint");
batchUpdate = Var.getBool("sys.db.batchUpdate");
sessionTimeout = Var.getInt("sys.session.sessionTimeout");
uniqueLogin = Var.getBool("sys.session.uniqueLogin");
useDouble = Var.getBool("sys.db.useDouble");
ajaxTimeout = Var.getInt("sys.session.ajaxTimeout");
maskTimeout = Var.getInt("sys.session.maskTimeout");
useLocalTime = Var.getBool("sys.locale.useLocalTime");
recordSession = Var.getBool("sys.session.recordSession");
stringAsText = Var.getInt("sys.db.stringAsText");
syncPath = Var.getString("sys.ide.syncPath");
jndi = Var.getString("sys.jndi.default");
language = Var.getString("sys.locale.language");
defaultLanguage = Var.getString("sys.locale.defaultLanguage");
urlEncoding = Var.getString("sys.locale.urlEncoding");
sessionVars = Var.getString("sys.session.sessionVars");
forceUpperCase = Var.getBool("sys.db.forceUpperCase");
emptyString = Var.getString("sys.db.emptyString");
fetchSize = Var.getInt("sys.db.fetchSize");
}
}

View File

@@ -0,0 +1,286 @@
package com.wb.common;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Set;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import javax.servlet.http.HttpServletRequest;
import org.json.JSONArray;
import org.json.JSONObject;
/**
* 模块缓存器。
*/
public class XwlBuffer {
/** 模块文件转换成JSONObject后缓存HashMap。 */
private static ConcurrentHashMap<String, Object[]> buffer;
/**
* 获取指定路径的模块文件内容的JSON对象。
*
* @param path 请求的文件相对路径。
* @param silent 如果值为true且文件不存在返回null否则将抛出异常。
* @return 模块内容JSON对象或null。
* @throws IOException 如果读取文件发生错误将抛出异常。
*/
public static JSONObject get(String path, boolean silent) throws IOException {
if (path == null) {
if (silent)
return null;
throw new NullPointerException("Module path is not specified.");
}
File file;
Object[] obj;
String pathKey;
long lastModified;
pathKey = path.toLowerCase();
if (Var.uncheckModified) {
file = null;
lastModified = -1;
} else {
file = new File(Base.modulePath, path);
lastModified = file.lastModified();
}
obj = buffer.get(pathKey);
// 如果文件已经在缓存中中直接返回
if (obj != null) {
if (Var.uncheckModified || lastModified == (Long) obj[1])
return (JSONObject) obj[0];
}
if (Var.uncheckModified) {
file = new File(Base.modulePath, path);
lastModified = file.lastModified();
}
// 判断文件是否存在
if (lastModified == 0) {
if (silent)
return null;
throw new IllegalArgumentException("Module \"" + path + "\" is not found.");
}
JSONObject root = com.wb.util.JsonUtil.readObject(file);
JSONObject moduleNode = root.getJSONArray("children").getJSONObject(0).getJSONObject("configs");
// 把管理员权限设置到模块
root.getJSONObject("roles").put("admin", 1);
// 把module的loginRequired属性转换为布尔值并设置到根节点以方便访问
root.put("loginRequired", !"false".equals(moduleNode.opt("loginRequired")));
boolean libTypes[] = optimize(root, true, com.wb.util.SysUtil.getId() + ".");
autoSetConfig(moduleNode, libTypes);
if (moduleNode.optString("loadJS").indexOf("touch") != -1)
root.put("hasTouch", true);
obj = new Object[2];
obj[0] = root;
obj[1] = lastModified;
buffer.put(pathKey, obj);
return root;
}
/**
* 根据使用的控件自动设置模块模块项。
* @param root 模块根节点。
* @param moduleNode 模块配置项节点。
* @param libTypes 加载的控件库列表。
*/
private static void autoSetConfig(JSONObject moduleNode, boolean[] libTypes) {
String loadJS = (String) moduleNode.opt("loadJS");
if (loadJS == null) {
ArrayList<String> libs = new ArrayList<String>();
// 0项为未知控件
if (libTypes[1])
libs.add("ext");
if (libTypes[2])
libs.add("touch");
if (libTypes[3])
libs.add("bootstrap");
moduleNode.put("loadJS", com.wb.util.StringUtil.join(libs, "+"));
}
}
/**
* 删除指定文件或目录的模块缓存。
* @param path 文件或目录的相对路径。
*/
public static void clear(String path) {
Set<Entry<String, Object[]>> es = buffer.entrySet();
String key, modulePath, delPath;
Object[] value;
delPath = com.wb.util.StringUtil.concat(path, "/").toLowerCase();
for (Entry<String, Object[]> e : es) {
key = e.getKey();
modulePath = com.wb.util.StringUtil.concat(key, "/");
if (modulePath.startsWith(delPath)) {
value = e.getValue();
// 根据模块的id号清除ServerScript缓存
ScriptBuffer.remove(((JSONObject) value[0]).getJSONArray("children").getJSONObject(0)
.getJSONObject("configs").getString("id"));
buffer.remove(key);
}
}
}
/**
* 加载和初始化。
*/
public static synchronized void load() {
buffer = new ConcurrentHashMap<String, Object[]>();
}
/**
* 优化及设置模块。
*
* @param data 模块数据对象。
* @param parentRoot 父节点是否是根控件。
* @param moduleId 用于标识模块节点的id。
* @return 加载的库列表。0 未知, 1 Ext, 2 Touch, 3 BS。
* @throws IOException 访问文件发生异常。
*/
private static boolean[] optimize(JSONObject data, boolean parentRoot, String moduleId) throws IOException {
JSONArray children, ja = data.getJSONArray("children");
JSONObject jo, configs, configItems, tag, meta, general, autoNames;
String type, parentType;
Object isConfig;
int i, j = ja.length(), k, l;
Integer lib;
boolean asConfig, subLibTypes[], libTypes[] = new boolean[4];
l = libTypes.length;
if (j == 0)
data.remove("children");
else {
parentType = (String) data.opt("type");
for (i = 0; i < j; i++) {
jo = ja.getJSONObject(i);
type = (String) jo.opt("type");
configs = (JSONObject) jo.opt("configs");
meta = com.wb.interact.Controls.get(type);
general = (JSONObject) meta.opt("general");
tag = (JSONObject) general.opt("tag");
if (tag != null) {
lib = (Integer) tag.opt("lib");
if (lib == null)
lib = 0;
else
lib = (Integer) lib;
libTypes[lib] = true;// 标识使用指定库的控件,便于系统自动选择加载
}
autoNames = (JSONObject) general.opt("autoNames");
isConfig = configs.opt("isConfig");
if (!parentRoot && autoNames != null && isConfig == null
&& (autoNames.has(parentType) || autoNames.has("any")))
asConfig = true;
else
asConfig = "true".equals(isConfig);
// 如果指定控件为配置项移动控件到配置项列表属性__configs中
if (asConfig) {
configItems = (JSONObject) data.opt("__configs");
if (configItems == null) {
configItems = new JSONObject();
children = new JSONArray();
configItems.put("children", children);
data.put("__configs", configItems);
} else
children = (JSONArray) configItems.opt("children");
children.put(jo);
ja.remove(i);
i--;
j--;
}
if ("module".equals(type)) {
configs.put("id", moduleId);
} else if ("serverscript".equals(type)) {
// id用于ServerScript缓存id前缀必须保留moduleId用于清除
configs.put("id", com.wb.util.StringUtil.concat(moduleId, com.wb.util.SysUtil.getId()));
}
jo.remove("expanded");
subLibTypes = optimize(jo, Boolean.TRUE.equals(general.opt("root")), moduleId);
for (k = 0; k < l; k++) {
if (subLibTypes[k])
libTypes[k] = true;
}
}
// 如果移动配置项节点后为空删除children
if (j == 0)
data.remove("children");
}
return libTypes;
}
/**
* 判断指定模块或目录是否可显示。如果模块未隐藏且可访问则模块可显示,
* 如果目录下存在1个或以上可显示模块则目录可显示。
* @param file 需要判断的文件或目录。
* @param roles 当前用户的角色列表。
* @param type 1桌面应用2移动应用3权限设置。
* @return true可显示false不可显示。
* @throws IOException 判断过程发生异常。
*/
public static boolean canDisplay(File file, String[] roles, int type) throws IOException {
if (file.isDirectory()) {
File configFile = new File(file, "folder.json");
if (configFile.exists()) {
JSONObject content = com.wb.util.JsonUtil.readObject(configFile);
if (type != 3 && Boolean.TRUE.equals(content.opt("hidden")))
return false;
}
File[] files = com.wb.util.FileUtil.listFiles(file);
for (File subFile : files) {
if (canDisplay(subFile, roles, type))
return true;
}
} else if (file.getName().endsWith(".xwl")) {
JSONObject content = get(com.wb.util.FileUtil.getModulePath(file), false);
if (type != 3) {
if (content.has("hasTouch")) {
if (type == 1 && !Var.homeShowApp)
return false;
} else if (type == 2)
return false;
}
if ((type == 3 || Boolean.FALSE.equals(content.opt("hidden"))) && canAccess(content, roles))
return true;
}
return false;
}
/**
* 判断指定角色列表对模块是否可访问。如果模块无需登录或包含权限中的任意一个角色返回true
* 否则返回false。
* @param module 模块内容。
* @param roles 角色列表。
* @return true可访问false不可访问。
*/
public static boolean canAccess(JSONObject module, String[] roles) {
boolean noLoginRequired = Boolean.FALSE.equals(module.opt("loginRequired"));
if (noLoginRequired)
return true;
if (roles == null)
return false;
JSONObject setRoles = (JSONObject) module.opt("roles");
for (String role : roles) {
if (setRoles.has(role))
return true;
}
return false;
}
/**
* 判断当前请求对指定模块是否可访问。如果模块无需登录或包含权限中的任意一个角色返回true
* 否则返回false。
* @param request 请求对象。
* @param path 模块路径。
* @return true可访问false不可访问。
*/
public static boolean canAccess(HttpServletRequest request, String path) throws Exception {
JSONObject module = XwlBuffer.get(com.wb.util.FileUtil.getModuleFile(path), false);
String roles[] = Session.getRoles(request);
return canAccess(module, roles);
}
}

View File

@@ -0,0 +1,24 @@
package com.wb.controls;
public class Array extends ScriptControl {
public void create() throws Exception {
boolean parentRoot = Boolean.TRUE.equals(parentGeneral.opt("root"));
if (parentRoot) {
headerScript.append("app.");
headerScript.append(gs("itemId"));
headerScript.append("=[");
footerScript.append("];");
} else {
if ("Array".equals(parentGeneral.opt("type"))) {
headerScript.append("[");
} else {
headerScript.append(gs("itemId"));
headerScript.append(":[");
}
if (lastNode)
footerScript.append("]");
else
footerScript.append("],");
}
}
}

View File

@@ -0,0 +1,13 @@
package com.wb.controls;
/**
* 客户端脚本控件用于输出用户自定义的客户端html和js脚本。
*/
public class ClientScript extends com.wb.controls.ScriptControl {
public void create() throws Exception {
headerHtml.append(gs("headerHtml"));
footerHtml.insert(0, gs("footerHtml"));
headerScript.append(gs("headerScript"));
footerScript.insert(0, gs("footerScript"));
}
}

View File

@@ -0,0 +1,243 @@
package com.wb.controls;
import java.util.Date;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.json.JSONObject;
import com.wb.util.WebUtil;
/**
* 控件基类。
*/
public class Control {
/**
* 请求对象
*/
public HttpServletRequest request;
/**
* 响应对象
*/
public HttpServletResponse response;
/**
* 控件节点数据
*/
public JSONObject controlData;
/**
* 控件节点配置项
*/
public JSONObject configs;
/**
* 控件节点事件
*/
protected JSONObject events;
/**
* 控件元数据信息
*/
protected JSONObject controlMeta;
/**
* 控件元数据常规配置信息
*/
protected JSONObject generalMeta;
/**
* 控件元数据配置项配置信息
*/
protected JSONObject configsMeta;
/**
* 控件元数据事件配置信息
*/
protected JSONObject eventsMeta;
/**
* 父控件元数据常规配置信息
*/
protected JSONObject parentGeneral;
/**
* 控件节点是否是末尾子节点
*/
protected boolean lastNode;
/**
* 是否为普通运行模式
*/
protected boolean normalRunType;
/**
* 创建控件时执行的方法
*
* @throws Exception 创建过程中发生异常
*/
public void create() throws Exception {
};
/**
* 初始化控件,获取控件的配置数据。
*
* @param request 请求对象
* @param response 响应对象
* @param controlData 控件节点数据
* @param controlMeta 控件节点元数据
* @param parentGeneral 父控件元数据常规配置信息
* @param lastNode 控件节点是否是末尾子节点
* @param normalRunType 是否为普通运行模式
*/
public void init(HttpServletRequest request, HttpServletResponse response,
JSONObject controlData, JSONObject controlMeta,
JSONObject parentGeneral, boolean lastNode, boolean normalRunType) {
this.request = request;
this.response = response;
this.controlData = controlData;
configs = (JSONObject) controlData.opt("configs");
events = (JSONObject) controlData.opt("events");
this.controlMeta = controlMeta;
generalMeta = (JSONObject) controlMeta.opt("general");
configsMeta = (JSONObject) controlMeta.opt("configs");
eventsMeta = (JSONObject) controlMeta.opt("events");
this.parentGeneral = parentGeneral;
this.lastNode = lastNode;
this.normalRunType = normalRunType;
}
/**
* 获取控件中指定配置项的字符串值如果值为null则返回空串。
*
* @param name 配置项名称
* @param defaultValue 默认值
* @return 配置项值
*/
protected String gs(String name) {
Object value = configs.opt(name);
if (value == null)
return "";
else
return WebUtil.replaceParams(request, (String) value);
}
/**
* 获取控件中指定配置项的整数值如果值为空则返回0。
*
* @param name 配置项名称
* @return 配置项值
*/
protected int gi(String name) {
return gi(name, 0);
}
/**
* 获取控件中指定配置项的整数值,如果值为空则返回默认值。
*
* @param name 配置项名称
* @param defaultValue 默认值
* @return 配置项值
*/
protected int gi(String name, int defaultValue) {
String value = gs(name);
if (value.isEmpty())
return defaultValue;
else
return Integer.parseInt(value);
}
/**
* 获取控件中指定配置项的浮点数值如果值为空则返回0。
*
* @param name 配置项名称
* @return 配置项值
*/
protected float gf(String name) {
return gf(name, 0);
}
/**
* 获取控件中指定配置项的浮点值,如果值为空则返回默认值。
*
* @param name 配置项名称
* @param defaultValue 默认值
* @return 配置项值
*/
protected float gf(String name, float defaultValue) {
String value = gs(name);
if (value.isEmpty())
return defaultValue;
else
return Integer.parseInt(value);
}
/**
* 获取控件中指定配置项的日期值如果值为空则返回null。
*
* @param name 配置项名称
* @return 配置项值
*/
protected Date gd(String name) {
return gd(name, null);
}
/**
* 获取控件中指定配置项的日期值,如果值为空则返回默认值。
*
* @param name 配置项名称
* @param defaultValue 默认值
* @return 配置项值
*/
protected Date gd(String name, Date defaultValue) {
String value = gs(name);
if (value.isEmpty())
return defaultValue;
else
return com.wb.util.DateUtil.strToDate(value);
}
/**
* 获取控件中指定配置项的布尔值如果值为空则返回false。
*
* @param name 配置项名称
* @return 配置项值
*/
protected boolean gb(String name) {
return gb(name, false);
}
/**
* 获取控件中指定配置项的布尔值,如果值为空则返回默认值。
*
* @param name 配置项名称
* @param defaultValue 默认值
* @return 配置项值
*/
protected boolean gb(String name, boolean defaultValue) {
String value = gs(name);
if (value.isEmpty())
return defaultValue;
else
return Boolean.parseBoolean(value);
}
/**
* 获取控件中指定事件的脚本。
*
* @param name 事件名称
* @return 事件脚本。
*/
protected String ge(String name) {
if (events == null)
return "";
Object event = events.opt(name);
if (event == null)
return "";
else
return WebUtil.replaceParams(request, (String) event);
}
/**
* 获取当前请求对象指定名称的attribute或parameter值。
* 如果attribute存在则返回attribute否则返回paramter。
* 如果相同名称的attribute或parameter都存在则返回前者。
* 如果都不存在则返回null。
* @param name 属性或参数名称
* @return 属性或参数值
*/
protected String gp(String name) {
return WebUtil.fetch(request, name);
}
}

View File

@@ -0,0 +1,332 @@
package com.wb.controls;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.dialect.oracle.parser.OracleStatementParser;
import com.alibaba.druid.sql.dialect.oracle.visitor.OracleSchemaStatVisitor;
import com.alibaba.druid.sql.parser.SQLStatementParser;
import com.wb.tool.DataAutoGenProvider;
import com.wb.tool.DataProvider;
import com.wb.util.DbUtil;
import com.wb.util.StringUtil;
import com.wb.util.WebUtil;
import org.json.JSONArray;
import org.json.JSONObject;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.util.*;
import java.util.Map.Entry;
/**
* 数据库内容查询控件,见:{@link DataProvider}
*/
public class DpAutoGenControl extends Control {
public void create() throws Exception {
getContent(true);
}
public String createfalse() throws Exception {
return getContent(false);
}
private String getSchema(Connection conn) throws Exception {
String schema;
schema = conn.getMetaData().getUserName();
if ((schema == null) || (schema.length() == 0)) {
throw new Exception("ORACLE数据库模式不允许为空");
}
return schema.toUpperCase().toString();
}
public String gettables(String sql) {
// String sql = "select id,name from apbpst";
// 新建 MySQL Parser
SQLStatementParser parser = new OracleStatementParser(sql);
// 使用Parser解析生成AST这里SQLStatement就是AST
SQLStatement statement = parser.parseStatement();
// 使用visitor来访问AST
OracleSchemaStatVisitor visitor = new OracleSchemaStatVisitor();
statement.accept(visitor);
// System.ouimport com.alibaba.druid.sql.ast.SQLStatement;
// statement.(visitor);
// 从visitor中拿出你所关注的信息
System.out.println(visitor.getTables());
return "";
}
/**
* 获取列信息
* @param jndi
* @return
* @throws Exception
*/
public List getcolumnconinfo(String jndi) throws Exception {
List result = new ArrayList();
Connection conn = DbUtil.getConnection(request, jndi);
//String sql= gs("sql");
// String tables= gettables(sql);
ResultSet rs=null;
try {
String tablename = request.getParameter("tableName");
//读取表注释
DatabaseMetaData dbmd = conn.getMetaData();
String[] types = {"TABLE"};
rs = conn.getMetaData().getColumns(null, getSchema(conn), tablename.toUpperCase(), "%");
while (rs.next()) {
//System.out.println("字段名:"+rs.getString("COLUMN_NAME")+"--字段注释:"+rs.getString("REMARKS")+"--字段数据类型:"+rs.getString("TYPE_NAME"));
Map map = new HashMap();
String colName = rs.getString("COLUMN_NAME");
map.put("code", colName);
String remarks = rs.getString("REMARKS");
if (remarks == null || remarks.equals("")) {
remarks = colName;
}
map.put("name", remarks);
String dbType = rs.getString("TYPE_NAME");
map.put("dbType", dbType);
// map.put("valueType", changeDbType(dbType));
result.add(map);
}
return result;
}catch (Exception e){
e.printStackTrace();
return null;
}
}
/**
* 获取查询的内容,该内容为从数据库查询获得的结果转换为指定类型的脚本或二进制流。
*
* @param directOutput 是否直接输出到客户端如果为false仅返回脚本类型的内容。
* @return 当directOutput为false时返回脚本类内容否则返回null。
*/
public String getContent(boolean directOutput) throws Exception {
if (gb("disabled", false))
return null;
long startTime = System.currentTimeMillis();
DataAutoGenProvider dp;
Long totalCount = null;
ResultSet resultSet = null, totalResultSet = null;
Object result, totalResult;
String sql, totalSql, jndi = gs("jndi");
String limitRecords = gs("limitRecords");
String limitExportRecords = gs("limitExportRecords");
String loadParams = gs("loadParams");
String totalLoadParams = gs("totalLoadParams");
String startParam = request.getParameter("start");
String limitParam = request.getParameter("limit");
String type = gs("type"), dictTableNames;
long beginIndex, endIndex;
try {
if (type.isEmpty() && "1".equals(request.getParameter("_istree")))
type = "tree";
if (StringUtil.isEmpty(type) || "array".equals(type))
setOrderVars();
sql = gs("sql");
totalSql = gs("totalSql");
if (StringUtil.isEmpty(startParam)) {
beginIndex = 1;
request.setAttribute("start", 0l);
} else
beginIndex = Long.parseLong(startParam) + 1;
if (StringUtil.isEmpty(limitParam)) {
endIndex = Long.MAX_VALUE;
request.setAttribute("limit", endIndex);
} else
endIndex = beginIndex + Long.parseLong(limitParam) - 1;
// beginIndex和endIndex可用于SQL between语句
request.setAttribute("beginIndex", beginIndex);
request.setAttribute("endIndex", endIndex);
sql="select * from "+request.getAttribute("tableName").toString();
result = getResult(DbUtil.run(request, sql, jndi, loadParams));
List datacolumninfo= getcolumnconinfo(jndi);
if (result instanceof ResultSet) {
resultSet = (ResultSet) result;// ResultSet在请求结束后自动关闭
} else {
String text = StringUtil.concat(
"{\"total\":1,\"metaData\":{\"fields\":[{\"name\":\"result\",\"type\":\"string\"}]},\"columns\":[{\"xtype\":\"rownumberer\",\"width\":40},{\"dataIndex\":\"result\",flex:1,\"text\":\"result\"}],\"rows\":[{\"result\":",
result == null ? "null" : StringUtil.quote(result.toString()), "}],\"elapsed\":",
Long.toString(System.currentTimeMillis() - startTime), "}");
if (directOutput) {
WebUtil.send(response, text);
return null;
} else
return text;
}
if (!StringUtil.isEmpty(totalSql)) {
totalResult = getResult(DbUtil.run(request, totalSql, jndi, totalLoadParams));
if (totalResult == null)
throw new NullPointerException("No value in the totalSql.");
if (totalResult instanceof ResultSet) {
totalResultSet = (ResultSet) totalResult;
if (totalResultSet.next()) {
// 比使用totalResultSet.getLong更安全和通用
totalCount = Long.parseLong(totalResultSet.getString(1));
} else
throw new NullPointerException("Empty total ResultSet.");
} else
totalCount = Long.parseLong(totalResult.toString());
}
dp = new DataAutoGenProvider();
dp.startTime = startTime;
dp.request = request;
dp.response = response;
dp.resultSet = resultSet;
dp.fields = gs("fields");
dp.fieldsTag = gs("fieldsTag");
dp.keyDefines = gs("keyDefines");
dp.totalCount = totalCount;
dp.createColumns = gb("createColumns", true);
if (gb("autoPage", true)) {
dp.beginIndex = beginIndex;
dp.endIndex = endIndex;
}
if (!limitRecords.isEmpty())
dp.limitRecords = Integer.parseInt(limitRecords);
if (!limitExportRecords.isEmpty())
dp.limitExportRecords = Integer.parseInt(limitExportRecords);
dp.tag = gs("tag");
dp.type = type;
dictTableNames = gs("dictTableNames");
dp.createKeyValues = gb("createKeyValues", false);
if (dictTableNames.isEmpty())
dp.dictTableNames = null;
else
dp.dictTableNames = StringUtil.split(dictTableNames, ',', true);
dp.dictFieldsMap = gs("dictFieldsMap");
if (directOutput) {
dp.output(datacolumninfo);
return null;
} else
return dp.getScript(datacolumninfo);
} finally {
if (resultSet != null)
resultSet.close();
if (totalResultSet != null)
totalResultSet.close();
}
}
/**
* 获取Query运行返回的ResultSet或影响记录数如果存在输出参数则尝试获取名称为
* result的输出参数否则返回运行Query返回的值结果集或影响记录数
*
* @param
* @return 获取的结果集或影响记录数。
*/
private Object getResult(Object result) {
if (result instanceof HashMap<?, ?>) {
HashMap<?, ?> map = (HashMap<?, ?>) result;
// 设置输出参数值
Set<?> es = map.entrySet();
Entry<?, ?> entry;
String name, itemId = StringUtil.select(gs("itemId"));
for (Object e : es) {
entry = (Entry<?, ?>) e;
name = (String) entry.getKey();
// 在hashmap中返回值名称为return
if (name.equals("return")) {
if (!itemId.isEmpty())
name = itemId;
} else {
if (!itemId.isEmpty())
name = StringUtil.concat(itemId, ".", name);
}
request.setAttribute(name, entry.getValue());
}
Object val = map.get(StringUtil.select(gs("resultName"), "result"));
if (val == null)
return map.get("return");
else
return val;
} else
return result;
}
/**
* 设置sql.orderBy和sql.orderFields变量以方便使用前端参数进行排序。仅适用于type为array。
*
* @throws Exception 设置过程发生异常。
*/
private void setOrderVars() throws Exception {
String sort = request.getParameter("sort");
if (StringUtil.isEmpty(sort) || request.getAttribute("sql.orderBy") != null)
return;
JSONArray ja = new JSONArray(sort);
int i, j = ja.length();
if (j > 0) {
JSONObject jo;
StringBuilder exp = new StringBuilder();
String property, defaultPrefix, prefix;
JSONObject orderJo;
String orderFields = gs("orderFields");
if (StringUtil.isEmpty(orderFields)) {
orderJo = null;
defaultPrefix = null;
} else {
orderJo = new JSONObject(orderFields);
defaultPrefix = orderJo.optString("default", null);
}
for (i = 0; i < j; i++) {
jo = ja.getJSONObject(i);
if (i > 0)
exp.append(',');
property = jo.getString("property");
// 检查名称合法性防止被SQL注入
if (!StringUtil.checkName(property)) {
throw new IllegalArgumentException("Invalid name \"" + property + "\".");
}
if (orderJo != null) {
if (orderJo.has(property)) {
prefix = orderJo.optString(property);
if (!prefix.isEmpty()) {
exp.append(prefix);
exp.append('.');
}
} else if (defaultPrefix != null) {
exp.append(defaultPrefix);
exp.append('.');
}
}
exp.append(property);
if (StringUtil.isSame(jo.optString("direction"), "desc"))
exp.append(" desc");
}
request.setAttribute("sql.orderBy", " order by " + exp);
// sql.orderFields前置","以方便使用order by field{#sql.orderFields#}
request.setAttribute("sql.orderFields", "," + exp);
}
}
}

View File

@@ -0,0 +1,301 @@
package com.wb.controls;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.util.*;
import java.util.Map.Entry;
import org.json.JSONArray;
import org.json.JSONObject;
import com.wb.tool.DataProvider;
import com.wb.util.DbUtil;
import com.wb.util.StringUtil;
import com.wb.util.WebUtil;
/**
* 数据库内容查询控件,见:{@link DataProvider}
*/
public class DpControl extends com.wb.controls.Control {
public void create() throws Exception {
getContent(true);
}
private String getSchema(Connection conn) throws Exception {
String schema;
schema = conn.getMetaData().getUserName();
if ((schema == null) || (schema.length() == 0)) {
throw new Exception("ORACLE数据库模式不允许为空");
}
return schema.toUpperCase().toString();
}
/**
* 获取列信息,多表要考虑合并
* @param jndi
* @return
* @throws Exception
*/
public List getcolumnconinfo(String jndi,String tablename) throws Exception {
List result = new ArrayList();
Connection conn = DbUtil.getConnection(request, jndi);
ResultSet rs=null;
try {
// String tablename = ;
//读取表注释
DatabaseMetaData dbmd = conn.getMetaData();
String[] types = {"TABLE"};
rs = conn.getMetaData().getColumns(null, getSchema(conn), tablename.toUpperCase(), "%");
while (rs.next()) {
//System.out.println("字段名:"+rs.getString("COLUMN_NAME")+"--字段注释:"+rs.getString("REMARKS")+"--字段数据类型:"+rs.getString("TYPE_NAME"));
Map map = new HashMap();
String colName = rs.getString("COLUMN_NAME");
map.put("code", colName);
String remarks = rs.getString("REMARKS");
if (remarks == null || remarks.equals("")) {
remarks = colName;
}
map.put("name", remarks);
String dbType = rs.getString("TYPE_NAME");
map.put("dbType", dbType);
// map.put("valueType", changeDbType(dbType));
result.add(map);
}
return result;
}catch (Exception e){
e.printStackTrace();
return null;
}
}
/**
* 获取查询的内容,该内容为从数据库查询获得的结果转换为指定类型的脚本或二进制流。
*
* @param directOutput 是否直接输出到客户端如果为false仅返回脚本类型的内容。
* @return 当directOutput为false时返回脚本类内容否则返回null。
*/
public String getContent(boolean directOutput) throws Exception {
if (gb("disabled", false))
return null;
long startTime = System.currentTimeMillis();
DataProvider dp;
Long totalCount = null;
ResultSet resultSet = null, totalResultSet = null;
Object result, totalResult;
String sql, totalSql, jndi = gs("jndi");
String limitRecords = gs("limitRecords");
String limitExportRecords = gs("limitExportRecords");
String loadParams = gs("loadParams");
String totalLoadParams = gs("totalLoadParams");
String startParam = request.getParameter("start");
String limitParam = request.getParameter("limit");
String type = gs("type"), dictTableNames;
long beginIndex, endIndex;
try {
if (type.isEmpty() && "1".equals(request.getParameter("_istree")))
type = "tree";
if (StringUtil.isEmpty(type) || "array".equals(type))
setOrderVars();
sql = gs("sql");
totalSql = gs("totalSql");
if (StringUtil.isEmpty(startParam)) {
beginIndex = 1;
request.setAttribute("start", 0l);
} else
beginIndex = Long.parseLong(startParam) + 1;
if (StringUtil.isEmpty(limitParam)) {
endIndex = Long.MAX_VALUE;
request.setAttribute("limit", endIndex);
} else
endIndex = beginIndex + Long.parseLong(limitParam) - 1;
// beginIndex和endIndex可用于SQL between语句
request.setAttribute("beginIndex", beginIndex);
request.setAttribute("endIndex", endIndex);
result = getResult(DbUtil.run(request, sql, jndi, loadParams));
if (result instanceof ResultSet) {
resultSet = (ResultSet) result;// ResultSet在请求结束后自动关闭
} else {
String text = StringUtil.concat(
"{\"total\":1,\"metaData\":{\"fields\":[{\"name\":\"result\",\"type\":\"string\"}]},\"columns\":[{\"xtype\":\"rownumberer\",\"width\":40},{\"dataIndex\":\"result\",flex:1,\"text\":\"result\"}],\"rows\":[{\"result\":",
result == null ? "null" : StringUtil.quote(result.toString()), "}],\"elapsed\":",
Long.toString(System.currentTimeMillis() - startTime), "}");
if (directOutput) {
WebUtil.send(response, text);
return null;
} else
return text;
}
if (!StringUtil.isEmpty(totalSql)) {
totalResult = getResult(DbUtil.run(request, totalSql, jndi, totalLoadParams));
if (totalResult == null)
throw new NullPointerException("No value in the totalSql.");
if (totalResult instanceof ResultSet) {
totalResultSet = (ResultSet) totalResult;
if (totalResultSet.next()) {
// 比使用totalResultSet.getLong更安全和通用
totalCount = Long.parseLong(totalResultSet.getString(1));
} else
throw new NullPointerException("Empty total ResultSet.");
} else
totalCount = Long.parseLong(totalResult.toString());
}
dp = new DataProvider();
dp.startTime = startTime;
dp.request = request;
dp.response = response;
dp.resultSet = resultSet;
dp.fields = gs("fields");
dp.fieldsTag = gs("fieldsTag");
dp.keyDefines = gs("keyDefines");
dp.totalCount = totalCount;
dp.createColumns = gb("createColumns", true);
if (gb("autoPage", true)) {
dp.beginIndex = beginIndex;
dp.endIndex = endIndex;
}
if (!limitRecords.isEmpty())
dp.limitRecords = Integer.parseInt(limitRecords);
if (!limitExportRecords.isEmpty())
dp.limitExportRecords = Integer.parseInt(limitExportRecords);
dp.tag = gs("tag");
dp.type = type;
dictTableNames = gs("dictTableNames");
dp.createKeyValues = gb("createKeyValues", false);
if (dictTableNames.isEmpty())
dp.dictTableNames = null;
else
dp.dictTableNames = StringUtil.split(dictTableNames, ',', true);
dp.dictFieldsMap = gs("dictFieldsMap");
List datacolumninfo=new ArrayList();
if(request.getParameter("table")!=null) {
datacolumninfo = getcolumnconinfo(jndi, request.getParameter("table"));
}
if (directOutput) {
dp.output(datacolumninfo);
return null;
} else
return dp.getScript(datacolumninfo);
} finally {
if (resultSet != null)
resultSet.close();
if (totalResultSet != null)
totalResultSet.close();
}
}
/**
* 获取Query运行返回的ResultSet或影响记录数如果存在输出参数则尝试获取名称为
* result的输出参数否则返回运行Query返回的值结果集或影响记录数
*
* @param
* @return 获取的结果集或影响记录数。
*/
private Object getResult(Object result) {
if (result instanceof HashMap<?, ?>) {
HashMap<?, ?> map = (HashMap<?, ?>) result;
// 设置输出参数值
Set<?> es = map.entrySet();
Entry<?, ?> entry;
String name, itemId = StringUtil.select(gs("itemId"));
for (Object e : es) {
entry = (Entry<?, ?>) e;
name = (String) entry.getKey();
// 在hashmap中返回值名称为return
if (name.equals("return")) {
if (!itemId.isEmpty())
name = itemId;
} else {
if (!itemId.isEmpty())
name = StringUtil.concat(itemId, ".", name);
}
request.setAttribute(name, entry.getValue());
}
Object val = map.get(StringUtil.select(gs("resultName"), "result"));
if (val == null)
return map.get("return");
else
return val;
} else
return result;
}
/**
* 设置sql.orderBy和sql.orderFields变量以方便使用前端参数进行排序。仅适用于type为array。
*
* @throws Exception 设置过程发生异常。
*/
private void setOrderVars() throws Exception {
String sort = request.getParameter("sort");
if (StringUtil.isEmpty(sort) || request.getAttribute("sql.orderBy") != null)
return;
JSONArray ja = new JSONArray(sort);
int i, j = ja.length();
if (j > 0) {
JSONObject jo;
StringBuilder exp = new StringBuilder();
String property, defaultPrefix, prefix;
JSONObject orderJo;
String orderFields = gs("orderFields");
if (StringUtil.isEmpty(orderFields)) {
orderJo = null;
defaultPrefix = null;
} else {
orderJo = new JSONObject(orderFields);
defaultPrefix = orderJo.optString("default", null);
}
for (i = 0; i < j; i++) {
jo = ja.getJSONObject(i);
if (i > 0)
exp.append(',');
property = jo.getString("property");
// 检查名称合法性防止被SQL注入
if (!StringUtil.checkName(property)) {
throw new IllegalArgumentException("Invalid name \"" + property + "\".");
}
if (orderJo != null) {
if (orderJo.has(property)) {
prefix = orderJo.optString(property);
if (!prefix.isEmpty()) {
exp.append(prefix);
exp.append('.');
}
} else if (defaultPrefix != null) {
exp.append(defaultPrefix);
exp.append('.');
}
}
exp.append(property);
if (StringUtil.isSame(jo.optString("direction"), "desc"))
exp.append(" desc");
}
request.setAttribute("sql.orderBy", " order by " + exp);
// sql.orderFields前置","以方便使用order by field{#sql.orderFields#}
request.setAttribute("sql.orderFields", "," + exp);
}
}
}

View File

@@ -0,0 +1,19 @@
package com.wb.controls;
import com.wb.common.XwlBuffer;
/**
* 模块绑定的解析类。如果当前用户对指定模块不可访问在控件中添加hidden:true属性。
*/
public class ExtActionUI extends com.wb.controls.ExtControl {
protected void extendConfig() throws Exception {
String bindModule = gs("bindModule");
if (!bindModule.isEmpty() && !XwlBuffer.canAccess(request, bindModule)) {
if (hasItems)
headerScript.append(',');
else
hasItems = true;
headerScript.append("hidden:true");
}
}
}

View File

@@ -0,0 +1,33 @@
package com.wb.controls;
import com.wb.common.KVBuffer;
import com.wb.util.WebUtil;
/**
* Column控件的解析类。
*/
public class ExtColumn extends com.wb.controls.ExtControl {
protected void extendConfig() {
String keyName = gs("keyName");
if (!keyName.isEmpty()) {
if (hasItems)
headerScript.append(',');
else
hasItems = true;
headerScript.append("renderer:Wb.kvRenderer,keyItems:");
headerScript.append(KVBuffer.getList(keyName, WebUtil.fetch(request, "sys.tenancyId")));
}
/**
* 添加列隐藏功能
if(this.configs.get("itemId").equals("nameCol")){
if (hasItems)
headerScript.append(',');
else
hasItems = true;
headerScript.append("hidden:");
headerScript.append("true");
} */
}
}

View File

@@ -0,0 +1,38 @@
package com.wb.controls;
import com.wb.common.KVBuffer;
import com.wb.util.StringUtil;
import com.wb.util.WebUtil;
/**
* Combo控件的解析类。
*/
public class ExtCombo extends ExtControl {
protected void extendConfig() throws Exception {
String keyName = gs("keyName");
if (!keyName.isEmpty()) {
if (hasItems)
headerScript.append(',');
else
hasItems = true;
headerScript.append(getkeyNameScript(keyName));
}
}
/**
* 获得键值相关的表达式脚本。
* @return
*/
public String getkeyNameScript(String keyName) {
/**
* update by yangxh 2021/07/26
* 取消keyName下拉按key排序
*/
return StringUtil.concat(
"displayField:\"V\",valueField:\"K\",forceSelection:true,queryMode:\"local\",store:{fields:[\"K\",\"V\"],data:",
KVBuffer.getList(keyName, WebUtil.fetch(request, "sys.tenancyId")), "}");
/*return StringUtil.concat(
"displayField:\"V\",valueField:\"K\",forceSelection:true,queryMode:\"local\",store:{fields:[\"K\",\"V\"],sorters:\"K\",data:",
KVBuffer.getList(keyName), "}");*/
}
}

View File

@@ -0,0 +1,35 @@
package com.wb.controls;
import java.io.File;
import com.wb.util.StringUtil;
import com.wb.util.WebUtil;
public class ExtContainer extends com.wb.controls.ExtControl {
protected void extendConfig() throws Exception {
String excelForm = gs("excelForm");
String excelFormAlign = gs("excelFormAlign");
int sheetIndex;
if (!excelForm.isEmpty()) {
if (hasItems)
headerScript.append(',');
else
hasItems = true;
if (gs("autoScroll").isEmpty())
headerScript.append("autoScroll:true,createObject:true,");
else
headerScript.append("createObject:true,");
headerScript.append("html:");
if (excelForm.indexOf('|') == -1) {
sheetIndex = 0;
} else {
sheetIndex = Integer.parseInt(StringUtil.getValuePart(excelForm, '|'));
excelForm = StringUtil.getNamePart(excelForm, '|');
}
File file = new File(com.wb.common.Base.path, excelForm);
headerScript.append(
StringUtil.quote(com.wb.tool.ExcelForm.getHtml(WebUtil.fetch(request), file, sheetIndex, excelFormAlign)));
}
}
}

View File

@@ -0,0 +1,373 @@
package com.wb.controls;
import java.util.Map.Entry;
import java.util.Set;
import org.json.JSONArray;
import org.json.JSONObject;
import com.wb.util.StringUtil;
import com.wb.util.WebUtil;
/**
* Ext控件的解析类。
*/
public class ExtControl extends ScriptControl {
/**
* 是否为普通模式。非普通模式下不创建变量和items脚本。
*/
public boolean normalMode = true;
protected boolean hasItems;
protected boolean hasMediaItems;
private StringBuilder mediaScript = new StringBuilder();
public void create() throws Exception {
if (directOutput())
return;
String type, itemId, xtype, userXtype;
boolean hasXtype, typeAdded = false;
boolean parentRoot = Boolean.TRUE.equals(parentGeneral.opt("root"));
userXtype = gs("xtype");
if (userXtype.isEmpty()) {
// 如果用户未设置xtype使用控件指定的xtype
xtype = (String) generalMeta.opt("xtype");
hasXtype = xtype != null;
} else {
// 使用由用户设置的xtype
xtype = userXtype;
hasXtype = true;
}
type = (String) generalMeta.opt("type");
if (parentRoot) {
itemId = gs("itemId");
if (normalMode) {
headerScript.append("app.");
// 实例变量
headerScript.append(itemId);
headerScript.append("=app._");
// 原始变量,加下划线
headerScript.append(itemId);
}
if (gb("createInstance", !Boolean.FALSE.equals(generalMeta.opt("autoCreate")))) {
if (normalMode) {
if (type == null) {
headerScript.append("={");
footerScript.insert(0, "};");
} else {
headerScript.append("=new ");
if (!normalRunType && type.endsWith(".Viewport"))
headerScript.append("Ext.container.Container");
else if (!normalRunType && type.equals("tviewport"))
headerScript.append("Ext.Container");
else
headerScript.append(type);
headerScript.append("({");
if (normalRunType && hasXtype && !Boolean.FALSE.equals(generalMeta.opt("render"))) {
headerScript.append("renderTo:document.body");
hasItems = true;
}
footerScript.insert(0, "});");
typeAdded = true;
}
} else {
headerScript.append("{");
footerScript.insert(0, "}");
}
} else {
headerScript.append("={");
footerScript.insert(0, "};");
}
} else {
// 如果父控件不是容器则添加为属性
if (!Boolean.TRUE.equals(parentGeneral.opt("container"))) {
headerScript.append((String) configs.opt("itemId"));
headerScript.append(':');
}
headerScript.append('{');
if (lastNode)
footerScript.insert(0, '}');
else
footerScript.insert(0, "},");
}
if (hasItems)
headerScript.append(',');
else
hasItems = true;
if (normalMode)
headerScript.append("appScope:app");
else
headerScript.append("appScope:null");// appScope在代码中设置
if ("tviewport".equals(type)) {
headerScript.append(",isViewport:true");
// TViewport默认为card布局
if (gs("layout").isEmpty())
headerScript.append(",layout:\"card\"");
}
if (!typeAdded && hasXtype) {
if (hasItems)
headerScript.append(',');
else
hasItems = true;
headerScript.append("xtype:\"");
headerScript.append(xtype);
headerScript.append("\"");
}
extendConfig();
processConfigs();
if (events != null)
processEvents();
if (controlData.has("children")) {
addMedia(true);
if (normalMode) {
if (Boolean.TRUE.equals(generalMeta.opt("container"))) {
if (hasItems)
headerScript.append(',');
headerScript.append("items:[");
footerScript.insert(0, ']');
} else
headerScript.append(',');
}
} else
addMedia(false);
}
/**
* 如果存在直接输出的配置项,则直接输出数据。
* @return true存在false不存在。
*/
private boolean directOutput() {
JSONObject config = (JSONObject) generalMeta.opt("directOutput");
if (config == null)
return false;
String value = gs((String) config.opt("name"));
if (!value.isEmpty()) {
JSONArray array = (JSONArray) config.optJSONArray("values");
if (array.indexOf(value) != -1) {
headerScript.append('"');
headerScript.append(value);
headerScript.append('"');
if (!lastNode)
headerScript.append(',');
return true;
}
}
return false;
}
/**
* 添加中间项脚本。
* @param hasChildren 是否有子项。
*/
protected void addMedia(boolean hasChildren) {
JSONObject media = (JSONObject) generalMeta.opt("media");
if (media == null)
return;
String xtypeName = (String) media.opt("xtypeName"), xtype = null;
boolean xtypeEmpty;
if (xtypeName == null)
xtypeEmpty = true;
else {
xtype = gs(xtypeName);
xtypeEmpty = xtype.isEmpty();
}
if (!hasChildren && !hasMediaItems && xtypeEmpty)
return;
if (hasItems)
headerScript.append(',');
headerScript.append((String) media.opt("name"));
headerScript.append(":{");
footerScript.insert(0, '}');
if (hasMediaItems) {
headerScript.append(mediaScript.toString());
hasItems = true;
} else
hasItems = false;
if (!xtypeEmpty) {
if (hasMediaItems)
headerScript.append(',');
else
hasMediaItems = true;
headerScript.append("xtype:\"");
headerScript.append(xtype);
headerScript.append('\"');
hasItems = true;
}
}
/**
* 处理配置项。
*/
protected void processConfigs() {
Set<Entry<String, Object>> es = configs.entrySet();
String key, value, type, rename;
StringBuilder script;
JSONObject itemObject;
JSONArray params;
boolean addComma = hasItems, addMediaComma = false;
char firstChar;
for (Entry<String, Object> entry : es) {
key = entry.getKey();
value = (String) entry.getValue();
itemObject = (JSONObject) configsMeta.opt(key);
if (itemObject == null || Boolean.TRUE.equals(itemObject.opt("hidden")))
continue;
if (Boolean.TRUE.equals(itemObject.opt("media"))) {
if (addMediaComma)
mediaScript.append(',');
else {
addMediaComma = true;
hasMediaItems = true;
}
script = mediaScript;
} else {
if (addComma)
headerScript.append(',');
else {
addComma = true;
hasItems = true;
}
script = headerScript;
}
rename = (String) itemObject.opt("rename");
if (rename == null)
script.append(key);
else
script.append(rename);
script.append(':');
firstChar = value.charAt(0);
if (firstChar == '@') {
script.append(WebUtil.replaceParams(request, value.substring(1)));
} else {
type = (String) itemObject.opt("type");
if (type.startsWith("exp"))
script.append(WebUtil.replaceParams(request, value));
else if (type.equals("glyph")) {
script.append("0x");
script.append(WebUtil.replaceParams(request, value));
} else if (type.equals("js")) {
script.append("function(");
params = (JSONArray) itemObject.opt("params");
if (params != null)
script.append(com.wb.util.JsonUtil.join(params, ","));
script.append("){\n");
script.append(WebUtil.replaceParams(request, value));
script.append("\n}");
} else
script.append(StringUtil.quote(WebUtil.replaceParams(request, value)));
}
}
addTags(configs, hasItems);
}
/**
* 处理事件。
*/
protected void processEvents() {
Set<Entry<String, Object>> es = events.entrySet();
String key, value, rename;
StringBuilder script;
JSONObject itemObject;
JSONArray params;
boolean addComma = false, addMediaComma = false;
for (Entry<String, Object> entry : es) {
key = entry.getKey();
value = (String) entry.getValue();
itemObject = (JSONObject) eventsMeta.opt(key);
if (itemObject == null || Boolean.TRUE.equals(itemObject.opt("hidden")))
continue;
if (Boolean.TRUE.equals(itemObject.opt("media"))) {
if (addMediaComma)
mediaScript.append(',');
else {
addMediaComma = true;
if (hasMediaItems)
mediaScript.append(',');
else
hasMediaItems = true;
mediaScript.append("listeners:{");
}
script = mediaScript;
} else {
if (addComma)
headerScript.append(',');
else {
addComma = true;
if (hasItems)
headerScript.append(',');
else
hasItems = true;
headerScript.append("listeners:{");
}
script = headerScript;
}
script.append('\n');
rename = (String) itemObject.opt("rename");
if (rename == null)
script.append(key);
else
script.append(rename);
script.append(":function(");
params = (JSONArray) itemObject.opt("params");
if (params != null)
script.append(com.wb.util.JsonUtil.join(params, ","));
script.append("){\n");
script.append(WebUtil.replaceParams(request, value));
script.append("\n}");
}
// 事件在单独的对象中描述因此使用addComma判断是否有事件。
if (addTags(events, addComma))
headerScript.append("\n}");
if (addMediaComma)
mediaScript.append("\n}");
}
/**
* 添加配置项或事件的附加项。
* @param object 配置项或事件数据对象。
* @param hasContent 是否已经存在内容。
* @return true已经添加false未添加。
*/
private boolean addTags(JSONObject object, boolean hasContent) {
boolean isEvents = object == events;
String tags;
if (isEvents)
tags = (String) object.opt("tagEvents");
else
tags = (String) object.opt("tagConfigs");
if (tags != null) {
tags = WebUtil.replaceParams(request, tags);
String trimsTag = tags.trim();
int beginPos = trimsTag.indexOf('{'), endPos = trimsTag.lastIndexOf('}');
if (beginPos == 0 && endPos == trimsTag.length() - 1)
tags = trimsTag.substring(beginPos + 1, endPos).trim();
if (tags.isEmpty())
return hasContent;
if (hasContent)
headerScript.append(',');
else {
hasContent = true;
if (isEvents) {
if (hasItems)
headerScript.append(',');
else
hasItems = true;
headerScript.append("listeners:{");
}
}
headerScript.append('\n');
headerScript.append(tags);
hasItems = true;
}
return hasContent;
}
/**
* 扩展配置项处理方法,子类可以继承和扩充。
*/
protected void extendConfig() throws Exception {
}
}

View File

@@ -0,0 +1,51 @@
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.wb.controls;
import com.wb.common.Resource;
import com.wb.util.StringUtil;
import com.wb.util.WebUtil;
public class ExtGrid extends ExtControl {
public ExtGrid() {
}
protected void extendConfig() throws Exception {
String syncStateId = this.gs("syncStateId");
String allowExportUrl = this.gs("allowExportUrl");
String gridName = this.gs("itemId");
syncStateId = request.getQueryString().replace("xwl=","").replace("&xwlt=1","") + "#" + gridName;
if (!allowExportUrl.isEmpty()) {
if (this.hasItems) {
this.headerScript.append(',');
} else {
this.hasItems = true;
}
this.headerScript.append("hideExportBtns:true");
}
if (!syncStateId.isEmpty()) {
String headersData = this.getHeadersData(syncStateId);
if (!StringUtil.isEmpty(headersData)) {
if (this.hasItems) {
this.headerScript.append(',');
} else {
this.hasItems = true;
}
this.headerScript.append("syncHeadersData:");
this.headerScript.append(headersData);
}
}
}
public String getHeadersData(String syncStateId) {
//获取wb_resources,通过 gridState#+syncStateId+userid
return Resource.getString(this.request, "gridState#" + syncStateId, (String)null);
}
}

View File

@@ -0,0 +1,30 @@
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.wb.controls;
import com.wb.common.KVBuffer;
import com.wb.util.WebUtil;
public class ExtRadioGroup extends ExtControl {
public ExtRadioGroup() {
}
protected void extendConfig() throws Exception {
String keyName = this.gs("keyName");
if (!keyName.isEmpty()) {
if (this.hasItems) {
this.headerScript.append(',');
} else {
this.hasItems = true;
}
this.headerScript.append("items:");
this.headerScript.append(KVBuffer.getList(keyName, WebUtil.fetch(request, "sys.tenancyId")));
}
}
}

View File

@@ -0,0 +1,134 @@
package com.wb.controls;
import java.util.ArrayList;
import java.util.Set;
import java.util.Map.Entry;
import org.json.JSONObject;
import com.wb.util.StringUtil;
import com.wb.util.WebUtil;
/**
* HTML控件的解析类。
*/
public class HtmlControl extends ScriptControl {
public void create() throws Exception {
String html, tag = StringUtil.select(gs("tagType"), (String) generalMeta.opt("type"));
StringBuilder tagEnd = new StringBuilder(tag.length() + 3);
String value, glyph, xtype = (String) generalMeta.opt("xtype");
tagEnd.append("</").append(tag).append(">");
ArrayList<String> classList = new ArrayList<String>();
ArrayList<String> styleList = new ArrayList<String>();
// tag开始
headerHtml.append('<');
headerHtml.append(tag);
if (xtype != null) {
// xtype在html控件中定义为固定的输出项
headerHtml.append(' ');
headerHtml.append(xtype);
}
// 初始化baseClass
value = generalMeta.optString("baseClass");
if (!value.isEmpty())
classList.add(value);
// 输出配置项
processConfigs(classList, styleList);
// 添加合并的class
value = gs("class");
if (!value.isEmpty())
classList.add(value);
value = StringUtil.join(classList, " ");
if (!value.isEmpty()) {
headerHtml.append(" class=\"");
headerHtml.append(value);
headerHtml.append('"');
}
// 添加合并的style
value = gs("style");
if (!value.isEmpty())
styleList.add(value);
value = StringUtil.join(styleList, ";");
if (!value.isEmpty()) {
headerHtml.append(" style=\"");
headerHtml.append(value);
if (!value.endsWith(";"))
headerHtml.append(';');
headerHtml.append('"');
}
// tag结尾
headerHtml.append('>');
// glyph图标
glyph = gs("glyph");
if (!glyph.isEmpty()) {
headerHtml.append("<span class=\"wb_glyph\">&#" + Integer.valueOf(glyph, 16) + ";</span> ");
}
// text为短html
html = gs("text");
if (!html.isEmpty())
headerHtml.append(html);
html = gs("html");
if (!html.isEmpty())
headerHtml.append(html);
if (!Boolean.FALSE.equals(generalMeta.opt("tagEnd")))
footerHtml.insert(0, tagEnd);
}
/**
* 处理配置项。
* @param classList class属性列表。
* @param styleList style属性列表。
*/
protected void processConfigs(ArrayList<String> classList, ArrayList<String> styleList) {
char firstChar;
String key, value, rename, type, tagItems, group;
JSONObject itemObject;
Set<Entry<String, Object>> es = configs.entrySet();
boolean hasGroup = classList != null && styleList != null;
for (Entry<String, Object> entry : es) {
key = entry.getKey();
value = (String) entry.getValue();
itemObject = (JSONObject) configsMeta.opt(key);
if (itemObject == null)
continue;
else {
if (Boolean.TRUE.equals(itemObject.opt("hidden")))
continue;
rename = (String) itemObject.opt("rename");
if (rename != null)
key = rename;
if (hasGroup) {
group = (String) itemObject.opt("group");
if (group != null) {
if ("class".equals(group))
classList.add(value);
else
styleList.add(StringUtil.concat(key, ":", value));
continue;
}
}
}
headerHtml.append(' ');
headerHtml.append(key);
headerHtml.append('=');
firstChar = value.charAt(0);
if (firstChar == '@') {
headerHtml.append(WebUtil.replaceParams(request, value.substring(1)));
} else {
type = (String) itemObject.opt("type");
if (type.startsWith("exp")) {
headerHtml.append(WebUtil.replaceParams(request, value));
} else {
headerHtml.append(StringUtil.quote(WebUtil.replaceParams(request, value)));
}
}
}
tagItems = gs("tagConfigs");
if (!tagItems.isEmpty()) {
headerHtml.append(' ');
headerHtml.append(tagItems);
}
}
}

View File

@@ -0,0 +1,20 @@
package com.wb.controls;
/**
* 发送邮件控件。
*/
public class Mailer extends Control {
public void create() throws Exception {
if (gb("disabled", false))
return;
com.wb.tool.MailSender mailSender = new com.wb.tool.MailSender(gs("smtp"), gs("username"),
gs("password"), gb("needAuth", true));
try {
mailSender.send(gs("from"), gs("to"), gs("cc"), gs("bcc"),
gs("title"), gs("content"), gs("attachFiles"), request,
gs("attachObjects"), gs("attachObjectNames"));
} finally {
mailSender.close();
}
}
}

View File

@@ -0,0 +1,13 @@
package com.wb.controls;
import com.wb.util.SysUtil;
/**
* 动态调用指定的方法。
*/
public class Method extends com.wb.controls.Control {
public void create() throws Exception {
String method = gs("method");
SysUtil.executeMethod(method, request, response);
}
}

View File

@@ -0,0 +1,61 @@
package com.wb.controls;
import java.sql.ResultSet;
import java.util.HashMap;
import java.util.Map.Entry;
import java.util.Set;
import com.wb.common.Var;
import com.wb.tool.Query;
import com.wb.util.DbUtil;
import com.wb.util.StringUtil;
/**
* 数据库SQL执行控件{@link Query}
*/
public class QueryControl extends com.wb.controls.Control {
public void create() throws Exception {
if (gb("disabled", false))
return;
Query query;
Object result;
boolean isHashMap;
String name, itemId = gs("itemId");
query = new Query();
query.sql = gs("sql");
query.request = request;
query.jndi = gs("jndi");
query.arrayName = gs("arrayName");
query.batchUpdate = gb("batchUpdate", Var.batchUpdate);
query.type = gs("type");
query.errorText = gs("errorText");
query.transaction = gs("transaction");
query.loadParams = gs("loadParams");
query.isolation = gs("isolation");
query.uniqueUpdate = gb("uniqueUpdate", false);
result = query.run();
isHashMap = result instanceof HashMap<?, ?>;
// 如果是hashmap表明含输出参数在下面设置值
if (!isHashMap)
request.setAttribute(itemId, result);
if (result instanceof ResultSet) {
if (gb("loadData", false))
DbUtil.loadFirstRow(request, (ResultSet) result, itemId);
} else if (isHashMap) {
HashMap<?, ?> map = (HashMap<?, ?>) result;
Set<?> es = map.entrySet();
Entry<?, ?> entry;
for (Object e : es) {
entry = (Entry<?, ?>) e;
name = (String) entry.getKey();
// 在hashmap中返回值名称为return
if (name.equals("return"))
name = itemId;
else
name = StringUtil.concat(itemId, ".", name);
request.setAttribute(name, entry.getValue());
}
}
}
}

View File

@@ -0,0 +1,25 @@
package com.wb.controls;
import java.util.Set;
import java.util.Map.Entry;
import com.wb.util.WebUtil;
/**
* 用于把指定文本内容发送到客户端。控件将把第一个字符串发送到客户端。
*/
public class Response extends com.wb.controls.Control {
public void create() throws Exception {
String key;
Set<Entry<String, Object>> es = configs.entrySet();
for (Entry<String, Object> entry : es) {
key = entry.getKey();
if (key.equals("itemId"))
continue;
WebUtil.send(response, WebUtil.replaceParams(request,
(String) entry.getValue()));
return;
}
}
}

View File

@@ -0,0 +1,51 @@
package com.wb.controls;
/**
* 产生客户端脚本的控件基类。如果控件产生客户端脚本可继承此类。
*/
public class ScriptControl extends com.wb.controls.Control {
/** 上下文中的HTML头脚本 **/
protected StringBuilder headerHtml = new StringBuilder();
/** 上下文中的HTML尾脚本 **/
protected StringBuilder footerHtml = new StringBuilder();
/** 上下文中的JS头脚本 **/
protected StringBuilder headerScript = new StringBuilder();
/** 上下文中的JS尾脚本 **/
protected StringBuilder footerScript = new StringBuilder();
/**
* 获取控件生成的HTML头脚本。
*
* @return 生成的脚本。
*/
public String getHeaderHtml() {
return headerHtml.toString();
}
/**
* 获取控件生成的HTML尾脚本。
*
* @return 生成的脚本。
*/
public String getFooterHtml() {
return footerHtml.toString();
}
/**
* 获取控件生成的JS头脚本。
*
* @return 生成的脚本。
*/
public String getHeaderScript() {
return headerScript.toString();
}
/**
* 获取控件生成的JS尾脚本。
*
* @return 生成的脚本。
*/
public String getFooterScript() {
return footerScript.toString();
}
}

View File

@@ -0,0 +1,35 @@
package com.wb.controls;
import org.json.JSONObject;
import com.wb.common.ScriptBuffer;
/**
* 服务器端脚本控件用以使用JavaScript语法执行Java代码。
*/
public class ServerScript extends Control {
public void create() throws Exception {
String script = getScript(configs, "script");
if (!script.isEmpty())
ScriptBuffer.run(gs("id"), script, request, response, gs("sourceURL"));
}
/**
* 获取对象中指定名称的。
* @param object JSNObject对象。
* @param name 名称。
* @return 获取的值。如果值为空返回空字符串。
*/
public static String getScript(JSONObject object, String name) {
Object value = object.opt(name);
if (value == null)
return "";
else {
String script = (String) value;
if (script.indexOf("{#") != -1)
throw new IllegalArgumentException(
"ServerScript does not support {#param#} feature, please use app.get(param) instead.");
return script;
}
}
}

View File

@@ -0,0 +1,16 @@
package com.wb.controls;
import com.wb.common.Var;
public class SqlSwitcher extends com.wb.controls.Control {
public void create() throws Exception {
String sql, varName = gs("varName");
// 数据库类型由varName属性指定如果为空使用defaultType变量指定类型
sql = gs(Var.getString(varName.isEmpty() ? "sys.db.defaultType"
: varName));
if (sql.isEmpty())
sql = gs("default");
request.setAttribute(gs("itemId"), sql);
}
}

View File

@@ -0,0 +1,207 @@
package com.wb.controls;
import com.wb.util.StringUtil;
import com.wb.util.WebUtil;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.Map.Entry;
import java.util.Set;
/**
* HTML控件的解析类。
*/
public class SupcanControl extends ScriptControl {
public void create() throws Exception {
String html, tag = StringUtil.select(gs("tagType"), (String) generalMeta.opt("type"));
StringBuilder tagEnd = new StringBuilder(tag.length() + 3);
String value, glyph, xtype = (String) generalMeta.opt("xtype");
tagEnd.append("</").append(tag).append(">");
ArrayList<String> classList = new ArrayList<String>();
ArrayList<String> styleList = new ArrayList<String>();
headerScript.append("\n" +
"var opt = Wb.getUuid();"+
"window.OnReady= function(id){\n" +
" var fun ='init'+id;\n" +
" \tif(window[fun]){\n" +
" window[fun](id);\n" +
" }\n" +
" };\n" +
" window.OnEvent= function(id, Event, p1, p2, p3, p4){\n" +
" var fun ='event'+id;\n" +
" \tif(window[fun]){\n" +
" window[fun](id, Event, p1, p2, p3, p4);\n" +
" }\n" +
" };\n" +
"");
footerScript.append("var mt1 = bldStr(\"BCV1.TreeList\", opt, \"Hue=LightGray\", \"100%\");\n" +
"app.{@pansupcan@}.update(mt1);\n" +
"window[\"init\" + opt] = function(id) {\n" +
" var m = document.getElementById(opt);\n" +
" if (id == opt) {\n" +
" m.func(\"Build\", '{@headurl@}?' + Math.round(Math.random() * 100)+'\\r\\n editable={@editable@}');\n" +
" //在第一列位置插入新列\n" +
" m.func(\"InsertCol\", \"0\\r\\nname=checked;isCheckboxOnly=true\");\n" +
" m.func(\"DisableMenu\", \"showRuler,exportAll,printAll,delete,insert,import ,curselMode,hue ,language , enter \\r\\n true\");\n" +
" m.func(\"EnableMenu\", \" curselMode \\r\\n true\");\n" +
" m.func('Load', Wb.loadSupcanData('{@dataurl@}',''));\n" +
" }\n" +
"};");
// tag开始
headerHtml.append('<');
headerHtml.append(tag);
if (xtype != null) {
// xtype在html控件中定义为固定的输出项
headerHtml.append(' ');
headerHtml.append(xtype);
}
// 初始化baseClass
value = generalMeta.optString("baseClass");
if (!value.isEmpty())
classList.add(value);
// 输出配置项
processConfigs(classList, styleList);
// 添加合并的class
value = gs("class");
if (!value.isEmpty())
classList.add(value);
value = StringUtil.join(classList, " ");
if (!value.isEmpty()) {
headerHtml.append(" class=\"");
headerHtml.append(value);
headerHtml.append('"');
}
// 添加合并的style
value = gs("style");
if (!value.isEmpty())
styleList.add(value);
value = StringUtil.join(styleList, ";");
if (!value.isEmpty()) {
headerHtml.append(" style=\"");
headerHtml.append(value);
if (!value.endsWith(";"))
headerHtml.append(';');
headerHtml.append('"');
}
// tag结尾
headerHtml.append('>');
// glyph图标
glyph = gs("glyph");
if (!glyph.isEmpty()) {
headerHtml.append("<span class=\"wb_glyph\">&#" + Integer.valueOf(glyph, 16) + ";</span> ");
}
// text为短html
html = gs("text");
if (!html.isEmpty())
headerHtml.append(html);
html = gs("html");
if (!html.isEmpty())
headerHtml.append(html);
if (!Boolean.FALSE.equals(generalMeta.opt("tagEnd")))
footerHtml.insert(0, tagEnd);
}
/**
* 实现StringBuilder的replaceAll
*
* @param stb
* @param oldStr 被替换的字符串
* @param newStr 替换oldStr
* @return
*/
public StringBuilder replaceAll(StringBuilder stb, String oldStr, String newStr) {
if (stb == null || oldStr == null || newStr == null || stb.length() == 0 || oldStr.length() == 0)
return stb;
int index = stb.indexOf(oldStr);
if (index > -1 && !oldStr.equals(newStr)) {
int lastIndex = 0;
while (index > -1) {
stb.replace(index, index + oldStr.length(), newStr);
lastIndex = index + newStr.length();
index = stb.indexOf(oldStr, lastIndex);
}
}
return stb;
}
/**
* 处理配置项。
* @param classList class属性列表。
* @param styleList style属性列表。
*/
protected void processConfigs(ArrayList<String> classList, ArrayList<String> styleList) {
char firstChar;
String key, value, rename, type, tagItems, group;
JSONObject itemObject;
Set<Entry<String, Object>> es = configs.entrySet();
boolean hasGroup = classList != null && styleList != null;
for (Entry<String, Object> entry : es) {
key = entry.getKey();
value = (String) entry.getValue();
if(key.equals("headurl")){
footerScript=replaceAll(footerScript,"{@headurl@}",value);
}
if(key.equals("dataurl")){
footerScript=replaceAll(footerScript,"{@dataurl@}",value);
}
if(key.equals("panelsupcan")){
footerScript=replaceAll(footerScript,"{@pansupcan@}",value);
}
if(key.equals("editable")){
footerScript=replaceAll(footerScript,"{@editable@}",value);
}
itemObject = (JSONObject) configsMeta.opt(key);
if (itemObject == null)
continue;
else {
if (Boolean.TRUE.equals(itemObject.opt("hidden")))
continue;
rename = (String) itemObject.opt("rename");
if (rename != null)
key = rename;
if (hasGroup) {
group = (String) itemObject.opt("group");
if (group != null) {
if ("class".equals(group))
classList.add(value);
else
styleList.add(StringUtil.concat(key, ":", value));
continue;
}
}
}
headerHtml.append(' ');
headerHtml.append(key);
headerHtml.append('=');
firstChar = value.charAt(0);
if (firstChar == '@') {
headerHtml.append(WebUtil.replaceParams(request, value.substring(1)));
} else {
type = (String) itemObject.opt("type");
if (type.startsWith("exp")) {
headerHtml.append(WebUtil.replaceParams(request, value));
} else {
headerHtml.append(StringUtil.quote(WebUtil.replaceParams(request, value)));
}
}
}
tagItems = gs("tagConfigs");
if (!tagItems.isEmpty()) {
headerHtml.append(' ');
headerHtml.append(tagItems);
}
}
}

View File

@@ -0,0 +1,213 @@
package com.wb.controls;
import com.wb.util.StringUtil;
import com.wb.util.WebUtil;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.Map.Entry;
import java.util.Set;
/**
* HTML控件的解析类。
*/
public class SupcanReportControl extends ScriptControl {
public void create() throws Exception {
String html, tag = StringUtil.select(gs("tagType"), (String) generalMeta.opt("type"));
StringBuilder tagEnd = new StringBuilder(tag.length() + 3);
String value, glyph, xtype = (String) generalMeta.opt("xtype");
tagEnd.append("</").append(tag).append(">");
ArrayList<String> classList = new ArrayList<String>();
ArrayList<String> styleList = new ArrayList<String>();
headerScript.append("\n" +
"var opt = Wb.getUuid();"+
"window.OnReady= function(id){\n" +
" var fun ='init'+id;\n" +
" \tif(window[fun]){\n" +
" window[fun](id);\n" +
" }\n" +
" };\n" +
" window.OnEvent= function(id, Event, p1, p2, p3, p4){\n" +
" var fun ='event'+id;\n" +
" \tif(window[fun]){\n" +
" window[fun](id, Event, p1, p2, p3, p4);\n" +
" }\n" +
" };\n" +
"");
footerScript.append("var mt1 = bldStr(\"LuxForm\", opt, \"\", \"100%\");\n" +
"app.{@pansupcan@}.update(mt1);\n" +
"\n" +
"window[\"init\" + opt] = function(id) {\n" +
" var m = document.getElementById(opt);\n" +
" //console.log(m);\n" +
" if (id == opt) {\n" +
" m.func(\"setCookie\", \"JSESSIONID="+request.getRequestedSessionId()+"\");\n" +
" m.func(\"Build\", '{@templateurl@}?' + Math.round(Math.random() * 100));\n" +
" m.func(\"DisableMenu\", \"showRuler,exportAll,printAll,delete,insert,import ,curselMode,hue ,language , enter \\r\\n true\");\n" +
" //中心数据源\n" +
" m.func(\"SetSource\", \"{@dataurl@}\");\n" +
" m.func(\"Calc\", \"\");"+
" }\n" +
"};");
// tag开始
headerHtml.append('<');
headerHtml.append(tag);
if (xtype != null) {
// xtype在html控件中定义为固定的输出项
headerHtml.append(' ');
headerHtml.append(xtype);
}
// 初始化baseClass
value = generalMeta.optString("baseClass");
if (!value.isEmpty())
classList.add(value);
// 输出配置项
processConfigs(classList, styleList);
// 添加合并的class
value = gs("class");
if (!value.isEmpty())
classList.add(value);
value = StringUtil.join(classList, " ");
if (!value.isEmpty()) {
headerHtml.append(" class=\"");
headerHtml.append(value);
headerHtml.append('"');
}
// 添加合并的style
value = gs("style");
if (!value.isEmpty())
styleList.add(value);
value = StringUtil.join(styleList, ";");
if (!value.isEmpty()) {
headerHtml.append(" style=\"");
headerHtml.append(value);
if (!value.endsWith(";"))
headerHtml.append(';');
headerHtml.append('"');
}
// tag结尾
headerHtml.append('>');
// glyph图标
glyph = gs("glyph");
if (!glyph.isEmpty()) {
headerHtml.append("<span class=\"wb_glyph\">&#" + Integer.valueOf(glyph, 16) + ";</span> ");
}
// text为短html
html = gs("text");
if (!html.isEmpty())
headerHtml.append(html);
html = gs("html");
if (!html.isEmpty())
headerHtml.append(html);
if (!Boolean.FALSE.equals(generalMeta.opt("tagEnd")))
footerHtml.insert(0, tagEnd);
}
/**
* 实现StringBuilder的replaceAll
*
* @param stb
* @param oldStr 被替换的字符串
* @param newStr 替换oldStr
* @return
*/
public StringBuilder replaceAll(StringBuilder stb, String oldStr, String newStr) {
if (stb == null || oldStr == null || newStr == null || stb.length() == 0 || oldStr.length() == 0)
return stb;
int index = stb.indexOf(oldStr);
if (index > -1 && !oldStr.equals(newStr)) {
int lastIndex = 0;
while (index > -1) {
stb.replace(index, index + oldStr.length(), newStr);
lastIndex = index + newStr.length();
index = stb.indexOf(oldStr, lastIndex);
}
}
return stb;
}
/**
* 处理配置项。
* @param classList class属性列表。
* @param styleList style属性列表。
*/
protected void processConfigs(ArrayList<String> classList, ArrayList<String> styleList) {
char firstChar;
String key, value, rename, type, tagItems, group;
JSONObject itemObject;
Set<Entry<String, Object>> es = configs.entrySet();
boolean hasGroup = classList != null && styleList != null;
for (Entry<String, Object> entry : es) {
key = entry.getKey();
value = (String) entry.getValue();
if(key.equals("templateurl")){
footerScript=replaceAll(footerScript,"{@templateurl@}",value);
}
if(key.equals("dataurl")){
if(value.equals("")){
footerScript=replaceAll(footerScript,"{@dataurl@}","m?xwl=common/report/reportTemplate/dataSource");
}else
footerScript=replaceAll(footerScript,"{@dataurl@}",value);
}
if(key.equals("panelsupcan")){
footerScript=replaceAll(footerScript,"{@pansupcan@}",value);
}
if(key.equals("editable")){
footerScript=replaceAll(footerScript,"{@editable@}",value);
}
itemObject = (JSONObject) configsMeta.opt(key);
if (itemObject == null)
continue;
else {
if (Boolean.TRUE.equals(itemObject.opt("hidden")))
continue;
rename = (String) itemObject.opt("rename");
if (rename != null)
key = rename;
if (hasGroup) {
group = (String) itemObject.opt("group");
if (group != null) {
if ("class".equals(group))
classList.add(value);
else
styleList.add(StringUtil.concat(key, ":", value));
continue;
}
}
}
headerHtml.append(' ');
headerHtml.append(key);
headerHtml.append('=');
firstChar = value.charAt(0);
if (firstChar == '@') {
headerHtml.append(WebUtil.replaceParams(request, value.substring(1)));
} else {
type = (String) itemObject.opt("type");
if (type.startsWith("exp")) {
headerHtml.append(WebUtil.replaceParams(request, value));
} else {
headerHtml.append(StringUtil.quote(WebUtil.replaceParams(request, value)));
}
}
}
tagItems = gs("tagConfigs");
if (!tagItems.isEmpty()) {
headerHtml.append(' ');
headerHtml.append(tagItems);
}
}
}

View File

@@ -0,0 +1,23 @@
package com.wb.controls;
import com.wb.common.KVBuffer;
import com.wb.util.WebUtil;
/**
* Touch Select控件的解析类。
*/
public class TSelect extends com.wb.controls.ExtControl {
protected void extendConfig() {
String keyName = gs("keyName");
if (!keyName.isEmpty()) {
if (hasItems)
headerScript.append(',');
else
hasItems = true;
headerScript
.append("displayField:\"V\",valueField:\"K\",store:{fields:[\"K\",\"V\"],sorters:\"K\",data:");
headerScript.append(KVBuffer.getList(keyName, WebUtil.fetch(request, "sys.tenancyId")));
headerScript.append('}');
}
}
}

View File

@@ -0,0 +1,19 @@
package com.wb.controls;
public class TViewport extends com.wb.controls.ScriptControl {
public void create() throws Exception {
if (normalRunType) {
// 属性在Ext.Setup中设置
headerScript.append("this.add([");
footerScript.insert(0, "]);");
} else {
// 把TViewport转换为Container处理
com.wb.controls.ExtControl control = new com.wb.controls.ExtControl();
control.init(request, response, controlData, controlMeta,
parentGeneral, lastNode, normalRunType);
control.create();
headerScript.append(control.getHeaderScript());
footerScript.insert(0, control.getFooterScript());
}
}
}

View File

@@ -0,0 +1,27 @@
package com.wb.controls;
import java.util.Map.Entry;
import java.util.Set;
import com.wb.util.StringUtil;
/**
* 用于存储大段的文本。控件将把第一个字符串属性存储到以name为名称的request attribute中。
*/
public class Text extends Control {
public void create() throws Exception {
String key, text;
Set<Entry<String, Object>> es = configs.entrySet();
for (Entry<String, Object> entry : es) {
key = entry.getKey();
if (key.equals("itemId") || key.equals("quoted"))
continue;
text = gs(key);
if (gb("quoted"))
text = StringUtil.text(text);
request.setAttribute(gs("itemId"), text);
return;
}
}
}

View File

@@ -0,0 +1,39 @@
package com.wb.controls;
import org.json.JSONObject;
import com.wb.common.Var;
/**
* 上下文绑定的数据库更新控件,见:{@link com.wb.tool.Updater}
*/
public class UpdaterControl extends com.wb.controls.Control {
public void create() throws Exception {
if (gb("disabled", false))
return;
com.wb.tool.Updater updater = new com.wb.tool.Updater();
String value;
updater.request = request;
updater.jndi = gs("jndi");
updater.tableName = gs("tableName");
updater.transaction = gs("transaction");
updater.isolation = gs("isolation");
updater.type = gs("type");
updater.batchUpdate = gb("batchUpdate", Var.batchUpdate);
updater.uniqueUpdate = gb("uniqueUpdate", true);
updater.sqlDelete = gs("sqlDelete");
updater.sqlInsert = gs("sqlInsert");
updater.sqlUpdate = gs("sqlUpdate");
updater.paramDelete = gs("paramDelete");
updater.paramInsert = gs("paramInsert");
updater.paramUpdate = gs("paramUpdate");
updater.whereFields = gs("whereFields");
updater.useExistFields = gb("useExistFields", true);
updater.mode = gs("mode");
value = gs("fieldsMap");
updater.fieldsMap = value.isEmpty() ? null : new JSONObject(value);
updater.ignoreBlob = gb("ignoreBlob", false);
updater.run();
}
}

View File

@@ -0,0 +1,358 @@
package com.wb.interact;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.json.JSONArray;
import org.json.JSONObject;
import com.wb.util.SysUtil;
import com.wb.util.WebUtil;
/**
* 控件管理器后台部分应用。
*/
public class Controls {
/**
* 控件的缓存HashMap。
* */
private static ConcurrentHashMap<String, JSONObject> buffer;
/**
* 控件文件。
*/
private static final File file = new File(com.wb.common.Base.path,
"wb/system/controls.json");
/**
* 读取指定控件的数据,并发送至客户端。
*
* @param request
* 请求对象。
* @param response
* 响应对象。
* @throws Exception
* 处理过程中发生异常。
*/
public static void open(HttpServletRequest request,
HttpServletResponse response) throws Exception {
JSONObject json = com.wb.util.JsonUtil.readObject(file), control;
JSONArray data = new JSONArray(), nodes = new JSONArray(request
.getParameter("controls"));
int i, j = nodes.length();
String id;
for (i = 0; i < j; i++) {
id = nodes.getString(i);
control = com.wb.util.JsonUtil.findObject(json, "children", "id", id);
if (control == null)
throw new IOException("\"" + id + "\" 没有找到。");
data.put(control);
}
WebUtil.send(response, data);
}
/**
* 获取控件树数据,并发送到客户端。
*
* @param request
* 请求对象。
* @param response
* 响应对象。
* @throws Exception
* 处理过程中发生异常。
*/
public static void getControlTree(HttpServletRequest request,
HttpServletResponse response) throws Exception {
JSONObject json = com.wb.util.JsonUtil.readObject(file);
if ("ide".equals(request.getParameter("type")))
setControlNode(json);
WebUtil.send(response, json);
}
/**
* IDE模式下设置控件节点为目录节点并标识控件control属性为true。
*
* @param node
* 需要设置的控件。
*/
private static void setControlNode(JSONObject node) {
if (node.has("leaf")) {
node.remove("leaf");
node.put("type", node.get("id"));
node.put("control", true);
node.put("children", new JSONArray());
} else {
JSONArray children = node.getJSONArray("children");
int i, j = children.length();
for (i = 0; i < j; i++)
setControlNode(children.getJSONObject(i));
}
}
/**
* 在当前的目录结构中添加控件。
*
* @param request
* 请求对象。
* @param response
* 响应对象。
* @throws Exception
* 添加过程中发生异常。
*/
public static synchronized void addControl(HttpServletRequest request,
HttpServletResponse response) throws Exception {
JSONObject json = com.wb.util.JsonUtil.readObject(file), newNode, parentNode;
JSONArray children;
String name = request.getParameter("name");
String parent = request.getParameter("parent");
String selNode = request.getParameter("selNode");
String folderId = "";
boolean isFolder = Boolean.parseBoolean(request
.getParameter("isFolder"));
folderId = com.wb.util.StringUtil.concat("n", SysUtil.getId());
if (com.wb.util.JsonUtil.findObject(json, "children", "id", isFolder ? folderId
: name) != null)
throw new IOException("名称 \"" + name + "\" 已经存在。");
parentNode = com.wb.util.JsonUtil.findObject(json, "children", "id", parent);
newNode = new JSONObject();
newNode.put("text", name);
if (isFolder) {
newNode.put("id", folderId);
newNode.put("children", new JSONArray());
} else {
newNode.put("id", name);
newNode.put("iconCls", "item_icon");
newNode.put("leaf", true);
newNode.put("general", new JSONObject("{iconCls:'item_icon'}"));
newNode.put("configs", new JSONObject("{itemId:{type:'string'}}"));
newNode.put("events", new JSONObject());
}
children = parentNode.getJSONArray("children");
if (selNode.isEmpty())
children.put(newNode);
else {
JSONObject node = com.wb.util.JsonUtil.findObject(json, "children", "id",
selNode);
int index = children.indexOf(node);
children.add(++index, newNode);
}
save(json);
if (!isFolder)
buffer.put("name", new JSONObject(newNode.toString()));
WebUtil.send(response, folderId);
}
/**
* 保存一个或多个指定的控件。
*
* @param request
* 请求对象。
* @param response
* 响应对象。
* @throws Exception
* 保存过程中发生异常。
*/
public static synchronized void saveControls(HttpServletRequest request,
HttpServletResponse response) throws Exception {
JSONObject json = com.wb.util.JsonUtil.readObject(file), control;
JSONArray nodes = new JSONArray(com.wb.util.StringUtil.getString(request
.getInputStream()));
int i, j = nodes.length();
String id;
for (i = 0; i < j; i++) {
control = nodes.getJSONObject(i);
id = control.getString("id");
if (!com.wb.util.JsonUtil.replace(json, "children", "id", id, control
.get("data")))
throw new IOException("\"" + id + "\" 没有找到。");
}
save(json);
for (i = 0; i < j; i++) {
control = nodes.getJSONObject(i);
buffer.put(control.getString("id"), new JSONObject(control.get(
"data").toString()));
}
}
/**
* 对控件目录名称进行重命名。
*
* @param request
* 请求对象。
* @param response
* 响应对象。
* @throws Exception
* 重命名过程中发生异常。
*/
public static synchronized void renameFolder(HttpServletRequest request,
HttpServletResponse response) throws Exception {
JSONObject json = com.wb.util.JsonUtil.readObject(file);
String id = request.getParameter("id");
JSONObject folder = com.wb.util.JsonUtil.findObject(json, "children", "id", id);
if (folder == null)
throw new IOException("目录 \"" + id + "\" 已经被删除。");
folder.put("text", request.getParameter("newName"));
save(json);
}
/**
* 删除控件或目录。
*
* @param request
* 请求对象。
* @param response
* 响应对象。
* @throws Exception
* 删除过程中发生异常。
*/
public static synchronized void deleteControls(HttpServletRequest request,
HttpServletResponse response) throws Exception {
JSONObject json = com.wb.util.JsonUtil.readObject(file);
JSONArray nodes = new JSONArray(request.getParameter("controls"));
int i, j = nodes.length();
for (i = 0; i < j; i++)
com.wb.util.JsonUtil.remove(json, "children", "id", nodes.getString(i));
save(json);
buffer.clear();
saveToBuffer(json);
}
/**
* 移动控件或目录。
*
* @param request
* 请求对象。
* @param response
* 响应对象。
* @throws Exception
* 移动过程中发生异常。
*/
public static synchronized void moveControls(HttpServletRequest request,
HttpServletResponse response) throws Exception {
JSONObject json = com.wb.util.JsonUtil.readObject(file);
JSONArray sourceNodes = new JSONArray(request
.getParameter("sourceNodes")), destChildren, parentNode;
String destNodeId = request.getParameter("destNode");
JSONObject destNode = com.wb.util.JsonUtil.findObject(json, "children", "id",
destNodeId);
String id, movedNode, dropPosition = request
.getParameter("dropPosition");
int i, j = sourceNodes.length(), index;
for (i = 0; i < j; i++) {
id = sourceNodes.getString(i);
movedNode = com.wb.util.JsonUtil.remove(json, "children", "id", id);
if (dropPosition.equals("append")) {
destChildren = destNode.getJSONArray("children");
destChildren.put(new JSONObject(movedNode));
} else {
parentNode = com.wb.util.JsonUtil.findArray(json, "children", "id",
destNodeId);
index = parentNode.indexOf(destNode);
if (dropPosition.equals("after"))
index++;
parentNode.add(index, new JSONObject(movedNode));
}
}
save(json);
}
/**
* 复制控件。
*
* @param request
* 请求对象。
* @param response
* 响应对象。
* @throws Exception
* 复制过程中发生异常。
*/
public static synchronized void copyControl(HttpServletRequest request,
HttpServletResponse response) throws Exception {
JSONObject json = com.wb.util.JsonUtil.readObject(file), control, newControl;
String source = request.getParameter("source");
String dest = request.getParameter("dest");
control = com.wb.util.JsonUtil.findObject(json, "children", "id", source);
if (control == null)
throw new IOException("控件 \"" + source + "\" 没有找到。");
if (com.wb.util.JsonUtil.findObject(json, "children", "id", dest) != null)
throw new IOException("名称 \"" + dest + "\" 已经存在。");
JSONArray parentNode = com.wb.util.JsonUtil.findArray(json, "children", "id",
source);
int index = parentNode.indexOf(control);
newControl = new JSONObject(control.toString()).put("id", dest).put(
"text", dest);
parentNode.add(index + 1, newControl);
save(json);
buffer.put("name", new JSONObject(newControl.toString()));
}
/**
* 获取缓存中指定控件的数据。
*
* @param id
* 控件id编号。
* @return 控件数据。
* @throws IOException
* 控件没有找到。
*/
public static JSONObject get(String id) throws IOException {
JSONObject object = buffer.get(id);
if (object == null)
throw new IOException("控件 \"" + id + "\" 没有找到。");
return object;
}
/**
* 保存控件文件的数据至控件文件。
*
* @param json
* 控件文件数据。
* @throws Exception
* 保存过程中发生异常。
*/
private static void save(JSONObject json) throws Exception {
com.wb.util.FileUtil.syncSave(file, json.toString());
}
/**
* 加载和初始化。
*/
public static synchronized void load() {
try {
buffer = new ConcurrentHashMap<String, JSONObject>();
saveToBuffer(new JSONObject(com.wb.util.FileUtil.readString(file)));
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
/**
* 把控件文件中的所有控件缓存到HashMap中。
*
* @param json 控件文件的数据。
*/
private static void saveToBuffer(JSONObject json) {
JSONArray ja = json.getJSONArray("children");
JSONObject jo;
int i, j = ja.length();
for (i = 0; i < j; i++) {
jo = ja.getJSONObject(i);
if (jo.optBoolean("leaf"))
buffer.put(jo.getString("id"), new JSONObject(jo.toString()));
else
saveToBuffer(jo);
}
}
}

View File

@@ -0,0 +1,273 @@
package com.wb.interact;
import java.io.File;
import java.sql.Connection;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map.Entry;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.json.JSONArray;
import org.json.JSONObject;
import com.wb.util.WebUtil;
public class DBE {
/**
* 获取数据库表树数据。
*/
public static void getTree(HttpServletRequest request, HttpServletResponse response) throws Exception {
String type = request.getParameter("type");
String jndi = request.getParameter("jndi");
String schema = request.getParameter("schema");
String result;
if ("db".equals(type)) {
result = getSchemaList(jndi, null);
//如果没有Schema直接返回表列表
if (result == null)
result = getTableList(jndi, null, null);
} else if ("schema".equals(type))
result = getTableList(jndi, schema, null);
else
result = getDbList();
WebUtil.send(response, result);
}
/**
* 如果用户包含演示角色且非管理员SQL语句仅允许执行select * from table否则抛出异常。
*/
public static void checkSelectSql(HttpServletRequest request, HttpServletResponse response) throws Exception {
String sql = request.getParameter("sql");
String roles[] = (String[]) WebUtil.fetchObject(request, "sys.roles");
if (com.wb.util.StringUtil.indexOf(roles, "demo") != -1 && com.wb.util.StringUtil.indexOf(roles, "admin") == -1
&& (!sql.startsWith("select * from ") || !com.wb.util.StringUtil.checkName(sql.substring(14), true)
|| sql.substring(14).equalsIgnoreCase("WB_USER")))
com.wb.util.SysUtil.accessDenied();
}
/**
* 从变量sys.jndi节点获得所有配置的jndi并生成树组件脚本。
*/
public static String getDbList() throws Exception {
JSONObject config = com.wb.util.JsonUtil.readObject(new File(com.wb.common.Base.path, "wb/system/var.json"));
HashMap<String, Object> map = new HashMap<String, Object>();
ArrayList<Entry<String, Object>> sortedItems;
config = config.optJSONObject("sys").optJSONObject("jndi");
Set<Entry<String, Object>> es = config.entrySet();
String key;
JSONObject jo;
JSONArray ja = new JSONArray();
// 默认jndi插入到首行
config.remove("default");
for (Entry<String, Object> e : es) {
key = e.getKey();
map.put(key, ((JSONArray) e.getValue()).optString(0));
}
sortedItems = com.wb.util.SortUtil.sortKey(map);
jo = new JSONObject();
jo.put("text", "default");
jo.put("jndi", "default");
jo.put("type", "db");
jo.put("iconCls", "db_icon");
ja.put(jo);
for (Entry<String, Object> e : sortedItems) {
jo = new JSONObject();
jo.put("text", e.getKey());
jo.put("jndi", e.getKey());
jo.put("type", "db");
jo.put("iconCls", "db_icon");
ja.put(jo);
}
return ja.toString();
}
/**
* 获取指定jndi所有数据库表JSON脚本。
* @param jndi jndi名称。
* @param schema 表Schema。
* @param tables 已经配置的表定义。
* @return 表列表JSON脚本。
*/
public static String getTableList(String jndi, String schema, HashSet<String> tables) throws Exception {
Connection conn = null;
ResultSet rs = null;
boolean isFirst = true, hasTableDefine = tables != null;
String types[] = { "TABLE" }, tableSchema, tableName, tableText, upperTableName,
jndiText = com.wb.util.StringUtil.quote(jndi);
StringBuilder buf = new StringBuilder();
ArrayList<Entry<String, String>> sortedEntries;
HashMap<String, String> tableMap = new HashMap<String, String>();
try {
conn = com.wb.util.DbUtil.getConnection(jndi);
rs = conn.getMetaData().getTables(null, schema, null, types);
while (rs.next()) {
tableSchema = com.wb.util.StringUtil.opt(rs.getString(2));
tableName = rs.getString(3);
tableMap.put(tableName, tableSchema);
}
sortedEntries = com.wb.util.SortUtil.sortKey(tableMap);
buf.append('[');
for (Entry<String, String> entry : sortedEntries) {
if (isFirst)
isFirst = false;
else
buf.append(',');
tableName = entry.getKey();
tableText = com.wb.util.StringUtil.quote(tableName);
tableSchema = com.wb.util.StringUtil.quote(entry.getValue());
buf.append("{\"text\":");
buf.append(tableText);
buf.append(",\"type\":\"table\",\"table\":");
buf.append(tableText);
buf.append(",\"schema\":");
buf.append(tableSchema);
buf.append(",\"jndi\":");
buf.append(jndiText);
buf.append(",\"leaf\":true,\"iconCls\":\"");
upperTableName = tableName.toUpperCase();
if (hasTableDefine && tables.contains(upperTableName)) {
tables.remove(upperTableName);
buf.append("table_add_icon\"}");
} else {
buf.append("table_icon\"}");
}
}
// 不匹配的表添加到最后
if (hasTableDefine && schema == null) {
for (String fullName : tables) {
fullName = com.wb.util.StringUtil.quote(fullName);
buf.append(",{\"text\":");
buf.append(fullName);
buf.append(",\"type\":\"table\",\"table\":");
buf.append(fullName);
buf.append(",\"schema\":\"\",\"jndi\":");
buf.append(jndiText);
buf.append(",\"leaf\":true,\"iconCls\":\"table_delete_icon\"}");
}
}
buf.append(']');
return buf.toString();
} finally {
com.wb.util.DbUtil.close(rs);
com.wb.util.DbUtil.close(conn);
}
}
/**
* 获取指定jndi所有Schema列表。
* @param jndi jndi名称。
* @param tables 已经配置的表定义。
* @return Schema列表JSON脚本。 如果没有Schema返回null。
*/
public static String getSchemaList(String jndi, HashSet<String> tables) throws Exception {
Connection conn = null;
ResultSet rs = null;
String types[] = { "TABLE" }, schema, tableName, upperTableName, jndiText = com.wb.util.StringUtil.quote(jndi);
StringBuilder buf = new StringBuilder();
HashMap<String, Boolean> schemaMap = new HashMap<String, Boolean>();
ArrayList<Entry<String, Boolean>> entryList;
boolean isFirst = true, hasTableDefine = tables != null;
try {
conn = com.wb.util.DbUtil.getConnection(jndi);
rs = conn.getMetaData().getTables(null, null, null, types);
while (rs.next()) {
schema = com.wb.util.StringUtil.opt(rs.getString(2));
tableName = rs.getString(3);
upperTableName = tableName.toUpperCase();
schemaMap.put(schema, true);
if (hasTableDefine && tables.contains(upperTableName))
tables.remove(upperTableName);
}
//如果不包含Schema返回null
if (schemaMap.isEmpty() || schemaMap.size() == 1 && schemaMap.containsKey(""))
return null;
entryList = com.wb.util.SortUtil.sortKey(schemaMap);
buf.append('[');
for (Entry<String, Boolean> entry : entryList) {
schema = com.wb.util.StringUtil.quote(entry.getKey());
if (isFirst)
isFirst = false;
else
buf.append(',');
buf.append("{\"text\":");
buf.append(schema);
buf.append(",\"jndi\":");
buf.append(jndiText);
buf.append(",\"schema\":");
buf.append(schema);
buf.append(",\"type\":\"schema\",\"iconCls\":\"db_form_icon\"}");
}
// 不匹配的表添加到最后
if (hasTableDefine) {
for (String fullName : tables) {
fullName = com.wb.util.StringUtil.quote(fullName);
buf.append(",{\"text\":");
buf.append(fullName);
buf.append(",\"type\":\"table\",\"table\":");
buf.append(fullName);
buf.append(",\"schema\":\"\",\"jndi\":");
buf.append(jndiText);
buf.append(",\"leaf\":true,\"iconCls\":\"table_delete_icon\"}");
}
}
buf.append(']');
return buf.toString();
} finally {
com.wb.util.DbUtil.close(rs);
com.wb.util.DbUtil.close(conn);
}
}
/**
* 从指定表下载二进制字段内容。
*/
public static void downloadBlob(HttpServletRequest request, HttpServletResponse response) throws Exception {
String jndi = request.getParameter("__jndi"), tableName = request.getParameter("__tableName"),
fieldName = request.getParameter("__fieldName");
String selectSql = com.wb.util.DbUtil.buildSQLs(jndi, tableName, false, 1, null, new JSONObject().put(fieldName, 1), null,
null)[3];
ResultSet rs = (ResultSet) com.wb.util.DbUtil.run(request, selectSql, jndi);
com.wb.util.DbUtil.outputBlob(rs, request, response, "download");
}
/**
* 上传文件数据至指定数据库表二进制字段。
*/
public static void uploadBlob(HttpServletRequest request, HttpServletResponse response) throws Exception {
setBlob(request, false);
}
/**
* 上传文件数据至指定数据库表二进制字段。
*/
public static void clearBlob(HttpServletRequest request, HttpServletResponse response) throws Exception {
setBlob(request, true);
}
/**
* 上传文件数据至指定数据库表二进制字段或清除该字段。
* @param isClear 是否清除二进制字段true清除false更新。
*/
private static void setBlob(HttpServletRequest request, boolean isClear) throws Exception {
String jndi = WebUtil.fetch(request, "__jndi"), tableName = WebUtil.fetch(request, "__tableName"),
fieldName = WebUtil.fetch(request, "__fieldName");
if (isClear)
request.setAttribute(fieldName, "");
else
request.setAttribute(fieldName, request.getAttribute("file"));
String updateSql = com.wb.util.DbUtil.buildSQLs(jndi, tableName, false, 1, null, new JSONObject().put(fieldName, 1), null,
null)[1];
com.wb.util.DbUtil.run(request, updateSql, jndi);
}
}

View File

@@ -0,0 +1,795 @@
package com.wb.interact;
import com.wb.common.Base;
import com.wb.common.KVBuffer;
import com.wb.util.FileUtil;
import com.wb.util.JsonUtil;
import com.wb.util.StringUtil;
import com.wb.util.WebUtil;
import org.json.JSONArray;
import org.json.JSONObject;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
/**
* 创建模板
*
* @author shao
*/
public class FileGenProcess {
/**
* 创建基本增删改查
*
* @param request
* @param response
* @param name
* @param title
* @param iconCls
* @param path
* @param tableName
* @param keyField
* @param codeField
* @param nameField
* @param isDialog
* @param hasUpload
* @throws Exception
*/
private static void addbasiceCRUDFrame(HttpServletRequest request, HttpServletResponse response, String name, String title, String iconCls, File path, String tableName, String keyField, String codeField, String nameField, boolean isDialog, boolean hasUpload) throws Exception {
File destFolder = new File(path, name);
File destModule = new File(path, name + ".xwl");
// File filedestfolder = new File(destFolder, "select.xwl");
// JSONObject jsondest=new JSONObject();
// jsondest.put("tablesql","T_student");
// FileUtil.syncSave(filedestfolder, StringUtil.replaceParams(jsondest, FileUtil.readString(filedestfolder)));
if (destModule.exists()) {
throw new RuntimeException("模块“" + name + ".xwl”已经存在。");
} else if (destFolder.exists()) {
throw new RuntimeException("目录“" + name + "”已经存在。");
} else {
if (!StringUtil.isEmpty(codeField) && StringUtil.isEmpty(nameField)) {
nameField = codeField;
codeField = null;
}
File sourcePath;
if (isDialog) {
if (hasUpload) {
sourcePath = new File(Base.path, "wb/modules/dev/template/");
} else {
sourcePath = new File(Base.path, "wb/modules/dev/template/");
}
} else {
sourcePath = new File(Base.path, "wb/modules/dev/template/");
}
//==========创建查询文件start=========
FileUtil.syncCreate(destFolder, true);
File destfolderModule = new File(destFolder, "select" + name + ".xwl");
FileUtil.syncCopyA(new File(sourcePath, "selectall.xwl"), destfolderModule);
String contentchild = FileUtil.readString(destfolderModule);
contentchild = contentchild.replace("#{tablename}", tableName);
JSONObject modulechild = new JSONObject(contentchild);
FileUtil.syncSave(destfolderModule, modulechild.toString());
//======end=======
FileUtil.syncCopyA(new File(sourcePath, "basic-dialog-edit.xwl"), destModule);
File file = new File(path, "folder.json");
JSONObject json = JsonUtil.readObject(file);
JSONArray array = json.optJSONArray("index");
array.put(name + ".xwl");
array.put(name);
StringBuffer buffer = new StringBuffer();
buffer.append("{\n" +
"\"configs\": {\n" +
"\"itemId\": \"columns\"\n" +
"},\n" +
"\"expanded\": true,\n" +
"\"children\": [");
request.setAttribute("tableName",request.getParameter("tableName"));
String data = WebUtil.runresulte("m?xwl=dev/autogenControl/datasource", request, response);
JSONObject datas = new JSONObject(data);
JSONObject datama = new JSONObject(datas.optString("metaData"));
JSONArray djons = new JSONArray(datama.optString("fields"));
for (int a = 0; a < djons.length(); a++) {
JSONObject jsondata = djons.getJSONObject(a);
String namedata = jsondata.optString("name");
String typedata = jsondata.optString("type");
String usernuldata = jsondata.optString("useNull");
String comment = jsondata.optString("comment");
boolean flag = true;
if (KVBuffer.getList(namedata, WebUtil.fetch(request, "sys.tenancyId")).equals("[]")) {
flag = false;
}
buffer.append(" {\n" +
" \"configs\": {" +
"\"itemId\": \"" + namedata + "\",\n" +
"\"dataIndex\": \"" + namedata + "\",\n" +
"\"width\": \"130\",\n" +
"\"text\": \"" + comment + "\",\n");
if (flag) {//如果存在key
buffer.append(" \"keyName\": \"" + namedata + "\",");
}
buffer.append("\"titleAlign\": \"center\"" +
"},\n" +
" \"expanded\": true,\n" +
" \"children\": [],"+
"\"type\": \"column\"\n");
if (a == djons.length() - 1) {
buffer.append("}");
} else {
buffer.append("},");
}
}
buffer.append("],\n" +
"\"type\": \"array\"\n" +
"}");
FileUtil.syncSave(file, json.toString());
String baseUrl = FileUtil.getModuleUrl(destModule) + "/";
String content = FileUtil.readString(destModule);
json = new JSONObject();
json.put("selectUrl", baseUrl + "select");
json.put("searchUrl", baseUrl + "search");
json.put("title", title);
json.put("iconCls", iconCls);
if (isDialog) {
json.put("insertUrl", baseUrl + "insert");
json.put("updateUrl", baseUrl + "update");
json.put("deleteUrl", baseUrl + "delete");
} else {
json.put("saveUrl", baseUrl + "save");
}
json.put("nameField", nameField);
json.put("codeField", codeField);
boolean emptyCodeField = StringUtil.isEmpty(codeField);
boolean hasSearch = !emptyCodeField || !StringUtil.isEmpty(nameField);
if (hasSearch) {
if (emptyCodeField) {
json.put("searchKeyField", nameField);
} else {
json.put("searchKeyField", codeField);
json.put("codeFieldExp", codeField + ", ");
}
}
content = StringUtil.replaceParams(json, content);
content = content.replace("#{columnsrep}", buffer.toString());
StringBuffer windowbuffer = new StringBuffer();
windowbuffer.append("{\n" +
"\t\t\t\"configs\": {\n" +
// "\t\t\t\t\"layout\": \"absolute\",\n" +
"\t\t\t\t\"dialog\": \"true\",\n" +
"\t\t\t\t\"itemId\": \"win\",\n" +
" \"defaults\": \"{margin: 4,labelAlign: 'right',style: 'float:left;'}\"," +
"\t\t\t\t\"createInstance\": \"false\",\n" +
"\t\t\t\t\"focusControl\": \"STRING_FIELD\",\n" +
"\t\t\t\t\"closeAction\": \"destroy\",\n" +
"\t\t\t\t\"width\": \"664\",\n" +
"\t\t\t\t\"title\": \"增删改查\",\n" +
"\t\t\t\t\"modal\": \"true\",\n" +
"\t\t\t\t\"height\": \"352\"\n" +
"\t\t\t},\n" +
"\t\t\t\"expanded\": true,\n" +
"\t\t\t\"children\": [");
for (int a = 0; a < djons.length(); a++) {
JSONObject jsondata = djons.getJSONObject(a);
String namedata = jsondata.optString("name");
String typedata = jsondata.optString("type");
String usernuldata = jsondata.optString("useNull");
String comment = jsondata.optString("comment");
boolean flag = true;
if (KVBuffer.getList(namedata, WebUtil.fetch(request, "sys.tenancyId")).equals("[]")) {
flag = false;
}
windowbuffer.append(
"{\n" +
"\t\t\t\t\"configs\": {\n" +
"\t\t\t\t\t\"allowBlank\": \"false\",\n" +
"\t\t\t\t\t\"itemId\": \"" + namedata + "\",\n" );
if(flag){
windowbuffer.append(" \"keyName\": \""+namedata+"\",");
}
windowbuffer.append( "\t\t\t\t\t\"labelAlign\": \"right\",\n" +
"\t\t\t\t\t\"fieldLabel\": \"" + comment + "\",\n" +
"\t\t\t\t\t\"width\": \"312\",\n" +
"\t\t\t\t\t\"x\": \"8\",\n" +
"\t\t\t\t\t\"y\": \"16\",\n" +
"\t\t\t\t\t\"labelWidth\": \"90\",\n" +
"\t\t\t\t\t\"height\": \"22\"\n" +
"\t\t\t\t},\n" +
"\t\t\t\t\"expanded\": false,\n" +
"\t\t\t\t\"children\": [],\n");
if (typedata.equals("number")) {
windowbuffer.append("\"type\": \"number\"\n");
}
if (typedata.equals("date")) {
windowbuffer.append("\"type\": \"date\"\n");
} else if(flag){
windowbuffer.append("\"type\": \"combo\"\n");
}else{
windowbuffer.append("\"type\": \"text\"\n");
}
if (a == djons.length() - 1) {
windowbuffer.append("}");
} else {
windowbuffer.append("},");
}
}
windowbuffer.append(
"],\n" +
"\t\t\t\"type\": \"window\"\n" +
"\t\t}");
content = content.replace("#{windowresp}", windowbuffer.toString());
content = content.replace("#{controller}", request.getAttribute("controllername").toString());
content = content.replace("#{table_store_url}", "m?xwl=" + destfolderModule.getPath().toString().split("modules")[1].replace(".xwl", ""));
JSONObject module = new JSONObject(content);
FileUtil.syncSave(destModule, module.toString());
}
}
/**
* 创建基本增删改查
*
* @param request
* @param response
* @param name
* @param title
* @param iconCls
* @param path
* @param tableName
* @param keyField
* @param codeField
* @param nameField
* @param isDialog
* @param hasUpload
* @throws Exception
*/
private static void addcrudmultiFormbasicFrame(HttpServletRequest request, HttpServletResponse response, String name, String title, String iconCls, File path, String tableName, String keyField, String codeField, String nameField, boolean isDialog, boolean hasUpload) throws Exception {
File destFolder = new File(path, name);
File destModule = new File(path, name + ".xwl");
if (destModule.exists()) {
throw new RuntimeException("模块“" + name + ".xwl”已经存在。");
} else if (destFolder.exists()) {
throw new RuntimeException("目录“" + name + "”已经存在。");
} else {
if (!StringUtil.isEmpty(codeField) && StringUtil.isEmpty(nameField)) {
nameField = codeField;
codeField = null;
}
File sourcePath;
if (isDialog) {
if (hasUpload) {
sourcePath = new File(Base.path, "wb/modules/dev/template/");
} else {
sourcePath = new File(Base.path, "wb/modules/dev/template/");
}
} else {
sourcePath = new File(Base.path, "wb/modules/dev/template/");
}
//==========创建查询文件start=========
FileUtil.syncCreate(destFolder, true);
File destfolderModule = new File(destFolder, "select" + name + ".xwl");
FileUtil.syncCopyA(new File(sourcePath, "selectall.xwl"), destfolderModule);
String contentchild = FileUtil.readString(destfolderModule);
contentchild = contentchild.replace("#{tablename}", tableName);
JSONObject modulechild = new JSONObject(contentchild);
FileUtil.syncSave(destfolderModule, modulechild.toString());
//======end=======
FileUtil.syncCopyA(new File(sourcePath, "multiform_mainDetail.xwl"), destModule);
File file = new File(path, "folder.json");
JSONObject json = JsonUtil.readObject(file);
JSONArray array = json.optJSONArray("index");
array.put(name + ".xwl");
array.put(name);
//===========================================grid 列替换 start===============================
StringBuffer buffer = new StringBuffer();
buffer.append("{\n" +
"\"configs\": {\n" +
"\"itemId\": \"columns\"\n" +
"},\n" +
"\"expanded\": true,\n" +
"\"children\": [");
request.setAttribute("tableName",request.getParameter("tableName"));
String data = WebUtil.runresulte("m?xwl=dev/autogenControl/datasource", request, response);
JSONObject datas = new JSONObject(data);
JSONObject datama = new JSONObject(datas.optString("metaData"));
JSONArray djons = new JSONArray(datama.optString("fields"));
for (int a = 0; a < djons.length(); a++) {
JSONObject jsondata = djons.getJSONObject(a);
String namedata = jsondata.optString("name");
String typedata = jsondata.optString("type");
String usernuldata = jsondata.optString("useNull");
String comment = jsondata.optString("comment");
boolean flag = true;
if (KVBuffer.getList(namedata, WebUtil.fetch(request, "sys.tenancyId")).equals("[]")) {
flag = false;
}
buffer.append(" {\n" +
" \"configs\": {" +
"\"itemId\": \"" + namedata + "\",\n" +
"\"dataIndex\": \"" + namedata + "\",\n" +
"\"width\": \"130\",\n" +
"\"text\": \"" + comment + "\",\n");
if (flag) {//如果存在key
buffer.append(" \"keyName\": \"" + namedata + "\",");
}
buffer.append("\"titleAlign\": \"center\"" +
"},\n" +
" \"expanded\": true,\n" +
" \"children\": [],"+
"\"type\": \"column\"\n");
if (a == djons.length() - 1) {
buffer.append("}");
} else {
buffer.append("},");
}
}
buffer.append("],\n" +
"\"type\": \"array\"\n" +
"}");
FileUtil.syncSave(file, json.toString());
String baseUrl = FileUtil.getModuleUrl(destModule) + "/";
String content = FileUtil.readString(destModule);
json = new JSONObject();
json.put("selectUrl", baseUrl + "select");
json.put("searchUrl", baseUrl + "search");
json.put("title", title);
json.put("iconCls", iconCls);
if (isDialog) {
json.put("insertUrl", baseUrl + "insert");
json.put("updateUrl", baseUrl + "update");
json.put("deleteUrl", baseUrl + "delete");
} else {
json.put("saveUrl", baseUrl + "save");
}
json.put("nameField", nameField);
json.put("codeField", codeField);
boolean emptyCodeField = StringUtil.isEmpty(codeField);
boolean hasSearch = !emptyCodeField || !StringUtil.isEmpty(nameField);
if (hasSearch) {
if (emptyCodeField) {
json.put("searchKeyField", nameField);
} else {
json.put("searchKeyField", codeField);
json.put("codeFieldExp", codeField + ", ");
}
}
content = StringUtil.replaceParams(json, content);
content = content.replace("#{columnsrep}", buffer.toString());
//===========================================grid 列替换 end===============================
//===========================================grid 2列替换 start===============================
StringBuilder bufferchild = new StringBuilder();
bufferchild.append("{\n" +
"\"configs\": {\n" +
"\"itemId\": \"columns\"\n" +
"},\n" +
"\"expanded\": true,\n" +
"\"children\": [");
request.setAttribute("tableName",request.getParameter("tablechildName"));
String datachild = WebUtil.runresulte("m?xwl=dev/autogenControl/datasource", request, response);
JSONObject dataschild = new JSONObject(datachild);
JSONObject datametaachild = new JSONObject(dataschild.optString("metaData"));
JSONArray djsonchild = new JSONArray(datametaachild.optString("fields"));
for (int a = 0; a < djsonchild.length(); a++) {
JSONObject jsondata = djsonchild.getJSONObject(a);
String namedata = jsondata.optString("name");
String typedata = jsondata.optString("type");
String usernuldata = jsondata.optString("useNull");
String comment = jsondata.optString("comment");
if(comment==null||comment.equals("")){
comment=namedata;
}
boolean flag = true;
if (KVBuffer.getList(namedata, WebUtil.fetch(request, "sys.tenancyId")).equals("[]")) {
flag = false;
}
bufferchild.append(" {\n" +
" \"configs\": {" +
"\"itemId\": \"" + namedata + "\",\n" +
"\"dataIndex\": \"" + namedata + "\",\n" +
"\"width\": \"130\",\n" +
"\"text\": \"" + comment + "\",\n");
if (flag) {//如果存在key
bufferchild.append(" \"keyName\": \"" + namedata + "\",");
}
bufferchild.append("\"titleAlign\": \"center\"" +
"},\n" +
" \"expanded\": true,\n" +
" \"children\": [],"+
"\"type\": \"column\"\n");
if (a == djsonchild.length() - 1) {
bufferchild.append("}");
} else {
bufferchild.append("},");
}
}
bufferchild.append("],\n" +
"\"type\": \"array\"\n" +
"}");
// FileUtil.syncSave(file, json.toString());
// String baseUrlchild = FileUtil.getModuleUrl(destModule) + "/";
// String contentchild = FileUtil.readString(destModule);
// json = new JSONObject();
// json.put("selectUrl", baseUrl + "select");
// json.put("searchUrl", baseUrl + "search");
// json.put("title", title);
// json.put("iconCls", iconCls);
// if (isDialog) {
// json.put("insertUrl", baseUrl + "insert");
// json.put("updateUrl", baseUrl + "update");
// json.put("deleteUrl", baseUrl + "delete");
// } else {
// json.put("saveUrl", baseUrl + "save");
// }
// boolean emptyCodeFieldchild = StringUtil.isEmpty(codeField);
// boolean hasSearchchild = !emptyCodeFieldchild || !StringUtil.isEmpty(nameField);
// content = StringUtil.replaceParams(json, content);
// content = content.replace("#{columnsrepchild}", bufferchild.toString());
content = content.replace("#{columnsrepchild}", bufferchild.toString());
//===========================================grid 列替换 end===============================
//===============================================窗口替换 start=============================================
StringBuffer windowbuffer = new StringBuffer();
windowbuffer.append("{\n" +
"\t\t\t\"configs\": {\n" +
// "\t\t\t\t\"layout\": \"absolute\",\n" +
"\t\t\t\t\"dialog\": \"true\",\n" +
"\t\t\t\t\"itemId\": \"win\",\n" +
" \"defaults\": \"{margin: 4,labelAlign: 'right',style: 'float:left;'}\"," +
"\t\t\t\t\"createInstance\": \"false\",\n" +
"\t\t\t\t\"focusControl\": \"STRING_FIELD\",\n" +
"\t\t\t\t\"closeAction\": \"destroy\",\n" +
"\t\t\t\t\"width\": \"664\",\n" +
"\t\t\t\t\"title\": \"增删改查\",\n" +
"\t\t\t\t\"modal\": \"true\",\n" +
"\t\t\t\t\"height\": \"352\"\n" +
"\t\t\t},\n" +
"\t\t\t\"expanded\": true,\n" +
"\t\t\t\"children\": [");
for (int a = 0; a < djons.length(); a++) {
JSONObject jsondata = djons.getJSONObject(a);
String namedata = jsondata.optString("name");
String typedata = jsondata.optString("type");
String usernuldata = jsondata.optString("useNull");
String comment = jsondata.optString("comment");
boolean flag = true;
if (KVBuffer.getList(namedata, WebUtil.fetch(request, "sys.tenancyId")).equals("[]")) {
flag = false;
}
windowbuffer.append(
"{\n" +
"\t\t\t\t\"configs\": {\n" +
"\t\t\t\t\t\"allowBlank\": \"false\",\n" +
"\t\t\t\t\t\"itemId\": \"" + namedata + "\",\n" );
if(flag){
windowbuffer.append(" \"keyName\": \""+namedata+"\",");
}
windowbuffer.append( "\t\t\t\t\t\"labelAlign\": \"right\",\n" +
"\t\t\t\t\t\"fieldLabel\": \"" + comment + "\",\n" +
"\t\t\t\t\t\"width\": \"312\",\n" +
"\t\t\t\t\t\"x\": \"8\",\n" +
"\t\t\t\t\t\"y\": \"16\",\n" +
"\t\t\t\t\t\"labelWidth\": \"90\",\n" +
"\t\t\t\t\t\"height\": \"22\"\n" +
"\t\t\t\t},\n" +
"\t\t\t\t\"expanded\": false,\n" +
"\t\t\t\t\"children\": [],\n");
if (typedata.equals("number")) {
windowbuffer.append("\"type\": \"number\"\n");
}
if (typedata.equals("date")) {
windowbuffer.append("\"type\": \"date\"\n");
} else if(flag){
windowbuffer.append("\"type\": \"combo\"\n");
}else{
windowbuffer.append("\"type\": \"text\"\n");
}
if (a == djons.length() - 1) {
windowbuffer.append("}");
} else {
windowbuffer.append("},");
}
}
windowbuffer.append(
"],\n" +
"\t\t\t\"type\": \"window\"\n" +
"\t\t}");
content = content.replace("#{windowresp}", windowbuffer.toString());
//===============================================窗口替换 end=============================================
content = content.replace("#{controller}", request.getAttribute("controllername").toString());
content = content.replace("#{table_store_url}", "m?xwl=" + destfolderModule.getPath().toString().split("modules")[1].replace(".xwl", ""));
JSONObject module = new JSONObject(content);
FileUtil.syncSave(destModule, module.toString());
}
}
/**
* 创建表格编辑增删改查
*
* @param request
* @param response
* @param name
* @param title
* @param iconCls
* @param path
* @param tableName
* @param keyField
* @param codeField
* @param nameField
* @param isDialog
* @param hasUpload
* @throws Exception
*/
private static void addeditgridCRUDFrame(HttpServletRequest request, HttpServletResponse response, String name, String title, String iconCls, File path, String tableName, String keyField, String codeField, String nameField, boolean isDialog, boolean hasUpload) throws Exception {
File destFolder = new File(path, name);
File destModule = new File(path, name + ".xwl");
if (destModule.exists()) {
throw new RuntimeException("模块“" + name + ".xwl”已经存在。");
} else if (destFolder.exists()) {
throw new RuntimeException("目录“" + name + "”已经存在。");
} else {
if (!StringUtil.isEmpty(codeField) && StringUtil.isEmpty(nameField)) {
nameField = codeField;
codeField = null;
}
File sourcePath;
if (isDialog) {
if (hasUpload) {
sourcePath = new File(Base.path, "wb/modules/dev/template/");
} else {
sourcePath = new File(Base.path, "wb/modules/dev/template/");
}
} else {
sourcePath = new File(Base.path, "wb/modules/dev/template/");
}
//==========创建查询文件start=========
FileUtil.syncCreate(destFolder, true);
File destfolderModule = new File(destFolder, "select" + name + ".xwl");
FileUtil.syncCopyA(new File(sourcePath, "selectall.xwl"), destfolderModule);
String contentchild = FileUtil.readString(destfolderModule);
contentchild = contentchild.replace("#{tablename}", tableName);
JSONObject modulechild = new JSONObject(contentchild);
FileUtil.syncSave(destfolderModule, modulechild.toString());
//======end=======
FileUtil.syncCopyA(new File(sourcePath, "gridCrud.xwl"), destModule);
File file = new File(path, "folder.json");
JSONObject json = JsonUtil.readObject(file);
JSONArray array = json.optJSONArray("index");
array.put(name + ".xwl");
array.put(name);
StringBuffer buffer = new StringBuffer();
buffer.append("{\n" +
"\"configs\": {\n" +
"\"itemId\": \"columns\"\n" +
"},\n" +
"\"expanded\": true,\n" +
"\"children\": [");
request.setAttribute("tableName",request.getParameter("tableName"));
String data = WebUtil.runresulte("m?xwl=dev/autogenControl/datasource", request, response);
JSONObject datas = new JSONObject(data);
JSONObject datama = new JSONObject(datas.optString("metaData"));
JSONArray djons = new JSONArray(datama.optString("fields"));
for (int a = 0; a < djons.length(); a++) {
JSONObject jsondata = djons.getJSONObject(a);
String namedata = jsondata.optString("name");
boolean flag = true;
if (KVBuffer.getList(namedata, WebUtil.fetch(request, "sys.tenancyId")).equals("[]")) {
flag = false;
}
String text = jsondata.optString("comment");
String typedata = jsondata.optString("type");
String usernuldata = jsondata.optString("useNull");
buffer.append(" {\n" +
"\"configs\": {" +
"\"itemId\": \"" + namedata + "\",\n" +
"\"dataIndex\": \"" + namedata + "\",\n" +
"\"width\": \"130\",\n" +
"\"text\": \"" + text + "\",\n");
if (flag) {//如果存在key
buffer.append(" \"keyName\": \"" + namedata + "\",");
}
buffer.append("\"titleAlign\": \"center\"" +
"},\n" +
" \"expanded\": true,\n" +
" \"children\": [{\n" +
" \"configs\": {\"itemId\": \"editor\"");
if (flag) {//如果存在key
buffer.append(",\n" +
" \"keyName\": \"" + namedata + "\",\n" +
" \"displayField\": \"V\",\n" +
" \"valueField\": \"K\"");
}
buffer.append("" +
"},\n" +
" \"expanded\": false,\n" +
" \"children\": [],\n");
if (typedata.equals("number")) {
buffer.append("\"type\": \"number\"\n");
}
if (typedata.equals("date")) {
buffer.append("\"type\": \"date\"\n");
} else if (flag) {
buffer.append("\"type\": \"combo\"\n");
} else {
buffer.append("\"type\": \"text\"\n");
}
buffer.append(" }],\"type\": \"column\"\n");
if (a == djons.length() - 1) {
buffer.append("}");
} else {
buffer.append("},");
}
}
buffer.append("],\n" +
"\"type\": \"array\"\n" +
"}");
FileUtil.syncSave(file, json.toString());
String baseUrl = FileUtil.getModuleUrl(destModule) + "/";
String content = FileUtil.readString(destModule);
json = new JSONObject();
json.put("selectUrl", baseUrl + "select");
json.put("searchUrl", baseUrl + "search");
json.put("title", title);
json.put("iconCls", iconCls);
if (isDialog) {
json.put("insertUrl", baseUrl + "insert");
json.put("updateUrl", baseUrl + "update");
json.put("deleteUrl", baseUrl + "delete");
} else {
json.put("saveUrl", baseUrl + "save");
}
json.put("nameField", nameField);
json.put("codeField", codeField);
boolean emptyCodeField = StringUtil.isEmpty(codeField);
boolean hasSearch = !emptyCodeField || !StringUtil.isEmpty(nameField);
if (hasSearch) {
if (emptyCodeField) {
json.put("searchKeyField", nameField);
} else {
json.put("searchKeyField", codeField);
json.put("codeFieldExp", codeField + ", ");
}
}
content = StringUtil.replaceParams(json, content);
content = content.replace("#{columnsrep}", buffer.toString());
content = content.replace("#{entityname}", request.getAttribute("entityname").toString());
content = content.replace("#{servicebean}", request.getAttribute("controllername").toString());
content = content.replace("#{table_store_url}", "m?xwl=" + destfolderModule.getPath().toString().split("modules")[1].replace(".xwl", ""));
JSONObject module = new JSONObject(content);
FileUtil.syncSave(destModule, module.toString());
}
}
public static synchronized void addFrame(HttpServletRequest request, HttpServletResponse response) throws Exception {
String name = request.getParameter("name");
String title = request.getParameter("title");
String iconCls = request.getParameter("iconCls");
File path = new File(request.getParameter("path"));
String frameType = request.getParameter("frameType");
if (!FileUtil.isAncestor(Base.modulePath, path)) {
throw new Exception("模块文件必须创建于模块目录。");
} else {
if ("crud".equals(frameType)) {
addeditgridCRUDFrame(request, response, name, title, iconCls, path, request.getParameter("tableName"), request.getParameter("keyField"), request.getParameter("codeField"), request.getParameter("nameField"), Boolean.parseBoolean(request.getParameter("dialog")), Boolean.parseBoolean(request.getParameter("hasUpload")));
}
if ("crudbasic".equals(frameType)) {
addbasiceCRUDFrame(request, response, name, title, iconCls, path, request.getParameter("tableName"), request.getParameter("keyField"), request.getParameter("codeField"), request.getParameter("nameField"), Boolean.parseBoolean(request.getParameter("dialog")), Boolean.parseBoolean(request.getParameter("hasUpload")));
} if ("crudmultiFormbasic".equals(frameType)) {
addcrudmultiFormbasicFrame(request, response, name, title, iconCls, path, request.getParameter("tableName"), request.getParameter("keyField"), request.getParameter("codeField"), request.getParameter("nameField"), Boolean.parseBoolean(request.getParameter("dialog")), Boolean.parseBoolean(request.getParameter("hasUpload")));
}
}
}
}

View File

@@ -0,0 +1,263 @@
package com.wb.interact;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.wb.tool.ColumnUpper;
import org.apache.commons.io.IOUtils;
import org.json.JSONArray;
import org.json.JSONObject;
import com.wb.tool.ExcelObject;
import com.wb.util.WebUtil;
public class FilePush {
/**
* 根据客户端推送的数据生成原始数据文件,并发送给客户端。
*/
public static void getFile(HttpServletRequest request, HttpServletResponse response) throws Exception {
String filename = WebUtil.fetch(request, "filename");
String data = WebUtil.fetch(request, "data");
boolean gzip = Boolean.parseBoolean(WebUtil.fetch(request, "gzip"));
if (filename == null) {
if (gzip)
filename = "data.gz";
else
filename = "data";
}
response.setHeader("content-type", "application/force-download");
response.setHeader("content-disposition", "attachment;" + WebUtil.encodeFilename(request, filename));
if (gzip) {
GZIPOutputStream gos = new GZIPOutputStream(response.getOutputStream());
try {
gos.write(data.getBytes("utf-8"));
} finally {
gos.close();
}
response.flushBuffer();
} else
WebUtil.send(response, data);
}
/**
* 根据客户端推送的数据生成原始文本,并发送给客户端。
*/
public static void getText(HttpServletRequest request, HttpServletResponse response) throws Exception {
WebUtil.send(response, request.getParameter("text"));
}
/**
* 根据客户端推送的数据生成Excel文件并发送给客户端。
*/
public static void getExcel(HttpServletRequest request, HttpServletResponse response) throws Exception {
String ext = ExcelObject.getExtName();
String filename = WebUtil.fetch(request, "filename");
String title = WebUtil.fetch(request, "title");
String tenancyId = WebUtil.fetch(request, "sys.tenancyId");
if (com.wb.util.StringUtil.isEmpty(filename))
filename = "data" + ext;
else
filename += ext;
response.setHeader("content-type", "application/force-download");
response.setHeader("content-disposition", "attachment;" + WebUtil.encodeFilename(request, filename));
com.wb.tool.DataOutput.outputExcel(response.getOutputStream(), new JSONArray(WebUtil.fetch(request, "headers")),
new JSONArray(WebUtil.fetch(request, "rows")), com.wb.util.StringUtil.isEmpty(title) ? null : title,
new JSONObject("{mergeInfo:[]}"), com.wb.util.StringUtil.select(WebUtil.fetch(request, "dateFormat"), "Y-m-d"),
com.wb.util.StringUtil.select(WebUtil.fetch(request, "timeFormat"), "H:i:s"), false, tenancyId);
response.flushBuffer();
}
/**
* 根据客户端推送的数据在服务器端指定目录生成原始数据文件。
*/
public static void writeFile(HttpServletRequest request, HttpServletResponse response) throws Exception {
String filename = WebUtil.fetch(request, "filename");
String data = WebUtil.fetch(request, "data");
boolean gzip = Boolean.parseBoolean(WebUtil.fetch(request, "gzip"));
File file = new File(filename);
if (file.exists())
throw new Exception("文件 “" + filename + "” 已经存在。");
if (gzip) {
FileOutputStream fos = null;
GZIPOutputStream gos = null;
try {
fos = new FileOutputStream(file);
gos = new GZIPOutputStream(fos);
gos.write(data.getBytes("utf-8"));
} finally {
IOUtils.closeQuietly(gos);
if (fos != null)
fos.close();
}
} else
com.wb.util.FileUtil.writeString(file, data);
}
/**
* 对指定url使用include的方法发起请求并把请求获取的数据按指定格式进行输出。
*/
public static void transfer(HttpServletRequest request, HttpServletResponse response) throws Exception {
String data, filename, fileExtName, respText;
String type, title, dateFormat, timeFormat;
String decimalSeparator, thousandSeparator;
String tenancyId = WebUtil.fetch(request, "sys.tenancyId");
String metaParamsStr = request.getParameter("__metaParams");
if (metaParamsStr.contains("&quot;")){
metaParamsStr = metaParamsStr.replace("&quot;", "\"");
}
JSONObject responseObject, reportInfo, metaParams = new JSONObject(metaParamsStr);
JSONArray headers, records;
boolean isHtml = false, neptune;
com.wb.tool.CustomResponse resp;
type = metaParams.optString("type");
if ("excel".equals(type)) {
fileExtName = ExcelObject.getExtName();
} else if ("text".equals(type)) {
fileExtName = ".txt";
} else if ("html".equals(type)) {
fileExtName = ".html";
isHtml = true;
} else if ("csv".equals(type)) {
fileExtName = ".csv";
}else
throw new IllegalArgumentException("Invalid request file type.");
data = metaParams.optString("data", null);// 获取客户端数据
if (data == null) {
// 如果客户端无数据(输出全部页时)重新获取服务端数据
resp = new com.wb.tool.CustomResponse(response);
request.setAttribute("sys.rowOnly", 1);// 标记仅生成rows数据
request.setAttribute("sys.fromExport", 1);// 标记操作来自导出
WebUtil.include(request, resp, metaParams.optString("url"));
respText = getResponseString(resp);
if (respText.startsWith("<textarea>")) {
// json response格式
data = respText.substring(10, respText.length() - 11);
responseObject = new JSONObject(data);
data = (String) responseObject.opt("value");
if (!responseObject.optBoolean("success")) {
WebUtil.send(response, data, false);
return;
}
} else {
// Ajax格式
respText = respText.trim();
if (!respText.startsWith("{") || !respText.endsWith("}")) {
WebUtil.send(response, respText, false);
return;
}
data = respText;
}
records = new JSONObject(data).getJSONArray("rows");
} else
records = new JSONArray(data);
headers = metaParams.optJSONArray("headers");
title = metaParams.optString("title", null);// 标题如果为null不输出
reportInfo = metaParams.optJSONObject("reportInfo");
/*JSONObject summaryData = metaParams.optJSONObject("summaryData");//合计数据
if(summaryData!= null){
//将合计行数据增加到原始的数据中
records.put(summaryData);
}*/
dateFormat = metaParams.optString("dateFormat");// 默认日期格式
timeFormat = metaParams.optString("timeFormat");// 默认时间格式
neptune = metaParams.optBoolean("neptune");
decimalSeparator = metaParams.optString("decimalSeparator");
thousandSeparator = metaParams.optString("thousandSeparator");
filename = metaParams.optString("filename");
if (com.wb.util.StringUtil.isEmpty(filename))
filename = "data";
filename += fileExtName;
if (!isHtml) {
// 非html下载文件
response.setHeader("content-type", "application/force-download");
response.setHeader("content-disposition", "attachment;" + WebUtil.encodeFilename(request, filename));
}
//records中所有key转大写
JSONArray recordeUpper = new JSONArray();
List<Map<String, Object>> recList = CollUtil.list(false);
for (int i=0; i<records.length(); i++){
com.alibaba.fastjson.JSONObject fastJson = com.alibaba.fastjson.JSONObject.parseObject(records.getJSONObject(i).toString());
Map<String, Object> recMap = ColumnUpper.keyToUpperCase(fastJson);
recordeUpper.put(recMap);
recList.add(recMap);
}
records = recordeUpper;
//grid导出时要能根据客户选的的排序字段排序
JSONArray sortArray = metaParams.getJSONArray("sorters");
if (sortArray.length() > 0 ){
JSONObject sortObject = sortArray.getJSONObject(0);
String property = sortObject.getString("property");
String direction = sortObject.getString("direction");
com.alibaba.fastjson.JSONArray fastRecords = JSON.parseArray(JSON.toJSONString(recList));
if (StrUtil.equals(direction, "ASC")){
fastRecords.sort(Comparator.comparing(st-> ((com.alibaba.fastjson.JSONObject)st).getString(property), Comparator.nullsFirst(Comparator.naturalOrder())));
}
if (StrUtil.equals(direction, "DESC")){
fastRecords.sort(Comparator.comparing(st-> ((com.alibaba.fastjson.JSONObject)st).getString(property), Comparator.nullsFirst(Comparator.naturalOrder())).reversed());
}
JSONArray recordSort = new JSONArray();
for (int i=0; i<fastRecords.size(); i++){
recordSort.put(fastRecords.getJSONObject(i));
}
records = recordSort;
}
if ("excel".equals(type)) {
com.wb.tool.DataOutput.outputExcel(response.getOutputStream(), headers, records, title, reportInfo, dateFormat,
timeFormat, neptune, tenancyId);
} else if ("csv".equals(type)) {
response.setContentType("application/octet-stream");
response.setCharacterEncoding("utf-8");
com.wb.tool.DataOutput.outputCsv(response.getWriter(), headers, records, dateFormat, timeFormat,
decimalSeparator, thousandSeparator, tenancyId);
}else if ("text".equals(type)) {
com.wb.tool.DataOutput.outputText(response.getOutputStream(), headers, records, dateFormat, timeFormat,
decimalSeparator, thousandSeparator, tenancyId);
} else {// html预览
com.wb.tool.DataOutput.outputHtml(response.getOutputStream(), headers, records, title, dateFormat, timeFormat, neptune,
metaParams.getInt("rowNumberWidth"), metaParams.optString("rowNumberTitle"), decimalSeparator,
thousandSeparator, tenancyId);
}
response.flushBuffer();
}
/**
* 获取使用include方法返回的Response对象数据。
* @param response 响应对象。
* @return 响应对象的输出数据。
*/
private static String getResponseString(com.wb.tool.CustomResponse response) throws Exception {
byte data[] = response.getBytes();
String result;
if (data.length > 2 && data[0] == (byte) 0x1F && data[1] == (byte) 0x8B) {
// 使用gzip压缩的数据
InputStream is = new GZIPInputStream(new ByteArrayInputStream(data));
try {
result = com.wb.util.StringUtil.getString(is);
} finally {
is.close();
}
} else
result = new String(data, "utf-8");
return result;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,350 @@
package com.wb.interact;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Date;
import java.util.Map.Entry;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.io.FileUtils;
import org.json.JSONArray;
import org.json.JSONObject;
import com.wb.common.ScriptBuffer;
import com.wb.common.Var;
import com.wb.util.SysUtil;
import com.wb.util.WebUtil;
public class Install {
/**
* 检查当前系统是否允许安装,如果不允许安装则抛出异常。
*/
public static void checkInstall(HttpServletRequest request, HttpServletResponse response) throws Exception {
if (!Var.getBool("sys.service.allowInstall"))
throw new RuntimeException("系统已经安装完成如需重新安装请设置变量sys.service.allowInstall为true。");
}
/**
* 立即生成JNDI数据源配置文件。
*/
public static void generateJndi(HttpServletRequest request, HttpServletResponse response) throws Exception {
checkInstall(request, response);
String overwrite = request.getParameter("overwrite");
if (overwrite == null)
throw new NullPointerException("overwrite 参数为null");
char dbType = request.getParameter("dbType").charAt(0);
String contextFilename = null, libFilename = null;
switch (dbType) {
case 's':
contextFilename = "s-context.xml";
libFilename = "sqljdbc4.jar";
break;
case 'm':
contextFilename = "m-context.xml";
libFilename = "mysql51.jar";
break;
case 'o':
contextFilename = "o-context.xml";
libFilename = "ojdbc6.jar";
break;
}
File metaFolder = new File(com.wb.common.Base.path, "META-INF"), contextFile = new File(metaFolder, "context.xml"),
rootFolder, syncFolder, libFolder;
if (!metaFolder.exists() && !metaFolder.mkdir())
throw new IOException("创建META-INF目录失败。");
if (!Boolean.parseBoolean(overwrite) && contextFile.exists())
SysUtil.error("文件 \"META-INF/context.xml\" 已经存在,确定要覆盖吗?", "106");
rootFolder = com.wb.common.Base.path.getParentFile().getParentFile();
libFolder = new File(rootFolder, "lib");
if (!new File(libFolder, libFilename).exists()) {
FileUtils.copyFileToDirectory(new File(com.wb.common.Base.path, "wb/system/database/" + libFilename), libFolder);
}
String xml = com.wb.util.FileUtil.readString(new File(com.wb.common.Base.path, "wb/system/database/" + contextFilename));
xml = WebUtil.replaceParams(request, xml);
com.wb.util.FileUtil.writeString(contextFile, xml);
syncFolder = new File(rootFolder, "conf/Catalina/localhost");
if (!syncFolder.exists())
syncFolder.mkdirs();
com.wb.util.FileUtil.writeString(new File(syncFolder, com.wb.common.Base.path.getName() + ".xml"), xml);
}
/**
* 自动生成指定版本的软件包。
*/
public static synchronized void getPack(HttpServletRequest request, HttpServletResponse response) throws Exception {
getReleasePath();// 测试发布目录是否存在。
com.wb.interact.IDE.makeFile(request, com.wb.common.Base.path, false);
exportWBTables("r".equals(request.getParameter("type")));
createPack(request, response);
}
/**
* 导出所有sqls.sql文件中定义的需要创建的数据库表数据至指定目录。
* @param userRelease 是否为用户发布版本。
*/
private static void exportWBTables(boolean userRelease) throws Exception {
Connection conn = null;
Statement st = null;
ResultSet rs = null;
BufferedWriter writer;
int index;
String withoutTables[] = { "WB_LOG", "WB_ROUTE", "WB_SN", "WB_SYS1", "WB_SYS2", "WB_VALUE" };
String tableName, upperSQL,
sqls[] = com.wb.util.FileUtil.readString(new File(com.wb.common.Base.path, "wb/system/database/sqls.sql")).split(";");
File destTable, tablesPath = new File(com.wb.common.Base.path, "wb/system/database/tables"),
syncPath = com.wb.util.FileUtil.getSyncPath(tablesPath);
try {
FileUtils.cleanDirectory(tablesPath);
if (syncPath != null)
FileUtils.cleanDirectory(syncPath);
conn = com.wb.util.DbUtil.getConnection();
st = conn.createStatement();
st.executeUpdate("update WB_USER set LOGIN_TIMES=0");
for (String sql : sqls) {
upperSQL = sql.toUpperCase();
index = upperSQL.indexOf("CREATE TABLE");
if (index != -1) {
tableName = sql.substring(index + 13, sql.indexOf('(')).trim();
if (!userRelease && com.wb.util.StringUtil.indexOf(withoutTables, tableName) != -1)
continue;
writer = null;
rs = null;
try {
destTable = new File(tablesPath, tableName + ".dat");
if (userRelease)
rs = st.executeQuery("select * from " + tableName);
else {
if (tableName.equals("WB_USER"))
rs = st.executeQuery("select * from WB_USER where USER_ID in ('admin','test')");
else if (tableName.equals("WB_RESOURCE"))
rs = st.executeQuery(
"select * from WB_RESOURCE where RES_ID in ('desktop@admin','desktop@test')");
else
rs = st.executeQuery("select * from " + tableName);
}
writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(destTable), "utf-8"));
com.wb.util.DbUtil.exportData(rs, writer);
writer.close();
writer = null;
if (syncPath != null)
FileUtils.copyFileToDirectory(destTable, syncPath);
} finally {
if (writer != null)
writer.close();
if (rs != null)
rs.close();// 无需使用DbUtil.close
}
}
}
} finally {
com.wb.util.DbUtil.close(rs);
com.wb.util.DbUtil.close(st);
com.wb.util.DbUtil.close(conn);
}
}
/**
* 测试JNDI是否有效。如果JNDI无效则抛出异常。
*/
public static void testJNDI(HttpServletRequest request, HttpServletResponse response) throws Exception {
checkInstall(request, response);
String jndi = request.getParameter("jndi");
Var.set("sys.jndi.default", jndi);
Var.jndi = jndi;
com.wb.util.DbUtil.getConnection().close();
}
/**
* 把相关的数据库表复制到目标数据库,并对相关参数进行设置和备份。
*/
public static void setup(HttpServletRequest request, HttpServletResponse response) throws Exception {
checkInstall(request, response);
String jndi = request.getParameter("jndiText");
String type = request.getParameter("typeText");
Var.set("sys.jndi.default", jndi);
Var.jndi = jndi;
if ("postgresql".equals(type) && !"e".equals(Var.getString("sys.app.versionType")))
throw new RuntimeException("postgresql数据库类型只有企业版本支持。");// 企业版本提供支持使用小写的postgresql数据库
Connection conn = null;
Statement st = null;
int index;
String tableName, sqls[];
File mapJson = new File(com.wb.common.Base.path, "wb/system/map.json");
File tablePath = new File(com.wb.common.Base.path, "wb/system/database/tables");
JSONArray mapArray;
JSONObject jo;
File file;
try {
mapArray = com.wb.util.JsonUtil.readArray(mapJson);
jo = new JSONObject();
jo.put("var.json", com.wb.util.FileUtil.readString(Var.file));
com.wb.util.FileUtil.syncSave(mapJson, mapArray.put(jo).toString());
sqls = replaceSQLMacro(com.wb.util.FileUtil.readString(new File(com.wb.common.Base.path, "wb/system/database/sqls.sql")), type)
.split(";");
conn = com.wb.util.DbUtil.getConnection();
st = conn.createStatement();
for (String sql : sqls) {
index = sql.indexOf("CREATE TABLE");
if (index == -1)
st.executeUpdate(sql.trim());
else {
tableName = sql.substring(index + 13, sql.indexOf('(')).trim();
try {
st.executeUpdate("DROP TABLE " + tableName);
} catch (Throwable e) {
// 忽略,因为有可能指定表不存在。
}
st.executeUpdate(sql.trim());
file = new File(tablePath, com.wb.util.StringUtil.concat(tableName, ".dat"));
if (file.exists()) {
com.wb.util.DbUtil.importData(conn, tableName,
new BufferedReader(new InputStreamReader(new FileInputStream(file), "utf-8")));
}
}
}
} finally {
com.wb.util.DbUtil.close(st);
com.wb.util.DbUtil.close(conn);
}
Var.set("sys.db.defaultType", type);
if ("d".equals(Var.getString("sys.app.versionType"))) {
Var.set("sys.portal", "demo-index");
com.wb.common.UrlBuffer.buffer.put("/", "sys/portal/demo-index.xwl");
} else {
Var.set("sys.portal", "index");
com.wb.common.UrlBuffer.put("/", "sys/portal/index.xwl");
}
// 禁用安装服务如需再次使用安装需设置该变量为true。
Var.set("sys.service.allowInstall", false);
// 安装后加载数据库相关类
SysUtil.reload(3);
// 安装后立即启动计划任务
com.wb.tool.TaskManager.start();
}
/**
* 获取发布目录路径。
* @return 发布目录路径。
* @throws RuntimeException 发布目录未指定或目录不存在。
*/
private static File getReleasePath() {
String releasePathVar = Var.getString("sys.ide.releasePath");
if (releasePathVar.isEmpty())
throw new RuntimeException("发布目录变量 \"sys.ide.releasePath\" 未指定。");
File releasePath = new File(releasePathVar);
if (!releasePath.exists())
throw new RuntimeException("发布目录 \"" + releasePath + "\" 不存在。");
return releasePath;
}
/**
* 创建软件包。
*/
private static void createPack(HttpServletRequest request, HttpServletResponse response) throws Exception {
File releasePath = getReleasePath();
String type = request.getParameter("type");
boolean userReleaseVersion = "r".equals(type);// 用户发布版本
File destPath = com.wb.util.FileUtil.getUniqueFile(
new File(releasePath, (userReleaseVersion ? Var.getString("sys.app.title") : ("wb7" + type)) + "("
+ com.wb.util.DateUtil.format(new Date(), "yyyy-MM-dd") + ")"));
if (userReleaseVersion) {
File files[] = com.wb.util.FileUtil.listFiles(com.wb.common.Base.path);
for (File file : files) {
FileUtils.copyDirectoryToDirectory(file, destPath);
}
File varFile = new File(destPath, "wb/system/var.json");
JSONObject varObject = com.wb.util.JsonUtil.readObject(varFile);
((JSONArray) com.wb.util.JsonUtil.getValue(varObject, "sys.db.defaultType", '.')).put(0, "");
((JSONArray) com.wb.util.JsonUtil.getValue(varObject, "sys.jndi.default", '.')).put(0, "");
((JSONArray) com.wb.util.JsonUtil.getValue(varObject, "sys.ide.releasePath", '.')).put(0, "");
((JSONArray) com.wb.util.JsonUtil.getValue(varObject, "sys.ide.syncPath", '.')).put(0, "");
((JSONArray) com.wb.util.JsonUtil.getValue(varObject, "sys.portal", '.')).put(0, "setup");
((JSONArray) com.wb.util.JsonUtil.getValue(varObject, "sys.service.allowInstall", '.')).put(0, true);
com.wb.util.FileUtil.writeString(varFile, varObject.toString(2));
} else {
File destWebInf = new File(destPath, "wb/WEB-INF");
FileUtils.copyDirectoryToDirectory(new File(com.wb.common.Base.path, "WEB-INF/lib"), destWebInf);
FileUtils.copyFileToDirectory(new File(com.wb.common.Base.path, "WEB-INF/web.xml"), destWebInf);
FileUtils.copyDirectoryToDirectory(new File(com.wb.common.Base.path, "wb"), new File(destPath, "wb"));
if ("e".equals(type))
FileUtils.copyDirectory(new File(Var.getString("sys.ide.sourcePath")), new File(destPath, "source"));
FileUtils.copyFileToDirectory(
new File(releasePath, "webbuilder-" + Var.getString("sys.app.version") + ".jar"),
new File(destPath, "wb/WEB-INF/lib"));
FileUtils.copyDirectoryToDirectory(new File(releasePath, "misc"), destPath);
FileUtils.copyFileToDirectory(new File(releasePath, "api.html"), destPath);
FileUtils.copyFileToDirectory(new File(releasePath, "manual.docx"), destPath);
FileUtils.copyFileToDirectory(new File(releasePath, "license.html"), destPath);
FileUtils.copyFileToDirectory(new File(releasePath, "readme.html"), destPath);
File ssproto = new File(destPath, "wb/wb/system/database/ssproto.sql");
if (!ssproto.delete())
throw new RuntimeException("无法删除 \"" + ssproto + "\"");
String packJSPath = "wb/wb/system/pack.js";
File packJS = new File(destPath, packJSPath);
if (!packJS.delete())
throw new RuntimeException("无法删除 \"" + packJS + "\"");
packJSPath = "wb/system/pack.js";
packJS = new File(com.wb.common.Base.path, packJSPath);
request.setAttribute("destPath", destPath);
request.setAttribute("releasePath", releasePath);
ScriptBuffer.run(packJSPath, com.wb.util.FileUtil.readString(packJS), request, response, packJSPath);
}
WebUtil.send(response, destPath);
}
/**
* 根据指定数据库类型替换SQL中的宏把宏转换为指定数据库可识别的关键字。
* @param sql SQL语句。
* @param dbType 数据库类型。
* @return 转换后的SQL。
* @throws Exception
*/
private static String replaceSQLMacro(String sql, String dbType) throws Exception {
JSONObject object = com.wb.util.JsonUtil.readObject(new File(com.wb.common.Base.path, "wb/system/database/types.json"));
JSONObject items = object.getJSONObject(dbType);
Set<Entry<String, Object>> es = items.entrySet();
for (Entry<String, Object> entry : es) {
sql = com.wb.util.StringUtil.replaceAll(sql, "{#" + entry.getKey() + "#}", entry.getValue().toString());
}
return sql;
}
/**
* 把产品注册信息写入到系统变量。
*/
public static void register(HttpServletRequest request, HttpServletResponse response) throws Exception {
Var.set("sys.app.licensee", request.getParameter("licText"));
Var.set("sys.app.serialNumber", request.getParameter("snText"));
}
/**
* 在线验证指定序列号是否有效。
*/
public static void verify(HttpServletRequest request, HttpServletResponse response) throws Exception {
String sn, msg;
try {
sn = request.getParameter("snText");
msg = WebUtil.submit("http://www.ag6666666/sn-verify", new JSONObject().put("sn", sn));
} catch (Throwable e) {
throw new RuntimeException("验证失败,网络无效或服务暂时不可访问。");
}
if (!"ok".equals(msg))
throw new RuntimeException("验证失败,序列号 “" + sn + "” 无效。");
}
}

View File

@@ -0,0 +1,563 @@
package com.wb.interact;
import com.wb.common.*;
import com.wb.util.*;
import org.json.JSONArray;
import org.json.JSONObject;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Map;
import java.util.Map.Entry;
/**
* 门户及其相关的应用。
*/
public class Portal {
/**
* 递归获取所有模块列表树的节点列表。
* @param request 请求对象。
* @param path 请求的路径。
* @param roles 角色列表。
* @param type 数据请求来源类型1主页2权限模块3用户模块。
*/
private static JSONArray getModuleList(HttpServletRequest request,
String path, String[] roles, int type) throws Exception {
String iconCls, fileName, pageLink, relPath, title;
File file, base;
int displayType = (type == 1 ? 1 : 3);
if (path == null)
base = Base.modulePath;
else {
base = new File(Base.modulePath, path);
if (!FileUtil.isAncestor(Base.modulePath, base))
SysUtil.accessDenied();
}
path = path + "/";
ArrayList<Entry<String, Integer>> fileNames = com.wb.interact.IDE.getSortedFile(base);
JSONObject content = null, fileObject;
JSONArray fileArray;
boolean isFolder;
fileArray = new JSONArray();
for (Entry<String, Integer> entry : fileNames) {
fileName = entry.getKey();
file = new File(base, fileName);
// 文件列表取自配置文件,如果不存在返回
if (!file.exists())
continue;
if (!XwlBuffer.canDisplay(file, roles, displayType))
continue;
isFolder = file.isDirectory();
if (isFolder) {
if (type != 1 && !hasLoginModule(file))
continue;
File configFile = new File(file, "folder.json");
if (configFile.exists())
content = JsonUtil.readObject(configFile);
else
content = new JSONObject();
} else {
// 如果设置模块权限且非模块文件则返回
if (type != 1 && !file.getName().endsWith(".xwl"))
continue;
content = XwlBuffer.get(path + fileName, false);
// 无需登录的模块不允许设置权限
if (type != 1
&& Boolean.FALSE.equals(content.opt("loginRequired")))
continue;
}
fileObject = new JSONObject();
title = content.optString("title");
if (title.startsWith("Str."))
title = Str.format(request, title.substring(4));
fileObject.put("text", StringUtil.select(title, fileName));
relPath = FileUtil.getModulePath(file);
fileObject.put("path", relPath);
fileObject.put("fileName", fileName);
fileObject.put("inframe", Boolean.TRUE.equals(content
.opt("inframe")));
if (isFolder) {
if (type != 1)
fileObject.put("expanded", true);
fileObject.put("children", getModuleList(request, relPath,
roles, type));
} else {
pageLink = (String) content.opt("pageLink");
if (!StringUtil.isEmpty(pageLink))
fileObject.put("pageLink", pageLink);
fileObject.put("leaf", true);
}
fileObject.put("cls", "wb_pointer");
iconCls = content.optString("iconCls");
if (!StringUtil.isEmpty(iconCls))
fileObject.put("iconCls", iconCls);
if (type == 2 && !isFolder)
fileObject.put("checked", false);
fileArray.put(fileObject);
}
return fileArray;
}
/**
* 判断指定目录下是否具有需要登录的模块
* @param path 目录路径。
* @return true存在需要登录的模块false不存在需要登录的模块。
* @throws IOException
*/
private static boolean hasLoginModule(File path) throws IOException {
File[] files = FileUtil.listFiles(path);
for (File file : files) {
if (file.isDirectory()) {
if (hasLoginModule(file))
return true;
} else {
if (file.getName().endsWith(".xwl")) {
JSONObject content = XwlBuffer.get(FileUtil
.getModulePath(file), true);
if (Boolean.TRUE.equals(content.opt("loginRequired")))
return true;
}
}
}
return false;
}
/**
* 初始化主页。
*/
public static void initHome(HttpServletRequest request,
HttpServletResponse response) throws Exception {
String desktopString = Resource.getString(request, "desktop", null);
int treeWidth, viewIndex;
boolean treeCollapsed, treeHidden;
if (desktopString == null)
desktopString = Resource.getString("sys.home.desktop", null);
if (desktopString != null) {
JSONObject desktop = new JSONObject(desktopString);
treeWidth = desktop.optInt("treeWidth", 200);
viewIndex = desktop.optInt("viewIndex", 0);
treeCollapsed = desktop.optBoolean("treeCollapsed", false);
treeHidden = desktop.optBoolean("treeHidden", false);
JSONArray pages = desktop.optJSONArray("pages");
if (pages != null) {
int i, j = pages.length(), activeIndex = desktop.optInt(
"active", 0);
String url, title, pageLink, params, rawUrl;
JSONObject page, module, item;
JSONArray tabItems = new JSONArray();
for (i = 0; i < j; i++) {
page = pages.optJSONObject(i).getJSONObject("params");
rawUrl = page.optString("url");
url = FileUtil.getModuleFile(rawUrl, true);
module = XwlBuffer.get(url, true);
if (module == null) {
if (i <= activeIndex)
activeIndex--;
} else {
item = new JSONObject();
item.put("url", rawUrl);
item.put("title", page.opt("title"));
item.put("iconCls", (String) page.opt("iconCls"));
item.put("useIFrame", Boolean.TRUE.equals(module
.opt("inframe")));
params = page.optString("params");
if (!StringUtil.isEmpty(params))
item.put("params", new JSONObject(params));
pageLink = (String) module.opt("pageLink");
if (!StringUtil.isEmpty(pageLink))
JsonUtil.apply(item, new JSONObject(pageLink));
tabItems.put(item);
}
}
request.setAttribute("activeIndex", activeIndex);
request.setAttribute("tabItems", StringUtil.text(tabItems
.toString()));
request.getSession().setAttribute("userDesktop", StringUtil.text(tabItems
.toString()));
}
JSONArray portlets = desktop.optJSONArray("portlets");
if (portlets != null) {
int i, j = portlets.length(), k, l;
String url, title, pageLink;
JSONArray cols;
JSONObject portlet, module;
for (i = 0; i < j; i++) {
cols = portlets.optJSONArray(i);
l = cols.length();
for (k = 0; k < l; k++) {
portlet = cols.optJSONObject(k);
url = FileUtil.getModuleFile(portlet.optString("url"),
true);
module = XwlBuffer.get(url, true);
if (module == null) {
cols.remove(k);
k--;
l--;
continue;
}
title = (String) module.opt("title");
if (title.startsWith("Str."))
title = Str.format(request, title.substring(4));
portlet.put("title", StringUtil.select(title, FileUtil
.getFilename(url)));
portlet.put("iconCls", (String) module.opt("iconCls"));
portlet.put("useIFrame", Boolean.TRUE.equals(module
.opt("inframe")));
pageLink = (String) module.opt("pageLink");
if (!StringUtil.isEmpty(pageLink))
JsonUtil.apply(portlet, new JSONObject(pageLink));
}
}
request.setAttribute("portlets", StringUtil.text(portlets
.toString()));
}
} else {
treeWidth = 200;
viewIndex = 0;
treeCollapsed = false;
treeHidden = false;
}
request.setAttribute("treeWidth", treeWidth);
request.setAttribute("viewIndex", viewIndex);
request.setAttribute("treeCollapsed", treeCollapsed);
request.setAttribute("treeHidden", treeHidden);
request.setAttribute("hideSetDefaultDesktop", !XwlBuffer.canAccess(
request, "m?xwl=sys/portal/home/save-default-desktop"));
request.setAttribute("hideSetAllDesktop", !XwlBuffer.canAccess(request,
"m?xwl=sys/portal/home/save-all-desktop"));
}
/**
* 保存当前用户桌面。
*/
public static void saveDesktop(HttpServletRequest request,
HttpServletResponse response) throws Exception {
doSaveDesktop(request, 1);
}
/**
* 保存当前桌面为默认桌面。
*/
public static void saveAsDefaultDesktop(HttpServletRequest request,
HttpServletResponse response) throws Exception {
doSaveDesktop(request, 2);
}
/**
* 保存当前桌面为所有用户桌面。
*/
public static void saveAsAllDesktop(HttpServletRequest request,
HttpServletResponse response) throws Exception {
doSaveDesktop(request, 3);
}
/**
* 保存桌面信息。
* @param request 请求对象。
* @param type 保存类型1当前用户桌面2默认桌面3所有桌面
*/
private static void doSaveDesktop(HttpServletRequest request, int type)
throws Exception {
JSONObject desktop = new JSONObject();
/*desktop.put("treeWidth", Integer.parseInt(request
.getParameter("treeWidth")));
desktop.put("treeCollapsed", Boolean.parseBoolean(request
.getParameter("treeCollapsed")));
desktop.put("treeHidden", Boolean.parseBoolean(request
.getParameter("treeHidden")));*/
// desktop.put("viewIndex", Integer.parseInt(request
// .getParameter("viewIndex")));
desktop.put("pages", new JSONArray(request.getParameter("pages")));
desktop
.put("portlets",
new JSONArray(request.getParameter("portlets")));
desktop.put("active", Integer.parseInt(request.getParameter("active")));
if (type == 1) {
Resource.set(request, "desktop", desktop.toString());
} else {
if (type == 3)
DbUtil
.run(request,
"delete from WB_RESOURCE where RES_ID like 'desktop@%'");
Resource.set("sys.home.desktop", desktop.toString());
}
}
/**
* 获取主页应用列表树的节点列表。
*/
public static void getAppList(HttpServletRequest request,
HttpServletResponse response) throws Exception {
WebUtil.send(response, new JSONObject().put("children", getModuleList(
request, request.getParameter("path"), Session
.getRoles(request), 1)));
}
/**
* 获取权限模块列表树的节点列表。
*/
public static void getPermList(HttpServletRequest request,
HttpServletResponse response) throws Exception {
WebUtil.send(response, new JSONObject().put("children", getModuleList(
request, request.getParameter("path"), Session
.getRoles(request), 2)));
}
/**
* 获取用户模块权限模块列表树的节点列表。
*/
public static void getUserPermList(HttpServletRequest request,
HttpServletResponse response) throws Exception {
WebUtil.send(response, new JSONObject().put("children", getModuleList(
request, request.getParameter("path"), Session
.getRoles(request), 3)));
}
/**
* 设置桌面应用界面方案。
*/
public static void setTheme(HttpServletRequest request,
HttpServletResponse response) throws Exception {
String theme = request.getParameter("theme");
Value.set(request, "theme", theme);
WebUtil.setSessionValue(request, "sys.theme", theme);
}
/**
* 设置移动应用界面方案。
*/
public static void setTouchTheme(HttpServletRequest request,
HttpServletResponse response) throws Exception {
String theme = request.getParameter("theme");
Value.set(request, "touchTheme", theme);
WebUtil.setSessionValue(request, "sys.touchTheme", theme);
}
/**
* 初始化移动应用首页模块。
*/
public static void initTouchHome(HttpServletRequest request,
HttpServletResponse response) throws Exception {
HttpSession session = request.getSession(false);
boolean isNotLogin = session == null
|| session.getAttribute("sys.logined") == null;
request.setAttribute("isNotLogin", isNotLogin ? 1 : 0);
}
/**
* 搜索模块目录下指定名称的模块。
*/
private static void searchModule(HttpServletRequest request,
HttpServletResponse response, boolean isPerm) throws Exception {
JSONArray array = new JSONArray();
String query = request.getParameter("query").toLowerCase();
String[] roles = Session.getRoles(request);
if (query.isEmpty())
query = ".xwl";
doSearchFile(request, Base.modulePath, query.toLowerCase(), "", "",
array, isPerm, roles);
WebUtil.send(response, new JSONObject().put("rows", array));
}
/**
* 搜索主页模块目录下指定名称的模块。
*/
public static void searchAppModule(HttpServletRequest request,
HttpServletResponse response) throws Exception {
searchModule(request, response, false);
}
/**
* 搜索权限模块目录下指定名称的模块。
*/
public static void searchPermModule(HttpServletRequest request,
HttpServletResponse response) throws Exception {
searchModule(request, response, true);
}
/**
*
* 在指定目录下搜索文件。内部函数,用于递归搜索。
* @param request 请求对象。
* @param folder 目录。
* @param searchName 查找的文件名称关键字,任何包括该关键字的文件均将被列举。
* @param parentText 上级目录显示名称。
* @param array 用于存放搜索结果。
* @param isPerm 是否来自权限设置模块。
* @param roles 当前用户角色列表。
* @return 是否完成搜索如果搜索结果大于等于100项将返回true否则返回false。
* @throws Exception 搜索过程中发生异常。
*/
private static boolean doSearchFile(HttpServletRequest request,
File folder, String searchName, String parentText,
String parentFile, JSONArray array, boolean isPerm, String[] roles)
throws Exception {
File files[] = FileUtil.listFiles(folder);
String path, title;
for (File file : files) {
if (!XwlBuffer.canDisplay(file, roles, isPerm ? 3 : 1))
continue;
if (file.isDirectory()) {
File indexFile = new File(file, "folder.json");
String folderTitle, folderFile;
folderFile = file.getName();
if (indexFile.exists()) {
JSONObject jo = JsonUtil.readObject(indexFile);
folderTitle = jo.optString("title");
if (folderTitle.isEmpty())
folderTitle = folderFile;
} else
folderTitle = folderFile;
if (folderTitle.startsWith("Str."))
folderTitle = Str.format(request, folderTitle.substring(4));
// 查找权限时只查找模块不查找目录
if (!isPerm) {
if (folderTitle.toLowerCase().indexOf(searchName) != -1) {
JSONObject jo = new JSONObject();
jo.put("path", parentText);
jo.put("title", folderTitle);
jo.put("file", folderFile);
jo.put("parentFile", parentFile);
array.put(jo);
if (array.length() > 99)
return true;
}
}
if (doSearchFile(request, file, searchName, StringUtil.concat(
parentText, "/", folderTitle), StringUtil.concat(
parentFile, "/", folderFile), array, isPerm, roles))
return true;
} else {
path = FileUtil.getModulePath(file);
if (path.endsWith(".xwl")) {
JSONObject moduleData = XwlBuffer.get(path, false);
if (isPerm
&& Boolean.FALSE.equals(moduleData
.opt("loginRequired")))
continue;
title = moduleData.optString("title");
if (title.isEmpty())
title = path.substring(path.lastIndexOf('/') + 1);
if (title.startsWith("Str."))
title = Str.format(request, title.substring(4));
if (title.toLowerCase().indexOf(searchName) != -1) {
JSONObject jo = new JSONObject();
jo.put("path", parentText);
jo.put("title", title);
jo.put("file", file.getName());
jo.put("parentFile", parentFile);
array.put(jo);
if (array.length() > 99)
return true;
}
}
}
}
return false;
}
/**
* 获取移动模块列表。
*/
public static void getMobileAppList(HttpServletRequest request,
HttpServletResponse response) throws Exception {
ArrayList<JSONObject> appList = new ArrayList<JSONObject>();
JSONArray outputList = new JSONArray();
String[] roles;
roles = Session.getRoles(request);
scanMobileApp(request, appList, new File(Base.modulePath, "apps"),
roles);
for (JSONObject jo : appList)
outputList.put(jo);
WebUtil.send(response, new JSONObject().put("rows", outputList));
}
/**
* 递归扫描移动模块列表。
* @param request 请求对象。
* @param appList 获取的应用放在此列表对象中。
* @param path 模块目录。
* @param roles 用户角色。
*/
private static void scanMobileApp(HttpServletRequest request,
ArrayList<JSONObject> appList, File path, String[] roles)
throws Exception {
JSONObject content, item, viewport;
ArrayList<Entry<String, Integer>> fileNames = IDE.getSortedFile(path);
String title, url, image, glyph, fileName;
File file;
for (Entry<String, Integer> entry : fileNames) {
fileName = entry.getKey();
file = new File(path, fileName);
if (!XwlBuffer.canDisplay(file, roles, 2))
continue;
if (file.isDirectory()) {
scanMobileApp(request, appList, file, roles);
} else {
url = FileUtil.getModulePath(file);
content = XwlBuffer.get(url, true);
if (content == null)
continue;
viewport = getViewport(content);
// 没有Viewport的模块不能作为应用
if (viewport == null)
continue;
viewport = viewport.getJSONObject("configs");
item = new JSONObject();
title = content.optString("title");
if (title.startsWith("Str."))
title = Str.format(request, title.substring(4));
item.put("title", StringUtil.select(title, file.getName()));
image = viewport.optString("appImage");
if (image.isEmpty()) {
glyph = viewport.optString("appGlyph");
if (glyph.isEmpty())
item.put("glyph", "&#xf10a;");
else
item.put("glyph", StringUtil.concat("&#x", glyph, ";"));
} else
item.put("image", image);
item.put("url", url);
appList.add(item);
}
}
}
/**
* 扫描模块控件下的子控件列表获取Viewport控件如果没有找到返回null。
* @param rootNode module控件。
* @return Viewport控件或null。
*/
private static JSONObject getViewport(JSONObject rootNode) throws Exception {
int i, j;
JSONObject jo;
JSONArray items;
JSONObject module = (JSONObject) ((JSONArray) rootNode.opt("children"))
.opt(0);
items = (JSONArray) module.opt("children");
if (items == null)
return null;
j = items.length();
for (i = 0; i < j; i++) {
jo = ((JSONObject) items.opt(i));
if ("tviewport".equals(jo.opt("type")))
return jo;
}
return null;
}
}

View File

@@ -0,0 +1,272 @@
package com.wb.interact;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.StringReader;
import java.io.Writer;
import java.sql.Connection;
import java.sql.ResultSet;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.json.JSONArray;
import com.wb.tool.ExcelObject;
import com.wb.util.WebUtil;
/**
* 提供可交互的系统Web服务。
*/
public class Service {
/**
* 下载指定路径的文件或目录。接受参数files文件或目录路径列表zip是否启用zip压缩
*如果下载的是目录或多个文件将自动设置为truedownloadName下载时使用的文件名称。
* @param request 请求对象
* @param response 响应对象
* @param webFilesOnly 是否仅允许下载webapps目录下的非系统文件。
* @throws Exception 下载受限制的文件或读取文件发生异常。
*/
private static void download(HttpServletRequest request, HttpServletResponse response, boolean webFilesOnly)
throws Exception {
JSONArray ja = new JSONArray(WebUtil.fetch(request, "files"));
int i, j = ja.length();
File base = null, sysFolder = null, files[] = new File[j];
boolean useZip;
String filename, downloadName;
if (webFilesOnly) {
base = new File(com.wb.common.Base.path, "wb");
sysFolder = new File(com.wb.common.Base.path, "wb/system");
}
for (i = 0; i < j; i++) {
if (webFilesOnly) {
files[i] = new File(com.wb.common.Base.path, ja.optString(i));
if (!com.wb.util.FileUtil.isAncestor(base, files[i]) || com.wb.util.FileUtil.isAncestor(sysFolder, files[i])
|| com.wb.util.FileUtil.isAncestor(com.wb.common.Base.modulePath, files[i]))
com.wb.util.SysUtil.accessDenied();
} else
files[i] = new File(ja.optString(i));
}
useZip = com.wb.util.StringUtil.getBool(WebUtil.fetch(request, "zip")) || j > 1 || files[0].isDirectory();
downloadName = WebUtil.fetch(request, "downloadName");
if (com.wb.util.StringUtil.isEmpty(downloadName)) {
filename = files[0].getName();
if (j == 1) {
if (useZip)
filename = com.wb.util.FileUtil.removeExtension(filename) + ".zip";
} else {
File parentFile = files[0].getParentFile();
if (parentFile == null)
filename = "file.zip";
else
filename = parentFile.getName() + ".zip";
}
if (filename.equals(".zip") || filename.equals("/.zip"))
filename = "file.zip";
} else
filename = downloadName;
response.setHeader("content-type", "application/force-download");
response.setHeader("content-disposition", "attachment;" + WebUtil.encodeFilename(request, filename));
if (useZip) {
com.wb.util.ZipUtil.zip(files, response.getOutputStream());
response.flushBuffer();
} else
WebUtil.send(response, new FileInputStream(files[0]));
}
/**
* 下载任意目录内指定路径的文件或目录。详细信息见download方法。
* @param request 请求对象
* @param response 响应对象
* @throws Exception 读取文件发生异常。
* @see Service#download
*/
public static void downloadAtAll(HttpServletRequest request, HttpServletResponse response) throws Exception {
download(request, response, false);
}
/**
* 下载应用目录内指定路径的文件或目录。详细信息见download方法。
* @param request 请求对象
* @param response 响应对象
* @throws Exception 下载受限制的文件或读取文件发生异常。
* @see Service#download
*/
public static void downloadAtApp(HttpServletRequest request, HttpServletResponse response) throws Exception {
download(request, response, true);
}
/**
* 上传文件至指定目录。参数path上传路径file文件流[filename]文件名称,
* [unzip]是否解压缩zip文件。
* @param request 请求对象
* @param response 响应对象
* @throws Exception 上传过程发生异常。
*/
public static void upload(HttpServletRequest request, HttpServletResponse response) throws Exception {
boolean unzip = com.wb.util.StringUtil.getBool((String) request.getAttribute("unzip"));
boolean sync = com.wb.util.StringUtil.getBool((String) request.getAttribute("sync"));
String path = request.getAttribute("path").toString();
InputStream stream = (InputStream) request.getAttribute("file");
String filename = (String) request.getAttribute("filename");
File destPath, syncPath;
if (filename == null)
filename = (String) request.getAttribute("file__name");
if (unzip) {
if (filename.toLowerCase().endsWith(".zip")) {
destPath = new File(path);
com.wb.util.ZipUtil.unzip(stream, destPath);
if (sync) {
syncPath = com.wb.util.FileUtil.getSyncPath(destPath);
if (syncPath != null)
FileUtils.copyDirectory(destPath, syncPath);
}
} else
throw new Exception("Invalid zip file.");
} else {
destPath = new File(path, filename);
com.wb.util.FileUtil.saveStream(stream, destPath);
if (sync) {
syncPath = com.wb.util.FileUtil.getSyncPath(destPath);
if (syncPath != null)
FileUtils.copyFile(destPath, syncPath);
}
}
}
/**
* 获取指定id号进度的当前位置信息。
* @param request 请求对象
* @param response 响应对象
* @throws Exception 读取进度发生异常。
*/
public static void getProgress(HttpServletRequest request, HttpServletResponse response) throws Exception {
String id = request.getParameter("progressId");
HttpSession session = request.getSession(true);
Long pos = (Long) session.getAttribute("sys.upread." + id);
Long len = (Long) session.getAttribute("sys.uplen." + id);
double result;
if (pos == null || len == null || len == 0)
result = 0;
else
result = (double) pos / (double) len;
WebUtil.send(response, result);
}
/**
* 导入使用gzip压缩的JSON格式文件数据至指定数据库表。
* @param request 请求对象
* @param response 响应对象
* @throws Exception 导入发生异常。
*/
public static void importData(HttpServletRequest request, HttpServletResponse response) throws Exception {
boolean fromServer = com.wb.util.StringUtil.getBool(WebUtil.fetch(request, "fromServer"));
String filename;
InputStream stream;
if (fromServer) {
filename = WebUtil.fetch(request, "filename");
stream = new FileInputStream(new File(filename));
filename = filename.toLowerCase();
} else {
filename = ((String) request.getAttribute("file__name")).toLowerCase();
stream = (InputStream) request.getAttribute("file");
}
try {
String tableName = WebUtil.fetch(request, "table");
BufferedReader reader;
boolean trans = com.wb.util.StringUtil.getBool(WebUtil.fetch(request, "trans"));
Connection connection = com.wb.util.DbUtil.getConnection(WebUtil.fetch(request, "jndi"));
try {
if (trans)
connection.setAutoCommit(false);
if (filename.endsWith(".gz")) {
// JSON格式
reader = new BufferedReader(new InputStreamReader(new GZIPInputStream(stream), "utf-8"));
com.wb.util.DbUtil.importData(connection, tableName, reader);
} else {
if (filename.endsWith(".xls") || filename.endsWith(".xlsx")) {
// Excel格式
reader = new BufferedReader(
new StringReader(ExcelObject.excelToJson(stream, filename.endsWith(".xlsx"))));
com.wb.util.DbUtil.importData(connection, tableName, reader);
} else {
// 文本格式
reader = new BufferedReader(new InputStreamReader(stream, "utf-8"));
String fields = reader.readLine(), fieldList[];
char separator;
if (fields.indexOf('\t') == -1)
separator = ',';
else
separator = '\t';
fieldList = com.wb.util.StringUtil.split(fields, separator);
com.wb.util.DbUtil.importData(connection, tableName, reader, fieldList, separator);
}
}
if (trans)
connection.commit();
} finally {
com.wb.util.DbUtil.close(connection);
}
} finally {
stream.close();
}
}
/**
* 导出指定数据库结果集至客户端使用gzip压缩的JSON格式文件。
* @param request 请求对象
* @param response 响应对象
* @throws Exception 导出发生异常。
*/
public static void exportJson(HttpServletRequest request, HttpServletResponse response) throws Exception {
ResultSet rs = (ResultSet) com.wb.util.DbUtil.run(request, WebUtil.fetch(request, "sql"), WebUtil.fetch(request, "jndi"));
String filename = WebUtil.fetch(request, "filename");
if (filename == null)
filename = "data.gz";
response.setHeader("content-type", "application/force-download");
response.setHeader("content-disposition", "attachment;" + WebUtil.encodeFilename(request, filename));
Writer writer = new BufferedWriter(
new OutputStreamWriter(new GZIPOutputStream(response.getOutputStream()), "utf-8"));
try {
com.wb.util.DbUtil.exportData(rs, writer);
} finally {
writer.close();
}
response.flushBuffer();
}
/**
* 导出指定数据库结果集至服务器端使用gzip压缩的JSON格式文件。
*/
public static void exportJsonToServer(HttpServletRequest request, HttpServletResponse response) throws Exception {
ResultSet rs = (ResultSet) com.wb.util.DbUtil.run(request, WebUtil.fetch(request, "sql"), WebUtil.fetch(request, "jndi"));
String filename = WebUtil.fetch(request, "filename");
File file = new File(filename);
if (file.exists())
throw new Exception("文件 “" + filename + "” 已经存在。");
FileOutputStream fos = null;
Writer writer = null;
try {
fos = new FileOutputStream(file);
writer = new BufferedWriter(new OutputStreamWriter(new GZIPOutputStream(fos), "utf-8"));
com.wb.util.DbUtil.exportData(rs, writer);
} finally {
IOUtils.closeQuietly(writer);
fos.close();// 确保writer创建异常时fos被关闭
}
}
}

View File

@@ -0,0 +1,187 @@
package com.wb.interact;
import java.io.File;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.wb.common.KVBuffer;
import org.json.JSONArray;
import org.json.JSONObject;
import com.wb.common.XwlBuffer;
import com.wb.util.SortUtil;
import com.wb.util.SysUtil;
import com.wb.util.WebUtil;
public class Tools {
/**
* 获取数据字典数据库表树数据。
*/
public static void getDictTree(HttpServletRequest request, HttpServletResponse response) throws Exception {
String type = request.getParameter("type");
String jndi = request.getParameter("jndi");
String schema = request.getParameter("schema");
String result;
HashSet<String> tables, copyTables;
if ("db".equals(type)) {
tables = getDictTables(request, jndi);
copyTables = new HashSet<String>();//getSchemaList会删除tables中的值因此建立一个副本
for (String t : tables) {
copyTables.add(t);
}
result = com.wb.interact.DBE.getSchemaList(jndi, tables);
//如果没有Schema直接返回表列表
if (result == null)
result = com.wb.interact.DBE.getTableList(jndi, null, copyTables);
} else if ("schema".equals(type)) {
result = com.wb.interact.DBE.getTableList(jndi, schema, getDictTables(request, jndi));
} else
result = com.wb.interact.DBE.getDbList();
WebUtil.send(response, result);
}
/**
* 获取所有已经定义的字典表表名集。
* @param request 请求对象。
* @param jndi 数据库JNDI。
*/
private static HashSet<String> getDictTables(HttpServletRequest request, String jndi) throws Exception {
String tableName;
boolean otherDb = !"default".equals(jndi);
int jndiLen = jndi.length() + 1;
HashSet<String> tables = new HashSet<String>();
ResultSet rs = (ResultSet) com.wb.util.DbUtil.run(request, "select distinct TABLE_NAME from WB_DICT");
jndi = jndi.toUpperCase() + '.';
while (rs.next()) {
// DICT表名不区分大小写以统一不同数据库差异
tableName = rs.getString(1).toUpperCase();
if (otherDb) {
if (tableName.startsWith(jndi))
tables.add(tableName.substring(jndiLen));
} else if (tableName.indexOf('.') == -1) //表名不区分Schema只按表名识别
tables.add(tableName);
}
return tables;
}
/**
* 获取所有键名组成的数组并设置到request attribute名为keyNameList为属性中。
*/
public static void loadKeyNames(HttpServletRequest request, HttpServletResponse response) {
boolean isFirst = true;
StringBuilder buf = new StringBuilder();
ArrayList<Entry<String, ConcurrentHashMap<Object, String>>> keys = SortUtil
.sortKey(KVBuffer.buffer);
buf.append("[");
for (Entry<String, ConcurrentHashMap<Object, String>> key : keys) {
if (isFirst)
isFirst = false;
else
buf.append(",");
buf.append(com.wb.util.StringUtil.quote(key.getKey()));
}
buf.append("]");
request.setAttribute("keyNameList", com.wb.util.StringUtil.quote(buf.toString(), false));
}
/**
* 获取所有模块的角色信息。
*/
public static void getModulesPerm(HttpServletRequest request, HttpServletResponse response) throws Exception {
JSONObject perms = new JSONObject();
scanModulePerm(com.wb.common.Base.modulePath, perms);
WebUtil.send(response, perms);
}
/**
* 对指定目录下的模块进行扫描并获取这些模块的权限信息至JSONObject。
* @param path 路径。
* @param perms 获取的模块角色列表。
*/
private static void scanModulePerm(File path, JSONObject perms) throws Exception {
File files[] = com.wb.util.FileUtil.listFiles(path);
JSONObject jo;
JSONObject roles;
String filename;
for (File file : files) {
if (file.isDirectory()) {
scanModulePerm(file, perms);
} else {
filename = file.getName();
if (!filename.endsWith(".xwl"))
continue;
jo = com.wb.util.JsonUtil.readObject(file);
System.out.println(file.getAbsolutePath()+"==="+filename);
roles = (JSONObject) jo.opt("roles");
perms.put(com.wb.util.FileUtil.getModulePath(file), roles);
}
}
}
/**
* 删除所有模块中的指定角色信息。
*/
public static void delModulesPerm(HttpServletRequest request, HttpServletResponse response) throws Exception {
JSONArray destroy = new JSONArray(request.getParameter("destroy"));
int i, j = destroy.length();
if (j == 0)
return;
String[] roles = new String[j];
for (i = 0; i < j; i++)
roles[i] = destroy.getJSONObject(i).getString("ROLE_ID");
doDelPerm(com.wb.common.Base.modulePath, roles);
}
/**
* 对指定目录下的模块进行扫描,并删除模块文件内指定的角色信息。
* @param path 路径。
* @param roles 删除的模块角色列表。
*/
private static void doDelPerm(File path, String[] delRoles) throws Exception {
File files[] = com.wb.util.FileUtil.listFiles(path);
String filename;
for (File file : files) {
if (file.isDirectory()) {
doDelPerm(file, delRoles);
} else {
filename = file.getName();
if (filename.endsWith(".xwl"))
com.wb.interact.IDE.updateModule(file, null, delRoles, false);
}
}
}
/**
* 设置指定模块列表的角色信息。
*/
public static void setModulesPerm(HttpServletRequest request, HttpServletResponse response) throws Exception {
String[] roles = new String[1], userRoles = com.wb.common.Session.getRoles(request);
boolean checked = Boolean.parseBoolean(request.getParameter("checked"));
JSONArray pathList = new JSONArray(request.getParameter("path"));
int i, j = pathList.length();
File file;
roles[0] = request.getParameter("role");
for (i = 0; i < j; i++) {
file = new File(com.wb.common.Base.modulePath, pathList.getString(i));
// 禁止无权限的用户设置该权限
if (!file.isDirectory()) {
if (!XwlBuffer.canAccess(XwlBuffer.get(com.wb.util.FileUtil.getModulePath(file), false), userRoles))
SysUtil.accessDenied();
com.wb.interact.IDE.updateModule(file, null, roles, checked);
}
}
}
}

View File

@@ -0,0 +1,31 @@
package com.wb.interact;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.wb.util.WebUtil;
public class Utils {
/**
* 获取指定表的特定SQL语句。
*/
public static void getSQLDefines(HttpServletRequest request,
HttpServletResponse response) throws Exception {
String sql = request.getParameter("sql");
String type = request.getParameter("type");
String jndi = request.getParameter("jndi");
String table = request.getParameter("table");
String prefix = request.getParameter("prefix");
String[] sqlTypes = { "insert", "update", "delete", "select" };
String[] types = { "native", "params", "replace" };
String[] sqls = com.wb.util.DbUtil.buildSQLs(jndi, table, false, com.wb.util.StringUtil
.indexOf(types, type), null, null, null, null);
boolean isSelect = "select".equals(sql);
sql = sqls[com.wb.util.StringUtil.indexOf(sqlTypes, sql)];
if (!com.wb.util.StringUtil.isEmpty(prefix) && isSelect)
sql = com.wb.util.StringUtil.concat("select ", prefix, ".", com.wb.util.StringUtil
.replaceAll(sql.substring(7), ",", "," + prefix + "."));
WebUtil.send(response, sql);
}
}

View File

@@ -0,0 +1,221 @@
package com.wb.interact;
import java.io.IOException;
import java.util.Set;
import java.util.Map.Entry;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.json.JSONArray;
import org.json.JSONObject;
import com.wb.util.WebUtil;
public class VarConfig {
/**
* 获取变量树数据源。
*/
public static void getTree(HttpServletRequest request,
HttpServletResponse response) throws Exception {
JSONObject jo = com.wb.util.JsonUtil.readObject(com.wb.common.Var.file);
JSONObject tree = new JSONObject();
buildTree(jo, tree);
WebUtil.send(response, tree);
}
/**
* 设置变量值,更新缓存中的变量值并把变量值写进文件。
*/
public static synchronized void setVar(HttpServletRequest request,
HttpServletResponse response) throws Exception {
JSONObject config, folder, object = com.wb.util.JsonUtil.readObject(com.wb.common.Var.file);
JSONArray value;
String name = request.getParameter("name");
String path = request.getParameter("path");
String type = request.getParameter("type");
String valueStr = request.getParameter("value");
String configStr = request.getParameter("config");
boolean isNew = Boolean.parseBoolean(request.getParameter("isNew"));
Object folderObject, primativeVal;
if (name.indexOf('.') != -1)
throw new RuntimeException("名称 \"" + name + "\" 不能包含符号 “.”。");
folderObject = com.wb.util.JsonUtil.getValue(object, path, '.');
if (folderObject instanceof JSONObject) {
folder = (JSONObject) folderObject;
if (folder.has(name)) {
if (isNew)
throw new RuntimeException("名称 \"" + name + "\" 已经存在。");
} else {
if (!isNew)
throw new RuntimeException("名称 \"" + name + "\" 不存在。");
}
} else {
throw new RuntimeException("目录 \"" + path + "\" 不存在或不是一个目录。");
}
if (type.equals("int"))
primativeVal = Integer.parseInt(valueStr);
else if (type.equals("bool"))
primativeVal = Boolean.parseBoolean(valueStr);
else if (type.equals("double"))
primativeVal = Double.parseDouble(valueStr);
else
primativeVal = valueStr;
if (isNew) {
value = new JSONArray();
value.put(primativeVal);
value.put(request.getParameter("remark"));
if (configStr.isEmpty())
config = new JSONObject();
else
config = new JSONObject(configStr);
config.put("type", request.getParameter("type"));
value.put(config);
folder.put(name, value);
} else {
value = folder.getJSONArray(name);
value.put(0, primativeVal);
}
com.wb.util.FileUtil.syncSave(com.wb.common.Var.file, object.toString(2));
com.wb.common.Var.buffer.put(path + '.' + name, primativeVal);
com.wb.common.Var.loadBasicVars();
}
/**
* 删除变量。
*/
public static synchronized void delVar(HttpServletRequest request,
HttpServletResponse response) throws Exception {
String path = request.getParameter("path");
if (com.wb.util.StringUtil.isEmpty(path))
throw new RuntimeException("Empty path value.");
JSONArray names = new JSONArray(request.getParameter("names"));
JSONObject object = com.wb.util.JsonUtil.readObject(com.wb.common.Var.file), selFolder = (JSONObject) com.wb.util.JsonUtil
.getValue(object, path, '.');
int i, j = names.length();
for (i = 0; i < j; i++) {
selFolder.remove(names.optString(i));
}
com.wb.util.FileUtil.syncSave(com.wb.common.Var.file, object.toString(2));
for (i = 0; i < j; i++) {
com.wb.common.Var.buffer.remove(com.wb.util.StringUtil.concat(path, ".", names.optString(i)));
}
}
/**
* 添加、删除或修改目录。
*/
public static synchronized void setFolder(HttpServletRequest request,
HttpServletResponse response) throws Exception {
String type = request.getParameter("type");
JSONObject folder, object = com.wb.util.JsonUtil.readObject(com.wb.common.Var.file);
String path = request.getParameter("path"), name = request
.getParameter("name");
if (path == null)
throw new RuntimeException("null path parameter");
if (type.equals("add")) {
if (name == null)
throw new RuntimeException("null name parameter");
if (name.indexOf('.') != -1)
throw new RuntimeException("名称 \"" + name + "\" 不能包含符号 “.”。");
folder = (JSONObject) com.wb.util.JsonUtil.getValue(object, path, '.');
if (folder.has(name))
throw new RuntimeException("名称 \"" + name + "\" 已经存在。");
folder.put(name, new JSONObject());
} else if (type.equals("delete")) {
com.wb.util.JsonUtil.setValue(object, path, '.', null);
path += '.';
Set<Entry<String, Object>> es = com.wb.common.Var.buffer.entrySet();
String key;
for (Entry<String, Object> e : es) {
key = e.getKey();
if (key.startsWith(path))
com.wb.common.Var.buffer.remove(key);
}
} else if (type.equals("update")) {
String newPath, newName = request.getParameter("newName");
if (newName.indexOf('.') != -1)
throw new RuntimeException("名称 \"" + newName + "\" 不能包含符号 “.”。");
folder = (JSONObject) com.wb.util.JsonUtil.getValue(object, path, '.');
if (folder.has(newName))
throw new RuntimeException("名称 \"" + newName + "\" 已经存在。");
JSONObject jo = folder.getJSONObject(name);
folder.remove(name);
folder.put(newName, jo);
newPath = com.wb.util.StringUtil.concat(path, ".", newName, ".");
path = com.wb.util.StringUtil.concat(path, ".", name, ".");
Set<Entry<String, Object>> es = com.wb.common.Var.buffer.entrySet();
String key;
int oldPathLen = path.length();
for (Entry<String, Object> e : es) {
key = e.getKey();
if (key.startsWith(path)) {
com.wb.common.Var.buffer.remove(key);
com.wb.common.Var.buffer.put(newPath + key.substring(oldPathLen), e
.getValue());
}
}
}
com.wb.util.FileUtil.syncSave(com.wb.common.Var.file, object.toString(2));
}
/**
* 递归生成变量目录树。
* @param jo 当前变量目录。
* @param tree 当前树。
*/
private static void buildTree(JSONObject jo, JSONObject tree)
throws IOException {
Set<Entry<String, Object>> entrySet = jo.entrySet();
Object object;
String key;
JSONObject node;
JSONArray children = new JSONArray();
tree.put("children", children);
for (Entry<String, Object> entry : entrySet) {
key = entry.getKey();
object = jo.opt(key);
if (object instanceof JSONObject) {
node = new JSONObject();
node.put("text", key);
children.put(node);
buildTree((JSONObject) object, node);
}
}
}
/**
* 获取变量列表。
*/
public static void getVars(HttpServletRequest request,
HttpServletResponse response) throws Exception {
JSONObject jo = com.wb.util.JsonUtil.readObject(com.wb.common.Var.file);
JSONObject folder = (JSONObject) com.wb.util.JsonUtil.getValue(jo, request
.getParameter("path"), '.');
if (folder == null)
throw new IllegalArgumentException("指定路径变量不存在。");
Set<Entry<String, Object>> entrySet = folder.entrySet();
JSONArray items = new JSONArray(), jsonValue;
JSONObject item;
Object value;
for (Entry<String, Object> entry : entrySet) {
value = entry.getValue();
if (value instanceof JSONArray) {
jsonValue = (JSONArray) value;
item = new JSONObject();
item.put("name", entry.getKey());
item.put("value", jsonValue.opt(0));
item.put("remark", jsonValue.opt(1));
item.put("meta", jsonValue.opt(2));
items.put(item);
}
}
WebUtil.send(response, new JSONObject().put("rows", items));
}
}

View File

@@ -0,0 +1,117 @@
package com.wb.interact;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import com.wb.common.Var;
/**
* 图片验证码生成器。
*/
public class VerifyImage {
public static void outputImage(HttpServletRequest request,
HttpServletResponse response) throws Exception {
response.setHeader("Cache-Control",
"no-cache, no-store, max-age=0, must-revalidate");
response.setContentType("image/jpeg");
int width = 90, height = 20, i, x, y, xl, yl, fontStyle;
String varPrefix = "sys.session.verifyImage.", styles[] = { "plain",
"bold", "italic" };
fontStyle = com.wb.util.StringUtil.indexOf(styles, Var.getString(
varPrefix + "fontStyle").toLowerCase());
if (fontStyle == -1)
fontStyle = 1;
Font font = new Font(Var.getString(varPrefix + "fontName"), fontStyle,
16);
BufferedImage image = new BufferedImage(width, height,
BufferedImage.TYPE_INT_RGB);
Graphics g = image.getGraphics();
try {
Random random = new Random();
g.setColor(getRandColor(200, 250));
g.fillRect(1, 1, width - 1, height - 1);
g.setColor(new Color(102, 102, 102));
g.drawRect(0, 0, width - 1, height - 1);
g.setFont(font);
g.setColor(getRandColor(160, 200));
for (i = 0; i < 155; i++) {
x = random.nextInt(width - 1);
y = random.nextInt(height - 1);
xl = random.nextInt(6) + 1;
yl = random.nextInt(12) + 1;
g.drawLine(x, y, x + xl, y + yl);
}
for (i = 0; i < 70; i++) {
x = random.nextInt(width - 1);
y = random.nextInt(height - 1);
xl = random.nextInt(12) + 1;
yl = random.nextInt(6) + 1;
g.drawLine(x, y, x - xl, y - yl);
}
StringBuilder rand = new StringBuilder(5);
String str, key;
for (i = 0; i < 5; i++) {
str = getRandomChar();
rand.append(str);
g.setColor(new Color(20 + random.nextInt(110), 20 + random
.nextInt(110), 20 + random.nextInt(110)));
g.drawString(str, 16 * i + 7, 16);
}
HttpSession session = request.getSession(true);
key = request.getParameter("key");
if (com.wb.util.StringUtil.isEmpty(key))
key = "sys.verifyCode";
else if (key.indexOf('.') != -1)
throw new Exception("Illegal key.");
session.setAttribute(key, rand.toString());
} finally {
g.dispose();
}
ImageIO.write(image, "jpeg", response.getOutputStream());
response.flushBuffer();
}
private static Color getRandColor(int fc, int bc) {
Random random = new Random();
int r = fc + random.nextInt(bc - fc);
int g = fc + random.nextInt(bc - fc);
int b = fc + random.nextInt(bc - fc);
return new Color(r, g, b);
}
private static String getRandomChar() {
int rand = (int) Math.round(Math.random() * 2);
long itmp;
char ctmp;
switch (rand) {
case 1:
itmp = Math.round(Math.random() * 25 + 65);
ctmp = (char) itmp;
if (ctmp == 'I' || ctmp == 'L')
ctmp = '1';
else if (ctmp == 'O')
ctmp = '0';
return String.valueOf(ctmp);
case 2:
itmp = Math.round(Math.random() * 25 + 97);
ctmp = (char) itmp;
if (ctmp == 'i' || ctmp == 'l')
ctmp = '1';
else if (ctmp == 'o')
ctmp = '0';
return String.valueOf(ctmp);
default:
itmp = Math.round(Math.random() * 9);
return String.valueOf(itmp);
}
}
}

View File

@@ -0,0 +1,18 @@
package com.wb.task;
import java.util.Date;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
/**
* 在系统控制台打印指定字符串任务。
*/
public class DemoTask implements Job {
public void execute(JobExecutionContext context)
throws JobExecutionException {
System.out
.println(com.wb.util.DateUtil.format(new Date(), "hh:mm:ss") + ": 示例任务 3");
}
}

View File

@@ -0,0 +1,37 @@
package com.wb.task;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
/**
* 用于执行服务器端脚本任务的代理。
*/
public class ScriptProxy implements Job {
public void execute(JobExecutionContext context)
throws JobExecutionException {
long start = System.currentTimeMillis();
String jobDesc = context.getJobDetail().getDescription();
try {
if (com.wb.common.Var.taskLog)
com.wb.util.LogUtil.info("Start job " + jobDesc);
JobDataMap dataMap = context.getJobDetail().getJobDataMap();
String serverScript = dataMap.getString("job.serverScript");
if (!com.wb.util.StringUtil.isEmpty(serverScript))
com.wb.common.ScriptBuffer.run(dataMap.getString("job.id"), serverScript,
context);
if (com.wb.common.Var.taskLog)
com.wb.util.LogUtil.info(com.wb.util.StringUtil.concat("Finish job ", jobDesc, " in ",
com.wb.util.DateUtil.format(System.currentTimeMillis() - start)));
} catch (Throwable e) {
if (com.wb.common.Var.taskLog)
com.wb.util.LogUtil.error(com.wb.util.StringUtil.concat("Execute job ", jobDesc,
" failed with error ", com.wb.util.SysUtil.getRootError(e), " in ",
com.wb.util.DateUtil.format(System.currentTimeMillis() - start)));
if (com.wb.common.Var.printError)
throw new RuntimeException(e);
}
}
}

View File

@@ -0,0 +1,93 @@
package com.wb.tool;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* Created by yangxh on 2021/8/18.
*/
public class ColumnUpper {
public static String toUpper(String str){
JSONObject json = JSON.parseObject(str);
JSONObject metaData = json.getJSONObject("metaData");
if(metaData == null){
return str;
}
JSONArray fields = metaData.getJSONArray("fields");
JSONArray columns = json.getJSONArray("columns");
JSONArray rows = json.getJSONArray("rows");
// System.out.println("=================fields=================");
JSONArray fieldsCpy = new JSONArray();
metaData.put("fields", fieldsCpy);
convertToVal(fields, fieldsCpy, "name");
// System.out.println(fieldsCpy.toJSONString());
//
// System.out.println("=================columns=================");
JSONArray columnsCpy = new JSONArray();
json.put("columns", columnsCpy);
convertToVal(columns, columnsCpy, "dataIndex");
// System.out.println(JSON.toJSONString(columnsCpy, SerializerFeature.WriteNullStringAsEmpty));
//
// System.out.println("=================rows=================");
JSONArray rowsCpy = new JSONArray();
json.put("rows", rowsCpy);
convertToKey(rows, rowsCpy);
// System.out.println(JSON.toJSONString(rowsCpy, SerializerFeature.WriteNullStringAsEmpty));
return JSON.toJSONString(json, SerializerFeature.DisableCircularReferenceDetect, SerializerFeature.WriteMapNullValue);
}
private static void convertToVal(JSONArray fields, JSONArray fieldsCpy, String name){
for (int i=0; i<fields.size(); i++){
JSONObject field = fields.getJSONObject(i);
Set<String> set = field.keySet();
JSONObject fieldCpy = new JSONObject();
fieldsCpy.add(fieldCpy);
for (String key : set){
if (name.equals(key)){
fieldCpy.put(key, field.getString(key).toUpperCase());
}else {
fieldCpy.put(key, field.get(key));
}
}
}
}
private static void convertToKey(JSONArray fields, JSONArray fieldsCpy){
for (int i=0; i<fields.size(); i++){
JSONObject field = fields.getJSONObject(i);
Set<String> set = field.keySet();
JSONObject fieldCpy = new JSONObject();
fieldsCpy.add(fieldCpy);
for (String key : set){
fieldCpy.put(key.toUpperCase(), field.getString(key));
}
}
}
/**
* map类型的数据key转换为大写
* @param orgMap
* @return
*/
public static Map<String, Object> keyToUpperCase(Map<String, Object> orgMap) {
Map<String, Object> resultMap = new HashMap<>();
if (orgMap == null || orgMap.isEmpty()) {
return resultMap;
}
Set<Map.Entry<String,Object>> entrySet = orgMap.entrySet();
for (Map.Entry<String, Object> entry : entrySet) {
String key = entry.getKey();
Object value = entry.getValue();
resultMap.put(key.toUpperCase(), value);
}
return resultMap;
}
}

View File

@@ -0,0 +1,86 @@
package com.wb.tool;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
public class Console {
/**
* 向当前用户的浏览器控制台中输出指定对象的日志信息。
* @param request 请求对象。该请求对象用于关联到对应用户。
* @param object 打印的对象。
*/
public static void log(HttpServletRequest request, Object object) {
print(request, object, "log");
}
/**
* 向当前用户的浏览器控制台中输出指定对象的调试信息。
* @param request 请求对象。该请求对象用于关联到对应用户。
* @param object 打印的对象。
*/
public static void debug(HttpServletRequest request, Object object) {
print(request, object, "debug");
}
/**
* 向当前用户的浏览器控制台中输出指定对象的提示信息。
* @param request 请求对象。该请求对象用于关联到对应用户。
* @param object 打印的对象。
*/
public static void info(HttpServletRequest request, Object object) {
print(request, object, "info");
}
/**
* 向当前用户的浏览器控制台中输出指定对象的警告信息。
* @param request 请求对象。该请求对象用于关联到对应用户。
* @param object 打印的对象。
*/
public static void warn(HttpServletRequest request, Object object) {
print(request, object, "warn");
}
/**
* 向当前用户的浏览器控制台中输出指定对象的错误信息。
* @param request 请求对象。该请求对象用于关联到对应用户。
* @param object 打印的对象。
*/
public static void error(HttpServletRequest request, Object object) {
print(request, object, "error");
}
/**
* 向当前用户的浏览器控制台中输出指定对象的字符串信息。
* @param request 请求对象。该请求对象用于关联到对应用户。
* @param object 打印的对象。
* @param type 输出类型。
* @param encoded 是否被编码,被编码的内容可在客户端解码。
*/
public static void print(HttpServletRequest request, Object object, String type, boolean encoded) {
if (com.wb.common.Var.serverConsolePrint)
System.out.println(object);
if (com.wb.common.Var.consolePrint) {
try {
HttpSession session = request.getSession(false);
if (session != null) {
QueueWriter out = (QueueWriter) session.getAttribute("sys.out");
if (out != null)
out.print(object, type, encoded);
}
} catch (Throwable e) {
// 忽略
}
}
}
/**
* 向当前用户的浏览器控制台中输出指定对象的字符串信息。
* @param request 请求对象。该请求对象用于关联到对应用户。
* @param object 打印的对象。
* @param type 输出类型。
*/
public static void print(HttpServletRequest request, Object object, String type) {
print(request, object, type, false);
}
}

View File

@@ -0,0 +1,242 @@
package com.wb.tool;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.Collection;
import java.util.HashSet;
import java.util.Locale;
import javax.servlet.ServletOutputStream;
import javax.servlet.WriteListener;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
/**
* 定制HttpServlet响应对象用于获取数据。该类非继承自HttpServletResponseWrapper
* 直接实现HttpServletResponse接口。该类减少了对response进行不必要的更改以兼容所有服务器。
*/
public class CustomResponse implements HttpServletResponse {
/** 头名称集。用于响应containsHeader方法。 */
private HashSet<String> headerSet;
/** 实际响应对象。用于调用设置状态等方法。 */
private HttpServletResponse response;
/** 响应对象绑定的Writer。 */
private PrintWriter writer;
/** 响应对象绑定的ServletOutputStream对象。 */
private ServletOutputStream sos;
/** 响应对象绑定的ByteArrayOutputStream对象。 */
private ByteArrayOutputStream bos = new ByteArrayOutputStream(8192);
/** 是否已经提交。 */
private boolean submited = false;
/** 区域。*/
private Locale locale;
/** 内容类型。 */
private String contentType;
/** 字符串编码类型。 */
private String charEncoding;
/** 状态码。 */
private int statusCode = -1;
/** 是否使用Writer。 */
private boolean usingWriter;
/** 是否使用OutputStream。 */
private boolean usingOutputStream;
public CustomResponse(HttpServletResponse response) {
this.response = response;
headerSet = new HashSet<String>();
}
/** 获取输出数据的字节数组。 */
public byte[] getBytes() {
if (usingWriter)
writer.flush();
return bos.toByteArray();
}
/** 获取状态码,如果状态码未被设置返回-1。 */
public int getStatusCode() {
return statusCode;
}
// 以下所有方法说明略:见方法接口说明
public void addCookie(Cookie cookie) {
}
public void addDateHeader(String name, long date) {
headerSet.add(name);
}
public void addHeader(String name, String value) {
headerSet.add(name);
}
public void addIntHeader(String name, int value) {
headerSet.add(name);
}
public boolean containsHeader(String name) {
return headerSet.contains(name);
}
public String encodeRedirectURL(String url) {
return response.encodeRedirectURL(url);
}
public String encodeRedirectUrl(String url) {
return response.encodeRedirectURL(url);
}
public String encodeURL(String url) {
return response.encodeURL(url);
}
public String encodeUrl(String url) {
return response.encodeURL(url);
}
public void sendError(int sc) throws IOException {
statusCode = sc;
response.sendError(sc);
}
public void sendError(int sc, String msg) throws IOException {
statusCode = sc;
response.sendError(sc, msg);
}
public void sendRedirect(String location) throws IOException {
}
public void setDateHeader(String name, long date) {
headerSet.add(name);
}
public void setHeader(String name, String value) {
headerSet.add(name);
}
public void setIntHeader(String name, int value) {
headerSet.add(name);
}
public void setStatus(int sc) {
statusCode = sc;
response.setStatus(sc);
}
public void setStatus(int sc, String sm) {
statusCode = sc;
}
public void flushBuffer() throws IOException {
submited = true;
}
public int getBufferSize() {
return 8192;
}
public String getCharacterEncoding() {
if (charEncoding == null)
return response.getCharacterEncoding();
else
return charEncoding;
}
public String getContentType() {
return contentType;
}
public Locale getLocale() {
return locale;
}
public ServletOutputStream getOutputStream() throws IOException {
if (usingWriter)
throw new IllegalStateException("getWriter() has already been called for this response");
if (sos != null)
return sos;
sos = new ServletOutputStream() {
public void write(byte[] data, int offset, int length) {
if (!submited)
bos.write(data, offset, length);
}
public void write(int b) throws IOException {
if (!submited)
bos.write(b);
}
public boolean isReady() {
return false;
}
public void setWriteListener(WriteListener arg0) {
}
};
usingOutputStream = true;
return sos;
}
public PrintWriter getWriter() throws IOException {
if (usingOutputStream)
throw new IllegalStateException("getOutputStream() has already been called for this response");
if (writer != null)
return writer;
writer = new PrintWriter(new OutputStreamWriter(getOutputStream(), "utf-8"));
usingWriter = true;
return writer;
}
public boolean isCommitted() {
return submited;
}
public void reset() {
resetBuffer();
}
public void resetBuffer() {
if (!submited)
bos.reset();
}
public void setBufferSize(int size) {
}
public void setCharacterEncoding(String charset) {
charEncoding = charset;
}
public void setContentLength(int len) {
}
public void setContentType(String type) {
contentType = type;
}
public void setLocale(Locale loc) {
locale = loc;
}
public void setContentLengthLong(long arg0) {
}
public String getHeader(String arg0) {
return null;
}
public Collection<String> getHeaderNames() {
return null;
}
public Collection<String> getHeaders(String arg0) {
return null;
}
public int getStatus() {
return 0;
}
}

View File

@@ -0,0 +1,472 @@
package com.wb.tool;
import com.wb.common.Dictionary;
import com.wb.util.DbUtil;
import com.wb.util.StringUtil;
import com.wb.util.WebUtil;
import org.json.JSONArray;
import org.json.JSONObject;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.Types;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* 从数据库获取数据,并输出指定格式的脚本、图片或流数据至客户端。
*/
public class DataAutoGenProvider {
/** 请求对象。 */
public HttpServletRequest request;
/** 响应对象。 */
public HttpServletResponse response;
/** 记录集对象,用于输出数据。 */
public ResultSet resultSet;
/** 记录总数。 */
public Long totalCount;
/** 开始执行的时间。 */
public long startTime;
/** 开始行索引号首行为1包含该行。 */
public long beginIndex = 1;
/** 结束行索引号首行为1包含该行。 */
public long endIndex = Long.MAX_VALUE;
/** 输出的数据类别。可能值为array,object,tree,stream,download,image,gif,jpg,png,bmp */
public String type;
/** 字典定义的表名列表。 */
public String[] dictTableNames;
/** 字典定义中字段与表的对应关系。用于多表重名字段的表名指定。 */
public String dictFieldsMap;
/** 是否输出指定字段的键值字段键值字段名称为“字段名称__V”。 */
public boolean createKeyValues;
/** 字段元数据定义,定义的字段将覆盖系统自动生成的字段定义,未定义的字段仍将使用系统自动
*生成的字段定义。设置为"-"将不生成定义。 */
public String fields;
/** 字段元数据定义附加项定义的脚本将直接输出该属性适用于包含function语法的字段定义。 */
public String fieldsTag;
/** 输出到数组的附加信息。 */
public String tag;
/** 查询时默认最多允许单次输出到客户端的记录数。 */
public Integer limitRecords;
/** 导出时默认最多允许单次输出到客户端的记录数。 */
public Integer limitExportRecords;
/** 是否创建列模型默认为true。 */
public boolean createColumns = true;
/** 字段值转换为键值定义的名称列表。 */
public String keyDefines;
/** tree内置字段项。 */
private static JSONArray treeMeta = new JSONArray(
"[{name:'parentId',type:'auto',defaultValue:null,useNull:true},{name:'index',type:'int',defaultValue:-1,persist:false,convert:null},{name:'depth',type:'int',defaultValue:0,persist:false,convert:null},{name:'expanded',type:'bool',defaultValue:false,persist:false},{name:'expandable',type:'bool',defaultValue:true,persist:false},{name:'checked',type:'bool',defaultValue:null,persist:false},{name:'leaf',type:'bool',defaultValue:false},{name:'cls',type:'string',defaultValue:'',persist:false,convert:null},{name:'iconCls',type:'string',defaultValue:'',persist:false,convert:null},{name:'icon',type:'string',defaultValue:'',persist:false,convert:null},{name:'root',type:'bool',defaultValue:false,persist:false},{name:'isLast',type:'bool',defaultValue:false,persist:false},{name:'isFirst',type:'bool',defaultValue:false,persist:false},{name:'allowDrop',type:'bool',defaultValue:true,persist:false},{name:'allowDrag',type:'bool',defaultValue:true,persist:false},{name:'loaded',type:'bool',defaultValue:false,persist:false},{name:'loading',type:'bool',defaultValue:false,persist:false},{name:'href',type:'string',defaultValue:'',persist:false,convert:null},{name:'hrefTarget',type:'string',defaultValue:'',persist:false,convert:null},{name:'qtip',type:'string',defaultValue:'',persist:false,convert:null},{name:'qtitle',type:'string',defaultValue:'',persist:false,convert:null},{name:'qshowDelay',type:'int',defaultValue:0,persist:false,convert:null},{name:'children',type:'auto',defaultValue:null,persist:false,convert:null},{name:'visible',type:'bool',defaultValue:true,persist:false}]");
/**
* 获得结果集生成的脚本内容如果type不是array/object/tree将抛出异常。
* @throws Exception 读取数据库或输出过程发生异常。
*/
public String getScript(List data) throws Exception {
if ("array".equals(type) || com.wb.util.StringUtil.isEmpty(type))
return getArray(false,data);
else if ("tree".equals(type))
return getArray(true,data);
else if ("object".equals(type))
return getObject();
throw new IllegalArgumentException("The type is invalid.");
}
/**
* 按类型直接输出获得的结果集内容,包括脚本,二进制流或图片等。
* @throws Exception 读取数据库或输出过程发生异常。
*/
public void output(List data) throws Exception {
String script;
if ("array".equals(type) || com.wb.util.StringUtil.isEmpty(type))
script = getArray(false,data);
else if ("tree".equals(type))
script = getArray(true,data);
else if ("object".equals(type))
script = getObject();
else {
com.wb.util.DbUtil.outputBlob(resultSet, request, response, type);
return;
}
if (com.wb.util.WebUtil.jsonResponse(request))
com.wb.util.WebUtil.send(response, script, true);
else
com.wb.util.WebUtil.send(response, script);
}
/**
* 从结果集生成JSON格式的字符串。
* @param isTree 是否生成tree格式脚本。
* @return 生成的数组字符串。
* @throws Exception 读取过程发生异常。
*/
public String getArray(boolean isTree,List data) throws Exception {
int i, j, maxRecs;
long count = 0;
// 内置标记标记值为1时仅生成rows数据不生成字段定义和列模型数据
boolean rowOnly = com.wb.util.WebUtil.exists(request, "sys.rowOnly"), hasKeyDefine;
boolean hasDict = dictTableNames != null, first = true, hasTotal = totalCount != null;
Object object;
String val, kdValue, names[], keyNames[];
Object keyMaps[], kdMaps[];
JSONArray sysMeta;
JSONObject kd, dictFieldsObj;
int types[];
DictRecord dictRecord;
StringBuilder buf = new StringBuilder();
ResultSetMetaData meta = resultSet.getMetaData();
if (com.wb.util.WebUtil.exists(request, "sys.fromExport")) {
if (limitExportRecords == null)
maxRecs = com.wb.common.Var.limitExportRecords;
else if (limitExportRecords == -1)
maxRecs = Integer.MAX_VALUE;
else
maxRecs = limitExportRecords;
} else {
if (limitRecords == null)
maxRecs = com.wb.common.Var.limitRecords;
else if (limitRecords == -1)
maxRecs = Integer.MAX_VALUE;
else
maxRecs = limitRecords;
}
j = meta.getColumnCount();
names = new String[j];
keyNames = new String[j];
types = new int[j];
if (createKeyValues)
keyMaps = new Object[j];
else
keyMaps = null;
if (com.wb.util.StringUtil.isEmpty(dictFieldsMap))
dictFieldsObj = null;
else
dictFieldsObj = new JSONObject(dictFieldsMap);
hasKeyDefine = !com.wb.util.StringUtil.isEmpty(keyDefines);
if (hasKeyDefine) {
kd = new JSONObject(keyDefines);
kdMaps = new Object[j];
} else {
kd = null;
kdMaps = null;
}
for (i = 0; i < j; i++) {
names[i] = meta.getColumnLabel(i + 1);
names[i] = com.wb.util.DbUtil.getFieldName(names[i]);
if (com.wb.util.StringUtil.isEmpty(names[i]))
names[i] = "FIELD" + Integer.toString(i + 1);
if (createKeyValues) {
if (hasDict) {
dictRecord = com.wb.common.Dictionary.find(dictTableNames, names[i]);
if (dictRecord == null || dictRecord.keyName == null)
keyMaps[i] = null;
else
keyMaps[i] = com.wb.common.KVBuffer.buffer.get(dictRecord.keyName);
} else
keyMaps[i] = null;
}
if (hasKeyDefine) {
kdValue = (String) kd.opt(names[i]);
if (kdValue == null)
kdMaps[i] = null;
else
kdMaps[i] = com.wb.common.KVBuffer.buffer.get(kdValue);
}
keyNames[i] = com.wb.util.StringUtil.quote(names[i] + "__V");
names[i] = com.wb.util.StringUtil.quote(names[i]);
types[i] = meta.getColumnType(i + 1);
}
buf.append("{\"success\":true");
if (!rowOnly && !"-".equals(fields)) {
sysMeta = getFields(data,meta, createKeyValues ? dictTableNames : null, dictFieldsObj, kd);
if (!com.wb.util.StringUtil.isEmpty(fields))
mergeFields(sysMeta, new JSONArray(fields));
buf.append(",\"metaData\":{\"fields\":");
if (isTree)
buf.append(mergeFields(sysMeta, treeMeta).toString());
else
buf.append(sysMeta.toString());
if (!com.wb.util.StringUtil.isEmpty(fieldsTag)) {
buf.insert(buf.length() - 1, ',' + fieldsTag.substring(1, fieldsTag.length() - 1));
}
buf.append('}');
}
if (isTree)
buf.append(",\"children\":[");
else {
if (!rowOnly && (createColumns || hasDict)) {
buf.append(",\"columns\":");
buf.append(com.wb.util.DbUtil.getColumns(data,meta, dictTableNames, dictFieldsObj, kd, WebUtil.fetch(request, "sys.tenancyId")));
}
buf.append(",\"rows\":[");
}
while (resultSet.next()) {
count++;
if (count > maxRecs) {
count--;
break;
}
if (count < beginIndex)
continue;
else if (count > endIndex) {
if (hasTotal)
break;
else
continue;
}
if (first)
first = false;
else
buf.append(',');
buf.append('{');
for (i = 0; i < j; i++) {
if (i > 0)
buf.append(',');
object = com.wb.util.DbUtil.getObject(resultSet, i + 1, types[i]);
if (hasKeyDefine && kdMaps[i] != null)
object = com.wb.common.KVBuffer.getValue(((ConcurrentHashMap<?, ?>) kdMaps[i]), object);
buf.append(names[i]);
buf.append(':');
if (isTree) {
if (object == null)
val = "null";
else {
val = object.toString();
if (val.equals("[]") && "\"children\"".equals(names[i]))
val = "[]";
else
val = com.wb.util.StringUtil.encode(val);
}
buf.append(val);
} else
buf.append(com.wb.util.StringUtil.encode(object));
if (createKeyValues && keyMaps[i] != null) {
buf.append(',');
buf.append(keyNames[i]);
buf.append(':');
if (object == null)
buf.append("null");
else {
val = com.wb.common.KVBuffer.getValue(((ConcurrentHashMap<?, ?>) keyMaps[i]), object);
buf.append(com.wb.util.StringUtil.quote(val));
}
}
}
buf.append('}');
}
if (!hasTotal)
totalCount = count;
buf.append("],\"total\":");
buf.append(totalCount);
if (!com.wb.util.StringUtil.isEmpty(tag)) {
buf.append(',');
if (tag.charAt(0) == '{' && tag.charAt(tag.length() - 1) == '}')
buf.append(tag.substring(1, tag.length() - 1));
else
buf.append(tag);
}
if (startTime > 0) {
buf.append(",\"elapsed\":");
buf.append(Long.toString(System.currentTimeMillis() - startTime));
}
buf.append("}");
return buf.toString();
}
/**
* 从结果集首行记录生成指定格式的JSON对象字符串。
* @return 生成的JSON对象字符串。
* @throws Exception 读取过程发生异常。
*/
public String getObject() throws Exception {
JSONObject jo = new JSONObject();
if (resultSet.next()) {
int i, j, type;
ResultSetMetaData meta = resultSet.getMetaData();
String key, kdValue;
Object value;
JSONObject kd;
if (com.wb.util.StringUtil.isEmpty(keyDefines))
kd = null;
else
kd = new JSONObject(keyDefines);
j = meta.getColumnCount();
for (i = 0; i < j; i++) {
type = meta.getColumnType(i + 1);
key = meta.getColumnLabel(i + 1);
key = com.wb.util.DbUtil.getFieldName(key);
if (com.wb.util.StringUtil.isEmpty(key))
key = "FIELD" + Integer.toString(i + 1);
value = com.wb.util.DbUtil.getObject(resultSet, i + 1, type);
if (value == null)
value = JSONObject.NULL;
else {
if (kd != null) {
kdValue = (String) kd.opt(key);
if (kdValue != null) {
value = com.wb.common.KVBuffer.getValue(com.wb.common.KVBuffer.buffer.get(kdValue), value);
}
}
}
jo.put(key, value);
}
}
return jo.toString();
}
/**
* 把dest中的项合并到source中如果source中已经存在指定名称的项将被覆盖。
* @param source 合并项1。
* @param dest 合并项2。
* @return source本身。
*/
private JSONArray mergeFields(JSONArray source, JSONArray dest) {
int i, j = source.length() - 1, k, l = dest.length();
JSONObject sourceObj, destObj;
String destName;
for (k = 0; k < l; k++) {
destObj = dest.getJSONObject(k);
destName = destObj.getString("name");
for (i = j; i >= 0; i--) {
sourceObj = source.getJSONObject(i);
if (destName.equals(sourceObj.getString("name"))) {
source.remove(i);
j--;
break;
}
}
}
for (k = 0; k < l; k++) {
source.put(dest.getJSONObject(k));
}
return source;
}
/**
* 获取结果集元数据的字段定义信息。
*
* @param meta 结果集元数据。
* @param dictTableNames 字典表名列表如果该值不是null将创建字段对应的键值字段定义。
* 键值字段名称为“字段名__V”。
* @param dictFieldsMap 字典定义中字段与表的对应关系。用于多表重名字段的表名指定。
* @param keyDefines 字段值转换为键值定义的名称列表。
* @return 元数据定义。
* @throws Exception 读取过程发生异常。
*/
public static JSONArray getFields(List datacomment,ResultSetMetaData meta, String[] dictTableNames, JSONObject dictFieldsMap,
JSONObject keyDefines) throws Exception {
int i, j = meta.getColumnCount(), k, type;
String name, format, category, mapTable[] = new String[1];
JSONArray ja = new JSONArray();
JSONObject jo;
DictRecord dictRecord;
boolean hasDict = dictTableNames != null;
for (i = 0; i < j; i++) {
k = i + 1;
jo = new JSONObject();
name = meta.getColumnLabel(k);
name = DbUtil.getFieldName(name);
if (StringUtil.isEmpty(name))
name = "FIELD" + Integer.toString(k);
type = meta.getColumnType(k);
if (keyDefines != null && keyDefines.has(name))
category = "string";
else
category = getTypeCategory(type);
switch (type) {
case Types.TIMESTAMP:
format = "Y-m-d H:i:s.u";
break;
case Types.DATE:
format = "Y-m-d";
break;
case Types.TIME:
format = "H:i:s";
break;
default:
format = null;
}
jo.put("name", name);
jo.put("type", category);
for(int h=0;datacomment!=null&&h<datacomment.size();h++){
Map datacommentmap=(Map)datacomment.get(h);
if(datacommentmap.get("code").toString().equals(name)){
if(datacommentmap.get("name")!=null) {
jo.put("comment", datacommentmap.get("name").toString());
}else{
jo.put("comment", name);
}
}
}
if (format != null)
jo.put("dateFormat", format);
if (category.equals("string"))
jo.put("useNull", false);
ja.put(jo);
if (hasDict) {
dictRecord = null;
if (dictFieldsMap != null) {
mapTable[0] = dictFieldsMap.optString(name);
if (!StringUtil.isEmpty(mapTable[0]))
dictRecord = Dictionary.find(mapTable, name);
}
if (dictRecord != null)
dictRecord = Dictionary.find(dictTableNames, name);
if (dictRecord != null && dictRecord.keyName != null) {
jo = new JSONObject();
jo.put("name", name + "__V");
jo.put("type", "string");
jo.put("useNull", false);
ja.put(jo);
}
}
}
return ja;
}
/**
* 获取指定字段类型的大类别。
*
* @param type 字段类型。
* @return 类别。
*/
public static String getTypeCategory(int type) {
switch (type) {
case Types.BIGINT:
case Types.INTEGER:
case Types.SMALLINT:
case Types.TINYINT:
case Types.BOOLEAN:
case Types.BIT:
// boolean bit为兼容不同数据库返回int型
return "int";
case Types.DECIMAL:
case Types.DOUBLE:
case Types.FLOAT:
case Types.NUMERIC:
case Types.REAL:
return "float";
case Types.TIMESTAMP:
case Types.DATE:
case Types.TIME:
return "date";
default:
return "string";
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,351 @@
package com.wb.tool;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.alibaba.fastjson.JSON;
import com.wb.util.WebUtil;
import org.json.JSONArray;
import org.json.JSONObject;
/**
* 从数据库获取数据,并输出指定格式的脚本、图片或流数据至客户端。
*/
public class DataProvider {
/** 请求对象。 */
public HttpServletRequest request;
/** 响应对象。 */
public HttpServletResponse response;
/** 记录集对象,用于输出数据。 */
public ResultSet resultSet;
/** 记录总数。 */
public Long totalCount;
/** 开始执行的时间。 */
public long startTime;
/** 开始行索引号首行为1包含该行。 */
public long beginIndex = 1;
/** 结束行索引号首行为1包含该行。 */
public long endIndex = Long.MAX_VALUE;
/** 输出的数据类别。可能值为array,object,tree,stream,download,image,gif,jpg,png,bmp */
public String type;
/** 字典定义的表名列表。 */
public String[] dictTableNames;
/** 字典定义中字段与表的对应关系。用于多表重名字段的表名指定。 */
public String dictFieldsMap;
/** 是否输出指定字段的键值字段键值字段名称为“字段名称__V”。 */
public boolean createKeyValues;
/** 字段元数据定义,定义的字段将覆盖系统自动生成的字段定义,未定义的字段仍将使用系统自动
*生成的字段定义。设置为"-"将不生成定义。 */
public String fields;
/** 字段元数据定义附加项定义的脚本将直接输出该属性适用于包含function语法的字段定义。 */
public String fieldsTag;
/** 输出到数组的附加信息。 */
public String tag;
/** 查询时默认最多允许单次输出到客户端的记录数。 */
public Integer limitRecords;
/** 导出时默认最多允许单次输出到客户端的记录数。 */
public Integer limitExportRecords;
/** 是否创建列模型默认为true。 */
public boolean createColumns = true;
/** 字段值转换为键值定义的名称列表。 */
public String keyDefines;
/** tree内置字段项。 */
private static JSONArray treeMeta = new JSONArray(
"[{name:'parentId',type:'auto',defaultValue:null,useNull:true},{name:'index',type:'int',defaultValue:-1,persist:false,convert:null},{name:'depth',type:'int',defaultValue:0,persist:false,convert:null},{name:'expanded',type:'bool',defaultValue:false,persist:false},{name:'expandable',type:'bool',defaultValue:true,persist:false},{name:'checked',type:'bool',defaultValue:null,persist:false},{name:'leaf',type:'bool',defaultValue:false},{name:'cls',type:'string',defaultValue:'',persist:false,convert:null},{name:'iconCls',type:'string',defaultValue:'',persist:false,convert:null},{name:'icon',type:'string',defaultValue:'',persist:false,convert:null},{name:'root',type:'bool',defaultValue:false,persist:false},{name:'isLast',type:'bool',defaultValue:false,persist:false},{name:'isFirst',type:'bool',defaultValue:false,persist:false},{name:'allowDrop',type:'bool',defaultValue:true,persist:false},{name:'allowDrag',type:'bool',defaultValue:true,persist:false},{name:'loaded',type:'bool',defaultValue:false,persist:false},{name:'loading',type:'bool',defaultValue:false,persist:false},{name:'href',type:'string',defaultValue:'',persist:false,convert:null},{name:'hrefTarget',type:'string',defaultValue:'',persist:false,convert:null},{name:'qtip',type:'string',defaultValue:'',persist:false,convert:null},{name:'qtitle',type:'string',defaultValue:'',persist:false,convert:null},{name:'qshowDelay',type:'int',defaultValue:0,persist:false,convert:null},{name:'children',type:'auto',defaultValue:null,persist:false,convert:null},{name:'visible',type:'bool',defaultValue:true,persist:false}]");
/**
* 获得结果集生成的脚本内容如果type不是array/object/tree将抛出异常。
* @throws Exception 读取数据库或输出过程发生异常。
*/
public String getScript(List commentinfo) throws Exception {
if ("array".equals(type) || com.wb.util.StringUtil.isEmpty(type)) {
return ColumnUpper.toUpper(getArray(false, commentinfo));
}
else if ("tree".equals(type)) {
return getArray(true, commentinfo);
}
else if ("object".equals(type)) {
return getObject();
}
throw new IllegalArgumentException("The type is invalid.");
}
/**
* 按类型直接输出获得的结果集内容,包括脚本,二进制流或图片等。
* @throws Exception 读取数据库或输出过程发生异常。
*/
public void output(List comentinfo) throws Exception {
String script;
if ("array".equals(type) || com.wb.util.StringUtil.isEmpty(type))
script = ColumnUpper.toUpper(getArray(false,comentinfo));
else if ("tree".equals(type))
script = getArray(true,comentinfo);
else if ("object".equals(type))
script = getObject();
else {
com.wb.util.DbUtil.outputBlob(resultSet, request, response, type);
return;
}
if (com.wb.util.WebUtil.jsonResponse(request))
com.wb.util.WebUtil.send(response, script, true);
else
com.wb.util.WebUtil.send(response, script);
}
/**
* 从结果集生成JSON格式的字符串。
* @param isTree 是否生成tree格式脚本。
* @return 生成的数组字符串。
* @throws Exception 读取过程发生异常。
*/
public String getArray(boolean isTree,List comentinfo) throws Exception {
int i, j, maxRecs;
long count = 0;
// 内置标记标记值为1时仅生成rows数据不生成字段定义和列模型数据
boolean rowOnly = com.wb.util.WebUtil.exists(request, "sys.rowOnly"), hasKeyDefine;
boolean hasDict = dictTableNames != null, first = true, hasTotal = totalCount != null;
Object object;
String val, kdValue, names[], keyNames[];
Object keyMaps[], kdMaps[];
JSONArray sysMeta;
JSONObject kd, dictFieldsObj;
int types[];
DictRecord dictRecord;
StringBuilder buf = new StringBuilder();
ResultSetMetaData meta = resultSet.getMetaData();
if (com.wb.util.WebUtil.exists(request, "sys.fromExport")) {
if (limitExportRecords == null)
maxRecs = com.wb.common.Var.limitExportRecords;
else if (limitExportRecords == -1)
maxRecs = Integer.MAX_VALUE;
else
maxRecs = limitExportRecords;
} else {
if (limitRecords == null)
maxRecs = com.wb.common.Var.limitRecords;
else if (limitRecords == -1)
maxRecs = Integer.MAX_VALUE;
else
maxRecs = limitRecords;
}
j = meta.getColumnCount();
names = new String[j];
keyNames = new String[j];
types = new int[j];
if (createKeyValues)
keyMaps = new Object[j];
else
keyMaps = null;
if (com.wb.util.StringUtil.isEmpty(dictFieldsMap))
dictFieldsObj = null;
else
dictFieldsObj = new JSONObject(dictFieldsMap);
hasKeyDefine = !com.wb.util.StringUtil.isEmpty(keyDefines);
if (hasKeyDefine) {
kd = new JSONObject(keyDefines);
kdMaps = new Object[j];
} else {
kd = null;
kdMaps = null;
}
for (i = 0; i < j; i++) {
names[i] = meta.getColumnLabel(i + 1);
names[i] = com.wb.util.DbUtil.getFieldName(names[i]);
if (com.wb.util.StringUtil.isEmpty(names[i]))
names[i] = "FIELD" + Integer.toString(i + 1);
if (createKeyValues) {
if (hasDict) {
dictRecord = com.wb.common.Dictionary.find(dictTableNames, names[i]);
if (dictRecord == null || dictRecord.keyName == null)
keyMaps[i] = null;
else
keyMaps[i] = com.wb.common.KVBuffer.buffer.get(dictRecord.keyName);
} else
keyMaps[i] = null;
}
if (hasKeyDefine) {
kdValue = (String) kd.opt(names[i]);
if (kdValue == null)
kdMaps[i] = null;
else
kdMaps[i] = com.wb.common.KVBuffer.buffer.get(kdValue);
}
keyNames[i] = com.wb.util.StringUtil.quote(names[i] + "__V");
names[i] = com.wb.util.StringUtil.quote(names[i]);
types[i] = meta.getColumnType(i + 1);
}
buf.append("{\"success\":true");
if (!rowOnly && !"-".equals(fields)) {
sysMeta = com.wb.util.DbUtil.getFields(comentinfo,meta, createKeyValues ? dictTableNames : null, dictFieldsObj, kd);
if (!com.wb.util.StringUtil.isEmpty(fields))
mergeFields(sysMeta, new JSONArray(fields));
buf.append(",\"metaData\":{\"fields\":");
if (isTree)
buf.append(mergeFields(sysMeta, treeMeta).toString());
else
buf.append(sysMeta.toString());
if (!com.wb.util.StringUtil.isEmpty(fieldsTag)) {
buf.insert(buf.length() - 1, ',' + fieldsTag.substring(1, fieldsTag.length() - 1));
}
buf.append('}');
}
if (isTree)
buf.append(",\"children\":[");
else {
if (!rowOnly && (createColumns || hasDict)) {
buf.append(",\"columns\":");
buf.append(com.wb.util.DbUtil.getColumns(comentinfo,meta, dictTableNames, dictFieldsObj, kd, WebUtil.fetch(request, "sys.tenancyId")));
}
buf.append(",\"rows\":[");
}
while (resultSet.next()) {
count++;
if (count > maxRecs) {
count--;
break;
}
if (count < beginIndex)
continue;
else if (count > endIndex) {
if (hasTotal)
break;
else
continue;
}
if (first)
first = false;
else
buf.append(',');
buf.append('{');
for (i = 0; i < j; i++) {
if (i > 0)
buf.append(',');
object = com.wb.util.DbUtil.getObject(resultSet, i + 1, types[i]);
if (hasKeyDefine && kdMaps[i] != null)
object = com.wb.common.KVBuffer.getValue(((ConcurrentHashMap<?, ?>) kdMaps[i]), object);
buf.append(names[i]);
buf.append(':');
if (isTree) {
if (object == null)
val = "null";
else {
val = object.toString();
if (val.equals("[]") && "\"children\"".equals(names[i]))
val = "[]";
else
val = com.wb.util.StringUtil.encode(val);
}
buf.append(val);
} else
buf.append(com.wb.util.StringUtil.encode(object));
if (createKeyValues && keyMaps[i] != null) {
buf.append(',');
buf.append(keyNames[i]);
buf.append(':');
if (object == null)
buf.append("null");
else {
val = com.wb.common.KVBuffer.getValue(((ConcurrentHashMap<?, ?>) keyMaps[i]), object);
buf.append(com.wb.util.StringUtil.quote(val));
}
}
}
buf.append('}');
}
if (!hasTotal)
totalCount = count;
buf.append("],\"total\":");
buf.append(totalCount);
if (!com.wb.util.StringUtil.isEmpty(tag)) {
buf.append(',');
if (tag.charAt(0) == '{' && tag.charAt(tag.length() - 1) == '}')
buf.append(tag.substring(1, tag.length() - 1));
else
buf.append(tag);
}
if (startTime > 0) {
buf.append(",\"elapsed\":");
buf.append(Long.toString(System.currentTimeMillis() - startTime));
}
buf.append("}");
return buf.toString();
}
/**
* 从结果集首行记录生成指定格式的JSON对象字符串。
* @return 生成的JSON对象字符串。
* @throws Exception 读取过程发生异常。
*/
public String getObject() throws Exception {
JSONObject jo = new JSONObject();
if (resultSet.next()) {
int i, j, type;
ResultSetMetaData meta = resultSet.getMetaData();
String key, kdValue;
Object value;
JSONObject kd;
if (com.wb.util.StringUtil.isEmpty(keyDefines))
kd = null;
else
kd = new JSONObject(keyDefines);
j = meta.getColumnCount();
for (i = 0; i < j; i++) {
type = meta.getColumnType(i + 1);
key = meta.getColumnLabel(i + 1);
key = com.wb.util.DbUtil.getFieldName(key);
if (com.wb.util.StringUtil.isEmpty(key))
key = "FIELD" + Integer.toString(i + 1);
value = com.wb.util.DbUtil.getObject(resultSet, i + 1, type);
if (value == null)
value = JSONObject.NULL;
else {
if (kd != null) {
kdValue = (String) kd.opt(key);
if (kdValue != null) {
value = com.wb.common.KVBuffer.getValue(com.wb.common.KVBuffer.buffer.get(kdValue), value);
}
}
}
jo.put(key, value);
}
}
return jo.toString();
}
/**
* 把dest中的项合并到source中如果source中已经存在指定名称的项将被覆盖。
* @param source 合并项1。
* @param dest 合并项2。
* @return source本身。
*/
private JSONArray mergeFields(JSONArray source, JSONArray dest) {
int i, j = source.length() - 1, k, l = dest.length();
JSONObject sourceObj, destObj;
String destName;
for (k = 0; k < l; k++) {
destObj = dest.getJSONObject(k);
destName = destObj.getString("name");
for (i = j; i >= 0; i--) {
sourceObj = source.getJSONObject(i);
if (destName.equals(sourceObj.getString("name"))) {
source.remove(i);
j--;
break;
}
}
}
for (k = 0; k < l; k++) {
source.put(dest.getJSONObject(k));
}
return source;
}
}

View File

@@ -0,0 +1,33 @@
package com.wb.tool;
/** 字典记录实体类。 */
public class DictRecord {
/** 链接到字段id */
public String linkTo;
/** 是否显示在列表中 */
public boolean listable;
/** 是否可编辑 */
public boolean editable;
/** 显示名称,为空表示根据字段属性 */
public String dispText;
/** 显示宽度,-1表示根据字段属性 */
public int dispWidth;
/** 显示格式 */
public String dispFormat;
/** 自动换行 */
public boolean autoWrap;
/** 是否允许为空null表示根据字段属性 */
public Boolean allowBlank;
/** 是否只读null表示根据字段属性 */
public Boolean readOnly;
/** 键值名称 */
public String keyName;
/** 字段长度,-1表示根据字段属性 */
public int fieldSize;
/** 小数位数,-1表示根据字段属性 */
public int decimalPrecision;
/** 编辑时合法性验证函数 */
public String validator;
/** 自定义显示函数 */
public String renderer;
}

View File

@@ -0,0 +1,131 @@
package com.wb.tool;
import java.security.MessageDigest;
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
/**
* 提供常用的加密/解密方法。
*/
public class Encrypter {
/**
* DES字符常量。
*/
private static final String des = "DES";
/**
* MD5 16进制转码时的映射字母表。
*/
private static final String keyMap = "C2E8D9A3B5F14607";
/**
* 使用密钥通过DES算法加密指定的文本。
*
* @param text
* 需要加密的文本。
* @param key
* 8位字节的密钥。
* @return 加密后的文本。
* @throws Exception
* 加密过程发生异常。
*/
public static String encrypt(String text, String key) throws Exception {
return com.wb.util.StringUtil.encodeBase64(encrypt(text.getBytes("utf-8"), key));
}
/**
* 使用密钥解密通过DES算法加密的文本。
*
* @param text
* 需要解密的文本。
* @param key
* 8位字节的密钥。
* @return 解密后的文本。
* @throws Exception
* 解密过程发生异常。
*/
public static String decrypt(String text, String key) throws Exception {
return new String(decrypt(com.wb.util.StringUtil.decodeBase64(text), key), "utf-8");
}
/**
* 使用密钥通过DES算法加密指定的字节。
*
* @param bytes
* 需要加密的字节。
* @param key
* 8位字节的密钥。
* @return 加密后的字节。
* @throws Exception
* 加密过程发生异常。
*/
public static byte[] encrypt(byte[] bytes, String key) throws Exception {
byte[] keyBytes = key.getBytes("utf-8");
SecureRandom sr = new SecureRandom();
DESKeySpec dks = new DESKeySpec(keyBytes);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(des);
SecretKey securekey = keyFactory.generateSecret(dks);
Cipher cipher = Cipher.getInstance(des);
cipher.init(Cipher.ENCRYPT_MODE, securekey, sr);
return cipher.doFinal(bytes);
}
/**
* 使用密钥解密通过DES算法加密的字节。
*
* @param bytes
* 需要解密的字节。
* @param key
* 8位字节的密钥。
* @return 解密后的字节。
* @throws Exception
* 解密过程发生异常。
*/
public static byte[] decrypt(byte[] bytes, String key) throws Exception {
byte[] keyBytes = key.getBytes("utf-8");
SecureRandom sr = new SecureRandom();
DESKeySpec dks = new DESKeySpec(keyBytes);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(des);
SecretKey securekey = keyFactory.generateSecret(dks);
Cipher cipher = Cipher.getInstance(des);
cipher.init(Cipher.DECRYPT_MODE, securekey, sr);
return cipher.doFinal(bytes);
}
/**
* 对指定文本使用MD5算法进行加密使用此加密算法获得的值不可解密。
*
* @param text 需要加密的字节。
* @return 32位16进制字符组成的密码。
* @throws Exception 加密过程中发生异常。
*/
public static String getMD5(String text) throws Exception {
return getMD5(text.getBytes("utf-8"));
}
/**
* 对指定字节使用MD5算法进行加密使用此加密算法获得的值不可解密。
*
* @param bytes
* 需要加密的字节。
* @return 32位16进制字符组成的密码。
* @throws Exception
* 加密过程中发生异常。
*/
public static String getMD5(byte[] bytes) throws Exception {
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(bytes);
byte bt, codes[] = md.digest();
char str[] = new char[32];
int i, j = 0;
for (i = 0; i < 16; i++) {
bt = codes[i];
str[j++] = keyMap.charAt(bt >>> 4 & 0xf);
str[j++] = keyMap.charAt(bt & 0xf);
}
return new String(str);
}
}

View File

@@ -0,0 +1,342 @@
package com.wb.tool;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Iterator;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.json.JSONObject;
import com.wb.controls.ExtCombo;
import com.wb.util.StringUtil;
import com.wb.util.WebUtil;
public class ExcelForm {
/**
* 获取Excel 2007+模板文件转换得到的Web脚本字符串。这些Web脚本字符串可应用于前端容器控件用于直接生成表单。
* @param params 数据来源的参数对象。
* @param excelFile Excel 2007+模板文件。
* @param sheetIndex 引用模板文件中的Sheet索引号。
* @param excelFormAlign 生成的表单对齐方式有效值为left, center, right。
* @return 生成的Web脚本。
*/
public static String getHtml(JSONObject params, File excelFile, int sheetIndex, String excelFormAlign)
throws Exception {
if (excelFile.getName().toLowerCase().endsWith(".xls"))
throw new IllegalArgumentException("Excel file version requires 2007+");
FileInputStream is = new FileInputStream(excelFile);
try {
return getHtml(params, is, sheetIndex, excelFormAlign);
} finally {
is.close();
}
}
/**
* 获取Excel 2007+模板文件转换得到的Web脚本字符串。这些Web脚本字符串可应用于前端容器控件用于直接生成表单或报表。
* @param params 数据来源的参数对象。
* @param inputStream Excel 2007+模板文件输入流。
* @param sheetIndex 引用模板文件中的Sheet索引号。
* @param excelFormAlign 生成的表单对齐方式有效值为left, center, right。
* @return 生成的Web脚本。
*/
public static String getHtml(JSONObject params, InputStream inputStream, int sheetIndex, String excelFormAlign)
throws Exception {
XSSFWorkbook book;
XSSFSheet sheet;
XSSFRow row;
XSSFCell cell;
XSSFCellStyle style;
Iterator<Row> rows;
Iterator<Cell> cells;
String value, alignHtml;
StringBuilder tableHtml = new StringBuilder(), rowsHtml = new StringBuilder();
int i, lastCol, lastRow, defaultHeight, tableWidth, columnWidth, columnIndex, rowIndex, spanXY[],
maxColumnIndex;
boolean requiredField, isNumericCell;
Object mergeRegion[];
book = new XSSFWorkbook(inputStream);
try {
sheet = book.getSheetAt(sheetIndex);
com.wb.tool.ExcelObject.executeInstruction(sheet, params);
maxColumnIndex = getMaxColumnIndex(sheet);
defaultHeight = getPixcelHeight(sheet.getDefaultRowHeight());
mergeRegion = getMergeRegion(sheet);
rows = sheet.rowIterator();
lastRow = 0;
while (rows.hasNext()) {
row = (XSSFRow) rows.next();
rowIndex = row.getRowNum();
fillTR(rowsHtml, lastRow, rowIndex, defaultHeight, maxColumnIndex);
lastRow = rowIndex + 1;
cells = row.cellIterator();
rowsHtml.append("<tr height=\"");
rowsHtml.append(getPixcelHeight(row.getHeight()));
rowsHtml.append("px\">");
lastCol = 0;
requiredField = false;
while (cells.hasNext()) {
cell = (XSSFCell) cells.next();
columnIndex = cell.getColumnIndex();
spanXY = getSpanXY(mergeRegion, columnIndex, rowIndex);
fillTD(rowsHtml, lastCol, columnIndex);
lastCol = columnIndex + 1;
//位于合并区其他单元格直接返回不需要生成td
if (spanXY[0] == -1)
continue;
style = cell.getCellStyle();
if (spanXY[0] > 1)
lastCol += spanXY[0];
rowsHtml.append("<td");
//位于合并区首个单元格需要指定rowspan colspan
if (spanXY[0] > 1) {
rowsHtml.append(" colspan=\"");
rowsHtml.append(spanXY[0]);
rowsHtml.append("\"");
}
if (spanXY[1] > 1) {
rowsHtml.append(" rowspan=\"");
rowsHtml.append(spanXY[1]);
rowsHtml.append("\"");
}
rowsHtml.append(" style=\"white-space:nowrap;overflow:hidden;");
isNumericCell = com.wb.tool.ExcelObject.isNumericCell(cell);
rowsHtml.append(com.wb.tool.ExcelObject.getCellStyle(style, isNumericCell));
rowsHtml.append("\">");
value = com.wb.tool.ExcelObject.getDisplayText(cell);
if (!isNumericCell) {
value = WebUtil.replaceParams(params, value);
if (value.startsWith("{") && value.endsWith("}"))
value = createExpress(value, requiredField);
else
value = StringUtil.toHTML(value);
}
rowsHtml.append(value);
rowsHtml.append("</td>");
requiredField = value.startsWith("*");
}
fillTD(rowsHtml, lastCol, maxColumnIndex);
rowsHtml.append("</tr>");
}
//添加表格和首行列的宽度信息
tableWidth = 0;
tableHtml.append("<tr style=\"height:0;\">");
for (i = 0; i < maxColumnIndex; i++) {
columnWidth = getPixcelWidth(sheet.getColumnWidth(i));
tableHtml.append("<td style=\"border:none;padding:0;width:");
tableHtml.append(columnWidth);
tableHtml.append("px;\"></td>");
tableWidth += columnWidth;
}
tableHtml.append("</tr>");
//添加表格头
if ("left".equals(excelFormAlign))
alignHtml = "margin-left:8px;margin-right:auto;";
else if ("right".equals(excelFormAlign))
alignHtml = "margin-left:auto;margin-right:8px;";
else
alignHtml = "margin-left:auto;margin-right:auto;";
tableHtml.insert(0,
StringUtil.concat("<table style=\"margin-top:8px;margin-bottom:8px;", alignHtml,
"table-layout:fixed;border-collapse:collapse;\" cellspacing=\"0\" cellpadding=\"5\" width=\"",
Integer.toString(tableWidth), "px\">"));
//添加表格行
tableHtml.append(rowsHtml);
tableHtml.append("</table>");
} finally {
book.close();
}
return tableHtml.toString();
}
/**
* 根据指定单元格参数值创建控件表达式。
* @param value 单元格参数值。
* @param required 该控件的值是否为必须项。该属性仅适用于快捷表达式模式。
* @return 控件表达式。
*/
private static String createExpress(String value, boolean required) {
String innerText = value.substring(1, value.length() - 1).trim();
//关联控件:语法{%controlItemId}
if (innerText.startsWith("%"))
return "##" + innerText.substring(1);
else {
//快捷表达式:语法{itemId [xtype] [vtype]}默认xtype为textfield如果xtype前缀为%表示为键值
if (innerText.indexOf(':') == -1) {
String items[] = StringUtil.split(innerText, ' ');
StringBuilder script = new StringBuilder();
//itemId前加*表示不为空,加!允许为空,默认根据前一单元格标签是否加前缀*号来判断
if (items[0].startsWith("*")) {
required = true;
items[0] = items[0].substring(1);
} else if (items[0].startsWith("!")) {
required = false;
items[0] = items[0].substring(1);
}
script.append("##{itemId:\"");
script.append(items[0]);
script.append("\"");
if (required)
script.append(",allowBlank:false");
script.append(",xtype:\"");
if (items.length > 1) {
if (items[1].startsWith("%")) {
//绑定键值
script.append("combobox\",");
script.append(new ExtCombo().getkeyNameScript(items[1].substring(1)));
script.append('}');
} else {
script.append(items[1]);
if (items.length > 2) {
if ("image".equals(items[1]))
script.append("\",src:\"");
else
script.append("\",vtype:\"");
script.append(items[2]);
}
script.append("\"}");
}
} else {
script.append("textfield");
script.append("\"}");
}
return script.toString();
} else //普通表达式
return "##" + value;
}
}
/**
* 添加指定数量的空的单元格,以使后续单元格保持正确位置。
* @param html html脚本输出缓冲区。
* @param fromIndex 开始列索引号。
* @param toIndex 结束列索引号。
*/
private static void fillTD(StringBuilder html, int fromIndex, int toIndex) {
int i;
for (i = fromIndex; i < toIndex; i++) {
html.append("<td></td>");
}
}
/**
* 添加指定数量的空的行,以使后续行保持正确位置。
* @param html html脚本输出缓冲区。
* @param fromIndex 开始行索引号。
* @param toIndex 结束行索引号。
* @param defaultRowHeight 默认行高度。
* @param maxColumnIndex 最大列索引号。
*/
private static void fillTR(StringBuilder html, int fromIndex, int toIndex, int defaultRowHeight,
int maxColumnIndex) {
int i;
for (i = fromIndex; i < toIndex; i++) {
html.append("<tr height=\"");
html.append(defaultRowHeight);
html.append("px\"><td colspan=\"");
html.append(maxColumnIndex);
html.append("\"></tr>");
}
}
/**
* 根据行列号指定的单元格是否位于合并单元格区域来返回不同的信息。
* 如果位于合并区首个单元格返回该单元格的[colspan,rowspan]信息,
* 如果位于其他合并区返回[-1,-1]。如果不在合并区,返回[-2,-2]。
* @param mergeRegion 区域的合并信息。
* @param columnIndex 列索引号。
* @param rowIndex 行索引号。
* @return 单元格合并信息。
*/
private static int[] getSpanXY(Object[] mergeRegion, int columnIndex, int rowIndex) {
int info[], result[] = { -2, -2 };
for (Object obj : mergeRegion) {
info = (int[]) obj;
//如果位于区域内首个单元格
if (columnIndex == info[0] && rowIndex == info[1]) {
result[0] = info[2] - info[0] + 1;
result[1] = info[3] - info[1] + 1;
return result;
}
//如果位于区域内其他单元格
if (!(columnIndex < info[0] || columnIndex > info[2] || rowIndex < info[1] || rowIndex > info[3])) {
result[0] = -1;
result[1] = -1;
}
}
return result;
}
/**
* 获取Excel表格中最大一列的索引号。
* @param sheet Sheet对象。
* @return 最大一列的索引号。
*/
private static int getMaxColumnIndex(XSSFSheet sheet) {
XSSFRow row;
Iterator<Row> rows;
int index = 0;
rows = sheet.rowIterator();
while (rows.hasNext()) {
row = (XSSFRow) rows.next();
index = Math.max(index, row.getLastCellNum());
}
return index;
}
/**
* 获取列宽度转换为象素宽度。
* @param width 列宽度。
* @return 象素宽度。
*/
private static int getPixcelWidth(int width) {
return Math.round((width * 0.0281f));
}
/**
* 获取列高度转换为象素高度。
* @param height 列高度。
* @return 象素高度。
*/
private static int getPixcelHeight(int height) {
return Math.round(height / 15.12f);
}
/**
* 获取指定sheet所有的合并单元格信息。
* @param sheet Sheet对象。
* @return 所有的合并单元格信息。
*/
private static Object[] getMergeRegion(XSSFSheet sheet) {
CellRangeAddress rangeAddress;
int i, mergeCount, info[];
Object mergeRegion[];
mergeCount = sheet.getNumMergedRegions();
mergeRegion = new Object[mergeCount];
for (i = 0; i < mergeCount; i++) {
rangeAddress = sheet.getMergedRegion(i);
info = new int[4];
info[0] = rangeAddress.getFirstColumn();
info[1] = rangeAddress.getFirstRow();
info[2] = rangeAddress.getLastColumn();
info[3] = rangeAddress.getLastRow();
mergeRegion[i] = info;
}
return mergeRegion;
}
}

View File

@@ -0,0 +1,816 @@
package com.wb.tool;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import com.wb.util.DateUtil;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.FontUnderline;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFColor;
import org.apache.poi.xssf.usermodel.XSSFFont;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.json.JSONArray;
import org.json.JSONObject;
/**
* 用于Excel的工具方法。
*/
public class ExcelObject {
/**
* 把包含Excel数据的输入流内容转换为JSON格式的字符串。每行数据以JSONObject存储
* 不同行之间以换行符分隔。首行为字段名称,字段名称允许加备注,"()"内的内容将被忽略。
* @param inputStream 输入流。
* @param xlsxFormat Excel格式true为xlsxfalse为xls。
* @return 转换为JSON格式的字符串。
* @throws Exception 转换过程发生异常。
*/
public static String excelToJson(InputStream inputStream, boolean xlsxFormat) throws Exception {
Workbook book;
Sheet sheet;
Row row;
Cell cell;
Iterator<Row> rows;
Iterator<Cell> cells;
Object value;
int pos, pos1, colIndex, rowIndex = 0;
String valueStr;
ArrayList<String> fieldList = new ArrayList<String>();
StringBuilder text = new StringBuilder("");
if (xlsxFormat)
book = new XSSFWorkbook(inputStream);
else
book = new HSSFWorkbook(inputStream);
try {
sheet = book.getSheetAt(0);
rows = sheet.rowIterator();
while (rows.hasNext()) {
if (rowIndex > 1)
text.append("\n{");
else if (rowIndex > 0)
text.append('{');
row = rows.next();
cells = row.cellIterator();
colIndex = 0;
while (cells.hasNext()) {
cell = cells.next();
value = getCellValue(cell);
if (rowIndex == 0) {
if (value == null)
throw new NullPointerException("Field name has null value.");
valueStr = value.toString();
pos = valueStr.indexOf('(');
pos1 = valueStr.indexOf("");
if (pos1 != -1 && (pos == -1 || pos1 < pos))
pos = pos1;
if (pos == -1)
fieldList.add(valueStr);
else
fieldList.add(valueStr.substring(0, pos));
} else {
if (colIndex > 0)
text.append(',');
if (colIndex >= fieldList.size())
throw new RuntimeException(
"Row " + (rowIndex + 1) + " column " + (colIndex + 1) + " is out of bounds.");
text.append(com.wb.util.StringUtil.quote(fieldList.get(colIndex)));
text.append(':');
text.append(com.wb.util.StringUtil.encode(value));
}
colIndex++;
}
if (rowIndex > 0)
text.append('}');
rowIndex++;
}
} finally {
book.close();
}
return text.toString();
}
/**
* 获取单元格用于显示的文本。
* @param cell 单元格。
* @return 单元格值。如果null返回空串。
*/
public static String getDisplayText(Cell cell) {
Object object = getCellValue(cell);
if (object == null)
return "";
else {
if (object instanceof Boolean)
return object.toString();
else if (object instanceof Double) {
double doubleVal = (Double) object;
String value, format = cell.getCellStyle().getDataFormatString();
//General为单元格常规数据格式按数值原样进行输出
if ("General".equals(format))
value = com.wb.util.StringUtil.doubleToString(doubleVal);
else
value = com.wb.util.StringUtil.formatNumber(doubleVal, convertNumFormat(format));
//多节格式,负数显示为红色
if (doubleVal < 0 && format != null && format.indexOf(';') != -1 && format.indexOf("[Red]") != -1)
value = "<span style=\"color:red;\">" + value + "</span>";
return value;
} else if (object instanceof Date)
return DateUtil.format((Date) object, "yyyy/M/d");
else
return object.toString();
}
}
/**
* 转换Excel数字格式为Java可用的数字格式。
* @param format excel数字格式。
* @return java数字格式。
*/
public static String convertNumFormat(String format) {
if (format == null)
return "0";
String keys[] = { "\"", "_", "(", ")" };
int pos = format.indexOf(';');
if (pos != -1)
format = format.substring(0, pos);
for (String key : keys) {
format = com.wb.util.StringUtil.replaceAll(format, key, "");
}
return format;
}
/**
* 根据对齐方法字符串返回对应Excel对齐值。
* @param align 对齐字符串。
* @return 对齐值。
*/
public static short getAlignment(String align, short defaultAlign) {
if ("right".equals(align))
return CellStyle.ALIGN_RIGHT;
else if ("center".equals(align))
return CellStyle.ALIGN_CENTER;
else if ("left".equals(align))
return CellStyle.ALIGN_LEFT;
else
return defaultAlign;
}
/**
* 根据Excel单元格的水平对齐值返回对应的HTML水平对齐字符串。
* @param align Excel单元格的对齐值。
* @return HTML对齐字符串。
*/
public static String toHtmlAlign(short align, String defaultAlign) {
switch (align) {
case CellStyle.ALIGN_LEFT:
return "left";
case CellStyle.ALIGN_CENTER:
return "center";
case CellStyle.ALIGN_RIGHT:
return "right";
case CellStyle.ALIGN_JUSTIFY:
return "justify";
default:
return defaultAlign;
}
}
/**
* 根据Excel单元格的垂直对齐值返回对应的HTML垂直对齐字符串。
* @param align Excel单元格的对齐值。
* @return HTML对齐字符串。
*/
public static String toHtmlVerticalAlign(short align, String defaultAlign) {
switch (align) {
case CellStyle.VERTICAL_TOP:
return "top";
case CellStyle.VERTICAL_CENTER:
return "middle";
case CellStyle.VERTICAL_BOTTOM:
return "bottom";
default:
return defaultAlign;
}
}
/**
* 根据设置的变量创建并获取Excel指定版本的workbook对象。
* @return 新创建的workbook对象。
*/
public static Workbook getBook() {
if (com.wb.common.Var.getBool("sys.service.excel.xlsx"))
return new XSSFWorkbook();
else
return new HSSFWorkbook();
}
/**
* 根据设置的变量获取Excel文件的扩展名.xls或.xlsx。
* @return 指定版本的Excel文件扩展名。
*/
public static String getExtName() {
if (com.wb.common.Var.getBool("sys.service.excel.xlsx"))
return ".xlsx";
else
return ".xls";
}
/**
* 获取前端日期时间格式对应到Excel的日期时间格式。
* @param format 日期时间格式。
* @param returnDefault 如果格式不支持是否返回默认格式true默认格式false返回null。
* @return 转换后的Excel日期时间格式。
*/
public static String toExcelDateFormat(String format, boolean returnDefault) {
String[] unSupportFormats = { "N", "S", "w", "z", "W", "t", "L", "o", "u", "O", "P", "T", "Z", "c", "U", "MS",
"time", "timestamp" };
String[][] supportFormats = { { "d", "dd" }, { "D", "aaa" }, { "j", "d" }, { "l", "aaaa" }, { "F", "mmmm" },
{ "m", "mm" }, { "M", "mmm" }, { "n", "m" }, { "Y", "yyyy" }, { "y", "yy" }, { "a", "am/pm" },
{ "A", "AM/PM" }, { "g", "h" }, { "G", "hh" }, { "h", "h" }, { "H", "hh" }, { "i", "mm" },
{ "s", "ss" } };
for (String s : unSupportFormats) {
if (format.indexOf(s) != -1)
return returnDefault ? "yyyy-mm-dd" : null;
}
for (String[] s : supportFormats) {
format = com.wb.util.StringUtil.replaceAll(format, s[0], s[1]);
}
return format;
}
/**
* 获取前端日期时间格式对应到Java的日期时间格式。
* @param format 日期时间格式。
* @param returnDefault 如果格式不支持是否返回默认格式true默认格式false返回null。
* @return 转换后的Java日期时间格式。
*/
public static String toJavaDateFormat(String format, boolean returnDefault) {
String[] unSupportFormats = { "N", "S", "D", "w", "z", "W", "t", "L", "o", "O", "P", "T", "Z", "c", "U", "F",
"MS", "l", "M", "time", "timestamp" };
String[][] supportFormats = { { "y", "yy" }, { "Y", "yyyy" }, { "m", "MM" }, { "n", "M" }, { "d", "dd" },
{ "j", "d" }, { "H", "HH" }, { "h", "hh" }, { "G", "H" }, { "g", "h" }, { "i", "mm" }, { "s", "ss" },
{ "u", "SSS" }, { "a", "'_x'" }, { "A", "'_X'" } };
for (String s : unSupportFormats) {
if (format.indexOf(s) != -1)
return returnDefault ? "yyyy-MM-dd" : null;
}
for (String[] s : supportFormats) {
format = com.wb.util.StringUtil.replaceAll(format, s[0], s[1]);
}
return format;
}
/**
* 把Excel的单元格样式转换为HTML的样式。
* @param
* @return 转换后的文本。
*/
public static String getCellStyle(XSSFCellStyle style, boolean isNumber) {
StringBuilder buf = new StringBuilder();
XSSFFont font = style.getFont();
XSSFColor color;
String rgb;
//设置对齐方式
buf.append("text-align:");
buf.append(toHtmlAlign(style.getAlignment(), isNumber ? "right" : "left"));
buf.append(";vertical-align:");
buf.append(toHtmlVerticalAlign(style.getVerticalAlignment(), "middle"));
//设置字体
buf.append(";font-family:");
buf.append(font.getFontName());
buf.append(";font-size:");
buf.append(font.getFontHeightInPoints());
buf.append("pt;font-weight:");
buf.append(font.getBoldweight());
rgb = getRGBColor(font.getXSSFColor());
if (rgb != null) {
buf.append(";color:");
buf.append(rgb);
}
color = style.getFillForegroundXSSFColor();
if (color != null) {
rgb = getRGBColor(color);
if (rgb != null) {
buf.append(";background-color:");
buf.append(rgb);
}
}
if (font.getItalic())
buf.append(";font-style:italic;");
if (font.getStrikeout())
buf.append(";text-decoration:line-through;");
else if (FontUnderline.valueOf(font.getUnderline()) != FontUnderline.NONE)
buf.append(";text-decoration:underline;");
//设置边框线
buf.append(";border-top:");
buf.append(getBorderStyle(style.getBorderTop(), style.getTopBorderXSSFColor()));
buf.append(";border-right:");
buf.append(getBorderStyle(style.getBorderRight(), style.getRightBorderXSSFColor()));
buf.append(";border-bottom:");
buf.append(getBorderStyle(style.getBorderBottom(), style.getBottomBorderXSSFColor()));
buf.append(";border-left:");
buf.append(getBorderStyle(style.getBorderLeft(), style.getLeftBorderXSSFColor()));
return buf.toString();
}
/**
* 获取边框css样式。
* @param border excel边框样式。
* @param color 边框颜色。
* @return 边框css样式。
*/
private static String getBorderStyle(short border, XSSFColor color) {
String width, style, rgb;
switch (border) {
case CellStyle.BORDER_DOTTED:
case CellStyle.BORDER_HAIR:
width = "thin";
style = "dotted";
break;
case CellStyle.BORDER_DASH_DOT:
case CellStyle.BORDER_DASH_DOT_DOT:
case CellStyle.BORDER_SLANTED_DASH_DOT:
case CellStyle.BORDER_DASHED:
width = "thin";
style = "dashed";
break;
case CellStyle.BORDER_DOUBLE:
width = "thin";
style = "double";
break;
case CellStyle.BORDER_MEDIUM:
width = "medium";
style = "solid";
break;
case CellStyle.BORDER_MEDIUM_DASH_DOT:
case CellStyle.BORDER_MEDIUM_DASH_DOT_DOT:
case CellStyle.BORDER_MEDIUM_DASHED:
width = "medium";
style = "dashed";
break;
case CellStyle.BORDER_NONE:
return "none";
case CellStyle.BORDER_THICK:
width = "thick";
style = "solid";
break;
default:
width = "thin";
style = "solid";
}
rgb = getRGBColor(color);
if (rgb == null)
rgb = "black";
return String.format("%s %s %s", width, style, rgb);
}
/**
* 把Excel颜色转换为RGB格式的颜色字符串。
* @param color Excel颜色。
* @return RGB格式的颜色字符串。如果颜色无效或未设置返回null。
*/
public static String getRGBColor(XSSFColor color) {
if (color == null)
return null;
int red, green, blue;
byte[] xrgb =null;
//color.getRgbWithTint();
if (xrgb == null)
return null;
red = (xrgb[0] < 0) ? (xrgb[0] + 256) : xrgb[0];
green = (xrgb[1] < 0) ? (xrgb[1] + 256) : xrgb[1];
blue = (xrgb[2] < 0) ? (xrgb[2] + 256) : xrgb[2];
return String.format("#%02x%02x%02x", red, green, blue);
}
/**
* 获取单元格的值。
* @param cell 单元格。
* @return 单元格值。如果为空返回null。
*/
public static Object getCellValue(Cell cell) {
switch (cell.getCellType()) {
case Cell.CELL_TYPE_FORMULA:
case Cell.CELL_TYPE_NUMERIC:
if (isDateFormatted(cell))
return cell.getDateCellValue();
else
return cell.getNumericCellValue();
case Cell.CELL_TYPE_STRING:
return cell.getStringCellValue();
case Cell.CELL_TYPE_BOOLEAN:
return cell.getBooleanCellValue();
default:
return null;
}
}
/**
* 检查单元格是否格式化为日期。
* @param cell 需要判断的单元格对象。
* @return true格式化为日期false没有格式化为日期。
*/
public static boolean isDateFormatted(Cell cell) {
//该方法区别于DateUtil.isCellDateFormatted方法采用格式是否包括指定字符来判断。
String format = cell.getCellStyle().getDataFormatString();
if (format == null)
return true;
if (format.toLowerCase().equals("general"))
return false;
if (format.startsWith("reserved"))
return true;
int pos = format.lastIndexOf(']');
if (pos != -1)
format = format.substring(pos + 1);
return format.indexOf('0') == -1 && format.indexOf('#') == -1;
}
/**
* 判断指定单元格是否为数字或公式单元格。日期类型单元格使用数字存储,因此也属于数字单元格。
* @param cell 单元格。
* @return true数字或公式单元格false其他类型单元格。
*/
public static boolean isNumericCell(Cell cell) {
int cellType = cell.getCellType();
return cellType == Cell.CELL_TYPE_FORMULA || cellType == Cell.CELL_TYPE_NUMERIC;
}
/**
* 填充表格数据到指定开始位置的单元格。新生成的单元格样式同起始单元格。
* @param sheet 填充的sheet对象。
* @param fill 填充的指令数据数组每一项为一个对象。对象中name为参数名称x为起始单元格x坐标y为起始单元y坐标,
* mergeCols是合并列mergeRows是合并行。
* @param params 参数对象。
*/
public static void fillRows(Sheet sheet, JSONArray fill, JSONObject params) {
if (fill == null)
return;
int i, j = fill.length(), k, l, m, n, x, y;
String fields[];
JSONObject obj, mergeConfig;
JSONArray mergeInfo, mergeRows, mergeCols, mergeItem, subItem, data;
for (i = 0; i < j; i++) {
obj = fill.optJSONObject(i);
//添加数据
x = obj.optInt("x");
y = obj.optInt("y");
data = com.wb.util.JsonUtil.getArray(params.opt(obj.optString("name")));
fields = createRows(sheet, x, y, data);
if (data == null)
continue;
//生成单元格合并的配置信息
try {
mergeConfig = new JSONObject();
mergeRows = obj.optJSONArray("mergeRows");
mergeCols = obj.optJSONArray("mergeCols");
mergeInfo = new JSONArray();
mergeConfig.put("mergeInfo", mergeInfo);
if (mergeRows != null) {
mergeConfig.put("mergeRows", true);
}
for (String field : fields) {
mergeItem = new JSONArray();
if (mergeRows != null)
mergeItem.put(mergeRows.indexOf(field) != -1);
else
mergeItem.put(false);
mergeItem.put(JSONObject.NULL);
mergeInfo.put(mergeItem);
}
if (mergeCols != null) {
mergeConfig.put("mergeCols", true);
l = mergeCols.length();
for (k = 0; k < l; k++) {
subItem = mergeCols.getJSONArray(k);
n = subItem.length();
for (m = 0; m < n; m++) {
mergeInfo.getJSONArray(com.wb.util.StringUtil.indexOf(fields, subItem.getString(m))).put(1, "g" + k);
}
}
}
} catch (Throwable e) {
throw new IllegalArgumentException("Invalid merge config " + obj.toString());
}
//合并单元格
ExcelObject.mergeCells(sheet, mergeConfig, y, y + data.length());
}
}
/**
* 把JSONArray对象中的数据直接输出至Sheet中由x,y指定的开始单元格。该方法将在起始单元格之后插入新的行。
* @param sheet sheet对象。
* @param x 单元格x坐标。
* @param y 单元格y坐标。
* @param recs 要插入的数据。
* @return 填充的字段名称组成的列表。
*/
public static String[] createRows(Sheet sheet, int x, int y, JSONArray recs) {
int i, j, k, l, m;
short height;
Row row;
Cell cell;
JSONObject rec;
String fields[];
CellStyle style[], rowStyle;
Object objVal;
//定义样式和数据源的首行
row = sheet.getRow(y);
rowStyle = row.getRowStyle();
height = row.getHeight();
l = row.getLastCellNum() - x;
fields = new String[l];
style = new CellStyle[l];
for (k = x; k < l; k++) {
cell = row.getCell(k);
objVal = ExcelObject.getCellValue(cell);
m = k - x;
fields[m] = objVal == null ? null : com.wb.util.StringUtil.force(objVal.toString());
style[m] = cell.getCellStyle();
}
//如果无数据移除空行
if (recs == null || recs.length() == 0) {
removeRow(sheet, y);
return fields;
}
//插入recs长度的row
j = recs.length();
sheet.shiftRows(y, sheet.getLastRowNum(), j - 1);
for (i = 0; i < j; i++) {
row = sheet.createRow(i + y);
row.setRowStyle(rowStyle);
row.setHeight(height);
rec = recs.optJSONObject(i);
if (rec == null) {
continue;
}
for (k = 0; k < l; k++) {
cell = row.createCell(k + x);
cell.setCellStyle(style[k]);
ExcelObject.setCellValue(cell, com.wb.util.JsonUtil.opt(rec, fields[k]));
}
}
return fields;
}
/**
* 设置Excel单元格的值。该方法能把值依据其不同的类型填充到单元格中。
* 如果值为标准字符串日期格式,在设置值前系统将自动转换为日期格式。
* @param cell 单元格对象。
* @param value 需要设置的值。
*/
public static void setCellValue(Cell cell, Object value) {
String strVal;
if (value == null)
cell.setCellValue("");
else if (value instanceof String) {
strVal = (String) value;
if (DateUtil.isDate(strVal))
cell.setCellValue(DateUtil.strToDate(strVal));
else {
//多行文本
if (strVal.indexOf('\n') != -1)
cell.getCellStyle().setWrapText(true);
cell.setCellValue(strVal);
}
} else if (value instanceof Number)
cell.setCellValue(((Number) value).doubleValue());
else if (value instanceof Date)
cell.setCellValue((Date) value);
else if (value instanceof Boolean)
cell.setCellValue((Boolean) value);
else {
strVal = value.toString();
//多行文本
if (strVal.indexOf('\n') != -1)
cell.getCellStyle().setWrapText(true);
cell.setCellValue(value.toString());
}
}
/**
* 删除Sheet指定索引的行。该方法区别于sheet.removeRow使用该方法删除行后下方行将上移。
* @param sheet Sheet对象。
* @param rowIndex 删除的行索引号。
*/
public static void removeRow(Sheet sheet, int rowIndex) {
int lastRowNum = sheet.getLastRowNum(), i, mergeRegions;
CellRangeAddress range;
//如果包含单元格的合并信息则予以删除
mergeRegions = sheet.getNumMergedRegions();
for (i = mergeRegions - 1; i >= 0; i--) {
range = sheet.getMergedRegion(i);
if (range.getFirstRow() <= rowIndex && range.getLastRow() >= rowIndex) {
sheet.removeMergedRegion(i);
}
}
//移动单元格
if (rowIndex >= 0 && rowIndex < lastRowNum) {
sheet.shiftRows(rowIndex + 1, lastRowNum, -1);
}
//如果为最后一行执行删除
if (rowIndex == lastRowNum) {
Row removingRow = sheet.getRow(rowIndex);
if (removingRow != null) {
sheet.removeRow(removingRow);
}
}
}
/**
* 执行Excel表格中的指令指令位于最后一行并由"!!"开始。指令包括填充批量数据和合并单元格等。
* @param sheet Sheet对象。
* @param params 参数对象。
*/
public static void executeInstruction(Sheet sheet, JSONObject params) {
Cell cell;
Object value;
String instruction;
JSONArray ja, mergeCols;
JSONObject jo;
int i, j, lastRowIndex;
Row lastRow;
lastRowIndex = sheet.getLastRowNum();
lastRow = sheet.getRow(lastRowIndex);
if (lastRow == null)
return;
cell = lastRow.getCell(0);
if (cell == null)
return;
value = ExcelObject.getCellValue(cell);
if (value == null)
return;
instruction = value.toString();
instruction = com.wb.util.WebUtil.replaceParams(params, instruction);
if (instruction.startsWith("!!"))
instruction = instruction.substring(2);
else
return;
//删除最后一行
ExcelObject.removeRow(sheet, lastRowIndex);
//修改指令的语法使其符合规范
try {
if (instruction.startsWith("{"))
ja = new JSONArray("[" + instruction + "]");
else
ja = new JSONArray(instruction);
j = ja.length();
for (i = 0; i < j; i++) {
jo = ja.getJSONObject(i);
jo.put("mergeRows", com.wb.util.JsonUtil.toArray(jo.opt("mergeRows")));
mergeCols = jo.optJSONArray("mergeCols");
if (mergeCols != null && mergeCols.length() > 0 && !(mergeCols.opt(0) instanceof JSONArray))
jo.put("mergeCols", new JSONArray().put(mergeCols));
}
} catch (Throwable e) {
throw new IllegalArgumentException("Invalid fill instruction " + instruction);
}
//填充数据
ExcelObject.fillRows(sheet, ja, params);
}
/**
* 合并表格中需要合并的单元格。
* @param sheet sheet对象。
* @param config 合并的配置信息以象。
* @param startRow 开始合并的行索引号。
* @param endRow 结束合并的行索引号。
*/
public static void mergeCells(Sheet sheet, JSONObject config, int startRow, int endRow) {
JSONArray mergeInfo = config.optJSONArray("mergeInfo");
int i, j = mergeInfo.length(), rowIndex, colIndex, span;
int lastRowNum = sheet.getLastRowNum(), lastColNum = j - 1;
Iterator<Row> rows;
Iterator<Cell> cells;
Row row;
Cell cell;
Object object;
String value, prevValue, group, prevGroup, colGroup[];
boolean isLast;
// 合并行
if (config.optBoolean("mergeRows")) {
for (i = 0; i < j; i++) {
if (!mergeInfo.getJSONArray(i).getBoolean(0))
continue;
rows = sheet.rowIterator();
span = 0;
rowIndex = 0;
prevValue = null;
while (rows.hasNext()) {
row = rows.next();
if (rowIndex < startRow) {
rowIndex++;
continue;
}
if (rowIndex > endRow)
break;
cell = row.getCell(i);
object = ExcelObject.getCellValue(cell);
if (object == null)
value = "";
else
value = object.toString();
isLast = rowIndex == lastRowNum;
if (prevValue != null && (!value.equals(prevValue) || isLast)) {
if (isLast) {
if (value.equals(prevValue))
span++; // 如果最后一行值相等合并单元格数+1
else
isLast = false; // 否则不执行最后一行合并的处理
}
if (span > 1) {
if (isLast)
sheet.addMergedRegion(new CellRangeAddress(rowIndex - span + 1, rowIndex - 1, i, i));
else
sheet.addMergedRegion(new CellRangeAddress(rowIndex - span, rowIndex - 1, i, i));
}
span = 0;
}
prevValue = value;
span++;
rowIndex++;
}
}
}
// 合并列
rowIndex = 0;
if (config.optBoolean("mergeCols")) {
rows = sheet.rowIterator();
// 获取合并列的组信息到数组,以提高访问性能
colGroup = new String[j];
for (i = 0; i < j; i++) {
colGroup[i] = mergeInfo.getJSONArray(i).optString(1);
}
while (rows.hasNext()) {
row = rows.next();
if (rowIndex < startRow) {
rowIndex++;
continue;
}
if (rowIndex > endRow)
break;
cells = row.cellIterator();
span = 0;
colIndex = 0;
prevValue = null;
prevGroup = null;
while (cells.hasNext()) {
cell = cells.next();
object = ExcelObject.getCellValue(cell);
group = colGroup[colIndex];
if (object == null)
value = "";
else
value = object.toString();
isLast = colIndex == lastColNum;
if (prevValue != null && (!value.equals(prevValue) || !group.equals(prevGroup) || isLast)) {
if (isLast) {
if (value.equals(prevValue))
span++; // 如果最后一行值相等合并单元格数+1
else
isLast = false; // 否则不执行最后一行合并的处理
}
if (span > 1) {
if (isLast && !group.isEmpty()) {
sheet.addMergedRegion(
new CellRangeAddress(rowIndex, rowIndex, colIndex - span + 1, colIndex));
} else if (!prevGroup.isEmpty()) {
sheet.addMergedRegion(
new CellRangeAddress(rowIndex, rowIndex, colIndex - span, colIndex - 1));
}
}
span = 0;
}
prevValue = value;
prevGroup = group;
span++;
colIndex++;
}
rowIndex++;
}
}
}
}

View File

@@ -0,0 +1,211 @@
package com.wb.tool;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Types;
import java.util.Date;
import java.util.HashSet;
import org.json.JSONArray;
import org.json.JSONObject;
import com.wb.util.DbUtil;
import com.wb.util.JsonUtil;
import com.wb.util.SysUtil;
public class Flow {
/**
* 开始一个新的流程路由,并返回路由对象。如果流程中包含开始节点, 流程自动激活开始节点,否则自动激活所有可作为起点的节点。
* 如果未能找到可用的开始节点,将抛出异常。<br>
* 示例: <blockquote>
* <pre>
* Route route = Flow.start(workflowId);
* route.set(&quot;param1&quot;, &quot;foo&quot;); //设置参数param1
* route.set(&quot;param2&quot;, &quot;bar&quot;); //设置参数param2
* route.set(request); //把request中的parameters和attributes中的值设置到路由对象中
* route.commit(); //提交保存
* </pre>
* </blockquote>
* @param workflowId 工作流模板的id号。
* @return 路由对象
* @exception Exception 如果工作流模板文件不存在或开始节点未找到将抛出异常。
*/
public static com.wb.tool.Route start(String workflowId) throws Exception {
return start(workflowId, null);
}
/**
* 开始一个新的流程路由并返回路由对象。路由将激活startNodes指定的所有节点。 如果未能找到可用的开始节点,将抛出异常。
* @param workflowId 工作流模板的id号。
* @param startNodes 开始的结点名称列表。
* @return 路由对象
* @exception Exception 如果工作流模板文件不存在或开始节点未找到将抛出异常。
*/
public static com.wb.tool.Route start(String workflowId, String[] startNodes)
throws Exception {
String workflow = getContent(workflowId, true);
Date date = new Date();
if (workflow == null)
throw new Exception("Workflow \"" + workflowId
+ "\" does not exist.");
JSONObject template = new JSONObject(workflow), jo = new JSONObject();
JSONArray nodes;
com.wb.tool.Route route;
if (startNodes == null)
nodes = getStartNodes(template);
else
nodes = new JSONArray(startNodes);
if (nodes.length() == 0)
throw new Exception("Please select some nodes to start the route.");
route = new com.wb.tool.Route(jo, template);
route.set("CURRENT_NODES", nodes);
route.set("ACTIVE_NODE", nodes.optString(0));
route.set("ROUTE_ID", SysUtil.getId());
route.set("FLOW_ID", workflowId);
route.set("CREATE_DATE", date);
route.set("MODIFY_DATE", date);
return route;
}
/**
* 获取开始节点列表。
* @param template 流程模板。
* @return 开始节点列表。
*/
private static JSONArray getStartNodes(JSONObject template)
throws Exception {
JSONArray list = template.getJSONArray("list"), conn, currentNodes = new JSONArray();
JSONObject obj;
obj = JsonUtil.findObject(list, "label", "开始");
if (obj == null) {
HashSet<String> nodes = new HashSet<String>();
int i, j;
String name;
conn = template.getJSONArray("conn");
j = conn.length();
for (i = 0; i < j; i++) {
obj = conn.getJSONObject(i);
nodes.add(obj.getString("dst"));
}
j = list.length();
for (i = 0; i < j; i++) {
obj = list.getJSONObject(i);
if (obj.getBoolean("isObj")) {
name = obj.getString("label");
if (!nodes.contains(name))
currentNodes.put(name);
}
}
} else
currentNodes.put("开始");
return currentNodes;
}
/**
* 通过路由id号创建新的路由实例。<br>
* 示例: <blockquote>
* <pre>
* Route route = Flow.create(routeId);
* </pre>
* </blockquote>
* @param routeId 路由id。
* @return 路由实例对象。
* @exception Exception 如果路由不存在将抛出异常。
*/
public static com.wb.tool.Route create(String routeId) throws Exception {
String route = getContent(routeId, false);
if (route == null)
throw new Exception("Route \"" + routeId + "\" does not exist.");
JSONObject routeObj = new JSONObject(route);
String tpl = routeObj.optString("FLOW_XTPL");
if (tpl == null)
throw new Exception("The workflow does not exist.");
return new com.wb.tool.Route(routeObj, new JSONObject(tpl));
}
/**
* 通过路由数据和流程数据创建新的路由实例。<br>
* 示例: <blockquote>
* <pre>
* Route route = Flow.create(routeText, flowJson);
* </pre>
* </blockquote>
* @param routeText 路由数据JSON对象。
* @param flowJson 流程数据JSON对象。
* @return 路由实例对象。
*/
public static com.wb.tool.Route create(String routeText, JSONObject flowJson) {
return new com.wb.tool.Route(new JSONObject(routeText), flowJson);
}
/**
* 删除指定的路由。<br>
* 示例: <blockquote>
* <pre>
* Flow.remove(routeId);
* </pre>
* </blockquote>
* @param routeId 路由id号。
* @exception Exception 如果删除过程出现错误将抛出异常。
*/
public static void remove(String routeId) throws Exception {
Connection conn = null;
PreparedStatement st = null;
try {
conn = DbUtil.getConnection();
st = conn.prepareStatement("delete from WB_ROUTE where ROUTE_ID=?");
st.setString(1, routeId);
st.executeUpdate();
} finally {
DbUtil.close(st);
DbUtil.close(conn);
}
}
/**
* 获得新的指定id流程模板对象实例。
* @param id 流程id号。
* @return 流程模板对象实例。
*/
public static JSONObject get(String id) {
return new JSONObject(getContent(id, true));
}
/**
* 获取指定ID的流程或路由数据。
* @param id 编号。
* @param isFlow true流程数据false路由数据。
* @return 获取的内容。如果未找到指定id的内容返回null。
*/
public static String getContent(String id, boolean isFlow) {
Connection conn = null;
PreparedStatement st = null;
ResultSet rs = null;
try {
conn = DbUtil.getConnection();
if (isFlow)
st = conn
.prepareStatement("select FLOW_CONTENT from WB_FLOW where FLOW_ID=?");
else
st = conn
.prepareStatement("select ROUTE_CONTENT from WB_ROUTE where ROUTE_ID=?");
st.setString(1, id);
rs = st.executeQuery();
if (rs.next()) {
return (String) DbUtil.getObject(rs, 1, Types.CLOB);
}
} catch (Throwable e) {
throw new RuntimeException(e);
} finally {
DbUtil.close(rs);
DbUtil.close(st);
DbUtil.close(conn);
}
return null;
}
}

View File

@@ -0,0 +1,241 @@
package com.wb.tool;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Date;
import java.util.Properties;
import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.mail.BodyPart;
import javax.mail.Message;
import javax.mail.Multipart;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.internet.MimeUtility;
import javax.servlet.http.HttpServletRequest;
import org.json.JSONArray;
import com.wb.common.Base;
import com.wb.common.Var;
import com.wb.util.FileUtil;
import com.wb.util.StringUtil;
public class MailSender {
private Session session;
private Transport transport;
/**
* 邮件发送器构造函数
* @param smtp smtp地址。
* @param username 邮件帐户用户名称。
* @param password 邮件帐户密码。
* @param needAuth 是否需要认证。
*/
public MailSender(String smtp, String username, String password,
boolean needAuth) throws Exception {
Properties props = new Properties();
props.put("mail.smtp.host", smtp);
props.put("mail.smtp.auth", Boolean.toString(needAuth));
session = Session.getDefaultInstance(props, null);
transport = session.getTransport("smtp");
try {
transport.connect(smtp, username, password);
} catch (Throwable e) {
close();
}
}
/**
* 关闭邮件发送端口。
* @throws Exception
*/
public void close() throws Exception {
transport.close();
}
/**
* 发送邮件。
* @param from 发件人地址。
* @param to 收件人地址。
* @param cc 抄送人地址。
* @param bcc 私密抄送人地址
* @param title 邮件标题。
* @param content 邮件内容。
*/
public void send(String from, String to, String cc, String bcc,
String title, String content) throws Exception {
send(from, to, cc, bcc, title, content, null, null, null, null);
}
/**
* @param from 发件人地址。
* @param to 收件人地址。
* @param cc 抄送人地址。
* @param bcc 私密抄送人地址
* @param title 邮件标题。
* @param content 邮件内容。
* @param attachFiles 作为邮件附件的应用目录下的文件相对路径数组列表。
* @param request 请求对象。。
* @param attachObjects 作为邮件附件的存储在请求对象属性中的属性名称数组列表。
* @param attachObjectNames 使用attachObjects作为附件时使用的文件名称数组列表。
*/
public void send(String from, String to, String cc, String bcc,
String title, String content, String attachFiles,
HttpServletRequest request, String attachObjects,
String attachObjectNames) throws Exception {
Multipart multipart = new MimeMultipart();
MimeMessage message = new MimeMessage(session);
int sepPos;
sepPos = from.indexOf('<');
if (sepPos != -1)
message.setFrom(new InternetAddress(from.substring(sepPos + 1, from
.length() - 1), from.substring(0, sepPos).trim()));
else
message.setFrom(new InternetAddress(from));
message.setRecipients(Message.RecipientType.TO, InternetAddress
.parse(to));
if (!StringUtil.isEmpty(cc))
message.setRecipients(Message.RecipientType.CC, InternetAddress
.parse(cc));
if (!StringUtil.isEmpty(bcc))
message.setRecipients(Message.RecipientType.BCC, InternetAddress
.parse(bcc));
message.setSubject(title);
message.setSentDate(new Date());
addContent(multipart, content);
attachFiles(multipart, attachFiles, request, attachObjects,
attachObjectNames);
message.setContent(multipart);
message.saveChanges();
transport.sendMessage(message, message.getAllRecipients());
}
/**
* 向邮件中添加内容。
*/
private void addContent(Multipart multipart, String content)
throws Exception {
BodyPart bodyPart = new MimeBodyPart();
bodyPart.setContent(content, "text/html;charset=utf-8");
multipart.addBodyPart(bodyPart);
}
/**
* 向邮件中添加附件。
*/
private void attachFiles(Multipart multipart, String attachFiles,
HttpServletRequest request, String attachObjects,
String attachObjectNames) throws Exception {
boolean hasObjNames;
int i, j;
Object object;
BodyPart bodyPart;
if (!StringUtil.isEmpty(attachFiles)) {
JSONArray ja = new JSONArray(attachFiles);
String file;
j = ja.length();
for (i = 0; i < j; i++) {
bodyPart = new MimeBodyPart();
file = ja.getString(i);
bodyPart.setDataHandler(new DataHandler(new FileDataSource(
new File(Base.path, file))));
bodyPart.setFileName(MimeUtility.encodeText(FileUtil
.getFilename(file)));
bodyPart.setHeader("content-id", "attach" + i);
multipart.addBodyPart(bodyPart);
}
}
if (!StringUtil.isEmpty(attachObjects)) {
JSONArray list, objNames;
String name;
list = new JSONArray(attachObjects);
hasObjNames = !StringUtil.isEmpty(attachObjectNames);
if (hasObjNames)
objNames = new JSONArray(attachObjectNames);
else
objNames = null;
j = list.length();
for (i = 0; i < j; i++) {
name = list.getString(i);
object = request.getAttribute(name);
DataSource dataSource;
if (object != null) {
if (object instanceof InputStream)
dataSource = new BinDataSource((InputStream) object);
else if (object instanceof byte[])
dataSource = new BinDataSource((byte[]) object);
else
dataSource = new BinDataSource(object.toString());
bodyPart = new MimeBodyPart();
bodyPart.setDataHandler(new DataHandler(dataSource));
if (hasObjNames)
bodyPart.setFileName(MimeUtility.encodeText(objNames
.getString(i)));
else
bodyPart.setFileName(MimeUtility.encodeText(name));
bodyPart.setHeader("content-id", name);
multipart.addBodyPart(bodyPart);
}
}
}
}
/**
* 实现DataSource接口。
*/
private class BinDataSource implements DataSource {
private byte[] byteData;
public BinDataSource(InputStream stream) throws IOException {
ByteArrayOutputStream os = new ByteArrayOutputStream();
int ch;
while ((ch = stream.read()) != -1)
os.write(ch);
byteData = os.toByteArray();
}
public BinDataSource(byte[] data) {
byteData = data;
}
public BinDataSource(String data) throws Exception {
String charset = Var.getString("sys.locale.mailCharset");
if (StringUtil.isEmpty(charset))
byteData = data.getBytes();
else
byteData = data.getBytes(charset);
}
public InputStream getInputStream() throws IOException {
return new ByteArrayInputStream(byteData);
}
public OutputStream getOutputStream() throws IOException {
return null;
}
public String getContentType() {
return "application/octet-stream";
}
public String getName() {
return "dummy";
}
}
}

View File

@@ -0,0 +1,8 @@
package com.wb.tool;
public class PageInfo {
public int start;
public int end;
public int limit;
public int count;
}

View File

@@ -0,0 +1,435 @@
package com.wb.tool;
import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.json.JSONArray;
import org.json.JSONObject;
/**
* 执行数据库SQL语句的工具类。
*/
public class Query {
/**
* 请求对象,用于读取参数和存储数据。在该请求结束后系统自动关闭和释放资源。
*/
public HttpServletRequest request;
/**
* SQL语句。
*/
public String sql;
/**
* 数据库连接jndi。
*/
public String jndi;
/**
* 执行批处理时指定数据源来自request中存储的该变量。
*/
public String arrayName;
/**
* 执行批处理时指定数据源来自JSONArray对象。
*/
public JSONArray arrayData;
/**
* 是否允许批处理操作。
*/
public boolean batchUpdate;
/**
* 执行何种SQL操作可为"query","update","execute","call",默认为自动。
*/
public String type;
/**
* 是否自动加载输出参数,可为"auto","load","none",默认为自动。
*/
public String loadParams;
/**
* 执行何种数据库事务操作,可为"start","commit","none"。
*/
public String transaction;
/**
* 数据库事务隔离级别,可为"readCommitted","readUncommitted","repeatableRead","serializable"。
*/
public String isolation;
/**
* 指定插入、更改或删除记录操作是否有且只有1条。
*/
public boolean uniqueUpdate;
/**
* 当该值不为空且查询结果集不为空,系统将抛出该信息的异常。
*/
public String errorText;
/**
* 用于调试的SQL语句。
*/
private String debugSql;
/**
* 经过格式化后可直接运行的SQL语句。
*/
private String formattedSql;
/**
* 参数列表0项名称1项类型2项标识true输出参数false输出参数
*/
private ArrayList<Object[]> paramList;
/**
* 参数值列表
*/
private ArrayList<String> paramValList;
/**
* 参数数量
*/
private int paramCount;
/**
* 用于执行SQL的statement对象
*/
private PreparedStatement statement;
/**
* 运行SQL并返回运行结果。如果SQL为空或disabled为true将直接返回null。
*
* @return 运行的结果。可能值为结果集影响记录数或输出参数结果Map。
*/
public Object run() throws Exception {
checkProperties();
boolean isCall, isCommit, autoLoadParams, hasArray = arrayData != null || !com.wb.util.StringUtil.isEmpty(arrayName);
int affectedRows;
Object result = null;
Connection connection;
sql = sql.trim();
replaceMacros();
connection = com.wb.util.DbUtil.getConnection(request, jndi);
//getcolumncontet(connection);
isCommit = "commit".equals(transaction);
if (isCommit) {
if (connection.getAutoCommit())
transaction = "start";
} else if (com.wb.util.StringUtil.isEmpty(transaction) && (uniqueUpdate || hasArray) && connection.getAutoCommit())
transaction = "start";
if ("start".equals(transaction))
com.wb.util.DbUtil.startTransaction(connection, isolation);
if (com.wb.util.StringUtil.isEmpty(type)) {
if (sql.startsWith("{"))
type = "call";
else
type = "execute";
}
isCall = "call".equals(type);
if (isCall)
statement = connection.prepareCall(formattedSql);
else
statement = connection.prepareStatement(formattedSql);
if (com.wb.common.Var.fetchSize != -1)
statement.setFetchSize(com.wb.common.Var.fetchSize);
com.wb.util.WebUtil.setObject(request, com.wb.util.SysUtil.getId(), statement);
regParameters();
if (hasArray)
executeBatch();
else {
if (com.wb.common.Var.debug)
printSql();
if ("query".equals(type)) {
result = statement.executeQuery();
// 如果返回多个resultset,可通过result获得statement进而获得更多resultset
com.wb.util.WebUtil.setObject(request, com.wb.util.SysUtil.getId(), result);
} else if ("update".equals(type)) {
affectedRows = statement.executeUpdate();
result = affectedRows;
if (uniqueUpdate && affectedRows != 1)
notUnique();
} else {
autoLoadParams = com.wb.util.StringUtil.isEmpty(loadParams) || "auto".equals(loadParams);
if (statement.execute()) {
if (autoLoadParams)
loadParams = "none";
result = statement.getResultSet();
com.wb.util.WebUtil.setObject(request, com.wb.util.SysUtil.getId(), result);
} else {
if (autoLoadParams)
loadParams = "load";
affectedRows = statement.getUpdateCount();
result = affectedRows;
if (uniqueUpdate && affectedRows != 1)
notUnique();
}
if (isCall && paramCount > 0) {
HashMap<String, Object> map = getOutParameter("load".equals(loadParams));
if (map.size() > 0) {
if (map.containsKey("return"))
throw new IllegalArgumentException("Invalid output parameter name \"return\"");
map.put("return", result);
result = map;
}
}
}
}
if (isCommit) {
connection.commit();
connection.setAutoCommit(true);
}
checkError(result);
return result;
}
/**
* 检查参数的合法性,如果非法将抛出异常。
*/
private void checkProperties() {
if (!com.wb.util.StringUtil.isEmpty(transaction)) {
String trans[] = {"start", "commit", "none"};
if (com.wb.util.StringUtil.indexOf(trans, transaction) == -1)
throw new IllegalArgumentException("Invalid transaction \"" + transaction + "\".");
}
if (!com.wb.util.StringUtil.isEmpty(loadParams)) {
String params[] = {"auto", "load", "none"};
if (com.wb.util.StringUtil.indexOf(params, loadParams) == -1)
throw new IllegalArgumentException("Invalid loadParams \"" + loadParams + "\".");
}
if (!com.wb.util.StringUtil.isEmpty(type)) {
String types[] = {"query", "update", "execute", "call"};
if (com.wb.util.StringUtil.indexOf(types, type) == -1)
throw new IllegalArgumentException("Invalid type \"" + type + "\".");
}
if (!com.wb.util.StringUtil.isEmpty(isolation)) {
String isolations[] = {"readCommitted", "readUncommitted", "repeatableRead", "serializable"};
if (com.wb.util.StringUtil.indexOf(isolations, isolation) == -1)
throw new IllegalArgumentException("Invalid isolation \"" + isolation + "\".");
}
}
/**
* 根据arrayName指定的数组参数名称执行批处理操作。
* 批处理中的记录如果未指定参数值将引用最后一次设置的值。
*
* @param arrayName 在parameters或attribute中的数据参数名称。
* @throws Exception 执行过程发生异常。
*/
private void executeBatch() throws Exception {
Object param[], valObj;
JSONArray ja;
JSONObject jo;
String val, name;
int i, j, k, affectedRows;
if (arrayData == null) {
Object obj = com.wb.util.WebUtil.fetchObject(request, arrayName);
if (obj instanceof JSONArray)
ja = (JSONArray) obj;
else {
if (obj == null)
return;
val = obj.toString();
if (val.isEmpty())
return;
ja = new JSONArray(val);
}
} else
ja = arrayData;
j = ja.length();
if (j == 0)
return;
for (i = 0; i < j; i++) {
jo = ja.getJSONObject(i);
for (k = 0; k < paramCount; k++) {
param = paramList.get(k);
name = (String) param[0];
if (!((Boolean) param[2]) && jo.has(name)) {
valObj = com.wb.util.JsonUtil.opt(jo, name);
com.wb.util.DbUtil.setObject(statement, k + 1, (Integer) param[1], valObj);
if (com.wb.common.Var.debug)
paramValList.set(k, com.wb.util.StringUtil.toString(valObj));
}
}
if (com.wb.common.Var.debug)
printSql();
if (batchUpdate)
statement.addBatch();
else {
affectedRows = statement.executeUpdate();
if (uniqueUpdate && affectedRows != 1)
notUnique();
}
}
if (batchUpdate)
statement.executeBatch();
// 批处理时不判断uniqueUpdate因为不是所有数据库都支持
// 批处理如果要使用uniqueUpdate必须设置batchUpdate为false
}
/**
* 抛出更新不唯一异常。
*/
private void notUnique() {
throw new RuntimeException(com.wb.common.Str.format(request, "updateNotUnique"));
}
/**
* 替换SQL中的宏参数为SQL参数。
*/
private void replaceMacros() {
StringBuilder buf = new StringBuilder();
int startPos = 0, endPos = 0, lastPos = 0;
while ((startPos = sql.indexOf("{?", startPos)) > -1 && (endPos = sql.indexOf("?}", endPos)) > -1) {
buf.append(sql.substring(lastPos, startPos));
startPos += 2;
endPos += 2;
buf.append("'{?");
buf.append(sql.substring(endPos - 1, endPos));
buf.append('\'');
lastPos = endPos;
}
buf.append(sql.substring(lastPos));
debugSql = buf.toString();
formattedSql = com.wb.util.StringUtil.replaceAll(debugSql, "'{?}'", "?");
}
/**
* 注册输入和输出参数。
*
* @throws Exception 注册参数发生异常。
*/
private void regParameters() throws Exception {
String paraName, param, typeText, orgParam;
Object obj, paramObjects[];
int index = 1, dotPos, type, subType, startPos = 0, endPos = 0;
Integer typeObj;
boolean hasSub, isOutParam, isCall;
CallableStatement callStatement;
paramList = new ArrayList<Object[]>();
if (com.wb.common.Var.debug)
paramValList = new ArrayList<String>();
if (statement instanceof CallableStatement)
callStatement = (CallableStatement) statement;
else
callStatement = null;
isCall = callStatement != null;
while ((startPos = sql.indexOf("{?", startPos)) > -1 && (endPos = sql.indexOf("?}", endPos)) > -1) {
startPos += 2;
param = sql.substring(startPos, endPos);
endPos += 2;
orgParam = param;
isOutParam = isCall && param.startsWith("@");
if (isOutParam) {
param = param.substring(1);
dotPos = param.indexOf('.');
if (dotPos == -1) {
typeText = "varchar";
paraName = param;
} else {
typeText = param.substring(0, dotPos);
paraName = param.substring(dotPos + 1);
}
hasSub = typeText.indexOf('=') != -1;
if (hasSub) {
typeObj = com.wb.util.DbUtil.getFieldType(com.wb.util.StringUtil.getNamePart(typeText));
if (typeObj == null)
throw new Exception("Invalid type " + typeText);
type = typeObj;
subType = Integer.parseInt(com.wb.util.StringUtil.getValuePart(typeText));
callStatement.registerOutParameter(index, type, subType);
} else {
typeObj = com.wb.util.DbUtil.getFieldType(typeText);
if (typeObj == null)
throw new Exception("Invalid type " + typeText);
type = typeObj;
callStatement.registerOutParameter(index, type);
}
if (com.wb.common.Var.debug) {
// 输出参数直接输出参数类型和名称
paramValList.add(orgParam);
}
} else {
dotPos = param.indexOf('.');
if (dotPos == -1) {
type = Types.VARCHAR;
paraName = param;
} else {
typeObj = com.wb.util.DbUtil.getFieldType(param.substring(0, dotPos));
if (typeObj == null) {
type = Types.VARCHAR;
paraName = param;
} else {
type = typeObj;
paraName = param.substring(dotPos + 1);
}
}
obj = com.wb.util.WebUtil.fetchObject(request, paraName);
com.wb.util.DbUtil.setObject(statement, index, type, obj);
if (com.wb.common.Var.debug) {
// 输入参数输出替换后的值
paramValList.add(com.wb.util.StringUtil.toString(obj));
}
}
paramObjects = new Object[3];
paramObjects[0] = paraName;
paramObjects[1] = type;
paramObjects[2] = isOutParam;
paramList.add(paramObjects);
index++;
}
paramCount = paramList.size();
}
/**
* 获得输出参数值。
*
* @param loadOutParams 是否自动加载输出参数到Map中。true加载所有参数false返回statement本身。
* @return 输出参数组成的map。
*/
private HashMap<String, Object> getOutParameter(boolean loadOutParams) throws Exception {
CallableStatement st = (CallableStatement) statement;
HashMap<String, Object> map = new HashMap<String, Object>();
Object object, param[];
int i;
for (i = 0; i < paramCount; i++) {
param = paramList.get(i);
if ((Boolean) param[2]) {
if (!loadOutParams) {
//如果不加载输出参数直接返回statement对象
map.put("outParams", st);
return map;
}
object = com.wb.util.DbUtil.getObject(st, i + 1, (Integer) param[1]);
if (object instanceof ResultSet)
com.wb.util.WebUtil.setObject(request, com.wb.util.SysUtil.getId(), object);
map.put((String) param[0], object);
}
}
return map;
}
/**
* 如果结果集不为空且指定errorText属性将抛出该信息的异常。
*/
private void checkError(Object object) throws Exception {
if (!com.wb.util.StringUtil.isEmpty(errorText) && object instanceof ResultSet) {
ResultSet rs = (ResultSet) object;
if (rs.next())
throw new RuntimeException(errorText);
}
}
/**
* 打印用于调试的SQL语句。
*/
private void printSql() {
String sql = debugSql;
for (String s : paramValList) {
sql = com.wb.util.StringUtil.replaceFirst(sql, "{?}", s);
}
Console.log(request, sql);
}
}

View File

@@ -0,0 +1,56 @@
package com.wb.tool;
public class QueueWriter implements java.io.Serializable {
private static final long serialVersionUID = 2100540580239114561L;
/** 打印缓冲区,支持多线程访问*/
private StringBuffer buf;
/** 缓冲区大小 */
private int bufferSize;
/** 构造函数。
* @param bufferSize 缓冲区大小。
*/
public QueueWriter(int bufferSize) {
buf = new StringBuffer();
this.bufferSize = bufferSize;
}
/**
* 打印对象的字符串信息。
* @param object 打印的对象。
* @param type 输出的类型。
* @param encoded 是否被编码,被编码的内容可在客户端解码。
*/
public synchronized void print(Object object, String type, boolean encoded) {
String string;
if (object == null)
string = "null";
else
string = object.toString();
if (buf.length() > 0)
buf.append(',');
buf.append("{type:\"");
buf.append(type);
buf.append("\",msg:");
buf.append(com.wb.util.StringUtil.quote(string));
if (encoded)
buf.append(",encode:true");
buf.append('}');
if (buf.length() > bufferSize)
clear();
}
/**
* 重载该对象转字符串的方法。
*/
public String toString() {
return buf.toString();
}
/**
* 清空缓存中的所有内容。
*/
public void clear() {
buf.delete(0, buf.length());
}
}

View File

@@ -0,0 +1,340 @@
package com.wb.tool;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.Timestamp;
import java.util.Date;
import java.util.Map.Entry;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.io.IOUtils;
import org.json.JSONArray;
import org.json.JSONObject;
import com.wb.common.Resource;
import com.wb.util.DbUtil;
import com.wb.util.JsonUtil;
import com.wb.util.SysUtil;
import com.wb.util.WebUtil;
public class Route {
public JSONObject flow;
/** 流程中的所有节点 */
private JSONArray allNodes;
/** 路由数据对象。 */
private JSONObject data;
/** 创建一个新的路由对象。
* @param jo 路由数据对象。
* @param tpl 流程模板对象。
*/
public Route(JSONObject jo, JSONObject tpl) {
flow = tpl;
allNodes = getNodes(tpl);
jo.put("FLOW_XTPL", tpl.toString());
data = jo;
}
/**
* 获取当前激活的节点名称列表。
* @return 节点列表。
*/
public JSONArray getCurrentNodes() {
return (JSONArray) data.opt("CURRENT_NODES");
}
/**
* 把路由中激活的节点从src移动到dst。<br>
* 示例: <blockquote>
* <pre>
* route.move(&quot;节点1&quot;, &quot;节点2&quot;);
* </pre>
* </blockquote>
* @param src 源节点,源节点必须是当前激活节点中的一个。
* @param dst 目标节点。
* @exception Exception 如果源节点不是激活的节点或目标节点不存在将抛出异常。
*/
public void move(String src, String dst) throws Exception {
JSONArray currentNodes = getCurrentNodes();
int fromIndex = JsonUtil.indexOf(currentNodes, src);
if (fromIndex == -1)
throw new Exception("Node \"" + src + "\" is not active.");
JSONObject dstObj = JsonUtil.findObject(allNodes, "label", dst);
if (dstObj == null)
throw new Exception("Node \"" + dst + "\" does not exist.");
currentNodes.put(fromIndex, dst);
}
/**
* 把路由中当前激活的节点转移到name指定的节点。<br>
* 示例: <blockquote>
* <pre>
* route.to(&quot;dstNode&quot;);
* </pre>
* </blockquote>
* @param name 目标节点名称
*/
public void to(String name) throws Exception {
String[] names = { name };
deactivateAll();
activate(names);
}
/**
* 激活names列表指定的节点。<br>
* 示例: <blockquote>
* <pre>
* String[] nodes = { &quot;节点1&quot;, &quot;节点2&quot; };
* route.activate(nodes);
* </pre>
* </blockquote>
* @param names 需要激活的节点列表
* @exception Exception 如果列表中的任意一个节点不存在将抛出异常。
*/
public void activate(String[] names) throws Exception {
JSONObject obj;
JSONArray currentNodes = getCurrentNodes();
for (String n : names) {
obj = JsonUtil.findObject(allNodes, "label", n);
if (obj == null)
throw new Exception("Node \"" + n + "\" does not exist.");
if (JsonUtil.indexOf(currentNodes, n) == -1)
currentNodes.put(n);
}
}
/**
* 取消names列表指定的节点激活状态。<br>
* 示例: <blockquote>
* <pre>
* String[] nodes = { &quot;节点1&quot;, &quot;节点2&quot; };
* route.deactivate(nodes);
* </pre>
* </blockquote>
* @param names 需要取消激活状态的节点列表。
*/
public void deactivate(String[] names) {
int i;
JSONArray currentNodes = getCurrentNodes();
for (String n : names) {
i = JsonUtil.indexOf(currentNodes, n);
if (i != -1)
currentNodes.remove(i);
}
}
/**
* 停止所有节点的激活状态。<br>
* 示例: <blockquote>
* <pre>
* route.deactivateAll();
* </pre>
* </blockquote>
*/
public void deactivateAll() {
JSONArray currentNodes = getCurrentNodes();
int i, j = currentNodes.length();
for (i = j - 1; i >= 0; i--)
currentNodes.remove(i);
}
/**
* 为路由标上暂停执行标识。
*/
public void pause() {
data.put("paused", true);
}
/**
* 为路由移去暂停执行标识。
*/
public void resume() {
data.put("paused", false);
}
/**
* 删除路由。
* @exception Exception 如果删除过程中发生错误将抛出异常。
*/
public void remove() throws Exception {
Flow.remove((String) get("ROUTE_ID"));
}
/**
* 获取路由的暂停状态标记。
* @return 状态标记
*/
public boolean isPaused() {
return data.optBoolean("paused", false);
}
/**
* 保存路由的任何改动。
*/
public void commit() throws Exception {
Connection conn = null;
PreparedStatement st = null;
Date date = new Date();
String routeId = data.optString("ROUTE_ID");
String userId = data.optString("sys.user", "-");
String activeNode = getCurrentNodes().optString(0);
try {
conn = DbUtil.getConnection();
conn.setAutoCommit(false);
st = conn.prepareStatement("delete from WB_ROUTE where ROUTE_ID=?");
st.setString(1, routeId);
st.executeUpdate();
DbUtil.close(st);
st = conn.prepareStatement("insert into WB_ROUTE values(?,?,?,?,?,?,?,?)");
st.setString(1, routeId);
st.setString(2, data.optString("FLOW_ID"));
st.setTimestamp(3, new Timestamp(date.getTime()));
st.setString(4, userId);
st.setString(5, activeNode);
st.setString(6, data.optString("TITLE", "-"));
st.setString(7, data.optString("STATUS", "-"));
DbUtil.setText(st, 8, data.toString());
st.executeUpdate();
conn.commit();
set("MODIFY_DATE", date);
set("USER_ID", userId);
set("ACTIVE_NODE", activeNode);
} finally {
DbUtil.close(st);
DbUtil.close(conn);
}
}
/**
* 把指定参数设置到路由。<br>
* 示例: <blockquote>
* <pre>
* route.set(&quot;param1&quot;, &quot;foo&quot;);
* route.set(&quot;param2&quot;, &quot;bar&quot;);
* route.commit();
* </pre>
* </blockquote>
* @param name 参数名称
* @param value 参数值
* @exception Exception 如果设置值过程中发生错误将抛出异常。
*/
public void set(String name, Object value) throws Exception {
if (value instanceof Date) {
value = com.wb.util.DateUtil.dateToStr((Date) value);
} else if (value instanceof InputStream) {
String id = SysUtil.getId();
Resource.set(id, getBytes((InputStream) value));
value = "@@blob." + id;
} else if (value instanceof byte[]) {
String id = SysUtil.getId();
Resource.set(id, (byte[]) value);
value = "@@byte." + id;
} else if (value instanceof Object[]) {
value = new JSONArray((Object[]) value).toString();
}
data.put(name, value);
}
/**
* 把request的parameters和attributes中的所有参数设置到路由。
* 如果parameters和attributes中的参数名称重复前者将被覆盖。
* @param request HttpServletRequest对象
* @exception Exception 如果设置值过程中发生错误将抛出异常。
*/
public void set(HttpServletRequest request) throws Exception {
JSONObject items = WebUtil.fetch(request);
Set<Entry<String, Object>> es = items.entrySet();
for (Entry<String, Object> e : es) {
set(e.getKey(), e.getValue());
}
}
/**
* 获取路由中指定名称的参数值。
* @param name 参数名称
* @return 参数值
*/
public Object get(String name) {
Object value = data.opt(name);
if (value instanceof String) {
String prefix = (String) value;
if (prefix.startsWith("@@blob."))
value = new ByteArrayInputStream(Resource.getBytes(prefix.substring(7), null));
else if (prefix.startsWith("@@byte."))
value = Resource.getBytes(prefix.substring(7), null);
}
return value;
}
/**
* 获取路由数据对象。
*/
public JSONObject get() {
return data;
}
/**
* 读取指定输入流的所有字节数组。
* @param is 输入流对象。
* @return 读取的字节数组。
*/
private byte[] getBytes(InputStream is) throws Exception {
ByteArrayOutputStream bos;
try {
bos = new ByteArrayOutputStream();
IOUtils.copy(is, bos);
} finally {
is.close();
}
return bos.toByteArray();
}
/**
* 路由中指定节点流转到下一个节点列表。
* @param request 请求对象。
* @return true成功false失败。
*/
public boolean forward(HttpServletRequest request) throws Exception {
return false;
}
/**
* 路由中指定节点流转到上一个节点列表。
* @param request 请求对象。
* @return true成功false失败。
*/
public boolean backward(HttpServletRequest request) throws Exception {
// String[] nodes={getCurrentNodes().optString(0)};
// deactivateAll();
// activate(nodes);
return false;
}
/**
* 获取指定流程模板的所有节点对象组成的JSONArray。
* @param template 流程模板对象。
* @return 节点列表。
*/
private JSONArray getNodes(JSONObject template) {
JSONArray list, nodes = new JSONArray();
JSONObject obj;
int i, j;
list = template.getJSONArray("list");
j = list.length();
for (i = 0; i < j; i++) {
obj = list.getJSONObject(i);
if (obj.getBoolean("isObj")) {
obj.remove("box");
nodes.put(obj);
}
}
return nodes;
}
}

View File

@@ -0,0 +1,115 @@
package com.wb.tool;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import org.apache.commons.io.IOUtils;
import org.mozilla.javascript.ErrorReporter;
import org.mozilla.javascript.EvaluatorException;
import com.yahoo.platform.yui.compressor.CssCompressor;
import com.yahoo.platform.yui.compressor.JavaScriptCompressor;
/**
* JS和CSS脚本压缩器。
*/
public class ScriptCompressor {
/**
* 压缩JS文件。
*
* @param oldFile 压缩之前的文件。
* @param newFile 压缩之后的新文件。
* @throws IOException 压缩过程发生异常。
*/
public static synchronized void compressJs(File oldFile, File newFile,
boolean lineBreak) throws IOException {
Reader in = new BufferedReader(new InputStreamReader(
new FileInputStream(oldFile), "utf-8"));
Writer out = new BufferedWriter(new OutputStreamWriter(
new FileOutputStream(newFile), "utf-8"));
final String filename = oldFile.getName();
try {
JavaScriptCompressor compressor = new JavaScriptCompressor(in,
new ErrorReporter() {
public void warning(String message, String sourceName,
int line, String lineSource, int lineOffset) {
if (com.wb.common.Var.printError) {
System.err.println("WARNING in compress "
+ filename);
if (line < 0) {
System.err.println(" " + message);
} else {
System.err.println(" " + line + ':'
+ lineOffset + ':' + message);
}
}
}
public void error(String message, String sourceName,
int line, String lineSource, int lineOffset) {
if (com.wb.common.Var.printError) {
System.err.println("ERROR in compress "
+ filename);
if (line < 0) {
System.err.println(" " + message);
} else {
System.err.println(" " + line + ':'
+ lineOffset + ':' + message);
}
}
}
public EvaluatorException runtimeError(String message,
String sourceName, int line, String lineSource,
int lineOffset) {
error(message, sourceName, line, lineSource,
lineOffset);
return new EvaluatorException(message);
}
});
if (lineBreak) {
compressor.compress(out, 0, true, false, true, false);
}
else
compressor.compress(out, -1, true, false, false, false);
} finally {
IOUtils.closeQuietly(in);
IOUtils.closeQuietly(out);
}
}
/**
* 压缩CSS文件。
*
* @param oldFile
* 压缩之前的文件。
* @param newFile
* 压缩之后的新文件。
* @throws IOException
* 压缩过程发生异常。
*/
public static synchronized void compressCss(File oldFile, File newFile)
throws IOException {
Reader in = new BufferedReader(new InputStreamReader(
new FileInputStream(oldFile), "utf-8"));
Writer out = new BufferedWriter(new OutputStreamWriter(
new FileOutputStream(newFile), "utf-8"));
try {
CssCompressor compressor = new CssCompressor(in);
compressor.compress(out, -1);
} finally {
IOUtils.closeQuietly(in);
IOUtils.closeQuietly(out);
}
}
}

View File

@@ -0,0 +1,164 @@
package com.wb.tool;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.sql.Types;
import java.util.Date;
import java.util.Properties;
import com.wb.common.ScriptBuffer;
import com.wb.task.ScriptProxy;
import com.wb.util.StringUtil;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import com.wb.common.Var;
import com.wb.util.DbUtil;
public class TaskManager {
public static Scheduler scheduler;
/**
* 把指定参数的任务加载到任务引擎中。如果相同id的任务已经存在则重新加载该任务。
* @param taskId 任务id
* @param taskName 任务名称
* @param intervalType 周期类型
* @param intervalExpress 周期表达式
* @param className 执行的Java类
* @param serverScript 执行的服务器端脚本
* @param beginDate 开始时间
* @param endDate 结束时间s
* @throws Exception 加载任务发生异常
*/
public static void loadTask(String taskId, String taskName,
int intervalType, String intervalExpress, String className,
String serverScript, Date beginDate, Date endDate) throws Exception {
JobDetail job;
String express[];
Trigger trigger = null;
// 如果指定id的任务已经存在删除后重新加载
deleteTask(taskId);
if (StringUtil.isEmpty(className)) {
job = new JobDetail(taskId, Scheduler.DEFAULT_GROUP,
ScriptProxy.class);
JobDataMap dataMap = job.getJobDataMap();
dataMap.put("job.id", "job." + taskId);
dataMap.put("job.serverScript", serverScript);
} else
job = new JobDetail(taskId, Scheduler.DEFAULT_GROUP, Class
.forName(className));
job.setDescription(taskName);
express = StringUtil.split(intervalExpress, ":");
switch (intervalType) {
case 0:
trigger = TriggerUtils.makeSecondlyTrigger(Integer
.parseInt(express[0]));
break;
case 1:
trigger = TriggerUtils.makeMinutelyTrigger(Integer
.parseInt(express[0]));
break;
case 2:
trigger = TriggerUtils.makeHourlyTrigger(Integer
.parseInt(express[0]));
break;
case 3:
trigger = TriggerUtils.makeDailyTrigger(Integer
.parseInt(express[0]), Integer.parseInt(express[1]));
break;
case 4:
trigger = TriggerUtils.makeWeeklyTrigger(Integer
.parseInt(express[0]), Integer.parseInt(express[1]),
Integer.parseInt(express[2]));
break;
case 5:
trigger = TriggerUtils.makeMonthlyTrigger(Integer
.parseInt(express[0]), Integer.parseInt(express[1]),
Integer.parseInt(express[2]));
break;
}
trigger.setName(taskId);
if (beginDate != null)
trigger.setStartTime(beginDate);
if (endDate != null)
trigger.setEndTime(endDate);
if(scheduler != null) {
scheduler.scheduleJob(job, trigger);
}else {
start();
}
}
/**
* 删除指定id的任务如果任务不存在则该方法无任何效果。
* @param taskId 任务id
*/
public static void deleteTask(String taskId) throws Exception {
if (scheduler != null)
if (scheduler.getJobDetail(taskId, Scheduler.DEFAULT_GROUP) != null)
scheduler.deleteJob(taskId, Scheduler.DEFAULT_GROUP);
ScriptBuffer.remove("job." + taskId);
}
/**
* 开始计划任务引擎,加载所有已经配置的计划任务。如果任务已经加载,则重新加载该任务。
* @throws Exception
*/
public static synchronized void start() throws Exception {
if (!Var.getBool("sys.task.enabled"))
return;
if (scheduler == null) {
StdSchedulerFactory factory = new StdSchedulerFactory();
Properties props = new Properties();
props.put(StdSchedulerFactory.PROP_THREAD_POOL_CLASS,
"org.quartz.simpl.SimpleThreadPool");
props.put("org.quartz.threadPool.threadCount", Var
.getString("sys.task.threadCount"));
factory.initialize(props);
scheduler = factory.getScheduler();
scheduler.start();
} else if (scheduler.isStarted())
return;
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try {
conn = DbUtil.getConnection();
st = conn.createStatement();
rs = st.executeQuery("select * from WB_TASK");
while (rs.next()) {
// 停止的任务
if (rs.getInt("STATUS") == 0)
continue;
loadTask(rs.getString("TASK_ID"), rs.getString("TASK_NAME"), rs
.getInt("INTERVAL_TYPE"), rs
.getString("INTERVAL_EXPRESS"), rs
.getString("CLASS_NAME"), (String) DbUtil.getObject(rs,
"SERVER_SCRIPT", Types.NCLOB), rs
.getTimestamp("BEGIN_DATE"), rs
.getTimestamp("END_DATE"));
}
} finally {
DbUtil.close(rs);
DbUtil.close(st);
DbUtil.close(conn);
}
}
/**
* 停止计划任务引擎。
* @throws Exception
*/
public static synchronized void stop() throws Exception {
if (!Var.getBool("sys.task.enabled"))
return;
if (scheduler == null || scheduler.isShutdown())
return;
scheduler.shutdown();
scheduler = null;
Thread.sleep(Var.getInt("sys.task.stopDelay"));
}
}

View File

@@ -0,0 +1,173 @@
package com.wb.tool;
import java.sql.Connection;
import javax.servlet.http.HttpServletRequest;
import org.json.JSONArray;
import org.json.JSONObject;
import com.wb.util.DbUtil;
import com.wb.util.JsonUtil;
import com.wb.util.StringUtil;
import com.wb.util.WebUtil;
/**
* 执行上下文绑定的insert, update, delete数据库更新操作。
*/
public class Updater {
/** 请求对象。 */
public HttpServletRequest request;
/** 数据库连接jndi。 */
public String jndi;
/** 执行何种SQL操作可为"query","update","execute","call",默认为自动。 */
public String type;
/** 执行何种数据库事务操作,可为"start","commit","none"。 */
public String transaction;
/** 是否允许批处理操作。 */
public boolean batchUpdate;
/** 指定插入、更改或删除记录操作是否有且只有1条。 */
public boolean uniqueUpdate = true;
/** 数据库事务隔离级别。 */
public String isolation;
/** 需要更新的表名。 */
public String tableName;
/** insert语句。 */
public String sqlInsert;
/** update语句。 */
public String sqlUpdate;
/** delete语句。 */
public String sqlDelete;
/** insert数据源参数名称默认为create。 */
public String paramInsert;
/** update数据源参数名称默认为update。 */
public String paramUpdate;
/** delete数据源参数名称默认为destroy。 */
public String paramDelete;
/** 执行SQL的类型分为insertupdatedelete如果为空表示数据来自特定参数且执行所有类型。 */
public String mode;
/** 是否忽略对二进制字段的处理默认为false。 */
public boolean ignoreBlob = false;
/** SQL语句中的字段是否只使用存在参数值的字段默认为true。 */
public boolean useExistFields = true;
/** where条件部分使用的字段列表字段之间使用“,”分隔。 */
public String whereFields;
/** 用于把字段名称列表转换为指定名称的Map。 */
public JSONObject fieldsMap;
/** 运行指定的delete, insert和update操作。 */
public void run() throws Exception {
JSONArray destroyData = null, createData = null, updateData = null;
JSONObject fields = null, whereFieldsObj;
if (StringUtil.isEmpty(mode)) {
// 根据destroy/create/update参数执行指定SQL语句
String params;
params = WebUtil.fetch(request, StringUtil.select(paramDelete,
"destroy"));
if (!StringUtil.isEmpty(params)) {
destroyData = new JSONArray(params);
if (useExistFields && fields == null
&& destroyData.length() > 0)
fields = destroyData.getJSONObject(0);
}
params = WebUtil.fetch(request, StringUtil.select(paramInsert,
"create"));
if (!StringUtil.isEmpty(params)) {
createData = new JSONArray(params);
if (useExistFields && fields == null && createData.length() > 0)
fields = createData.getJSONObject(0);
}
params = WebUtil.fetch(request, StringUtil.select(paramUpdate,
"update"));
if (!StringUtil.isEmpty(params)) {
updateData = new JSONArray(params);
if (useExistFields && fields == null && updateData.length() > 0)
fields = updateData.getJSONObject(0);
}
} else {
// 指定模式执行单一类型SQL语句数据源来自所有参数
JSONArray data;
if (useExistFields) {
fields = WebUtil.fetch(request);
data = new JSONArray().put(fields);
} else
data = new JSONArray().put(WebUtil.fetch(request));
if (mode.equals("delete"))
destroyData = data;
else if (mode.equals("update"))
updateData = data;
else
// insert
createData = data;
}
if ((destroyData == null ? 0 : destroyData.length())
+ (createData == null ? 0 : createData.length())
+ (updateData == null ? 0 : updateData.length()) == 0)
return; // 无有效数据返回
com.wb.tool.Query query = new com.wb.tool.Query();
String sql;
Connection connection = DbUtil.getConnection(request, jndi);
boolean isCommit;
isCommit = "commit".equals(transaction);
if ((isCommit || StringUtil.isEmpty(transaction))
&& connection.getAutoCommit()) {
transaction = "start";
}
if ("start".equals(transaction))
DbUtil.startTransaction(connection, isolation);
query.request = request;
query.jndi = jndi;
query.type = type;
query.batchUpdate = batchUpdate;
query.transaction = "none";// 事务由updater控制因此query事务设置为none
query.uniqueUpdate = uniqueUpdate;
if (!StringUtil.isEmpty(tableName)) {
if (StringUtil.isEmpty(whereFields))
whereFieldsObj = fields;
else
whereFieldsObj = JsonUtil.fromCSV(whereFields);
String[] sqls = DbUtil.buildSQLs(jndi, tableName, ignoreBlob, 1,
request, fields, whereFieldsObj, fieldsMap);
if (StringUtil.isEmpty(sqlInsert))
sqlInsert = sqls[0];
if (StringUtil.isEmpty(sqlUpdate))
sqlUpdate = sqls[1];
if (StringUtil.isEmpty(sqlDelete))
sqlDelete = sqls[2];
}
if (!StringUtil.isEmpty(sqlDelete) && !"-".equals(sqlDelete)
&& destroyData != null && destroyData.length() > 0) {
sql = sqlDelete;
if (!sql.isEmpty()) {
query.sql = sql;
query.arrayData = destroyData;
query.run();
}
}
if (!StringUtil.isEmpty(sqlUpdate) && !"-".equals(sqlUpdate)
&& updateData != null && updateData.length() > 0) {
sql = sqlUpdate;
if (!sql.isEmpty()) {
query.sql = sql;
query.arrayData = updateData;
query.run();
}
}
if (!StringUtil.isEmpty(sqlInsert) && !"-".equals(sqlInsert)
&& createData != null && createData.length() > 0) {
sql = sqlInsert;
if (!sql.isEmpty()) {
query.sql = sql;
query.arrayData = createData;
query.run();
}
}
if (isCommit) {
connection.commit();
connection.setAutoCommit(true);
}
}
}

View File

@@ -0,0 +1,314 @@
package com.wb.util;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
/**
* 日期工具方法类。
*/
public class DateUtil {
public static boolean isDate(String dateStr) {
int len = dateStr.length();
if (len < 19) {
return false;
} else {
for(int i = 0; i < len; ++i) {
char ch = dateStr.charAt(i);
switch(i) {
case 4:
case 7:
if (ch != '-') {
return false;
}
break;
case 10:
if (ch != ' ') {
return false;
}
break;
case 13:
case 16:
if (ch != ':') {
return false;
}
break;
case 19:
if (ch != '.') {
return false;
}
break;
default:
if (ch < '0' || ch > '9') {
return false;
}
}
}
return true;
}
}
/**
* 格式化日期。
*
* @param date 需要格式化的日期。
* @param format 日期格式。
* @return 格式化后的日期字符串。如果date为空则返回空字符串。
*/
public static String format(Date date, String format) {
if (date == null)
return "";
SimpleDateFormat dateFormat = new SimpleDateFormat(format);
return dateFormat.format(date);
}
/**
* 按yyyy-MM-dd HH:mm:ss格式化日期。
*
* @param date 需要格式化的日期。
* @return 格式化后的日期字符串。如果date为空则返回空字符串。
*/
public static String format(Date date) {
return format(date, "yyyy-MM-dd HH:mm:ss");
}
/**
* 把以长整数表示的时间戳转换为Timestamp对象。
*
* @param time 时间戳值。
* @return 转换后的Timestamp对象。
*/
public static Timestamp getTimestamp(long time) {
return new Timestamp(time);
}
/**
* 获取指定日期所在月的天数。
*
* @param date 日期。
* @return 位于所在月的天数。
*/
public static int daysInMonth(Date date) {
Calendar cal = Calendar.getInstance();
cal.setTime(date);
return cal.getActualMaximum(Calendar.DAY_OF_MONTH);
}
/**
* 获取指定日期在所在月位于第几天。
*
* @param date 日期。
* @return 位于所在月的第天几。
*/
public static int dayOfMonth(Date date) {
Calendar cal = Calendar.getInstance();
cal.setTime(date);
return cal.get(Calendar.DAY_OF_MONTH);
}
/**
* 获取指定日期的年部分值。
*
* @param date 日期。
* @return 年部分值。
*/
public static int yearOf(Date date) {
Calendar cal = Calendar.getInstance();
cal.setTime(date);
return cal.get(Calendar.YEAR);
}
/**
* 获取指定日期在所在年位于第几天。
*
* @param date 日期。
* @return 位于所在年的第几天。
*/
public static int dayOfYear(Date date) {
Calendar cal = Calendar.getInstance();
cal.setTime(date);
return cal.get(Calendar.DAY_OF_YEAR);
}
/**
* 获取指定日期在所在周位于第几天。
*
* @param date 日期。
* @return 位于所在周的第几天。
*/
public static int dayOfWeek(Date date) {
Calendar cal = Calendar.getInstance();
cal.setTime(date);
return cal.get(Calendar.DAY_OF_WEEK);
}
/**
* 把日期转换成yyyy-MM-dd HH:mm:ss.fffffffff格式的字符串。
*
* @param value 需要转换的日期。
* @return 转换后的字符串。
*/
public static String dateToStr(Date value) {
if (value == null)
return null;
Timestamp t = new Timestamp(value.getTime());
return t.toString();
}
/**
* 把以 yyyy-MM-dd HH:mm:ss[.f...] 格式的字符串转换成时间戳。如果value为null或空串返回null。
*
* @param value 需要转换的字符串。
* @return 转换后的时间戳。
*/
public static Timestamp strToDate(String value) {
if (com.wb.util.StringUtil.isEmpty(value))
return null;
return Timestamp.valueOf(value);
}
/**
* 在指定日期上增加年数。
*
* @param date 日期。
* @param years 增加的年数。
* @return 增加年数后的日期。
*/
public static Date incYear(Date date, int years) {
Calendar cal = Calendar.getInstance();
cal.setTime(date);
cal.add(Calendar.YEAR, years);
return cal.getTime();
}
/**
* 在指定日期上增加月数。
*
* @param date 日期。
* @param months 增加的月数。
* @return 增加月数后的日期。
*/
public static Date incMonth(Date date, int months) {
Calendar cal = Calendar.getInstance();
cal.setTime(date);
cal.add(Calendar.MONTH, months);
return cal.getTime();
}
/**
* 获取指定日期的小时部分值。
*
* @param date 日期。
* @return 小时值。
*/
public static int hourOfDay(Date date) {
Calendar cal = Calendar.getInstance();
cal.setTime(date);
return cal.get(Calendar.HOUR_OF_DAY);
}
/**
* 把指定毫秒数格式化成 HH:mm:ss.fff形式显示的字符串。小时值允许大于24小时显示。
* @param milliSecs 毫秒数。
* @return 格式化后的文本。
*/
public static String format(long milliSecs) {
long h = milliSecs / 3600000, hm = milliSecs % 3600000;
long m = hm / 60000, mm = hm % 60000;
long s = mm / 1000, sm = mm % 1000;
return com.wb.util.StringUtil.concat(Long.toString(h), ":", Long.toString(m), ":",
Long.toString(s), ".", Long.toString(sm));
}
/**
* 在指定日期上增加天数。
*
* @param date 日期。
* @param days 增加的天数。
* @return 增加天数后的日期。
*/
public static Date incDay(Date date, long days) {
return new Date(date.getTime() + 86400000 * days);
}
/**
* 在指定日期上增加秒数。
*
* @param date 日期。
* @param
* @return 增加秒数后的日期。
*/
public static Date incSecond(Date date, long seconds) {
return new Date(date.getTime() + 1000 * seconds);
}
/**
* 计算两个日期相关的天数
* @param beginDate 开始日期。
* @param endDate 结束日期。
* @return 去掉小数后的相差天数。
*/
public static int getElapsedDays(Date beginDate, Date endDate) {
return (int) ((endDate.getTime() - beginDate.getTime()) / 86400000);
}
/**
* 修正以字符串形式表示的时间值,如果时间不符合格式将修正该值。
* @param str 以字符串形式表达的时间值。
* @return 修正后的值。
*/
public static String fixTime(String str) {
if (str.indexOf(':') == -1)
return "00:00:00";
int b = str.indexOf(' '), e = str.indexOf('.');
if (b == -1)
b = 0;
else
b++;
if (e == -1)
e = str.length();
return str.substring(b, e);
}
/**
* 修正以字符串形式表示的日期时间值,如果日期时间不符合格式将修正该值。
* @param str 以字符串形式表达的日期时间值。
* @param dateOnly 是否只返回日期部分字符串。
* @return 修正后的值。
*/
public static String fixTimestamp(String str, boolean dateOnly) {
int pos = str.indexOf(' ');
String datePart, timePart = null, sec[];
if (pos == -1) {
datePart = str;
if (!dateOnly)
timePart = "00:00:00";
} else {
datePart = str.substring(0, pos);
if (!dateOnly)
timePart = str.substring(pos + 1);
}
sec = StringUtil.split(datePart, "-");
if (sec.length == 3) {
StringBuilder buf = new StringBuilder(dateOnly ? 10 : 30);
buf.append(sec[0]);
buf.append('-');
if (sec[1].length() == 1)
buf.append('0');
buf.append(sec[1]);
buf.append('-');
if (sec[2].length() == 1)
buf.append('0');
buf.append(sec[2]);
if (!dateOnly) {
buf.append(' ');
buf.append(timePart);
}
return buf.toString();
} else
return str;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,635 @@
package com.wb.util;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import javax.swing.filechooser.FileSystemView;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.json.JSONArray;
import org.json.JSONObject;
import com.wb.common.Base;
import com.wb.common.UrlBuffer;
import com.wb.common.Var;
import com.wb.common.XwlBuffer;
/**
* 文件工具方法类。
*/
public class FileUtil {
public static String getModuleUrl(File file) {
String path = getPath(file);
return path.startsWith(Base.modulePathText) && path.toLowerCase().endsWith(".xwl") ? "m?xwl=" + path.substring(Base.modulePathLen, path.length() - 4) : null;
}
/**
* 获取指定文件名在同级目录下的唯一文件名称。
* 如果文件名称重复将通过在文件名称后添加序号的方法来获得唯一的名称。
* @param file 文件对象。
* @return 获得唯一文件名称的文件对象。
*/
public static File getUniqueFile(File file) {
if (file.exists()) {
File parent = file.getParentFile();
String fullName = file.getName(), namePart = removeExtension(fullName);
String extPart = getFileExt(fullName);
boolean emptyExt = extPart.isEmpty();
int i = 1;
if (!emptyExt)
extPart = '.' + extPart;
do {
if (emptyExt)
file = new File(parent, com.wb.util.StringUtil.concat(namePart, Integer.toString(i)));
else
file = new File(parent, com.wb.util.StringUtil.concat(namePart, Integer.toString(i), extPart));
i++;
} while (file.exists());
}
return file;
}
/**
* 读取以utf-8编码的文本文件数据。
* @param file 读取的文件。
* @return 文件中存储的文本。
* @throws IOException 读取文本过程发生异常。
*/
public static String readString(File file) throws IOException {
return FileUtils.readFileToString(file, "utf-8");
}
/**
* 把字符串以utf-8编码写入文件。
* @param file 写入的文件。
* @param content 写入的字符串。
* @throws IOException 写入文本过程发生异常。
*/
public static void writeString(File file, String content) throws IOException {
FileUtils.writeStringToFile(file, content, "utf-8");
}
/**
* 保存输入流对象数据至文件。保存完成后将关闭输入流inputStream。
* @param inputStream 输入流对象。
* @param file 文件对象。
* @throws IOException 保存过程发生异常。
*/
public static void saveStream(InputStream inputStream, File file) throws IOException {
FileOutputStream os = new FileOutputStream(file);
try {
IOUtils.copy(inputStream, os);
} finally {
IOUtils.closeQuietly(inputStream);
IOUtils.closeQuietly(os);
}
}
/**
* 获取指定文件名的扩展名,文件扩展名为文件名称中最后一个“.”号后的字符串。
* 如果文件名为空或没有扩展名则返回空字符串。
* @param fileName 文件名称。
* @return 文件扩展名。
*/
public static String getFileExt(String fileName) {
if (fileName != null) {
int i = fileName.lastIndexOf('.');
if (i != -1)
return fileName.substring(i + 1);
}
return "";
}
/**
* 获取文件或目录的类别显示名称。
* @param file 文件对象。
* @return 文件类别显示名称。
*/
public static String getFileType(File file) {
String type;
try {
type = FileSystemView.getFileSystemView().getSystemTypeDescription(file);
} catch (Throwable e) {
type = null;
}
if (com.wb.util.StringUtil.isEmpty(type))
return getFileExt(file.getName());
else
return type;
}
/**
* 获取文件路径中的文件名称部分,文件名称包含文件扩展名。
* @param path 文件路径。
* @return 文件名称。
*/
public static String getFilename(String path) {
if (com.wb.util.StringUtil.isEmpty(path))
return "";
int p = Math.max(path.lastIndexOf('/'), path.lastIndexOf('\\'));
if (p == -1)
return path;
else
return path.substring(p + 1);
}
/**
* 移去文件名称中的扩展名称部分。
* @param fileName 文件路径或名称。
* @return 移去扩展名后的文件名称,不含路径。
*/
public static String removeExtension(String fileName) {
String s = getFilename(fileName);
int i = s.lastIndexOf('.');
if (i != -1)
return s.substring(0, i);
else
return s;
}
/**
* 为指定文件名添加文件扩展名。如果文件名含扩展名将直接返回该文件名,否则在该文件名基础上添加扩展名。
* @param fileName 文件名称。
* @param extension 文件扩展名称。如js, java等。
* @return 添加扩展名后的文件名称。
*/
public static String addExtension(String fileName, String extension) {
if (fileName == null)
return null;
if (fileName.indexOf('.') != -1)
return fileName;
return fileName + "." + extension;
}
/**
* 把路径中所有的分隔符“\”转换成“/”。
* @param path 路径。
* @return 替换后的路径。
*/
public static String getPath(String path) {
return com.wb.util.StringUtil.replaceAll(path, "\\", "/");
}
/**
* 获取指定文件/目录的绝对路径,路径分隔符统一使用“/”来表示。
* @param file 文件或目录。
* @return 绝对路径。
*/
public static String getPath(File file) {
return getPath(file.getAbsolutePath());
}
/**
* 获取下级文件/目录相对于上级文件/目录的相对路径。
* @param parent 上级文件/目录。
* @param child 下级文件/目录。
* @return 相对路径。如果parent和child不存在上下级关系则返回null。
* @throws IOException 获取相对路径发生异常。
* @throws NullPointerException 如果parent和child目录中的任何一个为空。
*/
public static String getRelativePath(File parent, File child) {
if (parent == null)
throw new NullPointerException("Parent file is null.");
if (child == null)
throw new NullPointerException("Child file is null.");
String originChildPath = child.getAbsolutePath();
String childPath = originChildPath + File.separatorChar;
String parentPath = parent.getAbsolutePath() + File.separatorChar;
if (childPath.equals(parentPath))
return "";
if (childPath.startsWith(parentPath))
return getPath(originChildPath.substring(parentPath.length()));
else
return null;
}
/**
* 判断两个文件/目录是否存在上下级关系。
* @param parent 上级文件/目录。
* @param child 下级文件/目录。
* @return 如果parent等于child或者是child的上级目录则返回true否则返回false。
* @throws IOException 读取文件/目录正式路径时发生异常。
*/
public static boolean isAncestor(File parent, File child) throws IOException {
return isAncestor(parent, child, true);
}
/**
* 判断两个文件/目录是否存在上下级关系。
* @param parent 上级文件/目录。
* @param child 下级文件/目录。
* @param includeSelf 是否包括本身如果true表示两个文件相等也属于上下级关系。
* @return parent和child存在上下级关系则返回true否则返回false。
* @throws IOException 读取文件/目录正式路径时发生异常。
*/
public static boolean isAncestor(File parent, File child, boolean includeSelf) throws IOException {
String parentPath = parent.getCanonicalPath();
String childPath = child.getCanonicalPath();
// 某些操作系统根目录路径带File.separatorChar
if (!parentPath.endsWith(File.separatorChar + ""))
parentPath += File.separatorChar;
if (!childPath.endsWith(File.separatorChar + ""))
childPath += File.separatorChar;
return childPath.startsWith(parentPath) && (includeSelf || childPath.length() > parentPath.length());
}
/**
* 判断指定目录是否是空目录。
* @param folder 目录对象。
* @return 如果目录为空或folder对象为null则返回true否则返回false。
*/
public static boolean isEmpty(File folder) {
String[] fs;
return folder == null || (fs = folder.list()) == null || fs.length == 0;
}
/**
* 判断指定目录是否含有子目录。
* @param folder 目录对象。
* @return 如果目录含子目录返回true否则返回false。
*/
public static boolean hasFolder(File folder) {
File[] fs;
if (folder != null && (fs = folder.listFiles()) != null && fs.length > 0) {
for (File file : fs) {
if (file.isDirectory())
return true;
}
}
return false;
}
/**
* 判断文件修改日期是否大于等于指定的日期lastModified。如果指定的文件为目录则只要目录内任意一个文件修改日期大于等于lastModified
* 那么就判定该目录修改日期大于等于lastModified。
* @param file 需要判断的文件或目录。
* @param lastModified 修改日期。
* @return true大于等于该指定日期false小于该指定日期。
*/
public static boolean checkLastModified(File file, Date lastModified) {
if (file.isDirectory()) {
File fs[] = file.listFiles();
for (File f : fs) {
if (checkLastModified(f, lastModified))
return true;
}
return false;
} else
return file.lastModified() >= lastModified.getTime();
}
/**
* 获取指定目录下的所有子文件/目录列表。该方法功能同File.listFiles
* 区别在于该方法使用空数组替代返回null。
* @param file 目录对象。
* @return 目录下的所有子文件/目录列表。
*/
public static File[] listFiles(File file) {
if (!file.exists())
throw new RuntimeException("\"" + file.getName() + "\" does not exist.");
File[] fs = file.listFiles();
if (fs == null)
return new File[0];
else
return fs;
}
/**
* 复制文件或目录至目标目录,并同步复制同步目录下的同名文件或目录。如果在同一目录内复制
*系统会自动进行重命名。同步目录由变量sys.syncPath指定。
*
* @param src 复制的文件或目录。
* @param dst 复制到目标目录。
* @throws IOException 复制时发生异常。
* @return 复制后的文件或目录和目标是否存在组成的对象数组。
* @see FileUtil#getSyncPath
* @see FileUtil#syncCopyA
*/
public static Object[] syncCopy(File src, File dst) throws IOException {
String name = src.getName();
dst = new File(dst, name);
File syncDst = getSyncPath(dst);
boolean dstExists, isDir = src.isDirectory();
boolean sameParent = src.getParentFile().equals(dst.getParentFile());
// 同一目录内的复制自动重命名
if (sameParent)
dst = getUniqueFile(dst);
dstExists = dst.exists();
if (isDir)
FileUtils.copyDirectory(src, dst);
else
FileUtils.copyFile(src, dst);
if (syncDst != null) {
if (sameParent)
syncDst = getUniqueFile(syncDst);
if (isDir)
FileUtils.copyDirectory(src, syncDst);
else
FileUtils.copyFile(src, syncDst);
}
Object[] result = new Object[2];
result[0] = getPath(dst);
result[1] = dstExists;
return result;
}
/**
* 复制文件或目录至目标文件或目录,并同步复制同步目录下的同名文件或目录。该方法按指定路径
*进行复制。该方法同syncCopy的区别为前者严格按路径复制后者相当于在文件管理器中执行复制
*操作。同步目录由变量sys.syncPath指定。
*
* @param src 复制的文件或目录。
* @param dst 复制后的目标文件或目录。
* @throws IOException 复制时发生异常。
* @see FileUtil#getSyncPath
* @see FileUtil#syncCopy
*/
public static void syncCopyA(File src, File dst) throws IOException {
boolean isDir = src.isDirectory();
if (isDir)
FileUtils.copyDirectory(src, dst);
else
FileUtils.copyFile(src, dst);
File syncPath = FileUtil.getSyncPath(dst);
if (syncPath != null) {
if (isDir)
FileUtils.copyDirectory(src, syncPath);
else
FileUtils.copyFile(src, syncPath);
}
}
/**
* 创建文件或目录,并同步创建同步目录下的同名文件或目录。
*同步目录由变量sys.syncPath指定。
*
* @param file 需要创建的文件或目录。
* @param isDir 是否创建目录。
* @throws IOException 无法创建时抛出异常。
* @see FileUtil#getSyncPath
*/
public static void syncCreate(File file, boolean isDir) throws IOException {
String name = file.getName();
File syncPath = getSyncPath(file);
if (file.exists())
throw new IllegalArgumentException("\"" + name + "\" already exists.");
if (syncPath != null && syncPath.exists())
throw new IllegalArgumentException("\"" + syncPath.getAbsolutePath() + "\" already exists.");
if (isDir) {
if (!file.mkdir())
throw new IOException("Create \"" + name + "\" failure.");
if (syncPath != null && !syncPath.mkdir())
throw new IOException("Create \"" + syncPath.getAbsolutePath() + "\" failure.");
} else {
if (!file.createNewFile())
throw new IOException("Create \"" + name + "\" failure.");
if (syncPath != null && !syncPath.createNewFile())
throw new IOException("Create \"" + syncPath.getAbsolutePath() + "\" failure.");
}
if (syncPath != null)
syncPath.setLastModified(file.lastModified());
}
/**
* 删除指定的文件或目录,并同步删除同步目录下的同名文件或目录。
*同步目录由变量sys.syncPath指定。
*
* @param file 需要删除的文件或目录。
* @param clearUrl 是否清除URL捷径。
* @throws IOException 无法删除时抛出异常。
* @see FileUtil#getSyncPath
*/
public static void syncDelete(File file, boolean clearUrl) throws Exception {
if (!FileUtils.deleteQuietly(file))
throw new IOException("Cannot delete \"" + file.getName() + "\".");
File syncPath = getSyncPath(file);
if (syncPath != null && !FileUtils.deleteQuietly(syncPath))
throw new IOException("Cannot delete \"" + syncPath.toString() + "\".");
clearFiles(file, clearUrl);
}
/**
* 移动文件或目录至目标目录,并同步移动同步目录下的同名文件或目录。
*同步目录由变量sys.syncPath指定。
*
* @param src
* 移动的文件或目录。
* @param dst
* 移动到目标目录。
* @throws IOException
* 移动时发生异常。
* @see FileUtil#getSyncPath
*/
public static void syncMove(File src, File dst) throws Exception {
File syncDst = getSyncPath(dst);
FileUtils.moveToDirectory(src, dst, true);
if (syncDst != null) {
try {
File syncSrc = getSyncPath(src);
// 源目录无需同步时直接复制
if (syncSrc == null) {
if (syncDst.isDirectory())
FileUtils.copyDirectory(dst, syncDst);
else
FileUtils.copyFile(dst, syncDst);
} else
FileUtils.moveToDirectory(syncSrc, syncDst, true);
} catch (Throwable e) {
// 忽略
}
}
clearFiles(src, false);
}
/**
* 重命名文件或目录,并同步重命名同步目录下的同名文件或目录。
*同步目录由变量sys.syncPath指定。
*
* @param file
* 需要重命名的文件或目录。
* @param newFile
* 命名为新的文件或目录。
* @throws IOException
* 不能重命名。
* @see FileUtil#getSyncPath
*/
public static void syncRename(File file, File newFile) throws IOException {
File syncPath = getSyncPath(file);
if (!file.renameTo(newFile))
throw new IOException("Cannot rename \"" + file.getName() + "\".");
if (syncPath != null && !syncPath.renameTo(getSyncPath(newFile)))
throw new IOException("Cannot rename \"" + syncPath.toString() + "\".");
}
/**
* 保存二进制数据至指定文件,并同步保存至另一目录。
*同步目录由变量sys.syncPath指定。
*
* @param file
* 保存的文件对象。
* @param content
* 保存的二进制字节内容。
* @throws IOException
* 保存过存中发生异常。
* @see FileUtil#getSyncPath
*/
public static void syncSave(File file, byte[] content) throws Exception {
FileUtils.writeByteArrayToFile(file, content);
File syncPath = getSyncPath(file);
if (syncPath != null)
FileUtils.copyFile(file, syncPath);
}
/**
* 使用utf-8编码保存文本数据至指定文件并同步保存至另一目录。
*同步保存的目录由变量sys.syncPath指定。
*
* @param file 保存的文件对象。
* @param content 保存的文本内容。
* @throws IOException 保存过存中发生异常。
* @see FileUtil#getSyncPath
*/
public static void syncSave(File file, String content) throws Exception {
syncSave(file, content, "utf-8");
}
/**
* 使用指定编码保存文本数据至指定文件,并同步保存至另一目录。
*同步保存的目录由变量sys.syncPath指定。
* @param file 保存的文件对象。
* @param content 保存的文本内容。
* @param charset 字符编码。
* @throws IOException 保存过存中发生异常。
* @see FileUtil#getSyncPath
*/
public static void syncSave(File file, String content, String charset) throws Exception {
// 无需加文件锁
if (StringUtil.isEmpty(charset))
FileUtils.writeStringToFile(file, content);
else
FileUtils.writeStringToFile(file, content, charset);
File syncPath = getSyncPath(file);
if (syncPath != null) {
FileUtils.copyFile(file, syncPath);
}
String relPath = FileUtil.getModulePath(file);
if (relPath != null)
XwlBuffer.clear(relPath);
}
/**
* 获取位于同步目录下的指定文件或目录。路径为同步目录+指定文件/目录相对于应用目录的相对路径。
*
* @param path 获取同步文件/目录时的参考文件/目录。
* @return 位于同步目录下的指定文件如果不存在返回null。
* @throws IOException 获取过程发生异常。
*/
public static File getSyncPath(File path) throws IOException {
if (!Var.syncPath.isEmpty() && isAncestor(Base.path, path)) {
File base = new File(Base.path, Var.syncPath);
return new File(base, FileUtil.getPath(path).substring(Base.pathLen));
}
return null;
}
/**
* 清除指定文件/目录相关的资源。
* @param file 需要清除的文件或目录。
* @param clearUrl 是否清除URL捷径。
* @throws IOException 读写文件发生异常。
*/
private static void clearFiles(File file, boolean clearUrl) throws Exception {
// 清除索引信息
File folder = file.getParentFile();
File configFile = new File(folder, "folder.json");
if (configFile.exists()) {
JSONObject object = JsonUtil.readObject(configFile);
JSONArray index = object.optJSONArray("index");
if (index != null) {
int i, j = index.length();
File indexFile;
for (i = j - 1; i >= 0; i--) {
indexFile = new File(folder, index.getString(i));
if (!indexFile.exists())
index.remove(i);
}
syncSave(configFile, object.toString());
}
}
// 清除模块缓存数据
String relPath = FileUtil.getModulePath(file);
if (relPath != null) {
XwlBuffer.clear(relPath);
if (clearUrl) {
if (UrlBuffer.remove(relPath))
UrlBuffer.save();
}
}
}
/**
* 获得模块文件的相对路径。如果指定文件不是模块目录的子文件返回null。
* @param file 模块文件。
* @return 模块文件相对模块目录相对路径。
*/
public static String getModulePath(File file) {
String path = FileUtil.getPath(file);
if (path.startsWith(Base.modulePathText))
return path.substring(Base.modulePathLen);
else
return null;
}
/**
* 获取url中的模块文件路径url可为合法的xwl引用或其捷径。如果未找到文件抛出异常。
* @param url url路径。
* @return xwl模块文件相对路径。
*/
public static String getModuleFile(String url) {
return getModuleFile(url, false);
}
/**
* 获取url中的模块文件路径url可为合法的xwl引用或其捷径。
* @param url url路径。
* @param silent 如果未找到true返回nullfalse抛出异常。
* @return xwl模块文件相对路径。
*/
public static String getModuleFile(String url, boolean silent) {
if (url == null) {
if (silent)
return null;
throw new NullPointerException("The requested url is not specified.");
}
if (url.startsWith("m?xwl="))
return url.substring(6) + ".xwl";
else if (url.endsWith(".xwl"))
return url;
else {
// 捷径
String shortcut = url;
url = UrlBuffer.get("/" + shortcut);
if (url == null) {
if (silent)
return null;
throw new NullPointerException("The requested url shortcut \"" + shortcut + "\" is not found.");
}
return url;
}
}
}

View File

@@ -0,0 +1,379 @@
package com.wb.util;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.File;
import java.io.IOException;
import java.util.Map.Entry;
import java.util.Set;
/**
* JSON工具方法类。
*/
public class JsonUtil {
/**
* 获取JSONObject对象指定路径的值。如果值不存在将返回null。
* @param object JSONObject对象。
* @param path 路径。
* @param separator 路径分隔符。
* @return 获取的值。
*/
public static Object getValue(JSONObject object, String path, char separator) {
if (path == null)
throw new RuntimeException("null path value");
if (path.isEmpty())
return object;
String item, items[] = com.wb.util.StringUtil.split(path, separator);
JSONObject obj = object;
int i, j = items.length - 1;
for (i = 0; i < j; i++) {
item = items[i];
obj = obj.optJSONObject(item);
if (obj == null)
return null;
}
return obj.opt(items[j]);
}
/**
* 设置JSONObject对象指定路径属性的值如果属性不存在将创建该属性。如果值为null将删除该属性。
* @param object 需要设置的JSONObject对象。
* @param path 属性路径。
* @param separator 路径分隔符。
* @param value 设置的值。
* @return object本身。
*/
public static JSONObject setValue(JSONObject object, String path, char separator, Object value) {
if (com.wb.util.StringUtil.isEmpty(path))
throw new RuntimeException("Path is null or empty");
String item, items[] = com.wb.util.StringUtil.split(path, separator);
JSONObject obj = object;
int i, j = items.length - 1;
for (i = 0; i < j; i++) {
item = items[i];
obj = obj.optJSONObject(item);
if (obj == null) {
throw new RuntimeException("Path \"" + path + "\" does not exist.");
}
}
obj.put(items[j], value);
return object;
}
/**
* 读取文件中以utf-8格式存储的JSONObject字符串并生成JSONObject对象。
* @param file 文件对象。
* @return 生成的JSONObject对象。
* @throws IOException 读取文件过程发生异常。
* @throws JSONException 文件中的数据不是一个有效的JSONObject字符串。
*/
public static JSONObject readObject(File file) throws IOException {
String text = com.wb.util.FileUtil.readString(file);
text = text.replaceAll("\\\\(\\r\\n|\\r|\\n)","\\\\n");//add by liaw 2017-5-16 xwl多行保存支持版本工具进行合并
if (text.isEmpty())
return new JSONObject();
else {
try {
return new JSONObject(text.substring(text.indexOf('{')));
} catch (Throwable e) {
throw new JSONException("Invalid JSONObject: " + com.wb.util.StringUtil.ellipsis(text, 50));
}
}
}
/**
* 读取文件中以utf-8格式存储的JSONArray字符串并生成JSONArray对象。
* @param file 文件对象。
* @return 生成的JSONArray对象。
* @throws IOException 读取文件过程发生异常。
* @throws JSONException 文件中的数据不是一个有效的JSONArray字符串。
*/
public static JSONArray readArray(File file) throws IOException {
String text = FileUtil.readString(file);
if (text.isEmpty())
return new JSONArray();
else
try {
return new JSONArray(text.substring(text.indexOf('[')));
} catch (Throwable e) {
throw new JSONException("Invalid JSONArray: " + com.wb.util.StringUtil.ellipsis(text, 30));
}
}
/**
* 查找特定的包含某个键值的子JSONObject对象。
* @param jo 需要查找的JSONObject对象。
* @param itemsKey 子列表项的属性名称。
* @param key 查找的属性名称。
* @param value 查找的属性值。
* @return JSONObject对象。
*/
public static JSONObject findObject(JSONObject jo, String itemsKey, String key, String value) {
if (jo.optString(key).equals(value))
return jo;
JSONArray ja = jo.optJSONArray(itemsKey);
if (ja != null) {
int i, j = ja.length();
JSONObject item, result;
for (i = 0; i < j; i++) {
item = ja.optJSONObject(i);
if (item != null) {
result = findObject(item, itemsKey, key, value);
if (result != null)
return result;
}
}
}
return null;
}
/**
* 在由JSONObject组成的JSONArray中查找特定的JSONObject项。
* @param ja 查询的JSONArray
* @param key JSONobject包含的键名
* @param text 键名对应的值
* @return 查找到的JSONObject如果没有找到返回null
*/
public static JSONObject findObject(JSONArray ja, String key, String text) throws Exception {
int i, j = ja.length();
JSONObject jo;
for (i = 0; i < j; i++) {
jo = ja.getJSONObject(i);
if (jo.optString(key).equals(text))
return jo;
}
return null;
}
/**
* 查找特定的包含某个键值的子JSONObject对象的上级JSONArray对象。
* @param jo 需要查找的JSONObject对象。
* @param itemsKey 子列表项的属性名称。
* @param key 查找的属性名称。
* @param value 查找的属性值。
* @return JSONArray对象。
*/
public static JSONArray findArray(JSONObject jo, String itemsKey, String key, String value) {
JSONArray ja = jo.optJSONArray(itemsKey);
if (ja != null) {
int i, j = ja.length();
JSONObject item;
JSONArray result;
for (i = 0; i < j; i++) {
item = ja.optJSONObject(i);
if (item != null) {
if (item.optString(key).equals(value))
return ja;
result = findArray(item, itemsKey, key, value);
if (result != null)
return result;
}
}
}
return null;
}
/**
* 在JSONArray对象中查找指定值的索引号。
* <p>
* 示例: <blockquote>
*
* <pre>
* int index = JsonUtil.indexOf(jsonArray, &quot;value1&quot;);
* </pre>
*
* </blockquote>
*
* @param ja 需要查找的JSONArray对象
* @param value 需要查找的值
* @return 值所在的索引号
*/
public static int indexOf(JSONArray ja, String value) {
int i, j = ja.length();
for (i = 0; i < j; i++) {
if (value == null && ja.isNull(i) || value != null && value.equals(ja.opt(i)))
return i;
}
return -1;
}
/**
* 删除特定的包含某个键值的子JSONObject对象。
* @param jo 需要删除某个子项的JSONObject对象。
* @param itemsKey 子列表项的属性名称。
* @param key 查找的属性名称。
* @param value 查找的属性值。
* @return 以字符串形式表示的被删除的JSONObject对象。
*/
public static String remove(JSONObject jo, String itemsKey, String key, String value) {
JSONArray ja = jo.optJSONArray(itemsKey);
if (ja != null) {
int i, j = ja.length();
JSONObject item;
String result;
for (i = j - 1; i >= 0; i--) {
item = ja.optJSONObject(i);
if (item != null) {
if (com.wb.util.StringUtil.isEqual(item.optString(key, null), value)) {
result = item.toString();
ja.remove(i);
return result;
} else {
result = remove(item, itemsKey, key, value);
if (result != null)
return result;
}
}
}
}
return null;
}
/**
* 替换首个包含某个键值的子JSONObject对象为另一Object对象。
* @param jo 需要替换某个子项的JSONObject对象。
* @param itemsKey 子列表项的属性名称。
* @param key 查找的属性名称。
* @param value 查找的属性值。
* @param data 替换的对象。
* @return 找到对象并被替换返回true否则返回false。
*/
public static boolean replace(JSONObject jo, String itemsKey, String key, String value, Object data) {
JSONArray ja = jo.optJSONArray(itemsKey);
if (ja != null) {
int i, j = ja.length();
JSONObject item;
for (i = 0; i < j; i++) {
item = ja.optJSONObject(i);
if (item != null) {
if (com.wb.util.StringUtil.isEqual(item.optString(key, null), value)) {
ja.put(i, data);
return true;
} else if (replace(item, itemsKey, key, value, data))
return true;
}
}
}
return false;
}
/**
* 合并JSON数组中的所有项为字符串每项之间以指定分隔符分隔。
* @param array 需要合并的JSON数组对象。
* @param separator 分隔符。
* @return 合并后组成的字符串。
*/
public static String join(JSONArray array, String separator) {
int i, j = array.length();
if (j == 0)
return "";
StringBuilder buf = new StringBuilder();
for (i = 0; i < j; i++) {
if (i > 0)
buf.append(separator);
buf.append(array.getString(i));
}
return buf.toString();
}
/**
* 把使用逗号分隔的字符串转换成JSONObjectkey为分隔的文本内容value为true。
* @param text 需要转换的文本。
* @return 转换后生成的JSONObject。如果text为空返回空JSONObject。
*/
public static JSONObject fromCSV(String text) {
JSONObject jo = new JSONObject();
if (com.wb.util.StringUtil.isEmpty(text))
return jo;
String items[] = StringUtil.split(text, ',', true);
for (String item : items) {
jo.put(item, true);
}
return jo;
}
/**
* 获取JSONObject对象中指定名称的对象值如果值为JSON.null或null则返回null。
* @param jo 需要获取值的JSONObject对象。
* @param key 名称。
* @return 指定名称的对象值。
*/
public static Object opt(JSONObject jo, String key) {
if (jo.isNull(key))
return null;
else
return jo.opt(key);
}
/**
* 获取JSONArray对象中指定名称的对象值如果值为JSON.null或null则返回null。
* @param ja 需要获取值的JSONArray对象。
* @param index 索引值。
* @return 指定名称的对象值。
*/
public static Object opt(JSONArray ja, int index) {
if (ja.isNull(index))
return null;
else
return ja.opt(index);
}
/**
* 把dest中的项合并到source中如果source已经存在相同名称的项将被覆盖。
* @param source 源对象。
* @param dest 目录对象。
*/
public static void apply(JSONObject source, JSONObject dest) {
Set<Entry<String, Object>> es = dest.entrySet();
for (Entry<String, Object> e : es)
source.put(e.getKey(), e.getValue());
}
/**
* 把值转换为JSONArray对象。如果值为null或JSONArray直接返回该值否则返回使用此值构造后的JSONArray对象。
* @param value 需要转换为JSONArray的值。
* @return 转换为JSONArray后的值或null。
*/
public static JSONArray getArray(Object value) {
if (value == null || value instanceof JSONArray)
return (JSONArray) value;
else
return new JSONArray(value.toString());
}
/**
* 把值转换为JSONArray对象。如果值为null或JSONArray直接返回该值否则返回新的包含该值的JSONArray对象。
* @param value 需要转换为JSONArray的值。
* @return 转换为JSONArray后的值或null。
*/
public static JSONArray toArray(Object value) {
if (value == null || value instanceof JSONArray)
return (JSONArray) value;
else
return new JSONArray().put(value);
}
/**
* 把值转换为JSONObject对象。如果值为null或JSONObject直接返回该值否则返回使用此值构造后的JSONObject对象。
* @param value 需要转换为JSONObject的值。
* @return 转换为JSONObject后的值或null。
*/
public static JSONObject getObject(Object value) {
if (value == null || value instanceof JSONObject)
return (JSONObject) value;
else
return new JSONObject(value.toString());
}
}

View File

@@ -0,0 +1,155 @@
package com.wb.util;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.Timestamp;
import javax.servlet.http.HttpServletRequest;
import com.wb.common.Var;
/**
* 存储在数据库中的日志工具方法类。
*/
public class LogUtil {
/** 提示信息 */
public static final int INFO = 1;
/** 警告信息 */
public static final int WARN = 2;
/** 错误信息 */
public static final int ERROR = 3;
/**
* 把日志信息记入数据库日志表中。
* @param userName 用户名称。
* @param ip ip地址。
* @param type 日志类别1信息2警告3错误。
* @param object 要记录日志的对象。
*/
private static void record(String userName, String ip, int type,
Object object) {
long milliSec = System.currentTimeMillis();
int len;
Connection conn = null;
PreparedStatement st = null;
String text;
try {
conn = DbUtil.getConnection();
st = conn.prepareStatement("insert into WB_LOG (LOG_DATE, USER_NAME, IP, LOG_TYPE, MSG)values(?,?,?,?,?)");
if (StringUtil.isEmpty(ip))
ip = "-";
if (StringUtil.isEmpty(userName))
userName = "-";
if (object == null)
text = "-";
else {
text = object.toString();
if (StringUtil.isEmpty(text))
text = "-";
}
st.setTimestamp(1, new Timestamp(milliSec));
st.setString(2, userName);
st.setString(3, ip);
st.setInt(4, type);
// 确保最多只有255个字节被写入数据库
len = Math.min(text.length(), 256);
while (text.getBytes().length > 255) {
len--;
text = text.substring(0, len);
}
st.setString(5, text);
st.executeUpdate();
} catch (Throwable e) {
} finally {
DbUtil.close(st);
DbUtil.close(conn);
}
}
/**
* 把指定类型的日志信息记入数据库日志表中。
* @param type 日志类别1信息2警告3错误。
* @param msg 日志信息。
*/
private static void recordMsg(int type, Object msg) {
if (Var.log)
record(null, null, type, msg);
}
/**
* 把当前用户指定类型的日志信息记入数据库日志表中。
* @param request 请求对象该对象包含有当前用户和IP信息。
* @param type 日志类别0日志1信息2警告3错误。
* @param msg 日志信息。
*/
private static void recordUserMsg(HttpServletRequest request, int type,
Object msg) {
if (Var.log)
record(com.wb.util.WebUtil.fetch(request, "sys.username"), request
.getRemoteAddr(), type, msg);
}
/**
* 把指定用户IP类型的日志信息记入数据库日志表中。
* @param userName 用户名称。
* @param ip ip地址。
* @param type 日志类别1信息2警告3错误。
* @param msg 日志信息。
*/
public static void log(String userName, String ip, int type, Object msg) {
if (Var.log)
record(userName, ip, type, msg);
}
/**
* 把当前用户信息类日志信息记入数据库日志表中。
* @param request 请求对象该对象包含有当前用户和IP信息。
* @param msg 日志信息。
*/
public static void info(HttpServletRequest request, Object msg) {
recordUserMsg(request, INFO, msg);
}
/**
* 把信息类日志信息记入数据库日志表中。
* @param msg 日志信息。
*/
public static void info(Object msg) {
recordMsg(INFO, msg);
}
/**
* 把当前用户警告类日志信息记入数据库日志表中。
* @param request 请求对象该对象包含有当前用户和IP信息。
* @param s 日志信息。
*/
public static void warn(HttpServletRequest request, Object s) {
recordUserMsg(request, WARN, s);
}
/**
* 把警告类日志信息记入数据库日志表中。
* @param s 日志信息。
*/
public static void warn(Object s) {
recordMsg(WARN, s);
}
/**
* 把当前用户错误类日志信息记入数据库日志表中。
* @param request 请求对象该对象包含有当前用户和IP信息。
* @param s 日志信息。
*/
public static void error(HttpServletRequest request, Object s) {
recordUserMsg(request, ERROR, s);
}
/**
* 把错误类日志信息记入数据库日志表中。
* @param s 日志信息。
*/
public static void error(Object s) {
recordMsg(ERROR, s);
}
}

View File

@@ -0,0 +1,229 @@
package com.wb.util;
import java.io.File;
import java.text.CollationKey;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
/**
* 排序工具方法类。
*/
public class SortUtil {
/**
* 对指定文件列表中的文件/目录按名称正向排序。
* 目录将排列在文件之前。排序将影响files内文件的顺序。
* @param files 需要排序的文件列表。
* @return files对象本身。
*/
public static File[] sort(File[] files) {
sort(files, 0, false);
return files;
}
/**
* 对指定文件列表中的文件/目录按指定类别排序。
* 目录将排列在文件之前。排序将影响files内文件的顺序。
* 排序将影响files内文件的顺序。
* @param files 需要排序的文件列表。
* @param type 排序类别0文件名1文件大小2文件类别3修改日期。
* @param desc 是否逆向排序。
* @return files对象本身。
*/
public static File[] sort(File[] files, int type, boolean desc) {
final int fType = type;
final boolean fDesc = desc;
final Collator collator = Collator.getInstance();
Arrays.sort(files, new Comparator<File>() {
public int compare(File f1, File f2) {
switch (fType) {
case 1:
Long l1 = f1.isDirectory() ? -1 : f1.length();
Long l2 = f2.isDirectory() ? -1 : f2.length();
if (fDesc)
return l2.compareTo(l1);
return l1.compareTo(l2);
case 2:
CollationKey t1 = collator
.getCollationKey(f1.isDirectory() ? "0" : "1"
+ FileUtil.getFileType(f1).toLowerCase());
CollationKey t2 = collator
.getCollationKey(f2.isDirectory() ? "0" : "1"
+ FileUtil.getFileType(f2).toLowerCase());
if (fDesc)
return t2.compareTo(t1);
return t1.compareTo(t2);
case 3:
Long d1 = f1.lastModified();
Long d2 = f2.lastModified();
boolean b1 = f1.isDirectory();
boolean b2 = f2.isDirectory();
if (b1 && !b2)
d1 = Long.MIN_VALUE;
if (b2 && !b1)
d2 = Long.MIN_VALUE;
if (fDesc)
return d2.compareTo(d1);
return d1.compareTo(d2);
default:
int result;
String file1 = f1.getName();
String file2 = f2.getName();
CollationKey k1 = collator.getCollationKey((f1
.isDirectory() ? 0 : 1)
+ FileUtil.removeExtension(file1).toLowerCase());
CollationKey k2 = collator.getCollationKey((f2
.isDirectory() ? 0 : 1)
+ FileUtil.removeExtension(file2).toLowerCase());
if (fDesc)
result = k2.compareTo(k1);
else
result = k1.compareTo(k2);
if (result == 0) {
CollationKey ke1 = collator.getCollationKey((f1
.isDirectory() ? 0 : 1)
+ FileUtil.getFileExt(file1).toLowerCase());
CollationKey ke2 = collator.getCollationKey((f2
.isDirectory() ? 0 : 1)
+ FileUtil.getFileExt(file2).toLowerCase());
if (fDesc)
result = ke2.compareTo(ke1);
else
result = ke1.compareTo(ke2);
}
return result;
}
}
});
return files;
}
/**
* 对数组中的字符串按正序进行排序。排序结果将影响list。
* @param list 需要排序的字符串数组。
* @return list本身。
*/
public static String[] sort(String[] list) {
Arrays.sort(list, new Comparator<String>() {
Collator collator = Collator.getInstance();
public int compare(String s1, String s2) {
CollationKey key1 = collator.getCollationKey(StringUtil.opt(s1)
.toLowerCase());
CollationKey key2 = collator.getCollationKey(StringUtil.opt(s2)
.toLowerCase());
return key1.compareTo(key2);
}
});
return list;
}
/**
* 对Map中的键名按正序进行排序。
* @param map 需要排序的map。
* @return 排序后的Map Entry列表。
*/
public static <K, V> ArrayList<Entry<K, V>> sortKey(Map<K, V> map) {
return sortKey(map, false);
}
/**
* 对Map中的键名按正序进行排序。
* @param map 需要排序的map。
* @param keyAsNumber 是否把键名按数字进行排序。
* @return 排序后的Map Entry列表。
*/
public static <K, V> ArrayList<Entry<K, V>> sortKey(Map<K, V> map,
boolean keyAsNumber) {
ArrayList<Entry<K, V>> list = new ArrayList<Entry<K, V>>(map.entrySet());
final boolean keyAsNum = keyAsNumber;
final Collator collator = Collator.getInstance();
Collections.sort(list, new Comparator<Entry<K, V>>() {
public int compare(Entry<K, V> e1, Entry<K, V> e2) {
Object k1 = e1.getKey(), k2 = e2.getKey();
if (keyAsNum) {
if (k1 instanceof Number && k2 instanceof Number)
return (int) Math.ceil(((Number) k1).doubleValue()
- ((Number) k2).doubleValue());
else
return (int) Math.ceil(Double
.parseDouble(k1.toString())
- Double.parseDouble(k2.toString()));
} else {
CollationKey key1 = collator.getCollationKey(k1.toString()
.toLowerCase());
CollationKey key2 = collator.getCollationKey(k2.toString()
.toLowerCase());
return key1.compareTo(key2);
}
}
});
return list;
}
/**
* 对Map中的值按正序进行排序。
* @param map 需要排序的map。
* @return 排序后的Map Entry列表。
*/
public static <K, V> ArrayList<Entry<K, V>> sortValue(Map<K, V> map) {
return sortValue(map, false);
}
/**
* 对Map中的值按正序进行排序。
* @param map 需要排序的map。
* @param keyAsNumber 是否把值按数字进行排序。
* @return 排序后的Map Entry列表。
*/
public static <K, V> ArrayList<Entry<K, V>> sortValue(Map<K, V> map,
boolean keyAsNumber) {
ArrayList<Entry<K, V>> list = new ArrayList<Entry<K, V>>(map.entrySet());
final boolean keyAsNum = keyAsNumber;
final Collator collator = Collator.getInstance();
Collections.sort(list, new Comparator<Entry<K, V>>() {
public int compare(Entry<K, V> e1, Entry<K, V> e2) {
Object v1 = e1.getValue(), v2 = e2.getValue();
if (keyAsNum) {
if (v1 instanceof Number && v2 instanceof Number)
return (int) Math.ceil(((Number) v1).doubleValue()
- ((Number) v2).doubleValue());
else
return (int) Math.ceil(Double
.parseDouble(v1.toString())
- Double.parseDouble(v2.toString()));
} else {
CollationKey key1 = collator.getCollationKey(v1.toString()
.toLowerCase());
CollationKey key2 = collator.getCollationKey(v2.toString()
.toLowerCase());
return key1.compareTo(key2);
}
}
});
return list;
}
/**
* 对List进行排序排序忽略大小写。
* @param list 需要排序的list。
* @return list本身。
*/
public static <T> List<T> sort(List<T> list) {
Collections.sort(list, new Comparator<T>() {
public int compare(T b1, T b2) {
return b1.toString().toLowerCase().compareTo(
b2.toString().toLowerCase());
}
});
return list;
}
}

View File

@@ -0,0 +1,996 @@
package com.wb.util;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.mail.internet.MimeUtility;
import com.wb.common.Var;
import org.apache.commons.io.IOUtils;
import org.json.JSONObject;
/**
* 字符串工具方法类。
*/
public class StringUtil {
public static String doubleToString(double value) {
String text = Double.toString(value);
return !text.endsWith(".0") && !text.endsWith(",0") ? text : text.substring(0, text.length() - 2);
}
/**
* 生成指定重复数量的字符串组成的新字符串。
* @param text 需要重复的字符串。
* @param count 重复次数。
* @return 生成的新字符串。
*/
public static String repeat(String text, int count) {
StringBuilder buf = new StringBuilder(text.length() * count);
int i;
for (i = 0; i < count; i++)
buf.append(text);
return buf.toString();
}
public static String replaceParams(JSONObject jo, String text) {
if (jo != null && !isEmpty(text)) {
int start = 0;
int startPos = text.indexOf("{#", start);
int endPos = text.indexOf("#}", startPos + 2);
if (startPos != -1 && endPos != -1) {
StringBuilder buf;
for(buf = new StringBuilder(text.length()); startPos != -1 && endPos != -1; endPos = text.indexOf("#}", startPos + 2)) {
String paramName = text.substring(startPos + 2, endPos);
String paramValue;
if (paramName.startsWith("Var.")) {
paramValue = Var.getString(paramName.substring(4));
} else {
paramValue = jo.optString(paramName);
}
buf.append(text.substring(start, startPos));
if (paramValue != null) {
buf.append(paramValue);
}
start = endPos + 2;
startPos = text.indexOf("{#", start);
}
buf.append(text.substring(start));
return buf.toString();
} else {
return text;
}
} else {
return text;
}
}
/**
* 对字符串按指定分隔符进行分割,并返回分隔后字符串组成的数组。
* 如果分隔符separator是单个字符请使用更高效的split(String, char)方法。
* 该方法不支持正则表达式因此较String.split方法具有更高的性能。
* @param string 需要分隔的字符串。
* @param separator 分隔符。
* @return 分隔字符串组成的数组。
* @see StringUtil#split(String, char)
* @see String#split(String)
*/
public static String[] split(String string, String separator) {
return split(string, separator, false);
}
/**
* 对字符串按指定分隔符进行分割,并返回分隔后字符串组成的数组。
* 如果分隔符separator是单个字符请使用更高效的split(String, char, boolean)方法。
* 该方法允许对每个分隔的字符串执行trim操作。
* 该方法不支持正则表达式因此较String.split方法具有更高的性能。
* @param string 需要分隔的字符串。
* @param separator 分隔符。
* @param trim 是否对每个分隔的字符串执行trim操作。
* @return 分隔字符串组成的数组。
* @see StringUtil#split(String, char, boolean)
* @see String#split(String)
*/
public static String[] split(String string, String separator, boolean trim) {
int pos = 0, oldPos = 0, index = 0, separatorLen = separator.length();
ArrayList<Integer> posData = new ArrayList<Integer>();
if (string == null)
string = "";
while ((pos = string.indexOf(separator, pos)) != -1) {
posData.add(pos);
pos += separatorLen;
}
posData.add(string.length());
String[] result = new String[posData.size()];
for (int p : posData) {
if (trim)
result[index] = string.substring(oldPos, p).trim();
else
result[index] = string.substring(oldPos, p);
oldPos = p + separatorLen;
index++;
}
return result;
}
/**
* 对字符串按指定分隔符进行分割,并返回分隔后字符串组成的数组。
* 该方法不支持正则表达式因此较String.split方法具有更高的性能。
* @param string 需要分隔的字符串。
* @param separator 分隔符。
* @return 分隔字符串组成的数组。
* @see StringUtil#split(String, String)
* @see String#split(String)
*/
public static String[] split(String string, char separator) {
return split(string, separator, false);
}
/**
* 对字符串按指定分隔符进行分割,并返回分隔后字符串组成的数组。
* 该方法允许对每个分隔的字符串执行trim操作。
* 该方法不支持正则表达式因此较String.split方法具有更高的性能。
* @param string 需要分隔的字符串。
* @param separator 分隔符。
* @param trim 是否对每个分隔的字符串执行trim操作。
* @return 分隔字符串组成的数组。
* @see StringUtil#split(String, String, boolean)
* @see String#split(String)
*/
public static String[] split(String string, char separator, boolean trim) {
int pos = 0, oldPos = 0, index = 0;
ArrayList<Integer> posData = new ArrayList<Integer>();
if (string == null)
string = "";
while ((pos = string.indexOf(separator, pos)) != -1) {
posData.add(pos);
pos++;
}
posData.add(string.length());
String[] result = new String[posData.size()];
for (int p : posData) {
if (trim)
result[index] = string.substring(oldPos, p).trim();
else
result[index] = string.substring(oldPos, p);
oldPos = p + 1;
index++;
}
return result;
}
/**
* 判断两个字符串是否相等,该比较忽略字符串大小写。
* @param string1 比较的源字符串。
* @param string2 比较的目标字符串。
* @return 比较结果。如果两个字符串都为null返回true。
* @see StringUtil#isEqual(String, String)
*/
public static boolean isSame(String string1, String string2) {
if (string1 != null)
return string1.equalsIgnoreCase(string2);
else if (string2 != null)
return string2.equalsIgnoreCase(string1);
else
return true;
}
/**
* 判断两个字符串是否相等,该比较区分字符串大小写。
* @param string1 比较的源字符串。
* @param string2 比较的目标字符串。
* @return 比较结果。如果两个字符串都为null返回true。
* @see StringUtil#isSame(String, String)
*/
public static boolean isEqual(String string1, String string2) {
if (string1 != null)
return string1.equals(string2);
else if (string2 != null)
return string2.equals(string1);
else
return true;
}
/**
* 把对象转换成字符串。如果对象为空则返回空字符串。
* @param object 对象。
* @return 转换的字符串。
*/
public static String toString(Object object) {
if (object == null)
return "";
if (object instanceof Date)
return com.wb.util.DateUtil.dateToStr((Date) object);
return object.toString();
}
/**
* 使用html textarea标记引用指定文本。
* @param text 需要引用的文本。
* @return 引用后的文本。
*/
public static String textareaQuote(String text) {
return StringUtil.concat("<textarea>", text, "</textarea>");
}
/**
* 把指定字符串文本的关键字符(&, <, >, ', 和 ")转换成其对应的html字符。该方法同toHTML的区别
*在于前者用于转码后者仅用于显示目的。
* @param text 需要转换的文本。
* @return 转换后的HTML脚本。
*/
public static String toHTMLKey(String text) {
if (isEmpty(text))
return "";
int i, j = text.length();
StringBuilder out = new StringBuilder(text.length());
char c;
for (i = 0; i < j; i++) {
c = text.charAt(i);
switch (c) {
case '&':
out.append("&amp;");
break;
case '<':
out.append("&lt;");
break;
case '>':
out.append("&gt;");
break;
case '\'':
out.append("&#39;");
break;
case '"':
out.append("&quot;");
break;
default:
out.append(c);
}
}
return out.toString();
}
/**
* 把指定字符串文本转换成HTML脚本。
* @param text 需要转换的文本。
* @return 转换后的HTML脚本。
*/
public static String toHTML(String text) {
return toHTML(text, false, true);
}
/**
* 把指定字符串文本转换成HTML脚本。
* @param text 需要转换的文本。
* @param nbspAsEmpty 如果文本为空是否使用&amp;nbsp;替代。
* @param allowNewLine 是否允许换行,如果不允许则使用&amp;nbsp;替代。
* @return 转换后的HTML脚本。
*/
public static String toHTML(String text, boolean nbspAsEmpty, boolean allowNewLine) {
if (isEmpty(text)) {
if (nbspAsEmpty)
return "&nbsp;";
else
return "";
}
int i, j = text.length();
StringBuilder out = new StringBuilder(text.length());
char c;
for (i = 0; i < j; i++) {
c = text.charAt(i);
switch (c) {
case ' ':
if (i < j - 1 && text.charAt(i + 1) == ' ' || i > 1 && text.charAt(i - 1) == ' ')
out.append("&nbsp;");
else
out.append(" ");
break;
case '"':
out.append("&quot;");
break;
case '\'':
out.append("&#39;");
break;
case '<':
out.append("&lt;");
break;
case '>':
out.append("&gt;");
break;
case '&':
out.append("&amp;");
break;
case '\n':
if (allowNewLine)
out.append("<br>");
else
out.append("&nbsp;");
break;
case '\r':
break;
case '\t':
out.append("&nbsp;&nbsp;&nbsp;&nbsp;");
break;
default:
out.append(c);
}
}
return out.toString();
}
/**
* 查找指定字符串在数组中的位置。如果list参数为null返回-1。
* @param list 查找的数组。
* @param string 查找的字符串。
* @return 在数组中位置的索引号。
*/
public static int indexOf(String list[], String string) {
int i, j;
if (list == null)
return -1;
j = list.length;
for (i = 0; i < j; i++)
if (list[i].equals(string))
return i;
return -1;
}
/**
* 把以字符串形式表达的布尔值转换为对应的数字。字符串比较将忽略大小写。
* @param value 以字符串表达的布尔值。
* @return 布尔值对应的数字,"true"转换为"1", "false"转换为"0",其他值保持不变。
*/
public static String convertBool(String value) {
if ("true".equalsIgnoreCase(value))
return "1";
else if ("false".equalsIgnoreCase(value))
return "0";
else
return value;
}
/**
* 连接多个字符串为单个字符串。
* @param string 多个字符串列表。
* @return 多个字符串连接起来的单个字符串。
*/
public static String concat(String... string) {
int length = 0;
// 计算StringBuilder初始容量
for (String str : string)
length += str.length();
StringBuilder buf = new StringBuilder(length);
for (String str : string)
buf.append(str);
return buf.toString();
}
/**
* 查找目标字符在源字符串中出现的次数。
* @param source 源字符串。
* @param dest 目标字符。
* @return 源字符出现的次数。
*/
public static int stringOccur(String source, char dest) {
return stringOccur(source, dest, 0, source.length())[0];
}
/**
* 查找目标字符在源字符串中出现的次数。
* @param source 源字符串。
* @param dest 目标字符。
* @param startIndex 查找的开始位置。
* @param endIndex 查找的结束位置。
* @return 查找结果数组0项出现个数1项目标字符在源字符串最后一次出现的位置末尾。
*/
public static int[] stringOccur(String source, char dest, int startIndex, int endIndex) {
int result[] = new int[2], newPos, pos = startIndex, count = 0;
while ((newPos = source.indexOf(dest, pos)) != -1) {
if (newPos > endIndex)
break;
pos = newPos + 1;
count++;
}
result[0] = count;
result[1] = count == 0 ? (source.lastIndexOf(dest, endIndex) + 1) : pos;
return result;
}
/**
* 判断指定字符串是否是正负整数组成的字符串。
* @param string 需要判断的字符串。
* @return true整数false不是整数。
*/
public static boolean isInteger(String string) {
int i, j = string.length();
char ch;
if (j == 0)
return false;
for (i = 0; i < j; i++) {
ch = string.charAt(i);
if ((ch < '0' || ch > '9') && (i != 0 || ch != '-'))
return false;
}
return true;
}
/**
* 把指定字符串的文本转换成单行的字符串。文本中的回车、换行和tab都将被替换为空格。
* @param string 需要转换的文本。
* @return 转换后的单行字符串。
*/
public static String toLine(String string) {
int i, len = string.length();
if (len == 0)
return "";
StringBuilder buffer = new StringBuilder();
char c;
for (i = 0; i < len; i++) {
c = string.charAt(i);
switch (c) {
case '\n':
case '\r':
case '\t':
buffer.append(' ');
break;
default:
buffer.append(c);
}
}
return buffer.toString();
}
/**
* 获取字符串中“=”前面部分的字符串。如果没找到“=”将返回整个字符串。
* @param string 字符串。
* @return “=”前面部分的字符串。
*/
public static String getNamePart(String string) {
return getNamePart(string, '=');
}
/**
* 获取字符串中“=”后面部分的字符串。如果没找到“=”将返回空串。
* @param string 字符串。
* @return “=”后面部分的字符串。
*/
public static String getValuePart(String string) {
return getValuePart(string, '=');
}
/**
* 获取字符串中指定分割符前面部分的字符串。如果没找到分割符将返回整个字符串。
* @param string 字符串。
* @param separator 分割符。
* @return 分割符前的字符串。
*/
public static String getNamePart(String string, char separator) {
if (string == null)
return "";
int index = string.indexOf(separator);
if (index == -1)
return string;
else
return string.substring(0, index);
}
/**
* 获取字符串中指定分割符后面部分的字符串。如果没找到分割符将返回空串。
* @param string 字符串。
* @param separator 分割符。
* @return 分割符后的字符串。
*/
public static String getValuePart(String string, char separator) {
if (string == null)
return "";
int index = string.indexOf(separator);
if (index == -1)
return "";
else
return string.substring(index + 1);
}
/**
* 全部替换字符串中指定子串为另一字符串。该方法不支持正则表达式,
*因此较String.replace具有更高效率。
* @param string 需要替换的文本。
* @param oldString 替换的源字符串。
* @param newString 替换的目标字符串。
* @return 替换后的文本。
* @see String#replaceAll(String, String)
*/
public static String replaceAll(String string, String oldString, String newString) {
return innerReplace(string, oldString, newString, true);
}
/**
* 替换字符串中首个指定子串为另一字符串。该方法不支持正则表达式,
*因此较String.replace具有更高效率。
* @param string 需要替换的文本。
* @param oldString 替换的源字符串。
* @param newString 替换的目标字符串。
* @return 替换后的文本。
* @see String#replaceFirst(String, String)
*/
public static String replaceFirst(String string, String oldString, String newString) {
return innerReplace(string, oldString, newString, false);
}
/**
* 替换字符串中指定子串为另一字符串。该方法不支持正则表达式,
*因此较String.replace方法具有更高效率。
* @param string 需要替换的文本。
* @param oldString 替换的源字符串。
* @param newString 替换的目标字符串。
* @param isAll 是否替换全部出现的字符串true替换全部false替换首个。
* @return 替换后的文本。
*/
private static String innerReplace(String string, String oldString, String newString, boolean isAll) {
int index = string.indexOf(oldString);
if (index == -1)
return string;
int start = 0, len = oldString.length();
if (len == 0)
return string;
StringBuilder buffer = new StringBuilder(string.length());
do {
buffer.append(string.substring(start, index));
buffer.append(newString);
start = index + len;
if (!isAll)
break;
index = string.indexOf(oldString, start);
} while (index != -1);
buffer.append(string.substring(start));
return buffer.toString();
}
/**
* 读取指定输入流数据并转换为使用utf-8编码的字符串。完成后将关闭输入流stream。
* @param stream 输入流。
* @return 读取的字符串。
* @throws IOException 读取过程发生异常。
*/
public static String getString(InputStream stream) throws IOException {
return getString(stream, "utf-8");
}
/**
* 读取指定输入流数据并转换为使用utf-8编码的字符串。完成后不关闭输入流stream。
* @param stream 输入流。
* @return 读取的字符串。
* @throws IOException 读取过程发生异常。
*/
public static String getStringA(InputStream stream) throws IOException {
return getString(stream, "utf-8", false);
}
/**
* 读取指定输入流数据并转换为字符串。完成后将关闭输入流stream。
* @param stream 输入流。
* @param charset 使用的字符编码。
* @return 读取的字符串。
* @throws IOException 读取过程发生异常。
*/
public static String getString(InputStream stream, String charset) throws IOException {
return getString(stream, charset, true);
}
/**
* 读取指定输入流数据并转换为字符串。
* @param stream 输入流。
* @param charset 使用的字符编码。
* @param closeStream 读取完成后是否关闭输入流。
* @return 读取的字符串。
* @throws IOException 读取过程发生异常。
*/
public static String getString(InputStream stream, String charset, boolean closeStream) throws IOException {
try {
ByteArrayOutputStream os = new ByteArrayOutputStream();
IOUtils.copy(stream, os);
if (StringUtil.isEmpty(charset))
return new String(os.toByteArray());
else
return new String(os.toByteArray(), charset);
} finally {
if (closeStream)
stream.close();
}
}
/**
* 获取字符串的省略文本,如果字符串长过超过指定长度,
*将使用“...”省略显示,否则直接返回原字符串。
* @param string 需要省略显示的字符串。
* @param length 最大显示长度。
* @return 省略后的字符串。
*/
public static String ellipsis(String string, int length) {
if (string.length() > length)
return string.substring(0, length - 3) + "...";
return string;
}
/**
*对指定字符串进行引用操作,替换字符串中的特殊符号或不可见关键字为转义符,
*使字符串可以文本的形式直接显示和表达。字符串本身也加引号。
* @param string 需要被引用的字符串。
* @return 加引用后的字符串。
*/
public static String quote(String string) {
return quote(string, true);
}
/**
*对指定对象进行引用操作,先把对象转换为字符串,再替换字符串中的特殊符号或不可见关键字为转义符,
*使字符串可以文本的形式直接显示和表达。字符串本身不加引号。
* @param value 需要被引用的对象。
* @return 加引用后的字符串。
*/
public static String text(Object value) {
return quote(value == null ? null : value.toString(), false);
}
/**
*对指定字符串进行引用操作,替换字符串中的特殊符号或不可见关键字为转义符,
*使字符串可以文本的形式直接显示和表达。
* @param string 需要被引用的字符串。
* @param addQuotes 字符串是否需要加引号。
* @return 加引用后的字符串。
*/
public static String quote(String string, boolean addQuotes) {
int i, len;
if (string == null || (len = string.length()) == 0)
if (addQuotes)
return "\"\"";
else
return "";
char lastChar, curChar = 0;
String str;
StringBuilder sb = new StringBuilder(len + 10);
if (addQuotes)
sb.append('"');
for (i = 0; i < len; i++) {
lastChar = curChar;
curChar = string.charAt(i);
switch (curChar) {
case '\\':
case '"':
sb.append('\\');
sb.append(curChar);
break;
case '/':
if (lastChar == '<')
sb.append('\\');
sb.append(curChar);
break;
case '\b':
sb.append("\\b");
break;
case '\t':
sb.append("\\t");
break;
case '\n':
sb.append("\\n");
break;
case '\f':
sb.append("\\f");
break;
case '\r':
sb.append("\\r");
break;
default:
if (curChar < ' ' || (curChar >= '\u0080' && curChar < '\u00a0')
|| (curChar >= '\u2000' && curChar < '\u2100')) {
sb.append("\\u");
str = Integer.toHexString(curChar);
sb.append("0000", 0, 4 - str.length());
sb.append(str);
} else
sb.append(curChar);
}
}
if (addQuotes)
sb.append('"');
return sb.toString();
}
/**
* 如果指定字符串为null则返回空串否则返回字符串本身。
* @param string 字符串。
* @return 获得的字符串。
*/
public static String opt(String string) {
if (string == null)
return "";
else
return string;
}
/**
* 如果指定字符串为null或空串则返回null否则返回字符串本身。
* @param string 字符串。
* @return 获得的字符串或null。
*/
public static String force(String string) {
if (isEmpty(string))
return null;
else
return string;
}
/**
* 返回第1个非空字符串如果都为空则返回空串。
* @param string 字符串列表。
* @return 第1个非空字符串或空串。
*/
public static String select(String... string) {
for (String s : string)
if (!isEmpty(s))
return s;
return "";
}
/**
* 判断指定字符串值逻辑是否为真,'false'(不区分大小写)'0'''null返回false其他返回true。
* @param value 判断的字符串值。
* @return 布尔值。
*/
public static boolean getBool(String value) {
if (value == null || value.equalsIgnoreCase("false") || value.equals("0") || value.isEmpty())
return false;
else
return true;
}
/**
* 判断指定字符串值逻辑是否为真value为null返回nullvalue为'false'(不区分大小写)'0'
* ''null返回false其他返回true。
* @param value 判断的字符串值。
* @return 布尔值。
*/
public static Boolean getBoolA(String value) {
if (value == null)
return null;
return getBool(value);
}
/**
* 判断指定的字符串是否为空空串是指值为null或长度为0。
* @param string 需要判断的字符串。
* @return true为空false非空。
*/
public static boolean isEmpty(String string) {
return string == null || string.length() == 0;
}
/**
* 对指定字节数组采用BASE64编码并生成编码后的字符串。
* @param bytes 需要编码的字节数组。
* @return 使用BASE64编码的字符串。
* @throws Exception 编码过程发生异常。
*/
public static String encodeBase64(byte[] bytes) throws Exception {
OutputStream os = null;
ByteArrayOutputStream data;
try {
data = new ByteArrayOutputStream();
os = MimeUtility.encode(data, "base64");
os.write(bytes);
} finally {
os.close();
}
return new String(data.toByteArray());
}
/**
* 对指定输入流数据采用BASE64编码并生成编码后的字符串。编码完成后将关闭输入流is。
* @param is 需要编码的输入流。
* @return 使用BASE64编码的字符串。
* @throws Exception 编码过程发生异常。
*/
public static String encodeBase64(InputStream is) throws Exception {
OutputStream os = null;
ByteArrayOutputStream inData = null, outData = null;
try {
inData = new ByteArrayOutputStream();
outData = new ByteArrayOutputStream();
IOUtils.copy(is, inData);
os = MimeUtility.encode(outData, "base64");
os.write(inData.toByteArray());
} finally {
IOUtils.closeQuietly(is);
IOUtils.closeQuietly(os);
}
return new String(outData.toByteArray());
}
/**
* 对BASE64编码的字符串解码并生成解码后的字节数组。
* @param data 需要解码的字符串。
* @return 使用BASE64解码的字节数组。
* @throws Exception 解码过程发生异常。
*/
public static byte[] decodeBase64(String data) throws Exception {
ByteArrayInputStream is = new ByteArrayInputStream(data.getBytes());
ByteArrayOutputStream os = new ByteArrayOutputStream();
InputStream base64is;
base64is = MimeUtility.decode(is, "base64");
try {
IOUtils.copy(base64is, os);
} finally {
base64is.close();
}
return os.toByteArray();
}
/**
* 对指定对象进行编码。对字符串进行引用对数字转换成字符串对输入流转换成BASE64字符串
*对其他对象则转换成对应的字符串并进行引用。如果对象为null则返回字符串"null"。
* @param object 需要进行编码的对象。
* @return 编码后的字符串。
* @throws Exception 编码过程发生异常。
*/
public static String encode(Object object) throws Exception {
if (object == null)
return "null";
else if (object instanceof InputStream)
return quote(encodeBase64((InputStream) object));
else if (object instanceof Number || object instanceof Boolean)
return object.toString();
else if (object instanceof java.sql.Timestamp || object instanceof java.sql.Date
|| object instanceof java.sql.Time)
return quote(object.toString());
else if (object instanceof Date)
return quote(DateUtil.dateToStr((Date) object));
else
return quote(object.toString());
}
/**
* 验证name的合法性。name必须由字母数字和下划线组成其中首字符不能是数字。
* @param name 需要被验证的字符串对象。
* @return true合法false非法。
*/
public static boolean checkName(String name) {
return checkName(name, false);
}
/**
* 验证name的合法性。name必须由字母小数点数字和下划线组成其中首字符不能是数字。
* @param name 需要被验证的字符串对象。
* @param containDot 是否包含小数点。
* @return true合法false非法。
*/
public static boolean checkName(String name, boolean containDot) {
int i, j = name.length();
char c;
for (i = 0; i < j; i++) {
c = name.charAt(i);
if (!(c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '_' || i > 0 && c >= '0' && c <= '9'
|| containDot && c == '.')) {
return false;
}
}
return true;
}
/**
* 如果指定名称是由字母、数字和下划线组成的合法名称直接返回,否则将被双引号引用后返回。
* @param name 需要引用的名称。
* @return 引用后的名称。
*/
public static String quoteIf(String name) {
if (checkName(name))
return name;
else
return quote(name);
}
/**
* 连接数组中的每个字符串,并以指定分隔符分隔。如果子项为空,则排除该项。
* @param strings 需要连接的字符串数组。
* @param splitter 分隔字符串。
* @return 连接后的字符串。
*/
public static String join(String[] strings, String splitter) {
StringBuilder buf = new StringBuilder();
boolean added = false;
for (String s : strings) {
if (StringUtil.isEmpty(s))
continue;
if (added)
buf.append(splitter);
else
added = true;
buf.append(s);
}
return buf.toString();
}
/**
* 连接列表中的每个对象,并以指定分隔符分隔。如果子项为空,则排除该项。
* @param list 需要连接的列表。
* @param splitter 分隔字符串。
* @return 连接后的字符串。
*/
public static String join(List<String> list, String splitter) {
StringBuilder buf = new StringBuilder();
boolean added = false;
for (String item : list) {
if (StringUtil.isEmpty(item))
continue;
if (added)
buf.append(splitter);
else
added = true;
buf.append(item);
}
return buf.toString();
}
/**
* 截取字符串指定开始和结束位置的子串。此方法实现同js substring但不同于java substring方法。
* @param string 需要截取的字符串。
* @param beginIndex 开始位置。
* @param endIndex 结束位置。
* @return 截取的子串。
*/
public static String substring(String string, int beginIndex, int endIndex) {
if (string == null)
return null;
int len = string.length(), i, j;
if (beginIndex > endIndex) {
i = endIndex;
j = beginIndex;
} else {
i = beginIndex;
j = endIndex;
}
if (i < 0)
i = 0;
else if (i > len)
i = len;
if (j < 0)
j = 0;
else if (j > len)
j = len;
return string.substring(i, j);
}
/**
* 把浮点数按指定格式进行格式化并转换为文本值。
* @param value 需要格式化的浮点数值。
* @return 格式化后的文本值。
*/
public static String formatNumber(double value, String format) {
DecimalFormat df;
df = new DecimalFormat(format);
df.setRoundingMode(RoundingMode.HALF_UP);
return df.format(value);
}
}

View File

@@ -0,0 +1,455 @@
package com.wb.util;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.io.IOUtils;
import com.wb.common.Dictionary;
import com.wb.common.FileBuffer;
import com.wb.common.KVBuffer;
import com.wb.common.ScriptBuffer;
import com.wb.common.Str;
import com.wb.common.Var;
import com.wb.common.XwlBuffer;
/**
* 系统工具方法类。
*/
public class SysUtil {
/**
* 服务器端维护的维一ID号。
*/
private static long currentId = 0;
/**
* 服务器ID号的首位字符。
*/
private static byte serverId0;
/**
* 服务器ID号的次位字符。
*/
private static byte serverId1;
/**
* 同步锁。
*/
private static Object lock = new Object();
/**
* 36进制数字表。
*/
public static final byte[] digits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E',
'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' };
/**
* 默认缓冲区大小。
*/
public static final int bufferSize = 4096;
/**
* 把反射的方法存储到HashMap中以提高对方法的访问性能。
*/
private static final ConcurrentHashMap<String, Method> methodBuffer = new ConcurrentHashMap<String, Method>();
/**
* 获取服务器端唯一且正增长的13位长度编号。该编号由2位服务器编号字符串和11位基于时序动态
*生成的字符串组成。编号由26个大写字母和10个数字组成。该方法可产生唯一且正增长的id号
*可保证在公元2386年前的编码长度不超过11位另2位为服务器编号。该方法仅保证指定服务器
*内前2位服务器编号的编号唯一。如果要使用全球唯一的编号请使用java.util.UUID。
* @return 指定服务器内唯一的id号。
* @see java.util.UUID#randomUUID()
*/
public static String getId() {
long id;
synchronized (lock) {
if (currentId == 0) {
currentId = (new Date()).getTime() * 10000;
String serverId = Var.getString("sys.serverId");
serverId0 = (byte) serverId.charAt(0);
serverId1 = (byte) serverId.charAt(1);
}
id = currentId++;
}
return numToString(id);
}
/**
* 把长整数转换为36进制的字符串并在该字符串前加上服务器编号作为整个字符串返回。
* @param num 需要转换的数值。
* @return 转换后的字符串。
*/
private static String numToString(long num) {
byte buf[] = new byte[13], charPos = 12;
long val;
buf[0] = serverId0;
buf[1] = serverId1;
while ((val = num / 36) > 0) {
buf[charPos--] = digits[(byte) (num % 36)];
num = val;
}
buf[charPos] = digits[(byte) num];
return new String(buf);
}
/**
* 获取指定异常对象的根异常信息。
* @param e 异常对象。
* @return 获取的根异常信息。
*/
public static String getRootError(Throwable e) {
Throwable cause, c = e;
String message;
do {
cause = c;
c = c.getCause();
} while (c != null);
message = cause.getMessage();
if (StringUtil.isEmpty(message))
message = cause.toString();
return StringUtil.toLine(message.trim());
}
/**
* 获取指定异常对象的根异常信息。
* @param e 异常对象。
* @return 获取的根异常信息。
*/
public static Throwable getRootExcept(Throwable e) {
Throwable cause, c = e;
do {
cause = c;
c = c.getCause();
} while (c != null);
return cause;
}
/**
* 执行含HttpServletRequest和HttpServletResponse参数的静态方法。
* @param classMethodName 包名、类名和方法名构成的全名。
* @param request 请求对象。
* @param response 响应对象。
* @throws Exception 执行方法过程发生异常。
*/
public static void executeMethod(String classMethodName, HttpServletRequest request, HttpServletResponse response)
throws Exception {
Method method = methodBuffer.get(classMethodName);
if (method == null) {
// 无需使用同步。
int pos = classMethodName.lastIndexOf('.');
String className, methodName;
if (pos == -1) {
className = "";
methodName = classMethodName;
} else {
className = classMethodName.substring(0, pos);
methodName = classMethodName.substring(pos + 1);
}
Class<?> cls = Class.forName(className);
method = cls.getMethod(methodName, HttpServletRequest.class, HttpServletResponse.class);
methodBuffer.put(classMethodName, method);
}
method.invoke(null, request, response);
}
/**
* 把输入流对象转换成基于字节的输入流对象,并关闭原输入流对象。
* @param is 输入流。
* @return 字节输入流。
* @throws IOException 读取流过程发生异常。
*/
public static ByteArrayInputStream toByteArrayInputStream(InputStream is) throws IOException {
if (is instanceof ByteArrayInputStream)
return (ByteArrayInputStream) is;
byte[] bytes;
try {
bytes = IOUtils.toByteArray(is);
} finally {
is.close();
}
return new ByteArrayInputStream(bytes);
}
/**
* 从Reader对象读取字符串。读取完成后关闭reader。
* @param reader Reader对象。
* @return 读取的字符串。
* @throws IOException 读取过程发生异常。
*/
public static String readString(Reader reader) throws IOException {
try {
char buf[] = new char[bufferSize];
StringBuilder sb = new StringBuilder();
int len;
while ((len = reader.read(buf)) > 0) {
sb.append(buf, 0, len);
}
return sb.toString();
} finally {
reader.close();
}
}
/**
* 抛出异常信息。
* @param msg 异常信息。
* @throws RuntimeException 抛出异常。
*/
public static void error(String msg) {
throw new RuntimeException(msg);
}
/**
* 抛出包含指定错误代码的异常信息。错误代码包含在错误信息中,并使用特定关键字引用。
* @param msg 异常信息。
* @param errorNo 错误代码。
* @throws RuntimeException 抛出异常。
*/
public static void error(String msg, String errorNo) throws RuntimeException {
throw new RuntimeException(StringUtil.concat("#WBE", errorNo, ":", msg));
}
/**
* 判断指定对象是否是数组。
* @return true对象是数组false对象不是数组。
*/
public static boolean isArray(Object object) {
if (object == null)
return false;
return object.getClass().isArray();
}
/**
* 把JS数组转换为Java数组。
* @return 转换后的Java数组。
*/
public static Object[] javaArray(Object[] value) {
return value;
}
/**
* 把JS数组转换为Java整数数组。
* @return 转换后的Java整数数组。
*/
public static Integer[] javaIntArray(Integer[] value) {
return value;
}
/**
* 把对象类型值转换为字符串类型值。
* @return 转换后的字符串值。
*/
public static String javaString(Object value) {
return value.toString();
}
/**
* 把对象类型值转换为整数类型值。
* @return 转换后的值。
*/
public static Integer javaInt(Object value) {
if (value == null)
return null;
else if (value instanceof Number)
return ((Number) value).intValue();
else
return Integer.parseInt(value.toString());
}
/**
* 把对象类型值转换为长整数类型值。
* @return 转换后的值。
*/
public static Long javaLong(Object value) {
if (value == null)
return null;
else if (value instanceof Number)
return ((Number) value).longValue();
else
return Long.parseLong(value.toString());
}
/**
* 把对象类型值转换为浮点数类型值。
* @return 转换后的值。
*/
public static Float javaFloat(Object value) {
if (value == null)
return null;
else if (value instanceof Number)
return ((Number) value).floatValue();
else
return Float.parseFloat(value.toString());
}
/**
* 把对象类型值转换为双精度类型值。
* @return 转换后的值。
*/
public static Double javaDouble(Object value) {
if (value == null)
return null;
else if (value instanceof Number)
return ((Number) value).doubleValue();
else
return Double.parseDouble(value.toString());
}
/**
* 把JS类型值转换为Java布尔类型值。
* @return 转换后的Java值。
*/
public static Boolean javaBool(Boolean value) {
return value;
}
/**
* 判断指定对象是否是Map。
* @return true对象是Mapfalse对象不是Map。
*/
public static boolean isMap(Object object) {
return object instanceof Map<?, ?>;
}
/**
* 判断指定对象是否是可遍历的Iterable对象。
* @return true是false不是。
*/
public static boolean isIterable(Object object) {
return object instanceof Iterable<?>;
}
/**
* 重新热加载系统。
* @param type 加载类型1全部2非数据库相关类3数据库相关类。
*/
public static void reload(int type) {
if (type == 1 || type == 2) {
Var.load();
com.wb.interact.Controls.load();
FileBuffer.load();
ScriptBuffer.load();
Str.load();
com.wb.common.UrlBuffer.load();
XwlBuffer.load();
}
if (type == 1 || type == 3) {
KVBuffer.load();
Dictionary.load();
}
}
/**
* 获取二维数组内指定的值。索引0存放键索引1存放值根据键获取值。
* @param data 二维数组。
* @param key 键名
* @return 键名对应的值。
*/
public static Object getValue(Object[][] data, String key) {
for (Object[] item : data) {
if (key.equals(item[0]))
return item[1];
}
return null;
}
/**
* 抛出包含Access denied信息的异常。
*/
public static void accessDenied() {
throw new RuntimeException("Access denied.");
}
/**
* 获取指定对象的类fields和methods成员名称组成的列表。
* @return 对象的类成员名称列表。
*/
public static ArrayList<String> getObjectMembers(Object object) {
return getClassMembers(object.getClass());
}
/**
* 获取指定对象的类fields和methods成员名称组成的列表。
* @return 对象的类成员名称列表。
*/
public static ArrayList<String> getClassMembers(Class<?> cls) {
ArrayList<String> list = new ArrayList<String>();
Field[] fields = cls.getFields();
Method[] methods = cls.getMethods();
String name;
for (Field field : fields) {
name = field.getName();
if (list.indexOf(name) == -1)
list.add(name);
}
for (Method method : methods) {
name = method.getName();
if (list.indexOf(name) == -1)
list.add(name);
}
return list;
}
/**
* 获取本机的mac地址如果获取过程发生异常返回"invalid"字符串。
* @return 本机mac地址或invalid字符串。
*/
public static String getMacAddress() {
try {
NetworkInterface network = NetworkInterface.getByInetAddress(InetAddress.getLocalHost());
byte[] mac = network.getHardwareAddress();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < mac.length; i++) {
sb.append(String.format("%02X%s", mac[i], (i < mac.length - 1) ? "-" : ""));
}
return sb.toString();
} catch (Throwable e) {
return "invalid";
}
}
/**
* 获取用户设置的输出至用户文件时换行符号。
* @return 换行符号。
*/
public static String getLineSeparator() {
String sp = Var.getString("sys.locale.lineSeparator");
if ("\\r".equals(sp))
return "\r";
else if ("\\n".endsWith(sp))
return "\n";
else
return "\r\n";
}
/**
* 把数组列表项内的所有值添加到HashSet中。
* @param <T> 指定类型。
* @param items 列表项数组。
* @return 所有列表项添加到HashSet值。
*/
public static <T> HashSet<T> toHashSet(T[] items) {
HashSet<T> hashSet = new HashSet<T>();
for (T item : items) {
hashSet.add(item);
}
return hashSet;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,133 @@
package com.wb.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import org.apache.commons.io.IOUtils;
import com.syspatch.zip.ZipEntry;
import com.syspatch.zip.ZipInputStream;
import com.syspatch.zip.ZipOutputStream;
import com.wb.common.Var;
/**
* 压缩工具方法类。
*/
public class ZipUtil {
/**
* 压缩文件列表到输入流中。压缩包中的文件名称编码由变量sys.locale.filenameCharset设定默认为空表示
*使用操作系统默认编码。
* @param source 需要压缩的文件列表。
* @param outputStream 压缩的文件输出到该流。
* @throws IOException 压缩过程中发生异常。
*/
public static void zip(File source[], OutputStream outputStream) throws IOException {
ZipOutputStream zipStream = new ZipOutputStream(outputStream);
zipStream.fileCharset = Var.getString("sys.locale.filenameCharset");
try {
for (File file : source)
zip(file, zipStream, file.getName());
} finally {
zipStream.close();
}
}
/**
* 压缩文件列表到指定文件中。压缩包中的文件名称编码由变量sys.locale.filenameCharset设定
*默认为空表示使用操作系统默认编码。
* @param source 需要压缩的文件列表。
* @param zipFile 压缩的文件输出到该文件。
* @throws IOException 压缩过程中发生异常。
*/
public static void zip(File source[], File zipFile) throws Exception {
zip(source, new FileOutputStream(zipFile));
}
/**
* 压缩文件或目录指输出流。
* @param source 被压缩的文件。
* @param zipStream 输出的文件。
* @param base 文件地址。
* @throws IOException 压缩过程发生异常。
*/
private static void zip(File source, ZipOutputStream zipStream, String base) throws IOException {
ZipEntry entry;
if (source.isDirectory()) {
entry = new ZipEntry(base + '/');
entry.setTime(source.lastModified());
zipStream.putNextEntry(entry);
if (!StringUtil.isEmpty(base))
base += '/';
File[] fileList = FileUtil.listFiles(source);
for (File file : fileList)
zip(file, zipStream, base + file.getName());
} else {
entry = new ZipEntry(base);
entry.setTime(source.lastModified());
zipStream.putNextEntry(entry);
FileInputStream in = new FileInputStream(source);
try {
IOUtils.copy(in, zipStream);
} finally {
in.close();
}
}
}
/**
* 解压缩流中的文件至指定目录。压缩包中的文件名称编码由变量sys.locale.filenameCharset设定
*默认为空表示使用操作系统默认编码。
* @param inputStream 需要解压缩的流。
* @param dest 流中的文件解压缩到该目录。
* @throws IOException 解压缩过程发生异常。
*/
public static void unzip(InputStream inputStream, File dest) throws IOException {
ZipInputStream zipStream = new ZipInputStream(inputStream);
zipStream.fileCharset = Var.getString("sys.locale.filenameCharset");
ZipEntry z;
File f;
String name;
FileOutputStream out;
try {
while ((z = zipStream.getNextEntry()) != null) {
name = z.getName();
if (z.isDirectory()) {
name = name.substring(0, name.length() - 1);
f = new File(dest, name);
if (!f.exists())
f.mkdir();
} else {
f = new File(dest, name);
if (!f.exists())
f.createNewFile();
out = new FileOutputStream(f);
try {
IOUtils.copy(zipStream, out);
} finally {
out.close();
}
}
f.setLastModified(z.getTime());
}
} finally {
zipStream.close();
}
}
/**
* 解压缩压缩文件中的文件至指定目录。压缩包中的文件名称编码由变量sys.locale.filenameCharset设定
*默认为空表示使用操作系统默认编码。
* @param zipFile 需要解压缩的文件。
* @param dest 文件解压缩到该目录。
* @throws IOException 解压缩过程发生异常。
*/
public static void unzip(File zipFile, File dest) throws IOException {
unzip(new FileInputStream(zipFile), dest);
}
}