移动办公OA系统

好久没有更新文章了,总觉得心里空空的,最近由于工作的原因,没有来的及及时更新,总感觉应该把学习到的东西做个记录,供大家学习,也供自己复习,温故而知新。今天趁着周末休息时间,把自己最近在公司的做的项目做一个总结。由于是刚入职不久,进公司负责的项目内容也很少,主要还是以学习为主。

一、项目介绍

某银行移动办公系统,简称移动OA,是我进公司参与的第一个项目,主要负责的是java后台接口的开发,该系统涉及iOS,android,pad三个前台页面,后台就是为这三个客户端提供公共的接口,根据业务需要,以json格式传递过来的数据在后台进行处理,然后返回到前台进行展示。我们项目组负责的是OA里面的一个小项目-督办,该项目要实现银行项目申报、催促、进度查看、项目再分解等一些功能。根据页面展示需要,我完成了一下几个接口的开发,其中包括一些常用的查找功能和图片压缩下载。

  在介绍接口实现之前,有必要把自己学到的json解析再分析一遍,之前接触啊到的json格式的的字符串数据量很小,但在实际项目中数据量是如此之大,面对如此大的数据量,我也曾迷茫过,怎么解析是个问题,后来在项目经理的帮助和自己的努力下,终于完成了json解析这个工具类的开发,我觉的这个类可以应用到很多项目中,只要是涉及到json的地方都可以。

json解析代码如下:

/**
	 * 将json转化成map
	 * @param json
	 * @return
	 * @date 2017年2月25日
	 * @return Map<String,Object>
	 * @author 我心自在
	 */
	public static Map<String, Object> json2Map(Object json){
		if(json.equals("null")){
			return null;
		}
		JSONObject object = JSONObject.fromObject(json);
		Map map = new HashMap();
		Iterator it = object.keys();
		while (it.hasNext()) {
			String key = (String)it.next();
			String value = object.getString(key);
			if (JSONUtils.isObject(object.get(key))) {
				map.put(key, json2Map(value));
			} else if (JSONUtils.isArray(object.get(key))) {
				List list = new ArrayList();
				JSONArray jArray = JSONArray.fromObject(value);
				for (int i = 0; i < jArray.size(); i++) {
					if(JSONUtils.isObject(jArray.get(i)) ){
						list.add(json2Map(jArray.get(i)));
					}else if ( JSONUtils.isArray(jArray.get(i))){
						list.add(json2List(jArray.get(i)));
					}else {
						list.add(jArray.get(i));
					}
				}
				map.put(key, list);
			} else {
				map.put(key, ConvertUtil.obj2Str(object.get(key)));
			}
		}
		return map;
	}      //下面是ConvertUtil中的部分代码,下面的方法将Object转化为String

        public static String obj2Str(Object obj) {
          return obj == null ? null : obj.toString();
        }


下面适用于json里面带数组的:

/**
	 * 用于 JSON里面带数组的
	 * @param json
	 * @return
	 */
	public static Map<String, Object> jsonArray2Map(Object json){
//		if(StringUtils.startsWith(json, "{") && StringUtils.endsWith(json, "}")){
//			json = "["+json+"]";
//		}
		JSONArray jsonArray = JSONArray.fromObject(json);
		JSONObject object = jsonArray.getJSONObject(0);
		Map map = new HashMap();
		Iterator it = object.keys();
		while (it.hasNext()) {
			String key = (String)it.next();
			String value = object.getString(key);
			if (JSONUtils.isObject(object.get(key))) {
				map.put(key, json2Map(value));
			} else if (JSONUtils.isArray(object.get(key))) {
				List list = new ArrayList();
				JSONArray jArray = JSONArray.fromObject(value);
				for (int i = 0; i < jArray.size(); i++) {
					if(JSONUtils.isObject(jArray.get(i)) ){
						list.add(json2Map(jArray.get(i)));
					}else if ( JSONUtils.isArray(jArray.get(i))){
						list.add(json2List(jArray.get(i)));
					}else {
						list.add(jArray.get(i));
					}
				}
				map.put(key, list);
			} else {
				map.put(key, ConvertUtil.obj2Str(object.get(key)));
			}
		}
		return map;
	}

二、接口的开发

2.1 接口一:左侧菜单显示

该接口主要实现的功能是:将json传递过来的数据到展示到前台页面,主要是左侧菜单的三个按钮。

代码如下:

public class LeftMenuListServlet extends HttpServlet {
    private static final long serialVersionUID = -169633978370129408L;
    private Logger logger = Logger.getLogger(this.getClass());
    private SuperviseService superviseService = (SuperviseService) ApplicationContextProvider.getBean("superviseService");

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//        response.setContentType("application/x-www-form-urlencoded");
        response.setContentType("text/html;charset=UTF-8");
        request.setCharacterEncoding("UTF-8");
//        //获取入参
        String loginUserId = ConvertUtil.obj2Str(request.getSession(true).getAttribute(CurrencyVariable.SESSION_KEY_USER_ID));

        MDC.put("user", loginUserId);
        MDC.put("sessionid", request.getSession().getId());
        MDC.put("starttime", System.currentTimeMillis());

        String opCode = "code_0001_0018_0001_0003";
        MDC.put("opcode", opCode);

        ResultJson resultJson = new ResultJson();

        try {
            String json = request.getParameter("json");
            if (StringUtils.isBlank(json)) {
                resultJson.setEc(CurrencyVariable.EC_PARAMETER_EXCEPTION);
                resultJson.setEm(CurrencyVariable.EM_PARAMETER_EXCEPTION);
            } else {
//                设置入参
                Map jsonMap = JsonUtil.json2Map(json);
                Map dataMap = (Map) jsonMap.get("data");
                String bottomTab = (String) dataMap.get("bottomTab");
                String headerTab = (String) dataMap.get("headerTab");
                Object currentUserId = loginUserId;
                logger.info("code_0001_0018_0001_0002");
                logger.info("\t currentUserId = " + currentUserId);

                resultJson = superviseService.leftMenulist(opCode, loginUserId, bottomTab,headerTab);
                resultJson.setOpCode(opCode);
            }
        } catch (Exception e) {
            logger.error("参数异常 ", e);
            resultJson.setEc(CurrencyVariable.EC_PARAMETER_EXCEPTION);
            resultJson.setEm(CurrencyVariable.EM_PARAMETER_EXCEPTION);
        }

//        Gson gson = GsonUtil.getGson();
//
//        String newsResultJson = gson.toJson(resultJson);
        String newsResultJson = new GsonBuilder().serializeNulls().create().toJson(resultJson);

        logger.info(opCode + " newsResultJson==" + newsResultJson);
        response.getOutputStream().write(newsResultJson.getBytes("UTF-8"));
        //业务逻辑结束。。。
        MDC.put("endtime", System.currentTimeMillis());//请求结束后put
//        logger.info("操作结果:"+resultJson.getEc());
        logger.log(SeriousLogger.SERIOUS_LEVEL, "操作结果:" + resultJson.getEc());
    }
}

//service方法如下:
@Override
    public ResultJson leftMenulist(String opCode, String loginId,
            String bottomTab, String headerTab) {
        CloseableHttpClient httpClient = getHttpClient();
        ResultJson resultJson = new ResultJson();
        resultJson.setOpCode(opCode);
        // resultJson.setData(jsonObject.get("data"););
        CloseableHttpResponse httpResponse = null;
        HttpPost post = new HttpPost(SUPERWISE_HOST + LEFT_MENU_LIST_PATH);
        log.info(post.getURI());
        List<NameValuePair> list = new ArrayList<NameValuePair>();

        // 封装入参
        list.add(new BasicNameValuePair("bottomTab", bottomTab));
        list.add(new BasicNameValuePair("loginId", loginId));
        list.add(new BasicNameValuePair("headerTab", headerTab));

        // 重写ec,em
        Common.util(httpClient, resultJson, httpResponse, post, list);

        return resultJson;
    }

这里解释一下opCode。该项目的设计思想是通过OpCode来访问servlet,提高访问速度,有利于后期项目的维护,具体的配置在web.xml中可见:

首先定义opcode使之指向要访问的servlet如:

//左侧菜单
public static final String code_0001_0018_0001_0003 = "/mobileoa/web/servlet/duban/LeftMenuListServlet.do";

然后通过反射的方式加载此类

static{
try{
Class<?> c = Class.forName("com.thitect.middletier.mobileoa.util.ForwardCtrlVariable");
  Field[] fields = c.getDeclaredFields();
  for (int i = 0; i < fields.length; i++) {
  String m = Modifier.toString(fields[i].getModifiers());
  if (m != null && m.indexOf("final") > -1 && !("map".equals(fields[i].getName()))) {
    map.put(fields[i].getName(), (String) fields[i].get(String.class));
  }
}
  }catch (ClassNotFoundException e){
    log.error("ForwardCtrlVariable:",e);
  }catch (IllegalArgumentException e){
    log.error("ForwardCtrlVariable:",e);
  }catch (IllegalAccessException e){
    log.error("ForwardCtrlVariable:",e);
}

获得opcode值,从而访问servlet,web.xml中的配置如下:

<servlet>
<servlet-name>dubanLeftMenuListServlet</servlet-name>
<servlet-class>com.thitect.middletier.mobileoa.web.servlet.duban.LeftMenuListServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>dubanLeftMenuListServlet</servlet-name>
<url-pattern>/mobileoa/web/servlet/duban/LeftMenuListServlet.do</url-pattern>
</servlet-mapping>

Common中util方法主要是对http请求进行了封装,关于http请求的实现方法,参见文章:http://www.cnblogs.com/10158wsj/p/6767209.html

public class Common {
    private static final Logger log = Logger.getLogger(Common.class);
    static ResultJson util(CloseableHttpClient httpClient, ResultJson resultJson, CloseableHttpResponse httpResponse, HttpPost post, List<NameValuePair> list) {
        try {
            UrlEncodedFormEntity uefEntity = new UrlEncodedFormEntity(list, "UTF-8");
            post.setEntity(uefEntity);
            httpResponse = httpClient.execute(post);
            HttpEntity entity = httpResponse.getEntity();
            String s = EntityUtils.toString(entity);

            JSONObject jsonObject = JSONObject.fromObject(s);
            log.info(jsonObject);
            Object result = jsonObject.get("data");
            resultJson.setData(result);
            String ec = (String) jsonObject.get("ec");
            if (ec.equals("0001")) {
                resultJson.setEc(CurrencyVariable.EC_DUBAN_NOEXIST);
                resultJson.setEm(CurrencyVariable.EM_DUBAN_NOEXIST);
            }
            if (ec.equals("0002")) {
                resultJson.setEc(CurrencyVariable.EC_DUBAN_EXCEED);
                resultJson.setEm(CurrencyVariable.EM_DUBAN_EXCEED);
            }
            if (ec.equals("0003") || ec.equals("0005")) {
                resultJson.setEc(CurrencyVariable.EC_DUBAN_DBERROR);
                resultJson.setEm(CurrencyVariable.EC_DUBAN_DBERROR);
            }
            if (ec.equals("0004")) {
                resultJson.setEc(CurrencyVariable.EC_DUBAN_EXCEPTION);
                resultJson.setEm(CurrencyVariable.EC_DUBAN_EXCEPTION);
            }

            EntityUtils.consume(entity);
            if (ec.equals("0000")) {
                resultJson.setEc(CurrencyVariable.EC_SUCESS);
                resultJson.setEm(CurrencyVariable.EM_SUCESS);
                resultJson.setData(result);

            }
        } catch (Exception e) {
            e.printStackTrace();
            resultJson.setEc(CurrencyVariable.EC_RUNTIME_EXCEPTION);
            resultJson.setEm(CurrencyVariable.EM_RUNTIME_EXCEPTION);
        } finally {
            Common.CloseableHttpResponse(httpResponse);
            Common.CloseableHttpClient(httpClient);
        }

        return resultJson;
    }
    private static void CloseableHttpResponse(CloseableHttpResponse httpResponse) {
        if (httpResponse != null) {
            try {
                httpResponse.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private static void CloseableHttpClient(CloseableHttpClient client) {
        if (client != null) {
            try {
                client.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

至此,完成了第一个接口的开发,主要的实现就是这样,后面还陆续写了几个这种类型接口的开发,个人认为这几个接口大同小异,没有必要一一罗列,如图所示:

2.2接口二:图片压缩功能

督办项目中,有一些文件信息十一图片的形式给出的,这就要求前端打开的图片的速度要快,用户体验要好,由于之前没有做图片压缩,导致打开图片事件较长且耗费流量,所以为了实现用户体验,有必要对图片做一下压缩,压缩之后以流的方式进行下载,这个方法是写在action中的也就是struts框架。实现代码如下:

    /**
     * 查看流程意见图片
     */
    public void showNodeOpinionPic(){
        String picURL = request.getParameter("pic_url");
        log.info("流程框架页面:ProcBaseForm_正文表单:查看流程处理意见图片=" + picURL);
        String kmURL = this.getKMHttpUrl();
        String url=kmURL+picURL;
        String fdId = getParamFormUrl(url);
        logger.info("fdId=" + fdId);
        String loginUserId = this.getUserId();
        logger.info("loginUserId=" + loginUserId);
        InputStream ins = null;
        BufferedInputStream bis = null;
        OutputStream out = null;
        HttpServletResponse response = ServletActionContext.getResponse();

        List filePathResultList = oaImageReduceService.getImageList(fdId, url,request);

        try {
            if (filePathResultList != null && filePathResultList.size() > 0) {
                // 下载
                Map<String, Object> filePathMap = (Map) filePathResultList.get(0);
                logger.info("filePathMap===" + filePathMap);
                String filePath = (String) filePathMap.get("file_path");
                if (!filePath.contains(File.separator) && !filePath.contains("/")) {
                    filePath = auditDownloadService.getFileNameByAuditCode(
                            loginUserId, filePath);
                }
                logger.info("filePath===" + filePath);
                if (StringUtils.isNotEmpty(filePath)) {
                    File file = new File(filePath);
                    if (file.exists()) {
                        long p = 0L;
                        long toLength = 0L;
                        long contentLength = 0L;
                        int rangeSwitch = 0; // 0,从头开始的全文下载;1,从某字节开始的下载(bytes=27000-);2,从某字节开始到某字节结束的下载(ex:bytes=27000-39000)
                        long fileLength;
                        String rangBytes = "";
                        fileLength = file.length();
                        logger.info("fileLength Value = " + fileLength);
                        ins = new FileInputStream(file);
                        bis = new BufferedInputStream(ins);
                        response.reset();
                        response.setHeader("Accept-Ranges", "bytes");
                        String range = request.getHeader("Range");
                        logger.info("Range‘s Value = " + range);
                        if (range != null && range.trim().length() > 0
                                && !"null".equals(range)) {
                            response.setStatus(javax.servlet.http.HttpServletResponse.SC_PARTIAL_CONTENT);
                            rangBytes = range.replaceAll("bytes=", "");
                            if (rangBytes.endsWith("-")) { // bytes=270000-
                                rangeSwitch = 1;
                                p = Long.parseLong(rangBytes.substring(0,
                                        rangBytes.indexOf("-")));
                                contentLength = fileLength - p; // 客户端请求的是270000之后的字节(包括bytes下标索引为270000的字节)
                            } else { // bytes=270000-320000
                                rangeSwitch = 2;
                                String temp1 = rangBytes.substring(0,
                                        rangBytes.indexOf("-"));
                                String temp2 = rangBytes.substring(
                                        rangBytes.indexOf("-") + 1,
                                        rangBytes.length());
                                p = Long.parseLong(temp1);
                                toLength = Long.parseLong(temp2);
                                contentLength = toLength - p + 1; // 客户端请求的是270000-320000之间的字节
                            }
                        } else {
                            contentLength = fileLength;
                        }
                        // 如果设设置了Content-Length,则客户端会自动进行多线程下载。如果不希望支持多线程,则不要设置这个参数。
                        // Content-Length: [文件的总大小] - [客户端请求的下载的文件块的开始字节]
                        //response.setHeader("Content-Length",new Long(contentLength).toString());
                        // 断点开始
                        // 响应的格式是:
                        // Content-Range: bytes [文件块的开始字节]-[文件的总大小 - 1]/[文件的总大小]
                        if (rangeSwitch == 1) {
                            String contentRange = new StringBuffer("bytes ")
                                    .append(new Long(p).toString()).append("-")
                                    .append(new Long(fileLength - 1).toString())
                                    .append("/")
                                    .append(new Long(fileLength).toString())
                                    .toString();
                            response.setHeader("Content-Range", contentRange);
                            bis.skip(p);
                        } else if (rangeSwitch == 2) {
                            String contentRange = range.replace("=", " ") + "/"
                                    + new Long(fileLength).toString();
                            response.setHeader("Content-Range", contentRange);
                            bis.skip(p);
                        } else {
                            String contentRange = new StringBuffer("bytes ")
                                    .append("0-").append(fileLength - 1)
                                    .append("/").append(fileLength).toString();
                            response.setHeader("Content-Range", contentRange);
                        }
                        String fileName = file.getName();
                        response.setContentType("application/octet-stream");
                        response.addHeader("Content-Disposition","attachment;filename=" + fileName);
                        out = response.getOutputStream();
                        int n = 0;
                        long readLength = 0;
                        int bsize = 1024;
                        byte[] bytes = new byte[bsize];
                        if (rangeSwitch == 2) {
                            // 针对 bytes=27000-39000 的请求,从27000开始写数据
                            while (readLength <= contentLength - bsize) {
                                n = bis.read(bytes);
                                readLength += n;
                                out.write(bytes, 0, n);
                            }
                            if (readLength <= contentLength) {
                                n = bis.read(bytes, 0,(int) (contentLength - readLength));
                                out.write(bytes, 0, n);
                            }
                        } else {
                            while ((n = bis.read(bytes)) != -1) {
                                out.write(bytes, 0, n);
                            }
                        }
                    } else {
                        logger.info("文件不存在!");
                    }
                }
            }
        } catch (NumberFormatException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 业务处理结束
        if (bis != null) {
            try {
                bis.close();
            } catch (Exception e2) {
            }
        }
        if (ins != null) {
            try {
                ins.close();
            } catch (Exception e2) {
            }
        }
        if (out != null) {
            try {
                out.flush();
                out.close();
            } catch (Exception e2) {
            }
        }
    }

    /**
     * 从url中获取fdId
     */
    private static String getParamFormUrl(String url) {
        String fdId = "";
        if (StringUtils.isEmpty(url)) {
            fdId = null;
        }
        String[] urlArr = url.split("\\?");
        if (urlArr == null || urlArr.length == 0) {
            fdId = null;
        }
        for (int i = 0; i < urlArr.length; i++) {
            if (urlArr[i].contains("FCheckbox=")) {
                String[] params = urlArr[i].split("\\/");
                for (int j = 0; j < params.length; j++) {
                    if (params[j].endsWith(".jpg")) {
                        fdId = params[j].replace(".jpg", "");
                    }
                }
            }
        }
        return fdId;
    }
//service部分代码
@Override
    @Transactional
    public List getImageList(String fdId, String url, HttpServletRequest request) {
        logger.info("services param[fdId="+ fdId + ", url=" + url+ "]");
        List markList = fileDao.findFileByExtendMark(fdId);
        logger.info("markList="+ markList);
        byte[] fileByte = null;
        String fileNameTemp = null;
        if(markList == null || markList.size() == 0){
            fileByte = this.getImageFromURLNew1(url);
            fileNameTemp = this.getNewPicName(fileByte, url);
            logger.info("生成图片名称"+fileNameTemp);
        } else {
            fileNameTemp = (String)((Map)markList.get(0)).get("file_path");
            logger.info("从数据库获取图片信息:" + fileNameTemp);
        }

        List list = fileDao.findChildFileNameByFileName(fileNameTemp, "source");
        logger.info("fileDao.findChildFileNameByFileName(fileNameTemp, ‘source‘)"+list);
        if (list == null || list.size() == 0) {
            list = postfixFileConvertService.postfixConvert(fileNameTemp, CurrencyVariable.FILE_TYPE_SOURCE_TO_IMAGE, true, fileByte, null, null, request, CurrencyVariable.PORTAL, fdId);
        } else {
            list = postfixFileConvertService.postfixConvert(fileNameTemp, CurrencyVariable.FILE_TYPE_SOURCE_TO_IMAGE, true, null, null, null, request, CurrencyVariable.PORTAL, fdId);
        }
        return list;
    }

这段代码基本完成了图片压缩功能的实现,另外通过设置http请求告诉浏览器以流的方式下载图片并显示到前台页页面。

三、总结

这是从学校毕业毕业工作以来,真正意义上接触到的企业大项目,该项目主要的架构就是Spring+Struts+Hibernate,另外还有部分业务的实现用的是Servlet,其实struts本身就是一个大大的Servlet,只不过是更好的对Servlet进行了封装,并且能够更好的实现MVC模式。通过该项目,大大的增加了企业项目的开发经验,熟悉了很多开发工具的使用,本项目采用的是Spring-tools-suitIDE,目的是能够更好的使用Spring。熟悉了代码管理工具SVN的使用,进一步熟悉了开发服务器Weblogic的使用,在linux环境下部署、开发javaWEB项目。

  写这篇博文的目的就是及时把自己的项目经验写出来与大家共勉,也为增加自己的开发经验,进一步熟悉企业项目的开发流程,开发特点。

时间: 2024-10-06 02:33:06

移动办公OA系统的相关文章

智能化办公oa系统是如何体现的?

随着社会信息化的不断进步和向前发展,企业办公也已逐渐步入多元化.办公oa系统说到底是为企业办公服务的,企业业务的扩大与多元化的需求决定了办公oa系统也必须走向智能化,只有这样才能满足企业的办公需求.要想在市场中发展下去就必须跟上时代的脚步,否则下一个淘汰的就是你.说到办公oa系统的智能化,或许你会问"听过智能手机,没听说过智能办公oa系统啊?"今天就来说一说智能化办公oa系统是如何体现的? 首先,办公oa系统实现桌面自动提醒.这里的自动提醒包括,待处理的事务,未读邮件,待处理的计划/任

办公OA系统与故障报修系统的区别

近期青鸟报修云客服经常接到酒店方电话,需要在青鸟报修云报修功能基础上增加物料附件并转交给审批人的定制需求,在这里给大家讲清楚报修系统与OA系统功能区别. 报修系统: 故障报修系统一般是指报修人将故障通过二维码扫码提交给故障处理人,注重的是报修效率,如果增加报修节点审核会大大降低企业的报修效率.所以青鸟报修云作为专业的故障报修系统不支持审批流程开发定制,专注于故障报修. OA系统: 企业OA办公系统注重的是流程审批功能,不同职能部门参与某件事无的审批,注重的是多人协同办公.很显然酒店方应该需要的是

使用 asp.net mv4开发企业级办公OA

大家好!这是我第一次写asp.net 开发笔记,哪里写的不好,请见谅! 本程序是一个在线办公(OA)系统 B/S项目: 项目开发环境:Microsoft Visual Studio 2012 + Sql Server 2008 +Windows 8.1 本人是微软粉... 开发过程中用到的技术:ADO.NET.Ajax.JavaScript.JQuery.HTML.存储过程.三层架构.ASP.NET MVC4.easyui框架 等.. 好了不多说了,先上个今天刚这两天刚做好的成果,如图: 好了,

OA系统市场发展状况深度解析

互联网时代企业办公愈加现代化,OA系统亦开始为越来越多的人所熟知,并普遍应用于企业办公管理.那么,就目前的发展状况来看,OA办公系统市场发展状况又如何呢? 第一.纵观整个OA系统领域不难发现, OA系统从早期由厂商定义概念产品正在向市场所需转变.过去20年,国内有超过2000多家软件企业曾经涉足OA系统软件行业,但在它们当中没有形成具有领导能力的品牌,虽然存在一些主流厂商,但是它们并没有在行业中成为佼佼者,由于不断有新的公司出现,主流厂商面临的竞争力是非常大的,所以即便在经历了惨烈搏杀之后也没有

移动OA系统真的有这么重要?

移动OA系统真的有这么重要?随着企业信息化建设的飞速发展,移动OA系统技术已取得长足的进步.企事业单位纷纷开始选择移动办公系统作为办公平台,系统的作用就在企业中显现的日益重要,主要体现子啊以下几个方面:移动办公系统,主要在办公的便捷性,对于出差跟公出等不在公司办公时,处理公司事务的及时性.移动OA还可以利用碎片时间及时的去处理相关的工作,实现随时随地办公,所以它才会越来越重要.移动办公OA系统能够更快速解决企事业内部的审批流转问题,解决了时间和空间上的限制,提高审批效率,OA系统全面的管理功能,

为啥移动办公oa管理软件能整合企业原有的业务系统?

一般情况下,企业在引入移动办公oa管理软件之前就有了相关的一些业务系统,或是CRM系统,或是oa管理软件等等,所以,引进移动办公oa管理软件最重要的就是要整合企业原有的业务系统,让移动办公oa管理软件与企业的原有系统更好的统一协作,这样才能更加有效的促进企业的发展. 移动办公oa管理软件导入之后第一时间应该处理的问题就是整合问题,只有整合这些oa管理软件才能让移动办公oa管理软件与其他系统更好的融合,人们的工作和使用才会更加顺利.在整合移动办公oa管理软件与企业其他业务系统的时候首先需要全体员工

心理服务OA系统可以解决万人心理测评吗?心理机构办公系统

心理服务的从业者想必都应该知道做咨询并不是最难而复杂的事情,有些比咨询更费时间的其他事情总是让咨询师的时间不够用,比如咨询机构的各种数据分析啦,各种机构管理表格啦,甚至是机构的团体测评这些,而每个机构似乎都应有一套专属的测评软件,这样才能更好的带动机构的整体运转和发展.那么,怎样拥有一套这样的心理测评软件呢? 做心理咨询的难免离不开测评软件,通过一道道测试题实现对来访者心理的了解及认知,更好的方便后续的咨询过程及沟通方向,但是测评软件针对一对一的来访者是非常轻松的问题,但若想实现多人乃至万人的测

整理几个互联网公司常用的概念: SaaS是软件即服务 OA系统 意为办公自动化系统 BOSS指的是业务运营支撑系统 CRM客户关系管理 ERP系统是企业资源计划

整理几个互联网公司常用的概念: 解决以下几个疑问以及容易忘记或者混淆的概念: SaaS系统是什么 OA系统是什么  BOSS系统是什么 CRM系统是什么客户关系管理 ERP系统是什么 SaaS是Software-as-a-Service(软件即服务OA系统是Office Automation System 意为办公自动化系统.BOSS(Business & Operation Support System)指的是业务运营支撑系统CRM(Customer Relationship Manageme

《华油能源OA系统数据同步和扩展的设计与实现_张宇峰》阅读笔记

为什么我会找到这篇论文? 华油能源集团拥有多套信息化软件系统,每个用户需要登录操作多个软件系统,记住多个系统的用户名.密码,需要不停的切换到每个系统,查看是否有需要进行的工作:管理员更是疲于每天对各个软件后台进行部门.人员.密码等信息的维护操作.基于此,华油能源集团有必要对这些系统进行关联整合:各个系统之间的数据同步:各个系统之间的数据的发送扩展:基于一套系统可以登录多套系统的单点登录操作. 我现在项目中遇到的问题就是,如何去整合不同系统中的密码和账号.我需要一个同步机制. 然后,我现在有的系统