Spring 之 SpringMVC
Web 应用的分层通常是 MVC,对应着数据层-视图层-控制层
SpringMVC 就是控制层框架
SpringMVC 工作流程
Spring MVC 框架主要由 DispatcherServlet、处理器映射、控制器、视图解析器、视图组成
- 客户端请求提交到 DispatcherServlet。
- 由 DispatcherServlet 控制器寻找一个或多个 HandlerMapping,找到处理请求的 Controller。
- DispatcherServlet 将请求提交到 Controller。
- Controller 调用业务逻辑处理后返回 ModelAndView。
- DispatcherServlet 寻找一个或多个 ViewResolver 视图解析器,找到 ModelAndView 指定的视图。
- 视图(JSP 等视图层)负责将结果显示到客户端。
从宏观角度考虑,DispatcherServlet 是整个 Web 应用的控制器;从微观考虑,Controller 是单个 Http 请求处理过程中的控制器,而 ModelAndView 是 Http 请求过程中返回的模型(Model)和视图(View)。
SpringMVC 的实现实例
在 web.xml 文件中配置部署 DispatcherServlet
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<web-app
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
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>springMVC</display-name>
<!-- 部署 DispatcherServlet -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class
>org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<!-- 加载springmvc-servlet.xml配置文件 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-servlet.xml</param-value>
</init-param>
<!-- 表示容器再启动时立即加载servlet -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<!-- 处理所有URL -->
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>创建 Controller 类
1
2
3
4
5
6public class LoginController implements Controller {
public ModelAndView handleRequest(HttpServletRequest arg0,
HttpServletResponse arg1) throws Exception {
return new ModelAndView("/WEB-INF/jsp/register.jsp");
}
}创建 springmvc-servlet.xml 配置 Controller 的映射信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd"
>
<!-- LoginController控制器类,映射到"/login" -->
<bean name="/login" class="controller.LoginController" />
</beans>在配置文件中定义视图解析器(ViewResolver)
1
2
3
4
5
6
7
8<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver"
>
<!--前缀-->
<property name="prefix" value="/WEB-INF/jsp/" />
<!--后缀-->
<property name="suffix" value=".jsp" />
</bean>上述视图解析器配置了前缀和后缀两个属性,因此 Controller 中只需要返回
login
,视图解析器就会自动添加前缀和后缀
通过注释实现 SpringMVC
传统风格的控制器不仅需要在配置文件中部署映射,而且只能编写一个处理方法,不够灵活。
在基于注解的控制器类中可以编写多个处理方法,进而可以处理多个请求(动作),这就允许将相关的操作编写在同一个控制器类中,从而减少控制器类的数量,方便以后的维护。
基于注解的控制器不需要在配置文件中部署映射,仅需要使用 RequestMapping 注释类型注解一个方法进行请求处理。
注释实现的 Controller 类
1 | /** |
使用注释需要在配置文件开启注释扫描
1 | <!-- 使用扫描机制扫描控制器类,控制器类都在controller包及其子包下 --> |
SpringMVC 获取参数
把表单参数写在控制器类相应方法的形参中,即形参名称与请求参数名称完全相同。适用于 get 和 post
1
2
3
4
5
6
7
8
9
10
11
12
13"/register") (
public String register(String uname,String upass,Model model) {
if ("zhangsan".equals(uname)
&& "123456".equals(upass)) {
logger.info("成功");
return "login"; // 注册成功,跳转到 login.jsp
} else {
logger.info("失败");
// 在register.jsp页面上可以使用EL表达式取出model的uname值
model.addAttribute("uname", uname);
return "register"; // 返回 register.jsp
}
}通过一个实体 Bean 来接收请求参数,Bean 的属性名称必须与请求参数名称相同.适用于 get 和 post
1
2
3
4
5
6
7
8
9
10
11"/login") (
public String login(UserForm user, HttpSession session, Model model) {
if ("zhangsan".equals(user.getUname())
&& "123456".equals(user.getUpass())) {
session.setAttribute("u", user);
return "main"; // 登录成功,跳转到 main.jsp
} else {
model.addAttribute("messageError", "用户名或密码错误");
return "login";
}
}通过 HttpServletRequest 接收请求参数适用于 get 和 post
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16"/register") (
/**
* 通过HttpServletRequest接收请求参数
*/
public String register(HttpServletRequest request,Model model) {
String uname = request.getParameter("uname");
String upass = request.getParameter("upass");
if ("zhangsan".equals(uname)
&& "123456".equals(upass)) {
return "login"; // 注册成功,跳转到 login.jsp
} else {
// 在register.jsp页面上可以使用EL表达式取出model的uname值
model.addAttribute("uname", uname);
return "register"; // 返回 register.jsp
}
}通过 @PathVariable 获取 URL 中的参数,适用 get
1
2
3
4
5
6
7
8
9public String register(@PathVariable String uname,@PathVariable String upass,Model model) {
if ("zhangsan".equals(uname) && "123456".equals(upass)) {
return "login"; // 注册成功,跳转到 login.jsp
} else {
// 在register.jsp页面上可以使用EL表达式取出model的uname值
model.addAttribute("uname", uname);
return "register"; // 返回 register.jsp
}
}通过 @RequestParam 接收请求参数,适用于 get 和 post
1
2
3
4
5
6
7
8
9
10
11public String register(@RequestParam String uname,
@RequestParam String upass, Model model) {
if ("zhangsan".equals(uname) && "123456".equals(upass)) {
logger.info("成功");
return "login"; // 注册成功,跳转到 login.jsp
} else {
// 在register.jsp页面上可以使用EL表达式取出model的uname值
model.addAttribute("uname", uname);
return "register"; // 返回 register.jsp
}
}通过 @ModelAttribute 接收请求参数,适用于 get 和 post
1
2
3
4
5
6
7
8
9
10"/register") (
public String register(@ModelAttribute("user") UserForm user) {
if ("zhangsan".equals(uname) && "123456".equals(upass)) {
return "login"; // 注册成功,跳转到 login.jsp
} else {
// 使用@ModelAttribute("user")与model.addAttribute("user",user)的功能相同
//register.jsp页面上可以使用EL表达式${user.uname}取出ModelAttribute的uname值
return "register"; // 返回 register.jsp
}
}
SpringMVC 的转发和重定向
转发是服务器行为,重定向是客户端行为。
转发地址栏不变,请求数据不丢失,
重定向地址栏改变,请求数据丢失
在 Spring MVC 框架中,重定向与转发的示例代码如下:
1 | "/login") ( |
SpringMVC 的 JSON 数据交互
Spring MVC 提供了 MappingJackson2HttpMessageConverter 实现类默认处理 JSON 格式请求响应。该实现类利用 Jackson 开源包读写 JSON 数据,将 Java 对象转换为 JSON 对象和 XML 文档,同时也可以将 JSON 对象和 XML 文档转换为 Java 对象。
在使用注解开发时需要用到两个重要的 JSON 格式转换注解,分别是 @RequestBody 和 @ResponseBody。
- @RequestBody:用于将请求体中的数据绑定到方法的形参中,_该注解应用在方法的形参上_。把传来的 JSON 数据转换为响应 java 对象
- @ResponseBody:用于直接返回 return 对象,_该注解应用在方法上_。表示该方法返回一个 JSON 格式数据