SpringMVC-SSM整合


  • 第一阶段:项目的准备

Spring整合MyBatis

  • 坐标与插件

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

    <!--        这个版本太低,不支持com.mysql.cj.jdbc.Driver-->
    <!--        <dependency>-->
    <!--            <groupId>mysql</groupId>-->
    <!--            <artifactId>mysql-connector-java</artifactId>-->
    <!--            <version>5.1.47</version>-->
    <!--        </dependency>-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.29</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>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.tomcat.maven</groupId>
            <artifactId>tomcat7-maven-plugin</artifactId>
            <version>2.2</version>
            <configuration>
                <port>80</port>
                <path>/</path>
            </configuration>
        </plugin>
    </plugins>
</build>
  • 配置:

    • SpringConfig

    @Configuration
    @ComponentScan({"com.itheima.service"})
    @PropertySource("classpath:jdbc.properties")
    @Import({JdbcConfig.class,MyBatisConfig.class})
    @EnableTransactionManagement
    public class SpringConfig {
    }
    
    • JdbcConfig、jdbc.properties

    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;
        }
    
       
    }
    
    jdbc.driver=com.mysql.cj.jdbc.Driver
    jdbc.url=jdbc:mysql://localhost:3306/ssm_db
    jdbc.username=root
    jdbc.password=12345678
    
    • MyBatisConfig

    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;
        }
    }
    
  • 模型

    • Book

    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;
        }
    
        @Override
        public String toString() {
            return "Book{" +
                    "id=" + id +
                    ", type='" + type + '\'' +
                    ", name='" + name + '\'' +
                    ", description='" + description + '\'' +
                    '}';
        }
    }
    
  • 数据层标准开发

    • BookDao

    @Repository
    public interface BookDao {
    
        //    @Insert("insert into tbl_book values(null,#{type},#{name},#{description})")
        @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();
    }
    
  • 业务层标准开发–需要添加注释

    • BookService

    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);
    
        /**
         * 查询全部
         *
         * @return
         */
    
    
        public List<Book> getAll();
    }
    
    • BookServiceImpl

    @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();
        }
    }
    
  • 测试接口

    • BookServiceTest

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes = SpringConfig.class)
    public class BookServiceTest {
    
        @Autowired
        private BookService bookService;
    
        @Test
        public void testGetBtyId(){
            Book book = bookService.getById(1);
            System.out.println(book);
        }
    
        @Test
        public void testGetAll(){
            List<Book> bookList = bookService.getAll();
            System.out.println(bookList);
        }
    }
    
  • 如果有需要进行事务处理(了解)

    • 这部分代码实际上可以写在任何一个配置类中,因为最后都可以扫描到,但是一般建议加载jdbc配置类的最后

     @Bean
        public PlatformTransactionManager transactionManager(DataSource dataSource) {
            DataSourceTransactionManager ds = new DataSourceTransactionManager();
            ds.setDataSource(dataSource);
            return ds;
        }
    
    • 在SpringConfig中开启事务!!!

    @Configuration
    @ComponentScan({"com.itheima.service"})
    @PropertySource("classpath:jdbc.properties")
    @Import({JdbcConfig.class,MyBatisConfig.class})
    //开启事务
    @EnableTransactionManagement
    public class SpringConfig {
    }
    
    • 挂上事务,挂在service的业务层接口中,而不是实现类。
    @Transactional
    public interface BookService {}
    

Spring整合SpringMVC

  • Web配置类

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};
    }
}
  • SpringMVC配置类

@Configuration
@ComponentScan("com.itheima.controller")
@EnableWebMvc
public class SpringMvcConfig {
}
  • 基于Restful的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();
    }

}

  • 第二阶段:表现层数据封装

  • 前端的需求:

    • 操作(增?删?还是改)–code字段
    • 数据–date字段
    • 成功还是失败?–msg字段
  • 因此,我们要疯转一下返回的格式

表现层封装数据

  • 设置统一数据返回类
public class Result {
    private Object data;
    private Integer code;
    private String msg;
 	//自行设置setter与getter方法
    //提供若干个构造方法,方便操作
}
  • 设置统一数据返回结果编码,主要按照规范文档进行操作
public class Code {

    public static final Integer SAVE_OK = 20011;
    public static final Integer DELETE_OK = 200121;
    public static final Integer UPDATAE_OK = 20031;
    public static final Integer GET_OK = 20041;

    public static final Integer SAVE_ERR = 20010;
    public static final Integer DELETE_ERR = 200120;
    public static final Integer UPDATAE_ERR = 20030;
    public static final Integer GET_ERR = 20040;

}
  • 根据情况设定合理的Result
@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);
    }

    @PutMapping
    public Result update(@RequestBody Book book) {
        boolean flag = bookService.update(book);
        return new Result(flag ? Code.UPDATAE_OK : Code.UPDATAE_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("/{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);
    }

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

}

异常处理器

  • 程序开发过程中不可避免会遇到异常

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

    • 框架内部抛出的异常,因为使用不合规范
    • 数据层抛出的异常:因外部服务器故障导致(例如:服务器超时访问)
    • 业务层抛出的异常:因为业务逻辑书写错误导致(例如:遍历业务书写操作,导致索引异常等)
    • 表现层抛出的异常:因数据收集、校验等规则导致(例如:不匹配的数据类型间导致异常)
    • 工具类抛出的异常:因工具类数据不严谨不够健壮导致(例如:必要释放的连接长期为释放等)
  • 一般来说,所有的异常都抛出到表现层进行处理,AOP思想解决每个方法单独书写

  • Spring提供了集中、统一的异常处理器,其中的内部思想也就是AOP

//@ControllerAdvice
//我们使用Rest风格的异常处理器,并且必须保证在SPringConfig中被扫描到
@RestControllerAdvice
public class ProjectExceptionAdvice {
    //异常拦截器,在这里说明要拦截的异常
    @ExceptionHandler(Exception.class)
    public Result doException(Exception ex) {
        System.out.println("抓到异常了" + ex);
        return new Result(666, (Object) null,"抓到异常了" + ex);
    }
}
  • 异常处理器
  • 名称:@ExceptionHandler
  • 类型:方法注解
  • 位置:专用于异常处理的控制器方法上方
  • 作用:设置指定异常的处理方案,功能等同于控制器的方法,出现异常后终止原始控制器执行,并转入当前方法执行
  • 说明:此类方法可以根据处理的异常不同,制作多个方法分别处理对应的异常

项目异常处理方法

  • 项目异常分类:

    • 业务异常(BussinessException)
      • 规范的用户行为产生的异常
      • 不规范的用户行为产生的异常
    • 系统异常(SystemException)
      • 系统项目运行过程中可预计且无法避免的异常
    • 其他异常(Exception)
      • 编程人员未预期到的
  • 项目异常处理方案

    • 业务异常(BusinessException)
      • 发送对应消息传递给用户,提醒规范操作
    • 系统异常(SystemException)
      • 发送固定消息传递给用户,安抚用户
      • 发送特定消息给运维人员,提醒运维
      • 记录日志
    • 其他异常(Exception)
      • 发送固定消息传递给用户,安抚用户
      • 发送特定消息给运维人员,提醒维护(纳入预期范围内)
      • 记录日志

项目异常处理

①自定义项目系统异常

//让他可以运行,需要继承这个类
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;
    }


}

②自定义项目业务级异常

//让他可以运行,需要继承这个类
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;
    }

}

③自定义异常编码(持续补充)

package com.itheima.controller;

public class Code {

    public static final Integer SAVE_OK = 20011;
    public static final Integer DELETE_OK = 200121;
    public static final Integer UPDATAE_OK = 20031;
    public static final Integer GET_OK = 20041;

    public static final Integer SAVE_ERR = 20010;
    public static final Integer DELETE_ERR = 200120;
    public static final Integer UPDATAE_ERR = 20030;
    public static final Integer GET_ERR = 20040;

    public static final Integer SYSTEM_ERR = 50001;
    public static final Integer SYSTEM_TIMEOUT_ERR = 50002;
    public static final Integer SYSTEM_UNKNOW_ERR = 50002;


    public static final Integer BUSINESS_ERR = 60002;


}

④触发自定义异常

@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) {
        //将可能出现的异常进行包装,转换成自定义异常
        if (id == 1) {
            throw new BusinessException(Code.BUSINESS_ERR, "请不要使用使用你的技术挑战我的耐性!");
        }
        try {
            int i = 1 / 0;
        } catch (Exception e) {
            throw new SystemException(Code.SYSTEM_TIMEOUT_ERR, "服务器访问超时,请重试!", e);
        }

        return bookDao.getById(id);
    }

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

⑤拦截并处理异常

package com.itheima.controller;

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

//@ControllerAdvice
//我们使用Rest风格的异常处理器,并且必须保证在SPringConfig中被扫描到
@RestControllerAdvice
public class ProjectExceptionAdvice {
    //异常拦截器
    @ExceptionHandler(SystemException.class)
    public Result doException(SystemException ex) {
        //记录日志
        //发送消息给运维
        //发送邮件给开发人员,ex对象发送给开发人员
        return new Result(ex.getCode(), null, ex.getMessage());
    }

    @ExceptionHandler(BusinessException.class)
    public Result doException(BusinessException ex) {
        return new Result(ex.getCode(), null, ex.getMessage());
    }

    @ExceptionHandler(Exception.class)
    public Result doException(Exception ex) {
        return new Result(Code.SYSTEM_UNKNOW_ERR, null, "系统繁忙,请稍后再试!");
    }

}

⑥异常处理器效果对比

{
    "data": [
        {
            "id": 1,
            "type": "计算机理论",
            "name": "Spring实战第五版",
            "description": "Spring入门经典教程,深入理解Spring原理技术内幕"
        }
    ],
    "code": 20041,
    "msg": ""
}
{
    "data": null,
    "code": 50002,
    "msg": "服务器访问超时,请重试!"
}

案例:SSM整合标准开发

①自定义项目系统级异常

axios.get("/books").then((res)=>{})
axios.post("/books",this.formData).then((res)=>{})
axios.delete("/books/"+row.id).then((res)=>{})
axios.put("/books",this.formData).then((res)=>{})
axios.get("/books/"+row.id).then((res)=>{})

②有关方法

methods: {

    // 重置表单
    resetForm() {
        //清空输入框
        this.formData = {};
    },

    // 弹出添加窗口
    openSave() {
        this.dialogFormVisible = true;
        this.resetForm();
    },

    //添加
    saveBook() {
        //发送ajax请求
        axios.post("/books", this.formData).then((res) => {

            //如果操作成功,关闭弹窗,刷新数据
            if (20011 == res.data.code) {
                this.dialogFormVisible = false;
                this.$message.success("添加成功!");

            } else if (20010 == res.data.code) {
                //如果失败,返回错误信息
                this.$message.error("添加失败!");

            } else {
                this.$message.error(res.data.msg)

            }
        }).finally(() => {
            this.getAll();
        });

    },

    //主页列表查询
    getAll() {
        //发送ajax请求
        axios.get("/books").then((res) => {
            this.dataList = res.data.data;
        });
    },
    //弹出编辑窗口
    handleUpdate(row) {
        //查询数据,根据id查询
        console.log(row.id)
        axios.get("/books/" + row.id).then((res) => {

            //如果操作成功,关闭弹窗,刷新数据
            if (20041 == res.data.code) {
                //展示弹层,加载数据
                this.formData = res.data.data;
                this.dialogFormVisible4Edit = true;

            } else {
                this.$message.error(res.data.msg)

            }


        })

    },
    //编辑
    update() {
        //发送ajax请求
        axios.put("/books", this.formData).then((res) => {
            console.log(res.data)
            //如果操作成功,关闭弹窗,刷新数据
            if (20031 == res.data.code) {
                this.dialogFormVisible4Edit = false;
                this.$message.success("修改成功!");

            } else if (20030 == res.data.code) {
                //如果失败,返回错误信息
                this.$message.error("修改失败!");

            } else {
                this.$message.error(res.data.msg)

            }
        }).finally(() => {
            this.getAll();
        });

    },
    //删除
    handleDelete(row) {
        //1.弹出提示框--提示信息,标题,具体操作
        this.$confirm("此操作永久删除,是否继续?", "提示", {
            type: 'info'
        }).then(() => {
            //2.做删除业务
            axios.delete("/books/" + row.id).then(() => {
                if (res.data.code == 20021) {
                    this.$message.success("删除成功!");
                } else {
                    this.$message.error("删除失败!");
                }
            })

        }).catch(() => {
            //3.取消删除
            this.$message.info("取消删除")

        }).finally(() => {
            this.getAll();
        })


    }


}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值