diff --git a/APIJSON-Java-Server/APIJSONDemo_oracle/.gitignore b/APIJSON-Java-Server/APIJSONDemo_oracle/.gitignore
new file mode 100644
index 000000000..b83d22266
--- /dev/null
+++ b/APIJSON-Java-Server/APIJSONDemo_oracle/.gitignore
@@ -0,0 +1 @@
+/target/
diff --git a/APIJSON-Java-Server/APIJSONDemo_oracle/apijson-demo.iml b/APIJSON-Java-Server/APIJSONDemo_oracle/apijson-demo.iml
new file mode 100644
index 000000000..e34a907a0
--- /dev/null
+++ b/APIJSON-Java-Server/APIJSONDemo_oracle/apijson-demo.iml
@@ -0,0 +1,70 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/APIJSON-Java-Server/APIJSONDemo_oracle/libs/apijson-library-2.1.0-SNAPSHOT.jar b/APIJSON-Java-Server/APIJSONDemo_oracle/libs/apijson-library-2.1.0-SNAPSHOT.jar
new file mode 100644
index 000000000..126e51725
Binary files /dev/null and b/APIJSON-Java-Server/APIJSONDemo_oracle/libs/apijson-library-2.1.0-SNAPSHOT.jar differ
diff --git a/APIJSON-Java-Server/APIJSONDemo_oracle/libs/postgresql-42.2.4.jar b/APIJSON-Java-Server/APIJSONDemo_oracle/libs/postgresql-42.2.4.jar
new file mode 100644
index 000000000..4f747bea0
Binary files /dev/null and b/APIJSON-Java-Server/APIJSONDemo_oracle/libs/postgresql-42.2.4.jar differ
diff --git a/APIJSON-Java-Server/APIJSONDemo_oracle/pom.xml b/APIJSON-Java-Server/APIJSONDemo_oracle/pom.xml
new file mode 100644
index 000000000..be41cf7f1
--- /dev/null
+++ b/APIJSON-Java-Server/APIJSONDemo_oracle/pom.xml
@@ -0,0 +1,110 @@
+
+
+ 4.0.0
+
+ apijson.demo.server
+ apijson-demo
+ 2.1.0-SNAPSHOT
+ jar
+
+ APIJSONDemo
+ Demo project for APIJSON Server
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 1.4.1.RELEASE
+
+
+
+
+ UTF-8
+ UTF-8
+ 1.8
+
+
+
+
+ org.jyaml
+ jyaml
+ 1.3
+
+
+
+ ojdbc6
+ ojdbc6
+ 1.0
+
+
+
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+ com.alibaba
+ fastjson
+ 1.2.21
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ 1.8
+ 1.8
+
+
+
+
+
+
+
+
+
+ spring-snapshots
+ http://repo.spring.io/snapshot
+ true
+
+
+ spring-milestones
+ http://repo.spring.io/milestone
+ true
+
+
+
+
+ spring-snapshots
+ http://repo.spring.io/snapshot
+
+
+ spring-milestones
+ http://repo.spring.io/milestone
+
+
+
+
diff --git a/APIJSON-Java-Server/APIJSONDemo_oracle/src/main/java/apijson/demo/server/APIJSONApplication.java b/APIJSON-Java-Server/APIJSONDemo_oracle/src/main/java/apijson/demo/server/APIJSONApplication.java
new file mode 100644
index 000000000..55a555eed
--- /dev/null
+++ b/APIJSON-Java-Server/APIJSONDemo_oracle/src/main/java/apijson/demo/server/APIJSONApplication.java
@@ -0,0 +1,53 @@
+package apijson.demo.server;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Bean;
+import org.springframework.web.cors.CorsConfiguration;
+import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
+import org.springframework.web.filter.CorsFilter;
+
+
+/**application
+ * @author Lemon
+ */
+@SpringBootApplication
+public class APIJSONApplication {
+
+ public static void main(String[] args) throws Exception {
+ SpringApplication.run(APIJSONApplication.class, args);
+ System.out.println("\n\n\n\n\n<<<<<<<<<<<<<<<<<<<<<<<<< APIJSON >>>>>>>>>>>>>>>>>>>>>>>>\n");
+ System.out.println("开始测试:远程函数 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
+ System.out.println("\n完成测试:远程函数 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
+ System.out.println("\n\n\n开始测试:请求校验 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
+ System.out.println("\n完成测试:请求校验 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
+ System.out.println("\n\n<<<<<<<<<<<<<<<<<<<<<<<<< APIJSON已启动 >>>>>>>>>>>>>>>>>>>>>>>>\n");
+ }
+
+
+
+ //支持JavaScript跨域请求<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+ /**
+ * 跨域过滤器
+ * @return
+ */
+ @Bean
+ public CorsFilter corsFilter() {
+ UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
+ source.registerCorsConfiguration("/**", buildConfig());
+ return new CorsFilter(source);
+ }
+ /**CORS跨域配置
+ * @return
+ */
+ private CorsConfiguration buildConfig() {
+ CorsConfiguration corsConfiguration = new CorsConfiguration();
+ corsConfiguration.addAllowedOrigin("*"); //允许的域名或IP地址
+ corsConfiguration.addAllowedHeader("*"); //允许的请求头
+ corsConfiguration.addAllowedMethod("*"); //允许的HTTP请求方法
+ corsConfiguration.setAllowCredentials(true); //允许发送跨域凭据,前端Axios存取JSESSIONID必须要
+ return corsConfiguration;
+ }
+ //支持JavaScript跨域请求 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+
+}
diff --git a/APIJSON-Java-Server/APIJSONDemo_oracle/src/main/java/apijson/demo/server/Controller.java b/APIJSON-Java-Server/APIJSONDemo_oracle/src/main/java/apijson/demo/server/Controller.java
new file mode 100644
index 000000000..2dec3b670
--- /dev/null
+++ b/APIJSON-Java-Server/APIJSONDemo_oracle/src/main/java/apijson/demo/server/Controller.java
@@ -0,0 +1,861 @@
+package apijson.demo.server;
+
+import static zuo.biao.apijson.RequestMethod.DELETE;
+import static zuo.biao.apijson.RequestMethod.GET;
+import static zuo.biao.apijson.RequestMethod.GETS;
+import static zuo.biao.apijson.RequestMethod.HEAD;
+import static zuo.biao.apijson.RequestMethod.HEADS;
+import static zuo.biao.apijson.RequestMethod.POST;
+import static zuo.biao.apijson.RequestMethod.PUT;
+
+import java.net.URLDecoder;
+import java.util.Random;
+import java.util.concurrent.TimeoutException;
+
+import javax.servlet.http.HttpSession;
+
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.alibaba.fastjson.JSONObject;
+
+import apijson.demo.server.model.BaseModel;
+import apijson.demo.server.model.Comment;
+import apijson.demo.server.model.Moment;
+import apijson.demo.server.model.Privacy;
+import apijson.demo.server.model.User;
+import apijson.demo.server.model.Verify;
+import zuo.biao.apijson.JSON;
+import zuo.biao.apijson.JSONResponse;
+import zuo.biao.apijson.Log;
+import zuo.biao.apijson.RequestMethod;
+import zuo.biao.apijson.StringUtil;
+import zuo.biao.apijson.server.JSONRequest;
+import zuo.biao.apijson.server.exception.ConditionErrorException;
+import zuo.biao.apijson.server.exception.ConflictException;
+import zuo.biao.apijson.server.exception.NotExistException;
+import zuo.biao.apijson.server.exception.OutOfRangeException;
+
+
+/**request controller
+ *
建议全通过HTTP POST来请求:
+ *
1.减少代码 - 客户端无需写HTTP GET,PUT等各种方式的请求代码
+ *
2.提高性能 - 无需URL encode和decode
+ *
3.调试方便 - 建议使用 APIJSON在线测试工具 或 Postman
+ * @author Lemon
+ */
+@RestController
+@RequestMapping("")
+public class Controller {
+ private static final String TAG = "Controller";
+
+ //通用接口,非事务型操作 和 简单事务型操作 都可通过这些接口自动化实现<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+ /**获取
+ * @param request 只用String,避免encode后未decode
+ * @param session
+ * @return
+ * @see {@link RequestMethod#GET}
+ */
+ @PostMapping(value = "get")
+ public String get(@RequestBody String request, HttpSession session) {
+ return new DemoParser(GET).setSession(session).parse(request);
+ }
+
+ /**计数
+ * @param request 只用String,避免encode后未decode
+ * @param session
+ * @return
+ * @see {@link RequestMethod#HEAD}
+ */
+ @PostMapping("head")
+ public String head(@RequestBody String request, HttpSession session) {
+ return new DemoParser(HEAD).setSession(session).parse(request);
+ }
+
+ /**限制性GET,request和response都非明文,浏览器看不到,用于对安全性要求高的GET请求
+ * @param request 只用String,避免encode后未decode
+ * @param session
+ * @return
+ * @see {@link RequestMethod#GETS}
+ */
+ @PostMapping("gets")
+ public String gets(@RequestBody String request, HttpSession session) {
+ return new DemoParser(GETS).setSession(session).parse(request);
+ }
+
+ /**限制性HEAD,request和response都非明文,浏览器看不到,用于对安全性要求高的HEAD请求
+ * @param request 只用String,避免encode后未decode
+ * @param session
+ * @return
+ * @see {@link RequestMethod#HEADS}
+ */
+ @PostMapping("heads")
+ public String heads(@RequestBody String request, HttpSession session) {
+ return new DemoParser(HEADS).setSession(session).parse(request);
+ }
+
+ /**新增
+ * @param request 只用String,避免encode后未decode
+ * @param session
+ * @return
+ * @see {@link RequestMethod#POST}
+ */
+ @PostMapping("post")
+ public String post(@RequestBody String request, HttpSession session) {
+ return new DemoParser(POST,true).setSession(session).parse(request);
+ }
+
+ /**修改
+ * @param request 只用String,避免encode后未decode
+ * @param session
+ * @return
+ * @see {@link RequestMethod#PUT}
+ */
+ @PostMapping("put")
+ public String put(@RequestBody String request, HttpSession session) {
+ return new DemoParser(PUT,true).setSession(session).parse(request);
+ }
+
+ /**删除
+ * @param request 只用String,避免encode后未decode
+ * @param session
+ * @return
+ * @see {@link RequestMethod#DELETE}
+ */
+ @PostMapping("delete")
+ public String delete(@RequestBody String request, HttpSession session) {
+ return new DemoParser(DELETE,true).setSession(session).parse(request);
+ }
+
+
+ /**获取
+ * 只为兼容HTTP GET请求,推荐用HTTP POST,可删除
+ * @param request 只用String,避免encode后未decode
+ * @param session
+ * @return
+ * @see {@link RequestMethod#GET}
+ */
+ @RequestMapping("get/{request}")
+ public String openGet(@PathVariable String request, HttpSession session) {
+ try {
+ request = URLDecoder.decode(request, StringUtil.UTF_8);
+ } catch (Exception e) {
+ // Parser会报错
+ }
+ return get(request, session);
+ }
+
+ /**计数
+ * 只为兼容HTTP GET请求,推荐用HTTP POST,可删除
+ * @param request 只用String,避免encode后未decode
+ * @param session
+ * @return
+ * @see {@link RequestMethod#HEAD}
+ */
+ @RequestMapping("head/{request}")
+ public String openHead(@PathVariable String request, HttpSession session) {
+ try {
+ request = URLDecoder.decode(request, StringUtil.UTF_8);
+ } catch (Exception e) {
+ // Parser会报错
+ }
+ return head(request, session);
+ }
+
+
+ //通用接口,非事务型操作 和 简单事务型操作 都可通过这些接口自动化实现>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+
+
+
+
+
+
+
+
+
+
+
+
+
+ public static final String USER_;
+ public static final String PRIVACY_;
+ public static final String MOMENT_;
+ public static final String COMMENT_;
+ public static final String VERIFY_; //加下划线后缀是为了避免 Verify 和 verify 都叫VERIFY,分不清
+ static {
+ USER_ = User.class.getSimpleName();
+ PRIVACY_ = Privacy.class.getSimpleName();
+ MOMENT_ = Moment.class.getSimpleName();
+ COMMENT_ = Comment.class.getSimpleName();
+ VERIFY_ = Verify.class.getSimpleName();
+ }
+
+ public static final String VERSION = JSONRequest.KEY_VERSION;
+ public static final String COUNT = JSONResponse.KEY_COUNT;
+ public static final String TOTAL = JSONResponse.KEY_TOTAL;
+
+ public static final String RANGE = "range";
+
+ public static final String ID = "id";
+ public static final String USER_ID = "userId";
+ public static final String CURRENT_USER_ID = "currentUserId";
+
+ public static final String NAME = "name";
+ public static final String PHONE = "phone";
+ public static final String PASSWORD = "password";
+ public static final String _PASSWORD = "_password";
+ public static final String _PAY_PASSWORD = "_payPassword";
+ public static final String OLD_PASSWORD = "oldPassword";
+ public static final String VERIFY = "verify";
+
+ public static final String SEX = "sex";
+ public static final String TYPE = "type";
+ public static final String WAY = "way";
+ public static final String CONTENT = "content";
+
+
+
+
+
+ public static final String DATE_UP = "date+";//同 "date ASC"
+ public static final String DATE_DOWN = "date-";//同 "date DESC"
+
+ public static final String ID_AT = ID + "@";
+ public static final String USER_ID_AT = USER_ID + "@";
+ public static final String MOMENT_ID_AT = "momentId@";
+ public static final String COMMENT_ID_AT = "commentId@";
+
+ public static final String ID_IN = ID + "{}";
+ public static final String USER_ID_IN = USER_ID + "{}";
+ public static final String MOMENT_ID_IN = "momentId{}";
+ public static final String COMMENT_ID_IN = "commentId{}";
+
+ public static final String NAME_SEARCH = NAME + "$";
+ public static final String PHONE_SEARCH = PHONE + "$";
+ public static final String CONTENT_SEARCH = CONTENT + "$";
+
+
+
+ public static final String COLUMNS_USER_SIMPLE = "id,name";
+ public static final String COLUMNS_USER = "id,sex,name,head";
+
+
+
+
+ /**生成验证码,修改为post请求
+ * @param request
+ * @return
+ */
+ @PostMapping("post/verify")
+ public JSONObject postVerify(@RequestBody String request) {
+ JSONObject requestObject = null;
+ int type;
+ String phone;
+ try {
+ requestObject = DemoParser.parseRequest(request);
+ type = requestObject.getIntValue(TYPE);
+ phone = requestObject.getString(PHONE);
+ } catch (Exception e) {
+ return DemoParser.extendErrorResult(requestObject, e);
+ }
+
+ new DemoParser(DELETE, true).parse(newVerifyRequest(type, phone, null));
+
+ JSONObject response = new DemoParser(POST, true).parseResponse(
+ newVerifyRequest(type, phone, "" + (new Random().nextInt(9999) + 1000)));
+
+ JSONObject verify = null;
+ try {
+ verify = response.getJSONObject(VERIFY_);
+ } catch (Exception e) {
+ // TODO: handle exception
+ }
+ if (verify == null || JSONResponse.isSuccess(verify.getIntValue(JSONResponse.KEY_CODE)) == false) {
+ new DemoParser(DELETE, true).parseResponse(new JSONRequest(new Verify(type, phone)));
+ return response;
+ }
+
+ //TODO 这里直接返回验证码,方便测试。实际上应该只返回成功信息,验证码通过短信发送
+ JSONObject object = new JSONObject();
+ object.put(TYPE, type);
+ object.put(PHONE, phone);
+ return getVerify(JSON.toJSONString(object));
+ }
+
+ /**获取验证码
+ * @param request
+ * @return
+ */
+ @PostMapping("gets/verify")
+ public JSONObject getVerify(@RequestBody String request) {
+ JSONObject requestObject = null;
+ int type;
+ String phone;
+ try {
+ requestObject = DemoParser.parseRequest(request);
+ type = requestObject.getIntValue(TYPE);
+ phone = requestObject.getString(PHONE);
+ } catch (Exception e) {
+ return DemoParser.extendErrorResult(requestObject, e);
+ }
+ return new DemoParser(GETS, true).parseResponse(newVerifyRequest(type, phone, null));
+ }
+
+ /**校验验证码
+ * @param request
+ * @return
+ */
+ @PostMapping("heads/verify")
+ public JSONObject headVerify(@RequestBody String request) {
+ JSONObject requestObject = null;
+ int type;
+ String phone;
+ String verify;
+ try {
+ requestObject = DemoParser.parseRequest(request);
+ type = requestObject.getIntValue(TYPE);
+ phone = requestObject.getString(PHONE);
+ verify = requestObject.getString(VERIFY);
+ } catch (Exception e) {
+ return DemoParser.extendErrorResult(requestObject, e);
+ }
+ return headVerify(type, phone, verify);
+ }
+
+ /**校验验证码
+ * @author Lemon
+ * @param type
+ * @param phone
+ * @param code
+ * @return
+ */
+ public JSONObject headVerify(int type, String phone, String code) {
+ JSONResponse response = new JSONResponse(
+ new DemoParser(GETS, true).parseResponse(
+ new JSONRequest(
+ new Verify(type, phone)
+ .setVerify(code)
+ ).setTag(VERIFY_)
+ )
+ );
+ Verify verify = response.getObject(Verify.class);
+ if (verify == null) {
+ return DemoParser.newErrorResult(StringUtil.isEmpty(code, true)
+ ? new NotExistException("验证码不存在!") : new ConditionErrorException("手机号或验证码错误!"));
+ }
+
+ //验证码过期
+ long time = BaseModel.getTimeMillis(verify.getDate());
+ long now = System.currentTimeMillis();
+ if (now > 60*1000 + time) {
+ new DemoParser(DELETE, true).parseResponse(
+ new JSONRequest(new Verify(type, phone)).setTag(VERIFY_)
+ );
+ return DemoParser.newErrorResult(new TimeoutException("验证码已过期!"));
+ }
+
+ return new JSONResponse(
+ new DemoParser(HEADS, true).parseResponse(
+ new JSONRequest(new Verify(type, phone).setVerify(code))
+ )
+ );
+ }
+
+
+
+ /**新建一个验证码请求
+ * @param phone
+ * @param verify
+ * @return
+ */
+ private JSONObject newVerifyRequest(int type, String phone, String verify) {
+ return new JSONRequest(new Verify(type, phone).setVerify(verify)).setTag(VERIFY_);
+ }
+
+
+ public static final String LOGIN = "login";
+
+ public static final int LOGIN_TYPE_PASSWORD = 0;//密码登录
+ public static final int LOGIN_TYPE_VERIFY = 1;//验证码登录
+ /**用户登录
+ * @param request 只用String,避免encode后未decode
+ * @return
+ * @see
+ *
+ {
+ "type": 0, //登录方式,非必须 0-密码 1-验证码
+ "phone": "13000082001",
+ "password": "1234567",
+ "version": 1 //全局版本号,非必须
+ }
+ *
+ */
+ @PostMapping(LOGIN)
+ public JSONObject login(@RequestBody String request, HttpSession session) {
+ JSONObject requestObject = null;
+ boolean isPassword;
+ String phone;
+ String password;
+ int version;
+ try {
+ requestObject = DemoParser.parseRequest(request);
+
+ isPassword = requestObject.getIntValue(TYPE) == LOGIN_TYPE_PASSWORD;//登录方式
+ phone = requestObject.getString(PHONE);//手机
+ password = requestObject.getString(PASSWORD);//密码
+
+ if (StringUtil.isPhone(phone) == false) {
+ throw new IllegalArgumentException("手机号不合法!");
+ }
+
+ if (isPassword) {
+ if (StringUtil.isPassword(password) == false) {
+ throw new IllegalArgumentException("密码不合法!");
+ }
+ } else {
+ if (StringUtil.isVerify(password) == false) {
+ throw new IllegalArgumentException("验证码不合法!");
+ }
+ }
+
+ //全局版本号
+ version = requestObject.getIntValue(VERSION);
+ requestObject.remove(VERSION);
+ } catch (Exception e) {
+ return DemoParser.extendErrorResult(requestObject, e);
+ }
+
+
+
+ //手机号是否已注册
+ JSONObject phoneResponse = new DemoParser(HEADS, true).parseResponse(
+ new JSONRequest(
+ new Privacy().setPhone(phone)
+ )
+ );
+ JSONResponse response = new JSONResponse(phoneResponse).getJSONResponse(PRIVACY_);
+ if (JSONResponse.isSuccess(response) == false) {
+ return response;
+ }
+ if(JSONResponse.isExist(response) == false) {
+ return DemoParser.newErrorResult(new NotExistException("手机号未注册"));
+ }
+
+ //根据phone获取User
+ JSONObject privacyResponse = new DemoParser(GETS, true).parseResponse(
+ new JSONRequest(
+ new Privacy().setPhone(phone)
+ )
+ );
+ response = new JSONResponse(privacyResponse);
+
+ Privacy privacy = response == null ? null : response.getObject(Privacy.class);
+ long userId = privacy == null ? 0 : BaseModel.value(privacy.getId());
+ if (userId <= 0) {
+ return privacyResponse;
+ }
+
+ //校验凭证
+ if (isPassword) {//password密码登录
+ response = new JSONResponse(
+ new DemoParser(HEADS, true).parseResponse(
+ new JSONRequest(new Privacy(userId).setPassword(password))
+ )
+ );
+ } else {//verify手机验证码登录
+ response = new JSONResponse(headVerify(Verify.TYPE_LOGIN, phone, password));
+ }
+ if (JSONResponse.isSuccess(response) == false) {
+ return response;
+ }
+ response = response.getJSONResponse(isPassword ? PRIVACY_ : VERIFY_);
+ if (JSONResponse.isExist(response) == false) {
+ return DemoParser.newErrorResult(new ConditionErrorException("账号或密码错误"));
+ }
+
+ response = new JSONResponse(
+ new DemoParser(GETS, true).parseResponse(
+ new JSONRequest(new User(userId))
+ )
+ );
+ User user = new User(userId);
+ if (user == null || BaseModel.value(user.getId()) != userId) {
+ return DemoParser.newErrorResult(new NullPointerException("服务器内部错误"));
+ }
+
+ //登录状态保存至session
+ session.setAttribute(USER_ID, userId);//用户id
+ session.setAttribute(TYPE, isPassword ? LOGIN_TYPE_PASSWORD : LOGIN_TYPE_VERIFY);//登录方式
+ session.setAttribute(USER_, user);//用户
+ session.setAttribute(PRIVACY_, privacy);//用户隐私信息
+ session.setAttribute(VERSION, version);//全局默认版本号
+ // session.setMaxInactiveInterval(1*60);//设置session过期时间
+
+ return response;
+ }
+
+ /**退出登录,清空session
+ * @param session
+ * @return
+ */
+ @PostMapping("logout")
+ public JSONObject logout(HttpSession session) {
+ long userId;
+ try {
+ userId = DemoVerifier.getVisitorId(session);//必须在session.invalidate();前!
+ Log.d(TAG, "logout userId = " + userId + "; session.getId() = " + (session == null ? null : session.getId()));
+ session.invalidate();
+ } catch (Exception e) {
+ return DemoParser.newErrorResult(e);
+ }
+
+ JSONObject result = DemoParser.newSuccessResult();
+ JSONObject user = DemoParser.newSuccessResult();
+ user.put(ID, userId);
+ user.put(COUNT, 1);
+ result.put(USER_, user);
+
+ return result;
+ }
+
+
+ private static final String REGISTER = "register";
+ /**注册
+ * @param request 只用String,避免encode后未decode
+ * @return
+ * @see
+ *
+ {
+ "Privacy": {
+ "phone": "13000082222",
+ "_password": "123456"
+ },
+ "User": {
+ "name": "APIJSONUser"
+ },
+ "verify": "1234"
+ }
+ *
+ */
+ @PostMapping(REGISTER)
+ public JSONObject register(@RequestBody String request) {
+ JSONObject requestObject = null;
+
+ JSONObject privacyObj;
+
+ String phone;
+ String verify;
+ String password;
+ try {
+ requestObject = DemoParser.parseRequest(request);
+ privacyObj = requestObject.getJSONObject(PRIVACY_);
+
+ phone = StringUtil.getString(privacyObj.getString(PHONE));
+ verify = requestObject.getString(VERIFY);
+ password = privacyObj.getString(_PASSWORD);
+
+ if (StringUtil.isPhone(phone) == false) {
+ return newIllegalArgumentResult(requestObject, PRIVACY_ + "/" + PHONE);
+ }
+ if (StringUtil.isPassword(password) == false) {
+ return newIllegalArgumentResult(requestObject, PRIVACY_ + "/" + _PASSWORD);
+ }
+ if (StringUtil.isVerify(verify) == false) {
+ return newIllegalArgumentResult(requestObject, VERIFY);
+ }
+ } catch (Exception e) {
+ return DemoParser.extendErrorResult(requestObject, e);
+ }
+
+
+ JSONResponse response = new JSONResponse(headVerify(Verify.TYPE_REGISTER, phone, verify));
+ if (JSONResponse.isSuccess(response) == false) {
+ return response;
+ }
+ //手机号或验证码错误
+ if (JSONResponse.isExist(response.getJSONResponse(VERIFY_)) == false) {
+ return DemoParser.extendErrorResult(response, new ConditionErrorException("手机号或验证码错误!"));
+ }
+
+
+
+ //生成User和Privacy
+ if (StringUtil.isEmpty(requestObject.getString(JSONRequest.KEY_TAG), true)) {
+ requestObject.put(JSONRequest.KEY_TAG, REGISTER);
+ }
+ response = new JSONResponse(
+ new DemoParser(POST).setNoVerifyLogin(true).parseResponse(requestObject)
+ );
+
+ //验证User和Privacy
+ User user = response.getObject(User.class);
+ long userId = user == null ? 0 : BaseModel.value(user.getId());
+ Privacy privacy = response.getObject(Privacy.class);
+ long userId2 = privacy == null ? 0 : BaseModel.value(privacy.getId());
+ Exception e = null;
+ if (userId <= 0 || userId != userId2) { //id不同
+ e = new Exception("服务器内部错误!写入User或Privacy失败!");
+ }
+
+ if (e != null) { //出现错误,回退
+ new DemoParser(DELETE, true).parseResponse(
+ new JSONRequest(new User(userId))
+ );
+ new DemoParser(DELETE, true).parseResponse(
+ new JSONRequest(new Privacy(userId2))
+ );
+ }
+
+ return response;
+ }
+
+
+ /**
+ * @param requestObject
+ * @param key
+ * @return
+ */
+ public static JSONObject newIllegalArgumentResult(JSONObject requestObject, String key) {
+ return newIllegalArgumentResult(requestObject, key, null);
+ }
+ /**
+ * @param requestObject
+ * @param key
+ * @param msg 详细说明
+ * @return
+ */
+ public static JSONObject newIllegalArgumentResult(JSONObject requestObject, String key, String msg) {
+ return DemoParser.extendErrorResult(requestObject
+ , new IllegalArgumentException(key + ":value 中value不合法!" + StringUtil.getString(msg)));
+ }
+
+
+ /**设置密码
+ * @param request 只用String,避免encode后未decode
+ * @return
+ * @see
+ *
+ 使用旧密码修改
+ {
+ "oldPassword": 123456,
+ "Privacy":{
+ "id": 13000082001,
+ "_password": "1234567"
+ }
+ }
+ 或使用手机号+验证码修改
+ {
+ "verify": "1234",
+ "Privacy":{
+ "phone": "13000082001",
+ "_password": "1234567"
+ }
+ }
+ *
+ */
+ @PostMapping("put/password")
+ public JSONObject putPassword(@RequestBody String request){
+ JSONObject requestObject = null;
+ String oldPassword;
+ String verify;
+
+ int type = Verify.TYPE_PASSWORD;
+
+ JSONObject privacyObj;
+ long userId;
+ String phone;
+ String password;
+ try {
+ requestObject = DemoParser.parseRequest(request);
+ oldPassword = StringUtil.getString(requestObject.getString(OLD_PASSWORD));
+ verify = StringUtil.getString(requestObject.getString(VERIFY));
+
+ requestObject.remove(OLD_PASSWORD);
+ requestObject.remove(VERIFY);
+
+ privacyObj = requestObject.getJSONObject(PRIVACY_);
+ if (privacyObj == null) {
+ throw new IllegalArgumentException(PRIVACY_ + " 不能为空!");
+ }
+ userId = privacyObj.getLongValue(ID);
+ phone = privacyObj.getString(PHONE);
+ password = privacyObj.getString(_PASSWORD);
+
+ if (StringUtil.isEmpty(password, true)) { //支付密码
+ type = Verify.TYPE_PAY_PASSWORD;
+ password = privacyObj.getString(_PAY_PASSWORD);
+ if (StringUtil.isNumberPassword(password) == false) {
+ throw new IllegalArgumentException(PRIVACY_ + "/" + _PAY_PASSWORD + ":value 中value不合法!");
+ }
+ } else { //登录密码
+ if (StringUtil.isPassword(password) == false) {
+ throw new IllegalArgumentException(PRIVACY_ + "/" + _PASSWORD + ":value 中value不合法!");
+ }
+ }
+ } catch (Exception e) {
+ return DemoParser.extendErrorResult(requestObject, e);
+ }
+
+
+ if (StringUtil.isPassword(oldPassword)) {
+ if (userId <= 0) { //手机号+验证码不需要userId
+ return DemoParser.extendErrorResult(requestObject, new IllegalArgumentException(ID + ":value 中value不合法!"));
+ }
+ if (oldPassword.equals(password)) {
+ return DemoParser.extendErrorResult(requestObject, new ConflictException("新旧密码不能一样!"));
+ }
+
+ //验证旧密码
+ Privacy privacy = new Privacy(userId);
+ if (type == Verify.TYPE_PASSWORD) {
+ privacy.setPassword(oldPassword);
+ } else {
+ privacy.setPayPassword(oldPassword);
+ }
+ JSONResponse response = new JSONResponse(
+ new DemoParser(HEAD, true).parseResponse(
+ new JSONRequest(privacy)
+ )
+ );
+ if (JSONResponse.isExist(response.getJSONResponse(PRIVACY_)) == false) {
+ return DemoParser.extendErrorResult(requestObject, new ConditionErrorException("账号或原密码错误,请重新输入!"));
+ }
+ }
+ else if (StringUtil.isPhone(phone) && StringUtil.isVerify(verify)) {
+ JSONResponse response = new JSONResponse(headVerify(type, phone, verify));
+ if (JSONResponse.isSuccess(response) == false) {
+ return response;
+ }
+ if (JSONResponse.isExist(response.getJSONResponse(VERIFY_)) == false) {
+ return DemoParser.extendErrorResult(response, new ConditionErrorException("手机号或验证码错误!"));
+ }
+ response = new JSONResponse(
+ new DemoParser(GET, true).parseResponse(
+ new JSONRequest(
+ new Privacy().setPhone(phone)
+ )
+ )
+ );
+ Privacy privacy = response.getObject(Privacy.class);
+ long id = privacy == null ? 0 : BaseModel.value(privacy.getId());
+ privacyObj.remove(PHONE);
+ privacyObj.put(ID, id);
+
+ requestObject.put(PRIVACY_, privacyObj);
+ } else {
+ return DemoParser.extendErrorResult(requestObject, new IllegalArgumentException("请输入合法的 旧密码 或 手机号+验证码 !"));
+ }
+ //TODO 上线版加上 password = MD5Util.MD5(password);
+
+
+ // requestObject.put(JSONRequest.KEY_TAG, "Password");
+ //修改密码
+ return new DemoParser(PUT, true).parseResponse(requestObject);
+ }
+
+
+
+ /**充值/提现
+ * @param request 只用String,避免encode后未decode
+ * @param session
+ * @return
+ * @see
+ *
+ {
+ "Privacy": {
+ "id": 82001,
+ "balance+": 100,
+ "_payPassword": "123456"
+ }
+ }
+ *
+ */
+ @PostMapping("put/balance")
+ public JSONObject putBalance(@RequestBody String request, HttpSession session) {
+ JSONObject requestObject = null;
+ JSONObject privacyObj;
+ long userId;
+ String payPassword;
+ double change;
+ try {
+ DemoVerifier.verifyLogin(session);
+ requestObject = new DemoParser(PUT).setRequest(DemoParser.parseRequest(request)).parseCorrectRequest();
+
+ privacyObj = requestObject.getJSONObject(PRIVACY_);
+ if (privacyObj == null) {
+ throw new NullPointerException("请设置 " + PRIVACY_ + "!");
+ }
+ userId = privacyObj.getLongValue(ID);
+ payPassword = privacyObj.getString(_PAY_PASSWORD);
+ change = privacyObj.getDoubleValue("balance+");
+
+ if (userId <= 0) {
+ throw new IllegalArgumentException(PRIVACY_ + "." + ID + ":value 中value不合法!");
+ }
+ if (StringUtil.isPassword(payPassword) == false) {
+ throw new IllegalArgumentException(PRIVACY_ + "." + _PAY_PASSWORD + ":value 中value不合法!");
+ }
+ } catch (Exception e) {
+ return DemoParser.extendErrorResult(requestObject, e);
+ }
+
+ //验证密码<<<<<<<<<<<<<<<<<<<<<<<
+
+ privacyObj.remove("balance+");
+ JSONResponse response = new JSONResponse(
+ new DemoParser(HEADS, true).setSession(session).parseResponse(
+ new JSONRequest(PRIVACY_, privacyObj)
+ )
+ );
+ response = response.getJSONResponse(PRIVACY_);
+ if (JSONResponse.isExist(response) == false) {
+ return DemoParser.extendErrorResult(requestObject, new ConditionErrorException("支付密码错误!"));
+ }
+
+ //验证密码>>>>>>>>>>>>>>>>>>>>>>>>
+
+
+ //验证金额范围<<<<<<<<<<<<<<<<<<<<<<<
+
+ if (change == 0) {
+ return DemoParser.extendErrorResult(requestObject, new OutOfRangeException("balance+的值不能为0!"));
+ }
+ if (Math.abs(change) > 10000) {
+ return DemoParser.extendErrorResult(requestObject, new OutOfRangeException("单次 充值/提现 的金额不能超过10000元!"));
+ }
+
+ //验证金额范围>>>>>>>>>>>>>>>>>>>>>>>>
+
+ if (change < 0) {//提现
+ response = new JSONResponse(
+ new DemoParser(GETS, true).parseResponse(
+ new JSONRequest(
+ new Privacy(userId)
+ )
+ )
+ );
+ Privacy privacy = response == null ? null : response.getObject(Privacy.class);
+ long id = privacy == null ? 0 : BaseModel.value(privacy.getId());
+ if (id != userId) {
+ return DemoParser.extendErrorResult(requestObject, new Exception("服务器内部错误!"));
+ }
+
+ if (BaseModel.value(privacy.getBalance()) < -change) {
+ return DemoParser.extendErrorResult(requestObject, new OutOfRangeException("余额不足!"));
+ }
+ }
+
+
+ privacyObj.remove(_PAY_PASSWORD);
+ privacyObj.put("balance+", change);
+ requestObject.put(PRIVACY_, privacyObj);
+ requestObject.put(JSONRequest.KEY_TAG, PRIVACY_);
+ //不免验证,里面会验证身份
+ return new DemoParser(PUT).setSession(session).parseResponse(requestObject);
+ }
+
+
+}
diff --git a/APIJSON-Java-Server/APIJSONDemo_oracle/src/main/java/apijson/demo/server/DemoFunction.java b/APIJSON-Java-Server/APIJSONDemo_oracle/src/main/java/apijson/demo/server/DemoFunction.java
new file mode 100644
index 000000000..912472eb6
--- /dev/null
+++ b/APIJSON-Java-Server/APIJSONDemo_oracle/src/main/java/apijson/demo/server/DemoFunction.java
@@ -0,0 +1,412 @@
+/*Copyright ©2016 TommyLemon(https://github.com/TommyLemon/APIJSON)
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.*/
+
+package apijson.demo.server;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+import javax.servlet.http.HttpSession;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+
+import apijson.demo.server.model.BaseModel;
+import apijson.demo.server.model.Comment;
+import zuo.biao.apijson.JSONResponse;
+import zuo.biao.apijson.Log;
+import zuo.biao.apijson.RequestMethod;
+import zuo.biao.apijson.RequestRole;
+import zuo.biao.apijson.StringUtil;
+import zuo.biao.apijson.server.Function;
+import zuo.biao.apijson.server.JSONRequest;
+import zuo.biao.apijson.server.NotNull;
+
+
+/**可远程调用的函数类
+ * @author Lemon
+ */
+public class DemoFunction extends Function implements FunctionList {
+ private static final String TAG = "DemoFunction";
+
+ private final HttpSession session;
+ public DemoFunction(HttpSession session) {
+ this.session = session;
+ }
+
+ public static void test() throws Exception {
+ int i0 = 1, i1 = -2;
+ JSONObject request = new JSONObject();
+ request.put("id", 10);
+ request.put("i0", i0);
+ request.put("i1", i1);
+ JSONArray arr = new JSONArray();
+ arr.add(new JSONObject());
+ request.put("arr", arr);
+
+ JSONArray array = new JSONArray();
+ array.add(1);//new JSONObject());
+ array.add(2);//new JSONObject());
+ array.add(4);//new JSONObject());
+ array.add(10);//new JSONObject());
+ request.put("array", array);
+
+ request.put("position", 1);
+ request.put("@position", 0);
+
+ request.put("key", "key");
+ JSONObject object = new JSONObject();
+ object.put("key", true);
+ request.put("object", object);
+
+
+ Log.i(TAG, "plus(1,-2) = " + new DemoFunction(null).invoke(request, "plus(i0,i1)"));
+ Log.i(TAG, "count([1,2,4,10]) = " + new DemoFunction(null).invoke(request, "countArray(array)"));
+ Log.i(TAG, "isContain([1,2,4,10], 10) = " + new DemoFunction(null).invoke(request, "isContain(array,id)"));
+ Log.i(TAG, "getFromArray([1,2,4,10], 0) = " + new DemoFunction(null).invoke(request, "getFromArray(array,@position)"));
+ Log.i(TAG, "getFromObject({key:true}, key) = " + new DemoFunction(null).invoke(request, "getFromObject(object,key)"));
+
+ }
+
+
+
+
+ /**反射调用
+ * @param request
+ * @param function 例如get(object,key),参数只允许引用,不能直接传值
+ * @return
+ */
+ public Object invoke(JSONObject request, String function) throws Exception {
+ //TODO 不允许调用invoke,避免死循环
+ // if (function.startsWith("invoke(")) {
+ //
+ // }
+ return invoke(this, request, function);
+ }
+
+
+
+ /**
+ * @param request
+ * @return
+ * @throws Exception
+ */
+ public Object verifyIdList(@NotNull JSONObject request, @NotNull String idList) throws Exception {
+ Object obj = request.get(idList);
+ if (obj instanceof Collection == false) {
+ throw new IllegalArgumentException(idList + " 不符合 Array 类型! 结构必须是 [] !");
+ }
+ JSONArray array = (JSONArray) obj;
+ if (array != null) {
+ for (int i = 0; i < array.size(); i++) {
+ if (array.get(i) instanceof Long == false && array.get(i) instanceof Integer == false) {
+ throw new IllegalArgumentException(idList + " 内字符 " + array.getString(i) + " 不符合 Long 类型!");
+ }
+ }
+ }
+ return null;
+ }
+
+
+ /**
+ * @param request
+ * @return
+ * @throws Exception
+ */
+ public Object verifyURLList(@NotNull JSONObject request, @NotNull String urlList) throws Exception {
+ Object obj = request.get(urlList);
+ if (obj instanceof Collection == false) {
+ throw new IllegalArgumentException(urlList + " 不符合 Array 类型! 结构必须是 [] !");
+ }
+ JSONArray array = (JSONArray) obj;
+ if (array != null) {
+ for (int i = 0; i < array.size(); i++) {
+ if (StringUtil.isUrl(array.getString(i)) == false) {
+ throw new IllegalArgumentException(urlList + " 内字符 " + array.getString(i) + " 不符合 URL 格式!");
+ }
+ }
+ }
+ return null;
+ }
+
+ /**判断array是否为空
+ * @param request
+ * @param array
+ * @return
+ */
+ public int deleteChildComment(@NotNull JSONObject rq, @NotNull String toId) throws Exception {
+ long tid = rq.getLongValue(toId);
+ if (tid <= 0 || rq.getIntValue(JSONResponse.KEY_COUNT) <= 0) {
+ return 0;
+ }
+
+ //递归获取到全部子评论id
+
+ JSONRequest request = new JSONRequest();
+
+ //Comment<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+ JSONRequest comment = new JSONRequest();
+ comment.put("id{}", getChildCommentIdList(tid));
+ request.put("Comment", comment);
+
+ //Comment>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+
+ JSONObject rp = new DemoParser(RequestMethod.DELETE).setNoVerify(true).parseResponse(request);
+
+ JSONObject c = rp.getJSONObject("Comment");
+ return c == null ? 0 : c.getIntValue(JSONResponse.KEY_COUNT);
+ }
+
+
+ private JSONArray getChildCommentIdList(long tid) {
+
+ JSONArray arr = new JSONArray();
+
+ JSONRequest request = new JSONRequest();
+
+ //Comment-id[]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+ JSONRequest idItem = new JSONRequest();
+
+ //Comment<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+ JSONRequest comment = new JSONRequest();
+ comment.put("toId", tid);
+ comment.setColumn("id");
+ idItem.put("Comment", comment);
+ //Comment>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+
+ request.putAll(idItem.toArray(0, 0, "Comment-id"));
+ //Comment-id[]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+
+ JSONObject rp = new DemoParser().setNoVerify(true).parseResponse(request);
+
+ JSONArray a = rp.getJSONArray("Comment-id[]");
+ if (a != null) {
+ arr.addAll(a);
+
+ JSONArray a2;
+ for (int i = 0; i < a.size(); i++) {
+
+ a2 = getChildCommentIdList(a.getLongValue(i));
+ if (a2 != null) {
+ arr.addAll(a2);
+ }
+ }
+ }
+
+ return arr;
+ }
+
+
+ /**TODO 仅用来测试 "key-()":"getIdList()" 和 "key()":"getIdList()"
+ * @param request
+ * @return JSONArray 只能用JSONArray,用long[]会在SQLConfig解析崩溃
+ * @throws Exception
+ */
+ public JSONArray getIdList(@NotNull JSONObject request) throws Exception {
+ return new JSONArray(new ArrayList