SpringMVC基础

1 基础知识

1.1 什么是 SpringMVC?

SpringMVC 是一门属于 Spring 的技术,主要用于一定程度的简化 Web 开发,其主要对 Servlet 做了封装,使得我们的开发更加快捷;同时利用 Spring 的特性,使得开发更加简便快捷;

当然,传统 Servlet 开发的时候很多项目都是前端和后端是同步响应的方式,而 SpringMVC 更倾向于异步的响应,在向前端传递响应数据的时候非常的方便。

异步响应?
1) 给前端返回信息的时候只返回数据,前端获取到数据后将数据渲染到页面;
2) 在使用 Servlet 开发 Web 项目的时候,Servlet 本身是一个动态的资源,同时还有 JSP 等等,这两者都属于动态资源,需要先将它们编译成.class 文件的形式,然后服务器再将其渲染到前端。显然这是十分麻烦的事情;
3)在 Web 开发的基础课程当中,也有使用到异步响应,做法是使用 vue.js,后端返回 JSON 数据给前端,前端将数据获取之后直接渲染即可;

1.2 bean 的加载控制

1)在 SpringMVC 中有一个专门针对 SpringMVC 的配置类,而 Spring 本身也有一个 Spring 的配置类。
2)应该将 controller 层的 bean 将给 SpringMVC 管理,其他的 bean 交给 Spring 管理;

主要的有几种方式:
1)修改Spring配置类,设定扫描范围为精准范围;

@Configuration
@ComponentScan({"cn.edu.njust.dao", "cn.edu.njust.service"})
public class SpringConfig {
}

2)修改Spring配置类,设定扫描范围为cn.edu.njust,排除掉controller包中的bean;

@Configuration
//@ComponentScan({"cn.edu.njust.dao", "cn.edu.njust.service"})
@ComponentScan(value = "cn.edu.njust",
        excludeFilters = @ComponentScan.Filter(
                type = FilterType.ANNOTATION,
                classes = Controller.class
        ))
public class SpringConfig {
}

3)不区分 Spring 与 SpringMVC 的环境,加载到同一个环境中;

这种方式不常用

1.3 Web 项目中加载 Spring 和 SpringMVC 上下文

有两种方式,一种是比较中规中矩的方式,先声明变量,然后将配置类注册进去;
这个配置类在 SpringWeb 项目中十分重要的,是加载配置路由加载 bean 等等十分重要的配置;
主要是继承AbstractDispatcherServletInitializer并且实现三个方法;

1.3.1 方式一:注册配置类的 class 对象

package cn.edu.njust.config;

import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.servlet.support.AbstractDispatcherServletInitializer;

import javax.servlet.Filter;

public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer {

    /**
     * 加载SpringMVC配置类,获取SpringMVC/SpringWeb上下文环境,我看作是获取的IoC容器
     * 和之前使用注解加载IoC容器的时候类似,不过这里为了获取SpringMVC的bean
     * 这里获取IoC对象ctx的形式和Spring中有些区别就是:这里没有直接将Class对象传入的方法,需要调用register注册
     *
     * @return SpringMVC的IoC对象
     */
    protected WebApplicationContext createServletApplicationContext() {
        //初始化WebApplicationContext对象
        AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
        //加载指定配置类
        ctx.register(SpringMvcConfig.class);
        return ctx;
    }

    /**
     * 设置由springmvc控制器处理的请求映射路径
     * 即SpringMVC拦截哪些请求
     * @return 拦截的路由数组
     */
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }


    /**
     * 加载spring环境,获取Spring的容器上下文环境
     * createRootApplicationContext方法:
     *      如果创建Servlet容器时需要加载非SpringMVC对应的bean,使用当前方法进行
     *      使用方式和createServletApplicationContext相同
     *
     * @return Spring的上下文环境
     */
    protected WebApplicationContext createRootApplicationContext() {
        AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
        ctx.register(SpringConfig.class);
        return ctx;
    }

    /**
     * 乱码处理
     * @return 一个过滤器数组
     */
    @Override
    protected Filter[] getServletFilters() {
        CharacterEncodingFilter filter = new CharacterEncodingFilter();
        filter.setEncoding("UTF-8");
        return new Filter[]{filter};
    }
}

1.3.2 方式二:返回配置类数组

使用这两个方法代替上面的两个方法

package cn.edu.njust.config;

import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.servlet.support.AbstractDispatcherServletInitializer;

import javax.servlet.Filter;

public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer {
    /**
     * 设置由springmvc控制器处理的请求映射路径
     * 即SpringMVC拦截哪些请求
     * @return 拦截的路由数组
     */
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }

    // Spring上下文环境
    protected Class<?>[] getRootConfigClasses() {
        return new Class[]{SpringConfig.class};
    }
    // SpringMvc上下文环境
    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{SpringMvcConfig.class};
    }

    /**
     * 乱码处理
     * @return 一个过滤器数组
     */
    @Override
    protected Filter[] getServletFilters() {
        CharacterEncodingFilter filter = new CharacterEncodingFilter();
        filter.setEncoding("UTF-8");
        return new Filter[]{filter};
    }
}

2 SpringMVC 中的请求与响应

2.1 请求路径

请求路径是指使用 url 具体匹配到哪个方法,具体的做法是使用 @RequestMapping 注解设置访问路径
1)设置在类上:整个类中所有方法的访问都需要经过这个路径
2)设置在方法上:给每个方法指定具体的访问路径,方法的访问路径是 类+方法 上的注解路径

// 访问路径
@RequestMapping("/save")
@ResponseBody
public String save() {
    System.out.println("save in running...");
    return "{'info':'SpringMVC'}";
}

2.2 请求参数

主要是前端在发起请求的时候通常会带有一定的参数,后端需要接受参数做一定的处理。而请求参数一般有好几种形式,如路径参数,get 请求参数,请求体参数等等;

2.2.1 GET 请求

直接在方法后用参数进行接受,需要指定参数的类型
1)接受参数的形式

@RequestMapping("/commonParam")
@ResponseBody
public String commonParam(String name, int age){
    System.out.println("普通参数传递 name = " + name);
    System.out.println("普通参数传递 age = " + age);
    return "{'module':'commonParam'}";
}

2)乱码问题:如果使用 tomcat7 插件运行,会遇到中文乱码问题,解决方法是在 pom.xml 文件中将编码格式指定为 UTF-8

<build>
  <plugins>
    <plugin>
      <groupId>org.apache.tomcat.maven</groupId>
      <artifactId>tomcat7-maven-plugin</artifactId>
      <version>2.1</version>
      <configuration>
        <port>8080</port>
        <path>/</path>
        <uriEncoding>UTF-8</uriEncoding>
      </configuration>
    </plugin>
  </plugins>
</build>

3)使用本地 Tomcat 乱码

Tomcat8 以上的版本一般不会 Get 请求乱码,但是较低版本的还是可能会存在问题的,如果发生这样的错误,可以使用这样的方式来解决

原理:默认的 URL 使用 ISO-8859-1 字符集,使用 UTF-8 字符集重新编码;其中 str 是获取到的乱码的字符串

str = new String(str.getBytes(StandardCharsets.ISO_8859_1),StandardCharsets.UTF_8);

2.2.2 POST 请求

1) 接受参数和 GET 请求类似:https://www.yuque.com/gzwangsong/mystudy_java/gd0k2pl8gaggvnxg?inner=LqCF8

一般来说,POST 请求不推荐使用 GET 请求的参数形式,但是确实可以使用那样形式的参数

2)中文乱码:POST 请求的中文乱码和 GET 请求的中文乱码不一样,通常是使用过滤器对请求的数据进行处理

//乱码处理
@Override
protected Filter[] getServletFilters() {
    CharacterEncodingFilter filter = new CharacterEncodingFilter();
    filter.setEncoding("UTF-8");
    return new Filter[]{filter};
}

2.3 五种类型参数的传递

2.3.1 简单数据参数

基本数据类型和 String 字符串类的,一把是直接在方法里面使用参数来接收即可

@RequestMapping("/commonParam")
@ResponseBody
public String commonParam(String name,int age){
    System.out.println("普通参数传递 name ==> "+name);
    System.out.println("普通参数传递 age ==> "+age);
    return "{'module':'commonParam'}";
}

2.3.2 POJO 类型的参数

需要请求请求参数的名称和 POJO 对象的成员变量名称一致;

2.3.3 嵌套 POJO 类型的参数

类似 2.3.2,需要成员变量的名称和前端请求数据的名称一致;

2.3.4 数组类型参数

直接定义数据类型的参数接收即可

//数组参数:同名请求参数可以直接映射到对应名称的形参数组对象中
@RequestMapping("/arrayParam")
@ResponseBody
public String arrayParam(String[] likes){
    System.out.println("数组参数传递 likes ==> "+ Arrays.toString(likes));return "{'module':'array param'}";
}

2.3.5 集合类型参数

//集合参数:同名请求参数可以使用@RequestParam注解映射到对应名称的集合对象中作为数据
@RequestMapping("/listParam")
@ResponseBody
public String listParam(List<String> likes){
    System.out.println("集合参数传递 likes ==> "+ likes);
    return "{'module':'list param'}";
}

2.4 响应

对于 SpringMVC 的响应,主要包含两个方面:响应页面响应数据

2.4.1 响应页面

直接返回页面的名称,会直接跳转到响应的页面;

2.4.2 响应文本数据

直接返回即可

2.4.3 响应 JSON 数据

1)将数据封装到 POJO 类型数据
将请求的数据封装到 POJO 模型当中,参数名称和 POJO 模型中的属性名称相对应,Spring 底层会自动将数据类型给封装到 POJO 模型的数据当中;

2)开启 SpringMVC 的增强功能:@EnableWebMvc

@Configuration
@ComponentScan("cn.edu.njust.controller")
@EnableWebMvc
public class SpringMvcConfig {
}

3)@ResponseBody:标识方法返回的是数据;

3 JSON 数据传输

在 SpringMVC 参与开发的项目中,大多数是使用 JSON 数据格式进行前后端的数据交互;
SpringMVC默认使用的是jackson来处理json的转换,所以需要在pom.xml添加jackson依赖

3.1 简单使用

1)导入依赖坐标,加载依赖

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.15.2</version>
</dependency>

2)开启 SpringMVC 对 JSON 的支持

主要是:@EnableWebMvc 注解

@Configuration
@ComponentScan("cn.edu.njust.controller")
@EnableWebMvc
public class SpringMvcConfig {
}

3)使用@RequestBody 注解著名参数

@RequestMapping("/jsonarray")
@ResponseBody
public String jsonArray(@RequestBody List<Integer> list) {
    System.out.println(list);
    return "{'status':'true'}";
}
@RequestMapping("/jsonobject")
@ResponseBody
public String jsonRequest(@RequestBody User user) {
    System.out.println(user);
    return "{'status':'true'}";
}

3.2 SpringMVC 的转换 JSON 的底层原理

SpringMVC 底层通过一些转换数据的接口,对我们传入的数据进行转换,其中一个接口是:Converter,所属的包为org.springframework.core.convert.converter

4 REST 风格

1)对 URL 的请求路径做隐藏,隐藏客户的行为动作;
2)同一个 URL 使用不同的方式发起请求,代表着不同的意义;
3)常见的风格(不是规范)
3.1) 发送GET请求是用来做查询
3.2) 发送POST请求是用来做新增
3.3) 发送PUT请求是用来做修改
3.4) 发送DELETE请求是用来做删除

指定请求参数:

@Controller
public class UserController {
    //设置当前请求方法为POST,表示REST风格中的添加操作
    @RequestMapping(value = "/users",method = RequestMethod.POST)
    @ResponseBody
    public String save() {
        System.out.println("user save...");
        return "{'module':'user save'}";
    }
}
/**
 * restful风格的请求,使用 method 指明请求方法
 * @param userId -- 使用 PathVariable 绑定路径参数,如果参数名称与路径参数一样,可以省略
 * @return 可以直接返回字符串
 */
@RequestMapping(value = "/user/test/{id}", method = RequestMethod.GET)
@ResponseBody
public String testMethod(@PathVariable("id") Integer userId) {
    System.out.println(userId);
    return "true";
}

5 Spring 中的拦截器

5.1 拦截器和过滤器

1)归属不同:过滤器(Filter)属于 Servlet 技术,而拦截器(interceptor)是属于 SpringMVC 的技术;
2)拦截的内容不同:过滤器拦截访问,对访问进行增强控制;而拦截器主要对 SpringMVC 的访问进行控制;
3)顺序:请求应该先经过过滤器,再到达拦截器;响应先通过拦截器,再通过过滤器;

5.2 实例

1)实现 HandlerInterceptor 接口

package cn.edu.njust.controller.interceptor;

import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component
//定义拦截器类,实现HandlerInterceptor接口
//注意当前类必须受Spring容器控制
public class ProjectInterceptor implements HandlerInterceptor {
    @Override
    //原始方法调用前执行的内容
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
                             Object handler) throws Exception {
        System.out.println("preHandle...");
        return true;
    }

    @Override
    //原始方法调用后执行的内容
    public void postHandle(HttpServletRequest request, HttpServletResponse response,
                           Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle...");
    }

    @Override
    //原始方法调用完成后执行的内容
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
                                Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion...");
    }
}

2)添加拦截器

package cn.edu.njust.config;

import cn.edu.njust.controller.interceptor.ProjectInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {
    @Autowired
    private ProjectInterceptor projectInterceptor;

    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
        registry.addResourceHandler("/css/**").addResourceLocations("/css/");
        registry.addResourceHandler("/js/**").addResourceLocations("/js/");
        registry.addResourceHandler("/plugins/**").addResourceLocations("/plugins/");
    }

    /**
     * 配置拦截器
     * @param registry
     */
    @Override
    protected void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(projectInterceptor).addPathPatterns("/books");
    }
}

3)将拦截器添加到 SpringMVC 的配置类中

5.3 拦截器的执行

image.png

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

拜见老天師

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值