AJAX+Spring MVCプログラムの基本原理


プログラムの機能説明:ページの上で1つの“Disable Account”ボタンをクリックして、バックグラウンドはDisableのあるアカウントを実現して、プログラムの原理は以下の通りです:
  • まずページ上でボタンをクリックし、このボタンのIDは「disableAccountBtn」であり、ページにロードされたJSファイルを探し出し、ファイルの中でこのIDを検索すると、
    $('#disableAccountBtn').click(function() {
    $('#promptWinYes').unbind('click').click(function() {
    $('#promptWin').dialog('close');
    $.getJSON(DISABLE_USER_ACTION, {
    uid : clientId
    }, function(data) {
    switchButtonVisible(false);
    showAlertWin('Warning', DISABLE_USER_CALLBACK_MSG);
    });
    });
    showPromptWin('Warning', DISABLE_USER_MSG);
    }); 
    の中で$が発見された.getJSONは、リモートのJSON文字列を呼び出して取得し、それをJSONオブジェクトに変換し、成功すればコールバック関数を実行し、JSからDISABLE_を検索するUSER_ACTION=".../disableUser.action.この呼び出しが最終的に実行されたことがわかります./disableUser.action?uid=userIDというサービス
  • バックグラウンドJAVAコードを探して、UserManagementControllerにいます.JAvaでは、clientAction
  • を用いたSpring MVCのフレームワークを用いる方法が見つかった.
  • ワークフローコントローラに再アクセスする.disableClient(request,clientAction)
    @RequestMapping("/disableUser.action")
    	public ModelAndView disableUser(HttpServletRequest request)
    			throws Exception {
    		return WorkflowController.disableClient(request, clientAction);
    	}
    が表示され、このサービスの実行に成功した後、返される文字列は
     public static ModelAndView disableClient(HttpServletRequest httpReq, ClientAction clientAction) {
            String clientId = httpReq.getParameter("uid");
            UserBean sales = resolveSales(httpReq);
    
            String methodId = "{" + sales.getId() + "," + clientId + "," + System.currentTimeMillis() + "}";
            logger.info("/disableUser.action BEGIN " + methodId);
    
            boolean success = true;
            String errorMsg = null;
            try {
                clientAction.disableClient(clientId, sales);
            } catch (Throwable e) {
                logger.error("Failed to disable user " + methodId, e);
                success = false;
                errorMsg = "Server Internal Error. Please contact the system Admin.";
            } finally {
                logger.info("/disableUser.action END " + methodId);
            }
    
            ModelMap model = new ModelMap();
            model.addAttribute("success", success);
            model.addAttribute("errorMsg", errorMsg);
            return new ModelAndView("results", model);
        }
  • である.
  • clientActionに入る.disableClient(clientId,sales)メソッド、ClientActionには多くのメソッドがあります:
    {"errorMsg":null,"success":true}
  • さらにdsiableClient:
     /**
         * Action to disable an existing client.
         * 
         * @param clientId
         * @param currentUser
         * @throws Exception
         */
        public void disableClient(String clientId, UserBean currentUser) throws Exception {
        	umUserService.createESFDataIfMissing(clientId);
            UserProfile oldUser = umUserService.getUserProfile(clientId);
            disableClient(currentUser, oldUser);
        }
  • 最終呼び出し共通のstartDisableClientWorkflow()メソッド:
     void disableClient(UserBean salesUserBean, UserProfile clientUserProfile) throws Exception {
            if (salesUserBean == null || clientUserProfile == null) {
                return;
            }
            String clientId = clientUserProfile.getUid();
            String clientName = clientUserProfile.getDisplayName();
            UserRequestEntity userEntity = new UserRequestEntity();
            userEntity.setTitle(UMTConstants.USER_PROFILE_TITLE + "(Disable)");
            userEntity.setClientId(clientId);
            userEntity.setClientName(clientName);
            userEntity.setSalesId(salesUserBean.getId());
            userEntity.setSalesName(salesUserBean.getName());
    
            //restore old user profile
            try {
                userEntity.setProfile(JsonUtil.write(clientUserProfile));
            } catch (Exception e) {
                logger.error("Failed to encode user profile into JSON.", e);
            }
    
            umWorkflow.startDisableClientWorkflow(userEntity, UMTConstants.WF_DISABLE_CLIENT);
        } 
    startWorkflow():
     /**
         * Start the workflow to disable an existing client.
         * 
         * @param userEntity the user profile provided by front-end, cannot be null
         */
        public void startDisableClientWorkflow(UserRequestEntity userEntity, String workflowName) throws Exception {
            //1) save records into request tables
            UserRequestEntityHelper.validatePV(userEntity);
            UMRequestEntity umEntity = requestTracker.save(userEntity);
            Long requestId = umEntity.getId();
            logger.info("Saved request entity of [disable] for {" + userEntity.getClientId() + "} as " + requestId);
    
            //2) update request status
            umEntity.setStatus(UMRequestEntity.Status.ESF_DISABLE);
            startWorkflow(requestId, workflowName, umEntity);
        }
  • WorkFlowServiceの実装クラス対応を見つける方法:
     /**
         * Start workflow for request.
         * 
         * @param requestId
         * @param workflowName
         * @param umEntity
         * @throws Exception
         */
        public void startWorkflow(Long requestId, String workflowName, UMRequestEntity umEntity) throws Exception {
            logger.info("Start workflow " + workflowName + " for request [" + requestId + "]");
    
            //1) get workflow and start the process instance
            UMWorkflowBean workflowBean = workflowRepository.findUMWorkflowByName(workflowName);
            String processId = workflowService.startProcessInstance(workflowBean.getProcessName(), new HashMap<String, String>());
    
            //2) update request status
            if (umEntity == null) {
                umEntity = new UMRequestEntity();
                umEntity.setStatus(UserRequestEntity.Status.PROCESSING);
                umEntity.setStatusFlag(0);
            }
            umEntity.setId(requestId);
            umEntity.setWorkflowId(workflowBean.getWorkflowId());
            umEntity.setProcessId(processId);
            requestTracker.update(umEntity);
            logger.info("Started workflow for request [" + requestId + "]");
    
            //3) transit to first state
            Set<String> nextStates = workflowService.findActiveStates(processId);
            StateHandler nextStateHandler = null;
            for (String nextState : nextStates) {
                nextStateHandler = handlerRepository.getByState(nextState);
                if (nextStateHandler != null) {
                    break;
                }
            }
            if (nextStateHandler != null) {
                nextStateHandler.execute(requestId);   
            }
        }
    }
    ExecutionServiceこのクラスはJBPMに属し、全称Java Business Process Managementであり、J 2 EEベースの軽量レベルワークフロー管理システムである.

  • まとめ:このようなAJAX+Spring MVCのプログラムの基本原理はフロントJSコードがバックグラウンドのServicesを呼び出すことである.テスト時にFidderまたはFirebugを開くと、特定のサービスが伝達したパラメータをキャプチャできます.
    次は本物のDisableロジックです.
  • ESFServiceImplにはdisableUser()メソッドがある:
     /**
         * Start the process instance.
         * 
         */
        public String startProcessInstance(String processKey, Map<String, String> variables) {
            ProcessInstance processInstance = executionService.startProcessInstanceByKey(processKey, variables);
            return processInstance.getId();
        }
    CallableStatementを使用してストレージ・プロシージャESFconstansを呼び出す.CALL_DISABLE_USER:
    public void disableUser(String operator, String userId) throws Exception {
    		//		Map<String, String> userESFAttrMap = queryUserESFInfo(userId);
    		//		if (userESFAttrMap == null) {
    		//			throw new Exception("Disable user error. Can not find user: "
    		//					+ userId);
    		//		}
    		//		if (ESFConstans.STATUS_ENABLED.equals(userESFAttrMap
    		//				.get(ESFConstans.CLIENT_USERS_ATTR.STATUS))) {
    		//			changeUserStatus(operator, userId);
    		//		}
    		Connection con = null;
    		CallableStatement st = null;
    		ResultSet rs = null;
    		try {
    			con = getConnection();
    			st = con.prepareCall(ESFConstans.CALL_DISABLE_USER);
    			st.setString(1, userId);
    			st.setString(2, operator);
    			st.execute();
    		} catch (SQLException e) {
    			throw e;
    		} catch (Exception e) {
    			throw e;
    		} finally {
    			closeAllDBResources(rs, st, con);
    		}
    	}