04 SpringMVC
lix_uan 31 0

SpringMVC入门案例

  • 创建Web工程,导入依赖

    <dependencies>
        <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.3.16</version>
        </dependency>
    </dependencies>
  • 定义处理请求功能的类(UserController)

    //定义表现层控制器bean
    @Controller
    public class UserController {
        //设置映射路径为/save,即外部访问路径
        @RequestMapping("/save")
        //设置当前操作返回结果为指定json数据(本质上是一个字符串信息)
        @ResponseBody
        public String save(){
            System.out.println("user save ...");
            return "{'info':'springmvc'}";
        }
    }
  • 编写SpringMVC配置类,加载处理请求的Bean

    //springmvc配置类,本质上还是一个spring配置类
    @Configuration
    @ComponentScan("cn.lixuan.controller")
    public class SpringMvcConfig {
    }
  • 加载SpringMVC配置,并设置SpringMVC请求拦截的路径

    //web容器配置类
    public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer {
        //加载springmvc配置类,产生springmvc容器(本质还是spring容器)
        protected WebApplicationContext createServletApplicationContext() {
            //初始化WebApplicationContext对象
            AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
            //加载指定配置类
            ctx.register(SpringMvcConfig.class);
            return ctx;
        }
    
        //设置由springmvc控制器处理的请求映射路径
        protected String[] getServletMappings() {
            return new String[]{"/"};
        }
    
        //加载非SpringMVC对应的bean
        protected WebApplicationContext createRootApplicationContext() {
            return null;
        }
    }
  • // 简化格式
    
    public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer{
        protected Class<?>[] getServletConfigClasses() {
            return new Class[]{SpringMvcConfig.class}
        };
        protected String[] getServletMappings() {
            return new String[]{"/"};
        }
        protected Class<?>[] getRootConfigClasses() {
            return new Class[]{SpringConfig.class};
        }
    }

Controller加载控制

@Configuration
@ComponentScan(value = "cn.lixuan",
               excludeFilters = @ComponentScan.Filter(
                   type = FilterType.ANNOTATION,
                   classes = Controller.class
               )
              )
public class SpringConfig {
}

请求与响应

  • @RequestMapping

    @Controller
    //类上方配置的请求映射与方法上面配置的请求映射连接在一起,形成完整的请求映射路径
    @RequestMapping("/user")
    public class UserController {
        //请求路径映射
        @RequestMapping("/save") //此时save方法的访问路径是:/user/save
        @ResponseBody
        public String save(){
            System.out.println("user save ...");
            return "{'module':'user save'}";
        }
    }
  • GET请求传递普通参数

    //普通参数:请求参数与形参名称对应即可完成参数传递
    //http://localhost:8080/commonParam?name=lixuan&age=18
    @RequestMapping("/commonParam")
    @ResponseBody
    public String commonParam(String name ,int age){
        System.out.println("普通参数传递 name ==> "+name);
        System.out.println("普通参数传递 age ==> "+age);
        return "{'module':'common param'}";
    }
  • 解决GET请求中文乱码问题

    <build>
        <plugins>
          <plugin>
            <groupId>org.apache.tomcat.maven</groupId>
            <artifactId>tomcat7-maven-plugin</artifactId>
            <version>2.1</version>
            <configuration>
              <port>80</port><!--tomcat端口号-->
              <path>/</path> <!--虚拟目录-->
              <uriEncoding>UTF-8</uriEncoding><!--访问路径编解码字符集-->
            </configuration>
          </plugin>
        </plugins>
      </build>
  • POST请求传递普通参数(同Get)

  • POST请求中文乱码处理

    // 在加载SpringMVC配置的配置类中指定字符过滤器。
    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};
        }
    }

五种类型参数传递

  • 普通参数

    //普通参数:请求参数名与形参名不同时,使用@RequestParam注解关联请求参数名称与形参名称之间的关系
    @RequestMapping("/commonParamDifferentName")
    @ResponseBody
    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类型参数

    @Data
    public class User {
        private String name;
        private int age;
    }
    // 请求参数key的名称要和POJO中属性的名称一致,否则无法封装
    
    @RequestMapping("/pojoParam")
    @ResponseBody
    public String pojoParam(User user){
        System.out.println("pojo参数传递 user ==> "+user);
        return "{'module':'pojo param'}";
    }
  • 嵌套POJO类型参数

    @Data
    public class User {
        private String name;
        private int age;
        private Address address;
    }
    
    @Data
    public class Address {
        private String province;
        private String city;
    }
  //嵌套POJO参数:嵌套属性按照层次结构设定名称即可完成参数传递
  //http://localhost:8080/pojoContainPojoParam?name=lixuan&age=18&address.province=hubei&address.city=wuhan
  @RequestMapping("/pojoContainPojoParam")
  @ResponseBody
  public String pojoContainPojoParam(User user){
      System.out.println("pojo嵌套pojo参数传递 user ==> "+user);
      return "{'module':'pojo contain pojo param'}";
  }
  • 数组类型参数

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

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

json数据参数传递

  • json数据参数介绍

    • json普通数组(["","","",...])
    • json对象({key:value,key:value,...})
    • json对象数组([{key:value,...},{key:value,...}])
  • 传递json普通数组

    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.9.0</version>
    </dependency>
    @Configuration
    @ComponentScan("cn.lixuan.controller")
    //开启json数据类型自动转换
    @EnableWebMvc
    public class SpringMvcConfig {
    }
    //集合参数:json格式
    //1.开启json数据格式的自动转换,在配置类中开启@EnableWebMvc
    //2.使用@RequestBody注解将外部传递的json数组数据映射到形参的集合对象中作为数据
    @RequestMapping("/listParamForJson")
    @ResponseBody
    public String listParamForJson(@RequestBody List<String> likes){
        System.out.println("list common(json)参数传递 list ==> "+likes);
        return "{'module':'list common for json param'}";
    }
  • 传递json对象

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

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

日期类型参数传递

//日期参数 http://localhost:80/dataParam?date=2088/08/08&date1=2088-08-18&date2=2088/08/28 8:08:08
//使用@DateTimeFormat注解设置日期类型数据格式,默认格式yyyy/MM/dd
@RequestMapping("/dataParam")
@ResponseBody
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'}";
}

响应json数据

//响应POJO对象
//返回值为实体类对象,设置返回值为实体类类型,即可实现返回对应对象的json数据,需要依赖@ResponseBody注解和@EnableWebMvc注解
@RequestMapping("/toJsonPOJO")
@ResponseBody
public User toJsonPOJO(){
    System.out.println("返回json对象数据");
    User user = new User();
    user.setName("xuan");
    user.setAge(15);
    return user;
}
//响应POJO集合对象
//返回值为集合对象,设置返回值为集合类型,即可实现返回对应集合的json数组数据,需要依赖@ResponseBody注解和@EnableWebMvc注解
@RequestMapping("/toJsonList")
@ResponseBody
public List<User> toJsonList(){
    System.out.println("返回json集合数据");
    User user1 = new User();
    user1.setName("数据科学");
    user1.setAge(15);

    User user2 = new User();
    user2.setName("大数据技术");
    user2.setAge(12);

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

    return userList;
}

REST风格

  • RESTful介绍

  • RESTful入门案例

    @RestController   
    @RequestMapping("/books")
    @CrossOrigin(origins = "*",maxAge = 3600)
    public class BookController {
    
        @PostMapping//使用@PostMapping简化Post请求方法对应的映射配置
        public String save(@RequestBody Book book){
            System.out.println("book save..." + book);
            return "{'module':'book save'}";
        }
    
        @DeleteMapping("/{id}")  //使用@DeleteMapping简化DELETE请求方法对应的映射配置
        public String delete(@PathVariable Integer id){
            System.out.println("book delete..." + id);
            return "{'module':'book delete'}";
        }
    
        @PutMapping   //使用@PutMapping简化Put请求方法对应的映射配置
        public String update(@RequestBody Book book){
            System.out.println("book update..."+book);
            return "{'module':'book update'}";
        }
    
        @GetMapping("/{id}")    //使用@GetMapping简化GET请求方法对应的映射配置
        public String getById(@PathVariable Integer id){
            System.out.println("book getById..."+id);
            return "{'module':'book getById'}";
        }
    
        @GetMapping      //使用@GetMapping简化GET请求方法对应的映射配置
        public String getAll(){
            System.out.println("book getAll...");
            return "{'module':'book getAll'}";
        }
    }

案例:基于RESTful页面数据交互

  • POJO实体类

    @Data
    public class Book {
        private Integer id;
        private String type;
        private String name;
        private String description;
    }
  • SpringMVC容器初始化类

    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};
        }
    }
  • SpringMVC配置类

    @Configuration
    @ComponentScan({"cn.lixuan.controller","cn.lixuan.config"})
    @EnableWebMvc
    public class SpringMvcConfig {
    }
  • 制作SpringMVC控制器,并通过PostMan测试接口功能

    @RestController
    @RequestMapping("/books")
    @CrossOrigin(origins = "*",maxAge = 3600)
    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;
        }
    }
  • 设置对静态资源的访问放行

    @Configuration
    public class SpringMvcSupport extends WebMvcConfigurationSupport {
        //设置静态资源访问过滤,当前类需要设置为配置类,并被扫描加载
        @Override
        protected void addResourceHandlers(ResourceHandlerRegistry registry) {
            //当访问/pages/????时候,从/pages目录下查找内容
            registry.addResourceHandler("/pages/**")
                .addResourceLocations("/pages/");
            registry.addResourceHandler("/js/**")
                .addResourceLocations("/js/");                
            registry.addResourceHandler("/css/**")
                .addResourceLocations("/css/");       
            registry.addResourceHandler("/plugins/**")
                .addResourceLocations("/plugins/");
        }
    }
  • 前端页面通过异步提交访问后台控制器

    //添加
    saveBook () {
        axios.post("/books",this.formData)
    },
    //主页列表查询
    getAll() {
        axios.get("/books").then((res)=>{
            this.dataList = res.data;
        });
    },

SSM整合

  • 添加依赖

    <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>

Spring整合MyBatis

  • 创建数据库和表

    -- 创建ssm_db数据库
    CREATE DATABASE IF NOT EXISTS ssm_db CHARACTER SET utf8;
    
    -- 使用ssm_db数据库
    USE ssm_db;
    
    -- 创建tbl_book表
    CREATE TABLE tbl_book(
        id INT PRIMARY KEY AUTO_INCREMENT, -- 图书编号
        TYPE VARCHAR(100), -- 图书类型
        NAME VARCHAR(100), -- 图书名称
        description VARCHAR(100) -- 图书描述
    );
    -- 添加初始化数据
    INSERT INTO tbl_book VALUES(NULL,'计算机理论','Spring实战 第5版','Spring入门经典教材,深入理解Spring原理技术内幕');
    INSERT INTO tbl_book VALUES(NULL,'计算机理论','Spring 5核心原理与30个类手写实战','十年沉淀之作,手写Spring精华思想');
    INSERT INTO tbl_book VALUES(NULL,'计算机理论','Spring 5设计模式','深入Spring源码剖析,Spring源码蕴含的10大设计模式');
    INSERT INTO tbl_book VALUES(NULL,'市场营销','直播就该这么做:主播高效沟通实战指南','李子柒、李佳琦、薇娅成长为网红的秘密都在书中');
    INSERT INTO tbl_book VALUES(NULL,'市场营销','直播销讲实战一本通','和秋叶一起学系列网络营销书籍');
    INSERT INTO tbl_book VALUES(NULL,'市场营销','直播带货:淘宝、天猫直播从新手到高手','一本教你如何玩转直播的书,10堂课轻松实现带货月入3W+');
  • jdbc.properties属性文件

    jdbc.driver=com.mysql.jdbc.Driver
    jdbc.url=jdbc:mysql://localhost:3306/ssm_db
    jdbc.username=root
    jdbc.password=root
  • JdbcConfig配置类

    public class JdbcConfig {
        @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;
        }
        //Spring事务管理需要的平台事务管理器对象
        @Bean
        public PlatformTransactionManager transactionManager(DataSource dataSource){
            DataSourceTransactionManager ds = new DataSourceTransactionManager();
            ds.setDataSource(dataSource);
            return ds;
        }
    }
  • MybatisConfig配置类

    public class MyBatisConfig {
        @Bean
        public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource){
            SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
            factoryBean.setDataSource(dataSource);
            factoryBean.setTypeAliasesPackage("cn.lixuan.domain");
            return factoryBean;
        }
    
        @Bean
        public MapperScannerConfigurer mapperScannerConfigurer(){
            MapperScannerConfigurer msc = new MapperScannerConfigurer();
            msc.setBasePackage("cn.lixuan.dao");
            return msc;
        }
    }
  • SpringConfig配置类

    @Configuration
    @ComponentScan({"cn.lixuan.service"})
    @PropertySource("classpath:jdbc.properties")
    @Import({JdbcConfig.class,MyBatisConfig.class})
    @EnableTransactionManagement //开启Spring事务管理
    public class SpringConfig {
    }

Spring整合SpringMVC

  • SpringMvcConfig配置类

    @Configuration
    @ComponentScan("cn.lixuan.controller")
    @EnableWebMvc
    public class SpringMvcConfig {
    }
  • ServletConfig配置类,加载SpringMvcConfig和SpringConfig配置类

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

功能模块开发

  • 数据层开发(BookDao)

    @Data
    public class Book {
        private Integer id;
        private String type;
        private String name;
        private String description;
    }
    @Mapper
    public interface BookDao {
    
        //@Insert("insert into tbl_book values(null,#{type},#{name},#{description})")
        @Insert("insert into tbl_book (type,name,description) values(#{type},#{name},#{description})")
        public int save(Book book);  //返回值表示影响的行数
    
        @Update("update tbl_book set type = #{type}, name = #{name}, description = #{description} where id = #{id}")
        public int update(Book book);
    
        @Delete("delete from tbl_book where id = #{id}")
        public int delete(Integer id);
    
        @Select("select * from tbl_book where id = #{id}")
        public Book getById(Integer id);
    
        @Select("select * from tbl_book")
        public List<Book> getAll();
    }
  • 业务层开发

    @Transactional //表示所有方法进行事务管理
    public interface BookService {
    
        /**
         * 保存
         * @param book
         * @return
         */
        public boolean save(Book book);
    
        /**
         * 修改
         * @param book
         * @return
         */
        public boolean update(Book book);
    
        /**
         * 按id删除
         * @param id
         * @return
         */
        public boolean delete(Integer id);
    
        /**
         * 按id查询
         * @param id
         * @return
         */
        public Book getById(Integer id);
    
        /**
         * 查询全部
         * @return
         */
        public List<Book> getAll();
    }
    @Service
    public class BookServiceImpl implements BookService {
        @Autowired
        private BookDao bookDao;
        //增删改的方法判断了影响的行数是否大于0,而不是固定返回true
        public boolean save(Book book) {
            return bookDao.save(book) > 0;
        }
        //增删改的方法判断了影响的行数是否大于0,而不是固定返回true
        public boolean update(Book book) {
            return bookDao.update(book) > 0;
        }
        //增删改的方法判断了影响的行数是否大于0,而不是固定返回true
        public boolean delete(Integer id) {
            return bookDao.delete(id) > 0;
        }
    
        public Book getById(Integer id) {
            if(id < 0){
                throw new BusinessException(Code.BUSINESS_ERR,"请不要使用你的技术挑战我的耐性!");
            }
            return bookDao.getById(id);
        }
        public List<Book> getAll() {
            return bookDao.getAll();
        }
    }
  • 表现层开发(BookController)

    @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 getById(@PathVariable Integer id) {
            return bookService.getById(id);
        }
    
        @GetMapping
        public List<Book> getAll() {
            return bookService.getAll();
        }
    }

接口测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class)
public class BookServiceTest {

    @Autowired
    private BookService bookService;

    @Test
    public void testGetById(){
        Book book = bookService.getById(1);
        System.out.println(book);
    }

    @Test
    public void testGetAll(){
        List<Book> all = bookService.getAll();
        System.out.println(all);
    }
}

表现层数据封装

  • Result类封装响应结果

    @Data
    public class Result {
        //描述统一格式中的编码,用于区分操作,可以简化配置0或1表示成功失败
        private Integer code;
        //描述统一格式中的数据
        private Object data;
        //描述统一格式中的消息,可选属性
        private String msg;
    }
  • Code类封装响应码

    //状态码
    public class Code {
        public static final Integer SAVE_OK = 20011;
        public static final Integer DELETE_OK = 20021;
        public static final Integer UPDATE_OK = 20031;
        public static final Integer GET_OK = 20041;
    
        public static final Integer SAVE_ERR = 20010;
        public static final Integer DELETE_ERR = 20020;
        public static final Integer UPDATE_ERR = 20030;
        public static final Integer GET_ERR = 20040;
    }
  • 表现层数据封装返回Result对象

    @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 getById(@PathVariable Integer id) {
            Book book = bookService.getById(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);
        }
    }

异常处理器

  • 编写异常处理器

    @RestControllerAdvice  //用于标识当前类为REST风格对应的异常处理器
    public class ProjectExceptionAdvice {
    
        //统一处理所有的Exception异常
        @ExceptionHandler(Exception.class)
        public Result doOtherException(Exception ex){
            return new Result(666,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;
    }
}

自定义项目业务级异常

//自定义异常处理器,用于封装异常信息,对异常进行分类
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;
    }
}

自定义异常编码

public class Code {

    //之前其他状态码省略没写,以下是新补充的状态码,可以根据需要自己补充

    public static final Integer SYSTEM_ERR = 50001;
    public static final Integer SYSTEM_TIMEOUT_ERR = 50002;
    public static final Integer SYSTEM_UNKNOW_ERR = 59999;
    public static final Integer BUSINESS_ERR = 60002;

}

触发自定义异常

@Service
public class BookServiceImpl implements BookService {
    @Autowired
    private BookDao bookDao;

    //在getById演示触发异常,其他方法省略没有写进来
    public Book getById(Integer id) {
        //模拟业务异常,包装成自定义异常
        if(id <0){
            throw new BusinessException(Code.BUSINESS_ERR,"请不要使用你的技术挑战我的耐性!");
        }
    }
}

在异常通知类中拦截并处理异常

@RestControllerAdvice //用于标识当前类为REST风格对应的异常处理器
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,"系统繁忙,请稍后再试!");
    }
}

SSM整合页面开发

  • 列表查询功能

    //列表
    getAll() {
        //发送ajax请求
        axios.get("/books").then((res)=>{
            this.dataList = res.data.data;
        });
    }
  • 添加功能

    //弹出添加窗口
    handleCreate() {
        this.dialogFormVisible = true;
        this.resetForm();
    },
    //重置表单
    resetForm() {
        this.formData = {};
    },
    //添加
    handleAdd () {
        //发送ajax请求
        axios.post("/books",this.formData).then((res)=>{
            console.log(res.data);
            //如果操作成功,关闭弹层,显示数据
            if(res.data.code == 20011){
                this.dialogFormVisible = false;
                this.$message.success("添加成功");
            }else if(res.data.code == 20010){
                this.$message.error("添加失败");
            }else{
                this.$message.error(res.data.msg);
            }
        }).finally(()=>{
            this.getAll();
        });
    },
  • 修改功能

    //弹出编辑窗口
    handleUpdate(row) {
        // console.log(row);   //row.id 查询条件
        //查询数据,根据id查询
        axios.get("/books/"+row.id).then((res)=>{
            // console.log(res.data.data);
            if(res.data.code == 20041){
                //展示弹层,加载数据
                this.formData = res.data.data;
                this.dialogFormVisible4Edit = true;
            }else{
                this.$message.error(res.data.msg);
            }
        });
    }
    //编辑
    handleEdit() {
        //发送ajax请求
        axios.put("/books",this.formData).then((res)=>{
            //如果操作成功,关闭弹层,显示数据
            if(res.data.code == 20031){
                this.dialogFormVisible4Edit = false;
                this.$message.success("修改成功");
            }else if(res.data.code == 20030){
                this.$message.error("修改失败");
            }else{
                this.$message.error(res.data.msg);
            }
        }).finally(()=>{
            this.getAll();
        });
    }
  • 删除功能

    // 删除
    handleDelete(row) {
        //1.弹出提示框
        this.$confirm("此操作永久删除当前数据,是否继续?","提示",{
            type:'info'
        }).then(()=>{
            //2.做删除业务
            axios.delete("/books/"+row.id).then((res)=>{
                if(res.data.code == 20021){
                    this.$message.success("删除成功");
                }else{
                    this.$message.error("删除失败");
                }
            }).finally(()=>{
                this.getAll();
            });
        }).catch(()=>{
            //3.取消删除
            this.$message.info("取消删除操作");
        });
    }

拦截器

  • 定义拦截器

    @Component //注意当前类必须受Spring容器控制
    //定义拦截器类,实现HandlerInterceptor接口
    public class ProjectInterceptor implements HandlerInterceptor {
        @Override
        //原始方法调用前执行的内容
        //返回值类型可以拦截控制的执行,true放行,false终止
        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...");
        }
    }
  • 配置加载拦截器

    @Configuration
    @ComponentScan({"cn.lixuan.controller"})
    @EnableWebMvc
    //实现WebMvcConfigurer接口可以简化开发,但具有一定的侵入性
    public class SpringMvcConfig implements WebMvcConfigurer {
        @Autowired
        private ProjectInterceptor projectInterceptor;
    
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            //配置多拦截器
            //访问/books或者/books/1...都拦截
            registry.addInterceptor(projectInterceptor)
                .addPathPatterns("/books","/books/*");
        }
    }

拦截器链配置

  • 定义第二个拦截器

    @Component
    public class ProjectInterceptor2 implements HandlerInterceptor {
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            System.out.println("preHandle...222");
            return false;
        }
    
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
            System.out.println("postHandle...222");
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            System.out.println("afterCompletion...222");
        }
    }
  • 配置第二个拦截器

    @Configuration
    @ComponentScan({"com.itheima.controller"})
    @EnableWebMvc
    //实现WebMvcConfigurer接口可以简化开发,但具有一定的侵入性
    public class SpringMvcConfig implements WebMvcConfigurer {
        @Autowired
        private ProjectInterceptor projectInterceptor;
        @Autowired
        private ProjectInterceptor2 projectInterceptor2;
    
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            //配置多拦截器
            registry.addInterceptor(projectInterceptor)
                .addPathPatterns("/books","/books/*");
            registry.addInterceptor(projectInterceptor2)
                .addPathPatterns("/books","/books/*");
        }
    }
评论区

索引目录