美文网首页算法刷题笔记
Java - SSM 整合案例

Java - SSM 整合案例

作者: Du1in9 | 来源:发表于2024-06-06 17:23 被阅读0次

    👉 在线笔记:https://du1in9.github.io/ssm_demo.github.io/

    1 SSM 整合

    1.1 整合配置

    1. Spring:Springconfig

      @Configuration
      @ComponentScan({"com.itheima.service"})
      @PropertySource("classpath:jdbc.properties")
      @Import({JdbcConfig.class,MyBatisConfig.class})
      @EnableTransactionManagement // 开启注解式事务驱动
      public class SpringConfig {
      }
      
    2. SpringMVC:Servletconfig、SpringMvcConfig

      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[]{"/"};
          }
          @Override
          protected Filter[] getServletFilters() {
              CharacterEncodingFilter filter = new CharacterEncodingFilter();
              filter.setEncoding("UTF-8");
              return new Filter[]{filter};
          }
      }
      
      @Configuration
      @ComponentScan("com.itheima.controller")
      @EnableWebMvc
      public class SpringMvcConfig {
      }
      
    3. MyBatis:MybatisConfig、Jdbcconfig、jdbc.properties

      public class MyBatisConfig {
          @Bean
          public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource){
              SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
              factoryBean.setDataSource(dataSource);
              factoryBean.setTypeAliasesPackage("com.itheima.domain");
              return factoryBean;
          }
      
          @Bean
          public MapperScannerConfigurer mapperScannerConfigurer(){
              MapperScannerConfigurer msc = new MapperScannerConfigurer();
              msc.setBasePackage("com.itheima.dao");
              return msc;
          }
      }
      
      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;
          }
      
          @Bean        // 设置事务管理器
          public PlatformTransactionManager transactionManager(DataSource dataSource){
              DataSourceTransactionManager ds = new DataSourceTransactionManager();
              ds.setDataSource(dataSource);
              return ds;
          }
      }
      
      jdbc.driver=com.mysql.jdbc.Driver
      jdbc.url=jdbc:mysql://localhost:3306/ssm_db?useSSL=false
      jdbc.username=root
      jdbc.password=123456
      

    1.2 功能模块

    1. 表与实体类

      CREATE TABLE `tbl_book`  (
          `id` int(11) NOT NULL AUTO_INCREMENT,
          `type` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
          `name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
          `description` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
          PRIMARY KEY (`id`) USING BTREE
      ) ENGINE = InnoDB AUTO_INCREMENT = 13 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
      
      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应用的轻量级框架'),
             (5, '计算机理论', '轻量级Java Web企业应用实战', '源码级刨析Spring框架,适合已掌握Java基础的读者'),
             (6, '计算机理论', 'Java核心技术 卷Ⅰ 基础知识(原书第11版)', 'Core Java第11版,Jolt大奖获奖作品'),
             (7, '计算机理论', '深入理解Java虚拟机', '5个纬度全面刨析JVM,大厂面试知识点全覆盖'),
             (8, '计算机理论', 'Java编程思想(第4版)', 'Java学习必读经典,殿堂级著作!赢得了全球程序员的广泛赞誉'),
             (9, '计算机理论', '零基础学Java(全彩版)', '零基础自学编程的入门图书,由浅入深,详解Java语言的编程思想'),
             (10, '市场营销', '直播就这么做:主播高效沟通实战指南', '李子柒、李佳奇、薇娅成长为网红的秘密都在书中'),
             (11, '市场营销', '直播销讲实战一本通', '和秋叶一起学系列网络营销书籍'),
             (12, '市场营销', '直播带货:淘宝、天猫直播从新手到高手', '一本教你如何玩转直播的书,10堂课轻松实现带货月入3W+');
      
      @Data
      public class Book {
          private Integer id;
          private String type;
          private String name;
          private String description;
      }
      
    2. dao(数据层):接口+自动代理

      public interface BookDao {
          @Insert("insert into tbl_book (type,name,description) values(#{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 where id = #{id}")
          public Book getById(Integer id);
      
          @Select("select * from tbl_book")
          public List<Book> getAll();
      }
      
    3. service(业务层):接口+实现类

      @Transactional   // 添加 Spring 事务管理
      public interface BookService {
          public boolean save(Book book);
      
          public boolean update(Book book);
      
          public boolean delete(Integer id);
      
          public Book getById(Integer id);
      
          public List<Book> getAll();
      }
      
      @Service
      public class BookServiceImpl implements BookService {
          @Autowired
          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 Book getById(Integer id) {
              return bookDao.getById(id);
          }
          public List<Book> getAll() {
              return bookDao.getAll();
          }
      }
      
    4. controller(表现层)

      @RestController
      @RequestMapping("/books")
      public class BookController {
          @Autowired
          private BookService bookService;
      
          @PostMapping
          public boolean save(@RequestBody Book book) {
              return bookService.save(book);
          }
          @PutMapping
          public boolean update(@RequestBody Book book) {
              return bookService.update(book);
          }
          @DeleteMapping("/{id}")
          public boolean delete(@PathVariable Integer id) {
              return bookService.delete(id);
          }
          @GetMapping("/{id}")
          public Book getById(@PathVariable Integer id) {
              return bookService.getById(id);
          }
          @GetMapping
          public List<Book> getAll() {
              return bookService.getAll();
          }
      }
      

    1.3 接口测试

    1. service 接口测试(JUnit)

      @RunWith(SpringJUnit4ClassRunner.class)
      @ContextConfiguration(classes = SpringConfig.class)
      public class BookServiceTest {
          @Autowired
          private BookService bookService;
          @Test
          public void testDeleteById(){
              System.out.println(bookService.delete(2));
          }
          @Test
          public void testGetById(){
              System.out.println(bookService.getById(1));
          }
          @Test
          public void testGetAll(){
              System.out.println(bookService.getAll());
          }
      }
      
    2. controller 接口测试(PostMan)

      post: http://localhost:80/books
      {"type": "def", "name": "123", "description": "abc"}
      
      put: http://localhost:80/books
      {"id": "1", "type": "def", "name": "123", "description": "abc"}
      
      delete: http://localhost:80/books/2
      
      get: http://localhost:80/books/3
      
      get: http://localhost:80/books
      

    2 统一结果封装

    • 前端数据传输格式协议

    • 表现层与协议实现

      @Data
      public class Result { // 结果模型类
          private Integer code;
          private Object data;
          private String msg;
      }
      
      public class 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 GET_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 GET_ERR = 20040;
      }
      
      @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);
          }
          
        ...
              
          @GetMapping
          public Result getAll() {
              List<Book> bookList = bookService.getAll();
              Integer code = bookList != null ? Code.GET_OK : Code.GET_ERR;
              String msg = bookList != null ? "" : "数据查询失败,请重试!";
              return new Result(code, bookList, msg);
          }
      }
      

    3 统一异常处理

    3.1 异常处理器

    • 出现异常现象的常见位置与常见诱因如下

      • 框架内部地出的异常:因使用不合规导致

      • 数据层抛出的异常:因外部服务器故障导致(例如:服务器访问超时)

      • 业务层抛出的异常:因业务逻辑书写错误导致(例如:遍历业务书写操作,导致索引异常等

      • 表现层抛出的异常:因数据收集、校验等规则导致(例如:不匹配的数据类型间导致异常)

      • 工具类抛出的异常:因工具类书写不严谨不够健壮导致(例如:必要释放的连接长期未释放等)

    • 异常处理器:集中的、统一的处理项目中出现的异常

      package com.itheima.controller;
      
      @RestControllerAdvice
      public class ProjectExceptionAdvice {
          @ExceptionHandler(Exception.class)
          public Result doException(Exception ex){
              return new Result(666, null, "嘿嘿,异常你哪里跑!");
          }
      }
      

    3.2 项目异常处理

    • 业务异常(BusinessException):规范 or 不规范的用户行为产生的异常
      • 发送对应消息传递给用户,提醒规范操作
    • 系统异常(SystemException):项目运行过程中可预计且无法避免的异常
      • 发送固定消息传递给用户,安抚用户
      • 发送特定消息给运维人员,提醒维护
      • 记录日志
    • 其他异常(Exception):编程人员未预期到的异常
      • 发送固定消息传递给用户,安抚用户
      • 发送特定消息给运维人员,提醒维护
      • 记录日志
    1. 自定义异常编码

      public class Code {
          public static final Integer SYSTEM_ERR = 50001;
          public static final Integer SYSTEM_TIMEOUT_ERR = 50002;
          public static final Integer SYSTEM_UNKNOW_ERR = 59999;
          public static final Integer BUSINESS_ERR = 60002;
      }
      
    2. 拦截并处理异常

      package com.itheima.controller;
      
      @RestControllerAdvice
      public class ProjectExceptionAdvice {
          @ExceptionHandler(SystemException.class)
          public Result doSystemException(SystemException ex){
              return new Result(ex.getCode(), null, ex.getMessage());
          }
          @ExceptionHandler(BusinessException.class)
          public Result doBusinessException(BusinessException ex){
              return new Result(ex.getCode(), null, ex.getMessage());
          }
          @ExceptionHandler(Exception.class)
          public Result doOtherException(Exception ex){
              return new Result(Code.SYSTEM_UNKNOW_ERR, null, "系统繁忙,请稍后再试!");
          }
      }
      

    4 前后台协议联调

    4.1 环境准备

    1. 将静态资源拷贝到 webapp 下,book.html 中的核心代码如下:

      <body>
          <el-button @click="getAll()" class="dalfBut">查询</el-button>
      
          <el-button type="primary" class="butT" @click="handleCreate()">新建</el-button>
          <el-button @click="dialogFormVisible = false">取消</el-button>
          <el-button type="primary" @click="handleAdd()">确定</el-button>
      
          <el-button type="primary" size="mini" @click="handleUpdate(scope.row)">编辑</el-button>
          <el-button @click="dialogFormVisible4Edit = false">取消</el-button>
          <el-button type="primary" @click="handleEdit()">确定</el-button>
      
          <el-button type="danger" size="mini" @click="handleDelete(scope.row)">删除</el-button>
      </body>
      
      <script>
          var vue = new Vue({
              methods: {
                  getAll() {},         // 1. 列表展示
                  resetForm() {},          // 重置表单
                  handleAdd () {},     // 2. 添加功能
                  handleCreate() {},       // 添加窗口
                  handleEdit() {},     // 3. 修改功能
                  handleUpdate(row) {},    // 编辑窗口
                  handleDelete(row) {} // 4. 删除功能
              }
          })
      </script>
      
    2. 因为 SpringMVC 会拦截,所以需要在 SpringConfig 的配置类中将其放行

      @Configuration       
      public class SpringMvcSupport extends WebMvcConfigurationSupport {
          @Override
          protected void addResourceHandlers(ResourceHandlerRegistry registry) {
              registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
              registry.addResourceHandler("/css/**").addResourceLocations("/css/");
              registry.addResourceHandler("/js/**").addResourceLocations("/js/");
              registry.addResourceHandler("/plugins/**").addResourceLocations("/plugins/");
          }
      }
      
      @Configuration   
      @ComponentScan({"com.itheima.controller","com.itheima.config"})
      @EnableWebMvc
      public class SpringMvcConfig {
      }
      

    4.2 列表展示

    1. 页面的钩子函数 created() 调用了 this.getAll() 方法,使用 axios 发送异步请求从后台获取数据

      getAll() {
          axios.get("/books").then((res)=>{
              this.dataList = res.data.data;
          });
      }
      
    2. 访问 http://localhost/pages/books.html 进行测试

    4.3 添加功能

    1. 页面的新建按钮绑定了 @click="handleCreate()" 方法,在方法中打开新增面板

      handleCreate() {
          this.dialogFormVisible = true;
          this.resetForm();
      },
          
      resetForm(){
          this.formData = {};
      }
      

      确定按钮绑定了 @click="handleAdd()" 方法,在方法中发送请求和数据,响应成功后将新增面板关闭并重新查询数据

      handleAdd () {
          axios.post("/books",this.formData).then((res)=>{
              if(res.data.code == 20011){          // 如果操作成功,关闭弹层,显示数据
                  this.dialogFormVisible = false;
                  this.$message.success("添加成功");
              }else if(res.data.code == 20010){    // 如果操作失败,提示错误信息
                  this.$message.error("添加失败");
              }else{
                  this.$message.error(res.data.msg);
              }
          }).finally(()=>{
              this.getAll();
          });
      }
      
    2. 后台返回操作结果,将 Dao 层的增删改方法返回值从 void 改成 int

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

      在 BookServiceImpl 中,增删改方法根据 Dao 的返回值来决定返回 true/false

      public boolean save(Book book) {
          return bookDao.save(book) > 0;
      }
      public boolean update(Book book) {
          return bookDao.update(book) > 0;
      }
      public boolean delete(Integer id) {
          return bookDao.delete(id) > 0;
      }
      

    4.4 编辑功能

    1. 页面中的编辑按钮绑定了 @click="handleUpdate(scope.row)",在方法中根据 ID 查询图书信息

      handleUpdate(row) {
          axios.get("/books/"+row.id).then((res)=>{
              if(res.data.code == 20041){          // 如果查询成功, 打开修改面板回显数据
                  this.formData = res.data.data;
                  this.dialogFormVisible4Edit = true;
              }else{                               // 如果查询失败, 提示错误信息
                  this.$message.error(res.data.msg);
              }
          });
      }
      
    2. handleEdit 方法中发送异步请求提交修改数据

      handleEdit() {
          axios.put("/books",this.formData).then((res)=>{
              if(res.data.code == 20031){          // 如果操作成功,关闭弹层,显示数据
                  this.dialogFormVisible4Edit = false;
                  this.$message.success("修改成功");
              }else if(res.data.code == 20030){    // 如果操作失败,提示错误信息
                  this.$message.error("修改失败");
              }else{
                  this.$message.error(res.data.msg);
              }
          }).finally(()=>{
              this.getAll();
          });
      }
      

    4.5 删除功能

    handleDelete(row) {
        this.$confirm("此操作永久删除当前数据,是否继续?","提示",{
            type:'info'
        }).then(()=>{           // 用户点击确定,发送异步请求, 并携带需要删除数据的主键ID
            axios.delete("/books/"+row.id).then((res)=>{
                if(res.data.code == 20021){     
                    this.$message.success("删除成功");
                }else{                          
                    this.$message.error("删除失败");
                }
            }).finally(()=>{
                this.getAll();
            });
        }).catch(()=>{          // 用户点击取消,提示操作已经被取消
            this.$message.info("取消删除操作");
        });
    }
    

    5 基于 SpringBoot 整合

    需求:根据之前的 Spring 案例,实现基于 SpringBoot 的 SSM 整合

    1. config 类:全部删除

    2. dao 类:设置 @Mapper

    3. test 类:设置 @SpringBootTest

    4. pom.xml:配置必要的资源坐标

      <dependency>
          <groupId>com.alibaba</groupId>
          <artifactId>druid</artifactId>
          <version>1.1.16</version>
      </dependency>
      
    5. application.yml:配置数据源、端口等

      spring:
        datasource:
          type: com.alibaba.druid.pool.DruidDataSource
          driver-class-name: com.mysql.cj.jdbc.Driver
          url: jdbc:mysql://localhost:3306/ssm_db
          username: root
          password: 123456
      
    6. static:静态资源,index.html 设置主页

      <script>
          document.location.href="pages/books.html”;
      </script>
      

    案例源码:https://wwb.lanzouo.com/ic4f42166e7c

    相关文章

      网友评论

        本文标题:Java - SSM 整合案例

        本文链接:https://www.haomeiwen.com/subject/bqopqjtx.html