概述
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}
獲取異常信息
THE END
關注微信公衆號【程序媛琬淇】,專注分享Java乾貨,給你意想不到的收穫。