开发者博客 – IT技术 尽在开发者博客

开发者博客 – 科技是第一生产力


  • 首页

  • 归档

  • 搜索

JAVA—出租车公司租车

发表于 2021-11-26

这是我参与11月更文挑战的第18天,活动详情查看:2021最后一次更文挑战

样例

在这里插入图片描述

题目需求

1.一个人去租车公司租车,车分为轿车、客车、电动车,轿车品牌有宝马(200)、奔驰(300)、奥拓(50)、客车品牌五菱(800)、长安(1500);电动车有雅迪(20)、艾玛(50)、阳光(80);根据租车类型、品牌、天数计算租车费用
2.每类车都需要维护,轿车维护主要是加油;客车维护是清洁,电动车维护是补胎。出租公司每天都要对车辆进行维护。轿车还需要定期保养

分析

1.有哪些类:轿车类、客车类、电动车类、宝马(车的品牌属性),车类、人类、公司类
2.类之间的关系:车类是父类,轿车、客车、电车是子类
3.每个类的属性:只要有继承关系,那么所有子类都有的属性放在父类,品牌、价格,子类还可以有自己的属性
4.每个类的行为:只要有继承关系,那么所有子类都有的行为,如果实现一样,放在父类;如果某个行为子类都有,但是实现不一样,那么写成抽象方法放到父类,子类实现

代码块

  • 车类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
typescript复制代码/**
* Car类
*/
public abstract class Car {
private String name;
private String model;
private double price;
public Car() {
super();
// TODO Auto-generated constructor stub
}
public Car(String name, String model, double price) {
super();
this.name = name;
this.model = model;
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getModel() {
return model;
}
public void setModel(String model) {
this.model = model;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public abstract void weihu();
}
  • 轿车类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
typescript复制代码/**
* 轿车类
*/
public class jiaoche extends Car{
public jiaoche() {
super();
}
public jiaoche(String name, String model, double price) {
super(name, model, price);
}
@Override
public void weihu() {
System.out.println(this.getModel()+this.getName()+"加油完毕");
}
}
  • 客车类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
typescript复制代码/**
* 客车类
*/
public class keche extends Car{
public keche() {
super();
}
public keche(String name, String model, double price) {
super(name, model, price);
}
@Override
public void weihu() {
System.out.println(this.getModel()+this.getName()+"清洁完毕");
}
}
  • 电动车类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
typescript复制代码/**
*电动车类
*/
public class diandongche extends Car{
public diandongche() {
super();
}
public diandongche(String name, String model, double price) {
super(name, model, price);
}
@Override
public void weihu() {
System.out.println(this.getModel()+this.getName()+"补胎完毕");
}
}
  • 公司类
1
2
3
4
5
6
7
8
9
10
11
csharp复制代码/*
*公司类
*/
public class Company {
public Company() {
super();
}
public void weihu(Car car){
car.weihu();
}
}
  • 人类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
typescript复制代码/**
*人类
*/
public class Person {
public int getDay() {
return day;
}
public void setDay(int day) {
this.day = day;
}
@Override
public String toString() {
return name + ", 租的车:" + car.getModel()+car.getName()+car.getPrice() + "/天,租了"+day+"天";
}
public Car getCar() {
return car;
}
public void setCar(Car car) {
this.car = car;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
private String name;
private Car car;
private int day;
public Person(String name, Car car) {
super();
this.name = name;
this.car = car;
}
public Person() {
super();
}
public Person(String name) {
super();
this.name = name;
}
public Person(String name, Car car, int day) {
super();
this.name = name;
this.car = car;
this.day = day;
}
public void zuche(Car car){
System.out.println("需要花费:"+car.getPrice()*day);
}
}
  • 测试类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
java复制代码public class Test {
public static void main(String[] args) {
Company company = new Company();
Car[] car = {
new diandongche("电动车","雅迪",20),
new diandongche("电动车","艾玛",50),
new diandongche("电动车","阳光",80),
new keche("客车", "五菱", 800),
new keche("客车","长安",1500),
new jiaoche("轿车", "奥拓", 20),
new jiaoche("轿车", "奔驰", 300),
new jiaoche("轿车", "宝马", 200)
};
Person p1 = new Person("张三");
p1.setCar(car[1]);
p1.setDay(3);
System.out.println(p1);
p1.zuche(car[1]);
company.weihu(car[1]);
}
}

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

Java实现——地下城与勇士DNF武器强化(+0——+16)

发表于 2021-11-26

这是我参与11月更文挑战的第18天,活动详情查看:2021最后一次更文挑战

相信很多人都玩过腾讯的 DNF 游戏,有不少都是冲着大马猴玩的,这游戏最好玩的地方我感觉非强化锻造莫属,因为刺激啊,一念天堂,强化深似海。

DNF中强化装备能够为装备增加攻击力,从而增加角色的攻击力。强化的等级越高,增加的攻击越高,但强化装备有着一定的失败

无聊所以就随便写的代码,代码实现的也很简单没有考虑那么多,使用大量的 swtich...case... 实现。

只能通过代码来满足一下的强化欲望了。

1.运行样例

代码运行起来的样例基本就是图片上这样,强化成功会显示目前强化等级,强化失败则会有失败结果。

在这里插入图片描述

2.强化几率

从百度贴吧搞来的 DNF 装备的各个等级的强化成功率:

强化等级 强化成功几率 描述
1-3 100%=1
3-4 95%=0.95 失败则降级
4-5 90%=0.9 失败则降级
5-6 80%=0.8 失败则降级
6-7 75%=0.75 失败则降级
7-8 62.1%=0.621 若失败则变回0
8-9 53.7%=0.537 若失败则变回0
9-10 41.4%=0.414 若失败则变回0
10-11 33.9%=0.339 失败则装备消失
12-13 28%=0.28 失败则装备消失
13-14 17.3%=0.173 失败则装备消失
14-15 13.6%=0.136 失败则装备消失
15-16 10.1%=0.101 失败则装备消失

2.强化方法(实现强化)

实现方法特别简单,就是通过 switch...case... 实现。至于每次强化的几率则是使用 Math.random() 生成的随机数来判断。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
java复制代码public static int qianghua(int lever) {
switch (lever) {
case 0:
case 1:
case 2:
lever++;
break;
case 3:
if (Math.random() <= 0.95) {
++lever;
}
break;
case 4:
if (Math.random() <= 0.90) {
++lever;
}
break;
case 5:
if (Math.random() <= 0.8) {
++lever;
}
break;
case 6:
if (Math.random() <= 0.75) {
++lever;
}
break;
case 7:
if (Math.random() <= 0.621) {
++lever;
}
break;
case 8:
if (Math.random() <= 0.537)
++lever;
else
--lever;
break;
case 9:
if (Math.random() <= 0.414)
++lever;
else
--lever;
break;
case 10:
if (Math.random() <= 0.339) {
++lever;
} else
lever -= 3;
break;
case 11:
if (Math.random() <= 0.28) {
++lever;
} else
lever -= 3;
break;
case 12:
if (Math.random() <= 0.207) {
++lever;
} else
lever = 0;
break;
case 13:
if (Math.random() <= 0.173) {
++lever;
} else lever = 0;
break;
case 14:
if (Math.random() <= 0.136) {
++lever;
} else lever = 0;
break;
case 15:
if (Math.random() <= 0.101) {
++lever;
} else lever = 0;
break;

}
return lever;
}

3.源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
java复制代码import java.util.Scanner;
/*
地下城强化
*/
public class Test {
public static void main(String[] args) {
int lever;
boolean flag = false;
Scanner scan = new Scanner(System.in);
System.out.println("------------------------");
System.out.println("--------强------化-------");
System.out.println("------------------------");
while (true) {
System.out.println("武器自身强化等级:");
lever = scan.nextInt();
if (lever == 16) {
System.out.println("武器强化到顶" + "+16");
} else if (lever > 16 || lever < 0) {
System.out.println("输入不合法,请重新输入");
} else {
flag = true;
break;
}
}
if (flag) {
System.out.println("要强化武器吗?Y/N");
if ("Y".equals(scan.next())) {
while (flag) {
System.out.println("------开始强化------");
if(flag==false){
System.out.println("武器已破碎,请放入武器");
}
int n =lever;
lever = qianghua(lever);

if (lever == 0) {
flag = false;
System.out.println("强化失败,武器破碎");
} else if(n>=lever){
System.out.println("强化失败:+" + lever);
}else if(n<lever){
System.out.println("强化成功:+"+lever);
}
if(flag){
System.out.println("要继续强化吗?y/n");
if ("n".equals(scan.next())){
System.out.println("退出强化");
break;
}
}else {
System.out.println("武器已破碎");
break;
}
}
}
}
}
public static int qianghua(int lever) {
switch (lever) {
case 0:
case 1:
case 2:
lever++;
break;
case 3:
if (Math.random() <= 0.95) {
++lever;
}
break;
case 4:
if (Math.random() <= 0.90) {
++lever;
}
break;
case 5:
if (Math.random() <= 0.8) {
++lever;
}
break;
case 6:
if (Math.random() <= 0.75) {
++lever;
}
break;
case 7:
if (Math.random() <= 0.621) {
++lever;
}
break;
case 8:
if (Math.random() <= 0.537)
++lever;
else
--lever;
break;
case 9:
if (Math.random() <= 0.414)
++lever;
else
--lever;
break;
case 10:
if (Math.random() <= 0.339) {
++lever;
} else
lever -= 3;
break;
case 11:
if (Math.random() <= 0.28) {
++lever;
} else
lever -= 3;
break;
case 12:
if (Math.random() <= 0.207) {
++lever;
} else
lever = 0;
break;
case 13:
if (Math.random() <= 0.173) {
++lever;
} else lever = 0;
break;
case 14:
if (Math.random() <= 0.136) {
++lever;
} else lever = 0;
break;
case 15:
if (Math.random() <= 0.101) {
++lever;
} else lever = 0;
break;

}
return lever;
}
}

千万不要碰强化,希望大家强化不会失败,打造自己的 DNF 豪华装备。

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

JAVA——实现使用控制台模拟实际开发中上传用户头像的功能

发表于 2021-11-26

这是我参与11月更文挑战的第18天,活动详情查看:2021最后一次更文挑战

JAVA——I/O流实现使用控制台模拟实际开发中上传用户头像的功能

一.运行实例

在这里插入图片描述

需求:

使用控制台模拟实际开发中上传用户头像的功能,假设上传到lib文件下

分析:

1.定义一个方法,用来获取要上传的用户头像的路径 getPath();
2.定义一个方法,用来判断要上传的用户头像,在lib文件中是否存在
3.如果存在,提示:该用户头像已存在,上传失败
4.如果不存在,就上传头像。提示成功
5.定义一个方法,实现具体的上传头像I/O

二.代码块

  • 1.定义一个方法,用来获取要上传的用户头像的路径 getPath();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
java复制代码    /*
用来获取要上传用户头像的路径
*/
//因为要的是一个路径,所以返回值是一个File类型的对象
public static File getPath() {
//1.提示用户录入要上传的用户头像路径,并接收
Scanner scan = new Scanner(System.in);
//7.因为不知道用户多少次录入成功,用while
while (true) {
System.out.println("请录入您要上传的用户头像的路径:");
String path = scan.nextLine();
//2.判断该路径的后缀名是否是.jpg .bmp .png
//3.如果不是,就提示,您录入的不是图片,请重新录入
if (!path.endsWith(".jpg") && !path.endsWith(".png") && !path.endsWith(".bmp")) {
//path.endsWith()判断path是否以()结尾
System.out.println("您录入的不是图片,请重新录入");
//细节,千万注意,别忘了写
//如果已经不是图片了就不需要往下执行判断是否存在
continue;
}
//4.如果是,程序往下执行,判断路径是否存在,并且是否是文件
//因为path是字符串类型的,无法判断是否文件,所以封装成File类型
File file = new File(path);
if (file.exists() && file.isFile()) {
//6.如果是,说明就是我们想要的数据,图片,文件,直接返回
return file;
} else {
//5.如果不是,提示您录入的路径不合法,请重新录入
System.out.println("您录入的路径不合法,请重新录入:");
}
}
}
  • 2.定义一个方法,用来判断要上传的用户头像,在lib文件中是否存在
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
java复制代码    public static boolean isExists(String path) {    //1.jpg
//1.将lib文件夹封装成File对象
File file = new File("lib");
//2.获取lib文件夹中所有文件(夹)的名称数组
//list方法将lib文件夹下所有文件名存到数组返回
String[] names = file.list();
//3.遍历第二步获取到的数组,与path进行比较
for (String name : names) {
//4.如果一致,说明头像已存在,返回true
if (path.equals(name)) {
return true;
}
}
//5.如果不一致,说明用户头像不存在,返回false
return false;
}
  • 3.定义一个方法,实现具体的上传头像I/O
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
java复制代码/*
用来上传具体的用户头像
path 数据源文件的路径
*/
public static void uploadFile(File path) throws IOException {
// 1.创建字符流输入流对象,关联数据源文件
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(path));
// 2.创建字符流输出流对象,关联目的地文件
//数据源文件 目的地文件 文件名必须一致 路径和path.getName拼接
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("lib/" + path.getName()));
// //如果文件不存在,会自动创建
// 3.定义变量,记录读取到的内容
int len;
// 4.循环读取,只要满足条件就一直读,并将读取到内容给变量
while ((len = bis.read()) != -1) {
// 5.将读取到的数据写入到目的地文件中
bos.write(len);
}
// 6.释放资源
bis.close();
bos.close();
System.out.println("用户头像上传成功");
}

三.源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
java复制代码
import java.io.*;
import java.util.Scanner;

public class UploadFile {
public static void main(String[] args) throws IOException {
//需求:使用控制台模拟实际开发中上传用户头像的功能,假设上传到lib文件下
//1.定义一个方法,用来获取要上传的用户头像的路径 getPath();
File path = getPath();
System.out.println(path.getName());
//2.定义一个方法,用来判断要上传的用户头像,在lib文件中是否存在
boolean flag = isExists(path.getName());
//3.如果存在,提示:该用户头像已存在,上传失败
if (flag) {
System.out.println("该用户头像已存在,上传失败");
} else {
//4.如果不存在,就上传头像。提示成功
//数据源文件 目的地文件 文件名必须一致
uploadFile(path);

}
}

//定义一个方法,用来获取要上传的用户头像的路径 getPath();
/*
用来获取要上传用户头像的路径
*/
public static File getPath() {
//1.提示用户录入要上传的用户头像路径,并接收
Scanner scan = new Scanner(System.in);
while (true) {
System.out.println("请录入您要上传的用户头像的路径:");
String path = scan.nextLine();
//2.判断该路径的后缀名是否是.jpg .bmp .png
//3.如果不是,就提示,您录入的不是图片,请重新录入
if (!path.endsWith(".jpg") && !path.endsWith(".png") && !path.endsWith(".bmp")) {
//path.endsWith()判断path是否以()结尾
System.out.println("您录入的不是图片,请重新录入");
//细节,千万注意,别忘了写
//如果已经不是图片了就不需要往下执行判断是否存在
continue;
}
//4.如果是,程序往下执行,判断路径是否存在,并且是否是文件
File file = new File(path);
if (file.exists() && file.isFile()) {
//6.如果是,说明就是我们想要的数据,图片,文件,直接返回
return file;
} else {
//5.如果不是,提示您录入的路径不合法,请重新录入
System.out.println("您录入的路径不合法,请重新录入:");
}
//7.因为不知道用户多少次录入成功,用while
}
}


//2.定义一个方法,用来判断要上传的用户头像,在lib文件中是否存在
public static boolean isExists(String path) { //1.jpg
//1.将lib文件夹封装成File对象
File file = new File("lib");
//2.获取lib文件夹中所有文件(夹)的名称数组
//list方法将lib文件夹下所有文件名存到数组返回
String[] names = file.list();
//3.遍历第二步获取到的数组,与path进行比较
for (String name : names) {
//4.如果一致,说明头像已存在,返回true
if (path.equals(name)) {
return true;
}
}
//5.如果不一致,说明用户头像不存在,返回false
return false;
}

/*
用来上传具体的用户头像
path 数据源文件的路径
*/
public static void uploadFile(File path) throws IOException {
// 1.创建字符流输入流对象,关联数据源文件
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(path));
// 2.创建字符流输出流对象,关联目的地文件
//数据源文件 目的地文件 文件名必须一致 路径和path.getName拼接
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("lib/" + path.getName()));
// //如果文件不存在,会自动创建
// 3.定义变量,记录读取到的内容
int len;
// 4.循环读取,只要满足条件就一直读,并将读取到内容给变量
while ((len = bis.read()) != -1) {
// 5.将读取到的数据写入到目的地文件中
bos.write(len);
}
// 6.释放资源
bis.close();
bos.close();
System.out.println("用户头像上传成功");
}
}

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

Java模拟物流快递系统程序设计(此题仅仅实现类的继承与多态

发表于 2021-11-26

这是我参与11月更文挑战的第18天,活动详情查看:2021最后一次更文挑战

任务描述

网购已成为人民生活的重要组成部分,当人们在购物网站中下订单后,订单中的货物就会在经过一系列的流程后,送到客户手中.而在送货其间,物流管理人员可以在系统中查看所有物品的物流信息。编写一个模拟物流快递系统的程序,模拟后台系统处理货物的过程.

实现思路

运输货物首先需要有交通工具,所以需要定义一个交通工具类。由于交通工具可能有很多,所以可以将该交通工具类定义为一个抽象类,类中需要包含该交通工具的编号、型号以及运货负责人等属性,还需要定义一个抽象的运输方法。

交通工具有很多种,可以定义一个专用的运输车类,该类继承交通工具类。

有了运输工具后,就可以运送货物了,货物在运输前,运输时和运输后,都需要检查和记录,并且每一个快递都有快递单号,可以定义一个快递任务类,包含快递单号和货物重量的属性及货物发送前,发送途中和送到后得方法。

实现

定义工具类:此类定义为抽象的,包含车辆编号、车辆型号、运货负责人等属性、以及其各自get 和set 方法,同时定义一个抽象的运输方法。

定义专用运输车类。该类继承交通工具类(可多定义几种运输车类:大货车,小货车)。

定义快递任务类该类包含快递单号,货物重量属性,送前准备方法(显示订单开始处理,仓库验货中;货物重量信息,货物检验完毕,货物填装完毕,运货人已通知,快递单号信息);发送货物(显示运货人信息,位置暂时可以自定增加接口后自动获取);送后操作(显示货物运送任务结束,运货人所驾驶的编号为。。。的型号为。。。的车已经归还);定义设置,获取快递单号的方法及货物重量的方法。

定义测试类,实例化对象并传入数据,测试运行。

代码实现

交通工具抽象类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
java复制代码/**
*
* @author
* 交通工具抽象类
*/
public abstract class Vehicle {
private String number;
private String model;
private String admin;
//构造方法
public Vehicle() {

}
public Vehicle(String number, String model, String admin) {
super();
this.number = number;
this.model = model;
this.admin = admin;
}

//送货方法
public abstract void vehicle();

//生成getter和setter方法
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public String getModel() {
return model;
}
public void setModel(String model) {
this.model = model;
}
public String getAdmin() {
return admin;
}
public void setAdmin(String admin) {
this.admin = admin;
}


}

专用交通工具子类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
java复制代码/**
*
* @author
* 专用交通工具子类
*/
public class AVehicle extends Vehicle{

//构造方法
public AVehicle() {
super();
}

public AVehicle(String number, String model, String admin) {
super(number, model, admin);
}

//重写送货方法
@Override
public void vehicle(){
System.out.println("货物正在运送中......");
}
}

快递类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
java复制代码/**
*
* @author
* 快递任务类
*/
public class ExpressTask {
double weight; //货物重量
String number;//快递单号

//生成构造方法
public ExpressTask() {
}
public ExpressTask(double weight, String number) {
super();
this.weight = weight;
this.number = number;
}

//运送前方法
public void before() {
System.out.println("订单开始处理...");
System.out.println("仓库验货中...");
System.out.println("货物重量:"+this.weight+"kg");
System.out.println("货物检验完毕...");
System.out.println("货物填装完毕...");
System.out.println("正在随机分配运货人...");
System.out.println("运货人已通知...");
System.out.println("快递单号:"+this.number);
}

//实例化交通工具
AVehicle tool = new AVehicle("001","宾利","老马");

//运送中方法
public void sending() {

System.out.println("运货人:"+ tool.getAdmin()+"\n"
+"车辆型号:"+tool.getModel()+"\n"
+"车辆编号:"+tool.getNumber());
tool.vehicle();
}

//运送后方法
public void later() {
System.out.println("货物运送结束...");
System.out.println("运货人"+tool.getAdmin()
+"所驾驶的编号为"+tool.getNumber()
+"的型号为"+tool.getModel()
+"的车已归还");
}
}

测试类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
java复制代码/**
*
* @author
* 快递测试类
*/
public class test {

public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
//创建快递任务
ExpressTask express = new ExpressTask();

System.out.println("正在创建快递任务...");
System.out.println("请输入快递重量(kg):");
express.weight = scanner.nextDouble();
System.out.println("请输入快递单号:");
express.number = scanner.next();
System.out.println("订单创建成功...");

//调用送货前
express.before();
System.out.println("=============================");
//调用送货中

express.sending();
System.out.println("=============================");
//调用送货后
express.later();
}

}

运行实例

在这里插入图片描述

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

C# XmlWriter 读写xml

发表于 2021-11-26

这是我参与11月更文挑战的第5天,活动详情查看:2021最后一次更文挑战

之前介绍了使用 XmlDocument读写xml的操作,接着XmlDocument获取XML 使用XmlWriter 将xml写入后获取文本,我们再来看一看XmlWriter 如何读写XML。

XmlWriter 类

表示一个写入器,该写入器提供一种快速、非缓存和只进方式以生成包含 XML 数据的流或文件。
使用XmlWriter可以:

  • 检查字符是不是合法的 XML 字符,元素和属性的名称是不是有效的 XML 名称。
  • 检查 XML 文档的格式是否正确。
  • 将二进制字节编码为 Base64 或 BinHex,并写出结果文本。
  • 使用公共语言运行时类型而不是字符串传递值,以避免必须手动执行值转换。
  • 将多个文档写入一个输出流。
  • 写出有效的名称、限定名和名称标记。

XmlWriter 示例

我们还是以上一篇的xml结构文档为例演示如何写xml文档。

1
2
3
4
5
6
7
8
9
10
11
12
xml复制代码<?xml version="1.0"?>
<books>
<book>
<author>Carson</author>
<price format="dollar">31.95</price>
<pubdate>05/01/2001</pubdate>
</book>
<pubinfo>
<publisher>MSPress</publisher>
<state>WA</state>
</pubinfo>
</books>

首先创建XmlWriter对象,由于XmlWriter是数据流,所以我们还要关闭XmlWriter数据流。

创建对象需要我们使用XmlWriterSettings来进行设置,可以设置xml的编码格式,默认是utf-16,我们设置utf-8。然后设置换行符号,使用MemoryStream来存储写入的数据, XmlWriter.Create(ms, settings)创建。
WriteStartElement 方法写节点开始。

WriteEndElement 写节点结束。

WriteElementString 写入整个元素节点,包括字符串值。

WriteAttributeString 写入整个属性节点,包括字符串值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
ini复制代码XmlWriter xmlWriter = null;

XmlWriterSettings settings = new XmlWriterSettings();
//要求缩进
settings.Indent = true;
//设置encoding utf-8,默认将输出utf-16
settings.Encoding = new UTF8Encoding(false);
//设置换行符
settings.NewLineChars = Environment.NewLine;

MemoryStream ms = new MemoryStream();
try
{
xmlWriter = XmlWriter.Create(ms, settings);
xmlWriter.WriteStartDocument();
//books 开始
xmlWriter.WriteStartElement("books");

//book 开始
xmlWriter.WriteStartElement("book");
xmlWriter.WriteElementString("author","Carson");
xmlWriter.WriteElementString("price", "19.95");
writer.WriteAttributeString("format", "dollar");
xmlWriter.WriteElementString("pubdate", "05/01/2001");
//book 结束
xmlWriter.WriteEndElement();

//pubinfo 开始
xmlWriter.WriteStartElement("pubinfo");
xmlWriter.WriteElementString("publisher","MSPress");
xmlWriter.WriteElementString("state","WA");
//pubinfo 结束
xmlWriter.WriteEndElement();

//books 结束
xmlWriter.WriteEndElement();
}
finally
{
if (xmlWriter != null)
xmlWriter.Close();
ms.Close();
}
string xmlStr=Encoding.UTF8.GetString(ms.ToArray());

通过XmlWriter的展示我们就写入了xml文档并且可以直接获取xml文本使用。还有些添加注释,命名空间等等方法都是类似的。

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

C语言实现16进制转10进制(包含小数部分)

发表于 2021-11-26

这是我参与11月更文挑战的第18天,活动详情查看:2021最后一次更文挑战

原理就跟我们平常手动的去16进制转10进制一样,是通过最常用的按权展开的方法,即位权,那么为了将输入的16进制分开,方便我们进行每位按权去求10进制,我们可以用一个字符数组通过下标来实现这种需要。

想法:

通过按权展开的方法:
(BC)H=11x16^1 + 12x16^0

那么首先了解下什么是位权:

位权:在数制中每一固定位置对应的单位值称为位权。即比如我们日常生活中经常使用的十进制举例。

十进制:110D(D 结尾代表十进制,B 结尾代表二进制,O 结尾代表八进制,H 结尾代表十进制)
那么我们可以看到 123D 的个位就是 0,又因为它是十进制,所以个位的位权为10的0次方,即10^0=1;
同理,十位上的位权则为10的1次方,即10^1=10;百位上的位权就可以是10的2次方,即10^2=100;
最后我们按权相加起来,即 10^21+10^12+10^0*3=123。按权展开很神奇吧。
那么怎么判断位权的基数呢,就好比将123D看作在一个数轴上,个位为原点,x=0,向左依次递增,向右依次递减。若基数为 10,则 每位的位权就是 10^x 。

我们就可以通过判断每位相对于小数点的位置就可以分辨出整数部分和小数部分。

步骤:

  1. 用字符数组来放16进制
  2. 将数组元素逆序排放
  3. 将数组元素的下标当做16进制的权
  4. 将字符转换成数字 * 16的权

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
c复制代码float fun(int n)   //递归函数实现16的N次方
{
if(n==0)
return 1;
else
return 16*fun(n-1);
}
void main()
{
char s[20],*s1=s,*s2=s,*s3=s,t;
int num;
float sum=0.0;
gets(s);
while(*s1) s1++;
for(num=s1---s;s2<s1;s2++,s1--) //将数组元素逆序排放
t=*s2,*s2=*s1,*s1=t;//数组元素的下标当做16进制的权
while(*s3)
{
if(*s3=='.')
break;
s3++;
}
for(s1=s;s1<s+num;s1++)
{
if(s1-s3<0&&*s3=='.') //求小数部分,*s3='.',说明有小数
{
if(*s1>=48&&*s1<=57) //根据小数点的下标确定16的权
sum=sum+(*s1-48)/fun(s3-s1); //将字符转换成数字 * 16的权
else if(*s1>='A'&&*s1<='Z')
sum=sum+(*s1-55)/fun(s3-s1);
else if (*s1>='a'&&*s1<='z')
sum=sum+(*s1-87)/fun(s3-s1);
}
else if(*s3=='.') //求整数部分,*s3='.',说明有小数
{
if(*s1>=48&&*s1<=57) //根据小数点的下标确定16的权
sum=sum+(*s1-48)*fun(s1-s3-1); //将字符转换成数字 * 16的权
else if(*s1>='A'&&*s1<='Z')
sum=sum+(*s1-55)*fun(s1-s3-1);
else if (*s1>='a'&&*s1<='z')
sum=sum+(*s1-87)*fun(s1-s3-1);
}
else
{
if(*s1>=48 && *s1<=57) //将字符转换成数字 * 16的权
sum=sum+(*s1-48)*fun(s1-s);
else if(*s1>='A'&&*s1<='Z')
sum=sum+(*s1-55)*fun(s1-s);
else if (*s1>='a'&&*s1<='z')
sum=sum+(*s1-87)*fun(s1-s);
}
}
printf("%f",sum);
}

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

Spring IOC概念及体系结构 IOC与DI IOC的体

发表于 2021-11-26

「这是我参与11月更文挑战的第26天,活动详情查看:2021最后一次更文挑战」。

IOC与DI

IOC(控制反转)概念

平时在开发程序的时候,每个对象在使用它的合作对象时都要自己主动去创建这个合作对象,需要时就主动创建出来,创建权在自己手里,但是这种方式耦合度就很高;在使用Spring之后,将对象的创建权交给Spring容器来处理,所谓的控制就是将对象创建控制权交给了容器来创建,即容器控制了对象的创建,起初依赖对象的创建时对象主动创建,是正转,而反转就是将依赖对象的创建及注入给Spirng容器处理,对象只是被动的接受依赖对象。

注入方式

在IOC中,为被注入对象提供被依赖对象有三种方式:构造方法注入,setter注入,接口注入

DI(依赖注入)概念

容器动态的将依赖关系注入到组件中,容器实例化对象的时候主动将它依赖的类注入给它

IOC的体系结构

设计结构图

image.png

下面对结构图进行简要分析,来理解这个接口设计图

第一条接口设计主线是从BeanFactory到HierarchicalBeanFactory再到ConfigurableBeanFactory,BeanFactory定义了基本方法,例如getBean()等,HierarchicalBeanFactory增加了getParentBeanFactory接口功能,使BeanFactory具备了双亲IOC容器的管理功能;ConfigurableBeanFactory主要定义了一些对BeanFactory的配置功能,例如setParentBeanFactory()设置双亲IOC容器,通过addBeanPostProcessor()配置Bean后置管理器等;通过这些接口设计的叠加,定义了BeanFactory就是简单IOC容器的基本功能

第二条设计主线是以ApplicationContext为核心的接口设计,从BeanFactory到ListableBeanFactory再到ApplicationContext,再到我们常用的WebApplicationContext或者ConfigurableApplicationContext。L在这个接口体系中ListableBeanFactory和HierarchicalBeanFactory两个接口,连接BeanFactory接口定义和ApplicationContext应用上下文的接口定义。在ListableBeanFactory接口中,细化了许多BeanFactory接口功能,例如getBeanDefinitionNames()方法;对于ApplicationContext接口,它通过继承MessageSource,ResourceLoader,ApplicationEventPublisher,在BeanFactory简单IOC容器的基础上添加了许多对高级容器的特性支持。

Resource体系

org.springframework.core.io.Resource,它的每一个实现类都代表了一周资源的访问策略,例如

ClassPathResource、RLResource、FileSystemResource 等。

image.png

ResourceLoader 体系

有了资源之后,就要对资源进行加载,Spring就是利用ResourceLoader来进行统一的资源加载

image.png

BeanFactory体系

BeanFactory提供的是最基本的IOC容器的功能,并且提供了IoC容器所应该遵守的最基本的服务契约;BeanFactory只是一个接口,而例如DefaultListableBeanFactory、XmlBeanFactory、ApplicationContet等都可以提供具体的实现。

image.png

BeanFactory基本方法

  • containsBean(String name)方法可以根据名字判断是否还有此名字的Bean
  • isSingleton(String name)方法可以根据名字判断是否是单例的Bean
  • isPrototype(String name)方法可以根据名字判断是否是多例的Bean
  • isTypeMatch(String name, Class<?> typeToMatch)方法可以根据名字的Bean的Class类型是否是特定的Class类型
  • getType(String name)方法查询指定名字的Bean的Class类型
  • getAliases(String name)查询 该指定名字所有的Bean的别名

BeanFactory容器的设计原理

BeanFactory接口提供了使用IOC容器的基本接口规范,Spring还提供了符合这个IOC容器的一系列容器进行具体实现;通过XmlBeanFactory的实现为例进行说明:

image.png

从图中可以看到类之间的联系

image.png

从源码可知,XmlBeanFactory继承自DefaultListableBeanFactory,XmlBeanFactory新增了读取XML文件的方法

image.png

XmlBeanFactory就是通过这个方法进行xml读取,方法传参需要Resource做为参数进行传递,对xmlBeanDefinitionReader对象初始化,以及使用这个对象来完成对loadBeanDefinitions的调用

BeanDefinition体系

用来描述Spring中的Bean对象。

image.png

BeanDefinitionReader体系

读取Spring配置文件内容,并将其转成IOC容器内部的数据结构:BeanDefinition

image.png

ApplicationContext体系

image.png

ApplicationContext除了能够提供前面介绍的容器的基本功能,还为用户提供了BeanFactory不具备的新特性

  • 支持不同的信息源。ApplicationContext扩展了MessageSource接口,这些信息源的扩展功能可以支持国际化的实现
  • 访问资源:我们可以通过Resource来得到不同地方的Bean定义资源
  • 支持应用事件:继承了接口ApplicationEventPublisher,从而在上下文中引入了事件机制

ApplicationContext容器的设计原理

我们通过FileSystemXmlApplicationContext的实现为例来说明ApplicationContext的设计原理

FileSystemXmlApplicationContext有两个重要的功能

  • 一个功能是应用直接使用FileSystemXmlApplicationContext,对于实例化这个应用上下文支持,同时启动IOC容器refresh()过程。这在FileSystemApplicationContext的代码实现中可以看到:

image.png

这个refresh()过程会涉及IOC容器启动的复杂操作,关于这个reresh()在IOC容器启动时的具体表现,在后面再进行详细分析

  • 另一个功能是与怎样从文件系统中加载XML的Bean定义资源有关。

实现代码如下:

image.png

调用这个方法,可以得到FileSystemResource的资源定位

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

C语言编写程序计算某年某月某日是该年中的第几天

发表于 2021-11-26

这是我参与11月更文挑战的第18天,活动详情查看:2021最后一次更文挑战

编写程序计算某年某月某日是该年中的第几天?

例如输入fool girl 的出生日期1999-5-27
输出147

这种程序在编写实现的时候很简单,我们只需要判别出我们需要特别注意的地方即可。比如闰年之类的。

注意:闰年的判别条件是该年年份能被4整除但不能被100整除、或者能被400整除。并且闰年当中的2月有29天。

第1种 switch 语句代码实现

第一种方法是我们可以利用 switch ... case... 的特性,将都是 31 天的月份归到一类,都是 30 天的归位一类,特殊的归为一类,最后再判断出是否是闰年,天数加1即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
c复制代码    int year,month,day,sum=0,i;
scanf("%d-%d-%d",&year,&month,&day);
if(month==1) //如果是1月,直接输出day就行
printf("%d ",day);
else{
for(i=1;i<month;i++)
switch(i)
{
case 1:case 3:case 5:case 7:case 8:case 10:case 12:
sum+=31;
break;
case 4:case 6:case 9:case 11:
sum+=30;
break;
case 2:sum+=28;
}
sum+=day; //如果是闰年,3月之后的都需要+1
if(year%400==0||year%4==0&&year%100!=0&&month>2)
sum+=1;
printf("%d ",sum);
}

第2种(将之前的月天数直接给出)

第二种方法就是将第一种归类的月份分开,每个月每个月依次累加即可,最后再判断出是否是闰年,天数加1即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
c复制代码    int year, month, day,sum=0;
scanf("%d-%d-%d",&year,&month,&day);
switch(month)
{
case 1: sum=0; break;
case 2: sum=31; break;
case 3: sum=59; break;
case 4: sum=90; break;
case 5: sum=120; break;
case 6: sum=151; break;
case 7: sum=181; break;
case 8: sum=212; break;
case 9: sum=243; break;
case 10: sum=273; break;
case 11: sum=304; break;
case 12: sum=334; break;
}
sum+=day;
if(year%4==0&&year%100!=0||year%400==0&&month>2)
sum++;
printf("%d",sum);

第3种最简方法(纯属个人认为)

个人感觉第3种方法最简单,将所有天数存成一个数组,数组的下标就是当前月,只需要依次循环遍历数组即可。最后再判断出是否是闰年,天数加1即可。

1
2
3
4
5
6
7
8
9
10
11
c复制代码        int a[13]={0,31,28,31,30,31,30,31,31,30,31,30,31},year,month,day,sum=0,i;
//数组下标和月份一一对应,内容为对应月份的天数
scanf("%d-%d-%d",&year,&month,&day);
if(year%400==0||year%4==0&&year%100!=0)
a[0]=day,a[2]=29;
else a[0]=day;
//将day存放到a[0]的位置,方便后续统计,如果是闰年,需要将2月份改为29天
for(i=0;i<month;i++)
sum+=a[i];
//因为a[0]存放的是day,所以就可以直接从a[0]遍历相加
printf("%d ",sum);

第3种运算实例

在这里插入图片描述

第3种扩展方法(总天数倒着减)

最后一种方法跟第三种方法相差不大,无聊的时候写的,还是将所有天数存成一个数组,数组的下标就是当前月,我们先判断是否是闰年,得出当年的总天数,然后只需要依次循环遍历数组递减即可。

1
2
3
4
5
6
7
c复制代码int year,month,day,sum=365,i,a[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
scanf("%d-%d-%d",&year,&month,&day);
if(year%400==0||year%4==0&&year%100!=0) //闰年366天
a[2]=29,sum=366; //因为是从a[12]开始,所以a[0]就用不到了
for(i=12;i>month;i--) //从12月份开始往前减
sum-=a[i];
printf("%d ",sum-a[month]+day); //天数减去该月的该天之后的天数

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

Mybatis 的 XML 映射

发表于 2021-11-26

这是我参与11月更文挑战的第18天,活动详情查看:2021最后一次更文挑战

ParameterType

  1. 一个基本类型的参数,可以通过 #{参数名} 获取
1
2
3
4
5
6
7
8
9
10
11
12
13
14
xml复制代码<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="mapper.UserMapper">

<delete id="deleteUserById" parameterType="int">
delete
from user
where id = #{id}
</delete>

</mapper>
  1. 多个参数时采用Map,通过 #{Key} 获取
1
2
3
4
java复制代码Map<String, Object> map = new HashMap<>();
map.put("name", "test");
map.put("password", "test");
User user = userMapper.selectUserByNameAndPassword(map);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
xml复制代码<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="mapper.UserMapper">

<select id="selectUserByNameAndPassword" parameterType="map" resultType="pojo.User">
select *
from user
where name = #{name}
and password = #{password}
</select>

</mapper>
  1. 对象传递参数,通过 #{属性名} 获取
1
2
3
4
5
6
7
8
9
10
11
12
13
xml复制代码<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="mapper.UserMapper">

<insert id="addUser" parameterType="pojo.User">
insert into user(id, name, password)
values (#{id}, #{name}, #{password})
</insert>

</mapper>
  1. 使用注解,在接口方法的参数前加 @Param() 属性,直接取 @Param() 中设置的值即可,不需要单独设置参数类型
1
2
3
4
5
6
7
java复制代码import org.apache.ibatis.annotations.Param;

public interface UserMapper {

int deleteUserById(@Param("id") int id);

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
xml复制代码<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="mapper.UserMapper">

<delete id="deleteUserById">
delete
from user
where id = #{id}
</delete>

</mapper>

关于@Param

使用 @Param 注解用于给方法参数起一个名字。使用原则:

  • 在方法只接受一个参数的情况下,可以不使用 @Param。
  • 在方法接受多个参数的情况下,建议一定要使用 @Param 注解给参数命名。
  • 如果参数是 JavaBean , 则不能使用@Param。
  • 不使用 @Param 注解时,参数只能有一个,并且是Javabean。

#与$的区别

  • #{} 的作用主要是替换预编译语句(PrepareStatement)中的占位符? 【推荐使用】
1
2
sql复制代码INSERT INTO user (name) VALUES (#{name});
INSERT INTO user (name) VALUES (?);
  • ${} 的作用是直接进行字符串替换
1
2
sql复制代码INSERT INTO user (name) VALUES ('${name}');
INSERT INTO user (name) VALUES ('zhangsan');

ResultType

自动映射

  • resultMap 元素是 MyBatis 中最重要最强大的元素。它可以让你从 90% 的 JDBC ResultSets 数据提取代码中解放出来。
  • 实际上,在为一些比如连接的复杂语句编写映射代码的时候,一份 resultMap 能够代替实现同等功能的长达数千行的代码。
  • ResultMap 的设计思想是,对于简单的语句根本不需要配置显式的结果映射,而对于复杂一点的语句只需要描述它们的关系就行了

简单映射语句示例,不需要显指定 resultMap。比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
xml复制代码<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="mapper.UserMapper">

<select id="selectUserById" resultType="map">
select id , name , pwd
from user
where id = #{id}
</select>

</mapper>

上述语句只是简单地将所有的列映射到 HashMap 的键上,这由 resultType 属性指定。虽然在大部分情况下都够用,但是 HashMap 不是一个很好的模型。你的程序更可能会使用 JavaBean 或 POJO(Plain Old Java Objects,普通老式 Java 对象)作为模型。

手动映射

返回值类型为 resultMap,编写 resultMap,实现手动映射!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
xml复制代码<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="mapper.UserMapper">

<!-- 编写 resultMap -->
<resultMap id="UserMaps" type="pojo.User">
<!-- id为主键 -->
<id column="id" property="id"/>
<!-- column是数据库表的列名 , property是对应实体类的属性名 -->
<result column="name" property="name"/>
<result column="password" property="password"/>
</resultMap>

<!-- 返回值类型为 resultMap ,值为编写的 resultMap 的 id -->
<select id="selectUser" resultMap="UserMaps">
select *
from user
</select>

</mapper>

注解开发

适用于简单的 SQL 语句,利用注解开发就不需要 mapper.xml 映射文件

  1. 在接口中添加注解
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
java复制代码package mapper;

import org.apache.ibatis.annotations.*;
import pojo.User;

import java.util.List;

public interface UserMapper {

@Insert("insert into user(id, name, password) values (#{id}, #{name}, #{password})")
int addUser(User user);

@Delete("delete from user where id=#{id}")
int deleteUserById(@Param("id") int id);

@Update("update user set name=#{name},password=#{password} where id = #{id}")
int updateUserById(User user);

@Select("select id,name,password from user")
List<User> selectUser();

}
  1. 在mybatis的核心配置文件中注入
1
2
3
4
xml复制代码<!--注册 Mapper-->
<mappers>
<mapper class="mapper.UserMapper"/>
</mappers>
  1. 测试 OK 即可

一对多

多个学生对应一个老师

  1. 创建学生实体类
1
2
3
4
5
6
7
java复制代码@Data
public class Student {
private int id;
private String name;
//多个学生可以是同一个老师,即多对一
private Teacher teacher;
}
  1. 编写 StudentMapper 接口
1
2
3
4
5
6
java复制代码public interface StudentMapper {

//获取所有学生及对应老师的信息
public List<Student> getStudents();

}
  1. 编写 Mapper.xml 文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
xml复制代码<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="mapper.StudentMapper">

<!--需求:获取所有学生及对应老师的信息-->

<!--思路1:嵌套查询
association → 一个复杂类型的关联;使用它来处理关联查询
-->
<select id="getStudents" resultMap="StudentTeacher">
select * from student
</select>

<resultMap id="StudentTeacher" type="Student">
<!--association关联属性 property→属性名 javaType→属性类型 column→关联列名 select→子查询-->
<association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/>
</resultMap>

<!-- 传递一个参数的时候,下面可以写任何值 -->
<select id="getTeacher" resultType="teacher">
select * from teacher where id = #{id}
</select>

<!---------------------------------------------------------------------------------------------------->

<!--思路2:结果集的映射-->
<select id="getStudents2" resultMap="StudentTeacher2" >
select s.id sid, s.name sname , t.name tname
from student s,teacher t
where s.tid = t.id
</select>

<resultMap id="StudentTeacher2" type="Student">
<id property="id" column="sid"/>
<result property="name" column="sname"/>
<!--association关联属性 property→属性名 javaType→属性类型-->
<association property="teacher" javaType="Teacher">
<!-- column是数据库表的列名 , property是对应实体类的属性名 -->
<result property="name" column="tname"/>
</association>
</resultMap>

</mapper>

注:当子查询需要传多个参数时

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
XML复制代码<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="mapper.StudentMapper">

<select id="getStudents" resultMap="StudentTeacher">
select * from student
</select>

<!-- 传递多个参数时
association 中 column 多参数配置:column="{key=value,key=value}"
其实就是键值对的形式,key 是传给下个 sql 的取值名称,value 是片段一中 sql 查询的字段名-->
<resultMap id="StudentTeacher" type="Student">
<!--association关联属性 property→属性名 javaType→属性类型 column→关联列名 select→子查询-->
<association property="teacher" column="{id=tid,name=tname}" javaType="Teacher" select="getTeacher"/>
</resultMap>

<select id="getTeacher" resultType="teacher">
select * from teacher where id = #{id} and name = #{name}
</select>

</mapper>

多对一

一个老师对应多个学生

  1. 创建教师实体类
1
2
3
4
5
6
7
java复制代码@Data
public class Teacher {
private int id;
private String name;
//一个老师多个学生
private List<Student> students;
}
  1. 编写 TeacherMapper 接口
1
2
3
4
5
6
java复制代码public interface TeacherMapper {

//获取指定老师,及老师下的所有学生
public Teacher getTeacher(int id);

}
  1. 编写 Mapper.xml 文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
xml复制代码<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="mapper.TeacherMapper">

<!--需求:获取指定老师,及老师下的所有学生-->

<!--思路1:嵌套查询-->
<select id="getTeacher" resultMap="TeacherStudent2">
select * from teacher where id = #{id}
</select>

<resultMap id="TeacherStudent2" type="Teacher">
<!--column是 student 表外键的列名-->
<collection property="students" javaType="ArrayList" ofType="Student" column="id" select="getStudentByTeacherId"/>
</resultMap>

<select id="getStudentByTeacherId" resultType="Student">
select * from student where tid = #{id}
</select>

<!---------------------------------------------------------------------------------------------------->

<!--思路2:结果集映射
集合映射使用 collection!
JavaType 和 ofType都是用来指定对象类型的
JavaType是用来指定 pojo 中属性的类型
ofType 指定的是映射到 list集合属性中 pojo的类型。
-->
<select id="getTeacher" resultMap="TeacherStudent">
select s.id sid, s.name sname , t.name tname, t.id tid
from student s,teacher t
where s.tid = t.id and t.id=#{id}
</select>

<resultMap id="TeacherStudent" type="Teacher">
<result property="name" column="tname"/>
<collection property="students" ofType="Student">
<result property="id" column="sid" />
<result property="name" column="sname" />
<result property="tid" column="tid" />
</collection>
</resultMap>

</mapper>

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

Mybatis 的 动态SQL

发表于 2021-11-26

这是我参与11月更文挑战的第18天,活动详情查看:2021最后一次更文挑战


MyBatis 的强大特性之一便是它的动态 SQL。如果你有使用 JDBC 或其它类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句的痛苦。例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL 这一特性可以彻底摆脱这种痛苦。
虽然在以前使用动态 SQL 并非一件易事,但正是 MyBatis 提供了可以被用在任意 SQL 映射语句中的强大的动态 SQL 语言得以改进这种情形。
动态 SQL 元素和 JSTL 或基于类似 XML 的文本处理器相似。在 MyBatis 之前的版本中,有很多元素需要花时间了解。MyBatis 3 大大精简了元素种类,现在只需学习原来一半的元素便可。MyBatis 采用功能强大的基于 OGNL 的表达式来淘汰其它大部分元素。

IF 语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
xml复制代码<!--
如果名字为空,那么只根据密码查询,反之,则根据名字来查询
select * from blog where name = #{name} and password = #{password}
-->
<select id="selectUserByNameAndPassword" parameterType="map" resultType="pojo.User">
select *
from user
where
<if test="name!=null">
name = #{name}
</if>
<if test="password!=null">
and password = #{password}
</if>
</select>

上述语句中,如果 title 为空那么查询语句为 select * from user where and password = #{password} ,这是错误的 SQL 语句

Where 语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
xml复制代码<!--
如果名字为空,那么只根据密码查询,反之,则根据名字来查询
select * from blog where name = #{name} and password = #{password}
-->
<select id="selectUserByNameAndPassword" parameterType="map" resultType="pojo.User">
select *
from user
<where>
<if test="name != null">
name = #{name}
</if>
<if test="password != null">
and password = #{password}
</if>
</where>
</select>

“where”标签:如果它包含的标签中有返回值的话,它就会插入一个‘where’。此外,如果标签返回的内容是以 AND 或 OR 开头的,则它会将其剔除掉。

Set 语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
xml复制代码<!--
update user set name=#{name},password=#{password} where id=#{id}
-->
<update id="updateUserById" parameterType="pojo.User">
update user
<set>
<if test="name!=null">
name=#{name},
</if>
<if test="password!=null">
password = #{password}
</if>
</set>
where id = #{id}
</update>

Choose语句

类似于 Java 的 switch 语句,查询条件有一个满足即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
xml复制代码
<select id="selectUserByNameAndPassword" parameterType="map" resultType="pojo.User">
select *
from user
<where>
<choose>
<when test="name != null">
name = #{name}
</when>
<when test="password != null">
and password = #{password}
</when>
<otherwise>
and id=#{id}
</otherwise>
</choose>
</where>
</select>

foreach

foreach 元素的功能是非常强大的,它允许你指定一个集合,声明可以用在元素体内的集合项和索引变量。它也允许你指定开闭匹配的字符串以及在迭代中间放置分隔符。这个元素是很智能的,因此它不会偶然地附加多余的分隔符。

动态 SQL 的另外一个常用的必要操作是需要对一个集合进行遍历,通常是在构建 IN 条件语句的时候。比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
xml复制代码<!--select * from user where id in (1,2,3)-->
<select id="selectUser" resultType="pojo.User">
select *
from user
where id in
<!--
List 实例将会以 "list" 作为键
数组实例的键是 "array"
-->
<foreach collection="array" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</select>
  • collection:指定输入对象中的集合属性
  • item:每次遍历生成的对象
  • open:开始遍历时的拼接字符串
  • close:结束时拼接的字符串
  • separator:遍历对象之间需要拼接的字符串

注意:可以将一个 List 实例或者数组作为参数对象传给 MyBatis,当你这么做的时候,MyBatis 会自动将它包装在一个 Map 中并以名称为键。List 实例将会以 “list” 作为键,而数组实例的键将是 “array”。

SQL片段

有时候可能某个 sql 语句我们用的特别多,为了增加代码的重用性,简化代码,我们需要将这些代码抽取出来,然后使用时直接调用。

  • 提取重复 SQL 片段:
1
2
3
4
5
6
7
8
XML复制代码<sql id="if-name-password">
<if test="name != null">
name = #{name}
</if>
<if test="password != null">
and password = #{password}
</if>
</sql>
  • 引用SQL片段:
1
2
3
4
5
6
7
8
xml复制代码<select id="selectUserByNameAndPassword" parameterType="map" resultType="pojo.User">
select * from user
<where>
<!-- 引用 sql 片段,如果 refid 指定的不在本文件中,那么需要在前面加上 namespace -->
<include refid="if-name-password"></include>
<!-- 在这里还可以引用其他的 sql 片段 -->
</where>
</select>

注意:

  1. 最好基于单表来定义 sql 片段,提高片段的可重用性
  2. 在 sql 片段中不要包括 where

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

1…164165166…956

开发者博客

9558 日志
1953 标签
RSS
© 2025 开发者博客
本站总访问量次
由 Hexo 强力驱动
|
主题 — NexT.Muse v5.1.4
0%