用户中心-小记
用户中心-小记
实操遇见的问题
用 npm
或 yarn
无法安装 umi
安装报错或者一直卡顿的问题:**首先已经确保在 node.js 官网安装好了之后在命令行*用 node -v 查看版本号(有版本号说明安装成功),然后安装 tyarn ,使用 npm i yarn tyarn -g 命令在命令行安装( -g:全局安装),安装完之后同样输入 tyarn -v 进行测试是否安装成功,tyarn 使用的是 npm.taobao.org 的源 速度会快些(如果安装失败,考虑是否是没有将 yarn 添加到系统环境变量导致,可自行搜索添加),本机是用 npm 或 yarn 无法安装 umi ,换 tyarn 可以的,安装umi--- tyarn global add umi ,安装完之后测试直接在命令行输入 umi 即可。 仍然安装失败
ant-design卸载:
- 查看是否已安装 ant-design:
npm ls antd | yarn list antd
- 卸载(如果确认已经安装):
npm uninstall antd | yarn remove antd
- 如果还报错可以清一下缓存:
npm cache clean | yarn cache clean
npm换源 : npm config set registry https://registry.npmmirror.com/m
,然后使用 npm config set registry
命令切换到这个源即可。
使用哪个镜像,只需要
npm config set registry + 对应的镜像网址
就好了还原:
npm config set registry https://registry.npmjs.org/
安装时报错:error Couldn't find a package.json file in "文件路径"info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
-
错误原因:依赖包产生了缓存(重复下载了就是)
-
解决办法:删除 node_modules 包
-
执行如下命令:
npm cache clean --force | yarn cache clean
npm cache clean --force 可能会报错:npm warn using --force Recommended protections disabled.
换成
npm cache verify
即可 -
重新下载依赖包
-
-
如果上述方法没有解决,可以右键 nodejs 文件夹选择属性=》安全=》编辑,将 ”写入“ 权限勾选上即可。
用IDEA初始化项目时,jdk版本大于等于17,是因为官方"全面升级",将URL源改为-> https://start.aliyun.com/
阿里云即可选择 Java8 版本初始化项目,还原-> https://start.spring.io/
IDEA maven plugin Cannot resolve symbol ‘xxx‘问题解决:会发现pom文件下的 repackage 爆红 <goal>repackage<\goal>没有识别
,初步判断为IDEA中 maven repository 中没有相应依赖,可以去https://mvnrepository.com/中查找相关依赖(Spring-Boot-Maven-Plugin)引入项目中。
tips:其他的Cannot resolve symbol ‘xxx’ ’问题也可用上述思路解决。
- 如若问题没有解决还是爆红,可以点开IDEA侧边栏的 Maven ,然后先"clean"一下,再"install"即可。参考_脚本之家_ 解决方案所有Intellij IDEA Cannot Resolve Symbol XXX问题的解决方法汇总_编程开发_软件教程_脚本之家
IDEA粘贴代码后自动导包:file-->settings 搜索auto import(自动导包) 勾选上下图的add选框即可。其他新建的项目需要修改设置,file-->other settings-->settings for new objects 同理修改即可保存。以后的项目都是相同的设置
@MapperScan("")和@Mapper
- 首先了解
@MapperScan
注解的作用@MapperScan
是Spring Boot提供的一个注解,用于扫描指定包下的所有Mapper
接口。它的主要目的是告诉Spring框架在哪里可以找到数据访问层(DAO)的接口,这些接口通常用于与数据库进行交互,例如通过MyBatis等持久层框架。- 当在主类上添加
@MapperScan("com.example.mapper")
(这里com.example.mapper
是假设的Mapper
接口所在的包路径)后,Spring会自动扫描这个包及其子包下的所有接口,并将它们注册为MyBatis的Mapper
。
- 再看
@Mapper
注解的作用@Mapper
注解是MyBatis - Spring - Boot - Starter库提供的,用于将一个接口标记为MyBatis的Mapper
接口。当一个接口被标记为@Mapper
后,MyBatis - Spring会为这个接口创建一个代理对象,这个代理对象可以用于执行SQL语句等数据库操作。
- 关于是否还需要添加
@Mapper
注解- 在已经使用
@MapperScan
的情况下,理论上可以不在Mapper
包下的接口中添加@Mapper
注解。因为@MapperScan
已经完成了接口的扫描和注册工作。 - 不过,添加
@Mapper
注解也不会产生冲突。在一些复杂的项目结构或者当你想要明确某个接口是Mapper
接口时,仍然可以添加@Mapper
注解。
- 在已经使用
- 所以,在主类下加了
@MapperScan
后,一般不需要在Mapper
包下的文件中添加@Mapper
注解,但添加也不会有问题。
```java
Loading class com.mysql.jdbc.Driver'. This is deprecated. The new driver class is
com.mysql.cj.jdbc.Driver'. The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary.
测试运行后或者项目启动控制台会出现这条信息的爆红,意思是不需要手动加载驱动类了,新的驱动类 `com.mysql.cj.jdbc.Driver` 会自动注册。在 .yml(或者 .yaml 或 .properties) 配置文件里修改配置信息即可。 ##### ‘SpringBootTest‘ 注解 报红问题解决方案:如果对应的包不自动导入(`import org.springframework.boot.test.context.SpringBootTest;` ) 在 ==Libraries== 里找到对应的版本号并添加到pom.xml文件中即可。 ```java <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>3.3.5</version> //这个就是自己添加的版本号 </dependency>
然后重新加载一下maven,返回测试文件中重新输入一下即可有提示且自动导包。
插件-GenerateAllSetter :一键生成一个对象的所有set方法。
在request 包中创建可供控制层调用的类时实现了 Serialiable 接口(防止序列化冲突,所以需要实现接口并生成序列化UID)但是如果没有生成 serialVersionUID 的选项,就打开插件市场搜索安装插件 GenerateSerialVersionUID 即可。
在IntelliJ IDEA中用于重构的快捷键
1. 重命名(Rename)
- 快捷键:
Shift + F6
(在Windows和Linux系统中)或⇧ + F6
(在Mac系统中)。 - 功能说明:这个快捷键用于重命名变量、方法、类等元素。当你按下这个快捷键后,IDEA会自动识别元素的所有引用,并在你修改名称后,将所有引用处的名称同步更新,这样可以有效避免手动逐个修改引用可能出现的遗漏或错误。例如,如果你有一个名为
oldVariableName
的变量,在多个方法中被使用,使用重命名快捷键后,将其改为newVariableName
,IDEA会自动在所有使用该变量的地方进行替换。
2. 提取方法(Extract Method)
- 快捷键:
Ctrl + Alt + M
(在Windows和Linux系统中)或⌘ + ⌥ + M
(在Mac系统中)。 - 功能说明:当你有一段复杂的代码块,它可以被独立出来作为一个方法时,就可以使用这个快捷键。例如,你有一段计算订单总价的代码,包括计算商品价格总和、加上运费、计算折扣等步骤,这些步骤原本都写在一个较长的
calculateTotalPrice
方法中。你可以选中计算运费的代码块,使用提取方法快捷键,IDEA会弹出一个对话框让你输入新方法的名称(比如calculateShippingFee
),然后它会自动将选中的代码块提取到一个新的方法中,并在原来的位置调用这个新方法。
3. 提取变量(Extract Variable)
- 快捷键:
Ctrl + Alt + V
(在Windows和Linux系统中)或⌘ + ⌥ + V
(在Mac系统中)。 - 功能说明:如果在代码中有一个复杂的表达式被多次使用,或者这个表达式的意图不明显,你可以使用这个快捷键将表达式提取为一个变量。比如,你有一个很长的数学表达式
(a * b + c * d) / e
,在代码中多次出现,使用提取变量快捷键后,IDEA会将这个表达式提取出来,并提示你为这个变量命名,如resultVariable
,然后在原来使用表达式的地方替换为这个变量,这样代码会更加清晰易读。
4. 内联变量/方法(Inline)
- 快捷键:
Ctrl + Alt + N
(在Windows和Linux系统中)或⌘ + ⌥ + N
(在Mac系统中)。 - 功能说明:与提取变量/方法相反,内联操作是将变量或者方法的调用处直接替换为变量的值或者方法体内容。例如,你有一个简单的变量
int simpleVariable = 5;
,并且在代码中有一个方法printValue
里面只是简单地打印这个变量的值System.out.println(simpleVariable);
,你可以对simpleVariable
使用内联变量快捷键,IDEA会将System.out.println(simpleVariable);
替换为System.out.println(5);
。
5. 移动(Move)
- 快捷键:
F6
。 - 功能说明:用于将类、方法、变量等元素移动到另一个包、类或者文件中。例如,你有一个工具方法
utilityMethod
在com.example.oldpackage
包下的一个类中,你想将这个方法移动到com.example.newpackage
包下的另一个类中,选中这个方法后,按下F6
,IDEA会引导你完成移动操作,包括更新相关的导入语句等。
这些快捷键可以极大地提高代码的质量和可维护性,帮助你更高效地进行软件开发。
处理用户脱敏:
原本的过程(没有将脱敏过程单摘出去作为一个独立的方法时): List<User> userList = userService.list(queryWrapper); return userList.stream().map(user -> { user.setUserPassword(null); return user; }).collect(Collectors.toList()); ------------------------------------------------------ 现在: List<User> userList = userService.list(queryWrapper); return userList.stream().map(user -> { user.setUserPassword(null); return userService.getSafetyUser(user); }).collect(Collectors.toList()); 现在已经把脱敏过程写了一个方法getSafetyUser,为什么user.setUserPassword(null);流处理操作以及将user的密码属性设置为了null,返回的时候要变成返回userService.getSafetyUser(user);
以下是关于这段代码中为何既设置 user
对象的密码属性为 null
,又返回 userService.getSafetyUser(user)
的原因分析:
- 数据脱敏的多步骤需求
- 密码属性置空:在很多应用场景中,用户的密码属于敏感信息,不应该被随意暴露。所以首先通过
user.setUserPassword(null)
操作,将用户对象中原本存储的密码值设置为null
,这是最直接的一种防止密码信息泄露的手段,确保在后续的处理过程中,即使对象在各个环节流转,密码信息也不会意外被获取到。 - 其他脱敏操作(通过
getSafetyUser
方法):然而,除了密码之外,可能用户对象中还存在其他敏感信息,例如手机号、身份证号等,这些信息也需要进行相应的脱敏处理。getSafetyUser
方法很可能就是封装了对用户对象中多种敏感信息进行综合脱敏的逻辑。它可能会按照既定的业务规则,对手机号进行部分隐藏、对身份证号进行特定格式的处理等,从而返回一个经过全面脱敏的、安全的用户对象版本。
- 密码属性置空:在很多应用场景中,用户的密码属于敏感信息,不应该被随意暴露。所以首先通过
- 整体返回安全版本用户对象的考虑 -
- 遵循安全规范:从安全和数据隐私保护的角度来看,系统往往需要对外提供的用户信息是经过全面脱敏处理后的。只将密码设置为
null
并不足以满足整体的安全要求,必须要通过调用userService.getSafetyUser(user)
来确保所有该处理的敏感信息都已经按照业务要求进行了合适的处理,这样返回的用户对象才是可以放心地在后续流程中(比如返回给前端展示、传递给其他外部接口等)使用的安全版本。 - 方法职责划分:代码这样编写也是一种合理的职责划分体现。
user.setUserPassword(null)
聚焦于解决密码这一关键敏感信息的即时处理,而userService.getSafetyUser(user)
则负责更全面、系统地对整个用户对象进行各种必要的脱敏操作,各司其职共同保障了返回的用户列表中的每个用户对象都是符合安全标准的。
- 遵循安全规范:从安全和数据隐私保护的角度来看,系统往往需要对外提供的用户信息是经过全面脱敏处理后的。只将密码设置为
- 后续使用的便利性与一致性
- 统一的安全数据格式:返回经过
userService.getSafetyUser(user)
处理后的用户对象,使得后续在代码的任何地方使用这个返回的用户列表时,都可以直接依赖于这些已经是统一脱敏格式的对象,不需要再去额外判断哪些信息还没处理或者担心敏感信息泄露问题,保证了整个数据使用流程中数据安全相关处理的一致性。 - 便于维护和扩展:如果将来业务需求发生变化,例如又增加了新的敏感信息需要脱敏或者修改了现有的脱敏规则,只需要在
getSafetyUser
方法内部进行相应的调整即可,而不用在每个涉及返回用户对象的地方去分别修改具体的脱敏逻辑,提高了代码的可维护性和扩展性。 综上所述,在代码中同时进行user.setUserPassword(null)
以及返回userService.getSafetyUser(user)
是出于多方面对数据安全、代码职责划分以及后续使用便利性等因素的综合考量。
- 统一的安全数据格式:返回经过
补充...乌龙了,直接用
List<User> userList = userService.list(queryWrapper); return userList.stream().map(user -> userService.getSafetyUser(user)).collect(Collectors.toList()); 这样就好
打包JAR后无法运行,”缺少主清单属性“
网上的方法都不对应问题,项目没有问题,按照网上的修改 .MF 文件也不行。最后通过挨个搜索 spring - boot - maven - plugin
的标签发现,我的标签里有一个 <skip>true</skip>
标签 ,搜了一下它的作用是会 跳过该插件的执行 ,ok问题就在这里了,删掉或者改成 false 即可。回看之前打的包就几十KB,成功之后的是几十MB。成功运行 java -jar .\user-center-0.0.1-SNAPSHOT.jar --spring.profiles.active=prod
实用技巧
判断参数是否为空时,不用 if(...)
,在 [Maven官网](Maven Repository: Search/Browse/Explore) 引入依赖 Apache Commons Lang
,选一个用的人多的版本,放在项目的 .xml 文件中。
要放在运行时依赖的上边,因为是项目全过程都需要用到的依赖。
org.springframework.boot spring-boot-devtools runtime true 放在这个上边即可.
插入数据时减少挨个对变量进行 .set... 方法进行设置,太过繁琐冗余,可以alt + enter 一键生成所有的setter方法。
[密码验证正则表达式 ](正则表达式 - 密码格式验证大全 - TinyMaD - 博客园) :博客园,基本很全。
mybatis-plus框架配置逻辑删除:
步骤一: mybatis-plus: global-config: db-config: logic-delete-field: deleted # 全局逻辑删除字段名 logic-delete-value: 1 # 逻辑已删除值 logic-not-delete-value: 0 # 逻辑未删除值 步骤二: 在对应字段(上段配置中对应的 "全局逻辑删除字段名")处加上 @TableLogic 注解
在数据库表新加字段后:
需要自行更新mapper的相关信息,如 resources.mapper 下的
java8特性 - stream流API中的peek方法:
- 以下是关于
peek
方法以及为何它能在上述场景中平替map
方法的相关解释: ###peek
方法概述 在Java 8引入的Stream API中,peek
方法主要用于对Stream中的元素执行一个中间操作(intermediate operation),其目的通常是在元素流经Stream管道时查看或者调试元素的状态等。 -
- 语法和参数:它接收一个
Consumer
类型的参数,这个Consumer
定义了针对每个元素要执行的操作。例如在userList.stream().peek(user -> user.setUserPassword(null))
中,user -> user.setUserPassword(null)
就是一个Consumer
,它会对Stream中每一个user
对象执行设置密码为null
的操作。 - 作用特点:
peek
方法主要是为了让开发者有机会在Stream处理流程中观察或者对元素进行一些附带的修改(像这里修改对象的某个属性值),它不会改变流中元素的数量,只是对每个元素逐个应用传入的操作,然后继续将元素传递到后续的操作环节。
- 语法和参数:它接收一个
- 与
map
方法在上述场景平替的原因 -
- 操作目的角度 在给定的代码场景中,
map
方法实现的是:java userList.stream().map(user -> { user.setUserPassword(null); return user; }).collect(Collectors.toList());
它的目的是对userList
这个Stream中的每个user
对象,修改其userPassword
属性为null
,然后返回这个修改后的user
对象,最终收集成一个新的列表。 而peek
方法实现的是:java userList.stream().peek(user -> user.setUserPassword(null)).collect(Collectors.toList());
同样也是针对每个user
对象,去执行将userPassword
设置为null
的操作,从对每个元素执行的具体修改操作这个角度来看,二者达成的最终效果是一样的,都是把每个user
对象的密码属性进行了清空操作。
- 操作目的角度 在给定的代码场景中,
-
- 返回值方面 -
map
方法:它要求传入的Lambda
表达式必须返回一个值,这个返回值会替换原来Stream中的元素,进而后续的操作是基于返回后的新元素来继续进行的。在上述代码中,它返回了修改后的user
对象本身(其实就是原对象,只是属性值改变了)。peek
方法:虽然它本身的设计重点不在于返回值去改变Stream元素,主要是执行附带的操作,但对于修改对象内部属性这种情况,因为修改是直接作用在对象自身上(是引用类型,不是基本类型),所以即便peek
方法返回的还是原来的元素(并没有像map
那样通过返回值去替换元素),但由于对象自身的属性已经被修改了,也就等同于达到了类似map
中返回修改后元素的效果。 总的来说,在上述只是想对Stream中元素(这里是user
对象)进行修改其某个属性这种场景下,peek
方法能够起到和map
方法类似的最终效果,进而可以平替map
方法使用。不过要注意在其他一些需要严格通过返回值来改变元素的场景下,二者是不能随意替换的,要依据具体的业务逻辑和期望的处理结果来选择合适的方法。
- 返回值方面 -
在Service实现类里写了方法后:
要在上方加上 @Override
注解,因为一般都调用接口,而不是实现类,然后 alt+enter 选择 Pull method 'getSafetyUser' to 'UserService'
在接口中完善方法。
IDEA悬浮参数提醒
- 可能是 IDEA 的设置问题。你可以检查 “Editor - General - Show quick documentation on mouse move” 选项是否被勾选。如果没有勾选,将其勾选上后应该就可以正常显示悬浮参数提醒了。
- 也有可能是因为 IDEA 的缓存问题导致功能异常。尝试通过 “File - Invalidate Caches / Restart” 来清除缓存并重启 IDEA,看看是否能恢复悬浮提示功能。
小知识
控制层 Controller 封装请求
server: # 指定接口全局 api servlet: context-path: /api
@RestController 适用于编写 restful 风格的 api 返回值默认为json类型
-
可以封装一个对象(在model中, 最好是在 domain 下创建一个 request 包),专门用来接受请求,用于 Controller 层的调用。使用 Lombok 的
@Data
注解自动生成get set方法。 -
在Controller 层中使用到该类作为参数时(实际上就是把前端应该传过来的参数打包用一个变量表示,减少代码繁琐程度) 要加上
@RequestBody
注释,不然 SpringMVC不知道怎么把前端传来的 json参数和对象做关联 。eg:在model.domain.request路径下创建了 UserRegisterRequest 类,然后在 Controller 层中的方法 userRegister()中将 userRegisterRequest (UserRegisterRequest 的实例) 当作参数传入,对其加上@RequestBody
注解。public Long userRegister(@RequestBody UserRegisterRequest userRegisterRequest) { } -
接受方法的请求参数参考以上注册方法的请求参数也在 domain.request 新建1个类往里写。
-
总结地说 ,controller 层里用到的方法比如注册、登录等等,注册方法的请求参数在 domain.request 包下 UserRegisterRequest,登录方法的请求参数在 domain.request 包下 UserLogin ... 诸如此类。
controller 层和 service 层校验的区别
- controller 层倾向于对请求参数本身的校验,不涉及业务逻辑本身(越少越好)
- service 层时对业务逻辑的校验,因为有可能被除了 controller 之外的类调用,所以这一层的校验也是必须的(尽管看着可能哪哪都有校验会觉得多余,但这个过程时必须的)。
service层和controller层中同名的方法中都有HttpServletRequest参数是为什么,这两个方法是怎么产生关联的 :
-
MVC架构背景
- 在典型的Java Web应用的MVC(Model - View - Controller)架构中,
Controller
层主要负责接收和处理来自客户端(如浏览器)的请求,它是请求处理的入口。Service
层则专注于业务逻辑的实现,是处理具体业务操作的地方。
- 在典型的Java Web应用的MVC(Model - View - Controller)架构中,
HttpServletRequest
参数在Controller
层的作用- 在
Controller
层的方法中,HttpServletRequest
对象用于获取请求的各种信息,比如请求头(Headers
)、请求参数(Parameters
)、请求路径(Path
)等。例如,通过HttpServletRequest.getParameter("paramName")
可以获取URL中传递的参数值。假设我们有一个简单的用户登录Controller
方法:
@RequestMapping("/login") public String login(HttpServletRequest request) { String username = request.getParameter("username"); String password = request.getParameter("password"); // 调用Service层方法进行业务逻辑处理 boolean result = userService.login(username, password); if (result) { return "success"; } else { return "failure"; } } - 这里的
Controller
层方法接收HttpServletRequest
,获取了用户名和密码参数,然后准备将这些数据传递给Service
层进行登录验证。
- 在
HttpServletRequest
参数在Service
层(通常不应该有这个参数)的情况分析- 严格来说,
Service
层方法不应该直接接收HttpServletRequest
参数。Service
层应该是独立于Web容器的,专注于业务逻辑,如数据的持久化操作(与数据库交互)、业务规则的实现等。 - 但有时候出现这种情况可能是因为设计不够合理。一种可能是开发人员想在
Service
层直接访问请求相关的信息,比如获取请求头中的某些认证信息(如令牌)来进行业务逻辑判断。不过,这会导致Service
层和Web层(Controller
)耦合过紧。 - 更好的做法是将
Controller
层获取到的必要数据(如从HttpServletRequest
中提取的参数)进行整理,以合适的数据结构(如普通的Java
对象,如UserLoginDTO
)传递给Service
层。例如:
public class UserLoginDTO { private String username; private String password; // 构造方法、getter和setter方法 } Controller
层可以这样调用Service
层:
@RequestMapping("/login") public String login(HttpServletRequest request) { String username = request.getParameter("username"); String password = request.getParameter("password"); UserLoginDTO userLoginDTO = new UserLoginDTO(username, password); boolean result = userService.login(userLoginDTO); if (result) { return "success"; } else { return "failure"; } } - 在
Service
层:
public boolean login(UserLoginDTO userLoginDTO) { // 根据userLoginDTO中的用户名和密码进行业务逻辑验证 // 比如查询数据库等操作 return true; } - 严格来说,
- 关于关联方式
- 当
Controller
层和Service
层的方法同名(这只是一种命名习惯,不是必须同名)时,它们的关联主要是通过方法调用实现的。Controller
层在接收到请求并处理HttpServletRequest
获取必要数据后,会将经过整理的数据(如通过数据传输对象DTO
)传递给Service
层对应的方法来执行具体的业务逻辑。Service
层处理完成后,将结果返回给Controller
层,Controller
层再根据结果进行后续的操作,如返回不同的视图或者响应数据。这种分层的架构有助于分离关注点,使得代码结构更加清晰,便于维护和扩展。
- 当
关于 POST 和 GET 方式的选择 :有来有回用POST,光拿不给用GET。
用GET请求就不需要参数的 @RequestBody
注解了。
**编写每一个接口必须考虑这个接口会不会被恶意调用,有可能的话,就一定要 鉴权 ** 。简单的直接在业务里判断是不是管理员即可,复杂的可以用一些如 shiro、spring security之类的框架。
lambda表达式:
- 定义 - Lambda表达式是Java 8中引入的一种新的语言特性,它是一种匿名函数。简单来说,它提供了一种简洁的方式来表示可传递给方法或存储在变量中的代码块。Lambda表达式允许你将代码作为数据进行传递,这在处理集合、事件处理和并行编程等场景中非常有用。
- 语法结构 - Lambda表达式的基本语法有两种形式:
- 表达式形式:
(parameters) -> expression
。例如,(int a, int b) -> a + b
,这里(int a, int b)
是参数列表,a + b
是一个表达式,这个Lambda表达式表示接收两个整数参数并返回它们的和。 - 代码块形式:(parameters) ->{ statements; }
。例如,(String str) ->{ System.out.println(str); return str.length(); }
,参数str
是一个字符串,代码块中先打印这个字符串,然后返回字符串的长度。
- 表达式形式:
- 参数部分 - 参数列表可以为空,如
() -> System.out.println("Hello")
,这表示一个没有参数的Lambda表达式,它的功能是打印"Hello"。 - 如果只有一个参数,参数的括号可以省略。例如,str -> System.out.println(str)
和(str) -> System.out.println(str)
是等价的,这里的Lambda表达式用于打印传入的字符串。 - 当有多个参数时,参数之间用逗号分隔,并且括号不能省略,如(int a, int b) -> a * b
。 - 函数式接口与Lambda表达式的关系
- Lambda表达式主要用于实现函数式接口。函数式接口是只包含一个抽象方法的接口。例如,
java.util.function
包中的Consumer
接口,它的抽象方法是void accept(T t)
。一个符合Consumer
接口的Lambda表达式可以是(T t) ->{ /* 对t进行操作 */ }
,如(String s) -> System.out.println(s)
,这个Lambda表达式实现了Consumer<String>
接口,用于打印传入的字符串。
- Lambda表达式主要用于实现函数式接口。函数式接口是只包含一个抽象方法的接口。例如,
- 应用场景
- 集合操作(以Stream API为例):在处理集合时,Lambda表达式可以和Stream API一起使用。例如,
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
,可以使用numbers.stream().filter(n -> n % 2 == 0).forEach(System.out::println);
。这里n -> n % 2 == 0
是一个Lambda表达式,用于筛选出偶数,System.out::println
也是一种方法引用(和Lambda表达式相关的特性),用于打印筛选后的偶数。 - 事件处理:在图形用户界面(GUI)编程中,Lambda表达式可以用于处理按钮点击等事件。例如,
button.addActionListener(event -> System.out.println("Button clicked"));
,这里event -> System.out.println("Button clicked")
是一个Lambda表达式,用于定义当按钮被点击时要执行的操作。 - 并行编程:Lambda表达式结合Java的
parallelStream
可以实现并行处理。例如,List<String> strings = Arrays.asList("a", "b", "c");
,strings.parallelStream().forEach(s -> System.out.println(s));
可以并行地打印列表中的每个字符串,其中s -> System.out.println(s)
是用于打印字符串的Lambda表达式。
- 集合操作(以Stream API为例):在处理集合时,Lambda表达式可以和Stream API一起使用。例如,
写代码的流程:
先做设计
代码实现
持续优化
。。。。先简单实现功能再逐渐完善逐渐优化,不能想着一步起高楼,而是要先搭整体框架,然后慢慢完善慢慢优化。
代理
正向代理:替客户端向服务器发送请求。
反向代理:替服务器接收请求。
- 怎么设置代理:(包括但不限于)
- Nginx 服务器
- Node.js 服务器
跨域
跨域的问题只在浏览器里出现,因为浏览器的同源策略
跨域解决:
- 后端来支持跨域
- 代理 nginx 第三方工具、前端脚手架自带的工具,都可以
本文来自博客园,作者:sevenShaw,转载请注明原文链接:https://www.cnblogs.com/sevenShaw/p/18628593
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)