Java学生管理系统:数据库加强版 (java学生管理系统加数据库)

2023-07-24 15:15:04 数据库 管理系统 学生

随着互联网技术的发展和应用领域的不断扩展,越来越多的数据需要整合和管理。对于学生管理系统而言,基于数据库的管理方式已经成为了当前最为常见和有效的方法之一。在Java编程语言的基础上,应用数据库技术进行学生管理系统的开发,不仅具有管理便捷、效率高、安全可靠等优势,同时也是一种技术逐步发展和完善的表现。

一、Java学生管理系统的基本构成

Java学生管理系统的基本构成框架主要包括:基础框架设计、用户登录注册、学生信息录入、管理查询与增删改查等。

在基础框架设计中,根据学生管理系统实现的要求和业务流程,进行系统整体架构和关键细节的设计。这里需要考虑到用户界面的友好性和操作的便捷性,同时也需要注意到系统的稳定性和安全性。一般而言,这一环节可以通过前期需求分析、系统架构设计以及用户访谈等方式来确立。

在用户登录注册中,主要是对用户身份的验证和管理。使用Java提供的身份验证机制、Cookie技术或者Token验证等方式,实现用户信息的查找、注册与登录,并统一能够接入第三方登录API接口,方便用户快速登录管理系统。

在学生信息录入环节中,可以通过Java开发框架中提供的ORM技术(如Hibernate,MyBatis等),连接数据库并实现对学生信息的录入和维护,包括学生基本信息、成绩信息、考勤信息、课程安排和选修情况等。

在管理查询与增删改查环节中,管理员可以通过学生管理系统的管理界面对学生信息进行查找、修改、删除和添加等操作,将学生个人信息唯一化地存储、进行数据分析和处理。

以上环节只是Java学生管理系统的基本框架,而其中协同作用最重要的方法之一,就是基于数据库的数据管理。

二、Java学生管理系统中的数据管理

在Java学生管理系统的基本框架之上,数据库作为系统的数据存储和管理平台,是其最为重要的技术之一。使用Java作为系统编程语言,常用的数据库管理方式包括MySQL、Oracle、SQL Server、PostgreSQL等。这里,以MySQL数据库管理平台为例,阐述Java学生管理系统的数据库管理技术。

1. 数据库建库和设计

在MySQL数据库管理平台中,首先需要将基础框架设计中的概念和要求转换为具体的数据库架构和数据库设计。在建库和设计过程中,需要考虑到数据库表之间的逻辑关系、数据的读取和修改效率,以及数据安全和防护需求等。一般而言,可以采用ER图或者UML建模工具对数据库架构进行设计,完成后进行数据库正式建库。

2. 数据库连接

在Java中,采用JDBC或者ORM框架可以连接MySQL数据库。在JDBC方式中,由Java API通过JDBC Driver连接到MySQL服务端上,使用sql语句实现对MySQL数据库的操作;而在ORM框架中,则可以直接将Java对象映射为数据库中的表,通过对象实例对象化的方式进行数据管理。

3. 数据库增删改查

在连接MySQL数据库之后,Java学生管理系统就可以进行各种数据管理操作,例如插入、删除、更新和查询等。具体操作可以通过Sql语句实现,也可以通过ORM框架直接操作Java对象。为了提高数据的操作效率和数据存储安全性,可以采用批量插入和批量更新的操作方法,同时也需要注意到数据库的锁定,尽可能减少死锁的发生。

三、Java学生管理系统的数据加强方案

数据库管理平台在Java学生管理系统中的使用,可以有效提升学生管理系统的数据安全性和效率。然而,仅仅是使用数据库仍然可能存在一些问题和短处,如数据加密、数据备份和数据恢复等。因此,开发者需要对Java学生管理系统的数据方案进行加强,以提高数据的安全保障和数据存储的稳定性。

1. 数据库备份

数据备份是Java学生管理系统中数据方案加强的重要一环。针对数据备份策略,可以根据项目具体需求制定不同的计划,例如全排、增量备份和时间周期备份等。对于大通量数据的管理,可以采用分库分表的方式来提高操作性能和数据库的稳定性。

2. 数据加密

数据加密的目的是提高数据的安全性,防止数据泄漏和被破解。针对Java学生管理系统的数据加密,可以使用对称加密算法、非对称加密算法或者哈希算法等现代加密技术来保证数据可控性和安全性。

3. 数据恢复

Java学生管理系统中的数据恢复也是非常重要的。数据恢复需要针对数据丢失、数据完整性和数据恢复成本进行综合考虑,制定最合理的恢复方案。除此之外,也可以进行数据压缩和索引优化,以提高数据访问效率和减少数据存储空间。

四、结语

Java学生管理系统的数据库加强方案,是提高学生管理系统数据安全和稳定性的有效手段。通过对数据库的备份、加密和恢复等技术实现及时保护学生信息,增强学生管理系统的数据可控性与数据存储效率,为数据安全保障提供了强有力的技术支持。未来将有更多技术及发展空间用于完善学生管理系统中的数据管理。

相关问题拓展阅读:

  • (高分)急求连接数据库的JAVA学生信息管理系统源代码
  • 急求一个Java编写的学生成绩管理系统,数据库更好能是SqlServer。先在这儿谢谢大家啦!

(高分)急求连接数据库的JAVA学生信息管理系统源代码

书店有的很好的例子,自己去书店看看,我看过。

数据库连接(Connection)者首

数据库连接

获取数据库连接有两种方法,一种是通过驱动程序管理器DriverManager类,另一种则是使用DataSource接口。这两种方法都提供了了一个getConnection方法,用户可以在程序中对它们进行相应处理后调用这个方猜山法来返回数据库连接。

• DriverManager类

• DataSource接口

• Connection接口

• JDBC URL

jdbc::

•穗嫌中 驱动程序注册方法

(1)调用Class.forName方法

(2)设置jdbc.drivers系统属性

• DriverManager方法

DriverManager类中的所有方法都是静态方法,所以使用DriverManager类的方法时,不必生成实例。

DriverManager

• getConnection方法

作用是用于获取数据库连接,原型如下:

public static Connection getConnection(String url)

throws SQLException;

public static Connection getConnection(String url, String user, String password)

throws SQLException;

public static Connection getConnection(String url, Properties info)

throws SQLException;

• 使用DriverManager的getConnetion方法

Class.forName(“sun.jdbc.odbc.JdbcOdbcDriver”);

Connection conn = DriverManager.getConnection

(“jdbc:odbc:sqlserver”, “sa”, “sa”);

• 使用设置jdbc.drivers系统属性的方法

java -Djdbc.drivers=sun.jdbc.odbc.JdbcOdbcDriver test.java

DataSource 接口

……

//从上下文中查找数据源,并获取数据库连接

Context ctx = new InitialContext();

DataSource ds = (DataSource) ctx.lookup(“sqlserver”);

Connection conn = ds.getConnection();

//查询数据库中所有记录

Statement stmt = conn.createStatement();

ResultSet rs = stmt.executeQuery(“SELECT * FROM student”);

……

Connection 接口

Connection接口代表了已经建立的数据库连接,它是整个JDBC的核心内容。Connnection接口中的方法按照它们所实现的功能,可以分为三类:

• 生成数据库语句

• 管理数据库事务

• 获取数据库信息

生成数据库语句

JDBC将数据库语句分成三种类型 :

• 生成Statement 语句 :

Connection.createStatement()

• 生成PreparedStatement 语句 :

Connection. prepareStatement()

• 生成CallableStatement 语句 :

Connection. prepareCall ()

管理数据库事务

• 默认情况下,JDBC将一条数据库语句视为一个完整的事务。可以关掉默认事务管理:

public void setAutoCommit(Boolean autoCommit) throws SQLException;

将autoCommit的值设置为false,就关掉了自动事务管理模式

• 在执行完事务后,应提交事务:

public void commit() throws SQLException;

• 可以取消事务:

public void rollback() throws SQLException;

第二讲 第四部分

数据库语句

数据库语句

JDBC数据库语句共有三种类型:

• Statement:

Statement语句主要用于嵌入一般的SQL语句,包括查询、更新、插入和删除等等。

• PreparedStatement:

PreparedStatement语句称为准备语句,它是将SQL语句中的某些参数暂不指定,而等到执行时在统一指定。

• CallableStatement:

CallableStatement用于执行数据库的存储过程。

Statement 语句

• executeQuery方法

• executeUpdate方法

• execute方法

• close方法

executeQuery方法

• executeQuery方法主要用于执行产生单个结果集的SQL查询语句(QL),即SELECT语句。executeQuery方法的原型如下所示:

• public ResultSet executeQuery(String sql) throws SQLException;

executeUpdate方法

• executeUpdate方法主要用于执行 INSERT、UPDATE、DELETE语句,即SQL的数据操作语句(DML)

• executeUpdate方法也可以执行类似于CREATE TABLE和DROP TABLE语句的SQL数据定义语言(DDL)语句

• executeUpdate方法的返回值是一个整数,指示受影响的行数(即更新计数)。而对于CREATE TABLE 或 DROP TABLE等并不操作特定行的语句,executeUpdate的返回值总为零。

execute方法

execute方法用于执行:

• 返回多个结果集

• 多个更新计数

• 或二者组合的语句

execute方法

• 返回多个结果集:首先要调用getResultSet方法获得之一个结果集,然后调用适当的getter方法获取其中的值。要获得第二个结果集,需要先调用getMoreResults方法,然后再调用getResultSet方法。

• 返回多个更新计数:首先要调用getUpdateCount方法获得之一更新计数。然后调用getMoreResults,并再次调用getUpdateCount获得后面的更新计数。

• 不知道返回内容:如果结果是ResultSet对象,则execute方法返回true;如果结果是int类型,则意味着结果是更新计数或执行的语句是DDL命令。

execute方法

为了说明如果处理execute方法返回的结果,下面举一个代码例子:

stmt.execute(query);

while (true) {

int row = stmt.getUpdateCount();

//如果是更新计数

if (row > 0) {

System.out.println(“更新的行数是:” + row);

stmt.getMoreResults();

continue;

}

execute方法

//如果是DDL命令或0个更新

if (row == 0) {

System.out.println(“没有更新,或SQL语句是一条DDL语句!”);

stmt.getMoreResults();

continue;

}

//如果是一个结果集

ResultSet rs = stmt.getResultSet;

if (rs != null) {

while (rs.next()) {

// 处理结果集

. . .

}

stmt.getMoreResults();

continue;

}

break;

}

PreparedStatement 语句

登录一个网站或BBS时 :

• 使用Statement语句

Statement stmt = conn.createStatement();

ResultSet rs = stmt.executeQuery

(“SELECT password FROM userinfo

WHERE id=userId”);

• 使用PreparedStatement语句

PreparedStatement pstmt=conn.prepareStatement

(“SELECT password FROM userinfo

WHERE id=?”);

pstmt.setString(1, userId);

PreparedStatement语句

• 常用的setter方法

public void setBoolean(int parameterIndex, boolean x) throws SQLException;

public void setByte(int parameterIndex, byte x) throws SQLException;

public void setShort(int parameterIndex, short x) throws SQLException;

public void setInt(int parameterIndex,int x) throws SQLException;

public void setLong(int parameterIndex, long x) throws SQLException;

public void setFloat(int parameterIndex, float x) throws SQLException;

public void setDouble(int parameterIndex, double x) throws SQLException;

public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException;

public void setString(int parameterIndex, String x) throws SQLException;

public void setBytes(int parameterIndex, byte x) throws SQLException;

public void setDate(int parameterIndex, Date x) throws SQLException;

public void setTime(int parameterIndex, Time x) hrows SQLException;

public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException;

PreparedStatement语句

• PreparedStatement接口是由Statement接口扩展而来的,重写了executeQuery方法、executeUpdate方法和execute 方法

• public ResultSet executeQuery() throws SQLException

• public int executeUpdate() throws SQLException

• public boolean execute() throws SQLException

CallableStatement语句

• CallableStatement语句是由Connection接口的prepareCall方法创建的,创建时需要传入字符串参数,参数的形式为:

• {call procedure_name}

• {? = call procedure_name}

• {call procedure_name}

CallableStatement语句

• 其中的问号是参数占位符,参数共有两种:

• IN参数

• OUT参数

• IN参数使用setter方法来设置

• OUT参数则使用registerOutParameter方法来设置

CallableStatement 语句

CallableStatement cstmt = con.prepareCall

(“{call getTestData(?, ?)}”);

cstmt.registerOutParameter

(1, java.sql.Types.TINYINT);

cstmt.registerOutParameter

(2, java.sql.Types.DECIMAL, 3);

cstmt.executeQuery();

byte x = cstmt.getByte(1);

java.math.BigDecimal n =

cstmt.getBigDecimal(2, 3);

第二讲 第五部分

结 果 集

结果集

• JDBC为了方便处理查询结果,又专门定义了一个接口,这个接口就是ResultSet接口。ResultSet接口提供了可以访问数据库查询结果的方法,通常称这个接口所指向的对象为结果集。

• 有两种方法得到结果集,一种是直接执行查询语句,将结果存储在结果集对象上;另一种是不存储返回结果,而在需要时调用数据库语句的getResultSet方法来返回结果集

结果集

• 结果集指针

由于返回的结果集可能包含多条数据记录,因此ResultSet 接口提供了对结果集的所有数据记录轮询的方法。结果集自动维护了一个指向当前数据记录的指针,初始时这个指针是指向之一行的前一个位置。 next 方法就是用于向前移动指针的

结果集

• 结果集属性

默认情况下,结果集是一个不可更新集,并且结果集的指针也只能向前移动。也就是说,在得到了一个结果集之后,用户只能按照从之一条记录到最后一条记录的顺序依次向后读取,而不能跳到任意条记录上,也不能返回到前面的记录。不仅如此,结果集的这种轮询只能进行一次,而不能再将指针重置到初始位置进行多次轮询

结果集

• 结果集属性

类型

并发性

有效性

• 属性的设置是在生成数据库语句时通过向生成方法传入相应的参数设定的,而当结果集已经返回时就不能够再改变它的属性了。

结果集生成Statement语句共有三种方法

public Statement createStatement() throws SQLException;

public Statement createStatement

(int resultSetType, int resultSetConcurrency)

throws SQLException;

public Statement createStatement

(int resultSetType, int resultSetConcurrency,

int resultSetHoldability)

throws SQLException;

结果集

• 生成PreparedStatement语句共有六种方法

public PreparedStatement prepareStatement(String sql) throws SQLException;

public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys)

throws SQLException;

public PreparedStatement prepareStatement(String sql, int columnIndexes)

throws SQLException;

public PreparedStatement prepareStatement(String sql, int resultSetType,

int resultSetConcurrency)

throws SQLException;

public PreparedStatement prepareStatement(String sql, int resultSetType,

int resultSetConcurrency,

int resultSetHoldability)

throws SQLException;

public PreparedStatement prepareStatement(String sql. String columnNames)

throws SQLException;

结果集

• 生成CallableStatement语句共有三种方法

public CallableStatement prepareCall(String sql)

throws SQLException;

public CallableStatement prepareCall

(String sql, int resultSetType,

int resultSetConcurrency)

throws SQLException;

public CallableStatement prepareCall

(String sql, int resultSetType,

int resultSetConcurrency,

int resultSetHoldability)

throws SQLException;

结果集

结果集类型

• 结果集的类型共有三种,TYPE_FORWARD_ON类型的结果集只能向前移动指针,而TYPE_SCROLL_INSENSITIVE类型和TYPE_SCROLL_SENSITIVE类型的结果集则可以任意移动指针。后两种类型的区别在于,前者对来自其它处的修改不敏感(静态),而后者则对于别人的修改敏感(动态视图)。

结果集

结果集类型

• 对于可以任意移动指针的结果集,可以用来移动指针的方法包括:

• next 和previous :

• absolute 和relative :参数可正可负

• afterLast 、beforeFirst 、last 和first :

结果集

结果集并发性

• 结果集的并发性共有两种,CONCUR_READ_ON的结果集是只读而不可更新的;而CONCUR_UPDATABLE的结果集则是可以通过update方法进行更新的。

• ResultSet接口提供了一组update方法,用于更新结果集中的数据。这些方法与PreparedStatement接口中定义的setter方法一样,也是与类型相对应的。所有的update方法都以update开头 。

• 所有的update方法都有两个参数,之一个参数用于指定更新的列,它可以是列名称也可以是列的序号;第二个参数则表示将要更新列的值。

结果集

结果集并发性

• Statement stmt = conn.createStatement

•(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);

•ResultSet rs = stmt.executeQuery(“SELECT * FROM student ” +

•”WHERE grade=2 AND math>60 AND physics>60 AND ” +

•”chemistry>60 AND english>60 AND chinese>60″);

•while(rs.next()){

•rs.updateString(“grade”, “3”);

•rs.updateRow();

•}

结果集

结果集有效性

• 结果集的有效性是指在调用了Connection 接口的commit 方法后,结果集是否自动关闭。所以它只有两个可选值,即HOLD_CURSORS_OVER_COMMIT 和CLOSE_CURSORS_AT_COMMIT 。前者表示调用commit 方法之后,结果集不关闭;而后者则表示关闭结果集。

结果结果集

• 结果集的getter方法

ResultSet接口还提供了一组getter方法,用于返回当前记录的属性值。它们都是以get开头的,后接数据类型。比如,如果要返回一个float类型的列值,则应调用getFloat方法。每一种类型的getter方法都有两种形式,它们的名称相同而参数不同。这两种形式的getter方法都只有一个参数,之一种形式的getter方法参数是String类型的,用于指定列的名称;另外一种形式的getter方法参数则是int类型的,用于指定列的序号。

你要连的数据库是SQL 还是ORACLE

但是代码都查不多

下面的是连接SQL数据库的代码

你需要先创建个数据库,还有表,表的字段是登陆名和密码

下面的”SA” 是登陆名 “111111” 是密码

ORACLE 和这个查不多

import java.sql.*;//做数据库时候必须要引入的包

import com.microsoft.jdbc.sqlserver.SQLServerDriver;

public class DBFactory {

Connection Conn=null;

PreparedStatement Stmt=null;

ResultSet Rs=null;

String driverName=”com.microsoft.jdbc.sqlserver.SQLServerDriver”;

String OracleUserName=”sa”;

String OracleUserPwd=”111111″;

String ConnUrl=”jdbc:

public Connection getConnection()

{

try {

Class.forName(driverName);

} catch (ClassNotFoundException ex) {

System.out.println(“加载驱动程序有错误”);

}

try {

Conn = DriverManager.getConnection(ConnUrl, OracleUserName,OracleUserPwd);

} catch (SQLException ex1) {

System.out.print(“取得仿陆连接的时候有错误,请核对用户名和密码”);

}

return Conn;

}

这个是连接ORACLE数据库代码

import java.sql.*;

import oracle.jdbc.driver.OracleDriver;

public class DBFactory {

Connection Conn=null;

PreparedStatement Stmt=null;

ResultSet Rs=null;

String driverName=”oracle.jdbc.driver.OracleDriver”;

String OracleUserName=”scott”;

String OracleUserPwd=”tiger”;

String ConnUr1=”jdbc:oracle:thin:@locahost:1521:Ora”;

public Connection getConnection()

{

try {

Class.forName(driverName);

} catch (ClassNotFoundException ex) {

System.out.println(“加载驱动程序有错误”);

}

try {

Conn = DriverManager.getConnection(ConnUr1, OracleUserName,OracleUserPwd);

} catch (SQLException ex1) {

System.out.print(“取得连接时有错误,备启顷旁核请核对用户名和密码”);

}

return Conn;

}

急求一个Java编写的学生成绩管理系统,数据库更好能是SqlServer。先在这儿谢谢大家啦!

import java.applet.Applet;

import java.awt.*;

import java.awt.event.*;

import java.util.*;

import java.lang.*;

public class Students extends Applet implements ActionListener

{

Vector StuInf=new Vector();

StudentInf SI;

String xm;

String bj;

int i,j,xh,cj;

static int mid;

Label prompt1=new Label(“学生成绩管理系统”);

Label prompt2=new Label(” 用户:”);

Label prompt3=new Label(” 密码:”);

Label prompt4=new Label(” 班级:”);

Label prompt5=new Label(” 成绩:”);

TextField input1=new TextField(8);

TextField input2=new TextField(8);

TextField input3=new TextField(8);

TextField input4=new TextField(8);

Button btn1=new Button(“登录”);

Button btn2=new Button(“增加”);

Button btn3=new Button(“修改”);

Button btn4=new Button(“删除”);

public void init()

{

setLayout(new GridLayout(6,3));

add(new Label());

add(prompt1);

add(new Label());

add(prompt2);

add(input1);

add(new Label());

add(prompt3);

add(input2);

add(btn1);

add(prompt4);

add(input3);

add(new Label());

add(prompt5);

add(input4);

add(new Label());

add(btn2);

add(btn3);

add(btn4);

prompt4.setVisible(false);

prompt5.setVisible(false);

input3.setVisible(false);

input4.setVisible(false);

btn2.setVisible(false);

btn3.setVisible(false);

btn4.setVisible(false);

btn1.addActionListener(this);

btn2.addActionListener(this);

btn3.addActionListener(this);

btn4.addActionListener(this);

}

public void actionPerformed(ActionEvent e)

{

if(e.getActionCommand()==”登录”明慎)

{

String a,b;

a=input1.getText();

b=input2.getText();

input1.setText(“”);

if((a.equals(“12”)==true)&&(b.equals(“12”)==true))

{

prompt2.setText(” 姓名:”);

prompt3.setText(“升槐者 学吵薯号:”);

prompt4.setVisible(true);

prompt5.setVisible(true);

input3.setVisible(true);

input4.setVisible(true);

btn2.setVisible(true);

btn3.setVisible(true);

btn4.setVisible(true);

btn3.setEnabled(false);

btn4.setEnabled(false);

btn1.setLabel(“查询”);

input1.setText(“登录成功”);

input1.selectAll();

}

else

input2.setText(“用户名或密码错”);

}

if(e.getActionCommand()==”增加”)

{

boolean scucss=true;

try

{

XingMing();

}

catch(EmptyException as)

{

input1.setText(“姓名不能为空”);

scucss=false;

}

try

{

xh=Integer.parseInt(input2.getText());

}

catch(NumberFormatException m)

{

input2.setText(“学号为空或格式错”);

scucss=false;

}

bj=input3.getText();

try

{

ChengJi();

}

catch(EmptyException as)

{

cj=-1;

}

catch(OverException dd)

{

input4.setText(“应在0-100间”);

scucss=false;

}

catch(NumberFormatException cm)

{

input4.setText(“成绩应为数据”);

scucss=false;

}

if(scucss==true)

{

SI=new StudentInf(xm,xh,bj,cj);

Insert(SI);

}

}

if(e.getActionCommand()==”修改”)

{

xm=input1.getText();

xh=Integer.parseInt(input2.getText());

bj=input3.getText();

cj=Integer.parseInt(input4.getText());

SI=new StudentInf(xm,xh,bj,cj);

StuInf.setElementAt(SI, mid);

btn3.setEnabled(false);

}

if(e.getActionCommand()==”删除”)

{

StuInf.removeElementAt(mid);

btn4.setEnabled(false);

input1.setText(“删除成功”);

input2.setText(“”);

input3.setText(“”);

input4.setText(“”);

}

if(e.getActionCommand()==”查询”)

{

boolean right=true;

try

{

xh=Integer.parseInt(input2.getText());

}

catch(NumberFormatException m)

{

input2.setText(“学号为空或格式错”);

right=false;

}

if(right==true)

{

search(xh);

btn3.setEnabled(true);

btn4.setEnabled(true);

}

}

}

//查找方法

public void search(int k)

{

boolean exist=false;

int low=0;

int high=StuInf.size()-1;

while(low100)

throw (new OverException());

}

//学生信息类

public class StudentInf

{

private String name;

private int StuNo;

private String ClassNo;

private int Level;

StudentInf(String xingming,int xuehao,String banji,int chengji)

{

name=xingming;

StuNo=xuehao;

ClassNo=banji;

Level=chengji;

}

public int getStuNo()

{

return StuNo;

}

public String getname()

{

return name;

}

public String getClassNo()

{

return ClassNo;

}

public int getLevel()

{

return Level;

}

}

}

java学生管理系统加数据库的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于java学生管理系统加数据库,Java学生管理系统:数据库加强版,(高分)急求连接数据库的JAVA学生信息管理系统源代码,急求一个Java编写的学生成绩管理系统,数据库更好能是SqlServer。先在这儿谢谢大家啦!的信息别忘了在本站进行查找喔。

相关文章