辛苦堆砌,转载请注明出处,谢谢!
今天开始一个新的主题,开始Spring MVC的学习。有关Spring MVC的部分,准备做一个简单的微博程序。希望通过该微博程序,能够包含Spring MVC尽可能多的内容。
首先,搭建Spring MVC开发的环境,DispatcherServlet是Spring MVC的前端控制器,也是Spring MVC最重要的Servlet,使用Spring MVC请求的流程如图所示:
1.客户端向服务器发送http请求,之后经过Web容器,交给Spring MVC的DispatcherServlet。
2.DispatcherServlet通过处理器映射,查找能够处理该请求的控制器。
3.将请求交给控制器,控制器执行必要的逻辑。
4.控制器创建模型(Model)以及逻辑视图名(程序内能够识别的视图名称,依赖于视图解析器的配置)
5.控制器将逻辑视图名和模型交给DispatcherServlet。
6.DispatcherServlet通过视图解析器,获得视图。
7.渲染视图。
8.返回视图响应。
总的来看,Spring MVC是基于MVC的框架,结构清晰。首先,我们将DispatcherServlet注册到Web容器。配置DispatcherServlet可以通过派生AbstractAnnotationConfigDispatcherServletInitializer并重写其中的相关方法实现。下面我们新建一个Maven Webapp项目,然后开始Spring MVC代码的学习,首先配置DispatcherServlet。
package com.yjp.springmvc.blog.config;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class BlogWebApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
//DispatcherServlet之外使用的配置类
return new Class<?>[] { RootConfig.class };
}
@Override
protected Class<?>[] getServletConfigClasses() {
//DispatcherServlet使用的配置类
return new Class<?>[] { WebConfig.class };
}
@Override
protected String[] getServletMappings() {
//DispatcherServlet处理映射到"/"的请求
return new String[] { "/" };
}
}
可以看到,重写了三个方法,分别设置DispatcherServlet的配置类,之前两篇文章的配置类,也就是除Spring MVC之外的配置内容以及DispatcherServlet处理的映射路径。两个配置如果进行自动扫描组建,不可重复,千万记住,你可以理解为两个配置分别配置了两个上下文,不可混用,否则会出现问题。先来看一下RootConfig类
package com.yjp.springmvc.blog.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.context.annotation.ComponentScan.Filter;
@Configuration
@ComponentScan(basePackages={"com.yjp.springmvc.blog.beans"},
excludeFilters={
@Filter(type=FilterType.ANNOTATION, value=EnableWebMvc.class)
})
public class RootConfig {
}
使用@Configuration注解,说明它是一个配置类,然后添加了@ComponentScan,启动组件自动扫描,方便进行自动装配,但是不同之处,添加了一个excludeFilters,也就是要排除的,这里就是为了排除掉WebConfig的部分,一会儿会看到,WebConfig使用@EnableWebMvc注解,因此这里将它排除在外。实际上我们项目中已经分别将两部分的内容分别安排在了两个包,让两个Config分别扫描两个包即可,但为了安全起见,还是注意一下。看一下WebConfig
package com.yjp.springmvc.blog.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
@Configuration
@EnableWebMvc
@ComponentScan("com.yjp.springmvc.blog.web")
public class WebConfig {
}
无非多了一个@EnableWebMvc注解,其他和普通的配置类一样。
但是我们现在还需要做一些进一步的配置,首先,我们会用到JSP,所以需要配置ViewResolver,来指定一个可以处理JSP的视图解析器,然后,我们将静态资源交给默认的Servlet处理,而不是使用DispatcherServlet。修改WebConfig,创建一个id为viewResolver的bean,然后派生WebMvcConfigurerAdapter,重写configureDefaultServletHandling即可达到上面提到的两个目的。
package com.yjp.springmvc.blog.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
@Configuration
@EnableWebMvc
@ComponentScan("com.yjp.springmvc.blog.web")
public class WebConfig extends WebMvcConfigurerAdapter {
@Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver viewResolver =
new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".jsp");
viewResolver.setExposeContextBeansAsAttributes(true);
return viewResolver;
}
@Override
public void configureDefaultServletHandling(
DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}
主要看一下viewResolver bean,我们创建了一个InternalResourceViewResolver,该类可处理JSP视图,然后我们设置了前缀和后缀,这样,当我们的控制器返回视图的逻辑名称时,如login,视图解析器会找到/WEB-INF/views/login.jsp,然后进行处理。setExposeContextBeansAsAttributes则时将模型对象作为request的属性暴漏出来。这样,我们的配置工作就基本完成了,现在做一个简单的Controller和一个页面,然后测试一下我们的框架能否正常使用。
先看一下我们模拟的一个Service
package com.yjp.springmvc.blog.beans.model;
import org.springframework.stereotype.Service;
@Service
public class HelloWorld {
public String getHelloWorld() {
return "Hello World";
}
}
提供了一个获取HelloWorld的方法,注解为一个Service
再看看控制器
package com.yjp.springmvc.blog.web.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.yjp.springmvc.blog.beans.model.HelloWorld;
@Controller
public class Login {
@Autowired
private HelloWorld helloWorld;
@RequestMapping(method=RequestMethod.GET, value="/")
public String login(Model model) {
model.addAttribute(helloWorld);
return "login";
}
}
首先使用注解@Controller说明这个类是一个控制器,然后控制器使用自动装配获得一个helloWorld的引用,使用@RequestMapping注解,说明login方法处理的请求是http://localhost:8080/blog/,使用GET方法。login方法以一个Model对象为参数,将需要页面渲染的参数传入其中,然后返回login,这就是逻辑试图名,按照我们视图解析器的设置,找的视图就是/WEB-INF/views/login.jsp文件
看一下页面
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page isELIgnored="false"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>登陆</title>
</head>
<body>
${helloWorld.helloWorld}
</body>
</html>
很简单,使用EL显示helloWorld属性的helloWorld属性,这会调用getHelloWorld方法。
运行测试可以看看结果,页面显示HelloWorld.