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均有需要配置的内容。