我们在进行指定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},'%')