SpringMVC

SpringMVC

1、springMVC简介:

SpringMVC概述:

  • springMVC技术与Service技术功能等同,均属于web层开发技术

image-20230412103813286

  • SpringMVC是一种基于Java实现MVC模型的轻量级web框架

  • 优点

    • 使用简单,开发便捷(相比于Servlet)
  • springMVC原始开发的工作流程

    image-20230421084445160

2、springMVC入门案例

2.1、操作步骤:

  • 使用springMVC技术需要导入springMVC坐标于servlet坐标和tomcat插件
<!--1、导入springMVC和servlet的坐标-->
<dependencies>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>3.1.0</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.2.10.RELEASE</version>
    </dependency>

</dependencies>

 <build>
        <plugins>
            <!-- 配置Tomcat插件 -->
            <plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <version>2.1</version>
                <configuration>
                    <!--端口号-->
                    <port>8088</port>
                    <!--设置项目路径-->
                    <path>/</path>
                </configuration>

            </plugin>
        </plugins>
    </build>

  • 创建springMVC控制器类(等同于servlet功能)
/**
 * @author: anle
 * @date: 2023/04/12 11:07
 *
 * 2、定义Controller类
 * 2.1使用@Controller来定义bean
 **/
@Controller
public class UserController {

    //2.2 设置当前操作的访问路径
    @RequestMapping("/sho")
    //2.3 设置当前操作的返回值类型
    @ResponseBody
    public String sho(){
        System.out.println("user...sho");
        return  "{'module':'springmvc'}";
    }

}
  • 初始化springMVC环境(同spring环境),设置springMVC加载对应的bean

    /**
     * @author: anle
     * @date: 2023/04/12 11:15
     **/
    //3、创建springmvc的配置文件,加载controller对应的bean
    @Configuration
    @ComponentScan("com.anle.controller")
    public class SpringMvcConfig {
    }
    
  • 初始化servlet容器,加载springMVC环境并设置springMVC技术处理的请求

/**
 * @author: anle
 * @date: 2023/04/12 11:18
 **/
//4、定义一个servlet容器的配置类,在里面加载spring的配置
public class ServletConfig extends AbstractDispatcherServletInitializer {

    //加载springMvc容器配置
    @Override
    protected WebApplicationContext createServletApplicationContext() {
        AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
        ctx.register(SpringMvcConfig.class);
        return ctx;
    }

    //设置那些请求归属sprigMVC处理
    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }

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

2.2、相关注解:

  • 名称:@Controller

  • 类型:类注解

  • 位置:springMVC控制器类上方

  • 作用:设定springMVC的核心控制器bean

  • 范例:

    @Controller
    public class UserController {
    }
    
  • 名称:@RequestMapping

  • 类型:类注解

  • 位置:springMVC控制器类上方

  • 作用:设置当前控制器方法请求访问的路径

  • 范例:

    //2.2 设置当前操作的访问路径
    @RequestMapping("/sho")
    //2.3 设置当前操作的返回值类型
    @ResponseBody
    public String sho(){
        System.out.println("user...sho");
        return  "{'module':'springmvc'}";
    }
    
  • 相关属性:value(默认):请求访问路径

  • 名称:@ResponseBody

  • 类型:类注解

  • 位置:springMVC控制器类上方

  • 作用:设置当前控制器方法响应内容为当前返回值,无需解析

  • 范例:

    //2.2 设置当前操作的访问路径
    @RequestMapping("/sho")
    //2.3 设置当前操作的返回值类型
    @ResponseBody
    public String sho(){
        System.out.println("user...sho");
        return  "{'module':'springmvc'}";
    }
    

2.3、springMVC入门程序开发总结

  • 一次性工作
    • 创建工程,设置服务器,加载工程
    • 导入坐标
    • 创建web容器启动类,加载springMVC配置,并设置springMVC请求拦截路径
    • springMVC核心配置类(设置配置类,扫描controller包,加载controller控制器包)
  • 多次工作
    • 定义处理请求控制器类
    • 定义请求的控制方法,并配置映射路径(@RequestMapping)与返回值json数据(@ResponseBody)

2.4、servlet容器简介:

  • AbstractDispatcherServletInitializer类是springMVC提供的快速初始化web3.0容器的抽象类

  • AbstractDispatcherServletInitializer提供三个接口方提供用户使用

    • createServletApplicationContext()方法,创建servlet容器时,加载springMVC对应的bean并放入

      WebApplicationContext对象范围中,而 WebApplicationContext的作用范围为ServletContext范围,即整个web容器

//加载springMvc容器配置
@Override
protected WebApplicationContext createServletApplicationContext() {
    AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
    ctx.register(SpringMvcConfig.class);
    return ctx;
}
  • getServletMappings()方法,设定springMVC对应的请求映射路径,设置为/表示拦截所有请求,任意请求都将转入到springMVC进行处理
//设置那些请求归属sprigMVC处理
@Override
protected String[] getServletMappings() {
    return new String[]{"/"};
}
  • createRootApplicationContext()方法,如果创建servlet容器时需要加载非springMVC对应的bean,使用当前方法进行,使用方法式同createRootApplicationContext()
 //加载spring配置
    @Override
    protected WebApplicationContext createRootApplicationContext() {
        return null;
    }
}

3、springMVC-bean加载控制

  • springMVC相关bean(表现层bean)
  • spring控制bean
    • 业务层
    • 功能bean(service)
    • 功能bean(DataSource)

包结构:

image-20230413142342564

​ 问题:因为功能不同我们怎么去避免spring错误加载到springMVC的bean?

​ 解决方法:加载spring控制的bean的时候排除掉springMVC控制的bean

  • springMVC相关bean加载控制
    • springMVC加载的bean对应在com.anle.controller包内
  • spring相关bean加载控制
    • 方式一:spring加载bean设定扫描范围为com.anle ,排除controller包类的bean
    • 方式二:spring加载bean设置扫描范围精准范围,类如:service包 dao包等
    • 方式三:不区分spring和springMVC的环境,加载到同一环境中

3.1、使用的相关注解

  • 名称:@ComponentScan

  • 类型:类注解

  • 范例:

    @ComponentScan(value = "com.anle",
            excludeFilters = @ComponentScan.Filter(
                    type = FilterType.ANNOTATION,
                    classes = Controller.class
            )
    )
    
  • 属性:

    • excludeFilters:排除扫描路径中加载的bean,需要指定类别(type)与具体项(classes)
    • includeFiltres:加载指定的bean,需要指定类别(type)与具体项(classes)

3.2bean的完整加载格式

/**
 * @author: anle
 * @date: 2023/04/12 11:18
 **/
//4、定义一个servlet容器的配置类,在里面加载spring的配置
public class ServletConfig extends AbstractDispatcherServletInitializer {

    //加载springMvc容器配置
    @Override
    protected WebApplicationContext createServletApplicationContext() {
        AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
        ctx.register(SpringMvcConfig.class);
        return ctx;
    }

    //设置那些请求归属sprigMVC处理
    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }

    //加载spring配置
    @Override
    protected WebApplicationContext createRootApplicationContext() {
        AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
        ctx.register(SpringConfig.class);
        return ctx;
    }
}
  • 简化开发的格式:

    public class ServletConfig2 extends AbstractAnnotationConfigDispatcherServletInitializer  {
    
    
        @Override
        protected Class<?>[] getRootConfigClasses() {
            return new Class[]{SpringConfig.class};
        }
    
        @Override
        protected Class<?>[] getServletConfigClasses() {
            return new Class[]{SpringMvcConfig.class};
        }
    
        @Override
        protected String[] getServletMappings() {
            return new String[]{"/"};
        }
    }
    

4、Apipost工具介绍

4.1、Apipost简介

  • 官网:Apipost-API

  • Apipost = Postman + Swagger + Mock + Jmeter

    后端、前端、测试,同时在线协作,内容实时同步

  • 作用:常用于进行接口测试

  • 特征:

    • 简单
    • 实用
    • 美观

4.2、Apipsot使用教程

image-20230424111234847

image-20230424111436586

5、设置请求路径

  • 团队多人开发,每个人设置不同的请求路径,冲突问题如何解决?
    • 设置模块名作为请求路径前缀
/**
 * @author: anle
 * @date: 2023/04/18 08:37
 **/
@Controller
@RequestMapping("/user")
public class UserController {

    @RequestMapping("/sho")
    @ResponseBody
    public String sho() {
        System.out.println("user...sho");
        return "{'module':'user sho}";
    }

    @RequestMapping("/delete")
    @ResponseBody
    public String delete() {
        System.out.println("user...delete");
        return "{'module':'user delete}";
    }


}

5.1、请求映射路径

  • 名称:@RequestMapping

  • 类型:方法注解 类注解

  • 位置:springMVC控制器方法定义上方

  • 作用:设置当前控制器方法请求访问路径,如果设置在类上统一设置当前控制器方法请求访问当前前缀

  • 范例:

    @Controller
    @RequestMapping("/user")
    public class UserController {
    
        @RequestMapping("/sho")
        @ResponseBody
        public String sho() {
            System.out.println("user...sho");
            return "{'module':'user sho}";
        }
    
  • 属性

    • value(默认):请求访问路径,或者访问路径前缀。

6、get请求与post请求发送普通参数

6.1、Get请求参数

  • 普通参数:url地址参数,地址参数与形参变量相同,定义形参即可接收参数

    image-20230421114419717
/**
 * @author: anle
 * @date: 2023/04/21 10:57
 *
 **/

@Controller
public class UserController {
    //普通参数的传递
    @RequestMapping("/common")
    @ResponseBody
    public String common(String name , String age){
        System.out.println("普通的参数传递--->"+name);
        System.out.println("普通的参数传递--->"+age);
        return "{module: 'common'}";
    }
}

6.2、Post请求

  • 提交post请求的时候,在表单直接提交即可

image-20230421115114929

/**

 * @author: anle
 * @date: 2023/04/21 10:57
   *
    **/

@Controller
public class UserController {
    //普通参数的传递
    @RequestMapping("/common")
    @ResponseBody
    public String common(String name , String age){
        System.out.println("普通的参数传递--->"+name);
        System.out.println("普通的参数传递--->"+age);
        return "{module: 'common'}";
    }
}
  • 注意:在我们传递的参数是中文时可能会出现中文乱码的

6.3、解决中文乱码的方法:

  • get请求中文乱码

    • 在自己下载的tomcat文件夹里面的conf文件中的server.xml文件里将原配置:

      <Connector port="8080" protocol="HTTP/1.1"
                     connectionTimeout="20000"
                     redirectPort="8443"/>
      
    • 修改为:

      <Connector port="8080" protocol="HTTP/1.1"
                     connectionTimeout="20000"
                     redirectPort="8443" URIEncoding="utf-8"/>
      
  • post请求乱码

    • 方法一:为web容器增加过滤器并指定字符集,spring-web包中提供了专用的字符集过滤

      //解决乱码问题
      @Override
      protected Filter[] getServletFilters() {
          CharacterEncodingFilter filter = new CharacterEncodingFilter();
          filter.setEncoding("UTF-8");
          return new Filter[]{filter};
      }
      
    • 方法二:

    • spring MVC中默认的编码格式为“ISO-8859-1”,因此造成乱码。

      解决:
      在web.xml中配置Spring字符过滤器

      <!--配置解决中文乱码的过滤器-->
          <filter>
              <filter-name>characterEncodingFilter</filter-name>
              <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
              <!--配置过滤器初始化参数-->
              <init-param>
                  <param-name>encoding</param-name>
                  <param-value>UTF-8</param-value>
              </init-param>
              <init-param>
                  <param-name>forceEncoding</param-name>
                  <param-value>true</param-value>
              </init-param>
          </filter>
          <filter-mapping>
              <filter-name>characterEncodingFilter</filter-name>
              <url-pattern>/*</url-pattern>
          </filter-mapping>
      

7、5中不同参数请求

7.1、普通参数

  • 普通参数:ur地址传参,地址参数与形参变量名相同,定义形参即可接收参数

    image-20230421133910961

//普通参数,请求参数与形参不同
@RequestMapping("/ordinary")
@ResponseBody
public String commonParam(@RequestParam("name") String username , String age){
    System.out.println("普通的参数传递--->"+username);
    System.out.println("普通的参数传递--->"+age);
    return "{module: 'common Param'}";
}

7.2、请求参数

  • 名称:@RequestParam

  • 类型:形参注解

  • 位置:springMVC控制器方法形参定义前面

  • 作用:绑定请求参数与处理器方法形参间的关系

  • //普通参数,请求参数与形参不同
    @RequestMapping("/ordinary")
    @ResponseBody
    public String commonParam(@RequestParam("name") String username , String age){
        System.out.println("普通的参数传递--->"+username);
        System.out.println("普通的参数传递--->"+age);
        return "{module: 'common Param'}";
    }
    

7.3、pojo参数

  • 请求参数名与形参对象属性名相同,定义pojo类型形参即可接收参数

    image-20230421134611731

//pojo参数
    @RequestMapping("/pojo")
    @ResponseBody
    public String pojo(User user){
        System.out.println("pojo参数传递--->"+user);
        return "{module: 'pojo'}";
    }

7.4、pojo嵌套参数

  • 请求参数名与形参对象属性名相同,按照对象层次结构关系即可接收嵌套pojo属性参数
image-20230421134855302
//pojo参数嵌套使用
@RequestMapping("/pojop")
@ResponseBody
public String pojo2(User user){
    System.out.println("pojo参数传递--->"+user);
    return "{module: 'pojo2'}";
}

7.5、数组参数

  • 请求参数名与形参对象属性名相同且请求参数为多个,定义数组类型形参即可接收参数

    image-20230421135123616

//数组参数
@RequestMapping("/array")
@ResponseBody
public String array(String[] likes){
    System.out.println("数组参数传递--->"+ Arrays.toString(likes));
    return "{module: 'array'}";
}

7.6、集合参数

  • 集合保存普通参数:请求参数名与形参集合对象名相同且请求参数为多个,@RequestParam绑定关系

image-20230421135422496

//集合参数
@RequestMapping("/list")
@ResponseBody
public String list(@RequestParam List<String> likes){
    System.out.println("集合参数传递--->"+ likes);
    return "{module: 'list'}";
}

8、json数据传递参数

  • 增加json数据转换相应的坐标

    <dependency>
        <groupId>mvn_resp.com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.12.3</version>
    </dependency>
    
  • 增加json数据发送请求

    image-20230424110625587

  • 开启自动转化json数据的支持

    @Configuration
    @ComponentScan("com.anle.controller")
    @EnableWebMvc
    public class SpringMvcConfig {
    }
    

    注意:@EnableWebMvc功能强大,该注解整合了多个功能,此处仅用其中的一部分共功能,即json数据进行自动类型转换

  • 设置接收json数据

    @RequestMapping("/listJson")
    @ResponseBody
    public String listJson(@RequestBody List<String> likes){
        System.out.println("集合参数传递--->"+ likes);
        return "{module: 'listJson'}";
    }
    

9、日期型参数传递

  • 日期类型数据基于系统不同格式也不尽相同

    • 2023-01-01
    • 2023/01/01
    • 01/01/2023
  • 接收参数时,根据不同的日期格式设置不同的接收方式

    //日期参数
    @RequestMapping("/date")
    @ResponseBody
    public String date(Date date,
                       @DateTimeFormat(pattern = "yyy-mm-dd") Date date1,
                       @DateTimeFormat(pattern = "yyy/mm/dd hh:mm:ss") Date date2){
        System.out.println("日期参数传递date--->"+date);
        System.out.println("日期参数传递date1  yyy-mm-dd--->"+date1);
        System.out.println("日期参数传递date2  yyy/mm/dd hh:mm:ss--->"+date2);
        return "{module: 'date'}";
    }
    

    访问参数:http://localhost:8080/req/date?date=2023/01/01&date1=2023-01-01&date2=2023/08/01 8:08:08

  • @DateTimeFormat注解

  • 类型:形参注解

    • 位置:springMVC控制器方法形参前面
    • 作用:设定日期时间型数据格式
    • 属性:pattern:日期时间格式字符串
  • 类型转换器

    • Convertor接口
      • 请求年龄数据(String->Integer)
      • 日期格式转换(String—>Date)
  • @EnablWedMvc功能之一:根据类型匹配对应的类型转换器

10、响应

10.1、响应页面

//响应页面/跳转页面
@RequestMapping("/a")
public String toJumPage() {
    System.out.println("跳转页面");
    return "hello.jsp";
}
  • 注意这里看可能出现404报错可能时tomcat导包的问题,我们可以进入项目结构中进行查看。

    image-20230424221936191

10.2、响应文本数据

//响应文本
@RequestMapping("/b")
@ResponseBody
public String toTextPage() {
    System.out.println("响应文本");
    return "hello text";
}

10.3、响应json数据

//响应pojo集合对象
@RequestMapping("/d")
@ResponseBody
public List<User> toPojoArrayPage() {
    System.out.println("返回json数据集合对象");
    User user1 = new User();
    user1.setName("张三");
    user1.setAge(18);

    User user2 = new User();
    user2.setName("李四");
    user2.setAge(19);

    List<User> userList = new ArrayList<>();
    userList.add(user1);
    userList.add(user2);

    return userList;
}

@ResponseBody注解

  • 类型:方法注解

  • 位置:springMVC控制器方法定义上方

  • 作用:设置当前控制器返回值作为响应体

  • HttpMessageConverter接口:主要就是这个接口进行数据的转换,前面的转换的接口都是它的子类。

11、REST风格

11.1、简介:

  • REST(Representational String Transfer),表现形式状态转换
    • 传统风格资源描述形式
      • http://localhost/user/getById?id=1
      • http://localhost/user/saveUser
    • REST风格描述形式
      • http://localhost/user/1
      • http://localhost/user
  • 优点:
    • 隐藏资源的访问行为,无法通过地址得到资源是何种操作
    • 书写简化
  • 按照REST风格访问资源时使用行为动作区分对资源进行了何种操作
    • 查询全部用户信息 GET (查询)
    • 查询指定用户信息 GET (查询)
    • 增加用户信息 POST (新增/保存)
    • 修改用户信息 PUT(修改/更新)
    • 删除用户信息 DELETE (删除)
  • 根据REST风格对资源进行访问称为RESTful

注意:–上述行为是约定方式,约定不是规范,可以打破的,所以称为REST风格

11.2、REST入门案列

  • 设定http请求动作(动词)

    @RequestMapping(value = "/users",method = RequestMethod.PUT)
    @ResponseBody
    public String update(@RequestBody User user) {
        System.out.println("user update..."+user);
        return "{'module':'user update'}";
    }
    
  • 设置请求参数

    @RequestMapping(value = "/users/{id}",method = RequestMethod.DELETE)
    @ResponseBody
    public String delete(@PathVariable Integer id) {
        System.out.println("user delete..."+id);
        return "{'module':'user delete'}";
    }
    
    
  • @RequestMapping注解

    • 类型:方法注解
    • 位置:springMVC控制器方法定义上方
    • 作用:设置当前控制器方法请求访问路径
    • 属性:
      • value(默认):请求访问路径
      • method:http请求动作,标准动作(GET/POST/DELETR/PUT)
  • @PathVariable

    • 类型:形参注解
    • 位置:springMVC形参定义前面
    • 作用:绑定路劲参数与处理器方法形参间的关系,要求路径参数名与形参名一一对应

@RequestBody @RequestParam @PathVariable

  • 区别
    • @RequestBody用于接收json数据
    • @RequestParam用于接收url地址传参或者表单传参
    • @PathVariable用于接收路径参数,使用(参数名称)描述路径参数
  • 应用
    • 后期开发中,发送请求参数超过1个小时,以json格式,@RequestBody应用比较广泛
    • 如果发送非json数据,选用 @RequestParam接收请求参数
    • 采用RESTful进行开发时,当参数数量比较少时,列如1个,可以采用 @PathVariable接收请求路劲变量,通常用于传递id值

11.3、REST快速注解开发

  • @RestController

    • 类型:类注解
    • 位置:基于springMVC的RESTful开发控制器类定义上方
    • 作用:设置当前控制器为RESTful风格,等同于@Controller与@ResponseBody两个注解组合功能
    @RestController
    public class BookController {
    }
    
  • @GetMapping @PostMapping @DeleteMapping @PutMapping

    • 类型:方法注解

    • 位置:基于springMvc的RESTful开发控制器方法定义上方

    • 作用:设置当前控制器方法请求访问路径与请求动作,每种对应一个动作。

    • 属性:value(默认):请求访问路径

      实列:

      /**
       * @author: anle
       * @date: 2023/04/26 09:36
       **/
      @RestController
      @RequestMapping("/books")
      public class BookController {
      
          @PostMapping
          public String save(@RequestBody Book book) {
              System.out.println("book...save"+book);
              return "{'module': 'save'}";
          }
      
          @DeleteMapping("/{id}")
          public String delete(@PathVariable Integer id) {
              System.out.println("book..delete"+id);
              return "{'module': 'delete'}";
          }
      
          @PutMapping
          public String update(@RequestBody Book book){
              System.out.println("update..book"+book);
              return "{'module': 'update'}";
          }
      
          @GetMapping("/{id}")
          public String getById(@PathVariable Integer id){
              System.out.println("book getById"+id);
              return "{'module': 'getById'}";
          }
      
          @GetMapping()
          public String getAll() {
              System.out.println("book getAll");
              return "{'module': 'getAll'}";
          }
      
          }
      

12、springmvc-SSM整合

12.1、ssm-整合(整体配置)

  • 首先我们先创建一个maven模块

  • 在pom.xml中导入对应的依赖

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <groupId>com.anle</groupId>
            <artifactId>spring-mvc</artifactId>
            <version>1.0-SNAPSHOT</version>
        </parent>
    
        <artifactId>springmvc-09-ssm-demo</artifactId>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-webmvc</artifactId>
                <version>5.2.10.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-jdbc</artifactId>
                <version>5.2.10.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-test</artifactId>
                <version>5.2.10.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis</artifactId>
                <version>3.5.6</version>
            </dependency>
            <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis-spring</artifactId>
                <version>1.3.0</version>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.47</version>
            </dependency>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>1.1.16</version>
            </dependency>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.12</version>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>javax.servlet-api</artifactId>
                <version>3.1.0</version>
                <scope>provided</scope>
            </dependency>
            <dependency>
                <groupId>com.fasterxml.jackson.core</groupId>
                <artifactId>jackson-databind</artifactId>
                <version>2.9.0</version>
            </dependency>
        </dependencies>
    
        <properties>
            <maven.compiler.source>8</maven.compiler.source>
            <maven.compiler.target>8</maven.compiler.target>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        </properties>
    
    </project>
    
  • 在创建出对应的包结构

    image-20230509135847460

  • 在config包中增加配置

    springConfig

    /**
     * @author: anle
     * @date: 2023/05/01 10:42
     **/
    @Configuration
    @ComponentScan({"com.anle.service"})
    @PropertySource("classpath:jdbc.properties")
    @Import({JdbcConfig.class, MyBatisConfig.class})
    public class SpringConfig {
    }
    

    我们在这个项目里面需要用到数据库所有要配置我们的数据库

    JdbcConfig

    /**
     * @author: anle
     * @date: 2023/05/01 10:44
     **/
    public class JdbcConfig {
    
        public class jdbcConfig {
            //1、定义一个方法获得要管理的对象
            //2、@Bean、表示当前方法的返回值是一个bean
            @Value("${jdbc.driver}")
            private String driver;
            @Value("${jdbc.url}")
            private String url;
            @Value("${jdbc.username}")
            private String username;
            @Value("${jdbc.password}")
            private String password;
    
    
            @Bean
            public DataSource dataSource() {
                DruidDataSource dataSource = new DruidDataSource();
                dataSource.setDriverClassName(driver);
                dataSource.setUrl(url);
                dataSource.setUsername(username);
                dataSource.setPassword(password);
                return dataSource;
            }
    
        }
    }
    

    MybatisConfig

    public class MyBatisConfig {
    
        @Bean
        public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource){
            SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
            factoryBean.setDataSource(dataSource);
            factoryBean.setTypeAliasesPackage("com.anle.pojo");
            return factoryBean;
        }
    
        @Bean
        public MapperScannerConfigurer mapperScannerConfigurer(){
            MapperScannerConfigurer msc = new MapperScannerConfigurer();
            msc.setBasePackage("com.anle.dao");
            return msc;
        }
    
    }
    

    ServletConfig

    /**
     * @author: anle
     * @date: 2023/05/01 10:54
     **/
    public class ServletConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
        @Override
        protected Class<?>[] getRootConfigClasses() {
            return new Class[]{SpringConfig.class};
        }
    
        @Override
        protected Class<?>[] getServletConfigClasses() {
            return new Class[]{SpringMvcConfig.class};
        }
    
        @Override
        protected String[] getServletMappings() {
            return new String[]{"/"};
        }
    }
    

    SpringMvcConfig

    /**
     * @author: anle
     * @date: 2023/05/01 10:55
     **/
    @Configuration
    @ComponentScan("com.anle.controller")
    @EnableWebMvc
    public class SpringMvcConfig {
    }
    
  • 创建pojo实体类,更具数据库字段创建

    /**
     * @author: anle
     * @date: 2023/05/01 11:19
     **/
    public class Book {
        private Integer id; //图书id
        private String type; //图书类型
        private String name; //图书名字
        private String description; //图书描述
    
    
        public Book() {
        }
    
        public Book(Integer id, String type, String name, String description) {
            this.id = id;
            this.type = type;
            this.name = name;
            this.description = description;
        }
    
        /**
         * 获取
         * @return id
         */
        public Integer getId() {
            return id;
        }
    
        /**
         * 设置
         * @param id
         */
        public void setId(Integer id) {
            this.id = id;
        }
    
        /**
         * 获取
         * @return type
         */
        public String getType() {
            return type;
        }
    
        /**
         * 设置
         * @param type
         */
        public void setType(String type) {
            this.type = type;
        }
    
        /**
         * 获取
         * @return name
         */
        public String getName() {
            return name;
        }
    
        /**
         * 设置
         * @param name
         */
        public void setName(String name) {
            this.name = name;
        }
    
        /**
         * 获取
         * @return description
         */
        public String getDescription() {
            return description;
        }
    
        /**
         * 设置
         * @param description
         */
        public void setDescription(String description) {
            this.description = description;
        }
    
        public String toString() {
            return "Book{id = " + id + ", type = " + type + ", name = " + name + ", description = " + description + "}";
        }
    }
    
  • 创建dao层接口

    /**
     * @author: anle
     * @date: 2023/05/01 11:21
     **/
    public interface BookDao {
        /**
         * @return 增加图书
         * @param book
         */
        @Insert("insert into tb_book(type,name,description) values(#{type},#{name}),#{description}")
        public void save(Book book);
        /**
         * @return 修改图书
         * @param book
         */
        @Update("update tb_book set type = #{type}, name = #{name} ,description = #{description} where id = #{id}")
        public void update(Book book);
        /**
         * @return 根据id删除
         * @param id
         */
        @Delete("delete from tb_book where id = #{id}")
        public void delete(Integer  id);
        /**
         * @return 根据id查询
         * @param id
         */
        @Select("select id from tb_book where id = #{id}")
        public Book getBookById(Integer id);
        /**
         * @return 查询所有
         * @param
         */
        @Select("select id from tb_book ")
        public List<Book> getAll();
    
    }
    
    
    • 创建service层接口和实现类
    /**
     * @author: anle
     * @date: 2023/05/01 11:22
     **/
    public interface BookService {
        /**
         * @return 增加图书
         * @param book
         */
        public boolean save(Book book);
        /**
         * @return 修改图书
         * @param book
         */
        public boolean update(Book book);
        /**
         * @return 根据id删除
         * @param id
         */
        public boolean delete(Integer  id);
        /**
         * @return 根据id查询
         * @param id
         */
    
        public Book getBookById(Integer id);
        /**
         * @return 查询所有
         * @param
         */
        public List<Book> getAll();
    }
    

    实现类:

    /**
     * @author: anle
     * @date: 2023/05/01 11:22
     **/
    @Service
    public class BookServiceImpl implements BookService {
        @Autowired
        private BookDao bookDao;
    
        @Override
        public boolean save(Book book) {
            bookDao.save(book);
            return true;
        }
    
        @Override
        public boolean update(Book book) {
            bookDao.update(book);
            return true;
        }
    
        @Override
        public boolean delete(Integer id) {
            bookDao.delete(id);
            return true;
        }
    
        @Override
        public Book getBookById(Integer id) {
            return bookDao.getBookById(id);
        }
    
        @Override
        public List<Book> getAll() {
            return bookDao.getAll();
        }
    }
    
  • controller层

/**
 * @author: anle
 * @date: 2023/05/01 11:23
 **/
@RestController
@RequestMapping("books")
public class BookController {
    @Autowired
    private BookService bookService;

    @PostMapping
    public boolean save(@RequestBody Book book) {
        return bookService.save(book);
    }
    @PutMapping
    public boolean update(@RequestBody  Book book) {
        return bookService.update(book);
    }

    @DeleteMapping("/{id}")
    public boolean delete(@PathVariable Integer id) {

        return bookService.delete(id);
    }

    @GetMapping("/{id}")
    public Book getBookById(@PathVariable Integer id) {
        return bookService.getBookById(id);
    }

    @GetMapping
    public List<Book> getAll() {
        return bookService.getAll();
    }
}

12.2、ssm-整合(接口测试)

  • 在test目录下创建一个测试类

    /**
     * @author: anle
     * @date: 2023/05/07 16:36
     **/
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes = SpringConfig.class)
    public class BookServiceTest {
    
        @Autowired
        private BookService bookService;
    
        @Test
        public void testGetById(){
            Book book = bookService.getBookById(1);
            System.out.println(book);
    
        }
    
        @Test
        public void testGetAll(){
            List<Book> all = bookService.getAll();
            System.out.println(all);
        }
    
    
    
    
    }
    

12.3、ssm-整合(表现层与前端页面数据传输)

  • 前端接收数据格式—创建结果模型类,封装数据到data属性中

  • 前端接收数据格式—封装操作结果得到的code属性中

  • 前端接收数据格式—封装特殊消息到message(msg)属性中

  • 设置统一数据返回结果类

    public class Result {
        private Object data;
        private Integer code;
        private String msg;
        }
    
  • 注意==== Result类中的字段并不是固定的,可以根据需要自行增减提供若干个构造方法,方便操作。

  • 表现层与前端进行实现

    • 在controller包下创建一个Result类

      /**
       * @author: anle
       * @date: 2023/05/08 16:26
       **/
      public class Result {
          private Object data;
          private Integer code;
          private String msg;
      
      
          public Result() {
          }
      
          public Result(Integer code,Object data) {
              this.data = data;
              this.code = code;
          }
      
          public Result( Integer code,Object data, String msg) {
              this.data = data;
              this.code = code;
              this.msg = msg;
          }
      
          /**
           * 获取
           * @return data
           */
          public Object getData() {
              return data;
          }
      
          /**
           * 设置
           * @param data
           */
          public void setData(Object data) {
              this.data = data;
          }
      
          /**
           * 获取
           * @return code
           */
          public Integer getCode() {
              return code;
          }
      
          /**
           * 设置
           * @param code
           */
          public void setCode(Integer code) {
              this.code = code;
          }
      
          /**
           * 获取
           * @return msg
           */
          public String getMsg() {
              return msg;
          }
      
          /**
           * 设置
           * @param msg
           */
          public void setMsg(String msg) {
              this.msg = msg;
          }
      
          public String toString() {
              return "Result{data = " + data + ", code = " + code + ", msg = " + msg + "}";
          }
      }
      
    • 还需要创建一个Code状态码类,后面为1表示为成功,为0表示失败

      /**
       * @author: anle
       * @date: 2023/05/08 16:29
       **/
      public class Code {
          public static final Integer SAVE_OK =2011; //增加成功
          public static final Integer DELETE_OK =2021;//删除成功
          public static final Integer UPDATE_OK =2031;//修改成功
          public static final Integer GET_OK =2041;//查询成功
      
          public static final Integer SAVE_ERR =2010; //增加成功
          public static final Integer DELETE_ERR =2020;//删除成功
          public static final Integer UPDATE_ERR =2030;//修改成功
          public static final Integer GET_ERR =2040;//查询成功
      }
      
    • 重新书写我们的controller层的BookController

      /**
       * @author: anle
       * @date: 2023/05/01 11:23
       **/
      @RestController
      @RequestMapping("books")
      public class BookController {
          @Autowired
          private BookService bookService;
      
          @PostMapping
          public Result save(@RequestBody Book book) {
              boolean flag = bookService.save(book);
              return new Result(flag ? Code.SAVE_OK:Code.SAVE_ERR,flag);
          }
          @PutMapping
          public Result update(@RequestBody  Book book) {
              boolean flag = bookService.update(book);
              return new Result(flag ? Code.UPDATE_OK:Code.UPDATE_ERR,flag);
          }
      
          @DeleteMapping("/{id}")
          public Result delete(@PathVariable Integer id) {
      
              boolean flag = bookService.delete(id);
              return new Result(flag ? Code.DELETE_OK:Code.DELETE_ERR,flag);
          }
      
          @GetMapping("/{id}")
          public Result getBookById(@PathVariable Integer id) {
              Book book = bookService.getBookById(id);
              Integer code = book != null ? Code.GET_OK : Code.GET_ERR;
              String msg = book != null ? "查询成功" : "查询失败,请重新查询";
      
              return new Result(code,book,msg);
          }
      
          @GetMapping
          public Result getAll() {
              List<Book> bookList = bookService.getAll();
              Integer code = bookList != null ? Code.GET_OK : Code.GET_ERR;
              String msg = bookList != null ? "查询成功" : "查询失败,请重新查询";
              return new Result(code,bookList,msg);
          }
      }
      

      我们的返回值有所改变,这样前端就可以根据不同的请求得到对应的数据

12.4、smm-整合(异常处理)

  • 出现异常现象得常见位置与常见原因如下:
    • 框架内部抛异常:因使用不合格导致
    • 数据层抛异常:因外部服务器故障导致(列如:服务器超时)
    • 业务层抛出异常:因业务逻辑书写错误导致(列如:不匹配的数据类型间导致异常)
    • 工具类抛出的异常:因为工具类书写不严谨不够导致(”必须释放连接长期未释放等“)

思考:==各个阶层均出现异常,异常处理代码书写在哪一层

​ —所有的异常抛出到表现层进行处理

  • 异常处理器
    • 集中的、统一的处理项目中出现的异常
/**
 * @author: anle
 * @date: 2023/05/09 09:45
 **/
@RestControllerAdvice
public class ProjectExceptionAdvice {
    @ExceptionHandler(Exception.class)
    public Result doException(){
        System.out.println("异常抓到你了");
        return new Result(666,null,"异常抓到你了");
    }
}
  • 名称: @ExceptionHandler
  • 类型:方法注解
  • 位置:专用于异常处理的控制器方法上方
  • 作用:设置指定异常的处理方案,功能等同于控制器方法,出现异常后终止原始控制器执行,并转让当前执行
  • 说明:
    • 此类方法可以根据处理异常不同,制作多个方法分别处理对应的异常。

12.5、smm-整合(项目中的异常处理)

==项目异常分类:

  • 业务异常(BusinessException)
    • 规范的用户行为产生的异常
    • 不规范的用户行为操作产生的异常
  • 系统异常(SystemException)
    • 项目运行过程中可预计且无法避免的异常
  • 其他异常(Exception)
    • 编程人员未预测到的异常

==项目异常处理方法:

  • 业务异常(BusinessException)
    • 发送对应消息传递给用户,提醒规范操作
  • 系统异常(SystemException)
    • 发送固定请求消息传递给用户,安抚用户
    • 发送特定消息给运维人员,提醒维护
    • 记录日志
  • 其他异常(Exception)
    • 发送固定请求消息传递给用户,安抚用户
    • 发送固定消息给编程人员,提醒维护(纳入预期范围内)
    • 记录日志

=====操作:

  • 自定义项目系统异常
/**
 * @author: anle
 * @date: 2023/05/10 14:47
 **/
public class BusinessException extends RuntimeException{

    private Integer code;

    public Integer getCode() {
        return code;
    }

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

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

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

}
  • 自定义项目业务异常

    /**
     * @author: anle
     * @date: 2023/05/10 14:47
     **/
    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;
        }
    
    }
    
  • 自定义异常编码

  • 触发自定义异常

  • 拦截并处理异常

13、拦截器

13.1、拦截器概念:

  • 拦截器是一种动态拦截方法调用的机制,在SpringMVC中动态拦截器控制方法的执行
  • 作用:
    • 在指定的方法调用前后执行预先设定的代码
    • 阻止原始方法执行

13.2、拦截器与过滤器的区别

  • 归属不同: Filter属于servlet技术,Intrcptor属于SpringMVC 技术、
  • 拦截内容不同:Filter对所有访问进行增强,Intrcptor仅针对SpringMVC的访问进行增强

13.3、拦截器入门

  • 声明拦截器的bean,并实现HandInterceptor接口(注意扫描bean,建议写在Conrtoller包下)

    /**
     * @author: anle
     * @date: 2023/05/16 20:59
     **/
    @Component
    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");
        }
    }
    
  • 定义配置类,继承WebMvcConfigurationSupport,实现addInterceptor方法,增加拦截器并设定拦截器的访问路径,路劲可以通过可变传输设置多个(注意:扫描加载配置)

    /**
     * @author: anle
     * @date: 2023/05/16 21:04
     **/
    @Configuration
    public class SpringMvcSupport extends WebMvcConfigurationSupport {
        @Autowired
        private ProjectInterceptor projectInterceptor;
    
        @Override
        protected void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(projectInterceptor).addPathPatterns("/books/*","/books");
        }
    }
    

13.4、拦截器的参数

  • 前置处理

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String type = request.getHeader("type");
        
        System.out.println("preHandle...."+ type);
        return true;
    }
    
  • 参数

    • request:请求对象
    • response:响应对象
    • handler:被调用的处理器对象,本质上是一个方法对象,对反射技术中的Method对象进行了再包装
  • 返回值:

    • 返回值为false,被了解处理器将不在执行
  • 后置对象

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle");
    }
    
  • 参数

    • modelAndView:如果处理器执行完成具有返回结果,可以读取对应数据与页面的信息,并进行调整
  • 完成后处理:

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion");
    }
    
  • 参数

    • ex :如果处理器执行过程中出现异常对象,可以针对异常情况进行单独处理

13.5、拦截器链配置

  • 当配置多个拦截器时,形成拦截器链

  • 拦截器链的运行顺序参照拦截器增加顺序为准

  • 当拦截器中出对原始处理器拦截均终止运行

  • 当拦截器运行中断,仅运行配置在前面的拦截器afterCompletion操作

    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion");
    }
    

    }

    
    
  • 定义配置类,继承WebMvcConfigurationSupport,实现addInterceptor方法,增加拦截器并设定拦截器的访问路径,路劲可以通过可变传输设置多个(注意:扫描加载配置)

    /**
     * @author: anle
     * @date: 2023/05/16 21:04
     **/
    @Configuration
    public class SpringMvcSupport extends WebMvcConfigurationSupport {
        @Autowired
        private ProjectInterceptor projectInterceptor;
    
        @Override
        protected void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(projectInterceptor).addPathPatterns("/books/*","/books");
        }
    }
    

13.4、拦截器的参数

  • 前置处理

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String type = request.getHeader("type");
        
        System.out.println("preHandle...."+ type);
        return true;
    }
    
  • 参数

    • request:请求对象
    • response:响应对象
    • handler:被调用的处理器对象,本质上是一个方法对象,对反射技术中的Method对象进行了再包装
  • 返回值:

    • 返回值为false,被了解处理器将不在执行
  • 后置对象

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle");
    }
    
  • 参数

    • modelAndView:如果处理器执行完成具有返回结果,可以读取对应数据与页面的信息,并进行调整
  • 完成后处理:

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion");
    }
    
  • 参数

    • ex :如果处理器执行过程中出现异常对象,可以针对异常情况进行单独处理

13.5、拦截器链配置

  • 当配置多个拦截器时,形成拦截器链
  • 拦截器链的运行顺序参照拦截器增加顺序为准
  • 当拦截器中出对原始处理器拦截均终止运行
  • 当拦截器运行中断,仅运行配置在前面的拦截器afterCompletion操作
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值