11月接了两个小项目的开发任务,时间有点紧,代码还有很多可以优化的地方
项目需求:
前台加后台项目前台提过一个可控制用户权限的访问页面,管理员通过特定的权限访问属于自己权限范围之内的数据,并可按时间进行检索并提供EXCEL下载。
项目框架
Springmvc+MyBatis+jxl
技术重点:下载实现踩的坑,Mybatis 分页踩的坑以及junit,缓存的应用,Linux系统操作
需求分为两个部分,一个是记录的数据,这个部分在用户登陆系统中实现,一个为提供页面,传统的curd。
我犯的第一个错误,在提供下载的时候。因为需要使用EXCEL,所以我选择了jxl来生成excel,它最关键的是需要获取服务器中response的outstrem进行响应,但是奇怪的事情来了,不管在哪个系统下进行操作,每当jxl的workbook.close这一步操作的时候,服务器都会报出connect:reset的错误,连接被重置,出现这种情况一般都是服务器关闭了,客户端还在操作,如果此时客户端正在从Socket套接字的输出流中读数据则会提示Connection reset”;服务器返回了“RST”时,如果此时客户端正在往Socket套接字的输入流中写数据则会提示“Connection reset by peer”。但是这在我这个项目里是不存在这个问题的,使用springmvc框架,在没有返回响应的界面之前,我认为我的服务并没有关闭,所以,我怀疑是不是在jxl内部出现了什么问题,因为时间紧,没有去找jxl的源码,想了一个折中的点子。Workbook生成不是需要一个流吗,然后通过这个流输入到response里面去,那好,我先将excel文件生成之后,放在服务器的一个临时目录,然后再单独起一个fileinputStream去读这个文件,将读到的文件写入到response中去,这样避免了直接将response包装到workBook中去造成的Exception无法处理的情况。做完这一步之后,测试发现依然会出异常,但是异常居然是出现在response.write()这一步,当时觉得有点无力,想了两个解决办法,第一个,将下载这个功能单独起一个servlet,脱离srpingMVC框架,这么做的目的,是为了获取原生态的
httpServletrResponse,还有一个方法,仔细在网上查了查,springMVC 框架对于下载有一种实现方式ResponseEntity<byte[]> cEntity,我首先选择的是ResponseEntity<byte[]>cEntity这种方式,但是依然会报错,而且,还是同样的错误。好,我改成了servlet,错误依旧。当时有一种想崩溃的心情。冷静了很久之后,重点来了:
我在前台jsp做了一件事情,我之前的提交方式是windows.location=XXX,这种方式
然后,我把这个地址加入到了一个A标签,href=XXX..然后,可以下载了。。。当时有一万匹那什么在心中奔腾。。。
Mybatis,是我在逐渐熟悉的一个框架,网上对它的诟病在于,它使用的是逻辑分页,如果数据大的话,那么它提供的rowBounds几乎没有用,网上能找到许多对它的分页插件。分页插件的实现都是基于每个数据库的分页语言进行分页,ORACLE加rowNum,mySQL加入limit等等。
于是我下来了一个,并按照它的使用方式调用:
List<CertRegion> CertRegions =session.selectList("xx.xx.xx.CertRegionMapper.selectByDate", dates,rowBounds);
表面上看真的没有什么问题,直到我在一个页面上反复刷新个7,8次,,突然发现,页面卡住不动了,查后台,没报错,加入log4j 进行Debug,发现了这么一句话, Spring Fiting JDBCResoure(可能拼的不准了,按记忆来的),那么这就说明了是数据库连接没有释放。Mybatis查询一般都是按接口来操作的,所以采用声明式事物就可以处理了,可现在是按照sqlSession在操作,那就需要手动提交!可是,如果并发刚好达到8个,连接还没来的释放,怎么办?
咨询了一些朋友,他们的建议是,在sql动态拼接分页语句,而摒弃session.selectList这种做法。(这个地方需要再研究一下)。顺便提一下,在页面上显示的页面的总数的算法和当前页面的算法是数据数量/每页数量余数大于0则为结果+1,等于0为结果。
缓存 的使用体现在,我的需求是需要记录用户的使用频率,然后按天进行查询,那么简单了,用户登录一次,我就记录一次,如果当天登录无数次,我也只用记录一次,在第二天的凌晨将缓存中的数据定时扫入我需要的表中即可。之前在设计的时候,还考虑过定时将内存中的数据持久化成文件,但是时间太紧,没来得及实现。
Linux系统的操作没什么好说的,值得注意的是:如果要在linux中监听一个端口,那么仅仅在tomcat中对其进行配置是远远不够的,如果linux开启了防火墙,还需要对防火墙进行操作:
/sbin/iptables -I INPUT -p tcp --dport 8000 -j ACCEPT #开启8000端口
/etc/rc.d/init.d/iptables save #保存配置
/etc/rc.d/init.d/iptables restart #重启服务
附:mybatis对date的映射,默认会用yyyy-MM-ddhh:mm:ss的格式,如果不想用这个格式进行,我的解决办法是通过to_char的方式查询出数据,然后在实体类对该字段定义为String类型,再完成映射。
<result property="cert_optime" column="cert_optimes" javaType="String"/>
<![CDATA[ select id, cert_sn,cert_region,to_char(cert_optime,'YYYY-MM-DD')cert_optimes,....