diff --git a/JSD-8345需求确认书.docx b/JSD-8345需求确认书.docx
new file mode 100644
index 0000000..82ead75
Binary files /dev/null and b/JSD-8345需求确认书.docx differ
diff --git a/README.md b/README.md
index 3a8420c..b9a2c43 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,6 @@
# open-JSD-8345
-JSD-8345 开源任务材料
\ No newline at end of file
+JSD-8345 开源任务材料\
+免责说明:该源码为第三方爱好者提供,不保证源码和方案的可靠性,也不提供任何形式的源码教学指导和协助!\
+仅作为开发者学习参考使用!禁止用于任何商业用途!\
+为保护开发者隐私,开发者信息已隐去!若原开发者希望公开自己的信息,可联系hugh处理。
\ No newline at end of file
diff --git a/plugin.xml b/plugin.xml
new file mode 100644
index 0000000..341ff64
--- /dev/null
+++ b/plugin.xml
@@ -0,0 +1,27 @@
+
+ com.fr.plugin.ztzzSSO
+
+ yes
+ 1.0.10
+ 10.0
+ 2018-07-31
+ wink
+
+
+ com.fr.plugin.ztzzSSO
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/com/fr/plugin/ztzzSSO/config/InitializeMonitor.java b/src/main/java/com/fr/plugin/ztzzSSO/config/InitializeMonitor.java
new file mode 100644
index 0000000..d712c9d
--- /dev/null
+++ b/src/main/java/com/fr/plugin/ztzzSSO/config/InitializeMonitor.java
@@ -0,0 +1,21 @@
+package com.fr.plugin.ztzzSSO.config;
+
+import com.fr.plugin.context.PluginContext;
+import com.fr.plugin.observer.inner.AbstractPluginLifecycleMonitor;
+
+/**
+ * @author richie
+ * @version 10.0
+ * Created by richie on 2018-12-04
+ */
+public class InitializeMonitor extends AbstractPluginLifecycleMonitor {
+ @Override
+ public void afterRun(PluginContext pluginContext) {
+ PluginSimpleConfig.getInstance();
+ }
+
+ @Override
+ public void beforeStop(PluginContext pluginContext) {
+
+ }
+}
diff --git a/src/main/java/com/fr/plugin/ztzzSSO/config/PluginSimpleConfig.java b/src/main/java/com/fr/plugin/ztzzSSO/config/PluginSimpleConfig.java
new file mode 100644
index 0000000..589dbc5
--- /dev/null
+++ b/src/main/java/com/fr/plugin/ztzzSSO/config/PluginSimpleConfig.java
@@ -0,0 +1,176 @@
+package com.fr.plugin.ztzzSSO.config;
+
+import com.fr.config.*;
+import com.fr.config.holder.Conf;
+import com.fr.config.holder.factory.Holders;
+import com.fr.intelli.record.Focus;
+import com.fr.intelli.record.Original;
+import com.fr.record.analyzer.EnableMetrics;
+
+@Visualization(category = "单点登录和用户同步配置")
+@EnableMetrics
+public class PluginSimpleConfig extends DefaultConfiguration {
+
+ private static volatile PluginSimpleConfig config = null;
+
+ @Focus(id="com.fr.plugin.ztsso.config.simple", text = "单点登录配置", source = Original.PLUGIN)
+ public static PluginSimpleConfig getInstance() {
+ if (config == null) {
+ config = ConfigContext.getConfigInstance(PluginSimpleConfig.class);
+ }
+ return config;
+ }
+
+ @Identifier(value = "frDomain", name = "帆软系统域名", description = "帆软系统域名", status = Status.SHOW)
+ private Conf frDomain = Holders.simple("http://localhost:8075");
+
+ @Identifier(value = "clientId", name = "clientId", description = "client_id", status = Status.SHOW)
+ private Conf appId = Holders.simple("xxx");
+
+ @Identifier(value = "secret", name = "clientsecret", description = "client_secret", status = Status.SHOW)
+ private Conf host = Holders.simple("xxx");
+
+ @Identifier(value = "codeUrl", name = "获取授权码接口地址", description = "authorize", status = Status.SHOW)
+ private Conf codeUrl = Holders.simple("https://xxx/idp/oauth2/authorize");
+
+ @Identifier(value = "tokenUrl", name = "获取token接口地址", description = "getToken", status = Status.SHOW)
+ private Conf tokenUrl = Holders.simple("https://xxx/idp/oauth2/getToken");
+
+ @Identifier(value = "userInfoUrl", name = "获取用户信息接口地址", description = "getUserInfo", status = Status.SHOW)
+ private Conf userInfoUrl = Holders.simple("https://xxx/idp/oauth2/getUserInfo");
+
+ @Identifier(value = "logoutUrl", name = "登出接口地址", description = "GLO", status = Status.SHOW)
+ private Conf logoutUrl = Holders.simple("https://xxx/idp/oauth2//Redirect/GLO");
+
+ @Identifier(value = "rzzxUrl", name = "认证中心登录地址", description = "认证中心登录地址", status = Status.SHOW)
+ private Conf rzzxUrl = Holders.simple("https://xxx/idp/oauth2//Redirect/GLO");
+
+
+ // -----------------------------------用户同步---------------------------------
+ @Identifier(value = "username", name = "用户名-数据同步", description = "用户名-数据同步", status = Status.SHOW)
+ private Conf username = Holders.simple("xxx");
+
+ @Identifier(value = "psd", name = "密码-数据同步", description = "密码-数据同步", status = Status.SHOW)
+ private Conf psd = Holders.simple("xxx");
+
+ @Identifier(value = "tokenUrl2", name = "token接口-数据同步", description = "获取token-数据同步", status = Status.SHOW)
+ private Conf tokenUrl2 = Holders.simple("http://xxx/api/users/login");
+
+ @Identifier(value = "orgUrl", name = "组织接口-数据同步", description = "组织接口-数据同步", status = Status.SHOW)
+ private Conf orgUrl = Holders.simple("http://xxx/api/mdm/m_organization/query");
+
+ @Identifier(value = "userUrl", name = "用户接口-数据同步", description = "用户接口-数据同步", status = Status.SHOW)
+ private Conf userUrl = Holders.simple("http://xxx/api/mdm/m_person_basic_info/query");
+
+ public String getRzzxUrl() {
+ return rzzxUrl.get();
+ }
+
+ public void settRzzxUrl(String userInfoUrl) {
+ this.rzzxUrl.set(userInfoUrl);
+ }
+
+ public String getFrDomain() {
+ return frDomain.get();
+ }
+
+ public void setFrDomain(String url) {
+ this.frDomain.set(url);
+ }
+
+ public String getAppId() {
+ return appId.get();
+ }
+
+ public void setAppId(String url) {
+ this.appId.set(url);
+ }
+
+ public String getHost() {
+ return host.get();
+ }
+
+ public void setHost(String url) {
+ this.host.set(url);
+ }
+
+ public String getCodeUrl() {
+ return codeUrl.get();
+ }
+
+ public void setCodeUrl(String codeUrl) {
+ this.codeUrl.set(codeUrl);
+ }
+
+ public String getTokenUrl() {
+ return tokenUrl.get();
+ }
+
+ public void setTokenUrl(String tokenUrl) {
+ this.tokenUrl.set(tokenUrl);
+ }
+
+ public String getTokenUrl2() {
+ return tokenUrl2.get();
+ }
+
+ public void setTokenUrl2(String tokenUrl) {
+ this.tokenUrl2.set(tokenUrl);
+ }
+
+ public String getUserInfoUrl() {
+ return userInfoUrl.get();
+ }
+
+ public void setUserInfoUrl(String userInfoUrl) {
+ this.userInfoUrl.set(userInfoUrl);
+ }
+
+ public String getLogoutUrl() {
+ return logoutUrl.get();
+ }
+
+ public void setLogoutUrl(String userInfoUrl) {
+ this.logoutUrl.set(userInfoUrl);
+ }
+
+ public String getUsername() {
+ return username.get();
+ }
+
+ public void setUsername(String url) {
+ this.username.set(url);
+ }
+
+ public String getPsd() { return psd.get(); }
+
+ public void setPsd(String url) {
+ this.psd.set(url);
+ }
+
+
+ public String getOrgUrl() { return orgUrl.get(); }
+
+ public void setOrgUrl(String url) {
+ this.orgUrl.set(url);
+ }
+
+
+ public String getUserUrl() { return userUrl.get(); }
+
+ public void setUserUrl(String url) {
+ this.userUrl.set(url);
+ }
+
+ @Override
+ public Object clone() throws CloneNotSupportedException {
+ PluginSimpleConfig cloned = (PluginSimpleConfig) super.clone();
+// cloned.text = (Conf) text.clone();
+// cloned.count = (Conf) count.clone();
+// cloned.price = (Conf) price.clone();
+// cloned.time = (Conf) time.clone();
+// cloned.student = (Conf) student.clone();
+ return cloned;
+ }
+
+}
diff --git a/src/main/java/com/fr/plugin/ztzzSSO/filter/SSOFilter.java b/src/main/java/com/fr/plugin/ztzzSSO/filter/SSOFilter.java
new file mode 100644
index 0000000..ac1a50f
--- /dev/null
+++ b/src/main/java/com/fr/plugin/ztzzSSO/filter/SSOFilter.java
@@ -0,0 +1,175 @@
+package com.fr.plugin.ztzzSSO.filter;
+
+import com.fr.decision.fun.impl.AbstractEmbedRequestFilterProvider;
+import com.fr.decision.webservice.v10.login.LoginService;
+import com.fr.json.JSONObject;
+import com.fr.plugin.ztzzSSO.config.PluginSimpleConfig;
+import com.fr.plugin.ztzzSSO.utils.FRUtils;
+import com.fr.plugin.ztzzSSO.utils.HttpUtils;
+import com.fr.plugin.ztzzSSO.utils.ResponseUtils;
+import com.fr.plugin.ztzzSSO.utils.Utils;
+import com.fr.web.utils.WebUtils;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+
+
+public class SSOFilter extends AbstractEmbedRequestFilterProvider {
+
+ @Override
+ public void filter(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) {
+ PluginSimpleConfig psc = PluginSimpleConfig.getInstance();
+
+ //是否登录
+ boolean isLogin = FRUtils.isLogin(httpServletRequest);
+
+ //访问路径
+ String url = FRUtils.getAllUrl(httpServletRequest,psc.getFrDomain());
+ //获取code
+ String code = httpServletRequest.getParameter("code");
+ String msg = httpServletRequest.getParameter("msg");
+
+ //跳转路径
+ String redirectUrl = "";
+ //是否从一体化进入
+ String fromSSO = httpServletRequest.getParameter("fromSSO");
+
+ //从一体化进入每次都重新请求code
+ if(Utils.isNotNullStr(fromSSO) && "1".equals(fromSSO)){
+ FRUtils.FRLogInfo("一体化跳转:"+url);
+ redirectUrl = url.substring(0,url.indexOf("?fromSSO"));
+ FRUtils.FRLogInfo("一体化跳转,截取后url:"+url);
+
+ redirect(httpServletRequest,httpServletResponse,redirectUrl);
+ return ;
+ }
+
+ //如果已经登录而且没有code和msg则放行
+ if(isLogin && Utils.isNullStr(code) && Utils.isNullStr(msg)){
+ return ;
+ }
+
+ //如果是自带登录页资源则放行
+ if(url.contains("test")||url.contains("login")||url.contains("decision/file")||url.contains("decision/resource")||url.contains("decision/system")||url.contains("query/ip")){
+ return;
+ }
+
+ //如果是远程设计则放行
+ if(url.contains("remote")){
+ return;
+ }
+
+ //跳转 没有code
+ if(Utils.isNullStr(code) && Utils.isNullStr(msg)){
+ redirect(httpServletRequest,httpServletResponse,url);
+ return ;
+ }
+
+
+ //获取code错误
+ if(Utils.isNotNullStr(msg)){
+ FRUtils.FRLogInfo("获取授权码异常:"+msg);
+ ResponseUtils.failedResponse(httpServletResponse,"获取授权码异常:"+msg);
+ return;
+ }
+
+ //获取token
+ JSONObject tokenResultJson = getToken(code);
+ String token = tokenResultJson.getString("access_token");
+
+ if(Utils.isNullStr(token)){
+ ResponseUtils.failedResponse(httpServletResponse,"获取token异常:");
+ }
+
+ //获取用户信息
+ String uid = tokenResultJson.getString("uid");
+
+ String loginName = getUsername(token,uid);
+
+ if(Utils.isNullStr(loginName)){
+ FRUtils.FRLogInfo("获取用户信息异常:");
+ ResponseUtils.failedResponse(httpServletResponse,"获取用户信息异常:");
+
+ return;
+ }
+
+ if(url.contains("code=")){
+ url = url.contains("&code") ? url.substring(0,url.indexOf("&code")) :url.substring(0,url.indexOf("?code"));
+ }
+
+ FRUtils.FRLogInfo("登陆成功-url:"+url);
+
+ FRUtils.login(httpServletRequest,httpServletResponse,loginName,url);
+
+ }
+
+ private String getUsername(String token,String uid){
+ PluginSimpleConfig psc = PluginSimpleConfig.getInstance();
+ String clientId = psc.getAppId();
+
+ String userInfoUrl = psc.getUserInfoUrl();
+ userInfoUrl+="?access_token="+token+"&client_id="+clientId+"&uid="+uid;
+
+ String userInfoResult = HttpUtils.get(userInfoUrl,null,null);
+
+ if(Utils.isNullStr(userInfoResult)){
+ FRUtils.FRLogInfo("获取用户信息异常");
+ return "";
+ }
+
+ JSONObject userJsonObject = new JSONObject(userInfoResult);
+
+ String loginName = userJsonObject.getString("loginName");
+
+ return loginName;
+ }
+
+ private void redirect(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,String redirectUrl){
+ PluginSimpleConfig psc = PluginSimpleConfig.getInstance();
+ String clientId = psc.getAppId();
+
+ String authUrl = psc.getCodeUrl();
+
+ try {
+ redirectUrl= URLEncoder.encode(redirectUrl,"utf-8");
+ } catch (UnsupportedEncodingException e) {
+ return;
+ }
+
+ authUrl+= "?redirect_uri="+redirectUrl+"&state=123&client_id="+clientId+"&response_type=code";
+ try {
+ httpServletResponse.sendRedirect(authUrl);
+ } catch (IOException e) {
+ FRUtils.FRLogInfo("跳转异常:"+e.getMessage());
+ }
+ }
+
+ private JSONObject getToken(String code){
+ PluginSimpleConfig psc = PluginSimpleConfig.getInstance();
+ String clientId = psc.getAppId();
+ String clientSecret= psc.getHost();
+ //获取token
+ String tokenUrl = psc.getTokenUrl()+"?client_id="+clientId+"&client_secret="+clientSecret+"&code="+code+"&grant_type=authorization_code";
+ JSONObject tokenParam = new JSONObject();
+ tokenParam.put("client_id",clientId);
+ tokenParam.put("client_secret",clientSecret);
+ tokenParam.put("code",code);
+ tokenParam.put("grant_type","authorization_code");
+
+ String tokenParamStr = tokenParam.toString();
+
+ String tokenResult = HttpUtils.HttpPostJson(tokenUrl,tokenParamStr,null);
+
+ if(Utils.isNullStr(tokenResult)){
+ return new JSONObject();
+ }
+
+ JSONObject tokenResultJson = new JSONObject(tokenResult);
+
+ return tokenResultJson;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/fr/plugin/ztzzSSO/handler/ExtendAttrHandlerProvider.java b/src/main/java/com/fr/plugin/ztzzSSO/handler/ExtendAttrHandlerProvider.java
new file mode 100644
index 0000000..4d90f98
--- /dev/null
+++ b/src/main/java/com/fr/plugin/ztzzSSO/handler/ExtendAttrHandlerProvider.java
@@ -0,0 +1,14 @@
+package com.fr.plugin.ztzzSSO.handler;
+
+import com.fr.decision.fun.HttpHandler;
+import com.fr.decision.fun.impl.AbstractHttpHandlerProvider;
+import com.fr.io.context.info.GetConfig;
+
+public class ExtendAttrHandlerProvider extends AbstractHttpHandlerProvider {
+ @Override
+ public HttpHandler[] registerHandlers() {
+ return new HttpHandler[]{
+ new Test()
+ };
+ }
+}
diff --git a/src/main/java/com/fr/plugin/ztzzSSO/handler/Test.java b/src/main/java/com/fr/plugin/ztzzSSO/handler/Test.java
new file mode 100644
index 0000000..c3b1b0c
--- /dev/null
+++ b/src/main/java/com/fr/plugin/ztzzSSO/handler/Test.java
@@ -0,0 +1,50 @@
+package com.fr.plugin.ztzzSSO.handler;
+
+import com.fr.decision.fun.impl.BaseHttpHandler;
+import com.fr.decision.webservice.v10.login.LoginService;
+import com.fr.plugin.transform.FunctionRecorder;
+import com.fr.plugin.ztzzSSO.utils.FRUtils;
+import com.fr.plugin.ztzzSSO.utils.ResponseUtils;
+import com.fr.third.springframework.web.bind.annotation.RequestMethod;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+@FunctionRecorder
+public class Test extends BaseHttpHandler {
+
+
+ public Test() {
+ }
+
+ @Override
+ public RequestMethod getMethod() {
+ return RequestMethod.GET;
+ }
+
+ @Override
+ public String getPath() {
+ return "/test";
+ }
+
+ @Override
+ public boolean isPublic() {
+ return true;
+ }
+
+ @Override
+ public void handle(HttpServletRequest req, HttpServletResponse res) throws Exception {
+ String username = req.getParameter("username");
+ FRUtils.login(req,res,username,"http://localhost:8075/webroot/decision");
+ System.out.println();
+// HttpSession session = req.getSession(true);
+// LoginService.getInstance().crossDomainLogout(req,res,"");
+// session.invalidate();
+//
+// String username = LoginService.getInstance().getCurrentUserNameFromRequest(req);
+//
+// ResponseUtils.successResponse(res,username);
+ }
+
+}
+
diff --git a/src/main/java/com/fr/plugin/ztzzSSO/handler/URLAliasProvide.java b/src/main/java/com/fr/plugin/ztzzSSO/handler/URLAliasProvide.java
new file mode 100644
index 0000000..4c212d2
--- /dev/null
+++ b/src/main/java/com/fr/plugin/ztzzSSO/handler/URLAliasProvide.java
@@ -0,0 +1,17 @@
+package com.fr.plugin.ztzzSSO.handler;
+
+import com.fr.decision.fun.impl.AbstractURLAliasProvider;
+import com.fr.decision.webservice.url.alias.URLAlias;
+import com.fr.decision.webservice.url.alias.URLAliasFactory;
+
+public class URLAliasProvide extends AbstractURLAliasProvider {
+ @Override
+ public URLAlias[] registerAlias() {
+ return new URLAlias[]{
+
+ URLAliasFactory.createPluginAlias("/test","/test",true)
+
+
+ };
+ }
+}
diff --git a/src/main/java/com/fr/plugin/ztzzSSO/logout/Logout.java b/src/main/java/com/fr/plugin/ztzzSSO/logout/Logout.java
new file mode 100644
index 0000000..3df887d
--- /dev/null
+++ b/src/main/java/com/fr/plugin/ztzzSSO/logout/Logout.java
@@ -0,0 +1,29 @@
+package com.fr.plugin.ztzzSSO.logout;
+
+import com.fr.decision.fun.impl.AbstractLogInOutEventProvider;
+import com.fr.decision.webservice.login.LogInOutResultInfo;
+import com.fr.decision.webservice.v10.login.LoginService;
+import com.fr.plugin.ztzzSSO.config.PluginSimpleConfig;
+
+import javax.servlet.http.HttpSession;
+
+public class Logout extends AbstractLogInOutEventProvider {
+
+ @Override
+ public String logoutAction(LogInOutResultInfo result) {
+ HttpSession session = result.getRequest().getSession(true);
+ LoginService.getInstance().crossDomainLogout(result.getRequest(),result.getResponse(),"");
+ session.invalidate();
+
+ PluginSimpleConfig psc = PluginSimpleConfig.getInstance();
+
+ String authUrl = psc.getCodeUrl();
+ String redirectURL = psc.getFrDomain()+"/webroot/decision";
+ String clientId = psc.getAppId();
+ String logoutUrl = psc.getLogoutUrl();
+
+ logoutUrl+="?redirctToUrl="+redirectURL+"&redirectToLogin=true&entityId="+clientId;
+ return logoutUrl;
+ }
+}
+
diff --git a/src/main/java/com/fr/plugin/ztzzSSO/serverDS/DatasetData.java b/src/main/java/com/fr/plugin/ztzzSSO/serverDS/DatasetData.java
new file mode 100644
index 0000000..3b4616a
--- /dev/null
+++ b/src/main/java/com/fr/plugin/ztzzSSO/serverDS/DatasetData.java
@@ -0,0 +1,67 @@
+package com.fr.plugin.ztzzSSO.serverDS;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 数据集数据
+ */
+public class DatasetData {
+ private String name;
+ private List columns;
+ private List> values;
+
+ public DatasetData() {
+ columns = new ArrayList();
+ values = new ArrayList>();
+ }
+
+ /**
+ * 获取表名
+ * @return 表名
+ */
+ public String getName() {
+ return this.name;
+ }
+
+ /**
+ * 设置表名
+ * @param name 表名
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * 获取列名
+ * @return 列名
+ */
+ public List getColumns() {
+ return this.columns;
+ }
+
+ /**
+ * 设置列名
+ * @param columns 列名
+ */
+ public void setColumns(List columns) {
+ this.columns = columns;
+ }
+
+ /**
+ * 获取表数据
+ * @return 表数据
+ */
+ public List> getValues() {
+ return this.values;
+ }
+
+ /**
+ * 设置表数据
+ * @param values
+ */
+ public void setValues(List> values) {
+ this.values = values;
+ }
+
+}
diff --git a/src/main/java/com/fr/plugin/ztzzSSO/serverDS/ORGHttpDataModel.java b/src/main/java/com/fr/plugin/ztzzSSO/serverDS/ORGHttpDataModel.java
new file mode 100644
index 0000000..92d4ceb
--- /dev/null
+++ b/src/main/java/com/fr/plugin/ztzzSSO/serverDS/ORGHttpDataModel.java
@@ -0,0 +1,268 @@
+package com.fr.plugin.ztzzSSO.serverDS;
+
+import com.fr.base.TableData;
+import com.fr.data.AbstractDataModel;
+import com.fr.general.data.TableDataException;
+import com.fr.general.http.HttpToolbox;
+import com.fr.json.JSONArray;
+import com.fr.json.JSONObject;
+import com.fr.plugin.ztzzSSO.config.PluginSimpleConfig;
+import com.fr.plugin.ztzzSSO.utils.FRUtils;
+import com.fr.plugin.ztzzSSO.utils.HttpUtils;
+
+import java.io.*;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.*;
+
+public class ORGHttpDataModel extends AbstractDataModel {
+ private static String[] COLUMN_NAMES = {"DISPLAY_PATH", "DISPLAY_PATH_NAME", "MDM_CODE","ORG_NAME","ORG_NAME_SHORT",
+ "FOUND_DATE","UPDATE_TIME","REG_ADDRESS","ORG_CODE","ORG_UID","ORG_PID"};
+ private int rowCount = TableData.RESULT_ALL;
+ private DatasetData datas = new DatasetData();
+
+ public ORGHttpDataModel(int count) {
+ this.rowCount = count;
+ if (this.rowCount == 0) {
+ return;
+ }
+ queryData();
+ }
+
+ //获取列的数量
+ @Override
+ public int getColumnCount() throws TableDataException {
+ return COLUMN_NAMES.length;
+ }
+
+ //获取列的名称
+ @Override
+ public String getColumnName(int i) throws TableDataException {
+ return COLUMN_NAMES[i];
+ }
+
+ //是否还有行
+ @Override
+ public boolean hasRow(int rowIndex) throws TableDataException {
+ int count = getRowCount();
+ return rowIndex < count;
+ }
+
+ //获取行数量
+ @Override
+ public int getRowCount() throws TableDataException {
+ if (this.datas == null) {
+ return 0;
+ }
+ List> values = this.datas.getValues();
+ if (values == null) {
+ return 0;
+ }
+ int count = values.size();
+ return count;
+ }
+
+ //获取数据
+ @Override
+ public Object getValueAt(int rowIndex, int columnIndex) throws TableDataException {
+ if (this.datas == null) {
+ return "";
+ }
+ List> values = this.datas.getValues();
+ if ((values == null) || (values.size() <= rowIndex)) {
+ return "";
+ }
+ List