1. SpringMVC框架的作用
SpringMVC解决了V-C交互的问题,即V(View:视图)和C(Controller:控制器)之间的交互问题,具体表现在:用户可以通过视图将请求数据提交给服务器端的控制器,而控制器可以接收到相关数据后进行处理,最终,给予客户端某个视图,使得客户端得到响应结果。
在传统的JavaEE技术中,使用Servlet作为控制器,存在的问题主要在于:因为大多情况下,某1个Servlet可能对应的就只是1个功能(1种请求),在一个完事的软件系统中,可能有大量的功能,则需要编写大量的Servlet类,导致Servlet实例过多,并且配置信息过多,进而导致代码不易于管理和维护!另外,传统的开发模式也存在其它使用不便利的做法。
2. SpringMVC框架的核心组件
-
DispatcherServlet
:前端控制器,主要用于接收所有请求; -
HandlerMapping
:记录请求路径与处理请求的控制器的对应关系(映射关系); -
Controller
:具体处理请求的组件; -
ModelAndView
:控制器的返回结果,包括处理得到的数据(Model)和视图名称(View); -
ViewResolver
:视图解析器,根据视图名称确定视图组件。
3. SpringMVC HelloWorld
3.1. 目标
在浏览器中输入网址http://localhost:8080/项目名称/hello.do
即可打开所设计的页面,页面内容可以自定义。
3.2. 创建项目
创建Maven Project,创建时,勾选中Create a simple project,Group Id为cn.tedu.spring
,Artifact Id为SpringMVC-01
,Packaging选择war
。
创建完成后,首先,生成web.xml文件,对项目点右键,在Targeted Runtime中勾选Tomcat,从前序的项目中复制Spring的配置文件到当前项目的src/main/resources下,删除其中已有的配置,必须添加spring-webmvc
依赖(使用4.2或以上版本即可):
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.9.RELEASE</version>
</dependency>
3.3. 配置DispatcherServlet使之接收所有请求
在SpringMVC框架中已经定义了DispatcherServlet
,用于接收所有请求,它终究是一个Servlet
,必须在web.xml文件中进行配置,否则,当启动Tomcat时,它根本就不会工作!
基本配置代码如下:
<servlet>
<servlet-name>SpringMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SpringMVC</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
然后,SpringMVC框架是基于Spring框架的,应该在项目启动时就加载Spring的配置文件,
使得相关配置是生效的!在DispatcherServlet
的父类FrameworkServlet
中,定义了contextConfigLocation
属性,
该属性的值应该是Spring配置文件的位置,当设置了值以后,初始化DispatcherServlet
时,就会自动读取Spring的配置文件!所以,继续补充配置:
<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:spring.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>SpringMVC</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
注意:Spring的配置文件应该在src/main/resources下,并且文件名应该是spring.xml,与以上配置保持一致!
配置完成后,在spring.xml中配置组件扫描:
<context:component-scan
base-package="cn.tedu.spring" />
然后创建测试类:
package cn.tedu.spring;
import org.springframework.stereotype.Component;
@Component
public class Tests {
public Tests() {
System.out.println("Tests()");
}
}
最后,将项目部署到Tomcat,启动Tomcat,在控制台可以看到以上构造方法中输出的内容!
3.4. 使用控制器接收请求
先创建cn.tedu.spring.HelloController
控制器类,添加@Controller
注解:
package cn.tedu.spring;
import org.springframework.stereotype.Controller;
@Controller
public class HelloController {
}
注意:控制器类必须放在组件扫描范围之内!
然后,在类中添加处理请求的方法,关于方法的声明:
-
应该使用
public
权限; -
暂时使用
String
作为返回值类型; -
方法名称可以自定义;
-
参数列表暂时留空。
定义好方法后,还应该在方法之前使用@RequestMapping
注解,配置其对应的请求路径:
@RequestMapping("hello.do")
public String showHello() {
System.out.println("HelloController.showHello()");
return null;
}
以上配置,就实现了请求路径与处理请求的方法的对应关系,当客户端提交了hello.do
路径的请求时,SpringMVC框架就会自动调用其对应的showHello()
方法进行处理!
完成后,重新部署项目,通过http://localhost:8080/SpringMVC-01/hello.do
测试访问,在控制台可以看到以上方法中输出的内容,每次访问输出1次。
3.5. 显示页面
在webapp/WEB-INF下创建名为templates的文件夹,然后,在该文件夹中创建hello.html文件,并设计页面文件中的显示内容。
本次是希望使用Thymeleaf实现界面,所以,还需要添加thymeleaf
和thymeleaf-spring4
这2项依赖:
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf</artifactId>
<version>3.0.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring4</artifactId>
<version>3.0.9.RELEASE</version>
</dependency>
然后,还需要配置ServletContextTemplateResolver模版解析器,根据模版解析器得到SpringTemplateEngine模版引擎,然后再基于模版引擎得到ThymeleafViewResolver视图解析器!具体配置代码如下:
<!-- 模版解析器 -->
<bean id="templateResolver"
class="org.thymeleaf.templateresolver.ServletContextTemplateResolver">
<property name="prefix" value="/WEB-INF/templates/" />
<property name="suffix" value=".html" />
<property name="characterEncoding" value="utf-8" />
<property name="templateMode" value="HTML" />
<property name="cacheable" value="false" />
</bean>
<!-- 模版引擎 -->
<bean id="templateEngine"
class="org.thymeleaf.spring4.SpringTemplateEngine">
<property name="templateResolver"
ref="templateResolver" />
</bean>
<!-- 视图解析器 -->
<bean class="org.thymeleaf.spring4.view.ThymeleafViewResolver">
<property name="templateEngine"
ref="templateEngine" />
<property name="characterEncoding" value="utf-8" />
</bean>
4. 使用SpringMVC接收请求参数
4.1. 初期目标
创建新的项目,Artifact Id为SpringMVC-02
,其它配置不变,要求实现:通过http://localhost:8080/SpringMVC-02/reg.do
能打开注册页面,页面中需要有1个注册的表单,表单中至少包括:用户名、密码、年龄、手机号码、电子邮箱这5个数据的输入框,及1个提交按钮;另外,通过http://localhost:8080/SpringMVC-02/login.do
能打开登录页面,内容与注册页面大致相同,只需要用户名、密码这2个输入框即可。
4.2. 创建项目
先把项目创建出来,需要执行5项操作:生成web.xml文件;添加Tomcat运行环境;从前序项目中复制依赖;从前序项目中复制spring.xml;打开前序项目中的web.xml,将DispatcherServlet
的配置复制到当前项目的web.xml文件中。
复制得到的spring.xml中已经配置了组件扫描,如果接下来要创建的类的包不变,则不需要修改,如果计划将类放在别的包中,需要修改组件扫描配置的包名。
4.3. 开发页面
在webapp/WEB-INF/下创建templates文件夹,并在该文件夹下分别创建reg.html和login.html这2个页面文件,分别表示注册页面和登录页面。
4.4. 创建控制器接收并处理请求
创建cn.tedu.spring.UserController
控制器类,在类之前添加@Controller
注解,然后,在类中添加2个方法,处理所设计的2个请求:
@Controller
public class UserController {
public UserController() {
System.out.println("UserController()");
}
@RequestMapping("reg.do")
public String showRegister() {
System.out.println("UserController.showRegister()");
return "reg";
}
@RequestMapping("login.do")
public String showLogin() {
System.out.println("UserController.showLogin()");
return "login";
}
}
4.5. 通过HttpServletRequest接收请求参数 【不推荐】
可以在处理请求的方法的参数列表中添加HttpServletRequest
类型的参数,然后,在方法体中,调用参数对象的String getParameter(String name)
方法即可获取客户端提交的请求参数:
@RequestMapping("handle_register.do")
public String handleRegister(HttpServletRequest request) {
System.out.println("UserController.handleRegister()");
String username = request.getParameter("username");
String password = request.getParameter("password");
Integer age = Integer.valueOf(request.getParameter("age"));
String phone = request.getParameter("phone");
String email = request.getParameter("email");
System.out.println("username=" + username);
System.out.println("password=" + password);
System.out.println("age=" + age);
System.out.println("phone=" + phone);
System.out.println("email=" + email);
return null;
}
通常,并不推荐使用这种做法获取请求参数,主要问题有:
-
编写代码比较麻烦;
-
如果期望的数据类型不是
String
类型,需要自行转换类型; -
不便于执行单元测试。
4.6. 直接将请求参数声明为处理请求的方法的参数 【推荐】
可以将客户端提交的请求参数,直接声明为处理请求的方法的参数,甚至,还可以将这些参数的类型声明为所期望的类型,例如“年龄”的类型直接声明为Integer
即可,SpringMVC框架会自动完成数据类型的转换,当然,务必保证客户端所提交的数据是可以被转换成Integer
的,否则,可能出现异常。
@RequestMapping("handle_register.do")
public String handleRegister(String username,
String password, Integer age,
String phone, String email) {
System.out.println("UserController.handleRegister()");
System.out.println("username=" + username);
System.out.println("password=" + password);
System.out.println("age=" + (age + 1));
System.out.println("phone=" + phone);
System.out.println("email=" + email);
return null;
}
使用这种做法时,需要保证请求参数的名称,与方法的参数名称保持一致!如果名称不一致,则服务器端的方法的参数值将是null
值。
这种做法优点非常多,主要是简单、易用,但是,不适用于请求参数过多的应用场景!
4.7. 将请求参数封装并使用封装的类型作为方法参数 【推荐】
可以将若干个请求参数封装在自定义的数据类型中,例如:
public class User {
private String username;
private String password;
private Integer age;
private String phone;
private String email;
}
然后,将该类型作为处理请求的方法的参数即可:
@RequestMapping("handle_register.do")
public String handleRegister(User user) {
System.out.println("UserController.handleRegister()");
System.out.println(user);
return null;
}
4.8. 小结
永远不用第1种(使用HttpServletRequest
)做法!
如果请求参数数量较多(超过5个、6个左右),或参数数量可能变化,或参数的数据意义可能变化,优先使用第3种(封装)做法!
如果请求参数数量较少(通常不超过5个、4个左右),并且参数数量固定,优先使用第2种(穷举参数)做法!
-------------------------------------------------------
附1:依赖错误的解决方案
-
关闭Eclipse;
-
删除**.m2**文件夹;
-
打开Eclipse;
-
对项目点右键,选择Maven > Update Project,且勾选中**Force update …**再执行更新。
附2:Tomcat启动失败的解决方案
-
如果启动失败时,弹出对话框,且对话框中有8009等端口号的字样,必然是因为前序已经启动Tomcat,没有关闭,或没有正确关闭,导致前序的Tomcat依然处于运行状态,依然占用着端口,则再次启动就会失败!可以在Tomcat安装目录下的bin目录中执行
shutdown
指令,先结束前序的Tomcat,然后再次重新启动,如果不会指行指令,重新启动电脑也是可以的; -
如果不存在以上问题,可以尝试将项目Clean之后再次启动;
-
如果以上解决方案失败,将Tomcat也Clean之后再次启动;
-
如果问题仍存在,则Eclipse的控制台应该有错误提示,如果包含
ZipException
(在大量的异常信息中可能也会有1条),则必然是因为某个jar包文件损坏导致的,则考虑最近添加过哪些jar包,删除这些jar包文件并重新下载,或更换所使用的jar包的版本均可; -
如果问题仍存在,且并没有提示
ZipException
,绝大部分是LifecycleException
,应该将Servers
面板中的Tomcat删除,并在名为Servers
的项目删除,然后重新添加回来,再次尝试; -
如果以上解决方案均失败,则还是删除Tomcat,但是,添加时,添加另一个新的Tomcat,甚至版本不同的Tomcat。
附3:使用SpringMVC时提示No Mapping Found的解决方案
-
务必按照笔记中的开发顺序,先保证启动Tomcat时可以看到测试类中构造方法输出的日志;
-
控制器类没有添加
@Controller
注解(可能粗心添加了别的注解); -
控制器类没有放在组件扫描对应的包中;
-
没有配置
@RequestMapping
,或配置错误; -
实际访问时的路径,与配置的路径不匹配。
public class LoginServlet extends HttpServlet {
}