目录
- 目录
- 01项目训练目标
- 02项目中的功能模块
- 03技术的选择和相关jar包
- 04项目中的工具类
- 05数据表的设计
- 06创建数据库数据表写入测试数据
- 07项目中的分层设计
- 08创建项目分层导入jar包
- 09创建domain包中的类
- 10创建JDBCUtils工具类
- 11创建其他包中的类
- 12实现用户的界面菜单
- 13实现查询的界面菜单
- 14实现查询所有账务的控制业务层的实现
- 16实现查询所有账务的view层的实现
- 18实现条件查询账务的控制层业务层实现
- 19实现条件查询账务的dao层实现
- 20实现条件查询账务的view层实现
- 21添加账务功能分析
- 22添加账务功能菜单和输入功能实现
- 23添加账务功能控制层业务层实现
- 24添加账务功能dao层实现
- 25添加账务功能view层实现
- 26编辑账务功能分析
- 27编辑账务功能功能之前实现查询所有
- 28编辑账务功能菜单实现
- 29编辑账务功能控制层业务层实现
- 30编辑账务功能dao层实现
- 31编辑账务功能view层实现
- 32删除账务功能分析
- 33删除账务功能菜单实现
- 34删除账务功能控制层业务层实现
- 35删除账务功能dao实现
- 36删除账务功能view层实现
- 01网络模型
- 02IP地址
- 03端口号
- 04InetAddress类
- 05UDP协议
- 06TCP协议
- 07数据包和发送对象介绍
- 08UDP发送端
- 09UDP接收端
- 10UDP接收端的拆包
- 11键盘输入的聊天
- 12TCP的客户端和服务器
- 13TCP的客户端程序
- 14TCP的服务器程序accept方法
- 15TCP的服务器程序读取客户端数据
- 16TCP的服务器和客户端的数据交换
- 17TCP的中的流对象
- 18TCP图片上传案例分析
- 19TCP上传客户端
- 20TCP上传服务器
- 21TCP图片上传问题解决
- TCP上传文件名
- 多线程上传案例
- 01类加载器
- 02反射
01项目训练目标
* A: 项目训练目标
* a: 项目目标
* 综合运用前面所学习的知识点
* 熟练View层、Service层、Dao层之间的方法相互调用操作、
* 熟练dbutils操作数据库表完成增删改查
* 了解公司项目开发的流程,充分的掌握项目需求分析、设计与功能的代码实现。提高同学们独立分析需求与功能实现的能力。
02项目中的功能模块
* A: 项目中的功能模块
* a: 五大模块
* 查询账务
* 多条件组合查询账务
* 添加账务
* 编辑账务
* 删除账务
03技术的选择和相关jar包
* A: 技术的选择和相关jar包
* a: apache的commons组件:
* commons-dbutils-1.4.jar:封装并简化了JDBC;
* commons-dbcp-1.4.jar:apache commons提供的数据库连接池组件,命名为DBCP;
* b: commons.pool-1.3.jar:DBCP连接池依赖该jar包;
* mysql-connector-java-5.1.28-bin.jar:MySQL的JDBC驱动包,用JDBC连接MySQL数据库必须使用该JAR包。
04项目中的工具类
* A: 项目中的工具类
* a: 工具类的介绍
* 每个项目中都会有很多个工具类,不要求每个工具类对能独立写出来,但是要会使用工具类
* JDBCUtils:用来创建数据库连接池对象
05数据表的设计
* A: 数据表的设计
* a: 数据表的设计(详见:day34_source/表关系.JPG)
* 表与表之间是有关系的
* 主表和从表的关系
* 主表中的主键作为从表中的外键
06创建数据库数据表写入测试数据
* A: 创建数据库数据表写入测试数据
* a: 创建数据库数据表
/*
创建管家婆的数据库
名字 gjp
*/
CREATE DATABASE gjp;
USE gjp;
/*
创建数据表,表名账务
字段,列
主键
分类名称 可变字符
金额 double
账户 可变字符 (支付,收入方法)
创建日期 date
账务描述 可变字符
*/
CREATE TABLE gjp_zhangwu(
-- 主键
zwid INT PRIMARY KEY AUTO_INCREMENT,
-- 分类名称
flname VARCHAR(200),
-- 金额
money DOUBLE,
-- 账户
zhanghu VARCHAR(100),
-- 创建日期
createtime DATE,
-- 账务描述
description VARCHAR(1000)
);
SELECT * FROM gjp_zhangwu;
* b: 写入数据
-- 写入测试的数据
INSERT INTO gjp_zhangwu(zwid,flname,money,zhangHu,createtime,description) VALUES (1,'吃饭支出',247,'交通银行','2016-03-02','家庭聚餐');
INSERT INTO gjp_zhangwu(zwid,flname,money,zhangHu,createtime,description) VALUES (2,'工资收入',12345,'现金','2016-03-15','开工资了');
INSERT INTO gjp_zhangwu(zwid,flname,money,zhangHu,createtime,description) VALUES (3,'服装支出',1998,'现金','2016-04-02','买衣服');
INSERT INTO gjp_zhangwu(zwid,flname,money,zhangHu,createtime,description) VALUES (4,'吃饭支出',325,'现金','2016-06-18','朋友聚餐');
INSERT INTO gjp_zhangwu(zwid,flname,money,zhangHu,createtime,description) VALUES (5,'股票收入',8000,'工商银行','2016-10-28','股票大涨');
INSERT INTO gjp_zhangwu(zwid,flname,money,zhangHu,createtime,description) VALUES (6,'股票收入',5000,'工商银行','2016-10-28','股票又大涨');
INSERT INTO gjp_zhangwu(zwid,flname,money,zhangHu,createtime,description) VALUES (7,'工资收入',5000,'交通银行','2016-10-28','又开工资了');
INSERT INTO gjp_zhangwu(zwid,flname,money,zhangHu,createtime,description) VALUES (8,'礼金支出',5000,'现金','2016-10-28','朋友结婚');
INSERT INTO gjp_zhangwu(zwid,flname,money,zhangHu,createtime,description) VALUES (9,'其他支出',1560,'现金','2016-10-29','丢钱了');
INSERT INTO gjp_zhangwu(zwid,flname,money,zhangHu,createtime,description) VALUES (10,'交通支出',2300,'交通银行','2016-10-29','油价还在涨啊');
INSERT INTO gjp_zhangwu(zwid,flname,money,zhangHu,createtime,description) VALUES (11,'吃饭支出',1000,'工商银行','2016-10-29','又吃饭');
INSERT INTO gjp_zhangwu(zwid,flname,money,zhangHu,createtime,description) VALUES (12,'工资收入',1000,'现金','2016-10-30','开资');
INSERT INTO gjp_zhangwu(zwid,flname,money,zhangHu,createtime,description) VALUES (13,'交通支出',2000,'现金','2016-10-30','机票好贵');
INSERT INTO gjp_zhangwu(zwid,flname,money,zhangHu,createtime,description) VALUES (14,'工资收入',5000,'现金','2016-10-30','又开资');
07项目中的分层设计
* A: 项目中的分层设计
* a: 各层功能介绍
* view层作用: 视图层,即项目中的界面
* controller层作用: 控制层, 获取界面上的数据,为界面设置数据; 将要实现的功能交给业务层处理
* service层作用: 业务层, 功能的实现, 与controller控制层和数据访问层DAO交互, 将对数据库的操作交给DAO数据访问层来处理
* dao层作用: 数据访问层, 用来操作数据库表的数据
* db数据库: 这里指MySQL
* domain 实体包: 存放JavaBean
* tools工具包:存放项目中使用到的工具类
* test 测试包: 存放项目功能测试的代码
08创建项目分层导入jar包
* A: 创建项目_分层_导入jar包
* a: 创建工程包
* cn.itcast.gjp.app: 存放main方法类;
* cn.itcast.gjp.domain: 存放JavaBean;
* cn.itcast.gjp.view: 存放界面,及表现层类;
* cn.itcast.gjp.service: 存放业务层类;
* cn.itcast.gjp.dao: 存放数据访问层类;
* cn.itcast.gjp.tools:存放工具类
* b: 导入jar包
* 在项目根路径下建立文件夹lib
* 导入以下jar包
* mysql-connector-java-5.1.37-bin.jar:数据库驱动
* commons-dbutils-1.6.jar:提供QueryRunner类方便进行增删改查操作
* commons-dbcp-1.4.jar:
* commons-pool-1.5.6.jar:提供高效的数据库连接池技术
* 拷贝以上jar包,选定拷贝的jar包/右键/Build Path/Add to Build Path
09创建domain包中的类
* A: 创建domain包中的类
* a: 案例代码
public class ZhangWu {
private int zwid;
private String flname;
private double money;
private String zhanghu;
private String createtime;
private String description;
//注意生成空参构造、有参构造、set和get方法、toString方法等
}
10创建JDBCUtils工具类
* A:创建JDBCUtils工具类
* a: 案例代码
public class JDBCUtils{
//创建BasicDataSource对象
private static BasicDataSource datasource = new BasicDataSource();
//静态代码块,实现必要参数设置
static{
datasource.setDriverClassName("com.mysql.jdbc.Driver");
datasource.setUrl("jdbc:mysql://localhost:3306/gjp");
datasource.setUsername("root");
datasource.setPassword("123");
datasource.setMaxActive(10);
datasource.setMaxIdle(5);
datasource.setMinIdle(2);
datasource.setInitialSize(10);
}
public static DataSource getDataSource(){
return datasource;
}
}
11创建其他包中的类
* A: 创建其他包中的类
* a: cn.itcast.gjp.dao包中创建ZhangWuDao类
/*
* 实现对数据表 gjp_zhangwu 数据增删改查操作
* dbuils工具类完成,类成员创建QueryRunner对象,指定数据源
*/
public class ZhangWuDao {
private QueryRunner qr = new QueryRunner(JDBCUtils.getDataSource());
}
* b: cn.itcast.gjp.service包中创建ZhangWuService类
/*
* 业务层类
* 接收上一层,控制层controller的数据
* 经过计算,传递给dao层,操作数据库
* 调用dao层中的类,类成员位置,创建Dao类的对象
*/
public class ZhangWuService {
private ZhangWuDao dao = new ZhangWuDao();
}
* c: cn.itcast.gjp.controller包中建立ZhangWuController类
/*
* 控制器层
* 接收视图层的数据,数据传递给service层
* 成员位置,创建service对象
*/
public class ZhangWuController {
private ZhangWuService service = new ZhangWuService();
}
* d: cn.itcast.gjp.view包中建立MainView类
/*
* 试图层,用户看到和操作的界面
* 数据传递给controller层实现
* 成员位置,创建controller对象
*/
public class MainView {
private ZhangWuController controller = new ZhangWuController();
}
* e: cn.itcast.gjp.app包中建立MainApp类
/*
* 主程序类,作用,开启软件程序
*/
public class MainApp {
public static void main(String[] args) {
new MainView().run();
}
}
12实现用户的界面菜单
* A: 实现用户的界面菜单
* a: 案例核心代码
* cn.itcast.gjp.view包中建立MainView类中添加run方法
/*
* 实现界面效果
* 接收用户的输入
* 根据数据,调用不同的功能方法
*/
public void run(){
//创建Scanner类对象,反复键盘输入
Scanner sc = new Scanner(System.in);
while(true){
System.out.println("---------------管家婆家庭记账软件---------------");
System.out.println("1.添加账务 2.编辑账务 3.删除账务 4.查询账务 5.退出系统");
System.out.println("请输入要操作的功能序号[1-5]:");
//接收用户的菜单选择
int choose = sc.nextInt();
//对选择的菜单判断,调用不同的功能
switch(choose){
case 1:
// 选择添加账务,调用添加账务的方法
break;
case 2:
// 选择的编辑账务,调用编辑账务方法
break;
case 3:
// 选择的删除账务,调用删除账务方法
break;
case 4:
// 选择的是查询账务,调用查询方法
//selectZhangWu();
break;
case 5:
System.exit(0);
break;
}
}
}
13实现查询的界面菜单
* A: 实现查询的界面菜单
* a: 案例核心代码
* cn.itcast.gjp.view包中建立MainView类中添加selectZhangWu方法、selectAll方法、select方法
/*
* 定义方法 selectZhangWu()
* 显示查询的方式 1 所有查询 2 条件查询
* 接收用户的选择
*/
public void selectZhangWu(){
System.out.println("1. 查询所有 2. 条件查询");
Scanner sc = new Scanner(System.in);
int selectChooser = sc.nextInt();
//判断根据用户的选择,调用不同的功能
switch(selectChooser){
case 1:
//选择的查询所有,调用查询所有的方法
selectAll();
break;
case 2:
//选的条件查询,调用带有查询条件的方法
select();
break;
}
}
/*
* 定义方法,实现查询所有的账务数据
*/
public void selectAll(){
}
/*
* 定义方法,实现条件查询账务数据
* 提供用户的输入日期,开始日期结束日期
* 就2个日期,传递到controller层
* 调用controller的方法,传递2个日期参数
* 获取到controller查询的结果集,打印出来
*/
public void select(){
}
14实现查询所有账务的控制,业务层的实现
* A: 实现查询所有账务的控制,业务层的实现
* a: 案例核心代码
* a: cn.itcast.gjp.dao包中创建ZhangWuDao类
/*
* 实现对数据表 gjp_zhangwu 数据增删改查操作
* dbuils工具类完成,类成员创建QueryRunner对象,指定数据源
*/
public class ZhangWuDao {
private QueryRunner qr = new QueryRunner(JDBCUtils.getDataSource());
/*
* 定义方法,查询数据库,获取所有的账务数据
* 方法,由业务层调用
* 结果集,将所有的账务数据,存储到Bean对象中,存储到集合中
*/
public List<ZhangWu> selectAll(){
return null;
}
}
* b: cn.itcast.gjp.service包中创建ZhangWuService类
/*
* 业务层类
* 接收上一层,控制层controller的数据
* 经过计算,传递给dao层,操作数据库
* 调用dao层中的类,类成员位置,创建Dao类的对象
*/
public class ZhangWuService {
private ZhangWuDao dao = new ZhangWuDao();
/*
* 定义方法,实现查询所有的账务数据
* 此方法,由控制层调用, 去调用dao层的方法
* 返回存储ZhangWu对象的List集合
*/
public List<ZhangWu> selectAll(){
return dao.selectAll();
}
}
* c: cn.itcast.gjp.controller包中建立ZhangWuController类
/*
* 控制器层
* 接收视图层的数据,数据传递给service层
* 成员位置,创建service对象
*/
public class ZhangWuController {
private ZhangWuService service = new ZhangWuService();
/*
* 控制层类定义方法,实现查询所有的账务数据
* 方法由试图层调用,方法调用service层
*/
public List<ZhangWu> selectAll(){
return service.selectAll();
}
}
###15实现查询所有账务的dao层的实现
* A: 实现查询所有账务的dao层的实现
* a: 案例核心代码
* a: cn.itcast.gjp.dao包中创建ZhangWuDao类selectAll方法
/*
* 实现对数据表 gjp_zhangwu 数据增删改查操作
* dbuils工具类完成,类成员创建QueryRunner对象,指定数据源
*/
public class ZhangWuDao {
private QueryRunner qr = new QueryRunner(JDBCUtils.getDataSource());
/*
* 定义方法,查询数据库,获取所有的账务数据
* 方法,由业务层调用
* 结果集,将所有的账务数据,存储到Bean对象中,存储到集合中
*/
public List<ZhangWu> selectAll(){
try{
//查询账务数据的SQL语句
String sql = "SELECT * FROM gjp_zhangwu";
//调用qr对象的方法,query方法,结果集BeanListHandler
List<ZhangWu> list = qr.query(sql, new BeanListHandler<>(ZhangWu.class));
return list;
}catch(SQLException ex){
System.out.println(ex);
throw new RuntimeException("查询所有账务失败");
}
}
}
16实现查询所有账务的view层的实现
* A: 实现查询所有账务的view层的实现
* a: 案例核心代码
* cn.itcast.gjp.view包中建立MainView类selectAll方法
/*
* 定义方法,实现查询所有的账务数据
*/
public void selectAll(){
//调用控制层中的方法,查询所有的账务数据
List<ZhangWu> list = controller.selectAll();
//输出表头
System.out.println("ID\t\t类别\t\t账户\t\t金额\t\t时间\t\t说明");
//遍历集合,结果输出控制台
for(ZhangWu zw : list){
System.out.println(zw.getZwid()+"\t\t"+zw.getFlname()+"\t\t"+zw.getZhanghu()+"\t\t"+
zw.getMoney()+"\t\t"+zw.getCreatetime()+"\t"+zw.getDescription());
}
}
###17实现条件查询账务的菜单实现
* A: 实现条件查询账务的菜单实现
* a: 案例核心代码
* cn.itcast.gjp.view包中建立MainView类select方法
/*
* 定义方法,实现条件查询账务数据
* 提供用户的输入日期,开始日期结束日期
* 就2个日期,传递到controller层
* 调用controller的方法,传递2个日期参数
* 获取到controller查询的结果集,打印出来
*/
public void select(){
System.out.println("选择条件查询,输入日期格式XXXX-XX-XX");
Scanner sc = new Scanner(System.in);
System.out.print("请输入开始日期:");
String startDate = sc.nextLine();
System.out.print("请输入结果日期:");
String endDate = sc.nextLine();
//调用controller层的方法,传递日期,获取查询结果集
}
18实现条件查询账务的控制层,业务层实现
* A: 实现条件查询账务的控制层,业务层实现
* a: 案例核心代码
* a: cn.itcast.gjp.dao包中创建ZhangWuDao类
/*
* 实现对数据表 gjp_zhangwu 数据增删改查操作
* dbuils工具类完成,类成员创建QueryRunner对象,指定数据源
*/
public class ZhangWuDao {
private QueryRunner qr = new QueryRunner(JDBCUtils.getDataSource());
/*
* 定义方法,查询数据库,带有条件去查询账务表
* 由业务层调用,查询结果集存储到Bean对象,存储到List集合
* 调用者传递2个日期字符串
*/
public List<ZhangWu> select(String startDate,String endDate){
return null;
}
}
* b: cn.itcast.gjp.service包中创建ZhangWuService类
/*
* 业务层类
* 接收上一层,控制层controller的数据
* 经过计算,传递给dao层,操作数据库
* 调用dao层中的类,类成员位置,创建Dao类的对象
*/
public class ZhangWuService {
private ZhangWuDao dao = new ZhangWuDao();
/*
* 定义方法,实现条件查询账务
* 方法由控制层调用,传递2个日期字符串
* 调用dao层的方法,传递2个日期字符串
* 获取到查询结果集
*/
public List<ZhangWu> select(String startDate,String endDate){
return dao.select(startDate, endDate);
}
}
* c: cn.itcast.gjp.controller包中建立ZhangWuController类
/*
* 控制器层
* 接收视图层的数据,数据传递给service层
* 成员位置,创建service对象
*/
public class ZhangWuController {
private ZhangWuService service = new ZhangWuService();
/*
* 定义方法,实现条件查询账务
* 方法由试图层调用,传递两个日期的字符串
* 调用service层的方法,传递两个日期字符串,获取结果集
* 结果集返回给试图
*/
public List<ZhangWu> select(String startDate,String endDate){
return service.select(startDate, endDate);
}
}
19实现条件查询账务的dao层实现
* A: 实现条件查询账务的dao层实现
* a: 案例核心代码
* a: cn.itcast.gjp.dao包中创建ZhangWuDao类select方法
/*
* 实现对数据表 gjp_zhangwu 数据增删改查操作
* dbuils工具类完成,类成员创建QueryRunner对象,指定数据源
*/
public class ZhangWuDao {
private QueryRunner qr = new QueryRunner(JDBCUtils.getDataSource());
/*
* 定义方法,查询数据库,带有条件去查询账务表
* 由业务层调用,查询结果集存储到Bean对象,存储到List集合
* 调用者传递2个日期字符串
*/
public List<ZhangWu> select(String startDate,String endDate){
try{
//拼写条件查询的SQL语句
String sql = "SELECT * FROM gjp_zhangwu WHERE createtime BETWEEN ? AND ?";
//定义对象数组,存储?占位符
Object[] params = {startDate,endDate};
//调用qr对象的方法query查询数据表,获取结果集
return qr.query(sql, new BeanListHandler<>(ZhangWu.class),params);
}catch(SQLException ex){
System.out.println(ex);
throw new RuntimeException("条件查询失败");
}
}
}
20实现条件查询账务的view层实现
* A: 实现条件查询账务的view层实现
* a: 案例核心代码
* cn.itcast.gjp.view包中建立MainView类selectAll方法优化、抽取print方法、select方法
/*
* 定义方法,实现查询所有的账务数据
*/
public void selectAll(){
//调用控制层中的方法,查询所有的账务数据
List<ZhangWu> list = controller.selectAll();
if(list.size()!=0)
print(list);
else
System.out.println("没有查询到数据");
}
/*
* 定义方法,实现条件查询账务数据
* 提供用户的输入日期,开始日期结束日期
* 就2个日期,传递到controller层
* 调用controller的方法,传递2个日期参数
* 获取到controller查询的结果集,打印出来
*/
public void select(){
System.out.println("选择条件查询,输入日期格式XXXX-XX-XX");
Scanner sc = new Scanner(System.in);
System.out.print("请输入开始日期:");
String startDate = sc.nextLine();
System.out.print("请输入结果日期:");
String endDate = sc.nextLine();
//调用controller层的方法,传递日期,获取查询结果集
List<ZhangWu> list = controller.select(startDate, endDate);
if(list.size()!=0)
print(list);
else
System.out.println("没有查询到数据");
}
//输出账务数据方法,接收List集合,遍历集合,输出表格
private void print(List<ZhangWu> list) {
//输出表头
System.out.println("ID\t\t类别\t\t账户\t\t金额\t\t时间\t\t说明");
//遍历集合,结果输出控制台
for(ZhangWu zw : list){
System.out.println(zw.getZwid()+"\t\t"+zw.getFlname()+"\t\t"+zw.getZhanghu()+"\t\t"+
zw.getMoney()+"\t\t"+zw.getCreatetime()+"\t"+zw.getDescription());
}
}
21添加账务功能分析
* A: 添加账务功能分析
* a: 编写MainView类中addZhangWu方法
* 键盘输入新添加的账务信息
* 调用ZhangWuService类中addZhangWu方法,用来指定账务的添加
* 添加完毕后,使用输出语句,提示“添加账务成功!”
* b: 编写ZhangWuService类中addZhangWu方法
* 调用ZhangWuDao类中addZhangWu方法,用来指定账务的添加
* c: 编写ZhangWuDao类中addZhangWu方法
* 通过QueryRunner对象,调用update方法更新数据库表gjp_zhangwu,完成指定账务添加到数据库表中
22添加账务功能菜单和输入功能实现
* A: 添加账务功能菜单和输入功能实现
* a: 案例核心代码
* cn.itcast.gjp.view包中建立MainView类addZhangWu方法
/*
* 定义方法addZhangWu
* 添加账务的方法,用户在界面中选择菜单1的时候调用、
* 实现思想:
* 接收键盘输入,5项输入,调用controller层方法
*/
public void addZhangWu() {
System.out.println("选择的添加账务功能,请输入以下内容");
Scanner sc = new Scanner(System.in);
System.out.println("输入分类名称");
String flname = sc.next();
System.out.println("输入金额");
double money = sc.nextDouble();
System.out.println("输入账户");
String zhanghu = sc.next();
System.out.println("输入日期:格式XXXX-XX-xx");
String createtime = sc.next();
System.out.println("输入具体描述");
String description = sc.next();
//将接收到的数据,调用controller层的方法,传递参数,实现数据添加
}
23添加账务功能控制层,业务层实现
* A: 添加账务功能控制层,业务层实现
* a: 案例核心代码
* cn.itcast.gjp.controller包中的ZhangWuController类addZhangWu方法
/*
* 定义方法,实现账务添加功能
* 由视图层调用,传递参数(传递过来的参数不能是5个数据,传递的是一个ZhangWu类型的对象)
* 本方法调用service层的方法,传递ZhangWu对象,获取到添加后的结果集(添加成功影响的行数,int)
*
*/
public void addZhangWu(ZhangWu zw) {
service.addZhangWu(zw);
}
* cn.itcast.gjp.service包中的ZhangWuService类addZhangWu方法
/*
* 定义方法,实现添加账务
* 是由控制层调用,传递ZhangWu对象
*/
public void addZhangWu(ZhangWu zw) {
dao.addZhangWu(zw);
}
* cn.itcast.gjp.dao包中的ZhangWuDao类addZhangWu方法
/*
* 定义方法,实现添加账务功能
* 由业务层调用,传递ZhangWu对象
* 将ZhangWu对象中的数据,添加到数据库
*/
public void addZhangWu(ZhangWu zw) {
}
24添加账务功能dao层实现
* A: 添加账务功能dao层实现
* a: 案例核心代码
* cn.itcast.gjp.dao包中的ZhangWuDao类的addZhangWu方法
public void addZhangWu(ZhangWu zw) {
try{
//拼接添加数据的sql
String sql = "INSERT INTO gjp_zhangwu (flname,money,zhanghu,createtime,description) VALUES(?,?,?,?,?)";
//创建对象数组,处处5个占位符的实际参数
//实际参数来源是传递过来的对象ZhangWu
Object[] params = {zw.getFlname(),zw.getMoney(),zw.getZhanghu(),zw.getCreatetime(),zw.getDescription()};
//调用qr对象中的方法update执行添加
qr.update(sql, params);
}catch(SQLException ex) {
System.out.println(ex);
throw new RuntimeException("账务添加失败");
}
}
25添加账务功能view层实现
* A: 添加账务功能view层实现
* a: 案例核心代码
* cn.itcast.gjp.view包中建立MainView类addZhangWu方法
public void addZhangWu() {
System.out.println("选择的添加账务功能,请输入以下内容");
Scanner sc = new Scanner(System.in);
System.out.println("输入分类名称");
String flname = sc.next();
System.out.println("输入金额");
double money = sc.nextDouble();
System.out.println("输入账户");
String zhanghu = sc.next();
System.out.println("输入日期:格式XXXX-XX-xx");
String createtime = sc.next();
System.out.println("输入具体描述");
String description = sc.next();
//将接收到的数据,调用controller层的方法,传递参数,实现数据添加
//将用户输入的所有参数,封装成ZhangWu对象
ZhangWu zw = new ZhangWu(0, flname, money, zhanghu, createtime, description);
controller.addZhangWu(zw);
System.out.println("恭喜添加账务成功");
}
26编辑账务功能分析
* A: 编辑账务功能分析
* a: 编写MainView类中editZhangWu方法
* 键盘输入要编辑的账务信息ID号
* 键盘输入要修改的账务信息内容
* 调用ZhangWuService类中editZhangWu方法,用来将指定的账务信息进行更新
* 更新完毕后,使用输出语句,提示 “编辑账务成功!”
* b: 编写ZhangWuService类中editZhangWu方法
* 调用ZhangWuDao类中editZhangWu方法,用来将指定的账务信息进行更新
* c: 编写ZhangWuDao类中editZhangWu方法
* 通过QueryRunner对象,调用update方法更新数据库表gjp_zhangwu,完成数据库表中指定账务更新操作
27编辑账务功能功能之前实现查询所有
* A: 编辑账务功能功能之前实现查询所有
* a: 案例核心代码
* cn.itcast.gjp.view包中建立MainView类editZhangWu方法
public void editZhangWu() {
//调用查询所有账务数据的功能,显示出来
//看到所有数据,从中选择一项,进行修改
selectAll();
System.out.println("选择的是编辑功能,请输入数据");
}
28编辑账务功能菜单实现
* A: 编辑账务功能菜单实现
* a: 案例核心代码
* cn.itcast.gjp.view包中建立MainView类editZhangWu方法
public void editZhangWu() {
//调用查询所有账务数据的功能,显示出来
//看到所有数据,从中选择一项,进行修改
selectAll();
System.out.println("选择的是编辑功能,请输入数据");
Scanner sc = new Scanner(System.in);
System.out.print("请输入ID");
int zwid = sc.nextInt();
System.out.println("输入分类名称");
String flname = sc.next();
System.out.println("输入金额");
double money = sc.nextDouble();
System.out.println("输入账户");
String zhanghu = sc.next();
System.out.println("输入日期:格式XXXX-XX-xx");
String createtime = sc.next();
System.out.println("输入具体描述");
String description = sc.next();
//将用户输入的数据,封装到ZhangWu对象中
//用户输入的ID,必须封装到到对象中
ZhangWu zw = new ZhangWu(zwid, flname, money, zhanghu, createtime, description);
//调用controller层中的方法,实现编辑账务
}
29编辑账务功能控制层,业务层实现
* A: 编辑账务功能控制层,业务层实现
* a: 案例核心代码
* cn.itcast.gjp.controller包中的ZhangWuController类editZhangWu方法
/*
* 定义方法,实现编辑账务功能
* 由视图层调用,传递参数,也是ZhangWu对象
* 调用service层的方法,也是ZhangWu对象
*/
public void editZhangWu(ZhangWu zw) {
service.editZhangWu(zw);
}
* cn.itcast.gjp.service包中的ZhangWuService类editZhangWu方法
/*
* 定义方法,实现编辑账务
* 由控制层调用,传递ZhangWu对象
* 调用dao层的方法,传递ZhangWu对象
*/
public void editZhangWu(ZhangWu zw) {
dao.editZhangWu(zw);
}
* cn.itcast.gjp.dao包中的ZhangWuDao类editZhangWu方法
public void editZhangWu(ZhangWu zw) {
// TODO Auto-generated method stub
}
30编辑账务功能dao层实现
* A:编辑账务功能dao层实现
* a: 案例核心代码
* cn.itcast.gjp.dao包中的ZhangWuDao类editZhangWu方法
/*
* 定义方法,实现编辑功能
* 由业务层调用,传递ZhangWu对象
* 将对象中的数据,更新到数据表
*/
public void editZhangWu(ZhangWu zw) {
try {
//更新数据的SQL
String sql = "UPDATE zhangwu SET flname=?,money=?,zhanghu=?,createtime=?,description=? WHERE zwid=?";
//定义对象数组,封装所有数据
Object[] params = {zw.getFlname(),zw.getMoney(),zw.getZhanghu(),zw.getCreatetime(),zw.getDescription(),zw.getZwid()};
//调用qr对象方法update执行更新
qr.update(sql, params);
} catch (SQLException ex) {
System.out.println(ex);
throw new RuntimeException("编辑账务失败");
}
}
31编辑账务功能view层实现
* A: 编辑账务功能view层实现
* a: 案例核心代码
* cn.itcast.gjp.view包中建立MainView类editZhangWu方法
/*
* 定义方法,实现对账务的编辑功能
* 实现思想:
* 接收用户的输入的信息
* 封装成ZhangWu对象
* 调用控制层的方法,传递ZhangWu对象,实现编辑
*
*/
public void editZhangWu() {
//调用查询所有账务数据的功能,显示出来
//看到所有数据,从中选择一项,进行修改
selectAll();
System.out.println("选择的是编辑功能,请输入数据");
Scanner sc = new Scanner(System.in);
System.out.print("请输入ID");
int zwid = sc.nextInt();
System.out.println("输入分类名称");
String flname = sc.next();
System.out.println("输入金额");
double money = sc.nextDouble();
System.out.println("输入账户");
String zhanghu = sc.next();
System.out.println("输入日期:格式XXXX-XX-xx");
String createtime = sc.next();
System.out.println("输入具体描述");
String description = sc.next();
//将用户输入的数据,封装到ZhangWu对象中
//用户输入的ID,必须封装到到对象中
ZhangWu zw = new ZhangWu(zwid, flname, money, zhanghu, createtime, description);
//调用controller层中的方法,实现编辑账务
controller.editZhangWu(zw);
System.out.println("账务编辑成功");
}
32删除账务功能分析
* A: 删除账务功能分析
* a: 编写MainView类中deleteZhangWu方法
* 键盘输入要删除的账务信息ID号
* 调用ZhangWuService类中deleteZhangWu方法,用来将指定的账务信息删除
* 删除完毕后,使用输出语句,提示 “删除账务成功!”
* b: 编写ZhangWuService类中deleteZhangWu方法
* 调用ZhangWuDao类中deleteZhangWu方法,用来将指定的账务信息删除
* c: 编写ZhangWuDao类中deleteZhangWu方法
* 通过QueryRunner对象,调用update方法更新数据库表gjp_zhangwu,完成数据库表中指定账务删除操作
33删除账务功能菜单实现
* A: 删除账务功能菜单实现
* a: 案例核心代码
* cn.itcast.gjp.view包中建立MainView类deleteZhangWu方法
/*
* 定义方法,实现账务删除
* 实现思想:
* 接收用户的输入,输入一个主键数据
* 调用控制层方法,传递一个主键
*/
public void deleteZhangWu() {
//调用查询所有账务数据的功能,显示出来
//看到所有数据,从中选择一项,进行修改
selectAll();
System.out.println("选择的是删除功能,请输入序号即可");
int zwid = new Scanner(System.in).nextInt();
//调用控制层方法,传递主键id即可
}
34删除账务功能控制层,业务层实现
* A: 删除账务功能控制层,业务层实现
* a: 案例核心代码
* cn.itcast.gjp.controller包中的ZhangWuController类deleteZhangWu方法
/*
* 定义方法,实现删除功能
* 视图层调用,传递int类型主键
* 调用service层方法,传递int主键
*/
public void deleteZhangWu(int zwid) {
service.deleteZhangWu(zwid);
}
* cn.itcast.gjp.service包中的ZhangWuService类deleteZhangWu方法
/*
* 定义方法,实现删除账务功能
* 由控制层调用,传递主键id
* 调用dao层方法,传递主键id
*/
public void deleteZhangWu(int zwid) {
dao.deleteZhangWu(zwid);
}
* cn.itcast.gjp.dao包中的ZhangWuDao类deleteZhangWu方法
public void deleteZhangWu(int zwid) {
}
35删除账务功能dao实现
* A: 删除账务功能dao实现
* a: 案例核心代码
* cn.itcast.gjp.dao包中的ZhangWuDao类deleteZhangWu方法
/*
* 定义方法,实现删除业务
* 业务层调用,传递主键id
*/
public void deleteZhangWu(int zwid) {
try {
//拼写删除数据SQL
String sql = "DELETE FROM gjp_zhangwu WHERE zwid=?";
qr.update(sql, zwid);
} catch (SQLException ex) {
System.out.println(ex);
throw new RuntimeException("删除账务失败");
}
}
36删除账务功能view层实现
* A: 删除账务功能view层实现
* a: 案例核心代码
* cn.itcast.gjp.view包中建立MainView类editZhangWu方法
/*
* 定义方法,实现账务删除
* 实现思想:
* 接收用户的输入,输入一个主键数据
* 调用控制层方法,传递一个主键
*/
public void deleteZhangWu() {
//调用查询所有账务数据的功能,显示出来
//看到所有数据,从中选择一项,进行修改
selectAll();
System.out.println("选择的是删除功能,请输入序号即可");
int zwid = new Scanner(System.in).nextInt();
//调用控制层方法,传递主键id即可
controller.deleteZhangWu(zwid);
System.out.println("删除账务成功");
01网络模型
*A:网络模型
TCP/IP协议中的四层分别是应用层、传输层、网络层和链路层,每层分别负责不同的通信功能,接下来针对这四层进行详细地讲解。
链路层:链路层是用于定义物理传输通道,通常是对某些网络连接设备的驱动协议,例如针对光纤、网线提供的驱动。
网络层:网络层是整个TCP/IP协议的核心,它主要用于将传输的数据进行分组,将分组数据发送到目标计算机或者网络。
传输层:主要使网络程序进行通信,在进行网络通信时,可以采用TCP协议,也可以采用UDP协议。
应用层:主要负责应用程序的协议,例如HTTP协议、FTP协议等。
02IP地址
*A:IP地址
在TCP/IP协议中,这个标识号就是IP地址,它可以唯一标识一台计算机,
目前,IP地址广泛使用的版本是IPv4,它是由4个字节大小的二进制数来表示,如:00001010000000000000000000000001。
由于二进制形式表示的IP地址非常不便记忆和处理,因此通常会将IP地址写成十进制的形式,
每个字节用一个十进制数字(0-255)表示,数字间用符号“.”分开,如 “192.168.1.100”
127.0.0.1 为本地主机地址(本地回环地址)
03端口号
*A:端口号
通过IP地址可以连接到指定计算机,但如果想访问目标计算机中的某个应用程序,还需要指定端口号。
在计算机中,不同的应用程序是通过端口号区分的。
端口号是用两个字节(16位的二进制数)表示的,它的取值范围是0~65535,
其中,0~1023之间的端口号用于一些知名的网络服务和应用,用户的普通应用程序需要使用1024以上的端口号,从而避免端口号被另外一个应用或服务所占用
04InetAddress类
*A:InetAddress类
/*
* 表示互联网中的IP地址
* java.net.InetAddress
* 静态方法
* static InetAddress getLocalHost() LocalHost本地主机
* 返回本地主机,返回值InetAddress对象
*
* static InetAddress getByName(String hostName)传递主机名,获取IP地址对象
*
* 非静态方法
* String getHoustAddress()获取主机IP地址
* String getHoustName()获取主机名
*
*/
public class InetAddressDemo {
public static void main(String[] args)throws UnknownHostException {
function_1();
}
/*
* static InetAddress getByName(String hostName)传递主机名,获取IP地址对象
*/
public static void function_1()throws UnknownHostException {
InetAddress inet = InetAddress.getByName("www.baidu.com");
System.out.println(inet);
}
/*
* static InetAddress getLocalHost() LocalHost本地主机
*/
public static void function() throws UnknownHostException{
InetAddress inet = InetAddress.getLocalHost();
//输出结果就是主机名,和 IP地址
System.out.println(inet.toString());
String ip = inet.getHostAddress();
String name = inet.getHostName();
System.out.println(ip+" "+name);
/*String host = inet.toString();
String[] str = host.split("/");
for(String s : str){
System.out.println(s);
}*/
}
}
05UDP协议
A:UDP协议
a:UDP协议概述:
UDP是无连接通信协议,即在数据传输时,数据的发送端和接收端不建立逻辑连接。
简单来说,当一台计算机向另外一台计算机发送数据时,发送端不会确认接收端是否存在,就会发出数据,同样接收端在收到数据时,也不会向发送端反馈是否收到数据。
b:UDP协议特点:
由于使用UDP协议消耗资源小,通信效率高,所以通常都会用于音频、视频和普通数据的传输例如视频会议都使用UDP协议,
因为这种情况即使偶尔丢失一两个数据包,也不会对接收结果产生太大影响。
06TCP协议
*A:TCP协议
TCP协议是面向连接的通信协议,即在传输数据前先在发送端和接收端建立逻辑连接,然后再传输数据,它提供了两台计算机之间可靠无差错的数据传输。
在TCP连接中必须要明确客户端与服务器端,
由客户端向服务端发出连接请求,每次连接的创建都需要经过“三次握手”。
第一次握手,客户端向服务器端发出连接请求,等待服务器确认
第二次握手,服务器端向客户端回送一个响应,通知客户端收到了连接请求
第三次握手,客户端再次向服务器端发送确认信息,确认连接
========================================第二节课=========================================
07数据包和发送对象介绍
*A:数据包和发送对象介绍:
DatagramPacket数据包的作用就如同是“集装箱”,
可以将发送端或者接收端的数据封装起来。然而运输货物只有“集装箱”是不够的,还需要有码头。
在程序中需要实现通信只有DatagramPacket数据包也同样不行,为此JDK中提供的一个DatagramSocket类。
DatagramSocket类的作用就类似于码头,使用这个类的实例对象就可以发送和接收DatagramPacket数据包
DatagramPacket:封装数据
DatagramSocket:发送DatagramPacket
08UDP发送端
*A:UDP发送端
/*
* 实现UDP协议的发送端:
* 实现封装数据的类 java.net.DatagramPacket 将你的数据包装
* 实现数据传输的类 java.net.DatagramSocket 将数据包发出去
*
* 实现步骤:
* 1. 创建DatagramPacket对象,封装数据, 接收的地址和端口
* 2. 创建DatagramSocket
* 3. 调用DatagramSocket类方法send,发送数据包
* 4. 关闭资源
*
* DatagramPacket构造方法:
* DatagramPacket(byte[] buf, int length, InetAddress address, int port)
*
* DatagramSocket构造方法:
* DatagramSocket()空参数
* 方法: send(DatagramPacket d)
*
*/
public class UDPSend {
public static void main(String[] args) throws IOException{
//创建数据包对象,封装要发送的数据,接收端IP,端口
byte[] date = "你好UDP".getBytes();
//创建InetAddress对象,封装自己的IP地址
InetAddress inet = InetAddress.getByName("127.0.0.1");
DatagramPacket dp = new DatagramPacket(date, date.length, inet,6000);
//创建DatagramSocket对象,数据包的发送和接收对象
DatagramSocket ds = new DatagramSocket();
//调用ds对象的方法send,发送数据包
ds.send(dp);
//关闭资源
ds.close();
}
}
09UDP接收端
*A:UDP接收端
/*
* 实现UDP接收端
* 实现封装数据包 java.net.DatagramPacket 将数据接收
* 实现输出传输 java.net.DatagramSocket 接收数据包
*
* 实现步骤:
* 1. 创建DatagramSocket对象,绑定端口号
* 要和发送端端口号一致
* 2. 创建字节数组,接收发来的数据
* 3. 创建数据包对象DatagramPacket
* 4. 调用DatagramSocket对象方法
* receive(DatagramPacket dp)接收数据,数据放在数据包中
* 5. 拆包
* 发送的IP地址
* 数据包对象DatagramPacket方法getAddress()获取的是发送端的IP地址对象
* 返回值是InetAddress对象
* 接收到的字节个数
* 数据包对象DatagramPacket方法 getLength()
* 发送方的端口号
* 数据包对象DatagramPacket方法 getPort()发送端口
* 6. 关闭资源
*/
public class UDPReceive {
public static void main(String[] args)throws IOException {
//创建数据包传输对象DatagramSocket 绑定端口号
DatagramSocket ds = new DatagramSocket(6000);
//创建字节数组
byte[] data = new byte[1024];
//创建数据包对象,传递字节数组
DatagramPacket dp = new DatagramPacket(data, data.length);
//调用ds对象的方法receive传递数据包
ds.receive(dp);
}
}
10UDP接收端的拆包
*A:UDP接收端的拆包
/*
* 实现UDP接收端
* 实现封装数据包 java.net.DatagramPacket 将数据接收
* 实现输出传输 java.net.DatagramSocket 接收数据包
*
* 实现步骤:
* 1. 创建DatagramSocket对象,绑定端口号
* 要和发送端端口号一致
* 2. 创建字节数组,接收发来的数据
* 3. 创建数据包对象DatagramPacket
* 4. 调用DatagramSocket对象方法
* receive(DatagramPacket dp)接收数据,数据放在数据包中
* 5. 拆包
* 发送的IP地址
* 数据包对象DatagramPacket方法getAddress()获取的是发送端的IP地址对象
* 返回值是InetAddress对象
* 接收到的字节个数
* 数据包对象DatagramPacket方法 getLength()
* 发送方的端口号
* 数据包对象DatagramPacket方法 getPort()发送端口
* 6. 关闭资源
*/
public class UDPReceive {
public static void main(String[] args)throws IOException {
//创建数据包传输对象DatagramSocket 绑定端口号
DatagramSocket ds = new DatagramSocket(6000);
//创建字节数组
byte[] data = new byte[1024];
//创建数据包对象,传递字节数组
DatagramPacket dp = new DatagramPacket(data, data.length);
//调用ds对象的方法receive传递数据包
ds.receive(dp);
//获取发送端的IP地址对象
String ip=dp.getAddress().getHostAddress();
//获取发送的端口号
int port = dp.getPort();
//获取接收到的字节个数
int length = dp.getLength();
System.out.println(new String(data,0,length)+"..."+ip+":"+port);
ds.close();
}
}
11键盘输入的聊天
*A:键盘输入的聊天
*a:发送端:
/*
* 实现UDP发送,键盘输入的形式
* 输入完毕,发送给接收端
*/
public class UDPSend {
public static void main(String[] args) throws IOException{
Scanner sc = new Scanner(System.in);
DatagramSocket ds = new DatagramSocket();
InetAddress inet = InetAddress.getByName("127.0.0.1");
while(true){
String message = sc.nextLine();
/*if("886".equals(message)){
break;
}*/
byte[] date = message.getBytes();
DatagramPacket dp = new DatagramPacket(date, date.length, inet,6000);
ds.send(dp);
}
// ds.close();
}
}
/*
* 实现UDP接收端
* 永不停歇的接收端
*/
public class UDPReceive {
public static void main(String[] args)throws IOException {
//创建数据包传输对象DatagramSocket 绑定端口号
DatagramSocket ds = new DatagramSocket(6000);
//创建字节数组
byte[] data = new byte[1024];
//创建数据包对象,传递字节数组
while(true){
DatagramPacket dp = new DatagramPacket(data, data.length);
//调用ds对象的方法receive传递数据包
ds.receive(dp);
//获取发送端的IP地址对象
String ip=dp.getAddress().getHostAddress();
//获取发送的端口号
int port = dp.getPort();
//获取接收到的字节个数
int length = dp.getLength();
System.out.println(new String(data,0,length)+"..."+ip+":"+port);
}
//ds.close();
}
}
=======================第三节课======================================
12TCP的客户端和服务器
*A:TCP的客户端和服务器
TCP通信同UDP通信一样,都能实现两台计算机之间的通信,通信的两端都需要创建socket对象。
区别在于,UDP中只有发送端和接收端,不区分客户端与服务器端,计算机之间可以任意地发送数据。
而TCP通信是严格区分客户端与服务器端的,在通信时,必须先由客户端去连接服务器端才能实现通信,
服务器端不可以主动连接客户端,并且服务器端程序需要事先启动,等待客户端的连接。
在JDK中提供了两个类用于实现TCP程序,一个是ServerSocket类,用于表示服务器端,一个是Socket类,用于表示客户端。
通信时,首先创建代表服务器端的ServerSocket对象,该对象相当于开启一个服务,并等待客户端的连接,然后创建代表客户端的Socket对象向服务器端发出连接请求,服务器端响应请求,两者建立连接开始通信。
13TCP的客户端程序
*A:TCP的客户端程序
/*
* 实现TCP客户端,连接到服务器
* 和服务器实现数据交换
* 实现TCP客户端程序的类 java.net.Socket
*
* 构造方法:
* Socket(String host, int port) 传递服务器IP和端口号
* 注意:构造方法只要运行,就会和服务器进行连接,连接失败,抛出异常
*
* OutputStream getOutputStream() 返回套接字的输出流
* 作用: 将数据输出,输出到服务器
*
* InputStream getInputStream() 返回套接字的输入流
* 作用: 从服务器端读取数据
*
* 客户端服务器数据交换,必须使用套接字对象Socket中的获取的IO流,自己new流,不行
*/
public class TCPClient {
public static void main(String[] args)throws IOException {
//创建Socket对象,连接服务器
Socket socket = new Socket("127.0.0.1", 8888);
//通过客户端的套接字对象Socket方法,获取字节输出流,将数据写向服务器
OutputStream out = socket.getOutputStream();
out.write("服务器OK".getBytes());
socket.close();
}
}
14TCP的服务器程序accept方法
A:TCP的服务器程序accept方法
/*
* 实现TCP服务器程序
* 表示服务器程序的类 java.net.ServerSocket
* 构造方法:
* ServerSocket(int port) 传递端口号
*
* 很重要的事情: 必须要获得客户端的套接字对象Socket
* Socket accept()
*/
public class TCPServer {
public static void main(String[] args) throws IOException{
ServerSocket server = new ServerSocket(8888);
//调用服务器套接字对象中的方法accept() 获取客户端套接字对象
Socket socket = server.accept();
//通过客户端套接字对象,socket获取字节输入流,读取的是客户端发送来的数据
InputStream in = socket.getInputStream();
byte[] data = new byte[1024];
int len = in.read(data);
System.out.println(new String(data,0,len));
socket.close();
server.close();
}
}
15TCP的服务器程序读取客户端数据
A:TCP的服务器程序读取客户端数据
/*
* 实现TCP客户端,连接到服务器
* 和服务器实现数据交换
* 实现TCP客户端程序的类 java.net.Socket
*
* 构造方法:
* Socket(String host, int port) 传递服务器IP和端口号
* 注意:构造方法只要运行,就会和服务器进行连接,连接失败,抛出异常
*
* OutputStream getOutputStream() 返回套接字的输出流
* 作用: 将数据输出,输出到服务器
*
* InputStream getInputStream() 返回套接字的输入流
* 作用: 从服务器端读取数据
*
* 客户端服务器数据交换,必须使用套接字对象Socket中的获取的IO流,自己new流,不行
*/
public class TCPClient {
public static void main(String[] args)throws IOException {
//创建Socket对象,连接服务器
Socket socket = new Socket("127.0.0.1", 8888);
//通过客户端的套接字对象Socket方法,获取字节输出流,将数据写向服务器
OutputStream out = socket.getOutputStream();
out.write("服务器OK".getBytes());
socket.close();
}
}
/*
* 实现TCP服务器程序
* 表示服务器程序的类 java.net.ServerSocket
* 构造方法:
* ServerSocket(int port) 传递端口号
*
* 很重要的事情: 必须要获得客户端的套接字对象Socket
* Socket accept()
*/
public class TCPServer {
public static void main(String[] args) throws IOException{
ServerSocket server = new ServerSocket(8888);
//调用服务器套接字对象中的方法accept() 获取客户端套接字对象
Socket socket = server.accept();
//通过客户端套接字对象,socket获取字节输入流,读取的是客户端发送来的数据
InputStream in = socket.getInputStream();
byte[] data = new byte[1024];
int len = in.read(data);
System.out.println(new String(data,0,len));
}
}
16TCP的服务器和客户端的数据交换
A:TCP的服务器和客户端的数据交换
/*
* 实现TCP客户端,连接到服务器
* 和服务器实现数据交换
* 实现TCP客户端程序的类 java.net.Socket
*
* 构造方法:
* Socket(String host, int port) 传递服务器IP和端口号
* 注意:构造方法只要运行,就会和服务器进行连接,连接失败,抛出异常
*
* OutputStream getOutputStream() 返回套接字的输出流
* 作用: 将数据输出,输出到服务器
*
* InputStream getInputStream() 返回套接字的输入流
* 作用: 从服务器端读取数据
*
* 客户端服务器数据交换,必须使用套接字对象Socket中的获取的IO流,自己new流,不行
*/
public class TCPClient {
public static void main(String[] args)throws IOException {
//创建Socket对象,连接服务器
Socket socket = new Socket("127.0.0.1", 8888);
//通过客户端的套接字对象Socket方法,获取字节输出流,将数据写向服务器
OutputStream out = socket.getOutputStream();
out.write("服务器OK".getBytes());
//读取服务器发回的数据,使用socket套接字对象中的字节输入流
InputStream in = socket.getInputStream();
byte[] data = new byte[1024];
int len = in.read(data);
System.out.println(new String(data,0,len));
socket.close();
}
}
/*
* 实现TCP服务器程序
* 表示服务器程序的类 java.net.ServerSocket
* 构造方法:
* ServerSocket(int port) 传递端口号
*
* 很重要的事情: 必须要获得客户端的套接字对象Socket
* Socket accept()
*/
public class TCPServer {
public static void main(String[] args) throws IOException{
ServerSocket server = new ServerSocket(8888);
//调用服务器套接字对象中的方法accept() 获取客户端套接字对象
Socket socket = server.accept();
//通过客户端套接字对象,socket获取字节输入流,读取的是客户端发送来的数据
InputStream in = socket.getInputStream();
byte[] data = new byte[1024];
int len = in.read(data);
System.out.println(new String(data,0,len));
//服务器向客户端回数据,字节输出流,通过客户端套接字对象获取字节输出流
OutputStream out = socket.getOutputStream();
out.write("收到,谢谢".getBytes());
socket.close();
server.close();
}
}
17TCP的中的流对象
*A:TCP的中的流对象
参见图解TCP中的流对象.jpg
======================================第四节课=================================================
18TCP图片上传案例分析
*A:图片上传案例分析
参见图解TCP上传图片案例.jpg
19TCP上传客户端
*A TCP上传客户端
/*
* 实现TCP图片上传客户端
* 实现步骤:
* 1. Socket套接字连接服务器
* 2. 通过Socket获取字节输出流,写图片
* 3. 使用自己的流对象,读取图片数据源
* FileInputStream
* 4. 读取图片,使用字节输出流,将图片写到服务器
* 采用字节数组进行缓冲
* 5. 通过Socket套接字获取字节输入流
* 读取服务器发回来的上传成功
* 6. 关闭资源
*/
public class TCPClient {
public static void main(String[] args) throws IOException{
Socket socket = new Socket("127.0.0.1", 8000);
//获取字节输出流,图片写到服务器
OutputStream out = socket.getOutputStream();
//创建字节输入流,读取本机上的数据源图片
FileInputStream fis = new FileInputStream("c:\\t.jpg");
//开始读写字节数组
int len = 0 ;
byte[] bytes = new byte[1024];
while((len = fis.read(bytes))!=-1){
out.write(bytes, 0, len);
}
//给服务器写终止序列
//socket.shutdownOutput();
//获取字节输入流,读取服务器的上传成功
InputStream in = socket.getInputStream();
len = in.read(bytes);
System.out.println(new String(bytes,0,len));
fis.close();
socket.close();
}
}
20TCP上传服务器
A:TCP上传服务器
/*
* TCP图片上传服务器
* 1. ServerSocket套接字对象,监听端口8000
* 2. 方法accept()获取客户端的连接对象
* 3. 客户端连接对象获取字节输入流,读取客户端发送图片
* 4. 创建File对象,绑定上传文件夹
* 判断文件夹存在, 不存,在创建文件夹
* 5. 创建字节输出流,数据目的File对象所在文件夹
* 6. 字节流读取图片,字节流将图片写入到目的文件夹中
* 7. 将上传成功会写客户端
* 8. 关闭资源
*
*/
public class TCPServer {
public static void main(String[] args) throws IOException{
ServerSocket server = new ServerSocket(8000);
Socket socket = server.accept();
//通过客户端连接对象,获取字节输入流,读取客户端图片
InputStream in = socket.getInputStream();
//将目的文件夹封装到File对象
File upload = new File("d:\\upload");
if(!upload.exists())
upload.mkdirs();
//创建字节输出流,将图片写入到目的文件夹中
FileOutputStream fos = new FileOutputStream(upload+"t.jpg");
//读写字节数组
byte[] bytes = new byte[1024];
int len = 0 ;
while((len = in.read(bytes))!=-1){
fos.write(bytes, 0, len);
}
//通过客户端连接对象获取字节输出流
//上传成功写回客户端
socket.getOutputStream().write("上传成功".getBytes());
fos.close();
socket.close();
server.close();
}
}
21TCP图片上传问题解决
/*
* 实现TCP图片上传客户端
* 实现步骤:
* 1. Socket套接字连接服务器
* 2. 通过Socket获取字节输出流,写图片
* 3. 使用自己的流对象,读取图片数据源
* FileInputStream
* 4. 读取图片,使用字节输出流,将图片写到服务器
* 采用字节数组进行缓冲
* 5. 通过Socket套接字获取字节输入流
* 读取服务器发回来的上传成功
* 6. 关闭资源
*/
public class TCPClient {
public static void main(String[] args) throws IOException{
Socket socket = new Socket("127.0.0.1", 8000);
//获取字节输出流,图片写到服务器
OutputStream out = socket.getOutputStream();
//创建字节输入流,读取本机上的数据源图片
FileInputStream fis = new FileInputStream("c:\\t.jpg");
//开始读写字节数组
int len = 0 ;
byte[] bytes = new byte[1024];
while((len = fis.read(bytes))!=-1){
out.write(bytes, 0, len);
}
//给服务器写终止序列
socket.shutdownOutput();//想服务端写入一个结束标志
//获取字节输入流,读取服务器的上传成功
InputStream in = socket.getInputStream();
len = in.read(bytes);
System.out.println(new String(bytes,0,len));
fis.close();
socket.close();
}
}
TCP上传文件名
*A:TCP上传文件名
/*
* TCP图片上传服务器
* 1. ServerSocket套接字对象,监听端口8000
* 2. 方法accept()获取客户端的连接对象
* 3. 客户端连接对象获取字节输入流,读取客户端发送图片
* 4. 创建File对象,绑定上传文件夹
* 判断文件夹存在, 不存,在创建文件夹
* 5. 创建字节输出流,数据目的File对象所在文件夹
* 6. 字节流读取图片,字节流将图片写入到目的文件夹中
* 7. 将上传成功会写客户端
* 8. 关闭资源
*
*/
public class TCPServer {
public static void main(String[] args) throws IOException{
ServerSocket server = new ServerSocket(8000);
Socket socket = server.accept();
//通过客户端连接对象,获取字节输入流,读取客户端图片
InputStream in = socket.getInputStream();
//将目的文件夹封装到File对象
File upload = new File("d:\\upload");
if(!upload.exists())
upload.mkdirs();
//防止文件同名被覆盖,从新定义文件名字
//规则: 域名+毫秒值+6位随机数
String filename="itcast"+System.currentTimeMillis()+new Random().nextInt(999999)+".jpg";
//创建字节输出流,将图片写入到目的文件夹中
FileOutputStream fos = new FileOutputStream(upload+File.separator+filename);
//读写字节数组
byte[] bytes = new byte[1024];
int len = 0 ;
while((len = in.read(bytes))!=-1){
fos.write(bytes, 0, len);
}
//通过客户端连接对象获取字节输出流
//上传成功写回客户端
socket.getOutputStream().write("上传成功".getBytes());
fos.close();
socket.close();
server.close();
}
}
多线程上传案例
*A:多线程上传案例
public class TCPThreadServer {
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(8000);
while (true) {
// 获取到一个客户端,必须开启新线程,为这个客户端服务
Socket socket = server.accept();
new Thread(new Upload(socket)).start();
}
}
}
public class Upload implements Runnable {
private Socket socket;
public Upload(Socket socket) {
this.socket = socket;
}
public void run() {
try {
// 通过客户端连接对象,获取字节输入流,读取客户端图片
InputStream in = socket.getInputStream();
// 将目的文件夹封装到File对象
File upload = new File("d:\\upload");
if (!upload.exists())
upload.mkdirs();
// 防止文件同名被覆盖,从新定义文件名字
// 规则: 域名+毫秒值+6位随机数
String filename = "itcast" + System.currentTimeMillis() + new Random().nextInt(999999) + ".jpg";
// 创建字节输出流,将图片写入到目的文件夹中
FileOutputStream fos = new FileOutputStream(upload + File.separator + filename);
// 读写字节数组
byte[] bytes = new byte[1024];
int len = 0;
while ((len = in.read(bytes)) != -1) {
fos.write(bytes, 0, len);
}
// 通过客户端连接对象获取字节输出流
// 上传成功写回客户端
socket.getOutputStream().write("上传成功".getBytes());
fos.close();
socket.close();
} catch (Exception ex) {
}
}
}
01类加载器
* A.类的加载
当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化。
* a 加载
* 就是指将class文件读入内存,并为之创建一个Class对象。
* 任何类被使用时系统都会建立一个Class对象
* b 连接
* 验证 是否有正确的内部结构,并和其他类协调一致
* 准备 负责为类的静态成员分配内存,并设置默认初始化值
* 解析 将类的二进制数据中的符号引用替换为直接引用
* c 初始化
* 就是我们以前讲过的初始化步骤(new 对象)
* 注:简单的说就是:把.class文件加载到内存里,并把这个.class文件封装成一个Class类型的对象。
* B.类的加载时机
以下的情况,会加载这个类。
* a. 创建类的实例
* b. 类的静态变量,或者为静态变量赋值
* c. 类的静态方法
* d. 使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
* e. 初始化某个类的子类
* f. 直接使用java.exe命令来运行某个主类
* C: 类加载器(了解)
负责将.class文件加载到内在中,并为之生成对应的Class对象。
* a. Bootstrap ClassLoader 根类加载器
* 也被称为引导类加载器,负责Java核心类的加载
* 比如System,String等。在JDK中JRE的lib目录下rt.jar文件中
* b. Extension ClassLoader 扩展类加载器
* 负责JRE的扩展目录中jar包的加载。
* 在JDK中JRE的lib目录下ext目录
* c. System ClassLoader 系统类加载器
* 负责在JVM启动时加载来自java命令的class文件,以及classpath环境变量所指定的jar包和类路径。
* 我们用的是System ClassLoader 系统类加载器
02反射
* A. 反射定义
* a. JAVA反射机制是在运行状态中,
对于任意一个类,都能够知道这个类的所有属性和方法;
对于任意一个对象,都能够调用它的任意一个方法和属性;
这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
* b.反射技术
条件:运行状态
已知:一个类或一个对象(根本是已知.class文件)
结果:得到这个类或对象的所有方法和属性
* 注: 要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象。
* B. Class类
* a. Class类及Class对象的了解
要想解剖一个类,必须先了解Class对象。
阅读API的Class类得知,Class 没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的。
* b. 得到Class对象
* 1. 有三个方法
方式一: 通过Object类中的getClass()方法
Person person = new Person();
Class clazz = person.getClass();
方式二: 通过 类名.class 获取到字节码文件对象(任意数据类型都具备一个class静态属性,看上去要比第一种方式简单)。
Class clazz = Person.class;
方式三: 通过Class类中的方法(将类名作为字符串传递给Class类中的静态方法forName即可)。
Class c3 = Class.forName("Person");
注:第三种和前两种的区别是:
前两种你必须明确Person类型.
后面是指定这种类型的字符串就行.这种扩展更强.我不需要知道你的类.我只提供字符串,按照配置文件加载就可以了
* 2. 得到Class对象的三个方法代码演示:
代码演示
/*
* 获取.class字节码文件对象的方式
* 1:通过Object类中的getObject()方法
* 2: 通过 类名.class 获取到字节码文件对象
* 3: 反射中的方法,
* public static Class<?> forName(String className) throws ClassNotFoundException
* 返回与带有给定字符串名的类或接口相关联的 Class 对象
*/
public class ReflectDemo {
public static void main(String[] args) throws ClassNotFoundException {
// 1: 通过Object类中的getObject()方法
// Person p1 = new Person();
// Class c1 = p1.getClass();
// System.out.println("c1 = "+ c1);
// 2: 通过 类名.class 获取到字节码文件对象
// Class c2 = Person.class;
// System.out.println("c2 = "+ c2);
// 3: 反射中的方法
Class c3 = Class.forName("cn.itcast_01_Reflect.Person");// 包名.类名
System.out.println("c3 = " + c3);
}
}
Person类
package cn.itcast_01_Reflect;
public class Person {
//成员变量
public String name;
public int age;
private String address;
//构造方法
public Person() {
System.out.println("空参数构造方法");
}
public Person(String name) {
this.name = name;
System.out.println("带有String的构造方法");
}
//私有的构造方法
private Person(String name, int age){
this.name = name;
this.age = age;
System.out.println("带有String,int的构造方法");
}
public Person(String name, int age, String address){
this.name = name;
this.age = age;
this.address = address;
System.out.println("带有String, int, String的构造方法");
}
//成员方法
//没有返回值没有参数的方法
public void method1(){
System.out.println("没有返回值没有参数的方法");
}
//没有返回值,有参数的方法
public void method2(String name){
System.out.println("没有返回值,有参数的方法 name= "+ name);
}
//有返回值,没有参数
public int method3(){
System.out.println("有返回值,没有参数的方法");
return 123;
}
//有返回值,有参数的方法
public String method4(String name){
System.out.println("有返回值,有参数的方法");
return "哈哈" + name;
}
//私有方法
private void method5(){
System.out.println("私有方法");
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + ", address=" + address+ "]";
}
}
* 注: Class类型的唯一性
因为一个.class文件在内存里只生成一个Class对象,所以无论那一种方法得到Class对象,得到的都是同一个对象。
* C.通过反射获取无参构造方法并使用
* a. 得到无参构造方法
public Constructor<?>[] getConstructors()
获取所有的public 修饰的构造方法。
选择无参构造方法,不建议使用。
public Constructor<T> getConstructor(Class<?>... parameterTypes)
获取public修饰, 指定参数类型所对应的构造方法。
不传参数得到无参构造方法。
* b. 运行无参构造方法
public T newInstance(Object... initargs)
使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。
因为是无参构造,所以不传参数。
* c. 通过反射获取无参构造方法并使用的代码演示:
package cn.itcast.demo1;
import java.lang.reflect.Constructor;
/*
* 通过反射获取class文件中的构造方法,运行构造方法
* 运行构造方法,创建对象
* 获取class文件对象
* 从class文件对象中,获取需要的成员
*
* Constructor 描述构造方法对象类
*/
public class ReflectDemo1 {
public static void main(String[] args) throws Exception {
Class c = Class.forName("cn.itcast.demo1.Person");
//使用class文件对象,获取类中的构造方法
// Constructor[] getConstructors() 获取class文件对象中的所有公共的构造方法
/*Constructor[] cons = c.getConstructors();
for(Constructor con : cons){
System.out.println(con);
}*/
//获取指定的构造方法,空参数的构造方法
Constructor con = c.getConstructor();
//运行空参数构造方法,Constructor类方法 newInstance()运行获取到的构造方法
Object obj = con.newInstance();
System.out.println(obj.toString());
}
}
* D. 通过反射获取有参构造方法并使用
* a. 得到有参的构造方法
public Constructor<T> getConstructor(Class<?>... parameterTypes)
获取public修饰, 指定参数类型所对应的构造方法。
传相应的参数类型得到有参构造方法。
* b. 运行无参构造方法
public T newInstance(Object... initargs)
使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。
因为是有参构造,所以传相应的参数值。
* c. 通过反射获取有参构造方法并使用的代码演示:
package cn.itcast.demo1;
import java.lang.reflect.Constructor;
/*
* 通过反射,获取有参数的构造方法并运行
* 方法getConstructor,传递可以构造方法相对应的参数列表即可
*/
public class ReflectDemo2 {
public static void main(String[] args)throws Exception {
Class c = Class.forName("cn.itcast.demo1.Person");
//获取带有,String和int参数的构造方法
//Constructor<T> getConstructor(Class<?>... parameterTypes)
//Class<?>... parameterTypes 传递要获取的构造方法的参数列表
Constructor con = c.getConstructor(String.class,int.class);
//运行构造方法
// T newInstance(Object... initargs)
//Object... initargs 运行构造方法后,传递的实际参数
Object obj = con.newInstance("张三",20);
System.out.println(obj);
}
}
* E. 通过反射获取有参构造方法并使用快捷方式
* a. 使用的前提
类有空参的公共构造方法。(如果是同包,默认权限也可以)
* b. 使用的基础
Class类的 public T newInstance() 方法
创建此 Class 对象所表示的类的一个新实例。
* c. 通过反射获取有参构造方法并使用快捷方式的代码演示:
package cn.itcast.demo1;
/*
* 反射获取构造方法并运行,有快捷点的方式
* 有前提:
* 被反射的类,必须具有空参数构造方法
* 构造方法权限必须public
*/
public class ReflectDemo3 {
public static void main(String[] args) throws Exception {
Class c = Class.forName("cn.itcast.demo1.Person");
// Class类中定义方法, T newInstance() 直接创建被反射类的对象实例
Object obj = c.newInstance();
System.out.println(obj);
}
}
* F. 通过反射获取私有构造方法并使用
* a. 得到私有的构造方法
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
获取指定参数类型所对应的构造方法(包含私有的)。
public Constructor<?>[] getDeclaredConstructors()
获取所有的构造方法(包含私有的)。
* b. 运行私有构造方法
public void setAccessible(boolean flag)
将此对象的 accessible 标志设置为指示的布尔值。
设置为true,这个方法保证我们得到的私有构造方法的运行。(取消运行时期的权限检查。)
public T newInstance(Object... initargs)
使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。
* c. 通过反射获取私有构造方法并使用的代码演示:
package cn.itcast.demo1;
import java.lang.reflect.Constructor;
/*
* 反射获取私有的构造方法运行
* 不推荐,破坏了程序的封装性,安全性
* 暴力反射
*/
public class ReflectDemo4 {
public static void main(String[] args) throws Exception{
Class c = Class.forName("cn.itcast.demo1.Person");
//Constructor[] getDeclaredConstructors()获取所有的构造方法,包括私有的
/*Constructor[] cons = c.getDeclaredConstructors();
for(Constructor con : cons){
System.out.println(con);
}*/
//Constructor getDeclaredConstructor(Class...c)获取到指定参数列表的构造方法
Constructor con = c.getDeclaredConstructor(int.class,String.class);
//Constructor类,父类AccessibleObject,定义方法setAccessible(boolean b)
con.setAccessible(true);
Object obj = con.newInstance(18,"lisi");
System.out.println(obj);
}
}
* 注:不推荐,破坏了程序的封装性,安全性。
* G. 反射获取成员变量并改值
* a. 获取成员变量
* 得到公共的成员变量
public Field getField(String name)
返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段。
public Field[] getFields()
返回一个包含某些 Field 对象的数组,这些对象反映此 Class 对象所表示的类或接口的所有可访问公共字段。
* 得到所有的成员变量(包括私有的,如果要进行修改私有成员变量,要先进行public void setAccessible(boolean flag) 设置。)
public Field getDeclaredField(String name)
返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段。
public Field[] getDeclaredFields()
返回 Field 对象的一个数组,这些对象反映此 Class 对象所表示的类或接口所声明的所有字段。
* b. 修改成员变量(Field)的值
* 修改公共的成员变量
public void set(Object obj, Object value)
将指定对象变量上此 Field 对象表示的字段设置为指定的新值。
obj指的是修改的是那个对象的这个成员变量值。
* c. 反射获取成员变量并改值的代码演示
package cn.itcast.demo1;
import java.lang.reflect.Field;
/*
* 反射获取成员变量,并修改值
* Person类中的成员String name
*/
public class ReflectDemo5 {
public static void main(String[] args) throws Exception{
Class c = Class.forName("cn.itcast.demo1.Person");
Object obj = c.newInstance();
//获取成员变量 Class类的方法 getFields() class文件中的所有公共的成员变量
//返回值是Field[] Field类描述成员变量对象的类
/*Field[] fields = c.getFields();
for(Field f : fields){
System.out.println(f);
}*/
//获取指定的成员变量 String name
//Class类的方法 Field getField(传递字符串类型的变量名) 获取指定的成员变量
Field field = c.getField("name");
//Field类的方法 void set(Object obj, Object value) ,修改成员变量的值
//Object obj 必须有对象的支持, Object value 修改后的值
field.set(obj,"王五");
System.out.println(obj);
}
}
* H. 反射获取空参数成员方法并运行
* a. 获取空参数成员方法
* 得到公共的成员方法
public Method getMethod(String name, Class<?>... parameterTypes)
返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。
public Method[] getMethods()
返回一个包含某些 Method 对象的数组,这些对象反映此 Class对象所表示的类或接口(包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口)的公共 member 方法。
* 得到全部的成员方法(包括私有的,如果要使用私有成员方法,要先进行public void setAccessible(boolean flag) 设置。)
public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
返回一个 Method 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明方法。
public Method[] getDeclaredMethods()
返回 Method 对象的一个数组,这些对象反映此 Class 对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。
* b. 使用Method方法对象
public Object invoke(Object obj, Object... args)
对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。
obj 指的是调这个方法的对象。
args 指的是调用这个方法所要用到的参数列表。
返回值Object就是方法的返回对象。如果方法没有返回值 ,返回的是null.
* c. 反射获取空参数成员方法并运行代码演示
package cn.itcast.demo1;
import java.lang.reflect.Method;
/*
* 反射获取成员方法并运行
* public void eat(){}
*/
public class ReflectDemo6 {
public static void main(String[] args) throws Exception{
Class c = Class.forName("cn.itcast.demo1.Person");
Object obj = c.newInstance();
//获取class对象中的成员方法
// Method[] getMethods()获取的是class文件中的所有公共成员方法,包括继承的
// Method类是描述成员方法的对象
/*Method[] methods = c.getMethods();
for(Method m : methods){
System.out.println(m);
}*/
//获取指定的方法eat运行
// Method getMethod(String methodName,Class...c)
// methodName获取的方法名 c 方法的参数列表
Method method = c.getMethod("eat");
//使用Method类中的方法,运行获取到的方法eat
//Object invoke(Object obj, Object...o)
method.invoke(obj);
}
}
* I. 反射获取有参数成员方法并运行
* a. 获取有参数成员方法
* 得到公共的成员方法
public Method getMethod(String name, Class<?>... parameterTypes)
返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。
public Method[] getMethods()
返回一个包含某些 Method 对象的数组,这些对象反映此 Class对象所表示的类或接口(包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口)的公共 member 方法。
* 得到全部的成员方法(包括私有的,如果要使用私有成员方法,要先进行public void setAccessible(boolean flag) 设置。)
public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
返回一个 Method 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明方法。
public Method[] getDeclaredMethods()
返回 Method 对象的一个数组,这些对象反映此 Class 对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。
* b. 使用Method方法对象
public Object invoke(Object obj, Object... args)
对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。
obj 指的是调这个方法的对象。
args 指的是调用这个方法所要用到的参数列表。
返回值Object就是方法的返回对象。如果方法没有返回值 ,返回的是null.
* c. 反射获取有参数成员方法并运行代码演示
package cn.itcast.demo1;
import java.lang.reflect.Method;
/*
* 反射获取有参数的成员方法并执行
* public void sleep(String,int,double){}
*/
public class ReflectDemo7 {
public static void main(String[] args) throws Exception{
Class c = Class.forName("cn.itcast.demo1.Person");
Object obj = c.newInstance();
//调用Class类的方法getMethod获取指定的方法sleep
Method method = c.getMethod("sleep", String.class,int.class,double.class);
//调用Method类的方法invoke运行sleep方法
method.invoke(obj, "休眠",100,888.99);
}
}
* J. 反射泛型擦除
* a. 使用情况
例如:在泛型为String的集合里,添加Integer的数据
ArrayList<String> list = new ArrayList<String>();
list.add(100);
* b. 能用泛型擦除的理论
伪泛型:在编译后的.class文件里面是没有泛型的。类型为Object。
用反射的方法绕过编译,得到Class文件对象,直接调用add方法。
* c. 反射泛型擦除的代码演示
package cn.itcast.demo2;
import java.lang.reflect.Method;
import java.util.ArrayList;
/*
* 定义集合类,泛型String
* 要求向集合中添加Integer类型
*
* 反射方式,获取出集合ArrayList类的class文件对象
* 通过class文件对象,调用add方法
*
* 对反射调用方法是否理解
*/
public class ReflectTest {
public static void main(String[] args)throws Exception {
ArrayList<String> array = new ArrayList<String>();
array.add("a");
//反射方式,获取出集合ArrayList类的class文件对象
Class c = array.getClass();
//获取ArrayList.class文件中的方法add
Method method = c.getMethod("add",Object.class);
//使用invoke运行ArrayList方法add
method.invoke(array, 150);
method.invoke(array, 1500);
method.invoke(array, 15000);
System.out.println(array);
}
}
* K. 反射通过配置文件来决定运行的步骤
* a. 操作依据
通过配置文件得到类名和要运行的方法名,用反射的操作类名得到对象和调用方法
* b. 实现步骤:
* 1. 准备配置文件,键值对
* 2. IO流读取配置文件 Reader
* 3. 文件中的键值对存储到集合中 Properties
* 集合保存的键值对,就是类名和方法名
* 4. 反射获取指定类的class文件对象
* 5. class文件对象,获取指定的方法
* 6. 运行方法
* c. 代码演示
代码:
package cn.itcast.demo3;
import java.io.FileReader;
import java.lang.reflect.Method;
import java.util.Properties;
/*
* 调用Person方法,调用Student方法,调用Worker方法
* 类不清楚,方法也不清楚
* 通过配置文件实现此功能
* 运行的类名和方法名字,以键值对的形式,写在文本中
* 运行哪个类,读取配置文件即可
* 实现步骤:
* 1. 准备配置文件,键值对
* 2. IO流读取配置文件 Reader
* 3. 文件中的键值对存储到集合中 Properties
* 集合保存的键值对,就是类名和方法名
* 4. 反射获取指定类的class文件对象
* 5. class文件对象,获取指定的方法
* 6. 运行方法
*/
public class Test {
public static void main(String[] args) throws Exception{
//IO流读取配置文件
FileReader r = new FileReader("config.properties");
//创建集合对象
Properties pro = new Properties();
//调用集合方法load,传递流对象
pro.load(r);
r.close();
//通过键获取值
String className = pro.getProperty("className");
String methodName = pro.getProperty("methodName");
//反射获取指定类的class文件对象
Class c = Class.forName(className);
Object obj = c.newInstance();
//获取指定的方法名
Method method = c.getMethod(methodName);
method.invoke(obj);
}
}
配置文件:
#className=cn.itcast.demo3.Student
#methodName=study
className=cn.itcast.demo3.Person
methodName=eat
#className=cn.itcast.demo3.Worker
#methodName=job