SSM纯注解后台代码整合(Spring+SpringMvc+Mybatis)

news2025/1/15 6:29:26

SSM后台整合(Spring+SpringMvc+Mybtis+事务+Rest风格+统一结果封装+统一异常处理+拦截器)

文章目录

  • 1 基础环境搭建
    • 1.1 建表
    • 1.2 创建web项目
    • 1.3 导入依赖坐标(pom.xml)
    • 1.4 包路径的创建
    • 1.5 在pojo包下编写book实体类
    • 1.6 在webapp包下导入静态资源
    • 1.7 最终项目包结构
  • 2 创建Spring配置文件类SpringConfig
  • 3 Mybatis搭建
    • 3.1 在mapper包下编写bookDao接口
    • 3.2 在service包下编写bookService业务层接口
    • 3.3 在service包下创建impl包编写业务层接口实现类
    • 3.4 在resources包下创建db.properties配置文件
    • 3.5 在config包下创建数据源的JdbcConfig配置类
    • 3.6 创建Mybatis配置类并配置SqlSessionFactory
    • 3.7 完善SpringConfig配置类
    • 更多Mybatis搭建细节看这篇
  • 4 事务搭建
    • 4.1 在业务层需要被事务管理的方法上添加注解
    • 4.2 在JdbcConfig类中配置事务管理器
    • 4.3 在SpringConfig类中开启事务注解
    • 更多事务细节看这篇(第6节 AOP事务管理)
  • 5 Rest风格简介
  • 6 统一结果封装搭建
    • 6.1 在Controller包下创建Result类
    • 6.2 在Controller包下定义返回码Code枚举类
    • 6.3 实现的效果
  • 7 SpringMvc搭建
    • 7.1 在controller包下创建控制器类
    • 7.2 在controller包下创建Tomcat的Servlet容器配置类ServletContainersInitConfig
    • 7.3 在controller包下创建静态资源放行类SpringMvcSupport
    • 7.4 在controller包下创建SpringMvcConfig配置类
  • 8 统一异常处理搭建
    • 8.1 异常的种类及出现异常的原因:
    • 8.2 异常的分类和处理
    • 8.3 自定义异常类
    • 8.5 在异常处理器类中处理异常
    • 关于更多异常细节看这篇(第3节,统一异常处理)
  • 9 拦截器搭建
    • 9.1 在controller包下创建拦截器类
    • 9.2 在config包下的SpringMvcSupport类中配置拦截器bean
    • 关于拦截器更多细节看这篇(第5节,拦截器)
  • 10 结合前端页面实现简单(增删改查)
  • 11 注解汇总

1 基础环境搭建

1.1 建表

CREATE TABLE tbl_book(
  id INT PRIMARY KEY AUTO_INCREMENT,
  TYPE VARCHAR(20),
  NAME VARCHAR(50),
  description VARCHAR(255)
)ENGINE=INNODB DEFAULT CHARSET=utf8

INSERT  INTO `tbl_book`(`id`,`type`,`name`,`description`) VALUES 
(1,'计算机理论','Spring实战 第五版','Spring入门经典教程,深入理解Spring原理技术内幕'),
(2,'计算机理论','Spring 5核心原理与30个类手写实践','十年沉淀之作,手写Spring精华思想'),
(3,'计算机理论','Spring 5设计模式','深入Spring源码刨析Spring源码中蕴含的10大设计模式'),
(4,'计算机理论','Spring MVC+Mybatis开发从入门到项目实战','全方位解析面向Web应用的轻量级框架,带你成为Spring MVC开发高手'),
(5,'计算机理论','轻量级Java Web企业应用实战','源码级刨析Spring框架,适合已掌握Java基础的读者'),(6,'计算机理论','Java核心技术 卷Ⅰ 基础知识(原书第11版)','Core Java第11版,Jolt大奖获奖作品,针对Java SE9、10、11全面更新'),
(7,'计算机理论','深入理解Java虚拟机','5个纬度全面刨析JVM,大厂面试知识点全覆盖'),
(8,'计算机理论','Java编程思想(第4版)','Java学习必读经典,殿堂级著作!赢得了全球程序员的广泛赞誉'),
(9,'计算机理论','零基础学Java(全彩版)','零基础自学编程的入门图书,由浅入深,详解Java语言的编程思想和核心技术'),
(10,'市场营销','直播就这么做:主播高效沟通实战指南','李子柒、李佳奇、薇娅成长为网红的秘密都在书中'),
(11,'市场营销','直播销讲实战一本通','和秋叶一起学系列网络营销书籍'),
(12,'市场营销','直播带货:淘宝、天猫直播从新手到高手','一本教你如何玩转直播的书,10堂课轻松实现带货月入3W+');

1.2 创建web项目

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1.3 导入依赖坐标(pom.xml)

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
</properties>

  <dependencies>
<!--  导入spring和springMvc依赖包  -->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.1.0</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>5.2.10.RELEASE</version>
    </dependency>
<!-- 整合mybatis和操作数据库   -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</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>8.0.26</version>
    </dependency>
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>1.1.16</version>
    </dependency>

<!-- Spring整合test测试 -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-test</artifactId>
      <version>5.2.10.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>

<!--  json数据处理  -->
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.9.0</version>
    </dependency>
  </dependencies>
  <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>

说明: servlet的坐标为什么需要添加<scope>provided</scope>?
scope是maven中jar包依赖作用范围的描述,
如果不设置默认是compile在在编译、运行、测试时均有效
如果运行有效的话就会和tomcat中的servlet-api包发生冲突,导致启动报错
provided代表的是该包只在编译和测试的时候用,运行的时候无效直接使用tomcat中的,就避免冲突

1.4 包路径的创建

在这里插入图片描述

1.5 在pojo包下编写book实体类

package com.hyl.pojo;

/**
 * @author hyl
 * @version 1.0
 * @date 2023/1/10-10:23
 */

public class Book {
    private Integer id;
    private String type;
    private String name;
    private String description;


    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    @Override
    public String toString() {
        return "Book{" +
                "id=" + id +
                ", type='" + type + '\'' +
                ", name='" + name + '\'' +
                ", description='" + description + '\'' +
                '}';
    }
}


1.6 在webapp包下导入静态资源

SSM纯注解后台代码整合静态资源包
https://www.aliyundrive.com/s/Gvqs3fSuAEw
提取码: 9m2v
在这里插入图片描述
在这里插入图片描述
books.html页面效果
在这里插入图片描述

1.7 最终项目包结构

在这里插入图片描述

2 创建Spring配置文件类SpringConfig

在config包下创建SpringConfig配置类(替代Spring-config.xml配置文件)

package com.hyl.config;

import org.springframework.context.annotation.Configuration;

/**
 * @author hyl
 * @version 1.0
 * @date 2023/1/10-14:19
 */
@Configuration
public class SpringConfig {

}

3 Mybatis搭建

3.1 在mapper包下编写bookDao接口

使用Mybatis注解开发,不需要写对应的mapper.xml文件
对于复杂情况sql还是mapper.xml方便

package com.hyl.mapper;

import com.hyl.pojo.Book;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;

import java.util.List;

/**
 * @author hyl
 * @version 1.0
 * @date 2023/1/10-14:42
 */

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 * from tbl_book where name like concat('%',#{input},'%')")
    public List<Book> getByName(String input);

    @Select("select * from tbl_book where id = #{id}")
    public Book getById(Integer id);

    @Select("select * from tbl_book")
    public List<Book> getAll();
}

3.2 在service包下编写bookService业务层接口

package com.hyl.service;

import com.hyl.pojo.Book;

import java.util.List;

/**
 * @author hyl
 * @version 1.0
 * @date 2023/1/10-14:44
 */

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

    /**
     * 按输入模糊查询
     * @param input
     * @return
     */
    public List<Book> getByName(String input);

    /**
     * 查询全部
     * @return
     */
    public List<Book> getAll();
}

3.3 在service包下创建impl包编写业务层接口实现类

package com.hyl.service.impl;

import com.hyl.mapper.BookDao;
import com.hyl.pojo.Book;
import com.hyl.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * @author hyl
 * @version 1.0
 * @date 2023/1/10-14:44
 */

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

    @Override
    public boolean save(Book book) {
        return bookDao.save(book)>0;
    }

    @Override
    public boolean update(Book book) {
        return bookDao.update(book)>0;
    }

    @Override
    public boolean delete(Integer id) {
        return bookDao.delete(id)>0;
    }

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

    @Override
    public List<Book> getByName(String input) {
        return bookDao.getByName(input);
    }

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

3.4 在resources包下创建db.properties配置文件

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/table_04
username=root
password=123456

3.5 在config包下创建数据源的JdbcConfig配置类

package com.hyl.config;

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;


import javax.sql.DataSource;

/**
 * @author hyl
 * @version 1.0
 * @date 2023/1/10-14:18
 */
@Component
public class JdbcConfig {
    /**
     *从db.properties文件读取加载
     */

    @Value("${driver}")
    private String driver;
    @Value("${url}")
    private String url;
    @Value("${username}")
    private String username;
    @Value("${password}")
    private String password;

    /**
     * 获取数据源
     * @return
     */
    @Bean
    public DataSource dataSource(){
        DruidDataSource db=new DruidDataSource();
        db.setDriverClassName(driver);
        db.setUrl(url);
        db.setUsername(username);
        db.setPassword(password);
        return db;
    }
}

3.6 创建Mybatis配置类并配置SqlSessionFactory

package com.hyl.config;

import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

import javax.sql.DataSource;

/**
 * @author hyl
 * @version 1.0
 * @date 2023/1/10-14:33
 * Mybatis配置文件(等同于mybatis-config.xml配置文件)
 */
@Component
public class MybatisConfig {
    /**
     * 定义bean,SqlSessionFactoryBean,用于产生SqlSessionFactory对象
     * =====================================================
     * dataSource从JdbcConfig中获取,替代配置文件中的
     *<dataSource type="POOLED">
     *      <property name="driver" value="${driver}"/>
     *      <property name="url" value="${url}"/>
     *      <property name="username" value="${username}"/>
     *      <property name="password" value="${password}"/>
     *</dataSource>
     *
     *======================================================
     *
     * setTypeAliasesPackage("com.hyl.pojo")替代起别名
     *<typeAliases>
     *   <package name="com.hyl.pojo"/>
     *</typeAliases>
     *
     * =====================================================
     * @param dataSource 获取的DataSource在ioc容器中已经注入,会自动装填
     * @return 返回一个sqlSession对象
     */
    @Bean
    public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource){
        SqlSessionFactoryBean sqlSession=new SqlSessionFactoryBean();
        //设置模型类的别名扫描
        sqlSession.setTypeAliasesPackage("com.hyl.pojo");
        //设置数据源
        sqlSession.setDataSource(dataSource);
        return sqlSession;
    }
    /**
     * 定义bean,返回MapperScannerConfigurer对象,替代
     * <mappers>
     *      <package name="com.hyl.mapper"/>
     *<mappers/>
     * @return
     */
    @Bean
    public MapperScannerConfigurer mappers(){
        MapperScannerConfigurer msc = new MapperScannerConfigurer();
        msc.setBasePackage("com.hyl.mapper");
        return msc;
    }
}

3.7 完善SpringConfig配置类

主配置类中service包下的业务bean
@ComponentScan({"com.hyl.service"})
主配置类中引入Mybatis配置类
主配置类中读properties并引入数据源配置类
@PropertySource({"classpath:db.properties"}) @Import({JdbcConfig.class,MybatisConfig.class})

package com.hyl.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.PropertySource;

/**
 * @author hyl
 * @version 1.0
 * @date 2023/1/10-14:19
 */
@Configuration
@ComponentScan({"com.hyl.service"})
@PropertySource({"classpath:db.properties"})
@Import({JdbcConfig.class,MybatisConfig.class})
public class SpringConfig {

}

更多Mybatis搭建细节看这篇

https://blog.csdn.net/m0_58730471/article/details/128595925

4 事务搭建

4.1 在业务层需要被事务管理的方法上添加注解

注意:
@Transactional可以写在接口类上、接口方法上、实现类上和实现类方法上

写在接口类上,该接口的所有实现类的所有方法都会有事务
写在接口方法上,该接口的所有实现类的该方法都会有事务
写在实现类上,该类中的所有方法都会有事务
写在实现类方法上,该方法上有事务
建议写在实现类或实现类的方法上

给BookService接口添加@Transactional注解

package com.hyl.service;

import com.hyl.pojo.Book;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * @author hyl
 * @version 1.0
 * @date 2023/1/10-14:44
 */

@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);

    /**
     * 按name查询
     * @param input
     * @return
     */
    public List<Book> getByName(String input);

    /**
     * 查询全部
     * @return
     */
    public List<Book> getAll();
}

4.2 在JdbcConfig类中配置事务管理器

/**
* 配置事务管理器,mybatis使用的是jdbc事务
* @param dataSource
* @return
*/
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource){
DataSourceTransactionManager sourceTransactionManager=new DataSourceTransactionManager();
sourceTransactionManager.setDataSource(dataSource);
return sourceTransactionManager;
}

package com.hyl.config;

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Component;
import org.springframework.transaction.PlatformTransactionManager;

import javax.sql.DataSource;

/**
 * @author hyl
 * @version 1.0
 * @date 2023/1/10-14:18
 */
@Component
public class JdbcConfig {
    /**
     *从db.properties文件读取加载
     */

    @Value("${driver}")
    private String driver;
    @Value("${url}")
    private String url;
    @Value("${username}")
    private String username;
    @Value("${password}")
    private String password;

    /**
     * 获取数据源
     * @return
     */
    @Bean
    public DataSource dataSource(){
        DruidDataSource db=new DruidDataSource();
        db.setDriverClassName(driver);
        db.setUrl(url);
        db.setUsername(username);
        db.setPassword(password);
        return db;
    }

    /**
     * 配置事务管理器,mybatis使用的是jdbc事务
     * @param dataSource
     * @return
     */
    @Bean
    public PlatformTransactionManager transactionManager(DataSource dataSource){
        DataSourceTransactionManager sourceTransactionManager=new DataSourceTransactionManager();
        sourceTransactionManager.setDataSource(dataSource);
        return sourceTransactionManager;
    }
}

4.3 在SpringConfig类中开启事务注解

@EnableTransactionManagement

package com.hyl.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.PropertySource;
import org.springframework.transaction.annotation.EnableTransactionManagement;

/**
 * @author hyl
 * @version 1.0
 * @date 2023/1/10-14:19
 */
@Configuration
@ComponentScan({"com.hyl.service"})
@PropertySource({"classpath:db.properties"})
@Import({JdbcConfig.class,MybatisConfig.class})
@EnableTransactionManagement
public class SpringConfig {

}

更多事务细节看这篇(第6节 AOP事务管理)

https://blog.csdn.net/m0_58730471/article/details/127782322?spm=1001.2014.3001.5501

5 Rest风格简介

REST(Representational State Transfer),表现形式状态转换,它是一种软件架构风格
请求的方式比较多,但是比较常用的就4种,分别是GET,POST,PUT,DELETE

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

发送GET请求是用来做查询
发送POST请求是用来做新增
发送PUT请求是用来做修改
发送DELETE请求是用来做删除

例如:

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

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

REST的优点有:

  • 隐藏资源的访问行为,无法通过地址得知对资源是何种操作
  • 书写简化

那什么又是RESTful呢?

  • 根据REST风格对资源进行访问称为RESTful。

上述行为是约定方式,约定不是规范,可以打破,所以称REST风格,而不是REST规范

6 统一结果封装搭建

6.1 在Controller包下创建Result类

Result类名及类中的字段并不是固定的,可以根据需要自行增减提供若干个构造方法,方便操作。

package com.hyl.controller;

/**
 * @author hyl
 * @version 1.0
 * @date 2023/1/10-17:21
 */

public class Result {
    /**
     * 描述统一格式中的数据
     */
    private Object data;

    /**
     * 描述统一格式中的编码,用于区分操作,可以简化配置0或1表示成功失败
     */
    private Integer code;

    /**
     * 描述统一格式中的消息,可选属性
     */
    private String msg;

    public Result() {
    }

    public Result(Code code,Object data) {
        this.data = data;
        this.code = code.getCode();
    }

    public Result(Code code, Object data, String msg) {
        this.data = data;
        this.code = code.getCode();
        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;
    }
}

6.2 在Controller包下定义返回码Code枚举类

状态码都是自定义的,并不是规定都得这样写

package com.hyl.controller;

/**
 * @author hyl
 * @version 1.0
 * @date 2023/1/10-17:22
 * 状态码(枚举类)
 */

public enum Code {

    //保存成功
    SAVE_OK(20011),
    //删除成功
    DELETE_OK(20021),
    //更新成功
    UPDATE_OK(20031),
    //查询成功
    GET_OK(20041),
    //保存失败
    SAVE_ERR(20010),
    //删除失败
    DELETE_ERR(20020),
    //更新失败
    UPDATE_ERR(20030),
    //查询失败
    GET_ERR(20040),
    //系统异常
    SYSTEM_ERR(50001),
    //超时异常
    SYSTEM_TIMEOUT_ERR(50002),
    //未知异常
    SYSTEM_UN_KNOW_ERR(59999),
    //业务异常
    BUSINESS_ERR(60002);


    private Integer code;

    private Code(Integer code) {
        this.code = code;
    }

    public Integer getCode() {
        return code;
    }
}

6.3 实现的效果

在Controller包中返回结果(封装的Result对象处理成的json格式数据)就已经能以一种统一的格式返回给前端。前端根据返回的结果,先从中获取code,根据code判断,如果成功则取data属性的值,如果失败,则取msg中的值做提示。

最终无论操作处理成功或是失败,返回给前台的数据格式都如下所示

{
	"data":{"id":1,"type":"计算机理论","name":"Spring实战 第五版","description":"Spring入门经典教程,深入理解Spring原理技术内幕"},
	"code":20041,
	"msg":""
}

// data 携带数据
// code 是状态码
// msg 是信息

在这里插入图片描述

7 SpringMvc搭建

7.1 在controller包下创建控制器类

controller是表现层(写在该层下的BookController类就类似于javaweb阶段学习的servlet一样负责控制转发)
使用@RestController注解替换 @Controller、@ResponseBody注解,简化书写

package com.hyl.controller;

import com.hyl.pojo.Book;
import com.hyl.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/**
 * @author hyl
 * @version 1.0
 * @date 2023/1/10-10:34
 */
@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("/byName/{input}")
    public Result getByName(@PathVariable String input) {
        System.out.println("input="+input);
        List<Book> book = bookService.getByName(input);
        Code code = book != null ? Code.GET_OK : Code.GET_ERR;
        String msg = book != null ? "" : "数据查询失败,请重试!";
        return new Result(code,book,msg);
    }
    @GetMapping("/byId/{id}")
    public Result getById(@PathVariable Integer id){
        System.out.println("id="+id);
        Book book = bookService.getById(id);
        Code 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();
        Code code = bookList != null ? Code.GET_OK : Code.GET_ERR;
        String msg = bookList != null ? "" : "数据查询失败,请重试!";
        return new Result(code,bookList,msg);
    }

}

7.2 在controller包下创建Tomcat的Servlet容器配置类ServletContainersInitConfig

package com.hyl.config;

import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

import javax.servlet.Filter;

/**
 * @author hyl
 * @version 1.0
 * @date 2023/1/9-14:10
 * 定义servlet容器的配置类
 */

public class ServletContainersInitConfig 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[]{"/"};
    }

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

}

7.3 在controller包下创建静态资源放行类SpringMvcSupport

前端页面访问
静态资源会被SpringMVC拦截
我们在Servlet容器配置类中写的是拦截所有资源请求

在这里插入图片描述

package com.hyl.config;

import com.hyl.controller.interceptor.ProjectInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

/**
 * @author hyl
 * @version 1.0
 * @date 2023/1/10-11:00
 */
@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {

    @Autowired
    private ProjectInterceptor projectInterceptor;

    /**
     * 设置静态资源访问过滤,当前类需要设置为配置类,并被扫描加载
     * @param registry
     */
    @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/");

        // 解决该警告 No mapping for GET /favicon.ico
        registry.addResourceHandler("/**").addResourceLocations("classpath:/static/");
    }


}

7.4 在controller包下创建SpringMvcConfig配置类

扫描controller包下的XxxController类
扫描config包下的静态资源放行类
@ComponentScan({"com.hyl.controller","com.hyl.config"})

package com.hyl.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;

/**
 * @author hyl
 * @version 1.0
 * @date 2023/1/9-14:05
 */
@Configuration
@ComponentScan({"com.hyl.controller","com.hyl.config"})
@EnableWebMvc
public class SpringMvcConfig {

}

8 统一异常处理搭建

8.1 异常的种类及出现异常的原因:

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

看完上面这些出现异常的位置,你会发现,在我们开发的任何一个位置都有可能出现异常,而且这些异常是不能避免的。所以我们就得将异常进行处理。

思考:

  1. 各个层级均出现异常,异常处理代码书写在哪一层?
    所有的异常均抛出到表现层进行处理
  2. 异常的种类很多,表现层如何将所有的异常都处理到呢?
    异常分类
  3. 表现层处理异常,每个方法中单独书写,代码书写量巨大且意义不强,如何解决?
    AOP

对于上面这些问题及解决方案,SpringMVC已经为我们提供了一套解决方案:
异常处理器:集中的、统一的处理项目中出现的异常。

例如:

//@RestControllerAdvice用于标识当前类为REST风格对应的异常处理器
@RestControllerAdvice
public class ProjectExceptionAdvice {
    //除了自定义的异常处理器,保留对Exception类型的异常处理,用于处理非预期的异常
    @ExceptionHandler(Exception.class)
    public Result doException(Exception ex){
      	System.out.println("异常已捕获!")
        return new Result(666,null,"后台出异常了!");
    }
}

8.2 异常的分类和处理

因为异常的种类有很多,如果每一个异常都对应一个@ExceptionHandler,那得写多少个方法来处理各自的异常,所以我们在处理异常之前,需要对异常进行一个分类:

  • 业务异常(BusinessException)

规范的用户行为产生的异常
用户在页面输入内容的时候未按照指定格式进行数据填写,如在年龄框输入的是字符串
不规范的用户行为操作产生的异常
如用户故意传递错误数据

  • 系统异常(SystemException)

项目运行过程中可预计但无法避免的异常
比如数据库或服务器宕机

  • 其他异常(Exception)

编程人员未预期到的异常,如:用到的文件不存在

将异常分类以后,针对不同类型的异常,要提供具体的解决方案

8.3 自定义异常类

自定义异常类

  • 让自定义异常类继承RuntimeException的好处是,后期在抛出这两个异常的时候,就不用在try…catch…或throws了
  • 自定义异常类中添加code属性的原因是为了更好的区分异常是来自哪个业务的

在exception包下创建系统异常业务异常自定义异常类

SystemException.java

package com.hyl.exception;

import com.hyl.controller.Code;

/**
 * @author hyl
 * @version 1.0
 * @date 2023/1/10-17:52
 * 自定义异常处理器,用于封装异常信息,对异常进行分类
 */


public class SystemException extends RuntimeException{
    private Code code;

    public Code getCode() {
        return code;
    }

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

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

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

}

BusinessException.java

package com.hyl.exception;

import com.hyl.controller.Code;

/**
 * @author hyl
 * @version 1.0
 * @date 2023/1/10-17:53
 * 自定义异常处理器,用于封装异常信息,对异常进行分类
 */

public class BusinessException extends RuntimeException{
    private Code code;

    public Code getCode() {
        return code;
    }

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

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

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

}

8.5 在异常处理器类中处理异常

package com.hyl.controller;

import com.hyl.exception.BusinessException;
import com.hyl.exception.SystemException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

/**
 * @author hyl
 * @version 1.0
 * @date 2023/1/10-18:50
 * @RestControllerAdvice 用于标识当前类为REST风格对应的异常处理器
 */


@RestControllerAdvice
public class ProjectExceptionAdvice {
    /**
     * @ExceptionHandler 用于设置当前处理器类对应的异常类型
     * @param ex
     * @return
     */
    @ExceptionHandler(SystemException.class)
    public Result doSystemException(SystemException ex){
        //记录日志 (略)
        //发送消息给运维 (略)
        //发送邮件给开发人员,ex对象发送给开发人员 (略)
        return new Result(ex.getCode(),null,ex.getMessage());
    }

    /**
     * 自定义的业务异常
     * @param ex
     * @return
     */
    @ExceptionHandler(BusinessException.class)
    public Result doBusinessException(BusinessException ex){
        return new Result(ex.getCode(),null,ex.getMessage());
    }

    /**
     * 除了自定义的异常处理器,保留对Exception类型的异常处理,用于处理非预期的异常
     * @param ex
     * @return
     */
    @ExceptionHandler(Exception.class)
    public Result doOtherException(Exception ex){
        //记录日志 (略)
        //发送消息给运维 (略)
        //发送邮件给开发人员,ex对象发送给开发人员 (略)
        return new Result(Code.SYSTEM_UN_KNOW_ERR,null,"系统繁忙,请稍后再试!");
    }
}

在这里插入图片描述

关于更多异常细节看这篇(第3节,统一异常处理)

https://blog.csdn.net/m0_58730471/article/details/128611244?spm=1001.2014.3001.5501

9 拦截器搭建

拦截器(Interceptor)是一种动态拦截方法调用的机制,在SpringMVC中动态拦截控制器方法的执行
作用:

  • 在指定的方法调用前后执行预先设定的代码
  • 阻止原始方法的执行

总结:拦截器就是用来做增强

这个时候,就有一个问题需要思考:拦截器和过滤器之间的区别是什么?

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

在这里插入图片描述

9.1 在controller包下创建拦截器类

在controller包下创建interceptor包,在interceptor包下创建拦截器类,让类实现HandlerInterceptor接口,重写接口中的三个方法。

package com.hyl.controller.interceptor;

import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author hyl
 * @version 1.0
 * @date 2023/1/11-12:02
 * 定义拦截器类,实现HandlerInterceptor接口
 * 当前类必须受Spring容器控制
 */

@Component
public class ProjectInterceptor implements HandlerInterceptor {
    /**
     * 原始方法调用前执行的内容
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle...");
        return true;
    }

    /**
     * 原始方法调用后执行的内容
     * @param request
     * @param response
     * @param handler
     * @param modelAndView
     * @throws Exception
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle...");
    }

    /**
     * 原始方法调用完成后执行的内容
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion...");
    }
}

拦截器类要被SpringMVC容器配置类SpringMvcConfig扫描到
而我们的拦截器写在controller包下的interceptor包中
@ComponentScan({"com.hyl.controller","com.hyl.config"})正好可以扫描到
在这里插入图片描述

package com.hyl.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;

/**
 * @author hyl
 * @version 1.0
 * @date 2023/1/9-14:05
 */
@Configuration
@ComponentScan({"com.hyl.controller","com.hyl.config"})
@EnableWebMvc
public class SpringMvcConfig {

}

9.2 在config包下的SpringMvcSupport类中配置拦截器bean

/**
* 配置拦截器
* @param registry
/
@Override
protected void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(projectInterceptor).addPathPatterns(“/books”,“/books/*”,"/books/*/
" );
}

package com.hyl.config;

import com.hyl.controller.interceptor.ProjectInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

/**
 * @author hyl
 * @version 1.0
 * @date 2023/1/10-11:00
 */
@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {

    @Autowired
    private ProjectInterceptor projectInterceptor;

    /**
     * 设置静态资源访问过滤,当前类需要设置为配置类,并被扫描加载
     * @param registry
     */
    @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/");

        // 解决该警告 No mapping for GET /favicon.ico
        registry.addResourceHandler("/**").addResourceLocations("classpath:/static/");
    }

    /**
     * 配置拦截器
     * @param registry
     */
    @Override
    protected void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*","/books/*/*" );
    }
}

在这里插入图片描述

当有拦截器后,请求会先进入preHandle方法,
如果方法返回true,则放行继续执行后面的handle[controller的方法]和后面的方法
​如果返回false,则直接跳过后面方法的执行。

关于拦截器更多细节看这篇(第5节,拦截器)

https://blog.csdn.net/m0_58730471/article/details/128611244?spm=1001.2014.3001.5501

10 结合前端页面实现简单(增删改查)

初始化查全表

在这里插入图片描述

添加图书(增)

在这里插入图片描述

修改图书信息(改)

在这里插入图片描述

删除(删)

在这里插入图片描述

模糊查询(查)

在这里插入图片描述

11 注解汇总

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/156257.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

很多人还不知道中视频计划手机上发布多端横竖屏视频的方法

如果说你刚开始接触中视频&#xff0c;你必须要学会的小知识。 横屏视频是16&#xff1b;9的视频&#xff0c;一般是手机横向拍摄的视频。 上传这样的视频有两种方法。第一种是需要用到电脑&#xff0c;第二种就是我今天要分享的这种&#xff0c;没有电脑&#xff0c;我们用手…

测试新人入职第一天都做什么?

测试入职第一天都做什么&#xff1f; 大家都知道&#xff0c;入职一家新公司就是一个新的起点&#xff0c;新的开始。不管在之前公司干了多久&#xff0c;还是第一次踏入社会进入企业上班&#xff0c;都需要遵守新公司的规则以及规章制度。不管企业的规章制度是什么&#xff0…

前端提交信息规范 commit规范 commitlint husky commitizen

前端提交规范 约定式提交约定式提交安装commitizen 及其适配器husky commitlint 提交校验至此恭喜你已经配置好提交校验了&#xff0c;快去试试吧技术同学开发中有没有出现 &#xff1a; 因某种原因当需要回滚&#xff0c;这时候一看之前提交的massage真的乌烟瘴气 无法分辨回…

使用ResNet50实现CIFAR100数据集的训练

如果对你有用的话&#xff0c;希望能够点赞支持一下&#xff0c;这样我就能有更多的动力更新更多的学习笔记了。&#x1f604;&#x1f604; 使用ResNet进行CIFAR-10数据集进行测试&#xff0c;这里使用的是将CIFAR-10数据集的分辨率扩大到32X32&#xff0c;因为算力相关的…

蓝桥杯2019年第十届省赛C++B组

文章目录A&#xff1a;组队&#xff08;5分 √&#xff09;B&#xff1a;年号字串&#xff08;5分 √&#xff09;C: 数列求值&#xff08;10分 √&#xff09;D: 数的分解&#xff08;10分 &#xff09;F: 特别数的和&#xff08;15分 √&#xff09;A&#xff1a;组队&#x…

【蓝桥杯简单篇】Python组刷题日寄Part05

刷题日记&#xff1f;刷题日寄&#xff01; 萌新备战蓝桥杯python组 &#x1f339; 发现有需要纠正的地方&#xff0c;烦请指正&#xff01; &#x1f680; 欢迎小伙伴们的三连关注&#xff01; 往期系列&#xff1a; 【蓝桥杯简单篇】Python组刷题日寄Part01 【蓝桥杯简单篇】…

Oracle Mysql审计日志等保测评

mysql oracle的审计日志 mysql的审计日志说是有两种方法&#xff0c;一种是需要安装插件模式的审计&#xff0c;一种直接开一个参数 1.安装插件模式 一、 mysql 日志 配置永久配置 &#xff1a; 保存时间及大小 https://blog.csdn.net/m0_51197424/article/details/12432840…

设计模式(二)----软件设计原则

在软件开发中&#xff0c;为了提高软件系统的可维护性和可复用性&#xff0c;增加软件的可扩展性和灵活性&#xff0c;要尽量根据7条原则来开发程序&#xff0c;从而提高软件开发效率、节约软件开发成本和维护成本。 1、单一职责原则 ( 核心&#xff1a;尽量保证类&#xff0…

毫米波雷达和视觉融合的学习路线

了解各个传感器的成像原理&#xff0c;知其所以然&#xff0c;同时了解每种传感器的对比及优缺点&#xff0c;为什么要用这几种融合&#xff0c;可以通过去看一些德州仪器的雷达原理视频&#xff08;b站&#xff09;&#xff0c;雷达工作手册等。先广而后深&#xff1a;了解经典…

C#-WPF介绍-创建项目-添加按钮等及其事件处理、属性设置

微软官网指导链接&#xff1a;适用于 .NET 5 的 Windows Presentation Foundation 文档 | Microsoft Learn WPF框架介绍&#xff1a;Windows Presentation Foundation 简介 - WPF .NET | Microsoft Learn WPF介绍 WPF&#xff08;Windows Presentation Foundation&#xff09…

python3在window上运行或安装模块各种问题

1. 在window上运行celery各种奇怪的问题 如出现错误&#xff1a; ValueError: not enough values to unpack (expected 3, got 0) 请先安装如下模块 pip install eventlet 启动时&#xff0c;带上改模块&#xff0c;指定为运行参数 celery -A tasks worker --loglevelinfo -P …

基于小程序云开发的智慧物业、智慧小区微信小程序,在线报修报检,重大事项投票,报名参加小区活动,小区公告通知,业委会公示、租售房屋

功能介绍 完整代码下载地址&#xff1a;基于小程序云开发的智慧物业、智慧小区微信小程序 当前小区的物业事务越来越多、越来越杂&#xff0c;而很多业主工作繁重&#xff0c;加班很晚&#xff0c;以往对于重大事项投票&#xff0c;报修报检&#xff0c;装修申请&#xff0c;…

大数据技术之SparkSQL(超级详细)

第1章 Spark SQL概述 1.1什么是Spark SQL Spark SQL是Spark用来处理结构化数据的一个模块&#xff0c;它提供了2个编程抽象&#xff1a;DataFrame和DataSet&#xff0c;并且作为分布式SQL查询引擎的作用。 它是将Hive SQL转换成MapReduce然后提交到集群上执行&#xff0c;大大…

易盾滑块再再再试

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录前言文章推荐自己的坑js部分效果展示前言 声明&#xff1a;本文只作学习研究&#xff0c;禁止用于非法用途&#xff0c;否则后果自负&#xff0c;如有侵权&#xff…

php宝塔搭建部署实战响应式自动化设备科技企业网站源码

大家好啊&#xff0c;我是测评君&#xff0c;欢迎来到web测评。 本期给大家带来一套php开发的响应式自动化设备科技企业网站源码&#xff0c;感兴趣的朋友可以自行下载学习。 技术架构 PHP7.2 nginx mysql5.7 JS CSS HTMLcnetos7以上 宝塔面板 文字搭建教程 下载源码&…

我眼中的偶数数据库 OushuDB

各位大家好&#xff0c;在论坛跟大家学习也有一段时间了&#xff0c;今天来聊聊我眼中的偶数数据库 &#xff5e; 首先&#xff0c;先来介绍介绍我和偶数的故事&#xff08;其实没有什么故事&#xff0c;只是一些交集片段&#xff09;。 2015 年我开始接触 Greenplum&#xf…

Spring Boot 配置文件

Spring Boot 配置文件一、配置文件作用二、配置文件的格式三、properties 配置文件说明3.1 properties 基本语法3.2 读取配置文件3.3 properties 优缺点分析四、yml 配置文件说明4.1 yml 优点分析4.2 yml 基本语法4.3 yml 基本配置读取4.4 配置对象与读取4.5 配置集合与读取五、…

时序预测 | Python实现XGBoost极限梯度提升树股票价格预测

时序预测 | Python实现XGBoost极限梯度提升树股票价格预测 目录 时序预测 | Python实现XGBoost极限梯度提升树股票价格预测预测效果基本描述环境配置模型描述程序设计参考资料预测效果 基本描述 Python实现XGBoost极限梯度提升树股票价格预测 环境配置 XGboost (0.7) numpy (1.…

负载均衡器Ribbon原理及实战演练

目录 一、负载均衡原理 二、Ribbon 原理及使用 三、Loadbalancer 原理及使用 负载均衡器Ribbon在微服务领域是很常用的服务调用、负载均衡的中间件,其面包含Loadbalancer专门负载负载均衡&#xff1b;比如Eureka、Fegin,Nacos的注册中心jar包里面均包含Ribbon相关的jar,如图…

python实战案例:采集某漫客《网游之近战法师》所有章节

前言 嗨喽~大家好呀&#xff0c;这里是魔王呐 ❤ ~! 环境使用: Python 3.8 Pycharm 模块使用: requests >>> pip install requests 数据请求模块 parsel >>> pip install parsel 数据解析模块 如果安装python第三方模块: win R 输入 cmd 点击确定, 输…