【Java】springmvc

2023-12-24 18:06:08

SpringMVC

SpringMVC和Servlet技术栈等同,都用于controller层/web层开发。但是SpringMVC的开发难度比Servlet更简单。

1、SpringMVC简单入门

  • 首先,导入SpringMVC坐标,以及servlet坐标

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 创建SpringMVC控制类,将这个类变成bean。 然后在这个类中写表现层的东西。使用@RequestMapping定义请求资源路径,使用@ResponseBody定义响应体。

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 新建一个springmvc的配置文件类加载Controller的bean。这里注意springmvc的配置文件和spring的配置文件要区分开,springmvc只导入表现层的bean,spring载入dao层和service层的bean。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 需要定义一个配置类ServletContainerInitConfig配置Tomcat。(更规范地来说,就是配置web容器。需要加载springmvc的配置类以及spring的配置类。)==这个类也是web程序的启动类。==里面会对springmvc和spring的配置类进行加载,创建这两个配置的IoC容器。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

其实这些东西都是很固定的,要用的时候只需要复制粘贴就可以了,只有一些是需要根据具体的需求进行修改的。

spring的IoC容器不要加载springmvc的bean,springmvc的IoC容器不要加载spring的bean。要实现这种功能,有两种方案:

  • 精准控制两个容器的包扫描范围。这种方法比较简单。
  • spring加载全部,不过排除掉controller的bean。springmvc只加载controller。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2、请求与响应

2.1、请求映射路径

注解@RequestMapping(“/brand”)是请求映射路径,用于设置当前控制器方法的资源请求路径。这个注解既可以用在controller类上,也可以用在方法上。类上的可以不用但是方法上的一定要用。controller中一个方法就是一个资源。

注意,不同的controller中资源的路径不要相同,如果有两个资源路径相同,当一个请求进来后,springmvc不知道要将该请求映射到哪个资源。事实上,如果写了两个相同路径的资源,springmvc在编译的时候就会报错了。

2.2、接收请求参数

(1)接收少量请求参数

直接在方法的参数上设置形参,这个形参就代表着请求的参数。

形参需要跟请求参数匹配:

  • 方式一:形参的名字和请求参数的键名字一样,会自动匹配。
  • 方式二:如果形参的名字和请求参数的键名字不一样,需要在形参之前使用@RequestParam("请求参数键名")来建立请求参数与形参之间的关系。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(2)接收大量请求参数

  • 第一种:方法形参写一个pojo实体类(实体类的属性名字必须和请求参数的名字完全一致)。框架会自动将请求参数装配到实体的属性中,非常方便。(如果pojo中的属性有引用数据类型,请求参数需要写成引用对象名.引用对象属性的形式。)

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 第二种:方法参数写一个数组。请求参数的形式需要写成:

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    键相同,值不同。如此一来,所有的值会自动转换为一个数组。

  • 第三种:方法参数写一个集合。形参前面需要写一个注解@RequestParam,这样一来,所有请求键值对会被视为一个大的请求参数,当方法参数又是集合类型时,springmvc会把键值对中的值装入集合中。如果不写注解,集合会被识别成pojo实体类,请求参数会被设置成集合的属性(报错,集合中不会有这些属性),而不是集合的数据。请求参数的写法跟上边的数组一样,键值对的所有键名需要一致。

2.3、接收请求体

首先先导入一个json依赖,用于实体类、数组类、集合类与json数据的相互转换。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

由于springmvc不知道请求携带的是json数据,所以还要告诉springmvc要进行json数据转换。在springmvc的配置类上使用注解@EnableWebMvc

json数据在请求体中。所以,接收请求数据时,方法的形参前需要写个注解@RequestBody。(要注意,实体类不要写构造方法,默认无参就可以了。getter和setter写上。

2.4、Convertor接口

springmvc之所以能将请求参数/请求体中的数据转成Java中的对象,其实是使用了各种内置的springmvc转换器对象。

当 Spring MVC 框架内置的类型转换器不能满足需求时,开发者可以开发自己的类型转换器类。

自定义类型转换器类需要实现 Converter<S,T> 接口,重写 convert(S) 接口方法。之后,需要将该类注册成bean。

也可以采取另一种方式,使用匿名内部类来实现接口。详见下边的接收时间日期的第二种方式,就使用了这种方式。

如此一来,当在自动转换时,springmvc就多出了一个自动转换的选择。我们的自动转换类也能生效啦。

2.5、接收时间日期

实际上jdk8以前的日期时间处理都是用Date和Calendar类。不过这两玩意实在是太难用了,一直被喷,所以jdk8出现了新的日期时间处理LocalDate/LocalDateTime。

  • 第一种,将请求参数转成Date类。

    在方法参数中使用Date类型来作为参数类型。当请求参数中携带日期格式的值时,会自动转为Date对象。值得注意的是,请求参数中日期的格式应该为yyyy/MM/dd,如果要用其他格式,需要为方法参数加上注解@DateTimeFormat

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 第二种,将请求参数转成LocalDate/LocalDateTime。springmvc的内置转换类是没有这种转换的,所以需要自定义转换器。

    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.core.convert.converter.Converter;
    import org.springframework.http.converter.HttpMessageConverter;
     
    import java.time.LocalDate;
    import java.time.LocalDateTime;
    import java.time.format.DateTimeFormatter;
     
    @Configuration
    public class DateConfig {
     
        @Bean
        public Converter<String, LocalDate> localDateConverter() {
            //匿名内部类,实现了Convertor接口
            return new Converter<>() {
                @Override
                public LocalDate convert(String source) {
                    return LocalDate.parse(source, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
                }
            };
        }
     
        @Bean
        public Converter<String, LocalDateTime> localDateTimeConverter() {
            //匿名内部类,实现了Convertor接口
            return new Converter<>() {
                @Override
                public LocalDateTime convert(String source) {
                    return LocalDateTime.parse(source, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
                }
            };
        }
     
    }
    
2.6、响应数据

接收请求数据写在形参中,那么响应数据写在方法的返回值中。只需要将对象返回,之前导入的坐标会自动将对象转化为json数据响应。

主要是@ResponseBody在发挥作用。如果不写这个注解返回的响应就是文本了。

@ResponseBody会将返回的响应自动转化为json数据。

springmvc能够自动将return的数据转为json数据,是通过一个接口(不是Convertor接口)完成的。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

3、REST风格

传统风格描述资源格式:

http://localhost/user/selectById?id=1

REST风格:

http://localhost/user/1

REST风格的优点是隐藏。既然做了隐藏,又该如何知道请求想要表达的是增、删、改、查中的哪种操作呢?

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

其实总结起来就是:请求资源限定为四种格式:GET、POST、PUT、DELETE。

客户端发出请求的时候,需要标明是哪一种格式。到服务器的表现层,会自动匹配到对应格式的资源。

这里就有两步:

  • 客户端发出请求给特定控制器(控制器的路径是要写上的),标明是哪一种格式(目前是直接在postman里直接设置进行测试)

  • 服务端对应的控制器接收请求,在控制器中匹配是哪一种格式,找到对应方法。

    ==这里,匹配是哪一种格式是由请求映射路径的注解@RequestMapping来进行的。现在@RequestMapping就不能只是简单地写资源路径,还要写上REST风格的行为动作(注解中加上一个参数method=),以便和请求匹配。==请求如果有路径变量,请求路径映射注解中要写上路径变量的占位符,而且方法形参中要写上@PathVariable注解。

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

RESTful快速开发

把@ResponseBody和@RequestMapping(”控制器路径“)从各个方法上提出来写到类名上,把@ResponseBody和@Controller合二为一叫做@RestController。把REST风格的行为动作在各个方法上写成@PostMapping()、@DeleteMapping(”/{路径变量名}“)等等。这样就大幅简化了开发。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

注意:对于Post和Put这些没有路径变量的行为动作,请求体中是可以有json数据的。同样,直接在方法形参上注解@RequestBody就可以了。

4、异常处理器

各个层级都会出现异常,那么异常代码书写在哪一层?所有的异常均抛出到表现controller层进行处理。

如果每有一个异常就写代码进行处理,太过臃肿,使用aop思想处理表现层中的异常。

spring中定义了一个异常处理器统一集中地处理表现层中异常。在controller包中定义一个类:ProjectExceptionAdvice类,注解是@RestControllerAdvice然后在这个类中写方法拦截异常。

注意:这个类要被springmvc的配置类加载到。然后要在这个类的方法中写一个注解:@ExceptonHandler,里边写上表现层抛出的异常类型,根据异常类型到这个方法中执行。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

5、拦截器

5.1、拦截器制作

在访问控制器资源的时候,首先进入拦截器方法进行处理,访问完控制器资源之后,也要进入拦截器方法进行一定处理。

  • 制作拦截器功能类

制作一个拦截器类,放在controller包下。而且要把这个类变成一个bean然后被springmvc加载

实现拦截器接口,重写三个方法。第一个方法preHandle()在访问控制器资源前执行,第二个方法postHandle()在访问控制器资源后执行,第三个方法afterCompletion()在第二个方法执行后执行。

==拦截器三个方法的参数就是拦截到的请求以及响应。==图片中没有写出来。

如果三个方法中,第一个方法return true,就能继续访问controller资源,然后进入第二个方法和第三个方法,return false,不能访问controller资源。return true就是放行,return false就是拒绝放行。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 注册拦截器到springmvc中并配置拦截路径

定义一个配置类,继承WebMvcConfigurationSupport,实现addInterceptor方法,在方法中添加上边写的拦截器并设定拦截路径。拦截的路径可以写多个,并且可以用*通配符。比如/books/ *表示拦截访问books下所有资源的请求。

注意使用@Configuration将这个类加载到SpringMVC的容器中。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

除了以上方式外,有一种侵入式比较强但是比较方便的方法。同样要写一个拦截器类,然后让springmvc配置类实现WebMvcConfigurer接口,然后重写方法添加拦截器并设置拦截路径。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

5.2、拦截器三个方法的参数

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

5.3、拦截器链

如果有多个拦截器,可以设置这些拦截器的执行顺序。这就形成了一个拦截器链。

如果创建了拦截器1、拦截器2、拦截器3,这三个拦截器按照拦截器2、拦截器1、拦截器3的顺序进行注册。

当一个请求进来,它的经过顺序为:

  • 2pre
  • 1pre
  • 3pre
  • 访问controller的资源
  • 3post
  • 1post
  • 2post
  • 3after
  • 1after
  • 2after

如果请求在1pre被拒绝放行,它会跳到1after后即2after继续执行。

一个递归的操作。

文章来源:https://blog.csdn.net/weixin_52808620/article/details/135172160
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。