一、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给用户。


涉及组件分析:

  1. 前端控制器DispatcherServlet(不需要程序员开发)由框架提供,在web.xml中配置。
    作用:接收请求,响应结果,相当于转发器,中央处理器。
  2. 处理器映射器HandlerMapping(不需要程序员开发)由框架提供。
    作用:根据请求的url查找Handler(处理器/Controller),可以通过XML和注解方式来映射。
  3. 处理器适配器HandlerAdapter(不需要程序员开发)由框架提供。
    作用:按照特定规则(HandlerAdapter要求的规则)去执行Handler中的方法。
  4. 处理器Handler(也称之为Controller,需要程序员开发)
    注意:编写Handler时按照HandlerAdapter的要求去做,这样适配器才可以去正确执行Handler。
    作用:接受用户请求信息,调用业务方法处理请求,也称之为后端控制器。
  5. 视图解析器ViewResolver(不需要程序员开发)由框架提供。
    作用:进行视图解析,把逻辑视图解析成真正的物理视图。
    SpringMVC框架支持多种View视图技术,包括:jstlView、freemarkerView、ThymeleafView等。
  6. 视图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 {
@Override
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

<?xml version="1.0" encoding="UTF-8"?>
<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

<?xml version="1.0" encoding="UTF-8"?>
<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

<?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: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;

@Controller
public class HelloController{
@RequestMapping("/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;

@Controller
public class RestFulController {
//原来:http://localhost:8080/hello?a=2&b=3
//restful:http://localhost:8080/x/2/3

@RequestMapping(value = "/x/{a}/{b}",method = RequestMethod.DELETE)
public String hello(@PathVariable int a,@PathVariable int b, Model model){
int res = a+b;
//封装数据
model.addAttribute("msg",res);
return "hello";//会被视图解析器处理
}

@GetMapping("/x/{a}/{b}")
public String hello2(@PathVariable int a,@PathVariable int b, Model model){
int res = a+b;
//封装数据
model.addAttribute("msg",res);
return "hello";//会被视图解析器处理
}
}
@GetMapping:扮演的是@RequestMapping(method =RequestMethod.GET) 的快捷方式。
@PostMapping
@PutMapping
@DeleteMapping
@PatchMapping


六、请求的转发与重定向

通过springmvc来实现转发和重定向:

若不在springmvc-servlet里配置视图解析器

在controller中:

请求转发

@Controller
public class RestFulController {

@GetMapping("/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​

@RequestMapping("/hello")
public String hello(String name){
System.out.println(name);
return hello;
}


提交的域名称和处理方法的参数名不一致

提交数据: ​​http://localhost:8080/hello?username=kennys​

@RequestMapping("/hello")
public String hello(@RequestParam("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​

@RequestMapping("/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;

@WebFilter(urlPatterns = "/*")
public class EncodingFilter implements Filter {
@Override
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;

@Controller
public class UserController {

@RequestMapping(value = "/x")
@ResponseBody //不会走视图解析器,直接返回字符串
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;

@RestController
@Controller
public class UserController {

@RequestMapping(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表示拦截请求,请求不能继续向后执行
*/
@Override
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是不会执行的
*/
@Override
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方法抛出的异常对象
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("MyInterceptor拦截器中的afterCompletion方法执行了...");
}
}