运行环境
生产环境: 大众was集群上,部署在2台应用上;
登录:通过大众门户和供应商门户进行单点登录;
用户数:供应商4000+,大众员工100+;
技术选型
lcms采用的典型的SSH框架:
ExtJs + Shiro + SpringMVC + Spring + Hibernate
- ExtJs 4.2
- Shiro 1.2.4
- Spring 3.2.4
- Hibernate 4.2.6
从完整lcms中抽离的基础框架:仅保留系统管理
配置
- web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<display-name>lcms_blank</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:applicationContext*.xml</param-value>
</context-param>
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>/WEB-INF/log4j.properties</param-value>
</context-param>
<context-param>
<param-name>log4jRefreshInterval</param-name>
<param-value>60000</param-value>
</context-param>
<filter>
<filter-name>shiroFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<param-name>targetFilterLifecycle</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter>
<filter-name>openSession</filter-name>
<filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class>
<init-param>
<param-name>singleSession</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>sessionFactoryBeanName</param-name>
<param-value>sessionFactory</param-value>
</init-param>
<init-param>
<param-name>flushMode</param-name>
<param-value>AUTO</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>openSession</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:spring-servlet-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>30</session-timeout>
</session-config>
<login-config>
<auth-method>BASIC</auth-method>
</login-config>
<!--
<error-page>
<error-code>404</error-code>
<location>/pages/exception/404.jsp</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/pages/exception/500.jsp</location>
</error-page>
-->
</web-app>
- applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:task="http://www.springframework.org/schema/task" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee-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/task
http://www.springframework.org/schema/task/spring-task-3.2.xsd"
default-lazy-init="false"
default-autowire="byName">
<description>Spring公共配置 </description>
<context:annotation-config />
<context:component-scan base-package="com.svw.lcms.framework" />
<context:component-scan base-package="com.svw.lcms.common" />
<bean id="SpringContextUtil" class="com.svw.lcms.utils.SpringContextUtil"
lazy-init="false" />
<!-- 定义受环境影响易变的变量 -->
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
<property name="ignoreResourceNotFound" value="true" />
<property name="locations">
<list>
<!-- 数据库配置 -->
<value>classpath*:/application.properties</value>
</list>
</property>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
<prop key="hibernate.show_sql">false</prop>
<prop key="hiberante.format_sql">false</prop>
<prop key="hibernate.hbm2ddl.auto">none</prop>
<prop key="hibernate.generate_statistics">true</prop>
<prop key="hibernate.cache.use_query_cache">true</prop>
<prop key="hibernate.cache.use_second_level_cache">true</prop>
<prop key="hibernate.jdbc.fetch_size">50</prop>
<prop key="hibernate.jdbc.batch_size">25</prop>
<prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</prop>
<prop key="hibernate.cache.configurationResourceName">ehcache.xml</prop>
<prop key="hibernate.current_session_context_class">org.springframework.orm.hibernate4.SpringSessionContext</prop>
<prop key="hibernate.query.factory_class">org.hibernate.hql.internal.ast.ASTQueryTranslatorFactory</prop>
<prop key="hibernate.temp.use_jdbc_metadata_defaults">false</prop>
</props>
</property>
<property name="annotatedClasses">
<list>
<value>com.svw.lcms.common.user.domain.SysUser</value>
<value>com.svw.lcms.common.role.domain.SysRole</value>
<value>com.svw.lcms.common.resources.domain.SysResource</value>
<value>com.svw.lcms.common.dict.domain.SysDict</value>
<value>com.svw.lcms.common.dict.domain.SysDictIdx</value>
</list>
</property>
</bean>
<!-- 事务管理器配置,单数据源事务 -->
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" />
<!-- shiro -->
<bean id="shiroService" class="com.svw.lcms.framework.realm.ShiroService">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<!-- 凭证匹配器 -->
<bean id="credentialsMatcher" class="com.svw.lcms.framework.realm.CustomCredentialsMatcher">
</bean>
<!-- realm -->
<bean id="realm" class="com.svw.lcms.framework.realm.Realm">
<property name="shiroService" ref="shiroService"></property>
<property name="credentialsMatcher" ref="credentialsMatcher"></property>
</bean>
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="realm"></property>
</bean>
<!-- shiro 权限控制 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager"></property>
<property name="loginUrl" value="/welcome.do"></property>
<property name="successUrl" value="/pages/login/welcomeaaa.do"></property>
<property name="unauthorizedUrl" value="/pages/common/unauthorized.jsp"></property>
<property name="filterChainDefinitions">
<value>
/js/** = anon
/selectyze/** = anon
/other/** = anon
/image/** = anon
/css/** = anon
/zTree/** = anon
/favicon.ico = anon
/welcome.do = anon
/login.do = anon
<!-- 其他链接必须授权 -->
/** = authc
</value>
</property>
</bean>
<!-- 事务控制 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- 对get/load/search开头的方法要求只读事务 -->
<tx:method name="get*" propagation="SUPPORTS" read-only="true" />
<tx:method name="load*" propagation="SUPPORTS" read-only="true" />
<tx:method name="search*" propagation="SUPPORTS" read-only="true" />
<tx:method name="query*" propagation="SUPPORTS" read-only="true" />
<tx:method name="find*" propagation="SUPPORTS" read-only="true" />
<!-- 对其它方法要求事务 -->
<tx:method name="*" propagation="REQUIRED" />
</tx:attributes>
</tx:advice>
<aop:config proxy-target-class="true">
<aop:pointcut id="bussinessService"
expression="execution(* com.svw.lcms..services..*.*(..))" />
<aop:advisor pointcut-ref="bussinessService" advice-ref="txAdvice" />
</aop:config>
<task:executor id="executor" pool-size="5" />
<task:scheduler id="scheduler" pool-size="10" />
<task:annotation-driven executor="executor"
scheduler="scheduler" />
<!--基于@AspectJ切面的驱动器,如果没有这句话 切面的代码是不会执行的 -->
<aop:aspectj-autoproxy />
</beans>
- applicationContext-datasource.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd"
default-lazy-init="true">
<description>Spring 数据源配置 </description>
<!-- JNDI
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="resourceRef" value="true"/>
<property name="jndiName"><value>jdbc/lcms</value></property>
</bean>
-->
<!-- JDBC -->
<bean id="dataSource" class="oracle.jdbc.pool.OracleDataSource" destroy-method="close">
<property name="dataSourceName" value="ORCL" />
<property name="URL" value="jdbc:oracle:thin:@localhost:1521:ORCL" />
<property name="user" value="LCMS" />
<property name="password" value="LCMS" />
</bean>
</beans>
- spring-servlet-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd">
<context:component-scan base-package="com.svw.lcms.framework.controller" />
<context:component-scan base-package="com.svw.lcms.common.base.controller" />
<context:component-scan base-package="com.svw.lcms.common.user.controller" />
<context:component-scan base-package="com.svw.lcms.common.role.controller" />
<context:component-scan base-package="com.svw.lcms.common.dict.controller" />
<context:component-scan base-package="com.svw.lcms.common.resources.controller" />
<!-- 拦截器配置 -->
<mvc:annotation-driven />
<!-- resource -->
<mvc:resources location="/WEB-INF/js/" mapping="/js/**"/>
<mvc:resources location="/WEB-INF/style/image/" mapping="/image/**"/>
<mvc:resources location="/WEB-INF/style/css/" mapping="/css/**"/>
<mvc:resources location="/WEB-INF/style/zTree/" mapping="/zTree/**"/>
<mvc:resources location="/WEB-INF/js/selectyze/" mapping="/selectyze/**"/>
<mvc:resources location="/WEB-INF/js/other/" mapping="/other/**"/>
<!-- 视图解析器 -->
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="utf-8" />
<property name="maxUploadSize" value="10485760000" />
<property name="maxInMemorySize" value="40960" />
</bean>
<!-- 显示用消息设定 -->
<bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<!-- 国际化信息所在的文件名 -->
<property name="basenames">
<list>
<value>classpath:internationalization/messages</value>
</list>
</property>
</bean>
<!-- 消息处理工具类 -->
<bean class="com.svw.lcms.framework.i18n.CustomMessageSource" lazy-init="false">
<constructor-arg ref="messageSource" />
</bean>
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="messageConverters">
<list>
<bean
class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
</bean>
</list>
</property>
</bean>
</beans>
代码封装
由于是简易的框架,且开发人员比较多,类的命名、方法命名以及开发习惯的不同,故底层只封装了 BaseDao和BaseController。
后面的个人blank中进一步封装了EntityService.
后端
baseDao: 简单的增删改查、翻页组件
baseController:简单的request封装、同一异常处理(基于@ExceptionHandler异常处理)
AbstractBaseValidator: 通用的后端验证,基于org.springframework.validation.Validator
- MultiFileService: 通用文件上传下载服务,基于SpringMVC的MultipartFile
- BaseFileService: 通用文件上传下载服务,基于文件流
- ExcelCommitUtil: 通用Excel导入验证,验证失败则返回原Excel文件,并把有问题单元格标记颜色,同时添加出错原因批注
- FileOperateUtil:通用Excel导出
- QuartzManager: 基于Quartz的定时任务管理
- IStatementCallback:自定义jdbc批处理(回调)
- Token: 防重复提交
前端
- ExtJs 4.2: 翻页列表控件
- jquery.validity.js : jQuery表单验证插件
- autoMultiple.js:自动完成插件
- laydate.js:通用日期控件
- jquery.ztree.core-3.5.js: jQuery 树插件
- exportLoading:自定义jQuery导出进度
- Selectyze:选择列表美化插件