Java SpringBoot實(shí)現(xiàn)帶界面的代碼生成器詳解
更新時(shí)間:2021年09月22日 10:12:50 作者:一只y
這篇文章主要介紹了Java SpringBoot如何實(shí)現(xiàn)帶界面的代碼生成器,幫助大家更好的理解和使用Java SpringBoot編程語言,感興趣的朋友可以了解下
1.項(xiàng)目gitthub地址鏈接: https://github.com/baisul/generateCode.git切換到master分支
2.環(huán)境
2.1 springboot+freemarker+mysql
2.2 要裝node.js,vue文件運(yùn)行依賴node.js
3.以下就只拿生成java實(shí)體類來作為例子
4.application.xml
server.port=8080 spring.datasource.url=jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai spring.datasource.username=root spring.datasource.password=root
5.pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.yl</groupId>
<artifactId>generate_code</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>generate_code</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>30.1-jre</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
6.Utils
package com.yl.generate_code.utils;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
public class CORFSConfiguration extends WebMvcConfigurerAdapter {
@Override
public void addCorsMappings(CorsRegistry registry) {
//所有請求都允許跨域
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("*")
.allowedHeaders("*");
}
}
package com.yl.generate_code.utils;
import com.yl.generate_code.model.Db;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class DBUtils {
private static Connection connection;
public static Connection getConnection() {
return connection;
}
public static Connection init(Db db) {
if (connection == null) {
try {
Class.forName("com.mysql.cj.jdbc.Driver");
connection = DriverManager.getConnection( db.getUrl(),db.getUsername(), db.getPassword());
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
}
return connection;
}
}
7.生成模板
package ${packetName}.model;
import java.util.Date;
/**
* @Description: ${modelName}實(shí)體類
* @Author: wfj
* @CreateDate ${createDate}
* @Version: 1.0V
*/
public class ${modelName} {
<#if columns??>
<#list columns as column>
<#if column.type='VARCHAR' || column.type='TEXT' || column.type='CHAR'>
/**
* ${column.remark}
*/
private String ${column.propertyName?uncap_first};
</#if>
<#if column.type='INT'>
/**
* ${column.remark}
*/
private Integer ${column.propertyName?uncap_first};
</#if>
<#if column.type='DATETIME'>
/**
* ${column.remark}
*/
private Date ${column.propertyName?uncap_first};
</#if>
<#if column.type='BIGINT'>
/**
* ${column.remark}
*/
private Long ${column.propertyName?uncap_first};
</#if>
<#if column.type='DOUBLE'>
/**
* ${column.remark}
*/
private Double ${column.propertyName?uncap_first};
</#if>
<#if column.type='BIT'>
/**
* ${column.remark}
*/
private Boolean ${column.propertyName?uncap_first};
</#if>
</#list>
<#list columns as column>
<#if column.type='VARCHAR' || column.type='TEXT' || column.type='CHAR'>
public String get${column.propertyName}() {
return ${column.propertyName?uncap_first};
}
public void set${column.propertyName}(String ${column.propertyName?uncap_first}) {
this.${column.propertyName?uncap_first} = ${column.propertyName?uncap_first};
}
</#if>
<#if column.type='INT'>
public Integer get${column.propertyName}() {
return ${column.propertyName?uncap_first};
}
public void set${column.propertyName}(Integer ${column.propertyName?uncap_first}) {
this.${column.propertyName?uncap_first} = ${column.propertyName?uncap_first};
}
</#if>
<#if column.type='DATETIME'>
public Date get${column.propertyName}() {
return ${column.propertyName?uncap_first};
}
public void set${column.propertyName}(Date ${column.propertyName?uncap_first}) {
this.${column.propertyName?uncap_first} = ${column.propertyName?uncap_first};
}
</#if>
<#if column.type='BIGINT'>
public Long get${column.propertyName}() {
return ${column.propertyName?uncap_first};
}
public void set${column.propertyName}(Long ${column.propertyName?uncap_first}) {
this.${column.propertyName?uncap_first} = ${column.propertyName?uncap_first};
}
</#if>
<#if column.type='DOUBLE'>
public Double get${column.propertyName}() {
return ${column.propertyName?uncap_first};
}
public void set${column.propertyName}(Double ${column.propertyName?uncap_first}) {
this.${column.propertyName?uncap_first} = ${column.propertyName?uncap_first};
}
</#if>
<#if column.type='BIT'>
public Boolean get${column.propertyName}() {
return ${column.propertyName?uncap_first};
}
public void set${column.propertyName}(Boolean ${column.propertyName?uncap_first}) {
this.${column.propertyName?uncap_first} = ${column.propertyName?uncap_first};
}
</#if>
</#list>
</#if>
}
8.Controller
package com.yl.generate_code.controller;
import com.google.common.base.CaseFormat;
import com.yl.generate_code.model.Db;
import com.yl.generate_code.model.ResultModel;
import com.yl.generate_code.model.TableClass;
import com.yl.generate_code.utils.DBUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@RestController
public class DBController {
@PostMapping("/connect")
public ResultModel connect(@RequestBody Db db) {
Connection connection = DBUtils.init(db);
if (connection == null) {
return ResultModel.fail("數(shù)據(jù)庫連接失敗");
} else {
return ResultModel.success("數(shù)據(jù)庫連接成功");
}
}
@PostMapping("/config")
public ResultModel config(@RequestBody Map<String,Object> map) {
String packetName = (String)map.get("packetName");
try {
//獲取數(shù)據(jù)庫連接
Connection connection = DBUtils.getConnection();
//獲取數(shù)據(jù)庫元數(shù)據(jù)
DatabaseMetaData metaData = connection.getMetaData();
//獲取數(shù)據(jù)庫所有的表
ResultSet rs = metaData.getTables(connection.getCatalog(), null, null, null);
List<TableClass> list = new ArrayList<>();
while (rs.next()) {
TableClass tableClass = new TableClass();
tableClass.setPacketName(packetName);
//獲取表名
String tableName = rs.getString("TABLE_NAME");
//數(shù)據(jù)庫表下劃線的字段轉(zhuǎn)成駝峰,且首字母大寫
String modelName = CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, tableName);
tableClass.setTableName(tableName);
tableClass.setModelName(modelName);
tableClass.setServiceName(modelName + "Service");
tableClass.setMapperName(modelName + "Mapper");
tableClass.setControllerName(modelName + "Controller");
list.add(tableClass);
}
return ResultModel.success("數(shù)據(jù)庫信息讀取成功",list);
} catch (SQLException e) {
e.printStackTrace();
return ResultModel.fail("數(shù)據(jù)庫信息讀取失敗");
}
}
}
package com.yl.generate_code.controller;
import com.yl.generate_code.model.ResultModel;
import com.yl.generate_code.model.TableClass;
import com.yl.generate_code.service.GenerateCodeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
@RestController
public class GenerateCodeController {
@Autowired
private GenerateCodeService generateCodeService;
@PostMapping("/generateCode")
public ResultModel generateCode(@RequestBody List<TableClass> list, HttpServletRequest request) {
return generateCodeService.generateCode(list,request.getServletContext().getRealPath("/"));
}
}
9.Model
package com.yl.generate_code.model;
import java.io.Serializable;
public class ColumnClass implements Serializable {
//實(shí)體類屬性名
private String propertyName;
//實(shí)體類屬性名對應(yīng)的表的字段名
private String columnName;
//字段類型
private String type;
//備注
private String remark;
//該字段是否為主鍵
private Boolean isPrimary;
public String getPropertyName() {
return propertyName;
}
public void setPropertyName(String propertyName) {
this.propertyName = propertyName;
}
public String getColumnName() {
return columnName;
}
public void setColumnName(String columnName) {
this.columnName = columnName;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getRemark() {
return remark;
}
public void setRemark(String remark) {
this.remark = remark;
}
public Boolean getPrimary() {
return isPrimary;
}
public void setPrimary(Boolean primary) {
isPrimary = primary;
}
@Override
public String toString() {
return "ColumnClass{" +
"propertyName='" + propertyName + '\'' +
", columnName='" + columnName + '\'' +
", type='" + type + '\'' +
", remark='" + remark + '\'' +
", isPrimary=" + isPrimary +
'}';
}
}
package com.yl.generate_code.model;
import java.io.Serializable;
public class Db implements Serializable {
private String username;
private String password;
private String url;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}
package com.yl.generate_code.model;
import java.io.Serializable;
public class ResultModel implements Serializable {
private Integer code;
private String msg;
private Object obj;
public static ResultModel success(String msg,Object obj) {
return new ResultModel(200,msg,obj);
}
public static ResultModel success(String msg) {
return new ResultModel(200,msg,null);
}
public static ResultModel fail(String msg,Object obj) {
return new ResultModel(500,msg,obj);
}
public static ResultModel fail(String msg) {
return new ResultModel(500,msg,null);
}
private ResultModel() {
}
public ResultModel(Integer code, String msg, Object obj) {
this.code = code;
this.msg = msg;
this.obj = obj;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public Object getObj() {
return obj;
}
public void setObj(Object obj) {
this.obj = obj;
}
}
package com.yl.generate_code.model;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class TableClass implements Serializable {
private String tableName;
private String modelName;
private String serviceName;
private String mapperName;
private String controllerName;
private String packetName;
private String createDate;
private List<ColumnClass> columns = new ArrayList<>();
public String getTableName() {
return tableName;
}
public void setTableName(String tableName) {
this.tableName = tableName;
}
public String getModelName() {
return modelName;
}
public void setModelName(String modelName) {
this.modelName = modelName;
}
public String getServiceName() {
return serviceName;
}
public void setServiceName(String serviceName) {
this.serviceName = serviceName;
}
public String getMapperName() {
return mapperName;
}
public void setMapperName(String mapperName) {
this.mapperName = mapperName;
}
public String getControllerName() {
return controllerName;
}
public void setControllerName(String controllerName) {
this.controllerName = controllerName;
}
public String getPacketName() {
return packetName;
}
public void setPacketName(String packetName) {
this.packetName = packetName;
}
public List<ColumnClass> getColumns() {
return columns;
}
public void setColumns(List<ColumnClass> columns) {
this.columns = columns;
}
public String getCreateDate() {
return createDate;
}
public void setCreateDate(String createDate) {
this.createDate = createDate;
}
}
10.index.html(數(shù)據(jù)庫連接生成代碼的界面)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!--引入vue.js,elementui和axios-->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<!-- 引入樣式 -->
<link rel="stylesheet" >
<!-- 引入組件庫 -->
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="app">
<table>
<tr>
<td><el-tag size="mini">數(shù)據(jù)庫用戶名:</el-tag></td>
<td><el-input size="mini" v-model="db.username"></el-input></td>
</tr>
<tr>
<td><el-tag size="mini">數(shù)據(jù)庫密碼:</el-tag></td>
<td><el-input size="mini" v-model="db.password"></el-input></td>
</tr>
<tr>
<td><el-tag size="mini">數(shù)據(jù)庫連接地址:</el-tag></td>
<td><el-input size="mini" v-model="db.url">
<template slot="prepend">jdbc:mysql://</template>
<template slot="append">?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai</template>
</el-input></td>
</tr>
</table>
<div style="display: flex">
<el-button type="primary" size="mini" @click="connect" :disabled="!enableButton">連接數(shù)據(jù)庫</el-button>
<div style="color: red;font-weight: bold" >{{msg}}</div>
<el-input v-model="packetName" size="mini" style="width:300px"></el-input>
<el-button size="mini" type="primary" @click="config">配置</el-button>
</div>
<el-table
:data="tableData"
stripe
border
style="width: 100%">
<el-table-column
prop="tableName"
label="表名稱"
width="180">
</el-table-column>
<el-table-column
label="實(shí)體類名稱"
width="180">
<template slot-scope="scope">
<el-input v-model="scope.row.modelName"></el-input>
</template>
</el-table-column>
<el-table-column
label="mapper名稱">
<template slot-scope="scope">
<el-input v-model="scope.row.mapperName"></el-input>
</template>
</el-table-column>
<el-table-column
label="service名稱">
<template slot-scope="scope">
<el-input v-model="scope.row.serviceName"></el-input>
</template>
</el-table-column>
<el-table-column
label="controller名稱">
<template slot-scope="scope">
<el-input v-model="scope.row.controllerName"></el-input>
</template>
</el-table-column>
</el-table>
<div>
<el-button type="success" size="mini" @click="generateCode">生成代碼</el-button>
<div style="color: green;font-weight: bold">{{result}}</div>
<div>{{codePath}}</div>
</div>
</div>
<script>
new Vue({
el:"#app",
data() {
return{
result: '',
codePath: '',
tableData:[],
packetName: 'com.yl',
msg : "數(shù)據(jù)庫未連接",
enableButton: true,
db: {
username: "root",
password: "root",
url : "localhost:3306/demo"
}
}
},
methods: {
connect() {
let _this = this
this.db.url = "jdbc:mysql://" + this.db.url + "?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai"
axios.post("/connect",this.db).then(res => {
console.log(res.data)
_this.db = {
username: "root",
password: "root",
url : "localhost:3306/demo"
}
_this.msg = res.data.msg
_this.enableButton = false
}).catch(err => {
console.log(err)
})
},
config() {
let _this = this
axios.post("/config",{packetName: _this.packetName}).then(res => {
console.log(res.data)
_this.msg = res.data.msg
_this.tableData = res.data.obj
}).catch(err => {
console.log(err)
})
},
generateCode() {
let _this = this
axios.post("/generateCode",_this.tableData).then(res => {
console.log(res.data)
_this.result = res.data.msg
_this.codePath = res.data.obj
}).catch(err => {
console.log(err)
})
}
}
})
</script>
</body>
</html>
11.接口
package com.yl.generate_code.service;
import com.yl.generate_code.model.ResultModel;
import com.yl.generate_code.model.TableClass;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
public interface GenerateCodeService {
ResultModel generateCode(List<TableClass> list, String realpath);
}
package com.yl.generate_code.service.impl;
import com.google.common.base.CaseFormat;
import com.yl.generate_code.model.ColumnClass;
import com.yl.generate_code.model.ResultModel;
import com.yl.generate_code.model.TableClass;
import com.yl.generate_code.service.GenerateCodeService;
import com.yl.generate_code.utils.DBUtils;
import freemarker.cache.ClassTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@Service
public class GenerateCodeServiceImpl implements GenerateCodeService {
Configuration cfg = null;
{
cfg = new Configuration(Configuration.VERSION_2_3_31);
cfg.setTemplateLoader(new ClassTemplateLoader(GenerateCodeServiceImpl.class,"/templates"));
cfg.setDefaultEncoding("utf-8");
}
@Override
public ResultModel generateCode(List<TableClass> list, String realpath) {
try {
Template modelTemplate = cfg.getTemplate("Model.java.ftl");
Template serviceTemplate = cfg.getTemplate("Service.java.ftl");
Template serviceImplTemplate = cfg.getTemplate("ServiceImpl.java.ftl");
Template mapperTemplate = cfg.getTemplate("Mapper.java.ftl");
Template mapperXmlTemplate = cfg.getTemplate("Mapper.xml.java.ftl");
Template controllerTemplate = cfg.getTemplate("Controller.java.ftl");
Connection connection = DBUtils.getConnection();
DatabaseMetaData metaData = connection.getMetaData();
for (TableClass tableClass : list) {
//根據(jù)表名獲取該表的所有字段
ResultSet columns = metaData.getColumns(connection.getCatalog(), null, tableClass.getTableName(), null);
//獲取該表的所有主鍵
ResultSet primaryKeys = metaData.getPrimaryKeys(connection.getCatalog(), null, tableClass.getTableName());
List<ColumnClass> columnClasses = new ArrayList<>();
while (columns.next()) {
//獲取字段名
String column_name = columns.getString("COLUMN_NAME");
//獲取字段類型
String type_name = columns.getString("TYPE_NAME");
//獲取字段注釋
String remark = columns.getString("REMARKS");
ColumnClass columnClass = new ColumnClass();
columnClass.setColumnName(column_name);
columnClass.setType(type_name);
columnClass.setRemark(remark);
columnClass.setPropertyName(CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL,column_name));
//指標(biāo)挪到第一
primaryKeys.first();
while (primaryKeys.next()) {
String primaryKey = primaryKeys.getString("COLUMN_NAME");
if (column_name.equals(primaryKey)) {
columnClass.setPrimary(true);
}
}
columnClasses.add(columnClass);
}
tableClass.setColumns(columnClasses);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
tableClass.setCreateDate(sdf.format(new Date()));
String path = realpath + "/" + tableClass.getPacketName().replace(".","/");
generate(modelTemplate,tableClass,path+"/model/",1);
generate(serviceTemplate,tableClass,path+"/service/",1);
generate(serviceImplTemplate,tableClass,path+"/service/impl",1);
generate(mapperTemplate,tableClass,path+"/mapper/",1);
generate(mapperXmlTemplate,tableClass,path+"/mapper/",2);
generate(controllerTemplate,tableClass,path+"/controller/",1);
}
return ResultModel.success("代碼已生成",realpath);
} catch (Exception e) {
e.printStackTrace();
return ResultModel.fail("代碼生成失敗");
}
}
private void generate(Template template,TableClass tableClass,String path,Integer flag) throws IOException, TemplateException {
File file = new File(path);
if (!file.exists()) {
file.mkdirs();
}
String fileName;
if (flag == 1) {
fileName = path + "/" + tableClass.getModelName() + template.getName().replace(".ftl","").replace("Model","");
} else {
fileName = path + "/" + tableClass.getModelName() + template.getName().replace(".ftl","").replace(".java","");
}
FileOutputStream fos = new FileOutputStream(fileName);
OutputStreamWriter out = new OutputStreamWriter(fos);
template.process(tableClass,out);
fos.close();
out.close();
}
}
12.圖形化界面

總結(jié)
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
您可能感興趣的文章:
- Java SpringBoot高級用法詳解
- java編程之基于SpringBoot框架實(shí)現(xiàn)掃碼登錄
- java進(jìn)階解析Springboot上傳excel存入數(shù)據(jù)庫步驟
- Java SpringBoot自動裝配原理詳解
- Java SpringBoot實(shí)現(xiàn)AOP
- Java SpringBoot整合SpringCloud
- Java Springboot的目的你知道嗎
- Java中Druid連接池連接超時(shí)獲取不到連接的解決
- java操作Apache druid的實(shí)例代碼
- Druid基本配置及內(nèi)置監(jiān)控使用_動力節(jié)點(diǎn)Java學(xué)院整理
- Java之SpringBoot自定義配置與整合Druid
相關(guān)文章
java 數(shù)值類型分秒時(shí)間格式化的實(shí)例代碼
這篇文章主要介紹了java 數(shù)值類型分秒時(shí)間格式化的實(shí)例代碼的相關(guān)資料,將秒或分鐘的值轉(zhuǎn)換為xx天xx小時(shí)xx分鐘xx秒 如果 “xx” 為0 自動缺省,需要的朋友可以參考下2017-07-07
SpringBoot3 Spring WebFlux簡介(推薦)
SpringWebFlux是Spring Framework 5中引入的響應(yīng)式Web框架,用于支持非阻塞異步通信和響應(yīng)式流處理,與傳統(tǒng)的SpringMVC相比,WebFlux提供了完全異步非阻塞的編程模型,適用高并發(fā)、微服務(wù)架構(gòu)和實(shí)時(shí)數(shù)據(jù)流,本文介紹SpringBoot3 Spring WebFlux簡介,感興趣的朋友一起看看吧2024-10-10
SpringBoot實(shí)現(xiàn)版本升級到2.7.18
這篇文章主要介紹了SpringBoot實(shí)現(xiàn)版本升級到2.7.18全過程,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-08-08
圖解二叉樹的三種遍歷方式及java實(shí)現(xiàn)代碼
本篇文章主要介紹了圖解二叉樹的三種遍歷方式及java實(shí)現(xiàn)代碼,具有一定的參考價(jià)值,有興趣的可以了解一下2017-07-07
Java基于fork/koin類實(shí)現(xiàn)并發(fā)排序
這篇文章主要介紹了Java基于fork/koin類實(shí)現(xiàn)并發(fā)排序,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-02-02

