Spring Boot项目中使用最新版HDFS Java API操作Hadoop 3.x详解

(1)在Spring Boot/Spring Cloud项目中添加以下依赖:

 

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

<!-- Apache Hadoop -->

<dependency>

    <groupId>org.apache.hadoop</groupId>

    <artifactId>hadoop-common</artifactId>

    <version>3.1.0</version>

</dependency>

<dependency>

    <groupId>org.apache.hadoop</groupId>

    <artifactId>hadoop-hdfs</artifactId>

    <version>3.1.0</version>

</dependency>

<dependency>

    <groupId>org.apache.hadoop</groupId>

    <artifactId>hadoop-mapreduce-client-core</artifactId>

    <version>3.1.0</version>

</dependency>

 

(2)HDFS相关的基本操作:

HDFS即Hadoop分布式文件系统(Hadoop Distributed File System)

 

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

327

328

329

330

331

332

333

334

335

336

337

338

339

340

341

342

343

344

345

346

347

348

349

350

351

352

353

354

355

356

357

358

359

360

361

362

363

364

365

366

367

368

369

370

371

372

373

374

375

376

377

378

379

380

381

382

383

384

385

386

387

388

389

390

391

392

393

394

395

396

397

398

399

400

401

402

403

404

405

406

407

408

409

410

411

412

413

414

415

416

417

418

419

420

421

422

423

424

425

426

427

428

429

430

431

432

433

434

435

436

437

438

439

440

441

442

443

444

445

446

447

448

449

450

451

452

package cn.zifangsky.common;

 

import com.alibaba.fastjson.JSON;

import org.apache.commons.io.IOUtils;

import org.apache.hadoop.conf.Configuration;

import org.apache.hadoop.fs.BlockLocation;

import org.apache.hadoop.fs.FSDataInputStream;

import org.apache.hadoop.fs.FileStatus;

import org.apache.hadoop.fs.FileSystem;

import org.apache.hadoop.fs.Path;

import org.apache.hadoop.fs.PathFilter;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

 

import java.io.IOException;

import java.nio.charset.Charset;

import java.text.MessageFormat;

import java.util.ArrayList;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

 

/**

* HDFS相关的基本操作

*

* @author zifangsky

* @date 2018/7/20

* @since 1.0.0

*/

public class HdfsService {

 

    private Logger logger = LoggerFactory.getLogger(HdfsService.class);

    private Configuration conf = null;

 

    /**

     * 默认的HDFS路径,比如:hdfs://192.168.197.130:9000

     */

    private String defaultHdfsUri;

 

    public HdfsService(Configuration conf,String defaultHdfsUri) {

        this.conf = conf;

        this.defaultHdfsUri = defaultHdfsUri;

    }

 

    /**

     * 获取HDFS文件系统

     * @return org.apache.hadoop.fs.FileSystem

     */

    private FileSystem getFileSystem() throws IOException {

        return FileSystem.get(conf);

    }

 

    /**

     * 创建HDFS目录

     * @author zifangsky

     * @date 2018/7/20 15:08

     * @since 1.0.0

     * @param path HDFS的相对目录路径,比如:/testDir

     * @return boolean 是否创建成功

     */

    public boolean mkdir(String path){

        //如果目录已经存在,则直接返回

        if(checkExists(path)){

            return true;

        }else{

            FileSystem fileSystem = null;

 

            try {

                fileSystem = getFileSystem();

 

                //最终的HDFS文件目录

                String hdfsPath = generateHdfsPath(path);

                //创建目录

                return fileSystem.mkdirs(new Path(hdfsPath));

            } catch (IOException e) {

                logger.error(MessageFormat.format("创建HDFS目录失败,path:{0}",path),e);

                return false;

            }finally {

                close(fileSystem);

            }

        }

    }

 

    /**

     * 上传文件至HDFS

     * @author zifangsky

     * @date 2018/7/20 15:28

     * @since 1.0.0

     * @param srcFile 本地文件路径,比如:D:/test.txt

     * @param dstPath HDFS的相对目录路径,比如:/testDir

     */

    public void uploadFileToHdfs(String srcFile, String dstPath){

        this.uploadFileToHdfs(false, true, srcFile, dstPath);

    }

 

    /**

     * 上传文件至HDFS

     * @author zifangsky

     * @date 2018/7/20 15:28

     * @since 1.0.0

     * @param delSrc 是否删除本地文件

     * @param overwrite 是否覆盖HDFS上面的文件

     * @param srcFile 本地文件路径,比如:D:/test.txt

     * @param dstPath HDFS的相对目录路径,比如:/testDir

     */

    public void uploadFileToHdfs(boolean delSrc, boolean overwrite, String srcFile, String dstPath){

        //源文件路径

        Path localSrcPath = new Path(srcFile);

        //目标文件路径

        Path hdfsDstPath = new Path(generateHdfsPath(dstPath));

 

        FileSystem fileSystem = null;

        try {

            fileSystem = getFileSystem();

 

            fileSystem.copyFromLocalFile(delSrc,overwrite,localSrcPath,hdfsDstPath);

        } catch (IOException e) {

            logger.error(MessageFormat.format("上传文件至HDFS失败,srcFile:{0},dstPath:{1}",srcFile,dstPath),e);

        }finally {

            close(fileSystem);

        }

    }

 

    /**

     * 判断文件或者目录是否在HDFS上面存在

     * @author zifangsky

     * @date 2018/7/20 15:37

     * @since 1.0.0

     * @param path HDFS的相对目录路径,比如:/testDir、/testDir/a.txt

     * @return boolean

     */

    public boolean checkExists(String path){

        FileSystem fileSystem = null;

        try {

            fileSystem = getFileSystem();

 

            //最终的HDFS文件目录

            String hdfsPath = generateHdfsPath(path);

 

            //创建目录

            return fileSystem.exists(new Path(hdfsPath));

        } catch (IOException e) {

            logger.error(MessageFormat.format("'判断文件或者目录是否在HDFS上面存在'失败,path:{0}",path),e);

            return false;

        }finally {

            close(fileSystem);

        }

    }

 

    /**

     * 获取HDFS上面的某个路径下面的所有文件或目录(不包含子目录)信息

     * @author zifangsky

     * @date 2018/7/20 18:12

     * @since 1.0.0

     * @param path HDFS的相对目录路径,比如:/testDir

     * @return java.util.List<java.util.Map<java.lang.String,java.lang.Object>>

     */

    public List<Map<String,Object>> listFiles(String path, PathFilter pathFilter){

        //返回数据

        List<Map<String,Object>> result = new ArrayList<>();

 

        //如果目录已经存在,则继续操作

        if(checkExists(path)){

            FileSystem fileSystem = null;

 

            try {

                fileSystem = getFileSystem();

 

                //最终的HDFS文件目录

                String hdfsPath = generateHdfsPath(path);

 

                FileStatus[] statuses;

                //根据Path过滤器查询

                if(pathFilter != null){

                    statuses = fileSystem.listStatus(new Path(hdfsPath),pathFilter);

                }else{

                    statuses = fileSystem.listStatus(new Path(hdfsPath));

                }

 

                if(statuses != null){

                    for(FileStatus status : statuses){

                        //每个文件的属性

                        Map<String,Object> fileMap = new HashMap<>(2);

 

                        fileMap.put("path",status.getPath().toString());

                        fileMap.put("isDir",status.isDirectory());

 

                        result.add(fileMap);

                    }

                }

            } catch (IOException e) {

                logger.error(MessageFormat.format("获取HDFS上面的某个路径下面的所有文件失败,path:{0}",path),e);

            }finally {

                close(fileSystem);

            }

        }

 

        return result;

    }

 

 

    /**

     * 从HDFS下载文件至本地

     * @author zifangsky

     * @date 2018/7/23 14:01

     * @since 1.0.0

     * @param srcFile HDFS的相对目录路径,比如:/testDir/a.txt

     * @param dstFile 下载之后本地文件路径(如果本地文件目录不存在,则会自动创建),比如:D:/test.txt

     */

    public void downloadFileFromHdfs(String srcFile, String dstFile){

        //HDFS文件路径

        Path hdfsSrcPath = new Path(generateHdfsPath(srcFile));

        //下载之后本地文件路径

        Path localDstPath = new Path(dstFile);

 

        FileSystem fileSystem = null;

        try {

            fileSystem = getFileSystem();

 

            fileSystem.copyToLocalFile(hdfsSrcPath,localDstPath);

        } catch (IOException e) {

            logger.error(MessageFormat.format("从HDFS下载文件至本地失败,srcFile:{0},dstFile:{1}",srcFile,dstFile),e);

        }finally {

            close(fileSystem);

        }

    }

 

    /**

     * 打开HDFS上面的文件并返回 InputStream

     * @author zifangsky

     * @date 2018/7/23 17:08

     * @since 1.0.0

     * @param path HDFS的相对目录路径,比如:/testDir/c.txt

     * @return FSDataInputStream

     */

    public FSDataInputStream open(String path){

        //HDFS文件路径

        Path hdfsPath = new Path(generateHdfsPath(path));

 

        FileSystem fileSystem = null;

        try {

            fileSystem = getFileSystem();

 

            return fileSystem.open(hdfsPath);

        } catch (IOException e) {

            logger.error(MessageFormat.format("打开HDFS上面的文件失败,path:{0}",path),e);

        }

 

        return null;

    }

 

    /**

     * 打开HDFS上面的文件并返回byte数组,方便Web端下载文件

     * <p>new ResponseEntity<byte[]>(byte数组, headers, HttpStatus.CREATED);</p>

     * <p>或者:new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(templateFile), headers, HttpStatus.CREATED);</p>

     * @author zifangsky

     * @date 2018/7/23 17:08

     * @since 1.0.0

     * @param path HDFS的相对目录路径,比如:/testDir/b.txt

     * @return FSDataInputStream

     */

    public byte[] openWithBytes(String path){

        //HDFS文件路径

        Path hdfsPath = new Path(generateHdfsPath(path));

 

        FileSystem fileSystem = null;

        FSDataInputStream inputStream = null;

        try {

            fileSystem = getFileSystem();

            inputStream = fileSystem.open(hdfsPath);

 

            return IOUtils.toByteArray(inputStream);

        } catch (IOException e) {

            logger.error(MessageFormat.format("打开HDFS上面的文件失败,path:{0}",path),e);

        }finally {

            if(inputStream != null){

                try {

                    inputStream.close();

                } catch (IOException e) {

                    // ignore

                }

            }

        }

 

        return null;

    }

 

    /**

     * 打开HDFS上面的文件并返回String字符串

     * @author zifangsky

     * @date 2018/7/23 17:08

     * @since 1.0.0

     * @param path HDFS的相对目录路径,比如:/testDir/b.txt

     * @return FSDataInputStream

     */

    public String openWithString(String path){

        //HDFS文件路径

        Path hdfsPath = new Path(generateHdfsPath(path));

 

        FileSystem fileSystem = null;

        FSDataInputStream inputStream = null;

        try {

            fileSystem = getFileSystem();

            inputStream = fileSystem.open(hdfsPath);

 

            return IOUtils.toString(inputStream, Charset.forName("UTF-8"));

        } catch (IOException e) {

            logger.error(MessageFormat.format("打开HDFS上面的文件失败,path:{0}",path),e);

        }finally {

            if(inputStream != null){

                try {

                    inputStream.close();

                } catch (IOException e) {

                    // ignore

                }

            }

        }

 

        return null;

    }

 

    /**

     * 打开HDFS上面的文件并转换为Java对象(需要HDFS上门的文件内容为JSON字符串)

     * @author zifangsky

     * @date 2018/7/23 17:08

     * @since 1.0.0

     * @param path HDFS的相对目录路径,比如:/testDir/c.txt

     * @return FSDataInputStream

     */

    public <T extends Object> T openWithObject(String path, Class<T> clazz){

        //1、获得文件的json字符串

        String jsonStr = this.openWithString(path);

 

        //2、使用com.alibaba.fastjson.JSON将json字符串转化为Java对象并返回

        return JSON.parseObject(jsonStr, clazz);

    }

 

    /**

     * 重命名

     * @author zifangsky

     * @date 2018/7/23 15:11

     * @since 1.0.0

     * @param srcFile 重命名之前的HDFS的相对目录路径,比如:/testDir/b.txt

     * @param dstFile 重命名之后的HDFS的相对目录路径,比如:/testDir/b_new.txt

     */

    public boolean rename(String srcFile, String dstFile) {

        //HDFS文件路径

        Path srcFilePath = new Path(generateHdfsPath(srcFile));

        //下载之后本地文件路径

        Path dstFilePath = new Path(dstFile);

 

        FileSystem fileSystem = null;

        try {

            fileSystem = getFileSystem();

 

            return fileSystem.rename(srcFilePath,dstFilePath);

        } catch (IOException e) {

            logger.error(MessageFormat.format("重命名失败,srcFile:{0},dstFile:{1}",srcFile,dstFile),e);

        }finally {

            close(fileSystem);

        }

 

        return false;

    }

 

    /**

     * 删除HDFS文件或目录

     * @author zifangsky

     * @date 2018/7/23 15:28

     * @since 1.0.0

     * @param path HDFS的相对目录路径,比如:/testDir/c.txt

     * @return boolean

     */

    public boolean delete(String path) {

        //HDFS文件路径

        Path hdfsPath = new Path(generateHdfsPath(path));

 

        FileSystem fileSystem = null;

        try {

            fileSystem = getFileSystem();

 

            return fileSystem.delete(hdfsPath,true);

        } catch (IOException e) {

            logger.error(MessageFormat.format("删除HDFS文件或目录失败,path:{0}",path),e);

        }finally {

            close(fileSystem);

        }

 

        return false;

    }

 

    /**

     * 获取某个文件在HDFS集群的位置

     * @author zifangsky

     * @date 2018/7/23 15:41

     * @since 1.0.0

     * @param path HDFS的相对目录路径,比如:/testDir/a.txt

     * @return org.apache.hadoop.fs.BlockLocation[]

     */

    public BlockLocation[] getFileBlockLocations(String path) {

        //HDFS文件路径

        Path hdfsPath = new Path(generateHdfsPath(path));

 

        FileSystem fileSystem = null;

        try {

            fileSystem = getFileSystem();

            FileStatus fileStatus = fileSystem.getFileStatus(hdfsPath);

 

            return fileSystem.getFileBlockLocations(fileStatus, 0, fileStatus.getLen());

        } catch (IOException e) {

            logger.error(MessageFormat.format("获取某个文件在HDFS集群的位置失败,path:{0}",path),e);

        }finally {

            close(fileSystem);

        }

 

        return null;

    }

 

 

    /**

     * 将相对路径转化为HDFS文件路径

     * @author zifangsky

     * @date 2018/7/20 15:18

     * @since 1.0.0

     * @param dstPath 相对路径,比如:/data

     * @return java.lang.String

     */

    private String generateHdfsPath(String dstPath){

        String hdfsPath = defaultHdfsUri;

        if(dstPath.startsWith("/")){

            hdfsPath += dstPath;

        }else{

            hdfsPath = hdfsPath + "/" + dstPath;

        }

 

        return hdfsPath;

    }

 

    /**

     * close方法

     */

    private void close(FileSystem fileSystem){

        if(fileSystem != null){

            try {

                fileSystem.close();

            } catch (IOException e) {

                logger.error(e.getMessage());

            }

        }

    }

 

}

 

(3)添加HDFS配置信息:

 

 

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

package cn.zifangsky.config;

 

import cn.zifangsky.common.HdfsService;

import org.apache.hadoop.hbase.HBaseConfiguration;

import org.springframework.beans.factory.annotation.Value;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

 

/**

* HDFS相关配置

*

* @author zifangsky

* @date 2018/7/20

* @since 1.0.0

*/

@Configuration

public class HdfsConfig {

 

    @Value("${hdfs.defaultFS}")

    private String defaultHdfsUri;

 

    @Bean

    public HdfsService getHbaseService(){

 

        org.apache.hadoop.conf.Configuration conf = HBaseConfiguration.create();

 

        conf.set("fs.defaultFS",defaultHdfsUri);

 

        return new HdfsService(conf,defaultHdfsUri);

    }

 

}

注意:如果不是在Hadoop安装的服务器上运行上述测试代码,可能会出现报错情况,建议参考我之前写的这篇文章自行解决:https://www.zifangsky.cn/1292.html

用到的具体属性如下:

 

1

hdfs.defaultFS=hdfs://192.168.197.130:9000

 

(4)测试上面的基本方法:

i)测试创建HDFS目录:

 

 

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

package cn.zifangsky.hbase;

 

import cn.zifangsky.common.HdfsService;

import org.junit.Test;

import org.junit.runner.RunWith;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.boot.test.context.SpringBootTest;

import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import org.springframework.test.context.web.WebAppConfiguration;

 

/**

* 测试HDFS的基本操作

*

* @author zifangsky

* @date 2018/7/20

* @since 1.0.0

*/

@RunWith(SpringJUnit4ClassRunner.class)

@SpringBootTest

@WebAppConfiguration

public class TestHdfs {

 

    @Autowired

    private HdfsService hdfsService;

 

 

    /**

     * 测试创建HDFS目录

     */

    @Test

    public void testMkdir(){

        boolean result1 = hdfsService.mkdir("/testDir");

        System.out.println("创建结果:" + result1);

 

        boolean result2 = hdfsService.mkdir("/testDir/subDir");

        System.out.println("创建结果:" + result2);

    }

 

}

 

运行单元测试后,输出如下:

 

1

2

创建结果:true

创建结果:true

 

ii)测试上传文件以及列出目录下面的文件:

 

 

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

    /**

     * 测试上传文件

     */

    @Test

    public void testUploadFile(){

        //测试上传三个文件

        hdfsService.uploadFileToHdfs("C:/Users/zifangsky/Desktop/a.txt","/testDir");

        hdfsService.uploadFileToHdfs("C:/Users/zifangsky/Desktop/b.txt","/testDir");

 

        hdfsService.uploadFileToHdfs("C:/Users/zifangsky/Desktop/c.txt","/testDir/subDir");

    }

 

    /**

     * 测试列出某个目录下面的文件

     */

    @Test

    public void testListFiles(){

        List<Map<String,Object>> result = hdfsService.listFiles("/testDir",null);

 

        result.forEach(fileMap -> {

            fileMap.forEach((key,value) -> {

                System.out.println(key + "--" + value);

            });

            System.out.println();

        });

    }

运行单元测试后,输出如下:

 

1

2

3

4

5

6

7

8

path--hdfs://192.168.197.130:9000/testDir/a.txt

isDir--false

 

path--hdfs://192.168.197.130:9000/testDir/b.txt

isDir--false

 

path--hdfs://192.168.197.130:9000/testDir/subDir

isDir--true

 

iii)测试下载文件:

 

 

1

2

3

4

5

6

7

    /**

     * 测试下载文件

     */

    @Test

    public void testDownloadFile(){

        hdfsService.downloadFileFromHdfs("/testDir/a.txt","C:/Users/zifangsky/Desktop/test.txt");

    }

运行单元测试后,可以发现文件已经下载到桌面了。

iv)测试打开HDFS上面的文件:

 

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

    /**

     * 测试打开HDFS上面的文件

     */

    @Test

    public void testOpen() throws IOException {

        FSDataInputStream inputStream = hdfsService.open("/testDir/a.txt");

 

        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));

        String line = null;

        while((line = reader.readLine())!=null){

            System.out.println(line);

        }

 

        reader.close();

    }

运行单元测试后,输出如下:

 

1

aaaaa

 

v)测试打开HDFS上面的文件,并转化为Java对象:

 

 

1

2

3

4

5

6

7

8

    /**

     * 测试打开HDFS上面的文件,并转化为Java对象

     */

    @Test

    public void testOpenWithObject() throws IOException {

        User user = hdfsService.openWithObject("/testDir/b.txt", User.class);

        System.out.println(user);

    }

上传之前的 b.txt 的内容是:

 

1

{"password":"$5$toOBSeX2$hSnSDyhJmVVRpbmKuIY4SxDgyeGRGacQaBYGrtEBnZA","createTime":1514736000000,"mobile":"110","updateTime":1514736000000,"id":2,"email":"admin@zifangsky.cn","status":1,"username":"zifangsky"}

运行单元测试后,输出如下:

 

1

User{id=2, username='zifangsky', password='$5$toOBSeX2$hSnSDyhJmVVRpbmKuIY4SxDgyeGRGacQaBYGrtEBnZA', mobile='110', email='admin@zifangsky.cn', createTime=Mon Jan 01 00:00:00 CST 2018, updateTime=Mon Jan 01 00:00:00 CST 2018, status=1}

 

vi)测试重命名:

 

 

1

2

3

4

5

6

7

8

9

10

    /**

     * 测试重命名

     */

    @Test

    public void testRename(){

        hdfsService.rename("/testDir/b.txt","/testDir/b_new.txt");

 

        //再次遍历

        testListFiles();

    }

运行单元测试后,输出如下:

 

1

2

3

4

5

6

7

8

path--hdfs://192.168.197.130:9000/testDir/a.txt

isDir--false

 

path--hdfs://192.168.197.130:9000/testDir/b_new.txt

isDir--false

 

path--hdfs://192.168.197.130:9000/testDir/subDir

isDir--true

可以发现,文件 b.txt 已经被重命名了。

vii)测试删除文件:

 

 

1

2

3

4

5

6

7

8

9

10

    /**

     * 测试删除文件

     */

    @Test

    public void testDelete(){

        hdfsService.delete("/testDir/b_new.txt");

 

        //再次遍历

        testListFiles();

    }

运行单元测试后,输出如下:

 

1

2

3

4

5

path--hdfs://192.168.197.130:9000/testDir/a.txt

isDir--false

 

path--hdfs://192.168.197.130:9000/testDir/subDir

isDir--true

可以发现,文件 b_new.txt 已经被删除了。

viii)测试获取某个文件在HDFS集群的位置:

 

 

1

2

3

4

5

6

7

8

9

10

11

12

13

    /**

     * 测试获取某个文件在HDFS集群的位置

     */

    @Test

    public void testGetFileBlockLocations() throws IOException {

        BlockLocation[] locations = hdfsService.getFileBlockLocations("/testDir/a.txt");

 

        if(locations != null && locations.length > 0){

            for(BlockLocation location : locations){

                System.out.println(location.getHosts()[0]);

            }

        }

    }

运行单元测试后,输出如下:

 

1

node01

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值