总体的ssm整合增删改查的思想:

1、一般我们做增删改查的项目的时候,我们可以先从数据层开始写,在数据层把增删改查的功能方法写好,然后再写业务逻辑层的逻辑,业务逻辑层接口的代码基本上和数据层的没什么区别,在业务层增删改查方法中加上和数据层的依赖关系,最后再在表现层加上和业务层的依赖,那么就是说当客户访问表现层的增删改查方法的时候,因为与业务层添加了依赖,那么就可以再调用业务层的增删改查方法,又因为业务层和数据层之间有依赖关系,所以最终就相当于调用了数据层的增删改查方法了~

(其实就是相互调用而已)

2、然后我们的增删改查功能返回的结果,前端肯定想要一眼就能知道访问增删改查的功能到底是否成功了,因此就需要我们把一些返回的数据封装到对象中然后响应给前端了(相当于说响应给前端POJO对象形式的数据),因此就用到了Code、Result类的作用了,下面代码有解释该两个类的作用

3、还要注意一点就是在增删改查功能的过程中,我们的项目难免会出现异常,但是出现异常后,我们不希望返回给前端的是一堆报错500然后一堆异常代码的数据,这样的话客户端就会蒙蔽了,我调用增删该查功能呢这返回的是什么玩意,因此就需要我们做异常的处理,下面代码有解释

4、还有就是客户端访问books.html的时候,因为我们tomcat服务器让客户端访问的路径全部交给springmvc处理了,而springmvc会把访问的books.html路径当成普通的get访问形式,因此在表现层找不到该路径资源,因此就报错了,所以我们希望走的是前端page包下的books.html 就需要我们设置拦截器了 (看restful笔记处理前端访问的那里)

项目总体布局格式如下所示:

 重点理解:

1、异常处理器

2、表现层返回到前端的数据形式(Code、Result类的作用)

3、拦截器

一、表现层代码

BookController:

package com.itheima.controller;

import com.itheima.domain.Book;
import com.itheima.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;

@RestController // 扫描bean的注解 and 响应给前端数据的注解之合
@RequestMapping("/books")   // 访问路径的注解
public class BookController {

    /**
     *  注入service业务逻辑层依赖,那么就可以调用业务层中对象的方法了,然而业务层中又有和数据层的依赖关系,
     *  因此最终调到了数据层的增删改查功能
     */
    @Autowired  // 自动装配处理依赖关系注解
    private BookService bookService;

    // 增
    @PostMapping    // REST风格访问路径Post动作注解
    public Result save(@RequestBody Book book) {   // @RequestBody注解:json5数据格式封装到book实体类中  // 把返回值类型设定为Result对象

        // 调用业务层的增加方法
        Boolean flag =bookService.save(book);  // 因为BookServiceImpl的save方法中已经把返回的true/false等返回过来了,所以这里保存成功的话,接收业务层返回的true
        return new Result(flag ?Code.SAVE_OK:Code.SAVE_ERR,flag);  // true的话相当于返回的是:(20011,true) 【注:走的是Result两个参数的构造方法】
        // 三元运算符:if flag为true,调用Code的SAVE_OK状态码进行传参
        //return new Result(flag ?Code.SAVE_OK:Code.SAVE_ERR,flag); 就相当于返回Result对象,后面的参数就是为属性赋的值,就相当于响应POJO类型数据
    }

    // 删
    @DeleteMapping(value = "/{id}")
    public Result delete(@PathVariable Integer id) {  // @PathVariable 注解的作用是为id赋上{id}的值   返回类型是Result对象

        // 调用业务层的删除方法
        boolean b = bookService.delete(id);
        return new Result(b? Code.DELETE_OK:Code.DELETE_ERR,b); // 注:这里就相当于往Result对象的属性中赋值,然后又因为方法类型是Result对象,
                                                                // 所以就是说把封装好数据的Result对象返回给前端(这个数据就是商量好的协议)

    }

    // 改
    @PutMapping
    public Result update(@RequestBody Book book) {

        // 调用业务层的修改方法
       boolean b = bookService.update(book);
       return new Result(b? Code.UPDATE_OK:Code.UPDATE_ERR,b);

    }

    // 通过id查询
    @GetMapping(value = "/{id}")
    public Result getById(@PathVariable Integer id) {

        // 调用业务层的通过id查询方法
        Book gs = bookService.getById(id);

        // 有可能通过id查询出来的没有数据,(比如说:数据库就id到5,而想查询id为6的数据,那么就会为null)
        Integer integer = gs != null ? Code.SELECT_OK : Code.SELECT_ERR;    // 如果不等于null SELECT_OK状态码
        String msg = gs != null ? "查询成功~" : "查询失败了~";

        return new Result(gs,integer,msg); // (数据,状态码,消息)

    }

    // 查询所有
    @GetMapping
    public Result getAll() {

        // 调用业务层的查询所有方法
        List<Book> all = bookService.getAll();
        // 判断查询出来的数据是否为null,有可能数据库是空的,所以要进行判断
        Integer code = all != null ? Code.SELECT_OK : Code.SELECT_ERR;// 查询出来的数据不为null时,把SELECT_OK状态码赋给code变量名(成功的状态码标识)
        String s = all != null ? "查询成功~" : "数据查询失败,请重试~";
        // (Object data, Integer code, String msg) 构造方法
        return new Result(all,code,s);

    }
}

注意1:

我们知道,客户端通过访问表现层BookController的增删改查的方法,
*          最终调用完增删改查方法拿到结果是我们返回的true或者false、要么就是查询出来的数据
*
*          前端人就开始找事了:说你返回给我的true到底是修改功能返回的true还是增加功能返回的true啊
*          所以为了解决事B,我们用一个类专门封装查询出来的数据,并且标记好状态码(比如1:表示成功,2:表示失败)
*
*          注意:该类的写法在实际开发中,是前后端商量出来的协议,就是说前后端程序员商量好后端的数据以什么样的格式返回给前端

Result类:

package com.itheima.controller;

/**
 *      分析该类的作用:
 *
 *          我们知道,客户端通过访问表现层BookController的增删改查的方法,
 *          最终调用完增删改查方法拿到结果是我们返回的true或者false、要么就是查询出来的数据
 *
 *          前端人就开始找事了:说你返回给我的true到底是修改功能返回的true还是增加功能返回的true啊
 *          所以为了解决事B,我们用一个类专门封装查询出来的数据,并且标记好状态码(比如1:表示成功,2:表示失败)
 *
 *          注意:该类的写法在实际开发中,是前后端商量出来的协议,就是说前后端程序员商量好后端的数据以什么样的格式返回给前端
 */
public class Result {

    private Object data;    // 封装结果数据 (用Object万能,返回给前端数据的时候,可以把表现层获取到的所有类型的数据,如Book类型、查询所有功能返回的List集合类型的数据,都可以封装到Object类型的属性当中)
    private Integer code;   // 标记状态码(比如1:表示成功,2:表示失败)
    private String msg;     // 消息(比如说:调用增删改查功能失败了,返回给前端一句话让前端知道失败了)

    /**
     *  直接把所有的构造方法写出来,用到哪种就直接用了,通过构造方法传参把传递的参数赋值到属性当中
     */

    public Result() {
    }

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

    public Result(String msg) {
        this.msg = msg;
    }

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

    // getter and setter方法
    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类:(专门存放字符标识的类)

package com.itheima.controller;


/**
 *      分析该类的作用:
 *           标记状态码(比如1:表示成功,2:表示失败)的类,( Result里面的 )
 *
 *           注意:这些状态码不是固定的,是实际开发中前端程序员和后端程序员商量好规定的一种状态信息,
 *           通过这些商量的状态码,就可以知道拿没拿到数据了
 *
 */
public class Code {

    /**
     *  调用增删改查功能成功的状态码标记
     *
     *  注:因为是static静态修饰的,所以可以直接用类名Code调用属性名
     *  public修饰:代表公共的(也就是说,任何包下的只要通过类名. 的方式都可以调取到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 SELECT_OK = 20041;

    /**
     *  调用增删改查功能失败的状态码标记
     */
    public static final Integer SAVE_ERR = 20010;
    public static final Integer DELETE_ERR = 20020;
    public static final Integer UPDATE_ERR = 20030;
    public static final Integer SELECT_ERR = 20040;


    /**
     *  系统异常 & 业务异常成功/失败状态码标记
     */
    public static final Integer SYSTEM_ERR =50001; // 出现系统异常状态码
    public static final Integer BUSINESS_ERR =60001;   // 出现业务异常状态码


}

客户端访问增加功能时,看返回给前端的信息(可以看出确实比true、false清晰多了):

二、异常处理器代码

* 异常处理器的作用就是:当客户端访问资源路径下的数据的时候,如果该资源路径下的程序出现了异常,那么客户端就会500然后就是一堆异常信息代码,那么客户端就会蒙蔽,我他妈查的是增删改查的功能,这返回的是什么玩意。

因此我们后端就需要异常处理器进行处理异常(忘记的话可以翻前面的笔记)

        而异常又分为:

                系统异常

                业务异常

                其他异常

假设模拟业务层通过id查询功能中出现了系统异常(也就是说:客户端正访问该资源路径下数据的时候,我们服务器宕机了,因此我们为了不直接返回给客户端一堆异常代码500,我们就需要处理系统异常):

package com.itheima.service.impl;

import com.itheima.controller.Code;
import com.itheima.dao.BookDao;
import com.itheima.domain.Book;
import com.itheima.exception.BusinessException;
import com.itheima.exception.SystemException;
import com.itheima.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;


@Service
public class BookServiceImpl implements BookService {

    /**
     *  注入dao数据层依赖 : private BookDao bookDao;
     *      然后等会spring容器拿到管理的业务层BookServiceImpl对象后,又因为业务层和数据层有依赖关系
     *      通过依赖关系就可以调用数据层的增删改查功能了
     */

    @Autowired // 自动装配(处理依赖关系)注解
    private BookDao bookDao;

    // 增
    public boolean save(Book book) {

        // 调用数据层的增加功能
        bookDao.save(book);
        return true;
    }

    // 删
    public boolean delete(Integer id) {

        // 调用数据层的删除功能
        bookDao.delete(id);
        return true;
    }

    // 改
    public boolean update(Book book) {

        // 调用数据层的修改功能
        bookDao.update(book);
        return true;
    }

    // 通过id查询
    public Book getById(Integer id) {

        /**
         *  模拟假定这个地方出现了 系统异常(比如说:程序运行到这里后服务器宕机了)
         *
         *      我们用 1/0来模拟:服务器宕机
         *
         */

        try {
            int i =1/0; // 模拟系统异常
        } catch (Exception e){
            throw new SystemException("服务器访问超时~",e, Code.SYSTEM_ERR);
            // 把想返回给前端的信息封装到SystemException对象的属性当中
            // Code.SYSTEM_ERR :系统异常状态码标识 50001
        }

        // 调用数据层的通过id查询功能
        Book books = bookDao.getById(id);
        return books;
    }

    // 查询所有
    public List<Book> getAll() {

        // 调用数据层的查询所有功能
        List<Book> list = bookDao.getAll();
        return list;
    }
}

 这里捕获到系统异常后,就要把想要返回给前端用户的提示信息封装到系统异常类当中,然后通过异常处理器进行系统异常的处理并且把封装在系统异常类属性中提示的信息响应给前端用户:

系统数据封装类:(该类的作用其实就是起到一个封装数据的作用)

SystemException:

package com.itheima.exception;

/**
 *  业务异常类
 *
 *  注:继承RuntimeException运行时异常类的目的就是运行时出现异常的时候不再手动往上抛了,自动帮我们往上抛
 *
 */
public class SystemException extends RuntimeException{

    private Integer code;    // 加个code编号属性,来标注以后出现的是哪一种异常

    /**
     *  把构造方法最好都写出来
     */

    public SystemException(Integer code) {
        this.code = code;
    }

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

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

    public SystemException(Throwable cause, Integer code) {
        super(cause);
        this.code = code;
    }

    public SystemException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace, Integer code) {
        super(message, cause, enableSuppression, writableStackTrace);
        this.code = code;
    }

    /**
     *  getter and setter方法
     */
    public Integer getCode() {
        return code;
    }

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

然后上面封装好数据后,就进入到异常处理器:

异常处理器:

        专门处理系统异常、业务异常、其他异常并且把封装的数据响应给前端用户

注: 通常使用异常处理器时:都会把系统异常处理方法、业务异常处理方法、其他异常处理方法全先写出来,然后项目中出现哪种形式的异常,异常处理器就直接可以进行处理了

ProjectExceptionAdvice: 

package com.itheima.controller;

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

/**
 *  spring处理异常 (异常处理器类)
 */

// @ControllerAdvice // 这是普通风格处理异常的注解 (只要访问路径用的不是REST风格就用这个注解)
@RestControllerAdvice   // 这是REST风格的处理异常的注解 (告诉spring这是一个处理异常的类的注解)
// 注1:这个@RestControllerAdvice注解需要被SpringMvcConfig类的@ComponentScan({"com.itheima.controller"})注解
// 扫描到,(SpringMvcConfig类的扫描注解刚好扫到controller包下,所以能扫到,因此如果换成其他的包,记得扫一下)

public class ProjectExceptionAdvice {

    /**
     *  注: 系统异常处理器
     *
     * @return: 返回给前端信息
     */

    @ExceptionHandler(SystemException.class)    // 该注解作用: 拦截是否是系统异常,是的话就调用下面的方法进行处理异常
    public Result doSystemException(SystemException sy){
            // (SystemException sy):把SystemException对象传递过来(因为刚才业务层模拟系统异常的时候,把返回给前端的信息封装到sy对象属性中了)
        /**
         *  拿到系统异常之后需要做以下几步骤:
         *  1、记录日志
         *  2、发送给运维,开发人员
         *  3、安抚一下客户(客户访问资源的时候出现异常了,咱们肯定要说一些好听的给用户)
         */

        return new Result(null,sy.getCode(), sy.getMessage());
        // 把封装到sy系统异常类属性中的系统异常状态码信息返回给用户
    }

    /**
     *  注: 业务异常处理器  (和系统异常处理器方式是一样的)
     *
     * @return: 返回给前端信息
     */

    @ExceptionHandler(BusinessException.class)   //  拦截是否是业务异常,是的话就调用下面的方法进行处理异常
    public Result doBusinessException(BusinessException bs){


        return new Result(null,bs.getCode(),bs.getMessage());
    }

    /**
     *  注: 其他异常处理器 (可以理解为除了业务异常和系统异常之外的所有异常)
     */

    @ExceptionHandler(Exception.class)    //  拦截是否是其他异常,是的话就调用下面的方法进行处理异常
    public Result doException(){

        return new Result(null,0,"出现异常了铁子~");
    }
}

 测试:

假设通过id查询的功能存在系统异常,与因为我们异常处理器处理该异常并且响应给前端相对应的数据了(比如:直接响应个服务器访问超时~),演示如下所示:(直接返回给客户端一些服务器访问超时信息什么的,而不是直接返回报错500然后一堆异常代码)

三、拦截器(看笔记)

SpringMvcSupport:

package com.itheima.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

/**
 *  用户访问地址过滤类 (看restful笔记处理前端访问的那里)
 */

@Configuration

public class SpringMvcSupport extends WebMvcConfigurationSupport {

    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry){
        // 意思就是说:当客户端访问/pages/**下的路径资源时,从/pages/包下开始走,不走Springmvc管理
        registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
        registry.addResourceHandler("/js/**").addResourceLocations("/js/");
        registry.addResourceHandler("/css/**").addResourceLocations("/css/");
        registry.addResourceHandler("/plugins/**").addResourceLocations("/plugins/");
    }
}

四、项目总代码

SpringConfig:

package com.itheima.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;

@Configuration  // spring容器注解
@ComponentScan({"com.itheima.service"}) // 扫描业务逻辑层service包下是否含有bean注解
@PropertySource({"classpath:jdbc.properties"})    // 配置加载jdbc.properties文件 使用$符获取数据(别忘记加classpath:)
@Import({jdbcConfig.class,MybatisConfig.class})

@EnableTransactionManagement    // 开启spring事务驱动的注解(因为是spring事务,所以在SpringConfig容器中配该注解)
public class SpringConfig {
}

SpringMvcConfig:

package com.itheima.config;

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

@Configuration
@ComponentScan({"com.itheima.controller","com.itheima.config"})  // 扫描表现层controller包下是否含有bean注解
// "com.itheima.config" 扫描的是前端访问页面被当成get方式然后出现错误
@EnableWebMvc   // json数据格式注解
public class SpringMvcConfig {
}

SpringMvcSupport:(过滤器类)

package com.itheima.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

/**
 *  用户访问地址过滤类 (看restful笔记处理前端访问的那里)
 */

@Configuration

public class SpringMvcSupport extends WebMvcConfigurationSupport {

    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry){
        // 意思就是说:当客户端访问/pages/**下的路径资源时,从/pages/包下开始走,不走Springmvc管理
        registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
        registry.addResourceHandler("/js/**").addResourceLocations("/js/");
        registry.addResourceHandler("/css/**").addResourceLocations("/css/");
        registry.addResourceHandler("/plugins/**").addResourceLocations("/plugins/");
    }
}

 4.1、表现层代码

BookController:

package com.itheima.controller;

import com.itheima.domain.Book;
import com.itheima.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;

@RestController // 扫描bean的注解 and 响应给前端数据的注解之合
@RequestMapping("/books")   // 访问路径的注解
public class BookController {

    /**
     *  注入service业务逻辑层依赖,那么就可以调用业务层中对象的方法了,然而业务层中又有和数据层的依赖关系,
     *  因此最终调到了数据层的增删改查功能
     */
    @Autowired  // 自动装配处理依赖关系注解
    private BookService bookService;

    // 增
    @PostMapping    // REST风格访问路径Post动作注解
    public Result save(@RequestBody Book book) {   // @RequestBody注解:json5数据格式封装到book实体类中  // 把返回值类型设定为Result对象

        // 调用业务层的增加方法
        Boolean flag =bookService.save(book);  // 因为BookServiceImpl的save方法中已经把返回的true/false等返回过来了,所以这里保存成功的话,接收业务层返回的true
        return new Result(flag ?Code.SAVE_OK:Code.SAVE_ERR,flag);  // true的话相当于返回的是:(20011,true) 【注:走的是Result两个参数的构造方法】
        // 三元运算符:if flag为true,调用Code的SAVE_OK状态码进行传参
        //return new Result(flag ?Code.SAVE_OK:Code.SAVE_ERR,flag); 就相当于返回Result对象,后面的参数就是为属性赋的值,就相当于响应POJO类型数据
    }

    // 删
    @DeleteMapping(value = "/{id}")
    public Result delete(@PathVariable Integer id) {  // @PathVariable 注解的作用是为id赋上{id}的值   返回类型是Result对象

        // 调用业务层的删除方法
        boolean b = bookService.delete(id);
        return new Result(b? Code.DELETE_OK:Code.DELETE_ERR,b); // 注:这里就相当于往Result对象的属性中赋值,然后又因为方法类型是Result对象,
                                                                // 所以就是说把封装好数据的Result对象返回给前端(这个数据就是商量好的协议)

    }

    // 改
    @PutMapping
    public Result update(@RequestBody Book book) {

        // 调用业务层的修改方法
       boolean b = bookService.update(book);
       return new Result(b? Code.UPDATE_OK:Code.UPDATE_ERR,b);

    }

    // 通过id查询
    @GetMapping(value = "/{id}")
    public Result getById(@PathVariable Integer id) {

        // 调用业务层的通过id查询方法
        Book gs = bookService.getById(id);

        // 有可能通过id查询出来的没有数据,(比如说:数据库就id到5,而想查询id为6的数据,那么就会为null)
        Integer integer = gs != null ? Code.SELECT_OK : Code.SELECT_ERR;    // 如果不等于null SELECT_OK状态码
        String msg = gs != null ? "查询成功~" : "查询失败了~";

        return new Result(gs,integer,msg); // (数据,状态码,消息)

    }

    // 查询所有
    @GetMapping
    public Result getAll() {

        // 调用业务层的查询所有方法
        List<Book> all = bookService.getAll();
        // 判断查询出来的数据是否为null,有可能数据库是空的,所以要进行判断
        Integer code = all != null ? Code.SELECT_OK : Code.SELECT_ERR;// 查询出来的数据不为null时,把SELECT_OK状态码赋给code变量名(成功的状态码标识)
        String s = all != null ? "查询成功~" : "数据查询失败,请重试~";
        // (Object data, Integer code, String msg) 构造方法
        return new Result(all,code,s);

    }
}

ProjectExceptionAdvice异常处理器:

package com.itheima.controller;

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

/**
 *  spring处理异常 (异常处理器类)
 */

// @ControllerAdvice // 这是普通风格处理异常的注解 (只要访问路径用的不是REST风格就用这个注解)
@RestControllerAdvice   // 这是REST风格的处理异常的注解 (告诉spring这是一个处理异常的类的注解)
// 注1:这个@RestControllerAdvice注解需要被SpringMvcConfig类的@ComponentScan({"com.itheima.controller"})注解
// 扫描到,(SpringMvcConfig类的扫描注解刚好扫到controller包下,所以能扫到,因此如果换成其他的包,记得扫一下)

public class ProjectExceptionAdvice {

    /**
     *  注: 系统异常处理器
     *
     * @return: 返回给前端信息
     */

    @ExceptionHandler(SystemException.class)    // 该注解作用: 拦截是否是系统异常,是的话就调用下面的方法进行处理异常
    public Result doSystemException(SystemException sy){
            // (SystemException sy):把SystemException对象传递过来(因为刚才业务层模拟系统异常的时候,把返回给前端的信息封装到sy对象属性中了)
        /**
         *  拿到系统异常之后需要做以下几步骤:
         *  1、记录日志
         *  2、发送给运维,开发人员
         *  3、安抚一下客户(客户访问资源的时候出现异常了,咱们肯定要说一些好听的给用户)
         */

        return new Result(null,sy.getCode(), sy.getMessage());
        // 把封装到sy系统异常类属性中的系统异常状态码信息返回给用户
    }

    /**
     *  注: 业务异常处理器  (和系统异常处理器方式是一样的)
     *
     * @return: 返回给前端信息
     */

    @ExceptionHandler(BusinessException.class)   //  拦截是否是业务异常,是的话就调用下面的方法进行处理异常
    public Result doBusinessException(BusinessException bs){


        return new Result(null,bs.getCode(),bs.getMessage());
    }

    /**
     *  注: 其他异常处理器 (可以理解为除了业务异常和系统异常之外的所有异常)
     */

    @ExceptionHandler(Exception.class)    //  拦截是否是其他异常,是的话就调用下面的方法进行处理异常
    public Result doException(){

        return new Result(null,0,"出现异常了铁子~");
    }
}

4.2、业务层代码

BookService:

package com.itheima.service;
import com.itheima.domain.Book;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 *  注:其实业务层接口的方法和数据层接口的方法差不多一样,在业务层实现类当中加上和数据层的依赖关系后,就可以拿到业务层实现类对象
 *  然后调用数据层的方法了(因为方法都差不多一样)
 */

@Transactional  // 为下面的增删改查功能添加开启spring事务的注解
public interface BookService {

    /**
     *  1、增加功能
     * @param book
     * @return  保存成功返回true 失败返回false
     */
    public boolean save(Book book);

    /**
     *  2、通过id删除功能
     * @param id
     * @return
     */
    public boolean delete(Integer id);

    /**
     *  3、修改功能
     * @param book
     * @return
     */
    public boolean update(Book book);

    /**
     * 4、通过id查询功能
     * @param id
     * @return
     */
    public Book getById(Integer id);

    /**
     *  5、查询所有功能
     * @return
     */
    public List<Book> getAll();
}

BookServiceImpl: 

package com.itheima.service.impl;

import com.itheima.controller.Code;
import com.itheima.dao.BookDao;
import com.itheima.domain.Book;
import com.itheima.exception.BusinessException;
import com.itheima.exception.SystemException;
import com.itheima.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;


@Service
public class BookServiceImpl implements BookService {

    /**
     *  注入dao数据层依赖 : private BookDao bookDao;
     *      然后等会spring容器拿到管理的业务层BookServiceImpl对象后,又因为业务层和数据层有依赖关系
     *      通过依赖关系就可以调用数据层的增删改查功能了
     */

    @Autowired // 自动装配(处理依赖关系)注解
    private BookDao bookDao;

    // 增
    public boolean save(Book book) {

        // 调用数据层的增加功能
        bookDao.save(book);
        return true;
    }

    // 删
    public boolean delete(Integer id) {

        // 调用数据层的删除功能
        bookDao.delete(id);
        return true;
    }

    // 改
    public boolean update(Book book) {

        // 调用数据层的修改功能
        bookDao.update(book);
        return true;
    }

    // 通过id查询
    public Book getById(Integer id) {

        /**
         *  模拟假定这个地方出现了 系统异常(比如说:程序运行到这里后服务器宕机了)
         *
         *      我们用 1/0来模拟:服务器宕机
         *
         */

        try {
            int i =1/0; // 模拟系统异常
        } catch (Exception e){
            throw new SystemException("服务器访问超时~",e, Code.SYSTEM_ERR);
            // 把想返回给前端的信息封装到SystemException对象的属性当中
            // Code.SYSTEM_ERR :系统异常状态码标识 50001
        }

        // 调用数据层的通过id查询功能
        Book books = bookDao.getById(id);
        return books;
    }

    // 查询所有
    public List<Book> getAll() {

        // 调用数据层的查询所有功能
        List<Book> list = bookDao.getAll();
        return list;
    }
}

4.3、数据层代码

BookDao:

package com.itheima.dao;

import com.itheima.domain.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;

/**
 *  要求:ssm整合做增删改查功能
 */

public interface BookDao {

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

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

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

    // 查 (通过id查单条数据)
    @Select("select * from tbl_book where id =#{id}")
    public Book getById(Integer id);

    // 查(查全部数据)
    @Select("select * from tbl_book")
    public List<Book> getAll();
}

BookDaoImpl:

package com.itheima.dao.impl;

import com.itheima.dao.BookDao;
import com.itheima.domain.Book;
import java.util.List;

public class BookDaoImpl implements BookDao {

    public void save(Book book) {

    }

    public void delete(Integer id) {

    }

    public void update(Book book) {

    }

    public Book getById(Integer id) {
        return null;
    }

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

4.4、系统/业务异常类:(代码都是一样的)

package com.itheima.exception;

/**
 *  业务异常类
 *
 *  注:继承RuntimeException运行时异常类的目的就是运行时出现异常的时候不再手动往上抛了,自动帮我们往上抛
 *
 */
public class SystemException extends RuntimeException{

    private Integer code;    // 加个code编号属性,来标注以后出现的是哪一种异常

    /**
     *  把构造方法最好都写出来
     */

    public SystemException(Integer code) {
        this.code = code;
    }

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

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

    public SystemException(Throwable cause, Integer code) {
        super(cause);
        this.code = code;
    }

    public SystemException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace, Integer code) {
        super(message, cause, enableSuppression, writableStackTrace);
        this.code = code;
    }

    /**
     *  getter and setter方法
     */
    public Integer getCode() {
        return code;
    }

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

Book类:

package com.itheima.domain;

public class Book {

    private Integer id;
    private String type;
    private String name;
    private String description;

    @Override
    public String toString() {
        return "Book{" +
                "id=" + id +
                ", type='" + type + '\'' +
                ", name='" + name + '\'' +
                ", description='" + 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;
    }
}

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐