类Redux 的代码组织
在笔者之前关于RARF的描述中,曾提及基于
笔者并没有评估过本文这种实现所引起的性能损耗,大概是因为
JVM 调试分析的能力太渣了吧。另一方面,本文很有可能矫枉过正,所以权当一乐。
Overview
为了能有一个大概的印象,我们以一个简单的登录注册逻辑作为示范,整个流程中只有两条主要的逻辑线,然后我们直接看最终的
@RequestMapping("/login/{verifyCode}")
String login(HttpServletRequest request, @PathVariable("verifyCode") String verifyCode) {
//初始化上下文
SyncContext syncContext = new SyncContext();
syncContext
//判断用户提交的信息是否有效
.requestHandler((uniResourceBag, action) -> {
JSONObject requestData = UniResourceBag.parseRequestData(request, "username", "password");
return new Action("RequestDataReady")
.addActionData("username", requestData.getString("username"))
.addActionData("password", requestData.getString("password"));
})
.step("请求处理")
.reducer("判断用户是否存在", (uniResourceBag, action) -> {
//判断接收到的类型是否为当前需要处理的类型,如果不是则忽略
if (!action.isType("RequestDataReady")) {
return new Action();
}
String username = (String) action.getActionDataOrDefault("username");
String password = (String) action.getActionDataOrDefault("password");
//如果用户名为chevalier,则认为是存在的
if (username.equals("chevalier")) {
return new Action("doLogin").addActionData("username", username).addActionData("password", password);
} else if (username.equals("error")) {
throw new NullPointerException("error");
} else {
//否则创建新用户
return new Action("doRegister").addActionData("username", username).addActionData("password", password);
}
})
.step("执行登录操作或者创建新用户")
.reducer("对于已存在用户进行登录操作,返回user_token", (uniResourceBag, action) -> {
if (!action.isType("doLogin")) {
return new Action();
}
String username = (String) action.getActionDataOrDefault("username");
String password = (String) action.getActionDataOrDefault("password");
//将username+password连接作为user_token登录
uniResourceBag.setRequestDataWhenSuccess("user_token", UUID.randomUUID());
return new Action("Complete");
})
.reducer("对于新用户判断用户名是否存在,返回创建好的信息与user_token", (uniResourceBag, action) -> {
if (!action.isType("doRegister")) {
return new Action();
}
//返回用户名,用户密码,创建时间和用户Token
String username = (String) action.getActionDataOrDefault("username");
String password = (String) action.getActionDataOrDefault("password");
//将username+password连接作为user_token登录
uniResourceBag.setRequestDataWhenSuccess(
"username", username,
"password", password,
"create_time", Instant.now().toEpochMilli(),
"user_token", UUID.randomUUID());
return new Action("Complete");
})
.responseHandler((uniResourceBag, action) -> {
//进行最后的处理
return new Action();
});
return syncContext
.getUniResourceBag()
.getResponseString();
}
上面就是完成该流程的整个的代码,可以看出整个流程由
{ "code": 0, "subCode": 0, "runtimeLog": { "Context Uptime": 2, "steps": [ { "actualReducerDesc": "RequestHandler", "stepDesc": "RequestHandler", "stepId": 0, "actualReducerAction": { "actionType": "RequestDataReady", "actionData": { "password": "123", "username": "chevalier" } }, "stepRunTime": 0, "actualReducerUUID": "2608550a-6550-40da-84aa-a6a5b68bb93d" }, { "actualReducerDesc": "判断用户是否存在", "stepDesc": "请求处理", "stepId": 1, "actualReducerAction": { "actionType": "doLogin", "actionData": { "password": "123", "username": "chevalier" } }, "stepRunTime": 0, "actualReducerUUID": "92277976-bc24-4f69-b286-a4c95be993ac" }, { "actualReducerDesc": "对于已存在用户进行登录操作,返回user_token", "stepDesc": "执行登录操作或者创建新用户", "stepId": 2, "actualReducerAction": { "actionType": "Complete", "actionData": { } }, "stepRunTime": 0, "actualReducerUUID": "f21b1a80-9b86-49d7-9751-5bdc6d90c355" } ] }, "user_token": "499206a2-0130-484b-82e0-2b822c3b8dfa", "desc": "Success"
}
{ "password": "123", "code": 0, "create_time": 1461944838909, "subCode": 0, "runtimeLog": { "Context Uptime": 0, "steps": [ { "actualReducerDesc": "RequestHandler", "stepDesc": "RequestHandler", "stepId": 0, "actualReducerAction": { "actionType": "RequestDataReady", "actionData": { "password": "123", "username": "123" } }, "stepRunTime": 0, "actualReducerUUID": "c3e3040d-6ff4-41a7-b911-dbc31de6c6dd" }, { "actualReducerDesc": "判断用户是否存在", "stepDesc": "请求处理", "stepId": 1, "actualReducerAction": { "actionType": "doRegister", "actionData": { "password": "123", "username": "123" } }, "stepRunTime": 0, "actualReducerUUID": "a5ea22dd-41c4-46bc-9d14-f60c8f6a737d" }, { "actualReducerDesc": "对于新用户判断用户名是否存在,返回创建好的信息与user_token", "stepDesc": "执行登录操作或者创建新用户", "stepId": 2, "actualReducerAction": { "actionType": "Complete", "actionData": { } }, "stepRunTime": 0, "actualReducerUUID": "eb06837e-03b3-4812-9c2d-ff86a4d795a0" } ] }, "user_token": "6866cf13-ee06-4333-831a-dde0f2114764", "username": "123", "desc": "Success"}
{ "code": -1008, "runtimeLog": { "Context Uptime": 5, "steps": [ { "actualReducerDesc": "RequestHandler", "stepDesc": "RequestHandler", "stepId": 0, "actualReducerAction": { "actionType": "RequestDataReady", "actionData": { "password": "123", "username": "error" } }, "stepRunTime": 0, "actualReducerUUID": "50cb7b43-cc09-4491-8650-3294903fd6e6" }, { "stepDesc": "请求处理", "stepId": 1, "stepRunTime": -1461944917734 }, { "stepDesc": "执行登录操作或者创建新用户", "stepId": 2, "stepRunTime": 0 } ] }, "stackTrace": "error
wx.controller.user.LoginController.lambda$login$13(LoginController.java:67)
wx.controller.user.LoginController$$Lambda$215/1765146717.doWork(Unknown Source)
wx.rarf.context.SyncContext.lambda$null$21(SyncContext.java:304)
wx.rarf.context.SyncContext$$Lambda$220/1322867488.call(Unknown Source)
rx.Observable.unsafeSubscribe(Observable.java:7507)
rx.internal.operators.OperatorMerge$MergeSubscriber.handleNewSource(OperatorMerge.java:215)
rx.internal.operators.OperatorMerge$MergeSubscriber.onNext(OperatorMerge.java:185)
rx.internal.operators.OperatorMerge$MergeSubscriber.onNext(OperatorMerge.java:120)
rx.internal.operators.OperatorMap$1.onNext(OperatorMap.java:55)
rx.internal.operators.OperatorSingle$ParentSubscriber.onCompleted(OperatorSingle.java:124)
rx.internal.operators.OperatorTake$1.onNext(OperatorTake.java:69)
rx.internal.operators.OperatorMerge$InnerSubscriber.emit(OperatorMerge.java:676)
rx.internal.operators.OperatorMerge$InnerSubscriber.onNext(OperatorMerge.java:586)
wx.rarf.context.SyncContext.lambda$requestHandler$18(SyncContext.java:93)
wx.rarf.context.SyncContext$$Lambda$214/1827551503.call(Unknown Source)
rx.Observable.unsafeSubscribe(Observable.java:7507)
rx.internal.operators.OperatorMerge$MergeSubscriber.handleNewSource(OperatorMerge.java:215)
rx.internal.operators.OperatorMerge$MergeSubscriber.onNext(OperatorMerge.java:185)
rx.internal.operators.OperatorMerge$MergeSubscriber.onNext(OperatorMerge.java:120)
rx.internal.operators.OnSubscribeFromIterable$IterableProducer.request(OnSubscribeFromIterable.java:98)
rx.Subscriber.setProducer(Subscriber.java:177)
rx.internal.operators.OnSubscribeFromIterable.call(OnSubscribeFromIterable.java:50)
rx.internal.operators.OnSubscribeFromIterable.call(OnSubscribeFromIterable.java:33)
rx.Observable$1.call(Observable.java:144)
rx.Observable$1.call(Observable.java:136)
rx.Observable$1.call(Observable.java:144)
rx.Observable$1.call(Observable.java:136)
rx.Observable$1.call(Observable.java:144)
rx.Observable$1.call(Observable.java:136)
rx.Observable$1.call(Observable.java:144)
rx.Observable$1.call(Observable.java:136)
rx.Observable$1.call(Observable.java:144)
rx.Observable$1.call(Observable.java:136)
rx.Observable.unsafeSubscribe(Observable.java:7507)
rx.internal.operators.OperatorMerge$MergeSubscriber.handleNewSource(OperatorMerge.java:215)
rx.internal.operators.OperatorMerge$MergeSubscriber.onNext(OperatorMerge.java:185)
rx.internal.operators.OperatorMerge$MergeSubscriber.onNext(OperatorMerge.java:120)
rx.internal.operators.OnSubscribeFromIterable$IterableProducer.request(OnSubscribeFromIterable.java:98)
rx.Subscriber.setProducer(Subscriber.java:177)
rx.internal.operators.OnSubscribeFromIterable.call(OnSubscribeFromIterable.java:50)
rx.internal.operators.OnSubscribeFromIterable.call(OnSubscribeFromIterable.java:33)
rx.Observable$1.call(Observable.java:144)
rx.Observable$1.call(Observable.java:136)
rx.Observable$1.call(Observable.java:144)
rx.Observable$1.call(Observable.java:136)
rx.Observable$1.call(Observable.java:144)
rx.Observable$1.call(Observable.java:136)
rx.Observable$1.call(Observable.java:144)
rx.Observable$1.call(Observable.java:136)
rx.Observable$1.call(Observable.java:144)
rx.Observable$1.call(Observable.java:136)
rx.Observable.unsafeSubscribe(Observable.java:7507)
rx.internal.operators.OperatorMerge$MergeSubscriber.handleNewSource(OperatorMerge.java:215)
rx.internal.operators.OperatorMerge$MergeSubscriber.onNext(OperatorMerge.java:185)
rx.internal.operators.OperatorMerge$MergeSubscriber.onNext(OperatorMerge.java:120)
rx.internal.operators.OnSubscribeFromIterable$IterableProducer.request(OnSubscribeFromIterable.java:98)
rx.Subscriber.setProducer(Subscriber.java:177)
rx.internal.operators.OnSubscribeFromIterable.call(OnSubscribeFromIterable.java:50)
rx.internal.operators.OnSubscribeFromIterable.call(OnSubscribeFromIterable.java:33)
rx.Observable$1.call(Observable.java:144)
rx.Observable$1.call(Observable.java:136)
rx.Observable$1.call(Observable.java:144)
rx.Observable$1.call(Observable.java:136)
rx.Observable$1.call(Observable.java:144)
rx.Observable$1.call(Observable.java:136)
rx.Observable$1.call(Observable.java:144)
rx.Observable$1.call(Observable.java:136)
rx.Observable$1.call(Observable.java:144)
rx.Observable$1.call(Observable.java:136)
rx.Observable$1.call(Observable.java:144)
rx.Observable$1.call(Observable.java:136)
rx.Observable.subscribe(Observable.java:7597)
rx.observables.BlockingObservable.blockForSingle(BlockingObservable.java:442)
rx.observables.BlockingObservable.first(BlockingObservable.java:169)
wx.rarf.context.SyncContext.responseHandler(SyncContext.java:172)
wx.controller.user.LoginController.login(LoginController.java:115)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:497)
org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221)
org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:136)
org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:817)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:731)
org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:968)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:859)
javax.servlet.http.HttpServlet.service(HttpServlet.java:687)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:844)
javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:812)
org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1669)
org.eclipse.jetty.websocket.server.WebSocketUpgradeFilter.doFilter(WebSocketUpgradeFilter.java:224)
org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration$ApplicationContextHeaderFilter.doFilterInternal(EndpointWebMvcAutoConfiguration.java:237)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
wx.application.filter.SystemFilter.doFilter(SystemFilter.java:95)
org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
org.springframework.boot.actuate.trace.WebRequestTraceFilter.doFilterInternal(WebRequestTraceFilter.java:112)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:87)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:121)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
org.springframework.boot.actuate.autoconfigure.MetricsFilter.doFilterInternal(MetricsFilter.java:103)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:585)
org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:577)
org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:223)
org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1127)
org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:515)
org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:185)
org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1061)
org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:97)
org.eclipse.jetty.server.Server.handle(Server.java:499)
org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:311)
org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:257)
org.eclipse.jetty.io.AbstractConnection$2.run(AbstractConnection.java:544)
org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:635)
org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:555)
java.lang.Thread.run(Thread.java:745)
", "desc": "内部错误"}
Features & Motivation
首先,我们需要考虑现在的问题是什么,以及改进的目标是什么。笔者最早萌生出要做出一些改进的动因,是看到了下面这一个
@RequestMapping("doShareCreateWithAt")
public void doShareCreateWithAt(HttpServletRequest request, PrintWriter out)
throws Exception {
HJSONObject rtn = new HJSONObject();
int code = ErrorConfig.CODE_SUCCESS;
String desc = "返回成功";
int subCode = -1;
HJSONObject json = new HJSONObject();
String user_id = null;
String share_id = "10";//默认的分享创建成功之后
try {
//鉴权:判断用户Token是否有效
json = requestHandler(request, new String[]{"user_token", "share_img_path"});
String user_token = json.getString("user_token");
user_id = userTokenServiceImpl.queryUserIdByToken(user_token);
if (user_id == null) {
code = ErrorConfig.CODE_1006;
subCode = 1;
desc = "[" + code + "]+" + "[" + subCode + "],用户鉴权失败";
errorInfo.setErrorInfo(code, subCode, desc, request, out);
return;
} else {
//提取分享的基本信息
String share_category = json.getString("share_category", "0");
String share_description = json.getString("share_description", "");
String share_img_path = json.getString("share_img_path");
String share_city = json.getString("share_city", "0");
String share_county = json.getString("share_county", "0");
String share_lon = json.getString("share_lon", "0.0");
String share_lat = json.getString("share_lat", "0.0");
//活动IDs
String activity_ids = json.getString("activity_ids", "");
//群组IDs
String group_ids = json.getString("group_ids", "");
//用户IDs
String user_ids = json.getString("user_ids", "");
String share_img_path_with_lables = json.getString("share_img_path_with_lables", "");
String share_img_path_with_pasters = json.getString("share_img_path_with_pasters", "");
String share_location = json.getString("share_location", "");
String sport_ids = json.getString("sport_ids", "");
//这个是抽出来的贴纸信息
String share_paster_ids = "";
HashMap<String, String> activityMap = null;
HashMap<String, String> groupMap = null;
//检查活动的参数-Json数组-只允许@一个活动
if (StringUtil.isBlank(activity_ids) || StringUtil.isEmpty(activity_ids)) {
activity_ids = null;
} else {
if (!isJSONArray(activity_ids)) {
code = ErrorConfig.CODE_1006;
subCode = 2;
desc = "[" + code + "]+" + "[" + subCode + "],activity_ids格式不符合";
errorInfo.setErrorInfo(code, subCode, desc, request, out);
return;
//throw new RequestException(code, subCode,desc);
} else {
JSONArray activityIds = JSONArray.parseArray(activity_ids);
//获取传来的id的个数
int idsSize = activityIds.size();
if (idsSize != 1) {
code = ErrorConfig.CODE_1005;
subCode = 3;
desc = "[" + code + "]+" + "[" + subCode + "],一条分享只允许@一个活动";
errorInfo.setErrorInfo(code, subCode, desc, request, out);
return;
//throw new RequestException(code, subCode,desc);
} else {
//目前只让@一个活动
//鉴别活动id
String activity_id = activityIds.getString(0);
String group_id = null;
if (StringUtil.isBlank(activity_id) || StringUtil.isEmpty(activity_id)) {
code = ErrorConfig.CODE_1005;
subCode = 4;
desc = "[" + code + "]+" + "[" + subCode + "],activity_id有误,活动不存在";
errorInfo.setErrorInfo(code, subCode, desc, request, out);
return;
//throw new RequestException(code, subCode,desc);
} else {
Map<String, Object> groupInfo = socialActivityServiceImpl.queryActivityByIdV(activity_id);
if (groupInfo == null) {
code = ErrorConfig.CODE_1005;
subCode = 4;
desc = "[" + code + "]+" + "[" + subCode + "],activity_id有误,活动不存在";
errorInfo.setErrorInfo(code, subCode, desc, request, out);
return;
//throw new RequestException(code, subCode,desc);
} else {
//活动存在,看看是不是官方活动?官方活动没有群:group_id为空
if (groupInfo.get("group_id") != null)
group_id = groupInfo.get("group_id").toString();
activityMap = new HashMap<String, String>();
activityMap.put("group_id", null);//默认放个null进去
//查看用户是否已经参加了该活动:1-已参加、-1-未参加、0-已退出
String attendState = socialActivityServiceImpl.queryUserAttendStateV(user_id, activity_id);
if (!attendState.equals("1")) {
activityMap.put("hasAttend", "0");
} else {
activityMap.put("hasAttend", "1");
}
if (StringUtil.isBlank(group_id) || StringUtil.isEmpty(group_id)) {
//官方活动,参加不参加都能@,没参加的先参加
//activity_ids = activity_id;
activityMap.put("isOfficial", "1");
} else {
//非官方活动,看参加没,没参加不能@
//TODO-直接参加?
activityMap.put("isOfficial", "0");
if (!attendState.equals("1")) {
code = ErrorConfig.CODE_1006;
subCode = 5;
desc = "[" + code + "]+" + "[" + subCode + "],非官方活动,没有参加不能@";
errorInfo.setErrorInfo(code, subCode, desc, request, out);
return;
//throw new RequestException(code, subCode,desc);
} else {
//参加了让@
//activity_ids = activity_id;
activityMap.put("group_id", group_id);
}
}
//TODO-两个?
activityMap.put("activity_id", activity_id);
activityMap.put("activity_ids", activity_ids);
}
}
}
}
}
//检查群组的参数-Json-只允许@一个群组
if (StringUtil.isBlank(group_ids) || StringUtil.isEmpty(group_ids)) {
group_ids = null;
} else {
if (!isJSONArray(group_ids)) {
code = ErrorConfig.CODE_1006;
subCode = 6;
desc = "[" + code + "]+" + "[" + subCode + "],group_ids格式不符合";
errorInfo.setErrorInfo(code, subCode, desc, request, out);
return;
//throw new RequestException(code, subCode,desc);
} else {
JSONArray groupIds = JSONArray.parseArray(group_ids);
//获取传来的id的个数
int idsSize = groupIds.size();
if (idsSize != 1) {
code = ErrorConfig.CODE_1005;
subCode = 7;
desc = "[" + code + "]+" + "[" + subCode + "],一条分享只允许@一个群组";
errorInfo.setErrorInfo(code, subCode, desc, request, out);
return;
//throw new RequestException(code, subCode,desc);
} else {
//目前只让@一个群组
//看看群组存在么
String group_id = groupIds.getString(0);
groupMap = new HashMap<String, String>();
if (StringUtil.isBlank(group_id) || StringUtil.isEmpty(group_id)) {
code = ErrorConfig.CODE_1005;
subCode = 8;
desc = "[" + code + "]+" + "[" + subCode + "],group_id有误,群组不存在";
errorInfo.setErrorInfo(code, subCode, desc, request, out);
return;
//throw new RequestException(code, subCode,desc);
} else {
//根据群组ID获取群组详情
Map<String, String> groupInfo = socialGroupServiceImpl.queryGroupInfo(group_id);
if (groupInfo == null) {
code = ErrorConfig.CODE_1005;
subCode = 8;
desc = "[" + code + "]+" + "[" + subCode + "],group_id有误,群组不存在";
errorInfo.setErrorInfo(code, subCode, desc, request, out);
return;
//throw new RequestException(code, subCode,desc);
} else {
//群组存在,看看参加没有
boolean isJoin = socialGroupServiceImpl.queryIdByGroupAndUserIdV(group_id, user_id);
if (isJoin == false) {
code = ErrorConfig.CODE_1005;
subCode = 9;
desc = "[" + code + "]+" + "[" + subCode + "],@了未加入的群组";
errorInfo.setErrorInfo(code, subCode, desc, request, out);
return;
//throw new RequestException(code, subCode,desc);
} else {
//group_ids = group_id;
groupMap.put("group_ids", group_ids);//这是存的,为了不该群相册接口,还是存一个array,以后如果可以关联多个群组什么的也可以
groupMap.put("group_id", group_id);//这是拿到service层做比较的,不用再从array转化一次
}
}
}
}
}
}
//@用户
if (StringUtil.isBlank(user_ids) || StringUtil.isEmpty(user_ids)) {
user_ids = null;
} else {
if (!isJSONArray(user_ids)) {
code = ErrorConfig.CODE_1005;
subCode = 10;
desc = "[" + code + "]+" + "[" + subCode + "],user_ids不符合";
errorInfo.setErrorInfo(code, subCode, desc, request, out);
return;
//throw new RequestException(code, subCode,desc);
} else {
JSONArray userIds = JSONArray.parseArray(user_ids);
//获取传来的id的个数
int idsSize = userIds.size();
if (idsSize < 1 || idsSize > 3) {
code = ErrorConfig.CODE_1005;
subCode = 11;
desc = "[" + code + "]+" + "[" + subCode + "],一条分享只允许1-3个好友";
errorInfo.setErrorInfo(code, subCode, desc, request, out);
return;
//throw new RequestException(code, subCode,desc);
} else {
//看看重不重复
Set<String> userIdSet = new HashSet<String>();
for (int i = 0; i < idsSize; i++) {
userIdSet.add(userIds.getString(i));
}
if (idsSize != userIdSet.size()) {
code = ErrorConfig.CODE_1005;
subCode = 12;
desc = "[" + code + "]+" + "[" + subCode + "],一个好友只能@一次";
errorInfo.setErrorInfo(code, subCode, desc, request, out);
return;
//throw new RequestException(code, subCode,desc);
}
//TODO-批量查询数据库
//看看好友存在么
for (int i = 0; i < idsSize; i++) {
String userId = userIds.getString(i);
//存在性
boolean isUser = userServiceImpl.queryUserIdById(userId);
if (isUser == false) {
code = ErrorConfig.CODE_1005;
subCode = 13;
desc = "[" + code + "]+" + "[" + subCode + "],@了一个不存在的用户";
errorInfo.setErrorInfo(code, subCode, desc, request, out);
return;
//throw new RequestException(code, subCode,desc);
}
//是否好友
boolean isAttention = socialFollowingServiceImpl.queryFollowingIdV(user_id, userId);
boolean isAttention1 = socialFollowingServiceImpl.queryFollowingIdV(userId, user_id);
if (isAttention == false || isAttention1 == false) {
code = ErrorConfig.CODE_1005;
subCode = 14;
desc = "[" + code + "]+" + "[" + subCode + "],@了一个不是好友的用户";
errorInfo.setErrorInfo(code, subCode, desc, request, out);
return;
//throw new RequestException(code, subCode,desc);
}
}
}
}
}
//图片标签-"share_img_path_with_lables":[{"pic1_url":[]},{"pic2_url":[]},{"pic3_url":[]}]
//键key:存图片的Url,值Value:存图片对应的标签
if (!"".equals(share_img_path_with_lables)) {
//判断是否是json格式
if (!isJSONArray(share_img_path_with_lables)) {
code = ErrorConfig.CODE_1006;
subCode = 15;
desc = "[" + code + "]+" + "[" + subCode + "],请求参数格式不符,检查share_img_path_with_lables";
errorInfo.setErrorInfo(code, subCode, desc, request, out);
return;
//throw new RequestException(code, subCode,desc);
}
//解析share_img_path_with_lables的值,真实的图片,总共有9张图片
JSONArray shareImgLableArr = JSONArray.parseArray(share_img_path_with_lables);
int urlSize = shareImgLableArr.size();
if (urlSize > 9) {
code = ErrorConfig.CODE_1005;
subCode = 16;
desc = "[" + code + "]+" + "[" + subCode + "],分享不能超过9张图,检查share_img_path_with_lables";
errorInfo.setErrorInfo(code, subCode, desc, request, out);
return;
//throw new RequestException(code, subCode,desc);
} else {
//遍历,看看必填的参数是不是都填了。
//遍历每个图片附带的标签属性
for (int i = 0; i < urlSize; i++) {
String shareImgLables = shareImgLableArr.getString(i);//"pic1_url":["":"","":""]
HJSONObject shareImgLablesJson = new HJSONObject(JSONObject.parseObject(shareImgLables));
//获取第i张图片的键key,存放的是pic_url的Url路径,所以key的size为1
Set<String> keyset = shareImgLablesJson.keySet();
if (keyset.size() != 1) {
code = ErrorConfig.CODE_1006;
subCode = 15;
desc = "[" + code + "]+" + "[" + subCode + "],请求参数格式不符,检查share_img_path_with_lables";
errorInfo.setErrorInfo(code, subCode, desc, request, out);
return;
//throw new RequestException(code, subCode,desc);
} else {
String url = keyset.iterator().next();
if (!isUrl(url)) {
code = ErrorConfig.CODE_1006;
subCode = 15;
desc = "[" + code + "]+" + "[" + subCode + "],请求参数格式不符,检查share_img_path_with_lables";
errorInfo.setErrorInfo(code, subCode, desc, request, out);
return;
//throw new RequestException(code, subCode,desc);
}
//根据键key获取对应的值value,其中存放的是图片对应的标签信息
String shareImgLablesStr = shareImgLablesJson.getString(url);
JSONArray shareImgLablesArr = JSONArray.parseArray(shareImgLablesStr);
int lableSize = shareImgLablesArr.size();
if (lableSize > 6) {
code = ErrorConfig.CODE_1005;
subCode = 17;
desc = "[" + code + "]+" + "[" + subCode + "],一张图片不能超过6个标签";
errorInfo.setErrorInfo(code, subCode, desc, request, out);
return;
//throw new RequestException(code, subCode,desc);
} else {
for (int j = 0; j < lableSize; j++) {
String shareImgLable = shareImgLablesArr.getString(j);
//标签在图片上的位置,还有牌子信息必填
HJSONObject shareImgLableJson = HJSONHandler(shareImgLable, new String[]{"offset_x", "offset_y", "brand", "direction"});
String offset_x = shareImgLableJson.getString("offset_x");
try {
Double.parseDouble(offset_x);
} catch (Exception e) {
code = ErrorConfig.CODE_1005;
subCode = 18;
desc = "[" + code + "]+" + "[" + subCode + "],非法的x偏移参数";
errorInfo.setErrorInfo(code, subCode, desc, request, out);
return;
//throw new RequestException(code, subCode,desc);
}
String offset_y = shareImgLableJson.getString("offset_y");
try {
Double.parseDouble(offset_y);
} catch (Exception e) {
code = ErrorConfig.CODE_1005;
subCode = 19;
desc = "[" + code + "]+" + "[" + subCode + "],非法的y偏移参数";
errorInfo.setErrorInfo(code, subCode, desc, request, out);
return;
//throw new RequestException(code, subCode,desc);
}
String direction = shareImgLableJson.getString("direction");
String brand = shareImgLableJson.getString("brand");
//这个需要一个brand数据表
String altitude = shareImgLableJson.getString("altitude", "");
String number = shareImgLableJson.getString("number", "");
String img_label_type = shareImgLableJson.getString("img_label_type", "");
shareImgLableJson.clear();
shareImgLableJson.put("offset_x", offset_x);
shareImgLableJson.put("offset_y", offset_y);
shareImgLableJson.put("brand", brand);
shareImgLableJson.put("altitude", altitude);
shareImgLableJson.put("number", number);
shareImgLableJson.put("img_label_type", img_label_type);
shareImgLableJson.put("direction", direction);
shareImgLablesArr.set(j, shareImgLableJson);
}
}
shareImgLablesJson.put(url, shareImgLablesArr);
}
shareImgLableArr.set(i, shareImgLablesJson);
share_img_path_with_lables = shareImgLableArr.toString();
}
}
}
//贴纸,类似标签的数据结构,"share_paster_ids":[{"url1":["1","2"]},{"url2":["1","2"]}]
if (!"".equals(share_img_path_with_pasters)) {
//判断是否是json格式
if (!isJSONArray(share_img_path_with_pasters)) {
code = ErrorConfig.CODE_1006;
subCode = 20;
desc = "[" + code + "]+" + "[" + subCode + "],请求参数格式不符,检查share_img_path_with_pasters";
errorInfo.setErrorInfo(code, subCode, desc, request, out);
return;
//throw new RequestException(code, subCode,desc);
}
JSONArray shareImgPasterUrlsArr = JSONArray.parseArray(share_img_path_with_pasters);
Set<String> shareImgPasterIdsSet = new HashSet<String>();
int urlSize = shareImgPasterUrlsArr.size();
if (urlSize > 9) {
code = ErrorConfig.CODE_1005;
subCode = 21;
desc = "[" + code + "]+" + "[" + subCode + "],分享不能超过9张图,检查share_img_path_with_pasters";
errorInfo.setErrorInfo(code, subCode, desc, request, out);
return;
//throw new RequestException(code, subCode,desc);
} else {
for (int i = 0; i < urlSize; i++) {
String shareImgPasterIdsArrStr = shareImgPasterUrlsArr.getString(i);
HJSONObject shareImgPasterIdsArrJson = new HJSONObject(JSONObject.parseObject(shareImgPasterIdsArrStr));
Set<String> keyset = shareImgPasterIdsArrJson.keySet();
if (keyset.size() != 1) {
code = ErrorConfig.CODE_1006;
subCode = 20;
desc = "[" + code + "]+" + "[" + subCode + "],请求参数格式不符,检查share_img_path_with_pasters";
errorInfo.setErrorInfo(code, subCode, desc, request, out);
return;
//throw new RequestException(code, subCode,desc);
} else {
String url = keyset.iterator().next();
if (!isUrl(url)) {
code = ErrorConfig.CODE_1006;
subCode = 20;
desc = "[" + code + "]+" + "[" + subCode + "],请求参数格式不符,检查share_img_path_with_pasters";
errorInfo.setErrorInfo(code, subCode, desc, request, out);
return;
//throw new RequestException(code, subCode,desc);
}
String shareImgPasterIdsStr = shareImgPasterIdsArrJson.getString(url);
JSONArray shareImgPasterIdsArr = JSONArray.parseArray(shareImgPasterIdsStr);
int idsSize = shareImgPasterIdsArr.size();
if (idsSize > 5) {
code = ErrorConfig.CODE_1005;
subCode = 22;
desc = "[" + code + "]+" + "[" + subCode + "],一张图不能超过5个贴纸";
errorInfo.setErrorInfo(code, subCode, desc, request, out);
return;
//throw new RequestException(code, subCode,desc);
} else {
for (int j = 0; j < idsSize; j++) {
String paster_id = shareImgPasterIdsArr.getString(j);
try {
int paster_id_int = Integer.parseInt(paster_id);
shareImgPasterIdsSet.add(String.valueOf(paster_id_int));
} catch (Exception e) {
e.printStackTrace();
subCode = 20;
desc = "[" + code + "]+" + "[" + subCode + "],请求参数格式不符,检查share_img_path_with_pasters";
errorInfo.setErrorInfo(code, subCode, desc, request, out);
return;
//throw new RequestException(code, subCode,desc);
}
}
}
}
}
}
}
//运动类型 "sport_ids":["1"]-json-一个分享智能关联一个运动类型
if (StringUtil.isBlank(sport_ids) || StringUtil.isEmpty(sport_ids)) {
sport_ids = null;
} else {
if (!isJSONArray(sport_ids)) {
code = ErrorConfig.CODE_1005;
subCode = 26;
desc = "[" + code + "]+" + "[" + subCode + "],sport_ids不符合";
errorInfo.setErrorInfo(code, subCode, desc, request, out);
return;
//throw new RequestException(code, subCode,desc);
} else {
JSONArray sportIds = JSONArray.parseArray(sport_ids);
//获取传来的id的个数
int idsSize = sportIds.size();
if (idsSize != 1) {
code = ErrorConfig.CODE_1005;
subCode = 27;
desc = "[" + code + "]+" + "[" + subCode + "],一条分享只关联1个运动类型";
errorInfo.setErrorInfo(code, subCode, desc, request, out);
return;
//throw new RequestException(code, subCode,desc);
} else {
//看看运动类型存在么
for (int i = 0; i < idsSize; i++) {
String sportId = sportIds.getString(i);
//存在性
String sport_id = sportIds.getString(i);
try {
int sport_id_i = Integer.parseInt(sport_id);
Boolean is_user_sport_id_exist = userPersonServiceImpl.queryUserSportBySportId(String.valueOf(sport_id_i));
if (!is_user_sport_id_exist) {
throw new Exception();
}
sportIds.set(i, String.valueOf(sport_id_i));
} catch (Exception e) {
code = ErrorConfig.CODE_1005;
subCode = 28;
desc = "[" + code + "]+" + "[" + subCode + "],用户运动类型有误";
errorInfo.setErrorInfo(code, subCode, desc, request, out);
return;
//throw new RequestException(code, subCode,desc);
}
}
sport_ids = sportIds.toString();
}
}
}
if (!"".equals(share_location)) {
if (StringUtil.isBlank(share_location) || StringUtil.isEmpty(share_location)) {
code = ErrorConfig.CODE_1006;
subCode = 25;
desc = "[" + code + "]+" + "[" + subCode + "],请检查share_location是否为空";
errorInfo.setErrorInfo(code, subCode, desc, request, out);
return;
//throw new RequestException(code, subCode,desc);
}
}
if (StringUtil.isBlank(share_img_path) || StringUtil.isEmpty(share_img_path) || Integer.parseInt(share_category) < 0 || Integer.parseInt(share_category) > 1 || !isJSONArray(share_img_path)) {
code = ErrorConfig.CODE_1006;
subCode = 23;
desc = "[" + code + "]+" + "[" + subCode + "],请求参数格式不符,检查share_img_path和share_category";
errorInfo.setErrorInfo(code, subCode, desc, request, out);
return;
//throw new RequestException(code, subCode,desc);
} else {
if (isJsonEmpty(share_img_path)) {
code = ErrorConfig.CODE_1006;
subCode = 23;
desc = "[" + code + "]+" + "[" + subCode + "],请求参数格式不符,检查share_img_path和share_category";
throw new RequestException(code, subCode, desc);
}
JSONArray share_img_path_json = JSONArray.parseArray(share_img_path);
//获取传来的id的个数
int idsSize = share_img_path_json.size();
if (idsSize > 9) {
code = ErrorConfig.CODE_1005;
subCode = 29;
desc = "[" + code + "]+" + "[" + subCode + "],一条分享最多关联9张图片";
errorInfo.setErrorInfo(code, subCode, desc, request, out);
return;
//throw new RequestException(code, subCode,desc);
} else {
for (int i = 0; i < idsSize; i++) {
String url = share_img_path_json.getString(i);
if (!isUrl(url)) {
code = ErrorConfig.CODE_1005;
subCode = 30;
desc = "[" + code + "]+" + "[" + subCode + "],分享图片中有不合法的url";
errorInfo.setErrorInfo(code, subCode, desc, request, out);
return;
//throw new RequestException(code, subCode,desc);
}
}
share_img_path = share_img_path_json.toString();
}
if (share_category.equals("0")) {
try {
//调用创建分享的服务,成功则返回分享的编号
share_id = socialShareServiceImpl.insertShareWithAt(user_id, share_category, share_description,
share_img_path, share_city, share_county, share_lon, share_lat, activityMap, groupMap, user_ids,
share_img_path_with_lables, share_paster_ids, share_img_path_with_pasters, share_location, sport_ids);
} catch (Exception e) {
e.printStackTrace();
code = ErrorConfig.CODE_1006;
subCode = 24;
desc = "[" + code + "]+" + "[" + subCode + "],数据库更新失败";
errorInfo.setErrorInfo(code, subCode, desc, request, out);
return;
}
} else if (share_category.equals("1")) {
//Promises的实现还没写
try {
socialShareServiceImpl.insertPromiseWithAt(user_id, share_category, share_description,
share_img_path, share_city, share_county, share_lon, share_lat, activityMap, groupMap, user_ids, share_img_path_with_lables);
} catch (Exception e) {
code = ErrorConfig.CODE_1006;
subCode = 24;
desc = "[" + code + "]+" + "[" + subCode + "],数据库更新失败";
errorInfo.setErrorInfo(code, subCode, desc, request, out);
return;
}
}
}
}
} catch (ParamException e) {
code = ErrorConfig.CODE_1005;
subCode = 0;
desc = "[" + code + "]+" + "[" + subCode + "],请求参数缺失";
rtn.put("subCode", subCode);
rtn.put("desc", desc);
errorInfo.setErrorInfo(code, subCode, desc, request, out);
return;
}
rtn.put("code", code);
//Todo 添加真实的返回share_id
rtn.put("share_id", share_id);
request.setAttribute("user_id", user_id);
out.print(responseHandler(rtn, request));
out.close();
}
清晰的业务代码逻辑
一般来说,一个
Scenario: 两数相加
Given 我有一个计算器
And 我向计算器输入50
And 我向计算器输入70
When 我点击累加
Then 我应该看到结果120
在
requestHandler().
step("我是本步骤的描述").
reducer("我是本步骤的第一个可能情况").
reducer("我是本步骤的第二个可能情况")
全局状态与局部状态的分割
在
可回溯性
可容错性
上文中已经提及,因为
并发编程与异步实现
随着计算机硬件,笔者比较推崇响应式流这种异步模型,在本部分的实现中,笔者也是优先考虑了并发的易实现性。subscribeOn
方法将某个
Terminology
Context
Step
一个
UniResourceBag
资源包即是上文描述的全局状态存放的地方,包括输入、输出。
Reducer & Action
每个
RequestHandler: 对于请求数据进行预处理
请求方式基于
/login/{verifyCode}?requestData={"username":chevalier,"password":123456}