Java第六次实验作业(山东大学)

【实验目的】  

(1)掌握MySQL数据库的安装和使用

(2)掌握通过JDBC方式操作数据库的基本步骤。

(3)掌握增、删、改、查记录的方法。

(4)学习MysqlDemo.java,完成简单的学生信息管理

【实验具体内容】

1.掌握MySQL数据库的安装和基本使用,在本机登录mysql后,利用GRANT授权法,实现远程访问数据库

服务器安装Mysql5.7,新建一个数据库名为sdujava,允许所有ip访问,放开服务器防火墙.

在IDEA中测试一下MysqlDemo.java.localhost改为服务器公网IP.

实验源程序: (MysqlDemo.java)

package Sixth;
import java.sql.*;

public class MysqlDemo {
    public static void main(String[] args) throws SQLException {
        Connection conn = null;
        String sql;
        String url = "jdbc:mysql://公网IP:3306/sdujava?"
                + "user=sdujava&password=ANkYKf6LdJznSaRt&useUnicode=true&characterEncoding=UTF8";
        try {
            // 之所以要使用下面这条语句,是因为要使用MySQL的驱动,所以我们要把它驱动起来,
            // 可以通过Class.forName把它加载进去,也可以通过初始化来驱动起来,下面三种形式都可以
            Class.forName("com.mysql.jdbc.Driver");// 动态加载mysql驱动
            // or:
            // com.mysql.jdbc.Driver driver = new com.mysql.jdbc.Driver();
            // or:
            // new com.mysql.jdbc.Driver();

            System.out.println("成功加载MySQL驱动程序");
            // 一个Connection代表一个数据库连接
            conn = DriverManager.getConnection(url);
            // Statement里面带有很多方法,比如executeUpdate可以实现插入,更新和删除等
            Statement stmt = conn.createStatement();
            sql = "create table student(NO char(20),name varchar(20),primary key(NO))";
            int result = stmt.executeUpdate(sql);// executeUpdate语句会返回一个受影响的行数,如果返回-1就没有成功
            if (result != -1) {
                System.out.println("创建数据表成功");
                sql = "insert into student(NO,name) values('2012003','Java1')";
                result = stmt.executeUpdate(sql);
                sql = "insert into student(NO,name) values('2012004','Java2')";
                result = stmt.executeUpdate(sql);
                sql = "insert into student(NO,name) values('2012005','Java3')";
                result = stmt.executeUpdate(sql);
                sql = "select * from student";
                ResultSet rs = stmt.executeQuery(sql);// executeQuery会返回结果的集合,否则返回空值
                System.out.println("学号\t姓名");
                while (rs.next()) {
                    System.out.println(rs.getString(1) + "\t" + rs.getString(2));// 入如果返回的是int类型可以用getInt()
                }
            }
        } catch (SQLException e) {
            System.out.println("MySQL操作错误");
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            conn.close();
        }
    }
}

实验运行结果:

2.学习MysqlDemo.java,熟悉GUI的同学可以编写一个简单的学生信息管理系统界面。如果不熟悉GUI,可以建立几个button来实现以下功能:

先创建student表,包含学生的学号、姓名、年龄信息。

① 点击“查询”按钮,根据学号,可以查询到学生的姓名和年龄;

② 点击“追加”按钮,根据给定的学生学号、姓名、年龄,在表中追加一行信息;

③ 点击“删除”按钮,利用给定的学生学号,可以从表中删除该学生的信息;

实验源程序:

package Sixth;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import  java.awt.Color;
import java.awt.BorderLayout;
import java.awt.event.*;
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.JPanel;
import javax.swing.JLabel;

//这个类里面有6个方法,主方法main()必须是公共的,其他都是设置为了protected,体现一个权限概念;这些方法都设置成了静态的,这个类无需实例化就可以直接调用这些方法
public class Mysql extends JFrame implements ActionListener {
    //给个序列号,保证对象串行化和存储
    private static final long serialVersionUID= 1L;
    /**按键*/
    private final String[] KEYS={"查询","追加","删除","清框"    };
    /**按键的按钮*/
    private JButton keys[]=new JButton[KEYS.length];
    /**交互文本框*/
    public JTextField interactText=new JTextField(" ");
    /**提示标签*/

    public JLabel label=new JLabel("<html><body><p align=\"center\">输入格式为'name.id.age'来追加一行新的学生信息<br/>输入id,点击查询来查询学生信息<br/>输入id,点击删除来删除学生信息</p></body></html>");

    //创建静态全局变量
    //因为几个方法都是静态的,在静态方法内部要使用这两个引用变量,所以他们也必须是静态的
    static Connection conn;
    static Statement st;

    /**构造函数*/
    public Mysql(){
        //调用public JFrame(String title)构造方法,构造一个新的、最初不可见的、具有指定标题的 Frame 对象
        super(" 学生信息管理系统");
        init();
        setBounds(300, 500, 500,500);
        //用来设置此窗体是否可由用户调整大小,参数:resizable - 如果此窗体是可调整大小的,则为 true;否则为 false
        this.setResizable(true);
        //使得各个组件大小合适
        this.pack();//调整此窗口的大小,以适合其子组件的首选大小和布局
    }

    protected  void init(){
        //创建一个新的面板
        JPanel panel=new JPanel();
        panel.setLayout(new GridLayout(1,4));
        //把三个按钮组件放上去
        for(int i=0;i<KEYS.length;i++){
            //给这3个符号创建相应的按钮
            keys[i]=new JButton(KEYS[i]);
            //将key组件追加到此容器的尾部,加进到面板中
            panel.add(keys[i]);
            //设置符号的颜色
            keys[i].setBackground(Color.black);
            //设置符号的颜色
            keys[i].setForeground(Color.white);
        }
        //建立一个画板放文本框
        JPanel top =new JPanel();
        //构造一个组件之间没有间距的新边框布局
        top.setLayout(new BorderLayout());
        top.add("Center",interactText);

        //建立一个画板放提示标签
        JPanel reminder =new JPanel();
        //构造一个组件之间没有间距的新边框布局
        top.setLayout(new BorderLayout());
        reminder.add("Center",label);

        //新建一个大的画板,把上面建立的画板放在该画板内
        JPanel panel1=new JPanel();
        //画板采用边界布局管理器,画板里组件之间的水平和垂直的方向上相隔都是3像素
        //构造一个具有指定组件间距(水平间距为5,垂直间距也是5个像素)的边框布局
        panel1.setLayout(new BorderLayout(10,10));
        //将commands画板放在计算器的北部
        panel1.add("North",reminder);
        panel1.add("Center",interactText);
        panel1.add("South",panel);

        //整体布局,这段代码至关重要,没有就不会显示新建的这些面板和布局,这就体现了Frame的组成中一个非常重要的ContentPane,必须加进去才能被我们看到!!
        getContentPane().setLayout(new BorderLayout(5,5));
        getContentPane().add("North",top);
        getContentPane().add("Center",panel1);

        //结果左对齐显示
        interactText.setHorizontalAlignment(JTextField.LEFT);
        //先设置为不可以编辑,后面状态改成true,可以编辑就会触发 PropertyChange 事件("editable")
        interactText.setEditable(true);
        //文本框的颜色
        interactText.setBackground(Color.lightGray);

        //为各个按钮添加事件监听器
        for(int i=0;i<KEYS.length;i++){
            keys[i].addActionListener(this);
        }

    }

    /**
     * 处理事件
     */
    //自定义的方法,组件发生动作时会产生事件,传递给这个对象
    public void actionPerformed(ActionEvent e){
        //获取事件源的标签
        //当特定于组件的动作(比如被按下)发生时,由组件(比如 Button)生成此高级别事件。事件被传递给每一个 ActionListener 对象,这些对象是使用组件的 addActionListener 方法注册的,用以接收这类事,返回与此动作相关的命令字符串。
        String label =e.getActionCommand();
        //如果用户按了"查询"键
        if (label.equals(KEYS[0])){
            handleQuery();
        }
        //如果用户按了"追加"键
        else if (label.equals(KEYS[1])){
            handleInsert();
        }
        //如果用户按了"删除"键
        else if (label.equals(KEYS[2])){
            handleDelete();
        }
        //如果用户按了"清框"键
        else if (label.equals(KEYS[3])){
            handleClear();
        }
    }

    /**
     * 处理查询键被按下的事件
     */
    private void handleQuery(){
        String s=interactText.getText();
        interactText.setText("");
        conn = getConnection(); //同样先要获取连接,即连接到数据库
        try {
            // 查询数据的sql语句 ,*是通配符,代表所有的数据
            String sql = "select   * from studentinfo where id='"+s+"' ";
            //String sql = "select   * from studentinfo where name='"+s+"' ";
            st = (Statement) conn.createStatement();    //创建用于执行静态sql语句的Statement对象,st属局部变量
            ResultSet rs = st.executeQuery(sql);    //执行sql查询语句,返回查询数据的结果集
            while (rs.next()) { //这个while必须要有,没有就查询不出来
                String name=rs.getString("name");
                String id=rs.getString("id");
                String age=rs.getString("age");
                interactText.setText(name+"\t"+id+"\t"+age);
            }
            st.close() ;//关闭数据库连接


        } catch (SQLException e) {
            interactText.setText ("查询数据失败");
        }
    }


    /**
     * 处理追加键被按下的事件
     */
    private void handleInsert(){
        conn = getConnection(); // 首先要获取连接,即连接到数据库,得到的是一个Connection接口类的对象  ,因为是静态方法所以直接调用
        String s=interactText.getText();
        interactText.setText("");
        //输入必须要用“name.id.age”这样的格式输入
        String[] a=s.split("\\.");
        for(int i=0;i<a.length;i++){
            System.out.println(a[i]);
        }
        try {
            // 插入数据的sql语句
            String sql = "INSERT INTO studentinfo(name, id ,age)" + " VALUES ('"+a[0]+"','"+a[1]+"','"+a[2]+"')";  // 插入数据的sql语句
            // 创建用于执行静态sql语句的Statement对象
            st = (Statement) conn.createStatement();
            // 执行插入操作的sql语句,并返回插入数据的个2数
            st.executeUpdate(sql);
            //立即释放此 Statement 对象的数据库和 JDBC 资源,这样可以避免对数据库资源的占用。
            st.close() ;
            //如果没有出现异常,插入成功以后就关闭数据库连接
            conn.close();   
            interactText.setText("追加数据成功");
        } catch (SQLException e) {  //executeUpdate(sql)抛出了这个异常,所以要捕获
            interactText.setText("追加数据失败" + e.getMessage());
            System.out.println ("追加数据失败" + e.getMessage());
        }
    }

    /**
     * 处理删除键被按下的事件,删除符合要求的记录
     */
    private void handleDelete(){
        conn = getConnection(); //同样先要获取连接,即连接到数据库  ,这是自定义的函数
        String s=interactText.getText();
        interactText.setText("");
        try {
            // 删除该学号对应的信息的sql语句
            String sql = "delete from studentinfo  where id = '"+s+"'";
            //创建用于执行静态sql语句的Statement对象,st属局部变量
            st = (Statement) conn.createStatement();
            // 执行sql删除语句,返回删除数据的数量
            st.executeUpdate(sql);
            //立即释放此 Statement 对象的数据库和 JDBC 资源,这样可以避免对数据库资源的占用。
            st.close() ;
            //关闭数据库连接
            conn.close();
            interactText.setText("删除数据成功");
        } catch (SQLException e) {
            System.out.println("删除数据失败");
            interactText.setText("删除数据失败");
        }
    }

    /**
     * 处理清框键被按下的事件
     */
    private void handleClear(){
        interactText.setText("");
    }
    
    /* 自定义的获取数据库连接的函数*/
    protected static Connection getConnection() {  //用Connection接口类作为返回值类型,这个getConnection方法不是JdbcTest类的,而是这个Connection类的
        Connection con = null;  //创建用于连接数据库的Connection对象  ,只用于这个方法内部。局部变量
        try {  // 动态加载Mysql数据驱动,利用java.lang.Class类的forName方法,方法的参数是一个字符串,
            //是类名 ,返回与带有给定字符串名的类或接口相关联的 Class 对象,所以也是实例化这个类
            Class.forName("com.mysql.jdbc.Driver");//返回的这个对象怎么用?设时候用?有什么用?
            //我新建的数据库叫做studentinfo,用户名和密码分别是root和JAVA
            /*
            useUnicode=true&characterEncoding=UTF8添加的作用是
            指定字符的编码、解码格式。mysql数据库用的是gbk编码,而项目数据库用的是utf-8编码。这时候如果添加了useUnicode=true&characterEncoding=UTF-8 ,那么作用有如下两个方面:
            存数据时:数据库在存放项目数据的时候会先用UTF-8格式将数据解码成字节码,然后再将解码后的字节码重新使用GBK编码存放到数据库中。
            取数据时:在从数据库中取数据的时候,数据库会先将数据库中的数据按GBK格式解码成字节码,然后再将解码后的字节码重新按UTF-8格式编码数据,最后再将数据返回给客户端。
            */
            con = DriverManager.getConnection(  "jdbc:mysql://公网IP:3306/sdujava?"
                    + "user=sdujava&password=7Sie4KRAEbdshtJT&useUnicode=true&characterEncoding=UTF8");
        } catch (SQLException ex) {//getConnection()抛出了这个异常,在这里捕获
            System.out.println("MySQL操作错误");
            System.out.println("SQLException: " + ex.getMessage());
            System.out.println("SQLState: " + ex.getSQLState());
            System.out.println("VendorError: " + ex.getErrorCode());
            ex.printStackTrace();
        } catch(ClassNotFoundException e){   //使用forName方法加载驱动有可能出现找不到类的异常
            System.out.println("找不到驱动程序类 ,加载驱动失败!+e.getMessage()");
            e.printStackTrace() ;
        }  catch (Exception e) {  //保证对于所有的异常都一定有通道,所以在最后一个catch写最大的异常类
            System.out.println("数据库连接失败" + e.getMessage());
        }
        return con; //返回所建立的数据库连接,一个Connection类的引用
    }

    public static void main(String[] args) {
        Mysql jdbc=new Mysql();
        //显示GUI界面
        jdbc.setVisible(true);
        jdbc.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
}


实验运行结果:

实验前,我已经在数据库中建立了一个名为sdujava的库,其中有一张表,表名叫做studentinfo,表中有三个字段,分别为name,id,age,分别对应学生姓名,学生学号和学生年龄.

其中的实验代码和老师给出的MysqlDemo,java差不多,不过是增加了一个字段,我就不展示了

最后的结果如下所示:

接下来运行程序:

程序运行界面如下:

追加信息后,数据库内容如下:

【实验心得】

1.任意IP都可访问

命令:

GRANT ALL PRIVILEGES ON *.* TO ‘root’@’%’ IDENTIFIED BY ‘password’ WITH GRANT OPTION;

/*字段解释:*.*:可访问所有数据库,可指定数据库;

‘root’:登陆用户名;

‘%’:任意IP可登陆;

password:为个人数据库登陆密码;

WITH GRANT OPTION;可赋予其他用户权限*/

2.指定IP可访问

GRANT ALL PRIVILEGES ON *.* TO ‘root’@’IP.%’ IDENTIFIED BY ‘password’ WITH GRANT OPTION;

/*字段解释:*.*:可访问所有数据库,可制定数据库;

‘root’:登陆用户名;

‘IP.%’:指定的IP可登陆,其他IP不行;

password:为个人数据库登陆密码;

WITH GRANT OPTION;可赋予其他用户权限*/

3.删除远程访问权限

直接删除对应的用户即可:

drop user 用户名@’%’;

记得每次创建或删除后运行以下命令,用于重新载入权限表:

flush privileges;

4.对varchar类的字段用一对单引号嵌套一对双引号,并且里面要用两个+把字段围起来,对于int型的变量就只需要一对单引号

5.Swing中的JLabel是支持基本的HTML代码的,

同样的JTextPane、JEditorPane也支持简单的HTML代码。

JLabel中换行是需要HTML的<br>标签进行换行的,不能用\n直接换行。

6. conn.close();必须写在try语句块里面,不能写在finally里面或者直接写在catch后面

7. protected static Connection getConnection() {····},定义方法在方法名前面加上java.sql的Connection接口类,是一个返回值类型,用类作为返回值类型,因为方法最后return了一个Connection类的引用,这个方法仍然是JdbcTest类的。

© 版权声明
THE END
喜欢就支持以下吧
点赞2赞赏 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容