zoukankan      html  css  js  c++  java
  • 移动办公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(Current.SESSION_KEY_USER_ID));
    
            MDC.put("user", loUserId);
            MDC.put("sessionid", request.getSession().getId());
            MDC.put("starttime", System.currentTimeMillis());
    
            String opCode = "code_0001_0018_0001";
            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_0002");
                    logger.info("	 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);
            }
            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_0001 = "/mobileoa/web/servlet/dd/LeftMListServlet.do";

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

    static{
    try{ 
    Class<?> c = Class.forName("com.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.dd.LeftMListServlet</servlet-class>
    </servlet>
    <servlet-mapping>
    <servlet-name>ddLeftMenuListServlet</servlet-name>
    <url-pattern>/mobileoa/web/servlet/dd/LeftMListServlet.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项目。

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

  • 相关阅读:
    gitlab 启用HTTPS
    centos7 部署 汉化版 gitlab 10.0.2
    前端常见跨域解决方案(全)
    [转]用python爬虫抓站的一些技巧总结 zz
    【转】通用权限管理设计 之 数据权限
    【转】通用权限管理设计 之 功能权限设计
    JavaScript数据结构和算法
    Vue.js 插件开发详解
    wdcpV3面板安装ssl证书 apache教程 子站SSL配置
    [POJ-2823] -Sliding Window
  • 原文地址:https://www.cnblogs.com/10158wsj/p/7044789.html
Copyright © 2011-2022 走看看