BULLETIN

Welcome to my website

公告: 网站正在建设中!!!

BLOG

1.1、原生 [https://oss.console.aliyun.com/overview](https://oss.console.aliyun.com/overview) 1、准备 1)、开通阿里云云存储功能 开通:[https://oss.console.aliyun.com/overview](https://oss.console.aliyun.com/overview) 开发文档:[https://help.aliyun.com/document_detail/32009.html?spm=a2c4g.11186623.6.778.614459aa0tT8Ms](https://help.aliyun.com/document_detail/32009.html?spm=a2c4g.11186623.6.778.614459aa0tT8Ms) 点击创建bucket,根据自己的需求选择相应规格 ![](https://img-blog.csdnimg.cn/2020062814550545.png) 2)、创建子用户 - 创建一个子用户专门用于我们上传文件时使用,创建好后记住AccessKey ID和SECRET [https://ram.console.aliyun.com/users/new](https://ram.console.aliyun.com/users/new) - 并且添加管理对象存储的权限 - 2、使用 1)、安装SDK 在Maven项目中加入依赖项(推荐方式) 在 Maven 工程中使用 OSS Java SDK,只需在 pom.xml 中加入相应依赖即可。以 3.8.0 版本为例,在 <dependencies> 内加入如下内容: ```csharp <dependency> <groupId>com.aliyun.oss</groupId> <artifactId>aliyun-sdk-oss</artifactId> <version>3.8.0</version> </dependency> ``` 2)、上传 以文件流上传 ```csharp // Endpoint以杭州为例,其它Region请按实际情况填写。 String endpoint = "http://oss-cn-hangzhou.aliyuncs.com"; // 云账号AccessKey有所有API访问权限,建议遵循阿里云安全最佳实践,创建并使用RAM子账号进行API访问或日常运维,请登录 https://ram.console.aliyun.com 创建。 String accessKeyId = "<yourAccessKeyId>"; String accessKeySecret = "<yourAccessKeySecret>"; // 创建OSSClient实例。 OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret); // 上传文件流。 InputStream inputStream = new FileInputStream("<yourlocalFile>"); ossClient.putObject("<yourBucketName>", "<yourObjectName>", inputStream); // 关闭OSSClient。 ossClient.shutdown(); ``` 1.2、直接上传 1)引入starter ```csharp <!-- OSS--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alicloud-oss</artifactId> </dependency> ``` 2)、配置oss ```csharp spring: cloud: alicloud: access-key: ****** secret-key: ****** oss: endpoint: ****** ``` 3)、引入OSSClient进行操作 ```java @Autowired OSSClient ossClient; @Test void upload() throws FileNotFoundException { InputStream inputStream = new FileInputStream("D:\\Pictures\\Saved Pictures\\logo.png"); ossClient.putObject("lomtom-mall", "logo.png", inputStream); // 关闭OSSClient。 ossClient.shutdown(); } ``` 1.3、服务端签名后上传 采用JavaScript客户端直接签名时,AccessKeyID和AcessKeySecret会暴露在前端页面,因此存在严重的安全隐患。因此,OSS提供了服务端签名后直传的方案。 ![](https://img-blog.csdnimg.cn/20200628161346538.png) 服务端签名后直传的原理如下: 1. 用户发送上传Policy请求到应用服务器。 2. 应用服务器返回上传Policy和签名给用户。 3. 用户直接上传数据到OSS。 参考:[https://help.aliyun.com/document_detail/91868.html?spm=a2c4g.11186623.2.15.4afc6e28LkeSweconcept-ahk-rfz-2fb](https://help.aliyun.com/document_detail/91868.html?spm=a2c4g.11186623.2.15.4afc6e28LkeSweconcept-ahk-rfz-2fb) 1)引入starter ```csharp <!-- OSS--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alicloud-oss</artifactId> </dependency> ``` 2)、配置oss ```csharp spring: cloud: alicloud: access-key: ****** secret-key: ****** oss: endpoint: ****** bucket: ***** ``` 3)、引入OSSClient进行操作 这里的R可以用JSONObject代替 ```java @Autowired OSS ossClient; @Value("${spring.cloud.alicloud.oss.endpoint}") private String endpoint; @Value("${spring.cloud.alicloud.oss.bucket}") private String bucket; @Value("${spring.cloud.alicloud.access-key}") private String accessId; @RequestMapping("/oss/policy") protected R poliocy(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // host的格式为 bucketname.endpoint String host = "https://" + bucket + "." + endpoint; // callbackUrl为 上传回调服务器的URL,请将下面的IP和Port配置为您自己的真实信息。 // String callbackUrl = "http://88.88.88.88:8888"; // 用户上传文件时指定的前缀。 String format = new SimpleDateFormat("yyyy-MM-dd").format(new Date()); String dir = format+"/"; Map<String, String> respMap = null; try { long expireTime = 30; long expireEndTime = System.currentTimeMillis() + expireTime * 1000; Date expiration = new Date(expireEndTime); // PostObject请求最大可支持的文件大小为5 GB,即CONTENT_LENGTH_RANGE为5*1024*1024*1024。 PolicyConditions policyConds = new PolicyConditions(); policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 1048576000); policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, dir); String postPolicy = ossClient.generatePostPolicy(expiration, policyConds); byte[] binaryData = postPolicy.getBytes("utf-8"); String encodedPolicy = BinaryUtil.toBase64String(binaryData); String postSignature = ossClient.calculatePostSignature(postPolicy); respMap = new LinkedHashMap<String, String>(); respMap.put("accessid", accessId); respMap.put("policy", encodedPolicy); respMap.put("signature", postSignature); respMap.put("dir", dir); respMap.put("host", host); respMap.put("expire", String.valueOf(expireEndTime / 1000)); // respMap.put("expire", formatISO8601Date(expiration)); } catch (Exception e) { // Assert.fail(e.getMessage()); System.out.println(e.getMessage()); } finally { ossClient.shutdown(); } return R.ok().put("data",respMap); } ``` 4)、在阿里云设置跨域请求 允许所有的ip通过post请求 ![](https://img-blog.csdnimg.cn/20200628173350886.png) 5)前端代码 方案一:用别人已经封装好的 资源下载:https://download.csdn.net/download/qq_41929184/12558619 1. 修改policy.js里的url,例如我这里是`/oss/policy` ```csharp url: http.adornUrl('/oss/policy'), ``` 2. 引入组件、绑定model ```csharp import SingleUpload from '@/components/upload/singleupload' <SingleUpload v-model="dataForm.logo"></SingleUpload> ``` 3. 修改OSS的 外网访问Bucket 域名 ```csharp <el-upload action='你自己的' :data='dataObj' '> ``` 方案二:自己撸一个 1、使用element上传组件 其中绑定上传的数据`dataObj`,上传前所需要处理的方法`beforeAvatarUpload`,上传后需要处理的方法`handleAvatarSuccess` ```cpp <el-upload class="avatar-uploader" :action="upload" :data='dataObj' :show-file-list="false" :on-success="handleAvatarSuccess" :multiple='false' :before-upload="beforeAvatarUpload"> <img v-if="imageUrl" :src="imageUrl" class="avatar"> <i v-else class="el-icon-plus avatar-uploader-icon"></i> </el-upload> ``` 2、设置数据 ```cpp data() { return { upload: this.$global.uploadUrl, //自己阿里云的上传地址 imageUrl: '', dataObj: { policy: '', signature: '', key: '', ossaccessKeyId: '', dir: '', host: '' }, } } ``` 3、编写相关方法 ```cpp methods: { handleAvatarSuccess(res, file) { this.imageUrl = this.dataObj.host + '/' + this.dataObj.key }, beforeAvatarUpload(file) { return new Promise((resolve, reject) => { this.$request.postRequest(this.$url.HOUSEINTERFACES.upload).then(res => { this.dataObj.policy = res.data.policy this.dataObj.signature = res.data.signature this.dataObj.ossaccessKeyId = res.data.accessid this.dataObj.key = res.data.dir + file.name this.dataObj.dir = res.data.dir this.dataObj.host = res.data.host console.log(this.dataObj) resolve(true) }) }) } } ``` 4、效果 ![](https://img-blog.csdnimg.cn/20200628184134394.png) 1.4、oss绑定域名 1、设置oss的初始页与404页面。 ![](https://img-blog.csdnimg.cn/2020102114221419.png) 2、申请域名,下载证书(nginx版本) 3、打开传输管理->域名管理->绑定域名 4、上传证书 ![](https://img-blog.csdnimg.cn/20201021142625385.png) 5、新建CNAME

2021-04-10

一、题目描述: 给定一个无重复元素的有序整数数组 nums 。 返回 恰好覆盖数组中所有数字 的 最小有序 区间范围列表。也就是说,nums 的每个元素都恰好被某个区间范围所覆盖,并且不存在属于某个范围但不属于 nums 的数字 x 。 列表中的每个区间范围 [a,b] 应该按如下格式输出: - "a->b" ,如果 a != b - "a" ,如果 a == b 示例 示例 1: >输入:nums = [0,1,2,4,5,7] 输出:["0->2","4->5","7"] 解释:区间范围是: [0,2] --> "0->2" [4,5] --> "4->5" [7,7] --> "7" 示例 2: >输入:nums = [0,2,3,4,6,8,9] 输出:["0","2->4","6","8->9"] 解释:区间范围是: [0,0] --> "0" [2,4] --> "2->4" [6,6] --> "6" [8,9] --> "8->9" 示例 3: >输入:nums = [] 输出:[] 示例 4: >输入:nums = [-1] 输出:["-1"] 示例 5: >输入:nums = [0] 输出:["0"] 提示: >0 <= nums.length <= 20 -231 <= nums[i] <= 231 - 1 nums 中的所有值都 互不相同 nums 按升序排列 二、解答 分析 解题思路: 1. 遍历整个数组,当相邻的数只相差1时,构成一个区间。 2. 当相邻的数相差大于1时,开始一个新的区间。 3. 当判断开始一个新的区间时,我们需要保存前面的区间。 4. 保存一个区间需要两个值分别记录区间开始的值,当前数的前一个数的值。 5. 唯一值得注意的是处理边界问题。 >时间复杂度:O(n),其中 n 为数组的长度。我们只需要遍历一次数组即可。 空间复杂度:O(1)。只需要常数空间存放若干变量。 代码 ```cpp class Solution { public List<String> summaryRanges(int[] nums) { int length = nums.length; List<String> result = new ArrayList<>(); if(length == 0){ return result; } int start = nums[0]; int now = nums[0]; int i = 1; for(;i < length;i++){ if(now + 1 == nums[i]){ now++; } else{ result.add(start == now?String.valueOf(start):start+"->"+now); start = now = nums[i]; } } result.add(start == now?String.valueOf(start):start+"->"+now); return result; } } ``` > 执行用时:7 ms, 在所有 Java 提交中击败了82.54%的用户 内存消耗:36.9 MB, 在所有 Java 提交中击败了53.76%的用户 改进 1. 因为当前数的前一个数的值,我可以通过当前的下标来获取,所以该值完全没有必要记录,所以可以省略该值 2. 省略该值之后,我只要通过下标来判断即可,所以在循环里,我只要判断前一个数加一与当前值不相等即可 ```java public List<String> summaryRanges(int[] nums) { int length = nums.length; List<String> result = new ArrayList<>(); if(length == 0){ return result; } int start = nums[0]; int i = 1; for(;i < length;i++){ if(nums[i - 1] + 1 != nums[i]){ result.add(start == nums[i - 1]?String.valueOf(start):start+"->"+nums[i - 1]); start = nums[i]; } } result.add(start == nums[i - 1]?String.valueOf(start):start+"->"+nums[i - 1]); return result; } ``` 这样做的好处就是节省了一定的空间。 三、官方解答 官方给出的题解也是一次遍历,但是是用双指针的方法,也就是使用维护下标low 和 high 分别记录区间的起点和终点,和我的大致思想也差不多。 ```cpp class Solution { public List<String> summaryRanges(int[] nums) { List<String> ret = new ArrayList<String>(); int i = 0; int n = nums.length; while (i < n) { int low = i; i++; while (i < n && nums[i] == nums[i - 1] + 1) { i++; } int high = i - 1; StringBuffer temp = new StringBuffer(Integer.toString(nums[low])); if (low < high) { temp.append("->"); temp.append(Integer.toString(nums[high])); } ret.add(temp.toString()); } return ret; } } ``` > 参考: > 1、[题目](https://leetcode-cn.com/problems/summary-ranges/) > 2、[官方解答](https://leetcode-cn.com/problems/summary-ranges/solution/hui-zong-qu-jian-by-leetcode-solution-6zrs/) >本文首发于CSDN,作者:lomtom 原文链接:**[https://blog.csdn.net/lomtom/article/details/112306554](https://blog.csdn.net/lomtom/article/details/112306554)** 个人网站:**[https://lomtom.top](https://lomtom.top)**,公众号:**博思奥园**,同步更新。 你的支持就是我最大的动力。 ![](https://img-blog.csdnimg.cn/20200405094243147.png)

2021-01-10

一、题目描述: 给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。 设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。 注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。 示例 示例 1: > **输入:** [7,1,5,3,6,4] 输出: 7 > **解释:** 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 =5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。 > 随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。 示例 2: > **输入:** [1,2,3,4,5] 输出: 4 > **解释:** 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。 > 注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。 > 因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。 示例 3: > **输入:** [7,6,4,3,1] 输出: 0 > **解释:** 在这种情况下, 没有交易完成, 所以最大利润为 0。 提示: > 1 <= prices.length <= 3 * 10 ^ 4 > 0 <= prices[i] <= 10 ^ 4 二、解答 分析 整个算法的精髓就是:**在最低点买入,在最高点卖出。** 恩,这钱真好赚。 而我们要做的就是找出n天当中的低谷和高谷。 例如七天中:7,1,5,3,6,4,找出低谷:1、3,高谷:5、6 ![](https://img-blog.csdnimg.cn/20201108183309769.pngpic_center) 所以,问题可以继续抽象成,我在数组中找到极小值与极大值 最终,我们可以用后一个是否比前一个小来判断,如果小我就卖出,并且在后一天买入。 这样带来的问题是,如果我最后持续上升 那么我就没办法卖出了(因为我通过后一天是否比前一天小来判断是否卖出),所以在最后再卖出一次。 >时间复杂度:O(n),其中 n 为数组的长度。我们只需要遍历一次数组即可。 空间复杂度:O(1)。只需要常数空间存放若干变量。 代码 ```cpp class Solution { public int maxProfit(int[] prices) { int sum = 0; int length = prices.length; if(length == 0){ return 0; } int temp = prices[0]; int i = 1; for(;i < prices.length;i++){ //后一天是否比前一天小 if(prices[i] < prices[i - 1]){ //计算获得的利润 sum += prices[i - 1] - temp; //重新买入 temp = prices[i]; } } //再卖出一次 sum += prices[i - 1] - temp; return sum; } } ``` > 执行用时:1 ms, 在所有 Java 提交中击败了99.54%的用户 > 内存消耗:38 MB, 在所有 Java提交中击败了96.68%的用户 三、官方解答 官方有两种:一种是动态规划,另一种是贪心算法(比我的更简洁) 贪心: ```cpp class Solution { public int maxProfit(int[] prices) { int ans = 0; int n = prices.length; for (int i = 1; i < n; ++i) { ans += Math.max(0, prices[i] - prices[i - 1]); } return ans; } } ``` > 参考: > 1、[题目](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/) > 2、[官方解答](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/solution/mai-mai-gu-piao-de-zui-jia-shi-ji-ii-by-leetcode-s/)

2020-11-08

由于业务的需求,我需要将每次写好的代码编译好后,并且通过ftp工具远程传到服务器上。 但是,这样的操作带来的问题是:整个的过程变得相当的复杂。 于是,就有了这篇文章。 我们可以这样理解: 1. 当我们把代码提交到github上时 2. github发起一次请求给服务器 3. 服务器接受请求后,执行拉取git的脚本 这样就实现了整个项目的自动部署。 ![](https://img-blog.csdnimg.cn/20201028212818382.pngpic_center) 准备 你需要安装**yum、git、go** 如果你已经安装过,那么你就可以跳过相应的步骤 并且默认你会ssh秘钥配对,如果不会请翻到最后。 一、安装yum ```cpp wget http://yum.baseurl.org/download/3.2/yum-3.2.28.tar.gz tar -xvf yum-3.2.28.tar.gz touch /etc/ yum.conf cd yum-3.2.28 ./yummain.py install yum ``` 二、安装git ```cpp yum install -y git git --version ``` 三、安装Go ```cpp yum install -y golang ``` 四、安装Webhook ```cpp 1、使用go 安装 go get github.com/adnanh/webhook 2、使用apt安装 sudo apt-get install webhook ``` 开源项目地址:https://github.com/adnanh/webhook 五、配置服务器 1、在一个目录下克隆github项目 我的在/root/test下拉取项目,项目名也叫test(拉取的项目存在于/root/test/test) 2、在同级目录新建hooks.json(位于/root/test/hooks.json) >定义一些需要webhook服务的钩子。首先创建一个名为hooks.json. 此文件将包含webhook将提供的钩子数组。查看钩子定义页面,查看钩子可以包含哪些属性以及如何使用它们的详细描述。 ```cpp [ { "id": "deploy", "execute-command": "./deploy.sh", "command-working-directory": "/root/test/" } ] ``` 3、新建你要执行的shell脚本,可以直接执行看脚本是否可用`./deploy.sh` 或者 `sh deploy.sh` 这里为了测试,只有拉取,实际应该比这更复杂 delploy.sh(位于/root/test/deploy.sh) ```cpp ! /bin/bash cd /root/test/test git pull ``` 六、运行 运行webhook,默认端口9000,所以我们需要开放9000端口。 ```cpp /root/go/bin/webhook -hooks hooks.json -verbose ``` ![](https://img-blog.csdnimg.cn/20201028213213798.pngpic_center) 在浏览器中访问,控制台即可打印相应日志 这里的deploy与你上方hooks.json文件中的id一致 ```cpp http://ip:9000/hooks/deploy ``` ![](https://img-blog.csdnimg.cn/2020102821380022.pngpic_center) 七、配置github 如果上方能够测试成功,那么直接复制url到下方配置中,配置好后他会自动发起一次请求。 ![](https://img-blog.csdnimg.cn/20201028214046702.pngpic_center) 八、设置后台运行 使用nohup来使我们的webhook后台运行并且打印日志:log.txt 为存放日志的文件 ```cpp [root@master test] nohup /root/go/bin/webhook -hooks hooks.json -verbose >log.txt 2>&1& [1] 3064 ``` 九、愉快玩耍 然后你就可以在自己电脑上写代码,写好后,他自己就会部署,爽歪歪。 ![](https://img-blog.csdnimg.cn/20201028214518205.pngpic_center) > 参考: > 1、[linux下yum](https://blog.csdn.net/iamhuanggua/article/details/60140867) > 2、[git生成证书](http://www.iimt.me/article/34) >3、 [钩子自动部署](https://blog.csdn.net/enoch612/article/details/105763647) >4、[webhook](https://github.com/adnanh/webhook) >5、[linux后台运行的几种方式](https://www.cnblogs.com/zsql/p/10827587.html)

2020-10-28

**每天一个小知识**,不定期更新 ![](https://img-blog.csdnimg.cn/2020090613504011.jpg?pic_center) 一、问题 之前有人问我这样一个问题: 如果你运行下面的代码,你会得到什么? ```java Integer a = 200, b = 200; Integer c = 100, d = 100; System.out.println(a == b); System.out.println(c == d); ``` 你会得到 ```clike false true ``` 为什么 Java 中`200==200`为false,而`100==100`为true? > 答案只有一个:那就是200没有100帅气,就像正在看这篇文章的你一样没有写这篇文章的我一样帅气。 二、分析 **基本知识:我们知道,如果两个引用指向同一个对象,用`==`表示它们是相等的。如果两个引用指向不同的对象,用`==`表示它们是不相等的,即使它们的内容相同。** 因此,后面一条语句也应该是false 。 这就是它有趣的地方了。如果你看去看 Integer.java 类,你会发现有一个内部私有类,IntegerCache.java,它缓存了从-128到127之间的所有的整数对象。 所以事情就成了,所有的小整数在内部缓存,然后当我们声明类似—— ```clike Integer c = 100; ``` 的时候,它实际上在内部做的是: ```clike Integer i = Integer.valueOf(100); ``` 现在,如果我们去看valueOf()方法,我们可以看到 ```java /** * Returns an {@code Integer} instance representing the specified * {@code int} value. If a new {@code Integer} instance is not * required, this method should generally be used in preference to * the constructor {@link Integer(int)}, as this method is likely * to yield significantly better space and time performance by * caching frequently requested values. * * This method will always cache values in the range -128 to 127, * inclusive, and may cache other values outside of this range. * * @param i an {@code int} value. * @return an {@code Integer} instance representing {@code i}. * @since 1.5 */ public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); } ``` 如果值的范围在-128到127之间,它就从高速缓存返回实例。 所以… ```java Integer c = 100, d = 100; ``` 指向了同一个对象。 这就是为什么我们写 ```java System.out.println(c == d); ``` 我们可以得到true。 现在你可能会问,为什么这里需要缓存? **合乎逻辑的理由是,在此范围内的“小”整数使用率比大整数要高,因此,使用相同的底层对象是有价值的,可以减少潜在的内存占用。** 然而,通过反射API你会误用此功能。 运行下面的代码,享受它的魅力吧 ```java public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException { Class cache = Integer.class.getDeclaredClasses()[0]; //1 Field myCache = cache.getDeclaredField("cache"); //2 myCache.setAccessible(true);//3 Integer[] newCache = (Integer[]) myCache.get(cache); //4 newCache[132] = newCache[133]; //5 int a = 2; int b = a + a; System.out.printf("%d + %d = %d", a, a, b); // } ``` 三、结论 **Integer 缓存是 Java 5 中引入的一个有助于节省内存、提高性能的特性。** **Integer中有个静态内部类IntegerCache,里面有个cache[],也就是Integer常量池,常量池的大小为一个字节(-128~127)。** **这种 Integer 缓存策略仅在自动装箱的时候有用,使用构造器创建的 Integer 对象不能被缓存。(例如in3和in4)** ```java int i = 10; int i1 = 10; Integer in1 = 10; Integer in2 = 10; Integer in3 = new Integer(10); Integer in4 = new Integer(10); Integer in5 = 200; Integer in6 = 200; System.out.println(i == i1); // true System.out.println(i == in1); // true System.out.println(i == in2); // true System.out.println(i == in3); // true System.out.println(in1 == in2); // true System.out.println(in5 == in6); // false System.out.println(in1 == in3); // false System.out.println(in3 == in4); // false ``` 除此之外: - 所有整数类型的类都有类似的缓存机制: 1、有 ByteCache 用于缓存 Byte 对象 2、有 ShortCache 用于缓存 Short 对象 3、有 LongCache 用于缓存 Long 对象 - Byte,Short,Long 的缓存池范围默认都是: -128 到 127。可以看出,Byte的所有值都在缓存区中,用它生成的相同值对象都是相等的。 - 所有整型(Byte,Short,Long)的比较规律与Integer是一样的。 - 同时Character 对象也有CharacterCache 缓存 池,范围是 0 到 127。 - 除了 Integer 可以通过参数改变范围外,其它的都不行。 > [1、为什么Java中1000`==`1000为false而100`==`100为true?原文](http://www.codeceo.com/article/why-java-1000-100.html) > [2、为什么Java中1000`==`1000为false而100`==`100为true?英文](https://dzone.com/articles/why-1000-1000-returns-false-but-100-100-returns-tr) > [3、Integer缓存池(IntegerCache)及整型缓存池](https://blog.csdn.net/maihilton/article/details/80101497) 关注公众号:**博奥思园** 还是那句话:**你的支持是我前进的最大动力** ![](https://img-blog.csdnimg.cn/20200405094243147.png)

概况 在处理后端的业务逻辑是常常会涉及表单数据的提交请求,我们不仅在前端对数据进行验证,而且在后端也需要对数据进行验证,以此来保证数据的完整性,而后端对于表单数据的验证使用的最多的莫过于JSR303。 你能get到的知识点? 1、表单验证的使用 2、由于表单验证引起的异常捕获 1、引入依赖 使用JSR303,我们需要引入依赖,一般来说我们只需要引入`javax.validation`即可,但是对于一些`javax.validation`无法验证的(例如URL)我们就需要引入`hibernate`来进行验证了。 ```xml <dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>2.0.1.Final</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>6.0.18.Final</version> <scope>compile</scope> </dependency> ``` 2、自定义验证规则 自定义验证规则,最方便的莫过于使用注解的方式对我们的bean进行验证,并且可以返回我们自己定义的返回消息。 JSR注释: - @NotNull –验证带注释的属性值不为 null - @AssertTrue –验证带注释的属性值为 true - @Size –验证带注释的属性值的大小介于属性 min和 max之间;可以应用于 String, Collection, Map和数组属性 - @Min – v验证带注释的属性的值不小于 value属性 - @Max –验证带注释的属性的值不大于 value属性 - @Email –验证带注释的属性是有效的电子邮件地址 一些注释接受其他属性,但是message属性是所有这些属性共有的。这是通常在相应属性的值未通过验证时呈现的消息。 在JSR中可以找到一些其他注释: - @NotEmpty –验证属性不为null或为空;可以应用于 String, Collection, Map或 Array值 - @NotBlank –只能应用于文本值,并验证该属性不是null还是空格 - @Positive和 @PositiveOrZero –适用于数值并验证其严格为正,或包含0的正数 - @Negative和 @NegativeOrZero –适用于数字值并验证其严格为负数,或包含0的负数 - @Past和 @PastOrPresent –验证日期值是过去还是现在(包括现在);可以应用于日期类型,包括Java 8中添加的日期类型 - @Future和@FutureOrPresent –验证日期值是将来的日期还是将来的日期(包括现在) ```java @Data @TableName("pms_brand") public class BrandEntity implements Serializable { private static final long serialVersionUID = 1L; /** * 品牌id */ @TableId private Long brandId; /** * 品牌名 */ @NotEmpty(message = "品牌名不能为空") private String name; /** * 品牌logo地址 */ @URL(message = "必须是一个合法的地址") private String logo; /** * 介绍 */ @NotEmpty(message = "介绍不能为空") private String descript; /** * 显示状态[0-不显示;1-显示] */ private Integer showStatus; /** * 检索首字母 */ @NotEmpty(message = "检索首字母不能为空") @Pattern(regexp = "/^[a-zA-Z]$/",message = "检索必须是一个字母") private String firstLetter; /** * 排序 */ @NotNull(message = "排序不能为空") @Min(value = 0,message = "排序的数必须大于等于零") private Integer sort; } ``` 3、校验捕获异常错误 第一种:controller捕获 在对bean进行验证后,我们需要捕获我们的验证结果。 1. @Valid:首先使用`@Valid` 为验证级联标记属性、方法参数或方法返回类型。也就是说我们使用这个注解后验证才生效。 2. BindingResult:在验证的bean后紧跟BindingResult,用于获取我们的验证结果,使用`result.hasErrors()`判断是否有异常,使用 `result.getFieldErrors()`获取验证后的详细数据 3. R:我们常常使用JSon数据来进行前后端的数据发送与接收,这里同理,该R为自定的类,如果你不想写自定义的消息类,你可以直接用JSONObject进行数据的保存。 ```java /** * 保存 */ @RequestMapping("/save") public R save(@Valid @RequestBody BrandEntity brand, BindingResult result){ Map<String,String> map = new LinkedHashMap<>(); if (result.hasErrors()){ result.getFieldErrors().forEach(item ->{ String message = item.getDefaultMessage(); String field = item.getField(); map.put(field, message); }); return R.error(400,"数据不合法").put("data",map); }else { brandService.save(brand); return R.ok(); } } ``` 第二种:统一异常捕获 所有的controller制作厂的逻辑处理,我们则需要使用一个统一的controller进行所有异常的捕获 ```csharp 1、正常的控制器处理正常的逻辑 /** * 保存 */ @RequestMapping("/save") public R save(@Valid @RequestBody BrandEntity brand){ brandService.save(brand); return R.ok(); } 2、编写一个controllerAdvice进行异常统一处理 @RestControllerAdvice("com.lomtom.mall.product.controller") public class ExceptionController { @ExceptionHandler(value = MethodArgumentNotValidException.class) public R handleValidException(MethodArgumentNotValidException e){ BindingResult result = e.getBindingResult(); Map<String,String> map = new LinkedHashMap<>(); result.getFieldErrors().forEach(item -> { String message = item.getDefaultMessage(); String field = item.getField(); map.put(field, message); }); return R.error(400, "数据不合法").put("data", map); } } ``` 第三种:统一处理配合枚举 与第二种同理,只是新增枚举统一管理异常的状态码与消息提醒,翻遍代码的修改与查看 ```csharp 1、编写枚举 public enum ExceptionEnum { DATA_EXCEPTION(400,"数据不合法"); private Integer code; private String message; ExceptionEnum(Integer code, String message) { this.code = code; this.message = message; } public Integer getCode() { return code; } public void setCode(Integer code) { this.code = code; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } } 2、与第二种唯一不同的是所有的状态码与消息提示交给枚举 return R.error(ExceptionEnum.DATA_EXCEPTION.getCode(), ExceptionEnum.DATA_EXCEPTION.getMessage()).put("data", map); ``` 4、测试 发送请求获取返回,所有的返回结果都一样,只是实现的方式稍有不同而已。 ```json { "msg": "数据不合法", "code": 400, "data": { "name": "品牌名不能为空", "descript": "介绍不能为空", "sort": "排序不能为空", "firstLetter": "检索首字母不能为空" } } ```

TODAY'S SHARE

ABOUT ME

I'M LOMTOM

我不想成为一个庸俗的人。十年百年后,当我们死去,质疑我们的人同样死去,后人看到的是裹足不前、原地打转的你,还是一直奔跑、走到远方的我?

CONTACT ME

You can contact me in the following ways

Copyright © 2019-2020 Made with love By LomTom | 湘ICP备19023870号 | 经历风雨 666 天 6 小时 6 分 6 秒