SpringMVC

发布时间 2023-09-09 11:49:22作者: SimpleWord

SpringMVC入门案例

SpringMVC和Spring是父子关系,他是Spring中专门用于web开发的模块。

Spring框架主要有两种类型的容器:核心容器(Spring容器)和Web容器(Spring MVC容器)。

  1. Spring容器:也被称为IoC容器,它负责实现依赖注入以管理Beans。Spring容器负责创建Bean、装配Bean、管理Bean的生命周期等任务。它使用XML文件或者注解来配置并初始化应用对象及其关联。在Spring容器中,常见的组件包括Service层的服务组件、DAO层的数据访问组件等。
  2. Spring MVC容器:也叫做子容器或者Web容器,它是在Spring容器的基础上增加了对Web应用的支持,特别是MVC设计模式的支持。Spring MVC容器会管理控制器、视图解析器、处理器映射等Web相关的组件。但需要注意的是,Spring MVC容器能访问Spring容器的Beans,但反过来则不行。

流程

  1. 创建web工程(Maven结构)
  2. 设置tomcat服务器,加载web工程(tomcat插件)
  3. 导入坐标(SpringMVC+Servlet)
  4. 定义处理请求的功能类(UserController)
  5. 设置请求映射(配置映射关系【请求路径】)
  6. 将SpringMVC设定加载到Tomcat容器中

image-20230826123221468

引入相关依赖

<dependencies>
        <dependency>
            <groupId>jakarta.servlet</groupId>
            <artifactId>jakarta.servlet-api</artifactId>
            <version>5.0.0</version>
            <scope>provided</scope>
        </dependency>

        <!--会关联Spring基本模块-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>6.0.9</version>
        </dependency>
</dependencies>

分层

Controller

@Controller // 这是一个控制器类的标识,表示这是一个Spring MVC控制器
@RequestMapping("user") //所有球球路径的前缀
@ResponseBody // 此注解表示方法的返回值将作为响应的请求体,而不是视图名称【页面】
public class UserController {

    @RequestMapping("/save") // 方法级别的路径映射,完整的访问路径是"user/save"
    public String saveUser() {
        String msg = "用户正在保存";
        System.out.println(msg);
        return msg; // 这个字符串会作为响应的请求体返回给客户端
    }
}

Config

@Configuration
@ComponentScan("bid.simpleword.controller") //这里包扫描controller由SpringMVC管理,如果要配置Spring,SpringConfig应该扫描service和dao
public class SpringMvcConfig {

}
public class ServletConfig extends AbstractDispatcherServletInitializer {
    //加载SpringMVC容器对象
    @Override
    protected WebApplicationContext createServletApplicationContext() {
        AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext(); //注意
        ctx.register(SpringMvcConfig.class);
        return ctx;
    }

    //哪些请求需要由SpringMVC处理
    @Override
    protected String[] getServletMappings() {
        //配置请求交由MVC处理【这里配置所有】,还是tomact[默认]
        return new String[]{"/"};
    }

    //加载Spring容器对象
    @Override
    protected WebApplicationContext createRootApplicationContext() {
        //现在我们还不需要Spring
        return null;
    }
}

访问【启动tomcat】,访问:localhost:8080/user/save

启动流程

image-20230826171326820

image-20230826171358475

注意事项

  • 有多个controller有相同的请求路径,应该设置父级访问路径

Post请求中文乱码处理

过滤器,设置编码格式是UTF-8

public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
    protected Class<?>[] getRootConfigClasses() {
        return new Class[0];
    }

    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{SpringMvcConfig.class};
    }

    protected String[] getServletMappings() {
        return new String[]{"/"};
    }

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

请求参数

  • 基本类型参数

  • pojo类型

  • 数组

  • 集合

  • json

@Controller
@ResponseBody
public class UserController {

    //普通参数:请求参数与形参名称对应即可完成参数传递
    @RequestMapping("/commonParam")
    public String commonParam(String name ,int age){
        System.out.println("普通参数传递 name ==> "+name);
        System.out.println("普通参数传递 age ==> "+age);
        return "{'module':'common param'}";
    }

    //普通参数:请求参数名与形参名不同时,使用@RequestParam注解关联请求参数名称与形参名称之间的关系
    @RequestMapping("/commonParamDifferentName")
    public String commonParamDifferentName(@RequestParam("name") String userName , int age){
        System.out.println("普通参数传递 userName ==> "+userName);
        System.out.println("普通参数传递 age ==> "+age);
        return "{'module':'common param different name'}";
    }

    //POJO参数:请求参数与形参对象中的属性对应即可完成参数传递
    @RequestMapping("/pojoParam")
    public String pojoParam(User user){
        System.out.println("pojo参数传递 user ==> "+user);
        return "{'module':'pojo param'}";
    }

    //嵌套POJO参数:嵌套属性按照层次结构设定名称即可完成参数传递
    @RequestMapping("/pojoContainPojoParam")
    public String pojoContainPojoParam(User user){
        System.out.println("pojo嵌套pojo参数传递 user ==> "+user);
        return "{'module':'pojo contain pojo param'}";
    }

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

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


    //集合参数:json格式【映入jackson依赖】
    //1.开启json数据格式的自动转换,在MVC配置类中开启@EnableWebMvc
    //2.使用@RequestBody注解将外部传递的json数组数据映射到形参的集合对象中作为数据
    @RequestMapping("/listParamForJson")
    public String listParamForJson(@RequestBody List<String> likes){
        System.out.println("list common(json)参数传递 list ==> "+likes);
        return "{'module':'list common for json param'}";
    }

    //POJO参数:json格式
    //1.开启json数据格式的自动转换,在配置类中开启@EnableWebMvc
    //2.使用@RequestBody注解将外部传递的json数据映射到形参的实体类对象中,要求属性名称一一对应
    @RequestMapping("/pojoParamForJson")
    public String pojoParamForJson(@RequestBody User user){
        System.out.println("pojo(json)参数传递 user ==> "+user);
        return "{'module':'pojo for json param'}";
    }

    //集合参数:json格式
    //1.开启json数据格式的自动转换,在配置类中开启@EnableWebMvc
    //2.使用@RequestBody注解将外部传递的json数组数据映射到形参的保存实体类对象的集合对象中,要求属性名称一一对应
    @RequestMapping("/listPojoParamForJson")
    public String listPojoParamForJson(@RequestBody List<User> list){
        System.out.println("list pojo(json)参数传递 list ==> "+list);
        return "{'module':'list pojo for json param'}";
    }

    //日期参数
    //使用@DateTimeFormat注解设置日期类型数据格式,默认格式yyyy/MM/dd
    @RequestMapping("/dataParam")
    public String dataParam(Date date,
                            @DateTimeFormat(pattern="yyyy-MM-dd") Date date1,
                            @DateTimeFormat(pattern="yyyy/MM/dd HH:mm:ss") Date date2){
        System.out.println("参数传递 date ==> "+date);
        System.out.println("参数传递 date1(yyyy-MM-dd) ==> "+date1);
        System.out.println("参数传递 date2(yyyy/MM/dd HH:mm:ss) ==> "+date2);
        return "{'module':'data param'}";
    }

}

image-20230826173323718

REST

image-20230826173522887

请求格式都是/user,因为请求方式的不同而含义不同

@RestController //restbaoy+controller
@RequestMapping("/books")
public class BookController {

    @PostMapping      //增加
    public String save(@RequestBody Book book){
        System.out.println("book save ==> "+ book);
        return "{'module':'book save success'}";
    }

    @GetMapping   //查询
    public List<Book> getAll(){
        System.out.println("book getAll is running ...");
        List<Book> bookList = new ArrayList<Book>();

        Book book1 = new Book();
        book1.setType("计算机");
        book1.setName("SpringMVC入门教程");
        book1.setDescription("小试牛刀");
        bookList.add(book1);

        Book book2 = new Book();
        book2.setType("计算机");
        book2.setName("SpringMVC实战教程");
        book2.setDescription("一代宗师");
        bookList.add(book2);

        Book book3 = new Book();
        book3.setType("计算机丛书");
        book3.setName("SpringMVC实战教程进阶");
        book3.setDescription("一代宗师呕心创作");
        bookList.add(book3);

        return bookList;
    }

}
@RestController
@RequestMapping("/books")
public class BookController2 {

    @PostMapping
    public String save(@RequestBody Book book) {
        System.out.println("book save..." + book);
        return "{'module':'book save'}";
    }

    @DeleteMapping("/{id}")  //删除,传入ID即可
    public String delete(@PathVariable Integer id) {
        System.out.println("book delete..." + id);
        return "{'module':'book delete'}";
    }

    @PutMapping
    public String update(@RequestBody Book book) {
        System.out.println("book update..." + book);
        return "{'module':'book update'}";
    }

    @GetMapping("/{id}")
    public String getById(@PathVariable Integer id) {
        System.out.println("book getById..." + id);
        return "{'module':'book getById'}";
    }

    @GetMapping
    public String getAll() {
        System.out.println("book getAll...");
        return "{'module':'book getAll'}";
    }
}

统一格式返回

可以在Controller下【实际哪都行】创建

  • Result类
  • code类

image-20230826174224305

每次返回都需要创建对象 new Result(code,msg,data)

code可以定义为新的类的静态常量或者枚举。

统一异常处理

image-20230826175151371

使用Spring提供的异常处理器【基于AOP,不需要每个类的写相同的代码】

  • 自定义注解

  • 异常返回也要是和之前的一样统一格式

    • 定义异常的code
    //@RestControllerAdvice用于标识当前类为REST风格对应的异常处理器[不用REST方格可使用@ControllerAdvice]
    @RestControllerAdvice
    public class ProjectExceptionAdvice {
        //@ExceptionHandler用于设置当前处理器类对应的异常类型
        @ExceptionHandler(SystemException.class) 
        public Result doSystemException(SystemException ex){
            //记录日志
            //发送消息给运维
            //发送邮件给开发人员,ex对象发送给开发人员
            return new Result(ex.getCode(),null,ex.getMessage());
        }
    
        @ExceptionHandler(BusinessException.class)
        public Result doBusinessException(BusinessException ex){
            return new Result(ex.getCode(),null,ex.getMessage());
        }
    
        //除了自定义的异常处理器,保留对Exception类型的异常处理,用于处理非预期的异常
        @ExceptionHandler(Exception.class)
        public Result doOtherException(Exception ex){
            //记录日志
            //发送消息给运维
            //发送邮件给开发人员,ex对象发送给开发人员
            return new Result(Code.SYSTEM_UNKNOW_ERR,null,"系统繁忙,请稍后再试!");
        }
    }
    
public class SystemException extends RuntimeException{
    private Integer code;

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public SystemException(Integer code, String message) {
        super(message);
        this.code = code;
    }

    public SystemException(Integer code, String message, Throwable cause) {
        super(message, cause);
        this.code = code;
    }

}

拦截器

拦截器是SpringMVC中的概念【基于AOP】

image-20230826175528403

image-20230826175439346