概述
Spring MVC是一个优秀的Web框架,MyBatis是一个ORM数据持久化层框架,它们是两个独立的框架,之间没有直接的联系。由于Spring 框架提供了IoC 和Aop等功能,若把Spring MVC和MyBatis的对象交给Spring容器进行解耦合管理,不仅能大大增强系统的灵活性,便于功能扩展,还能通过Spring提供的服务简化代码,减少工作开发量,提高开发效率。
一、搭建Spring MVC+Spring+MyBatis框架
1、新建WebProject,加入Spring、Spring MVC、MyBatis、数据库驱动等相关jar文件
2、编写配置文件
- 配置数据库连接database.properties文件
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/smbms
user=root
pwd=1898
注:其它属性根据实际情况设置
- 配置日志文件log4j.properties
log4j.rootLogger=debug,CONSOLE,file
#log4j.rootLogger=ERROR,ROLLING_FILE
log4j.logger.cn.easybuy=debug
log4j.logger.java.sql.Connection=debug
log4j.logger.java.sql.Statement=debug
log4j.logger.java.sql.PreparedStatement=debug
log4j.logger.java.sql.ResultSet=debug
######################################################################################
# Console Appender \u65e5\u5fd7\u5728\u63a7\u5236\u8f93\u51fa\u914d\u7f6e
######################################################################################
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.Threshold=debug
#log4j.appender.CONSOLE.DatePattern=yyyy-MM-dd
log4j.appender.CONSOLE.Target=System.out
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern= - (%r ms) - %d{yyyy-M-d HH:mm:ss}%x[%5p](%F:%L) %m%n
######################################################################################
# Rolling File \u6587\u4ef6\u5927\u5c0f\u5230\u8fbe\u6307\u5b9a\u5c3a\u5bf8\u7684\u65f6\u5019\u4ea7\u751f\u4e00\u4e2a\u65b0\u7684\u6587\u4ef6
######################################################################################
#log4j.appender.ROLLING_FILE=org.apache.log4j.RollingFileAppender
#log4j.appender.ROLLING_FILE.Threshold=INFO
#log4j.appender.ROLLING_FILE.File=${baojia.root}/logs/log.log
#log4j.appender.ROLLING_FILE.Append=true
#log4j.appender.ROLLING_FILE.MaxFileSize=5000KB
#log4j.appender.ROLLING_FILE.MaxBackupIndex=100
#log4j.appender.ROLLING_FILE.layout=org.apache.log4j.PatternLayout
#log4j.appender.ROLLING_FILE.layout.ConversionPattern=%d{yyyy-M-d HH:mm:ss}%x[%5p](%F:%L) %m%n
######################################################################################
# DailyRolling File \u6bcf\u5929\u4ea7\u751f\u4e00\u4e2a\u65e5\u5fd7\u6587\u4ef6\uff0c\u6587\u4ef6\u540d\u683c\u5f0f:log2009-09-11
######################################################################################
log4j.appender.file=org.apache.log4j.DailyRollingFileAppender
#log4j.appender.file.DatePattern=yyyy-MM-dd
log4j.appender.file.File=${EasyBuy.root}/logs/log.log
log4j.appender.file.Append=true
log4j.appender.file.Threshold=debug
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern= - (%r ms) - %d{yyyy-M-d HH:mm:ss}%x[%5p](%F:%L) %m%n
- 编写MyBatis配置文件mybatis-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "mybatis-3-config.dtd" >
<configuration>
<!-- 类型别名 -->
<typeAliases>
<package name="cn.smbms.pojo"/>
</typeAliases>
</configuration>
- 编写Spring配置文件applicationContext-mybatis.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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
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/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">
<context:component-scan base-package="cn.bdqn.service.*"/>
<!-- 引入database.propertis文件 -->
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>classpath:database.properties</value>
</property>
</bean>
<!-- 使用Spring配置文件配置数据源dbcp-->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${driver}"/>
<property name="url" value="${url}">
</property>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
<property name="initialSize" value="${initialSize}"/>
<property name="maxActive" value="${maxActive}"/>
<property name="maxIdle" value="${maxIdle}"/>
<property name="minIdle" value="${minIdle}"/>
<property name="maxWait" value="${maxWait}"/>
<property name="removeAbandoned" value="${removeAbandoned}"/>
<property name="removeAbandonedTimeout" value="${removeAbandonedTimeout}"/>
<!-- sql心跳-->
<!--testWhileIdle:定义开启Evict的定时校验(循环校验) -->
<property name="testWhileIdle" value="true" />
<!-- testOnBorrow:定义在进行borrowObject处理时,
对拿到的连接是否进行校验,false为不校验,默认false -->
<property name="testOnBorrow" value="false" />
<!-- testOnReturn:定义在returnObject时,对返回的连接是否进行校验,false为不校验, 默认false-->
<property name="testOnReturn" value="false" />
<!-- validationQuery:定义校验使用的sql语句,跟MySql简单通信下,
校验连接是否有效。该sql语句不能太复杂,复杂的校验sql会严重影响性能 -->
<property name="validationQuery" value="select 1" />
<!--timeBetweenEvictionRunsMillis:定义Evict的定时时间间隔 -->
<property name="timeBetweenEvictionRunsMillis" value="60000" />
<!-- 定义每次校验连接的数量。一般情况下,该值会和maxActive大小一样,每次可以校验 所有连接 -->
<property name="numTestsPerEvictionRun" value="${maxActive}" />
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 引用数据源组件 -->
<property name="dataSource" ref="dataSource" />
<!-- 引用MyBatis配置文件中的配置 -->
<property name="configLocation" value="classpath:mybatis-config.xml" />
<!-- 配置sql映射文件路径 -->
<property name="mapperLocations">
<list>
<value>classpath:mappers/*.xml</value>
</list>
</property>
</bean>
<!-- 使用MapperScannerConfigurer自定生成代理实现类 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 给指定包下的接口生成代理实现类 -->
<property name="basePackage" value="cn.smbms.dao"></property>
</bean>
<!-- 1、导入命名空间aop和tx -->
<!-- 2、定义事物管理器,并且注入数据源 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 开启注解方式,支持事务 -->
<tx:annotation-driven transaction-manager="txManager" proxy-target-class="true"/>
</beans>
- 编写Spring MVC配置文件springmvc-servlet.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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd">
<!-- 对指定包进行扫描,实现注解驱动Bean的定义 -->
<context:component-scan base-package="cn.smbms.controller" />
<!--配置消息转换器-->
<mvc:annotation-driven conversion-service="myConversionService">
<mvc:message-converters>
<!-- 装配消息转换器StringHttpMessageConverter,解决中文乱码 -->
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<!-- 通过设置 StringHttpMessageConverter的supportedMediaTypes属性指
定媒体类型为applciation/json,字符编码为utf-8 -->
<property name="supportedMediaTypes">
<list>
<value>application/json;charset=UTF-8</value>
</list>
</property>
</bean>
<!--配置FastJsonHttpMessageConverter消息转换器,解决日期格式问题 -->
<bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/html;charset=UTF-8</value>
<value>application/json</value>
</list>
</property>
<property name="features">
<list>
<!--输出Date的日期转换器 -->
<value>WriteDateUseDateFormat</value>
</list>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<!-- 自定义数据转换器-->
<bean id="myConversionService"
class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<list>
<bean class="cn.smbms.tools.StringToDateConverter">
<constructor-arg type="java.lang.String" value="yyyy-MM-dd"/>
</bean>
</list>
</property>
</bean>
<!-- 配置静态资源文件-->
<mvc:resources mapping="/statics/**" location="/statics/" />
<!-- 配置视图解析器:允许同样的内容数据呈现不同的View -->
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="favorParameter" value="true"/>
<property name="defaultContentType" value="text/html"/>
<property name="mediaTypes">
<map>
<entry key="html" value="text/html;charset=UTF-8"/>
<entry key="json" value="application/json;charset=UTF-8"/>
<entry key="xml" value="application/xml;charset=UTF-8"/>
</map>
</property>
<!-- 映射视图路径 -->
<property name="viewResolvers">
<list>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
</list>
</property>
</bean>
<!--配置拦截器 -->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/*/sys/**"/>
<!-- 自定义的系统拦截器,主要作用:拦截用户请求,进行session判断 -->
<bean class="cn.smbms.interceptor.SysInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
<!-- 配置全局异常处理 -->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<prop key="java.lang.RuntimeException">login</prop>
</props>
</property>
</bean>
<!-- 配置MultipartResolver,用于上传文件,使用spring的CommonsMultipartResolver -->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 上传文件的大小上限,单位为字节 -->
<property name="maxUploadSize" value="5000000"/>
<!--请求的编码格式,默认为ISO-8859-1,此处设置为utf-8 -->
<property name="defaultEncoding" value="UTF-8"/>
</bean>
</beans>
- 编写web.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
<!--配置首页默认页面路径-->
<welcome-file-list>
<welcome-file>/WEB-INF/jsp/login.jsp</welcome-file>
</welcome-file-list>
<!-- 配置Spring MVC的核心控制器DispatcherServlet -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<!--初始化参数 -->
<init-param>
<!-- 通过设置contextConfigLocatin参数来指定Spring MVC配置文件
的位置,此处使用Spring资源的方式进行指定 -->
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-servlet.xml</param-value>
</init-param>
<!-- 标记容器在启动的时候就加载此DispatcherServlet,即自动启动 -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<!-- 表示DispatcherServlet需要截获并处理该项目的所有url请求-->
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- 处理字符编码 -->
<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>
<!-- 配置环境参数,指定Spring配置文件所在目录-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext-*.xml</param-value>
</context-param>
<!-- 配置String监听器-->
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
</web-app>
注1: 由于Spring需要启动容器才能为其他框架提供服务,而Web应用程序的入口是被Web服务器控制的,因此无法在main()方法中通过创建ClassPathXMLApplicationContext 对象来启动容器。Spring提供了一个监听器类org.springframework.web.context.ContextLoaderListener
,该监听器实现了 ServletContextListener 接口,可以在Web容器启动的时候初始化Spring容器。
注2: 如果没有指定 contextConfigLocation 参数,ContextLoaderListener 默认会去查找/WEB-INF/applicationContext.xml
。即如果我们将配置文件命名为 ContextLoaderListener 并存放在WEB-INF目录下,可不指定contextConfigLocation 参数。
3、数据对象模型(cn.smbms.pojo)
4、DAO访问数据接口(cn.smbms.dao)
5、系统服务接口(cn.smbms.service)
6、前端控制层Controller(cn.smbms.controller)
7、系统工具类(cn.smbms.tools)
8、前端页面(WEB-INF/jsp)和静态资源文件(/WebRoot/statics)
二、静态资源文件引用
开发Web应用时,有时会出现css样式无法应用的情况,若有引用js文件,此时js也是无法起效的。这是由于web.xml中配置的DispatcherServlet请求映射为"/"
,则Spring MVC将捕捉Web容器的所有请求,这其中也包括了静态资源的请求。Spring MVC会将他们当成一个普通请求处理,但是由于找不到对应处理器,所以按照常规方式引用静态资源文件将无法访问。所以需要采用<mvc:resources/>
标签解决静态资源的访问问题。
- 为了方便配置管理,此处将所有的静态资源文件放在一个文件夹statics下,如下图
- 然后在Spring MVC配置文件springmvc-servlet.xml中加入以下配置即可解决
<!-- 配置静态资源文件-->
<mvc:resources mapping="/statics/**" location="/statics/" />
注:
mapping:将静态资源映射到指定的路径(/statics)
location:本地静态资源文件所在的目录
三、Spring MVC中的异常处理
Spring MVC通过 HandlerExceptionResolver 处理程序异常,包括处理器异常,数据绑定异常以及处理器执行时发生的异常。当发生异常时,Spring MVC会调用 resolveException() 方法,并转到ModelAndView 对应的视图中,作为一个异常报告页面反馈给用户。
1、局部异常处理
仅能处理指定Controller中的异常。使用@ExceptionHandler注解实现。
//验证登录
@RequestMapping(value = "/exlogin.html", method = RequestMethod.GET)
public String exLogin(@RequestParam String userCode, @RequestParam String userPassword) {
logger.debug("exLogin=============");
User user = userService.login(userCode, userPassword);
if (null == user) { //登录失败
throw new RuntimeException("用户名或密码不正确!");
}
return "redirect:/user/main.html";
}
@ExceptionHandler(value={RuntimeException.class})
public String handlerException(RuntimeException e,HttpServletRequest req){
req.setAttribute("e", e);
return "error";
}
注: 当用户发送请求进行登录时,调用处理器的exLogin()方法,该方法用于验证登录信息,当user==null
也就是登录失败的情况下,方法会抛出 RuntimeException 运行时异常,并指定了错误信息;而使用@ExceptionHandler(value={RuntimeException.class})
注解表示被注解的方法会拦截所有抛出的 RuntimeException ,并进行处理,在handlerException() 方法中将异常对象存放到了request作用域中,并转发到了error.jsp,error.jsp页面即可从request对象中获取错误信息并展示给用户。
2、全局异常处理
全局异常处理可使用 SimpleMappingExceptionResolver 来实现。它将异常类名映射为视图名,即发生异常时使用对应的视图报告异常。
- 在 springmvc-servlet.xml 中配置全局异常。
<!-- 配置全局异常处理 -->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<prop key="java.lang.RuntimeException">error</prop>
</props>
</property>
</bean>
- 在方法中定义抛出异常信息
@RequestMapping(value = "/exlogin.html", method = RequestMethod.GET)
public String exLogin(@RequestParam String userCode, @RequestParam String userPassword) {
logger.debug("exLogin=============");
User user = userService.login(userCode, userPassword);
if (null == user) { //登录失败
throw new RuntimeException("用户名或密码不正确!");
}
//重定向URL请求,该请求用于进入login.jsp登录页面
return "redirect:/user/main.html";
}
- 在异常页面使用
${exception.message}
获取异常信息
关注一下吧~【Pretty Kathy】