SpringMVC3.0之后的注解配置及RESTful架构可见之前的另一篇帖:springmvc
这里的spring web mvc层的配置采用的就是上篇的配置,所以这里说下spring同mybatis的整合以及其他一些东西。
spring同ibatis的整合是spring提供的,由于mybatis是在spring3.0之后更新的,所以其整合就由mybatis的mybatis-spring.jar自己完成,通过org.mybatis.spring.SqlSessionFactoryBean,配置如下:
<!-- MyBatis配置 --> <bean id="sqlSessionFactory" class="com.minyond.core.common.mybatis.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <!-- 自动扫描entity目录, 省掉Configuration.xml里的手工配置 --> <property name="typeAliasesPackage" value="com.minyond.modules.*.entity"/> <!-- 显式指定Mapper文件位置 --> <property name="mapperLocations" value="classpath:/mybatis/com/minyond/modules/**/mapper/*Mapper.xml"/> </bean> <!-- 扫描basePackage下所有以@MyBatisRepository标识的 接口--> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.minyond.modules" /> <property name="annotationClass" value="com.minyond.core.common.mybatis.MyBatisRepository"/> </bean>
给Dao接口添加自定义注解@MyBatisRepository,*Mapper.xml配置的namespace指定对应接口。
Controller的注解,类上的@Controller@RequestMapping,方法上的@RequestMapping,注入service的@AutoWired;
Service的注解,类上有@Component、@Tranditional,查询方法上有@Traditional(readOnly=true),以及注入dao的@AutoWired;
Dao的注解,类上自定义标识@MyBatisRepository。
spring-mvc.xml的配置见上面说的那帖,下面贴出其他配置
applicationContext.xml
<!-- 使用annotation 自动注册bean,并检查@Required,@Autowired的属性已被注入 --> <context:component-scan base-package="com.minyond.modules"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> <context:exclude-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice"/> </context:component-scan> <!-- MyBatis配置 --> <bean id="sqlSessionFactory" class="com.minyond.core.common.mybatis.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <!-- 自动扫描entity目录, 省掉Configuration.xml里的手工配置 --> <property name="typeAliasesPackage" value="com.minyond.modules.*.entity"/> <!-- 显式指定Mapper文件位置 --> <property name="mapperLocations" value="classpath:/mybatis/com/minyond/modules/**/mapper/*Mapper.xml"/> </bean> <!-- 扫描basePackage下所有以@MyBatisRepository标识的 接口--> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.minyond.modules" /> <property name="annotationClass" value="com.minyond.core.common.mybatis.MyBatisRepository"/> </bean> <!-- 事务管理器配置 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <!-- 使用annotation定义事务 --> <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" /> <!-- produce环境 --> <beans profile="produce"> <context:property-placeholder ignore-resource-not-found="true" location="classpath*:/jdbc.properties" /> <!-- 数据源配置,使用应用内的DBCP数据库连接池 --> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <!-- Connection Info --> <property name="driverClassName" value="${jdbc.driver}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> <property name="defaultAutoCommit" value="false" /> </bean> </beans> <!-- production环境 --> <beans profile="production"> <context:property-placeholder ignore-resource-not-found="true" location="classpath*:/jdbc.properties" /> <!-- 数据源配置,使用应用内的Tomcat JDBC连接池 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> <property name="driverClass" value="${jdbc.driver}"></property> <property name="jdbcUrl" value="${jdbc.url}"></property> <property name="user" value="${jdbc.username}"></property> <property name="password" value="${jdbc.password}"></property> <!-- 详细参数说明参见database-config.properties --> <property name="initialPoolSize" value="${c3p0.initialPoolSize}"></property> <property name="minPoolSize" value="${c3p0.minPoolSize}"></property> <property name="maxPoolSize" value="${c3p0.maxPoolSize}"></property> <property name="maxIdleTime" value="${c3p0.maxIdleTime}"></property> <property name="acquireIncrement" value="${c3p0.acquireIncrement}"></property> <property name="idleConnectionTestPeriod" value="${c3p0.idleConnectionTestPeriod}"></property> <property name="acquireRetryAttempts" value="${c3p0.acquireRetryAttempts}"></property> <property name="breakAfterAcquireFailure" value="${c3p0.breakAfterAcquireFailure}"></property> <property name="maxStatements" value="${c3p0.maxStatements}"></property> <property name="testConnectionOnCheckout" value="${c3p0.testConnectionOnCheckout}"></property> </bean> </beans>
web.xml
<context-param> <param-name>contextConfigLocation</param-name> <param-value> classpath*:/spring/applicationContext.xml, classpath*:/spring/applicationContext-shiro.xml </param-value> </context-param> <context-param> <param-name>spring.profiles.default</param-name> <param-value>produce</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <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-mapping> <filter-name>encodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <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/spring-mvc.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> <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-mapping> <filter-name>shiroFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <listener> <listener-class> org.springframework.web.context.request.RequestContextListener </listener-class> </listener> <session-config> <session-timeout>30</session-timeout> </session-config> <error-page> <exception-type>java.lang.Throwable</exception-type> <location>/WEB-INF/view/error/500.html</location> </error-page> <error-page> <error-code>500</error-code> <location>/WEB-INF/view/error/500.html</location> </error-page> <error-page> <error-code>404</error-code> <location>/WEB-INF/view/error/404.html</location> </error-page>
applicationContext-shiro.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.2.xsd" default-lazy-init="true"> <description>Shiro安全配置</description> <!-- Shiro's main business-tier object for web-enabled applications --> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="realm" ref="shiroRealm" /> </bean> <!-- 項目自定义的Realm --> <bean id="shiroRealm" class="com.minyond.modules.base.system.realm.ShiroRealm" depends-on="userDao"> <property name="userService" ref="userService"/> </bean> <!-- Shiro Filter --> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <property name="securityManager" ref="securityManager" /> <property name="loginUrl" value="/" /> <property name="successUrl" value="/main" /> <property name="filterChainDefinitions"> <value> <!--静态资源直接通过--> /libs/** = anon /login = anon /test = anon /logout = logout /** = authc </value> </property> </bean> <!-- 保证实现了Shiro内部lifecycle函数的bean执行 --> <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/> </beans>
mybatis.com.minyond.modules.base.classroom.mapper.ClassroomMapper.xml
<?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"> <!-- namespace必须指向Dao接口 --> <mapper namespace="com.minyond.modules.base.classroom.dao.ClassroomDao"> <!-- 分页查询 --> <select id="searchClassroom" resultType="map" parameterType="map"> select b.rownum_,a.*,c.name as school_name from bd_classroom a, ( select top ${endRow} row_number() over (order by ${sort} ${direction}) as rownum_,id from bd_classroom <where> <if test="id!=null and id!=''"> id = '${id}' </if> </where> )b,bd_school c where a.id = b.id and a.school_id = c.id and rownum_ >= ${startRow} order by rownum_ asc </select> <!-- 查询总数量 --> <select id="countClassroom" resultType="Integer" parameterType="map"> select count(*) from bd_classroom <where> <if test="id!=null and id!=''"> id = '${id}' </if> </where> </select> <!-- 根据Id查询 --> <select id="getClassroomById" resultType="Classroom" parameterType="Long"> select id, school_id as schoolId,name,code,position,capacity,kind,enabled,remark from bd_classroom where id = #{id} </select> <!-- 新增 --> <insert id="saveClassroom" parameterType="Classroom"> insert into bd_classroom( id,school_id,name,code,position,capacity,kind,enabled,remark) values( #{id},#{schoolId},#{name},#{code},#{position},#{capacity},#{kind},#{enabled},#{remark}) </insert> <!-- 修改 --> <update id="updateClassroom" parameterType="Classroom"> update bd_classroom set school_id = #{schoolId}, name = #{name}, code = #{code}, position = #{position}, capacity = #{capacity}, kind = #{kind}, remark = #{remark} where id = #{id} </update> <!-- 删除 --> <delete id="deleteClassroomById" parameterType="Long"> delete bd_classroom where id = #{id} </delete> </mapper>
关于freemarker标签的使用
<tr> <td>< @constant.m "workingresume_position"/>: </td> <td><@dictionaryDirective code="positionKindDict" name="position" value="${workingResume.po sition}" /> </td> </tr>
@constant及@dictionaryDirective的原理
spring-mvc.xml中freemarker的配置如下:
<bean id="freeMarkerConfigurer" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer"> <property name="templateLoaderPath" value="/WEB-INF/view/" /> <property name="freemarkerVariables"> <map> <entry key="schoolDirective" value-ref="schoolDirective"/> <entry key="dictionaryDirective" value-ref="dictionaryDirective"/> <entry key="gradeDirective" value-ref="gradeDirective"/> <entry key="periodDirective" value-ref="periodDirective"/> <entry key="subjectDirective" value-ref="subjectDirective"/> <entry key="sideDirective" value-ref="sideDirective"/> <entry key="permissionDirective" value-ref="permissionDirective"/> <entry key="commonContext" value="${commonContext}"/> <entry key="personalContext" value="${personalContext}"/> <entry key="exportTemplatePath" value="${exportTemplatePath}"/> <entry key="courseDirective" value-ref="courseDirective"/> <entry key="publisherDirective" value-ref="publisherDirective"/> <entry key="schoolTermDirective" value-ref="schoolTermDirective"/> </map> </property> <property name="freemarkerSettings"> <props> <prop key="template_update_delay">0</prop> <prop key="defaultEncoding">UTF-8</prop> <prop key="url_escaping_charset">UTF-8</prop> <prop key="locale">zh_CN</prop> <prop key="boolean_format">true,false</prop> <prop key="datetime_format">yyyy-MM-dd HH:mm:ss</prop> <prop key="date_format">yyyy-MM-dd</prop> <prop key="time_format">HH:mm:ss</prop> <prop key="number_format">0.######</prop> <prop key="whitespace_stripping">true</prop> <prop key="template_exception_handler">ignore</prop> <prop key="classic_compatible">true</prop> <prop key="auto_import">ftl/pony/index.ftl as ui,/ftl/spring.ftl as constant</prop> </props> </property> </bean> <!-- 针对freemarker的视图配置 --> <bean id="viewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver"> <property name="cache" value="true" /> <property name="prefix" value="" /> <property name="suffix" value=".html" /> <property name="contentType" value="text/html;charset=UTF-8"></property> <property name="requestContextAttribute" value="rc" /> <property name="exposeSpringMacroHelpers" value="true" /> <property name="exposeRequestAttributes" value="true" /> <property name="exposeSessionAttributes" value="true" /> </bean>
而@constant标签的使用,取决于
<prop key="auto_import">ftl/pony/index.ftl as ui,/ftl/spring.ftl as constant</prop>
的配置,文件spring.ftl及各国际化文件*.properties
类似于@dictionaryDirective标签,实现freemarker提供的接口TemplateDirectiveModel
当然也是使用spring提供的注解@Component完成创建该标签类实例,
在实现方法execute内实现自己的逻辑,比如这里就是为页面提供select下单选框标签,并通过下面两行
Dictionary dictionary = this.dictionaryService.getDictionaryByCode(code);
List<DictionaryValue> dictionaryValueList = this.dictionaryService.select- DictionaryValue(dictionary.getId());
查询数据库中字典dictionary表,遍历dictionaryValueList将相关kind类型值内容赋予<option>标签,最后将拼接成的html字符串输出到页面便完成了。
通过shiro完成权限控制
shiro提供的注解//@RequiresPermissions("/base/teachermanager/retired/search_retired")
若无此权限则不能访问相应请求链接。
@Component
public class PermissionDirective implements TemplateDirectiveModel
再借助freemarker提供的以上接口,根据逻辑判断权限,若无相应权限可屏蔽显示相应标签。
shiro的配置在以上的spring-mvc.xml及web.xml均有需要配置的内容。