目录
知识点七:postMapping、putMapping、getMapping、deleteMapping
九月第二周的笔记(1)
知识点一:公共字段填充
问题1:在项目中新增员工时候需要设置创建时间,修改时间,修改人姓名等字段,在编辑员工时需要设置的字段,有的属于公共字段,能不能对公共字段在某一个地方进行统一处理,来简化开发,Mybatis Plus 提供了公共字段填充功能。
实现步骤
步骤1:在实体类的属性上加上@TableField注解,指定自动填充的策略
步骤2:按照框架要求编写元数据对象处理器,在此类中统一为公共字段赋值,此类需要要实现MetaObjectHandler接口
@TableField(fill = FieldFill.INSERT):插入时填充字段
@TableField(fill = FieldFill.INSERT_UPDATE):插入和更新时填充字段
知识点二:ThreadLocal类
问题2:在自动填充createUser和UpdateUser两个字段的时候设置的用户id是固定值,应该动态的获得当天用户固定的值
//这个类是不能获得HttpSession对象的
//客户端发送的每次HTTP请求,对应的在服务器端会分配一个新的线程来处理,在处理过程中设计到下面类中的方法都属于同一个线程
//LgoninCheckFilter的doFilter方法
//EmployeeController的update方法
//MyMetaObjectHandler的updateFill方法
//可以在上面的三个方法中分别加入下面的代码获取当前线程
1.什么是ThreadLocal类?
ThreadLocal并不是一个Thread,而是Thread的变量,当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其他线程所对应的副本,ThreadLocal为每个线程提供单独一份存储空间,具有线程隔离的效果,只有在线程内才能获取对应的值,线程外不能访问
2.ThreadLocal的常用方法
Public void set(T value) 设置当前线程的线程局部变量的值
Public T get() 返回当前线程所对应的线程局部变量的值
3.可以在LoginCheckFilter的doFilter方法中获取当前登录用户id,并调用ThreadLocal的set方法设置当前线程的局部变量的值(用户id),然后在MyMetaObjectHandler的updateFill方法中调用ThreadLocal的get方法来获取当前线程所对应的线程局部变量的值(用户id)
4.具体实现方法
步骤1:编写BaseContext工具类,基于ThreadLocal封装的工具类
步骤2:在loginCheckFilter的doFiter方法中调用BaseContext来设置当前登录用户id
步骤3:在MyMetaObjectHandler类的方法中调用BaseContext获取用户登录的id
知识点三:Super关键字
- 可以引用父类中的成员:
- Super可以访问父类中定义的属性;super.xxx
- Suoer可以访问父类中定义的成员方法;super.xxx()
- Super可以在子类构造器中调用父类方法.super():无参构造方法;super(xxx)有参构造方
- 注意事项:
- 当子类和父类有相同的属性名时,在子类如果要使用父类的属性用super.
- Super只能应用到成员方法和构造方法中,不能 用在静态方法中
- 如果在构造方法中使用必须放在第一行
- 在构造方法中super()和this()不能同时出现
知识点四:MultipartFile工具类
String getName 返回参数名称
String getOriginalFilename 返回文件的内容类型
String getContentType
Byte[] getBytes[] throw IOException 将文件内容转换为一个byte[]数组
void transferTo(File var1) throws IOException, transferTo是复制file文件到指定位置(比如D盘下的某个位置),不然程序执行完,文件就会消失,程序运行时,临时存储在temp这个文件夹中
知识点五:Map的6种遍历方式
第一种方式:
for-each,+keySet()/values()遍历key/Value
KeySet():拿到苏所有的key;
Values():拿到全部的value
HashMap<String, Integer> map1 = new HashMap<>();
map1.put("小明", 1);
map1.put("小红", 2);
map1.put("小张", 3);
//for-each + keySet()遍历key
for (String key : map1.keySet()) { //遍历key
System.out.println("key = " + key);
}
//for-each + values()遍历value
for (Integer value : map1.values()) { //遍历value
System.out.println("value = " + value);
第二种方式:
For-each +entrySet()遍历
entrySet()方法:拿到全部的键值对对象
for (Map.Entry<String, Integer> entry : map1.entrySet()) {
System.out.print("key = " + entry.getKey());
System.out.println(", value = " + entry.getValue());
}
第三种方式:
for-each +KeySet()+get()方法遍历
Get()方法:传入key值,返回对应的Value;
一般不推荐,因为多一步根据key值去查找value的操作,效率会相对慢一点
map.get(key)方法的底层实现:
先调用Key的Hashcode方法得到哈希值,通过哈希算法得到对应的数组的下标,通过数组下标快速定位到某个位置上,如果这个位置上什么也没有,则返回null,如果这个位置上有单向链表,那么会拿着参数k和单项链表中的每个节点的k进行比较(equals()),如果所有的节点都返回false,那么最终该方法返回null,如果有一个节点的k和我们的k相匹配,那么该k节点所对应的value就是我们要找的value。
for (String key : map1.keySet()) {
Integer value = map1.get(key);
System.out.print("key = " + key);
System.out.println(", value = " + value);
}
第四种方式:
Iterator+entrySet()遍历
iterator()方法:返回一个用于遍历当前集合的迭代器
Iterator<Map.Entry<String, Integer>> iter = map1.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry<String, Integer> entry = iter.next();
System.out.print("key = " + entry.getKey());
System.out.println(", value = " + entry.getValue());
}
第五种方式:
lamabda表达式遍历
Foreach方法遍历数组种每一个元素并执行操作
//lambda表达式遍历
map1.forEach((key, value) -> {
System.out.print("key = " + key);
System.out.println(", value = " + value);
});
第六种方式:
Stream流进行遍历
Stream流的作用:区别与IO流,用于对容器进行书写简化
map1.entrySet().stream().forEach((Map.Entry<String, Integer> entry) -> {
System.out.print("key = " + entry.getKey());
System.out.println(", value = " + entry.getValue());
});
知识点六:JAVA的流式编程
流式编程的简介:
Stream API 是 Java 中引入的一种新的数据处理方法。 它提供了一种高效且易于使用的方法来处理数据集合。Stream API 支持函数式编程,可以让我们以简洁、优雅的方式进行数据操作,还有使用 Stream 的两大原因:
1.在大多数情况下,将对象存储在集合中就是为了处理它们,因此你会发现你把编程 的主要焦点从集合转移到了流上。
2.当 Lambda 表达式和方法引用(method references),流(Stream)结合使用的时候会让人感觉自成一体,行云流水的感觉
常见的中间操作:
1.filter(Predicate<T> predicate)
:根据给定的谓词筛选 Stream 中的元素。
2.map(Function<T, R> mapper)
:将 Stream 中的每个元素转换为另一种类型,根据给定的映射函数。
3.flatMap(Function<T, Stream<R>> mapper)
:将每个元素转换为另一个 Stream,然后将所有这些流连接成一个 Stream。
4.distinct()
:返回一个去重后的 Stream,其中每个元素只出现一次。
5.sorted()
:返回一个按自然顺序排序的 Stream。
6.sorted(Comparator<T> comparator)
:根据给定的比较器返回一个排序后的 Stream。
7.peek(Consumer<T> action)
:对 Stream 中的每个元素执行给定的操作,但不会改变 Stream 中的元素。通常用于调试目的
基于User 对象学习常见的几种操作:
static class User {
private Integer id;
private String name;
public User(Integer id, String name) {
this.id = id;
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
1.for循环
采用foreach+Lambda表达式的方式;
userList.forEach(user -> System.out.println(user.getId()));
2.filter过滤满足条件
使用.stream().filter()方法来筛选出满足条件的对象,最终返回的筛选过后的列表。
如下只获取到集合中用户id>2的所有用户:
Stream<User> satisfy = userList.stream().filter(user -> user.getId() > 2);
System.out.println("满足条件用户列表:" + satisfy.collect(Collectors.toList()));
3. 可以用.map 获取到遍历对象的所有属性值,拿到属性值后,我们可以重新将属性赋值到一个对象或基本类型的对象里,一般结合collect()方法来使用。
List<Integer> users = userList.stream().map(User::getId).collect(Collectors.toList());
System.out.println("用户id列表:" + users);
4.Collect()方法:toList()和toSet()、 toMap()
toList()和toSet()方法都是将map后的stream转换为一个列表对象,toSet()会去重重复的对象, 需要.map()方法将列表中的对象属性给映射出来。
// toList用法
List<Integer> list = userList.stream().map(User::getId).collect(Collectors.toList());
System.out.println("用户列表为: " + list);
toMap() 是将stream直接转换为一个map, 不需要.map()方法支持。
Map<Integer, String> map = userList.stream().collect(Collectors.toMap(User::getId, User::getName));System.out.println("用户map为: " + map);
知识点七:postMapping、putMapping、getMapping、deleteMapping
http与服务器交互提供了四种方式,get、post、put和delete
- get:是相当于select查询操作,不会改变或影响服务器端的任何内容信息;getMapping
- post:是相当于insert插入操作,会增加数据,存入到服务器端;postMapping
- put:是相当于update更新操作,不会增加数据,只是修改服务器端的信息;putMapping
- delete:是相当于delete删除操作,是用来删除资源的;deleteMapping
@RequestParam:于将指定的请求参数赋值给方法中的形参。
@RequestParam(required = false/true,value = “参数名”,defaultValue = “”) name和value等效这里用value,推荐使用value;
1.value:参数名,前端请求必须使用指定该参数名,不然项目会报错;
2.required:前端请求该方法是否包含该参数,默认为true,表示该请求路径中必须包含该参数,如果不包含就报错。
3.defaultValue:默认参数值,如果设置了该值,required=true将失效,自动为false,如果没有传该参数,就使用默认值。
例如blogs?blogId=1
@PathVariable
通过 @PathVariable 可以将 URL 中占位符参数绑定到控制器(controller)处理方法的形参中:URL 中的 { xxx} 占位符可以通过@PathVariable(“xxx“) 绑定到操作方法的形参中。
1.String value:可指定占位符 { } 中的参数名,若只指定value这一个属性可省略属性名不写,若占位符中的参数名和处理方法中的参数名相同可省略此属性。
2.String name:等价与value,和value无本质上的差异,两个属性指定其一即可。
3.boolean required:是否必需,默认为 true,即 请求中必须包含该参数,如果没有包含,将会抛出异常(可选配置)
例如/blogs/1
@RequestBody
1.@RequestBody主要用来接收前端传递给后端的json字符串中的数据的(请求体中的数据的);GET方式无请求体,所以使用@RequestBody接收数据时,前端不能使用GET方式提交数据,而是用POST等方式进行提交。
2.后端@RequestBody注解对应的类在将HTTP的输入流(含请求体)装配到目标类(即:@RequestBody后面的类)时,会根据json字符串中的key来匹配对应实体类的属性,如果匹配一致且json中的该key对应的值符合(或可转换为), 实体类的对应属性的类型要求时,会调用实体类的setter方法将值赋给该属性。
3.json字符串中,如果value为""的话,后端对应属性如果是String类型的,那么接受到的就是"",如果是后端属性的类型是Integer、Double等类型,那么接收到的就是null。
4.json字符串中,如果value为null的话,后端对应收到的就是null。
5.如果某个参数没有value的话,在传json字符串给后端时,要么干脆就不把该字段写到json字符串中;要么写value时, 必须有值,null 或""都行。
通过@RequestMapping注解中的 { } 占位符来标识URL中的变量部分
在控制器中的处理方法的形参中使用@PathVariable注解去获取@RequestMapping中 { } 中传进来的值,并绑定到处理方法定一的形参上
//请求路径:http://127.0.0.1/user/tom
@RequestMapping(value="/user/{name}")
public String username(@PathVariable(value="name") String username) {
return username;
}