1. 概述
Spring MVC 是Spring3.0 后发布的,基于Java 实现的MVC的轻量级Web 框架,底层仍然是Servlet;
用于接收请求,响应处理结果,管理界面层中的控制器对象;
2. 原理
2.1 原理图
2.2 说明
1)浏览器发送请求到前端控制器(DispatcherServlet);
2)前端控制器收到请求后,将请求转给处理器映射器(HandlerMapping);
3)处理器映射器根据配置信息(XML或注解)查找 Handler,返回给前端控制器;
4)前端控制器调用处理器适配器(HandlerAdapter)去执行Handler;
5)处理器适配器执行Handler,即具体的Controller 方法;
6)Handler 执行完毕,向处理器适配器返回ModelAndView (SpringMVC 一个底层对象);
7)处理器适配器再向前端控制器返回 ModelAndView ;
8)前端控制器请求视图解析器(ViewResolver)去执行视图解析,根据逻辑视图名解析成真正的视图(JSP);
9)视图解析器向前端控制器返回View;
10)前端控制器进行视图渲染,将模型数据(ModelAndView 对象中)填充到request域;
11)前端控制器向用户响应结果。
2.3 组件
2.3.1 前端控制器(DispatcherServlet)
就是一个Servlet,负责接收请求,响应处理结果;
相当于转发器或中央处理器,减少其他组件的耦合度。
位置:web.xml
2.3.2 处理器映射器(HandlerMapping)
根据用户请求的url,通过XML 配置或注解查找要执行的Handler。
位置:web.xml 中 classpath指定的文件中。如:classpath:dispatcher-servlet.xml
2.3.3 处理器适配器(HandlerAdapter)
按照特定的规则(HandlerAdapter 要求的规则)去执行Handler。
位置:与处理器映射器同文件
2.3.4 处理器(Handler)
具体的Controller 方法。
2.3.5 视图解析器(ViewResolver)
根据逻辑视图名解析成真正的视图(View 对象)。
2.3.6 视图(View)
视图类型:jsp、jstlView、freemarkerView、pdfView等。
3. 环境搭建(XML)
3.1 创建 Maven 项目并导入jar
pom.xml
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.5</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.1.3-b06</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
<!--POM右键 Maven ⇒ Reimport -->
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
3.2 创建Module
1)项目右键Add Support 选择Web。
2)Project Structure ⇒ Artifacts ⇒ 选中项目 ⇒ WEB-INF下创建 lib 文件文件夹 ⇒ 添加jar 包
3.3 web.xml
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<!--配置dispatcher.xml作为mvc的配置文件-->
<param-name>contextConfigLocation</param-name>
<param-value>classpath:dispatcher-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
3.4 dispatcher-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<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: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/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!--处理器映射器-->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<!--处理器适配器-->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
<!--视图解析器:DispatcherServlet 给他的ModelAndView-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
<!--前缀-->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!--后缀-->
<property name="suffix" value=".jsp"/>
</bean>
<!--Handler-->
<bean id="/hello" class="com.chengyu.controller.HelloController"/>
</beans>
3.5 controller
public class HelloController implements Controller {
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
// ModelAndView 模型和视图
ModelAndView mv = new ModelAndView();
// 封装对象,放到ModelAndView中。Model
mv.addObject("msg","HelloSpringMvc!");
// 封装要跳转的视图,放到ModelAndView中
mv.setViewName("hello"); // /WEB-INF/jsp/hello.jsp
return mv;
}
}
3.6 hello.jsp
${msg}
3.7 项目结构
4. 环境搭建(注解)
相较于XML 配置,3.1~3.3、3.6 的内容是一致的,下记两点不同。
4.1 dispatcher-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<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: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/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 自动扫描包,让指定包下的注解生效,由IOC容器统一管理 -->
<context:component-scan base-package="com.chengyu.controller"/>
<!-- 让SpringMvc 不处理静态资源 (.css,.js,.html,.mp3...) -->
<mvc:default-servlet-handler/>
<!-- 注册注解驱动,简化了纯Spring 中的配置。
Spring 中想要使@RequestMapping 生效,需要注册DefaultAnnotationHandlerMapping 和AnnotationMethodHandlerAdapet -->
<mvc:annotation-driven/>
<!--视图解析器:DispatcherServlet 给他的ModelAndView-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
<!--前缀-->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!--后缀-->
<property name="suffix" value=".jsp"/>
</bean>
</beans>
4.2 controller
@Controller
//@RequestMapping("/controller")
public class HelloController {
@RequestMapping("/hello")
public String hello(Model model){
model.addAttribute("msg","HelloSpringMvcAnnotation!");
return "hello"; // hello.jsp
}
}
5. RestFul 风格
5.1 概念
是一个资源定位及资源操作的风格,基于这个风格设计的软件可以更简介,更有层次,更易于实现缓存等机制。
5.2 例子
传统风格:
http://localhost:8080/03_restful/add?a=1&b=2
@Controller
public class RestFulController {
@RequestMapping("/add")
public String add(int a, int b, Model model){
model.addAttribute("msg",a + b);
return "hello";
}
}
RestFul 风格:
http://localhost:8080/03_restful/addRestFul/1/2
@Controller
public class RestFulController {
@RequestMapping("/addRestFul/{a}/{b}")
public String addRestFul(@PathVariable int a, @PathVariable int b, Model model){
model.addAttribute("msg",a + b);
return "hello";
}
}
5.3 约束请求类型
@RequestMapping 替换为:
@GetMapping
@PutMapping
@DeleteMapping
@PostMapping
@Controller
public class RestFulController {
@GetMapping("/addRestFulGet/{a}/{b}")
public String addRestFulGet(@PathVariable int a, @PathVariable int b, Model model){
model.addAttribute("msg",a + b);
return "hello";
}
}
5.4 优点
1)简介:路径简介,获取参数简介(名称可以不一致,类型会自动转换);
2)高效:支持缓存;
3)安全,隐藏参数。
6. 转发和重定向
6.1 请求和响应
@Controller
public class ModelTest {
@RequestMapping("/test")
public String testReqResp(HttpServletRequest req, HttpServletResponse resp){
HttpSession session = req.getSession();
System.out.println(session);
req.setAttribute("msg",session);
return "hello";
}
}
6.2 转发
dispatcher-servlet.xml 中的视图解析器部分删除。
默认就是转发。test1 与 test2 等价。
test2 写法与视图解析器有无无关。
@Controller
public class ModelTest {
@RequestMapping("/test1")
public String test1(Model model){
model.addAttribute("msg","123");
return "/WEB-INF/jsp/hello.jsp";
}
@RequestMapping("/test2")
public String test2(Model model){
model.addAttribute("msg","123");
return "forward:/WEB-INF/jsp/hello.jsp";
}
}
6.3 重定向
浏览器地址发生变化。
test3 写法与视图解析器有无无关。
@Controller
public class ModelTest {
@RequestMapping("/test3")
public String test3(Model model){
model.addAttribute("msg","123");
return "redirect:/index.jsp";
}
}
7. 前后台传参
7.1 同名参数
http://localhost:8080/03_restful/user/test1?name=chengyu
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/test1")
public String test1(String name, Model model){
model.addAttribute("msg",name);
return "hello";
}
}
7.2 不同名参数
http://localhost:8080/03_restful/user/test1?username=chengyu
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/test2")
public String test2(@RequestParam("username") String name, Model model){
model.addAttribute("msg",name);
return "hello";
}
}
7.3 对象参数
会自动匹配对象中属性,名称一样,可以直接传递。
http://localhost:8080/03_restful/user/test3?name=chengyu
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/test3")
public String test3(User user, Model model){
model.addAttribute("msg",user.getName());
return "hello";
}
}
8. 过滤器、拦截器
8.1 过滤器
过滤器是Servlet 规范中的一部分,任何Java web 项目都可以使用。
可以对所有要访问的资源进行过滤。
利用过滤器处理乱码。
web.xml
<!-- SpringMvc 的乱码过滤器 -->
<filter>
<filter-name>encoding</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
自定义过滤器的操作与Servlet 相同,此处省略。
8.2 拦截器
拦截器是SpringMVC框架自己的东西,只有使用了SpringMVC 框架的工程才能使用。
只负责拦截访问控制器的方法,访问Jsp等页面部分不会进行拦截。
AOP 思想的应用。
注意:SpringMVC 拦截器针对HandlerMapping
MyInterceptor:
public class MyInterceptor implements HandlerInterceptor {
// 进入Handler 之前执行,多用于身份验证、授权等
// true:放行,执行下个拦截器
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("===处理前===");
return true;
}
// 进入Handler 方法后,返回ModelAndView 前执行,将共用模型数据传到视图,如菜单导航等,也可统一指定视图
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("===处理后===");
}
// 执行完Handler 之后执行,统一异常、日志处理(放在第一个拦截器的地位)
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("===清理===");
}
}
dispatcher-servlet.xml
<!--拦截器配置-->
<mvc:interceptors>
<mvc:interceptor>
<!--拦截所有url 路径,包括子路径-->
<mvc:mapping path="/**"/>
<bean class="com.chengyu.controller.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
访问Controller 时会输出:
===处理前===
===处理后===
===清理===
9. JSON
JSON(JavaScript Object Notation),JS 对象标记语言,轻量级数据交换格式,层次清晰,有效的提升网络传输效率。本质是一个字符串!
9.1 JS 中JSON 字符串与对象转换
// 对象
var obj = {name:'chengyu',age:'30'};
// json 字符串
var json = '{"name":"chengyu","age":"30"}';
html:
<html>
<head>
<title>Title</title>
<script type="text/javascript">
var user = {
name:'chengyu',
age:'30'
};
console.log(user);
// 将JS 对象转为 Json
var json = JSON.stringify(user);
console.log(json);
// 将Json 转为 JS对象
var obj = JSON.parse(json);
console.log(obj);
</script>
</head>
<body>
${msg}
</body>
</html>
JSON 转字对象
9.2 Java 中对象转 JSON
9.2.1 引入第三方包 JackJson
lib 文件中也要添加引用。
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.3</version>
</dependency>
</dependencies>
@Controller
public class JsonController {
@RequestMapping(value = "/hello",produces = "application/json;charset=utf-8")
@ResponseBody // 不走视图解析器
public String jsonTest() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
User user = new User("chengyu",30,"大连");
// String str = user.toString();
String str = mapper.writeValueAsString(user);
return str;
}
}
user.toString() 返回的内容:
User{name=‘chengyu’, age=30, address=‘dalian’}
writeValueAsString 返回的内容:
{“name”:“chengyu”,“age”:30,“address”:“dalian”}
补充:
不走视图解析器方式一:
@Controller
@ResponseBody
不走视图解析器方式二:
@RestController
9.2.2 引入第三方包 FastJson
导包。lib 文件中也要添加引用。
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.76</version>
</dependency>
9.3 json 乱码
1)可以单独在Controller 中解决。
@RequestMapping(value = "/hello",produces = "application/json;charset=utf-8")
2)统一解决,修改配置文件,一劳永逸。
dispatcher-servlet.xml
<!-- json 乱码-->
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<constructor-arg value="UTF-8"/>
</bean>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
<property name="failOnEmptyBeans" value="false"/>
</bean>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
@Controller
public class JsonController {
@RequestMapping("/hello1")
@ResponseBody // 不走视图解析器
public String jsonTest2() {
User user = new User("chengyu",30,"大连");
String str = JSON.toJSONString(user);
return str;
}
}