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 切换 自己的本地库
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 作业
- 将SSM框架 试着整合到一起
- 复习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 分支结构介绍
- v-if 如果判断为真 则显示标签数据
- v-else 如果判断为假 则显示数据
- v-else-if 判断规则 位于if和else之间的.
- 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使用步骤
- 引入路由的js类库.
- 添加路由链接
- 添加路由的填充位
- 定义路由组件
- 配置路由规则,创建路由实例
- 实现路由的挂载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
- 商品的参数信息 注意每个商品都应该有自己单独的参数 item_param
- 商品详情信息 每个商品都应该有自己的详情 (大字段存储) 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服务器
- 查询服务器进程信息 ps -ef | grep java
- 检索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='吃,喝,玩'
如果前端采用,号的方式进行分隔,则在后端采用数组的方式接收.
- 利用对象的引入赋值 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(){ 失败的回调
}
})
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)