IDEA下使用maven构建web项目(SpringMVC+Mybatis整合)
本文未经作者允许,禁止内容转载,引用请标明出处。
需求背景:由于最近总是接到一些需求,需要配合前端团队快速建设移动端 UI 应用或 web 应用及后台业务逻辑支撑的需求,若每次都复用之前复杂业务应用的项目代码,总会携带很多暂时不会用到的功能或组件,这样的初始工程就存在冗余代码。
在本文中,我们将使用 Java 语言开发集成环境IntelliJ IDEA(其倡言是智能编码☺),应用maven构建SpringMVC整合Mybatis+MySQL5.7(流行框架)的 web 项目;目的在于快速构建一个简洁纯净版的 web 应用工程,将其作为一个基础 web-demo,以便类似的项目都可以复用本 demo。本文旨在快速搭建 web 项目,并未深入研究原理,有兴趣的可参考其他文章研究 Spring 及 mybatis 原理。
本项目的工程代码,已经提交到 github 上,方便每次下载使用。(github 源代码链接),新添加了本次 demo 的 war 包文件,亦可在 github 上下载。
一、IDEA 下构建 maven 的 web 项目
1、新建工程 New-->Project,创建 maven 的 web 项目,选择 maven-archetype-webapp,并配置 Project SDK,本次选用的是本机已安装的 jdk1.8,如下图所示:
2、下一步,填写自己项目的 GroupId,ArtifactId,如下图:
3、下一步,设置 maven 的安装目录,代替 IDEA 自带的 maven 版本,我换成了自己手动安装的 maven 版本,路径存在 D 盘;设置 maven 本地的仓库,我配置了本项目单独的仓库,但没去复用之前项目所用的 maven 仓库,为的是让本工程的依赖 jar 包保持纯净(虽然无关紧要,原谅我有莫名的洁癖☺)。
4、下一步,设置工程的 Project Name。
5、Finish,maven 的 web 项目就创建完成,接下来 maven 会下载相应的资源,下载时速度会很慢(maven 加载 jar 包过程,默认的是先扫描本地仓库,若本地仓库没有,则扫描远程仓库下载。默认的 conf/settings.xml 文件没有配置远程仓库,所以扫描的是 maven 的中央仓库(资源镜像一般在国外),所以慢);由于我使用的网络是 FQ 外网,直接默认 maven 下载方式速度还是可以的(或许也是人品好一点☺),如果大家想快一点,也可以参考网上配置 maven 使用国内镜像的教程。
二、搭建基于 SpringMVC 整合 mybatis 的 web 工程
1、等待 maven 下载资源完成后,注意到工程目录中会出现 src 的文件夹,src 下默认会存在 main 目录,main 下默认存在 resources 和 webapp 文件夹,其中 resources 文件夹主要存放项目的配置或属性等文件,webapp 则是 web 应用的根目录,会存放 HTML,CSS,js,JSP 或资源文件等。我们需要再 main 目录下创建 java 文件夹,java 目录下存放的将是 Java 程序的 package 及 class 文件等。由于我们将搭建 springMVC 框架,我们可以提前搭建好项目的文件目录结构,如下图所示:
其中,java 下创建项目的 package com.charlie,其下可以再分类不同的 package,包括 controller,service,service-->impl,entity,dao,dao-->mapper,dao-->xml,common,util 等,这些包是基于 springmvc+mybatis 所需的,还有可以存放一些公共类或工具类。
webapp 下可创建 css,js,image,WEB-INF-->views 等。
src 可创建 main 的同级目录 test,可以用于后续项目开发过程中的 Junit 程序测试。
2、配置 pom.xml 文件,maven 添加 web 项目必需的以及 SpringMVC 所必需的 dependencies 包。
2.1、以下是引入 Junit,日志,MySQL 驱动的依赖包,注意此次引入的是最新的 mysql-connector-java-6.0.6,会影响后续的 SpringMVC 及 jdbc 等的特殊配置,这将和旧版本的 mysql 驱动包有区别。
1 <!-- junit 测试包--> 2 <dependency> 3 <groupId>junit</groupId> 4 <artifactId>junit</artifactId> 5 <version>4.12</version> 6 <scope>test</scope> 7 </dependency> 8 <!--日志包--> 9 <dependency> 10 <groupId>org.slf4j</groupId> 11 <artifactId>slf4j-log4j12</artifactId> 12 <version>1.8.0-alpha2</version> 13 </dependency> 14 <!--mysql 驱动包--> 15 <dependency> 16 <groupId>mysql</groupId> 17 <artifactId>mysql-connector-java</artifactId> 18 <version>6.0.6</version> 19 </dependency>
这样,已经支持了日志的输出,我们仍然需要日志的属性文件,在 resources 目录下,新增日志属性文件log4j.properties,并配置如下(配置方式很多种,大家选择一种即可):
#配置根 Logger 后面是若干个 Appender
log4j.rootLogger=DEBUG,A1,R
#log4j.rootLogger=INFO,A1,R
# ConsoleAppender 输出
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%-d{yyyy-MM-dd HH🇲🇲ss,SSS} [%c]-[%p] %m%n
# File 输出 一天一个文件, 输出路径可以定制, 一般在根路径下
log4j.appender.R=org.apache.log4j.DailyRollingFileAppender
log4j.appender.R.File=log.txt
log4j.appender.R.MaxFileSize=500KB
log4j.appender.R.MaxBackupIndex=10
log4j.appender.R.layout=org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=%d{yyyy-MM-dd HH🇲🇲ss,SSS} [%t] [%c] [%p] - %m%n
其中,开发者可设置 rootLogger,开发调试环境时,可设置为 DEBUG 模式,输出系统的详细日志;生产环境时,可设置为 INFO 模式。
2.2、以下是引入 SpringMVC 所必需的依赖包,由于 maven 自动依赖功能,引入以下包时,会自动引入其他相关的依赖包,其中就包括 spring-core,spring-context 等重要的包(注意只要能够引入所有的 Spring 依赖包即可)。
1 <!--spring 相关包--> 2 <dependency> 3 <groupId>org.springframework</groupId> 4 <artifactId>spring-web</artifactId> 5 <version>4.3.8.RELEASE</version> 6 </dependency> 7 <dependency> 8 <groupId>org.springframework</groupId> 9 <artifactId>spring-webmvc</artifactId> 10 <version>4.3.8.RELEASE</version> 11 </dependency> 12 <dependency> 13 <groupId>org.springframework</groupId> 14 <artifactId>spring-context-support</artifactId> 15 <version>4.3.8.RELEASE</version> 16 </dependency> 17 <dependency> 18 <groupId>org.springframework</groupId> 19 <artifactId>spring-oxm</artifactId> 20 <version>4.3.8.RELEASE</version> 21 </dependency> 22 <dependency> 23 <groupId>org.springframework</groupId> 24 <artifactId>spring-tx</artifactId> 25 <version>4.3.8.RELEASE</version> 26 </dependency> 27 <dependency> 28 <groupId>org.springframework</groupId> 29 <artifactId>spring-test</artifactId> 30 <version>4.3.8.RELEASE</version> 31 </dependency> 32 <dependency> 33 <groupId>org.springframework</groupId> 34 <artifactId>spring-jdbc</artifactId> 35 <version>4.3.8.RELEASE</version> 36 </dependency> 37 <!--aspectj start--> 38 <dependency> 39 <groupId>org.aspectj</groupId> 40 <artifactId>aspectjweaver</artifactId> 41 <version>1.8.10</version> 42 </dependency> 43 <dependency> 44 <groupId>org.aspectj</groupId> 45 <artifactId>aspectjrt</artifactId> 46 <version>1.8.10</version> 47 </dependency>
2.3、以下是引入JSP的包,以支持 jsp 视图的功能。
1 <!-- 支持 jsp --> 2 <dependency> 3 <groupId>javax.servlet</groupId> 4 <artifactId>jstl</artifactId> 5 <version>1.2</version> 6 </dependency> 7 <dependency> 8 <groupId>taglibs</groupId> 9 <artifactId>standard</artifactId> 10 <version>1.1.2</version> 11 </dependency> 12 <!--servlet/jsp api start--> 13 <dependency> 14 <groupId>javax.servlet</groupId> 15 <artifactId>servlet-api</artifactId> 16 <version>3.0-alpha-1</version> 17 </dependency> 18 <dependency> 19 <groupId>javax.servlet.jsp</groupId> 20 <artifactId>jsp-api</artifactId> 21 <version>2.2.1-b03</version> 22 </dependency>
2.4、以下是引入datasource数据源的包,引入了 2 种方式,但本次项目中,我们使用的是 alibaba 的 Druid DataSource。
1 <!-- JDBC 连接池 --> 2 <dependency> 3 <groupId>com.mchange</groupId> 4 <artifactId>c3p0</artifactId> 5 <version>0.9.5.2</version> 6 </dependency> 7 <!-- DruidDataSource,本工程的 dataSource 配置使用的 Druid --> 8 <dependency> 9 <groupId>com.alibaba</groupId> 10 <artifactId>druid</artifactId> 11 <version>1.0.29</version> 12 </dependency>
到此,我们已经引入了 mysql 驱动包,DataSource 连接池,我们还需要配置 jdbc 属性文件,在 resources 下创建 jdbc.properties 文件,内容如下:
#JDBC Global Setting #jdbc.driver=com.mysql.jdbc.Driver jdbc.driver=com.mysql.cj.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/charlie_web_demo?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=GMT%2B8 jdbc.username=root jdbc.password=p@ssw0rd##DataSource Global Setting
#配置初始化大小、最小、最大
ds.initialSize=1
ds.minIdle=1
ds.maxActive=20#配置获取连接等待超时的时间
ds.maxWait=60000#配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
ds.timeBetweenEvictionRunsMillis=60000#配置一个连接在池中最小生存的时间,单位是毫秒
ds.minEvictableIdleTimeMillis=300000
其中,配置了 mysql 数据库的连接,用户名,密码等信息。由于使用了最新版本的 mysql-connector-java-6.0.6 驱动,这要求driver 和 url的特殊配置,否则项目启动时会报 1 个警告和 2 个异常。jdbc.driver 配置为 com.mysql.cj.jdbc.Driver,可以避免出现警告信息(具体警告信息没有记录下来,大家配置过程中可能会遇到);jdbc.url 里添加 useSSL 属性 --- 配置为 true;若出现 The server time zone value ‘?й???????’ is unrecognized or represents more than one time zone 的错误,则需添加 serverTimezone 属性,设置为 GMT%2B8 即可解决。
2.5、以下是引入一些其他可能需要的包,包括文件上传等。
1 <!--其他需要的包--> 2 <dependency> 3 <groupId>org.apache.commons</groupId> 4 <artifactId>commons-lang3</artifactId> 5 <version>3.5</version> 6 </dependency> 7 <dependency> 8 <groupId>commons-fileupload</groupId> 9 <artifactId>commons-fileupload</artifactId> 10 <version>1.3.2</version> 11 </dependency>
3、配置 pom.xml 文件,设置项目的编译属性,编译后的 war 包名称(即 finalName),存放配置或属性文件到 resources 目录下。
1 <build> 2 <finalName>CharlieWebDemo</finalName> 3 <resources> 4 <!--表示把 java 目录下的有关 xml 文件,properties 文件编译 / 打包的时候放在 resource 目录下--> 5 <resource> 6 <directory>${basedir}/src/main/java</directory> 7 <includes> 8 <include>**/*.properties</include> 9 <include>**/*.xml</include> 10 </includes> 11 </resource> 12 <resource> 13 <directory>${basedir}/src/main/resources</directory> 14 </resource> 15 </resources> 16 </build>
经过以上的 pom.xml 的配置,项目及 springmvc 所需的依赖包就已经基本引入了,通过 IDEA 右侧栏中的 maven projects 的 reimport 按钮实现依赖包的引入下载(并且,其中常用的是 clean,package,install 等,clean 可以清除生成的 target 目录,install 可以重新生成 target 目录),若 pom.xml 种引入 / 修改了新的依赖包 / 插件或者 Dependencies 存在红色提示,需要重新 reimport 以下。
4、配置项目的web.xml文件,包括首页,异常跳转,会话超时,字符编码过滤器 CharacterEncodingFilter,监听器 ContextLoaderListener,前置控制器 DispatcherServlet,静态文件单独处理等等。代码及解释如下:
<?xml version="1.0" encoding="UTF-8"?> <web-app 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_3_0.xsd" version="3.0"><display-name>Archetype Created Web Application</display-name>
<!--welcome pages-->
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<!--当系统出现 404 错误,跳转到页面 NoPage.html-->
<error-page>
<error-code>404</error-code>
<location>/WEB-INF/NoPage.html</location>
</error-page>
<!--当系统出现 java.lang.NullPointerException,跳转到页面 error.html-->
<error-page>
<exception-type>java.lang.NullPointerException</exception-type>
<location>/WEB-INF/error.html</location>
</error-page>
<!--会话超时配置,单位分钟-->
<session-config>
<session-timeout>360</session-timeout>
</session-config><!--Spring 框架给我们提供过滤器 CharacterEncodingFilter
这个过滤器就是针对于每次浏览器请求进行过滤的,然后再其之上添加了父类没有的功能即处理字符编码。
其中 encoding 用来设置编码格式,forceEncoding 用来设置是否理会 request.getCharacterEncoding() 方法,设置为 true 则强制覆盖之前的编码格式。-->
<filter>
<filter-name>characterEncodingFilter</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>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping><!-- 项目中使用 Spring 时,applicationContext.xml 配置文件中并没有 BeanFactory,要想在业务层中的 class 文件中直接引用 Spring 容器管理的 bean 可通过以下方式-->
<!--1、在 web.xml 配置监听器 ContextLoaderListener。ContextLoaderListener 的作用就是启动 Web 容器时,自动装配 ApplicationContext 的配置信息。因为它实现了 ServletContextListener 这个接口,在 web.xml 配置这个监听器,启动容器时,就会默认执行它实现的方法。
在 ContextLoaderListener 中关联了 ContextLoader 这个类,所以整个加载配置过程由 ContextLoader 来完成。-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!--2、部署 applicationContext 的 xml 文件。如果在 web.xml 中不写任何参数配置信息,默认的路径是 "/WEB-INF/applicationContext.xml,
在 WEB-INF 目录下创建的 xml 文件的名称必须是 applicationContext.xml。
如果是要自定义文件名可以在 web.xml 里加入 contextConfigLocation 这个 context 参数:
在 <param-value> </param-value> 里指定相应的 xml 文件名,如果有多个 xml 文件,可以写在一起并以“,”号分隔,也可以这样 applicationContext-*.xml 采用通配符,匹配的文件都会一同被载入。
在 ContextLoaderListener 中关联了 ContextLoader 这个类,所以整个加载配置过程由 ContextLoader 来完成。-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param><!--如果你的 DispatcherServlet 拦截 "/",为了实现 REST 风格,拦截了所有的请求,那么同时对 *.js,.jpg 等静态文件的访问也就被拦截了。-->
<!--方案一:激活 Tomcat 的 defaultServlet 来处理静态文件-->
<!--要写在 DispatcherServlet 的前面,让 defaultServlet 先拦截请求,这样请求就不会进入 Spring 了-->
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>.css</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>.swf</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>.gif</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>.jpg</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>.png</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>.js</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>.html</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>.xml</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>.json</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.map</url-pattern>
</servlet-mapping><!--使用 Spring MVC, 配置 DispatcherServlet 是第一步。DispatcherServlet 是一个 Servlet,, 所以可以配置多个 DispatcherServlet-->
<!--DispatcherServlet 是前置控制器,配置在 web.xml 文件中的。拦截匹配的请求,Servlet 拦截匹配规则要自已定义,把拦截下来的请求,依据某某规则分发到目标 Controller(我们写的 Action) 来处理。-->
<!--配置 SpringMVC DispatcherServlet-->
<servlet>
<!--在 DispatcherServlet 的初始化过程中,框架会在 web 应用的 WEB-INF 文件夹下寻找名为 [servlet-name]-servlet.xml 的配置文件,生成文件中定义的 bean。-->
<servlet-name>springMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<!--指明了配置文件的文件名,不使用默认配置文件名,而使用 spring-mvc.xml 配置文件。-->
<param-name>contextConfigLocation</param-name>
<!--其中 <param-value>**.xml</param-value> 这里可以使用多种写法-->
<!--1、不写, 使用默认值:/WEB-INF/<servlet-name>-servlet.xml-->
<!--2、<param-value>/WEB-INF/classes/dispatcher-servlet.xml</param-value>-->
<!--3、<param-value>classpath*:dispatcher-servlet.xml</param-value>-->
<!--4、多个值用逗号分隔-->
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
<!--是启动顺序,让这个 Servlet 随 Servlet 容器一起启动。-->
<load-on-startup>1</load-on-startup>
<async-supported>true</async-supported>
</servlet>
<servlet-mapping>
<!--这个 Servlet 的名字是 dispatcher,可以有多个 DispatcherServlet,是通过名字来区分的。每一个 DispatcherServlet 有自己的 WebApplicationContext 上下文对象。同时保存的 ServletContext 中和 Request 对象中.-->
<!--ApplicationContext 是 Spring 的核心,Context 我们通常解释为上下文环境,我想用“容器”来表述它更容易理解一些,ApplicationContext 则是“应用的容器”了,Spring 把 Bean 放在这个容器中,在需要的时候,用 getBean 方法取出-->
<servlet-name>springMVC</servlet-name>
<!--Servlet 拦截匹配规则可以自已定义,当映射为 @RequestMapping("/user/add") 时,为例, 拦截哪种 URL 合适?-->
<!--1、拦截 *.do、*.htm, 例如:/user/add.do, 这是最传统的方式,最简单也最实用。不会导致静态文件(jpg,js,css)被拦截。-->
<!--2、拦截 /,例如:/user/add, 可以实现现在很流行的 REST 风格。很多互联网类型的应用很喜欢这种风格的 URL。弊端:会导致静态文件(jpg,js,css)被拦截后不能正常显示。 -->
<url-pattern>/</url-pattern><!--会拦截 URL 中带“/”的请求。-->
</servlet-mapping></web-app>
5、由 web.xml 的配置中看出,我们还需要配置 applicationContext.xml 和 spring-mvc.xml,我们在spring-mvc.xml中配置 springmvc 的相关配置,如下:
<?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: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-4.3.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!--启用 spring 的一些 annotation --> <context:annotation-config/><span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 自动扫描该包,使SpringMVC认为包下用了@controller注解的类是控制器 </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">context:component-scan </span><span style="color: rgba(255, 0, 0, 1)">base-package</span><span style="color: rgba(0, 0, 255, 1)">="com.charlie.controller"</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">context:include-filter </span><span style="color: rgba(255, 0, 0, 1)">type</span><span style="color: rgba(0, 0, 255, 1)">="annotation"</span><span style="color: rgba(255, 0, 0, 1)"> expression</span><span style="color: rgba(0, 0, 255, 1)">="org.springframework.stereotype.Controller"</span><span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">context:component-scan</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)">扫描service</span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">context:component-scan </span><span style="color: rgba(255, 0, 0, 1)">base-package</span><span style="color: rgba(0, 0, 255, 1)">="com.charlie.service"</span><span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)">HandlerMapping 无需配置,SpringMVC可以默认启动</span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)">静态资源映射</span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)">本项目把静态资源放在了WEB-INF的子目录下,资源映射如下</span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">mvc:resources </span><span style="color: rgba(255, 0, 0, 1)">mapping</span><span style="color: rgba(0, 0, 255, 1)">="/css/**"</span><span style="color: rgba(255, 0, 0, 1)"> location</span><span style="color: rgba(0, 0, 255, 1)">="/css/"</span><span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">mvc:resources </span><span style="color: rgba(255, 0, 0, 1)">mapping</span><span style="color: rgba(0, 0, 255, 1)">="/js/**"</span><span style="color: rgba(255, 0, 0, 1)"> location</span><span style="color: rgba(0, 0, 255, 1)">="/js/"</span><span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">mvc:resources </span><span style="color: rgba(255, 0, 0, 1)">mapping</span><span style="color: rgba(0, 0, 255, 1)">="/image/**"</span><span style="color: rgba(255, 0, 0, 1)"> location</span><span style="color: rgba(0, 0, 255, 1)">="/image/"</span><span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 配置注解驱动 可以将request参数与绑定到controller参数上 </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">mvc:annotation-driven</span><span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 对模型视图名称的解析,即在模型视图名称添加前后缀(如果最后一个还是表示文件夹,则最后的斜杠不要漏了) 使用JSP</span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 默认的视图解析器在上边的解析错误时使用 (默认使用html)- </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">bean </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="defaultViewResolver"</span><span style="color: rgba(255, 0, 0, 1)"> class</span><span style="color: rgba(0, 0, 255, 1)">="org.springframework.web.servlet.view.InternalResourceViewResolver"</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="viewClass"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="org.springframework.web.servlet.view.JstlView"</span><span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)">设置JSP文件的目录位置</span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="prefix"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="/WEB-INF/views/"</span><span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="suffix"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">=".jsp"</span><span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">bean</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> SpringMVC文件上传需要配置的节点</span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">bean </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="multipartResolver"</span><span style="color: rgba(255, 0, 0, 1)"> class</span><span style="color: rgba(0, 0, 255, 1)">="org.springframework.web.multipart.commons.CommonsMultipartResolver"</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="maxUploadSize"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="20971500"</span><span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="defaultEncoding"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="UTF-8"</span><span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="resolveLazily"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="true"</span><span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">bean</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 支持返回json,用来处理json格式转换,避免IE执行ajax时,返回json出现下载文件 </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">bean </span><span style="color: rgba(255, 0, 0, 1)">class</span><span style="color: rgba(0, 0, 255, 1)">="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="messageConverters"</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">list </span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">ref </span><span style="color: rgba(255, 0, 0, 1)">bean</span><span style="color: rgba(0, 0, 255, 1)">="mappingJacksonHttpMessageConverter"</span> <span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">list</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">property</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">bean</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">bean </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="mappingJacksonHttpMessageConverter"</span><span style="color: rgba(255, 0, 0, 1)"> class</span><span style="color: rgba(0, 0, 255, 1)">="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="supportedMediaTypes"</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">list</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">value</span><span style="color: rgba(0, 0, 255, 1)">></span>application/json;charset=UTF-8<span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">value</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">list</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">property</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">bean</span><span style="color: rgba(0, 0, 255, 1)">></span>
</beans>
其中:
注解配置:<context:annotation-config/>;
注解驱动:<mvc:annotation-driven/>;
自动扫描 controller 类,自动扫描 service 类:context:component-scan;
静态资源映射(我们 springmvc 配置的是拦截“/”,例如:/user/getUserInfo,REST 风格,但会导致静态文件(jpg,js,css 等)被拦截后不能正常显示):mvc:resources;
模型视图名称的解析(默认路径及后缀):InternalResourceViewResolver;
支持返回 json 格式(前后端分离场景下,返回数据格式):AnnotationMethodHandlerAdapter,MappingJackson2HttpMessageConverter。通常在前后端分离项目中,后台要向前端返回 json 格式的相应数据,以上已经在 spring-mvc.xml 中配置了 json 格式转换的处理,我们仍需要引入json支持的依赖包,在 pom.xml 文件中添加以下:
<!-- 支持 json,旧包 --> <dependency> <groupId>org.codehaus.jackson</groupId> <artifactId>jackson-core-asl</artifactId> <version>1.9.13</version> </dependency> <dependency> <groupId>org.codehaus.jackson</groupId> <artifactId>jackson-mapper-asl</artifactId> <version>1.9.13</version> </dependency> <!-- 使用 MappingJackson2HttpMessageConverter,加入最新的 FastJackson 依赖 --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.9.0.pr3</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.0.pr3</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>2.9.0.pr3</version> </dependency> <!-- google 的 json 格式支持 --> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.8.0</version> </dependency>
我们注意到,json 依赖包存在旧包和新包,由于本项目使用的 spring4.3.8,所以 mappingJacksonHttpMessageConverter 使用的是 MappingJackson2HttpMessageConverter,代替了 MappingJacksonHttpMessageConverter,否则项目启动时会报错;而使用 MappingJackson2HttpMessageConverter 时,我们就需要引入新的 json 依赖包了,如以上程序注释所示(jackson-core,jackson-databind,jackson-annotations)。我们还添加了 google 的 json 格式依赖包 Gson,Gson 提供了fromJson()
和toJson()
两个直接用于解析和生成的方法,前者实现反序列化,后者实现了序列化,后续的 json 数据返回程序示例中会再次提及。
6、配置 applicationContext.xml 文件,在这里我们配置数据源以及与mybatis 的整合配置,内容如下所示:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" 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:p="http://www.springframework.org/schema/p" xsi:schemaLocation=" http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"><span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 自动扫描SpringMVC包 ,将带有注解的类 纳入spring容器管理 </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">context:component-scan </span><span style="color: rgba(255, 0, 0, 1)">base-package</span><span style="color: rgba(0, 0, 255, 1)">="com.charlie"</span><span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 引入jdbc配置文件 </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">bean </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="propertyConfigurer"</span><span style="color: rgba(255, 0, 0, 1)"> class</span><span style="color: rgba(0, 0, 255, 1)">="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="locations"</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">list</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">value</span><span style="color: rgba(0, 0, 255, 1)">></span>classpath*:jdbc.properties<span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">value</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">list</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">property</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">bean</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> dataSource 配置 </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">bean </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="dataSource"</span><span style="color: rgba(255, 0, 0, 1)"> class</span><span style="color: rgba(0, 0, 255, 1)">="com.alibaba.druid.pool.DruidDataSource"</span><span style="color: rgba(255, 0, 0, 1)"> init-method</span><span style="color: rgba(0, 0, 255, 1)">="init"</span><span style="color: rgba(255, 0, 0, 1)"> destroy-method</span><span style="color: rgba(0, 0, 255, 1)">="close"</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 基本属性 url、user、password </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="driverClassName"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="${jdbc.driver}"</span><span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="url"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="${jdbc.url}"</span><span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="username"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="${jdbc.username}"</span><span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="password"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="${jdbc.password}"</span><span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 配置初始化大小、最小、最大 </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="initialSize"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="${ds.initialSize}"</span><span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="minIdle"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="${ds.minIdle}"</span><span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="maxActive"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="${ds.maxActive}"</span><span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 配置获取连接等待超时的时间 </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="maxWait"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="${ds.maxWait}"</span><span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="timeBetweenEvictionRunsMillis"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="${ds.timeBetweenEvictionRunsMillis}"</span><span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 配置一个连接在池中最小生存的时间,单位是毫秒 </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="minEvictableIdleTimeMillis"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="${ds.minEvictableIdleTimeMillis}"</span><span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="validationQuery"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="SELECT 'x'"</span><span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="testWhileIdle"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="true"</span><span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="testOnBorrow"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="false"</span><span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="testOnReturn"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="false"</span><span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 打开PSCache,并且指定每个连接上PSCache的大小 </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="poolPreparedStatements"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="false"</span><span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="maxPoolPreparedStatementPerConnectionSize"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="20"</span><span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 配置监控统计拦截的filters </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="filters"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="stat"</span><span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">bean</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> mybatis文件配置,扫描所有mapper.xml文件 </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 配置mybatisSqlSessionFactoryBean </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">bean </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="sqlSessionFactory"</span><span style="color: rgba(255, 0, 0, 1)"> class</span><span style="color: rgba(0, 0, 255, 1)">="org.mybatis.spring.SqlSessionFactoryBean"</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="dataSource"</span><span style="color: rgba(255, 0, 0, 1)"> ref</span><span style="color: rgba(0, 0, 255, 1)">="dataSource"</span> <span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="configLocation"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="classpath:mybatis.xml"</span><span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="mapperLocations"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="classpath*:com/charlie/dao/xml/*Mapper.xml"</span><span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">bean</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 配置SqlSessionTemplate </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">bean </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="sqlSessionTemplate"</span><span style="color: rgba(255, 0, 0, 1)"> class</span><span style="color: rgba(0, 0, 255, 1)">="org.mybatis.spring.SqlSessionTemplate"</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">constructor-arg </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="sqlSessionFactory"</span><span style="color: rgba(255, 0, 0, 1)"> ref</span><span style="color: rgba(0, 0, 255, 1)">="sqlSessionFactory"</span> <span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">bean</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 配置mybatis mapper接口,扫描所有dao </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">bean </span><span style="color: rgba(255, 0, 0, 1)">class</span><span style="color: rgba(0, 0, 255, 1)">="org.mybatis.spring.mapper.MapperScannerConfigurer"</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="basePackage"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="com.charlie.dao"</span><span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="sqlSessionTemplateBeanName"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="sqlSessionTemplate"</span><span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">bean</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 事务管理 通知 </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">tx:advice </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="txAdvice"</span><span style="color: rgba(255, 0, 0, 1)"> transaction-manager</span><span style="color: rgba(0, 0, 255, 1)">="transactionManager"</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">tx:attributes</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 对insert,update,delete 开头的方法进行事务管理,只要有异常就回滚 </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">tx:method </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="insert*"</span><span style="color: rgba(255, 0, 0, 1)"> propagation</span><span style="color: rgba(0, 0, 255, 1)">="REQUIRED"</span><span style="color: rgba(255, 0, 0, 1)"> rollback-for</span><span style="color: rgba(0, 0, 255, 1)">="java.lang.Throwable"</span><span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">tx:method </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="update*"</span><span style="color: rgba(255, 0, 0, 1)"> propagation</span><span style="color: rgba(0, 0, 255, 1)">="REQUIRED"</span><span style="color: rgba(255, 0, 0, 1)"> rollback-for</span><span style="color: rgba(0, 0, 255, 1)">="java.lang.Throwable"</span><span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">tx:method </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="delete*"</span><span style="color: rgba(255, 0, 0, 1)"> propagation</span><span style="color: rgba(0, 0, 255, 1)">="REQUIRED"</span><span style="color: rgba(255, 0, 0, 1)"> rollback-for</span><span style="color: rgba(0, 0, 255, 1)">="java.lang.Throwable"</span><span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> select,count开头的方法,开启只读,提高数据库访问性能 </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">tx:method </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="select*"</span><span style="color: rgba(255, 0, 0, 1)"> read-only</span><span style="color: rgba(0, 0, 255, 1)">="true"</span><span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">tx:method </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="count*"</span><span style="color: rgba(255, 0, 0, 1)"> read-only</span><span style="color: rgba(0, 0, 255, 1)">="true"</span><span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 对其他方法 使用默认的事务管理 </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">tx:method </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="*"</span><span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">tx:attributes</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">tx:advice</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">aop:config</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">aop:pointcut </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="serviceMethods"</span><span style="color: rgba(255, 0, 0, 1)"> expression</span><span style="color: rgba(0, 0, 255, 1)">="execution(* com.charlie.service..*(..))"</span><span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">aop:advisor </span><span style="color: rgba(255, 0, 0, 1)">advice-ref</span><span style="color: rgba(0, 0, 255, 1)">="txAdvice"</span><span style="color: rgba(255, 0, 0, 1)"> pointcut-ref</span><span style="color: rgba(0, 0, 255, 1)">="serviceMethods"</span><span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">aop:config</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 配置使Spring采用CGLIB代理 </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">aop:aspectj-autoproxy </span><span style="color: rgba(255, 0, 0, 1)">proxy-target-class</span><span style="color: rgba(0, 0, 255, 1)">="true"</span><span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 对dataSource 数据源进行事务管理 </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">bean </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="transactionManager"</span><span style="color: rgba(255, 0, 0, 1)"> class</span><span style="color: rgba(0, 0, 255, 1)">="org.springframework.jdbc.datasource.DataSourceTransactionManager"</span><span style="color: rgba(255, 0, 0, 1)"> p:dataSource-ref</span><span style="color: rgba(0, 0, 255, 1)">="dataSource"</span><span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 使用annotation注解方式配置事务,启用对事务注解的支持 </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">tx:annotation-driven </span><span style="color: rgba(255, 0, 0, 1)">transaction-manager</span><span style="color: rgba(0, 0, 255, 1)">="transactionManager"</span><span style="color: rgba(0, 0, 255, 1)">/></span>
</beans>
在这里,我们引入了之前配置的 jdbc.properties 属性文件来配置我们的 DataSource;配置了对 dataSource 数据源进行事务管理;使用 annotation 注解方式配置事务, 启用对事务注解的支持;
注意在这里我们添加了对mybatis的设置,实现 springmvc 与 mybatis 的整合,配置可扫描所有 mapper.xml 和 mapper dao 文件以及对事务的管理。
Springmvc 整合 mybatis,需要引入 mybatis 包,在 pom.xml 中添加以下依赖包:
<!--mybatis--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.4</version> </dependency> <!--mybatis spring 整合--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.3.1</version> </dependency>
我们如果想使用 mybatis 逆向工程插件生成 mybatis 的 mapper,entity 等代码,则需要在之前的 <build> 标签下添加 mybatis-generator 插件:
<build> <plugins> <!--mybatis 逆向工程插件--> <plugin> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-maven-plugin</artifactId> <version>1.3.5</version> <configuration> <verbose>true</verbose> <overwrite>true</overwrite> </configuration> </plugin> </plugins> </build>
添加后,我们 reimport 下,会在 maven project 下新增出相应的插件,我们之后会使用到 mybatis-generator:generate 自动生成实体类,mapper 文件,如下图:
7、在 applicationContext.xml 的配置中看出,我们仍需要配置 mybatis.xml 的文件,进行 mybatis 相关的配置,如下所示:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!-- 配置 mybatis 的缓存,延迟加载等等一系列属性 --> <settings> <!-- 该配置影响的所有映射器中配置的缓存的全局开关。默认 true --> <setting name="cacheEnabled" value="true" /> <!-- 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态。默认 false --> <setting name="lazyLoadingEnabled" value="true" /> <!-- 是否允许单一语句返回多结果集(需要兼容驱动)。 默认 true --> <setting name="multipleResultSetsEnabled" value="true" /> <!-- 使用列标签代替列名。不同的驱动在这方面会有不同的表现, 具体可参考相关驱动文档或通过测试这两种不同的模式来观察所用驱动的结果。默认 true --> <setting name="useColumnLabel" value="true" /> <!-- 允许 JDBC 支持自动生成主键,需要驱动兼容。 如果设置为 true 则这个设置强制使用自动生成主键,尽管一些驱动不能兼容但仍可正常工作(比如 Derby)。 默认 false --> <setting name="useGeneratedKeys" value="false" /> <!-- 指定 MyBatis 应如何自动映射列到字段或属性。 NONE 表示取消自动映射;PARTIAL 只会自动映射没有定义嵌套结果集映射的结果集。 FULL 会自动映射任意复杂的结果集(无论是否嵌套)。 默认 PARTIAL --> <setting name="autoMappingBehavior" value="PARTIAL" /><span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">setting </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="autoMappingUnknownColumnBehavior"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="WARNING"</span> <span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 配置默认的执行器。SIMPLE 就是普通的执行器;REUSE 执行器会重用预处理语句(prepared statements); BATCH 执行器将重用语句并执行批量更新。默认SIMPLE </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">setting </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="defaultExecutorType"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="SIMPLE"</span> <span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 设置超时时间,它决定驱动等待数据库响应的秒数。Not Set (null) </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">setting </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="defaultStatementTimeout"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="25"</span> <span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 为驱动的结果集获取数量(fetchSize)设置一个提示值。此参数只可以在查询设置中被覆盖。 </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">setting </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="defaultFetchSize"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="100"</span> <span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 允许在嵌套语句中使用分页(RowBounds)。 If allow, set the false. </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">setting </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="safeRowBoundsEnabled"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="false"</span> <span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN 到经典 Java 属性名 aColumn 的类似映射。 </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">setting </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="mapUnderscoreToCamelCase"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="false"</span> <span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> MyBatis 利用本地缓存机制(Local Cache)防止循环引用(circular references)和加速重复嵌套查询。 默认值为 SESSION,这种情况下会缓存一个会话中执行的所有查询。 若设置值为 STATEMENT,本地会话仅用在语句执行上,对相同 SqlSession 的不同调用将不会共享数据。 </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">setting </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="localCacheScope"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="SESSION"</span> <span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 当没有为参数提供特定的 JDBC 类型时,为空值指定 JDBC 类型。 某些驱动需要指定列的 JDBC 类型,多数情况直接用一般类型即可,比如 NULL、VARCHAR 或 OTHER。 </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">setting </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="jdbcTypeForNull"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="OTHER"</span> <span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 指定哪个对象的方法触发一次延迟加载。 </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">setting </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="lazyLoadTriggerMethods"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="equals,clone,hashCode,toString"</span> <span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">settings</span><span style="color: rgba(0, 0, 255, 1)">></span>
</configuration>
OK,到目前为止,该 web-demo 项目的环境搭建就基本完成了。
三、web 实例
webdemo 环境搭建完成后,我们进行程序的实例,实现 springmvc+mybatis 的逻辑层级,数据库的访问及视图展示等。
示例数据准备:在数据库中创建表 user,并插入一条数据:
CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(32) NOT NULL COMMENT '用户名称', `birthday` date DEFAULT NULL COMMENT '生日', `sex` char(1) DEFAULT NULL COMMENT '性别', `address` varchar(256) DEFAULT NULL COMMENT '地址', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8;
1、通过 mybatis-generator 插件,生成 User 表相应的实体类,mapper 文件,我们首先需要在 resources 下创建一个 generatorConfig.xml 文件,内容如下 (注意 xml 中 & 特殊字符的转义,使用 & 表示):
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd"><generatorConfiguration>
<classPathEntry location="F:\IdeaProjects\MavenRepositoryForCharlie\mysql\mysql-connector-java\6.0.6\mysql-connector-java-6.0.6.jar"/>
<context id="testTables" targetRuntime="MyBatis3" >
<commentGenerator>
<!-- 是否去除自动生成的注释 true:是 : false: 否 -->
<property name="suppressAllComments" value="true" />
</commentGenerator>
<!--数据库连接的信息:驱动类、连接地址、用户名、密码 -->
<jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/charlie_web_demo?characterEncoding=UTF-8&amp;useSSL=true&amp;serverTimezone=GMT%2B8"
userId="root"
password="p@ssw0rd">
</jdbcConnection>
<!-- 默认 false,把 JDBC DECIMAL 和 NUMERIC 类型解析为 Integer,为 true 时把 JDBC DECIMAL 和
NUMERIC 类型解析为 java.math.BigDecimal -->
<javaTypeResolver>
<property name="forceBigDecimals" value="false" />
</javaTypeResolver>
<!-- targetProject: 生成 PO 类的位置 -->
<javaModelGenerator targetPackage="com.charlie.entity"
targetProject="src\main\java">
<!-- enableSubPackages: 是否让 schema 作为包的后缀 -->
<property name="enableSubPackages" value="false" />
<!-- 从数据库返回的值被清理前后的空格 -->
<property name="trimStrings" value="true" />
</javaModelGenerator>
<!-- targetProject:mapper 映射文件生成的位置 -->
<sqlMapGenerator targetPackage="com.charlie.dao.xml"
targetProject="src\main\java">
<!-- enableSubPackages: 是否让 schema 作为包的后缀 -->
<property name="enableSubPackages" value="false" />
</sqlMapGenerator>
<!-- targetPackage:mapper 接口生成的位置 -->
<javaClientGenerator type="XMLMAPPER"
targetPackage="com.charlie.dao.mapper"
targetProject="src\main\java">
<!-- enableSubPackages: 是否让 schema 作为包的后缀 -->
<property name="enableSubPackages" value="false" />
</javaClientGenerator><span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 指定数据库表 </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">table </span><span style="color: rgba(255, 0, 0, 1)">tableName</span><span style="color: rgba(0, 0, 255, 1)">="user"</span><span style="color: rgba(0, 0, 255, 1)">></</span><span style="color: rgba(128, 0, 0, 1)">table</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 有些表的字段需要指定java类型 <table schema="" tableName=""> <columnOverride column="" javaType="" /> </table> </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">context</span><span style="color: rgba(0, 0, 255, 1)">></span>
</generatorConfiguration>
我们需要设置相应的 mysql 驱动包的路径,本 demo 中使用的是 mysql-connector-java-6.0.6.jar;设置数据库连接信息;指定 mybatis-generator 生成的实体类、mapper 映射文件、mapper 接口文件的包路径;并指定需要生成的数据库表,本示例演示的是 user 表。我们通过执行 maven projects 的 mybatis-generator:generate 来生成相应的程序,如下图所示:
执行完毕,会生成相应的实体类及 dao 文件,如下目录结构所示:
2、在 controller 包下,编写 UserController.java 类,代码如下:
package com.charlie.controller;import com.charlie.common.GenericController;
import com.charlie.entity.User;
import com.charlie.service.UserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;@Controller
@RequestMapping(value = "/user")
public class UserController extends GenericController {
private static final Logger logger = LoggerFactory.getLogger(UserController.class);@Autowired </span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> UserService userService; </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">返回jsp视图展示</span> @RequestMapping(value = "/getUserModel",method =<span style="color: rgba(0, 0, 0, 1)"> RequestMethod.GET) </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> ModelAndView getUsers1(@RequestParam Integer userId) { ModelAndView modelAndView </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> ModelAndView(); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">调用service方法得到用户列表</span> List<User> users =<span style="color: rgba(0, 0, 0, 1)"> userService.getUsers(userId); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">将得到的用户列表内容添加到ModelAndView中</span> modelAndView.addObject("users"<span style="color: rgba(0, 0, 0, 1)">,users); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">设置响应的jsp视图</span> modelAndView.setViewName("getUsers"<span style="color: rgba(0, 0, 0, 1)">); logger.info(</span>"===============================成功查询用户列表!"<span style="color: rgba(0, 0, 0, 1)">); </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> modelAndView; } </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">返回json格式数据,形式1</span> @RequestMapping(value = "/getUserJson1",method =<span style="color: rgba(0, 0, 0, 1)"> RequestMethod.GET) @ResponseBody </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> List getUsers2(@RequestParam Integer userId, HttpServletRequest request, HttpServletResponse response) { </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">调用service方法得到用户列表</span> List<User> users =<span style="color: rgba(0, 0, 0, 1)"> userService.getUsers(userId); logger.info(</span>"===============================成功查询用户列表!"<span style="color: rgba(0, 0, 0, 1)">); </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> users; } </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">返回json格式数据,形式2(自定义了返回的格式)</span> @RequestMapping(value = "/getUserJson2",method =<span style="color: rgba(0, 0, 0, 1)"> RequestMethod.GET) </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> getUsers3(@RequestParam Integer userId, HttpServletRequest request, HttpServletResponse response) { </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">调用service方法得到用户列表</span> List<User> users =<span style="color: rgba(0, 0, 0, 1)"> userService.getUsers(userId); logger.info(</span>"===============================成功查询用户列表!"<span style="color: rgba(0, 0, 0, 1)">); renderSuccessString(response, users); }
}
其中,@controller 注解标注本类为 controller 类;
@RequestMapping 注解实现 web REST 风格请求的映射;
@Autowired 用来绑定 service 实现类;
方法 getUsers1 实现了 JSP 视图的解析和展示,由于在 spring-mvc.xml 中已经设置了 jsp 视图解析的配置,这里 modelAndView.setViewName("getUsers") 就直接响应的 jsp 视图为 /WEB-INF/views 下的 getUsers.jsp 文件(详见 github 项目代码)。
由于在 spring-mvc.xml 中已经配置了支持 json 数据的处理,这里我们可直接使用 @ResponseBody 注解就可实现 json 格式数据的返回,如方法 getUsers2 所示。
方法 getUsers3 则使用的 Gson 的 json 格式支持,我们在程序中,通过 common 包下的 GenericController 类的 renderSuccessString 等方法结合 Result 自定义类自定义了返回数据的 json 内容。
以上 3 种方法的效果会在后续介绍中展示。
3、在 dao-->mapper 包下,编写 UserMapper.java,@Repository 注解标注本类为 mapper dao 类,本次示例我们直接使用 selectByExample 方法。
package com.charlie.dao.mapper;import com.charlie.entity.User;
import com.charlie.entity.UserExample;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;@Repository
public interface UserMapper {
long countByExample(UserExample example);</span><span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> deleteByExample(UserExample example); </span><span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> insert(User record); </span><span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> insertSelective(User record); List</span><User><span style="color: rgba(0, 0, 0, 1)"> selectByExample(UserExample example); </span><span style="color: rgba(0, 0, 255, 1)">int</span> updateByExampleSelective(@Param("record") User record, @Param("example"<span style="color: rgba(0, 0, 0, 1)">) UserExample example); </span><span style="color: rgba(0, 0, 255, 1)">int</span> updateByExample(@Param("record") User record, @Param("example"<span style="color: rgba(0, 0, 0, 1)">) UserExample example);
}
dao 文件对应的 mapper 映射文件 UserMapper.xml,使用的是 mybatis-generator 默认生成的,此处不再描述。
4、在 service 包下编写 UserService.java 类,并在 service-impl 包下编写 UserServiceImpl.java 实现此类的方法,如下:
UserService.java
package com.charlie.service;import com.charlie.entity.User;
import java.util.List;
public interface UserService {
List</span><User><span style="color: rgba(0, 0, 0, 1)"> getUsers(Integer userId);
}
UserServiceImpl.java(使用 @Service 注解,标注为 service 实现类,并 @Autowired 绑定相应的 UserMapper)
package com.charlie.service.impl;import com.charlie.entity.User;
import com.charlie.dao.mapper.UserMapper;
import com.charlie.entity.UserExample;
import com.charlie.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.List;
@Service
public class UserServiceImpl implements UserService {@Autowired </span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> UserMapper userMapper; </span><span style="color: rgba(0, 0, 255, 1)">public</span> List<User><span style="color: rgba(0, 0, 0, 1)"> getUsers(Integer userId) { UserExample example </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> UserExample(); UserExample.Criteria criteria </span>=<span style="color: rgba(0, 0, 0, 1)"> example.createCriteria(); </span><span style="color: rgba(0, 0, 255, 1)">if</span> (!"".equals(userId == <span style="color: rgba(0, 0, 255, 1)">null</span> ? ""<span style="color: rgba(0, 0, 0, 1)"> : userId)) { criteria.andIdEqualTo(userId); } </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> userMapper.selectByExample(example); }
}
至此,我们的程序示例编写完成,下面我们以 REST 访问方式,展示下访问的效果。
①测试 JSP 视图展示效果,访问 http://localhost:8080/user/getUserModel?userId=1,效果如下:
②测试原始的 @ResponseBody 注解的 json 数据返回格式效果,访问 http://localhost:8080/user/getUserJson1?userId=1,效果如下:
注意到,使用这种 json 方式,birthday 将数据库的日期格式转化为了时间戳,通常这不是我们所期望的,我们可以通过特定的方法调整 json 返回的日期格式转换;也可以通过一下的 Gson 的方式处理 json 数据。
③测试 Gson 自定义了具体的 json 数据返回格式效果,访问 http://localhost:8080/user/getUserJson2?userId=1,效果如下:
提示:以上 2 种浏览器中格式化的 json 数据是由 JSON View 插件实现的。若用户在调试过程中想要达到格式化的 json 数据展示,可以通过安装 Chrome 浏览器的插件 JSON View 实现。
本文,旨在快速搭建一个 springmvc+mybatis 整合的通用的 web-demo,其中 springmvc 或 mybatis 深入的使用方法,需要大家再去研究,这里不再赘述。
在github 源代码链接里,新添加了本次 demo 的 war 包文件 CharlieWebDemo.war,感兴趣也可以下载下来运行测试。