CGB2102 京淘项目

1. 缓存控制

1.1 业务说明

用户有一个缓存的集合 static Map<k:v> key=id号 value=User对象 根据id将User对象进行了缓存
要求:当用户第二次根据Id查询用户时,如果缓存中有数据,则直接返回!!!!

1.2 业务分析

1).首选用AOP方式实现
2).通知方法: 使用环绕通知
3).切入点表达式: execution(........)

1.3 AOP切面实现

package com.jt.aop;

import com.jt.pojo.User;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

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

@Component
@Aspect
public class SpringAOP {

    private static Map<Integer,User> map = new HashMap();
    /**
     * 需求: 用户第一次查询走目标方法
     *       用户第二次查询走缓存  不执行目标方法
     * 判断依据: 如何判断用户是否为第一次查询?
     *       通过map集合进行判断 有数据 证明不是第一次查询
     * 执行步骤:
     *       1.获取用户查询的参数
     *       2.判断map集合中是否有该数据.
     *       true:  从map集合中get之后返回
     *       false: 执行目标方法,之后将user对象保存到Map中
     */

    //切入点表达式: 拦截service包中的所有方法
    @Around("execution(* com.jt.service..*.*(..))")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        Object result = null;
        //1.获取目标对象的参数
        Object[] args = joinPoint.getArgs();
        //2.强制类型转化为对象
        User user = (User) args[0];
        //3.判断map集合中是否有该数据  user的Id是唯一标识
        int id = user.getId();
        if(map.containsKey(id)){
            //map中有数据
            System.out.println("AOP缓存执行");
            //将获取的数据返回
            return map.get(id);
        }else{
            //map中没有数据 执行目标方法
            result = joinPoint.proceed();
            //将user对象保存到Map中
            map.put(id, user);
            System.out.println("AOP执行目标方法");
        }
        return result;
    }
}

2.SpringBoot

2.1 SpringBoot介绍

Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。通过这种方式,Spring Boot致力于在蓬勃发展的快速应用开发领域(rapid application development)成为领导者。

作用: SpringBoot的推出 让程序员更加专注于业务处理, SpringBoot是学习微服务框架基石
Spring 和SpringBoot关系 :
SpringBoot是Spring的工具API框架

2.2 SpringBoot入门案例

2.2.1 安装SpringBoot插件

1).IDEA破解版本,自带SpringBoot插件 所以无需安装
2).IDEA社区版本.需要手动安装一个SpringBoot插件.
在这里插入图片描述

2.2.2 创建SpringBoot项目

1).选择插件
在这里插入图片描述
2).编辑项目名称
在这里插入图片描述
3).勾选依赖项
在这里插入图片描述
4).初始化项目
在这里插入图片描述
5).执行main方法检查运行是否正常
在这里插入图片描述
如图所示表示程序正常.
在这里插入图片描述

2.2.3 如果项目创建出问题

1).检查系统环境变量JDK
在这里插入图片描述
2).检查maven配置
在这里插入图片描述

2.3 关于SpringBoot项目说明

2.3.1 关于POM.xml文件说明

<!--1.parent标签  父级工程
			SpringBoot将现有主流的框架都进行了整合,
			在内部完成了jar包的依赖的配置.如果用户需要,则只添加某些核心包
			那么所有的依赖都会按照规则自动的下载.
	-->
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.4.5</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>

2.3.2 依赖配置项

<!--Springboot通过启动项的方法的 进行jar包文件的加载.
			同时这些功能中的配置项 SpringBoot有些也会自动的完成.
			无特殊的要求 无需手动的配置.
			开箱即用的思想!!!!
		-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

2.3.3 build标签

<!--
		关于build标签说明
		1.build标签它是maven工程的要求.
		2.作用: 完成项目的打包/发布等一系列的功能.
		3.该标签的使用是SpringBoot必须的,如果没有该标签则项目无法使用jar包运行
	-->
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

2.4 SpringBoot Maven操作

2.4.1 项目打包

在这里插入图片描述

2.4.2 java命令运行项目

1.将jar包文件放置到指定的目录下.
在这里插入图片描述
2.dos命令
1.cd 切换目录
2.dir 查看当前目录结构
3.cls 清屏

3.java命令
在这里插入图片描述
项目关闭:
1.直接将dos窗口关闭
2. ctrl + c 万能的关闭指令

2.5 关于jar包依赖传递性

2.5.1 问题描述

问题: 当引入webjar包时, 其他jar包文件如何依赖的?
在这里插入图片描述

2.5.2 maven jar包依赖的传递性

例子:
1. A.jar ----> B.jar
2. B.jar -----> C.jar

maven原理说明:
1.当maven解析pom.xml文件时,会根据maven坐标查找指定的jar包文件. 在这里插入图片描述
2.当jar包加载完成之后,由于该项目也是maven工程,所以maven工具会解析该项目的pom.xml文件
根据POM.xml文件 再次加载依赖包 直到所有的jar包依赖加载完成
在这里插入图片描述

2.5.3 maven 如何保证jar包依赖安全性(了解)

算法: SHA1
SHA-1(英语:Secure Hash Algorithm 1,中文名:安全散列算法1)是一种密码散列函数,美国国家安全局设计,并由美国国家标准技术研究所(NIST)发布为联邦数据处理标准(FIPS)。SHA-1可以生成一个被称为消息摘要的160位(20字节)散列值,散列值通常的呈现形式为40个十六进制数

关于hash问题:
在这里插入图片描述

核心原理说明:
判断传递前后的sha1算法是否相同,如果相同则标识传输正常,
如果不同,则文件有问题.
在这里插入图片描述

3. SpringBoot学习

3.1 配置文件说明

3.1.1 关于properties文件说明

说明: 虽然pro文件是SpringBoot默认配置文件.但是其中编码格式比较繁琐,不便于查看.所以在项目中一般使用YML文件.
在这里插入图片描述

3.1.2 关于yml文件说明

在这里插入图片描述

3.2 @Value属性赋值

3.2.1 springBoot为属性赋值

在YML配置文件中编辑key=value结构,之后利用注解为属性赋值.

3.2.2 编辑YML配置文件

#YML文件语法
## 1.YML数据结构k-v结构
## 2.k与v 需要使用 :"空格" 连接
## 3.YMl配置文件有父子级关系 所以注意缩进项的位置
server:
  port: 8090    #配置端口
  servlet:      #web项目发布路径
    context-path: /  #/表示根目录

#定义dept属性值 YML文件默认支持UTF-8
dept:
  id: 100
  name: 财务部

3.2.3 为Dept对象赋值

在这里插入图片描述

3.2.4 编辑springBoot测试类

在这里插入图片描述

注意事项: 以后写代码都必须写到主启动类的同包及子包中

3.3 利用properties文件为属性赋值

3.3.1 编辑pro文件

在这里插入图片描述

3.3.2 实现自动赋值

在这里插入图片描述

3.4 lombok插件

3.4.1 安装插件

在这里插入图片描述

3.4.2 添加jar包

<!--引入插件lombok 自动的set/get/构造方法插件  -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>	

3.4.3 lombok注解使用

在这里插入图片描述

1.SpringBoot 用法

1.1 环境切换

1.1.1 业务需求

软件一般会在多个不同的环境中运行. 开发阶段有一个dev环境.开发完成会进行测试.则会有测试环境.最终项目部署到用户的服务中 生产环境.
问题: 如果每次切换环境,如果都需要手动的修改配置文件,则造成诸多的不便.
需求: 如果能够简化环境切换带来的影响.

1.1.2 多环境编辑

要求: 如果采用多环境测试,则要求每个环境中的数据项都应该保持一致. 否则缺失可能导致项目启动异常.
多环境配置: 关键语法"---" 环境分割
定义环境名称:

spring:
  config:
    activate:
      on-profile: prod

默认环境名称:

#默认环境选项
spring:
  profiles:
    #默认环境配置名称
    active: test

全部配置:

#默认环境选项
spring:
  profiles:
    #默认环境配置名称
    active: test

#环境分割
---
#YML文件语法
## 1.YML数据结构k-v结构
## 2.k与v 需要使用 :"空格" 连接
## 3.YMl配置文件有父子级关系 所以注意缩进项的位置
spring:
  config:
    activate:
      on-profile: prod
server:
  port: 80    #配置端口
  servlet:      #web项目发布路径
    context-path: /  #/表示根目录

#定义dept属性值 YML文件默认支持UTF-8
dept:
  id: 100
  name: 财务部

#环境分割线
---

# 每个环境都应该有自己的名称
spring:
  config:
    activate:
      on-profile: test
server:
  port: 8080    #配置端口
  servlet:      #web项目发布路径
    context-path: /  #/表示根目录

#定义dept属性值 YML文件默认支持UTF-8
dept:
  id: 100
  name: 集團本部

1.2 热部署

1.2.1 需求说明

在开发阶段每次修改完源码都要重启服务器,程序才能生效. 能否让程序自动的完成监控,重启服务器.

1.2.2 引入jar包

		<!--支持热部署 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
		</dependency>

1.2.3 配置IDEA环境

组合键: ctrl + shift + alt + / 或者 ctrl + alt + a
在这里插入图片描述
2.勾选自动编译
在这里插入图片描述

3).启动IDEA自动编译
在这里插入图片描述

2. SpringBoot整合Mybatis

2.1 导入数据库

2.1.1 安装SqlYog

1).解压安装包
在这里插入图片描述
2).运行sql文件
根据资料中的破解码 完成破解 输入用户名和密码 点解链接
在这里插入图片描述
3).正确的展现
在这里插入图片描述

2.1.2 导入数据库

1).新建数据库
在这里插入图片描述
2).导入数据
在这里插入图片描述

2.2 创建SpringBoot项目

2.2.1 创建项目

在这里插入图片描述

2.2.2 导入POM.xml文件

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.jt</groupId>
	<artifactId>springboot_demo_2</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>springboot_demo_2</name>
	<description>Demo project for Spring Boot</description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.4.5</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	
	<properties>
		<java.version>1.8</java.version>
	</properties>
	<dependencies>

		<!--spring-boot-starter 启动项  只要导入jar包 则可以完成自动的配置
			暂时没有数据库的链接
		-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-jdbc</artifactId>
		</dependency>

		<!--引入数据库驱动 -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<scope>runtime</scope>
		</dependency>

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

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<scope>runtime</scope>
			<optional>true</optional>
		</dependency>

		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<configuration>
					<excludes>
						<exclude>
							<groupId>org.projectlombok</groupId>
							<artifactId>lombok</artifactId>
						</exclude>
					</excludes>
				</configuration>
			</plugin>
		</plugins>
	</build>

</project>

2.2.3 Mavenjar包作用范围

1.test范围是指测试范围有效,在编译和打包时都不会使用这个依赖
2.compile范围是指编译范围内有效,在编译和打包时都会将依赖存储进去
3.provided依赖,在编译和测试过程中有效,最后生成的war包时不会加入 例如:
servlet-api,因为servlet-api tomcat服务器已经存在了,如果再打包会冲突
4.runtime在运行时候依赖,在编译时候不依赖
默认依赖范围是compile

2.2.4 数据源配置

#SpringBoot 开箱即用
spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/jtadmin?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true
    username: root
    password: root

关于参数说明:
1.serverTimezone=GMT%2B8 %2B "+" 号 新版本的驱动要求必须配置时区
2.&useUnicode=true&characterEncoding=utf8 使用Unicode编码 要求字符UTF-8编码
3.&autoReconnect=true 是否自动重连.
4.&allowMultiQueries=true 是否允许批量操作 同时执行多个sql!

2.2.5 Mybatis相关配置

#SpringBoot整合Mybatis配置
mybatis:
  #定义别名包
  type-aliases-package: com.jt.pojo
  mapper-locations: classpath:/mybatis/mappers/*.xml
  #开启驼峰映射
  configuration:
    map-underscore-to-camel-case: true

2.2.6 编辑Mapper接口/映射文件

在这里插入图片描述

2.2.7 将Mapper接口交给容器管理

在这里插入图片描述

2.2.8 Mybatis测试

编辑测试类,注意包路径的写法.

@SpringBootTest
public class TestSpringBoot {

    @Autowired
    private DemoUserMapper userMapper;

    @Test
    public void testFindAll(){

        System.out.println(userMapper.findAll());
    }

}

2.3 关于绑定异常

2.3.1 报错说明

绑定异常: mapper的接口与xml的映射文件之间绑定异常.

	org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.jt.mapper.DemoUserMapper.findAll

代码排查:
1).检查Mapper接口的路径
在这里插入图片描述
2).检查mapper.xml引入过程
在这里插入图片描述
3).检查mapper.xml映射文件
在这里插入图片描述
4).检查方法名称
检查mapper接口方法名称,与标签的ID是否一致.
在这里插入图片描述
5). 清空/重新编译项目
1).clean项目
在这里插入图片描述
2).build项目
在这里插入图片描述
6).将我的代码全部复制 测试一下. 只粘贴pom.xml 和src文件.

7).检查目录层级,是否使用/进行分割.

2.3.2 关于数据库密码问题

默认的数据库密码 root/root
创建数据库密码时 以数字0开头 012345
问题解释: 数据密码在进行编译时. 如果遇到首字母为0则自动删除.
解决方案: 如果以特殊数字开头 则 "012345" 引号包裹

2.4 关于Mapper接口代理对象创建流程

说明: 当springBoot启动时,加载pom.xml文件.实例化对象的流程图.
在这里插入图片描述

2.5 Mybatis入库练习

2.5.1 编辑Mapper接口

在这里插入图片描述

2.5.2 编辑Mapper.xml 文件

<!--
		完成用户入库操作 id="与方法名称保持一致"
		sql结束时不需要添加;号 在Mysql数据库中执行;号没有问题,
		但是如果在Oracle中执行则必然报错.
	-->
	<insert id="insertUser">
		insert into demo_user(id,name,age,sex)
			values(null,#{name},#{age},#{sex})
	</insert>

2.5.3 业务调用

 	//新增用户
    @Test
    public void testInsert(){
        DemoUser user = new DemoUser();
        user.setId(null).setName("mybatis信息").setAge(18).setSex("男");
        userMapper.insertUser(user);
    }

2.6 Mybatis更新练习

2.6.1 Mapper接口

在这里插入图片描述

2.6.2 编辑Mapper.xml映射文件

在mapper.xml文件中 实现更新操作
在这里插入图片描述

2.6.3 编辑测试类

在这里插入图片描述

1.MybatisPlus

1.1 MP介绍

MyBatis-Plus (opens new window)(简称 MP)是一个 MyBatis (opens new window)的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。

1.2 MP的特点

1.无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
2.损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
3.强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题
支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作
支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )
内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用
内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
分页插件支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库
内置性能分析插件:可输出 Sql 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作

1.3 MybatisPlus入门案例

1.3.1 导入jar包

		<!--spring整合mybatis-plus -->
		<dependency>
			<groupId>com.baomidou</groupId>
			<artifactId>mybatis-plus-boot-starter</artifactId>
			<version>3.4.2</version>
		</dependency>

1.3.2 编辑POJO对象

说明:MP要求以面向对象的方式操作数据库.其中对象与表 属性与字段必须映射!!!
实现方式: 利用注解进行绑定.
在这里插入图片描述

1.3.3 编辑Mapper接口

在这里插入图片描述

1.3.4 编译YML配置文件

说明: MP增强了Mybatis, MP内部包含了Mybatis 所以将Mybatis的包删除,否则内部jar包异常
修改YML配置文件:
修改mybatis名称为mybatis-plus
在这里插入图片描述

1.3.5 编辑测试案例

利用userMapper 实现以对象的方式操作数据库
在这里插入图片描述

1.4 MP核心原理

1.4.1 需求

说明: 之前操作数据库采用sql(面向过程的语言)方法进行编辑. 但是如果所有的单表操作都由程序员完成.则开发效率低. 能否开发一种机制可以实现以面向对象的方式操作数据库.

1.4.2 原理说明

1.对象与数据表进行关联 @TableName
2.MP采用BaseMapper的方式 将公共的接口方法进行了抽取. 采用泛型T的方式进行约束
3.MP将用户操作的对象在底层自动的转化为Sql语句!!!

1.4.3 对象转化Sql原理

对象方法: userMapper.insert(User对象);
Sql语句: insert into demo_user(id,name.....) value(100,xxx...)
步骤:
1.根据userMapper找到对应的class类型
2.根据userMapper的类型通过反射机制获取父级接口类型BaseMapper
3.找到BaseMapper类型之后,获取泛型类型 User.class
4.获取User.class之后,获取class的注解名@TableName注解.获取注解名称. 至此表名获取成功
5.根据User.class获取其中的属性名称.之后获取属性上的@TableField 获取字段名称.
6.之后利用对象的get方法获取属性的值最终实现了Sql语句的拼接过程.
7.MP将整理好的Sql交给Mybatis(jdbc)去处理. 最终实现了以对象的方式操作数据库.

1.5 MP常规操作

1.5.1 添加日志打印

server:
  port: 8090

#SpringBoot 开箱即用
spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/jtadmin?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true
    username: root
    #检查密码是否正确
    password: root

#SpringBoot整合MybatisPlus配置
mybatis-plus:
  #定义别名包
  type-aliases-package: com.jt.pojo
  mapper-locations: classpath:/mappers/*.xml
  #开启驼峰映射
  configuration:
    map-underscore-to-camel-case: true

#添加MP日志  打印执行的sql
logging:
  level:
    com.jt.mapper: debug

1.5.2 测试入库操作

package com.jt;

import com.jt.mapper.DemoUserMapper;
import com.jt.pojo.DemoUser;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class TestMP {

    @Autowired
    private DemoUserMapper userMapper;

    @Test
    public void insert(){
        DemoUser user = new DemoUser();
        user.setName("MP测试").setSex("男").setAge(19);
        userMapper.insert(user);
    }

}

1.5.2 测试更新操作

 //测试更新操作 修改id=231的数据 name="中午吃什么" age=18
    //原则: 根据对象中不为null的属性当做set条件. set name="xxx"
    //      如果ById的操作,则Id必须赋值 并且ID当做唯一where条件
    @Test
    public void updateById(){
        DemoUser user = new DemoUser();
        user.setName("中午吃什么").setAge(18).setId(231);
        userMapper.updateById(user);
    }

1.5 切换Maven工具

1.5.1 关于Maven说明

程序员操守:
1.Maven不要放到C的系统盘中 不要有中文目录 空格
2.在D盘中复制maven工具 在这里插入图片描述
3).配置settings文件
3.1 切换 自己的本地库
${user.home}/.m5/repository

		 3.2 切换私服镜像
	<mirror>
	<id>aliyun</id>
	<name>aliyun for maven</name>
	<mirrorOf>*</mirrorOf>
	<url>https://maven.aliyun.com/repository/public</url>
   </mirror>
			 
 3.3 切换JDK版本
	 <profile>
   <id>jdk-1.8</id>
   <activation>
	<activeByDefault>true</activeByDefault>
      <jdk>1.8</jdk>
   </activation>
   <properties>
	   <maven.compiler.source>1.8</maven.compiler.source>
	   <maven.compiler.target>1.8</maven.compiler.target>
	   <maven.compiler.compilerVersion>
        1.8
       </maven.compiler.compilerVersion>
	 </properties>
   </profile>	 

1.5.2 配置IDEA

在这里插入图片描述

1.7 MP常规操作

1.7.1 根据对象查询

    /**
     * 1.查询id=21的用户  根据ID查询数据   1条记录
     * 2.查询name="白骨精" sex=女 的用户   List
     * 知识点:
     *      1.queryWrapper  条件构造器  拼接where条件的.
     *      原则: 根据对象中不为null的属性拼接where条件
     */
    @Test
    public void testSelect(){
        //1.根据ID查询
        DemoUser user = userMapper.selectById(21);
        System.out.println(user);
        //2.根据属性查询
        DemoUser user2 = new DemoUser();
        user2.setName("白骨精").setSex("女");
        QueryWrapper<DemoUser> queryWrapper = new QueryWrapper<>(user2);
        List<DemoUser> userList = userMapper.selectList(queryWrapper);
        System.out.println(userList);
    }

1.7.2 条件构造器查询

说明: 如果查询条件中有特殊关系符,则使用特殊转义字符查询 代码如下.

/**
     * 需求: 查询age>18岁  并且性别为女的用户
     * Sql: select * from demo_user where age > 18 and sex="女"
     * 特殊字符:  > gt   < lt   = eq
     *           >= ge  <= le
     * 默认链接符: and
     *
     * */
    @Test
    public void testSelect2(){
        QueryWrapper<DemoUser> queryWrapper = new QueryWrapper<>();
        queryWrapper.gt("age", 18)
                    .eq("sex", "女");
        List<DemoUser> userList = userMapper.selectList(queryWrapper);
        System.out.println(userList);
    }

1.7.3 关键字like查询

 /**
     * 练习like关键字
     *      查询name中包含"精"字的数据
     * Sql: like "%精%"
     *      以精开头    like "精%"   likeRight
     *      以精结尾    like "%精"   likeleft
      */
    @Test
    public void testSelect3(){
        QueryWrapper<DemoUser> queryWrapper = new QueryWrapper<>();
        queryWrapper.like("name", "精");
        List<DemoUser> userList = userMapper.selectList(queryWrapper);
        System.out.println(userList);
    }

1.7.4 关键字OrderBy

 /**
     * 查询sex=男的数据,以id倒序排列
     * Sql: select * from demo_user where sex='男' order by id desc
     */
    @Test
    public void testSelect4(){
        QueryWrapper<DemoUser> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("sex", "男")
                    .orderByDesc("id");
        List<DemoUser> userList = userMapper.selectList(queryWrapper);
        System.out.println(userList);
    }

1.7.5 In关键字

/**
     * 5.查询id= 1,3,5,6,7的用户
     * Sql: select * from demo_user where id in (xxx,xx,xx)
     */
    @Test
    public void testSelect5(){
        //数组使用包装类型
        Integer[] ids = {1,3,5,6,7};
        //需要将数组转化为集合
        List idList = Arrays.asList(ids);
        QueryWrapper<DemoUser> queryWrapper = new QueryWrapper<>();
        //queryWrapper.in("id", idList);    //根据list查询 list集合功能丰富
        queryWrapper.in("id", ids); //数组必须包装类型
        List<DemoUser> userList = userMapper.selectList(queryWrapper);
        System.out.println(userList);
    }

1.7.6 带判断条件的查询

 /**
     * 需求: 如果根据name属性和age属性查询数据. 有时某个数据可能为null,
     *      要求动态查询!!!
     *      where name=xxx age>xxxx
     * 伪Sql: select * from demo_user
     *              where name!=null name=xxx and age!=null age>xxx
     * condition: 内部编辑一个判断的条件
     *                      如果返回值结果为true 则拼接该字段.
     *                      如果为false 则不拼接该字段
     * StringUtils.hasLength(name) 判断字符串是否有效
     */
    @Test
    public void testSelect6(){
        QueryWrapper<DemoUser> queryWrapper = new QueryWrapper<>();
        String name = "";
        int age = 18;
        queryWrapper.eq(StringUtils.hasLength(name),"name",name)
                    .gt(age>0, "age",age);
        List<DemoUser> userList = userMapper.selectList(queryWrapper);
        System.out.println(userList);
    }

1.7.7 查询第一列数据

/**
     * 需求: 只想查询第一列数据   selectObjs
     * 说明: queryWrapper=null 不需要where条件
     * selectObjs:
     *      1.一般根据条件查询Id的值,查询之后为后续的sql提供数据支持
     *      2. 有时用户只需要查询ID的值,并不需要其他数据项时 使用objs.
    */
    @Test
    public void testSelect7(){
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("sex","男");
        List objs = userMapper.selectObjs(queryWrapper);
        System.out.println(objs);
    }

1.7.8 查询指定字段的数据

/**
     * 需求: 想查询name/sex字段
     *  queryWrapper.select("name","sex"); 挑选执行字段
     */
    @Test
    public void testSelect8(){
        QueryWrapper<DemoUser> queryWrapper = new QueryWrapper();
        queryWrapper.select("name","sex");
        List objs = userMapper.selectList(queryWrapper);
        System.out.println(objs);
    }

1.7.9 更新数据

 /**
     * 更新数据
     *      将name="中午吃什么" 改为name="晚上吃什么"
     *      性别: 改为 其他
     * Sql:
     *      update demo_user set name="xxx",sex="其他"
     *          where name="xxxx"
     * 参数说明:
     *      1.entity 实体对象  需要修改的数据进行封装
     *      2.updateWrapper 条件构造器
     */
    @Test
    public void testSelect10(){
        DemoUser user = new DemoUser();
        user.setName("晚上吃什么").setSex("其他");
        UpdateWrapper updateWrapper = new UpdateWrapper();
        updateWrapper.eq("name", "中午吃什么");
        userMapper.update(user,updateWrapper);
    }

解决自动注入警告问题

在这里插入图片描述

作业

1.预习SpringMVC调用流程
2.复习Servlet机制.
3.MybatisPlus 熟练使用

1.SpringMVC

1.1 SpringMVC框架介绍

Spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面。Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块。使用 Spring 可插入的 MVC 架构,从而在使用Spring进行WEB开发时,可以选择使用Spring的Spring MVC框架或集成其他MVC开发框架,如Struts1(现在一般不用),Struts 2(一般老项目使用)等等。
小结: Spring内部整合SpringMVC(web的包)

1.2 SpringMVC入门案例

1.2.1 创建项目

在这里插入图片描述

1.2.2 添加依赖项

1).添加热部署/lombok包
在这里插入图片描述

1.2.3 检查pom.xml文件

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.jt</groupId>
	<artifactId>springboot_demo_3</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>springboot_demo_3</name>
	<description>Demo project for Spring Boot</description>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.4.5</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<properties>
		<java.version>1.8</java.version>
	</properties>
	<dependencies>
		<!--thymeleaf导入模版工具类-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>

		<!--SpringMVCjar包文件-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<!--热部署工具-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<scope>runtime</scope>
			<optional>true</optional>
		</dependency>
		<!--lombok插件-->
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>

		<!--测试包-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<!--负责项目打包部署-->
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<configuration>
					<excludes>
						<exclude>
							<groupId>org.projectlombok</groupId>
							<artifactId>lombok</artifactId>
						</exclude>
					</excludes>
				</configuration>
			</plugin>
		</plugins>
	</build>

</project>

1.2.4 编辑YML配置文件

#配置服务端口
server:
  port: 8090

#配置模版工具类
spring:
  thymeleaf:
    #设置页面前缀
    prefix: classpath:/templates/
    #设置页面后缀
    suffix: .html
    #是否使用缓存
    cache: false

1.2.5 编辑Html页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>SpringMVC入门案例</title>
</head>
<body>
    <h1>Hello SpringMVC</h1>
</body>
</html>

1.2.6 默认页面跳转机制

说明: SpringMVC项目启动时默认设置一个欢迎页面 并且名称必须为index.
在这里插入图片描述
页面效果 如图所示
在这里插入图片描述

1.3 @RequestMapping注解测试

说明: 使用@RequestMapping注解拦截用户请求 实现业务调用

1.3.1 编辑HelloController

@Controller //1.将该类交给Spring容器管理 2.同时开启Spring mvc机制
public class HelloController {
    /**
     * 需求: http://localhost:8090/hello 访问hello.html
     * 实现步骤:
     *      1.拦截用户请求 @RequestMapping("/hello")
     *      2.String 类型的返回值 表示返回页面名称
     *      3.根据YML配置文件中的内容 动态的拼接前缀和后缀 形成页面唯一路径
     */

    @RequestMapping("/hello")
    public String hello(){
        //动态的拼接前缀+后缀
        //classpath:/templates/hello.html
        return "hello";
    }
}

1.3.2 页面请求效果

说明: 根据http://localhost:8090/hello测试网站访问是否成功
在这里插入图片描述

1.4 实现数据传递

1.4.1 导入头标前

	<!DOCTYPE html>
	<!--导入模板标签!!!!!-->
	<html lang="en" xmlns:th="http://www.thymeleaf.org">

1.4.2 编辑UserController

package com.jt.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class UserController {

    /**
     *  mvc底层数据传输原则
     *  url: http://localhost:8090/user
     *  ModelAndView:
     *      1.model 封装数据的
     *      2.View  封装视图页面的
     */
    @RequestMapping("/user")
    public ModelAndView toUser(){
        ModelAndView modelAndView = new ModelAndView();
        //封装数据
        modelAndView.addObject("id", 1001);
        modelAndView.addObject("name", "安琪拉");
        //封装页面数据
        modelAndView.setViewName("user");
        return modelAndView;
    }

}

1.4.3 页面取值

<!DOCTYPE html>
<!--导入模板标签!!!!!-->
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>SpringMVC测试案例</title>
</head>
<body>
    <h1>用户测试代码</h1>
    <!--从服务器中获取数据 表达式  ${从服务器中的key}-->
    <h3 th:text="${id}"></h3>
    <h3 th:text="${name}"></h3>
</body>
</html>

1.4 SpringMVC 原理说明(!!!)

1.4.0 Servlet作用

说明: servlet是浏览器与服务器(tomcat) 进行交互的一种机制.
核心对象: 1.Request 包含了用户的所有的请求相关信息(参数..协议..地址..)
2.Response 包含了服务器相关的信息(服务器地址,返回的数据)

1.4.1 重要组件

1).前端控制器 DispatcherServlet(内部核心机制) 接收用户所有请求
2).处理器映射器 HandlerMapping 查找用户的请求与业务处理的映射
3).处理器适配器HandlerAdapter 在众多处理器中挑选合适的处理器去执行业务.
4).视图解析器ViewResolver 实现页面的路径的拼接.

1.4.2 SpringMVC调用流程图

在这里插入图片描述

1.4.3 SpringMVC调用步骤

1.当用户发起请求时,被SpringMVC框架中的前端控制器拦截.
2.由于前端控制器,并不清楚哪个方法与请求对应,所以查询处理器映射器.
3.当tomcat服务器启动,则处理器映射器会加载所有的@RequestMapping注解,将其中的路径与方法进行绑定. Map</请求路径,包名.类名.方法名(参数)>,将查找到的方法信息回传给前端控制器 进行后续调用.
4.秉承着松耦合的思想,前端控制器将查询得到的方法, 请求处理器适配器(mvc针对不同的配置文件有专门的处理器(运行程序的机制))挑选合适的处理器去执行(程序内置的规则 无需人为干预)
5.当挑选合适的处理器之后,程序开始真正的执行业务方法. Controller-Service-Mapper(Dao),执行业务. 当业务执行成功之后.返回统一的ModelAndView对象.
其中包含2部分数据 1-Model(服务器数据) 2.View(页面逻辑名称)
6.当前端控制器获取ModelAndView对象之后,交给视图解析器 解析View对象的逻辑名称. 动态的拼接前缀 + 页面逻辑名称 + 后缀. 最终形成了用户展现页面的全路径.
7.将Model数据填充到页面中的过程,叫做视图渲染. 渲染之后,将数据交给前端控制器处理.
8.将得到的完整页面 响应给用户进行展现.

1.5 简单参数传递

1.5.1 服务器向页面传值

 //简化数据传递
    @RequestMapping("/user")
    public String toUser(Model model){
        //将数据通过model进行传递
        model.addAttribute("id", 1003);
        model.addAttribute("name", "SpringMVC");
        return "user";
    }

1.5.2 编辑提交数据的页面

<tr>
                <td>ID:</td>
                <!--
                     id:标签的唯一标识 不能重复
                     name: 数据传递的必备要素.  不能省略
                  -->
                <td><input id="id" name="id" type="text"/></td>
            </tr>
            <tr>
                <td>姓名:</td>
                <td><input id="name" name="name" type="text"/></td>
            </tr>

1.5.3 Request 对象接收参数

说明: 当用户点击提交按钮时,将数据进行传递. 所以必须编辑Controller的方法进行接收
参数说明: 利用request对象进行参数的接收.

 /**
     * 请求路径: http://localhost:8090/addUser
     * 请求参数: id: 100  name: 张三
     * request/response对象说明  只要用户调用就会自动的赋值
     * servlet缺点:  接收的参数都是String类型
     * @param model
     * @return
     */
    @RequestMapping("/addUser")
    public String addUser(HttpServletRequest request){
        //利用工具API进行类型转化
        Integer id = Integer.parseInt(request.getParameter("id"));
        String name = request.getParameter("name");
        System.out.println("参数:"+id+":"+name);
        return "success";
    }

1.5.4 利用SpringMVC为属性赋值

在这里插入图片描述

2. SpringMVC 高级用法

2.1 @RequestParam

2.1.1 需求说明

有时用户的数据可能为null,如果后端服务器数据有特殊的要求,
要求:
1.数据为必填项
2.如果没有填写数据,可以为其设定默认值.
通过@RequestParam注解实现.

2.1.2 编辑UserController

说明: 图中演示了@RequestParam的注解用法
在这里插入图片描述

2.2 同名提交问题

2.2.1 业务描述

SpringMVC中对于页面要求应该保证name属性尽可能唯一.

	<input id="id" name="id" type="text"/></td>
	<input id="name" name="name" type="text"/>
	<td>
       <input  name="hobbys" type="checkbox" value="敲代码"/>敲代码
       <input  name="hobbys" type="checkbox" value="敲键盘"/>敲键盘
       <input  name="hobbys" type="checkbox" value="敲主机"/>敲主机
  	</td>

但是如果遇到复选框操作时 重名问题将不能避免,使用如下操作优化.

2.2.2 数据接收

在这里插入图片描述

2.3 对象的方式接收参数

2.3.1 需求说明

说明: 如果有大量的页面的提交数据,如果采用单独的参数接收,必然导致Controller方法结构混乱,不便于理解.所以采用对象的方式封装.

2.3.2 封装User对象

//POJO实体对象中 "必须"  使用包装类型
//规则说明:  1.基本类型有默认值  包装类型默认值为null
//          2. 基本类型中没有多余的方法 对后续代码取值有问题
@Data
@Accessors(chain = true)    //几乎不用构造方法赋值
public class User {
    //页面name属性 id/name/hobbys
    private Integer id;
    private String name;
    private String[] hobbys;
}

2.3.3 编辑UserController

实现以对象的方式接收参数
在这里插入图片描述

2.4 为对象的引用赋值

2.4.1 业务需求

说明: 有时可能会遇到 name属性重复的问题. 由于业务需要不得不写一个重复的名称.那么这时采用对象的引入赋值.

2.4.2 封装Dog对象

在这里插入图片描述

2.4.3 对象引用

说明: 为了实现数据封装,必须将对象进行嵌套(引用)
在这里插入图片描述

2.4.4 编辑页面

说明: 通过对象.的方式 封装所属关系.
在这里插入图片描述

2.4.5 编辑Controller

在这里插入图片描述

3 作业

  1. 将SSM框架 试着整合到一起
  2. 复习Spring/SpringMVC/Mybatis用法 熟练掌握.

1.SpringMVC

1.1重定向和转发

1.1.1 转发

概念: 由服务器内部进行页面的跳转.
说明: 一般情况下 SpringMVC内部 以转化为主.
在这里插入图片描述

1.1.2 重定向

说明: 当用户发起请求时,由服务器返回有效的网址信息.之后由用户再次发起请求的结构.
在这里插入图片描述

1.1.3 转发练习

/**
     * 测试转化和重定向
     * 1.准备一个请求 findUser请求.
     * 2.要求通用转发到 findDog请求中.
     * 3.关键字   forward: 转发的是一个请求.....
     * 4.特点:
     *      1.转发时 会携带用户提交的数据.
     * 5.转发的意义:
     *      如果直接转向到页面中,如果页面需要额外的参数处理,则没有执行.
     *      如果在该方法中添加业务处理,则方法的耦合性高.不方便后续维护
     *      所以方法应该尽可能松耦合
     */
    @RequestMapping("/findUser")
    public String findUser(String name){

        //return 本身就是一个转发
        //return "user1";
        //return "dog"; 页面耦合性高
        return "forward:/findDog";
    }

    //需要将name属性返回给页面
    @RequestMapping("/findDog")
    public String findDog(String name,Model model){
        System.out.println("动态获取name属性值:"+name);
        model.addAttribute("name",name+"旺旺旺");
        return "dog";
    }

1.1.4 重定向练习

 /**
     * 测试转化和重定向
     * 1.准备一个请求 findUser请求.
     * 2.要求通用转发到 findDog请求中.
     * 
     * 3.关键字   forward: 转发的是一个请求.....
     *           redirect: 多次请求多次响应
     * 4.特点:
     *      1.转发时 会携带用户提交的数据.
     *      2.转发时 用户浏览器的地址不会发生改变.
     *      3.重定向时  由于是多次请求,所以不会携带用户的数据
     *      4.重定向时  由于是多次请求,所以用户的浏览器的地址会发生变化
     *
     * 5.实际意义: 实现了方法内部的松耦合
     * 6.什么时候使用转发/什么时候使用重定向
     *   1.如果需要携带参数 使用转发
     *   2.如果一个业务已经完成需要一个新的开始 则使用重定向
     */
    @RequestMapping("/findUser")
    public String findUser(String name){

        //return 本身就是一个转发
        //return "user1";
        //return "dog"; 页面耦合性高
        //return "forward:/findDog";   转发到findDog请求
        return "redirect:/findDog";    //重定向到findDog请求
    }

    //需要将name属性返回给页面
    @RequestMapping("/findDog")
    public String findDog(String name,Model model){
        System.out.println("动态获取name属性值:"+name);
        model.addAttribute("name",name+"旺旺旺");
        return "dog";
    }

1.1.5 重定向/转发特点

1.转发时 会携带用户提交的数据.
2.转发时 用户浏览器的地址不会发生改变.
3.重定向时 由于是多次请求,所以不会携带用户的数据
4.重定向时 由于是多次请求,所以用户的浏览器的地址会发生变化

1.1.6 重定向/转发意义

意义: 实现了方法内部的松耦合
什么时候使用转发/重定向:
1.如果需要携带参数 使用转发
2.如果一个业务已经完成需要一个新的开始 则使用重定向

1.2 RestFul风格

1.2.1 RestFul入门案例

package com.jt.controller;

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

@Controller
public class RestFulController {

    /**
     * 常规get请求:
     * url地址: http://localhost:8090/restFul?id=1&name=tom
     * get请求弊端: 如果参数有多个,则key-value的结构需要多份.
     * RestFul结构:
     *  url地址: http://localhost:8090/restFul/{id}/{name}
     *      1.参数之间使用/分割
     *      2.参数的位置一旦确定,不可更改
     *      3.参数使用{}号的形式进行包裹,并且设定形参
     *      4.在接收参数时,使用特定的注解取值@PathVariable
     *
     * @PathVariable: 参数说明
     *      1.name/value  动态接收形参的数据  如果参数相同则省略不写
     *      2.必填项 required 默认为true
     */
    @RequestMapping("/restFul/{id}/{name}")
    public String restFul(@PathVariable Integer id,
                          @PathVariable String name){
        System.out.println("获取参数:"+id+"|"+name);
        return "success";
    }



}

1.2.2 简化业务调用

需求: 按照常规说明 执行增删改查的操作,需要多个业务方法.
例子:
1.新增用户 /insertUser
2.修改用户 /updateUser
3.删除用户 /deleteUser
4.查询用户 /selectUser
说明: 上述的操作在早期这么写没有问题.但是新的请求规范规定应该让请求尽可能变成无状态的请求.(删除动词)

常见请求类型: 1.GET 2.POST 3.PUT 4.DELETE
优化:
1.新增用户 /user 请求类型: POST
2.修改用户 /user 请求类型: PUT
3.删除用户 /user 请求类型: DELETE
4.查询用户 /user 请求类型: GET

优化注解: 在这里插入图片描述
总结:
1.利用RestFul 可以简化get请求类型.
2.利用RestFul可以使用无状态的请求,通过不同的请求类型 控制不同的业务逻辑(较为常用)

1.3 JSON

1.3.1 JSON介绍

JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式(字符串)。它使得人们很容易的进行阅读和编写。同时也方便了机器进行解析和生成。

1.3.2 JSON格式

1.3.2.1 Object格式

对象(object) 是一个无序的“‘名称/值’对”集合。一个对象以“{”(左括号)开始,“}”(右括号)结束。每个“名称”后跟一个“:”(冒号);“‘名称/值’ 对”之间使用“,”(逗号)分隔。

在这里插入图片描述
JSON练习: {"key1":"value1","key2":"value2"}

1.3.2.2 Array格式

数组(array) 是值(value)的有序集合。一个数组以“[”(左中括号)开始,“]”(右中括号)结束。值之间使用“,”(逗号)分隔。
在这里插入图片描述
JSON: ["value1","value2","value3"]

1.3.2.3 嵌套格式

在这里插入图片描述
关于JSON串 嵌套

[true,false,{"id":100,"name":"tomcat","hobbys":["敲代码","玩游戏","找对象",{"username":"admin","password":"123456"}]}]

1.4 SpringMVC JSON返回

1.4.1 学习的意义

现阶段一般的请求都是前后端分离的方式.ajax (jQuery/axios),一般向服务器请求的数据 通常详情下 都是采用JSON串的方式返回.

1.4.2 @ResponseBody注解

package com.jt.controller;

import com.jt.pojo.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class JSONController {

    /**
     * 需求: 要求根据getJSON的请求,获取User对象的JSON数据.
     * 用法: 如果需要返回JOSN数据则使用注解@ResponseBody
     * 知识点讲解:
     *      返回的对象之后,SpringMVC通过内部API(ObjectMapper)
     *      调用对象的getXXX()方法动态的获取属性和属性值.
     *  演化规则:
     *      getAge() ~~~~~去掉get首字母~~~~~Age()
     *      ~~~~~~首字母小写~~~~~age()~~~~获取属性age
     *      ~~~~~通过getAge() 动态获取属性的值
     *
     *  JSON: {"age": "今年18岁!!!"}
     *  注意事项:
     *      必须添加get/set方法
     */
    @RequestMapping("/getJSON")
    @ResponseBody //返回值就是一个JSON串
    public User getJSON(){
        User user = new User();
        user.setId(1000).setName("JSON测试");
        return user; //不需要执行视图解析器
    }
}

1.4.2 @RestController

在这里插入图片描述

2 SpringBoot整合其他框架

2.1 创建项目springboot_demo_4

在这里插入图片描述

2.2 编辑pom.xml文件

1.SpringBoot包(spring) 2.SpringMVC 3.MybatisPlus

<?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.jt</groupId>
    <artifactId>springboot_demo_4</artifactId>
    <version>1.0-SNAPSHOT</version>

    <!--引入父级工程-->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.5</version>
        <relativePath/>
    </parent>

    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <!--thymeleaf导入模版工具类-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

        <!--SpringMVCjar包文件-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--热部署工具-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <!--lombok插件-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <!--测试包-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!--引入jdbc包-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>

        <!--引入数据库驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

        <!--spring整合mybatis-plus -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.2</version>
        </dependency>
    </dependencies>

    <!--负责项目打包部署-->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

2.2 编辑yml配置文件

server:
  port: 8090

spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/jtadmin?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true
    username: root
    password: root

  #整合SpringMVC
  thymeleaf:
    #设置页面前缀
    prefix: classpath:/templates/
    #设置页面后缀
    suffix: .html
    #是否使用缓存
    cache: false

mybatis-plus:
  type-aliases-package: com.jt.pojo
  mapper-locations: classpath:/mappers/*.xml
  #开启驼峰映射
  configuration:
    map-underscore-to-camel-case: true

#添加MP日志  打印执行的sql
logging:
  level:
    com.jt.mapper: debug
  

2.3 编辑userList.html页面

<!DOCTYPE html>
<!--导入模板标签!!!!!-->
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>用户列表数据</title>
</head>
<body>
   <!--准备一个表格-->
    <table border="1px" align="center" width="800px">
        <tr align="center">
            <td colspan="4"><h3>用户列表</h3></td>
        </tr>
        <tr align="center">
            <td>ID</td>
            <td>名称</td>
            <td>年龄</td>
            <td>性别</td>
        </tr>
        <!--1.页面通过request对象 动态的获取userList数据 之后tr展现-->
        <tr align="center" th:each="user : ${userList}">
            <td th:text="${user.id}"></td>
            <td th:text="${user.name}"></td>
            <td th:text="${user.age}"></td>
            <td th:text="${user.sex}"></td>
        </tr>
    </table>
</body>
</html>

2.4 编辑UserController

/**
     * 查询所有的用户列表数据,在userList.html中展现数据
     */
    @RequestMapping("/userList")
    public String userList(Model model){
        //1.查询业务层获取数据
        List<User> userList = userService.findAll();
        //2.将数据保存到Model对象中返回给页面
        model.addAttribute("userList",userList);
        return "userList";
    }

2.5 编辑UserService

@Service
public class UserServiceImpl implements UserService{

    @Autowired
    private UserMapper userMapper;


    @Override
    public List<User> findAll() {

        return userMapper.selectList(null);
    }
}

2.6 编辑UserMapper

在这里插入图片描述

2.7 页面效果展现

在这里插入图片描述

2.8 RestFul策略优化

在这里插入图片描述

3. 作业

/**
     * 需求1: 利用restFul实现用户数据修改
     *       之后重定向到userList.html页面
     *       URL地址: /user/id/name
     *
     * 需求2:
     *        利用restFul实现数据删除
     *        url: /user/100(id)
     *        之后重定向到userList.html页面
     *
     * 需求3: jQuery的Ajax 预习
     */

1. VUE命令

1.1 v-on命令

1.作用: 如果需要对页面元素进行操作(事件)

1.1.1 click命令

在这里插入图片描述

1.1.2 methods属性介绍

通过methods属性定义众多方法.
在这里插入图片描述

1.2 事件修饰符

1.2.1 stop

在这里插入图片描述

1.2.2 prevent

在这里插入图片描述

1.2.3 按键修饰符

在这里插入图片描述

1.3 v-bind

1.3.1 属性绑定

在这里插入图片描述

1.3.2 属性动态绑定

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>属性绑定</title>
		
		<!-- 定义style标签 -->
		<style>
			.red{
				background-color: red;
				width: 100px;
				height: 100px;
			}
		</style>
	</head>
	<body>
		<div id="app">
			<!-- 需求:需要为href属性动态的绑定数据 v-bind属性绑定 -->
			<a href="http://www.baidu.com">百度</a>
			<!-- 属性绑定的语法 -->
			<a v-bind:href="url">百度</a>
			<!-- 简化操作 -->
			<a :href="url"></a>
			
			<hr >
			<!-- class的绑定 -->
			<div class="red">
				class的内容测试
			</div>
			<hr >
			<!-- 需求:需要动态的绑定样式 -->
			<div v-bind:class="{red: isRed}">
				class的内容测试
			</div>
			<!-- 简化写法 -->
			<div :class="{red: isRed}">
				class的内容测试
			</div>
			<!-- 切换样式 -->
			<button @click="isRed = !isRed">切换</button>
			
			v-on  v-bind
		</div>
		
		<script src="../js/vue.js"></script>
		<script>
			const app = new Vue({
				el: "#app",
				data: {
					url: 'http://www.baidu.com',
					//如果控制样式 则设定boolean类型的值
					isRed: false
				}
			})
		</script>
	</body>
</html>

1.4 分支结构语法

1.4.1 分支结构介绍

  1. v-if 如果判断为真 则显示标签数据
  2. v-else 如果判断为假 则显示数据
  3. v-else-if 判断规则 位于if和else之间的.
  4. v-show 展现数据.

1.4.2 分支结构介绍(if/else)

在这里插入图片描述

1.4.3 v-show命令

在这里插入图片描述

1.5 循环遍历

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>循环结构</title>
	</head>
	<body>
		<div id="app">
			<!-- 1.循环数组 注意事项:循环时最好指定key 标识循环数据的位置 -->
			<h3 v-for="item in hobbys" v-text="item" :key="item"></h3>
			
			<!-- 2.带下标的循环遍历语法 2个参数  参数1:遍历的数据   参数2:下标 -->
			<h3 v-for="(item,index) in hobbys" v-text="item" :key="index"></h3>
			
			<!-- 3.循环遍历对象 -->
			<div v-for="user in userList" :key="user.id">
				<span v-text="user.id"></span>
				<span v-text="user.name"></span>
			</div>
		</div>
		
		<script src="../js/vue.js"></script>
		<script>
			const app = new Vue({
				el: "#app",
				data: {
					//一般采用数组形式保存多个数据
					hobbys: ['打游戏','敲代码','喝水','水王八'],
					userList: [{
						id: 100,
						name: '孙尚香'
					},{
						id: 200,
						name: '王昭君'
					},{
						id: 300,
						name: '貂蝉'
					}]
				}
			})
		</script>
	</body>
</html>

1.6 Vue表单操作

1.6.1 常见表单元素

1.input 文本框
2.textarea 文本域
3.select 下拉框
4.radio 单选框
5.checkbox 多选框

1.6.2 数据绑定

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>表单数据提交</title>
	</head>
	<body>
		<div id="app">
			<form action="http://www.baidu.com">
				<div>
					<span>用户名:</span>
					<span>
						<input name="username" type="text" v-model="username"/>
					</span>
				</div>
				<div>
					<span>性别:</span>
					<span>
						<!--label相当于合并一个div 需要id-for进行关联  -->
						<input name="gender" type="radio" value="男" id="man"
						v-model="gender"/>
						<label for="man"></label>
						<input name="gender" type="radio" value="女" id="women"
						v-model="gender"/>
						<label for="women"></label>
					</span>
				</div>
				
				<div>
					<span>爱好:</span>
					<span>
						<input name="hobbys" type="checkbox" value="敲代码" v-model="hobbys"/>敲代码
						<input name="hobbys" type="checkbox" value="打游戏" v-model="hobbys"/>打游戏
						<input name="hobbys" type="checkbox" value="喝水" v-model="hobbys"/>喝水
					</span>
				</div>
				
				<div>
					<span>部门:</span>
					<span>
						<!-- 设定下拉框多选 -->
						<select name="dept" v-model="dept" 
							multiple="true">
							<option value="财务部">财务部</option>
							<option value="研发部">研发部</option>
							<option value="测试部">测试部</option>
						</select>
					</span>
				</div>
				<div>
					<span>用户详情</span>
					<span>
						文本域
					</span>
				</div>
				<div>
					<!-- 让默认的行为失效 -->
					<button @click.prevent="submit">提交</button>
				</div>
			</form>
		</div>
		<script src="../js/vue.js"></script>
		<script>
			const app = new Vue({
				el: "#app",
				data: {
					username: '',
					gender: '女',
					//如果数据项有多项 则使用数组接收
					hobbys: ['敲代码','喝水'],
					//定义下拉框 如果单个数据使用'' 多个数据使用数组
					//dept: '研发部'
					dept: ['财务部','研发部']
				},
				methods: {
					submit(){
						console.log("username数据:"+this.username)
						console.log("username数据:"+this.gender)
					}
				}
			})
		</script>
	</body>
</html>

1.6.3 表单修饰符

1.number : 将用户输入的内容转户为数值类型.
2.trim: 去除左右2边多余的空格.
3.lazy: 简化input框调用js的次数 当失去焦点时调用

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>表单修饰符</title>
	</head>
	<body>
		<div id="app">
			<!-- number 将字符转化为数值 -->
			数字1: <input type="text" v-model.number="num1"/><br>
			数字2: <input type="text" v-model.number="num2"/><br>
			<button @click="addNum">加法操作</button> <br>
			总数: {{count}}
			<hr >
			<!-- 去除多余的空格 -->
			数据: <input type="text" v-model.trim="msg"/> <br>
			字符长度 {{msg.length}}
			<hr />
			<!-- lazy 当数据失去焦点时触发事件 -->
			检验用户名: <input type="text" v-model.lazy="username"><br>
			{{username}}
		</div>
		<script src="../js/vue.js"></script>
		<script>
			const app = new Vue({
				el: "#app",
				data: {
					num1: '',
					num2: '',
					count: '',
					msg: '',
					username: ''
				},
				methods: {
					addNum(){
						this.count = this.num1 + this.num2
					}
				}
			})
		</script>
	</body>
</html>

1.7 计算属性

1.7.1 需求说明

有时在vue的JS中需要进行大量的数据计算. 但是如果将所有的数据计算都写到HTML标签中,则代码的结构混乱.
优化: VUE中提供了计算属性的功能.

1.7.2 计算属性案例

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>计算属性</title>
	</head>
	<body>
		<div id="app">
			<!-- 需求: 需要对一个字符串进行反转操作
				用户输入内容 abc 
				要求的输出内容   cba
				思路: 字符串拆分为数组  将数组进行反转  将数组拼接成串				 
				方法说明:
				reverse(): 将数组进行反转
				join("连接符") 将数组拼接为字符串
			 -->
			 用户输入: <input type="text" v-model="msg" /> <br>
			 常规调用:{{msg.split('').reverse().join('')}}<br>
			 
			 <!-- 添加计算属性的名称-->
			 计算属性调用: {{reverseMethod}}
			
		</div>
		<script src="../js/vue.js"></script>
		<script>
			const app = new Vue({
				el: "#app",
				data: {
					msg: ''
				},
				//定义计算属性的key
				computed: {
					//指定计算属性的名称 要求有返回值
					reverseMethod(){
						
						return this.msg.split('').reverse().join('')
					}
				}
			})
		</script>
	</body>
</html>

1.7.3 计算属性和方法的区别

考点: 1.方法调用时每次都会执行.
2.计算属性调用时 有缓存机制
3.如果数据需要被大量的引用 则使用计算属性更好 效率高
在这里插入图片描述

1.监听器

1.1 需求说明

当属性的数据发生变化时,则通过监听器实现对数据的监控. 从而实现数据的操作.

什么时候使用:
一般用于业务处理(异步操作 Ajax)

1.2 配置监听器

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>校验用户名是否可用</title>
	</head>
	<body>
		<div id="app">
			<!-- 
				需求:
					要求用户输入username的用户名,之后与服务器进行校验
					如果已经存在给用户提示. 如果不存在 则提示用户可用.
			 -->
			 用户名: <input type="text" v-model.lazy="username"/>{{msg}}
			 
		</div>
		<script src="../js/vue.js"></script>
		<script>
			const app = new Vue({
				el: "#app",
				data: {
					username: '',
					//校验的结果
					msg: ''
				},
				methods: {
					checkName(val){
						//===严格意义的数据校验 新版本提倡这么写 校验数值 还校验类型
						if(val === 'admin'){
							this.msg = "数据已存在"
						}
						else if(val === 'tom'){
							this.msg = "数据已存在"
						}
						else{
							this.msg = "数据可以使用"
						}
					}
				},
				watch: {
					//定义属性的监听器
					username(val){
						this.checkName(val)
					}
				}
			})
		</script>
	</body>
</html>

2.过滤器

2.1 关于过滤器说明

一般使用过滤器格式化数据. 价格/时间等

2.2 需求说明

当用户输入完成数据之后,要求使用过滤器将数据反转.

2.3 过滤器入门案例

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>过滤器的使用</title>
	</head>
	<body>
		<div id="app">
			 <!-- 使用 | 线 调用过滤器-->
			 用户输入内容: <input type="text" v-model="username" /><br>
			 {{username | rename}}<br>
			 <!-- 过滤器级联-->
			 {{username | rename | addChar}}
		</div>
		<script src="../js/vue.js"></script>
		<script>
			
			//1.单独定义过滤器 
			// 参数1: 过滤器名称  参数2: 过滤器执行的方法
			// 注意事项: 过滤器需要返回值.
			Vue.filter('rename',function(val){
				
				return val.split('').reverse().join('')	
			})
			
			//2.追加哈哈哈字符 
			//箭头函数写法 可以省略function关键字, 如果只有一个参数则()省略 
			//使用=>进行关联
			Vue.filter('addChar',val => {
				
				return val + '哈哈哈'
			})
			
			
			
			
			const app = new Vue({
				el: "#app",
				data: {
					username: '',
					
				},
				methods: {
					
				}
			})
		</script>
	</body>
</html>

3.VUE生命周期

3.1 VUE生命周期函数说明

所有的生命周期钩子自动绑定 this 上下文到实例中,因此你可以访问数据,对 property 和方法进行运算。这意味着你不能使用箭头函数来定义一个生命周期方法 (例如 created: () => this.fetchTodos())。这是因为箭头函数绑定了父上下文,因此 this 与你期待的 Vue 实例不同,this.fetchTodos 的行为未定义。

3.2 VUE对象周期函数流程图

在这里插入图片描述

3.3 VUE对象生命周期Demo

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>生命周期</title>
	</head>
	<body>
		<div id="app">
			
			<!-- 
				1.VUE对象的生命周期函数,可以单独的调用
				2.生命周期的函数名称是固定的,不能随意修改.
			 -->
			用户名: <input type="text" v-model="name"/>
			<button @click="destroyed">销毁</button>
		</div>
		<script src="../js/vue.js"></script>
		<script>
			const app = new Vue({
				el: "#app",
				data: {
					name: ''
				},
				methods: {
					destroyed(){
						//手动销毁VUE对象 vue中的对象API使用$调用
						this.$destroy()
					}
				},
				//在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用。
				beforeCreate(){
					console.log("初始化之后调用-beforeCreate")
				},
				//在实例创建完成后被立即调用。在这一步,实例已完成以下的配置
				created(){
					console.log("实力化对象完成,并且完成了配置之后调用created")
				},
				//在挂载开始之前被调用:相关的 render 函数首次被调用。
				beforeMount(){
					console.log("数据在备挂载前调用beforeMount")
				},
				//实例被挂载后调用 页面真正的加载完成之后调用
				mounted(){
					console.log("页面加载完成mounted")
				},
				//数据更新时调用,发生在虚拟 DOM 打补丁之前
				beforeUpdate(){
					console.log("数据更新时调用beforeUpdate")
				},
				//由于数据更改之后调用
				updated(){
					console.log("数据修改之后调用updated")
				},
				//实例销毁之前调用。在这一步,实例仍然完全可用。
				beforeDestroy(){
					console.log("VUE对象销毁之前调用beforeDestroy")
				},
				//实例销毁后调用。该钩子被调用后,对应 Vue 实例的所有指令都被解绑,所有的事件监听器被移除,所有的子实例也都被销毁。
				destroyed(){
					console.log("实例销毁后调用destroyed")
				}
				
			})
		</script>
	</body>
</html>

4 VUE中数组操作

4.1 官网API位置

说明: VUE针对数组的操作,开发了一套完整的API
在这里插入图片描述

4.2 数组用法案例说明

1).push() 在数组末尾追加数据.
2).pop() 删除数组最后一个元素
3).shift() 删除数组第一个元素
4.unshift() 在数据开头追加数据.
5.splice() 在指定的位置替换数据.
6.sort() 对数据进行排序 按照编码进行排序 由小到大
7.reverse() 数组反转.

4.3 数组基本案例

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>数组案例</title>
	</head>
	<body>
		<div id="app">
			<span v-for="item in array" v-text="item"></span><br>
			
			数据: <input type="text" v-model="data"/> 
			<button @click="push">追加</button>
			<button @click="pop">移除最后一个</button>
			<button @click="shift">删除第一个元素</button>
			<button @click="unshift">在开头追加元素</button>
			<button @click="splice">替换元素</button>
			<button @click="sort">排序</button>
			<button @click="reverse">反转</button>
		</div>
		<script src="../js/vue.js"></script>
		<script>
			const app = new Vue({
				el: "#app",
				data: {
					array: [5,7,4,1],
					data: ''
				},
				methods: {
					push(){
						this.array.push(this.data)
					},
					pop(){
						//移除最后一个数据
						this.array.pop()
					},
					shift(){
						this.array.shift()
					},
					unshift(){
						this.array.unshift(this.data)
					},
					splice(){
						//关于参数说明 参数1:操作数据起始位置 index
						//			  参数2:操作数据的个数
						//			  参数3:要替换的值
						//删除元素     删除第一个元素的后2位
						//this.array.splice(1,2,'')
						//替换元素     替换前2个元素(将元素当做整体进行替换)
						//替换后的元素可以有多个
						this.array.splice(0,2,this.data)
					},
					sort(){
						this.array.sort()
					},
					reverse(){
						this.array.reverse()
					},
					
				}
				
			})
		</script>
	</body>
</html>

5 VUE中组件化思想

5.1 组件化介绍

组件系统是 Vue 的另一个重要概念,因为它是一种抽象,允许我们使用小型、独立和通常可复用的组件构建大型应用。仔细想想,几乎任意类型的应用界面都可以抽象为一个组件树.
使用组件可以将一些重复的内容进行封装.各个组件单独维护.体现了分治的思想

在这里插入图片描述

5.2 组件化入门案例

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>组件</title>
	</head>
	<body>
		<div id="app">
			<!-- 3.调用组件 -->
			<hello></hello>
		</div>
		
		<script src="../js/vue.js"></script>
		<script>
			//1.定义全局组件  参数1: 定义组件名称 暂时不要使用驼峰规则
			//				 参数2: 定义组件对象
			Vue.component('hello',{
				//1.组件数据.
				data(){
					return {
						msg: 'hello 组件'
					}
				},
				//2.组件结构 html数据
				template: '<h1>{{msg}}</h1>'
			})
			
			/* 注意事项: 组件的使用必须有Vue对象的渲染 */
			const app = new Vue({
				el: "#app"
			})
			
		</script>
	</body>
</html>

5.3 组件驼峰规则命名

在这里插入图片描述

5.4 组件模板标签的使用

1). `号的作用
在这里插入图片描述
2).组件template的写法
在这里插入图片描述
在这里插入图片描述

5.5 局部组件定义

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>组件</title>
	</head>
	<body>
		<div id="app">
			<hello1></hello1>
			<hello1></hello1>
		</div>
		
		<template id="hello1Tem">
			<div>
				<h3>{{msg}}</h3>
			</div>
		</template>
		
		<script src="../js/vue.js"></script>
		<script>
			
			//1.定义组件对象
			const hello1 = {
				data(){
					return {
						msg: 'hello1局部组件'
					}
				},
				template: '#hello1Tem'
			}
			
			/* 局部组件的写法 */
			const app1 = new Vue({
				el: "#app",
				//vue对象中的组件  组件名称/组件对象
				components: {
					//hello1  : hello1
					//js简化写法 如果key与value值相同,则可以简化.
					hello1
				}
			})
			
		</script>
	</body>
</html>

6 Axios

6.1 Axios介绍

Axios 是一个基于 promise(内部封装了ajax) 的 HTTP 库,可以用在浏览器和 node.js 中。
作用: 在内部 简化异步调用
在这里插入图片描述

6.2 入门案例

6.2.1 编辑页面HTML

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>Axios入门案例</title>
	</head>
	<body>
		
		<h1>Axios Ajax调用</h1>
		
		<!-- 1.导入js类库 -->
		<script src="../js/axios.js"></script>
		<script>
			
			//1.发起Get请求
			// 原始参数  1: url地址  参数2:提交参数  参数3:回调函数
			// 知识点: 传统的ajax的操作有"回调地狱问题" '闭包' 
			// 回调地狱问题: 由于业务复杂,导致多重的ajax进行嵌套. 如果中间出现任何问题.则导致整个ajax调用失败.
			
			//参数 1: url地址  2.提交的参数
			//跨域请求: 浏览器不能正常执行!!!!
			let url = "http://localhost:8090/hello"
			axios.get(url)
				 .then(function(result){
					 //获取返回值 promise对象
					 console.log(result)
					 //如果需要获取服务器的返回值则使用.data属性
					 console.log(result.data)
				 })
		</script>
	</body>
</html>

6.2.2 编辑后台AxiosController

在这里插入图片描述

6.3 作业

1.掌握Vue组件/过滤器/监听器/数组操作
2.了解什么是跨域!!!
3.将Axios的get/delete/put/post 了解.

1. Axios

1.1 关于Axios 参数传递

1.1.1 Axios入门案例

1).编辑前端JS
在这里插入图片描述2).编辑后端Controller
在这里插入图片描述

1.1.2 GET 带参数写法

1).编辑前端JS
在这里插入图片描述
2).编辑后端Controller
在这里插入图片描述

1.1.3 GET RestFul风格

1).编辑页面JS
在这里插入图片描述
2).编辑Controller
在这里插入图片描述

1.1.4 GET Params用法

1).编辑页面JS
在这里插入图片描述
2).编辑Controller
在这里插入图片描述

1.2 Axios-POST/PUT请求

1.2.1 post/put说明

说明: POST/PUT请求一般都是页面向服务器提交数据. 参数应该可以使用对象的方式封装

1.2.2 post/put 对象传参

1).编辑页面JS
在这里插入图片描述
2).编辑后端Controller
在这里插入图片描述

1.2.3 post/put Form表单传参

1).编辑页面JS
在这里插入图片描述
2).编辑Controller方法
在这里插入图片描述

1.3 关于Axios的配置

在这里插入图片描述

1.4 async-await用法

1.4.1 语法介绍

1.async-await 是ES7 引入的最新的规范 更加简单的进行异步调用
2.async 用来标识方法(函数)
3.await 标识ajax调用

1.4.2 语法介绍

在这里插入图片描述

1.4.3 解构赋值操作

采用解构赋值的操作让代码更加灵活
在这里插入图片描述

1.5 VUE实现用户列表展现

1.5.1 编辑AxiosUserController

在这里插入图片描述

1.5.2 获取用户列表数据

1.利用mouted方法 初始化数据
2.利用axios方式获取数据
在这里插入图片描述

1.5.3 循环遍历数据

在这里插入图片描述

1.5.4 修改用户实现数据回显

<!DOCTYPE html>
<head>
    <meta charset="UTF-8">
    <title>用户列表数据</title>
</head>
<body>
	<div id="app">
		用户编号: <input type="text" disabled v-model="user.id"  />
		用户姓名: <input type="text" v-model="user.name"/><br>
		用户年龄: <input type="text" v-model="user.age"/>
		用户性别: <input type="text" v-model="user.sex"/>
		<button>更新</button>
		<hr />
		<!-- 用户展现的表格 -->
		<table id="userTable" border="1px" align="center" width="800px">
			<tr align="center">
				<td colspan="5"><h3>用户列表</h3></td>
			</tr>
			<tr align="center">
				<td>ID</td>
				<td>名称</td>
				<td>年龄</td>
				<td>性别</td>
				<td>操作</td>
			</tr>
			<tr align="center" v-for="user in userList">
				<td v-text="user.id"></td>
				<td v-text="user.name"></td>
				<td v-text="user.age"></td>
				<td v-text="user.sex"></td>
				<td>
					<button @click="updateBtn(user)">修改</button>
					<button>删除</button>
				</td>
			</tr>
		</table>
	</div>
	<!-- 1.引入页面JS -->
	<script src="../js/vue.js"></script>
	<script src="../js/axios.js"></script>
	
	<!-- 2.编辑自己的JS -->
	<script>
		const app = new Vue({
			el: "#app",
			data: {
				//1.定义用户列表数据
				userList: [],
				//2.定义用户属性
				user: {
					id: '',
					name: '',
					age: '',
					sex: ''
				}
			},
			methods: {
				async getUserList(){
					const {data: result} = await axios.get('http://localhost:8090/axiosUser/findAll')
					this.userList = result
					//console.log(this.userList)
				},
				//更新按钮操作
				updateBtn(user){
					//将用户传递的user对象赋值给data中的属性user
					this.user = user
				}
			},
			mounted(){
				//当页面渲染成功之后调用
				//调用查询用户的方法
				this.getUserList()
			}
		})
		
	</script>
	
</body>
</html>

1.6 实现用户修改

1.6.1 编辑页面JS

<!DOCTYPE html>
<head>
    <meta charset="UTF-8">
    <title>用户列表数据</title>
</head>
<body>
	<div id="app">
		用户编号: <input type="text" disabled v-model="user.id"  />
		用户姓名: <input type="text" v-model="user.name"/><br>
		用户年龄: <input type="text" v-model="user.age"/>
		用户性别: <input type="text" v-model="user.sex"/>
		<button @click="updateUser">更新</button>
		<hr />
		<!-- 用户展现的表格 -->
		<table id="userTable" border="1px" align="center" width="800px">
			<tr align="center">
				<td colspan="5"><h3>用户列表</h3></td>
			</tr>
			<tr align="center">
				<td>ID</td>
				<td>名称</td>
				<td>年龄</td>
				<td>性别</td>
				<td>操作</td>
			</tr>
			<tr align="center" v-for="user in userList">
				<td v-text="user.id"></td>
				<td v-text="user.name"></td>
				<td v-text="user.age"></td>
				<td v-text="user.sex"></td>
				<td>
					<button @click="updateBtn(user)">修改</button>
					<button>删除</button>
				</td>
			</tr>
		</table>
	</div>
	<!-- 1.引入页面JS -->
	<script src="../js/vue.js"></script>
	<script src="../js/axios.js"></script>
	
	<!-- 2.编辑自己的JS -->
	<script>
		const app = new Vue({
			el: "#app",
			data: {
				//1.定义用户列表数据
				userList: [],
				//2.定义用户属性
				user: {
					id: '',
					name: '',
					age: '',
					sex: ''
				}
			},
			methods: {
				async getUserList(){
					const {data: result} = await axios.get('http://localhost:8090/axiosUser/findAll')
					this.userList = result
					//console.log(this.userList)
				},
				//更新按钮操作
				updateBtn(user){
					//将用户传递的user对象赋值给data中的属性user
					this.user = user
				},
				//更新用户信息
				async updateUser(){
					//请求类型 PUT/POST   GET/DELETE
					//http://localhost:8090/axiosUser/updateUser
					//更新操作可以没有返回值
					await axios.put('http://localhost:8090/axiosUser/updateUser',this.user)
				}
			},
			mounted(){
				//当页面渲染成功之后调用
				//调用查询用户的方法
				this.getUserList()
			}
		})
		
	</script>
	
</body>
</html>

1.6.2 编辑AxiosUserController

根据用户更新操作的ajax ,接收用户参数
在这里插入图片描述

1.6.3 编辑AxiosUserService

根据用户ID实现数据入库
在这里插入图片描述

1.7 实现用户数据删除

1.7.1 编辑页面JS

1).为删除按钮添加事件
在这里插入图片描述
2).编辑点击函数
在这里插入图片描述

1.7.2 编辑AxiosUserController

在这里插入图片描述

2 跨域

2.1 同源策略

同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。
浏览器出于安全性的考虑,要求所有的请求都必须满足同源策略!!!!

要素: 请求协议://域名:端口 必须相同!!!!!

2.2 跨域问题

	Ajax的请求违反同源策略,ajax的请求就称之为跨域访问

在这里插入图片描述
跨域练习:
1.页面地址 https://www.jd.com/xxx/xx
2.ajax请求地址 http://www.jd.com/xx/xx
协议不同,是跨域请求.

1.页面地址	http://www.jd.com/xxx/xx
2.ajax请求地址  http://192.168.1.100/xx/xx      备注: IP就是域名的IP
域名不同  是跨域访问!!!!

1.页面地址	http://www.jd.com:80/xxx/xx
2.ajax请求地址  http://www.jd.com:8090/xx/xx  
端口不同  是跨域访问!!!!

2.4 CORS

CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。
CORS的实质就是在服务器端添加允许访问的响应头 CORS是服务端的一种技术.

在这里插入图片描述

2.4.1 响应头信息

*号代表通配符.允许所有的请求访问.
在这里插入图片描述

*号可以换成特定的网址.则只允许该网址访问
在这里插入图片描述

3 作业

1.手动搭建springBoot框架 要求整合SpringMVC 和Mybatis 手写
2.将用户列表的案例重新做一遍
3.总结VUE知识点

​ 1 VUE路由机制

1.1 VUE Router介绍

Vue Router 是 Vue.js (opens new window)官方的路由管理器。它和 Vue.js 的核心深度集成,让构建单页面应用变得易如反掌。包含的功能有:
嵌套的路由/视图表
模块化的、基于组件的路由配置
路由参数、查询、通配符
基于 Vue.js 过渡系统的视图过渡效果
细粒度的导航控制
带有自动激活的 CSS class 的链接
HTML5 历史模式或 hash 模式,在 IE9 中自动降级
自定义的滚动条行为

1.2 前端路由

1.2.1 后端路由介绍

在这里插入图片描述

1.2.2 前端路由

说明:前端路由在内部配置了路由表,之后用户发起请求之后,根据路由表的内容直接跳转html页面(组件)
在这里插入图片描述

1.3 路由入门案例

1.3.1 Router使用步骤

  1. 引入路由的js类库.
  2. 添加路由链接
  3. 添加路由的填充位
  4. 定义路由组件
  5. 配置路由规则,创建路由实例
  6. 实现路由的挂载vue

1.3.2 Router 入门案例

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>路由规则</title>
	</head>
	<body>
		<div id="app">
			<!-- 2.添加路由链接
				router-link: vue会将标签解析为a标签
				to: vue会解析为href属性
			 -->
			<router-link to="/user">用户</router-link>
			<router-link to="/dept">部门</router-link>
			
			<!-- 3.定义路由占位符 当用户点击路由时,在该位置展现页面
				理解为新的div.
			  -->
			<router-view></router-view>  
			
		</div>
		
		<!-- 1.引入js -->
		<script src="../js/vue.js"></script>
		<script src="../js/vue-router.js"></script>
		<script>
			
			/* 4.定义组件变量 */
			const user = {
				template: '<h1>我是user组件</>'
			}
			
			const dept = {
				template: '<h1>我是部门组件</>'
			}
			
			/* 5.配置路由规则  */
			const router = new VueRouter({
				//定义规则
				routes: [
					{ path:'/user', component:user},
					{ path:'/dept', component:dept}
				]
			})
			
			
			//6.将路由组件挂载到Vue中
			const app = new Vue({
				el: "#app",
				router
			})
		</script>
	</body>
</html>

1.3.3 Router 重定向

说明: 路由的组件提供了重定向的功能,可以让用户默认跳转指定的组件
需求: 默认的跳转下 跳转到/user 组件中.
在这里插入图片描述

1.4 Router 嵌套

1.4.1 需求说明

链接: 商场,动物园
嵌套: 商场 shoe,手机. 动物园: 鸡 鸭

1.4.2 嵌套实现

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>路由规则</title>
	</head>
	<body>
		<div id="app">
			<router-link to="/shopping">商场</router-link>
			<router-link to="/zoo">动物园</router-link>
			
			<router-view></router-view>
		</div>
		
		<!-- 定义商场组件 -->
		<template id="shoppingTem">
			<div>
				<h1>我是商场组件</h1>
				
				<router-link to="/shopping/shoe">鞋店</router-link>
				<router-link to="/shopping/phone">手机店</router-link>
				<router-view></router-view>
			</div>
		</template>
			
		
		<!-- 1.引入js 注意引入顺序 -->
		<script src="../js/vue.js"></script>
		<script src="../js/vue-router.js"></script>
		
		<script>
			const shopping = {
				template : "#shoppingTem"
			}
			
			const zoo = {
				template : "<h1>我是动物园组件</h1>"
			}
			
			const shoe = {
				template : "<h1>我是鞋店</h1>"
			}
			
			const phone = {
				template : "<h1>我是手机店</h1>"
			}
			
			//如果需要嵌套 则使用关键字children
			const router = new VueRouter({
				routes: [
					{path:'/shopping', component: shopping,
					children: [
						{path:'/shopping/shoe',component: shoe},
						{path:'/shopping/phone',component: phone}
					]},
					
					{path:'/zoo', component: zoo}
				]
			})
			
			const app = new Vue({
				el: "#app",
				router
			})
			
		</script>
	</body>
</html>

2 搭建京淘前端

2.1 node.js安装

具体步骤 参见博客文章 VUE后端管理插件安装

2.2 导入课前资料

在这里插入图片描述

2.3 关于导入src文件报错说明

2.3.1 报错演示

在这里插入图片描述
报错信息:
在这里插入图片描述

2.3.2 安装less-loader 依赖

要求: 在 jtweb的根目录中执行安装命令
在这里插入图片描述
安装成功:
在这里插入图片描述

2.3.3 安装less依赖

安装运行依赖
在这里插入图片描述

2.3.4 启动效果

在这里插入图片描述

1. 京淘项目后端架构图

在这里插入图片描述

2. 京淘项目后台搭建

2.1 互联网架构设计

2.1.1 高并发

定义: 在同一时间内,大量用户访问服务器的数量.
常识: 单台tomcat服务器 支持的并发数? 官方数据: 200-270左右(理论值)
实际值: 150左右 网速/硬件设备(核数/内存) 云平台
JVM调优: tomcat服务器单台性能 可以达到1000/秒 (增大运行内存) 监控
软件不够,硬件来凑

2.1.2 分布式

2.1.2.1 分布式计算

一项任务由多台服务器同时完成. 大数据的处理方式  任务拆分(包). 再有多个线程分别执行各自的包, 结果整合

2.1.2.2 分布式系统

说明: 当先的企业在构建项目时 一般都采用分布式的系统的方式.
核心思想: 化整为零 (拆)

2.1.3 分布式系统

2.1.3.0 业务分析

说明: 如果将项目中所有的功能都放到一起,则架构的耦合性较高,如果其中一个出现问题,则直接影响整个服务器.
在这里插入图片描述

2.1.3.1 按照业务拆分

说明: 将项目按照业务(模块) 将大型项目进行拆分,拆分为若干的小型的工程.
在这里插入图片描述

2.1.3.2 按照层级拆分

说明: 由于业务的复杂度高导致开发耦合性高/业务耦合较高, 则可以采用按照层级拆分的方式 实现解耦.
在这里插入图片描述

2.1.3.3 关于分布式总结

说明: 通常由于项目的模块众多业务复杂,导致项目开发时耦合性高. 这时采用分布式的思想进行项目拆分(业务(模块)拆分,按照层级拆分).从架构角度实现了解耦.

2.1.3 集群/高可用(HA)

集群: 通常采用多台服务器一起为用户提供服务.
高可用: 当服务器发生故障时,无需人为的干预,自动的实现故障的迁移.

2.2 分布式系统存在的问题

2.2.1 问题说明

1.众多项目如何管理jar包/版本
2.工具包如何优化

2.2.2 聚合工程构建

在这里插入图片描述

3 京淘项目后台搭建

3.1 创建父级工程

3.1.1 创建项目

在这里插入图片描述

3.1.2 编辑pom.xml文件

<?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.jt</groupId>
    <artifactId>jt</artifactId>
    <version>1.0-SNAPSHOT</version>
    <!--指定打包方式 jar/war/pom聚合工程 -->
    <packaging>pom</packaging>

    <!--引入父级工程-->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.5</version>
        <relativePath/>
    </parent>


    <properties>
        <java.version>1.8</java.version>
        <!--跳过测试类打包-->
        <skipTests>true</skipTests>
    </properties>

    <dependencies>
        <!--SpringMVCjar包文件-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- 引入aop支持 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

        <!--热部署工具-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <!--lombok插件-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <!--测试包-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!--引入jdbc包-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>

        <!--引入数据库驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

        <!--spring整合mybatis-plus -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.2</version>
        </dependency>

        <!--spring整合redis -->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-redis</artifactId>
        </dependency>
    </dependencies>

    <!--父级工程是一种结构 没有java代码 不需要执行运行,所以不需要build标签-->
</project>

3.2 创建工具API

3.2.1 创建common项目

在这里插入图片描述

3.2.2 导入资源文件

在这里插入图片描述

3.3 创建jt_manage

3.3.1 创建项目

在这里插入图片描述

3.3.2 编辑pom.xml文件

<?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">
    <parent>
        <artifactId>jt</artifactId>
        <groupId>com.jt</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>jt_manage</artifactId>

    <!-- 依赖工具API-->
    <dependencies>
        <dependency>
            <groupId>com.jt</groupId>
            <artifactId>jt_common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>

    <!--添加build标签-->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>


</project>

3.3.3 导入jt_manage的src文件

说明: 将课前资料中的jt_manage中的src文件导入. 导入之前先删除自己的文件, 效果如图.
在这里插入图片描述

3.3.4 代码测试

在这里插入图片描述

4. 京淘项目业务实现

4.1 关闭ESLint代码校验

在这里插入图片描述

4.1 编辑用户输入框

在这里插入图片描述

4.2 用户数据校验

4.2.1 思路

在防止用户犯错的前提下,尽可能让用户更早地发现并纠正错误。

4.2.2 elementUI表单校验

API用法: Form 组件提供了表单验证的功能,只需要通过 rules 属性传入约定的验证规则,并将 Form-Item 的 prop 属性设置为需校验的字段名即可。
1).编辑页面HTML
在这里插入图片描述
2).编辑页面JS
在这里插入图片描述
3).页面效果展现
在这里插入图片描述

4.3 表单重置

4.3.1 需求说明

说明:当用户点击重置按钮时,应该清空表单数据.

4.3.2 组件结构

在这里插入图片描述

4.3.4 实现表单重置

在这里插入图片描述

4.4 登录校验

4.4.1 校验API

在这里插入图片描述

4.4.2 编辑页面JS

在这里插入图片描述

4.5 引入Axios组件

说明: 在main.js中添加axios的组件,并且设定全局变量.

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import './plugins/element.js'
import './assets/css/global.css'
import './assets/ali-icon/iconfont.css'

/* 导入axios包 */
import axios from 'axios'
/* 设定axios的请求根目录 */
axios.defaults.baseURL = 'http://localhost:8091/'
/* 向vue对象中添加全局对象 以后发送ajax请求使用$http对象 */
Vue.prototype.$http = axios



Vue.config.productionTip = false

new Vue({
  router,
  render: h => h(App)
}).$mount('#app')

4.6 登录业务实现

4.6.1 编辑VO对象

说明: 在jt-common的vo中添加SysResult对象

package com.jt.vo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

@Data
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
public class SysResult {

    private Integer status; //状态码信息 200成功  201失败
    private String msg;     //服务器提示信息
    private Object data;    //服务器返回值

    public static SysResult fail(){
        return new SysResult(201,"服务器运行失败",null);
    }

    public static SysResult success(){
        return new SysResult(200, "服务器运行成功", null);
    }

    public static SysResult success(Object data){
        return new SysResult(200, "服务器运行成功", data);
    }

    public static SysResult success(String msg,Object data){
        return new SysResult(200, msg, data);
    }
}

4.6.2 编辑UserController

说明: 根据Ajax提交的请求,在UserController中编辑方法,实现用户登录业务.

package com.jt.controller;

import com.jt.pojo.User;
import com.jt.service.UserService;
import com.jt.vo.SysResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/**
 * @author 刘昱江
 * 时间 2021/5/11
 */
@RestController
@CrossOrigin
@RequestMapping("/user")    //抽取公共的请求
public class UserController {

    @Autowired
    private UserService userService;

    /**
     * 1.url地址: /user/login
     * 2.请求参数: 用户表单对象的JSON串   post类型
     * 3.返回值结果 SysResult  token?有值 正确        null 错误
     */
    @PostMapping("/login")
    public SysResult login(@RequestBody User user){

        String token = userService.findUserByUP(user);
        if(StringUtils.hasLength(token)){
            return SysResult.success(token);
        }else{
            return SysResult.fail();
        }
    }

}

4.6.3 MD5

MD5信息摘要算法(英语:MD5 Message-Digest Algorithm),一种被广泛使用的密码散列函数,可以产生出一个128位(16字节)的散列值(hash value),用于确保信息传输完整一致。MD5由美国密码学家罗纳德·李维斯特(Ronald Linn Rivest)设计,于1992年公开,用以取代MD4算法。这套算法的程序在 RFC 1321 标准中被加以规范。1996年后该算法被证实存在弱点,可以被加以破解,对于需要高度安全性的数据,专家一般建议改用其他算法,如SHA-2。2004年,证实MD5算法无法防止碰撞(collision),因此不适用于安全性认证,如SSL公开密钥认证或是数字签名等用途。

4.6.4 编辑UserService

在这里插入图片描述

作业

完成用户登录操作

1 用戶页面布局

1.1 面包屑导航

1.1.1官网API

在这里插入图片描述

1.1.2 编辑页面VUE

	  <!-- 1.编辑面包屑导航 -->
      <el-breadcrumb separator-class="el-icon-arrow-right">
        <el-breadcrumb-item :to="{ path: '/home' }">首页</el-breadcrumb-item>
        <el-breadcrumb-item>用户管理</el-breadcrumb-item>
        <el-breadcrumb-item>用户列表</el-breadcrumb-item>
      </el-breadcrumb>

1.1.3 页面效果展现

在这里插入图片描述

1.2 Card 卡片

1.2.1 官网API

在这里插入图片描述

1.2.2 vue中使用卡片

	  <!-- 2.定义卡片标签 -->
      <el-card class="box-card">
        这是一个卡片视图
      </el-card>

1.2.2 按需导入样式

1).导入标签
在这里插入图片描述
2).设置全局可用
在这里插入图片描述

1.3 编辑用户输入框

1.3.1 官方API

在这里插入图片描述

1.3.2 栅格API

在这里插入图片描述

1.3.3 编辑页面VUE

 <!-- 2.1 定义一行元素 -->
        <el-row :gutter="20">
          <el-col :span="9">
            <!-- 2.1定义用户的输入框 -->
             <el-input placeholder="请输入内容" v-model="input3" class="input-with-select">
                <el-button slot="append" icon="el-icon-search"></el-button>
             </el-input>
          </el-col>

          <el-col :span="4">
            <!-- 2.2 定义新增用户按钮-->
            <el-button type="primary">添加用户</el-button>
          </el-col>
        </el-row>

1.3.4 页面效果

在这里插入图片描述

1.4 获取后端用户数据

1.4.1 前端业务接口

在这里插入图片描述

1.4.2 PageResult对象 接口说明

在这里插入图片描述

1.4.3 编辑PageResult VO对象

说明: 在jt-manage中的com.jt.vo 中定义 VO对象
在这里插入图片描述

1.4.4 编辑UserController

 /**
     * 需求: 进行分页查询
     * URL地址:  /user/list
     * 请求参数: 使用PageResult对象接收
     * 请求返回值: SysResult对象
     * 请求类型: get请求
     */
    @GetMapping("/list")
    public SysResult findUserByPage(PageResult pageResult){//只有3个参数
        //携带所有的数据返回
        pageResult = userService.findUserByPage(pageResult);
        return SysResult.success(pageResult);
    }

1.4.5 编辑UserService

 /**
     * 业务说明: 将后台数据实现分页查询
     * 分页Sql:
     *      select * from user limit 起始位置,查询记录数
     * 查询第一页 每页20条
     *      select * from user limit 0,20
     * @param pageResult
     * @return
     *
     * MP实现分页查询
     *  MP通过分页对象进行查询,获取所有的分页相关的数据.
     *
     * 参数说明:
     *  page: 定义当前的分页对象 页面/每页的条数
     *  queryWrapper: 条件构造器 只有query属性不为null 才会拼接where条件.
     */

    @Override
    public PageResult findUserByPage(PageResult pageResult) {
        //1.定义分页对象  2个参数
        IPage<User> page =
                new Page<>(pageResult.getPageNum(),
                              pageResult.getPageSize());
        //2.定义查询条件
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        //3.判断用户是否有参数
        boolean flag = StringUtils.hasLength(pageResult.getQuery());
        queryWrapper.like(flag,"username", pageResult.getQuery());

        //page 参数4个
        page = userMapper.selectPage(page,queryWrapper);
        //4.获取总记录数
        long total = page.getTotal();
        //5.获取分页后的结果
        List<User> userList = page.getRecords();
        return pageResult.setTotal(total).setRows(userList);
    }

1.4.6 编辑MybatisPlus配置类

@Configuration  //标识配置类
public class MybatisPlusConfig {

    //MybatisPlus~~动态添加执行器~~Mybatis~~~~JDBC
    //照着官方文档实现即可
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MARIADB));
        return interceptor;
    }
}

1.4.7 获取返回值结果

URL地址: http://localhost:8091/user/list?query=&pageNum=3&pageSize=1   查询的第三页的数据 每页一条
JSON结构:
	{"status":200,"msg":"服务器运行成功","data":{"query":"","pageNum":3,"pageSize":1,"total":4,"rows":[{"created":"2021-02-18T11:17:23.000+00:00","updated":"2021-03-13T08:50:25.000+00:00","id":3,"username":"zhangsan","password":"a66abb5684c45962d887564f08346e8d","phone":"13111112223","email":"1235678@qq.com","status":true,"role":null}]}}

1.5 编辑用户列表前端

1.5.1 表格数据API

当el-table元素中注入data对象数组后,在el-table-column中用prop属性来对应对象中的键名即可填入数据,用label属性来定义表格的列名。可以使用width属性来定义列宽。

    <el-table
      :data="tableData"
      style="width: 100%">
      <el-table-column
        prop="date"
        label="日期"
        width="180">
      </el-table-column>
   </el-table>
   

1.5.2 编辑页面JS

<script>
  export default {
    data(){
      return {
        //定义分页查询对象
        queryInfo: {
          query: '',    //用户查询的数据
          pageNum: 1,   //默认第一页
          pageSize: 5   //每页5条
        },
        userList: [],   //获取分页后的结果
        total: 0
      }
    },
    methods: {
      //1.动态获取userList数据
      async getUserList(){
       const {data: result} = await this.$http.get("/user/list",{params: this.queryInfo})
       if(result.status !== 200) return this.$message.error("获取列表失败")
       //为total属性赋值
       this.total = result.data.total
       this.userList = result.data.rows
      }
    },
    //当页面加载完成之后 调用该函数
    mounted(){
      //获取userList列表数据
      this.getUserList()
    }
  }
</script>

1.5.3 编辑表格页面

 <!-- 定义表格数据
           :data: 表格的数据来源
           prop:  从userList中获取的属性值
           label: 字段名称
           stripe: 斑马纹效果
           border: 列
        -->
         <el-table :data="userList" style="width: 100%" stripe border>
            <el-table-column prop="username" label="用户名"></el-table-column>
            <el-table-column prop="phone" label="电话"></el-table-column>
            <el-table-column prop="email" label="邮箱"></el-table-column>
            <el-table-column prop="status" label="状态"></el-table-column>
            <el-table-column label="操作"></el-table-column>
         </el-table>

1.5.4 Vue语法作用域插槽

说明: 一般在循环遍历的表格中,需要获取当前行的元素.但是由于很多的UI工具将循环遍历的方式进行了封装.不方便直接获取对象.则可以使用作用域插槽的形式动态获取.

 <template slot-scope="scope">
              <!-- scope封装的对象 获取行级元素 row属性实行 -->
              {{scope.row.status}}
     </template>

1.5.5 展现开关

<el-table :data="userList" style="width: 100%" stripe border>
            <el-table-column prop="username" label="用户名"></el-table-column>
            <el-table-column prop="phone" label="电话"></el-table-column>
            <el-table-column prop="email" label="邮箱"></el-table-column>
            <el-table-column prop="status" label="状态">
              <template slot-scope="scope">
                  <!-- scope封装的对象 获取行级元素 row属性实行 -->
                  <el-switch
                    v-model="scope.row.status"
                    active-color="#13ce66"
                    inactive-color="#ff4949">
                  </el-switch>
              </template>
            </el-table-column>
            <el-table-column label="操作">
              <el-button type="primary" icon="el-icon-edit" size="small"></el-button>
              <el-button type="danger" icon="el-icon-delete" size="small"></el-button>
            </el-table-column>
         </el-table>

1.5.6 效果展现

在这里插入图片描述

1.6 表格分页实现

1.6.1 官网API

在这里插入图片描述

1.6.2 实现分页

 <!-- 3.定义分页功能
           1.@size-change  当页面的条数变化时触发
           2.@current-change  当页数改变时触发
           3.current-page  显示当前的页数 ??
           4.:page-sizes   显示页数的数组
           5.page-size     初始条件下每页的条数
           6.layout        显示分页的样式种类 全部显示
           7.total         数据的总数  ???
         -->
        <el-pagination
              @size-change="handleSizeChange"
              @current-change="handleCurrentChange"
              :current-page="queryInfo.pageNum"
              :page-sizes="[5, 10, 20, 40]"
              :page-size="queryInfo.pageSize"
              layout="total, sizes, prev, pager, next, jumper"
              :total="total">
        </el-pagination>

1.6.3 编辑页面JS

<script>
  export default {
    data(){
      return {
        //定义分页查询对象
        queryInfo: {
          query: '',    //用户查询的数据
          pageNum: 1,   //默认第一页
          pageSize: 5   //每页5条
        },
        userList: [],   //获取分页后的结果
        total: 0
      }
    },
    methods: {
      //1.动态获取userList数据
      async getUserList(){
       const {data: result} = await this.$http.get("/user/list",{params: this.queryInfo})
       if(result.status !== 200) return this.$message.error("获取列表失败")
       //为total属性赋值
       this.total = result.data.total
       this.userList = result.data.rows
      },
      handleSizeChange(pageSize){
        //查询的条件需要变化
        this.queryInfo.pageSize = pageSize
        //重新查询数据
        this.getUserList()
      },
      handleCurrentChange(pageNum){
        this.queryInfo.pageNum = pageNum
        this.getUserList()
      }


    },
    //当页面加载完成之后 调用该函数
    mounted(){
      //获取userList列表数据
      this.getUserList()
    }
  }
</script>

在这里插入图片描述

1.7 用户搜索的实现

1.7.1 编辑页面HTML

在这里插入图片描述

1.7.2 设定清空input框

1).页面API
在这里插入图片描述
2).input 事件
在这里插入图片描述

1.7.3 编辑页面HTML

在这里插入图片描述

1.8 实现用户状态修改

1.8.1 官网API

在这里插入图片描述
在这里插入图片描述

1.8.2 业务接口

在这里插入图片描述

1.8.3 编辑页面JS

async updateStatus(user){
        //获取用户的Id号/状态信息 发起restFul请求.
        //this.$http.put("/user/status/"+user.id+"/"+user.status)
        //模板字符串写法 `` 可以编辑多行,可以直接对象取值${key}
        //es6的高端写法
        const {data: result} =
        await this.$http.put(`/user/status/${user.id}/${user.status}`)
        if(result.status !== 200) return this.$message.error("更新操作失败")
        this.$message.success("更新操作成功!")
      }

1.8.4 编辑UserController

 /**
     * 更新状态信息
     * URL: /user/status/{id}/{status}
     * 参数:  id/status
     * 返回值: SysResult对象
     */
    @PutMapping("/status/{id}/{status}")
    public SysResult updateStatus(User user){

        userService.updateStatus(user);
        return SysResult.success();
    }

1.8.5 编辑UserService

@Override
    public void updateStatus(User user) {   //id/status

        userMapper.updateById(user);
    }

1.实现用户新增

1.1 编辑新增页面

1.1.1 官网API

在这里插入图片描述

1.1.2 定义对话框

在这里插入图片描述

1.2 关于正则表达式

1.2.1 正则介绍

正则表达式,又称规则表达式。(英语:Regular Expression,在代码中常简写为regex、regexp或RE),计算机科学的一个概念。正则表达式通常被用来检索、替换那些符合某个模式(规则)的文本。

1.2.2 正则语法

{固定次数} [取值的范围] (分组)
demo: "[a-z]+.(jpg|png|gif)"
在这里插入图片描述

1.2.3 完成用户校验

<script>
  export default {
    data(){

      //自定义校验规则 rule:当前规则对象一般不用  value: 当前校验的数据  callback:回调函数
      //校验邮箱规则
      const checkEmail = (rule, value, callback) => {
        //定义邮箱的正则表达式  JS中用/来表示正则表达式的开始和结束
        const emailRege = /^[a-zA-Z0-9-_]+@[a-zA-Z0-9-_]+\.[a-zA-Z0-9-_]+$/
        if (emailRege.test(value)) {
          //表示邮箱合法 正确返回  通过返回true   失败返回false
          return callback() //自定义规则执行成功,之后后续操作
        }
        callback(new Error('请填写正确的邮箱地址'))
      }

      //校验手机号的邮箱规则
      const checkPhone = (rule, value, callback) => {

        //定义校验手机号的正则语法
        const phoneRege = /^1[3456789][0-9]{9}$/
        if (phoneRege.test(value)) {

          return callback()
        }
        callback(new Error('请填写正确的手机号'))

      }

      //密码确认  判断与password是否相同
      const checkPassword = (rule, value, callback) => {

        if(value !== this.addUserForm.password){
           return callback(new Error('2次密码填写不一致'))
        }
        //如果相同,则调用回调函数
        callback()
      }

      return {
        //定义分页查询对象
        queryInfo: {
          query: '',    //用户查询的数据
          pageNum: 1,   //默认第一页
          pageSize: 5   //每页5条
        },
        userList: [],   //获取分页后的结果
        total: 0,
        addUserDialogVisible: false,
        //设定新增用户的对象
        addUserForm: {
          username: '',
          password: '',
          password2:  '',
          phone:  '',
          email:  ''
        },
        rules: {
           username: [
                      { required: true, message: '请输入用户名', trigger: 'blur' },
                      { min: 3, max: 30, message: '长度在 3 到 30 个字符', trigger: 'blur' }
                    ],
           password: [
                      { required: true, message: '请输入密码', trigger: 'blur' },
                      { min: 3, max: 30, message: '长度在 3 到 30 个字符', trigger: 'blur' }
                    ],
           password2: [
                      { required: true, message: '请输入密码', trigger: 'blur' },
                      { min: 3, max: 30, message: '长度在 3 到 30 个字符', trigger: 'blur' },
                      { validator: checkPassword, trigger: 'blur' }
                    ],
           phone: [
                      { required: true, message: '请输入电话', trigger: 'blur' },
                      { min: 11, max: 11, message: '长度必须11个字符', trigger: 'blur' },
                      { validator: checkPhone, trigger: 'blur' }
                    ],
           email: [
                      { required: true, message: '请输入邮箱地址', trigger: 'blur' },
                      { min: 3, max: 30, message: '长度在 3 到 30 个字符', trigger: 'blur' },
                      { validator: checkEmail, trigger: 'blur' }
                    ],
        }
      }
    }
    ....后边省略

1.3 重置表单

1.3.1 官网API

说明: 当用户点击取消/关闭对话框时,触发关闭回调操作.
在这里插入图片描述

1.3.2 编辑页面

在这里插入图片描述
在这里插入图片描述

1.3 用户最终校验

1.3.1 编辑页面JS

在这里插入图片描述

1.3.2 用户新增业务接口

在这里插入图片描述

1.3.3 编辑页面JS

在这里插入图片描述

1.3.4 编辑UserController

在这里插入图片描述

1.3.5 编辑UserService

在这里插入图片描述

1.4 数据自动填充

1.4.1 业务说明

由于架构设计通常会添加一些必要的属性,但是该属性每次都要写,造成重复. 代码冗余,能否优化?

1.4.2 编辑POJO

说明: 将公共的属性进行抽取,之后根据MP的自动填充的机制,跳转合适的操作(CRUD)进行填充
在这里插入图片描述

1.4.3 编辑自动填充代码

@Component
public class MyMetaObjectHandler implements MetaObjectHandler {

    //入库操作时,需要更新 创建事件/更新时间
    @Override
    public void insertFill(MetaObject metaObject) {
        Date date = new Date();
        this.setFieldValByName("created",date,metaObject);
        this.setFieldValByName("updated",date,metaObject);
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        this.setFieldValByName("updated",new Date(),metaObject);
    }
}

1.5 用户数据删除

1.5.1 官网API

在这里插入图片描述

1.5.2 编辑前端JS

async deleteUser(user){
        //定义消息确认框 promise对象 如果从中获取用户的选项 不方便
        const result = await this.$confirm('此操作将永久删除'+user.username+', 是否继续?', '提示', {
                  confirmButtonText: '确定',
                  cancelButtonText: '取消',
                  type: 'warning'
              }).catch(error => error)

        //确定: confirm   取消 cancel
        if(result !== 'confirm') return this.$message.info("用户取消操作")

        //发起ajax请求实现数据的删除...
        const {data: resultDB} = await this.$http.delete('/user/'+user.id)
        if(resultDB.status !== 200) return this.$message.error("用户删除失败!")
        this.$message.success("用户删除成功!")
        //重新加载用户列表
        this.getUserList()
      }

1.5.3 编辑UserController

/**
     * 删除用户
     * URL: /user/{id}
     * 参数: 用户的ID号
     * 返回值: SysResult对象
     * 关于ajax说明:
     *      @RequestBody PUT/POST  要求ajax传递的对象 自己封装为JSON 所以在后端添加注解
     *      GET/DELETE   数据都是普通数据  后端正常接收可以
     *
     */
    @DeleteMapping("/{id}")
    public SysResult deleteUserById(@PathVariable Integer id){

        userService.deleteUserById(id);
        return SysResult.success();
    }

1.5.3 编辑UserService

 @Override
    public void deleteUserById(Integer id) {

        userMapper.deleteById(id);
    }

2 关于知识点梳理

2.1 列表页面结构

在这里插入图片描述

2.2 新增用户页面

在这里插入图片描述

作业

实现用户的修改 要求只修改电话/邮箱
在这里插入图片描述

1. 商品业务处理

1.1 实现文件上传

1.1.1 编辑ImageVO对象

在这里插入图片描述

1.1.2 编辑FileController

@RestController
@CrossOrigin
@RequestMapping("/file")
public class FileController {

    @Autowired
    private FileService fileService;

    @PostMapping("/upload")
    public SysResult upload(MultipartFile file) throws IOException {

        ImageVO imageVO = fileService.upload(file);
        if(imageVO == null){
            return SysResult.fail();
        }
        return SysResult.success(imageVO);
    }
 }

1.1.3 编辑pro配置文件

	image.localPathDir=D:/JT_IMAGE
	image.localUrlPath=http://image.jt.com

1.1.4 编辑FileService

@Service
@PropertySource("classpath:/properties/image.properties")
public class FileServiceImpl implements FileService{

    //为属性动态赋值 注解@Value
    @Value("${image.localPathDir}")
    private String localPathDir;        // = "D:/JT_IMAGE";
    @Value("${image.localUrlPath}")
    private String localUrlPath;        // = "http://image.jt.com";


    //1.参数  ~~~已知条件
    //2.干什么 ~~~ 实现文件上传
    //3.返回值: void ImageVO 有效返回

    /**
     * 文件上传案例实现
     * 1.如何保证前端是上传的数据是有效的!!
     *      1.1 校验文件的名称检查是否为图片
     *      1.2 校验是否为恶意程序.
     * @param file
     * @return
     */
    @Override
    public ImageVO upload(MultipartFile file) throws IOException {
        //1.1校验是否为图片类型  abc.jpg ABC.JPG 文件大小写
        String fileName = file.getOriginalFilename();
        //将所有的文件名称转化为小写
        fileName = fileName.toLowerCase();
        if(!fileName.matches("^.+\\.(jpg|png|gif)$")){
            return null;
        }
        //1.2 校验图片类型是否为木马
        try {
            BufferedImage bufferedImage = ImageIO.read(file.getInputStream());
            int width = bufferedImage.getWidth();
            int height = bufferedImage.getHeight();
            if(width == 0 || height == 0 ){
                return null;
            }
        }catch (Exception e){
            return null;
        }

        //2. 目录结构
        //2.1 实现分目录存储...  可以以时间维度进行分隔 /yyyy/MM/dd/
        String datePath =
                new SimpleDateFormat("/yyyy/MM/dd/").format(new Date());
        //2.2 进行目录的拼接  "D:/JT_IMAGE/2021/11/11";
        String localDir = localPathDir + datePath;
        //2.3 需要创建目录
        File dirFile = new File(localDir);
        if(!dirFile.exists()){
            dirFile.mkdirs();
        }

        //3.文件名称重复  采用UUID防止文件重名 uuid.jpg
        String uuid = UUID.randomUUID().toString()
                        .replace("-", "");
        //fileName = abc.jpg
        String fileType =
                fileName.substring(fileName.lastIndexOf("."));
        String realFileName = uuid + fileType;

        //c:jt_image/2021/11/11/uuid.jpg
        String filePathAll = localDir + realFileName;
        //实现文件上传
        File realFile = new File(filePathAll);
        file.transferTo(realFile);

        //2021/11/11/uuid.jpg
        String virtualPath = datePath + realFileName;
        //http://image.jt.com/2021/11/11/uuid.jpg
        String urlPath = localUrlPath + virtualPath;
        return new ImageVO(virtualPath,urlPath,realFileName);
    }
 }

1.2 实现图片删除

1.2.1 编辑页面JS

在这里插入图片描述

1.2.2 编辑FileController

 //实现文件的删除功能
    //URL: /file/deleteFile
    @DeleteMapping("/deleteFile")
    public SysResult fileRemove(String virtualPath){

        fileService.fileRemove(virtualPath);
        return SysResult.success();
    }

1.2.3 编辑FileService

	//如何实现文件删除??  virtualPath: 2021/11/11/uuid.jpg
    @Override
    public void fileRemove(String virtualPath) {
        String filePath = localPathDir + virtualPath;
        File file = new File(filePath);
        //删除文件
        file.delete();
    }

1.3 富文本编辑器实现

1.3.1 导入样式

在这里插入图片描述

1.3.2 导入富文本CSS样式

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import './plugins/element.js'
import './assets/css/global.css'
import './assets/ali-icon/iconfont.css'

/* 导入富文本编辑器 */
import VueQuillEditor from 'vue-quill-editor'

/* 导入富文本编辑器对应的样式 */
import 'quill/dist/quill.core.css' // import styles
import 'quill/dist/quill.snow.css' // for snow theme
import 'quill/dist/quill.bubble.css' // for bubble theme
/* 导入axios包 */
import axios from 'axios'


/* 设定axios的请求根目录 */
axios.defaults.baseURL = 'http://localhost:8091/'
/* 向vue对象中添加全局对象 以后发送ajax请求使用$http对象 */
Vue.prototype.$http = axios

/* 将富文本编辑器注册为全局可用的组件 */
Vue.use(VueQuillEditor)

//定义格式化价格的过滤器
Vue.filter('priceFormat',(price) => {

  return (price/100).toFixed(2)
})


Vue.config.productionTip = false

new Vue({
  router,
  render: h => h(App)
}).$mount('#app')

1.4 实现商品新增

1.4.1 商品新增的数据结构

1.商品的基本信息 item

  1. 商品的参数信息 注意每个商品都应该有自己单独的参数 item_param
  2. 商品详情信息 每个商品都应该有自己的详情 (大字段存储) item_desc

1.4.2 商品新增的JS

在这里插入图片描述

1.4.3 商品新增业务接口

在这里插入图片描述
数据返回值:
在这里插入图片描述

1.4.4 关于JSON转化API

说明: 使用ObjectMapper 实现对象的转化
1). writeValueAsString 表示将对象转化为JSON
2). readValue 表示将JSON串转化为对象

 @Test
    public void toJSON() throws JsonProcessingException {
        ObjectMapper mapper = new ObjectMapper();
        ItemParamVO itemParamVO = new ItemParamVO();
        itemParamVO.setParamId(1);
        itemParamVO.setParamVals("100");
        ItemParamVO itemParamVO2 = new ItemParamVO();
        itemParamVO2.setParamId(1);
        itemParamVO2.setParamVals("100");
        List list = new ArrayList();
        list.add(itemParamVO);
        list.add(itemParamVO2);
        String json =
                mapper.writeValueAsString(list);

        //JSON转化为对象
        List<ItemParamVO> list2 = mapper.readValue(json, List.class);
        System.out.println(list2);
    }

1.4.5 编辑ItemController

在这里插入图片描述

1.4.6 编辑ItemService

/**
     * 实现三张表入库 商品表/商品详情表/商品参数表
     * @param itemVO
     */
    @Transactional
    @Override
    public void saveItem(ItemVO itemVO){
        //1.入库商品表
        Item item = itemVO.getItem();
        item.setStatus(true);    //默认启用状态
        //要求入库之后返回主键
        //MP如果设定了主键自增则会自动的实现数据回显
        itemMapper.insert(item);

        //2.入库商品详情
        ItemDesc itemDesc = itemVO.getItemDesc();
        itemDesc.setId(item.getId());
        itemDescMapper.insert(itemDesc);

        //3.入库商品参数
        //1.一个商品应该有自己的单独的参数. 动态参数/静态属性 KYE-VLAUE [key:value,key2:value2]
        ItemParam itemParam = itemVO.getItemParam();
        ItemParamVO[] dynamic = itemParam.getDynamicArray();
        ItemParamVO[] staticParam  = itemParam.getStaticArray();
        try {
            //将页面传递的数据转化为JSON,之后数据库保存
            String dynamicJSON = MAPPER.writeValueAsString(dynamic);
            String staticJSON = MAPPER.writeValueAsString(staticParam);
            //封装商品参数信息
            itemParam.setDynamicArgs(dynamicJSON)
                     .setStaticArgs(staticJSON)
                     .setId(item.getId());
            //实现入库操作
            itemParamMapper.insert(itemParam);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
            //如果程序执行报错 则抛出异常
            throw new RuntimeException(e);
        }
    }

1.Nginx

1.1 问题说明

虚拟路径:
http://image.jt.com/2021/05/22/6fc9566f8911420fb1ae5c31cd36ae34.jpg
真实磁盘路径:
D:\JT_IMAGE\2021\05\22\6fc9566f8911420fb1ae5c31cd36ae34.jpg
说明: 如果通过虚拟路径进行访问,由于没有进行路径的映射,所以不能展现图片!!!
解决方案:
http://image.jt.com -> D:\JT_IMAGE 进行绑定(映射)

实现方案:反向代理技术

1.2 关于代理机制说明(考点)

1.2.1 反向代理

介绍:
反向代理服务器位于用户与目标服务器之间,但是对于用户而言,反向代理服务器就相当于目标服务器,即用户直接访问反向代理服务器就可以获得目标服务器的资源。同时,用户不需要知道目标服务器的地址,也无须在用户端作任何设定。反向代理服务器通常可用来作为Web加速,即使用反向代理作为Web服务器的前置机来降低网络和服务器的负载,提高访问效率。 [1]

反向代理流程图:
在这里插入图片描述
总结:
1.反向代理服务器介于用户与目标服务器之间
2. 用户以为反向代理服务器就是目标服务器.
3. 用户无须关心真实的服务器地址. 反向代理机制保护了目标服务器的信息

1.2.2 正向代理

正向代理,意思是一个位于客户端和原始服务器(origin server)之间的服务器,为了从原始服务器取得内容,客户端向代理发送一个请求并指定目标(原始服务器),然后代理向原始服务器转交请求并将获得的内容返回给客户端。客户端才能使用正向代理。

总结:
1. 代理服务器介于用户和目标服务器之间
2. 用户发起请求时,明确告知代理服务器访问的真实地址是谁
3. 正向代理保护了客户的信息.服务器无须了解真实的访问者到底是谁!!!
一般的正向代理通常用在网络请求中(路由器!!!!)
在这里插入图片描述

1.2.3 实际应用

一般情况下 正向代理和反向代理都会使用. 正向服务实现网络通讯,,反向负责获取服务器数据.
在这里插入图片描述

1.3 Nginx服务器

1.3.1 Nginx介绍

Nginx (engine x) 是一个高性能的HTTP和反向代理web服务器,同时也提供了IMAP/POP3/SMTP服务。Nginx是由伊戈尔·赛索耶夫为俄罗斯访问量第二的Rambler.ru站点(俄文:Рамблер)开发的,第一个公开版本0.1.0发布于2004年10月4日。

Nginx并发能力: 5万/秒 实际能力: 3万/秒
开发语言: C语言

1.3.2 Nginx下载

在这里插入图片描述

1.3.3 Nginx安装说明

1).nginx安装的目录中不能出现中文/空格/C盘的系统文件中.
2).nginx 会默认占用80端口
3).nginx 启动时需要通过命令执行.

1.3.4 Nginx启动步骤

1).首先以管理员身份运行 获取权限
2).访问网址:localhost:80 是否正常
在这里插入图片描述
如果启动异常,则去京淘问题集 检查标题8

1.3.5 Nginx进程项说明

主进程: 主要提供反向代理服务的.
守护进程: 防止主进程意外关闭
在这里插入图片描述

1.3.6Nginx命令

要求: 在nginx的根目录中执行
命令:
1.启动nginx start nginx 如果配置文件有错 也不提示.
2.重启nginx nginx -s reload 配置文件有错 ,会报错提示
3.关闭nginx nginx -s stop

1.4 Nginx反向代理机制说明

在这里插入图片描述

1.5 Nginx实现图片反向代理

1.5.1 代理规则

虚拟路径: http://image.jt.com:80/2021/05/22/6fc9566f8911420fb1ae5c31cd36ae34.jpg
磁盘地址: D:\JT_IMAGE/2021/05/22/6fc9566f8911420fb1ae5c31cd36ae34.jpg

1.5.2 反向代理配置

#配置图片代理服务器
	server {
		listen 80;
		server_name image.jt.com;

		location / {
			#注意使用/   不要使用\
			root D:/JT_IMAGE;
		}
	}

在这里插入图片描述

1.5.3 图片回显流程

如果需要访问本地的Nginx服务器,则需要配置hosts文件,实现域名与IP的映射.
在这里插入图片描述
HOSTS.文件位置:
在这里插入图片描述

修改HOSTS:

#IP 域名  映射关系
#图片服务器域名
127.0.0.1  image.jt.com

#后台服务器域名
127.0.0.1  manage.jt.com

#前台服务器域名
127.0.0.1  web.jt.com

页面效果展现
在这里插入图片描述

1.6 关于图片回显报错解决方案

1.6.1 请求路径问题

1.检查URL路径是否正确: 注意协议名称是否添加
http://image.jt.com/2021/05/22/e342270ac43a4306a361d1d6a796a39a.jpg

2.更换磁盘路径 检查是否正确
D:/JT_IMAGE/2021/05/22/e342270ac43a4306a361d1d6a796a39a.jpg
如果测试通过则表示后端代码没错.

1.6.2 HOSTS文件测试

将hosts中的域名直接访问,,检查是否如图
在这里插入图片描述

1.6.3 检查Nginx配置

注意 / 问题
在这里插入图片描述

1.6.4 检查Nginx是否重启

将nginx全部关闭. 关闭之后重启nginx
在这里插入图片描述

2 Windows项目发布

2.1 将项目编译打包

2.1.1 打包前台

在这里插入图片描述

2.1.2 检查是否有打包文件

在这里插入图片描述

2.1.3 将文件导入nginx

在这里插入图片描述

2.1.4 编辑前端代理

	#配置前端服务器  web.jt.com:80
	server {
		listen 80;
		server_name web.jt.com;
		location / {
			root  dist;
			index  index.html;
		}
	}

2.1.5 页面效果展现

在这里插入图片描述

2.2 后端服务器搭建

2.2.1 动态获取端口

在这里插入图片描述

2.2.2 利用域名实现后端访问

说明: 要求用户访问: manage.jt.com 实现后端服务器跳转

#配置后端服务器
	server {
		listen 80;
		server_name manage.jt.com;

		location / {
			#表示映射远程链接
			proxy_pass  http://localhost:8091;
		}
	}

2.3 后端集群搭建

2.3.1 集群搭建架构图

在这里插入图片描述

2.3.2 项目打包

在这里插入图片描述2).查找jar包文件
在这里插入图片描述
3).将YMl配置文件修改为8092之后,重新打包,效果如下 启动之前确保IDEA中的服务应该关闭
在这里插入图片描述

2.3.3 项目发布

发布命令: java -jar 8091.jar
java -jar 8092.jar

注意事项: 每个终端都会被一个进程使用,如果需要启动多个tomcat服务器,则应该开启多个终端

在这里插入图片描述
在这里插入图片描述

2.4 实现集群配置

要求: 通过manage.jt.com 要求访问8091/8092的服务器.

2.4.1 编辑nginx配置文件

#集群配置
	upstream jts {
		server localhost:8091;
		server localhost:8092;
		
	}



	#配置后端服务器
	server {
		listen 80;
		server_name manage.jt.com;

		location / {
			#表示映射远程链接
			#proxy_pass  http://localhost:8091;
			proxy_pass  http://jts;		
		}
	}

2.5 负载均衡

2.5.1 轮询

说明: 根据配置文件的顺序 依次访问服务器.
在这里插入图片描述

2.5.2 权重

说明: 根据设定的权重大小 挑选哪台服务器优先访问.
在这里插入图片描述

2.5.3 IPHASH策略

说明: 如果需要用户与服务器进行绑定,则使用该策略
在这里插入图片描述
IPHASH算法:
在这里插入图片描述

2.6 实现前后端调用

1).修改路由文件
在这里插入图片描述
2).修改addItem.vue文件上传路径
在这里插入图片描述

1.windows项目发布

1.1 发布准备

1). web.jt.com 可以利用nginx反向代理机制 访问前端系统
2).前端访问后端的网址:
现在: http://localhost:8091
优化: 利用后端网址进行访问: http://manage.jt.com
3).后端访问:
http://manage.jt.com
真实服务器: localhost:8091/localhost:8092

1.2 发布流程图

在这里插入图片描述

1.3 项目发布流程

1). 修改main.js
在这里插入图片描述
2).修改文件上传的路径
在这里插入图片描述
3).项目重新编译
在这里插入图片描述
4).将前端重新发布到nginx目录下
在这里插入图片描述
5).项目发布
在这里插入图片描述

2 Linux项目发布

2.1 修改IP地址

2.1.1 修改虚拟机IP地址

在这里插入图片描述

2.1.2 配置DHCP

在这里插入图片描述

2.1.3 关于IP说明

1).windowsIP地址:
在这里插入图片描述
2).Linux IP 命令: ip addr

如果出现下列的现象,则表示Linux网卡没有刷新,需要重启即可.
在这里插入图片描述

2.1.4 重置Linux IP命令

说明: 如果Linux 中的IP地址不能展现,则是使用如下命令

service NetworkManager stop 
chkconfig  NetworkManager  off    永久关闭 Manager网卡
service  network restart		  重启network网卡

在这里插入图片描述

2.1.5 检查Linux 是否正常

在这里插入图片描述

2.2 远程连接工具安装

2.2.1 创建用户

创建用户之后填写密码保护(记住)
在这里插入图片描述

2.2.2 点击登录

在这里插入图片描述

3 Linux环境部署

3.1 安装JDK

3.1.1 上传JDK

在这里插入图片描述

3.1.2 解压文件

命令: tar -xvf jdk-8u51-linux-x64.tar.gz
在这里插入图片描述

3.1.3 校验JDK是否有效

在这里插入图片描述

3.1.4 修改JDK环境变量

编辑文件: /etc/profile
在这里插入图片描述
2).让环境变量生效
2.1).重启linux系统
2.2).刷新系统变量 source /etc/profile
在这里插入图片描述

3.2 安装Linux数据库

3.2.1 安装数据库流程

在这里插入图片描述

3.2.2 安装过程参见文档

3.2.3最终效果

只要能正常使用,导入windows中的数据库即可.
在这里插入图片描述

3.4 tomcat服务器部署

3.4.1 修改数据库连接

在这里插入图片描述

3.4.2 图片保存路径

在这里插入图片描述

3.4.3 tomcat打包部署

在这里插入图片描述

3.4.4 上传jar包文件

在这里插入图片描述

3.4.5 项目发布

命令: java -jar 8091.jar
访问测试:
在这里插入图片描述

3.4.6 tomcat服务器后端运行

命令: nohup java -jar 8091.jar -> 8091.log &
启动效果: 在这里插入图片描述
命令说明:
nohup是后端运行命令,与当前的终端没有绑定. 可以一直稳定的运行.

3.4.7 关闭tomcat服务器

  1. 查询服务器进程信息 ps -ef | grep java
    在这里插入图片描述
  1. 检索java 服务命令 jps
    在这里插入图片描述
    3).关闭服务
    kill PID号 简单的杀死进程 级别较低
    kill -15 PID号 必须杀死进程 但是可以执行善后操作
    kill -9 PID号 强制杀死进程 出现任务任何问题概不负责

3.4.6 关于日志查看命令

1.cat 输出文件所有的内容      (喵一眼)
2.more 输出文档所有的内容,分页输出,空格浏览下一屏,q退出
3.less 用法和more相同,只是通过PgUp、PgOn键来控制
4.tail 用于显示文件后几号,使用频繁
   tail -10 nginx.conf 查看nginx.conf的最后10

tail –f nginx.conf 动态查看日志,方便查看日志新增的信息
ctrl+c 结束查看

3.4.7 Linux脚本命令

说明: Linux中默认支持的是shell脚本 文件名称 xxx.sh
头文件信息: #!/bin/sh
创建文件: vim start.sh
在这里插入图片描述
执行脚本: sh start.sh
在这里插入图片描述

3.4.8检查服务器启动是否正常

在这里插入图片描述

3.5 安装nginx服务器

3.5.1 在线下载

命令: wget http://nginx.org/download/nginx-1.19.10.tar.gz
在这里插入图片描述

3.5.2 安装nginx

1).解压文件
tar -xvf nginx-1.19.10.tar.gz
2).修改文件名称
关于文件说明: nginx-source 文件是源文件目录 不是工作目录, 改目录的作用 是安装Nginx主要服务的.
在这里插入图片描述
3).命令 ./configure 将程序进行校验
在这里插入图片描述
4).指令: make 将程序进行编译
在这里插入图片描述
5).make install 安装nginx服务器
在这里插入图片描述
6).检查nginx目录
在这里插入图片描述

3.5.3 Linux Nginx启动

要求: 在/usr/local/nginx/sbin
在这里插入图片描述
2).命令:
Linux Windows
1. 启动nginx ./nginx start nginx
2. 重启nginx ./nginx -s reload nginx -s reload
3. 关闭nginx ./nginx -s stop nginx -s stop

3.6 前端项目部署

3.6.1 上传文件

说明: 将前端进行开发,之后将dist目录 上传到Linux的/usr/local/nginx/
在这里插入图片描述

3.6.2 配置nginx 前端反向代理

在这里插入图片描述
反向代理说明:
域名: web.jt.com 代理的是一个目录 dist (html/css/js)
域名: manage.jt.com 代理的是集群 8091/8092
域名: image.jt.com 代理的是目录 /usr/local/src/images
修改nginx配置文件

#前端反向代理
	server {
		listen 80;
		server_name web.jt.com;
		location / {
			root dist;
			index index.html;
		}
	}

	# 配置后端服务器 准备集群 默认就是轮询
	upstream tomcats {
		server 192.168.126.129:8091;
		server 192.168.126.129:8092;
	}

	server {
		listen 80;
		server_name manage.jt.com;
		# /表示拦截所有的请求
		location / {
			proxy_pass http://tomcats;
		}
	}
	
	#图片服务器代理
	server {
		listen 80;
		server_name image.jt.com;

		location / {
			root /usr/local/src/images;
		}
	}	

3.6.3 修改windows HOSTS文件

#IP 域名  映射关系

#图片服务器域名
#127.0.0.1  image.jt.com
192.168.126.129  image.jt.com

#后台服务器域名
#127.0.0.1  manage.jt.com
192.168.126.129  manage.jt.com

#前台服务器域名

#127.0.0.1  web.jt.com
192.168.126.129  manage.jt.com

3.6.4 项目部署调试

在这里插入图片描述

京淘项目阶段复习

1.1 Spring框架

总结: Spring框架的主要的作用整合其他第三方框架
2大核心机制: 1.IOC/DI 2.AOP

1.1.1 IOC

总结: 控制反转 将对象创建的权利交给Spring容器管理,由spring容器管理对象的生命周期.

1.1.2 DI

总结: DI依赖注入
注入方式: 1.Set注入 必须有set方法 2.构造注入 必须无参构造方法.

1.1.3 自动装配 autowire

总结: 注入的方式有2种
1.通过name属性进行注入
2.通过类型进行注入.

1.1.4 注解模式

1).@Repository
2).@Service
3).@Controller @RestController

1.2 AOP

1.2.1 AOP作用

总结: AOP的主要功能实现方法的扩展
实现方式: 代理思想
动态代理方式: 1.JDK动态代理 特点: 要求代理对象 实现与被代理者相同的接口(默认)
2.CGLIB代理 特点: 被代理者有无接口都可以,但是代理对象是被代理者的子类. extends

1.2.2 AOP公式

AOP = 切入点表达式 + 通知方法

1.切入点表达式4种:
bean() 按类型匹配
within(*)按类匹配
execution(...)方法参数级别 细粒度.
@annotation(....) 细粒度 根据注解匹配.
2.通知方法5种
1.before() 目标方法执行前
2.afterReturning 目标方法执行后
3.afterThrowing 目标方法执行抛出异常时执行
4.after 不管目标方法执行是否正确 都要执行.

	5.around(ProceedingJoinPoing)              目标方法执行前后都要执行     功能最为强大

在这里插入图片描述

1.2 SpringBoot框架

1.2.1 总结

SpringBoot 就是将Spring的调用的过程进行简化,可以理解为Spring的一种高级的封装.
机制: 开箱即用. 引入功能只需要导入少了的jar包及配置,即可实现功能.
关联项: SpringBoot-start-xxxxx
启动方式: main方法

1.2.2 配置文件

1.application.xml
2.application.yml 方法 注意层级关系 注意缩进 环境切换 ---环境分割

1.3 Mybatis Plus

1.3.1 作用

以对象的方式操作数据库. 做到面向对象编程.

1.3.2 核心步骤

1.对象与表 进行一对一关联 字段与属性进行一对一关联.
2.需要封装公共的接口 将CURD操作进行统一的管理 BaseMapper
3.MP 实现的原理 将对象按照特定的规则 转化为Sql语句.
userMapper.insert(user对象)
Sql: insert into user(字段....) value (属性的值.....)

1.4 SpringMVC

1.4.1 调用的流程图

在这里插入图片描述

1.4.2 参数传递问题

1).如果需要页面传参 则必须html中有name属性的支持!!!! name="age"
2).参数接收时,,必须与前端的name属性一致. age
3).如果前端传递了多个参数, 则后端可以采用对象的方式接收
要求: 对象的属性必须与name属性一致.
必须有set/get方法.
4).同名提交问题: 页面中如果是同名提交则会采用,号的方式进行拼接 hobby='吃,喝,玩'
如果前端采用,号的方式进行分隔,则在后端采用数组的方式接收.

  1. 利用对象的引入赋值 name="二郎神"/ dog.name="哮天犬"
    6).RestFul风格 /xxx/{id}/{name} 可以通过注解接收.可以通过对象接收.
    7).请求方式与业务的绑定 get 查询, post 新增,put 修改 delete 删除

1.5 jQuery 案例

1). $.get(url,data,callback(funcation(xx){
}))

2).$.post()
3).$.getJSON()
4). $.ajax({
url: xxx,
type: get
data: 数据,
success: function(){ 成功后的回调函数
},
error: function(){ 失败的回调

		}
})

1.6 VUE JS

在这里插入图片描述

posted @   yolin2  阅读(34)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
点击右上角即可分享
微信分享提示