JavaWeb 学习笔记
前端基础
HTML-CSS
<!doctype html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport"content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><!-- 定义一个标题,名为今日新闻--><title>今日新闻</title><!-- 内部样式--><style>span {color: gray;}a {/* 去除超链接下方的下划线*/text-decoration: none;/* 设置首行缩进*/text-indent: 2em;}p {/* 设置行高*/line-height: 20px;}/*宽度为整体页面的70%,居中显示margin: 0 auto;*/.container{width: 70%;margin: 0 auto;}</style>
</head>
<body><div class="container"><!-- 定义一个h1标签,名为某男子中奖100万人民币,居中显示--><h1>某男子中奖100万人民币</h1><!--定义一个超链接,显示央视网--><a href="https://www.cctv.com" target="_blank">央视网</a><span>2023-05-22 15:30:00
</span><!--定义一个hr标签,名为:--><hr><!-- 定义一个p标签,名为:近日..--><p>近日,某男子在网上抽奖中,中奖100万人民币,他表示,自己是通过网络渠道抽奖的,并没有直接接触到抽奖活动的工作人员。</p><!-- 定义一个h2标签,名为:--><p>他表示,自己是通过网络渠道抽奖的,并没有直接接触到抽奖活动的工作人员。</p><!--引入一张图片--><img src="https://img0.baidu.com/it/u=1876403284,1622726598&fm=253&app=120&size=w931&n=0&f=JPEG&fmt=auto?sec=1739379600&t=7d17357bb326b62b97ca5d2158f6300c"alt=""><!--src:图片的路径alt:图片的描述width:图片的宽度height:图片的高度--></div></body>
</html>
<div>A A A A A A A A A A A A A A A A A A A A
</div>
<div>B B B B B B B B B B B B B B B B B B B B
</div><span>C C C C C</span>
<span>C C C C C</span>
<!--action: 表单提交的地址method: 表单提交的方式如果表单中出现了隐私信息,那么表单提交的方式必须是post-->
<form action="http://localhost:8080/login" method="post"><!-- 定义一个input标签,名为:用户名--><input type="text" name="username" placeholder="请输入用户名"><!-- 定义一个input标签,名为:密码--><input type="password" name="password" placeholder="请输入密码"><!-- 定义一个input标签,名为:提交--><input type="submit" value="提交">
</form>
JS
引入方式
核心语法
<!-- js 代码-->
<script>// 变量let a=10;alert(a);a="hello js";alert(a);const PI=3.14;// 写到html中document.write(PI);
</script>
let a="你好啊";
// 控制台输出
console.log(typeof a);
let name="张三";let age=18;alert(`我是${name},今年${age}岁`);
函数
function add(a, b) {return a + b;}let c = add(1, 2);alert(c)
自定义对象
let user={name:"张三",age:20,sex:"男",sing(){alert("我会唱歌");}}alert(user.name);user.sing();
JSON
let user={name:"张三",age:20,sex:"男",sing(){alert("我会唱歌");}}alert(JSON.stringify(user));
事件监听
<!-- 默认代码 从上往下解析-->
<body><input type="button" id="text" value="点我试试"><!-- js 代码-->
<script>document.querySelector('#text').addEventListener('click', () => {alert("试试就试试")})</script></body>
Vue
学习Vue
v-for
v-bind
标签的属性 不能
使用{{}}
插值表达式
结果
v-if / v-show
v-model
结果
v-on
Axios
<!DOCTYPE html>
<html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml" xmlns="http://www.w3.org/1999/xhtml"xmlns:v-on="http://www.w3.org/1999/xhtml">
<head><meta charset="UTF-8"><title>Title</title><!-- 引入Vue.js --><script src="vue.js"></script><!-- 引入axios --><script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script></head><!-- 默认代码 从上往下解析-->
<body><div id="app"><p>{{ message }}</p><button type="button" @click="search()">点我</button></div><!--vue代码在下方-->
<script>var app = new Vue({el: '#app',data: {message: 'Hello Vue!',name: '张三',age: 20,list: [1, 2, 3, 4, 5],},methods: {search() {alert(1)// 发送axios请求axios.get(`https://localhost:8080/list?name=${this.name}&age=${this.age}`).then(res => {console.log(res)})}}})</script></body>
</html>
工具
Maven 基础
作用
安装
配置Maven 环境
构建Maven项目
依赖管理
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.6.11</version><!-- 排除依赖--><exclusions><exclusion><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-logging</artifactId></exclusion></exclusions>
</dependency>
生命周期
Maven 高级
1、分模块 设计与开发
策略
某一个模块 的依赖,类名 :应该 同包同名
2、 继承
3、版本锁定
只是 管理依赖版本,
没有引入依赖
4、 自定义属性
实践截图
5、聚合
6、私服
详见 Maven使用
单元测试
使用
<dependency><groupId>junit</groupId><artifactId>junit</artifactId><scope>test</scope>
</dependency>
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;/*** 测试类*/
@DisplayName("用户信息测试类")
public class UserInfoTest {/*** 返回值必须为 void* 方法名必须以 test 开头* 方法参数必须为空*/@BeforeAllpublic static void start() {System.out.println ("在每个测试方法之前执行一次");}@AfterAllpublic static void end() {System.out.println ("在每个测试方法之后执行一次");}@Test@DisplayName("测试年龄")public void testGetAge() {System.out.println ("Hello World");}@Testpublic void testOutPut() {System.out.println ("测试输出情况");}@Testpublic void testEquals() {String str = "男";// 断言,绿色代表测试通过Assertions.assertEquals ("女", str);/*** org.opentest4j.AssertionFailedError:* Expected :女* Actual :男*/}}
Maven 依赖范围
<dependency><groupId>junit</groupId><artifactId>junit</artifactId><!--依赖范围,仅在测试环境下有效--><scope>test</scope>
</dependency>
Web基础
Spring Boot
创建项目
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;/*** 启动类*/
@SpringBootApplication
public class SbApplication {public static void main(String[] args) {SpringApplication.run (SbApplication.class, args);}}
<properties><java.version>1.8</java.version><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><spring-boot.version>2.3.12.RELEASE</spring-boot.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope><exclusions><exclusion><groupId>org.junit.vintage</groupId><artifactId>junit-vintage-engine</artifactId></exclusion></exclusions></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>${spring-boot.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.8.1</version><configuration><source>1.8</source><target>1.8</target><encoding>UTF-8</encoding></configuration></plugin><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>${spring-boot.version}</version><configuration><mainClass>com.example.sb.SbApplication</mainClass><skip>true</skip></configuration><executions><execution><id>repackage</id><goals><goal>repackage</goal></goals></execution></executions></plugin></plugins></build>
启动成功!!!
测试使用
@RestController
public class BasicController {@RequestMapping("/hello")@ResponseBodypublic String hello(String name) {System.out.println ("hello"+name);return "Hello " + name;}}
Spring Boot 原理
Bean作用域
@Lazy // 第一次使用时,才创建 bean
@Component
@Scope("singleton") // 默认 单例bean;在项目启动时创建的
public class TokenInterceptor implements HandlerInterceptor {}
自动配置
HTTP协议 、 IOC与DI
HTTP协议
HTTP协议-请求数据格式
HTTP协议--响应数据格式
响应状态码
演示
@RequestMapping("/hello")
@ResponseBodypublic String hello(String name) {System.out.println ("hello"+name);int i=1/0;return "Hello " + name;}
import cn.hutool.core.io.IoUtil;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;@RestController
public class BasicController {@GetMapping("/list")public List<User> hello() throws IOException {InputStream in = this.getClass ().getResourceAsStream ("user.txt");ArrayList<String> list = IoUtil.readLines (in, "utf-8", new ArrayList<> ());List<User> users = list.stream ().map (s -> {String[] split = s.split (",");return new User (split[0], split[1], Integer.parseInt (split[2]));}).collect (Collectors.toList ());return users;}}
三层架构
解耦
IOC
@Component // 对象交给 Spring容器管理,名称 userService
public class UserService {public String getUserInfo() {return "张三,20,男";}
}
@RestController
public class BasicController {@Autowiredprivate UserService userService;@GetMapping("/list")public String hello() throws IOException {return userService.getUserInfo ();}}
/*** 启动类*/
@SpringBootApplication
public class SbApplication {public static void main(String[] args) {SpringApplication.run (SbApplication.class, args);}}
MySQL 数据库
使用Docker 安装
mysqladmin -u root password 1234 # 修改mysql密码
数据模型
SQL 分类
DDL-数据库
-- 查询数据库
show databases()-- 查询当前数据库
select database()-- 使用/切换数据库
use 数据库名字-- 创建数据库
create database if not exists user -- 删除数据库
drop database if exists user
图形化工具
DDL-表操作
-- 创建表
create table user(id int primary key comment 'ID,唯一标识' , # 要加以限制 primary key,主键约束username varchar(50) not null unique comment '用户名', # 最长50个字符name varchar(10) not null comment '姓名',age tinyint unsigned comment '年龄', # 无符号,满足业务条件下,选择占用磁盘小的gender char(1) default '男' comment '性别') comment '用户表';
约束
设计表
# 主键必须
create table emp(id int primary key comment '主键',username varchar(20) not null unique comment '用户名',password varchar(32) default '123456' comment '密码',name varchar(10) not null comment '姓名',gender tinyint not null comment '性别,1、男 2、女',phone char(11) not null comment '手机号',job tinyint not null comment '职业,1、班主任 2、讲师 3、教研主管',salary int unsigned not null comment '薪水',entry_date date comment '入职日期', # 年月日image varchar(255) comment '图像地址',create_time datetime comment '创建时间', #datetime精确到时分秒update_time datetime comment '修改时间')comment '员工表' default char set utf8mb4;
修改 、查询表结构
推荐使用图形化界面进行操作
DML — 增删改
-- 插入-- 插入一条数据
insert into emp(username,password,name,gender,phone) values('宋江','1245ds2','宋江',1,15122454665);
-- 批量插入数据
insert into emp(username,password,name,gender,phone)values('宋江','1245ds2','宋江',1,15122454665),('张三','zs5487','张三',1,15122454664),('李四','ls8789','李四',1,15122454662);
-- 修改update emp set password='12348' where id=5; # 必须加条件,不然全部都被修改
update emp set entry_date='2010-10-24'; # 修改所有员工的入职日期-- 删除数据 带 where条件,不然全部删除,十分危险!!!delete from emp where id=5; # 只能删除这一条数据,不能删除字段
DQL 数据库查询语言
注意
where 分组前,having 分组后
group by 分组后,只能 select分组字段
和聚合函数
-- 基本查询select id,username,entry_date from emp;
select * from emp;
select username as '用户名',entry_date as '入职日期' from emp; # 别名
select distinct job from emp; # 去重distinct-- 条件查询select id,username,entry_date from emp where username='zs';
select * from emp where id>=5 &&id<8 and (username='zs' ||username='ls');
select id,username,entry_date from emp where id in(1,6,9,5,7); # in (...)
select username from emp where job is null; # 判断是否为空 is null | 而不是 = null
select username from emp where entry_date between '2020-10-2' and '2023-2-15'; # between and 范围查询
# 查询姓名为 两个字的员工信息,like 模糊匹配
# _ :单个字符 % :任意个字符
select * from emp where name like '__';
select * from emp where name like '李%'; # 姓李-- 分组、排序、分页select count(1) 员工数 from emp;
select avg(salary) 平均薪资 from emp;
# 查询薪资最少的人, 子查询
select username from emp where salary =(select min(salary) from emp );
# group by 分组之后,select 字段不能随意书写,只能写分组字段和聚合函数
select gender 性别, count(1) 人数 from emp group by gender;
# 查询入职时间在 '2015-01-01' 之前的员工,并根据结果分组,获取 员工数量 ≥2 的职位
select job 职位,count(1) 数量 from emp# where 分组前where entry_date <='2015-01-01'group by job# having 用于分组后having count(1)>=2;select username,entry_date from emporder by entry_date ,update_time DESClimit 5; # 排序+分页
JDBC
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId>
</dependency>
/*** 使用JDBC连接 MySQL,并实现增删改查* username:root* password:root* url:jdbc:mysql://localhost:3306/user*/// 1. 加载驱动Class.forName ("com.mysql.cj.jdbc.Driver");Connection connection = null;PreparedStatement ps = null;ResultSet rs = null;try {// 2. 创建连接connection = DriverManager.getConnection ("jdbc:mysql://localhost:3306/user", "root", "root");// 3. 创建语句,预编译 SQL,防止SQL注入String sql = "select id,username,job,salary from user where id = ? and name =?";// 4. 预编译sqlps = connection.prepareStatement (sql);// 5. 设置参数ps.setInt (1, 5);ps.setString (2, "张三");// 6. 执行语句,并获取结果集rs = ps.executeQuery ();// 7. 处理结果ArrayList<User> list = new ArrayList<> ();while (rs.next ()) {int id = rs.getInt ("id");String username = rs.getString ("username");String job = rs.getString ("job");int salary = rs.getInt ("salary");// 封装为User 对象User user = new User (id, username, job, salary);// 添加到集合中list.add (user);}} catch (SQLException e) {throw new RuntimeException (e);} finally {// 8. 释放资源if (connection != null) {try {connection.close ();} catch (SQLException e) {throw new RuntimeException (e);}}if (ps != null) {try {ps.close ();} catch (SQLException e) {throw new RuntimeException (e);}}if (rs != null) {try {rs.close ();} catch (SQLException e) {throw new RuntimeException (e);}}}
Mybatis
使用
依赖
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId>
</dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId>
</dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.10</version>
</dependency>
配置
spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/userusername: rootpassword: 123456
Mapper 接口
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;@Mapper // 自动为接口 生成(实现类对象)代理对象且放入IOC容器中
public interface UserMapper {@Select("select * from user")// 自动为方法生成SQL语句/*** 查询所有用户* 返回值 List<User>*/public List<User> selectAll();
}
测试类
@SpringBootTest // 启动springboot测试,创建 IOC容器
public class UserInfoTest {@Autowiredprivate UserMapper userMapper;@Testpublic void testFindAll() {List<User> userList = userMapper.selectAll ();userList.forEach (user -> {System.out.println (user);});}}
Idea 连接 数据库
配置Mybatis日志输出
mybatis-plus:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
Mybatis 数据库连接池
<dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.2.15</version>
</dependency>
spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/userusername: rootpassword: 123456type: com.alibaba.druid.pool.DruidDataSource # 数据库 连接池druid:initial-size: 5 # 初始化大小max-active: 20 # 最大连接数min-idle: 5 # 最小连接数
Mybatis 增删改查
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;@Mapper // 自动为接口 生成(实现类对象)代理对象且放入IOC容器中
public interface UserMapper {/*** 根据id删除用户* DML语句返回值代表 影响的行数** @param id* @return*/@Delete("delete from user where id = #{id}") // 预编译SQLpublic Integer deleteById(Integer id);/*** 插入数据* 将参数封装到User对象中* 使用 对象属性填充占位符** @param user*/@Insert("insert into user (name,age) values (#{name},#{age})") // 对象属性名public void insert(User user);/*** 更新数据** @param user*/@Update("update user set name =#{name} and age=#{age} where id =#{id}") // 对象属性名public void update(User user);/*** 根据用户名和密码查询用户* @Param("username") 注解 表示 给参数起别名* 作用:* 1. 当参数只有一个时,起别名可以省略* 2. 当参数有多个时,起别名是必须的** #{} :使用的是 @Param注解起的别名* 如果没有 @Param注解,#{} 使用的是参数形参名称,编译时会报错 var1,var2* 推荐 ------->>>使用 @Param("username") 注解* @param username 用户名* @param password 密码*/@Select("select * from user where username=#{username} and password=#{password}") // 对象属性名public User selectByNameAndPwd(@Param("username") String username, @Param("password") String password);}
Mybatis XML 映射配置
创建文件时,不用 .
而是使用 /
代替
辅助配置
mybatis-plus:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl# 指定XML映射配置文件的位置mapper-locations: classpath:mapper/*.xml
SpringBoot开发
前置知识
Restful 风格
是约定,可以被打破,但是 不建议
https://apifox.com/
@Data
public class EmpQueryParam {private Integer start;private Integer size;private String name;private Integer gender;
}
Controller
@GetMapping("/emps")public Result add(EmpQueryParam empQueryParam) {PageInfo<Emp> pageInfo = deptService.selectList (empQueryParam);long total = pageInfo.getTotal ();List<Emp> empList = pageInfo.getList ();return Result.ok (empList);}
部门管理
1、结果 统一返回
Result 类
2、数据封装----->>>解决数据库字段与对象属性名不一致
mybatis-plus:configuration:map-underscore-to-camel-case: true # 驼峰命名log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 打印sql日志lazy-loading-enabled: true # 懒加载
3、前后端 联调
Nginx
4、增删改查部门
/*** @param deptId* @return* @RequestParam(name = "id") 表示:请求参数的名称为id 绑定到方法的参数上deptId* required = false 表示:请求参数id是可选的*/@DeleteMapping("/depts")// /depts?id=5public Result delete(@RequestParam(value = "id", required = false) Integer deptId) {System.out.println (deptId);return Result.ok ();}/*** 保存部门** @param dept* @return* @RequestBody: 将前端传来的json封装为 Dept对象*/@PostMapping("/depts")public Result save(@RequestBody Dept dept) {System.out.println (dept);return Result.ok ();}/*** 根据id查询用户** @param id* @return* @PathVariable("id") 表示:请求路径中的id 绑定到方法的参数上*/@GetMapping("/depts/{id}")public Result getUserById(@PathVariable("id") Integer id) {User user = new User ();user.setId (id);user.setName ("zhangsan");return Result.ok (user);}/*** 更新用户* 前端传的json数据封装为User对象** @param user* @return*/@PutMapping("/depts")public Result update(@RequestBody User user) {// 执行修改业务return Result.ok ();}
日志
1、logback入门
<dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId>
</dependency>
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.test.context.SpringBootTest;@SpringBootTest
class TialsManageApplicationTests {private static Logger logger = LoggerFactory.getLogger (TialsManageApplicationTests.class);@Testvoid contextLoads() {logger.info ("test");logger.info ("hello");}}
2、日志级别
Lombok 自带
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;@SpringBootTest
@Slf4j // lombok 日志
class TialsManageApplicationTests {@Testvoid contextLoads() {// 占位符 {}log.info ("你好,{}", "world");log.info ("hello");}}
多表关系、查询
1、一对多(不推荐使用 外键,在业务层面约束 )
使用外键-------->>> 保证数据一致性
# 外键名 fk_emp_dept_id
# 添加前要保证数据一致
alter table emp add constraint fk_emp_dept_id foreign key(dept_id) references dept(id)
2、 一对一
3、多对多
实现方式:引入第三张表,关联两张表的主键信息即可
4、多表查询概述
5、内连接
# 查询性别为男,且工资高于8000 的员工的ID,姓名,及所属部门名称
select emp.id,emp.name,dept.name from emp,deptwhere emp.dept_id=dept.idand emp.gender='男'and emp.salary>8000
6、外连接
解释:
包含 左表全部的数据
即使 右表的内容为null,左表内容 全部显示
左外连接
# 查询工资 高于8000的所有员工信息和对应的部门名称(左外连接)
select emp.name,dept.name from emp# 包括左表及俩表重合部分left join dept on emp.dept_id=dept.idwhere emp.salary>8000
7、子查询
# 查询教研部和咨询部的所有员工信息select * from emp where dept_id in(select id from dept where id=1 or id=2)select * from empwhere (salary,job)=(5000,1);# 查询 在2010-05-01 后入职,且薪资高于 10000 的教研部员工信息,并根据薪资倒序排序
select e.* from emp e,dept dwhere e.dept_id=d.idand e.entry_date >'2010-05-01'and e.salary>10000and d.name='教研部'order by e.salary desc
员工管理
1、分页查询
Mapper
@Mapper
public interface EmpMapper {// 统计员工数量@Select("select count(*) from emp left join dept on emp.dept_id = dept.id")public Long count();/*** 分页查询* 查询后 将d.name 取别名为deptName* 因为Emp类没有deptName属性,故在Emp类中添加deptName属性--->>进行封装** @return*/@Select("select e.*,d.name deptName from emp e left join dept d on e.dept_id = d.id" +"order by e.update_time desc limit #{start},#{size}")public List<Emp> list(@Param("start") Integer start, @Param("size") Integer size);}
Controller
@Slf4j
@RestController
@RequestMapping("/Dept") // 访问的公共前缀
public class DeptController {@GetMapping("/add")public Result add() {return Result.ok();}}
2、PageHelper
<dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper-spring-boot-starter</artifactId><version>1.4.5</version>
</dependency>
@Mapper
public interface EmpMapper {/*** PageHelper 实现分页,只需要指定从哪张表中查询,返回哪些字段** @return*/@Select("select e.*,d.name deptName from emp e left join dept d on e.dept_id = d.id" +"order by e.update_time desc")public List<Emp> list();}
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.List;@Service
public class DeptService {@Autowiredprivate EmpMapper empMapper;public PageInfo<Emp> selectList(Integer start, Integer size) {// 设置分页参数PageHelper.startPage (start, size);// 执行查询// Page extends ArrayList<>Page<Emp> page = (Page<Emp>) empMapper.list ();// 封装分页结果return new PageInfo<Emp> (page.getTotal (), page.getResult ());}
}
Controller
@Slf4j
@RestController
@RequestMapping("/Dept") // 访问的公共前缀
public class DeptController {@Autowiredprivate DeptService deptService;@GetMapping("/add")public Result add(Integer start, Integer size) {PageInfo<Emp> pageInfo = deptService.selectList (start, size);long total = pageInfo.getTotal ();List<Emp> empList = pageInfo.getList ();return Result.ok (empList);}}
3、条件分页查询----->>> 优化版
请求参数太多的优化,使用
对象 封装参数
SQL条件优化,即 使用动态SQL
@Mapper
public interface EmpMapper {/*** 查询* @param empQueryParam* @return*/public List<Emp> list(EmpQueryParam empQueryParam );}
@Autowiredprivate DeptService deptService;@GetMapping("/emps")public Result add(EmpQueryParam empQueryParam) {PageInfo<Emp> pageInfo = deptService.selectList (empQueryParam);long total = pageInfo.getTotal ();List<Emp> empList = pageInfo.getList ();return Result.ok (empList);}
Mapper 文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.example.tialsmanage.demos.web.EmpMapper"><select id="list" resultType="com.example.tialsmanage.demos.web.Demp">select emp.*,dept.name deptName from emp left join dept on dept.id=emp.dept_id-- #{name} 不能用在 ''中<where><if test="name !=null and name !='' ">and emp.name like concat('%',#{name},'%')</if><if test="gender !=null ">and emp.gender=#{gender}</if><if test="begin !=null and end !=null ">and emp.entry_date between #{begin} and #{end}</if></where></select>
</mapper>
4、保存员工
@PostMapping("/add")// 前端传来 json数据public Result add(@RequestBody Emp emp) {emp.setCreateTime(new Date ());emp.setUpdateTime(new Date ()); int i = deptService.save (emp);return Result.ok (i);}
Mapper
/*** 新增 Emp* @param emp* @return*/int save(Emp emp);
SQL 文件
<insert id="save">insert into emp(name, gender, entry_date, dept_id)values (#{name}, #{gender}, #{entryDate}, #{deptId})</insert>
5、批量保存
foreach 动态SQL
void insertBatch(List<Emp> empList);
<insert id="insertBatch">insert into emp(name, gender, entry_date, dept_id) values<foreach collection="empList" item="emp" separator=",">(#{emp.name}, #{emp.gender}, #{emp.entry_date}, #{emp.deptId})</foreach>
</insert>
考虑使用Mybatis-Plus
问题
插入几个数据之后出现问题,无法回滚
此时考虑 事务
使用事务控制----> @Transactional
–>指定回滚类型(可见 事务管理内容)
6、删除员工
Controller
/*** 批量删除 员工信息* 前端参数 提交类似 Post方式** @param ids*/@DeleteMappingpublic void delete(@RequestParam List<Integer> ids) {empService.delete (ids);}
Service & Mapper
使用事务
控制----> @Transactional
–>指定回滚类型(可见 事务管理内容)
7、修改员工
查询回显
使用ResultMap 进行封装
修改数据
事务管理
介绍
多次 修改数据库
使用
-- 开启事务
start transaction;insert into emp(id,name,pwd) values (1,'zs','wdww')
update emp set pwd='254sdw' where id=1;-- 提交/回滚
commit; # 如果两条语句都成功----->>commit,否则进行回滚
在 代码中如何保证事务的进行
@Transactional 默认是:出现 运行时异常会回滚
四大特性
文件上传
介绍
文件上传
1、前端页面
<head><!-- 设置编码为utf-8--><meta charset="utf-8">
</head><body><!--必须设置 enctype,此时才能传送文件的信息 方法为 post-->
<form action="http://localhost:8080/upload" method="post" enctype="multipart/form-data">姓名:<input type="text" name="name"><br>年龄:<input type="text" name="age"><br>头像:<input type="file" name="file"><br><input type="submit" value="提交"></form></body>
2、Controller层
@RestController
@Slf4j
public class UploadController {@PostMapping("/upload")public void upload(String name, Integer age, MultipartFile file) {log.info ("接受参数:{},{},{}",name,age,file);}
}
3.运行
4、结果
本地存储
# 设置文件上传大小
spring:servlet:multipart:# 单个文件大小max-file-size: -1# 最大请求大小max-request-size: -1
@PostMapping("/upload")public void upload(String name, Integer age, MultipartFile file) throws IOException {// 接受参数log.info ("接受参数:{},{},{}", name, age, file);// 获取原始文件名String filename = file.getOriginalFilename ();// 保存文件,考虑文件名相同时的问题 +UUIDUUID uuid = UUID.randomUUID ();String[] split = filename.split ("\\.");filename = split[0] + uuid.toString () + "." + split[split.length - 1];file.transferTo (new File ("E:\\images\\" + filename ));}
阿里云OSS
1、介绍
2、使用,查阅文档 即可
优化----->>>参数配置化
配置到yaml文件中
@Value
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;@Component
public class AliyunOSSOperator {@Value("${aliyun.oss.endpoint}")private String endpoint;@Value("${aliyun.oss.bucketName}")private String bucketName;@Value("${aliyun.oss.region}")private String region;}
aliyun:oss:endpoint: oss-cn-beijing.aliyuncs.combucketName: java-airegion: cn-beijing
@ConfigurationProperties 批量注入
故 使用对象 进行封装
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;@Component
@Data
@ConfigurationProperties(prefix = "aliyun.oss")
public class AliyunOSSOperator {private String endpoint;private String bucketName;private String region;}
aliyun:oss:endpoint: oss-cn-beijing.aliyuncs.combucketName: java-airegion: cn-beijing
全局异常处理
登录认证
1、登录
登录功能
2、登录校验
3、会话技术
介绍
Cookie
Session
@GetMapping("/get")public void get(HttpSession session) {Object name = session.getAttribute ("name");System.out.println (name);}@GetMapping("/set")public void set(HttpSession session) {session.setAttribute ("name","dc");}
JWT
使用
解析
@Testvoid contextLoads() {// 生成HashMap<String,Object> claims = new HashMap<>();String KEY = "SYBV====QBR";claims.put ("id","123456");claims.put ("name","dc");String jwt = Jwts.builder ().addClaims (claims).signWith (SignatureAlgorithm.HS256, KEY)// 设置过期时间.setExpiration (new Date (System.currentTimeMillis ()+1000*60*60*3)).compact ();System.out.println (jwt);// 解析Jws<Claims> claimsJws =Jwts.parser ().setSigningKey (KEY).parseClaimsJws (jwt);Claims body = claimsJws.getBody ();System.out.println (body);}
令牌过期异常
方案对比
使用JWT 进行登录
引入依赖
<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version>
</dependency>
生成令牌
登陆成功后 返回给前端
4、过滤器 Filter
@WebFilter(urlPatterns = "/**")public class DemoFilter implements Filter {// 拦截到请求之后执行@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {// 拦截到请求System.out.println ("拦截了");// 放行filterChain.doFilter (servletRequest, servletResponse);}/*** 资源的准备** @param filterConfig* @throws ServletException*/@Overridepublic void init(FilterConfig filterConfig) throws ServletException {System.out.println ("init 运行了");}/*** 资源的释放及环境清理*/@Overridepublic void destroy() {System.out.println ("destroy 运行了");}
}
@SpringBootApplication
@ServletComponentScan // 扫描过滤器
public class TialsManageApplication {public static void main(String[] args) {SpringApplication.run (TialsManageApplication.class, args);}}
令牌校验
代码测试
@WebFilter(urlPatterns = "/*")
public class TokenFilter implements Filter {// 拦截到请求之后执行@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws ServletException, IOException {HttpServletRequest request=(HttpServletRequest) servletRequest;HttpServletResponse response=(HttpServletResponse) servletResponse;String uri = request.getRequestURI ();// 判断是否是登录请求,是则放行if(uri.contains ("/login")){filterChain.doFilter (request,response);return;}// 获取请求头中的 tokenString token = request.getHeader ("token");// token 不存在,说明用户没有登陆if(token==null || token.isEmpty ()){// 设置状态码response.setStatus (HttpServletResponse.SC_UNAUTHORIZED);return;}// token存在,校验令牌try {JWT jwt = JWTUtil.parseToken (token);} catch (Exception e) {// 校验失败response.setStatus (HttpServletResponse.SC_UNAUTHORIZED);return;}// token 校验成功---->> 放行filterChain.doFilter (servletRequest, servletResponse);}/*** 资源的准备** @param filterConfig* @throws ServletException*/@Overridepublic void init(FilterConfig filterConfig) throws ServletException {System.out.println ("init 运行了");}/*** 资源的释放及环境清理*/@Overridepublic void destroy() {System.out.println ("destroy 运行了");}
}
拦截路径
过滤器链
5、拦截器 Interceptor
拦截器 Interceptor 实现 令牌校验
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;@Component
public class TokenInterceptor implements HandlerInterceptor {/*** true --> 放行* false --> 不放行* @param request* @param response* @param handler* @return* @throws Exception*/@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {String uri = request.getRequestURI ();// 判断是否是登录请求,是则放行if (uri.contains ("/login")) {return true;}// 获取请求头中的 tokenString token = request.getHeader ("token");// token 不存在,说明用户没有登陆if (token == null || token.isEmpty ()) {// 设置状态码response.setStatus (HttpServletResponse.SC_UNAUTHORIZED);return false;}// token存在,校验令牌try {JWT jwt = JWTUtil.parseToken (token);} catch (Exception e) {// 校验失败response.setStatus (HttpServletResponse.SC_UNAUTHORIZED);return false;}// token 校验成功---->> 放行return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {HandlerInterceptor.super.postHandle (request, response, handler, modelAndView);}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {HandlerInterceptor.super.afterCompletion (request, response, handler, ex);}
}
创建 配置类
@Configuration
public class WebConfig implements WebMvcConfigurer {@Autowiredprivate TokenInterceptor tokenInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor (tokenInterceptor).addPathPatterns ("/**") // 拦截哪些请求.excludePathPatterns ("/login"); // 不拦截的请求}
}
拦截路径
Spring AOP
1、AOP 基础
依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId>
</dependency>
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;@Component // 交给 spring 管理
@Aspect // 切面类
public class RecordTimeAspect {// 切入点表达式@Around(" execution(* com.example.tialsmanage.demos.web.UploadController.*(..))") // 切入点public Object recordTime(ProceedingJoinPoint joinPoint) throws Throwable { // joinPoint 切入对象long start = System.currentTimeMillis ();// 执行该方法Object o = joinPoint.proceed ();long end = System.currentTimeMillis ();System.out.println (end - start);return o;}}
2、AOP 进阶
通知类型
切入点表达式
@Pointcut(" execution(* com.example.tialsmanage.demos.web.UploadController.*(..))")public void bf() {}@Before("bf()")public void before() {System.out.println ("before");}
基于注解的方式----->> > 切入点
@Target (ElementType.ANNOTATION_TYPE)
@Retention (RetentionPolicy.RUNTIME)
public @interface Login {
}
@Before("@annotation(Login)")public void before() {System.out.println ("before");}
连接点
@Around(" execution(* com.example.tialsmanage.demos.web.UploadController.*(..))")public Object recordTime(ProceedingJoinPoint joinPoint) throws Throwable {long start = System.currentTimeMillis ();Object o = joinPoint.proceed ();long end = System.currentTimeMillis ();System.out.println (end - start);return o;}
3、AOP 案例
/*** 线程本地变量* 每个线程一个*/private static final ThreadLocal<Long> threadLocal = ThreadLocal.withInitial (() -> 3000L);public void get() {long val = threadLocal.get ().longValue ();System.out.println (val);}
获取当前的 登录员工
public class CurrentHolder {private static ThreadLocal<String> threadLocal = ThreadLocal.withInitial (() -> null);public static void set(String key) {threadLocal.set (key);}public static String get() {return threadLocal.get ();}public static void remove() {threadLocal.remove ();}
}
总结
前端开发-Vue工程化
介绍
Vue工程化
前后端 分离开发
登录功能
每次请求带上 Token
请求 拦截器
响应 拦截器
相关文章:

JavaWeb 学习笔记
前端基础 HTML-CSS <!doctype html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport"content"widthdevice-width, user-scalableno, initial-scale1.0, maximum-scale1.0, minimum-scale1.0…...

Linux7-线程
一、前情回顾 chdir();功能: 函数用于改变当前进程的工作目录。 参数:路径(Path):这是一个字符串参数,表示要切换到的目标目录的路径。 返回值: 成功:在成功改变当前工作目…...

在线VS离线TTS(语音合成芯片)有哪些优势-AIOT智能语音产品方案
离线 TTS 存在语音质量欠佳、音色选择有限、语言支持单一更新困难、占用资源多、适应性差、难以个性化定制等痛点 01更新维护困难 由于是离线模式,难以及时获取最新的语音数据和算法更新,无法得到持续改进。 02占用本地资源 需要在设备本地存储较大的…...
结构型模式 - 代理模式 (Proxy Pattern)
结构型模式 - 代理模式 (Proxy Pattern) 代理模式是一种结构型设计模式,它允许通过代理对象来控制对另一个对象(目标对象)的访问。代理对象充当目标对象的接口,客户端通过代理对象间接访问目标对象。 分为两大类 静态代理&#…...
el-select滚动获取下拉数据;el-select滚动加载
el-select下拉获取数据 1.解决问题2.封装MyScrollSelect组件3.使用MyScrollSelect组件 1.解决问题 场景:下拉数据量过大,后端提供一个分页查询接口;需要每次滚动加载下一页的下拉数据 且单选的状态,需要支持回显,通过n…...
HTTP GET 请求示例
鸿蒙操作系统(HarmonyOS)是华为公司自主研发的面向全场景的分布式操作系统,旨在为用户提供一个安全、流畅且跨设备无缝连接的体验。它支持多种终端设备,如智能手机、平板电脑、智能电视、汽车等,并实现了模块化解耦&am…...
简单理解Oracle中的latch
可以用一个小卖部抢购的例子来理解 Oracle 数据库中的 Latch: 1、 什么是 Latch? 打个比方,假设数据库的某个内存区域(比如缓存的数据块)是小卖部货架上的最后一包辣条,Latch 就像是货架前的一个狭窄通道&a…...

ubuntu新系统使用指南
1. 更新源 2. 配置rime 输入法 sudo apt install ibus-rimeibus-setup #打开配置界面添加雾凇拼音 cd ~/Documents/Tool/input_source/plumgit clone --depth 1 https://github.com/rime/plum plum #没有梯子就劝退cd plum/bash rime-install iDvel/rime-ice:others/recipe…...
sage-huga改进SITAN
Sage-Husa自适应滤波算法 Sage-Husa自适应滤波算法是一种在递推滤波过程中实时估计和修正系统噪声和观测噪声统计特性的算法,从而降低系统模型误差,提高滤波精度。该算法基于卡尔曼滤波,并通过自适应调整噪声协方差矩阵来优化滤波效果。 算法原理 Sage-Husa滤波器的核心思…...

DeepSeek开源周Day1:FlashMLA引爆AI推理性能革命!
项目地址:GitHub - deepseek-ai/FlashMLA 开源日历:2025-02-24起 每日9AM(北京时间)更新,持续五天! 一、开源周震撼启幕 继上周预告后,DeepSeek于北京时间今晨9点准时开源「FlashMLA」,打响开源周五连…...

Git add --- error: Filename too long
0 Preface/Foreword 1 解决办法 git config --system core.longpaths true...

Python入门12:面向对象的三大特征与高级特性详解
面向对象编程(OOP)是Python编程中非常重要的一部分,它通过封装、继承和多态这三大特征,帮助我们更好地组织和管理代码。除此之外,Python还提供了一些其他特性,如类属性、类方法和静态方法,进一步…...

动态链接器(九):.init和.init_array
ELF文件中的.init和.init_array段是程序初始化阶段的重要组成部分,用于在main函数执行前完成必要的初始化操作。 1 .init段和.init_array 段 1.1 作用 .init段包含编译器生成的初始化代码,通常由运行时环境(如C标准库的启动例程࿰…...

Elasticsearch:使用经过训练的 ML 模型理解稀疏向量嵌入
作者:来自 Elastic Dai Sugimori 了解稀疏向量嵌入,理解它们的作用/含义,以及如何使用它们实现语义搜索。 Elasticsearch 提供语义搜索功能,允许用户使用自然语言进行查询并检索相关信息。为此,目标文档和查询必须首先…...

安宝特方案 | 电力行业的“智能之眼”,AR重新定义高效运维!
引言: 电力行业正经历智能化变革,安宝特AR数字化工作流以四大核心优势,为电力企业打造全场景智慧运维方案! 四大颠覆性功能,直击行业痛点 1、高度自定义作业流程 支持图文指引、语音播报、AI实时识别(如…...

【落羽的落羽 数据结构篇】树、二叉树
文章目录 一、树1. 树的概念和结构2. 树的相关术语 二、二叉树1. 概念与结构2. 满二叉树3. 完全二叉树4. 二叉树的性质5. 二叉树的存储结构 一、树 1. 树的概念和结构 之前我们学习了线性表,今天我们再来接触一种全新的数据结构——树。 树是一种非线性的数据结构…...

[回顾]从原型链视角解读Vue底层实现Vue VueCompoent VM VC关系
从原型链视角解读VueComponent与Vue关系 原型链 根据,原型链涉及三个关键属性:__proto__是所有对象的私有属性,指向原型链的第一个元素;prototype是函数的属性,实例对象不拥有它;constructor指向构造函数。提到原型链是JS中实现继承的机制,通过属性链式查找属性,直到…...

springcloud nacos 整合seata解决分布式事务
文章目录 nacos安装Mysql5.7安装及表初始化seata server安装下载并解压seata安装包在conf文件夹修改file.conf文件向本地数据库导入seata需要的表修改registry.conf文件将seata配置信息添加到nacos配置中心启动seata server springcloud整合seata测试流程正常下单流程扣减库存失…...

【算法系列】快速排序详解
文章目录 快速排序的多种实现方式1. 基本快速排序(Lomuto 分区方案)1.1 基本原理1.2 步骤1.3 Java 实现示例 2. Hoare 分区方案2.1 基本原理2.2 步骤2.3 Java 实现示例 3. 三数取中法3.1 基本原理3.2 步骤3.3 Java 实现示例 4. 尾递归优化4.1 基本原理4.…...
神经网络发展简史:从感知机到通用智能的进化之路
引言 神经网络作为人工智能的核心技术,其发展历程堪称一场人类对生物大脑的致敬与超越。本文将用"模型进化"的视角,梳理神经网络发展的五大关键阶段,结合具象化比喻和经典案例,为读者呈现一幅清晰的AI算法发展图谱。 一…...
uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖
在前面的练习中,每个页面需要使用ref,onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入,需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...

YSYX学习记录(八)
C语言,练习0: 先创建一个文件夹,我用的是物理机: 安装build-essential 练习1: 我注释掉了 #include <stdio.h> 出现下面错误 在你的文本编辑器中打开ex1文件,随机修改或删除一部分,之后…...
【论文笔记】若干矿井粉尘检测算法概述
总的来说,传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度,通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...
Java 加密常用的各种算法及其选择
在数字化时代,数据安全至关重要,Java 作为广泛应用的编程语言,提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景,有助于开发者在不同的业务需求中做出正确的选择。 一、对称加密算法…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)
宇树机器人多姿态起立控制强化学习框架论文解析 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一) 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...

OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 在 GPU 上对图像执行 均值漂移滤波(Mean Shift Filtering),用于图像分割或平滑处理。 该函数将输入图像中的…...

深度学习习题2
1.如果增加神经网络的宽度,精确度会增加到一个特定阈值后,便开始降低。造成这一现象的可能原因是什么? A、即使增加卷积核的数量,只有少部分的核会被用作预测 B、当卷积核数量增加时,神经网络的预测能力会降低 C、当卷…...

视觉slam十四讲实践部分记录——ch2、ch3
ch2 一、使用g++编译.cpp为可执行文件并运行(P30) g++ helloSLAM.cpp ./a.out运行 二、使用cmake编译 mkdir build cd build cmake .. makeCMakeCache.txt 文件仍然指向旧的目录。这表明在源代码目录中可能还存在旧的 CMakeCache.txt 文件,或者在构建过程中仍然引用了旧的路…...

uniapp 开发ios, xcode 提交app store connect 和 testflight内测
uniapp 中配置 配置manifest 文档:manifest.json 应用配置 | uni-app官网 hbuilderx中本地打包 下载IOS最新SDK 开发环境 | uni小程序SDK hbulderx 版本号:4.66 对应的sdk版本 4.66 两者必须一致 本地打包的资源导入到SDK 导入资源 | uni小程序SDK …...

day36-多路IO复用
一、基本概念 (服务器多客户端模型) 定义:单线程或单进程同时监测若干个文件描述符是否可以执行IO操作的能力 作用:应用程序通常需要处理来自多条事件流中的事件,比如我现在用的电脑,需要同时处理键盘鼠标…...