MyBatis使用梳理

一、MyBatis使用时数据流动顺序分析

需求:
前端提交表单,请求后台使用MyBatis往数据库里插入一条数据

使用流程:

  1. 前端传回数据,此时数据传到controller的对应方法里
  2. controller使用调用service对象对应方法,将数据传递过去
  3. service实际上是个接口,数据只是通过这个接口,传递到service的接口实现类serviceImp
  4. serviceImp接收到调用,接到数据,调用本类中的userDAO对象对应方法,将数据传递出去
  5. userDAO实际上也是个接口,它头上有个Mapper注解,它会通过这个注解,将数据传递给其对应的Mapper
  6. Mapper.html有很多个,名字也可以多种多样,但是Mapper中有个namespace属性,这个属性定位了其对应的DAO接口的位置,userDAO也是根据这个属性,找到了自己对应的Mapper
  7. 一个DAO接口中有很多方法,所以也需要其对应的Mapper中有对应的实现,也就是完成该方法的具体实现,如往数据库中增删改查
  8. Mapper有个id属性,其的值对应了DAO中的各个方法名称,DAO有多个方法,Mapper中也有多个id值
  9. 找到对应的Mapper之后,根据id找到对应的实现,传递数据给该实现,由该实现按照既定的规则完成对数据库的操作

PS:该数据流动,实际上使用了设计模式中的依赖倒转原则。
附依赖倒转原则:

  1. 高层模块不应依赖底层模块,二者应该依赖其抽象。
  2. 抽象不应该依赖细节,细节应该依赖抽象
  3. 此原则的中心是:面向接口编程
  4. 此原则的设计理念:相对细节的多变性,抽象的东西要稳定的多;
    以抽象为基础搭建的架构,比以细节为基础的架构要稳定的多
  5. 使用接口或抽象类的目的是制定好规范,而不涉及任何细节,
    把展现细节的任务交给他们的实现类去完成

二、具体代码(实现注册功能)

目录结构:
在这里插入图片描述

regist.html:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
   <head>
      <title>regist</title>
      <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
      <link rel="stylesheet" type="text/css" href="css/style.css" />
   </head>
   <body>
      <div id="wrap">
         <div id="top_content">
               <div id="header">
                  <div id="rightheader">
                     <p>
                        2009/11/20
                        <br />
                     </p>
                  </div>
                  <div id="topheader">
                     <h1 id="title">
                        <a href="#">main</a>
                     </h1>
                  </div>
                  <div id="navigation">
                  </div>
               </div>
            <div id="content">
               <p id="whereami">
               </p>
               <h1>
                  注册
               </h1>
               <form action="login.html" method="post">
                  <table cellpadding="0" cellspacing="0" border="0"
                     class="form_table">
                     <tr>
                        <!--整个都是异步通讯,不提交表单,所以表单中input的name没有意义-->
                        <td valign="middle" align="right">
                           用户名:
                        </td>
                        <td valign="middle" align="left">
<!--                           将表单绑定到Vue属性中-->
                           <input type="text" class="inputgri" v-model="user.username" />
                        </td>
                     </tr>

                     <tr>
                        <td valign="middle" align="right">
                           真实姓名:
                        </td>
                        <td valign="middle" align="left">
                           <input type="text" class="inputgri" v-model="user.realName" />
                        </td>
                     </tr>
                     <tr>
                        <td valign="middle" align="right">
                           密码:
                        </td>
                        <td valign="middle" align="left">
                           <input type="password" class="inputgri" v-model="user.password" />
                        </td>
                     </tr>
                     <tr>
                        <td valign="middle" align="right">
                           性别:
                        </td>
                        <td valign="middle" align="left"><input type="radio" class="inputgri" v-model="user.sex" value="" checked="checked"/><input type="radio" class="inputgri" v-model="user.sex" value=""/>
                        </td>
                     </tr>
                     
                     <tr>
                        <td valign="middle" align="right">
                           验证码:
                        </td>
                        <td valign="middle" align="left">
                           <input type="text" class="inputgri" v-model="code" />
                        </td>

                        <td>
                           <!--从Vue中获取url属性-->
                           <img id="num" :src="url"/>
<!--                           从Vue中调用名为getImage()的方法-->
                           <a href="javascript:;" @click="getImage">换一张</a>
                        </td>


                     </tr>
                  </table>
                  <p>
                     <input type="buttton" @click="register" class="button" value="Submit &raquo;" />
                  </p>
               </form>
            </div>
         </div>
         <div id="footer">
            <div id="footer_bg">
            ABC@126.com
            </div>
         </div>
      </div>
   </body>
</html>
<!--vue导入-->
<script src="/ems_vue/js/vue.js"></script>
<!--异步请求导入-->
<script src="/ems_vue/js/axios.min.js"></script>
<script>
<!--   vue实例-->
   var app = new Vue({
      //挂载作用域
      //从register.html中可得知,整个都是由wrap包裹起来
      //所以作用域传wrap进来即可
      el:"#wrap",

      //作用域中获取的数据
      data:{
         //定义一个属性url,用来存从后端取得的验证码数据
         //让页面调用这个属性,即可得到验证码图片
         url:"",

         //user对象
         user:{
            sex:"男"
         },
         //验证码
         code:"",
      },
      methods:{
         //用来更换验证码
         getImage(){
            this.getSrc();
         },

         //获取验证码,代码复用,便于调用
         getSrc(){
            var _this = this;
            //console.log("xxxx");
            //异步请求:请求验证码图片
            axios.get("http://localhost:8989/ems_vue/user/getImage?time="+Math.random()).then(res=>{
               console.log(res.data);
               // 把图片赋给url属性
               _this.url = res.data;


            });
         },
         //用来注册用户信息
         register(){
            //this.code: 相当于地址栏传参,使得UserController能直接得到code
            axios.post("http://localhost:8989/ems_vue/user/register?code="+this.code,this.user).then(res=>{
               console.log(res.data);
               // 给用户一个提示
               // true:注册成功,是否跳转页面
               // false:注册失败
               if (res.data.state){
                  alert(res.data.msg+"点击确定跳转至登录页面!");
                  location.href="http://localhost:8989/ems_vue/login.html"
               }else{
                  alert(res.data.msg);
               }
            })
         }
      },
      //页面创建之前进行处理
      //用来在页面创建前,请求获取验证码
      created(){
         //获取验证码
         this.getSrc();
      }
   })
</script>

UserController:

package com.chen.controller;

import com.chen.entity.User;
import com.chen.service.UserService;
import com.chen.utils.VerifyCodeUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Base64Utils;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * @author 淡
 * @version 1.0
 * @description
 * @create 2021-02-23 12:44
 */
@Slf4j
@RestController
@CrossOrigin//允许跨域
@RequestMapping("user")
public class UserController {

    @Autowired
    //其实这个就是个工具对象,通过它调用业务方法
    //业务方法写在UserService接口的实现类:UserServiceImpl里
    private UserService userService;

    
    /**
     * @description 处理用户登录请求
     * <br>
     * @param  
     * @return java.util.Map<java.lang.String, java.lang.Object>
     * @author 淡
     * @since 2021/2/23 21:39
     */
    @PostMapping("login")
    public Map<String, Object> login(@RequestBody User user){
        log.info("当前登陆用户信息:[{}]",user.toString());
        Map<String, Object> map = new HashMap<>();
        try {
            User userDB = userService.login(user);
            map.put("state",true);
            map.put("msg","登陆成功");
            map.put("user",userDB);
        }catch (Exception e){
            e.printStackTrace();
            map.put("state", false);
            map.put("msg",e.getMessage());
        }

        return map;
        
    }
    
    
    
    
    

    /*
    * 用来处理用户注册方法
    * 返回一个注册信息到前台
    * */
    @PostMapping("register")
    // 使用@RequestBody的目的是:为了能直接封装对象
    // Axios传数据时,是直接以JSON字符串的形式传
    // 必须要用@RequestBody,才能自动把其转换成我们要的User对象
    // HttpServletRequest: 存储了之前最近一次传给浏览器的验证码信息
    public Map<String, Object> register( @RequestBody User user,String code, HttpServletRequest request){
        log.info("用户信息:[{}]",user.toString());
        log.info("用户输入的验证码:[{}]",code);
        Map<String, Object> map = new HashMap<>();

        try {
            String key = (String) request.getServletContext().getAttribute("code");
            if(key.equalsIgnoreCase(code)){
                //1、调用业务方法
                userService.register(user);
                map.put("state",true);
                map.put("msg","提示:注册成功!");
            }else{
                throw new RuntimeException("验证码异常");
            }
        }catch (Exception e){
            e.printStackTrace();
            map.put("state",false);
            map.put("msg","提示:"+e.getMessage());
        }
        return map;
    }





    /**
     * @description 生成验证码图片
     * <br>
     * @param request   HttpServletRequest对象
     *                  代表客户端的请求,
     *                  当客户端通过HTTP协议访问服务器时,
     *                  HTTP请求头中的所有信息都封装在这个对象中,
     *                  通过这个对象提供的方法,可以获得客户端请求的所有信息。
     * @return java.lang.String
     * @author 淡
     * @since 2021/2/23 12:47
     */
    @GetMapping("getImage")
    public String getImageCode(HttpServletRequest request) throws IOException {
        //1.使用工具类生成验证码
        String code = VerifyCodeUtils.generateVerifyCode(4);
        //2.将验证码放入servletContext作用域
        request.getServletContext().setAttribute("code",code);
        //3.将图片转换成base64
        //字节数组输出流在内存中创建一个字节数组缓冲区,所有发送到输出流的数据保存在该字节数组缓冲区中。
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        //将得到的验证码,使用工具类生成验证码图片,并放入到字节数组缓存区
        VerifyCodeUtils.outputImage(220,60,byteArrayOutputStream,code);
        //使用spring提供的工具类,将字节缓存数组中的验证码图片流转换成Base64的形式
        //并返回给浏览器
        return "data:image/png;base64," + Base64Utils.encodeToString(byteArrayOutputStream.toByteArray());

    }

}

UserService:

package com.chen.service;

import com.chen.entity.User;

public interface UserService {

    //用户注册
    void register(User user);

    //用户登录
    User login(User user);
}

UserServiceImp:

package com.chen.service;

import com.chen.dao.UserDAO;
import com.chen.entity.User;
import com.chen.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.util.Date;

/**
 * @author 淡
 * @version 1.0
 * @description
 * @create 2021-02-23 15:55
 */
@Service
@Transactional
public class UserServiceImpl implements UserService {

    @Autowired
    // 1、这个其实也是一个工具对象,通过它来调用业务方法
    // 2、业务方法,其实是写在UserMapper.xml里
    // 3、UserDAO通过@Mapper、UserMapper.xml通过namespace的指向,来使两者连系在一起
    // 4、UserMapper通过id这个属性,来分别对应UserDAO接口的方法
    // 5、实际上,UserMapper是UserDAO里方法的方法体,是方法的实现
    // 6、这其实就是设计模式中(依赖倒转原则)的一个体现

    // ps:依赖倒转原则:
    // 1. 高层模块不应依赖底层模块,二者应该依赖其抽象。
    // 2. 抽象不应该依赖细节,细节应该依赖抽象
    // 3. 此原则的中心是:面向接口编程
    // 4. 此原则的设计理念:相对细节的多变性,抽象的东西要稳定的多;
    //                   以抽象为基础搭建的架构,比以细节为基础的架构要稳定的多
    // 5. 使用接口或抽象类的目的是制定好规范,而不涉及任何细节,
    //    把展现细节的任务交给他们的实现类去完成
    private UserDAO userDAO;


    @Override
    public void register(User user){
        //0. 根据用户输入的用户名判断用户是否存在
        User userDB = userDAO.findByUserName(user.getUsername());
        if(userDB == null){
            //1. 生成用户状态
            user.setStatus("已激活");
            //2. 设置用户注册时间
            user.setRegisterTime(new Date());
            //3. 调用DAO
            userDAO.save(user);
        }else{
            throw new RuntimeException("用户名已存在!");
        }


    }

    @Override
    public User login(User user) {
        // 1. 根据用户输入的用户名进行查询
        User userDB = userDAO.findByUserName(user.getUsername());
        if(!ObjectUtils.isEmpty(userDB)){
            // 2. 比较密码
            if(userDB.getPassword().equals(user.getPassword())){
                return userDB;
            }else{
                throw new RuntimeException("密码错误");
            }
        }else {
            throw new RuntimeException("用户名输入错误");
        }


    }
}

UserDAO:

package com.chen.dao;

import com.chen.entity.User;
import org.apache.ibatis.annotations.Mapper;

@Mapper //创建DAO对象
public interface UserDAO {

    void save(User user);

    User findByUserName(String username);
}

UserMapper:

<?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" >
<mapper namespace="com.chen.dao.UserDAO">

<!--    save-->
<!--     useGeneratedKeys="true"把新增加的主键赋值到自己定义的keyProperty(id)中-->
    <insert id="save" parameterType="User" useGeneratedKeys="true" keyProperty="id">
        insert into t_user values (#{id},#{username},#{realName},#{password},#{sex},#{status},#{registerTime})
    </insert>

    <select id="findByUserName" parameterType="String" resultType="User">
        select id, username,realname,password,sex,status,regsterTime
        from t_user where username=#{username}
    </select>

</mapper>
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值