Intellij Idea搭建Spring环境-xml方式
本篇博客介绍适合使用xml配置Spring环境和SpringMVC环境。
① 首先我们使用maven新建一个普通的java web工程(包含WEB-INF/web.xml),然后在pom文件中相关的依赖
maven创建的web工程标准目录结构一般为:
|--root
|--pom.xml
|--src/
|--main/
|--java/ Java 源代码目录
|--resources/ 资源目录
|--webapp/ Web应用根目录
| --WEB-INF Web应用的安全目录
| -- web.xml 部署描述符文件,可以定义应用程序的配置信息,如 Servlet、过滤器、监听器
| -- lib 存放应用程序所需的外部库(JAR 文件)
| -- classes 存放编译后的 Java 类文件
|--test/
|--java/ -- 测试代码目录
|--resources --测试资源目录
|--target/ -- 项目主体输出目录
WEB-INF目录是WEB应用的安全目录。所谓安全就是客户端无法访问,只有服务端可以访问的目录。如果想在页面中直接访问其中的文件,必须通过web.xml文件对要访问的文件进行相应映射才能访问。
- ① webapp目录下的页面代码和资源文件,可以通过浏览器直接访问。
- ② WEB-INF目录是Java的WEB应用的安全目录,目录下文件不可以通过浏览器直接访问,但在springMVC内可以通过映射访问。
- ③ 一般客户端的页面放在webapp目录下,服务器端的页面放在WEB-INF目录下,文件放在WEB-INF目录下相对要安全很多。
pom.xml内容:
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.version>5.0.2.RELEASE</spring.version>
<jackson.version>2.11.4</jackson.version>
</properties>
<dependencies>
<!-- Spring 基础jar导入 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${spring.version}</version>
</dependency>
<!--start > Spring MVC-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<!--end > Spring MVC-->
<!-- start > Spring AOP-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- end > Spring AOP-->
<!-- start > Spring jdbc-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- end > Spring jdbc-->
<!-- start > Spring tx事务-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- end > Spring tx事务-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<!--Jackson-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>${jackson.version}</version>
</dependency>
</dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.5</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
② Spring 配置文件的所有命名空间
<?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:c="http://www.springframework.org/schema/c"
xmlns:cache="http://www.springframework.org/schema/cache"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:lang="http://www.springframework.org/schema/lang"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:task="http://www.springframework.org/schema/task"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:beans="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.3.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-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/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.3.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.3.xsd
http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-4.3.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.3.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-4.3.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd ">
</beans>
注:引入相应的命名控件有些是需要引入依赖的。
如果觉得命名空间中的版本号不对,也可以修改版本号,或者把版本号去掉,都不影响使用。
如果觉得不需要这么多的命名空间,也可以删除不需要的,如果要删除,需要删除两部分的,一个是xmls里面的,还有一个就是xsi:schemalocation中的。
web.xml
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<!--Spring 配置-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!--Spring MVC 配置-->
<servlet>
<servlet-name>SpringMVC</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:springMVC.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>SpringMVC</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
</web-app>
classpath是指 WEB-INF文件夹下的classes目录。
同时这里要特别注意一个问题就是web.xml中的标签配置是有约定的顺序的,否则可能会有红色的波浪线提示。
当有多个配置文件加载时,可采用下面代码来配置:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath*:conf/spring/applicationContext_core*.xml,
classpath*:conf/spring/applicationContext_dict*.xml,
classpath*:conf/spring/applicationContext_hibernate.xml,
......
</param-value>
</context-param>
或者
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:**/applicationContext-*.xml</param-value>
</context-param>
**/表示任意目录。
**/applicationContext-*.xml表示任意目录下的以"applicationContext-"开头的XML文件。
Spring配置文件最好以"applicationContext-"开头,且最好把所有Spring配置文件都放在一个统一的目录下,也可以分模块创建。
contextConfigLocation在spring中的作用
Spring 提供ServletContextListener 的一个实现类ContextLoaderListener ,该类可以作为listener使用,加载配置文件的流程:
1)org.springframework.web.context.ContextLoaderListener#contextInitialized
2)org.springframework.web.context.ContextLoader#configureAndRefreshWebApplicationContext
如果没有contextConfigLocation指定配置文件,则Spring自动查找applicationContext.xml配置文件。如果有contextConfigLocation,则利用该参数确定的配置文件。该参数指定的一个字符串,Spring 的ContextLoaderListener 负责将该字符串分解成多个配置文件,逗号、空格及分号都可作为字符串的分割符。如果既没有applicationContext.xml文件,也没有使用contextConfigLocation参数确定配置文件,或者contextConfigLocation确定的配置文件不存在。都将导致Spring无法加载配置文件或无法正常创建ApplicationContext实例。
DispatcherServlet配置的url-pattern
DispatcherServlet作用:拦截请求(浏览器的访问),然后根据自己定义的规则,去匹配处理器(Controller)来处理。
url-pattern一般有三种配置方式:
- 绝对路径 /UserServlet
- 多级目录 /aaa/bbb/UserServlet
- 通配符匹配 *.action *.do (只要请求的后置是.action 或.do都会执行该servlet)
有两种格式的建议不写:
- <url-pattern>/</url-pattern>:这样写的话,DispatcherServlet会将静态资源的获取请求,如.css、.js、.jpg、.png等资源的获取请求,当作一个普通的Controller请求。中央调度器会调用处理器映射器为其查找相应的处理器,这是找不到的,会报404。
- <url-pattern>/*</url-pattern>:*表示所有,即静态资源、动态页面(jsp页面,servlet)、其他请求都会被拦截。把静态资源、jsp页面的获取请求当作Controller请求去找处理器,然后找不到,也会报404。
当DispatcherServlet 的url-pattern配置成 / 访问不到静态资源的解决方案:
1)在web.xml中添加以下代码:
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.png</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>*.css</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.js</url-pattern>
</servlet-mapping>
2)在springmvc.xml中加以下代码:<mvc:default-servlet-handler/>
<mvc:default-servlet-handler/>会将对静态资源的访问请求通过HandlerMapping映射到默认Servlet 请求处理器DefaultServletHittpRequestHandler对象。而该处理器调用了Tomcat的DefaultServlet来处理静态资源的访问请求。当然了,要想使用<mvc: ...>标签,需要引入mvc约束。
3)使用MVC的resources解决
在Spring3.0.4版本后,Spring中定义了专门用于处理静态资源访问请求的处理器ResourceHttpRequestHandle。并且添加了<mvc:resources>标签,专门用于解决静态资源无法访问问题。需要在springmvc.xml中添加如下形式的配置:
<mvc:resources location="/images/" mapping="/images/**"/>
- location表示静态资源所在目录。当然,这里的目录可以是/WEB-INF/目录及其子目录。
- mapping表示对该资源的请求。注意,后面是两个星号**。
该配置会把对该静态资源的访问请求经HandlerMapping直接映射到静态资源处理器对象ResourceHttpRequestHandler。
Intellij Idea配置web.xml
Intellij Idea配置tomcat
Tomcat部署项目
applicationContext.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:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:beans="http://www.springframework.org/schema/beans"
xsi:schemaLocation="
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.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-4.3.xsd ">
<!--扫描包,排除注解是@Controller和@RestController的-->
<context:component-scan base-package="com.harvey">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
<context:exclude-filter type="annotation" expression="org.springframework.web.bind.annotation.RestController"/>
</context:component-scan>
<!--配置数据源 <bean/>-->
<!--配置事务管理器 <bean/>-->
<!-- 启用对事务注解的支持 <tx:annotation-driven transaction-manager="transactionManager"/>-->
<!--配置AOP <bean/>-->
<!--其他<bean/>...-->
</beans>
springMVC.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:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:beans="http://www.springframework.org/schema/beans"
xsi:schemaLocation="
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-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/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--开启注解-->
<mvc:annotation-driven/>
<!--扫描包含@Controller和@RestController-->
<context:component-scan base-package="com.harvey">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
<context:include-filter type="annotation" expression="org.springframework.web.bind.annotation.RestController"/>
</context:component-scan>
<!-- 静态资源访问 <mvc:resources/> -->
<!-- 配置拦截器 <mvc:interceptors/> -->
<!--......-->
<!-- 配置消息转换器,完成请求和注解POJO的映射 -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="mappingJacksonHttpMessageConverter"/>
</list>
</property>
</bean>
<bean id="mappingJacksonHttpMessageConverter"
class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>application/json;charset=UTF-8</value>
</list>
</property>
</bean>
<!--配置视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
常用配置项
context:annotation-config
<context:annotation-config> 是用于激活那些已经在spring容器里注册过的bean上面的注解,也就是显示的向Spring注册:
AutowiredAnnotationBeanPostProcessor
CommonAnnotationBeanPostProcessor
PersistenceAnnotationBeanPostProcessor
RequiredAnnotationBeanPostProcessor
这四个Processor,注册这4个BeanPostProcessor的作用,就是为了你的系统能够识别相应的注解。BeanPostProcessor就是处理注解的处理器。
1)比如我们要使用@Autowired注解,那么就必须事先在 Spring 容器中声明 AutowiredAnnotationBeanPostProcessor Bean。传统声明方式如下:
<bean class="org.springframework.beans.factory.annotation. AutowiredAnnotationBeanPostProcessor "/>
2)如果想使用@Resource 、@PostConstruct、@PreDestroy等注解就必须声明CommonAnnotationBeanPostProcessor。传统声明方式如下:
<bean class="org.springframework.beans.factory.annotation. CommonAnnotationBeanPostProcessor"/>
3)如果想使用@PersistenceContext注解,就必须声明PersistenceAnnotationBeanPostProcessor的Bean。传统声明方式如下:
<bean class="org.springframework.beans.factory.annotation.PersistenceAnnotationBeanPostProcessor"/>
4)如果想使用 @Required的注解,就必须声明RequiredAnnotationBeanPostProcessor的Bean。传统声明方式如下:
<bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor"/>
一般来说,像@Resource 、@PostConstruct、@Antowired这些注解在自动注入还是比较常用,所以如果总是需要按照传统的方式一条一条配置就显得有些繁琐和没有必要,于是spring给我们提供<context:annotation-config/>的简化配置方式,自动帮你完成声明。
思考1:假如我们要使用如@Component、@Controller、@Service等这些注解,使用能否激活这些注解呢?
答案:单纯使用<context:annotation-config/>对上面这些注解无效,不能激活!
因此我们常用的是使用<context:component-scan>,它除了具有上面的功能之外,还具有自动将带有@Component,@Service,@Repository等注解的对象注册到spring容器中的功能。
mvc:annotation-driven
Spring 3.0.x中使用了mvc:annotation-driven后,默认会帮我们注册默认处理请求,参数和返回值的类,其中最主要的两个类:DefaultAnnotationHandlerMapping 和 AnnotationMethodHandlerAdapter ,分别为HandlerMapping的实现类和HandlerAdapter的实现类,从3.1.x版本开始对应实现类改为了RequestMappingHandlerMapping和RequestMappingHandlerAdapter。
1)HandlerMapping的实现类的作用:实现类RequestMappingHandlerMapping,它会处理@RequestMapping 注解,并将其注册到请求映射表中。
2)HandlerAdapter的实现类的作用:实现类RequestMappingHandlerAdapter,则是处理请求的适配器,确定调用哪个类的哪个方法,并且构造方法参数,返回值。
在实际开发使用SpringMVC开启这个配置,否则会出现一些功能不能正常使用!
tx:annotation-driven
<tx:annotation-driven/> 会有一个属性来指定使用哪个事务管理器,如:<tx:annotation-driven transaction-manager="transactionManager" />。然后事务管理器 transactionManager 会引用 dataSource (如果我们使用JPA或Hibernate,也需要指定一个 entityManagerFactory ),dataSouce 肯定就是直接对数据库的了。
这样逐层引用下去,所以我们使用@Transactional 注解可以控制事务就通俗易懂了。另外要提一下的就是 spring 是使用 aop 通过 asm 操作java字节码的方式来实现对方法的前后事务管理的。
在 spring-framework-reference.pdf 文档上有这样一段话:
tx:annotation-driven only looks for @Transactional on beans in the same application context it is defined in. This means that, if you put tx:annotation-driven/ in a WebApplicationContext for a DispatcherServlet, it only checks for @Transactional beans in your controllers, and not your services.
意思就是:tx:annoation-driven只会查找和它在相同的应用上下文件中定义的bean上面的@Transactional注解,如果你把它放在Dispatcher的应用上下文中,它只检查控制器(Controller)上的@Transactional注解,而不是你services上的@Transactional注解。
所以,可以确定的是我们是可以在Controller上使用事务注解的,但是我们不推荐这样做。