[项目摘要] 发电厂安全培训管理系统摘要 MySql 授权和权限撤销操作 http://www.cnblogs.com/qlqwjy/p/8022575.html 在 windows 下注册 tomcat 服务并设置 jvm 参数
第一个项目开发也有将近半年了,这也是自己的第一个比较成熟的系统,项目从刚开始的8个人到最后的三个人,开发团队的人也越来越少,系统也越来越成熟。中间开发也遇到了大量的问题,尤其在开发考试与试卷管理,由于界面交互太复杂一个JS可以上千行。17年11月中旬系统的第一次上线,我带着服务器到机房给客户安装部署好之后,客户的需求发生了很大的变化,直到18年元旦之后,系统才算正式开发完成,中间在客户的地方开发了将近20天,每天与客户沟通完需求之后进行开发,同时也要不停的修改别的代码,也真正理解到清晰的思路与清晰的代码的重要性,指不定哪天别人会修改你的代码,所以最好是将代码写的清除点,乱七八糟的代码容易暴露自己的实力。项目也逐渐成熟,直到项目后期才真正使用上git,刚开始人多只是不停的写代码,写完之后手动合并代码浪费了大量的时间。到客户的地方开发才使用上git,也理解了git的强大。
项目也学会了POI导出excel、iText导出pdf、jacob将word转为pdf、freemarker导出带格式的word以及利用jsoup在后台解析html标签。windows远程桌面访问、Teamview远程桌面访问。也学会了自己封装一些常用的工具类。
一、项目描述
开发环境:Eclipse+Jdk1.7+Git+Spring3.2+struts2.3+mybatis3.2+shiro1.3+mysql 5.7
前台技术:bootstrap+Easuui的分页插件+zTree树插件+jedate日期插件+kindeditor文本编辑器插件+其他
硬件:研腾身份证识别仪、南昊判卷机、指纹识别仪、人脸识别仪
项目描述:电厂安全培训管理系统是一个用于电厂进行培训的系统,主要是考试与成绩管理。考试可以分为在线考试与线下考试,在线考试就是登录系统之后在线考试,考完之后系统自动给出成绩,线下考试是将试卷导出成pdf进行线下考试,并用判卷机进行判卷之后将成绩导入系统。辅助的功能有部门管理与人员管理、违章管理。权限管理是系统的一大难点,采用了shiro框架,对不同的用户显示不同的菜单与显示界面上不同的按钮,也就是不同的用户可以看见不同的菜单,也可以看见不同的按钮。
菜单后台主界面:(主要模块)
二、前台总结:
前台技术:bootstrap+Easuui的分页插件+zTree树插件+jedate日期插件+kindeditor文本编辑器插件+其他
前台主要是bootstrap,分页统一用的是EasyUi的分页插件(使用参考:http://www.cnblogs.com/qlqwjy/p/7816707.html),树用的zTree插件(使用参考:http://www.cnblogs.com/qlqwjy/p/7351604.html),编辑器用的是kindeditor(使用参考:http://www.cnblogs.com/qlqwjy/p/7637386.html)。日期插件用的jeDate的日期插件。
前台学到最多的是jQuery的使用以及ajax的使用,项目中大量的使用异步请求数据,使用了jQuery封装的三种ajax:
前台学到的主要开发思想:打开模态框之前清除之前的废旧数据,分页点击的时候带着条件去查询(将当前页与页大小存到页面的隐藏域),有时候reset按钮不能清空隐藏域,最可靠的办法就是将需要被清空的东西加个特殊的class,点击清除的时候清空所有的带class的。
--------------------jQuery封装的三种ajax:---------------------------------
第一种: $.ajax
$.ajax({
url : contextPath + '/exam_getEmployeeIns4Exam.action',
data : $("#queryInnerForm").serialize(),
type : 'POST',
dataType : 'json',
success : showEmployeeInModal,
error : function() {
alert("查询内部员工出错!!!")
}
});
第二种:$.post
$.post(baseurl + '/distribute_getUnitInfoByBigIdAndUnitId.action', { "unitId" : unitId, "bigId" : bigId }, function(response) { var unit = response.unitInfo; $("#unitTbody").html(""); $("#unitTbody").append( '<tr><td>' + treeNode.name + '</td><td>' + unit.manager + '</td><td>' + unit.managerPhone + '</td><td>' + unit.secure + '</dh><td>' + unit.securePhone + '</td><td>' + unit.projectNames + '</td><td>' + unit.perNum + '</td><td>' + unit.unitMinisMum + '</td></tr>'); $("#unitInfoDiv").css("display", "block"); }, 'json')
第三种: $.get
$.get( "/Ajax/ajaxServlet2", //请求地址 //"name=qlq&password=qlq", //请求参数 {"name":"qlq","password":"nicai"}, //请求传递的参数,也可以是JSON function(data){ //data表示传递回来的数据,只有在成功的时候才有 alert(data); }, "json" //表示返回内容的格式,json会将传回来的自动解析成json对象 );
参考:http://www.cnblogs.com/qlqwjy/p/7357073.html
------------常用的jQuery的选择器=---------------------------------
参考:http://www.cnblogs.com/qlqwjy/p/7491721.html
三、后台总结:
后台技术:Eclipse+Jdk1.7+Git+Spring3.2+struts2.3+mybatis3.2+shiro1.3+mysql 5.7
后台用的技术主要就是SSM框架+Shiro,项目刚开始的时候是分模块开发,也没有使用上git,都是手工的合称代码。直到项目的后期才使用上git,也真正了解到git的作用(git 的使用参考:http://www.cnblogs.com/qlqwjy/p/7577381.html)
。spring主要用到了spring的IOC和AOP,IOC主要用来管理项目的对象,AOP用在事务管理。IOC主要使用基于注解方式的配置,AOP采用XML配置。(spring事务配置参考:http://www.cnblogs.com/qlqwjy/p/7296493.html)。struts采用页面跳转与json结合的方式,struts与json结合主要是struts的package继承json-default。剩下的json转换交给struts。mybatis开发采用动态代理的方式,简单的写一下接口然后在xml中实现即可。spring与struts整合主要是将struts创建对象的一个常量配置为spring:<constant name="struts.objectFactory" value="spring"></constant>,剩下的配置spring扫描struts的包就行了,struts的配置只用写类名(第一个字母小写)。后台在Action层对异常的捕捉以及对日志的记录非常重要,在部署之后可以通过日志查看错误信息
0.dp.properties
;;;;;;;;;;;;;;;;;;;;
;DataBaseConnection;
;;;;;;;;;;;;;;;;;;;;
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/exam9
jdbc.username=root
jdbc.password=123456
jdbc.initialPoolSize=10
jdbc.minPoolSize=5
jdbc.maxPoolSize=30
jdbc.maxIdleTime=200
jdbc.maxStatementsPerConnection=50
1.Spring框架的配置:
大致的配置过程:
配置数据库配置文件存放位置、将连接池放入spring容器(数据源)、配置mybatis会话工厂、配置mybatis扫描的基本包、配置事务管理器、配置事务模板对象、配置事务通知、将通知织入切面、配置扫描service与Action的包
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd "> <!-- 0.连接池属性设置读取指定的properties文件 --> <context:property-placeholder location="classpath:db.properties" /> <!-- 1.将连接池放入spring容器 --> <bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> <property name="jdbcUrl" value="${jdbc.url}"></property> <property name="driverClass" value="${jdbc.driver}"></property> <property name="user" value="${jdbc.username}"></property> <property name="password" value="${jdbc.password}"></property> <property name="initialPoolSize" value="${jdbc.initialPoolSize}"></property> <property name="minPoolSize" value="${jdbc.minPoolSize}"></property> <property name="maxPoolSize" value="${jdbc.maxPoolSize}"></property> <property name="maxIdleTime" value="${jdbc.maxIdleTime}"></property> <property name="maxStatementsPerConnection" value="${jdbc.maxStatementsPerConnection}"></property> </bean> <!--2. 配置 Mybatis的会话工厂 --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!-- 数据源 --> <property name="dataSource" ref="dataSource" /> <!-- 配置Mybatis的核心 配置文件所在位置 --> <property name="configLocation" value="classpath:mybatis/SqlMapConfig.xml" /> </bean> <!-- 3.1 mapper代理配置方法一 这种方法需要大量重复的配置代理对象 MapperFactoryBean:根绝mapper接口生成代理对象 <bean id="selectUser" class="org.mybatis.spring.mapper.MapperFactoryBean"> <property name="mapperInterface" value="cn.qlq.core.dao.SelectUser"></property> <property name="sqlSessionFactory" ref="sqlSessionFactory"></property> </bean> --> <!-- 3.2通过MapperScannerConfigurer扫描进行批量生成代理对象 遵循规范:mapper.java和mapper.xml名字一样且在同一个目录下 自动扫描出来的代理对象的id为mapper类类名(首字母小写) --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <!-- 指定扫描的包名,如果有多个,用半角逗号分隔 --> <property name="basePackage" value="cn.xm.exam.mapper"></property> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property> </bean> <!-- 4.配置事务管理器 --> <!-- 事务核心管理器,封装了事务操作,依赖于连接池 --> <bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 5.开启注解管理aop事务 --> <tx:annotation-driven /> <!-- 事务模板对象,依赖于事务核心管理器 --> <bean name="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate"> <property name="transactionManager" ref="transactionManager"></property> </bean> <!-- ················开始使用XML管理事务························ --> <!-- 配置事务通知(无论哪种方式都要用到事务的核心管理器) --> <tx:advice transaction-manager="transactionManager" id="firstTx"> <tx:attributes> <!--以方法为单位,指定方法应用事务什么属性 isolation:隔离级别 read-only:只读属性 propagation:传播行为 --> <!-- 企业中运用通配符命名规则。两套增删改查(8种) --> <tx:method name="save*" isolation="DEFAULT" read-only="false" propagation="REQUIRED" /> <tx:method name="add*" isolation="DEFAULT" read-only="false" propagation="REQUIRED" /> <tx:method name="delete*" isolation="DEFAULT" read-only="false" propagation="REQUIRED" /> <tx:method name="remove*" isolation="DEFAULT" read-only="false" propagation="REQUIRED" /> <tx:method name="update*" isolation="DEFAULT" read-only="false" propagation="REQUIRED" /> <tx:method name="modify*" isolation="DEFAULT" read-only="false" propagation="REQUIRED" /> <tx:method name="get*" isolation="DEFAULT" read-only="true" propagation="REQUIRED" /> <tx:method name="find*" isolation="DEFAULT" read-only="true" propagation="REQUIRED" /> </tx:attributes> </tx:advice> <!-- 配置织入 --> <aop:config> <!-- 配置切点表达式 --> <aop:pointcut expression="execution(* cn.xm.exam.service.impl.*.*ServiceImpl.*(..))" id="texPc" /> <!-- 配置切面:切点+通知 advice-ref:通知名称 pointcut-ref:切点名称 --> <aop:advisor advice-ref="firstTx" pointcut-ref="texPc" /> </aop:config> <aop:config> <!-- 配置切点表达式 --> <aop:pointcut expression="execution(* cn.xm.exam.service.impl.*.*.*ServiceImpl.*(..))" id="secondPc" /> <!-- 配置切面:切点+通知 advice-ref:通知名称 pointcut-ref:切点名称 --> <aop:advisor advice-ref="firstTx" pointcut-ref="secondPc" /> </aop:config> <!-- 5.开启组件自动扫描,也就是启用注解。前提是导入spring-context-3.2.xsd约束和引入新的命名空间 --> <context:component-scan base-package="cn.xm.exam.service"></context:component-scan> <!-- 6与struts2整合的配置 --> <!-- 扫描Action基本包 --> <context:component-scan base-package="cn.xm.exam.action"></context:component-scan> </beans>
2.mybatis配置:
SqlMapConfig.xml(主配置)开启二级缓存与配置别名
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <settings> <!-- 开启二级缓存 --> <setting name="cacheEnabled" value="true" /> </settings> <!-- 只需要定义个别名,这个应该有 --> <typeAliases> <package name="cn.xm.exam.bean.common" /> <package name="cn.xm.exam.bean.employee" /> <package name="cn.xm.exam.bean.employee.in" /> <package name="cn.xm.exam.bean.employee.out" /> <package name="cn.xm.exam.bean.exam" /> <package name="cn.xm.exam.bean.grade" /> <package name="cn.xm.exam.bean.question" /> <package name="cn.xm.exam.bean.system" /> <package name="cn.xm.exam.bean.trainContent" /> </typeAliases> </configuration>
与接口对应的mapper(开启二级缓存)
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace="cn.xm.exam.mapper.exam.custom.ExampaperCustomMapper"> <!-- 开启二级缓存 --> <cache type="org.mybatis.caches.ehcache.EhcacheCache" /> <!-- S 分页查询试卷基本信息 --> <!-- SELECT COUNT(paperId) FROM exampaper WHERE title LIKE '%阳城%' AND LEVEL=1 --> <select id="getPaperTotalByCondition" parameterType="hashmap" resultType="int"> SELECT COUNT(paperId) FROM exampaper <where> <include refid="query_papaer_where"></include> </where> </select> <select id="findPapersByCondition" parameterType="hashmap" resultType="cn.xm.exam.bean.exam.Exampaper"> SELECT * FROM exampaper <where> <include refid="query_papaer_where"></include> </where> ORDER BY MAKETIME DESC <include refid="query_paper_limit"></include> </select> <!--S 查询条件 --> <!-- 查询试卷条件 --> <sql id="query_papaer_where"> <if test="title!=null"> and title like '%${title}%' </if> <if test="departmentId != null"> AND departmentId=#{departmentId} </if> <if test="level!=null"> and level=#{level} </if> </sql> <!--分页条件 --> <sql id="query_paper_limit"> <if test="index!=null"> LIMIT #{index},#{currentCount} </if> </sql> <!--E 查询条件 --> <!--E 分页查询试卷基本信息 --> <!-- S 查询一份试卷完整信息 --> <!-- 试卷映射map --> <resultMap type="cn.xm.exam.bean.exam.Exampaper" id="paperAllInfo"> <!-- 试卷基本信息 --> <id column="paperId" property="paperid" /> <result column="paperScore" property="paperscore" /> <result column="maketime" property="maketime" /> <result column="level" property="level" /> <result column="employeename" property="employeename" /> <result column="title" property="title" /> <result column="usetimes" property="usetimes" /> <result column="description" property="description" /> <!-- 大题 --> <collection property="bigQuestions" ofType="cn.xm.exam.bean.exam.Bigquestion"> <id column="bigquertionid" property="bigquertionid" /> <result column="paperid" property="paperid" /> <result column="bigquestionname" property="bigquestionname" /> <result column="bigquestionsequence" property="bigquestionsequence" /> <!-- 题 --> <collection property="questions" ofType="cn.xm.exam.bean.exam.Exampaperquestion"> <id column="questionid" property="questionid" /> <result column="paperid" property="paperid"></result> <result column="bigquertionid" property="bigquertionid"></result> <result column="questioncontent" property="questioncontent"></result> <result column="questionsequence" property="questionsequence"></result> <result column="type" property="type"></result> <result column="answer" property="answer"></result> <result column="analysis" property="analysis"></result> <result column="score" property="score"></result> <result column="questionsource" property="questionsource"></result