SpringMVC

发布于:2024-12-19 ⋅ 阅读:(12) ⋅ 点赞:(0)

SpringMVC

  • SpringMVC 技术与 Servlet 技术功能相同,均属于Web层开发技术
  • SpringMVC 是一种基于Java实现的MVC模型的轻量级Web框架
  • 相较于 Servlet 使用简单,开发便捷,灵活性强。

由于目前绝大多数项目都是使用Springboot框架开发,所以本文只讲述一些重要概念,而不去实现。

案例

第一步:导坐标

<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>3.1.0</version>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.2.10.RELEASE</version>
</dependency>

第二步:创建SpringMVC控制器类

等同于Servlet功能

@Controller					    //声明这个类是一个Bean	1
public class userControler {
    @RequestMapping("/save")    //设置当前操作的访问路径	2
    @ResponseBody			    //设置当前操作的返回值类型3
    public String save(){
        System.out.println("user save...");
        return "{'info':'springmvc'}";
    }
}

第三步:创建SpringMVC的配置类

@Configuration 
@ComponentScan("com.protectark.mysqlt")
public class SpringMvcConfig {
}

第四步:定义一个servlet容器启动的配置类,在里面加载spring的配置

public class servletInConfig extends AbstractDispatcherServletInitializer {
    
    //加载SpringMVC容器配置
    @Override
    protected WebApplicationContext createServletApplicationContext() {

        AnnotationConfigWebApplicationContext act = new AnnotationConfigWebApplicationContext();
        //注册配置
        act.register(SpringMvcConfig.class);
        return act;
    }
    
    //设置那些请求归属springMVC处理
    @Override
    protected String[] getServletMappings() {
        //设置所有请求归SpringMVC管理
        return new String[]{"/"};
    }

    //加载spring容器配置
    @Override
    protected WebApplicationContext createRootApplicationContext() {
        return null;
    }
}

注解说明

在以上案例中,出现了一些新的注解

注解 类型 位置 作用
@Controller 类注解 SpringMVC控制器类上 设定SpringMvc的核心控制器bean
@RequestMapping(地址) 方法注解 SpringMVC控制器类中方法上 设置当前控制器方法请求访问路径
@ResponseBody 方法注解 SpringMVC控制器方法定义上方 设置当前控制器方法响应内容为当前返回值,无需解析

工作流程说明

启动服务器初始化过程

  1. 服务器启动,执行ServletContainersInitConfig类,初始化web容器
  2. 执行createServletApplicationContext方法,创建了webApplicationcontext对象
  3. 加载SpringMvcConfig
  4. 执行@ComponentScan加载对应的bean
  5. 加载UserController,每个@RequestMapping的名称对应一个具体的方法
  6. 执行getServletMappings方法,定义所有的请求都通过springMVC

单次请求过程

  1. 发送请求localhost/ save
  2. web容器发现所有请求都经过springMVC,将请求交给SpringMVC处理
  3. 解析请求路径/save
  4. 由/save匹配执行对应的方法save( )
  5. 执行save()
  6. 检测到有@ResponseBody直接将save()方法的返回值作为响应求体返回给请求方

简化配置类

Spring提供了一个AbstractDispatcherServletInitializer的子类:
AbstractAnnotationConfigDispatcherServletInitializer

public class servletInConfig extends AbstractAnnotationConfigDispatcherServletInitializer {

    //Spring配置路径
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[]{springConfig.class};
    }

    //SpringMVC配置路径
    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{springMvcConfig.class};
    }

    //拦截路径
    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }
}

请求与响应

解决路径冲突

在团队多人开发,如何解决请求路径冲突

设置模块名作为请求路径的前缀
两种方法:

  1. 修改每个方法的路径@RuquestMapping如:
    "/user/save"
    "/book/save"
  2. 修改类的请求路径
    “/user”
    “/save”
    “/book”
    “/save”
注解 类型 位置 作用
@RequestMapping(value) 方法注解 类注解 SpringMVC控制器类中方法上 设置当前控制器方法请求访问路径,如果设置在类上统一设置当前控制器方法请求访问路径前缀

示例:

@Controller
@RequestMapping("/user")
public class userControler {
    @RequestMapping("/save")
    @ResponseBody
    public String save(){
        return "{'info':'springmvc'}";
    }
}
  • value(默认):请求访问你路径,或访问路径前缀

解决中文乱码

关于发送的中文乱码,可以在“servlet容器启动的配置类” servletInConfig中覆盖父类的方法:
为web容器添加过滤器并指定字符集,Spring-web包中提供了专用字符过滤器

//乱码处理
@Override
protected Filter[] getServletFilters() {
    //获取字符过滤器
    CharacterEncodingFilter filter = new CharacterEncodingFilter();
    //设定字符集
    filter.setEncoding("UTF-8");
    return new Filter[]{filter};
}

请求参数与形参不同

例如,定义的方法中形参名为usernameage,但是实际传参为name,age

@Controller
public class userControler {
    @RequestMapping("/save")
    @ResponseBody
    public String save(String username, int age){
        System.out.println(username + age);
        return "{'info':'springmvc'}";
    }
}

测试之后就会发现

username为null

此时我们可以使用一个注解,用来声明参数名: @RequestParam("name")

@Controller
public class userControler {
    @RequestMapping("/save")
    @ResponseBody
    public String save(@RequestParam("name") String username,
                       @RequestParam("age") int age){
        System.out.println(username + age);
        return "{'info':'springmvc'}";
    }
}

传递参数为实体类

如果我们需要的参数过多,比如在新增用户时需要大量的数据,这样我们一般会制作一个实体类,来进行接收。

@Controller
public class userControler {
    @RequestMapping("/save")
    @ResponseBody
    public String save(User user){
        return "{'info':'springmvc'}";
    }
}
public class User{
    private String username;
    private int age;
    //等其他属性
    //重写getter,setter,toString方法
}

这样请求时,如果请求的属性名与实体类中的属性名完全一致,则会自动放入user中。

传递JSON数据

传递JSON数据的时候,我们的数据并不是在请求头的参数中,而是在请求体中。

所以我们在接收的时候也要添加注解,来声明这是请求体中的数据

下面就来实际写一下:

首先应该导入JSON数据转化相关坐标

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

然后告诉SpringMVC开启JSON转化数据

只需要再SpringMvcConfig中加入@EnableWebMvc注释,开启JSON转化数据

@Configuration 
@ComponentScan("com.protectark.mysqlt")
@EnableWebMvc
public class SpringMvcConfig {
}

由于JSON请求再请求体当中所以,再Controller方法中
对于形参的修饰不能使用@RequestParam
要使用@RequestBody

@RequestMapping("/inputuser")
@ResponseBody
public String init(@RequestBody User user){
    System.out.println("input user ==>"+user);
    return "{'info':'springMVC'}";
}

到此完成。

注解 类型 位置 作用
@EnableWebMvc 配置类注解 SpringMVC配置类定义上方 开启SpringMVC多项辅助功能
@RequestBody 形参注解 Controller方法形参前 将请求中请求体所包含的数据传递给请求参数,此注解一个处理器方法只能使用一次

RequestBodyRequestParam对比

  • 区别

    • @RequestParam用于接收ur1地址传参,表单传参【application/x-www-form-urlencoded)
    • @RequestBody用于接收json数据【application/json】
  • 应用

    • 后期开发中,发送json格式数据为主,@RequestBody应用较广

    • 如果发送非json格式数据,选用@RequestParam接收请求参数

后面还有一个@PathVariable 属于形参注解,绑定路径参数与形参的关系

@RequestMapping("/users/{id}")
@ResponseBody
public String init(@PathVariable Integer id){
    System.out.println("input id ==>"+id);
    return "{'info':'springMVC'}";
}

日期类型参数传递

SpringMVC可以直接接收String类型的参数,并自动转为日期类型,如果需要指定格式可以使用注解

@DateTimeFormat

@RequestMapping("/inputuser")
@ResponseBody
public String init(@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss") Date date){
    System.out.println("input date ==>"+date);
    return "{'info':'springMVC'}";
}
注解 类型 位置 作用
@DateTimeFormat 形参注解 SpringMVC控制器方法形参前 设定日期时间型数据格式

属性:pattern:日期时间格式字符串

响应

如果要响应json数据,则只需要返回实体类即可

@RequestMapping("/select")
@ResponseBody
public User select(){
	User user = new User();
    return user;
}

SpringMVC会自动将实体类转化为json数据

注解 类型 位置 作用
@ResponseBody 方法注解 SpringMVC控制器方法上 设置当前控制器方法响应内容为当前返回值,无需解析

REST 风格

概念

REST(Representational state Transfer),表现形式状态转换

  • 传统风格资源描述形式
    • http://localhost/user/getById?id=1
    • http://localhost/user/saveUser
  • REST风格描述形式
    • http://localhost/user/1
    • http://localhost/user

优点:书写简化,隐藏资源访问方式,无法通过地址得知对资源是哪种请求方式。

按照REST风格访问资源时使用行为动作区分对资源进行了何种操作

  • http://localhost/users 查询全部用户信息 GET(查询)
  • http://localhost/users/1 查询指定用户信息 GET(查询)
  • http://localhost/users 添加用户信息 POST(新增/保存)
  • http://localhost/users 修改用户信息 PUT(修改/更新)
  • http://localhost/users/1 删除用户信息 DELETE(删除)

这种方式属于约定方式,称为REST风格。根据这种风格对资源访问的方式称为RESTful

描述模块的名称通常使用复数,也就是加s的格式描述,表示此类资源,而非单个资源,例如:users、books、accounts…

RESTful 快速开发

由于REST风格都使用JSON进行通信,所以每一个方法都需要带有@ResponseBody,所以我们可以将这个注解放到控制器类上,又因为我们所有的控制器类都有@Controller和@ResponseBody注解,所以SpringMVC就将这两个合二为一:@RestController

又因为我们使用的请求方式,绝大多数就四种,所以@RequestMapping注解也可以根据请求方式衍生出

  • @PostMapping
  • @GetMapping
  • @PutMapping
  • @DeleteMapping

使用这种方式,我们的Controller就由

@Controller
public class userControler {
    @RequestMapping(value = "/users/save",method = RequestMethod.Get)
    @ResponseBody
    public String save(@Requestbody User user){
        return "{'info':'springmvc'}";
    }
    
    @RequestMapping(value = "/users/delete",method = RequestMethod.Delete)
    @ResponseBody
    public String save(@Requestbody User user){
        return "{'info':'springmvc'}";
    }
}

变为了

@RestController
@RequestMapping("/users")
public class userControler {
	@GetMapping()
     public String save(@Requestbody User user){ 
         return "{'info':'springmvc'}";
    }
    @DeleteMapping()
    public String save(@Requestbody User user){
        return "{'info':'springmvc'}";
    }
}