1. 配置
一个常见的以servlet为主的Java Web与Spring MVC的首要区别在于WEB-INF文件夹下的web.xml的配置。老式的Servlet项目,web.xml中会配置很多Servlet,处理不同的url。而Spring MVC则将请求用一个前端Servlet来统一分发到不同的Controller,由Controller控制器处理具体的请求(中间还有Handler Mapping过程,此处略)。这样就减少了很多不必要的Servlet配置了。
首先配置web.xml
,一般来说,以下配置即可够用:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<display-name>SpringMVCDemo Web Application</display-name>
<!--配置log4j-->
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>classpath:log4j.properties</param-value>
</context-param>
<!--配置applicationContext-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/applicationContext.xml
</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<listener>
<listener-class>
org.springframework.web.util.Log4jConfigListener
</listener-class>
</listener>
<!--前端Dispatcher-->
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<!--启动即加载该servlet-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!--处理中文的Filter-->
<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>
</web-app>
名为dispatcher
的Servlet,是前端控制器。它有相应的配置文件,既可以自己指定一个配置文件,也可以不做处理,但要在WEB-INF文件夹下建立一个dispatcher-servlet.xml
的文件,这个就是它默认的配置文件,与它的名字一致。
在dispatcher-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: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.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd">
<!--配置注解驱动-->
<mvc:annotation-driven />
<!--配置扫描器-->
<context:component-scan base-package="com.chenyi.learn"/>
<!--静态文件自动处理-->
<mvc:default-servlet-handler/>
<!--配置视图解析器-->
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
此外注意我们在web.xml文件中配置了一个applicationContext.xml
文件,并给了对应的目录。这个文件用于在Spring容器启动的时候,初始化一些配置。一些开发中用到的Bean都可以在此处配置。我们现在在里面写了以下内容:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url"
value="${mysql.db.url}?useUnicode=true&characterEncoding=UTF-8&failOverReadOnly=false&autoReconnect=true" />
<property name="username" value="${mysql.db.user}" />
<property name="password" value="${mysql.db.pwd}" />
<property name="removeAbandoned" value="true"/>
<property name= "testWhileIdle" value="false" />
<property name= "testOnBorrow" value="true" />
<property name= "testOnReturn" value="false" />
<property name= "validationQuery" value="select 1" />
</bean>
</beans>
这里面配置了MySQL的数据源的Bean。里面的参数由pom.xml
中依据对应的proflie进行过滤,对了,我们这儿就不用conf.properties
来处理MySQL不同环境不同配置的问题。
2. 先运行起来
首先创建一些分隔代码要用的包和一些静态文件目录。
注意到js文件中我增加了个目前很火的vue的js文件。另外把index.jsp文件修改一下:
<html>
<script src="js/vue.min.js" type="text/javascript"></script>
<body>
<h2>Hello World!</h2>
</body>
</html>
增加对js的引用,运行时用来测试静态文件引用是否成功。注意它代码中的路径和项目中文件的路径。另外在dispatcher-servlet.xml
中,我们已经配置了静态文件处理的handler,如果没有那个配置,会找不到静态文件。
Intellij 菜单->Run->Edit Configurations:
"+"增加一个新的Tomcat本地服务器。这个必须要事先安装好Tomcat。其实Linux上安装Tomcat很容易,把下载的包解压到某个文件夹下,然后在Bash/Zsh配置文件下增加几个环境变量就可以了。具体可以Google。比较喜欢这种安装方式,Hadoop/Hbase/Spark都是这样安装的,不像windows下,做了很多我们不知道的事情。配置好了之后是这样子的:
点击运行,会自动启动浏览器。
按照js的访问路径在浏览器上输入路径,如果正常访问,则结果是这样子:
通过以上操作我们能够在本地正常运行Tomcat了,也能运行我们的初始项目了。接下来我们写一个简单的controller代码,开始SpringMVC的学习。
简单的代码
在controller包下增加一个HomeController.java
文件,内容如下:
@Controller
@RequestMapping("/")
public class HomeController {
@RequestMapping("/home")
public String sayHome() {
return "home";
}
}
@Controller
注解将该类注册为一个Bean,Spring容器初始化时会创建该类对像。可能有疑问,容器是怎么找到该注解呢?之前我们在dispatcher-servlet.xml
中定义了一句代码:
<!--配置扫描器-->
<context:component-scan base-package="com.chenyi.learn"/>
前端控制器初始化时会扫描这个配置下的代码,如果发现带有@Controller
的类,就会为它生成一个Bean。这种方法就是Spring中的注解,即AOP,注意哦,它的实现原理就是动态代理,有机会把这部分好好梳理一下。
@RequestMapping
注解就是把一个类或者某个方法注册到一个路径下,前端控制器根据请求中的路径,匹配到某个类对象,某个方法进行处理。这也是面向切面编程的方法,我猜想是利用动态代理把函数注册到一个全局变量中,然后根据这个全局变量查找对应方法进行处理。后续再研究这部分。
我们把sayHome
函数注册到了/home
路径下。代码中返回了一个home
字符串,这个字符串会用来同dispatcher-servlet.xml
里面配置的视图解析器中的参数构造出返回的html文件及路径。我们之前的配置是:
<!--配置视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>
</bean>
根据这个配置,我们的视图html文件路径是/WEB-INF/views/home.jsp
。于是在代码的该路径下创建一个home.jsp
文件,内容为:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Home</title>
</head>
<body>
Welcome to Home Page!
</body>
</html>
保存,运行,并在浏览器中输入http://localhost:8081/home
,会得到如下结果:
这样,咱们简单的运行代码已经实现了。接下来为了更好理解Spring MVC的开发方法,我们开发一个能通过Json接口来进行CRUD的小项目。