0%

栈的介绍

栈的英文为stack,栈是一个先入后出的有序链表,栈是限制线性表中元素的插入和删除只能在线性表的同一段进行的一种特殊的线性表。允许插入和删除的一端称为栈顶,另外一端称为栈底

image-20220608155318037

应用场景

  1. 子程序的调用,在跳往下一个程序的时候,将其数据暂时保存在栈中,递归就是这种情况https://moonshuo.cn/posts/28724.html
  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
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
package 数据结构和算法.栈;

/**
* @author 21050
*/
public class ArrayStack {
public static void main(String[] args) {
Stack stack=new Stack(5);
stack.push(1);
stack.push(2);
stack.push(3);
stack.push(4);
stack.push(5);
stack.push(6);
stack.show();

System.out.println("开始出栈");
System.out.println(stack.pop());
System.out.println(stack.pop());
System.out.println(stack.pop());
System.out.println(stack.pop());
System.out.println(stack.pop());
System.out.println(stack.pop());
System.out.println(stack.pop());

}


}

class Stack {
//定义size的大小
private int size;
//定义数据
private int[] stack;
//默认情况下top为-1
private int top = -1;

//定义构造函数定义一个栈
public Stack(int size) {
this.size = size;
stack = new int[size];
}

//判断栈是否为空
public boolean isNull() {
return top == -1;
}

//判断栈是否为满
public boolean isFull() {
return top == size - 1;
}

//入栈操作
public void push(int value) {
if (isFull()) {
System.out.println("栈为满");
} else {
stack[++top]=value;
}
}

//出栈操作
public int pop(){
if (isNull()){
throw new RuntimeException("栈为空");

}else {
return stack[top--];
}
}

//遍历栈,从top开始
public void show(){
if (isNull()){
System.out.println("为空");
}else {
for (int i=top;i>-1;i--){
System.out.println(stack[i]);
}
}
}
}

image-20220608163306074

链表模拟栈

类结构有一点瑕疵,先不调整了

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
package 数据结构和算法.栈;

/**
* @author 21050
*/
public class LinkedNode {


public static void main(String[] args) {

//建立一个头节点
Node head=new Node(0);
Node node1=new Node(1);
Node node2=new Node(2);
Node node3=new Node(3);
Node node4=new Node(4);
head.push(node1,head);
head.push(node2,head);
head.push(node3,head);
head.push(node4,head);

head.show(head);

head.pop(head);
head.pop(head);
head.show(head);
}

}
class Node{
private int data;
Node next;

public Node(int data) {
this.data = data;
}

public boolean isEmpty(Node head){
return head.next==null;
}
//设置插入方法,考虑到栈的遍历方法,我们这里使用头插法
public void push(Node node,Node head){
if (isEmpty(head)){
head.next=node;
}else {
node.next= head.next;
head.next=node;
}
}

//设置出栈方法,这里的出栈都是将head.next删除
public int pop(Node head){
if (isEmpty(head)){
throw new RuntimeException("栈为空,无法完成操作");
}
else {
int popData=head.next.data;
head.next=head.next.next;
return popData;
}
}

public void show(Node head){
Node temp=head;
while (temp.next!=null){
temp=temp.next;
System.out.println(temp);
}
}

@Override
public String toString() {
return "Node{" +
"data=" + data +
'}';
}
}

image-20220608165437129

表达式

前缀表达式

前缀表达式又称波兰表达式,前缀表达式的运算符位于操作数之前,例如(3+4)*5-6的前缀表达式时是- * + 3456

这个扫描的方法是从右向左依次进行扫描,在遇到第一个运算符之前,数字栈的空间如下

image-20220609145117365

当遇到一个运算符的时候,取出栈顶和次栈顶元素,与运算符进行运算

image-20220609145228092

模拟(这里偷懒,使用系统提供的栈):

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
package 数据结构和算法.栈;

import java.util.Stack;

public class StackExercise {
public static void main(String[] args) {
Stack<Integer> numSatck=new Stack<>();
//首先从右向左扫描,入栈6543
numSatck.add(6);
numSatck.add(5);
numSatck.add(4);
numSatck.add(3);

//扫描到+,出栈头元素个次头元素
int head=numSatck.pop();
int second=numSatck.pop();
//将得到的结果压入栈
numSatck.add(head+second);
//扫描到*,将结果压入栈
head=numSatck.pop();
second=numSatck.pop();
numSatck.add(head*second);
//-运算符,压入栈
head=numSatck.pop();
second=numSatck.pop();
numSatck.add(head-second);
System.out.println("最终的值为"+numSatck.pop());
}


}

image-20220609150314475

中缀表达式

是我们最常见的运算表达式(3+4)*5-6

后缀表达式

(3+4)*5-6这个的后缀表达式为

1
2
//在这个过程中从左向右扫描,遇到第一个数字压入数字栈,遇到运算符,将符号压入符号栈,同时取出栈顶元素与次栈顶元素进行计算,结果压入栈中
3 4 + 5 * 6 -

在运算后缀表达式的时候,遇到第一个运算符之前,数字栈空间如下

image-20220609144805019

而当遇到第一个之后

image-20220609144844278

剩下的依次类推得出相应的结果

这里就不模拟了

中缀转后缀表达式

我们知道中缀表达式中存在(),在转换后缀表达式的时候需要进行转换

比如5+((3+4)*5)-6这个在转化的时候,会扫描这个表达式,我们现在要将这个表达式转化为后缀表达式

此时我们开始扫描,遇到操作数直接将其压入栈中,左边s1为运算符栈

image-20220609155308517

遇到运算符与将其与运算符栈顶比较,此时为空,直接压入s1栈,此时遇到两个左括号,压入s1栈

image-20220609160833950

继续扫描,遇到3+4,3直接压入栈中,而+与s1栈顶元素(比较优先级,优先级大,直接压入s1栈

image-20220609161130061

此时再一次扫描遇到右括号,扫描s1栈,直到遇到左括号,并将中间扫描的全部移动到s2栈,括号去掉

image-20220609161327780

我们继续扫描,将*进入到s1栈中,5进入s2栈,此时我们再一次扫描到右括号,将这里的值调到s2中,去掉括号,

image-20220609161553473

接下来我们扫描到-,-与栈顶+的优先级相同,+出栈到s2,-入栈到s1,并且扫描到6

image-20220609161819577

将s1栈中值移动过去,得最终结果534+5*+6-

image-20220609161900585

我们使用代码进行模拟

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
package 数据结构和算法.栈;

import java.util.Stack;

public class StackExercise {

public boolean biggerPriority(char head, char operate) {
//遇到左括号直接加
if (head == '('||operate=='(') {
//如果左括号,则优先级最小
return true;
}
if (head == '+' || head == '-') {
//只要operate不是(,+-,那么就可以判断operate优先级大
return operate == '*' || operate == '/';
}
if (head == '*' || head == '/') {
//如果head为*/,则默认优先级最大
return false;
} else {
throw new RuntimeException("我们无法判断符号优先级,请检测符号是否正确");
}

}


public static void main(String[] args) {
StackExercise stackExercise = new StackExercise();
Stack<Character> s1 = new Stack<>();
Stack<Character> s2 = new Stack<>();
String expression = "5+((3+4)*5)-6";
for (int i = 0; i < expression.length(); i++) {
char a = expression.charAt(i);
//判断是否为数字
if (Character.isDigit(a)) {
s2.add(a);
//等于右括号的时候,括号之间的元素出栈到s1,同时删除()
} else if (a==')') {
char temp=s1.pop();
while (temp!='('){
s2.add(temp);
temp=s1.pop();
}
} else {
//如果为空,直接进入
if (s1.isEmpty()) {
s1.add(a);
//如果不为空,则比较优先级的大小,
} else {
//如果优先级大,直接插入s1
char temp = s1.pop();
if (stackExercise.biggerPriority(temp, a)) {
//记得将temp拿回去,此时并不能出栈
s1.add(temp);
s1.add(a);
//如果优先级小,temp到s2中,而a进入栈s1
} else {
s2.add(temp);
s1.add(a);
}

}
}
}
System.out.println(s2);
}


}

image-20220609165819173

sql文件:atguigudb.sql · moonshuo/fruit stand - 码云 - 开源中国 (gitee.com)

select基本语句

列别名

1
2
#下面的三种方式别名方式都可以进行
SELECT employee_id emp_id,first_name AS f_name, phone_number "phone" FROM employees

image-20220608103819095

去除重复行

1
2
#查询一共有多少个部门id
SELECT DISTINCT department_id FROM employees

注意,如果此时要查询每一个部门下面的工资

1
2
#执行这个语句会报错,因为salary拥有107行,而DISTINCT department_id,却有17行,无法进行匹配
SELECT salary,DISTINCT department_id FROM employees

但是注意,如果我将上面的顺序换一换,得到的是每用一个部门下面,不同的工资水平,这里会首先匹配DISTINCT department_id

1
SELECT DISTINCT department_id,salary FROM employees

image-20220608105213908

空值参与运算

空值这里指的是null,并不是“”或者0

如果空值参与运算,则运算的结果一定为空

现在我们需要查询一个员工一年的工资

1
2
#在这里,commission_pct表示绩效提升倍数,其实当其为null的时候,我们是要将其当作0来看待,但是这里却出现了问题,这也说明了null0和“”不相同
SELECT first_name,(1+commission_pct)*salary,commission_pct FROM employees

image-20220608110132591

这里我们可以使用一个函数

1
2
# 如果为null,则使用0来进行替换
SELECT first_name,(1+IFNULL(commission_pct,0))*salary,commission_pct FROM employees

着重号

此时有一个表格为order,但是关键字也为order,想要查询order表格

1
2
#不是单引号,而是tab上面的那个着重号
SELECT * FROM `order`

查询常数

1
SELECT "公司名称",456,department_id FROM employees

image-20220608111643285

显示表的信息

1
DESCRIBE  employees;

image-20220608111909672

select条件过滤

查询部门id为90的员工

1
SELECT * FROM employees WHERE department_id=90

查询first—name为den的人

1
SELECT * FROM employees WHERE first_name='Den'

但是注意次数mysql存在一定的缺陷

我执行下面的语句,发现两次查询的结果相同,但是在数据库中这个人的名称为Den,第二次查询应该不会有结果集,这是sql 的一个缺陷,但是像oracel不会出现这样的情况

1
SELECT * FROM employees WHERE first_name='den'

where要放到from的后面

算数运算符

+号使用

在sql中+没有Java语言中的字符转换的作用,只是体现运算符相加的作用

1
2
3
4
5
6
SELECT manager_id+'1' FROM departments
# 这个+a并不会将其看成ascii码进行处理,而是无法解析之后,看成0来进行处理
SELECT manager_id+'a' FROM departments

#null参数运算之后还是null
SELECT manager_id+NULL FROM departments

image-20220615144843674

image-20220615145100241

image-20220615145216075

其他

对于/,如果两个整型的数相除,其实结果为浮点型,mysql默认为除数不尽,所以默认为结果为浮点型

image-20220615145508379

而如果除数为0,那么最终得到的结果为null

image-20220615145554797

取模运算

其实最终得到的结果域被模数有关,与模数无关

image-20220615145854767

比较运算符

符号类型

1
2
3
4
5
6
7
8
# 比较运算符,正确为1,不正确为0
SELECT 1=1,2!=2 FROM departments
#字符串类型比较
SELECT 1='1',2='a',0='a' FROM departments 1 0 1
#两边全是字符串,不会隐式转换数值
SELECT 'a'='a','a'='b' FROM departments 1 0
#如果存在null,结果全为null
SELECT NULL=0,NULL=NULL FROM departments null null

image-20220615151019701

此时我们查看数据中的存在null的值,现在我们需要查询这些数据,执行以下语句,我们会发现这个结果居然为空集,这是因为在这个过程中manager_id=NULL返回的是null,而只有结果为1的才会被保留下来

1
2
3
4
SELECT * FROM departments WHERE manager_id=NULL
#那么这个结果我们因该怎么处理???
#使用安全等于,使得null也可以参数运算,当然我们也可以使用is null来进行判断
SELECT * FROM departments WHERE manager_id <=> NULL

image-20220615151131130

image-20220615151534631

字母类型

1
2
#LEAST 表示最小,GREATEST表示最大
SELECT LEAST(1,2,3,5,6),GREATEST(5,6,8,2) FROM departments 1 8

下面我们字符串进行这个函数的比较,他会对结果逐个字母进行比较,小的便是结果

between and,查询某个范围的信息,注意这个是包含两边的边界值的

image-20220615153232526

1
2
#不在6000-8000范围内
SELECT * FROM employees WHERE salary NOT BETWEEN 6000 AND 8000

查询是否在值内 in

这里查询部门id为10,20,30的部门,在没有学习in之前,这里的语句会发现他还返回了其他结果,这是因为or 20 不为0,所以sql看作1,就相当于所有条件都成立的。

image-20220615154104075

image-20220615154256596

模糊查询

现在查询包含字母a的员工信息

mysql怎样查询区分大小写-mysql教程-PHP中文网

1
2
3
# %表示不确定个数的字符,包括0个等等,注意此时大小写并不是区分的
SELECT * FROM employees WHERE last_name LIKE '%a%'

image-20220615155004171

查询其中包含字母a并且包含字母e的信息,注意两种写法的不同

1
2
#这样写虽然得到了结果,但是这样其实还是做出了条件限制,即a在e前面
SELECT * FROM employees WHERE last_name LIKE '%a%e%'

image-20220615155402837

所以说我们可以在加上

1
2
3
SELECT * FROM employees WHERE last_name LIKE '%a%e%' OR last_name LIKE '%e%a%'
#当然物品们也可以使用and进行链接,结果相同
SELECT * FROM employees WHERE last_name LIKE '%a%' AND last_name LIKE '%e%'

查询第二个字符为a的员工信息

1
2
#_表示一个不确定字符
SELECT * FROM employees WHERE last_name LIKE '_a%'

查询第二个字符为下划线,而都三个为a

1
2
# \使用转义字符,表示这是纯纯的下划线
SELECT * FROM employees WHERE last_name LIKE '_\_a%'

image-20220615160003847

正则表达式,REGEXP\RLIKE精确查询

插眼,学习!!!

1
2
#以a开始的名字
SELECT * FROM employees WHERE last_name REGEXP '^A'

image-20220615160454630

逻辑运算符

逻辑运算符中的or与and是存在优先级关系的,下面的运算中会先运算两个and的关系,并不会执行完第一个and,就立即执行or

1
SELECT * FROM `employees` WHERE employee_id>120 AND employee_id<130 OR salary>1000 AND salary<30000

位运算符

image-20220708111148368

排序与分页

排序数据

默认的排序顺序是我们添加的顺序

使用 ORDER BY 子句排序 ASC(ascend): 升序 DESC(descend,默认是升序):降序 ORDER BY 子句在SELECT语句的结尾。

1
2
3
SELECT last_name, job_id, department_id, hire_date
FROM employees
ORDER BY hire_date DESC;

image-20220708112830922

下面的排序中我们使用到了列的别名,最终的显示结果也是正确的

image-20220708113433761

但是如果在这里使用了where里面,就会无法识别,所以别名只能在order中使用

image-20220708113553085

其实这里与sql语句的执行顺序有关系,这里的执行顺序sql首先查看了from语句,看看我们想要查看哪一个表,然后在查看有什么过滤条件,最终再去查看的select这一行,所以where识别不了别名

二级排序

image-20220708114157388

分页操作

链表介绍

链表与数组其实都是表的一个,而数组的存储是一个连续的地址空间,如果想要对数组进行插入删除操作,那么加入插入点在最后的位置,时间复杂度为o(1),但是如果插入点在最前面,而由于地址空间连续那么就需要使之后的所有的地址空间向后移动,时间开销较大,但是如果我们对数组进行访问操作,会访问的很快,根据数组的索引即可直接访问,但是链表只能从头节点开始遍历,链表的插入和删除操作比较简单,只需要改变对应位置的next域即可,这是因为链表的存储方式,地址空间不连续,所以进行插入时,其他的地址空间不会放生变化,

链表是有序的列表,内存如下:

image-20220605094900976

链表的各个节点不一定是连续存储的,链表分为有头节点与没有头节点的

单链表

头节点不存放具体的数据,作用是表示单链表的头

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
package 数据结构和算法.链表;

/**
* @author 21050
*/
public class SingleLinkedList {

//首先定义节点
class HeroNode{
int no;
String name;
String nickName;
HeroNode next;

public HeroNode(int no, String name, String nickName) {
this.no = no;
this.name = name;
this.nickName = nickName;
}

@Override
public String toString() {
return "HeroNode{" +
"no=" + no +
", name='" + name + '\'' +
", nickName='" + nickName + '\'' +
'}';
}
}


//建立节点,首先建立头节点,但是不存储数据,只是指向下一个位置
HeroNode head=new HeroNode(0,"","");


public void addNode(HeroNode heroNode){
HeroNode temp=head;
while (temp.next!=null){
temp=temp.next;
}
temp.next=heroNode;
}

//显示当前链表
public void show(){
HeroNode temp=head.next;
while (temp!=null){
System.out.println(temp);
temp=temp.next;
}
}

HeroNode heroNode1=new HeroNode(1,"haha","heihei");
HeroNode heroNode2=new HeroNode(2,"ha","hei");
HeroNode heroNode3=new HeroNode(1,"hdfb","hei873");
public static void main(String[] args) {
SingleLinkedList singleLinkedList=new SingleLinkedList();
singleLinkedList.addNode(singleLinkedList.heroNode1);
singleLinkedList.addNode(singleLinkedList.heroNode2);
singleLinkedList.addNode(singleLinkedList.heroNode3);
singleLinkedList.show();
}
}

image-20220605104247671

排序插入

现在我们需要提出一个要求,要求这个程序必须按照no的顺序进行插入,并且如果有相同的no则第二个添加的失败,那么我们就需要进行更改添加的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public void addNode(HeroNode heroNode){
HeroNode temp=head;
while (temp.next!=null){
if (temp.next.no==heroNode.no){
System.out.println("序号相同,本次加入节点失败");
return;
}
if (temp.next.no>heroNode.no){
HeroNode temp1=temp.next;
temp.next=heroNode;
heroNode.next=temp1;
return;
}
temp=temp.next;
}
temp.next=heroNode;

}

image-20220605110454179

修改节点信息

1
2
3
4
5
6
7
8
9
10
//通过no修改节点,这里还可以加上其他的配置,比如判断是否删除成功这个节点等等
public void update(int No){
HeroNode temp=head;
while (temp.next!=null){
temp=temp.next;
if (temp.no==No){
temp.name="张三";
}
}
}

image-20220605112225842

删除节点

1
2
3
4
5
6
7
8
9
10
//删除节点
public void delete(int no){
HeroNode temp=head;
while (temp.next!=null){
if (temp.next.no==no){
temp.next=temp.next.next;
}
temp=temp.next;
}
}

image-20220605114058165

疑问

在这个过程中,我们的temp仅仅是一个替代品,为什么改变了temp.next就可以改变head的链表,在

1
HeroNode temp=head;

操作下,temp其实拿到了head的地址,同时传过去的不仅仅是head,还有head.next都传输过去了,这里定义的temp其实是引用数据数据类型。

image-20220605114417807

链表练习

单链表有效的个数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public void getNums(HeroNode head){
int count=0;
if (head.next==null){
System.out.println("链表为空");
}else {
HeroNode node=head;
while (node.next!=null){
count++;
node=node.next;
}
System.out.println("拥有"+count+"个节点");
}

}

image-20220606141511242

查找单链表中倒数第k个节点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public void getReciprocalNum(int k,HeroNode head){
//首先得到链表的长度
int size=getNums(head);
if (size==0||k>size){
System.out.println("无效");
return;
}
HeroNode temp=head;
for (int i=0;i<=size-k;i++){
temp=temp.next;
}
System.out.println(temp.toString());

}

image-20220606143344455

单链表的反转

我们将第一个节点加入到节点之后,然后将第一个节点删除,依次循环类推

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public void reverseLinkedList(HeroNode head) {
if (head.next == null) {
System.out.println("无效链表");
return;
}
//建立一个新的头节点
HeroNode newHead = new HeroNode(0, "", "");

while (head.next!=null){
HeroNode heroNode = head.next;
HeroNode temp=heroNode.next;
heroNode.next=null;
HeroNode temp1=newHead.next;
newHead.next=heroNode;
newHead.next.next=temp1;
head.next=temp;
}
show(newHead);
}

其他人的解决方法,此方法巧妙的将添加方法更改到cur上,而不是在新节点上面直接添加

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public void reverseList(HeroNode head){
if (head.next==null){
return;
}
HeroNode cur=head.next;
HeroNode next=null;
HeroNode newHead=new HeroNode(0,"","");
while (cur!=null){
next=cur.next;
//将新节点的下一个节点当作cur的下一个节点
cur.next=newHead.next;
//新节点下一个节点相当于插入了cur
newHead.next=cur;
cur=next;
}
show(newHead);
}

从尾到头打印单链表

先反转,在打印,(⊙﹏⊙),当然可以

这里展示递归调用的方法

1
2
3
4
5
6
7
8
public void printLinkList(HeroNode head){
if (head.next==null){
return;
}
HeroNode tempHead=head.next;
printLinkList(tempHead);
System.out.println(tempHead);
}

image-20220606171643583

栈调用

我们知道栈是先进后出的

1
2
3
4
5
6
7
8
9
10
11
public void printLinkList(HeroNode head){
Stack<HeroNode> heroNodes=new Stack<>();
HeroNode temp=head;
while (temp.next!=null){
temp=temp.next;
heroNodes.add(temp);
}
while (heroNodes.size()>0){
System.out.println(heroNodes.pop());
}
}

上述的两种方法其实都是将同string重写之后输出的,并没有输出next域,也可以输出next域,但是如果还是想要达到这个效果,就需要对压栈的过程再次细化,这个写起来方便,就这样写喽

tostring方法

1
2
3
4
5
6
7
8
@Override
public String toString() {
return "HeroNode{" +
"no=" + no +
", name='" + name + '\'' +
", nickName='" + nickName + '\'' +
'}';
}

合并链表,合并之后仍然有序

两个链表如下

image-20220606202324581

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
public static void mergeLinkedList(HeroNode head1, HeroNode head2) {
HeroNode temp2=head2;
while (temp2.next!=null){
HeroNode cur=temp2.next;
HeroNode next=cur.next;
cur.next=null;
head2.next=next;
//将cur加入head1中
HeroNode temp1=head1;
while (temp1.next!=null){
if (temp1.next.no== cur.no){
System.out.println("序号重复,本次加入失败");
break;
}
if (temp1.next.no> cur.no){
cur.next=temp1.next;
temp1.next=cur;
break;
}
temp1=temp1.next;
}
temp1.next=cur;
}
show(head1);

}

image-20220606211700745

双向链表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Node{
//定义数据区
int date;
Node next;
Node pre;
//初始化链表
public Node(int date) {
this.date = date;
}

@Override
public String toString() {
return "Node{" +
"date=" + date +
'}';
}
}

插入节点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//我们首先定义一个头节点
static Node head=new Node(0);
//在最末尾位置插入节点
public void insertNode(Node node){
Node temp=head;
while (temp.next!=null){
temp=temp.next;
}
temp.next=node;
node.pre=temp;
}

//遍历链表
public void showNode(Node head){
Node temp=head;
while (temp.next!=null){
temp=temp.next;
System.out.println(temp);
}
}

image-20220607191156373

顺序插入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//顺序插入
public void insertByOrder(Node node){
Node cur=head;
while (cur.next!=null){
cur=cur.next;
if (node.date==cur.date){
System.out.println("相同的序号,不允许加入");
}
if (node.date<cur.date){
cur.pre.next=node;
node.pre=cur.pre;
node.next=cur;
cur.pre=node;
return;
}

}
cur.next=node;
node.pre=cur;

}

删除节点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public void deleteNode(int no){
Node cur=head;
while (cur.next!=null){
cur=cur.next;
//此时我们需要防止这是否为最后一个节点,如果是最后一个节点,小心空指针
if (cur.date==no){
//删除最后一个节点
if (cur.next==null){
cur.pre.next=null;
cur.pre=null;
}else {
cur.pre.next=cur.next;
cur.next.pre=cur.pre;
cur.pre=null;
cur.next=null;
}
System.out.println("删除成功");
return;
}
}
System.out.println("删除失败,没有找到对应的节点信息");
}

image-20220607195032636

环形链表

约瑟夫问题:

15个教徒和15个非教徒在深海上遇险,必须将一半的人投入海中,其余的人才能幸免于难,于是想了一个办法:30个人围成一圆圈,从第一个人开始依次报数,每数到第九个人就将他扔入大海,如此循环进行直到仅余15个人为止。问怎样排法,才能使每次投入大海的都是非教徒。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Node{
int data;
Node next;

public Node(int data) {
this.data = data;
}

@Override
public String toString() {
return "Node{" +
"data=" + data +
'}';
}
}

环形链表的增加

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public void insertByorder(Node node){

Node cur=first.next;
if (cur.data== node.data){
System.out.println("这个节点已经加入了");
return;
}
while (cur.next.data!=first.data){
if (cur.next.data== node.data){
System.out.println("这个节点已经加入了");
return;
}
if (cur.next.data>node.data){
node.next=cur.next;
cur.next=node;
return;
}
cur=cur.next;
}
cur.next=node;
node.next=first;
}

image-20220607210336747

环形链表的删除

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* @param n 表示循环几次删除一个节点*/
public void delete(int n) {
Node cur = first;
for (int i=0;i<n-1;i++){
if (i!=0){
cur=cur.next;
}
}
//此时cur是应该删除的前一个
System.out.println("我是节点"+cur.next+"我真可怜,要被杀了");
//此时cur指向被杀节点的前一个节点
cur.next=cur.next.next;
}

image-20220607220413046

约瑟夫问题解决

这时候我们改一下删除的方法,加上一个循环,注意这一次循环判断条件要增加

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* @param n 表示循环几次删除一个节点*/
public void delete(int n) {
Node cur = first;
for (int j = 0; j < 15; j++) {
for (int i = 0; i < n - 1; i++) {
if (i != 0||j!=0) {
cur = cur.next;
}
}
//此时cur是应该删除的前一个
System.out.println("我是节点" + cur.next + "我真可怜,要被杀了");
//此时cur指向被杀节点的前一个节点
cur.next = cur.next.next;
}
}

image-20220607222738772

CRM客户管理系统

数据库

主键字段

在数据库设计中,如果有一组字段能够唯一确定一条记录,则可以把他们设计成表的主键,推荐使用一个字段做主键,而且推荐使用没有业务含义的字段做主键。

设置主键有两种方式

  1. 数据库自增,但是这个数据库自增,数据库会开辟出一个线程专门管理数据库自增的信息,当我们有多个并发的进程需要进行插入操作时,数据库会上锁,只允许一个一个的进行,效率比较低下你真的懂自增主键(auto_increment)?_wind_huise的博客-CSDN博客_自增主键
  2. 使用uuid,uuid使jdk自带的字段,我们可以使用这个类生成32位的不重复的字段作为主键,而且速度快,并不会引起效率降低

外键字段

外键用来确定表与表之间的关系,表与表之间存在1对1,1对多等等关系,当然如果外键不能为空,则使用内连接,如果外键可以为空,使用外连接。但是如果两种都可以使用,建议使用内连接,速度比较快

日期和事件的字段

data:年月日,time:时分秒 datatime:年月日时分秒

而由于sql中与Java之间的日期转换比较麻烦,所以在数据库中我们使用string类型进行存储

char(10):yyyy–MM–dd

char(19):yyyy–MM–dd HH:mm:ss

搭建开发环境

添加依赖

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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.moonshuo.crm</groupId>
<artifactId>crm</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>

<name>crm Maven Webapp</name>
<!-- FIXME change it to the project's website -->
<url>https://www.example.com</url>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<!-- MySQL数据库连接驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.29</version>
</dependency>
<!-- JDBC数据源连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.9</version>
</dependency>
<!-- MyBatis框架依赖 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.9</version>
</dependency>
<!-- Spring框架依赖的JAR配置 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.20</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.3.20</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.3.20</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.3.20</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.20</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.3.20</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.3.20</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.20</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
<version>5.3.20</version>
</dependency>
<!-- Spring AOP支持-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.9.1</version>
</dependency>
<!-- MyBatis与Spring整合依赖 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.7</version>
</dependency>
<!-- servlet及jstl标签库依赖的JAR配置 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
<!-- 加载jackson插件依赖 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.13.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.13.3</version>
</dependency>
<!--poi依赖-->
<!-- https://mvnrepository.com/artifact/org.apache.poi/poi -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>5.2.2</version>
</dependency>
<!-- 文件上传 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
<!-- Log4j2依赖的JAR配置 -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.17.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.17.2</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.36</version>
<scope>compile</scope>
</dependency>
<!-- Spring5和Thymeleaf整合包 -->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
<version>3.0.15.RELEASE</version>
</dependency>

</dependencies>

<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.*</include>
</includes>
</resource>
</resources>
</build>

</project>

设置编码格式

image-20220605144827804

添加配置文件

mybatis配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--打印日志-->
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<!--指明对象的位置-->
<typeAliases>
<package name="com.zss.pojo"/>
</typeAliases>
<!--指明mapper文件位置-->
<mappers>
<package name="com.zss.mapper"/>
</mappers>
</configuration>

配置数据链接和事务

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
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
<!--读取jdbc.properties配置文件的支持-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 配置数据源 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="url" value="${jdbc.url}"/>
</bean>
<!-- 配置SqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 必须注入属性dataSource -->
<property name="dataSource" ref="dataSource"/>
<!-- 如果mybatis没有特殊的配置(比如别名等),configLocation可以省去 ;否则,不能省略-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>
<!-- mapper注解扫描器配置,扫描@MapperScan注解,自动生成代码对象 -->
<bean id="mapperScanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!--这个basePackage和mybatis-config中的mappers标签作用有什么区别-->
<property name="basePackage" value="com.moonshuo.crm.mapper"/>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean>

<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 配置事务 -->
<aop:config>
<aop:pointcut expression="execution(* com.moonshuo.crm..service.*.*(..))" id="allMethodPointcut"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="allMethodPointcut"/>
</aop:config>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="add*" propagation="REQUIRED" rollback-for="Exception"/>
<tx:method name="save*" propagation="REQUIRED" rollback-for="Exception"/>
<tx:method name="edit*" propagation="REQUIRED" rollback-for="Exception"/>
<tx:method name="update*" propagation="REQUIRED" rollback-for="Exception"/>
<tx:method name="delete*" propagation="REQUIRED" rollback-for="Exception"/>
<tx:method name="do*" propagation="REQUIRED" rollback-for="Exception"/>
<tx:method name="*" propagation="REQUIRED" read-only="true"/>
</tx:attributes>
</tx:advice>
</beans>

mvc配置文件

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
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- dispatcherServlet截获所有URL请求 -->
<mvc:default-servlet-handler/>
<!--thymeleaf视图解析器-->
<bean id="viewResolver" class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
<property name="order" value="1"/>
<property name="characterEncoding" value="UTF-8"/>
<property name="templateEngine">
<bean class="org.thymeleaf.spring5.SpringTemplateEngine">
<property name="templateResolver">
<bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
<property name="prefix" value="/WEB-INF/pages/"/>
<property name="suffix" value=".html"/>
<property name="templateMode" value="HTML5"/>
<property name="characterEncoding" value="UTF-8"/>
</bean>
</property>
</bean>
</property>
</bean>



<!-- spring mvc 扫描包下的controller -->
<context:component-scan base-package="org.zuel.crm.web.controller"/>
<context:component-scan base-package="org.zuel.crm.settings.web.controller"/>
<context:component-scan base-package="org.zuel.crm.workbench.web.controller"/>

<!-- 配置注解驱动 -->
<mvc:annotation-driven/>

<!--配置拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/settings/**"/>
<mvc:mapping path="/workbench/**"/>
<!--登录页面和登录跳转验证要排除(排除拦截的优先级高于拦截)-->
<mvc:exclude-mapping path="/settings/qx/user/toLogin.do"/>
<mvc:exclude-mapping path="/settings/qx/user/login.do"/>
<!--拦截器类-->
<bean class="org.zuel.crm.settings.web.interceptor.LoginInterceptor" />
</mvc:interceptor>
</mvc:interceptors>

<!--
path:设置处理的请求地址
view-name:设置请求地址所对应的视图名称
-->
<!-- <mvc:view-controller path="/" view-name="index"></mvc:view-controller>-->

<!-- 虽然爆红,但是可以正常使用-->
<!-- <mvc:view-controller path="/" view-name="index"/>-->


<!-- 配置文件上传解析器 id:必须是multipartResolver-->
<!--<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="#{1024*1024*80}"/>
<property name="defaultEncoding" value="utf-8"/>
</bean>-->
</beans>

总配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 加载系统配置文件
<context:property-placeholder location="classpath:*.properties" />-->
<!-- 扫描注解 -->
<context:component-scan base-package="com.moonshuo.crm.service" />
<!-- 导入数据相关配置 -->
<import resource="applicationContext-datasource.xml" />
</beans>

配置web.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
48
49
50
51
52
53
54
55
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id="dataservice" version="3.0">
<display-name>dataservice application</display-name>
<!-- spring监听器加载applicationContext.xml配置文件 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- spring字符过滤器 -->
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- Spring mvc分发servlet -->
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<!-- 欢迎页,默认进入index controller -->
<welcome-file-list>
<welcome-file>/</welcome-file>
</welcome-file-list>
<!--<error-page>
<error-code>404</error-code>
<location>/settings/error/to404Page.do</location>
</error-page>-->
</web-app>

配置maven的编译选项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.*</include>
</includes>
</resource>
</resources>
</build>

注意放置文件的时候,web根目录下面数据都是不安全的,所以一般放到wen-inf下面,是受到保护的,而图片则放置到根目录下面。

测试

配置服务器,查看是否搭建成功

编码实现

image-20220605161143174

setting表示系统管理功能,而workbench表示业务管理功能

系统管理功能

首页

分析需求:

image-20220605163220625

编码实现:

设置mvc扫描这个包

登录功能实现

image-20220608152802924

我们这里的respondbody返回的对象,但是还需要携带相应的状态码等等,所以我们使用新建立一个对象,可以包含状态码和user对象等等

逆向工程创建类

1
2
3
4
5
6
7
8
9
10
11
12
13
<build>
<plugins>
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.2</version>
<configuration>
<verbose>true</verbose>
<overwrite>true</overwrite>
</configuration>
</plugin>
</plugins>
</build>

加入插件

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 version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<!--上面爆红可以不用管-->
<generatorConfiguration>
<!--这个需要配置一个jar包的位置,一般在maven长裤里面就直接找到了-->
<classPathEntry location="D:\Maven\maven-repository\mysql\mysql-connector-java\8.0.29\mysql-connector-java-8.0.29.jar"/>
<!--
targetRuntime: 执行生成的逆向工程的版本
MyBatis3Simple: 生成基本的CRUD(清新简洁版 增删改)
MyBatis3: 生成带条件的CRUD(奢华尊享版 )
-->
<context id="DB2Tables" targetRuntime="MyBatis3Simple">
<commentGenerator>
<!-- 是否去除自动生成的注释 -->
<property name="suppressAllComments" value="true" />
</commentGenerator>
<!-- 数据库的连接信息 -->
<jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/crm"
userId="root"
password="200101">
</jdbcConnection>
<!-- javaBean的生成策略-->
<javaModelGenerator targetPackage="com.moonshuo.crm.pojo" targetProject=".\src\main\java">
<property name="enableSubPackages" value="true" />
<property name="trimStrings" value="true" /><!--去掉空格-->
</javaModelGenerator>
<!-- SQL映射文件的生成策略 -->
<sqlMapGenerator targetPackage="com.moonshuo.crm.mapper"
targetProject=".\src\main\resources">
<property name="enableSubPackages" value="true" />
</sqlMapGenerator>
<!-- Mapper接口的生成策略 -->
<javaClientGenerator type="XMLMAPPER"
targetPackage="com.moonshuo.crm.mapper" targetProject=".\src\main\java">
<property name="enableSubPackages" value="true" />
</javaClientGenerator>
<!-- 逆向分析的表 -->
<!-- tableName设置为*号,可以对应所有表,此时不写domainObjectName -->
<!-- domainObjectName属性指定生成出来的实体类的类名 -->
<table tableName="tbl_user" domainObjectName="User"/>
</context>
</generatorConfiguration>

配置文件

功能优化

标志码

image-20220705164207995

这些0与1代表成功与否的标识码,0代表失败,而1代表成功,但是将来如果我们又因为业务要求需要开发许多的标志信息,那么这些的修改就比较冗余,所以我们将这些标志封装成一个常量类

1
2
3
4
5
public class Contants {
//保存标志位
public static final String RETURN_OBJECT_CODE_SUCCESS="1";
public static final String RETURN_OBJECT_CODE_FAIL="0";
}

image-20220705165922915

session名称问题

image-20220705175853289

这个sessionUser在这里其实已经写死了,但是如果我们需要进行更改,并且多个地方进行更改的时候,就会变得麻烦,所以我们使用和上述同样的方法,定义一个常量

image-20220705180129689

简单基础

sql语句去重

image-20220602201107144

查询出所有大学

1
2
3
select distinct university from user_profile

select university from user_profile group by university

查询出某个范围的数据

image-20220602202431393

1
2
3
select device_id,gender,age from user_profile where age>=20 and age<=23

select device_id,gender,age from user_profile where age between 20 and 23

当然也可以使用not between来进行操作

排除列查询

image-20220602203024174

1
2
3
select device_id,gender,age,university from user_profile where university != '复旦大学'

select device_id,gender,age,university from user_profile where university not in ('复旦大学')

其他

数据内连接与外连接

MySQL—内连接和外连接区别_leon.han的博客-CSDN博客_mysql内连接和外连接的区别

内连接:取出按照条件的数据,匹配不到的不进行保留

1
select * from users as u inner join topics as t on u.id=t.user_id

外连接:取出连接表中匹配到的数据,匹配不到的也会保留,值为null

1
2
3
4
#左边的表为主
select * from users as u left join topics as t on u.id=t.user_id;
#右边的表为主
select * from topics as t right join users as u on u.id=t.user_id;

当然还有全外链接

稀疏数组与队列

稀疏数组

基本介绍

当一个数组中大部分元素为0,或者为同一个值的数组时,可以使用稀疏数组来进行保存

处理方法

  1. 记录数组一共有几行几列,有多少个不同的值
  2. 把具有不同值的元素的行列及值记录在一个小规模数组中,从而缩小程序的规模

案例

image-20220602095921065

我们可以看出上面的图片中6*7的数组大小,存储之后可以编程9行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
package 数据结构和算法.稀疏数组和队列;

import java.util.Arrays;

public class SpareArray {
public static void main(String[] args) {
//创建二维的原始数组
int [][]arrays=new int[6][7];
arrays[0][3]=22;
arrays[0][6]=15;
arrays[1][1]=11;
//输出原始二维数组
for (int[]row:arrays){
System.out.println(Arrays.toString(row));
}



//转化稀疏数组
//首先需要获得值的个数确定行数,同时收集二维数组的行与列
int count=0;
//二维数组的行
int row=0;
//二维数组的列
int col=0;
for (int []rows:arrays){
//获得行
row=arrays.length;
//获得列
col=rows.length;
for (int i:rows){
if(i!=0){
//获得稀疏数组的行数
count++;
}
}
}
int [][]spareArray=new int[count+1][3];
//开始赋值
spareArray[0][0]=row;
spareArray[0][1]=col;
spareArray[0][2]=count;
int flag=1;
for (int i=0;i<row;i++){
for (int j=0;j<col;j++){
if(arrays[i][j]!=0){
spareArray[flag][0]=i;
spareArray[flag][1]=j;
spareArray[flag][2]=arrays[i][j];
flag++;
}
}
}
for (int[]rows:spareArray){
System.out.println(Arrays.toString(rows));
}
}
}

image-20220602104331351

稀疏数组转二维数组

得到行和列,还原二维数组,将有效数据还原到二维数组中

1
2
3
4
5
6
7
8
9
10
11
12
13
//稀疏数组转换为二维数组
int [][]newArray=new int[spareArray[0][0]][spareArray[0][1]];
//将有效值进行赋值,开始的行数
int flag1=1;
for (int i=0;i<spareArray[0][2];i++){
newArray[spareArray[flag1][0]][spareArray[flag1][1]]=spareArray[flag1][2];
flag1++;
}
for (int[]rows:newArray){
System.out.println(Arrays.toString(rows));
}

}

队列

队列是一个有序列表,可以用数组(有序数组)或者链表(有序链表)来实现,遵从先入先出的原则

image-20220604092742372

第一张图片没有存入数据的时候,rear与front都为-1,当我们加入数据的时候,rear+1,而front不变,当我们取出数据的时候,是从前面开始取出,那么front就开始+1

队列实现方法

数组方式普通实现

而数组队列需要一个front与rear还有maxsize表示最大的容量,当我们加入一个队列的时候,rear+1,而取出的时候,front+1,但是如果rear==maxsize-1的时候,就已经满了

代码实现

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
package 数据结构和算法.稀疏数组和队列;

/**
* @author 21050
*/
public class ArrayQueue {
int maxSize=0;
int front;
int rear;
int []array;

public ArrayQueue(int maxSize){
this.maxSize=maxSize;
front=-1;
rear=-1;
array=new int[maxSize];
}
/**判断是否为空*/
public boolean isEmpty(){
return front==rear;
}

/**判断是否满了*/
public boolean isFull(){
return rear==maxSize-1;
}

/**取出一个数*/
public void takeNum(){
if (isEmpty()){
System.out.println("为空,没有数据可取出");
}else{
front++;
System.out.println("取出成功,取出了"+array[front]);
}
}

/**插入一个数*/
public void insertNum(int n){
if (isFull()){
System.out.println("队列已经满了,无法插入数据");
}else{
rear++;
array[rear]=n;
System.out.println("插入成功");
}
}

/**打印当前队列*/
public void show(){
for (int i=front;i<rear;){
System.out.println(array[++i]);
}
}
public static void main(String[] args) {
ArrayQueue arrayQueue=new ArrayQueue(3);
System.out.println(arrayQueue.isFull());
System.out.println(arrayQueue.isEmpty());

//插入数据
arrayQueue.insertNum(1);
arrayQueue.insertNum(2);
arrayQueue.insertNum(3);
arrayQueue.insertNum(4);
//展示列表
arrayQueue.show();

//取出数据
arrayQueue.takeNum();
arrayQueue.takeNum();
arrayQueue.takeNum();
arrayQueue.takeNum();
//展示列表
arrayQueue.show();
}

}

image-20220604100621473

当然我们这个也是存在错误的,因为我们这个实现方法并没有完成取模,形成环形队列,只能使用一次

数组方式环形队列实现

初始情况下front=rear=0,此时并没有插入数,但是一旦插入数,front指向当前数,即front=0,而rear指向最后一个数的下一个位置,此时我们需要预留出来一个位置给rear,也就是说最多存放maxSize-1个数据,方便我们进行判断满或者为空

image-20220604202326445

而当我们插入一个元素的时候

image-20220604202454858

此时我们对判断满的条件进行观察,查看两种情况

插入123

image-20220604203013169

插入123,取出12,插入45

image-20220604203538042

我们可以看出判断为满的条件为front=(rear+1)%maxsize

那么判断为空的条件也很明显即rear==front

其实这里不明白为什么要留出一个空来,这样做为了方便分别空还是满,如果不留出来这个空间,插入1234,rear为0,front=0,但是这也是判断空的条件,容易混淆,当然不留空也可以,但是需要我们进行多重判断,反而思路比较麻烦

代码实现

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
package 数据结构和算法.稀疏数组和队列;

/**
* @author 21050
*/
public class ArrayQueue2 {
int front;
int rear;
int maxSize;
int[] array;

public ArrayQueue2(int maxSize){
this.maxSize=maxSize;
front=0;
rear=0;
array=new int[maxSize];
}

/**判断为空*/
public boolean isEmpty(){
return front==rear;
}

/**判断是否满*/
public boolean isFull(){
return (rear+1)%maxSize==front;
}

/**添加一个数,但是添加数的时候,要注意rear的数是否等于了maxsize,大于就需要减去进行进行循环*/
public void insertNum(int n){
if (isFull()){
System.out.println("队列已经满了,无法插入数据");
}else{

array[rear]=n;
System.out.println("插入成功");
rear++;
if (rear==maxSize){
rear= 0;
}
}
}

/**取出一个数,这里也要注意front与maxsize的关系*/
public void takeNum(){
if (isEmpty()){
System.out.println("为空,没有数据可取出");
}else{

System.out.println("取出成功,取出了"+array[front]);
front++;
if (front==maxSize){
front=0;
}
}
}

/**按照顺序展示当前队列*/
public void show(){
for (int i=front;i!=rear;i++){
if (i==maxSize){
i=0;
}
System.out.print(array[i]);

}
}


public static void main(String[] args) {
//插入数据
ArrayQueue2 arrayQueue2=new ArrayQueue2(4);
arrayQueue2.insertNum(1);
arrayQueue2.insertNum(2);
arrayQueue2.insertNum(3);
arrayQueue2.insertNum(4);
arrayQueue2.show();

System.out.println();

//取出数据
arrayQueue2.takeNum();
arrayQueue2.takeNum();
arrayQueue2.show();

System.out.println();

//插入45
arrayQueue2.insertNum(4);
arrayQueue2.insertNum(5);
arrayQueue2.show();
}
}

image-20220604205453247

配置Pom.xml文件

[什么是servlet? - niceyoo - 博客园 (cnblogs.com)](https://www.cnblogs.com/niceyoo/p/10617604.html#:~:text=Java Servlet API 是Servlet容器 (tomcat)和servlet之间的接口,它定义了Serlvet 的各种方法,还定义了 Servlet,容器传送给 Servlet 的对象类,其中最重要的就是 ServletRequest 和 ServletResponse 。)

需要的配置

  1. Spring
  2. SpringMVC
  3. Mybatis
  4. Spring适配Mybaits
  5. 阿里druid连接池
  6. jdbc
  7. 视图解析器包
  8. spring-jdbc事务控制的包
  9. 使用Aspectj的jar包
  10. servlet-api的包
  11. 单元测试包
  12. 除此之外,我们还需要将dao.xml文件可编译到target文件中

配置

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
<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>org.example</groupId>
<artifactId>SSM-Project</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>

<name>SSM-Project Maven Webapp</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>

<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.19</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.19</version>
</dependency>

<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.9</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.7</version>
</dependency>

<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.29</version>
</dependency>

<!--阿里巴巴数据库连接池依赖-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.9</version>
</dependency>

<!-- Spring5和Thymeleaf整合包 -->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
<version>3.0.15.RELEASE</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.19</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.3.19</version>
</dependency>


<!-- https://mvnrepository.com/artifact/org.mybatis.generator/mybatis-generator-core -->
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.4.1</version>
</dependency>

<!-- ServletAPI -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<!--使得不在resoures文件下的依赖也可以被编译-->
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.xml</include>
<include>**/*.properties</include>
<include>**/*.html</include>
</includes>
</resource>
</resources>
</build>

</project>

测试Spring环境

创建类

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
package com.zss.pojo;

/**
* @author zss
*/
public class Employee {
private Integer empId;
private String empName;
private byte gender;
private String email;
private Integer dId;

public Employee() {
}

public Employee(Integer empId, String empName, byte gender, String email, Integer dId) {
this.empId = empId;
this.empName = empName;
this.gender = gender;
this.email = email;
this.dId = dId;
}

public Integer getEmpId() {
return empId;
}

public void setEmpId(Integer empId) {
this.empId = empId;
}

public String getEmpName() {
return empName;
}

public void setEmpName(String empName) {
this.empName = empName;
}

public byte getGender() {
return gender;
}

public void setGender(byte gender) {
this.gender = gender;
}

public String getEmail() {
return email;
}

public void setEmail(String email) {
this.email = email;
}

public Integer getdId() {
return dId;
}

public void setdId(Integer dId) {
this.dId = dId;
}
}

设置dao

1
2
3
public interface EmployeeDao {
public List<Employee> getEmployees();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
import com.zss.dao.EmployeeDao;
import com.zss.pojo.Employee;
import org.springframework.stereotype.Repository;

import java.util.List;
@Repository
public class EmployeeDaoImpl implements EmployeeDao {
@Override
public List<Employee> getEmployees() {
System.out.println("执行dao");
return null;
}
}

设置Service

1
2
3
public interface EmployeeService {
public List<Employee> getEmployees();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.zss.service.impl;

import com.zss.dao.EmployeeDao;
import com.zss.pojo.Employee;
import com.zss.service.EmployeeService;
import org.springframework.stereotype.Service;

import java.util.List;
@Service
public class EmployeeServiceImpl implements EmployeeService {
private EmployeeDao employeeDao;

public void setEmployeeDao(EmployeeDao employeeDao) {
this.employeeDao = employeeDao;
}

@Override
public List<Employee> getEmployees() {

return employeeDao.getEmployees();
}
}

配置Spring容器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

<!--扫描spring加载包-->
<context:component-scan base-package="com.zss">
<!--不扫描Controller-->
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

<bean id="employeeService" class="com.zss.service.impl.EmployeeServiceImpl">
<property name="employeeDao" ref="employeeDao"/>
</bean>

<bean id="employeeDao" class="com.zss.dao.impl.EmployeeDaoImpl"/>
</beans>

测试

1
2
3
4
5
6
7
8
9
public class TestSpring {
@Test
public void test01(){
//加载spring配置文件
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
EmployeeService employeeService=(EmployeeService) applicationContext.getBean("employeeService");
List<Employee> employeeList= employeeService.getEmployees();
}
}

image-20220511110649142

测试springmvc环境

设置controller

1
2
3
public interface EmployeeController {
public ModelAndView showIndex();
}
1
2
3
4
5
6
7
8
9
10
@Controller
public class EmployeeControllerImpl implements EmployeeController {
@Override
@RequestMapping("/begin")
public ModelAndView showIndex() {
ModelAndView modelAndView=new ModelAndView();
modelAndView.setViewName("index");
return modelAndView;
}
}

配置Springmvc文件

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
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">

<!--扫描controller的组件-->
<context:component-scan base-package="com.zss">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

<!--配置视图解析器-->
<!--配置视图解析器-->
<!-- 配置Thymeleaf视图解析器 -->
<bean id="viewResolver" class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
<!--视图解析器优先级-->
<property name="order" value="1"/>
<property name="characterEncoding" value="UTF-8"/>
<property name="templateEngine">
<bean class="org.thymeleaf.spring5.SpringTemplateEngine">
<property name="templateResolver">
<bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">

<!-- 设置视图前缀 -->
<property name="prefix" value="/WEB-INF/templates/"/>
<!-- 设置视图后缀 -->
<property name="suffix" value=".html"/>
<property name="templateMode" value="HTML5"/>
<property name="characterEncoding" value="UTF-8" />
</bean>
</property>
</bean>
</property>
</bean>

<!--如果浏览器发送的信息,dispatcherservlet处理不了,则交给defaultservlet处理,开启对静态资源的访问和默认驱动-->
<mvc:default-servlet-handler/>
<!--开启注解驱动,要这两个标签同时使用-->
<mvc:annotation-driven/>

</beans>

配置web.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
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
<display-name>Archetype Created Web Application</display-name>

<!--控制中文乱码-->
<!--设置过滤器,控制编码-->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<!--//设置响应的编码是否也启用encoding-->
<init-param>
<param-name>forceResponseEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/</url-pattern>
</filter-mapping>

<!--设置中央控制器-->
<!--对所有的页面进行控制-->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--加载springmvc配置文件-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>

测试

配置tomcat,打开相应页面

image-20220511110935149

Spring整合Springmvc

配置监听器

监听器可以在第一时间告诉我们项目已经启动,可以加载spring容器

1
2
3
4
5
6
7
8
9
<!--配置监听器-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!--配置监听器加载文件的指定路径-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>

测试

添加依赖

1
2
3
<bean id="employeeController" class="com.zss.controller.impl.EmployeeControllerImpl">
<property name="employeeService" ref="employeeService"/>
</bean>
1
2
3
4
5
6
7
8
@Override
@RequestMapping("/begin")
public ModelAndView showIndex() {
ModelAndView modelAndView=new ModelAndView();
employeeService.getEmployees();
modelAndView.setViewName("index");
return modelAndView;
}

测试成功

配置mybatis

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--设置日志-->
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<!--设置包名-->
<typeAliases>
<!--实体类所在的包名称-->
<package name="com.zss.pojo"/>
</typeAliases>

<!--该包下面的所有包配置文件-->
<mappers>
<package name="com.zss.dao"/>
</mappers>
</configuration>

书写出执行的语句,设置映射对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?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="com.zss.dao.EmployeeDao">
<resultMap id="employeeMap" type="com.zss.pojo.Employee">
<result column="emp_id" property="empId"/>
<result column="emp_name" property="empName"/>
<result column="dept_name" property="deptName"/>
</resultMap>
<select id="getEmployees" resultMap="employeeMap">
SELECT emp_id,emp_name,gender,email,td.dept_name FROM tb_emp JOIN tb_dept td ON td.dept_id = tb_emp.d_id order by emp_id;
</select>
</mapper>

声明数据源创建对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<context:property-placeholder location="classpath:mysqldb.properties"/>
<!--声明数据源对象-->
<bean id="myDataSource" class="com.alibaba.druid.pool.DruidDataSource"
init-method="init" destroy-method="close">
<!--使用set注入提供配置信息-->
<property name="url" value="${url}"/>
<property name="username" value="root"/>
<property name="password" value="200101"/>
</bean>
<!--声明sqlSessionFactoryBean类,创建sqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--设置植入数据库的连接池-->
<property name="dataSource" ref="myDataSource"/>
<!--找到mybaits主配置文件的位置,如果要在主配置文件中加入其他文件的配置,需要使用classpath,赋值需要使用value-->
<property name="configLocation" value="classpath:mybatis.xml"/>
</bean>

<!--创建dao,MapperScannerConfigurer这个类在内部调用get-mapper生成每个接口的代理对象,同时会扫描包名,每一个接口执行
getMapper的方法,得到dao对象-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<property name="basePackage" value="com.zss.dao"/>
</bean>

测试并且映射页面

添加事务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!--启用事务管理器的事务处理-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--指定对哪一个事务进行管理-->
<property name="dataSource" ref="myDataSource"/>
</bean>
<!--声明业务方法事务属性,id表示这一段的配置内容-->
<tx:advice id="myAdvice" transaction-manager="transactionManager">
<!--<tx:attributes>配置事务属性,name配置方法名称,当然也可以使用通配符,也可以在这里配置隔离级别等信息-->
<tx:attributes>
<tx:method name="buyGood"/>
</tx:attributes>
</tx:advice>

<!--配置aop,表示那些类需要应用事务-->
<aop:config>
<!--execution(* *..service..*.*(..)),表示所有返回值 ,所有包和子包的service中的子包的所有类和所有方法-->
<aop:pointcut id="servicePt" expression="execution(* *..service..*.*(..))"/>
<!--配置增强器,,关联事务的配置属性-->
<aop:advisor advice-ref="myAdvice" pointcut-ref="servicePt"/>
</aop:config>
</beans>

环境搭建完成

image-20220512143323492

展示数据实现分页

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
package com.zss.controller.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.zss.controller.EmployeeController;
import com.zss.pojo.Employee;
import com.zss.service.EmployeeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import java.util.List;

/**
* @author zss
*/
@Controller
public class EmployeeControllerImpl implements EmployeeController {


private EmployeeService employeeService;
@Autowired
public void setEmployeeService(EmployeeService employeeService) {
this.employeeService = employeeService;
}

@Override
@RequestMapping("/show")
public ModelAndView showIndex(Integer pageNum) {
ModelAndView modelAndView=new ModelAndView();
PageHelper.startPage(pageNum,10);
List<Employee> employeeList=employeeService.getEmployees();
PageInfo<Employee> pageInfo=new PageInfo<>(employeeList);
modelAndView.addObject("employeeList",employeeList);
modelAndView.addObject("pageInfo",pageInfo);
modelAndView.setViewName("index");
return modelAndView;
}


}

在这里其实只需要传入一个域共享对象就好,但是这里thymeleaf不起作用,就传入了两个

使用JSON格式

其实这种方法适合电脑浏览器与服务器之间的结构,如果我们使用苹果或者安卓解析比较偏麻烦,那么这个适合就需要我们进行格式转换

浏览发送ajax请求进行员工分页数据的查询,服务器将查出的数据,以json字符串的形式返回浏览器,浏览器接收到json字符串,使用js对json进行解析

导入数据绑定的jackson包

方便我们进行自动转换

1
2
3
4
5
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.1</version>
</dependency>

更改源代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Controller
public class EmployeeControllerImpl implements EmployeeController {


private EmployeeService employeeService;
@Autowired
public void setEmployeeService(EmployeeService employeeService) {
this.employeeService = employeeService;
}

@Override
@ResponseBody
@RequestMapping("/show")
public PageInfo showIndex (@RequestParam(value = "pageNum",defaultValue = "1") Integer pageNum) {
PageHelper.startPage(pageNum,10);
List<Employee> employeeList=employeeService.getEmployees();
PageInfo<Employee> pageInfo=new PageInfo<>(employeeList,5);
return pageInfo;
}


}

image-20220512172020999

这是再次启动之后的数据情况,现在我们需要解析的是这些对象,但是这中情况发生在我们的查询操作中,但是如果是删除等等操作,我们又该如何返回浏览器信息那??

自定义数据状态

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
package com.zss.pojo;

import java.util.HashMap;
import java.util.Map;

public class Msg {
private int code;

private String msg;

private Map<String ,Object> extend=new HashMap<>();

public static Msg success(){
Msg result=new Msg();
result.setCode(100);
result.setMsg("操作成功");
return result;
}

public static Msg fail(){
Msg result=new Msg();
result.setCode(500);
result.setMsg("处理失败");
return result;
}

//方便我们进行链式操作
public Msg add(String key,Object value){
this.getExtend().put(key,value);
return this;
}

public int getCode() {
return code;
}

public void setCode(int code) {
this.code = code;
}

public String getMsg() {
return msg;
}

public void setMsg(String msg) {
this.msg = msg;
}

public Map<String, Object> getExtend() {
return extend;
}

public void setExtend(Map<String, Object> extend) {
this.extend = extend;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class EmployeeControllerImpl implements EmployeeController {


private EmployeeService employeeService;
@Autowired
public void setEmployeeService(EmployeeService employeeService) {
this.employeeService = employeeService;
}

@Override
@ResponseBody
@RequestMapping("/show")
public Msg showIndex (@RequestParam(value = "pageNum",defaultValue = "1") Integer pageNum) {
PageHelper.startPage(pageNum,10);
List<Employee> employeeList=employeeService.getEmployees();
PageInfo<Employee> pageInfo=new PageInfo<>(employeeList,5);
return Msg.success().add("pageInfo",pageInfo);
}


}

image-20220512193059472

解析json数据

同时我们也是同vue.js代理thymeleaf的解析

Thymeleaf

无法识别fruit.fid等条件

解决:在html头添加

1
<html lang="zh_CN" xmlns:th="http://www.thymeleaf.org" >
1
2
3
4
5
6
7
8
9
<tr th:unless="${#lists.isEmpty(session.fruitList)}" th:each="fruit : ${session.fruitList}">
<td th:text="${fruit.fid}"></td>
<td th:text="${fruit.fname}"></td>
<td th:text="${fruit.price}"></td>
<td th:text="${fruit.fcount}"></td>
<td th:text="${fruit.remark}"></td>
<td></td>
<td>删除</td>
</tr>

超链接问题

  • 使用此方法插入超链接,但是超链接无法显示
1
<td th:text="${fruit.fname}"><a href="Details"></a></td>

解决:

1
<td ><a th:text="${fruit.fname}" href="/detail"></a></td>
  • 此方法访问的路径为,并不在我们想要的水果的子目录下面

image-20220404164609975

解决:为了防止此情况的发生,我们使用绝对路径,并且进行设置

1
<td ><a th:text="${fruit.fname}" th:href="@{/detail.do}"></a></td>
  • 我们的超链接这样渲染时,所有的水果的详情都是对应一个地址,而不是对应的地址
1
<td ><a th:text="${fruit.fname}" th:href="@{/detail(fname=${fruit.fname})}"></a></td>

image-20220404170638784

对Thymeleaf语法不能跳转

1
<form  th:action="@{/fruit/add}" method="post">

点击此方法,并不会跳转到相应的页面

解决:在相应的servlet中并没有调用相关的Thmeleaf语法

其他

跳转疑问

1
2
3
4
<form action="/fruit.do?operate=inquire" method="get" >
<!--<input type="text" value="inquire" name="operate" hidden>-->
<input type="submit" value="查询">
</form>

当我在action中传入operate=inquire时,并且使用get方法,在地址栏中查看,竟然get方法没有将operate传输过来

image-20220407141037918

而且后端,竟然收到一个空字符串。。。。

image-20220407141135512

但是如果使用post方法进行传输的时候,将operate传输过来了,而且后端可以接受到

image-20220407141257253

image-20220407141350707

奇怪的是,get方法是不安全的,值会在其中展现出来,但是这里get方法却将后面的数据吃掉了,这个长度也远远达不到get的长度限制??

先插眼!!!

改用这个方法进行传参,可以避免上述错误,但是还是没有清楚错误在哪里???

1
2
3
4
<form action="/fruit.do?" method="post" >
<input type="text" value="inquire" name="operate" hidden>
<input type="submit" value="查询">
</form>

Servlet

工件部署错误

image-20220404203402761

解决1:新建的表单没有为其指定对应的servle组件,/也没有加上。

解决2:在web.xml中与servlet类中同时定义了响应的数据

解决3:

感谢这位作者:servlet与filter的url-pattern设置方式及映射规则_qiaqia609的博客-CSDN博客

我们需要首先了解到tomcat的寻找地址的方式localhost://8080:+上下文+响应的文件

上下文在tomcat部署中查看image-20220407203658616

而我们访问地址,比如说http://localhost:8080/fruit/fruit.do,那么我们需要在servlet中进行响应的部件应该为**/fruit.do,否则会工件部署无效。**

网页报405错误

image-20220406162156305

网络上说时是调用了父类的doget方法,但是我重写的是dopost,而且仅仅使用了dopost方法,没有用到doget方法。

Servlet类

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
package com.zss.servlets;

import com.zss.impl.FruitDAOImpl;
import com.zss.object.Fruit;

import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.List;
@WebServlet("/fruit/search")
public class SearchServlet extends ViewBaseServlet{
@Override
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
req.setCharacterEncoding("UTF-8");
String pagePer=req.getParameter("pageSearchNo");
if (pagePer == null|pagePer==""){
pagePer="1";
}
int pageNum=Integer.parseInt(pagePer);
FruitDAOImpl fruitDAO=new FruitDAOImpl();
String searchInfor=req.getParameter("searchInfor");
Object []objects={pageNum,searchInfor};
List<Fruit> list=fruitDAO.searchFruit(new Fruit(),objects);
//定义最后一页页数
int lastPageNum=((fruitDAO.getColumn()-1)/5)+1;
//将变量临时保存到内存中
HttpSession session=req.getSession();
session.setAttribute("searchInfor",searchInfor);
session.setAttribute("lastSearchPage",lastPageNum);
session.setAttribute("pageSearchNo",pageNum);
session.setAttribute("fruitSearchList",list);
//会将此处的视图名称对应到物理名称
//逻辑视图名称 Fruitshow
//物理视图名称 =前文+逻辑视图名称+后文=/fruit/Fruitshow.html
super.processTemplate("fruit/Search",req,resp);
}
}

thymeleaf跳转方法

1
2
3
4
5
6
<td colspan="7">
<input type="button" value="首页" th:onclick=|page(${1})| th:disabled="${session.pageNo==1}">
<input type="button" value="下一页" th:onclick=|page(${session.pageNo+1})| th:disabled="${session.pageNo==session.lastPage}">
<input type="button" value="上一页" th:onclick=|page(${session.pageNo-1})| th:disabled="${session.pageNo==1}">
<input type="button" value="尾页" th:onclick=|page(${session.lastPage})| th:disabled="${session.pageNo==session.lastPage}">
</td>
1
2
3
4
//调用函数的犯法
function pageSearch(pageSearchNo){
window.location.href="fruit/search?pageSearchNo="+pageSearchNo
}

后来,我发现,在页面跳转的时候我没有为其指定条装方式,导致请求默认为doget方法,而该方法没有被重写,导致了错误

于是我重新在servlet中重写了doget方法,但是这样会有一个缺陷,同一个表单跳转的时候,只能给指定的按钮进行指定跳转方法,但是在thymeleaf中页面跳转无法使用,所以在重写一个doget,去调用都dopost

servlet判断空

1
2
3
4
String searchInfor=req.getParameter("searchInfor");
if (searchInfor==null|searchInfor==""){
searchInfor= (String) req.getAttribute("searchInfor");
}

在servlet获得的字符串null与“是不同的”

412错误

HTTP 412错误,(Precondition failed),是HTTP协议状态码的一种,表示“未满足前提条件”。如果服务器没有满足请求者在请求中设置的其中一个前提条件时就会返回此错误代码。

412错误一般是由于要查看的网页设置了先决条件,一般是网页中有一个或多个请求标题字段中具有先决条件,这些字段经服务器测试后被认为是”FALSE”。客户端为当前资源的meta信息(头文件字段数据)设置了先决条件,以便防止请求的方法被用于指定资源外的其他资源,因此该请求无法完成而出现的错误

上面的412知道了错误,又看到HTTP status Code 412 未满足前提条件的解决方法之一_走错路的程序员的博客-CSDN博客_响应码412,这一篇博客,将请求方法更改为get方法,这样就会改好了,但是当我将请求又改到post方法时,他竟然又可以进行了

先插个眼

Servlet打印两次

1
2
3
4
5
6
7
8
9
10
11
12
13
@WebServlet("/*.do")
public class DispatcherServlet extends ViewBaseServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
//如果说url是:http://localhost:8080/fruit/hello.do
//servletPath是: /fruit/hello.do
String servletPath=req.getServletPath();
System.out.println(servletPath);

System.out.println("我运行了一次");
}
}

以上的代码我仅仅默认在http://localhost:8080/fruit/hello.do网址中打开,但是这个方法尽然输出了两个,难道不是service方法仅仅运行了一次吗???

现在学习到SpringMVC,其实在这个启动的过程中,tomcat我们也设置了一次请求,所以会响应两次,如果tomcat请求中的打开时取消打开网页,其实service就是仅仅运行了一次

image-20220407191910546

500错误

image-20220510161226120

image-20220510161434656

在web.xml文件中,配置了中央控制器,却没有初始化springmvc的参数值,网页请求经过web.xml的分发之后,找不到了springmvc配置文件,于是去默认路径下寻找,默认路径也没有,会发生错误。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!--对所有的页面进行控制-->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<!--//上下文配置路径-->
<param-name>contextConfigLocation</param-name>
<!--路径-->
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>

Tomcat

网页端报304问题

  • 2022年-4月-6日:tomcat服务器存在缓存存放在work工作夹的日志下面,将其删除即可

  • 2022年-4月-7日:今天使用thymeleaf进行跳转组合,又出现相同问题

不可跳转:

1
2
3
<form th:action="@{/fruit.do(operate='inquire')}"   method="get" >
<input type="submit" value="查询">
</form>

可以跳转:

1
2
3
<form action="/fruit.do?operate=inquire"   method="get" >
<input type="submit" value="查询">
</form>

因为它处在一个循环依赖关系中(artifact ‘SSM’, artifact ‘SSM:war exploded’)

无法构建 artifact ‘SSM’,因为它处在一个循环依赖关系中(artifact ‘SSM’, artifact ‘SSM:war exploded’)

artifact ‘SSM:war exploded属于可以热部署的部件,如果我们启动热部署,而原来的不去更改,会发生这中情况

idea tomcat部署web项目报错:Error:Cannot build artifact ‘xxx:war exploded‘ because it is included into 循环依赖_飞乐鸟的博客-CSDN博客_warexploded

数据库

java.sql.SQLException: Before start of result set

解决:使用rs.getString();前一定要加上rs.next();

Invalid argument value: java.io.NotSerializableException

参数传递错误,需要将参数进行转换之后在进行查询等操作

调度器dispatcher

调度器中无法使用parameter.getName()获得参数的实际名称

image-20220414210103167

其他错误

java.lang.InstantiationException

这种错误出现表示构造器出现问题了,但是我已经在其中定义了一个拥有三个参数的构造器

1
2
3
4
5
public CartItem(Book book, Integer buyCount, User userBean) {
this.book = book;
this.buyCount = buyCount;
this.userBean = userBean;
}

但是在后面dao层中调用时,参数类型转换,需要重新定义一个无参构造器,否则会发生错误。

1
T entity = (T)entityClass.newInstance();

SpringMVC

将请求打开页面

发送的delete请求,但是thymeleaf想要打开delete.html页面,

解决:如果不加上@ResponseBody,会将其解析成一个页面,而不是一个返回的数据。

https://blog.csdn.net/m0_48112568/article/details/116430574

JDBC复习回顾

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
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.sql.*;
import java.util.Properties;

/**
* @author zss
*/
public class GetInfor {
public static void main(String[] args) throws ClassNotFoundException, IOException, SQLException {
Properties properties=new Properties();
properties.load(new FileReader("src\\Information.properties"));
String jdbc= properties.getProperty("jdbcJar");
String url= properties.getProperty("url");
String password= properties.getProperty("password");
String user= properties.getProperty("user");
Class.forName(jdbc);
Connection connection= DriverManager.getConnection(url,user,password);
String selectSql="select * from user where name= ? ";
PreparedStatement preparedStatement= connection.prepareStatement(selectSql);
preparedStatement.setString(1,"郭富城");
ResultSet resultSet= preparedStatement.executeQuery();
if (resultSet.next()){
System.out.println(resultSet.getString("name"));
}
}
}

image-20220329235249837

练习

添加custom

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
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Properties;
import java.util.Scanner;

/**
* @author zss
*/
public class CustomerAdd {
public static void main(String[] args) throws SQLException, IOException, ClassNotFoundException {
CustomerAdd customerAdd=new CustomerAdd();
customerAdd.addPerson();
}
public void addPerson() throws SQLException, IOException, ClassNotFoundException {
Scanner scanner=new Scanner(System.in);
System.out.println("请输入添加的用户名");
String name=scanner.next();
System.out.println("请输入添加邮箱");
String email=scanner.next();
System.out.println("请输入添加的生日");
String birthday=scanner.next();
String mysqlInsert= "insert into customers (name,email,birth) values(?,?,?)";
dateAdd(mysqlInsert,name,email,birthday);

}
public void dateAdd(String sql,Object ...obj) throws IOException, ClassNotFoundException, SQLException {
Properties properties=new Properties();
properties.load(new FileReader("src\\Information.properties"));
String jdbc= properties.getProperty("jdbcJar");
String url= properties.getProperty("url");
String password= properties.getProperty("password");
String user= properties.getProperty("user");
Class.forName(jdbc);
Connection connection= DriverManager.getConnection(url,user,password);
PreparedStatement preparedStatement= connection.prepareStatement(sql);
for (int i=0;i<obj.length;i++){
preparedStatement.setObject(i+1,obj[i]);
}
int count=preparedStatement.executeUpdate();
if (count==1){
System.out.println("插入成功");
}else {
System.out.println("插入失败");
}

preparedStatement.close();
connection.close();

}

}

存储数据库的图片与视频

1
preparedStatement.setBlob(4,new BufferedInputStream(new FileInputStream(new File("D:\\壁纸\\女孩子.png"))));

注意,有时候我们使用了mediumBlog,但是还是插入不进去,这是因为mysql安装目录下,my.ini文件缺少相关发配置,加上max_allowed_packet=16M

批量插入

批量插入 中使用statement必须每一次都重新编译sql语句,但是preparementStament仅仅编译一次,其余使用占位符即可,使用for循环进行插入即可,只不过每一次的占位符不同

1
2
3
4
5
6
Connection connection= DriverManager.getConnection(url,user,password);
PreparedStatement preparedStatement= connection.prepareStatement("insert into goods (name) VALUES (?)");
for (int i=0;i<200;i++){
preparedStatement.setObject(1,"goods"+i);
int count=preparedStatement.executeUpdate();
}

优化

addBatch:积攒sql语句

excuteBatch:执行sql语句

clearBatch:清空sql语句

默认情况下,mysql关闭批处理,所以我们需要一个参数开启

1
url=jdbc:mysql://localhost:3306/test?rewriteBatchedStatements=true
1
2
3
4
5
6
7
8
for (int i=500;i<=1000;i++){
preparedStatement.setString(1,"goods"+i);
preparedStatement.addBatch();
if (i%500==0){
preparedStatement.executeBatch();
preparedStatement.clearBatch();
}
}

这样会优化我们插入的效率

优化2

关闭自动提交

1
2
3
4
5
6
7
8
9
10
11
12
Connection connection= DriverManager.getConnection(url,user,password);
connection.setAutoCommit(false);
PreparedStatement preparedStatement= connection.prepareStatement("insert into goods (name) VALUES (?)");
for (int i=500;i<=1000;i++){
preparedStatement.setString(1,"goods"+i);
preparedStatement.addBatch();
if (i%500==0){
preparedStatement.executeBatch();
preparedStatement.clearBatch();
}
}
connection.commit();