spring MVC是一个基于MVC模式的表现层框架,和其他MVC表现层框架相比,有如下特点:
1.基于的是Servlet模式
2.控制器不再需要继承其他的类,只需使用@Controller注解
3.应用控制器方法参数封装灵活,如果方法参数和表单数据键相同,由前端控制器完成封装
4.返回页面直接在方法中指定,可以String,void等
5.性能优秀
MVC模式:Model-View-Controller(模型-视图-控制器)模式,它是一种架构模式,其目标是软件的用户界面和业务逻辑分开,使得代码更高的可拓展性、可复用行、可维护性等。
控制器
SpringMVC围绕DispatcherServlet设计的,DispatcherServlet用来处理所有HTTP请求和响应。
解决了原本使用Serlvet处理请求,可能出现类爆炸的情况,一个Servlet只能处理一个请求,如果请求过多,100甚至1000个,我们需要提供100个甚至1000个Serlvet类。
前端控制器(DispatcherServlet):负责接收客户端的请求,根据请求路径访问应用控制器,负责把页面参数填充给JavaBean,负责转发页面等。
应用控制器(用户自定义含有@Controller注解的类),负责产生业务组件,调用业务组件方法完成业务,根据结果返回转发的页面对象。
Spirng MVC的工作流程
1.客户端向服务器发出请求时,服务器先使用前端控制器(DIspatcherServlet)接收请求。
2.前端控制器会根据请求的URL路径,定位到具体的应用控制器(Controller)中具体的方法,并把封装好的实体对象传入应用控制器方法。
3.在方法中生成业务组件调用组件的业务方法,把处理结果(模型),返回给转发的页面路径。由前端控制器(DIspatcherServlet)完成页面转发。
SpringMVC环境的搭建
1.导入SpringMVC依赖
<!-- Spring 核心-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.7.RELEASE</version>
</dependency>
<!-- MVC-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.7.RELEASE</version>
</dependency>
<!--tomcat-->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<version>9.0.36</version>
</dependency>
2.提供SpringMVC配置类
@Configuration
@ComponentScan(basePackageClasses = WebApplicationConfig.class)
@EnableWebMvc // 开启类型的自动转换
public class WebApplicationConfig implements WebMvcConfigurer {
// 请求映射处理适配器
@Autowired
private RequestMappingHandlerAdapter adapter;
// 设置响应信息的编码集
@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
StringHttpMessageConverter stringHttpMessageConverter
= (StringHttpMessageConverter)converters.get(1);
stringHttpMessageConverter.setDefaultCharset(Charset.forName("utf-8"));
}
// 提供静态资源的支持 请求的url以/html/开头,表示找类路径的/static/html/下的文件
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/html/**")
.addResourceLocations("classpath:/static/html/");
}
// 注册类型转换器
@PostConstruct
public void addConversionConfig() {
ConfigurableWebBindingInitializer initializer =
(ConfigurableWebBindingInitializer)
adapter.getWebBindingInitializer();
if (initializer.getConversionService() != null) {
GenericConversionService converService = (GenericConversionService) initializer.getConversionService();
// 添加自定义转换器
converService.addConverter(new LocalDateTypeChange());
}
}
}
类型转换器
import org.springframework.core.convert.converter.Converter;
// 第一个位置:表单元素提供的数据类型,第二个位置:需要转换的目标类型
public class LocalDateTypeChange implements Converter<String, LocalDate> {
@Override
public LocalDate convert(String s) {
if(s != null && s.matches("\\d{4}-\\d{2}-\\d{2}")){
return LocalDate.parse(s);
}
return null;
}
}
3.根据配置类在Tomcat容器中去创建并注册前端控制器(DispatcherServlet)
public class MainServer {
public MainServer(){
Tomcat tomcat = new Tomcat();
tomcat.setPort(8080);
tomcat.getConnector();
Context context = tomcat.addContext("",null);
// 创建前端控制器
DispatcherServlet dispatcherServlet =
new DispatcherServlet(
this.createApplicationContext(context.getServletContext())
);
// 注册前端控制器
Wrapper servlet =
Tomcat.addServlet(context,"dispatcherServlet",
dispatcherServlet);
servlet.setLoadOnStartup(1);
// 表示任何的路径请求都可以到达前端控制器
servlet.addMapping("/*");
try {
tomcat.start();
} catch (LifecycleException e) {
e.printStackTrace();
}
}
/**
* 创建SpringMVC的应用上下文对象
* @param servletContext servlet 上下文对象
* @return SpringMVC的应用上下文对象
*/
public WebApplicationContext createApplicationContext(ServletContext servletContext){
AnnotationConfigWebApplicationContext ctx =
new AnnotationConfigWebApplicationContext();
// 注入配置类
ctx.register(WebApplicationConfig.class);
ctx.setServletContext(servletContext);
ctx.refresh();
// 用于在非web应用中关闭IoC容器
ctx.registerShutdownHook();
return ctx;
}
public static void main(String[] args) {
new MainServer();
}
}
4.根据需求提供应用控制器(带有@Controller的类)
@Controller
public class TestController {
// RequestMapping 书写请求映射路径
// 当以该注解的映射路径访问前端控制器时会转发到对应映射路径的方法
// 方式1:通过RequestMapping 来设置MIME类型 produces = "text/html;charset=utf-8"
@RequestMapping("/test")
public String test(){
System.out.println("应用控制器的test方法");
/* 请求转发工作流程:
客户端向服务器发出请求,服务器在服务器内部进行资源的调配,将客户端想要的资源回发给客户端。
客户端只向服务器发出一次请求,可以共享request中绑定的数据
*/
return "/html/Test.html";
}
@RequestMapping("/test3")
public String test3(){
System.out.println("应用控制器的test方法");
/* 重定向工作流程:
客户端向服务器发起请求,服务器在重定向资源时,向客户端发送302状态码,同时发送location响应头。
客户端接收到响应信息后,发现为302状态码,就会读取location响应头信息,根据该信息的路径,再次向
服务器发出第二次请求
*/
return "redirect:/html/Test.html";
}
@RequestMapping("/test2")
@ResponseBody // 把JSON或XML或普通文本写入HttpServletOutStream
public String test2(){
System.out.println("应用控制器的test2方法");
return "测试2";
}
@RequestMapping("/addUser")
@ResponseBody
public String addUser(UserBean userBean,int age,String tel,
@RequestParam("tel") String userTel){
/*
如果表单元素的name属性值和控制器方法的参数名不同,可以通过
注解@RequestParam 对方法参数指定它对应的表单元素
*/
System.out.println(userBean);
System.out.println(age);
System.out.println(tel);
System.out.println(userTel);
return "添加成功";
}
}