10.8 maven高级 Git入门

1.头:日期、所学内容出处

【黑马程序员2022新版SSM框架教程_Spring+SpringMVC+Maven高级+SpringBoot+MyBatisPlus企业实用开发技术】 https://www.bilibili.com/video/BV1Fi4y1S7ix?p=31&share_source=copy_web&vd_source=c8ae4150b2286ee39a13a79bbe12b843

2.所学内容概述

Maven依赖管理

生命周期和插件

分模块开发

Git基本命令

3.根据概述分章节描述

Maven依赖管理

依赖配置和依赖传递

一个项目可以设置多个依赖

依赖就是平常说的jar包.

image-20221008102200401

依赖传递

依赖是有传递性的 分为直接依赖和间接依赖

1
2
直接依赖:在当前项目中通过依赖配置建立的依赖关系
间接依赖:被资源的资源如果依赖其他资源 当前项目间接依赖其他资源

image-20221008102436352

依赖范围

下面这个表比较重要

标签四种的作用 能解节约资源

image-20221008102506179

依赖范围

传递的时候的影响

image-20221008102618339

生命周期和插件

生命周期

Maven构建生命周期描述的是一次构建过程经历了多少的事件

compile test-compile test package install 类似于这些对 项目处理的功能都是事件

项目构建的生命周期分三套

1
2
3
clean 清洗工作
default 核心工作 编译 测试 打包 部署
site 产生报告 发布站点
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
default生命周期比较重要 加#都是重要点
列出
validate(校验) 校验项目是否正确并且所有必要的信息可以完成项目的构建过程。
initialize(初始化) 初始化构建状态,比如设置属性值。
generate-sources(生成源代码) 生成包含在编译阶段中的任何源代码。
process-sources(处理源代码) 处理源代码,比如说,过滤任意值。
generate-resources(生成资源文件) 生成将会包含在项目包中的资源文件。
process-resources (处理资源文件) 复制和处理资源到目标目录,为打包阶段最好准备。
#compile(编译) 编译项目的源代码。
process-classes(处理类文件) 处理编译生成的文件,比如说对Java class文件做字节码改善优化。
generate-test-sources(生成测试源代码) 生成包含在编译阶段中的任何测试源代码。
process-test-sources(处理测试源代码) 处理测试源代码,比如说,过滤任意值。generate-test-resources(生成测试资源文件) 为测试创建资源文件。
process-test-resources(处理测试资源文件) 复制和处理测试资源到目标目录。
#test-compile(编译测试源码) 编译测试源代码到测试目标目录.
process-test-classes(处理测试类文件) 处理测试源码编译生成的文件。
#test(测试) 使用合适的单元测试框架运行测试(Juint是其中之一)。
prepare-package(准备打包) 在实际打包之前,执行任何的必要的操作为打包做准备。
#package(打包) 将编译后的代码打包成可分发格式的文件,比如JAR、WAR或者EAR文件。
pre-integration-test(集成测试前) 在执行集成测试前进行必要的动作。比如说,搭建需要的环境。
integration-test(集成测试) 处理和部署项目到可以运行集成测试环境中。
post-integration-test(集成测试后) 在执行集成测试完成后进行必要的动作。比如说,清理集成测试环境。
verify (验证) 运行任意的检查来验证项目包有效且达到质量标准。
#install(安装) 安装项目包到本地仓库,这样项目包可以用作其他本地项目的依赖。
deploy(部署) 将最终的项目包复制到远程仓库中与其他开发者和项目共享。

插件

插件就是该生命周期所能支持的事件

多个插件组成一个生命周期

分模块开发

聚合 多个工程的功能集于一个工程

继承 父工程的坐标以及插件可以给子工程使用

image-20221008140717415

属性

1
2
3
4
5
<!--定义自定义属性-->
<properties>
<spring.version>5.1.9.RELEASE</spring.version>
<junit.version>4.12</junit.version>
</properties>

可自定义

调用方法如下

1
2
3
4
5
6
7
8
9
10
<dependency>
<groupId>com.itheima</groupId>
<artifactId>ssm_service</artifactId>
<version>${version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>

Git命令

Git的工作原理

分三个区 工作区 暂存区 本地库

1
2
3
工作区:写代码的
暂存区:缓冲点 临时存储
本地库:历史版本 可查可切换

常用命令如下:

黑色只用设置一次

image-20221008164523139

1
2
3
4
5
6
初始化的效果 会生成一个隐藏的.git文件
status查看本地库文件的状态 : 文件在什么区
git add 将文件提交到缓存区
git commit -m "日志信息" 文件名 提交到本地库
git reflog 查看历史记录
git reset --hard 版本号 版本穿梭 就是切换到之前保存到本地库的 时间库的状态

4. BUG点

难点(关键代码或关键配置,BUG截图+解决方案)

当时maven的pugin全部报错 之前遇到过找自己的setting.xml文件并没有问题

后面 发现默认的C中.m2的仓库就可以 觉得是仓库的问题 自己的仓库有问题,就把老师资料中的仓库直接覆盖自己 问题解决了

image-20221008223738434

5.总结

重点是哪些知识比较重要,难点是你在学习过程中觉得比较繁琐,掌握起来有一点

今天学习点是git和maven两大以后团队协作做项目很有用的操作,之前都略有接触过,maven都用过很久了,高级部分多看了一下,基础文档过了一眼。git的命令有点像linux,git就是解决团队协作时候,对服务器更改的各种问题。今天大部分都是看文档,安装的时候是跟着视频的,因为哪里没配置好会很麻烦,所以学习进度也很快。有过接触,掌握起来也不难。

10.9 Git分支 SSM框架Bean

1.头:日期、所学内容出处

【黑马程序员2022新版SSM框架教程_Spring+SpringMVC+Maven高级+SpringBoot+MyBatisPlus企业实用开发技术】 https://www.bilibili.com/video/BV1Fi4y1S7ix?p=31&share_source=copy_web&vd_source=c8ae4150b2286ee39a13a79bbe12b843

2.所学内容概述

Git分支

Spring入门

3.根据概述分章节描述

Git分支

分支按我自己的理解就像支线(影分身),各个人负责自己的支线,然后做完了以后,将任务提交到主线中去,能大大提高开发的效率,而且开发失败对主线影响不大,

分支的操作

1
2
3
4
5
git branch 分支名 创建分支
git branch -v 查看分支
git checkout 分支名 切换分支
git checkout -b 分支名 切换分支 分支不存在就创建
git merge 分支名 把指定的分支合并到当前的分支 一般当前分支需要是主分支

注意点

冲突问题

合并的时候,如果主线和分支的同一个文件的同一个位置有两套不同的 修改 Git 就无法为我们决定哪一个 就需要人为 的选择

1
2
编辑有冲突的文件,删除特殊符号,决定要使用的内容
特殊符号:<<<<<<< HEAD 当前分支的代码 ======= 合并过来的代码 >>>>>>> hot-fix

删除以后 添加暂存区然后提交

Spring相关概念

Spring框架主要的优势是在简化开发框架整合

我们平常写的代码中耦合度偏高 都知道低耦合度比较好

因为每次业务层调用数据层的方法,需要在业务层new数据层的对象 ,如果数据层的实现类发生变化,那么业务层的代码也需要跟着改变,发生变更后,都需要进行编译打包和重部署

使用对象时,在程序中不要主动使用new产生对象,转换为由==外部==提供对象

Spring中关于bean的使用

使用spring 需要导入依赖 如下

1
2
3
4
5
6
7
8
9
10
11
12
13
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>

bean基础设置

1
<bean id="" class=""/>

image-20221009164824083

bean的name属性

环境准备好后,接下来就可以在这个环境的基础上进行bean的别名配置,

image-20210729183558051

1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="bookService" name="u7Service bookEbi" class="com.itheima.service.impl.BookServiceImpl">

<!-- bean别名可以定义多个 使用逗号 分号 空格 分隔-->
<property name="bookDao" ref="bookDao"/>
</bean>
<bean id="bookDao" name="dao" class="com.itheima.dao.impl.BookDaoImpl" scope="prototype"/>
</beans>

bean作用范围scope配置

关于bean的作用范围是bean属性配置的一个==重点==内容。

prototype可以非单例

默认是singleton是单例模式

一般都是设置为单例 提高效率

image-20210729183628138

小总结

image-20221009181933493

生命周期

关于Spring中对bean生命周期控制提供了两种方式:

  • 在配置文件中的bean标签中添加初始化init-method和销毁destroy-method属性
  • 类实现InitializingBeanDisposableBean接口
1
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl" init-method="init" destroy-method="destory"/>

close关闭容器

  • ApplicationContext中没有close方法

  • 需要将ApplicationContext更换成ClassPathXmlApplicationContext

    1
    2
    ClassPathXmlApplicationContext ctx = new 
    ClassPathXmlApplicationContext("applicationContext.xml");
  • 调用ctx的close()方法

    1
    ctx.close();

    注册钩子关闭容器

    • 在容器未关闭之前,提前设置好回调函数,让JVM在退出之前回调此函数来关闭容器

    • 调用ctx的registerShutdownHook()方法

      1
      ctx.registerShutdownHook();

上面两种都可以关闭容器 调用xml文件中的destroy-method的方法

4. BUG点

难点(关键代码或关键配置,BUG截图+解决方案)

UserDaoFactory 的文件夹命名问题 导致找不到 该类

image-20221009153349981

6.总结

重点是哪些知识比较重要,难点是你在学习过程中觉得比较繁琐,掌握起来有一点

今天学习了git基本操作最后一点的分支和SSM框架前面Spring的基础部分,总体来说难度不是很大,spring文档前面概念性的自己理解起来花费了一些时间,结合文档给的案例,敲代码帮助自己理解起来快很多,xml调用接口的时候出现了点问题,解决起来也蛮快的,一个一个点进去找就行了。文档结合视频加上自己敲,理解起来很通透,这样学习是很不错的。

10.10 Spring

1.头:日期、所学内容出处

【黑马程序员2022新版SSM框架教程_Spring+SpringMVC+Maven高级+SpringBoot+MyBatisPlus企业实用开发技术】 https://www.bilibili.com/video/BV1Fi4y1S7ix?p=31&share_source=copy_web&vd_source=c8ae4150b2286ee39a13a79bbe12b843

2.所学内容概述

依赖注入

核心容器

3.根据概述分章节描述

依赖注入

setter注入

在BookDaoImpl类中声明对应的简单数据类型的属性,并提供对应的setter方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class BookDaoImpl implements BookDao {

private String databaseName;
private int connectionNum;
//基本类型
public void setConnectionNum(int connectionNum) {
this.connectionNum = connectionNum;
}

public void setDatabaseName(String databaseName) {
this.databaseName = databaseName;
}
//引用类型
public void save() {
System.out.println("book dao save ..."+databaseName+","+connectionNum);
}
}

配置中使用==property==标签==ref==属性注入引用类型对象

配置中使用==property==标签==value==属性注入基本类型对象

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

<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
<property name="bookDao" ref="bookDao"/>
<property name="userDao" ref="userDao"/>
</bean>
</beans>

构造器注入

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

<!-- 构造器注入-->
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
<!-- 形参名高耦合-->
<!-- <constructor-arg name="connectionNum" value="109"/>-->
<!-- <constructor-arg name="databaseName" value="mysql"/>-->
<!-- 形参名不耦合但是多个类型一样的会出问题-->
<!-- <constructor-arg type="int" value="100"/>-->
<!-- <constructor-arg type="java.lang.String" value="mysql"/>-->
<!--使用位置解决参数匹配-->
<constructor-arg index="0" value="mysql"/>
<constructor-arg index="1" value="1001"/>
</bean>

<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>

<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
<constructor-arg name="bookDao" ref="bookDao"/>
<constructor-arg name="userDao" ref="userDao"/>
</bean>
</beans>

Service使用构造器 传参

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.itheima.service.impl;

import com.itheima.dao.BookDao;
import com.itheima.dao.UserDao;
import com.itheima.service.BookService;

public class BookServiceImpl implements BookService{
private BookDao bookDao;
private UserDao userDao;

public BookServiceImpl(BookDao bookDao, UserDao userDao) {
this.bookDao = bookDao;
this.userDao = userDao;
}

public void save() {
System.out.println("book service save ...");
bookDao.save();
userDao.save();
}
}

依赖方式的选择

image-20221010085335820

自动注入

前面java文件不变 自动调用set方法

修改配置文件即可

1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

<bean class="com.itheima.dao.impl.BookDaoImpl"/>
<!--autowire属性:开启自动装配,通常使用按类型装配-->
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl" autowire="byType"/>
</beans>

集合注入

一般集合注入都是注入常量 如果需要注入引用类型 加标签

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
public interface BookDao {
public void save();
}

public class BookDaoImpl implements BookDao {

public class BookDaoImpl implements BookDao {

private int[] array;

private List<String> list;

private Set<String> set;

private Map<String,String> map;

private Properties properties;

public void save() {
System.out.println("book dao save ...");

System.out.println("遍历数组:" + Arrays.toString(array));

System.out.println("遍历List" + list);

System.out.println("遍历Set" + set);

System.out.println("遍历Map" + map);

System.out.println("遍历Properties" + properties);
}
//setter....方法省略,自己使用工具生成
}

配置文件如下

按照集合名字赋值

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
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
<!--数组注入-->
<property name="array">
<array>
<value>100</value>
<value>200</value>
<value>300</value>
</array>
</property>
<!--list集合注入-->
<property name="list">
<list>
<value>itcast</value>
<value>itheima</value>
<value>boxuegu</value>
<value>chuanzhihui</value>
</list>
</property>
<!--set集合注入-->
<property name="set">
<set>
<value>itcast</value>
<value>itheima</value>
<value>boxuegu</value>
<value>boxuegu</value>
</set>
</property>
<!--map集合注入-->
<property name="map">
<map>
<entry key="country" value="china"/>
<entry key="province" value="henan"/>
<entry key="city" value="kaifeng"/>
</map>
</property>
<!--Properties注入-->
<property name="properties">
<props>
<prop key="country">china</prop>
<prop key="province">henan</prop>
<prop key="city">kaifeng</prop>
</props>
</property>
</bean>
</beans>

核心容器

因为是之前的源代码了解

小结一下

容器相关

  • BeanFactory是IoC容器的顶层接口,初始化BeanFactory对象时,加载的bean延迟加载
  • ApplicationContext接口是Spring容器的核心接口,初始化时bean立即加载
  • ApplicationContext接口提供基础的bean操作相关方法,通过其他接口扩展其功能
  • ApplicationContext接口常用初始化类
    • ==ClassPathXmlApplicationContext(常用)==
    • FileSystemXmlApplicationContext

bean相关

1629986510487

其实整个配置中最常用的就两个属性==id==和==class==。

依赖注入相关

1629986848563

注解开发基础

注解开发分两块内容注解开发定义bean纯注解开发

注解开发定义bean用的是2.5版提供的注解,纯注解开发用的是3.0版提供的注解。

笔记我主要记纯注解开发

几个常用的注解我都列举出来

@Component等

名称 @Component/@Controller/@Service/@Repository
类型 类注解
位置 类定义上方
作用 设置该类为spring管理的bean
属性 value(默认):定义bean的id

知识点1:@Configuration

名称 @Configuration
类型 类注解
位置 类定义上方
作用 设置该类为spring配置类
属性 value(默认):定义bean的id

知识点2:@ComponentScan

名称 @ComponentScan
类型 类注解
位置 类定义上方
作用 设置spring配置类扫描路径,用于加载使用注解格式定义的bean
属性 value(默认):扫描路径,此路径可以逐层向下扫描
知识点1:@Scope
名称 @Scope
类型 类注解
位置 类定义上方
作用 设置该类创建对象的作用范围
可用于设置创建出的bean是否为单例对象
属性 value(默认):定义bean作用范围,
==默认值singleton(单例),可选值prototype(非单例)==
知识点1:@PostConstruct
名称 @PostConstruct
类型 方法注解
位置 方法上
作用 设置该方法为初始化方法
属性
知识点2:@PreDestroy
名称 @PreDestroy
类型 方法注解
位置 方法上
作用 设置该方法为销毁方法
属性
1
其实就是把xml文件中bean标签需要到的属性 利用注解放到java中 就不需要使用xml配置了

image-20221010154508693

注解开发依赖注入

知识点1:@Autowired

名称 @Autowired
类型 属性注解 或 方法注解(了解) 或 方法形参注解(了解)
位置 属性定义上方 或 标准set方法上方 或 类set方法上方 或 方法形参前面
作用 为引用类型属性设置值
属性 required:true/false,定义该属性是否允许为null

知识点2:@Qualifier

名称 @Qualifier
类型 属性注解 或 方法注解(了解)
位置 属性定义上方 或 标准set方法上方 或 类set方法上方
作用 为引用类型属性指定注入的beanId
属性 value(默认):设置注入的beanId

知识点3:@Value

名称 @Value
类型 属性注解 或 方法注解(了解)
位置 属性定义上方 或 标准set方法上方 或 类set方法上方
作用 为 基本数据类型 或 字符串类型 属性设置值
属性 value(默认):要注入的属性值

知识点4:@PropertySource

名称 @PropertySource
类型 类注解
位置 类定义上方
作用 加载properties文件中的属性值
属性 value(默认):设置加载的properties文件对应的文件名或文件名组成的数组

注解开发管理第三方bean

前面定义bean的时候都是在自己开发的类上面写个注解就完成了 第三方是需要导入jar包的

如果需要管理是要一个新的注解==@Bean==

其实就是建立一个Java类 retrun返回一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class JdbcConfig {
//1.定义一个方法获得要管理的对象
@Value("com.mysql.jdbc.Driver")
private String driver;
@Value("jdbc:mysql://localhost:3306/spring_db")
private String url;
@Value("root")
private String userName;
@Value("root")
private String password;
//2.添加@Bean,表示当前方法的返回值是一个bean
//@Bean修饰的方法,形参根据类型自动装配
@Bean
public DataSource dataSource(BookDao bookDao){
System.out.println(bookDao);
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(userName);
ds.setPassword(password);
return ds;
}
}

在spring连接的java类中放入注解即可 这时候需要componentScan导入包名扫描

1
2
3
4
5
6
@Configuration
@ComponentScan("com.itheima")
//@Import:导入配置信息
@Import({JdbcConfig.class})
public class SpringConfig {
}

注解开发小总结

图片总结 红色的是以后常用的

image-20221010161237920

4. BUG点

难点(关键代码或关键配置,BUG截图+解决方案)

Translation的问题 IDEA中谷歌插件 报错 CSDN搜索解决方法

C:\Windows\System32\drivers\etc 中的hosts 进行修改 添加

要获取ip获取:命令行 ping translate.google.cn 会返回对应的ip,然后加上translate.googleapis.com

1
Hosts是一个没有扩展名的系统文件,可以用记事本等工具打开,其作用就是将一些常用的网址域名与其对应的IP地址建立一个关联“数据库”

image-20221010153637331

命令如下

image-20221010153807876

6.总结

重点是哪些知识比较重要,难点是你在学习过程中觉得比较繁琐,掌握起来有一点

今天学习的内容比较多的,从依赖注入到容器到重点的注解开发,注解开发是比较重要的,前面的注入和容器什么的,都可以通过注解开发完成,就不需要写xml文件了,这样很方便。过程中没什么问题,但是注解那边需要记很多东西,不然估计不太好打。之前java学注解的时候,没怎么学,现在 算是又看了一遍,也是理解注解的作用了。今天基本都掌握到了,代码量比较多,学习状态也很不错的。

10.11 AOP Spring事务

1.头:日期、所学内容出处

【黑马程序员2022新版SSM框架教程_Spring+SpringMVC+Maven高级+SpringBoot+MyBatisPlus企业实用开发技术】 https://www.bilibili.com/video/BV1Fi4y1S7ix?p=31&share_source=copy_web&vd_source=c8ae4150b2286ee39a13a79bbe12b843

2.所学内容概述

AOP简介

AOP实现步骤

AOP配置管理

3.根据概述分章节描述

AOP简介

AOP(Aspect Oriented Programming)面向切面编程,一种编程范式,指导开发者如何组织程序结构。

和面向对象编程一样都是一种编程的思想

AOP作用

在不惊动原始设计的基础上为其进行功能增强,和之前学过的代理模式很像。

如图所实现的功能调用update和delete方法时候 会计算程序执行时间 但是调用select就不会执行

spring实现方式就是 三个方法为三个连接点,需要实现功能增强(通知)的方法 设置切入点

image-20221011151249847

AOP核心概念

总结下:

  • 连接点(JoinPoint):程序执行过程中的任意位置,粒度为执行方法、抛出异常、设置变量等
    • 在SpringAOP中,理解为方法的执行
  • 切入点(Pointcut):匹配连接点的式子
    • 在SpringAOP中,一个切入点可以描述一个具体方法,也可也匹配多个方法
      • 一个具体的方法:如com.itheima.dao包下的BookDao接口中的无形参无返回值的save方法
      • 匹配多个方法:所有的save方法,所有的get开头的方法,所有以Dao结尾的接口中的任意方法,所有带有一个参数的方法
    • 连接点范围要比切入点范围大,是切入点的方法也一定是连接点,但是是连接点的方法就不一定要被增强,所以可能不是切入点。
  • 通知(Advice):在切入点处执行的操作,也就是共性功能
    • 在SpringAOP中,功能最终以方法的形式呈现
  • 通知类:定义通知的类
  • 切面(Aspect):描述通知与切入点的对应关系。

AOP实现步骤

添加spring依赖

1
2
3
4
5
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>

实现java类

代码和注解 如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.itheima.aop;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
//通知类必须配置成Spring管理的bean
@Component
//设置当前类为切面类类
@Aspect
public class MyAdvice {
//设置切入点,要求配置在方法上方
//如此实现 update调用 method方法 其他的不调用
@Pointcut("execution(void com.itheima.dao.BookDao.update())")
private void pt(){}

//设置在切入点pt()的前面运行当前操作(前置通知)
@Before("pt()")
public void method(){
System.out.println("我是切入点");
}
}

开启注解格式AOP功能

1
2
3
4
5
6
@Configuration
@ComponentScan("com.itheima")
//开启AOP支持
@EnableAspectJAutoProxy
public class SpringConfig {
}

所用新注解

知识点1:@EnableAspectJAutoProxy
名称 @EnableAspectJAutoProxy
类型 配置类注解
位置 配置类定义上方
作用 开启注解格式AOP功能
知识点2:@Aspect
名称 @Aspect
类型 类注解
位置 切面类定义上方
作用 设置当前类为AOP切面类
知识点3:@Pointcut
名称 @Pointcut
类型 方法注解
位置 切入点方法定义上方
作用 设置切入点方法
属性 value(默认):切入点表达式
知识点4:@Before
名称 @Before
类型 方法注解
位置 通知方法定义上方
作用 设置当前通知方法与切入点之间的绑定关系,当前通知方法在原始切入点方法前运行

语法格式

各个关键字解释

1
execution(public User com.itheima.service.UserService.findById(int))
  • execution:动作关键字,描述切入点的行为动作,例如execution表示执行到指定切入点
  • public:访问修饰符,还可以是public,private等,可以省略
  • User:返回值,写返回值类型
  • com.itheima.service:包名,多级包使用点连接
  • UserService:类/接口名称
  • findById:方法名
  • int:参数,直接写参数的类型,多个类型用逗号隔开
  • 异常名:方法定义中抛出指定异常,可以省略

通配符

这样使用的话比较单一 肯定是有通配符的 和java中 sql中一样 可以简化配置

  • *:单个独立的任意符号,可以独立出现,也可以作为前缀或者后缀的匹配符出现

    1
    execution(public * com.itheima.*.UserService.find*(*))

    匹配com.itheima包下的任意包中的UserService类或接口中所有find开头的带有一个参数的方法

  • ..:多个连续的任意符号,可以独立出现,常用于简化包名与参数的书写

    1
    execution(public User com..UserService.findById(..))

    匹配com包下的任意包中的UserService类或接口中所有名称为findById的方法

通知类型

  • 前置通知

  • 后置通知

  • 环绕通知(重点)

    • 环绕通知依赖形参ProceedingJoinPoint才能实现对原始方法的调用
    • 环绕通知可以隔离原始方法的调用执行
    • 环绕通知返回值设置为Object类型
    • 环绕通知中可以对原始方法调用过程中出现的异常进行处理
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    @Component
    @Aspect
    public class MyAdvice {
    @Pointcut("execution(void com.itheima.dao.BookDao.update())")
    private void pt(){}
    //环绕通知
    @Around("pt()")
    public void around(){
    System.out.println("around before advice ...");
    //表示对原始操作的调用
    pjp.proceed();
    System.out.println("around after advice ...");
    }
    }
  • 返回后通知

  • 抛出异常后通知

通知中获取参数

  • 获取切入点方法的参数,所有的通知类型都可以获取参数
    • JoinPoint:适用于前置、后置、返回后、抛出异常后通知
    • ProceedingJoinPoint:适用于环绕通知

5.扩展学习部分

通配符使用练习

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
u7
execution(void com.itheima.dao.BookDao.update())
匹配接口,能匹配到
execution(void com.itheima.dao.impl.BookDaoImpl.update())
匹配实现类,能匹配到
execution(* com.itheima.dao.impl.BookDaoImpl.update())
返回值任意,能匹配到
execution(* com.itheima.dao.impl.BookDaoImpl.update(*))
返回值任意,但是update方法必须要有一个参数,无法匹配,要想匹配需要在update接口和实现类添加参数
execution(void com.*.*.*.*.update())
返回值为void,com包下的任意包三层包下的任意类的update方法,匹配到的是实现类,能匹配
execution(void com.*.*.*.update())
返回值为void,com包下的任意两层包下的任意类的update方法,匹配到的是接口,能匹配
execution(void *..update())
返回值为void,方法名是update的任意包下的任意类,能匹配
execution(* *..*(..))
匹配项目中任意类的任意方法,能匹配,但是不建议使用这种方式,影响范围广
execution(* *..u*(..))
匹配项目中任意包任意类下只要以u开头的方法,update方法能满足,能匹配
execution(* *..*e(..))
匹配项目中任意包任意类下只要以e结尾的方法,update和save方法能满足,能匹配
execution(void com..*())
返回值为void,com包下的任意包任意类任意方法,能匹配,*代表的是方法
execution(* com.itheima.*.*Service.find*(..))
将项目中所有业务层方法的以find开头的方法匹配
execution(* com.itheima.*.*Service.save*(..))
将项目中所有业务层方法的以save开头的方法匹配

百度网盘密码数据兼容处理

密码输入最后一个会是空格的问题 比如我密码是 root 但是我打成了root(空格) 这种情况 就可以使用环绕通知解决

代码如下 getArgs获取一个对象数组 一般情况其实是string 但是不严谨 所以要循环找出string类型的 再调用trim()处理掉空格最后将改args返回

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Component
@Aspect
public class DataAdvice {

@Pointcut("execution(boolean com.itheima.service.*Service.*(*,*))")
private void servicePt(){}

@Around("DataAdvice.servicePt()")
public Object trimStr(ProceedingJoinPoint pjp) throws Throwable {
Object[] args = pjp.getArgs();
for (int i = 0; i < args.length; i++) {
//判断参数是不是字符串
if (args[i].getClass().equals(String.class)) {
args[i] = args[i].toString().trim();
}
}
return pjp.proceed(args);
}
}

image-20221011154849906

执行结果如上 4是实际读取密码的位数

6.总结

重点是哪些知识比较重要,难点是你在学习过程中觉得比较繁琐,掌握起来有一点

今天是学习的内容是spring中的AOP和简单的事务管理,充分利用好注解来完成spring项目 ,比之前的xml方便很多,今天的学习任务还是很重的,整个的AOP,有很多的代码要敲,AOP从简介到总结,然后是和java差不多的转账的事务管理,比较麻烦的就是AOP后面的环绕通知了,但是很好用,也是花时间去看了一下,今天的学习状态也不错,明天加快进度学MVC了。

10.12 SpringMVC

1.头:日期、所学内容出处

【黑马程序员2022新版SSM框架教程_Spring+SpringMVC+Maven高级+SpringBoot+MyBatisPlus企业实用开发技术】 https://www.bilibili.com/video/BV1Fi4y1S7ix?p=31&share_source=copy_web&vd_source=c8ae4150b2286ee39a13a79bbe12b843

2.所学内容概述

SpringMVC简介

SpringMVC简单使用

PostMan使用

请求和响应

Rest风格

3.根据概述分章节描述

SpringMVC简介

  • SpringMVC与Servlet技术功能等同,均属于web层或者说表现层开发技术。SpringMVC比Servlet更简单快捷,能通过更少的代码完成项目的开发

  • SpringMVC是一种基于Java实现MVC模型的轻量级Web框架

  • 优点

    • 使用简单、开发便捷(相比于Servlet)
    • 灵活性强

SpringMVC入门案例

java控制器类代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.itheima.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class UserController {

@RequestMapping("/save")
@ResponseBody
public String save(){
System.out.println("user save ...");
return "{'info':'springmvc'}";
}
}

使用到的注解

知识点1:@Controller

名称 @Controller
类型 类注解
位置 SpringMVC控制器类定义上方
作用 设定SpringMVC的核心控制器bean

知识点2:@RequestMapping

名称 @RequestMapping
类型 类注解或方法注解
位置 SpringMVC控制器类或方法定义上方
作用 设置当前控制器方法请求访问路径
相关属性 value(默认),请求访问路径

知识点3:@ResponseBody

名称 @ResponseBody
类型 类注解或方法注解
位置 SpringMVC控制器类或方法定义上方
作用 设置当前控制器方法响应内容为当前返回值,无需解析

使用Tomcat7:run运行

如何排除某个备案 比如排除掉SpringMVC控制的备案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.itheima.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;

@Configuration
//@ComponentScan({"com.itheima.service","com.itheima.dao"})
//设置spring配置类加载bean时的过滤规则,当前要求排除掉表现层对应的bean
//excludeFilters属性:设置扫描加载bean时,排除的过滤规则
//type属性:设置排除规则,当前使用按照bean定义时的注解类型进行排除
//classes属性:设置排除的具体注解类,当前设置排除@Controller定义的bean
@ComponentScan(value="com.itheima",
excludeFilters = @ComponentScan.Filter( //排除 Controller的注解加载
type = FilterType.ANNOTATION,
classes = Controller.class
)
)
//@ComponentScan({"com.itheima.service","com.itheima.dao"})
public class SpringConfig {
}

原来的Web配置比较麻烦 可以优化的

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
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
//web配置类简化开发,仅设置配置类类名即可
public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {

protected Class<?>[] getRootConfigClasses() {
return new Class[]{SpringConfig.class};
}

protected Class<?>[] getServletConfigClasses() {
return new Class[]{SpringMvcConfig.class};
}

protected String[] getServletMappings() {
return new String[]{"/"};
}
}
/*

public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer {
protected WebApplicationContext createServletApplicationContext() {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(SpringMvcConfig.class);
return ctx;
}
protected WebApplicationContext createRootApplicationContext() {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(SpringConfig.class);
return ctx;
}
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
*/

PostMan工具的使用

就是一款功能为网页调试与发送网页HTTP请求的Chrome插件

使用截图

image-20221012142203706

Send可以直接发送 就不需要一次一次浏览器打开,也能很好的判断是否连接。

请求和响应

SpringMVC是web层的框架,那它作用应该是和web一样是接收请求、接收数据、响应结果

请求参数

请求参数的传递与接收是和请求方式有关系的,目前比较常见的两种请求方式为:

  • GET
  • POST

五种类型参数传递

GET的时候写入的信息和后台接受参数的设置会有不同,结合情况使用

因为PostMan中自己都写了,就不放入到笔记中去了

知识点1:@RequestParam

名称 @RequestParam
类型 形参注解
位置 SpringMVC控制器方法形参定义前面
作用 绑定请求参数与处理器方法形参间的关系
相关参数 required:是否为必传参数
defaultValue:参数默认值

JSON数据传输参数

现在比较流行的开发方式为异步调用。前后台以异步方式进行交换,传输的数据使用的是==JSON==

对于JSON数据类型,我们常见的有三种:

  • json普通数组([“value1”,“value2”,“value3”,…])
  • json对象({key1:value1,key2:value2,…})
  • json对象数组([{key1:value1,…},{key2:value2,…}])

如何传递

在SpringMVC的配置类中开启SpringMVC的注解支持,这里面就包含了将JSON转换成对象的功能。

1
2
3
4
5
6
@Configuration
@ComponentScan("com.itheima.controller")
//开启json数据类型自动转换
@EnableWebMvc
public class SpringMvcConfig {
}
参数前添加@RequestBody
1
2
3
4
5
6
7
//使用@RequestBody注解将外部传递的json数组数据映射到形参的集合对象中作为数据
@RequestMapping("/listParamForJson")
@ResponseBody
public String listParamForJson(@RequestBody List<String> likes){
System.out.println("list common(json)参数传递 list ==> "+likes);
return "{'module':'list common for json param'}";
}

后面的对象和集合也是差不多的,只要修改类型就就可以了 注意要在pom.xml中导入jackson包

知识点1:@EnableWebMvc

名称 @EnableWebMvc
类型 ==配置类注解==
位置 SpringMVC配置类定义上方
作用 开启SpringMVC多项辅助功能

知识点2:@RequestBody

名称 @RequestBody
类型 ==形参注解==
位置 SpringMVC控制器方法形参定义前面
作用 将请求中请求体所包含的数据传递给请求参数,此注解一个处理器方法只能使用一次

==REST==(Representational State Transfer),表现形式状态转换,它是一种软件架构==风格==

当我们想表示一个网络资源的时候,可以使用两种方式:

  • 传统风格资源描述形式
    • http://localhost/user/getById?id=1 查询id为1的用户信息
    • http://localhost/user/saveUser 保存用户信息
  • REST风格描述形式
    • http://localhost/user/1
    • http://localhost/user

个人理解:就是简化get post put delete等操作的时候 写路径会很繁琐的这种行为,称之为Rest风格 用这种风格访问就被称为==RESTful==

1
2
3
4
5
* `http://localhost/users`	查询全部用户信息 GET(查询)
* `http://localhost/users/1` 查询指定用户信息 GET(查询)
* `http://localhost/users` 添加用户信息 POST(新增/保存)
* `http://localhost/users` 修改用户信息 PUT(修改/更新)
* `http://localhost/users/1` 删除用户信息 DELETE(删除)

所用到的注解

知识点1:@PathVariable

名称 @PathVariable
类型 ==形参注解==
位置 SpringMVC控制器方法形参定义前面
作用 绑定路径参数与处理器方法形参间的关系,要求路径参数名与形参名一一对应

原本的get使用REST风格就变成如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Controller
public class UserController {
//设置当前请求方法为GET,表示REST风格中的查询操作
@RequestMapping(value = "/users" ,method = RequestMethod.GET)
@ResponseBody
public String getAll() {
System.out.println("user getAll...");
return "{'module':'user getAll'}";
}
@RequestMapping(value = "/users/{id}" ,method = RequestMethod.GET)
@ResponseBody
public String getById(@PathVariable Integer id){
System.out.println("user getById..."+id);
return "{'module':'user getById'}";
}

发现有些地方是重复的

解决方案如下 注解是原来的方式

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
@RestController //@Controller + ReponseBody
@RequestMapping("/books")
public class BookController {

//@RequestMapping(method = RequestMethod.POST)
@PostMapping
public String save(@RequestBody Book book){
System.out.println("book save..." + book);
return "{'module':'book save'}";
}

//@RequestMapping(value = "/{id}",method = RequestMethod.DELETE)
@DeleteMapping("/{id}")
public String delete(@PathVariable Integer id){
System.out.println("book delete..." + id);
return "{'module':'book delete'}";
}

//@RequestMapping(method = RequestMethod.PUT)
@PutMapping
public String update(@RequestBody Book book){
System.out.println("book update..." + book);
return "{'module':'book update'}";
}

//@RequestMapping(value = "/{id}",method = RequestMethod.GET)
@GetMapping("/{id}")
public String getById(@PathVariable Integer id){
System.out.println("book getById..." + id);
return "{'module':'book getById'}";
}

//@RequestMapping(method = RequestMethod.GET)
@GetMapping
public String getAll(){
System.out.println("book getAll...");
return "{'module':'book getAll'}";
}

}

问题1:每个方法的@RequestMapping注解中都定义了访问路径/books,重复性太高。

1
@RequestMapping提到类上面,用来定义所有方法共同的访问路径。

问题2:每个方法的@RequestMapping注解中都要使用method属性定义请求方式,重复性太高。

1
使用@GetMapping  @PostMapping  @PutMapping  @DeleteMapping代替

问题3:每个方法响应json都需要加上@ResponseBody注解,重复性太高。

1
2
1.将ResponseBody提到类上面,让所有的方法都有@ResponseBody的功能
2.使用@RestController注解替换@Controller@ResponseBody注解,简化书写

使用的注解

知识点1:@RestController

名称 @RestController
类型 ==类注解==
位置 基于SpringMVC的RESTful开发控制器类定义上方
作用 设置当前控制器类为RESTful风格,
等同于@Controller与@ResponseBody两个注解组合功能

知识点2:@GetMapping @PostMapping @PutMapping @DeleteMapping

名称 @GetMapping @PostMapping @PutMapping @DeleteMapping
类型 ==方法注解==
位置 基于SpringMVC的RESTful开发控制器方法定义上方
作用 设置当前控制器方法请求访问路径与请求动作,每种对应一个请求动作,
例如@GetMapping对应GET请求
相关属性 value(默认):请求访问路径
  1. BUG点

难点(关键代码或关键配置,BUG截图+解决方案)

做 REST风格的案例的时候 连接不到html

image-20221012220835426

但是问题是在MVC应该是拦截了前端的数据 导致无法访问

image-20221012220912323

换成下面这种方式就好了 具体原因没有搞清楚 老师示范的代码是上图的 静态资源进行放行

image-20221012220646291

5.扩展学习部分

@RequestBody与@RequestParam区别

  • 区别

    • @RequestParam用于接收url地址传参,表单传参【application/x-www-form-urlencoded】
    • @RequestBody用于接收json数据【application/json】
  • 应用

    • 后期开发中,发送json格式数据为主,@RequestBody应用较广
    • 如果发送非json格式数据,选用@RequestParam接收请求参数

6.总结

重点是哪些知识比较重要,难点是你在学习过程中觉得比较繁琐,掌握起来有一点

今天学习状态一般 没怎么睡好,下午还不错,学习的内容是MVC也就是和web框架差不多,前后端连接的点比较多,敲很多代码觉得不错的地方就是比原本的webServlet要快很多,而且我觉得很清楚,代码还简洁,利用注解就能接决连接的情况。做REST风格的案例的时候,稍微出现了一些问题,但是也在同学的帮助下解决了,学了很多的注解了,有些其实都没怎么记住,还是要多敲代码多用,才能更好的去记忆如何使用。

10.13 SSM整合 拦截器

1.头:日期、所学内容出处

【黑马程序员2022新版SSM框架教程_Spring+SpringMVC+Maven高级+SpringBoot+MyBatisPlus企业实用开发技术】 https://www.bilibili.com/video/BV1Fi4y1S7ix?p=31&share_source=copy_web&vd_source=c8ae4150b2286ee39a13a79bbe12b843

2.所学内容概述

3.根据概述分章节描述

SSM整合流程

把前面所学习的三个框架都整合在一起

1
2
3
4
5
6
7
8
9
10
1>>>创建工程
2>>>SSM整合
Spring
MyBatis
SpringMVC
3>>>功能模块
表和实现类
dao接口
service业务层
controller表现层

入门案例

以后spring 创建项目包结构都可以用这种 单词自己注意下

创建项目包结构

1630561591931

  • config目录存放的是相关的配置类
  • controller编写的是Controller类
  • dao存放的是Dao接口,因为使用的是Mapper接口代理方式,所以没有实现类包
  • service存的是Service接口,impl存放的是Service实现类
  • resources:存入的是配置文件,如Jdbc.properties
  • webapp:目录可以存放静态资源

个人理解:流程可以这样敲

1
2
3
4
SpringConfig -- JdbcConfig -- MybatisConfig -- jdbc.prperties -- SpringMVC --创建Web项目入口配置类 

模块开发
模型类 == Dao接口 == Service接口和实现类 == Contorller类

前后台协议统一

在webAPP添加静态资源

因为添加了静态资源所以SpringMVC会拦截的 我们需要放行 在SpringConfig放行

1
2
3
4
5
6
7
8
9
10
@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
registry.addResourceHandler("/css/**").addResourceLocations("/css/");
registry.addResourceHandler("/js/**").addResourceLocations("/js/");
registry.addResourceHandler("/plugins/**").addResourceLocations("/plugins/");
}
}

在SpringMvcConfig中扫描SpringMvcSupport

1
2
3
4
5
@Configuration
@ComponentScan({"com.itheima.controller","com.itheima.config"})
@EnableWebMvc
public class SpringMvcConfig {
}

然后写前端页面完成项目整合

拦截器

可以动态拦截控制器的执行

  • 在指定的方法调用前后执行预先设定的代码
  • 阻止原始方法的执行
  • 总结:拦截器就是用来做增强

拦截器开发

让类实现HandlerInterceptor接口,重写接口中的三个方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Component
//定义拦截器类,实现HandlerInterceptor接口
//注意当前类必须受Spring容器控制
public class ProjectInterceptor implements HandlerInterceptor {
@Override
//原始方法调用前执行的内容
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle...");
//如果返回true,则代表放行,会执行原始Controller类中要请求的方法,如果返回false,则代表拦截,后面的就不会再执行了。
return true;
}

@Override
//原始方法调用后执行的内容
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle...");
}

@Override
//原始方法调用完成后执行的内容
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion...");
}
}

**注意:**拦截器类要被SpringMVC容器扫描到。

所以需要再SpringMvcSupport允许通过

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {
@Autowired
private ProjectInterceptor projectInterceptor;

@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
}

@Override
protected void addInterceptors(InterceptorRegistry registry) {
//配置拦截器 访问结尾是books的会被拦截
//registry.addInterceptor(projectInterceptor).addPathPatterns("/books" );
//表示访问中有books结尾或者是books后面的 都会被拦截
registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*" );
}
}

4. BUG点

难点(关键代码或关键配置,BUG截图+解决方案)

@Autowired下面一直冒红 也找不到原因 索性重新打了一遍代码就莫名其妙好了

img

6.总结

重点是哪些知识比较重要,难点是你在学习过程中觉得比较繁琐,掌握起来有一点

今天学习状态一般,有点太疲劳了,还是内容问题,感觉有点不是很理解,类太多,使用的注解也很多 ,敲过去有些参数不是很理解,调用的方式,但是也没有死磕,大致的过了一下就好了,后面SpringBoot的时候会简单很多,这些到时候在复习一下,拦截器那里没怎么听懂,今天的掌握只有70吧。也没有报错但是就是有点云里雾里。

10.14 Mybatis-Puls

1.头:日期、所学内容出处

【黑马程序员MybatisPlus深入浅出教程,快速上手mybatisplus】 https://www.bilibili.com/video/BV1rE41197jR?p=12&share_source=copy_web&vd_source=c8ae4150b2286ee39a13a79bbe12b843

2.所学内容概述

了解Mybatis-plus

快速使用

使用sql简单功能实现

3.根据概述分章节描述

什么是Mybatis-plus(MP)

个人理解:之前学过mybatis,连接数据库,利用返回值,以及实现的接口,实现java对mysql的操作。这个Mybatis-plus相当于是把你java对mysql的操作进行封装,这样你开发的时候的代码量等操作就会少很多,提高效率。

快速使用

需要导入插件在Maven中

1
2
3
4
5
6
<!-- mybatis-plus插件依赖 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus</artifactId>
<version>3.1.1</version>
</dependency>

因为之前学过spring了,而且以后基本也都是使用spring 所以 前面mybatis+MP的代码就不列出来了

Spring+Mybatis+MP

熟悉的流程

实现查询User

1.编写jdbc.properties
1
2
3
4
5
6
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/mp?
useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true&useSSL
=false
jdbc.username=root
jdbc.password=root
2.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
<?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"/>
<!-- 定义数据源 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
destroy-method="close">
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="maxActive" value="10"/>
<property name="minIdle" value="5"/>
</bean>
<!--这里使用MP提供的sqlSessionFactory,完成了Spring与MP的整合-->
<bean id="sqlSessionFactory"
class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--扫描mapper接口,使用的依然是Mybatis原生的扫描器-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="cn.itcast.mp.simple.mapper"/>
</bean>
</beans>
3.UserMapper接口 继承BaseMapper
1
2
3
4
5
package cn.itcast.mp.simple.mapper;
import cn.itcast.mp.simple.pojo.User;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
public interface UserMapper extends BaseMapper<User> {
}
4.测试类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package cn.itcast.mp.simple;
import cn.itcast.mp.simple.mapper.UserMapper;
import cn.itcast.mp.simple.pojo.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.List;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class TestSpringMP {
@Autowired
private UserMapper userMapper;
@Test
public void testSelectList(){
List<User> users = this.userMapper.selectList(null);
for (User user : users) {
System.out.println(user);
}
}
}

通用CRUD

我都放到一个测试类里面了 也有注解 其实就是调用接口中的方法 忘记的话点击去源代码查看 有MP的中文注解的

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
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
package cn.itcast.mp;

import cn.itcast.mp.mapper.UserMapper;
import cn.itcast.mp.pojo.User;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RunWith(SpringRunner.class)
@SpringBootTest
public class TestUserMapper {

@Autowired
private UserMapper userMapper;

@Test
public void testInsert() {
User user = new User();
user.setMail("2@itcast.cn");
user.setAge(301);
user.setUserName("caocao1");
user.setName("曹操1");
user.setPassword("123456");
user.setAddress("北京");

int result = this.userMapper.insert(user); //result数据库受影响的行数
System.out.println("result => " + result);

//获取自增长后的id值, 自增长后的id值会回填到user对象中
System.out.println("id => " + user.getId());
}

@Test
public void testSelectById() {
User user = this.userMapper.selectById(2L);
System.out.println(user);
}

@Test
public void testUpdateById() {
User user = new User();
user.setId(1L); //条件,根据id更新
user.setAge(19); //更新的字段
user.setPassword("666666");

int result = this.userMapper.updateById(user);
System.out.println("result => " + result);
}

@Test
public void testUpdate() {
User user = new User();
user.setAge(20); //更新的字段
user.setPassword("8888888");

QueryWrapper<User> wrapper = new QueryWrapper<>(); //根据条件更新
wrapper.eq("user_name", "zhangsan"); //匹配user_name = zhangsan 的用户数据

//根据条件做更新
int result = this.userMapper.update(user, wrapper);
System.out.println("result => " + result);
}

@Test
public void testUpdate2() {

UpdateWrapper<User> wrapper = new UpdateWrapper<>();
wrapper.set("age", 21).set("password", "999999") //更新的字段
.eq("user_name", "zhangsan"); //更新的条件

//根据条件做更新
int result = this.userMapper.update(null, wrapper);
System.out.println("result => " + result);
}

@Test
public void testDeleteById(){
// 根据id删除数据
int result = this.userMapper.deleteById(9L);
System.out.println("result => " + result);
}

@Test
public void testDeleteByMap(){

Map<String,Object> map = new HashMap<>();
map.put("user_name", "zhangsan");
map.put("password", "999999");

// 根据map删除数据,多条件之间是and关系
int result = this.userMapper.deleteByMap(map);
System.out.println("result => " + result);
}

@Test
public void testDelete(){

//用法一:
// QueryWrapper<User> wrapper = new QueryWrapper<>();
// wrapper.eq("user_name", "caocao1")
// .eq("password", "123456");

//用法二:
User user = new User();
user.setPassword("123456");
user.setUserName("caocao");
//封装到User对象中 删除设置的对象
QueryWrapper<User> wrapper = new QueryWrapper<>(user);

// 根据包装条件做删除
int result = this.userMapper.delete(wrapper);
System.out.println("result => " + result);
}

@Test
public void testDeleteBatchIds(){
// 根据id批量删除数据
int result = this.userMapper.deleteBatchIds(Arrays.asList(6L, 7L));
System.out.println("result => " + result);
}

@Test
public void testSelectBatchIds(){
// 根据id批量查询数据
List<User> users = this.userMapper.selectBatchIds(Arrays.asList(2L, 3L, 4L, 100L));
for (User user : users) {
System.out.println(user);
}
}

@Test
public void testSelectOne(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
//查询条件
wrapper.eq("password", "123456");
// 查询的数据超过一条时,会抛出异常
User user = this.userMapper.selectOne(wrapper);
System.out.println(user);
}

@Test
public void testSelectCount(){

QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.gt("age", 20); // 条件:年龄大于20岁的用户

// 根据条件查询数据条数
Integer count = this.userMapper.selectCount(wrapper);
System.out.println("count => " + count);
}

@Test
public void testSelectList(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
//设置查询条件
wrapper.like("email", "itcast");

List<User> users = this.userMapper.selectList(wrapper);
for (User user : users) {
System.out.println(user);
}
}

// 测试分页查询
@Test
public void testSelectPage(){

Page<User> page = new Page<>(3,1); //查询第一页,查询1条数据

QueryWrapper<User> wrapper = new QueryWrapper<>();
//设置查询条件
wrapper.like("email", "itcast");

IPage<User> iPage = this.userMapper.selectPage(page, wrapper);
System.out.println("数据总条数: " + iPage.getTotal());
System.out.println("数据总页数: " + iPage.getPages());
System.out.println("当前页数: " + iPage.getCurrent());

List<User> records = iPage.getRecords();
for (User record : records) {
System.out.println(record);
}

}

/**
* 自定义的方法
*/
@Test
public void testFindById(){
User user = this.userMapper.findById(2L);
System.out.println(user);
}

@Test
public void testAllEq(){

Map<String,Object> params = new HashMap<>();
params.put("name", "李四");
params.put("age", "20");
params.put("password", null);

QueryWrapper<User> wrapper = new QueryWrapper<>();
//SELECT id,user_name,name,age,email AS mail FROM tb_user WHERE password IS NULL AND name = ? AND age = ?
// wrapper.allEq(params);
//SELECT id,user_name,name,age,email AS mail FROM tb_user WHERE name = ? AND age = ?
// wrapper.allEq(params, false);

//SELECT id,user_name,name,age,email AS mail FROM tb_user WHERE age = ?
// wrapper.allEq((k, v) -> (k.equals("age") || k.equals("id")) , params);
//SELECT id,user_name,name,age,email AS mail FROM tb_user WHERE name = ? AND age = ?
wrapper.allEq((k, v) -> (k.equals("age") || k.equals("id") || k.equals("name")) , params);

List<User> users = this.userMapper.selectList(wrapper);
for (User user : users) {
System.out.println(user);
}
}

@Test
public void testEq() {
QueryWrapper<User> wrapper = new QueryWrapper<>();

//SELECT id,user_name,password,name,age,email FROM tb_user WHERE password = ? AND age >= ? AND name IN (?,?,?)
wrapper.eq("password", "123456")
.ge("age", 20)
.in("name", "李四", "王五", "赵六");

List<User> users = this.userMapper.selectList(wrapper);
for (User user : users) {
System.out.println(user);
}

}

@Test
public void testLike(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
// SELECT id,user_name,name,age,email AS mail FROM tb_user WHERE name LIKE ?
// 参数:%五(String)
wrapper.likeLeft("name", "五");

List<User> users = this.userMapper.selectList(wrapper);
for (User user : users) {
System.out.println(user);
}
}

@Test
public void testOrderByAgeDesc(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
//按照年龄倒序排序
// SELECT id,user_name,name,age,email AS mail FROM tb_user ORDER BY age DESC
wrapper.orderByDesc("age");

List<User> users = this.userMapper.selectList(wrapper);
for (User user : users) {
System.out.println(user);
}
}

@Test
public void testOr(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
// SELECT id,user_name,name,age,email AS mail FROM tb_user WHERE name = ? OR age = ?
wrapper.eq("name", "王五").or().eq("age", 21);

List<User> users = this.userMapper.selectList(wrapper);
for (User user : users) {
System.out.println(user);
}
}

@Test
public void testSelect(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
//SELECT id,name,age FROM tb_user WHERE name = ? OR age = ?
wrapper.eq("name", "王五")
.or()
.eq("age", 21)
.select("id","name","age"); //指定查询的字段

List<User> users = this.userMapper.selectList(wrapper);
for (User user : users) {
System.out.println(user);
}
}

}

6.总结

重点是哪些知识比较重要,难点是你在学习过程中觉得比较繁琐,掌握起来有一点

今天的学习状态不错,看着文档敲了很多代码,MP是中国团队写出来的,也是我现在IDEA点进去,唯一一个注释是中文的Maven插件,一些基本的sql语句,我都是看他源代码和注释,了解用法了的。学习中也没遇到什么BUG,偶尔几次是自己写错了方法名字或者jdbc写错了,难度不是很大,前面基本使用是会了,打算明天看SpringBoot2,遇到使用MP进阶的时候再回头看看。

10.17 SpringBoot

1.头:日期、所学内容出处

【黑马程序员2022新版SSM框架教程_Spring+SpringMVC+Maven高级+SpringBoot+MyBatisPlus企业实用开发技术】 https://www.bilibili.com/video/BV1Fi4y1S7ix?p=31&share_source=copy_web&vd_source=c8ae4150b2286ee39a13a79bbe12b843

2.所学内容概述

简单的入门案例利用SpringBoot 只需要一行就能实现

1
2
3
4
5
6
7
8
9
10
11
//Rest模式
@RestController
@RequestMapping("/books")
public class BookController {

@GetMapping
public String getById(){
System.out.println("springboot is running...");
return "springboot is running!";
}
}

主程序如下

1
2
3
4
5
6
7
8
9
10
11
12
package com.itheima;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Springboot0101QuickstartApplication {

public static void main(String[] args) {
SpringApplication.run(Springboot0101QuickstartApplication.class, args);
}
}

原来的Spring项目结构如下

image-20221017190256901

SpringBoot项目结构如下

只需要一个java类

image-20221017190332984

个人理解显而易见SpringBoot简单很多 Spring中的配置 在SpringBoot中都给你配好了

还有一个很智能的 pom.xml文件 他能帮你把所有最合适的版本配置好 在IDEA可以直接创建

image-20221017190740086

3.总结

重点是哪些知识比较重要,难点是你在学习过程中觉得比较繁琐,掌握起来有一点

今天的学习内容不是很多,上午考驾照去了,下午先整理了一下前面SSM框架的一些内容,再来看的SpringBoot,只做了一个简单的入门案例,SpringBoot把之前要写Bean都帮你整理好了,这样你只要输入controller文件就好了。暂时没什么难的,就是搞清楚他运行原理的话有点麻烦,学到后面的原理篇再仔细看一下吧。

10.18 SpringBoot基础篇完结

1.头:日期、所学内容出处

【黑马程序员2022新版SSM框架教程_Spring+SpringMVC+Maven高级+SpringBoot+MyBatisPlus企业实用开发技术】 https://www.bilibili.com/video/BV1Fi4y1S7ix?p=31&share_source=copy_web&vd_source=c8ae4150b2286ee39a13a79bbe12b843

2.所学内容概述

SpringBoot基本配置

属性配置

配置文件分类

yaml文件使用

yaml数据读取

SpringBoot实现SSMP整合

3.根据概述分章节描述

SpringBoot基本配置

属性配置

修改application.properties文件 设置服务器端口号 格式如下 IDEA会有自动联想功能会有提示

1
2
3
4
5
server.port=80
# **关闭运行日志图表(banner)**
spring.main.banner-mode=off
# **设置运行日志的显示级别**
logging.level.root=debug

配置文件分类

分三种 默认的是properties 然后是两种yaml和yml

三种格式也不一样

  • application.properties(properties格式)
1
server.port=80
  • application.yml(yml格式)
1
2
server:
port: 81
  • application.yaml(yaml格式)
1
2
server:
port: 82

​ 仔细看会发现yml式和yaml格式除了文件名后缀不一样,格式完全一样,是这样的,yml和yaml文件格式就是一模一样的,只是文件后缀不同,所以可以合并成一种格式来看。以后企业比较常用的是yml格式的 是yml为重点

配置文件如果有相同的话 优先级来说的话如下 但是配置文件不同会同时起作用

1
2
application.properties  >  application.yml  >  application.yaml
# 优先级

yaml文件使用

数据书写格式i如下

1
2
3
4
5
6
7
8
boolean: TRUE  						#TRUE,true,True,FALSE,false,False均可
float: 3.14 #6.8523015e+5 #支持科学计数法
int: 123 #0b1010_0111_0100_1010_1110 #支持二进制、八进制、十六进制
null: ~ #使用~表示null
string: HelloWorld #字符串可以直接书写
string2: "Hello World" #可以使用双引号包裹特殊字符
date: 2018-02-17 #日期必须使用yyyy-MM-dd格式
datetime: 2018-02-17T15:02:31+08:00 #时间和日期之间使用T连接,最后使用+代表时区

也可以表示数组或多维数组

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
subject:
- Java
- 前端
- 大数据
enterprise:
name: itcast
age: 16
subject:
- Java
- 前端
- 大数据
likes: [王者荣耀,刺激战场] #数组书写缩略格式
users: #对象数组格式一
- name: Tom
age: 4
- name: Jerry
age: 5
users: #对象数组格式二
-
name: Tom
age: 4
-
name: Jerry
age: 5
users2: [ { name:Tom , age:4 } , { name:Jerry , age:5 } ] #对象数组缩略格式
yaml数据读取

读取单一数据

yaml中保存的单个数据,可以使用Spring中的注解直接读取,使用@Value可以读取单个数据,属性名引用方式:${一级属性名.二级属性名……}

image-20211126180433356

读取全部数据

​ 读取单一数据可以解决读取数据的问题,但是如果定义的数据量过大,这么一个一个书写肯定会累死人的,SpringBoot提供了一个对象,能够把所有的数据都封装到这一个对象中,这个对象叫做Environment,使用自动装配注解可以将所有的yaml数据封装到这个对象中

image-20211126180738569

但是要写env.getProperty太麻烦了

写成对象数据调用会方便很多

image-20221018140729972

读取方式如下

image-20221018140758872

会简单很多 直接输出就是 对象的tostring

4.总结

重点是哪些知识比较重要,难点是你在学习过程中觉得比较繁琐,掌握起来有一点

今天的学习内容是Boot2基础篇差不多结束了,配置方面学习的比较多,算是重点吧,yml感觉是比之前properties的文件要舒服很多,连接数据库的时候,输入也很方便,加上MP的配置,感觉将开发效率提高了很多。今天没什么难点,都是理解为主,文档看看,去实验了一下,明天把SSMP的案例过了,就能去下一个阶段了。

10.19 SSMP案例

1.头:日期、所学内容出处

【黑马程序员2022新版SSM框架教程_Spring+SpringMVC+Maven高级+SpringBoot+MyBatisPlus企业实用开发技术】 https://www.bilibili.com/video/BV1Fi4y1S7ix?p=31&share_source=copy_web&vd_source=c8ae4150b2286ee39a13a79bbe12b843

2.所学内容概述

SSMP步骤

个人理解:

1.pom.xml

配置依赖

2.application.yml

设置数据源 端口 框架

3.dao

继承BaseMapper 设置@Mapper

4.dao测试类

5.service

调用数据层接口或Mybatis-Plus提供的接口快速开发

6.service测试类

7.controller

基于Restful开发 用Postman测试

8.页面

放置resources目录中static静态页面

本人理解原理:

image-20221019194347499

接口各个实现原理

数据层BookDao接口继承mp中的BaseMapper拥有其方法

IBookService业务层接口 继承mp中IService

BookServiceImpl注入BookDao实现对象,业务层方法一目了然知道使用方法,创建对应类然后调用数据层的方法

在表现层BookController写对应请求类所调用的方法 并添加功能

表现层消息一致性

要求是前端请求得到的数据 需要统一

增删改操作结果

1
true

查询单个数据操作结果

1
2
3
4
5
6
{
    "id": 1,
    "type": "计算机理论",
    "name": "Spring实战 第5版",
    "description": "Spring入门经典教程"
}

查询全部数据操作结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[
    {
        "id": 1,
        "type": "计算机理论",
        "name": "Spring实战 第5版",
        "description": "Spring入门经典教程"
    },
    {
        "id": 2,
        "type": "计算机理论",
        "name": "Spring 5核心原理与30个类手写实战",
        "description": "十年沉淀之作"
    }
]

如上面的几种不同的操作 返回的数据格式都不一样,为了方便前端的开发,可以设计一个类 被称为模型类 用于数据统一的 被称为前后端数据协议

创建R类 写boolean类的flag Object的data 即可 (msg是后面对异常处理添加的)

Object类可以放数据 flag设计是有没有请求到数据 设计好构造方法 这样前端的返回的数据 都是一个flag一个data了

image-20221019195355827

效果如下

1
2
3
4
5
6
7
8
9
{
    "flag": true,
    "data":{
        "id": 1,
        "type": "计算机理论",
        "name": "Spring实战 第5版",
        "description": "Spring入门经典教程"
    }
}

3. BUG点

难点(关键代码或关键配置,BUG截图+解决方案)

4.扩展学习部分

5.总结

今天下午学了车,所以今天主要是做了SSMP的案例,之前讲过学SSM框架的时候的实现效果差不多,但是使用SSMP方便了很多,上次这个案例没怎么做,过了一遍,这次自己尝试去做了一遍,因为没学过vue,在前端实现的部分,就采用了老师的代码,后端开发基本都是自己看完视频以后独立完成,难度不是很大,sql语句也是很简单的,所以MP已经帮你写好了,明天可以进入开发篇中去了。

10.20 SpringBoot运维

1.头:日期、所学内容出处

【黑马程序员2022新版SSM框架教程_Spring+SpringMVC+Maven高级+SpringBoot+MyBatisPlus企业实用开发技术】 https://www.bilibili.com/video/BV1Fi4y1S7ix?p=31&share_source=copy_web&vd_source=c8ae4150b2286ee39a13a79bbe12b843

2.所学内容概述

使用cmd命令行 运行项目jar包

cmd运行jar包命令如下

1
java -jar XXXXXXX.jar

可以设置临时配置属性 两个–后面跟属性然后设置值 和properties文件格式差不多

1
java -jar xxxxxx.jar --server.port=80 --logging.level.root=debug

下面是有时候端口冲突或者进程冲突时候命令

1
2
3
4
5
6
7
8
9
10
# 查询端口
netstat -ano
# 查询指定端口
netstat -ano |findstr "端口号"
# 根据进程PID查询进程名称
tasklist |findstr "进程PID号"
# 根据PID杀死任务
taskkill /F /PID "进程PID号"
# 根据进程名称杀死任务
taskkill -f -t -im "进程名称"

多环境开发

个人理解:在公司中 一些配置是不需要底层的人看到的,所以相当于每个阶层负责的内容不一样。就是说你的电脑上写的程序最终要放到别人的服务器上去运行。每个计算机环境不一样,这就是多环境。常见的多环境开发主要兼顾3种环境设置,开发环境——自己用的,测试环境——自己公司用的,生产环境——甲方爸爸用的。所以一些配置是不一样的,利用不同的文件目录就可以实现

3. BUG点

难点(关键代码或关键配置,BUG截图+解决方案)

4.扩展学习部分

5.总结

今天学习的内容对我比较简单,之前学过一些运维方面的知识,打包什么都很熟悉,在大数据比赛的时候已经如鱼得水了,今天看文档就把运维看完了,然后附带了点后面开发的内容,如热部署什么的。总体来说,今天学习状态也不错,内容比较对口吧。

10.21下午-10.23下午 Spring开发使用篇

1.头:日期、所学内容出处

【黑马程序员2022新版SSM框架教程_Spring+SpringMVC+Maven高级+SpringBoot+MyBatisPlus企业实用开发技术】 https://www.bilibili.com/video/BV1Fi4y1S7ix?p=31&share_source=copy_web&vd_source=c8ae4150b2286ee39a13a79bbe12b843

2.所学内容概述

热部署

热部署相当于你启动完服务器,又修改了java的代码,之前是需要重新运行一次的,现在只要L+一下就好了,不需要再次运行浪费时间和资源了

因为自动和监控比较鸡肋,最常用的还是手动启动热部署,所以就记手动的实现 方式=就行了‘

1
2
3
4
5
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
1
<CTR>L+<F9> #IDEA启动热部署快捷键

配置高级

属性绑定时,可能会遇到如下情况,为了进行标准命名,开发者会将属性名严格按照驼峰命名法书写,在yml配置文件中将datasource修改为dataSource,如下:

1
2
dataSource:
driverClassName: com.mysql.jdbc.Driver

​ 此时程序可以正常运行,然后又将代码中的前缀datasource修改为dataSource,如下:

1
2
3
4
5
6
@Bean
@ConfigurationProperties(prefix = "dataSource")
public DruidDataSource datasource(){
DruidDataSource ds = new DruidDataSource();
return ds;
}

​ 明明确定的目标名是一样的,却无法匹配,就是有关属性名称的宽松绑定,也可以称为宽松绑定。

​ 实际上是springboot进行编程时人性化设计的一种体现,即配置文件中的命名格式与变量名的命名格式可以进行格式上的最大化兼容。可以与下面的配置属性名规则全兼容

1
2
3
4
5
servers:
ipAddress: 192.168.0.2 # 驼峰模式
ip_address: 192.168.0.2 # 下划线模式
ip-address: 192.168.0.2 # 烤肉串模式
IP_ADDRESS: 192.168.0.2 # 常量模式

​ 也可以说,以上4种模式最终都可以匹配到ipAddress这个属性名。不过springboot官方推荐使用烤肉串模式,也就是中划线模式。命名的规范问题。看开始出现的编程错误信息

1
2
3
4
5
6
7
8
Configuration property name 'dataSource' is not valid:

Invalid characters: 'S'
Bean: datasource
Reason: Canonical names should be kebab-case ('-' separated), lowercase alpha-numeric characters and must start with a letter

Action:
Modify 'dataSource' so that it conforms to the canonical names requirements.

​ 其中Reason描述了报错的原因,规范的名称应该是烤肉串(kebab)模式(case),即使用-分隔,使用小写字母数字作为标准字符,且必须以字母开头。

​ 以上规则仅针对springboot中@ConfigurationProperties注解进行属性绑定时有效,对@Value注解进行属性映射无效。

总结

  1. @ConfigurationProperties绑定属性时支持属性名宽松绑定,这个宽松体现在属性名的命名规则上
  2. @Value注解不支持松散绑定规则
  3. 绑定前缀名推荐采用烤肉串命名规则,即使用中划线做分隔符

数据层

数据源技术

之前我们用的是druid springboot还有三个内置的数据源技术

  • HikariCP
  • Tomcat提供DataSource
  • Commons DBCP、

HikariCP是默认的 不配置啥数据源的话就是这个

1
2
3
4
5
6
7
spring:
datasource:
druid: # 这里是选择数据源的
url: jdbc:mysql://localhost:3306/ssm_db?serverTimezone=UTC
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: root

持久化技术

个人觉得这里比较重要 就提高一个标题等级吧 这里主要是springboot充分发挥其最强辅助的特征,给开发者提供了一套现成的数据层技术,叫做JdbcTemplate。导入坐标完了 可以直接写自定义sql

导入jdbc对应的坐标,记得是starter

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency

自动装配JdbcTemplate对象

1
2
3
4
5
6
@SpringBootTest
class Springboot15SqlApplicationTests {
@Test
void testJdbcTemplate(@Autowired JdbcTemplate jdbcTemplate){
}
}

使用JdbcTemplate实现查询操作(非实体类封装数据的查询操作)

1
2
3
4
5
6
@Test
void testJdbcTemplate(@Autowired JdbcTemplate jdbcTemplate){
String sql = "select * from tbl_book";
List<Map<String, Object>> maps = jdbcTemplate.queryForList(sql);
System.out.println(maps);
}

使用JdbcTemplate实现查询操作(实体类封装数据的查询操作)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Test
void testJdbcTemplate(@Autowired JdbcTemplate jdbcTemplate){

String sql = "select * from tbl_book";
RowMapper<Book> rm = new RowMapper<Book>() {
@Override
public Book mapRow(ResultSet rs, int rowNum) throws SQLException {
Book temp = new Book();
temp.setId(rs.getInt("id"));
temp.setName(rs.getString("name"));
temp.setType(rs.getString("type"));
temp.setDescription(rs.getString("description"));
return temp;
}
};
List<Book> list = jdbcTemplate.query(sql, rm);
System.out.println(list);
}

使用JdbcTemplate实现增删改操作

1
2
3
4
5
@Test
void testJdbcTemplateSave(@Autowired JdbcTemplate jdbcTemplate){
String sql = "insert into tbl_book values(3,'springboot1','springboot2','springboot3')";
jdbcTemplate.update(sql);
}

个人理解:一些复杂的sql语句可以不依赖于MP,自定义会更好些,而且可以满足需求,想写什么类型的sql语句,写完调用jdbcTemplate中对应的实现方法就行了,查询比较麻烦,非实体类看起来不太方便,可以写一个实体类,封装进去。

数据库技术

讲的都是springboot内置的三个数据库,感觉没什么很大的用处以后,还是mysql居多

NOSQL非关系数据库

讲了三个Redis MongoDB ES 都是比较常用的数据库,跟着安装了一下,然后基本的使用学会了,用SpringBoot整合了一下,没什么难点,也没重点,后面需要用的使用,再局部的复习一下

3. BUG

难点(关键代码或关键配置,BUG截图+解决方案)

自己写的查询方法这里,想用sql来进行分页,报错了,发现这里修改以后,后面的Service业务层没有修改,导致报错

img

4.扩展学习部分

5.总结

因为上午都有点事情,就把这两天下午的学习内容放一天了,这两天下午的学习内容是有点难度的,而且内容比较多,从热部署,配置,测试,数据层结局问题,和整合第三方技术。在数据层那边难度比较大,重点在数据层和整合第三方技术,,数据层课件分了两部分,SQL和NOSQL,非关系和关系型的数据库,NOSQL比较简单,除了ES是有点难度的打算下次去专门回头看一下,也只讲了基本操作,SQL中数据源和持久化还是很有意思的,利用JdbcTemplate持久化,完成比较复杂的sql语句,也验证了我之前觉得MP虽然智能,但是在复杂的企业项目中,会用到复杂的SQL语句,肯定是有些要自己手敲sql的,学一暑假的MYSQL没白学。下次就结束整合第三方,开发篇也就完结了,就可以去做项目了,数据层还差一个ES没有看。自己试着用数据库技术,用自己之前比赛清洗的数据库清洗代码,放java中运行今天学习状态极佳,内容也比较多,因为自己擅长sql点,学习也有兴趣。

10.24 Spring整合第三方技术

1.头:日期、所学内容出处

【黑马程序员2022新版SSM框架教程_Spring+SpringMVC+Maven高级+SpringBoot+MyBatisPlus企业实用开发技术】 https://www.bilibili.com/video/BV1Fi4y1S7ix?p=31&share_source=copy_web&vd_source=c8ae4150b2286ee39a13a79bbe12b843

2.所学内容概述

缓存

缓存是一种介于数据永久存储介质与应用程序之间的数据临时存储介质,使用缓存可以有效的减少低速数据读取过程的次数(例如磁盘IO),提高系统性能。

内置缓存

就是一些数据可以临时放缓存中,Springboot提供了包

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>

然后在服务器启动上面

1
2
//开启缓存功能
@EnableCaching

在业务层方法上面注解

1
2
3
4
5
@Override
@Cacheable(value="cacheSpace",key="#id")
public Book getById(Integer id) {
return bookDao.selectById(id);
}

ehcache缓存

坐标

1
2
3
4
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
</dependency>

外置缓存需要配置的 在yml文件中

1
2
3
4
5
spring:
cache:
type: ehcache
ehcache:
config: ehcache.xml

ehcache的配置有独立的配置文件格式,因此还需要指定ehcache的配置文件,以便于读取相应配置

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
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
updateCheck="false">
<diskStore path="D:\ehcache" />

<!--默认缓存策略 -->
<!-- external:是否永久存在,设置为true则不会被清除,此时与timeout冲突,通常设置为false-->
<!-- diskPersistent:是否启用磁盘持久化-->
<!-- maxElementsInMemory:最大缓存数量-->
<!-- overflowToDisk:超过最大缓存数量是否持久化到磁盘-->
<!-- timeToIdleSeconds:最大不活动间隔,设置过长缓存容易溢出,设置过短无效果,可用于记录时效性数据,例如验证码-->
<!-- timeToLiveSeconds:最大存活时间-->
<!-- memoryStoreEvictionPolicy:缓存清除策略-->
<defaultCache
eternal="false"
diskPersistent="false"
maxElementsInMemory="1000"
overflowToDisk="false"
timeToIdleSeconds="60"
timeToLiveSeconds="60"
memoryStoreEvictionPolicy="LRU" />

<cache
name="smsCode"
eternal="false"
diskPersistent="false"
maxElementsInMemory="1000"
overflowToDisk="false"
timeToIdleSeconds="10"
timeToLiveSeconds="10"
memoryStoreEvictionPolicy="LRU" />
</ehcache>

Redis

redis的坐标

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

配置

1
2
3
4
5
6
7
8
9
10
11
spring:
redis:
host: localhost //本地
port: 6379
cache:
type: redis
redis:
use-key-prefix: false
key-prefix: sms_
cache-null-values: false
time-to-live: 10s

j2cache缓存

之前还有一种jet的整合方式,我觉得太麻烦,而且只能整合4种,所以就只记j2了。就以整合ehcache和redis

导入三个坐标

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<dependency>
<groupId>net.oschina.j2cache</groupId>
<artifactId>j2cache-core</artifactId>
<version>2.8.4-release</version>
</dependency>
<dependency>
<groupId>net.oschina.j2cache</groupId>
<artifactId>j2cache-spring-boot2-starter</artifactId>
<version>2.8.0-release</version>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
</dependency>

配置一级与二级缓存,并配置一二级缓存间数据传递方式,配置书写在名称为j2cache.properties的文件中。

1
2
3
4
5
6
7
8
9
10
11
# 1级缓存
j2cache.L1.provider_class = ehcache
ehcache.configXml = ehcache.xml

# 2级缓存
j2cache.L2.provider_class = net.oschina.j2cache.cache.support.redis.SpringRedisProvider
j2cache.L2.config_section = redis
redis.hosts = localhost:6379

# 1级缓存中的数据如何到达二级缓存
j2cache.broadcast = net.oschina.j2cache.cache.support.redis.SpringRedisPubSubPolicy
  1. j2cache是一个缓存框架,自身不具有缓存功能,它提供多种缓存整合在一起使用的方案
  2. j2cache需要通过复杂的配置设置各级缓存,以及缓存之间数据交换的方式
  3. j2cache操作接口通过CacheChannel实现

3. BUG点

难点(关键代码或关键配置,BUG截图+解决方案)

运行 cache缓存的时候报错,报错点一直没找到,看报错信息是XM,这个没听过,把那两个XM的jar包注释掉也没有用,最后把yml的配置全改了,然后检查数据层的一些注解,把和XM有关的都去掉,BUG解决了,看到后面才知道XM类是外置的一直缓存,需要下载配置才能使用,pom文件中导入不了

image-20221024183706622

4.扩展学习部分

手机验证码案例 自定义校对

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Component
public class CodeUtils {
//防止 出现开头是0然后变成整数后 数字不是六位
private String [] patch = {"000000","00000","0000","000","00","0",""};

public String generator(String tele){
int hash = tele.hashCode();
int encryption = 20206666;
long result = hash ^ encryption;
long nowTime = System.currentTimeMillis();
result = result ^ nowTime;
long code = result % 1000000;
code = code < 0 ? -code : code;
String codeStr = code + "";
int len = codeStr.length();
return patch[len] + codeStr;
}

@Cacheable(value = "smsCode",key="#tele")
public String get(String tele){
return null;
}
}

5.总结

今天学习的学习内容一般,内容比较多,主要是整合第三方的缓存部分,然后附带了点任务,出了一个小BUG,然后自己手动解决了,基本都是看文档,不知道具体用法的时候看视频去,然后试着敲一下,请求的时候有点云里雾里。跟着老师知道具体的请求,手敲了一遍简单的手机验证码,福袋啦Quartz任务,看了一会视频,还没明白是个什么事,明天就能结束Boot,后天可以做项目了。今天的学习状态不错,比较集中,看文档也看的下去,效率很高。

10.25 开发篇完结

1.头:日期、所学内容出处

【黑马程序员2022新版SSM框架教程_Spring+SpringMVC+Maven高级+SpringBoot+MyBatisPlus企业实用开发技术】 https://www.bilibili.com/video/BV1Fi4y1S7ix?p=31&share_source=copy_web&vd_source=c8ae4150b2286ee39a13a79bbe12b843

2.所学内容概述

任务Task

课件中还有一个Quartz,但是感觉很麻烦不太实用,现在主流的好像是Task

也就是定时任务,要做定时任务要容器有这功能,然后定时执行什么任务直接告诉对应的bean什么时间执行就行了

开启定时任务功能,在引导类上开启定时任务功能的开关,使用注解@EnableScheduling

1
2
3
4
5
6
7
8
@SpringBootApplication
//开启定时任务功能
@EnableScheduling
public class Springboot22TaskApplication {
public static void main(String[] args) {
SpringApplication.run(Springboot22TaskApplication.class, args);
}
}

步骤②:定义Bean,在对应要定时执行的操作上方,使用注解@Scheduled定义执行的时间,执行时间的描述方式还是cron表达式

1
2
3
4
5
6
7
@Component
public class MyBean {
@Scheduled(cron = "0/1 * * * * ?")
public void print(){
System.out.println(Thread.currentThread().getName()+" :spring task run...");
}
}

对定时任务进行相关配置,可以通过配置文件进行

1
2
3
4
5
6
7
8
9
spring:
task:
scheduling:
pool:
size: 1 # 任务调度线程池大小 默认 1
thread-name-prefix: ssm_ # 调度线程名称前缀 默认 scheduling-
shutdown:
await-termination: false # 线程池关闭时等待所有任务完成
await-termination-period: 10s # 调度线程关闭前最大等待时间,确保最后一定关闭

总结

  1. spring task需要使用注解@EnableScheduling开启定时任务功能
  2. 为定时执行的的任务设置执行周期,描述方式cron表达式

邮件

发邮件是java程序的基本操作,springboot整合javamail其实就是简化开发。发送邮件方是需要配置的,需要在自己的邮箱设置中找到密码SMTP的。收件方只需要一个邮箱地址就行了

消息

消息和之前用java做过的一个交互差不多,现在主要是异步消息,同步消息作用不大。

现在比较主流的RocketMQ,只要给要发送消息的方法挂上ROcketMQ的注解就可以了,还是比较简单的,步骤就不列出来了。

  1. springboot整合RocketMQ使用RocketMQTemplate对象作为客户端操作消息队列
  2. 操作RocketMQ需要配置RocketMQ服务器地址,默认端口9876
  3. 企业开发时通常使用监听器来处理消息队列中的消息,设置监听器使用注解@RocketMQMessageListener

监控

监控这边比较重要的是可视化监控平台

需要先看开启服务器 加入配置

1
2
3
4
5
6
7
8
9
10
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-server</artifactId>
<version>2.5.4</version>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

在引导类上添加注解@EnableAdminServer,声明当前应用启动后作为SpringBootAdmin的服务器使用

1
2
3
4
5
6
7
@SpringBootApplication
@EnableAdminServer
public class Springboot25AdminServerApplication {
public static void main(String[] args) {
SpringApplication.run(Springboot25AdminServerApplication.class, args);
}
}

​ 这样就能进去admin的页面了

然后就是开启一个自己的客户端 客户端比较简单导入坐标

导入springboot admin对应的starter,版本与当前使用的springboot版本保持一致,并将其配置成web工程

1
2
3
4
5
6
7
8
9
10
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
<version>2.5.4</version>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

​ 然后需要在yml配置信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
server:
port: 80
spring:
boot:
admin:
client:
url: http://localhost:8080

# 能显示health 很多详细信息
management:
endpoint:
health:
show-details: always
endpoints:
web:
exposure:
include: "*"

页面大致内容如下 功能很多 回头可以详细的一个一个功能的使用

image-20221025155656877

3. BUG点

难点(关键代码或关键配置,BUG截图+解决方案)

一直报错检查代码也没什么问题,提示是什么命名原因,但是自己根本没有dataSource这个名字, 后面重新开了一个模块,代码没改变没有报错信息了。之前的Spring是快速模块,现在换成2.4.1了,应该是模块的原因阿吧

image-20221025091629027

发送消息如下

image-20221025094450547

4.扩展学习部分

发送邮件和附件 超链接和图片

导入springboot整合javamail的starter

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>

步骤②:配置邮箱的登录信息 这里是发送方 发送方邮箱需要开启服务 一般都在设置中

1
2
3
4
5
6
7
8
9
10
11
12
#spring:
# mail:
# host: smtp.qq.com
# username: 1452582554@qq.com
# password: vxccjkvvlrokgigh


spring:
mail:
host: smtp.163.com
username: asrl825067@163.com
password: EPEKPEWBZXLAMCYL

写一个业务层的代码就好了

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
@Service
public class SendMailServiceImpl2 implements SendMailService {

private String from = "2272917904@qq.com";
private String to = "asrl825067@163.com";
private String subject = "测试邮件";
//图片和对应的超链接
private String context = "<img src='https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.soogif.com%2FV2a5qLlX2gFNIHXSvMrmUjyWxHdb4XXQ.gif&refer=http%3A%2F%2Fimg.soogif.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1669274278&t=7f8449969831195ab78eea7408740099'/><a href='https://www.itcast.cn'>点开有惊喜</a>";;


@Autowired
private JavaMailSender javaMailSender;

@Override
public void sendMail() {
try {

MimeMessage mimeMessage = javaMailSender.createMimeMessage();
MimeMessageHelper message = new MimeMessageHelper(mimeMessage,true);
message.setFrom(to+"(u7u7)");
message.setTo(from);
message.setSubject(subject);
message.setText(context,true);


//添加附件
// File f1 = new File("D:\\CC\\SpringBootCode\\springboot_mail_test\\target\\springboot_mail_test-0.0.1-SNAPSHOT.jar");
File f2 = new File("D:\\CC\\SpringBootCode\\springboot_mail_test\\src\\main\\resources\\cc.png");

// message.addAttachment(f1.getName(),f1);
message.addAttachment("最zz的cc.png",f2);

javaMailSender.send(mimeMessage);
}catch (Exception e){
e.printStackTrace();
}

}
}

测试点一直调用接口的sendMail的方法就行了需要注入的

5.总结

今天的内容算是一个结尾吧,然后把前面开发篇的部分又复习了一遍,开发实用篇到这里就暂时完结了,在开发实用篇中 都是大量的第三方技术的整合方案,选择的方案都是市面上比较流行的常用方案。今天也是把整个Boot篇做了个小总结吧,哪些注解哪些东西常用的也都记住了,明天开始做瑞吉外卖的项目,今天自己修改了一下用javamail发消息的代码, 能循环发消息和附件,但是会被官方拉黑。也明白平常的一些垃圾邮件是怎么发送的,利用随机值,发垃圾邮件,他们可能有不被官方拉黑的方法。监控那里的服务器还是很有意思的,能看页面的请求和次数还有自己代码的类啥的,功能很强,使用起来也方便,开启一个服务器,给自己要监控的代码,导入一个坐标,复制一个spring配置就好了。

10.26 瑞吉外卖 DAY1

1.头 所学内容出处

【黑马程序员2022新版SSM框架教程_Spring+SpringMVC+Maven高级+SpringBoot+MyBatisPlus企业实用开发技术】 https://www.bilibili.com/video/BV1Fi4y1S7ix?p=31&share_source=copy_web&vd_source=c8ae4150b2286ee39a13a79bbe12b843

2.所学内容概述

了解软件开发整体介绍

img

img

开发环境的搭建

数据库环境的搭建

课件提供了sql文件,可以直接source 导入mysql中 早就习以为常了

Maven项目创建

也很简单,普通的maven项目,复习导入坐标和yaml文件,因为不是直接创建的springBoot 项目,所以要创建Boot程序入口

后台登录开发

先创建一个实体类和mapper以及service

再封装一个R作为返回的结果类

将登录方法 以及返回值写入controller

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
@Slf4j
@RestController
@RequestMapping("/employee")
public class EmployeeController {
@Autowired
private EmployeeService employeeService;
@PostMapping("/login")
public R<Employee> login(HttpServletRequest request, @RequestBody Employee employee){//接收前端的json数据,这个json数据是在请求体中的
// 1、将页面提交的密码password进行md5加密处理
String password = employee.getPassword();//从前端用户获取到登录时候的密码
password = DigestUtils.md5DigestAsHex(password.getBytes()); //加密
// 2、根据页面提交的用户名username查询数据库
LambdaQueryWrapper<Employee> queryWrapper = new LambdaQueryWrapper<>(); //泛型需要填写Employee
queryWrapper.eq(Employee::getUsername,employee.getUsername()); //eq用lambda::
//在设计数据库的时候我们对username使用了唯一索引,所以这里可以使用getOne方法
Employee emp = employeeService.getOne(queryWrapper);
// 3、如果没有查询到则返回登录失败结果
if (emp == null){
return R.error("用户不存在");
}
// 4、密码比对,如果不一致则返回登录失败结果
if (! emp.getPassword().equals(password)){
return R.error("密码错误");
}
// 5、查看员工状态,如果为已禁用状态,则返回员工已禁用结果
if (emp.getStatus() == 0){
return R.error("用户已被禁用");
}
// 6、登录成功,将员工id存入Session并返回登录成功结果
request.getSession().setAttribute("employee",emp.getId());
//把从数据库中查询到的用户返回出去
return R.success(emp);
}
//员工退出
@PostMapping("logout")
public R<String> logout(HttpServletRequest request){
//清除Session中当前登录员工的id
request.getSession().removeAttribute("employee");
return R.success("退出成功");
}
}

后台系统退出功能

这个比较简单 点击按钮退出到登陆页面就行了

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* 退出功能
* ①在controller中创建对应的处理方法来接受前端的请求,请求方式为post;
* ②清理session中的用户id
* ③返回结果(前端页面会进行跳转到登录页面)
* @return
*/
@PostMapping("/logout")
public R<String> logout(HttpServletRequest request){
//清理session中的用户id
request.getSession().removeAttribute("employee");
return R.success("退出成功");
}

3. BUG点

难点(关键代码或关键配置,BUG截图+解决方案)

之前的登陆功能是有个bug的,像之前web的一个登陆案例,直接输入地址的话,就可以跳过登录页面,达到不登录就能进入需要登录的 页面,之前web是用过滤器的,现在用拦截器解决这个小bug

要先在启动项上面加入@ServletComponentScan注解 识别bean

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
/**
* 检查用户是否已经完成登陆
* filterName过滤器名字
* urlPatterns拦截的请求,这里是拦截所有的请求
*/
@WebFilter(filterName = "LongCheckFilter", urlPatterns = "/*")
@Slf4j
public class LoginCheckFilter implements Filter {
//路径匹配器,支持通配符
public static final AntPathMatcher PATH_MATCHER = new AntPathMatcher();
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
//1、获取本次请求的URI
String requestURI = request.getRequestURI();
//定义不需要处理的请求路径 比如静态资源(静态页面我们不需要拦截,因为此时的静态页面是没有数据的)
String[] urls = new String[]{
"/employee/login",
"/employee/logout",
"/backend/**",
"/front/**"
};
log.info("拦截到的请求:{}",requestURI);
//2、判断本次请求是否需要处理
boolean check = check(urls, requestURI);
//3、如果不需要处理,则直接放行
if (check){
//对请求进行放行
filterChain.doFilter(request,response);
return;
}
//4、判断登录状态,如果已登录,则直接放行
Object employee = request.getSession().getAttribute("employee"); //用户登录状态
if (employee != null){
log.info("用户已登录,用户id为:{}",employee);
//对请求进行放行
filterChain.doFilter(request,response);
return;
}
log.info("用户未登录");
//5、如果未登录则返回未登录结果,通过输出流方式向客户端页面响应数据,具体响应什么数据,看前端的需求,然后前端会根据登陆状态做页面跳转
response.getWriter().write(JSON.toJSONString(R.error("NOTLOGIN")));
}

public boolean check(String[] urls, String requestURI){
for (String url: urls){
boolean match = PATH_MATCHER.match(url, requestURI);
if (match){
return true;
}
}
return false;
}
}

4.扩展学习部分

5.总结

刚进入瑞吉外卖,下载了一些资料,没找到老师的官方的ppt文档,就CSDN去搜的,第一天的任务不是很难,主要是帮助回看一下springboot的部分,算是小复习,就做了一个登录和退出,还有个登录的小BUG,基本都是后台的代码,前端的一些功能都做好了,后端加bean,调用一下响应和请求就好了,比较基础的还是。学习方法就是看老师过一遍功能如何实现,如何测试,然后就自己试着去敲,慢慢做出来,这样学,进度可能会有些慢,但是能搞清楚每一块是干嘛的,每个注解和类的作用和功能。