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=utf8INSERT  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;}@Overridepublic 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 {@Autowiredprivate BookDao bookDao;@Overridepublic boolean save(Book book) {return bookDao.save(book)>0;}@Overridepublic boolean update(Book book) {return bookDao.update(book)>0;}@Overridepublic boolean delete(Integer id) {return bookDao.delete(id)>0;}@Overridepublic Book getById(Integer id) {return bookDao.getById(id);}@Overridepublic List<Book> getByName(String input) {return bookDao.getByName(input);}@Overridepublic 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*/@Beanpublic 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对象*/@Beanpublic 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*/@Beanpublic 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*/@Beanpublic 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*/@Beanpublic 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 {@Autowiredprivate BookService bookService;@PostMappingpublic Result save(@RequestBody Book book) {boolean flag = bookService.save(book);return new Result(flag ? Code.SAVE_OK:Code.SAVE_ERR,flag);}@PutMappingpublic 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);}@GetMappingpublic 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 {@Overrideprotected Class<?>[] getRootConfigClasses() {return new Class[]{SpringConfig.class};}@Overrideprotected Class<?>[] getServletConfigClasses() {return new Class[]{SpringMvcConfig.class};}@Overrideprotected String[] getServletMappings() {return new String[]{"/"};}/***乱码处理*/@Overrideprotected 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 {@Autowiredprivate ProjectInterceptor projectInterceptor;/*** 设置静态资源访问过滤,当前类需要设置为配置类,并被扫描加载* @param registry*/@Overrideprotected 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.icoregistry.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*/@Overridepublic 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*/@Overridepublic 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*/@Overridepublic 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 {@Autowiredprivate ProjectInterceptor projectInterceptor;/*** 设置静态资源访问过滤,当前类需要设置为配置类,并被扫描加载* @param registry*/@Overrideprotected 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.icoregistry.addResourceHandler("/**").addResourceLocations("classpath:/static/");}/*** 配置拦截器* @param registry*/@Overrideprotected 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 注解汇总

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

  1. 基于SSM的家校通系统(Spring+SpringMVC+Mybatis+mysql)

    这是一基于SSM框架开发的家校通. 源代码: 基于SSM的家校通系统(Spring+SpringMVC+Mybatis+mysql).zip-Java文档类资源-CSDN下载这是一基于SSM(spri ...

  2. SSM整合——Spring+SpringMVC+MyBatis整合

    文章目录 1. 数据库环境 2. 项目基本结构搭建 3. 配置MyBatis 4. 配置Spring 5. 配置SpringMVC 6. Controller和视图层编写 7. 配置Tomcat,进行 ...

  3. 基于ssm的志愿者管理系统(idea+spring+springmvc+mybatis+jsp)

    一.系统简介 本项目采用idea工具开发,jsp+spring+spring-mvc+mybatis+jquery技术编写,数据库采用的是mysql,navicat开发工具. 系统一共分为4个角色分别 ...

  4. MAVEN整合Spring+SpringMVC+Mybatis

    2016/1/20 14:47:28 原创,转载请注明出处 曾经看过<那些年我们一起追过的女孩>,片中有个比较经典的画面,至今记忆犹新,柯景腾多年后,做了一名作家,每天面对电脑码字,背后是 ...

  5. 基于SSM的台球室俱乐部管理系统Spring+SpringMVC+MyBatis

    摘 要 随着科学技术的不断提高,计算机科学与技术日趋成熟,计算机应用到生产和生活的各个领域,发挥了越来越重要的作用.作为计算机应用的一部分,使用计算机对理发店信息进行管理,具有手工操作无法比拟的优点, ...

  6. Spring+SpringMVC+MyBatis整合基础篇

    基础篇 Spring+SpringMVC+MyBatis+easyUI整合基础篇(一)项目简介 Spring+SpringMVC+MyBatis+easyUI整合基础篇(二)牛刀小试 Spring+S ...

  7. 【Spring+SpringMVC+Mybatis】利用SSM整合,完成用户登录、注册、修改密码系统

    近年来,由于Struts2+Hibernate3+Spring3,这套SSH框架,Struts2屡次爆出安全漏洞,Hibernate就只会推行它HQL那套而越来越远离SQL查询关系数据库的本质,所以S ...

  8. Maven整合SSM框架(maven+spring+springmvc+mybatis)

    啊哈,终于到了用Maven整合SSM这个扑街含家产了.弄了整整一天才跑通.Mybatis的配置有些繁琐,跟之前学习的那个有点出去,加上Eclipse的Spring工具没有弄,配置的时候没有提示被搞蒙圈 ...

  9. SSM(Spring+SpringMVC+Mybatis)框架环境搭建(整合步骤)(一)

    SSM(Spring+SpringMVC+Mybatis)框架环境搭建(整合步骤)(一) 1. 前言 最近在写毕设过程中,重新梳理了一遍SSM框架,特此记录一下. 附上源码:https://gitee ...

最新文章

  1. 这所双一流高校“研究生取消寒假”?!学校回应:系个别实验室和导师的要求...
  2. python字典按value逆序排序_python 对字典按照value进行排序的方法
  3. 【API知识】ElementUI一些问题的解决方案
  4. python官网怎么下载-python下载官网
  5. ant安装过程,配置过程
  6. 基于Java的RDMA高性能通信库(四):DaRPC
  7. Spring Cloud Gateway的全局异常处理
  8. Python学习笔记:Day 12 编写日志列表页
  9. 生产环境部署python代码(django+uwsgi+nginx)
  10. Java进阶:java字符串定位语句
  11. 信息学奥赛一本通(1195:判断整除)
  12. Oracle 20c 新特性:原生的 JSON 数据类型(Native JSON Datatype)
  13. jupyter配置不同的conda环境
  14. 好好编程-物流项目02【tomcat插件启动web项目】
  15. 小米8的usb计算机连接不上,小米手机usb已连接电脑不显示怎么办
  16. 微信小程序实现tab切换
  17. SLAM十四讲第三讲实践:useGeometry------小白强行读代码
  18. linux不能删除文件命令,无法删除文件的解决办法(rm命令的使用)
  19. Java 序列化详解
  20. LETO型空间光调制器(SLM)的安装

热门文章

  1. 百度莱茨狗刚出就有人卖到了1W+!4只百度狗领养指南及运营解析!
  2. 对比Excel,轻松学习 Python 报表自动化实战!
  3. 大学生学完Python靠几个接单网站兼职,实现经济独立,这不香吗?
  4. 在热闹非凡的AI时代,你能分清人类智力与人工智能吗?
  5. 基于NC633的移动审批开发(剔除某云)
  6. 计算机考研 程序设计题,计算机考研统考历年真题程序设计详尽解析
  7. 《音乐达人秀:Adobe Audition实战200例》——1.2 从双卡录音机到多轨录音软件
  8. 没计算机基础,就是评职称用的,软考中级哪个好考啊?
  9. 【ShaderToy】边栏的小雨伞
  10. android NE 分析