一、SpringMVC简介
spring和springmvc的区别:
- Spring是IOC和AOP的容器框架;
- 而SpringMVC是基于Spring功能的Web框架,想用SpringMVC必须先依赖Spring;SpringMVC是一个MVC模式的WEB开发框架。
Spring容器是一个父容器,SpringMVC容器是一个子容器,它继承自Spring容器。因此,在SpringMVC容器中,可以访问到Spring容器中定义的Bean,而在Spring容器中,无法访问SpringMVC容器中定义的Bean。在Web开发中,Controller全部在SpringMVC中扫描,除了Controller之外的Bean,全部在Spring容器中扫描(Service、Dao),按这种方式扫描,扫描完完成后,Controller可以访问到Service。
二、执行流程和原理
01、用户发送出请求被前端控制器DispatcherServlet拦截进行处理。
02、DispatcherServlet收到请求调用HandlerMapping(处理器映射器)。
03、HandlerMapping找到具体的处理器(查找xml配置或注解配置),生成处理器对象及处理器拦截器(如果有),再一起返回给DispatcherServlet。
04、DispatcherServlet调用HandlerAdapter(处理器适配器)。
05、HandlerAdapter经过适配调用具体的处理器(Handler/Controller)。
06、Controller执行完成返回ModelAndView对象。
07、HandlerAdapter将Controller执行结果ModelAndView返回给DispatcherServlet。
08、DispatcherServlet将ModelAndView传给ViewReslover(视图解析器)。
09、ViewReslover解析ModelAndView后返回具体View(视图)给DispatcherServlet。
10、DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。
11、DispatcherServlet响应View给用户。
涉及组件分析:
- 前端控制器DispatcherServlet(不需要程序员开发)由框架提供,在web.xml中配置。
作用:接收请求,响应结果,相当于转发器,中央处理器。 - 处理器映射器HandlerMapping(不需要程序员开发)由框架提供。
作用:根据请求的url查找Handler(处理器/Controller),可以通过XML和注解方式来映射。 - 处理器适配器HandlerAdapter(不需要程序员开发)由框架提供。
作用:按照特定规则(HandlerAdapter要求的规则)去执行Handler中的方法。 - 处理器Handler(也称之为Controller,需要程序员开发)
注意:编写Handler时按照HandlerAdapter的要求去做,这样适配器才可以去正确执行Handler。
作用:接受用户请求信息,调用业务方法处理请求,也称之为后端控制器。 - 视图解析器ViewResolver(不需要程序员开发)由框架提供。
作用:进行视图解析,把逻辑视图解析成真正的物理视图。
SpringMVC框架支持多种View视图技术,包括:jstlView、freemarkerView、ThymeleafView等。 - 视图View(需要工程师开发)
作用:把数据展现给用户的页面
View是一个接口,实现类支持不同的View技术(jsp、freemarker、pdf等)
根据以上分析,SpringMVC需要程序员完成的工作有三个:
【1】配置前端控制器DispatcherServlet。
【2】开发后端控制器Handler/Controller。
【3】开发视图View。
三、springmvc原始代码
controller
package com.X;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class HelloController implements Controller {
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
ModelAndView mv = new ModelAndView();
//业务代码
String result = "HelloSpringMVC";
mv.addObject("msg",result);
//视图跳转
mv.setViewName("test");
return mv;
}
}
spring-servlet
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd ">
<!--处理器映射器-->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<!--处理器适配器-->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
<!--视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
<bean id="/hello" class="com.X.HelloController"/>
</beans>
web.xml
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!--配置dispatchServlet:前端控制器-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--dispatchServlet要绑定Spring的配置文件-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-servlet.xml</param-value>
</init-param>
<!--启动级别:1-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
四、用注解开发
springmvc-servlet
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.x.controller"/>
<mvc:default-servlet-handler/>
<mvc:annotation-driven/>
<!--视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
controller
package com.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
public class HelloController{
("/hello")
public String hello(Model model){
//封装数据
model.addAttribute("msg","helloMVC");
return "hello";//会被视图解析器处理
}
}
五、restful风格
package com.x.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
public class RestFulController {
//原来:http://localhost:8080/hello?a=2&b=3
//restful:http://localhost:8080/x/2/3
(value = "/x/{a}/{b}",method = RequestMethod.DELETE)
public String hello( int a, int b, Model model){
int res = a+b;
//封装数据
model.addAttribute("msg",res);
return "hello";//会被视图解析器处理
}
("/x/{a}/{b}")
public String hello2( int a, int b, Model model){
int res = a+b;
//封装数据
model.addAttribute("msg",res);
return "hello";//会被视图解析器处理
}
}
:扮演的是 (method =RequestMethod.GET) 的快捷方式。
六、请求的转发与重定向
通过springmvc来实现转发和重定向:
若不在springmvc-servlet里配置视图解析器
在controller中:
请求转发:
public class RestFulController {
("/x")
public String hello(Model model){
model.addAttribute("msg","heavenly side");
return "forward:/WEB-INF/jsp/hello.jsp";
}
}
重定向:
return "redirect:index.jsp";
七、数据的处理
7.1 处理提交数据
提交的域名称和处理方法的参数名一致:
提交数据: http://localhost:8080/hello?name=kennys
"/hello")(
public String hello(String name){
System.out.println(name);
return hello;
}
提交的域名称和处理方法的参数名不一致
提交数据: http://localhost:8080/hello?username=kennys
"/hello")(
public String hello( ("username") String name){
System.out.println(name);
return hello;
}
从前端接受的数据参数最好都加上@RequestParam(),更加规范易懂
提交的是一个对象
要求提交的表单域和对象的属性名一致
实体类:
public class User{
private int id;
private String name;
private int age;
//构造
//get/set
//toString
}
提交数据:http://localhost:8080/user?name=kennys&id=1&age=15
"/user")(
public String user(User user){
System.out.println(user);
return hello;
}
7.2 乱码问题
使用过滤器来解决页面显示乱码问题
package com.x.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
(urlPatterns = "/*")
public class EncodingFilter implements Filter {
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
servletRequest.setCharacterEncoding("utf-8");
servletResponse.setCharacterEncoding("utf-8");
filterChain.doFilter(servletRequest,servletResponse);
}
}
八、JSON
8.1 基本用法
- JSON 是纯文本
JSON (JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式。它基于 ECMAScript (欧洲计算机协会制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。
JSON 数据的书写格式是:
key : value
JSON 对象在大括号 {} 中书写:
{key1 : value1, key2 : value2, ... keyN : valueN }
对象可以包含多个名称/值对:
{ "name":"xxx" , "url":"xxx" }
JSON 数组
JSON 数组在中括号 [] 中书写:
数组可包含多个对象:
[
{ key1 : value1-1 , key2:value1-2 },
{ key1 : value2-1 , key2:value2-2 },
{ key1 : value3-1 , key2:value3-2 },
{ keyN : valueN-1 , keyN:valueN-2 },
]
因为 JSON 使用 JavaScript 语法,所以无需额外的软件就能处理 JavaScript 中的 JSON。
通过 JavaScript,您可以创建一个对象数组,并像这样进行赋值:
var sites = [
{ "name":"runoob" , "url":"www.runoob.com" },
{ "name":"google" , "url":"www.google.com" },
{ "name":"微博" , "url":"www.weibo.com" }
];
JSON和JavaScript对象互转
JSON--->JavaScript:
var obj = JSON.parse('{"a":"Hello","b":"world"}')
JavaScript--->JSON:
var json = JSON.stringify({a:'hello',b:'world'})
8.2 jackson
pom
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.3</version>
</dependency>
package com.x.controller;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.x.pojo.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
public class UserController {
(value = "/x")
//不会走视图解析器,直接返回字符串
public String json() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
User user = new User("kennyS",7,"boy");
String s = mapper.writeValueAsString(user);
return s;
}
}
在controller类上加@RestController也会使所有方法只返回字符串
乱码问题配置:
<mvc:annotation-driven>
<mvc:message-converters>
<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>
8.3 fastjson
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.76</version>
</dependency>
package com.x.controller;
import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.x.pojo.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
public class UserController {
(value = "/x")
public String json() throws JsonProcessingException {
List<User> list = new ArrayList<>();
User user1 = new User("kenny1", 3, "boy");
User user2 = new User("kenny2", 3, "boy");
User user3 = new User("kenny3", 3, "boy");
User user4 = new User("kenny4", 3, "boy");
list.add(user1);
list.add(user2);
list.add(user3);
list.add(user4);
String s = JSON.toJSONString(list);
return s;
}
}
JSON字符串--->Java:
JSON.parseObject()
Java--->JSON:
JSON.toJSON()
JSON--->Java:
JSON.toJavaObject()
九、拦截器
拦截器配置:
<!-- 配置拦截器 -->
<mvc:interceptors>
<!-- 一个拦截器 -->
<mvc:interceptor>
<!-- 配置此拦截器所拦截的路径
拦截所有请求:/** 表示所有进入springmvc的请求
-->
<mvc:mapping path="/**"/>
<!-- 注册拦截器对象 -->
<bean class="com.kennyX.config.MyIntercepter"/>
</mvc:interceptor>
</mvc:interceptors>
拦截器类
/**
* springmvc中的拦截器对象
* 1.编写代码:实现拦截器接口 HandlerInterceptor
* 2.配置拦截器
*/
public class MyInterceptor implements HandlerInterceptor {
/**
* preHandle方法,预处理
* 作用:在请求进入指定Controller方法之前,执行的方法(对请求进行验证)
* @param handler 请求将要执行的Controller对象
* @return 布尔类型:true表示请求放行,继续向后执行(有可能进入下一个拦截器,也有可能进入Controller)
* false表示拦截请求,请求不能继续向后执行
*/
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("MyInterceptor拦截器中的preHandle方法执行了...");
return true;
}
/**
* postHandle 后处理
* @param handler 正在执行的Controller对象
* @param modelAndView 模型和视图数据,Controller方法执行完成之后的返回值
*
* 注意:此方法必须在请求进入Controller之后才会执行,如果没有进入Controller是不会执行的
*/
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("MyInterceptor拦截器中的postHandle方法执行了...");
}
/**
* afterCompletion 请求处理完成之后
* @param handler 已经执行过的Controller对象
* @param ex Controller方法抛出的异常对象
*/
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("MyInterceptor拦截器中的afterCompletion方法执行了...");
}
}