美文网首页
SSM整合(注解)

SSM整合(注解)

作者: h2coder | 来源:发表于2022-12-02 17:27 被阅读0次

前言

本篇记录Spring、SpringMVC、Mybatis,也就是SSM的整合,并且是基于注解方法的整合。

  • Spring,业务层,负责依赖注入、AOP
  • SpringMVC,表现层,负责请求和响应流转的流程、以及3层的注解
  • MyBatis,持久层,负责数据之间的操作

整合顺序

  1. 先Spring
  2. 再整合SpringMVC
  3. 最后整合MyBatis

案例

简单图片管理系统的增删改查

环境准备

  • 创建工程,并加入依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.itheima</groupId>
    <artifactId>day35-08-ssm-crud</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.encoding>UTF-8</maven.compiler.encoding>
        <spring.version>5.2.10.RELEASE</spring.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.version}</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.27</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>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.16</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.9.0</version>
        </dependency>
    </dependencies>
</project>
  • 创建数据库和表
-- 创建ssm_db数据库
CREATE DATABASE IF NOT EXISTS ssm_db CHARACTER SET utf8;

-- 使用ssm_db数据库
USE ssm_db;

-- 创建tbl_book表
CREATE TABLE tbl_book(
    id INT PRIMARY KEY AUTO_INCREMENT, -- 图书编号
    `type` VARCHAR(100), -- 图书类型
    `name` VARCHAR(100), -- 图书名称
    description VARCHAR(100) -- 图书描述
);
-- 添加初始化数据
INSERT INTO tbl_book VALUES(NULL,'计算机理论','Spring实战 第5版','Spring入门经典教材,深入理解Spring原理技术内幕');
INSERT INTO tbl_book VALUES(NULL,'计算机理论','Spring 5核心原理与30个类手写实战','十年沉淀之作,手写Spring精华思想');
INSERT INTO tbl_book VALUES(NULL,'计算机理论','Spring 5设计模式','深入Spring源码剖析,Spring源码蕴含的10大设计模式');
INSERT INTO tbl_book VALUES(NULL,'市场营销','直播就该这么做:主播高效沟通实战指南','李子柒、李佳琦、薇娅成长为网红的秘密都在书中');
INSERT INTO tbl_book VALUES(NULL,'市场营销','直播销讲实战一本通','和秋叶一起学系列网络营销书籍');
INSERT INTO tbl_book VALUES(NULL,'市场营销','直播带货:淘宝、天猫直播从新手到高手','一本教你如何玩转直播的书,10堂课轻松实现带货月入3W+');
  • 创建表对应的实体类
//lombok的注解,可以给实体类生成set\get和重写toString()方法
@Data
//2.生成全参构造函数
@AllArgsConstructor
//3.生成无参构造函数
@NoArgsConstructor
public class Book {
    private Integer id;
    private String type;
    private String name;
    private String description;
}
  • 统一返回结构实体类
@Data
public class Result<T> {
    /**
     * 业务操作的类型编码
     */
    private Integer code;
    /**
     * 封装业务返回的数据
     */
    private T data;
    /**
     * 业务失败的错误消息
     */
    private String msg;

    /**
     * 处理返回成功结果
     */
    public static Result<String> success(Integer code) {
        return success(code, "success");
    }

    /**
     * 处理返回成功结果
     */
    public static <T> Result<T> success(Integer code, T data) {
        Result<T> result = new Result<>();
        result.setCode(code);
        result.setData(data);
        return result;
    }

    /**
     * 处理返回成功结果
     */
    public static <T> Result<T> error(Integer code, T data, String msg) {
        Result<T> result = new Result<>();
        result.setCode(code);
        result.setData(data);
        result.setMsg(msg);
        return result;
    }
}
  • 创建数据库配置文件
jdbc.username=root
jdbc.password=root
jdbc.url=jdbc:mysql://localhost:3306/ssm_db?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useUnicode=true&useSSL=false
jdbc.driverClassName=com.mysql.cj.jdbc.Driver

搭建配置类

  • JDBC配置类
public class JdbcConfig {
    @Value("${jdbc.driverClassName}")
    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;
    }

    /**
     * Spring事务管理需要的平台事务管理器对象
     */
    @Bean
    public PlatformTransactionManager transactionManager(DataSource dataSource) {
        DataSourceTransactionManager ds = new DataSourceTransactionManager();
        ds.setDataSource(dataSource);
        return ds;
    }
}
  • Spring配置类
@Configuration
//排除Controller
@ComponentScan(value = "com.itheima",
        excludeFilters = @ComponentScan.Filter(
                type = FilterType.ANNOTATION,
                classes = Controller.class
        )
)
//加载外部配置文件jdbc.properties
@PropertySource("classpath:jdbc.properties")
//加载其他配置类JdbcConfig.class
@Import({JdbcConfig.class, MybatisConfig.class})
//开启事务注解扫描
@EnableTransactionManagement
public class SpringConfig {
}
  • SpringMVC配置类
@Configuration
@ComponentScan("com.itheima.controller")
@EnableWebMvc //这个注解有很多功能,这里暂时使用里面json与java对象自动转换
public class SpringMvcConfig implements WebMvcConfigurer {
    /**
     * 配置视图解析器,配置视图前缀与后缀
     */
    @Bean
    public InternalResourceViewResolver internalResourceViewResolver() {
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        //配置前缀
        viewResolver.setPrefix("/pages/");
        //配置后缀
        viewResolver.setSuffix(".jsp");
        return viewResolver;
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        //静态资源访问配置
        registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
        registry.addResourceHandler("/js/**").addResourceLocations("/js/");
        registry.addResourceHandler("/css/**").addResourceLocations("/css/");
        registry.addResourceHandler("/plugins/**").addResourceLocations("/plugins/");
    }
}
  • Servlet配置类
public class ServletConfig extends AbstractDispatcherServletInitializer {
    @Override
    protected WebApplicationContext createServletApplicationContext() {
        AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext();
        ac.register(SpringMvcConfig.class);
        return ac;
    }

    @Override
    protected String[] getServletMappings() {
        //“/”,可以拦截除了jsp以外所有的资源的请求,拦截这些请求的目的是交给SpringMvc去处理
        return new String[]{"/"};
    }

    @Override
    protected WebApplicationContext createRootApplicationContext() {
        AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext();
        ac.register(SpringConfig.class);
        return ac;
    }

    /**
     * 配置SpringMvc框架提供的处理post请求中文乱码过滤器
     */
    @Override
    protected Filter[] getServletFilters() {
        CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
        characterEncodingFilter.setEncoding("utf-8");
        return new Filter[]{characterEncodingFilter};
    }
}
  • MyBatis配置类
public class MybatisConfig {
    @Bean
    public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource) {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setTypeAliasesPackage("com.itheima.domain");
        sqlSessionFactoryBean.setDataSource(dataSource);

        Configuration configuration = new Configuration();
        //设置整合mybatis驼峰命名映射
        configuration.setMapUnderscoreToCamelCase(true);
        //设置打印日志
        configuration.setLogImpl(StdOutImpl.class);
        sqlSessionFactoryBean.setConfiguration(configuration);

        return sqlSessionFactoryBean;
    }

    @Bean
    public MapperScannerConfigurer mapperScannerConfigurer() {
        MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
        //设置mybatis加载映射接口位置
        mapperScannerConfigurer.setBasePackage("com.itheima.dao");
        return mapperScannerConfigurer;
    }
}

编写 MVC 3层代码

数据持久层(Dao)

  • BookDao

Mapper.java类,增、改、查,使用注解实现

public interface BookDao {
    /**
     * 新增图书
     */
    @Insert("insert into tbl_book values (NULL, #{type}, #{name}, #{description})")
    void add(Book book);

    /**
     * 删除图书
     */
    void delete(Integer id);

    /**
     * 更新图书
     */
    @Update("update tbl_book set type = #{id}, name = #{name}, description = #{description} where id = #{id}")
    void update(Book book);

    /**
     * 按Id查询图书
     */
    @Select("select * from tbl_book where id = #{id}")
    Book findById(Integer id);

    /**
     * 查询所有图书
     */
    @Select("select * from tbl_book")
    List<Book> findAll();
}
  • BookDao.xml

Mapper接口的xml映射文件,delete方法使用xml实现

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--
    namespace:配置对应的Mapper接口的全类名:包名 + 接口名
 -->
<mapper namespace="com.itheima.dao.BookDao">
    <!-- 删除图书 -->
    <delete id="delete">
        delete
        from tbl_book
        where id = #{id}
    </delete>
</mapper>

业务层

  • BookService

业务层接口

//开启事务管理
@Transactional
public interface BookService {
    /**
     * 新增图书
     */
    void add(Book book);

    /**
     * 删除图书
     */
    void delete(Integer id);

    /**
     * 更新图书
     */
    void update(Book book);

    /**
     * 按Id查询图书
     */
    Book findById(Integer id);

    /**
     * 查询所有图书
     */
    List<Book> findAll();
}
  • BookServiceImpl

业务层实现类

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

    @Override
    public void add(Book book) {
        bookDao.add(book);
    }

    @Override
    public void delete(Integer id) {
        bookDao.delete(id);
    }

    @Override
    public void update(Book book) {
        bookDao.update(book);
    }

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

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

Web层(控制器)

  • BookController

控制器,通过restful风格编写增删查改的接口

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

    /**
     * 新增图书
     */
    @PostMapping
    public String add(@RequestBody Book book) {
        bookService.add(book);
        System.out.println("添加成功");
        return "success";
    }

    /**
     * 删除图书
     */
    @DeleteMapping("/{id}")
    public String delete(@PathVariable Integer id) {
        bookService.delete(id);
        System.out.println("删除成功");
        return "success";
    }

    /**
     * 更新图书
     */
    @PutMapping
    public String update(@RequestBody Book book) {
        bookService.update(book);
        System.out.println("更新成功");
        return "success";
    }

    /**
     * 按Id查询图书
     */
    @GetMapping("/{id}")
    public Book findById(@PathVariable Integer id) {
        return bookService.findById(id);
    }

    /**
     * 查询所有图书
     */
    @GetMapping
    public List<Book> findAll() {
        return bookService.findAll();
    }
}

全局异常处理

  • Code(业务异常错误码-常量)
/**
 * 业务状态码
 * <p>
 * 前四位代表不同的操作,最后一位代表成功或失败(1成功、0失败)
 */
public interface Code {
    /**
     * 新增成功
     */
    Integer SAVE_OK = 20011;
    /**
     * 删除成功
     */
    Integer DELETE_OK = 20021;
    /**
     * 更新成功
     */
    Integer UPDATE_OK = 20031;
    /**
     * 查询成功
     */
    Integer GET_OK = 20041;
    Integer SAVE_ERR = 20010;
    Integer DELETE_ERR = 20020;
    Integer UPDATE_ERR = 20030;
    Integer GET_ERR = 20040;
}
  • BusinessException(业务异常)
/**
 * 业务异常
 */
public class BusinessException extends RuntimeException {
    private static final long serialVersionUID = 5408508596626762201L;
    private int code;

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

    public int getCode() {
        return code;
    }

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

    @Override
    public String toString() {
        return "BusinessException{" +
                "code=" + code +
                '}';
    }
}
  • SystemException(系统异常)
/**
 * 系统异常
 */
public class SystemException extends RuntimeException {
    private static final long serialVersionUID = 5408508596626762201L;
    private int code;

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

    public int getCode() {
        return code;
    }

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

    @Override
    public String toString() {
        return "SystemException{" +
                "code=" + code +
                '}';
    }
}
  • ProjectExceptionAdvice(全局异常处理器)
/**
 * 注解:@RestControllerAdvice:异步请求全局异常处理器,最后封装为统一结果为json输出
 * 注解:@ControllerAdvice,同步请求全局异常处理器,最后封装为ModelAndView,跳转视图页面输出
 */
@RestControllerAdvice
public class ProjectExceptionAdvice {
    /**
     * 可以预计的用户非法异常
     */
    @ExceptionHandler(BusinessException.class)
    public Result<String> doBusinessException(BusinessException ex) {
        return Result.error(ex.getCode(), null, ex.getMessage());
    }

    /**
     * 无法规避的系统异常
     */
    @ExceptionHandler(SystemException.class)
    public Result<String> doSystemException(SystemException ex) {
        //打印异常到控制台
        ex.printStackTrace();
        return Result.error(ex.getCode(), null, ex.getMessage());
    }

    /**
     * 全局异常捕获(捕获表现层所有Controller抛出的异常)
     */
    @ExceptionHandler(Exception.class)
    public Result<String> doException(Exception ex) {
        //打印异常到控制台
        ex.printStackTrace();
        return Result.error(666, null, "服务器忙,请稍后再试");
    }
}

测试

  • PostMan或其他工具,访问http://localhost:8080/book的相关接口(注意不同的请求方法,对应不同的功能接口)

相关文章

  • ssm整合

    SSM整合笔记 整合Spring 编写xml配置文件,开启注解扫描(指定Controller注解不扫描)