jdbc-代码重用和登录防sql注入

在刚刚学习jsp的时候,总是会遇到一些比较简单的sql注入的语句,例如or ‘1’ = ‘1’这种代码。从mysql里面解释的话,就是mysql拥有where = true就全部数据返回的功能,不过不太清楚这个设计。所以新手是提交容易遇到注入的事情。而且新手最常见的一个现象就是代码的重复度太过于高了,所以一份好的代码,应该是将重复的部分都结构化让其调用,这样子代码更简洁,找错误也不会这里一块那里一块的。

这里面的代码优化其实就是使用Statement的继承对象prepareStatement,这个对象可以进行一些简单的sql注入过滤,这样子就不会有这么低级的漏洞出现了。

这里的公共代码如下:

未过滤前的代码:

package com.d.cn.test;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Scanner;

import com.d.cn.dao.entity.User;
import com.d.cn.dao.utils.JdbcUtil;

public class Login {
	/*
	 * 获取数据库信息函数
	 * 
	 * */
	public User getUserMsg(User user){
		User ResultUser = null;
		Connection conn = null;
		ResultSet rs = null;
		Statement state = null;
		try {
			
			conn = JdbcUtil.getConnection();
			String sqlAll = "SELECT id ,name , password FROM `user` WHERE name='"+user.getName()+"' AND password='"+user.getPassword()+"'";
			//用statement接口发送sql语句并执行,执行后的结果集放在ResultSet
			state = conn.createStatement();
			rs = state.executeQuery(sqlAll);
			//处理结果
			while (rs.next()) {
				ResultUser = new User();
				ResultUser.setId(rs.getInt("id"));
				ResultUser.setName(rs.getString("name"));
				ResultUser.setPassword(rs.getString("password"));
			}
		
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			System.out.print("错误了");
			e.printStackTrace();
		}finally{
			
			JdbcUtil.closeAll(conn, state, rs);
			
		}
		return ResultUser;
	}
	//业务层
	public User loginService(User user){
		System.out.println("业务方法被调用!");
		System.out.println("接着调用数据库打交道的方法!");
		return this.getUserMsg(user);
	}
	//用户交互层
	public void loginView(){
		Scanner input = new Scanner(System.in);
		System.out.print("输入用户名:");
		String name = input.next();
		System.out.print("输入密码:");
		String password = input.next();
		User user = new User(0,name,password);
		User resultUser = this.loginService(user);
		if(resultUser != null){
			System.out.print("登录成功!!!");
		}else{
			System.out.print("登录失败!!!");
		}
	}
	
	public static void main(String[] args) {
		Login login = new Login();
		login.loginView();
	}
}

过滤后:

这个新函数是可以直接将sql的变量直接使用?来表示,之后再调用其的setObject函数来对问号的哪些变量赋值,这样子就能够将数据分离起来了,在setObject函数也可以写一些过滤sql注入的规则。

package com.d.cn.test;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Scanner;

import com.d.cn.dao.entity.User;
import com.d.cn.dao.utils.JdbcUtil;

public class Login2 {
	/*
	 * 获取数据库信息函数
	 * 
	 * */
	public User getUserMsg(User user){
		User ResultUser = null;
		Connection conn = null;
		ResultSet rs = null;
		PreparedStatement ps = null;
		try {
			
			conn = JdbcUtil.getConnection();
			/*使用prepareStatement对数据进行处理
			 * 1.性能相对Statement有所提高
			 * 2.防止sql的简单注入 1=1
			 * 3.代码更加直观
			 */
			String sqlAll = "SELECT id ,name , password FROM `user` WHERE name=? AND password=?";
			//用statement接口发送sql语句并执行,执行后的结果集放在ResultSet
			ps = conn.prepareStatement(sqlAll);
			ps.setObject(1, user.getName());
			ps.setObject(2, user.getPassword());
			rs = ps.executeQuery();
			//处理结果
			while (rs.next()) {
				ResultUser = new User();
				ResultUser.setId(rs.getInt("id"));
				ResultUser.setName(rs.getString("name"));
				ResultUser.setPassword(rs.getString("password"));
			}
		
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			System.out.print("错误了");
			e.printStackTrace();
		}finally{
			
			JdbcUtil.closeAll(conn, ps, rs);
			
		}
		return ResultUser;
	}
	//业务层
	public User loginService(User user){
		System.out.println("业务方法被调用!");
		System.out.println("接着调用数据库打交道的方法!");
		return this.getUserMsg(user);
	}
	//用户交互层
	public void loginView(){
		Scanner input = new Scanner(System.in);
		System.out.print("输入用户名:");
		String name = input.next();
		System.out.print("输入密码:");
		String password = input.next();
		User user = new User(0,name,password);
		User resultUser = this.loginService(user);
		if(resultUser != null){
			System.out.print("登录成功!!!");
		}else{
			System.out.print("登录失败!!!");
		}
	}
	
	public static void main(String[] args) {
		Login2 login = new Login2();
		login.loginView();
	}
}

上面的代码中的JdbcUtil其实还没有做到最简的操作,所以代码上存在着许多重复代码,增加维护的难度。所以下面是对代码的优化(未优化的代码在我的上一篇文章可以找到):

package com.d.cn.dao.utils;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import com.d.cn.dao.entity.User;

public class JdbcUtil {
	public static Connection conn = null;
	static{
		try {
			Class.forName("com.mysql.jdbc.Driver");
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	public static Connection getConnection(){
		try {
			conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/javatest","root","root");
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return conn;
	}
	
	public static void closeAll(Connection conn,Statement state,ResultSet rs){
		if(rs!=null){
			try {
				rs.close();
			} catch (Exception e) {
				// TODO Auto-generated catch block
				System.out.print("错误了");
				e.printStackTrace();
			}
		}
		
		if(state!=null){
			try {
				state.close();
			} catch (Exception e) {
				// TODO Auto-generated catch block
				System.out.print("错误了");
				e.printStackTrace();
			}
		}
		
		if(conn!=null){
			try {
				conn.close();
			} catch (Exception e) {
				// TODO Auto-generated catch block
				System.out.print("错误了");
				e.printStackTrace();
			}
		}
	}
	//重复代码提取出来,只是sql和sql的参数是不同的,所以可以提取这两个变量出来
	public static int commonExcue(String sql,Object[] object){
		int row = -1;
		
		Connection conn = null;
		PreparedStatement ps = null;
		
		try {
			
			conn = JdbcUtil.getConnection();
			ps = conn.prepareStatement(sql);
			
			for (int i = 0; i < object.length; i++) {
				ps.setObject(i+1, object[i]);
			}
			
			row = ps.executeUpdate();
			
		}catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally{
			JdbcUtil.closeAll(conn, ps, null);
		}
		
		return row;
	}
	
}

用来测试上面的代码:

package com.d.cn.test;

import java.util.List;
import java.util.Scanner;

import com.d.cn.dao.entity.User;
import com.d.cn.test.jdbcCrud;

public class test {
	public static void main(String[] args) {
		
//		//查询
//		jdbcCrud jdbcCrud = new jdbcCrud();
//		List<User> users = jdbcCrud.listAll();
//		System.out.println("编号\t姓名\t密码\t");
//		for (User user : users) {
//			System.out.println(user.getId()+"\t"+user.getName()+"\t"+user.getPassword());
//		}
		
//		//添加数据
//		jdbcCrud jdbcCrud = new jdbcCrud();
//		int flag = jdbcCrud.insert(new User(3,"六六","123"));
//		if(flag==1){
//			System.out.println("添加数据成功!");
//		}else{
//			System.out.println("添加数据失败!");
//		}
		
		删除数据
//		jdbcCrud jdbcCrud = new jdbcCrud();
//		int flag = jdbcCrud.delete(new User(3,"",""));
//		if(flag==1){
//			System.out.println("删除数据成功!");
//		}else{
//			System.out.println("删除数据失败!");
//		}
		
		修改数据
//		jdbcCrud jdbcCrud = new jdbcCrud();
//		int flag = jdbcCrud.update(new User(3,"六六1","3333"));
//		if(flag==1){
//			System.out.println("修改数据成功!");
//		}else{
//			System.out.println("修改数据失败!");
//		}

		
//		//	修改数据
//	jdbcCrud jdbcCrud = new jdbcCrud();
//	Scanner Input = new Scanner(System.in);
//	System.out.print("请输入登录用户名:");
//	String name = Input.next();
//	System.out.print("请输入登录密码:");
//	String password = Input.next();
//	User ResultUser = jdbcCrud.getUserMsg(new User(0,name,password));
//	if(ResultUser!=null){
//		System.out.println("登录成功!");
//	}else{
//		System.out.println("登录失败!");
//	}
		
	}
}

因为上面修改的只是一个封装的函数,所以这个测试类基本和上一篇的代码是一样的,毕竟只是对代码内部上添加了一个静态方法来去除重复代码。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值