章节索引
前提
这篇博文是这套Spring学习笔记的第九篇——Spring MVC篇,主要内容包括Spring MVC的基础知识和应用。如果需要了解有关Spring的综述信息或博文的索引信息,请移步:
《综述篇》
什么是MVC?
MVC是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计典范,用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。MVC被独特的发展起来用于映射传统的输入、处理和输出功能在一个逻辑的图形化用户界面的结构中。[1]
对于Model、View和Controller,我的理解是:
①Model: 模型主要用来存储数据,类似于Android中的Bundle,可以简单理解为一张<String, Object> 类型的表;
②View: 视图重定义了需要显示的元素,比如一张JSP页面或者图片、PDF等用于显示的资源;
③Controller: 控制器可以为请求找到相应的处理者,管理后端与前端的交互。
DispatcherServlet请求调度器
在《配置篇》中,我们曾在web.xml中配置了DispatcherServlet。为了便于讲解,再次列出代码:
<servlet>
<servlet-name>dispatcher</servlet-name> <!-- 注释① -->
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param> <!-- 注释② -->
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup> <!-- 注释③ -->
</servlet>
<servlet-mapping> <!-- 注释④ -->
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
注释:
①这里定义了Servlet的名字——dispatcher,可以根据喜好自定;
②这里定义了一个初始化参数——contextConfigLocation,即上下文配置地址,值指向了MVC的配置文件spring-mvc.xml;
③表示web容器在启动时就加载该Servlet,标签中的数值是优先级,数值越小优先级越大;
④Servlet映射,指定对dispatcher
进行映射,映射模式是/
,即接受任意请求。这里需要深入解释一下,/
会将所有的请求放进来,后面在Controller中,我们需要对请求进行过滤,不符合要求的请求仍无法得到响应。
需要注意的是,一个web.xml中可以配置多个DispatcherServlet,通过不同的<servlet-mapping>设置,让它们处理不同的请求。
Controller
同样为了便于讲解,我们再次列出RequestController和UserController:
RequestController
@Controller //注释①
public class RequestController {
@RequestMapping("") //注释②
public ModelAndView dispatch(HttpServletRequest request, HttpServletResponse response) {
String RequestType = request.getParameter("RequestType"); //注释③
return new ModelAndView("forward:" + RequestType); //注释④
}
}
注释:
①@Controller
注解标识这个类为控制器,可以被Spring容器扫描到以执行控制器的功能;
②@RequestMappring
标识下方的函数用来处理满足括号中地址映射规则的请求。如""
表示接受任何请求;
③从请求参数中取出"RequestType"
请求类型,这个参数是客户端在发送请求的时候传来的;
④通过"RequestType"
转发请求,如果RequestType="Login"
,该请求将被转发给能处理"/Login"
的函数。
UserController
@Controller
public class UserController {
@Autowired
private UserService userService;
@RequestMapping("Login") //注释①
public void handleLoginRequest(HttpServletRequest request, HttpServletResponse response) throws IOException { //注释②
try (PrintWriter out = response.getWriter()) {
//获得请求中传来的用户名和密码
String username = request.getParameter("UserName").trim();
String password = request.getParameter("Password").trim();
//密码验证结果
boolean result = userService.verifyLogin(username, password);
out.write(String.valueOf(result)); //注释③
}
}
}
注释:
①这个请求映射的映射规则是"Login"
,他就可以处理地址为/Login
的请求。但不仅于此,因为映射规则支持通配符,因此"Login"
对应的实际规则是/Login
+/Login.*
+/Login/
;
②这个函数是请求处理函数:
——当返回值为String或ModelAndView类型时,表示请求转发或向浏览器指定需要跳转和渲染的页面;如果仅仅像其他非浏览器客户端返回数据,则用void。
——函数的名字可以根据喜好任意取;
③向客户端打印一个简单的登录验证结果字符串。
请求处理函数中的参数绑定
在请求处理函数的函数签名(即函数头,一个函数在{
前的部分)中,我们可以使用多种注解绑定参数以达到简化代码的目的。
@RequestParam
在上述RequestController中,我们手动取了参数RequestType
,通过@RequestParam
绑定请求中的参数,就可以省一些代码,让Spring容器帮我们自动从请求中取出来绑定到函数的参数中。
@Controller
public class RequestController {
@RequestMapping("")
public ModelAndView dispatch(@RequestParam("RequestType") String requestType) { //注释
return new ModelAndView("forward:" + requestType);
}
}
注释:这里删除了request和response,通过
@RequestParam
注解定义了一个参数绑定,意为从请求参数中取出"RequestType"
的值,赋给参数requestType
.
@CookieValue
@CookieValue
可以绑定请求中的Cookie值
@RequestMapping("")
public ModelAndView dispatch(@CookieValue("sessionId") String sessionId) {
......
}
@RequestHeader
@RequestHeader
可以绑定请求头中的值
@RequestMapping("")
public ModelAndView dispatch(@RequestHeader("Accept-Encoding") String acceptEncoding) {
......
}
POJO自动填充
当我们的请求参数中包含与POJO类对应的属性时,可以使用这种方法将参数绑定到一个POJO类的对象上,如:
请求URL的参数部分
/?id=1001&username=Jackson&password=1234567890
请求处理函数
@RequestMapping("")
public ModelAndView dispatch(User user) {
......
}
解释:此时,请求参数将会被自动填充到user对象中。
Servlet原生API
其实我们之前的例子已经用到了:
RequestMapping("")
public ModelAndView dispatch(HttpServletRequest request, HttpServletResponse response) {
......
}
解释:这里的
HttpServletRequest
和HttpServletResponse
就属于Servlet原生API,我们需要用到这类参数的时候,直接在参数里面声明就可以用了,Spring IoC容器会自动为我们注入相应的依赖。
IO对象
通过IO对象可以读取请求中的数据,也可以输出数据到响应中。
RequestMapping("")
public ModelAndView dispatch(InputStream is, OutputStream os) {
......
}
处理Model中的数据
上文中我们已经定义了Model,它主要用于存储数据。如何在各种情形下都可以读写Model里的数据,是Spring MVC必须解决的问题。
ModelAndView
当一个Controller中的请求处理函数的返回值为ModelAndView时,它包含了模型和视图的信息。
可以用于向模型中添加数据的函数有:
ModelAndView addObject(String attributeName, Object attributeValue)
ModelAndView addAllObjects(Map<String, ?> modelMap)
可以用来设置视图的函数有:
void setView(View view)
void setViewName(String viewName)
@ModelAttribute
需要将方法的参数写入Model时,可以使用@ModelAttribute
@RequestMapping("/Login")
public ModelAndView handleLoginRequest(@ModelAttribute("user") User user) {
......
}
也可以给函数冠以@ModelAttribute
注解,这样,函数的返回值将被写入Model中。
@ModelAttribute("user")
public User getUser() {
User user = new User();
......
return user;
}
ModelMap
上文中说过,Model实际可以理解为一个Map<String, Object>表,我们可以通过ModelMap参数来读写Model中的数据。
@RequestMapping("")
public ModelAndView dispatcher(ModelMap modelMap) {
modelMap.addAttribute("sessionId", "1ESD8C26D1357F23F39D0");
User user = (User)modelMap.get("user");
......
}
@SessionAttributes
如果希望在多个请求中共享一些数据,可以使用@SessionAttribute
注解
@Controller
@SessionAttributes("user") //注释①
public class UserController {
@RequestMapping("/Login")
public ModelAndView handleLoginRequest(@ModelAttribute("user") User user) { //注释②
......
}
}
注释:①处标注了
@SessionAttribute
注解,Controller会自动把②处的user对象写入Session中。
后记
Spring框架的基础知识就到这了,如果学到了其他的进阶知识,我会续写新的博文来分享。