MyBatis(3)

news2024/11/24 15:21:56

 我们在进行指定ID进行删除的时候还可以加上一个属性:表示要传递的参数的类型是啥

<delete id="Delete" parameterType="java.lang.Integer">
      delete from user where userID=#{userID}
  </delete>

我们现在先实现一个场景----我们来进行查询一下UserID是7的学生信息(回顾)

注意:我们再进行查询数据库的操作的时候,进行写方法的时候,不可以将返回值类型写成int,既然是查询,那么返回的一定是一条一条的纪录

一:UserController里面的代码:

package com.example.demo.Controller;
import com.example.demo.Service.UserService;
import com.example.demo.User;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.List;
@Controller
public class UserController {
    @Autowired
    UserService userService;
   @RequestMapping("/SelectByID")
   @ResponseBody
   public User SelectByID(Integer userID)
   {
       if(userID==null||userID.equals("")||userID<0)
       {
           return null;
       }
       return userService.SelectByID(userID);
   }
}

二:UserService里面的代码:

package com.example.demo.Service;
import com.example.demo.User;
import com.example.demo.UserMapper.SpringBootMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class UserService {
        @Autowired
        private SpringBootMapper mapper;

    public User SelectByID(Integer userID) {
        return mapper.SelectByID(userID);
    }
}

XML文件里面的代码:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD com.example.demo.Mapper1 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.UserMapper.SpringBootMapper">
   <select id="SelectByID" resultType="com.example.demo.User">
       select * from user where userID="${userID}"
   </select>
</mapper>

MyBatisMapper里面的代码:

  User SelectByID(Integer userID);
我们最终查询的url是:http://127.0.0.1:8080/SelectByID?userID=11
#数据库连接配置:
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/springboot?characterEncoding=utf-8&useSSL=false
spring.datasource.username=root
spring.datasource.password=12503487
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
mybatis.mapper-locations=classpath:mapper/**Mapper.xml
#classpath表示项目的根路径,这里面的mapper和resources下的mapper是对应的,况且这里面的mapper的名称可以是任意的,我们想要在mapper目录里面创建
#xml文件,后缀名就必须是Mapper.xml
#开启MyBatisSQL语句打印
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

上面进行的查询语句还可以写成这种,那么使用#{}和使用${}他们之间有什么区别那?

  select * from user where userID=#{userID}

1)#是不会发生SQL注入的问题的,是当我们使用$时会发生SQL注入的问题,但是当我们使用order by进行查询的时候,我们所传递的参数一定要是程序员自己进行传入的,或者说当用户进行传入的时候我们直接调用replace方法直接把我们的单引号去掉,这样就可以减少SQL注入的发生

2)下面是我们自己写的一个登录功能:

1)UserController里面的代码:

package com.example.demo.Controller;

import com.example.demo.Service.UserService;
import com.example.demo.User;
import netscape.security.UserTarget;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.HashMap;
import java.util.List;

@Controller
public class UserController {
    @Autowired
    UserService userService;

  @RequestMapping("/Login")
    @ResponseBody
    public HashMap<String, Object> login(String username, String password,HttpServletRequest req)
  {
      HashMap<String,Object> map=new HashMap<>();
      String message="登陆成功";
      int state=1;
      if(username==null||password==null||username.equals("")||password.equals(""))
      {
          String str="当前您传递的用户名或者密码不存在,说明您传递参数丢失";
          state=-1;
      }else {
          User user = userService.login(username,password);
          if (user == null || user.equals("") || user.getUserID() < 0) {
              message = "您当前登录失败,用户名错误,在数据库中无法查询";
              state = -1;
          } else {
              message = "您当前登录成功";
              HttpSession httpSession=req.getSession(true);
              httpSession.setAttribute("user",user);
          }
      }
      map.put("message",message);
      map.put("state",state);
      return map;
  }
}

2)UserService里面的代码:

package com.example.demo.Service;
import com.example.demo.User;
import com.example.demo.UserMapper.SpringBootMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class UserService {
        @Autowired
        private SpringBootMapper mapper;
    public User login(String username,String password) {
        return mapper.login(username,password);
    }
}

3)我们写一下Mapper里面的代码:

 User login(String username,String password);
xml文件里面的代码:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD com.example.demo.Mapper1 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.UserMapper.SpringBootMapper">
  <select id="login" resultType="com.example.demo.User">
      select * from user where username=#{username} and password=#{password}
  </select>
</mapper>

但是当我们使用#的时候,查看程序是不会发生SQL注入的问题的:

 但是此时我们如果是把#改成$符,那么此时如果我们想输入密码还是' 1 or 1='1的时候,虽然不会登录成功,但是会成功的查询出所有的SQL语句:

http://127.0.0.1:8080/Login?username=李佳伟&passwor=’ or 1='1

 select * from user where username="${username}" and password='${password}'

所以我们一定要对前端用户输入的值进行过滤

User user = userService.login(username,password.replace("'",""));

1)#{}是预编译处理,是占位符,${}是字符串替换,是拼接符

2)Mybatis在处理#{}的时候会将sql中的#{}替换成?号,调用PreparedStatement来赋值

3)使用#{}是可以进行有效防止SQL注入的问题的

4)我们来假设一个场景:他可以适用于SQL关键字的替换,我们需要在浏览器上面输入一个指令,来返回MYSQL进行查询的结果,根据querystring中的字段order返回结果,它只能有两个值,一个是asc一个是desc,我们可以根据userID来进行升序查询也可以进行降序查询-----下面我们来进行写一段代码进行演示:

输入:127.0.0.1:8080/Java100?order=desc

一:我们在UserController里面的代码:

package com.example.demo.Controller;
import com.example.demo.Service.UserService;
import com.example.demo.User;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.List;
@Controller
public class UserController {
    @Autowired
    UserService userService;
  @RequestMapping("/GetAll")
  @ResponseBody
  public List<User> GetAll(String order)
  {
      //我们首先要在Controller层进行参数校验
      if(order==null||order.equals(""))
      {
          return null;
      }
      return userService.GetAll(order);
  }
}

二:我们在UserService里面的代码:

package com.example.demo.Service;
import com.example.demo.User;
import com.example.demo.UserMapper.SpringBootMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class UserService {
        @Autowired
        private SpringBootMapper mapper;
    public List<User> GetAll(String order) {
        return mapper.GetAll(order);
    }
}

三:我们在接口里面和XML文件里面的代码:

  List<User> GetAll(String order);
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD com.example.demo.Mapper1 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.UserMapper.SpringBootMapper">
   <select id="GetAll" resultType="com.example.demo.User">
       select * from user order by userID ${order}
   </select>
</mapper>

我们如果在这里面直接使用的是#{变量名}的方式,程序就会发生报错,这个时候的查询语句就变成:

select * from user order by userID ' 'desc' '

 但是这种情况是不会发生SQL注入的,是由程序员是进行这个操作的(不是由用户操作的),直接把单引号过滤掉,运用replace方法,里面加入要替换的字符串,过滤用户前台的输入词

小技巧:我们在application.properties里面写上一句:就可以看到执行的SQL

mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

SQL注入:'+空格+or+空格+or+1=’1;(and优先级最高)+后面还可以加上delete语句,把数据库搞没了

总结:

1)#是进行预处理,而$是直接进行替换

2)#适用于所有的参数类型匹配,但是$只能适用于数值类型匹配

2.1)也就是说#和$再进行数值替换的时候没有任何区别,得到的SQL语句都是相同的,对应的查询SQL语句都是正确的,现在从浏览器上面输入:127.0.0.1:8080/Java100?userID=1;

#:select * from user where userID=1,同时$也是一样的

2.2)127.0.0.1:8080/Java100?username=A&password=123456

但是针对于前端输入的字符串,#会自动将字符串加上双引号,但是$不会自动加上双引号

#:select * from user where username="A"&password="123456"

$:select * from user where username=A&password=123456,除非你给$加上

select * from user where username="${username}" and password="${password}"

3)使用#不会发生SQL注入,使用$是会发生SQL注入问题的:

3.1)User user= userMapper.SelectUser("A","' or 1='1");或者在浏览器上面输入

127.0.0.1:8080/Java100?username=A&password=' or 1=1'

使用$select * from user where username='${username}' and password='${password}'

会发生SQL注入: select * from user where username='A' and password='' or 1='1',但是此时使用#不会发生SQL注入问题

4)但是当我们进行传递的参数是一个查询关键字的时候,我们就要使用$的方式,例如进行SQL排序:127.0.0.1:8080/Java100?order=desc

4.1)使用#:select * from user order by time #{order}

会被自动替换成:select * from user order by time "desc"

4.2)但是现在使用$符的方式:select * from user order by time ${order}

会被自动替换成:select * from user order by time desc;

5)当我们进行like模糊匹配的时候,我们优先使用$,但会发生SQL注入的问题,所以我们需要使用#的形式,还需要进行搭配MYSQL提供的内置函数

select * from user where username like "%#{username}"使用这种格式是错误的,当我们输入:127.0.0.1:8080/Java100?username=a,最终就会变成"%"a"%"

下面我们来演示一下like查询----根据用户在浏览器上面的输入不同的like的值来进行模糊匹配

我们可以写一段代码:

这是UserController里面的代码:

package com.example.demo.Controller;
import com.example.demo.Service.UserService;
import com.example.demo.User;
import netscape.security.UserTarget;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.HashMap;
import java.util.List;
@Controller
public class UserController {
    @Autowired
    UserService userService;
     @RequestMapping("/SelectAll")
     @ResponseBody
    public List<User> start(String name)
     {
         //我们还是需要在Controller层进行参数校验
         if(name==null||name.equals(""))
         {
             return null;
         }
         return userService.start(name);
     }
}

二:我们使用的UserService层的代码和接口层的代码:

package com.example.demo.Service;
import com.example.demo.User;
import com.example.demo.UserMapper.SpringBootMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class UserService {
        @Autowired
        private SpringBootMapper mapper;
    public List<User> start(String name) {
        return mapper.start(name);
    }
}
接口层的代码:
   List<User> start(String name);

三:我们写的XML文件里面的代码:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD com.example.demo.Mapper1 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.UserMapper.SpringBootMapper">
  <select id="start" resultType="com.example.demo.User">
      select * from user where username like '%${name}%'
  </select>
</mapper>

1)我们如果使用$是可以的,但是很有可能会出现安全问题,可以直接过滤,但是如果name有可能是中文名,也有可能是英文名时可能会出现’字符的,所以我们不建议使用这种方法

2)但是我们不可以直接使用#的方式来进行模糊匹配,但是可以使用所以我们可以进行使用MYSQL提供的内置函数,这样做既可以保证了安全,还可以使用#的方式

  select * from user where username like concat('%',#{name},'%')

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/4806.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【毕业设计】大数据共享单车数据分析系统 - python

文章目录0 前言1 项目背景2 项目分析思维导图3 项目分析具体步骤3.1 读取数据3.2 数据分析3.1.1 数据预处理——每日使用量分析3.1.2 连续7天的单日使用分析结论3.1.3 数据预处理——每日不同时间段的使用量分析3.1.4 每日不同时间段使用量分析结论3.1.5 数据预处理——骑行距离…

【C++】智能指针

一、资源的管理 RAII:Resource Acquisition Is Initialization的简称&#xff0c;其翻译过来就是“资源获取即初始化”&#xff0c;即在构造函数中申请分配资源&#xff0c;在析构函数中释放资源&#xff0c;它是C语言中的一种管理资源、避免泄漏的良好方法。 C语言的机制保证…

python快速实现简易超级玛丽小游戏

《超级玛丽》是一款超级马里奥全明星的同人作品&#xff0c;也是任天堂公司出品的著名横版游戏。 《超级马里奥》是一款经典的像素冒险过关游戏。最早在红白机上推出&#xff0c;有多款后续作品&#xff0c;迄今多个版本合共销量已突破4000万套。其中的主角马里奥、路易、碧琪…

[附源码]计算机毕业设计JAVAjsp闲置物品线上交易系统

[附源码]计算机毕业设计JAVAjsp闲置物品线上交易系统 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM …

tensor和numpy相互转换

tensor转成numpy b a.numpy()import torcha torch.arange(5) b a.numpy() print(a) print(type(a)) print(b) print(type(b))numpy转成tensor b torch.tensor(a)import torch import numpy as npa np.ones(5) b torch.tensor(a) print(a) print(type(a)) print(b) prin…

Spring Cloud框架(原生Hoxton版本与Spring Cloud Alibaba)基础入门篇 ---- 搭建环境

springcloud官方文档&#xff08;Hoxton SR5&#xff09;&#xff1a;https://cloud.spring.io/spring-cloud-static/Hoxton.SR5/reference/htmlsingle/ springcloud中文文档&#xff1a;https://www.springcloud.cc/ springcloud中国社区文档&#xff1a;http://docs.springcl…

【C++】栈~~(很详细哦)

在前几天&#xff0c;我们刚一起学过顺序表&#xff0c;链表&#xff08;无头单向不循环&#xff0c;有头双向循环&#xff09;&#xff0c;这两种都属于线性表因为是一系列存储的。而以后的哈希表则是散列表 今天我们看一下栈 目录 1.栈的介绍 2.实现 3.题目 1.栈的介绍 …

mindspore::dataset::GetAffineTransform的输出与cv2的输出不同

在使用C进行推理时用到了函数mindspore::dataset::GetAffineTransform&#xff0c;但是输入相同的数据后&#xff0c;与Python的cv2中的同名函数cv2.getAffineTransform所输出的结果不同。 C Ascend310端测试核心代码 #include <iostream> #include <vector>#…

synchronized 关键字背后的锁升级流程

文章目录前言一、基本特点二、加锁过程总结前言 博主个人社区&#xff1a;开发与算法学习社区 博主个人主页&#xff1a;Killing Vibe的博客 欢迎大家加入&#xff0c;一起交流学习~~ 一、基本特点 结合多线程锁的策略, 我们就可以总结出, Synchronized 具有以下特性(只考虑 J…

基于51单片机的智能台灯设计

一.硬件方案 本文介绍了一种基于PWM调光的智能台灯设计。把单片机技术和PWM调光技术结合起来实现台灯光强的调节。即在不改变PWM方波周期的前提下&#xff0c;利用单片机控制PWM的占空比&#xff0c;从而来改变电压的大小实现灯光亮度的调节。 当人体在台灯的范围内且环…

linux驱动设备节点失踪之迷雾围城

前言 参考文章&#xff1a;无法生成设备节点 最后证实&#xff1a;是bootargs配置错误导致的&#xff0c;不过中间发现也是可以通过mdev -s间接解决的&#xff0c;算是学习经验吧。 misc驱动框架是linux内核驱动中最简单实用的框架了。记录一下今天调试misc驱动的问题。misc驱动…

笔试强训48天——day19

文章目录一. 单选1.二分查找的时间复杂度&#xff08;&#xff09;2. 有一个单向链表中有一个A、B两个相邻元素&#xff0c;有一个指针p指向元素A&#xff0c;现将一个指针r指向的S元素要插入3. 双向链表中有两个指针域,llink和rlink分别指向前驱和后继,设p指向链表中的一个结点…

spark底层原理理解--高级进阶

概念概念理解和解释备注窄依赖窄依赖指1个父RDD分区数据只被1个子RDD的分区使用&#xff0c;即一对一或多对一的关系。 分为两种映射情况&#xff1a;一个父RDD的分区对应于一个子RDD的分区&#xff0c;或者多个父RDD的分区对应于一个子RDD的分区。 1个子RDD的分区对应于1个父R…

深入理解JS作用域链与执行上下文

变量提升&#xff1a; 变量提升&#xff08; hoisting &#xff09;。 我可恨的 var 关键字&#xff1a; 你读完下面内容就会明白标题的含义&#xff0c;先来一段超级简单的代码&#xff1a; <script type"text/javascript">var str Hello JavaScript hoi…

【K8S】初探Kubernetes

文章目录什么是容器编排什么是KubernetesK8s 和 Docker 之间的关系Kubernetes的整体架构Master 里的组件构成Work Node 里的组件构成总结K8s 组件工作流程结束语什么是容器编排 在《Docker 进阶指南&#xff08;下&#xff09;- 使用Docker Compose编排多个容器》文章当中&…

文件缓冲区

本期介绍&#x1f356; 主要介绍&#xff1a;什么是文件缓冲区&#xff0c;文件缓冲区存在的意义是什么&#xff0c;文件缓冲区的证明&#x1f440;。 一、什么是文件缓冲区 每一个正在使用的文件&#xff0c;操作系统都会为其在内存中开辟一块区域&#xff0c;称之为&#xff…

【数据结构】带头双向链表的简单实现

目录前言链表的实现List.hList.c**ListCreate()****LTInit()****ListPushBack()****ListPopBack()****ListPrint()****ListPushFront()****ListPopFront()****ListFind()****ListInsert()****ListErase()**ListErase()test.c前言 该篇博客主要讲解了带头双向链表的实现和一些细…

Cadence Allegro DXF结构图的导入详细教程

很多消费类板卡的结构都是异形的&#xff0c;由专业的CAD结构工程师对其进行精准的设计&#xff0c;PCB布线工程师可以根据结构工程师提供的2D图&#xff08;DWG或DXF格式&#xff09;进行精准的导入操作&#xff0c;在PCB中定义板型结构。 同时&#xff0c;对于一些工控板或者…

Ajax--跨域与JSONP--案例-淘宝搜索

要实现的UI效果 获取用户输入的搜索关键词 为了获取到用户每次按下键盘输入的内容&#xff0c;需要监听输入框的 keyup 事件&#xff0c;示例代码如下&#xff1a; // 监听文本框的 keyup 事件$(#ipt).on(keyup, function() {// 获取用户输入的内容var keywords $(this).val…

支撑向量机

1、支持向量机算法原理 支持向量机&#xff08;Support Vetor Machine&#xff0c;SVM&#xff09;由Vapnik等人于1995年首先提出&#xff0c;在解决小样本、非线性及高维模式识别中表现出许多特有的优势&#xff0c;并推广到人脸识别、行人检测和文本分类等其他机器学习问题中…