SpringMvc+Spring+Mybatis整合+RESTFUl+异常处理

SSM开发基础案例

包结构

config
dao
service
controller
domain
exception (异常类)

resource———》 jdbc.properties


环境搭建

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.SpringMvcSum</groupId>
<artifactId>SpringMvcSum</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>

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

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

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

<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>

<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.0</version>
</dependency>

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

<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>

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

<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-to-slf4j</artifactId>
<version>2.11.2</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>
<path>/</path>
</configuration>
</plugin>
</plugins>
</build>

</project>

Config:
SpringConfig:


@Configuration
@ComponentScan("com.it.service")
@PropertySource("classpath:jdbc.properties")
@Import({JdbcConfig.class,MybatisConfig.class})
public class SpringConfig {
}

Spring整合Mybatis:

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

MybatisConfig:

public class MybatisConfig {

@Bean
public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource) {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dataSource);
factoryBean.setTypeAliasesPackage("com.it.domain");
return factoryBean;
}

@Bean
public MapperScannerConfigurer mapperScannerConfigurer() {
MapperScannerConfigurer msc = new MapperScannerConfigurer();
msc.setBasePackage("com.it.dao");
return msc;
}
}

resources:
jdbc.properties:

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ssm_db
jdbc.username=root
jdbc.password=1234

SpringMvcConfig:

@Configuration
@EnableWebMvc
@ComponentScan("com.it.controller")
@EnableTransactionManagement //SpringMvc开启事务
public class SpringMvcConfig {
}

ServletConfig:替代web.xml

public class ServletConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
protected Class<?>[] getRootConfigClasses() {
return new Class[]{SpringConfig.class};
}

protected Class<?>[] getServletConfigClasses() {
return new Class[]{SpringMvcConfig.class};
}

protected String[] getServletMappings() {
return new String[]{"/"}; //拦截所有
}


//这里可以添加一个过滤器,用来设置字符集编码
}

基础案例

dao:
BookDao:

public interface BookDao {

@Insert("insert into tbl_book values(null,#{type},#{name},#{description})")
public void save(Book book);

@Update("update tbl_book set type=#{type},name=#{name},description=#{description} where id=#{id}")
public void update(Book book);

@Delete("delete from tbl_book where id = #{id}")
public void delete(Integer id);

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

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

service:
BookService:

@Transactional //开启事务 一般情况下 都在业务层接口开启事务
public interface BookService {

/**
* 保存,添加
* @param book 添加的图书信息
* @return 返回布尔型,表示该操作成功与否
*/
public boolean save(Book book);

/**
* 更新,修改
* @param book 更新的图书信息
* @return 返回布尔型,表示该操作成功与否
*/
public boolean update(Book book);

/**
* 删除
* @param id 要删除的id号
* @return 返回布尔型,表示该操作成功与否
*/
public boolean delete(Integer id);

/**
* 查询所有
* @return 返回一个集合 集合中包括所有书籍信息
*/
public List<Book> getAll();

/**
* 通过id查询一本图书
* @param id 图书id
* @return 返回一本图书信息
*/
public Book getByid(Integer id);
}

BookServiceImpl:

@Service
public class BookServiceImpl implements BookService {
@Autowired //这里使用dao层接口,使用spring自动注入
private BookDao bookDao;

public boolean save(Book book) {
bookDao.save(book);
return true;
}

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

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

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

public Book getByid(Integer id) {
//模拟异常
if(id==1){
throw new BusinessException(Code.BUSINESS_ERR,"异常出现的消息提示");
}

//将可能出现的异常进行包装,转换成自定义异常
try {
int i = 1/0;
} catch (Exception e) { // throw语句通常用在方法体中,并且抛出一个异常对象。程序在执行到throw语句时立即停止,它后面的语句都不执行
throw new SystemException(Code.SYSTEM_ERR,"服务器超时,请重试",e);
}

return bookDao.getByid(id);
}
}

controller:
BookController:

@RestController
@RequestMapping("/books")
@ResponseBody
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
public Result getAll() {
List<Book> books = bookService.getAll();
Integer code = books != null ? Code.GET_OK : Code.GET_ERR;
String msg = books != null ? "查询成功" : "数据查询失败,请重试";
return new Result(code, books, msg);
}

@GetMapping("/{id}")
public Result getByid(@PathVariable Integer id) {


Book book = bookService.getByid(id);
Integer code = book != null ? Code.GET_OK : Code.GET_ERR;
String msg = book != null ? "查询成功" : "数据查询失败,请重试";
return new Result(code, book, msg);
}
}

由于前端人员看到异常信息的多样性和复杂性,我们后端给予处理,在表现层将所有调用业务层处理后的数据统一返回一个格式,方便前端人员处理,所以我们定义一个类,用来做为统一返回的类型格式(在实际开发中,返回的类型可能不止这些,根据业务需求而定,这里只简单的举例,思想是一样的,应该学会灵活运用)

没有经过处理的异常信息:
在这里插入图片描述

Result:

public class Result {

private Object data;//返回的结果数据

private Integer code;  //返回的状态码

private String msg; //返回的提示信息

public Result( Integer code,Object data, String msg) {
this.data = data;  
this.code = code; 
this.msg = msg; 
}

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

public Result() { }

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

由于状态码直接使用数字写在程序中不够专业,这里编写一个对象,用来存放这些状态码,并且将它们设置为静态常量这样在使用时,可以不创建对象,直接通过 对象.常量名 进行访问

Code:根据需求持续添加状态码,可以无数多

public class Code {

//增删改查状态码
public static final Integer SAVE_OK =2011;
public static final Integer DELETE_OK =2021;
public static final Integer UPDATE_OK =2031;
public static final Integer GET_OK =2041;
//失败
public static final Integer SAVE_ERR =2000;
public static final Integer DELETE_ERR =2020;
public static final Integer UPDATE_ERR =2030;
public static final Integer GET_ERR =2040;

//系统异常
public static final Integer SYSTEM_ERR = 50001;
//业务异常
public static final Integer BUSINESS_ERR = 60002;
//系统位置异常
public static final Integer SYSTEM_UNKONW_ERR = 59999;
}

前面是解决表现层返回值类型问题,我们进行了统一的要求。但在实际开发过程中,在前端中返回的结果可能会出现异常信息,所以我们应该定义一个异常处理器,用来拦截异常信息,并将异常信息封装为上面统一的格式,方便前端人员辨别和处理。

ProjectExceptionAdvice:异常拦截器,用户的异常信息会被该拦截器拦下,并进行分类(业务异常,系统异常,其它异常等)处理

/**
* 异常处理器类
*/
@RestControllerAdvice //advice:通知
public class ProjectExceptionAdvice {

/**
* 系统异常处理:应记录相关的异常信息,让运维和开发解决
* @param ex 异常参数
* @return 返回异常状态码,提示信息
*/
@ExceptionHandler(SystemException.class) // 异常处理器 拦截System异常
public Result doSystemException(SystemException ex) { //收集异常的方法
//记录日志
//发送消息给运维
//发送邮件给开发人员
return new Result(ex.getCode(), null, ex.getMessage());

}

/**
* 业务层异常:由于用户输入了不规范的数据导致,直接返回异常信息即可
* @param ex
* @return
*/
@ExceptionHandler(BusinessException.class) // 异常处理器 拦截Business异常
public Result doBusinessException(BusinessException ex) { //收集异常的方法
return new Result(ex.getCode(), null, ex.getMessage());

}

/**
* 其他异常
* @param ex
* @return
*/
@ExceptionHandler(Exception.class) // 异常处理器 拦截所有异常
public Result doException(Exception ex) { //收集异常的方法 所有异常都会进来
//记录日志
//发送消息给运维
//发送邮件给开发人员
return new Result(Code.SYSTEM_UNKONW_ERR, null, "系统繁忙,请稍后再试!");
}
}

下面定义了系统异常和业务异常,除此之外的异常统一为其它异常

exception:
SystemException:

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

BusinessException:

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

异常定义完之后,可以在合适的地方抛出异常,异常会被拦截器拦截并分类处理,最终返回给前端

模拟异常抛出:

if(id==1){
throw new BusinessException(Code.BUSINESS_ERR,"异常出现的消息提示");  //抛出业务异常
}

结果:
在这里插入图片描述

//将可能出现的异常进行包装,转换成自定义异常
try {
int i = 1/0;
} catch (Exception e) { // throw语句通常用在方法体中,并且抛出一个异常对象。程序在执行到throw语句时立即停止,它后面的语句都不执行
throw new SystemException(Code.SYSTEM_ERR,"服务器超时,请重试",e);  //抛出系统异常
}

结果:

在这里插入图片描述

测试表现层正常情况下的返回值:

在这里插入图片描述
提示:该文章为学习笔记,如有错误,望大佬批评指正,留言必回

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值