Maven中scope元素使用
前言
在梳理项目的过程中发现很多开发同学对Maven依赖文件的配置并不了解,特别是对Maven的optional元素和scope元素的使用也非常随意。这就会导致发布的jar包或war包非常“胖”、编译速度慢,而且还很容易生产jar冲突等问题。
optional元素
这里以Spring Boot项目中的使用为例,比如我们在项目中经常使用的热部署组件spring-boot-devtools,就可以使用optional元素来进行定义,对应pom文件中配置如下:
1 | <!--devtools 热部署--> |
那么,这里的optional元素设置为true表示何意?optional是Maven依赖jar时的一个选项,表示该依赖是可选的,项目之间依赖不传递。不设置optional(默认)或者optional是false,表示传递依赖。
文字描述可能比较抽象,下面用具体实例场景来进行更直观的描述,这里假设有两个项目A和B,其中A为父项目,B为子项目。在父项目中引入了单元测试的依赖:
1 | <dependency> |
optional元素默认值(false)
父项目并未设置optional元素为true,那么便具有依赖传递性。此时,子项目B中会直接引入父项目A中引入的Junit的jar包。也就是说B项目打包时,jar/war包中会包含junit的jar包
optional元素为true
当父项目引入junit依赖时,设置optional元素为true。那么,子项目B便有了更多的选择。
如果项目B不需要Junit的jar包,那么在其pom文件中不需进行任何处理便可以。如果B项目也需要对应的jar包依赖,可以有两种选择:第一、A项目中对应依赖的optional设置为false或去掉;第二、B项目中直接引入需要的该依赖。
scope元素
上面讲完了optional元素的使用,再来看看scope的使用。
scope元素主要用来控制依赖的使用范围,指定当前包的依赖范围和依赖的传递性,也就是哪些依赖在哪些classpath中可用。常见的可选值有:compile, provided, runtime, test, system等。
compile(编译)
默认值。compile表示对应依赖会参与当前项目的编译、测试、运行等,是一个比较强的依赖。打包时通常会包含该依赖,部署时会打包到lib目录下。比如:spring-core这些核心的jar包
1 | <dependency> |
test(测试)
scope为test表示依赖项目仅参与测试环节,在编译、运行、打包时不会使用。最常见的使用就是单元测试类了:
1 | <dependency> |
类似单元测试这样的依赖,如果不设置scope为test,很显然它们会被打包、发布,但其实真是环境中并无什么作用。
runntime(运行时)
runntime仅仅适用于运行和测试环节,在编译环境下不会被使用。比如编译时只需要JDBC API的jar,而只有运行时才需要JDBC驱动实现。
1 | <dependency> |
provided(已提供)
provided适合在编译和测试的环境,和compile功能相似,但provide仅在编译和测试阶段生效,provide不会被打包,也不具有传递性。
比如:上面讲到的spring-boot-devtools、servlet-api等,前者是因为不需要在生产中热部署,后者是因为容器已经提供,不需要重复引入。
1 | <dependency> |
system
system范围依赖与provided类似,不过依赖项不会从maven仓库获取,而需要从本地文件系统提供。使用时,一定要配合systemPath属性。不推荐使用,尽量从Maven库中引用依赖。
1 | <dependency> |
Shiro Filter的一个问题
前言
今天遇到个问题,项目中用的是shiro和jwt,自定义了一个jwt过滤器来判断当前请求是否有权限,项目跑起来后发现所有的请求都不走过滤器,直接放行了?
解决
在shiroConfig中是这么配置的
1 | Map<String, String> filterRuleMap = new HashMap<>(2); |
一眼看过去好像没什么问题,但是就是不走自定义的jwt过滤器,所以判断问题一定出在这里,经过打断点后,发现filterRuleMap中的”/**”没有jwt这条,居然是下面的这个anon这个,那就没啥问题了
总结
anon的匿名的缩写,走的是shiro的默认过滤器,默认放行接口,因为前面是/**,因此会放行所有接口,不走我们的过滤器,删除这行后,接口正常走过滤器
SpringBoot注解@RequestParam @RequestBody @PathVariable
前言
最近在项目上遇到个需求,之前用的post请求,json参数,但是json参数是个数组,现在想要加个参数,我不想在
数组里每个都加一个,一开始想的是我直接在post url后面加个/{id},比如这样的,我们知道Get请求是可以这样的,但是post是不能这样的,否则会报url找不到
解决
@RequestParam 和 @RequestBody 都是从 HttpServletRequest request 中取参的,而 @PathVariable 是映射 URI 请求参数中的占位符到目标方法的参数中的,接下来一一举例说明。
前端在不明确指出 Content-Type 时,默认为 application/x-www-form-urlencoded 格式,@RequestParam 可以获取 application/x-www-form-urlencoded 以及 application/json 这两种类型的参数,但是 @RequestBody 是用来获取非 application/x-www-form-urlencoded 类型的数据,比如 application/json、application/xml 等。
@RequestParam
这种方式无论是 GET 还是 POST 请求,都是可以获取到参数的,举例中使用了 @RequestParam 注解的一些参数,具体参数如下:
defaultValue如果本次请求没有携带这个参数,或者参数为空,那么就会启用默认值name绑定本次参数的名称,要跟URL上面的一样required这个参数不是必须的,如果为 true,不传参数会报错value跟name一样的作用,是name属性的一个别名
@PathVariable
@PathVariable 也有相应的参数:
- name 绑定参数的名称,默认不传递时,绑定为同名的形参。 赋值但名称不一致时则报错
- value 跟name一样的作用,是name属性的一个别名
- required 这个参数不是必须的,如果为 true,不传参数会报错
使用 @PathVariable 需要注意两点:
- 参数接收类型使用基本类型
- 如果
@PathVariable标明参数名称,则参数名称必须和URL中参数名称一致
@ReuqestBody(不能用于GET请求)
使用 @RequestBody 注解可以方便的实现 JSON 串到接收参数的数据映射。
说明一下 @RequestBody 为什么不能用用于 GET 请求,RequestBody 顾名思义,是将请求参数设置在请求 Body 中的,也就是请求体,而 GET 请求无请求体。
使用 @RequestBody 需要满足如下条件:
Content-Type为application/json,确保传递是 JSON 数据;- 参数转化的配置必须统一,否则无法接收数据,比如 json、request 混用等
总结
1、在 GET 请求中可以使用 @RequestParam,不能使用 @RequestBody,@RequestBody 是用来获取请求体中的参数,因为 GET 请求没有请求体,所以不能使用。
2、在 POST 请求中,可以使用 @RequestBody 和 @RequestParam ,其中 @RequestParam 是用来获取 application/x-www-form-urlencoded 、form-data 格式数据的,@RequestBody 用来获取非 application/x-www-form-urlencoded 数据的,比如 application/json、application/xml 等。
3、一个方法中,可以同时使用多个 @RequestParam ,但是只能使用一个 @RequestBody,否则会报错。
4、@PathVariable 起到的作用就是 URI 请求参数中的占位符到目标方法参数的映射。
5、前端请求的 Content-Type ,默认值为 application/x-www-form-urlencoded,在这种格式下,后端直接使用 @RequestParam 就可以直接获取指定的参数,但是一旦前端传递的是 JSON 数据,也就是 Content-Type 的值为 application/json,那么使用 @RequestParam 是取不到值的,不但取不到值还报错。
docker镜像加速-腾讯
前言
我用腾讯的服务比较多,比如服务器、域名、消息队列、cdn等,所以我看很多docker镜像加速提供的是阿里的加速服务,我搜了一下腾讯也有docker镜像源加速,那就直接用腾讯的吧,笔记在腾讯的服务器上,应该会更快
配置
执行以下命令,打开 /etc/docker/daemon.json 配置文件
1 | vim /etc/docker/daemon.json |
不用管有没有这个文件,直接编辑就行,不存在会直接新建
按 i 切换至编辑模式,添加以下内容,并保存
1 | { |
执行以下命令,重启 Docker 即可
1 | sudo systemctl restart docker |
SpringBoot项目集成WebSocket
jar包启动报错MalformedInputException: Input length = 2
Stream操作中peek的使用
前言
最近项目中遇到一个需求,一个List<entity>,实体里有多个字段,只有部分有值,需要遍历这个实体,给其他的字段也赋值后在更新会数据库,首先想到的就是stream流操作
过程
1 | waitDevs.parallelStream().map(rec -> { |
一开始是这么写的,map里设置完,return返回这个实体,但是idea提示了可以用peek这个操作,按照它的提示最后改进了这个代码
1 | waitDevs.parallelStream().peek(rec -> { |
不需要return了,下面说下这俩的区别
区别
1 | Stream peek(Consumer<? super T> action) |
返回由该流的元素组成的流,另外在从生成的流中消耗元素时对每个元素执行提供的操作。
1 | Stream map(Function<? super T,? extends R> mapper) |
返回由给定函数应用于此流的元素的结果组成的流。
- 两个函数都是中间操作,都非常的‘懒’,没有对Stream的终止操作,两个函数都不会工作。
- peek函数的存在仅仅是为了debug,而map是Stream的一个核心函数,两个函数的地位不同。
- 两个函数的返回值都是一个新的Stream,但是两个函数的参数(peek是Consumer,map是Function)起作用的时机不同。map的Function在生成新的Stream之前被执行,新Stream中的元素是上游Stream中元素经Function作用后的值。peek函数的Consumer工作在生成Stream之后,下一节详细讲解两个函数执行时机。
peek和map修改Stream的元素
map函数对Stream中元素执行的是映射操作,会以新的元素(map的结果)填充新的Stream,严格的讲map不是修改原来的元素。
peek只能消费Stream中的元素,是否可以更改Stream中的元素,取决于Stream中的元素是否是不可变对象。如果是不可变对象,则不可修改Stream中的元素;如果是可变对象,则可以修改对象的值,但是无法修改对象的引用。
总结
举个很简单的例子,比如 Stream.of("one", "two", "three", "four")流中是字符串,如果peek中修改了字符串,则是无效的,但是流中如果是个可变对象,就是可以修改的
Android Room: No value passed for parameter
前言
最近写客户端项目时用room数据库时,遇到个问题,编译项目报错:No value passed for parameter 'id',翻译过来是: 没有为参数“id”传递值,下面记录下解决方法
过程
我的实体类如下
1 | @Entity(tableName = "user") |
我在新建实体的时候报上面的错
1 | val user = User(name = 'jinsc', addr = '1') |
因为是让主键自动生成,所以不能给ID赋值,但是不赋值会报错
解决
1 | @Entity(tableName = "todos") |
相等于默认赋值
AES/DES加密padding填充问题
前言
最近在项目上遇到个加解密的问题,用的是3des加密,我这边在Android上需要解密它加密的数据,测试发现一直都是解密失败,但是它加密的肯定没错,它自己也能解密的,了解了这一点,就排除了密钥错误的问题,想想是不是别的问题呢
解决
Java中默认实现为:DESede/ECB/PKCS5Padding, 第一个是3des加密,肯定没问题,第二个模式为ecb(电子密码本模式),也没问题,那存在问题的可能就是第三个补码方式了
上面说了,java默认的补码方式是PKCS5Padding,常用的还有PKCS7Padding和ZeroPadding,先了解下三个的区别
ZeroPadding,数据长度不对齐时使用0填充,否则不填充。PKCS7Padding,假设数据长度需要填充n(n>0)个字节才对齐,那么填充n个字节,每个字节都是n;如果数据本身就已经对齐了,则填充一块长度为块大小的数据,每个字节都是块大小。PKCS5Padding,PKCS7Padding的子集,块大小固定为8字节。
那就用排除法一个个试下吧,PKCS5Padding是默认的补码方式,所以不用试了,PKCS7Padding也是一样的报错,最后用ZeroPadding发现没问题,可以正常解密,看来它加密的时候用的是ZeroPadding补码的