继开 | 博客

热爱生活,努力学习,实现自己的价值


  • 短诗的序

  • 迷途自渡

  • 寒星三两

  • 林深见鹿

  • 记昨日书

  • 顾探往昔

用Markdown来画流程图

发表于 2021-09-27
字数统计: 811 字 | 阅读时长 ≈ 4 min

使用 editor 画流程图

一直在用markdown(不得不说markdown语法真的太强大太简洁了,效果也太优美,没学过markdown语法的可以自己学下)写东西,知道用markdown可以画出来很性感的流程图,遂决定学下如何用markdown来画流程图。

代码

1
<div id="flowchart-0" class="flow-chart"></div>

效果

说明 这样几行简单的代码就生成了一个优雅的流程图。 流程图大致分为两段,第一段是定义元素,第二段是定义元素之间的走向。

定义元素的语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
tag=>type: content:>url
tag就是元素名字,
type是这个元素的类型,有6中类型,分别为:

start # 开始

end # 结束

operation # 操作

subroutine # 子程序

condition # 条件

inputoutput # 输入或产出

content就是在框框中要写的内容,注意type后的冒号与文本之间一定要有个空格。

url是一个连接,与框框中的文本相绑定

连接元素的语法
用->来连接两个元素,需要注意的是condition类型,因为他有yes和no两个分支,所以要写成

c2(yes)->io->e
c2(no)->op2->e

实际应用
这是一个爬取某网站的商品评论数据,然后进行情感分析的小项目,有四个模块:获取待爬取商品id,爬取代理,爬取评论,情感分析

代码

1
<div id="flowchart-2" class="flow-chart"></div>

效果

这个流程图有个问题,我希望ids_remain的两个条件都为空,但是markdown语法没法实现我这需求(不知道我这需求是不是有毛病),只能先这样画着了。

参考
https://www.zybuluo.com/mdeditor?
http://weibo.com/ghosert
http://meta.math.stackexchange.com/questions/5020/mathjax-basic-tutorial-and-quick-reference
http://editor.md.ipandao.com/examples/index.html

Java的list筛选重复的数据然后移除掉

发表于 2021-09-26
字数统计: 131 字 | 阅读时长 ≈ 1 min
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
* 筛选出重复数据然后然移除掉;
* @author wjk
* @Date 2021-09-16
*/

private List<AttendEmployeeMonth> getAttendEmployeeMonthRmHaveAttendEmployee(List<AttendEmployeeMonth> attendEmployeeMonthList) {
//根据列表查询这些员工是否已经做过考勤记录
List<AttendEmployeeMonth> attendEmployeeMonthListOld = attendEmployeeMonthService.getEmployeeListByAuditBtyArchiveList(attendEmployeeMonthList);
//若有,则剔除掉该员工,重新组成列表,

List<AttendEmployeeMonth> attendEmployeeMonthNew = new ArrayList<AttendEmployeeMonth>();

for(AttendEmployeeMonth attendEmployeeMonth :attendEmployeeMonthList){
for(AttendEmployeeMonth attendEmployeeMonthOld : attendEmployeeMonthListOld){
if (attendEmployeeMonth.getBtyArchicesId().equals(attendEmployeeMonthOld.getBtyArchicesId())){
attendEmployeeMonthNew.add(attendEmployeeMonth);
}
}
}
attendEmployeeMonthList.removeAll(attendEmployeeMonthNew);
//若没有,直接进行之后的操作
return attendEmployeeMonthList;
}

Sql统计值行转列

发表于 2021-09-25
字数统计: 51 字 | 阅读时长 ≈ 1 min
1
2
3
4
5
select date_year ,
sum(case when win_loss='胜' then 1 else 0 end ) '胜场数' ,
sum(case when win_loss='负' then 1 else 0 end) '负场数',
sum(case when win_loss='平' then 1 else 0 end) '平场数'
from scores group by date_year;

Java处理时间加减天数加减月

发表于 2021-09-24
字数统计: 450 字 | 阅读时长 ≈ 3 min
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/**** 
* 传入具体日期 ,返回具体日期增加一个月。
* @param date 日期(2017-04-13)
* @return 2017-05-13
* @throws ParseException
*/
private String calculateMonth(String date) throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date dt = sdf.parse(date);
Calendar rightNow = Calendar.getInstance();
rightNow.setTime(dt);
rightNow.add(Calendar.MONTH, 1);
Date dt1 = rightNow.getTime();
String reStr = sdf.format(dt1);
return reStr;
}


/****
* 传入具体日期 ,返回具体日期减少一天
* @param date 日期(2017-04-13)
* @return 2017-04-12
* @throws ParseException
*/
private String calculateDay(String date) throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date dt = sdf.parse(date);
Calendar rightNow = Calendar.getInstance();
rightNow.setTime(dt);
rightNow.add(Calendar.DATE, -1);
Date dt1 = rightNow.getTime();
String reStr = sdf.format(dt1);
return reStr;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/**
* 传入具体日期 ,返回具体日期增加或者减少天数,传出日期
* @author wjk
* @Date 2021-09-27
*/
private Date calculateDay(Date date,int day){
Calendar rightNow = Calendar.getInstance();
rightNow.setTime(date);
rightNow.add(Calendar.DATE, day);
Date date1 = rightNow.getTime();
return date1;
}


/**
* 传入具体日期 ,返回具体日期增加或者减少月数,传出日期
* @author wjk
* @Date 2021-09-27
*/
private Date calculateMonth(Date date,int month){
Calendar rightNow = Calendar.getInstance();
rightNow.setTime(date);
rightNow.add(Calendar.MONTH, month);
Date date1 = rightNow.getTime();
return date1;
}
1
2
3
4
5
6
7
8
9
10
/**
* 传入具体日期 ,返回当月的天数
* @author wjk
* @Date 2021-09-28
*/
public static int getDaysOfMonth(Date date) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
return calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* 获取当月最后几天
* @param days
* @return
*/
private static List<String> getLastDays(int days) {
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
Calendar calendar = Calendar.getInstance();
List<String> list=new ArrayList<String>();
for(int i=1;i<=days;i++){
calendar.add(Calendar.MONTH, 1);
calendar.set(Calendar.DATE, 1);
calendar.add(Calendar.DATE, -i);
Date theDate = calendar.getTime();
String s = df.format(theDate);
list.add(s);
}
return list;
}}

java.math.BigDecimal Cannot Be Cast to java.lang.String

发表于 2021-09-23
字数统计: 140 字 | 阅读时长 ≈ 1 min

从数据库取count、sum等函数的值需要转化成Integer的时候出现
java.math.BigDecimal cannot be cast to java.lang.String的报错

错误代码:

1
Integer.parseInt((String)map.get("id"))

解决方法:

1
2
Object object = map.get("id");
Integer.parseInt(String.valueOf(object ));

BigDecimal,判断正负

1
2
3
4
5
6
7
8
9
10
BigDecimal money = BigDecimal.ZERO.setScale(2, BigDecimal.ROUND_HALF_UP);

//signum():-1 负数,0 0 ,1 正数
if (money.signum() == -1) {
System.out.println("这是一个负数");
}else if(money.signum() == 0){
System.out.println("这是一个0");
}else {
System.out.println("这是一个正数");
}

初始化为0

1
BigDecimal zero = BigDecimal.ZERO;

Springboot集成minio做文件存储

发表于 2021-09-22
字数统计: 3,729 字 | 阅读时长 ≈ 21 min

准备

1.已经搭建好的minio环境

1
2
3
4
5
# minio 参数配置
minio.endpoint = http://192.168.0.18:8091
minio.accessKey: root
minio.secretKey: 1qaz2wsx
minio.bucketName: minitest

2.java 环境,springboot项目,maven项目

搭建

1.pom.xml文件引入minio 的包

1
2
3
4
5
6
<!-- 非结构化存储数据minio -->
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>8.0.3</version>
</dependency>

2.application.properties进行配置,

1
2
3
4
5
# minio 参数配置
minio.endpoint = http://192.168.0.18:8091
minio.accessKey: root
minio.secretKey: 1qaz2wsx
minio.bucketName: minitest

3.配置文件MinIoClientConfig.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package com.wangjikai.minitest.config;

import io.minio.MinioClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
* @ClassName MinIoClientConfig
* @Author wjk
* @Date 2021/09/20 10:48
* @Version 1.0
**/
@Configuration
public class MinIoClientConfig {


@Value("${minio.endpoint}")
private String endpoint;
@Value("${minio.accessKey}")
private String accessKey;
@Value("${minio.secretKey}")
private String secretKey;

/**
* 注入minio 客户端
* @return
*/
@Bean
public MinioClient minioClient(){

return MinioClient.builder()
.endpoint(endpoint)
.credentials(accessKey, secretKey)
.build();
}
}

4.操作文件:

MinIoService.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
package com.wangjikai.minitest.platform.minioClient;

import io.minio.*;
import io.minio.errors.*;
import io.minio.http.Method;
import io.minio.messages.Bucket;
import io.minio.messages.DeleteError;
import io.minio.messages.DeleteObject;
import io.minio.messages.Item;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.*;

/**
* @ClassName MinIoService
* @Deacription TODO
* @Author wjk
* @Date 2021-09-20
* @Version 1.0
**/
@Service
public class MinIoService {

@Resource
private MinioClient instance;

@Value("${minio.endpoint}")
private String endpoint;

@Value("${minio.bucketName}")
private String adataBucketName;

private static final String SEPARATOR_DOT = ".";

private static final String SEPARATOR_ACROSS = "-";

private static final String SEPARATOR_STR = "";

/**
* @Description 判断 bucket是否存在
*
* @author wjk
* @date 2021-09-20 16:33
* @param bucketName
* @return boolean
*/
public boolean bucketExists(String bucketName){
try {
return instance.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
} catch (Exception e) {
e.printStackTrace();
}
return false;
}

/**
* 创建 bucket
* @param bucketName
*/
public void makeBucket(String bucketName){
try {
boolean isExist = instance.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
if(!isExist) {
instance.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
}
} catch (Exception e) {
e.printStackTrace();
}
}

/**
* @Description 删除桶
*
* @author wjk
* @date 2021-09-20 16:46
* @param bucketName
* @return boolean
*/
public boolean removeBucket(String bucketName) throws InvalidKeyException, ErrorResponseException,
IllegalArgumentException, InsufficientDataException, InternalException,
InvalidResponseException, NoSuchAlgorithmException, XmlParserException, IOException, ServerException {
boolean flag = bucketExists(bucketName);
if (flag) {
Iterable<Result<Item>> myObjects = listObjects(bucketName);
for (Result<Item> result : myObjects) {
Item item = result.get();
// 有对象文件,则删除失败
if (item.size() > 0) {
return false;
}
}
// 删除存储桶,注意,只有存储桶为空时才能删除成功。
instance.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());
flag = bucketExists(bucketName);
if (!flag) {
return true;
}
}
return false;
}

/**
* @Description 获取文件存储服务的所有存储桶名称
*
* @author wjk
* @date 2021-09-20 16:35
* @param
* @return java.util.List<java.lang.String>
*/
public List<String> listBucketNames() throws IOException, InvalidResponseException, InvalidKeyException, NoSuchAlgorithmException, ServerException, ErrorResponseException, XmlParserException, InsufficientDataException, InternalException {
List<Bucket> bucketList = listBuckets();
List<String> bucketListName = new ArrayList<>();
for (Bucket bucket : bucketList) {
bucketListName.add(bucket.name());
}
return bucketListName;
}

/**
* @Description 列出所有存储桶
*
* @author wjk
* @date 2021-09-20 16:35
* @param
* @return java.util.List<io.minio.messages.Bucket>
*/
public List<Bucket> listBuckets() throws IOException, InvalidKeyException, InvalidResponseException, InsufficientDataException, NoSuchAlgorithmException, ServerException, InternalException, XmlParserException, ErrorResponseException {
return instance.listBuckets();
}

/**
* @Description 列出存储桶中的所有对象名称
*
* @author wjk
* @date 2021-09-20 16:39
* @param bucketName
* @return java.util.List<java.lang.String>
*/
public List<String> listObjectNames(String bucketName) throws InvalidKeyException, ErrorResponseException,
IllegalArgumentException, InsufficientDataException, InternalException,
InvalidResponseException, NoSuchAlgorithmException, XmlParserException, IOException, ServerException {
List<String> listObjectNames = new ArrayList<>();
boolean flag = bucketExists(bucketName);
if (flag) {
Iterable<Result<Item>> myObjects = listObjects(bucketName);
for (Result<Item> result : myObjects) {
Item item = result.get();
listObjectNames.add(item.objectName());
}
}
return listObjectNames;
}

/**
* @Description 列出存储桶中的所有对象
*
* @author wjk
* @date 2021-09-20 16:39
* @param bucketName
* @return java.lang.Iterable<io.minio.Result<io.minio.messages.Item>>
*/
public Iterable<Result<Item>> listObjects(String bucketName) throws InvalidKeyException, ErrorResponseException,
IllegalArgumentException {
boolean flag = bucketExists(bucketName);
if (flag) {
return instance.listObjects(ListObjectsArgs.builder().bucket(bucketName).build());
}
return null;
}



/**
* @Description 通过文件地址,保留原始文件名 文件上传
*
* @author wjk
* @date 2021-09-20 15:16
* @param bucketName
* @param objectName
* @param stream
* @return java.lang.String
*/
public MinIoUploadVo upload(String bucketName, String objectName, InputStream stream) throws Exception {
if(!this.bucketExists(bucketName)){
this.makeBucket(bucketName);
}
instance.putObject(
PutObjectArgs.builder().bucket(bucketName).object(objectName).stream(
stream, stream.available(), -1) // PutObjectOptions,上传配置(文件大小,内存中文件分片大小)
.build());
String url =instance.getPresignedObjectUrl(
GetPresignedObjectUrlArgs.builder()
.method(Method.GET)
.bucket(bucketName)
.object(objectName)
.expiry(60 * 60 * 24)
.build());
// 返回生成文件名、访问路径
return new MinIoUploadVo(bucketName,objectName,"",url);
}

/**
* @Description 文件上传 (自定义文件名称)
*
* @author wjk
* @date 2021-09-20 13:45
* @param multipartFile
* @return java.lang.String
*/
public MinIoUploadVo upload(String strDir, MultipartFile multipartFile) throws Exception {

// bucket 不存在,创建
if (!this.bucketExists(adataBucketName)) {
this.makeBucket(adataBucketName);
}
InputStream inputStream = multipartFile.getInputStream();
// 创建一个 headers
Map<String, String> headers = new HashMap<>();
// 添加请求头 文件的ContentType 动态配置 multipartFile.getContentType()
headers.put("Content-Type", "application/octet-stream");

String fileName=multipartFile.getOriginalFilename();

String minFileName = minFileName(fileName);
instance.putObject(
PutObjectArgs.builder().bucket(adataBucketName).object(minFileName).stream(
inputStream, inputStream.available(), -1) // PutObjectOptions,上传配置(文件大小,内存中文件分片大小)
.headers(headers)
.build());
/*String url =instance.getPresignedObjectUrl(
GetPresignedObjectUrlArgs.builder()
.method(Method.GET)
.bucket(bucketName)
.object(strDir.concat("/").concat(minFileName))
.build());*/
String url =endpoint.concat("/").concat("adata/").concat("/").concat(minFileName);
// 返回生成文件名、访问路径
return new MinIoUploadVo(adataBucketName,fileName,minFileName,url);
}

/**
* @Description 下载文件
*
* @author wjk
* @date 2021-09-20 15:18
* @param response
* @return java.lang.String
*/
public void download(HttpServletResponse response, String bucketName,String minFileName ) throws Exception {

//InputStream fileInputStream = instance.getObject(GetObjectArgs.builder().bucket("adata").object(bucketName.concat("/").concat(minFileName)).build());
InputStream fileInputStream = instance.getObject(
GetObjectArgs.builder().bucket(bucketName).object(minFileName).build());

response.setHeader("Content-Disposition", "attachment;filename=" + java.net.URLEncoder.encode("一些文件分享.txt", "UTF-8"));
response.setContentType("application/force-download");
response.setCharacterEncoding("UTF-8");
IOUtils.copy(fileInputStream,response.getOutputStream());
}

/**
* 删除一个文件
* @author wjk
* @date 2021-09-20 16:43
* @param bucketName
* @param objectName
* @return
*/
public boolean removeObject(String bucketName, String objectName) throws IOException, InvalidKeyException, InvalidResponseException, InsufficientDataException, NoSuchAlgorithmException, ServerException, InternalException, XmlParserException, ErrorResponseException {
boolean flag = bucketExists(bucketName);
if (flag) {
instance.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build());
return true;
}
return false;
}

/**
* @Description 删除指定桶的多个文件对象,返回删除错误的对象列表,全部删除成功,返回空列
* @author wjk
* @date 2021-09-20 16:43
* @param bucketName
* @param objects
* @return java.util.List<java.lang.String>
*/
public List<String> removeObject(String bucketName, List<DeleteObject> objects) throws IOException, InvalidKeyException, InvalidResponseException, InsufficientDataException, NoSuchAlgorithmException, ServerException, InternalException, XmlParserException, ErrorResponseException {
List<String> deleteErrorNames = new ArrayList<>();
boolean flag = bucketExists(bucketName);
if (flag) {
Iterable<Result<DeleteError>> results = instance.removeObjects(
RemoveObjectsArgs.builder().bucket(bucketName).objects(objects).build());
for (Result<DeleteError> result : results) {
DeleteError error = result.get();
deleteErrorNames.add(error.objectName());
}
}
return deleteErrorNames;
}



/**
* @Description 生成上传文件名
*
* @author wjk
* @date 2021-09-20 15:07
* @param originalFileName
* @return java.lang.String
*/
private String minFileName(String originalFileName) {
String suffix = originalFileName;
if(originalFileName.contains(SEPARATOR_DOT)){
suffix = originalFileName.substring(originalFileName.lastIndexOf(SEPARATOR_DOT));
}
return UUID.randomUUID().toString().replace(SEPARATOR_ACROSS,SEPARATOR_STR).toUpperCase()+suffix;
}
}

ObjectStorageController.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
package com.wangjikai.minitest.platform.minioClient;


import com.wangjikai.minitest.commonbase.BaseController;
import com.wangjikai.minitest.platform.goodsacceptancerecord.GoodsAcceptanceRecord;
import com.wangjikai.minitest.util.ReturnDataJson;
import io.minio.messages.DeleteObject;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
* @ClassName UploadController
* @Deacription 基于文件对象存储方案
* @Author wjk
* @Date 2021-09-20
* @Version 1.0
**/
@CrossOrigin
@RestController

@RequestMapping("/storage")
@Api("基于文件对象存储方案")
public class ObjectStorageController extends BaseController {


@Autowired
private MinIoService minIoService;

@Value("${minio.bucketName}")
private String bucketName;


@ApiOperation(value = "文件上传公共组件", notes = "基于所有类型文件上传公共组件")
@RequestMapping(value = "/upload" , method = RequestMethod.POST)
@ResponseBody
public FileResults upload(MultipartFile file) throws IOException {
String objectName=file.getOriginalFilename();
InputStream inputStream = file.getInputStream();
// String strDir= request.getParameter("bucketName")==null?"test":request.getParameter("bucketName");

try {
MinIoUploadVo uploadVo = minIoService.upload(null,file);
return new FileResults(true,200,"文件上传成功",uploadVo);
} catch (Exception e) {
//log.error("上传文件失败,msg={}",e.getMessage());
e.printStackTrace();
return new FileResults(false,500,"网络异常",null);
}
}

@ApiOperation(value = "文件下载公共组件", notes = "基于所有类型文件下载公共组件")
@RequestMapping(value = "/download", method = RequestMethod.GET)
public void download(MinIoUploadVo minIoUploadVo) {

try {
minIoService.download(response, minIoUploadVo.getBucketName(), minIoUploadVo.getMinFileName());
} catch (Exception e) {
//log.error("下载文件失败,msg={}",e.getMessage());
e.printStackTrace();
}
}

@ApiOperation(value = "文件服务器文件删除(支持多个)", notes = "文件服务器删除公共组件")
@RequestMapping(value = "/delete", method = RequestMethod.DELETE)
public FileResults delete(MinIoUploadVo minIoUploadVo) {

try {
List<DeleteObject> objectList= new ArrayList<>();

String fileDir = minIoUploadVo.getBucketName().concat("/");
Arrays.stream(minIoUploadVo.getMinFileName().split(",")).forEach(name -> objectList.add(new DeleteObject(fileDir.concat(name))));

minIoService.removeObject(bucketName, objectList);

return new FileResults(true,200,"删除文件成功",null);
} catch (Exception e) {
//log.error("删除文件失败,msg={}",e.getMessage());
e.printStackTrace();
return new FileResults(true,500,"网络异常",null);
}
}

/**
* 查询(获取全部Bucket)
*/
@RequestMapping(value = "/getAllBucket",method=RequestMethod.POST)
@ResponseBody
@ApiOperation(value = "查询(获取全部)")
public ReturnDataJson getallBucket() {
ReturnDataJson res;
try {
List<String> list = this.minIoService.listBucketNames();
res = this.responseReturnDataJson(true,"成功",list,Long.valueOf(list.size()));
} catch (Exception e) {
logger.error(e.getMessage(), e);
res = this.responseReturnDataJson(false,"失败");
}
return res;
}

/**
* 查询(获取全部文件)
*/
@RequestMapping(value = "/getallFile",method=RequestMethod.POST)
@ResponseBody
@ApiOperation(value = "查询(获取全部)")
public ReturnDataJson getallFile() {
ReturnDataJson res;
try {
List<String> list = this.minIoService.listObjectNames(bucketName);
res = this.responseReturnDataJson(true,"成功",list,Long.valueOf(list.size()));
} catch (Exception e) {
logger.error(e.getMessage(), e);
res = this.responseReturnDataJson(false,"失败");
}
return res;
}


}

5.相应的实体类:
FileResults.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package com.wangjikai.minitest.platform.minioClient;



/**
* @ClassName FileResults
* @Deacription TODO
* @Author wjk
* @Date 2021-09-20
* @Version 1.0
**/

public class FileResults {


private boolean success;//是否成功
private Integer code;// 返回码
private String message;//返回信息
private Object data;// 返回数据

public boolean isSuccess() {
return success;
}

public void setSuccess(boolean success) {
this.success = success;
}

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;
}

public Object getData() {
return data;
}

public void setData(Object data) {
this.data = data;
}

public FileResults(boolean success, Integer code, String message, Object data) {
this.success = success;
this.code = code;
this.message = message;
this.data = data;
}
}

MinIoUploadVo.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
package com.wangjikai.minitest.platform.minioClient;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;


import java.io.Serializable;

/**
* @ClassName MinIoUploadVo
* @Deacription
* @Author wjk
* @Date 2021-09-20
* @Version 1.0
**/

@ApiModel(value = "Minio 上传文件对象",description = "上传文件对象")
public class MinIoUploadVo implements Serializable {
private static final long serialVersionUID = 475040120689218785L;
@ApiModelProperty("对象桶名")
private String bucketName;

@ApiModelProperty("文件真实名称")
private String fileRealName;

@ApiModelProperty("文件名称")
private String minFileName;

@ApiModelProperty("文件路径")
private String minFileUrl;

public static long getSerialVersionUID() {
return serialVersionUID;
}

public String getBucketName() {
return bucketName;
}

public void setBucketName(String bucketName) {
this.bucketName = bucketName;
}

public String getFileRealName() {
return fileRealName;
}

public void setFileRealName(String fileRealName) {
this.fileRealName = fileRealName;
}

public String getMinFileName() {
return minFileName;
}

public void setMinFileName(String minFileName) {
this.minFileName = minFileName;
}

public String getMinFileUrl() {
return minFileUrl;
}

public void setMinFileUrl(String minFileUrl) {
this.minFileUrl = minFileUrl;
}

public MinIoUploadVo(String bucketName, String fileRealName, String minFileName, String minFileUrl) {
this.bucketName = bucketName;
this.fileRealName = fileRealName;
this.minFileName = minFileName;
this.minFileUrl = minFileUrl;
}
}

6.补充
BaseController

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
package com.wangjikai.minitest.commonbase;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.wangjikai.minitest.util.CommResultMsg;
import com.wangjikai.minitest.util.PagesBean4DataTables;
import com.wangjikai.minitest.util.PagingBean;
import com.wangjikai.minitest.util.ReturnDataJson;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.beans.PropertyEditorSupport;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.text.ParseException;
import java.util.Date;
import java.util.List;

import org.apache.commons.io.IOUtils;

public abstract class BaseController {
/**
* 日志
*/
protected Logger logger = LoggerFactory.getLogger(getClass());
protected HttpServletRequest request;
protected HttpServletResponse response;
protected HttpSession session;
public String httpBodyJson = null;

public PagesBean4DataTables getjqPages(PagingBean pagingBean, List<?> list) {
PagesBean4DataTables p = new PagesBean4DataTables();
String drawString = this.request.getParameter("draw");
Integer draw = Integer.valueOf(StringUtils.defaultString(drawString, "0"));
Integer total = pagingBean.getTotalItems();
p.setData(list);
p.setDraw(draw);
p.setRecordsTotal(total);
p.setRecordsFiltered(total);
return p;
}

@ModelAttribute
public void setReqAndRes(HttpServletRequest request, HttpServletResponse response) {
this.request = request;
this.response = response;
this.session = request.getSession();
try {
InputStream inputStream = request.getInputStream();
List<String> data = IOUtils.readLines(inputStream,"UTF-8");
StringBuffer buffer = new StringBuffer();
if (CollectionUtils.isNotEmpty(data)) {
for (String item : data) {
buffer.append(item);
}
httpBodyJson= buffer.toString();
}
} catch (IOException e) {
logger.error(e.getMessage(),e);
}
}

@InitBinder
public void initBinder(WebDataBinder binder) throws Exception{
String[] parsePatterns = new String[]{"yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm"};
// Date 格式化
binder.registerCustomEditor(Date.class, new PropertyEditorSupport() {
@Override
public void setAsText(String text) {
try {
setValue(DateUtils.parseDate(text,parsePatterns));
} catch (ParseException e) {
e.printStackTrace();
}
}
});
}

/**
* 返回json格式数据<br>
* contentType为application/json
*
* @param jsonString
*/
public void responseWriter(String jsonString) {
writeData(jsonString, "application/json");
}
/**
* 返回json格式数据<br>
* contentType为application/json
*
*/
public void responseWriter(Boolean result, String msg) {
writeData(getCommonJsonString(result,msg), "application/json");
}
/**
* 返回json格式数据<br>
* contentType为application/json
*
*/
public <T> void responseWriter(Boolean result, String msg, T t) {
writeData(getCommonJsonString(result,msg,t), "application/json");
}
/**
* 消息结果通用方法
*
* @param result 操作成功与否 标志位
* @param msg 额外描述系信息
* @return
*/
public String getCommonJsonString(Boolean result, String msg) {
CommResultMsg comm = new CommResultMsg();
comm.setResult(result);
comm.setDescription(msg);
return JSON.toJSONString(comm);
}

/**
* 消息结果通用方法
*
* @param result 操作成功与否 标志位
* @param msg 额外描述系信息
* @return
*/
public <T> String getCommonJsonString(Boolean result, String msg, T t) {
CommResultMsg<T> comm = new CommResultMsg<T>();
comm.setResult(result);
comm.setDescription(msg);
comm.setObj(t);
return JSON.toJSONString(comm);
}
/**
* 返回json格式数据<br>
* contentType为text/json
* @param jsonString
*/
public void writeTextJson(String jsonString) {
writeData(jsonString, "text/json");
}

/**
* 通过response返回字数据
* @param jsonString
* @param contentType
*/
public void writeData(String jsonString, String contentType) {
response.setContentType(contentType);
PrintWriter out = null;
try {
out = this.response.getWriter();
out.write(jsonString);
} catch (Exception e) {
logger.error(e.getMessage(), e);
} finally {
out.flush();
out.close();
}
}

/**
* 成功
* 返回值带总数
*
*/
public ReturnDataJson responseReturnDataJson(Boolean status, String message, Object result,Long total) {
String statusCode = status == true ? ReturnDataJson.SUCCESS_CODE:ReturnDataJson.ERROR_CODE ;
ReturnDataJson returnDataJson = new ReturnDataJson(statusCode, message, result,total);
return returnDataJson;
}
/**
*
* 成功
* 返回值
*
*/
public ReturnDataJson responseReturnDataJson(Boolean status, String message, Object result) {
String statusCode = status == true ? ReturnDataJson.SUCCESS_CODE:ReturnDataJson.ERROR_CODE ;
ReturnDataJson returnDataJson = new ReturnDataJson(statusCode, message, result);
return returnDataJson;
}
/**
* 失败
* 返回值带总数
*
*/
public ReturnDataJson responseReturnDataJson(Boolean status,String message) {
String statusCode = status == true ? ReturnDataJson.SUCCESS_CODE:ReturnDataJson.ERROR_CODE ;
ReturnDataJson returnDataJson = new ReturnDataJson(statusCode, message);
return returnDataJson;
}
}

Docker安装minio

发表于 2021-09-20
字数统计: 1,374 字 | 阅读时长 ≈ 5 min

简述

目前可用于文件存储的网络服务选择有很多,比如阿里云OSS、七牛云、腾讯云等等,但是收费都有点小贵。为了帮公司节约成本,之前一直是使用fastDFS作为文件服务器,准确的说是图片服务器。直到我发现了MinIO,我决定放弃FastDFS。关于MinIO的使用方法。可以去看MinIO官网瞄一眼吧,非常详细对比的角度fastDFS,转而使用MinIO作为图片存储服务器。

一:安装部署(运维)复杂度

之前公司在使用fastDFS的时候,只有少数的几个人能够掌握fasdtDFS的部署结构。所以只要出现有点问题,能够顶上的只有这么几个人。如果将一个fastDFS分布式服务部署完成,需要具备以下的知识

linux基础的目录操作
常用的分布式主从原理
C语言代码的编译
nginx安装部署
nginx插件的使用(防盗链)

如果仅仅是上面的这些基础知识,安排几个程序员学一学还好说。主要是fastdfs的部署结构之复杂,如果我长时间不回顾,自己都会忘了这复杂的架构是怎么回事。当我看到MinIO的安装过程之后,以及分布式的部署命令之后(分布式MinIO快速入门),放弃fastDFS的决心就已经做出了一大半。说白了:FastDFS的部署不过是零件的组装过程,需要你去理解fastDFS的架构设计,才能够正确的安装部署。MinIO在安装的过程是黑盒的,你不用去深入关注它的架构,也不需要你进行零件组装,基本上可以做到开箱即用。普通的技术人员就能够参与后期运维。

二:文档

我觉得从我知道fastDFS开始,也有十年了。竟然没有官方文档,所有的文档全是某某公司的自己总结的文档,或者是某某网友自己总结的文档。从这点上看fastDFS真的是一败涂地,当然阿里余庆大神在做这个项目的时候可能也没有考虑到后来会有这么多人用。即使用的人多了,在余庆大神眼里可能觉得这只是自己开发的一个小玩具,没有继续深入运营的必要。

三:开源项目运营组织

fastdfs是阿里余庆做的一个个人项目,在一些互联网创业公司中有应用,没有官网,不活跃,6个contributors。目前已经很少做更新。MinIO目前是由2014年在硅谷创立的公司MinIO.Inc运营的开源项目,社区论坛的活跃度目前也非常的不错。

四:UI界面

我们都知道fastDFS默认是不带UI界面的,看看MinIO的界面吧。这个界面不需要你单独的部署,和服务端一并安装。开箱即用,爱了爱了。

五:性能

MinIO号称是世界上速度最快的对象存储服务器。在标准硬件上,对象存储的读/写速度最高可以达到183 GB/s和171 GB/s。关于fastDFS我曾经单线程测试写了20万个文件,总共200G,大约用时10个小时。总体上是很难达到MinIO“号称的”以G为单位的每秒读写速度。

六:容器化支持

MinIO提供了与k8s、etcd、docker等容器化技术深度集成方案,可以说就是为了云环境而生的。这点是FastDFS不具备的。

七:丰富的SDK支持

fastDFS目前提供了 C 和 Java SDK ,以及 PHP 扩展 SDK。下图是MinIO提供的SDK支持,MinIO几乎提供了所有主流开发语言的SDK以及文档。同志们,重要的是文档。

不是说PHP不主流啊,不想引战。求生欲很强。  

八:AWS S3标准兼容

Amazon的S3 API是对象存储领域的事实标准。MinIO是S3兼容性的事实上的标准,是第一个采用API和第一个添加对S3 Select支持的标准之一。包括微软Azure在内的750多家公司使用MinIO的S3网关,这一数字超过了业内其他公司的总和。
什么意思?就是说你现在为了节约成本使用MinIO,等你的公司壮大了、有钱了。不想自己运维基础设施了,你就可以把对象存储放到云上,只要云厂商支持S3标准,你的应用程序是不需要重新开发的。

安装

直接docker-compose.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#docker network create --subnet=172.100.0.0/16 test-net
#mkdir -p /data/test-minio/{conf,data,logs}
#docker-compose -f test-minio.yml up -d
#docker-compose.yml 配置文件如下

version: "2"
services:
test-minio:
image: minio/minio:RELEASE.2021-06-17T00-10-46Z
ports:
- "8091:9000"
volumes:
- /data/test-minio/data:/data
- /data/test-minio/conf:/root/.minio
environment:
MINIO_ACCESS_KEY: root
MINIO_SECRET_KEY: 1qaz2wsx
command: server /data
restart: always
container_name: test-minio
networks:
test-net:
ipv4_address: 172.100.0.7
logging:
driver: "json-file"
options:
max-size: "50M" # 最大文件上传限制 # max-file: "10"

networks:
test-net:
external: true

相关链接

官网:https://min.io/

开源地址:https://github.com/minio/

文档:https://docs.min.io/cn/

中文文档:http://docs.minio.org.cn/docs/

.NET 客户端api地址:https://docs.min.io/cn/dotnet-client-api-reference.html

下载地址:https://min.io/download#/windows

minio-dotnet:https://github.com/minio/minio-dotnet

Linux查看java进程的端口lsof以及netstat查看进程和端口号相关命令

发表于 2021-09-18
字数统计: 469 字 | 阅读时长 ≈ 2 min

操作系统:Centos6.4 64位

在linux操作时,经常要查看运行的项目的进程和端口号,在这里总结了以下常用到的相关命令:

1.查看系统运行的java项目,并查看进程号

这个用到的命令为:

1
ps -ef|grep java
1
2
[root@localhost ~]# ps -ef|grep java
root 26517 26496 0 08:52 pts/0 00:00:00 grep --color=auto java

2.lsof命令:根据进程pid查端口:

1
lsof -i | grep pid
1
2
3
4
[root@localhost bty-bty]# lsof -i | grep 26541
java 26541 root 25u IPv6 192402 0t0 TCP localhost:38300->localhost:ms-sql-s (ESTABLISHED)
java 26541 root 27u IPv6 189113 0t0 TCP localhost:38304->localhost:ms-sql-s (ESTABLISHED)
java 26541 root 28u IPv6 192661 0t0 TCP localhost:38308->localhost:ms-sql-s (ESTABLISHED)

其中,java表示项目运行类型,26541表示进程号,root表示用户名

3.根据端口port查进程:

1
lsof -i:port
1
2
3
[root@localhost bty-bty]# lsof -i:82
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
java 26541 root 51u IPv6 192420 0t0 TCP *:xfer (LISTEN)

pid对应的为进程号,root为用户名,

4.根据用户查看进程和端口号:

1
lsof -i|grep user
1
2
3
4
5
6
[root@localhost bty-bty]#  lsof -i|grep root
dhclient 8966 root 6u IPv4 51387 0t0 UDP *:bootpc
sshd 9163 root 3u IPv4 53558 0t0 TCP *:ssh (LISTEN)
sshd 9163 root 4u IPv6 53560 0t0 TCP *:ssh (LISTEN)
master 9390 root 13u IPv4 51156 0t0 TCP localhost:smtp (LISTEN)
master 9390 root 14u IPv6 51157 0t0 TCP localhost:smtp (LISTEN)

其查询结果同lsof -i | grep pid,可参见第2个结果。

5. netstat命令根据进程pid查端口:

1
netstat -nap | grep pid
1
2
3
[root@localhost bty-bty]#  netstat -nap | grep 26541
tcp6 0 0 :::82 :::* LISTEN 26541/java
tcp6 0 0 192.168.244.128:48734 101.133.200.106:1433 ESTABLISHED 26541/java

6.根据端口port查进程

1
netstat -nap | grep port
1
2
3
4
5
[root@localhost bty-bty]#  netstat -nap | grep 82
tcp6 0 0 :::82 :::* LISTEN 26541/java
unix 2 [ ACC ] STREAM LISTENING 61076 13516/containerd-sh /run/containerd/s/98264f6aebf6620456f96edaa2389ae4c5a247e0e9085d298cc69bbc0b24a0dd
unix 3 [ ] STREAM CONNECTED 51182 9390/master
unix 3 [ ] STREAM CONNECTED 62809 13516/containerd-sh /run/containerd/s/98264f6aebf6620456f96edaa2389ae4c5a247e0e9085d298cc69bbc0b24a0dd
1…192021…38

继开

一辈子很短,努力的做好两件事就好:第一件事是热爱生活,好好的去爱身边的人;第二件事是努力学习,在工作中取得不一样的成绩,实现自己的价值,而不是仅仅为了赚钱。

303 日志
171 标签
RSS
gitee E-Mail
0%
鲁ICP备18007712号
© 2025 继开 | 站点字数统计: 262.2k
博客使用 Hexo 搭建
|
主题 — NexT.Mist v5.1.4
人访问 次查看