首页 > 其他分享 >SpringMVC-day02

SpringMVC-day02

时间:2023-03-11 16:45:12浏览次数:43  
标签:code 拦截器 return SpringMVC day02 book Integer public

SpringMVC-day02

01_基于SSM的三层架构

目标

  • 了解基于SSM框架的三层架构技术体系

路径

  1. SSM框架的三层架构技术体系

SSM框架的三层架构技术体系

在三层架构开发时会使用到SSM框架:

  • 表现层:SpringMVC
  • 业务层:Spring
  • 数据访问层:Mybatis

在使用SSM框架搭建三层架构时:

  • Spring ,管理全项目
    • IoC(父容器):管理除web层以外的bean
    • AOP :一般用在业务层(声明式事务放在业务层)
  • SpringMVC ,管理web层
    • 基于Spring
      • IoC(子容器):管理web层的bean
        • 父子容器:子容器可以访问父容器中的bean (反之不行)
      • AOP:统一异常处理器、拦截器
    • 封装web
      • 三大组件:Servlet(DispatcherServlet 前端控制器)、Filter(CharacterEncodeingFilter 乱码过滤器)、Listener
      • 请求、响应:请求参数映射、响应数据自动转换json格式
  • Mybatis ,管理dao层
    • 和数据库交互

小结

在三层架构体系中:

  • SpringMVC,属于表现层 (使用自己独立的IOC容器)
    • 接收前端请求
    • 处理请求(交给业务层完成)
    • 给前端响应
  • Spring,属于业务层(使用Spring的IOC容器)
    • 处理业务逻辑
  • Mybatis,属于持久层(由Spring的IOC容器管理)
    • 和数据库交互

02_SSM框架整合流程

目标

  • 了解SSM框架整合的流程

路径

  1. SSM框架整合的流程

SSM框架整合的流程

SSM框架整合流程步骤:

  1. 创建项目工程
  2. 创建包(分包):config、dao、service、controller、domain
  3. 搭建Spring框架环境
    • 导入Spring相关依赖
    • 编写SpingConfig配置类
  4. Spring整合Mybatis框架(业务层和持久层整合)
    • 导入坐标:MySQL、Mybatis、druid、Spring-jdbc、mybatis-spring
    • 编写配置类:
      • JdbcConfig // 连接池、事务管理器
      • MybatisConfig
      • 修改SpringConfig
    • 编写dao层代码
    • 编写service层代码
  5. Spring整合SpringMVC框架(业务层和表现层整合)
    • 导入坐标:Servlet、Jackson、Springmvc
    • 编写配置类
      • ServletConfig //Web容器配置类
      • SpringmvcConfig //SpringMVC配置类
    • 编写web层代码(Controller)

项目工程结构目录:

image-20220506230413504

03_SSM整合-搭建Spring环境

目标

  • 能够搭建Spring框架环境

路径

  1. 导入坐标
  2. 编写Spring配置类

导入坐标

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>
    <groupId>com.itheima</groupId>
    <artifactId>springmvc_day02-ssm</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <!-- 依赖管理 -->
    <dependencies>
        <!-- SpringMVC(底层依赖Spring)-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.2.10.RELEASE</version>
        </dependency>

    </dependencies>
</project>

image-20220506230208139

编写Spring配置类

SpringConfig:

/* Spring IoC容器(父容器)
    1. 管理除Controller包之外的所有bean
    2. spring的组件扫描 : 扫描controller包之外的其他包
        1). 方案一: 一个个配置,就是不配置controller包
        2). 方案二: 全扫描,排除controller包
            ComponentScan
                I. value : 要扫描的包
                II. excludeFilters : 排除不扫描 Controller和 RestController注解
                        a. type : 要排除的类型 (注解)
                        b. classes : 要排除的类
*/
/*@ComponentScan(value = "com.itheima",
        excludeFilters = {
               @ComponentScan.Filter(
                       type = FilterType.ANNOTATION,
                       classes = {Controller.class, RestController.class}
                       )
        }
)*/
//Spring配置类 (添加到IoC容器中)
@Configuration
@ComponentScan({"com.itheima.service"}) //扫描service层包
public class SpringConfig {
}

04_SSM整合-Spring整合Mybatis

目标

  • 能够使用Spring整合Mybatis,实现对数据的CRUD操作

路径

  1. 导入坐标
  2. 编写配置类
  3. 编写dao层
  4. 编写service层
  5. 测试service层功能

数据库:

create database ssm_db;
use ssm_db;

create table tbl_book(
		id int primary key auto_increment,
		type varchar(20),
	    name varchar(50),
		description varchar(255)
);

INSERT INTO `tbl_book` VALUES ('1', '编程', 'Spring实战', 'spring入门经典教程');
INSERT INTO `tbl_book` VALUES ('2', '编程', 'springmvc实战', 'springmvc经典教程');
INSERT INTO `tbl_book` VALUES ('3', '编程', 'mybatis入门', '手把手教你操作数据库');
INSERT INTO `tbl_book` VALUES ('4', '市场营销', '直播就该这么做', '李佳琦,薇娅推荐');
INSERT INTO `tbl_book` VALUES ('5', '市场营销', '直播带货', '一本教你如何玩转直播的书');

导入坐标

        <!-- Spring整合Mybatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.3.0</version>
        </dependency>

        <!-- Spring JDBC : 声明式事务 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.2.10.RELEASE</version>
        </dependency>

        <!-- Spring整合Junit -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.2.10.RELEASE</version>
        </dependency>

        <!-- MySQL -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>

        <!-- Mybatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.6</version>
        </dependency>

        <!-- druid连接池 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.1</version>
        </dependency>

        <!-- Junit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

编写配置类

db.properties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/ssm_db
jdbc.username=root
jdbc.password=itheima

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

    //设置事务管理器 (声明式事务)
    @Bean
    public PlatformTransactionManager transactionManager(DataSource dataSource){
        //PlatformTransactionManager是DataSourceTransactionManager的父接口
        DataSourceTransactionManager dstm = new DataSourceTransactionManager();
        dstm.setDataSource(dataSource);
        return dstm;
    }
}

MybatisConfig

//Mybatis配置类
public class MybatisConfig {
    @Bean
    public SqlSessionFactoryBean getSqlSessionFactoryBean(DataSource ds){
        SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
        //设置pojo的包扫描
        factoryBean.setTypeAliasesPackage("com.itheima.domain");
        //设置连接池
        factoryBean.setDataSource(ds);
        return factoryBean;
    }

    @Bean
    public MapperScannerConfigurer mapperScannerConfigurer(){
        MapperScannerConfigurer msc = new MapperScannerConfigurer();
        //设置dao层的接口扫描
        msc.setBasePackage("com.itheima.dao");
        return msc;
    }
}

SpringConfig修改

@Configuration //Spring配置类 (添加到IoC容器中)
@ComponentScan({"com.itheima.service"}) //扫描指定包下的类,并添加到IoC容器
@PropertySource("classpath:db.properties") //加载外部配置文件
@Import({JdbcConfig.class, MybatisConfig.class}) //引入配置类
@EnableTransactionManagement //开启事务管理支持
public class SpringConfig {
}

编写dao层

dao层:

public interface BookDao {
    @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 id, type, name, description from tbl_book where id = #{id}")
    public Book getById(Integer id);

    @Select("select id, type, name, description from tbl_book")
    public List<Book> getAll();
}

编写service层

service层:

//接口
@Transactional //给接口的每个方法添加事务
public interface IBookService {
    /**
     * 保存
     * @param book
     * @return
     */
    public boolean saveBook(Book book);

    /**
     * 修改
     * @param book
     * @return
     */
    public boolean updateBook(Book book);

    /**
     * 按id删除
     * @param id
     * @return
     */
    public boolean deleteBookById(Integer id);

    /**
     * 按id查询
     * @param id
     * @return
     */
    public Book getBookById(Integer id);

    /**
     * 查询全部
     * @return
     */
    public List<Book> getAllBook();
}
//实现类
@Service
public class BookServiceImpl implements IBookService {
    @Autowired
    private BookDao bookDao;

    @Override
    public boolean saveBook(Book book) {
        int result = bookDao.save(book);
        if(result>0){
            return  true;
        }
        return false;
    }

    @Override
    public boolean updateBook(Book book) {
        bookDao.update(book);
        return true;
    }

    @Override
    public boolean deleteBookById(Integer id) {
        bookDao.delete(id);
        return true;
    }

    @Override
    public Book getBookById(Integer id) {
        Book book = bookDao.getById(id);
        return book;
    }

    @Override
    public List<Book> getAllBook() {
        List<Book> bookList = bookDao.getAll();
        return bookList;
    }
}

测试service层功能

测试类:

@RunWith(SpringJUnit4ClassRunner.class)//spring整合junit
@ContextConfiguration(classes = SpringConfig.class)//加载注解配置类
public class BookServiceTest {
    @Autowired
    IBookService bookService;

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

    @Test
    public void testGetAllBook() {
        List<Book> bookList = bookService.getAllBook();
        for (Book book : bookList) {
            System.out.println(book);
        }
    }

    @Test
    public void testSaveBook(){
        Book book = new Book();
        book.setType("编程");
        book.setName("MySQL高级");
        book.setDescription("MySQL数据库的高级应用开发");

        boolean result = bookService.saveBook(book);
        System.out.println(result);
    }
}

05_SSM整合-Spring整合SpringMVC

目标

  • 能够使用Spring整合SpringMVC,实现前端数据交互

路径

  1. 导入坐标
  2. 编写配置类
  3. 编写Controller类
  4. 使用postman测试

导入坐标

        <!-- Servlet -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>

        <!-- Jackson : 实现json格式和javabean之间的数据转换 -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.9.0</version>
        </dependency>

编写配置类

SpringMVC配置类

@Configuration
@ComponentScan("com.itheima.controller")  //springmvc的ioc容器只管理web层相关的bean
@EnableWebMvc //开启javabean自动转换json
public class SpringmvcConfig {
}

Web容器配置类

public class ServletInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
    @Override
    protected Class<?>[] getRootConfigClasses() {
        //指定spring配置类加载(根配置)
        return new Class[]{SpringConfig.class};
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        //指定springmvc配置类加载
        return new Class[]{SpringmvcConfig.class};
    }

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

    //中文乱码过滤器
    @Override
    protected Filter[] getServletFilters() {
        CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter();
        encodingFilter.setEncoding("utf-8");
        return new Filter[]{encodingFilter};
    }
}
  • 配置启动顺序:

    1. Tomcat启动,利用SPI机制加载ServletInitConfig

    2. 在ServletInitConfig中,先加载SpringConfig,然后加载SpringmvcConfig,最后设置SpringMVC中的DispatcherServlet的匹配路径为:/

    3. SpringConfig

      • 1、加载com.itheima.service下的bean(IoC父容器)

      • 2、加载jdbc.properties文件

      • 3、加载mybatis配置类:JdbcConfig、MybatisConfig

        • 将com.itheima.dao下的bean放到父容器
    4. SpringmvcConfig

      • 加载com.itheima.controller下的bean(子容器)

父子容器:子容器可以访问父容器中的bean (反之不行)

编写Controller类

BookController

//RESTful风格
@RestController
@RequestMapping("/book")
public class BookController {
    @Autowired
    private IBookService bookService;

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

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

    @DeleteMapping("/{id}")
    public boolean delete(@PathVariable Integer id) {
        return bookService.deleteBookById(id);
    }

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

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

使用postman测试

  • 修改

    image-20220507120056572

  • 查询

    image-20220507120232667

06_SSM整合-封装表现层数据

目标

  • 能够使用封装的方式优化表现层响应的数据

路径

  1. 表现层存在的问题
  2. 改造表现层:对响应的数据进行统一封装

表现层存在的问题

现在后端程序响应的数据格式是五花八门,这种情况不利于前端解析,同时也加大了前后端交互的难度

1638285744660

解决方案:对响应的数据进行统一的封装 (自定义交互协议)

1638285619665

改造表现层:对响应的数据进行统一封装

添加:响应结果类(Result)、状态码类(Code)

1638286030207

响应结果类:设置统一数据返回结果

  • 说明:Result类中的字段并不是固定的,可以根据需要自行增减
public class Result{
    //描述统一格式中的数据
    private Object data;
    //描述统一格式中的编码,用于区分操作,可以简化配置0或1表示成功失败
    private Integer code;
    //描述统一格式中的消息,可选属性
    private String msg;

    public Result() {
    }
	//可用于增删改操作的响应结果(查询失败也可以用)
    public Result(Integer code,String msg) {
        this.msg = msg;
        this.code = code;
    }
	//可用于查询成功
    public Result(Integer code, Object data, String msg) {
        this.data = data;
        this.code = code;
        this.msg = msg;
    }
    public Object getData() {
        return data;
    }
    public void setData(Object data) {
        this.data = data;
    }
    public Integer getCode() {
        return code;
    }
    public void setCode(Integer code) {
        this.code = code;
    }
    public String getMsg() {
        return msg;
    }
    public void setMsg(String msg) {
        this.msg = msg;
    }
}
Result responseResult = new Result(响应状态码, 响应的数据, 响应状态消息);

问题:在Result类中有指定响应状态码,那么响应状态码应该怎么定义呢?

  • 可以参照之前学习http协议时有接触过的状态码。如:200、404、500

自定义状态码:设置统一数据返回结果编码

//状态码
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 = 50010;//保存失败
    public static final Integer DELETE_ERR = 50020;//删除失败
    public static final Integer UPDATE_ERR = 50030;//修改失败
    public static final Integer GET_ERR = 50040;//查询失败
}
  • 说明:Code类的常量设计也不是固定的,可以根据需要自行增减
    • 例如:将查询再进行细分为GET_OK,GET_ALL_OK,GET_PAGE_OK

修改BookController类:

@RestController
@RequestMapping("/book")
public class BookController {
    @Autowired
    private IBookService bookService;

    @PostMapping
    public Result save(@RequestBody Book book) {
        boolean result = bookService.saveBook(book);
        
        Integer code = result ? Code.SAVE_OK : Code.SAVE_ERR;
        String message = result ? "保存成功" : "保存失败";
        return new Result(code, result, message);
    }

    @PutMapping
    public Result update(@RequestBody Book book) {
        boolean result = bookService.updateBook(book);
        Integer code = result ? Code.UPDATE_OK : Code.UPDATE_ERR;
        String message = result ? "修改成功" : "修改失败";
        return new Result(code, result, message);
    }

    @DeleteMapping("/{id}")
    public Result delete(@PathVariable Integer id) {
        boolean result = bookService.deleteBookById(id);
        Integer code = result ? Code.DELETE_OK : Code.DELETE_ERR;
        String message = result ? "删除成功" : "删除失败";
        return new Result(code, result, message);
    }

    @GetMapping("/{id}")
    public Result getById(@PathVariable Integer id) {
        Book book = bookService.getBookById(id);
        Integer code = book != null ? Code.GET_OK : Code.GET_ERR;
        String message = book != null ? "查询用户成功" : "查询用户失败";
        return new Result(code, book, message);
    }

    @GetMapping
    public Result getAll() {
        List<Book> bookList = bookService.getAllBook();
        Integer code = bookList != null && bookList.size() != 0 ? Code.GET_OK : Code.GET_ERR;
        String message = bookList != null && bookList.size() != 0 ? "查询全部成功" : "查询全部失败";
        return new Result(code, bookList, message);
    }
}

使用postman测试:

  • 修改

    image-20220507132846251

  • 查询

    image-20220507132954724

  • 查询失败

    image-20220507133159799

07_SpringMVC异常处理器

目标

  • 了解SpringMVC异常处理器

路径

  1. 三层架构下的异常现象
  2. SpringMVC的异常处理器

三层架构下的异常现象

在三层架构下异常现象出现的位置与诱因:

  • 框架内部抛出的异常:因使用不合规导致
  • 数据层抛出的异常:因外部服务器故障导致(如:服务器访问超时)
  • 业务层抛出的异常:因业务逻辑书写错误导致(如:遍历过程中出现索引异常)
  • 表现层抛出的异常:因数据收集、校验等规则导致(如:不匹配的数据类型导致异常)
  • 工具类抛出的异常:因工具类书写不严谨不够健壮导致(如:要释放的连接长期未释放)

思考:各层都可能出现异常,那么异常处理代码应该写在哪一层?

之前:学习Java时,可以把异常都抛出到main方法中,在main方法中进行统一处理。
现在:三层架构体系下,把异常都抛出到表现层(controller)进行处理

思考:在表现层处理异常时,每个方法都可能会存在异常,如果在每个方法中都添加异常处理代码,代码书写量巨大且意义不强,如何解决?

AOP思想
SpringMVC参照AOP思想,设计了可以统一处理项目中发生异常的处理器
 -- 切面 = 切入点 + 通知
 -- 切入点: controller层所有方法
 -- 通知: 异常通知

SpringMVC的异常处理器

AOP思想:

  • 切面 = 切入点 + 通知
  • 切入点 : controller的方法
  • 通知 : 异常通知

SpringMVC的异常处理器可以集中的、统一的处理项目中出现的异常

  • 为SpringMVC控制器类做增强
//@RestControllerAdvice = @ResponseBody + @ControllerAdvice
//此注解自带@ResponseBody注解与@ControllerAdvice注解,具备对应的功能
@RestControllerAdvice
public class ProjectExceptionAdvice {
    /*
        专门处理Exception类型异常的通知
        1. 此方法在controller层代码抛出异常之后
        2. 并且此异常类型为Exception,那么此方法就会运行
        3. 而且参数ex就是所发生的异常
    */
    @ExceptionHandler(Exception.class)
    public Result doException(Exception ex){
        ex.printStackTrace();
        return new Result(666,null);
    }
}

08_项目异常处理方案

目标

  • 能够在SSM项目中添加自定义异常处理

路径

  1. 项目中异常的分类
  2. 改造SSM项目:添加异常处理

项目中异常的分类

异常出现的可能情况:

  1. 代码写错了:程序员自身原因
  2. 用户出错了:程序有一部分数据是由用户输入的
  3. 系统的影响:项目所依赖的整个环境(tomcat,mysql)

项目中异常分类:

  1. 业务异常(BusinessException) 用户行为产生的异常
  2. 系统异常(SystemException) 项目运行过程中可预计且无法避免的异常(数据库崩溃)
  3. 其他异常(Exception) 编程人员未预期到的异常

项目中异常处理方案

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

SpringMVC中异常处理示例

添加:自定义异常类、异常通知类

image-20220507172653976

自定义异常处理器: 用于封装异常信息,对异常进行分类

//业务异常处理器
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 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 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 = 50010;//保存失败
    public static final Integer DELETE_ERR = 50020;//删除失败
    public static final Integer UPDATE_ERR = 50030;//修改失败
    public static final Integer GET_ERR = 50040;//查询失败

    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 = 60001; //业务异常
}

异常通知:

@RestControllerAdvice
public class ProjectExceptionAdvice {
    //专门处理业务功能导致的异常
    @ExceptionHandler(BusinessException.class)
    public Result doBusinessException(BusinessException ex){
        //发送对应消息传递给用户,提醒规范操作
        return new Result(ex.getCode(),ex.getMessage());
    }

    //专门处理系统异常
    @ExceptionHandler(SystemException.class)
    public Result doSystemException(SystemException ex){
        //发送固定消息传递给用户,安抚用户
        //发送特定消息给运维人员,提醒维护
        //记录日志
        return new Result(ex.getCode(),ex.getMessage());
    }

    //处理其他未知异常
    @ExceptionHandler(Exception.class)
    public Result doException(Exception ex){
        //发送固定消息传递给用户,安抚用户
        //发送特定消息给编程人员,提醒维护
        //记录日志
        return new Result(Code.SYSTEM_UNKNOW_ERR,"服务器正在维护,请稍后访问");
    }
}

修改业务类(模拟异常发生)

@Service
public class BookServiceImpl implements IBookService {
    @Autowired
    private BookDao bookDao;//由于idea不能很好的识别spring整合myabtis的配置,所以可能报错,但实际运行没有问题

    @Override
    public boolean saveBook(Book book) {
        int result = bookDao.save(book);
        if(result>0){
            return  true;
        }
        return false;
    }

    @Override
    public boolean updateBook(Book book) {
        bookDao.update(book);
        return true;
    }

    @Override
    public boolean deleteBookById(Integer id) {
        bookDao.delete(id);
        return true;
    }

    @Override
    public Book getBookById(Integer id) {
        //业务逻辑判断:传递参数的合法性(用户录入)
        if (id < 0) {
            //业务异常: 用户造成的
            throw new BusinessException(Code.BUSINESS_ERR, "用户id不能为负数");
        }

        Book book = null;
        try {
            //数据库可能有问题抛出异常
            book = bookDao.getById(id);
        } catch (Exception e) {
            throw new SystemException(Code.SYSTEM_ERR, "当前访问人数较多,请稍后访问");
        }

        //模拟未知异常
        int i = 1 / 0;

        return book;
    }

    @Override
    public List<Book> getAllBook() {
        List<Book> bookList = bookDao.getAll();
        return bookList;
    }
}

使用postman测试:

image-20220507191355044

09_SpringMVC拦截器

目标

  • 了解SpringMVC中拦截器的概念

路径

  1. 拦截器介绍
  2. 拦截器和过滤器的区别
  3. 拦截器的应用场景

拦截器介绍

在前面学习Servlet技术时,有使用过:Filter(过滤器)

而在SpringMVC中有存在类似于Filter的功能:拦截器(Interceptor)。用于对controller进行预处理和后处理。

拦截器:

  • 拦截器是一种动态拦截方法调用的机制,在SpringMVC中动态拦截控制器方法的执行
  • 作用:
    1. 在指定的controller方法前后执行预先设定的代码
    2. 阻止controlle方法的执行
  • 原理:AOP思想

1638292219389

拦截器和过滤器的区别

官方:

image-20220507212512302

黑马:

  1. 归属不同:Filter属于Servlet技术,Interceptor属于SpringMVC技术
  2. 拦截内容不同:Filter对所有访问进行拦截,Interceptor仅针对SpringMVC的访问进行拦截
  3. 执行顺序:先执行过滤器,然后再能执行拦截器

拦截器的应用场景

应用场景:

  1. 权限检查
    • 如登录检测,进入处理器前检测用户是否登录,如果没有登陆直接返回到登录页面。
  2. 性能监控
    • 有时候系统在某段时间莫名其妙的慢,可以通过拦截器在进入处理器之前记录开始时间,在处理完后记录结束时间,统计处理器执行使用了多少时间。

10_SpringMVC拦截器的使用

目标

  • 能够使用SpringMVC拦截器增强contorller功能

路径

  1. 拦截器的使用步骤
  2. 拦截器的使用示例

拦截器的使用步骤

要使用SpringMVC拦截器,必须实现HandlerInterceptor接口,重写接口中的方法:

  • preHandle() ,在contorller方法执行前拦截

  • postHandle() ,在contorller方法执行后拦截

  • afterCompletion ,在视图解析器解析完毕后拦截

拦截器使用步骤:

  1. 自定义拦截器(通知)
    • 创建类并实现HandlerInterceptor接口,重写接口中的方法
  2. 配置拦截器的拦截规则(切入点)

拦截器的使用示例

image-20220507222152618

代码示例:

  • 自定义拦截器(通知)
//定义拦截器类,实现HandlerInterceptor接口
@Component  //当前类必须受Spring容器控制
public class TimeConsumeInterceptor implements HandlerInterceptor {
    long beginTime;//开始时间
    long endTime;//结束时间

    //原始方法调用前增强的功能
    /**
     * @param  request      请求对象
     * @param  response     响应对象
     * @param  handler      处理器方法的封装(方法对象) 
     * @return              true:表示资源放行 、 false:资源禁止访问
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle... 开始计时");
        beginTime = System.currentTimeMillis();
        return true;//返回值类型可以拦截控制的执行。 true放行,false终止
    }

    //原始方法调用后执行增强的功能
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle... 结束计时");
        endTime = System.currentTimeMillis();
        //强制转换为:HandlerMethod (反射中的Method对象再次包装)
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        //获取controller方法的名字
        String methodName = handlerMethod.getMethod().getName();
        System.out.println(methodName+"方法执行,耗时:" + (endTime - beginTime) + "毫秒");
    }
}
  • 配置拦截器的拦截规则(切入点)
//拦截器配置类
@Configuration
public class SpringmvcSupport extends WebMvcConfigurationSupport {
    @Autowired
    private TimeConsumeInterceptor timeConsumeInterceptor;

    @Override
    protected void addInterceptors(InterceptorRegistry registry) {
        //配置拦截器   设定拦截的访问路径,路径可以通过可变参数设置多个
        registry.addInterceptor(timeConsumeInterceptor)
                .addPathPatterns("/book","/book/*");
    }
}
//修改SpringmvcConfig配置类: 添加扫描包
@Configuration
@ComponentScan({"com.itheima.controller","com.itheima.config"}) //新增扫描包
@EnableWebMvc 
public class SpringmvcConfig {
}
//输出结果:
preHandle... 开始计时
postHandle... 结束计时
getAll方法执行,耗时:7毫秒

使用标准接口WebMvcConfigurer简化开发 (侵入式编码)

@Configuration
//@ComponentScan({"com.itheima.controller","com.itheima.config"})
@ComponentScan("com.itheima.controller")
@EnableWebMvc
public class SpringmvcConfig implements WebMvcConfigurer {
    @Autowired
    private TimeConsumeInterceptor timeConsumeInterceptor;
    
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //配置拦截器   设定拦截的访问路径,路径可以通过可变参数设置多个
        registry.addInterceptor(timeConsumeInterceptor)
                .addPathPatterns("/book","/book/*");
    }
}

11_SpringMVC拦截器链

目标

  • 了解SpringMVC中的拦截器链

路径

  1. 拦截器链介绍
  2. 拦截器链示例

拦截器链介绍

拦截器链:

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

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

  • 当拦截器中出现对原始处理器的拦截,后面的拦截器均终止运行

实际开发中,尽量避免多拦截器的使用,因为请求拦截器的增多会造成请求链路的增长,那么执行请求的效率也会降低

image-20200427171422781

以上图中3个拦截器为例说明:
规律:当3个拦截器的pre方法都返回true时,则对应的所有post和after方法都会被执行;
规律:当有一个pre方法返回false时,所有的post方法都不会被执行;
规律:after方法只有在对应的pre方法被执行且返回true时才执行;

拦截器链示例

代码示例:

  • 自定义拦截器(通知)
@Component
public class ProjectInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("ProjectInterceptor => preHandle");
        return true;//放行:执行controller方法
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
        System.out.println("ProjectInterceptor => postHandle");
    }
}
  • 配置多个拦截器(切入点)
@Configuration
public class SpringmvcSupport extends WebMvcConfigurationSupport {
    @Autowired
    private TimeConsumeInterceptor timeConsumeInterceptor;
    @Autowired
    private ProjectInterceptor projectInterceptorl;

    protected void addInterceptors(InterceptorRegistry registry) {
        //配置多个拦截器
        registry.addInterceptor(timeConsumeInterceptor)
                .addPathPatterns("/book","/book/*");
        registry.addInterceptor(projectInterceptorl)
                .addPathPatterns("/book","/book/*");
    }
}
//输出结果:
preHandle... 开始计时
ProjectInterceptor => preHandle
ProjectInterceptor => postHandle
postHandle... 结束计时
getAll方法执行,耗时:6毫秒

12_在SpringMVC中访问静态资源

目标

  • 能够解决在SpringMVC中访问静态资源时存在的问题

路径

  1. 问题演示
  2. 解决问题

问题演示

向项目工程下,添加web静态资源:

image-20220507194259664

启动Tomcat,访问页面时,会出现404错误(找不到资源):

image-20220507194447254

原理分析:

image-20220507212200275

解决问题

image-20220507201045649

在config包下,新建配置类:SpringmvcSupport

@Configuration
public class SpringmvcSupport extends WebMvcConfigurationSupport {
    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
        registry.addResourceHandler("/css/**").addResourceLocations("/css/");
        registry.addResourceHandler("/js/**").addResourceLocations("/js/");
        registry.addResourceHandler("/plugins/**").addResourceLocations("/plugins/");
    }
}

修改SpringMVC配置类:

@Configuration
@ComponentScan({"com.itheima.controller","com.itheima.config"}) //新增扫描包 
@EnableWebMvc //开启javabean自动转换json
public class SpringmvcConfig {
}

再次访问books.html页面:

image-20220507200207731

13_前端vue代码实现

目标

  • 能够编写vue代码,实现和后端程序的交互

路径

  1. 查询功能

查询功能

books.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>SpringMVC案例</title>
    <meta content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no" name="viewport">
    <!-- 引入样式 -->
    <link rel="stylesheet" href="../plugins/elementui/index.css">
    <link rel="stylesheet" href="../plugins/font-awesome/css/font-awesome.min.css">
    <link rel="stylesheet" href="../css/style.css">
</head>

<body class="hold-transition">

<div id="app">
    <div class="content-header">
        <h1>图书管理</h1>
    </div>

    <div class="app-container">
        <div class="box">
            <div class="filter-container">
                <el-input placeholder="图书名称" v-model="pagination.queryString" style="width: 200px;"
                          class="filter-item"></el-input>
                <el-button @click="getAll()" class="dalfBut">查询</el-button>
                <el-button type="primary" class="butT" @click="handleCreate()">新建</el-button>
            </div>

            <el-table size="small" current-row-key="id" :data="dataList" stripe highlight-current-row>
                <el-table-column type="index" align="center" label="序号"></el-table-column>
                <el-table-column prop="type" label="图书类别" align="center"></el-table-column>
                <el-table-column prop="name" label="图书名称" align="center"></el-table-column>
                <el-table-column prop="description" label="描述" align="center"></el-table-column>
                <el-table-column label="操作" align="center">
                    <template slot-scope="scope">
                        <el-button type="primary" size="mini" @click="handleUpdate(scope.row)">编辑</el-button>
                        <el-button type="danger" size="mini" @click="handleDelete(scope.row)">删除</el-button>
                    </template>
                </el-table-column>
            </el-table>

            <!-- 新增标签弹层 -->
            <div class="add-form">
                <el-dialog title="新增图书" :visible.sync="dialogFormVisible">
                    <el-form ref="dataAddForm" :model="formData" :rules="rules" label-position="right"
                             label-width="100px">
                        <el-row>
                            <el-col :span="12">
                                <el-form-item label="图书类别" prop="type">
                                    <el-input v-model="formData.type"/>
                                </el-form-item>
                            </el-col>
                            <el-col :span="12">
                                <el-form-item label="图书名称" prop="name">
                                    <el-input v-model="formData.name"/>
                                </el-form-item>
                            </el-col>
                        </el-row>

                        <el-row>
                            <el-col :span="24">
                                <el-form-item label="描述">
                                    <el-input v-model="formData.description" type="textarea"></el-input>
                                </el-form-item>
                            </el-col>
                        </el-row>
                    </el-form>
                    <div slot="footer" class="dialog-footer">
                        <el-button @click="dialogFormVisible = false">取消</el-button>
                        <el-button type="primary" @click="handleAdd()">确定</el-button>
                    </div>
                </el-dialog>
            </div>

            <!-- 编辑标签弹层 -->
            <div class="add-form">
                <el-dialog title="编辑检查项" :visible.sync="dialogFormVisible4Edit">
                    <el-form ref="dataEditForm" :model="formData" :rules="rules" label-position="right"
                             label-width="100px">
                        <el-row>
                            <el-col :span="12">
                                <el-form-item label="图书类别" prop="type">
                                    <el-input v-model="formData.type"/>
                                </el-form-item>
                            </el-col>
                            <el-col :span="12">
                                <el-form-item label="图书名称" prop="name">
                                    <el-input v-model="formData.name"/>
                                </el-form-item>
                            </el-col>
                        </el-row>
                        <el-row>
                            <el-col :span="24">
                                <el-form-item label="描述">
                                    <el-input v-model="formData.description" type="textarea"></el-input>
                                </el-form-item>
                            </el-col>
                        </el-row>
                    </el-form>
                    <div slot="footer" class="dialog-footer">
                        <el-button @click="dialogFormVisible4Edit = false">取消</el-button>
                        <el-button type="primary" @click="handleEdit()">确定</el-button>
                    </div>
                </el-dialog>
            </div>
        </div>
    </div>
</div>
</body>

<!-- 引入组件库 -->
<script src="../js/vue.js"></script>
<script src="../plugins/elementui/index.js"></script>
<script type="text/javascript" src="../js/jquery.min.js"></script>
<script src="../js/axios-0.18.0.js"></script>
<script>
    /*
    * TODO: Vue就两部分内容
    *  1. 视图 :  html(界面)
    *       1). 不用脚手架 <body>
            2). 脚手架 <template>
    *  2. 脚本 : js(data数据,methods交互)
    *        <script>

    *  TODO: Vue的理念
    *   1). 数据绑定  (通用)
    *       视图绑定脚本中的data数据 -> data数据改变,视图会随之改变
    *   2). 双向数据绑定 (表单 : v-model)
    *            data数据改变,视图会随之改变
    *            视图改变,data数据也会随之改变
    *  TODO: 交互部分,是不需要关注视图,关注data数据
    *       发送请求,获取数据,设置到data中
    *
    *   视图   <-  data   <- 交互
    * */
    var vue = new Vue({
        el: '#app',
        data: {
            pagination: {},
            dataList: [],//当前页要展示的列表数据
            formData: {},//表单数据
            dialogFormVisible: false,//控制表单是否可见
            dialogFormVisible4Edit: false,//编辑表单是否可见
            rules: {//校验规则
                type: [{required: true, message: '图书类别为必填项', trigger: 'blur'}],
                name: [{required: true, message: '图书名称为必填项', trigger: 'blur'}]
            },
            url: "/book"
        },

        //钩子函数,VUE对象初始化完成后自动执行
        created() {
            this.getAll();
        },

        methods: {
            //列表 TODO:
            getAll() {
                //查询 : 发起一个查询请求,接收数据,设置给dataList
                axios.get(this.url).then(response => {
                    console.log(response.data);
                    if (response.data.code == 20041) {
                        this.dataList = response.data.data
                    } else {
                        this.$message.error(response.data.msg);
                    }
                })

            },
            
            //重置表单
            resetForm() {
                this.formData = {};
            },
            //弹出添加窗口
            handleCreate() {
                this.dialogFormVisible = true;
                this.resetForm();
            },
            //弹出编辑窗口
            handleUpdate(row) {
                this.formData = row
                this.dialogFormVisible4Edit = true;
            },
            //TODO:省略....
        }
    });
</script>
</html>

扩展:文件上传

目标

  • 能够使用SpringMVC接收上传的文件

路径

  1. 客户端文件上传要求
  2. SpringMVC的文件上传

客户端文件上传要求

浏览器客户端实现文件上传的要求:

  1. form表单的method属性设置为post方式
    • get的请求参数拼接url中,体现在地址栏,长度是受限
    • post请求参数放在请求体中,长度不受限
  2. form表单的enctype属性设置为multipart/form-data,默认是:x-www-form-urlencoded
  3. form表单中需要一个的文本选择域
<form method="post" enctype="multipart/form-data">
    头像: <input type="file" name="file" />  <!-- 上传文件项 -->
    <input type="submit" value="提交表单" />  
</form>

SpringMVC的文件上传

代码示例:

  • 前端

    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <h1>文件上传</h1>
        <form action="uploadfile" method="post" enctype="multipart/form-data">
            <!-- 普通表单项 -->
            用户名: <input  type="text" name="username"/>  <br>
            密码: <input type="text" name="password" /> <br>
            <!-- 上传文件项 -->
            头像: <input type="file" name="myFile" /> <br>
            <input type="submit" value="提交表单" />
        </form>
    </body>
    </html>
    
  • 后端

    • 导入坐标
    <dependency>
        <groupId>commons-fileupload</groupId>
        <artifactId>commons-fileupload</artifactId>
        <version>1.3.2</version>
    </dependency>
    
    • 配置类:SpringMvcSupport
    @Configuration
    public class SpringMvcSupport extends WebMvcConfigurationSupport {
        /**
         * 释放静态资源
         * @param registry
         */
        @Override
        protected void addResourceHandlers(ResourceHandlerRegistry registry) {
            registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
            registry.addResourceHandler("/js/**").addResourceLocations("/js/");
        }
    
        //配置多媒体解析器,方法名须为:multipartResolver
        @Bean
        public CommonsMultipartResolver multipartResolver(){
            CommonsMultipartResolver resolver = new CommonsMultipartResolver();
            //设置上传文件的总大小,单位是字节 100MB
            resolver.setMaxUploadSize(1024*1024*100);
            //设置每个文件上传的大小,单位是字节 10MB
            resolver.setMaxUploadSizePerFile(1024*1024*10);
            return resolver;
        }
    }
    
    • Controller
    @RestController
    public class UploadController {
    
        /**
         *  注意参数名跟前端name属性一致
         * @param username
         * @param password
         * @param myFile  本质是个InputStream
         *                springmvc用这个对象封装了前端发送的文件数据             
         * @return
         */
        @PostMapping("/uploadfile")
        public String upload(String username,
                           String password,
                           MultipartFile myFile) throws IOException {
            System.out.println(username + "," + password);
            System.out.println(myFile);
            String name = myFile.getName();
            System.out.println("属性名:" + name);
            String originalFilename = myFile.getOriginalFilename();
            System.out.println("文件名:" + originalFilename);
    
            //随机文件名
            String randomName = UUID.randomUUID().toString().replaceAll("-", "");
    
            //切割文件名:   6.jpg  =切割=>  6 jpg
            String[] split = originalFilename.split("\\.");
            String fileName  = "f:/upload/" + randomName + "." + split[1];
    
            //创建文件对象
            File destFile = new File(fileName);
    
            //将myFile数据写到destFile去
            myFile.transferTo(destFile);
    
            return "success";
        }
    }
    

扩展:使用postman进行图片上传测试

1641309409772

附录:SSM整合案例完整依赖

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>

    <groupId>com.itheima</groupId>
    <artifactId>springmvc_day02-ssm</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <!-- 依赖管理 -->
    <dependencies>
        <!-- SpringMVC(底层依赖Spring)-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.2.10.RELEASE</version>
        </dependency>

        <!-- Spring整合Mybatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.3.0</version>
        </dependency>

        <!-- Spring JDBC : 声明式事务 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.2.10.RELEASE</version>
        </dependency>

        <!-- Spring整合Junit -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.2.10.RELEASE</version>
        </dependency>

        <!-- MySQL -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>

        <!-- Mybatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.6</version>
        </dependency>

        <!-- druid连接池 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.1</version>
        </dependency>

        <!-- Junit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

        <!-- Servlet -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>

        <!-- Jackson : 实现json格式和javabean之间的数据转换 -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.9.0</version>
        </dependency>

    </dependencies>
</project>

附录:books.html完整代码

books.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>SpringMVC案例</title>
    <meta content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no" name="viewport">
    <!-- 引入样式 -->
    <link rel="stylesheet" href="../plugins/elementui/index.css">
    <link rel="stylesheet" href="../plugins/font-awesome/css/font-awesome.min.css">
    <link rel="stylesheet" href="../css/style.css">
</head>

<body class="hold-transition">

<div id="app">
    <div class="content-header">
        <h1>图书管理</h1>
    </div>

    <div class="app-container">
        <div class="box">
            <div class="filter-container">
                <el-input placeholder="图书名称" v-model="pagination.queryString" style="width: 200px;"
                          class="filter-item"></el-input>
                <el-button @click="getAll()" class="dalfBut">查询</el-button>
                <el-button type="primary" class="butT" @click="handleCreate()">新建</el-button>
            </div>

            <el-table size="small" current-row-key="id" :data="dataList" stripe highlight-current-row>
                <el-table-column type="index" align="center" label="序号"></el-table-column>
                <el-table-column prop="type" label="图书类别" align="center"></el-table-column>
                <el-table-column prop="name" label="图书名称" align="center"></el-table-column>
                <el-table-column prop="description" label="描述" align="center"></el-table-column>
                <el-table-column label="操作" align="center">
                    <template slot-scope="scope">
                        <el-button type="primary" size="mini" @click="handleUpdate(scope.row)">编辑</el-button>
                        <el-button type="danger" size="mini" @click="handleDelete(scope.row)">删除</el-button>
                    </template>
                </el-table-column>
            </el-table>

            <!-- 新增标签弹层 -->
            <div class="add-form">
                <el-dialog title="新增图书" :visible.sync="dialogFormVisible">
                    <el-form ref="dataAddForm" :model="formData" :rules="rules" label-position="right"
                             label-width="100px">
                        <el-row>
                            <el-col :span="12">
                                <el-form-item label="图书类别" prop="type">
                                    <el-input v-model="formData.type"/>
                                </el-form-item>
                            </el-col>
                            <el-col :span="12">
                                <el-form-item label="图书名称" prop="name">
                                    <el-input v-model="formData.name"/>
                                </el-form-item>
                            </el-col>
                        </el-row>

                        <el-row>
                            <el-col :span="24">
                                <el-form-item label="描述">
                                    <el-input v-model="formData.description" type="textarea"></el-input>
                                </el-form-item>
                            </el-col>
                        </el-row>
                    </el-form>
                    <div slot="footer" class="dialog-footer">
                        <el-button @click="dialogFormVisible = false">取消</el-button>
                        <el-button type="primary" @click="handleAdd()">确定</el-button>
                    </div>
                </el-dialog>
            </div>

            <!-- 编辑标签弹层 -->
            <div class="add-form">
                <el-dialog title="编辑检查项" :visible.sync="dialogFormVisible4Edit">
                    <el-form ref="dataEditForm" :model="formData" :rules="rules" label-position="right"
                             label-width="100px">
                        <el-row>
                            <el-col :span="12">
                                <el-form-item label="图书类别" prop="type">
                                    <el-input v-model="formData.type"/>
                                </el-form-item>
                            </el-col>
                            <el-col :span="12">
                                <el-form-item label="图书名称" prop="name">
                                    <el-input v-model="formData.name"/>
                                </el-form-item>
                            </el-col>
                        </el-row>
                        <el-row>
                            <el-col :span="24">
                                <el-form-item label="描述">
                                    <el-input v-model="formData.description" type="textarea"></el-input>
                                </el-form-item>
                            </el-col>
                        </el-row>
                    </el-form>
                    <div slot="footer" class="dialog-footer">
                        <el-button @click="dialogFormVisible4Edit = false">取消</el-button>
                        <el-button type="primary" @click="handleEdit()">确定</el-button>
                    </div>
                </el-dialog>
            </div>
        </div>
    </div>
</div>
</body>

<!-- 引入组件库 -->
<script src="../js/vue.js"></script>
<script src="../plugins/elementui/index.js"></script>
<script type="text/javascript" src="../js/jquery.min.js"></script>
<script src="../js/axios-0.18.0.js"></script>
<script>
    /*
    * TODO: Vue就两部分内容
    *  1. 视图 :  html(界面)
    *       1). 不用脚手架 <body>
            2). 脚手架 <template>
    *  2. 脚本 : js(data数据,methods交互)
    *        <script>

    *  TODO: Vue的理念
    *   1). 数据绑定  (通用)
    *       视图绑定脚本中的data数据 -> data数据改变,视图会随之改变
    *   2). 双向数据绑定 (表单 : v-model)
    *            data数据改变,视图会随之改变
    *            视图改变,data数据也会随之改变
    *  TODO: 交互部分,是不需要关注视图,关注data数据
    *       发送请求,获取数据,设置到data中
    *
    *   视图   <-  data   <- 交互
    * */
    var vue = new Vue({
        el: '#app',
        data: {
            pagination: {},
            dataList: [],//当前页要展示的列表数据
            formData: {},//表单数据
            dialogFormVisible: false,//控制表单是否可见
            dialogFormVisible4Edit: false,//编辑表单是否可见
            rules: {//校验规则
                type: [{required: true, message: '图书类别为必填项', trigger: 'blur'}],
                name: [{required: true, message: '图书名称为必填项', trigger: 'blur'}]
            },
            url: "/book"
        },

        //钩子函数,VUE对象初始化完成后自动执行
        created() {
            this.getAll();
        },

        methods: {
            //列表 TODO:
            getAll() {
                //查询 : 发起一个查询请求,接收数据,设置给dataList
                axios.get(this.url).then(response => {
                    console.log(response.data);
                    if (response.data.code == 20041) {
                        this.dataList = response.data.data
                    } else {
                        this.$message.error(response.data.msg);
                    }
                })

            },

            //弹出添加窗口
            handleCreate() {
                this.dialogFormVisible = true;
                this.resetForm();
            },

            //重置表单
            resetForm() {
                this.formData = {};
            },

            //添加 TODO:
            handleAdd() {
                //发送ajax请求
                axios.post(this.url, 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) {
                this.formData = row
                this.dialogFormVisible4Edit = true;
            },

            //编辑 TODO:
            handleEdit() {
                //发送ajax请求
                axios.put(this.url, 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.做删除业务TODO:
                    //2.做删除业务
                    axios.delete(this.url + "/" + row.id).then((res) => {
                        if (res.data.code == 20021) {
                            this.$message.success("删除成功");
                        } else {
                            this.$message.error("删除失败");
                        }
                    }).finally(() => {
                        this.getAll();
                    });

                }).catch(() => {
                    //3.取消删除
                    this.$message.info("取消删除操作");
                });
            }
        }
    })

</script>

</html>

标签:code,拦截器,return,SpringMVC,day02,book,Integer,public
From: https://www.cnblogs.com/-turing/p/17206367.html

相关文章

  • Spring-day02
    Spring-day0201_开启Spring注解目标能够设置Spring的注解扫描路径注解开发的意义在配置文件中开启Spring注解扫描注解开发的意义在Spring中除了可以使用xml......
  • springmvc-通过控制器方法的形参获取请求参数
         ......
  • day02
    打开CMD的方式1.开始+系统+命令提示符2.Win键+R输入cmd打开控制台(推荐使用)3.在任意的文件夹下面按住shift+鼠标右键点击,在此处打开命令行窗口4.资源管理器的地址栏......
  • SpringMVC中的异常处理器
    SpringMVC中的异常处理器目录SpringMVC中的异常处理器一、概述二、异常处理器初始化位置默认策略@ControllerAdvice工作原理RequestMappingHandlerAdapterExceptionHandle......
  • 8_SpringMVC
    SpringMVCSpringMVC技术和Servlet技术功能等同,均属于web层开发技术学习目标掌握基于SpringMvc获取请求参数与响应json数据操作熟练应用基于REST风格的请求路径设置与......
  • 将springmvc.xml配置到resources目录
    web.xml配置<?xmlversion="1.0"encoding="UTF-8"?><web-appxmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-in......
  • Day02
    Linux-Day02课程内容软件安装项目部署1.软件安装1.1软件安装方式在Linux系统中,安装软件的方式主要有四种,这四种安装方式的特点如下:安装方式特点二......
  • 使用注解开发SpringMVC,也是以后开发的模板(重点)
    注解版配置SpringMVC(重点)第一步:新建一个moudel,添加web支持!建立包结构top.lostyou.controller第二步:由于maven可能存在资源过滤问题,我们将配置完善<!--在build中......
  • day02-项目实现01
    项目实现011.功能01-搭建Vue前端工程1.1需求分析使用Vue3的脚手架vue-cli工具,创建ssm的前端项目基础开发环境Vue-cli主要的功能是自动生成Vue的项目模板,提高开发效率......
  • springmvc配置文件
    <?xmlversion="1.0"encoding="UTF-8"?><beansxmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"......