SpringMVC学习笔记(三) - 手把手教你掌握SSM的基本开发

SpringMVC学习笔记(三) - SSM整合案例

初始化工程

初始化工程相关代码资料链接提取码-6666

创建工程

整合配置
  • 基本的SSM整合项目需要依赖的包
    <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>
      </dependency>
    
      <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>3.1.0</version>
      </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.1</version>
          <configuration>
            <port>81</port>
            <path>/</path>
          </configuration>
        </plugin>
      </plugins>
    </build>
    
  • 基本的项目项目结构
    在这里插入图片描述
SSM整合
  • Spring
    在config包下创建SpingConfig

    @Configuration
    @ComponentScan({"com.itheima.service"})
    @PropertySource("jdbc.properties")
    @Import({JdbcConfig.class,MybatisConfig.class})
    public class SpringConfig {
    }
    
  • MyBatis
    在resources包下创建jdbc.properties,配置连接数据库的基本信息

    jdbc.driver=com.mysql.jdbc.Driver
    jdbc.url=jdbc:mysql://localhost:3306/db1
    jdbc.username=root
    jdbc.password=XXXX	
    

    在config包下创建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;
    
       public DataSource dataSource(){
           DruidDataSource dataSource = new DruidDataSource();
           dataSource.setDriverClassName(driver);
           dataSource.setUrl(url);
           dataSource.setUsername(username);
           dataSource.setPassword(password);
           return dataSource;
       }
    }
    

    在config包下创建MyBatisConfig类,完成数据库到类对象之间的映射

    public class MybatisConfig {
    
        public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource){
            SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
            factoryBean.setDataSource(dataSource);
            factoryBean.setTypeAliasesPackage("com.itheima.domain");
            return factoryBean;
        }
    
        public MapperScannerConfigurer mapperScannerConfigurer(){
            MapperScannerConfigurer msc = new MapperScannerConfigurer();
            msc.setBasePackage("com.itheima.dao");
            return msc;
        }
    }
    
  • SpringMVC
    在config包下创建ServletConfig类,初始化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[]{"/"};
        }
    }
    

    在config包下创建SpringMvcConfig类,实现后台数据与前台数据交互(可以理解为服务端和客户端的枢纽)

    @Configuration
    @ComponentScan("com.itheima.controller")
    @EnableWebMvc
    public class SpringMvcConfig {
    }
    
功能模块
  • 表与实体类:在domain包下创建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 + '\'' +
                    '}';
        }
    }
    
  • dao(接口+自动代理):在dao包下创建BookDao接口,通过自动代理实现接口类

    public interface BookDao {
    
        /**
         * 插入新的数据操作
         * @param book
         */
        @Insert("insert into tbl_book values(null,#{type},#{name},#{description}")
        public void save(Book book);
    
    
        /**
         * 修改数据操作
         * @param book
         */
        @Update("update tbl_book set type=#{type},name=#{name},description=#{description} where id=#{id}")
        public void update(Book book);
    
    
        /**
         * 根据id删除指定数据操作
         * @param id
         */
        @Delete("delete from tbl_book where id=#{id}")
        public void delete(Integer id);
    
    
        /**
         * 根据id查找指定数据操作
         * @param id
         * @return
         */
        @Select("select * from tbl_book where id=#{id}")
        public Book getById(Integer id);
    
    
        /**
         * 查找所有数据操作
         * @return
         */
        @Select("select * from tbl_book")
        public List<Book> getAll();
    }
    

功能模块开发

表现层数据封装(前后端连接的枢纽)

问题引入:解决前端从后端接收统一格式的数据

  • 提出创建结果模型类,封装数据到data属性中,达到前端接收数据格式
  • 规定前端接收数据格式:封装操作结果到code属性中
  • 添加前端接收数据格式:封装特殊消息到message(msg)属性中

表现层数据封装的具体操作

  • 设置统一数据返回结果类

    public class Result {
        private Object data;
        private Integer code;
        private String msg;
    
        public Result() {
        }
    
        public Result(Object data, Integer code, String msg) {
            this.data = data;
            this.code = code;
            this.msg = msg;
        }
    
        public Result(Object data, Integer code) {
            this.data = data;
            this.code = code;
        }
    
        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;
        }
    }
    
  • 设置统一数据返回结果编码

    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;
    }
    
  • 根据情况设定合理的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,flag?Code.SAVE_OK:Code.SAVE_ERR);
        }
    
        @PutMapping
        public Result update(@RequestBody Book book) {
            boolean flag = bookService.update(book);
            return new Result(flag,flag?Code.UPDATE_OK:Code.UPDATE_ERR);
        }
    
        @DeleteMapping("/{id}")
        public Result delete(@PathVariable Integer id) {
            boolean flag = bookService.delete(id);
            return new Result(flag,flag?Code.DELETE_OK:Code.DELETE_ERR);
        }
    
        @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(book,code,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(bookList,code,msg);
        }
    }
    
异常处理

各个层级均出现异常,所有的异常均抛出到表现层进行处理(借鉴AOP思想)

项目异常分类

  • 【业务异常】:规范的用户行为产生的异常;不规范的用户行为操作产生的异常

    发送对应消息传递给用户,提醒规范操作

  • 【系统异常】:项目运行过程中可预计且无法避免的异常

    发送固定消息传递给用户,安抚用户

  • 【其它异常】:编程人员未预期到的异常

    发送固定消息传递给用户,安抚用户

基本步骤

  • 自定义项目系统级异常

    public class SystemException extends RuntimeException {
        private Integer code;//异常编号
    
        public Integer getCode() {
            return code;
        }
    
        public void setCode(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 class BusinessException extends RuntimeException {
        private Integer code;//异常编号
    
        public Integer getCode() {
            return code;
        }
    
        public BusinessException(String message, Integer code) {
            super(message);
            this.code = code;
        }
    
        public BusinessException(String message, Throwable cause, Integer code) {
            super(message, cause);
            this.code = code;
        }
    }
    
  • 自定义项目异常编码(根据就需要持续补充)

    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;
    
        public static final Integer SYSTEM_ERR = 50001;
        public static final Integer SYSTEM_TIMEOUT_ERR = 50002;
        public static final Integer SYSTEM_UNKNOWN_ERR = 59999;
    
        public static final Integer BUSINESS_ERR = 60002;
    }
    
  • 拦截并处理异常

    /**
     * 异常处理器
     */
    @RestControllerAdvice
    public class ProjectExceptionAdvice {
    
        @ExceptionHandler(SystemException.class)
        public Result doSystemException(SystemException ex){
            //记录日志
            //发送消息给运维
            //发送邮件给开发人员
            return new Result(null,ex.getCode(),ex.getMessage());
        }
    
        @ExceptionHandler(BusinessException.class)
        public Result doBusinessException(BusinessException ex){
            return new Result(null,ex.getCode(),ex.getMessage());
        }
    
        @ExceptionHandler(Exception.class)
        public Result doException(Exception ex){
            //记录日志
            //发送消息给运维
            //发送邮件给开发人员
            return new Result(null,Code.SYSTEM_UNKNOWN_ERR,"系统繁忙,请稍后再试!");
        }
    }
    

前后端数据交互

  • 导入前端页面文件
  • 设置不需要拦截的资源路径,同时还要再SpringMvcConfig类的@Import中导入com.itheima.config
    @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/");
        }
    }
    
  • 显示所有数据到页面(在/webapp/pages/books.html中添加以下代码)
    //列表
    getAll() {
        //发送ajax请求
        axios.get("/books").then((res)=>{
            this.dataList = res.data.data;
        });
    },
    

添加功能及其状态处理

在正式开发添加功能的时候,为了保证代码的健壮性,我们需要对添加正常和异常进行消息提醒,基于前面章节我们对数据层和业务层后台代码进行修改

  • 修改数据层,将返回结果类型返回查找到的数据存放列表的长度(目的是判断列表是否存在有效数据)
    public interface BookDao {
    
        @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);
    
        @Select("select * from tbl_book where id = #{id}")
        public Book getById(Integer id);
    
        @Select("select * from tbl_book")
        public List<Book> getAll();
    }
    
  • 修改业务层,通过判断有数据进行来操作数据
    @Service
    public class BookServiceImpl implements BookService {
    	//注意这是BookServiveImpl的部分代码,简化本部分的实现的代码方便大家理解
        @Autowired
        private BookDao bookDao;
    
        public boolean save(Book book) {
            return bookDao.save(book)>0;
        }
    
        public List<Book> getAll() {
            return bookDao.getAll();
        }
    }
    
  • 实现页面交互逻辑
    //钩子函数,VUE对象初始化完成后自动执行
    created() {
        this.getAll();
    },
    
    //写的是实现添加功能及状态处理的交互逻辑代码
    methods: {
        //列表
        getAll() {
            //发送ajax请求
            axios.get("/books").then((res)=>{
                this.dataList = res.data.data;
            });
        },
    
        //弹出添加窗口
        handleCreate() {
            this.dialogFormVisible = true;
            this.resetForm();
        },
    
        //重置表单
        resetForm() {
            this.formData = {};
        },
    
        //添加
        handleAdd () {
            //发送ajax请求
            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();
            });
        },
    }
    

修改功能

  • 根据id查找对应的数据,并将数据回显到页面
    //弹出编辑窗口
    handleUpdate(row) {
        //查询数据,根据id查询
        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);
            }
        });
    },
    
  • 将回显的数据进行修改
    //编辑
    handleEdit() {
        //发送ajax请求
        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();
        });
    },
    

删除功能

  • 根据id找到对应的数据,随后在业务层调用删除操作
    // 删除
    handleDelete(row) {
    
        //弹出提示框
        this.$confirm("此操作永久删除","提示",{
            type:'info'
        }).then(()=>{
            axios.delete("/books/"+row.id).then((res)=>{
                //判断删除是否成功
                if(res.data.code == 20021){
                    this.$message.success("删除成功!");
                }else{
                    this.$message.error("删除失败");
                }
            });
        }).catch(()=>{
            //取消删除
            this.$message.error("取消删除");
        }).finally(()=>{
            this.getAll();
        });
    }
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值